git-merge-base
Имя
git-merge-base - Найти как можно больше общих предков для слияния
Синтаксис
git merge-base [-a | --all] <commit> <commit>… git merge-base [-a | --all] --octopus <commit>… git merge-base --is-ancestor <commit> <commit> git merge-base --independent <commit>… git merge-base --fork-point <ref> [<commit>]
Описание
git merge-base находит лучшие общие предки между двумя коммитами для использования в слиянии трёх путей. Один общий предок better чем другой общий предок, если последний является предком первого. Общий предок, у которого нет лучшего общего предка, является best common ancestor, т.е. merge base. Обратите внимание, что для пары коммитов может быть более одного merge base.
Режимы работы
В наиболее распространённом частном случае указание только двух коммитов в командной строке означает вычисление merge base между двумя заданными коммитами.
Более общим образом, из двух коммитов для вычисления merge base, один задаётся первым аргументом коммита в командной строке; другой коммит — это (возможно, гипотетический) коммит, который является слиянием по всем остальным коммитам в командной строке.
Следовательно, merge base необязательно содержится в каждом из аргументов коммита, если указано более двух коммитов. Это отличается от git-show-branch[1] при использовании --merge-base опции.
- --octopus
-
Вычислить лучших общих предков всех предоставленных коммитов в подготовке к слиянию n путей. Это имитирует поведение
git show-branch --merge-base. - --independent
-
Вместо вывода merge bases, вывести минимальный набор предоставленных коммитов с одинаковыми предками. Другими словами, из данных коммитов указать те, которые не могут быть достигнуты ни из какого другого. Это имитирует поведение
git show-branch --independent. - --is-ancestor
-
Проверить, является ли первый <commit> предком второго <commit>, и выйти со статусом 0, если это так, или со статусом 1, если нет. Ошибки сигнализируются ненулевым статусом, отличным от 1.
- --fork-point
-
Найти точку, в которой ветвь (или любая история, ведущая к <commit>) разошлась с другой ветвью (или любой ссылкой) <ref>. Это не просто поиск общего предка двух коммитов, но также учитывает reflog <ref> , чтобы увидеть, разошлась ли история, ведущая к <commit>, с более ранней итерацией ветви <ref> (см. обсуждение этого режима ниже).
Параметры
- -a
- --all
-
Вывести все merge bases для коммитов, а не только один.
Обсуждение
Даны два коммита A и B, git merge-base A B выведет коммит, который достижим как из A , так и из B через родительскую связь.
Например, с этой топологией:
o---o---o---B
/
---o---1---o---o---o---A merge base между A и B является 1.
Даны три коммита A, B, и C, git merge-base A B C вычислит merge base между A и гипотетическим коммитом M, который является слиянием между B и C. Например, с этой топологией:
o---o---o---o---C
/
/ o---o---o---B
/ /
---2---1---o---o---o---A результатом git merge-base A B C является 1. Это потому, что эквивалентная топология с коммитом слияния M между B и C имеет вид:
o---o---o---o---o
/ \
/ o---o---o---o---M
/ /
---2---1---o---o---o---A и результат git merge-base A M является 1. Коммит 2 также является общим предком между A и M, но 1 является лучшим общим предком, потому что 2 является предком 1. Следовательно, 2 не является merge base.
Результат git merge-base --octopus A B C является 2, потому что 2 — это лучший общий предок всех коммитов.
Когда история включает пересекающиеся слияния, может быть более одного best общего предка для двух коммитов. Например, с этой топологией:
---1---o---A
\ /
X
/ \
---2---o---o---B и 1 , и 2 являются merge bases для A и B. Ни один из них не лучше другого (оба являются best merge bases). Если --all опция не задана, то не определено, какой лучший из них вывести.
Общим приёмом для проверки «быстрого продвижения» между двумя коммитами A и B является (или, по крайней мере, им пользовались раньше) вычисление merge base между A и B и проверка, совпадает ли он с A. В этом случае A является предком B. Этот приём часто используется в более старых скриптах.
A=$(git rev-parse --verify A)
if test "$A" = "$(git merge-base A B)"
then
... A is an ancestor of B ...
fi В современных Git можно сказать это более прямо:
if git merge-base --is-ancestor A B
then
... A is an ancestor of B ...
fi вместо этого.
Обсуждение режима fork-point
После работы над ветвью topic , созданной с git switch -c
topic origin/master, история ветви удалённого отслеживания origin/master может быть перемотана и перестроена, что приводит к истории такого вида:
o---B2
/
---o---o---B1--o---o---o---B (origin/master)
\
B0
\
D0---D1---D (topic) где origin/master указывал на коммиты B0, B1, B2, а теперь указывает на B, и ваша ветвь topic была запущена на её основе, когда origin/master был в B0, и вы построили три коммита, D0, D1 и D, на её основе. Представьте, что теперь вы хотите перебазировать свою работу на тему поверх обновлённого origin/master.
В таком случае git merge-base origin/master topic вернёт родителя B0 на вышеприведённой картинке, но B0^..D не является диапазоном коммитов, которые вы хотите повторно запустить на основе B (он включает B0, что не то, что вы написали; это коммит, который другая сторона отбросила, когда переместила свой указатель с B0 на B1).
git merge-base --fork-point origin/master topic предназначено для помощи в такой ситуации. Оно учитывает не только B, но также B0, B1 и B2 (т.е. старые указатели удалённых отслеживаемых ветвей, о которых знает reflog вашей репозитории), чтобы увидеть, на каком коммите была основана ваша ветвь темы, и найти B0, позволяя вам повторно запустить только коммиты на вашей теме, исключая коммиты, которые другая сторона позже отбросила.
Поэтому
$ fork_point=$(git merge-base --fork-point origin/master topic)
найдёт B0, а
$ git rebase --onto origin/master $fork_point topic
повторно запустит D0, D1 и D на основе B, чтобы создать новую историю такого вида:
o---B2
/
---o---o---B1--o---o---o---B (origin/master)
\ \
B0 D0'--D1'--D' (topic - updated)
\
D0---D1---D (topic - old) Особенность заключается в том, что более старые записи reflog в вашей репозитории могут быть удалены git gc. Если B0 больше не отображается в reflog ветви удалённого отслеживания origin/master, режим --fork-point очевидно не может его найти и завершается ошибкой, избегая давать случайный и бесполезный результат (например, родителя B0, как даёт та же команда без опции --fork-point).
Кроме того, ветвь удалённого отслеживания, с которой вы используете режим --fork-point , должна быть той, от которой ваша тема разошлась с её указателем. Если вы разошлись с более старым коммитом, чем указатель, этот режим не найдёт точку разветвления (представьте себе в примере истории выше, что B0 не существует, origin/master начался с B1, перешёл к B2, а затем к B, и вы разошлись со своей ветвью темы в origin/master^ , когда origin/master был B1; форма истории будет такой же, как выше, без B0, и родителем B1 является то, что git merge-base origin/master topic правильно находит, но режим --fork-point не найдёт, потому что это не один из коммитов, которые раньше были на указателе origin/master).
См. также
merge-base
© 2005–2026 Linus Torvalds and others
Licensed under the GNU General Public License version 2.
https://git-scm.com/docs/git-merge-base