Как происходит перекрестное слияние в Git?
Я просматриваю страницу "git merge-base", man, и я не могу понять, как развиваются множественные базы слияния. В частности, я завис на следующей иллюстрации на странице man:
When the history involves criss-cross merges, there can be more than one best common
ancestor for two commits. For example, with this topology:
---1---o---A
\ /
X
/ \
---2---o---o---B
both 1 and 2 are merge-bases of A and B. Neither one is better than the other (both
are best merge bases). When the --all option is not given, it is unspecified which
best one is output.
Я просто не понимаю, как такая ситуация может быть создана. Я попытался воссоздать эту ситуацию скрещивания слияния между ветвями, используя тестовый репозиторий, но я не могу его реплицировать. Во всех случаях я всегда заканчиваю 1 фиксацией слияния, к которой указывают как A, так и B (вместо A и B, указывающие на независимое объединение, как показано на диаграмме).
Может ли кто-нибудь проиллюстрировать, как может возникнуть эта ситуация?
Это обычная ситуация или ситуация с ошибкой?
Ответы
Ответ 1
Я просто не понимаю, как такая ситуация может быть создана. Я попытался воссоздать эту ситуацию скрещивания слияния между ветвями, используя тестовый репозиторий, но я не могу его реплицировать. Во всех случаях я всегда заканчиваю 1 фиксацией слияния, к которой указывают как A, так и B (вместо A и B, указывающие на независимое объединение, как показано на диаграмме).
Может ли кто-нибудь проиллюстрировать, как может возникнуть эта ситуация?
Criss-cross слияния могут возникать по-разному. Например, возникает вопрос, когда у вас есть две ссылки на ветки, указывающие на одно и то же слияние (одна из этих ветвей проверяется), и вы запускаете git commit --amend
. Следующий пример игрушек делает только это:
# set things up
cd ~/Desktop
mkdir crisscross
cd crisscross
git init
# make an initial commit
printf "bar\n" > README.md
git add README.md
git commit -m "add README"
# add a line at the top of the file and commit
sed -i '' '1s/^/foo\n/' README.md
git commit -am "add foo line"
# create and checkout a branch pointing at the initial commit
git checkout -b other master^
# add a line at the bottom of the file and commit
printf "baz\n" >> README.md
git commit -am "add baz line"
# do a merge and make both branches point to this merge commit
git merge master
git checkout master
git merge other
На этом этапе вывод git log --graph --oneline --decorate --all
равен
* 30b9175 (HEAD, master, other) Merge branch 'master' into other
|\
| * f318ead add foo line
* | 31875d9 add baz line
|/
* 8b313a0 add README
Теперь измените последнее фиксацию (см. Как git совершить -amend работать, точно? для получения дополнительной информации):
git commit --amend
После этого вывод git log --graph --oneline --decorate --all
будет
* 69bbcbe (HEAD, master) Amended merge commit
|\
| | * 30b9175 (other) Merge branch 'master' into other
| | |\
| |/ /
|/| /
| |/
| * f318ead add foo line
* | 31875d9 add baz line
|/
* 8b313a0 add README
Вот вы: история теперь содержит крест-крест.
Это обычная ситуация или ситуация с ошибкой?
Как показано выше, может возникнуть ситуация. Это может быть нежелательно, но это не следует рассматривать как "состояние ошибки".
Ответ 2
Это происходит, когда другой выбор разработчика берет на себя от вас, вы извлекаете из них, а затем вы оба объединяете друг с другом ветки в свои собственные после того, как вы оба извлечены. Это может случиться, это не состояние ошибки.
Ответ 3
Вот последовательность коммитов, которая сгенерировала бы скрещивание. Больше шагов, чем тот, который включает - modify
, но использует только основы. Запустите этот скрипт, чтобы убедиться, что вы действительно получаете слияние креста.
#!/bin/sh
# Инициализировать
git init.
эхо-дата > file.txt; git добавить file.txt
git commit -m "Исходное сообщение"
# Делать ветки
git-ветвь A; гит-ветвь B
# Сделать изменение в A
git checkout A
эхо-дата > fileA.txt; git добавить файлA.txt
git commit -m "сначала зафиксировать вдоль ветки A"
# Внесите изменения в B; добавить тег для более поздней версии
git checkout B
эхо-дата > fileB.txt; git добавить файлB.txt
git commit -m "сначала фиксировать вдоль ветки B"
git tag "tag-B"
# Слить A в B (все еще на B)
git merge --no-edit A; git tag "M"
# Добавить еще одну фиксацию на B, родитель которой M
эхо-дата > fileB2.txt; git добавить fileB2.txt
git commit -m "вторая фиксация по B"
# Переключитесь на A и добавьте фиксацию; Обратите внимание, что
# M не является предком этой фиксации
git checkout A
эхо-дата > fileA2.txt; git добавить файлA2.txt
git commit -m "second commit вдоль A"
эхо "Лучшие общие предки (до креста):"
# Должен быть только один
git merge-base - all A B
# Объединить фиксацию с тегами "tag-B"
# в A, генерирующий cris-cross-merge
git merge --no-edit tag-B
эхо "Лучшие общие предки (после креста):"
# Должно быть два
git merge-base - all A B
Код>