Spec-Zone.ru › Git

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).

См. также

git-rev-list[1], git-show-branch[1], git-merge[1]

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

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API