あるコミットが別のコミットの子孫であるかどうかはどうすればわかりますか?


146

Gitを使用して、自分のブランチの1つのコミットが別のコミットの子孫であるかどうかを確認するにはどうすればよいですか?


2
同じ質問には反対のことを尋ねた:stackoverflow.com/questions/18345157/...
クリスCleeland

11
受け入れられた答えを変更できますか?大多数が--is-ancestorソリューションを気に入っています。
Robert Siemer、2015年

回答:


51

これをプログラムで(たとえばスクリプトで)チェックする場合git merge-base A Bは、が等しいgit rev-parse --verify A(BからAに到達できる)か、またはgit rev-parse --verify B(BがAから到達できる)かどうかをチェックできます。 git rev-parseここでは、コミット名からコミットSHA-1 /コミットIDに変換する必要があります。

VonC回答のgit rev-listように使用することも可能です。

編集:最近のGitでは、このクエリがの形式で明示的にサポートされていますgit merge-base --is-ancestor


質問しているコミットの1つがブランチのヒントである場合は、非プログラム的な解決策であるgit branch --contains <commit>か、git branch --merged <commit>そうでない可能性があります。


1
おそらく最速の方法は、になりgit checkout -b quickcheck <more-recent-commit-ID>、その後、git branch --contains <older-commit-ID>(その後、git branch -D quickcheck一時的な枝を取り除くために)。
クリー

2
2つの可能なアプローチ。どちらも@MattRの回答にあるアプローチよりもはるかに悪いものです。
jwg

6
@jwg:MattRの回答の方が優れていますが、この回答(そしておそらくそれが受け入れられている)はgit 1.8.0よりもgit merge-base --is-ancestor2年前のものです。
JakubNarębski16年

@JakubNarębski結構です、ごめんなさい。
jwg

2
大きなリポジトリ(200万コミット)において、Iは、速度を比較git branch --contains <commit>し、git merge-base --is-ancestor ...:0.14s対3m40s
hagello

259

Git 1.8.0以降、これは次のオプションとしてサポートされますmerge-base

git merge-base --is-ancestor <maybe-ancestor-commit> <descendant-commit>

manページから:

--is-ancestor

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

例えば:

git merge-base --is-ancestor origin/master master; echo $?

4
いいね!この回答を人間が理解できる出力でラップするシェルスクリプトを次に示します。gist.github.com
Simon Whitaker

1
言い換えると、git merge-base THING --is-ancestor OF_THING && echo yes || echo no例:git merge-base my-feature-branch --is-ancestor master && echo yes || echo no
user1735594、2018

2
@smarber git merge-base --is-ancestor -- commit commitは私の側でgit2.1.4(Debian / Devuan 7.10 jessie)と1.9.1(Ubuntu 14.04 trusty)のハッシュに対して機能します。Debian wheezyでも機能しますsudo apt-get install git/wheezy-backports
ティノ

15

この種の操作は、SOの質問で詳しく説明されている一連のリビジョンの概念に依存しています。「「git log origin / master」と「git log origin / master ..」の違い

git rev-list コミットから到達可能であれば別のコミットまで戻ることができるはずです。

だから私は試してみます:

git rev-list --boundary 85e54e2408..0815fcf18a
0815fcf18a19441c1c26fc3495c4047cf59a06b9
8a1658147a460a0230fb1990f0bc61130ab624b2
-85e54e240836e6efb46978e4a1780f0b45516b20

(境界コミットには接頭辞-

表示された最後のコミットがgit rev-listコマンドの最初のコミットと同じ場合、2番目のコミットから到達可能なコミットです。

最初のコミットが2番目のコミットから到達できない場合、git rev-list何も返さないはずです。

git rev-list --boundary A..B

終了するA場合、Aから到達可能なBます。
以下と同じです。

git rev-list --boundary B --not A

正の基準、および陰性参照。 それはから始まり、から到達可能なリビジョンに遭遇するまでグラフをウォークバックします。から直接到達できる 場合は、それ自体に遭遇する(そしてオプションにより表示される)と私は主張します。BA
BA
AB--boundaryA


これは、gitがこれを正確に実行する「磁器」コマンドをまだ公開していないことに驚いた、一般的な十分なユースケースのように聞こえます。
ローレンスI.シデン

1
@lsiden:true。補足:プログラムで何かをチェックすることを忘れないでください。磁器コマンド(stackoverflow.com/questions/6976473/…など)を使用する必要はありませんが、配管コマンド(stackoverflow.com/questionsで説明)を使用する必要があります/ 3878624 /…
VonC

ああ、シェルスクリプトチョップに戻って作業する必要があるようです。
ローレンスI.シデン

1
質問:なぜ-85e54e2...スニペットのマイナス記号があるのですか?また、タイプミスの可能性もあります:「...は最初のコミットと同じ...」
sdaau

1
@sdaau -は境界コミットであることを意味します。回答をより明確にするために編集し、ドキュメントリンクを更新して、この5年前の回答のタイプミスを修正しました。
VonC 2015年

11

もう1つの方法はgit log、およびを使用することgrepです。

git log --pretty=format:%H abc123 | grep def456

これは、commit def456がcommit abc123の祖先である場合は1行の出力を生成し、それ以外の場合は出力を生成しません。

通常は--pretty引数を省略してもかまいませんが、ログコメントなどではなく、実際のコミットハッシュのみを検索するようにする場合に必要です。


このソリューションは遅いと
思っていましたが、2万回以上の

2
--pretty--onelineを使用する代わりに:git log --oneline ce2ee3d | grep ec219ccうまく機能します
gens

3

https://stackoverflow.com/a/13526591/895245はそれについて言及していますが、今ではより人に優しいものにしています:

git-is-ancestor() (
  if git merge-base --is-ancestor "$1" "$2"; then
      echo 'ancestor'
  elif git merge-base --is-ancestor "$2" "$1"; then
      echo 'descendant'
  else
      echo 'unrelated'
  fi
)
alias giia='git-is-ancestor'

両方のパラメーターが同じコミットを指している場合、これは「無関係」を返します
mik

1

git show-branch branch-sha1 commit-sha1

どこ:

  • ブランチ-sha1:確認するブランチ内のsha1
  • commit-sha1:チェックするコミットのsha1

0

使用している場合 git merge-base --is-ancestor、必ずGit 2.28(2020年第3四半期)を使用してください。

Git 2.28(2020年第3四半期)では、struct commit常に存在する必要のない" "のいくつかのフィールドが、スラブをコミットするために移動されました。

参照c752ad0をコミットしc49c82aをコミットし4844812をコミットし6da43d9をコミットすることで(2020年6月17日)アビシェーク・クマール(abhishekkumar2718
(合併によりJunio C浜野- gitster-コミットd80bea4、2020年7月6日)

commit-graph: 導入する commit_graph_data_slab

サインオフ:Abhishek Kumar

commit構造体は多くのコンテキストで使用されます。ただし、メンバーgenerationgraph_posは、コミットグラフ関連の操作にのみ使用され、それ以外の場合はメモリを浪費します。

現在の32ビットではなく64ビットの世代番号を使用する世代番号v2に移行すると、この浪費はより顕著になります。

一緒にアクセスされることが多いので、構造体commit_graph_dataを導入してcommit_graph_dataスラブに移動しましょう。

全体的なテストスイートはと同じくらい高速に実行されますがmaster(シリーズ:26分48秒、master27分34秒、2.87%高速)、などの特定のコマンドはSzederGáborによって発見されたようgit merge-base --is-ancestorに40%遅くなりました。 commit-slabアクセスを最小化した後、速度低下は持続しますが、20%に近づきます。

Derrick Stoleeは、速度の低下はコミットスラブアクセスの遅さではなく、基になるアルゴリズムに起因するものであると考えており、後のシリーズでフォローアップします。


-1

リポジトリ内のすべてのタグに対してこれを行う必要がある場合に備えて、itubの答えに基づいて構築します。

for i in `git tag` ; do echo -ne $i "\t" ; git log --pretty=format:%H $i | (grep <commit to find> || echo ""); done
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.