Почему ветвь B конфликтует во всех коммитах слияния от A до B после первого коммита слияния?

У меня есть основная ветка разработки (A), которая имеет долгую историю. Все коммиты релиза в A помечены как таковые. Я проверил корневой коммит A, и разветвился в тест (B).

Итак, у меня есть первичная ветвь A, а глава ветки B указывает на корневой коммит A. Моя цель - создать историю всех выпусков путем слияния каждого тегового коммита от A до B.

Первое слияние из А в Б работает как положено, никаких конфликтов.

$git checkout B
$git merge [release-commit-ID] --squash
$git commit -m "release#"

Первый коммит работает отлично, но все остальные коммиты рассматривают все коммиты слияния как полные конфликты. Я вижу, что корень B такой же, как корень A, но общая история не распознается после первого сдавленного коммита слияния из первого релиза коммит в A в B. Что вызывает конфликты и как мне получить общую историю быть признанным?

1 ответ

Решение

Что вызывает конфликты и как я могу получить общую историю, которая будет распознана?

Там нет общей истории (или, скорее, не достаточно). Там нет ничего, чтобы признать, поэтому есть конфликты.

Ключ является --squash флаг:

$ git checkout B
$ git merge [release-commit-ID] --squash

Первый шаг прикрепляет ваш HEAD на название филиала B, проверяя, какое имя зафиксировать B определяет:

...--*--C--D--E   <-- B (HEAD)
      \
       F--G--H   <-- somebranch

Здесь имя B определяет совершить E (каждая из этих букв обозначает настоящие хэш-идентификаторы). совершить * (который я бы назвал B (но вы использовали это название для своей ветви) - это точка, в которой два потока разработки расходятся, что означает, что когда мы работаем в обратном направлении (как это делает Git), это точка, где они объединяются. Вы сейчас бежите git merge --squash <hash> где <hash> определяет совершить F, или же G, или же H так что Git сравнивает содержимое коммита * к содержанию коммита E чтобы узнать, что вы изменили:

git diff --find-renames <hash-of-*> <hash-of-E>   # what we changed

и повторяет, скажем, G:

git diff --find-renames <hash-of-*> <hash-of-G>   # what they changed

Git теперь объединяет эти два набора изменений, применяет объединенные изменения для фиксации * и делает новый коммит.

Если вы не используете --squash Гит записывает новый коммит с двумя родителями:

...--*--C--D--E--I   <-- B (HEAD)
      \         /
       F-------G--H   <-- somebranch

и теперь самая последняя общая отправная точка между двумя строками - это фиксация G, Но если вы используете --squash Git записывает новый коммит только с одним родителем:

...--*--C--D--E--I   <-- B (HEAD)
      \
       F--G--H   <-- somebranch

и теперь общая отправная точка не изменилась. Вся работа через G находится в совершении I, но совершают I не помню, почему эта работа там. Будущее git merge от коммита H должен начать заново при коммите *,

Git не помешает вам развиваться на ветке somebranch, но в целом после git merge --squash, вы должны считать ветку, из которой вы слились, "мертвой" и просто прекратить ее использование. После того, как мы объединились G с git merge --squash мы должны перестать использовать F а также G полностью. Это означает, что мы также должны прекратить использование H полностью. Если H полезно, мы должны скопировать его в новый, другой коммит:

$ git checkout -b newbranch B

давая нам:

...--*--C--D--E--I   <-- B, newbranch (HEAD)
      \         /
       F-------G--H   <-- somebranch

с последующим:

$ git cherry-pick somebranch   # or <hash of H>

копировать H очень похожий, но не идентичный, совершить H':

                   H'   <-- newbranch (HEAD)
                  /
...--*--C--D--E--I   <-- B
      \         /
       F-------G--H   <-- somebranch

Теперь мы можем отказаться somebranch:

$ git branch -D somebranch

и переименовать newbranch в somebranch если нам нравится

(Обратите внимание, что мы можем сделать это с помощью копирования с именем за один шаг, используя git rebase --onto, с git checkout somebranch; git rebase --onto B <hash of G>, Независимо от того, как вы это делаете, однако, имейте в виду, что git cherry-pick не может скопировать коммиты слияния, и любой, кто использует коммиты, которые мы хотим убить - здесь F-G-H цепочка - должна сделать эту вещь "убить с копированием тех, кто хочет сохранить". Так что перед использованием --squash Убедитесь, что вы понимаете все последствия.)

Другие вопросы по тегам