SYNOPSIS

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>]

DESCRIPTION

git merge-base は、3方向マージで使用する2つのコミット間で最良の共通の祖先を探します。「ある共通の祖先」の祖先が、「別の共通の祖先」である場合、「ある共通の祖先」は「別の共通の祖先」よりも「より良い」です。より良い共通の祖先を持たない共通の祖先は、「最良の共通の祖先」、つまり「マージベース」です。注意: コミットのペアに対して複数のマージベースが存在する可能性があることに注意してください。

OPERATION MODES

最も一般的な特別のケースとして、コマンドラインで2つのコミットのみを指定することは、指定された2つのコミット間のマージベースを計算することを意味します。

より一般的には、マージベースを計算する2つのコミットのうち、1つはコマンドラインの最初のコミット引数で指定されます。もう1つのコミットは、コマンドラインの残りのすべてのコミットをマージする(おそらく仮想の)コミットです。

結果として、3つ以上のコミットが指定されている場合、「マージベース」は必ずしも各コミット引数に含まれているとは限りません。 これは、 --merge-base オプションを伴った git-show-branch(1) とは異なります。

--octopus

n方向マージの準備として、提供されたすべてのコミットの最良の共通の祖先を計算します。これは、 git show-branch --merge-base の振る舞いを模倣しています。

--independent

マージベースを出力する代わりに、提供されたコミットの最小限のサブセットを同一祖先で出力します。言い換えれば、与えられたコミットの中にで他から到達できないコミットをリストします。これは、 git show-branch --independent の振る舞いを模倣しています。

--is-ancestor

1番目の <commit> が2番目の <commit> の祖先であるかどうかを確認し、trueの場合はステータス0で終了し、そうでない場合はステータス1で終了します。 エラーは、1では無い、かつ、ゼロ以外のステータスによって通知されます。

--fork-point

ブランチ(または <commit> につながる履歴)が、別のブランチ(または参照) <ref> から分岐したポイントを見つけます。これは、2つのコミットの共通の祖先を探すだけでなく、 <ref> のreflogを考慮して、 <commit> につながる履歴がブランチ <ref> の以前の実体(incarnation)から分岐したかどうかを確認します(下記の、このモードに関するdiscussionを参照してください)。

OPTIONS

-a
--all

1つだけではなく、コミットのすべてのマージベースを出力します。

DISCUSSION

2つのコミット「A」と「B」が与えられると、「git merge-base A B」は、親子関係を辿って「A」と「B」の両方から到達可能なコミットを出力します。

たとえば、このトポロジでは以下のようになります:

         o---o---o---B
        /
---o---1---o---o---o---A

「A」と「B」の間のマージベースは「1」です。

3つのコミット「A」、「B」、「C」が与えられると、「git merge-base A B C」は、「A」と仮想のコミット「M」の間のマージベースを計算します。仮想のコミット「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」です。 これは、「B」と「C」の間にマージコミット「M」がある同等のトポロジが以下のとおりであるためです:

       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」の間の共通の祖先ですが、「2」は「1」の祖先であるため、「1」の方がよりよい共通の祖先です。 したがって、「2」はマージベースではありません。

git merge-base --octopus A B C の結果は「2」です。これは、「2」がすべてのコミットの中で最も共通の祖先であるためです。

履歴に交差マージ(criss-cross merges)が含まれる場合、2つのコミットに対して「最良の」共通の祖先が複数存在する可能性があります。 たとえば、このトポロジでは以下のようになります:

---1---o---A
    \ /
     X
    / \
---2---o---o---B

「1」と「2」はどちらもAとBのマージベースです。どちらももう一方よりも優れているわけではありません(どちらも「最良の」マージベースです)。 --all オプションが指定されていない場合、どちらの最良のマージベースが出力されるかは指定されていません。

2つのコミットAとBの間の「早送り性」(fast-forward-ness)をチェックする、という慣用句は、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

このように、上記にとって代わります。

Discussion on fork-point mode

git switch -c topic origin/master で作成された topic ブランチで作業した後、リモート追跡ブランチ origin/master の履歴が巻き戻されて再構築された可能性があり、以下形の履歴につながります:

                 o---B2
                /
---o---o---B1--o---o---o---B (origin/master)
        \
         B0
          \
           D0---D1---D (topic)

ここで、 origin/master はコミットB0、B1、B2を指していましたが、現在はBを指しています。そして、 origin/master がB0にあったときに、あなたの topic ブランチがその上で開始されました。あなたは、その上に、D0、D1、Dの3つのコミットを作成しました。あなたは更新された origin/master の上に、トピックで行った作業をリベースしたいとします。

このような場合、 git merge-base origin/master topic は上の図のB0の親を返しますが、 B0^..D はBの上でリプレイしたいコミットの範囲ではありません(これには、あなたが書いたものではないB0が含まれます。これは、先端をB0からB1に移動したときに破棄された自分側で無い側(the other side)のコミットです)。

git merge-base --fork-point origin/master topic は、このような場合に役立つように設計されています。 Bだけでなく、B0、B1、およびB2も(つまり、リポジトリのreflogが知っているリモート追跡ブランチの古い先端も)考慮に入れて、あなたのtopicブランチが構築されたコミットを確認し、B0を見つけます。これにより、topicのコミットのみをリプレイできます。ただし、自分の側で無い側(the other side)で後で破棄されるコミットは除きます。

したがって、以下は

$ fork_point=$(git merge-base --fork-point origin/master topic)

B0 を見つけ、そして

$ git rebase --onto origin/master $fork_point topic

以下の形の新しい履歴を作成するために、B の上で D0 と D1 と D をリプレイします:

                 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がリモート追跡ブランチ origin/ master のreflogに表示されなくなった場合、--fork-point モードは明らかにそれを見つけることができず失敗し、ランダムで役に立たない結果(--fork-point オプション無しの同じコマンドが返すB0の親など)を与えることを避けます。

また、 --fork-point モードを使用するリモート追跡ブランチは、あなたのトピックがその先端から分岐したものである必要があります。先端よりも古いコミットからフォークした場合、このモードではフォークポイントが見つかりません。(上記の履歴例でB0が存在せず、 origin/master がB1で始まり、B2、次にBに移動し、 origin/master がB1のときに、 origin/master^ でトピックをフォークしたと想像してください。履歴の形は上記と同じですが、B0はありません。B1の親は、 git merge-base origin/master topic が正しく検出するものですが、 --fork-point モードは検出しません。なぜなら origin/master の先端にあったコミットの1つではないためです。)

See also

GIT

Part of the git(1) suite