Setup and Config
Getting and Creating Projects
Basic Snapshotting
Branching and Merging
Sharing and Updating Projects
Inspection and Comparison
Patching
Debugging
External Systems
Server Admin
Guides
- gitattributes
- Command-line interface conventions
- Everyday Git
- Frequently Asked Questions (FAQ)
- Glossary
- Hooks
- gitignore
- gitmodules
- Revisions
- Submodules
- Tutorial
- Workflows
- All guides...
Administration
Plumbing Commands
- 2.43.1 → 2.54.0 no changes
-
2.43.0
2023-11-20
- 2.39.1 → 2.42.4 no changes
-
2.39.0
2022-12-12
- 2.24.1 → 2.38.5 no changes
-
2.24.0
2019-11-04
- 2.23.1 → 2.23.4 no changes
-
2.23.0
2019-08-16
- 2.19.3 → 2.22.5 no changes
-
2.19.2
2018-11-21
- 2.16.6 → 2.19.1 no changes
-
2.15.4
2019-12-06
- 2.11.4 → 2.14.6 no changes
-
2.10.5
2017-09-22
- 2.1.4 → 2.9.5 no changes
-
2.0.5
2014-12-17
ОБЗОР
git merge-base [-a | --all] <коммит> <коммит>… git merge-base [-a | --all] --octopus <коммит>… git merge-base --is-ancestor <коммит> <коммит> git merge-base --independent <коммит>… git merge-base --fork-point <ссылка> [<коммит>]
ОПИСАНИЕ
git merge-base находит наилучшего(их) общего(их) предка(ов) между двумя коммитами для использования в трёхстороннем слиянии. Один общий предок «лучше» другого общего предка, если последний является предком первого. Общий предок, у которого нет никакого лучшего общего предка, является «наилучшим общим предком», т.е. «базой слияния» (merge base). Обратите внимание, что для пары коммитов может быть более одной базы слияния.
РЕЖИМЫ РАБОТЫ
В наиболее распространённом частном случае указание только двух коммитов в командной строке означает вычисление базы слияния между указанными двумя коммитами.
В более общем смысле, среди двух коммитов, для которых вычисляется база слияния, один задаётся первым аргументом-коммитом в командной строке; другой коммит — это (возможно, гипотетический) коммит, который является слиянием всех остальных коммитов в командной строке.
Как следствие, «база слияния» не обязательно содержится в каждом из аргументов-коммитов, если указано более двух коммитов. Это отличается от git-show-branch[1] при использовании с параметром --merge-base.
- --octopus
-
Вычисляет наилучших общих предков всех предоставленных коммитов, готовясь к n-стороннему слиянию. Это имитирует поведение git show-branch --merge-base.
- --independent
-
Вместо вывода баз слияния выводит минимальное подмножество предоставленных коммитов с теми же предками. Другими словами, среди указанных коммитов перечисляет те, которые не могут быть достигнуты из какого-либо другого. Это имитирует поведение git show-branch --independent.
- --is-ancestor
-
Проверяет, является ли первый <коммит> предком второго <коммита>, и завершается с кодом 0, если это так, или с кодом 1, если нет. Ошибки сигнализируются ненулевым кодом, отличным от 1.
- --fork-point
-
Находит точку, в которой ветка (или любая история, ведущая к <коммиту>) ответвилась от другой ветки (или любой ссылки) <ссылка>. Это не просто ищет общего предка двух коммитов, но также учитывает журнал ссылок (reflog) <ссылка>, чтобы увидеть, ответвилась ли история, ведущая к <коммиту>, от более ранней инкарнации ветки <ссылка> (см. обсуждение этого режима ниже).
ОБСУЖДЕНИЕ
Для двух коммитов A и B git merge-base A B выведет коммит, который достижим из обоих A и B через связь «родитель».
Например, при такой топологии:
o---o---o---B / ---o---1---o---o---o---A
базой слияния между A и B является 1.
Для трёх коммитов A, B и C git merge-base A B C вычислит базу слияния между 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 не является базой слияния.
Результатом git merge-base --octopus A B C является 2, потому что 2 — наилучший общий предок всех коммитов.
Когда история включает перекрёстные слияния, для двух коммитов может быть более одного «наилучшего» общего предка. Например, при такой топологии:
---1---o---A
\ /
X
/ \
---2---o---o---B
и 1, и 2 являются базами слияния A и B. Ни одна из них не лучше другой (обе являются «наилучшими» базами слияния). Когда параметр --all не указан, не определено, какая из наилучших будет выведена.
Распространённая идиома для проверки «перематываемости» (fast-forward-ness) между двумя коммитами A и B заключается (или, по крайней мере, раньше заключалась) в вычислении базы слияния между A и B и проверке, совпадает ли она с A, и в этом случае A является предком B. Вы часто будете видеть эту идиому в старых сценариях.
A=$(git rev-parse --verify A) if test "$A" = "$(git merge-base A B)" then ... A является предком B ... fi
В современном git вы можете сказать это более прямым способом:
if git merge-base --is-ancestor A B then ... A является предком 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, поверх него. Представьте, что теперь вы хотите переместить (rebase) работу, которую вы сделали в теме, поверх обновлённого 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 (т.е. старые верхушки отслеживаемых внешних веток, о которых знает журнал ссылок вашего репозитория), чтобы увидеть, на каком коммите была основана ваша ветка topic, и находит 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 - обновлённая) \ D0---D1---D (topic - старая)
Предостережение заключается в том, что более старые записи журнала ссылок в вашем репозитории могут быть устаревшими из-за git gc. Если B0 больше не появляется в журнале ссылок отслеживаемой внешней ветки 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).
GIT
Является частью пакета git[1]