Я пытался понять, смогу ли я заставить общего предка работать с слиянием, но я не уверен, что смогу сделать это из того, что прочитал.
Нет. Git вычисляет базы слияния для вас. Они основаны на графике фиксации.
Стоит сесть и нарисовать график (или сделать git log --graph
для вас). Попробуйте использовать git log --all --decorate --oneline --graph
(запомните это как , чтобы получить помощь от A DOG ), и, возможно, добавьте --simplify-by-decoration
, чтобы помочь отбросить большую часть визуального беспорядка.
Поиск баз слияния с помощью глазного яблока
С помощью простых графиков легко увидеть визуально, какой коммит является базой слияния двух других коммитов. Например, учитывая график, который может отображаться таким образом, с последующими коммитами вправо:
o--o--L <-- branch1 (HEAD)
/
...--o--*
\
o--o--R <-- branch2
... база слияния коммитов L
(ваш текущий извлеченный коммит, HEAD
, на кончике branch1
) и коммит R
(коммит на кончике branch2
) это совершить *
.
Многие графики ужасны и запутаны, и их совсем не так просто разобрать визуально. Поначалу даже некоторые из них немного сложнее. Довольно распространенный случай возникает при повторных слияниях:
...--o--o--o--o--o--o--*--o--L <-- branch1
\ \ \
o--o--A--o--o--B--o--R <-- branch2
Еще раз, база слияния L
и R
является коммитом *
. Существует два существующих слияния, A
и B
. Слияние A
не имеет значения, потому что слияние B
создает первый коммит, достижимый из обеих подсказок ветви: мы начинаем с L
и возвращаемся к двум коммитам до *
, а начинаем с R
, возвращаемся к двум фиксирует B
, идет к его родителю *
и достигает общего коммита.
перебазирования
Я пытался [перебазировать]
Обратите внимание, что при использовании git rebase
копий коммиты, обычно , отбрасывая слияний. Предположим, у вас есть график выше, сливающийся в branch2
, и вы решаете git rebase branch2 branch1
. Это будет перечислять все коммиты, которые доступны с branch2
, но не с branch1
, за исключением слияний. Хотя мы можем достичь коммита *
из branch2
и branch1
, мы не можем достичь любого коммитов нижнего ряда из branch1
. Таким образом, копируемые коммиты - это все те, которые находятся в нижнем ряду. Давайте дадим им всем однобуквенные имена, чтобы мы могли говорить о них:
...--o--o--o--o--o--o--*--o--L <-- branch1
\ \ \
C--D--A--E--F--B--G--R <-- branch2
(я сохранил однобуквенные имена, которые у нас уже были для A
, B
и R
здесь).
Операция rebase - git checkout branch2; git rebase branch1
- выбирает все фиксации без слияния вдоль нижнего ряда и копирует их. Копии идут после коммита L
, на кончике branch1
, поэтому получается:
C'-D'-E'-F'-G'-R' <-- branch2
/
...--o--o--o--o--o--o--o--o--L <-- branch1
\ \ \
C--D--A--E--F--B--G--R <-- ???
Хотя имя branch2
было перемещено в этот момент - теперь оно указывает на R'
, копия R
- оригинального коммитов все еще существует. Они просто не достижимы от названия branch2
больше.
Если есть другая ветвь - скажем, branch3
- которая происходит от некоторых или всех этих коммитов, мы могли бы нарисовать это в:
C'-D'-E'-F'-G'-R' <-- branch2
/
...--o--o--o--o--o--o--o--o--L <-- branch1
\ \ \
C--D--A--E--F--B--G--R <-- ???
\
H--I <-- branch3
Поскольку R
, G
и B
не могут быть легко найдены, мы можем прекратить рисовать их полностью:
C'-D'-E'-F'-G'-R' <-- branch2
/
...--o--o--o--o--o--o--o--o--L <-- branch1
\ \
C--D--A--E--F
\
H--I <-- branch3
Коммиты C-D-A-E-F
все еще живы и здоровы, однако достижимы, начиная с branch3
(коммит I
) и работая в обратном направлении.
Если теперь вы решите объединить branch3
с branch1
или branch2
, база для слияния будет найдена, начиная с обоих концов веток и работая в обратном порядке, как обычно. В этом случае база слияния - это коммит, которого мы достигаем, переходя вверх и влево от коммита A
(слияние все еще достижимо с кончика branch3
), поскольку этот коммит доступен с обеих кончиков веток и является «ближе всего к концу».
BecausИз этой вещи, состоящей из нескольких имен, доходят до старых коммитов, обычно нет смысла перебазировать ветви, поддерживающие другие ветви.Также сложно перебазировать ветки, содержащие слияния.Современный (2.18+) Git имеет опцию --rebase-merges
, которая позволяет Git заново создавать слияния;У старого Git есть --preserve-merges
, который пытается сделать то же самое, но более хрупок, чем современный метод.Во всех случаях, однако, важно знать, что когда rebase должен скопировать коммит слияния, он действительно просто снова запускает git merge
, чтобы вычислить new базу слияния и повторить слияние с нуля.
Дополнительные примечания
Обратите внимание, что отметки даты и времени на коммитах здесь совершенно неактуальны. Только граф имеет значение .Коммиты с их хэш-идентификаторами узлов и родительскими хэш-идентификаторами ребер образуют граф фиксации.Содержимое внутри каждого коммита - это история;* * * * * * * * * * * * * * * *
* * * * * * * * *1132* * * * * * *1132* Чтобы Git сообщал вам, что он использует для базы слияния, делайте то же, что и вы, но добавьте --all
в случае нескольких баз слияния:
git merge-base --all branch1 branch2
Git выполнит поиск базы слияния: начните с последнего коммита, на который указывают имена, пройдитесь назад по всем путям и найдителучший коммит (ы) .Затем он распечатает хеш-код (ы) всех баз слияния.Затем слияние будет продолжено путем сравнения (как и в случае git diff
) (единственной) базы слияния с двумя коммитами с ветвлением.
Если равно более чем одной базе слияния,стратегия по умолчанию -s recursive
сначала будет запускаться git merge
на самих базах слияния, 1 делать рекурсивное слияние до тех пор, пока Git не сможет создать один коммит, который будет использоваться в качестве "виртуальной базы слияния" процесса слияния,Вы можете сделать так, чтобы Git просто выбрал один из них (по-видимому) случайным образом, используя вместо этого -s resolve
.Обычно это не является каким-либо улучшением, но это стоит знать в сложных случаях.
1 Если вы не действительно невезучие / сошли с умаВ вашем предыдущем построении графиков будет максимум две базы слияния.Если их больше, Git объединяет два, фиксирует результат, объединяет его со следующим, фиксирует результат и т. Д.