Git
英語 ▾ トピック ▾ 最新バージョン ▾ git-merge-base は 2.43.0 で最後に更新されました

名前

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 は、3方マージで使用される2つのコミット間の最良の共通祖先(複数可)を見つけます。 ある共通祖先は、後者が前者の祖先である場合、別の共通祖先よりも「優れています」。 より良い共通祖先を持たない共通祖先は、最良の共通祖先、つまりマージベースです。 コミットのペアには、複数のマージベースが存在する可能性があることに注意してください。

動作モード

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

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

その結果、2つ以上のコミットが指定されている場合、マージベースは必ずしも各コミット引数に含まれているわけではありません。これは、--merge-base オプションを付けて使用した場合のgit-show-branch[1]とは異なります。

--octopus

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

--independent

マージベースを出力する代わりに、同じ祖先を持つ提供されたコミットの最小限のサブセットを出力します。つまり、指定されたコミットの中で、他のコミットから到達できないものをリストします。これは、git show-branch --independentの動作を模倣しています。

--is-ancestor

最初の<commit>が2番目の<commit>の祖先であるかどうかを確認し、真の場合はステータス0で終了し、偽の場合はステータス1で終了します。エラーは、1ではないゼロ以外のステータスで示されます。

--fork-point

ブランチ(または<commit>につながる履歴)が別のブランチ(または参照)<ref>から分岐した点を検出します。これは、2つのコミットの共通祖先を探すだけでなく、<ref>のreflogも考慮して、<commit>につながる履歴がブランチ<ref>の以前のバージョンから分岐したかどうかを確認します(このモードの詳細については後述)。

オプション

-a
--all

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

詳細

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

例えば、次のトポロジーの場合

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

ABのマージベースは1です。

3つのコミットABCが与えられると、git merge-base A B Cは、BCのマージである仮想的なコミットMAのマージベースを計算します。 例えば、次のトポロジーの場合

       o---o---o---o---C
      /
     /   o---o---o---B
    /   /
---2---1---o---o---o---A

git merge-base A B Cの結果は1です。これは、BCの間のマージコミットMを持つ同等のトポロジーが

       o---o---o---o---o
      /                 \
     /   o---o---o---o---M
    /   /
---2---1---o---o---o---A

であり、git merge-base A Mの結果が1であるためです。コミット2AMの共通祖先ですが、21の祖先であるため、1はより良い共通祖先です。したがって、2はマージベースではありません。

git merge-base --octopus A B Cの結果は2です。なぜなら、2がすべてのコミットの最良の共通祖先だからです。

履歴にクロスオーバーマージが含まれている場合、2つのコミットに対して複数の最良の共通祖先が存在する可能性があります。 例えば、次のトポロジーの場合

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

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

2つのコミットAとBの間の「高速転送」をチェックするための一般的なイディオムは(少なくとも以前は)、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

代わりに。

フォークポイントモードに関する説明

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の上にtopicで行った作業をrebaseしたいとします。

このような場合、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が認識するリモート追跡ブランチの古い先端)も考慮して、topicブランチが作成されたコミットを特定し、B0を見つけます。これにより、先方が後で破棄したコミットを除いて、topic上のコミットのみを再生できます。

したがって

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

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

GIT

git[1]スイートの一部

scroll-to-top