Git: Найти последнего общего предка двух веток

844

Как найти самого последнего общего предка двух веток Git?

Тед
источник
3
Определите самые последние: реальное время, количество коммитов, другие метрики?
Сиро Сантилли 郝海东 冠状 病 六四 事件 法轮功
2
Соответствующий (слияние крестов): stackoverflow.com/questions/26370185/…
jub0bs
1
@CiroSantilli 新疆 改造 中心 996ICU 六四 事件 это то же самое в любой метрике, не так ли?
ЯковЛ
@YakovL Я считаю, что нет из-за ветвления и потому, что вы можете устанавливать произвольные даты фиксации для ваших объектов фиксации: эта дата, скорее всего, не та, которую вы хотите.
Сиро Сантилли 郝海东 冠状 病 六四 事件 法轮功
1
@CiroSantilli 新疆 改造 中心 996ICU 六四 事件 мне кажется, что это может быть иначе, только если перед последним общим коммитом в дереве есть коммит, который имеет более старую временную метку. Можете ли вы привести менее тривиальный пример?
ЯковЛ

Ответы:

1020

Вы ищете git merge-base. Применение:

$ git merge-base branch2 branch3
050dc022f3a65bdc78d97e2b1ac9b595a924c3f2
CB Bailey
источник
85
Обратите внимание, что это находит самого последнего общего предка ... который я полагаю, это то, что хочет спрашивающий, так что +1. Просто отмечая это, на случай, если кто-нибудь придет сюда, пытаясь найти самого старого общего предка (как я это сделал) - о котором см. Также: stackoverflow.com/questions/1527234/…
lindes
16
@funroll: Или сокращение для этого:git log master...HEAD
CB Bailey
17
@ lindes будет ли самый старый общий предок не быть начальным коммитом?
Торбьерн Равн Андерсен
8
@ ThorbjørnRavnAndersen, да, я полагаю, что это так ... Сложность описания связана с тем, что git использует направленный ациклический граф, и все же его часто рассматривают как дерево, которое технически не так. Чтобы быть более осторожным в моей формулировке, я говорил о случае, когда вы хотите, чтобы родительский элемент первого экземпляра "ветвей" расходился ... поскольку они могут иметь несколько точек, где они объединяются и повторно разделяются, это самый старый из них, но не самый старый предок, который (я думаю) всегда является первоначальным коммитом.
Линд
5
Хотя этот вопрос строго касается поиска общего предка двух ветвей, любой, кто хочет иметь общего предка трех или более ветвей, должен заметить, что ему нужно пройти --octopusфлаг, чтобы получить правильный результат. Очевидное, но неправильное git merge-base branch1 branch2 branch3даст вам коммит, но, как описано в разделе «Обсуждение» в документации, он не обязательно является общим предком всех трех ветвей.
Марк Амери
46

git diff master...feature

показывает все новые коммиты вашей текущей (возможно, многокомпонентной) ветки функций.

man git-diff документы, которые:

git diff A...B

такой же как:

git diff $(git merge-base A B) B

но ...легче набрать и запомнить.

Как упомянул Дэйв , особый случай HEADможет быть опущен. Так:

git diff master...HEAD

такой же как:

git diff master...

этого достаточно, если текущая ветвь есть feature.

Наконец, помните, что порядок имеет значение! Выполнение git diff feature...masterпокажет изменения, которые masterне включены feature.

Я хотел бы, чтобы больше команд git поддерживали этот синтаксис, но я не думаю, что они делают. А некоторые даже имеют различную семантику для ...: Каковы различия между двойной точкой ".." и тройной точкой "..." в диапазонах коммитов Git?

Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
источник
8
Или только git diff master...в частном случае сравнивает кHEAD
Дэйву
"..." не работал для меня в powershell, забавно, что он работал в консоли git, может быть, репозиторий не был завершен, git diff $ (git merge-base AB) B и так как я немного новичок в git Я немного скептически относился к тому, что это может объединить ветви :)
Moiz Ahmed
1
Ух ты. довольно удивительно. и если нужная вам ветка не существует в вашем локальном репо, потому что вы ее никогда не проверяли, вы можете просто сделать этоgit diff origin/branchname...
Марк Ч
25

Как отмечалось в предыдущем ответе, git merge-baseработает:

$ git merge-base myfeature develop
050dc022f3a65bdc78d97e2b1ac9b595a924c3f2

но если myfeatureэто текущая ветвь, как обычно, вы можете использовать use --fork-point:

$ git merge-base --fork-point develop
050dc022f3a65bdc78d97e2b1ac9b595a924c3f2

Этот аргумент работает только в достаточно последних версиях git. К сожалению, это не всегда работает, и не понятно почему. Пожалуйста, ознакомьтесь с ограничениями, указанными в конце этого ответа .


Для полной информации о коммите, рассмотрите:

$ git log -1 $(git merge-base --fork-point develop) 
Акаменус
источник
У меня есть git version 2.14.1.windows.1. Запуск git merge-base --fork-point branch2с веткой (с ее собственными коммитами), который, как я знаю , разветвился из текущей ветви, не даст никакого результата, тогда как git merge-base branch1 branch2правильно показывает точку ветвления . В чем может быть проблема?
ADTC
@ADTC Checkout, branch2а затем запустить git merge-base --fork-point branch1.
Acumenus
@ADTC Используйте графический просмотрщик коммитов, например gitk, и т. Д., Чтобы увидеть, как выглядит дерево. Может быть, вы получите ответ.
Acumenus
Я не вижу ничего странного в дереве, так как вижу его графически. Я могу проследить пути и найти общего предка, который соответствует результату git merge-base branch1 branch2. Но что странно, это то, что --fork-pointничего не дает в любом случае. Вы подтвердили, что это работает для вас, как задумано?
ADTC
1
Я получаю то же самое, что @ADTC. Команда 'git log -1 $ (git merge-base --fork-point anotherBranch) "не показывает никаких результатов при использовании git версии 2.16.2.windows.1.
masinger
10

С помощью gitkвы можете просмотреть две ветви графически:

gitk branch1 branch2

И тогда легко найти общего предка в истории двух ветвей.

Мартин Г
источник
6
Не все может быть сделано визуально в каждом случае. Есть причины, по которым вещи, возможно, должны быть автоматизированы программно.
ADTC