Gitコミットのブランチを見つける


650

SHA-1ハッシュ値を指定すると、コミットがどのブランチからのものかを見つける方法はありますか?

Ruby Gritを使用してこれを実現する方法を教えてもらえれば、ボーナスポイント。


4
以下の異なる方法が実用的、便利、作業する方法があります推測する可能性はgitで質問自体が誤解であることの答えを、しかしレッツノート、コミットが枝から来ていません。ブランチは行き来し、移動し、コミットのみが実際のレポ履歴を表します。繰り返しますが、これは以下のソリューションが悪いと言う方法ではありません。それらのどれも完全に信頼できる答えを与えないことを知ってください。これはgitの設計では取得できません。(単純なケースは、ブランチを削除することです:私はブランチし、2回コミットし、別のブランチにマージし、最初のブランチを削除します。コミットはどこから「どこから」来たのですか?
RomainValeri

1
タグから深さ1の浅いクローンを明示的にプルする場合があります。それは安くて簡単で効率的です...そして今まで私が美しく望んだすべてをしました。タグがどのブランチにあったか知りたいので、少なくともその詳細については、私はうんざりしています。あなたはいつも家に帰ることはできません、笑
ポール・ホッジス

回答:


865

Dav氏は、情報が直接保存されないことは正しいが、それがあなたがそれを見つけることができないということを意味するわけではない。ここでは、いくつかのことができます。

コミットが存在するブランチを見つける

git branch -a --contains <commit>

これにより、履歴に特定のコミットがあるすべてのブランチがわかります。コミットがすでにマージされている場合、明らかにこれはあまり役に立ちません。

reflogsを検索

コミットが行われたリポジトリで作業している場合は、reflogでそのコミットの行を検索できます。90日以上経過したreflogはgit-gcによって整理されるため、コミットが古すぎると、それを見つけることができません。つまり、これを行うことができます:

git reflog show --all | grep a871742

コミットa871742を検索します。コミットの最初の7桁はabbreviatd 7を使用する必要があることに注意してください。出力は次のようになります。

a871742 refs/heads/completion@{0}: commit (amend): mpc-completion: total rewrite

コミットがブランチ「完了」で行われたことを示します。デフォルトの出力では、短縮されたコミットハッシュが表示されるため、完全なハッシュを検索しないでください。検索すると、何も見つかりません。

git reflog showは実際にはのエイリアスにすぎないgit log -g --abbrev-commit --pretty=onelineため、出力形式をいじってgrepでさまざまなものを使用できるようにする場合は、それが出発点です。

コミットが行われたリポジトリで作業していない場合、この場合にできる最善の方法は、reflogを調べて、コミットがリポジトリに最初に導入された時期を見つけることです。運が良ければ、コミットされたブランチをフェッチしました。コミットツリーとreflogの両方を同時に歩くことはできないため、これは少し複雑です。reflogの出力を解析し、各ハッシュを調べて、目的のコミットが含まれているかどうかを確認します。

後続のマージコミットを見つける

これはワークフローに依存しますが、適切なワークフローでは、開発ブランチでコミットが行われ、マージされます。これは次のようにして行うことができます。

git log --merges <commit>..

指定されたコミットを祖先として持つマージコミットを確認します。(コミットが一度だけマージされた場合、最初のコミットは後のマージである必要があります。それ以外の場合は、いくつかを調べる必要があると思います。)マージコミットメッセージには、マージされたブランチ名が含まれているはずです。

これを当てにできるようにしたい場合は、--no-ffオプションを使用git mergeして、早送りの場合でもマージコミットの作成を強制することができます。(ただし、あまり熱心になりすぎないでください。乱用すると難読化する可能性があります。)関連する質問に対するVonCの回答は、このトピックについて詳しく説明しています。


5
+1。その特定の問題に関する情報がまったくないため、それが実際に問題なのかどうか疑問に思いますか?ブランチはいつでも変更、名前変更、削除できます。かもしれgit describe(注釈付き)タグは枝よりも重要とみなすことができるため、十分です。
VonC 2010

9
私は間違いなく同意します-ブランチは軽量で柔軟であることを意味します。その情報が重要になるワークフローを採​​用する場合は、--no-ffオプションを使用して常にマージコミットが存在することを確認できるため、マスターに向かってマージされる特定のコミットのパスを常に追跡できます。
Cascabel

32
参考までに、リモートにのみ存在するコミットを検索する場合は-a、最初のコマンドにフラグを追加してください。git branch -a --contains <commit>
Jonathan Day

8
@JonathanDay:いいえ、どのブランチでもコミットが見つかります。リモートで1つだけ必要な場合は、を使用します-r
カスカベル

7
@SimonTewsi私が言ったように、それが本当に問題であるmerge --no-ff場合、マージするときにブランチ名を確実に記録するために使用します。しかし、そうでなければ、ブランチ名を一時的な短いラベルとして考え、説明を永続的なものとしてコミットしてください。「開発中に、これはどの略称で呼ばれたのですか?」「このコミットは何をするのか」ほど重要な質問ではありません。
カスカベル

154

この単純なコマンドは、魅力のように機能します。

git name-rev <SHA>

例(test-branchはブランチ名です):

git name-rev 651ad3a
251ad3a remotes/origin/test-branch

これでも、次のような複雑なシナリオで機能します。

origin/branchA/
              /branchB
                      /commit<SHA1>
                                   /commit<SHA2>

ここでgit name-rev commit<SHA2>は、branchBを返します。


3
あなたは私の日を救った。これは完璧なソリューションです。
Taco

7
そして、この完璧なソリューションにたった8年しかかかりませんでした。ありがとう!
S1J0

6
git name-rev --name-only <SHA>ブランチ名だけを取得する方が便利であることがわかりました。私の質問...それはどんな状況でも複数のブランチを返すことができますか?
Dean Kayton

1
これが最良の答えです。
JCollier

1
親切な言葉をありがとう@JCollier。
khichar.anil

47

2013年12月の更新:

sschuberth コメント

git-what-branch(Perlスクリプト、以下を参照)はもう保守されていないようです。 git-when-mergedPythonで書かれた代替手段であり、私にとって非常にうまく機能しています。

これは、「特定のコミットを含むマージコミットの検索」に基づいています

git when-merged [OPTIONS] COMMIT [BRANCH...]

コミットが1つ以上のブランチにマージされた時期を見つけます。指定されたBRANCHに
もたらさCOMMITれたマージコミットを見つけます。

具体的にBRANCHは、COMMITを祖先として含む最初の親の履歴で最も古いコミットを探します。


2010年9月の元の回答:

Sebastien Doucheひねりました(このSOの回答の16分前):

git-what-branch:コミットがどのブランチにあるか、またはどのようにして名前付きブランチに到達したかを発見します

これは、Perlスクリプトからのセス・ロバートソン非常に興味深いと思われます。

あらすじ

git-what-branch [--allref] [--all] [--topo-order | --date-order ]
[--quiet] [--reference-branch=branchname] [--reference=reference]
<commit-hash/tag>...

概要

要求されたコミットが名前付きブランチに到達するためのコミットとマージの最も早い因果パスを(デフォルトで)教えてください。名前付きブランチで直接コミットが行われた場合、それが明らかに最も早いパスです。

最も早い因果パスとは、(--topo-order指定されていない限り)コミット時刻までに最も早く名前付きブランチにマージされたパスを意味します。

パフォーマンス

多くのブランチ(たとえば、数百)にコミットが含まれている場合、システムはパスを追跡するのに長い時間がかかる可能性があります(Linuxツリーでの特定のコミットの場合、ブランチの探索に8秒かかりましたが、200を超える候補ブランチがありました)。各コミットに。
特定の選択--reference-branch --reference tag調べる数百倍速くなります(候補ブランチが数百ある場合)。

 # git-what-branch --all 1f9c381fa3e0b9b9042e310c69df87eaf9b46ea4
 1f9c381fa3e0b9b9042e310c69df87eaf9b46ea4 first merged onto master using the following minimal temporal path:
   v2.6.12-rc3-450-g1f9c381 merged up at v2.6.12-rc3-590-gbfd4bda (Thu May  5 08:59:37 2005)
   v2.6.12-rc3-590-gbfd4bda merged up at v2.6.12-rc3-461-g84e48b6 (Tue May  3 18:27:24 2005)
   v2.6.12-rc3-461-g84e48b6 is on master
   v2.6.12-rc3-461-g84e48b6 is on v2.6.12-n
   [...]

このプログラムは、関心のあるコミットをチェリーピッキングする効果を考慮せず、マージ操作のみを考慮します。


4
git-what-branchもうメンテナンスされていないようです。git-when-mergedは、Pythonで書かれた代替手段であり、私にとって非常にうまく機能しています。
sschuberth 2013

@sschuberth更新ありがとうございます。見やすくするために、回答にコメントを含めました。
VonC、2013

37

たとえば、そのc0118faコミットが次のように行われたことを確認するにはredesign_interactions

* ccfd449 (HEAD -> develop) Require to return undef if no digits found
*   93dd5ff Merge pull request #4 from KES777/clean_api
|\
| * 39d82d1 Fix tc0118faests for debugging debugger internals
| * ed67179 Move &push_frame out of core
| * 2fd84b5 Do not lose info about call point
| * 3ab09a2 Improve debugger output: Show info about emitted events
| *   a435005 Merge branch 'redesign_interactions' into clean_api
| |\
| | * a06cc29 Code comments
| | * d5d6266 Remove copy/paste code
| | * c0118fa Allow command to choose how continue interaction
| | * 19cb534 Emit &interact event

あなたは実行する必要があります:

git log c0118fa..HEAD --ancestry-path --merges

下にスクロールして、最後のマージコミットを見つけます。それは:

commit a435005445a6752dfe788b8d994e155b3cd9778f
Merge: 0953cac a06cc29
Author: Eugen Konkov
Date:   Sat Oct 1 00:54:18 2016 +0300

    Merge branch 'redesign_interactions' into clean_api

更新

または、ただ1つのコマンド:

git log c0118fa..HEAD --ancestry-path --merges --oneline --color | tail -n 1

4
これが私に望ましい結果をもたらした唯一の解決策でした。残りを試しました。
製作者

これが機能するのは、マージコミットの要約に、マージで使用されるブランチ名が含まれている場合のみであることに注意してください。ただしgit merge -m"Any String Here"、ソースとターゲットのブランチ情報は不明瞭になります。
qneill 2018年

@qneill:いいえ、マージには常にマージされたブランチに関する情報があります:Merge: f6b70fa d58bdcb。マージコミットには同じ名前を付けることができます。私には問題はありません
オイゲンコンコフ

1
@EugenKonkovは、ブランチがマージを通過すると、ブランチの元のグラフのパスに関する履歴がreflogに残りますが、gitオブジェクトデータベースには残りません。私は自分の言っていることを説明しようとする回答を投稿しました
qneill

元のコミットを見つける単純なコマンドであるUPDバージョンは私にとっては機能します
vpalmu 2018

9

git branch --contains <ref>これを行う最も明白な「磁器」コマンドです。「配管」コマンドのみで同様のことをしたい場合:

COMMIT=$(git rev-parse <ref>) # expands hash if needed
for BRANCH in $(git for-each-ref --format "%(refname)" refs/heads); do
  if $(git rev-list $BRANCH | fgrep -q $COMMIT); then
    echo $BRANCH
  fi
done

このSO回答からのクロスポスト)


6

khichar.anilは彼の答えでこれのほとんどをカバーしました。

リビジョン名リストからタグを削除するフラグを追加しています。これは私たちに与えます:

git name-rev --name-only --exclude=tags/* $SHA

2番目の文で何かが欠けているようです。
Peter Mortensen、

説明を更新しました。フィードバックのためのThx。
phyatt

4

貧乏人のオプションが使用することですツールtig1上にHEAD、コミットを検索して、視覚的にバックアップマージが見られてコミットするまでコミットそれからラインに従ってください。デフォルトのマージメッセージは、どのブランチがどこにマージされるかを指定する必要があります:)

1 Tigは、Gitのncursesベースのテキストモードインターフェイスです。主にGitリポジトリブラウザーとして機能しますが、チャンクレベルでのコミットの変更のステージングを支援し、さまざまなGitコマンドからの出力のページャーとして機能することもできます。


3

実験として、現在チェックアウトされているブランチに関する情報をコミットメタデータに格納するポストコミットフックを作成しました。また、gitkを少し変更して、その情報を表示しました。

こちらでチェックできます:https : //github.com/pajp/branch-info-commits


1
しかし、メタデータを追加したい場合は、コミットのヘッダーをいじるのではなく、git notesを使用しないのはなぜですか?参照stackoverflow.com/questions/5212957/...stackoverflow.com/questions/7298749/...またはstackoverflow.com/questions/7101158/...
VonC

正直なところ、私が書いたときはgit notesが存在することを知りませんでした。はい、Git Noteを使用して同じことを達成することは、おそらくより良いアイデアです。
pajp

3

私は同じ問題(Jenkinsマルチブランチパイプライン)を扱います-コミット情報のみを持ち、このコミットが最初に発生したブランチ名を見つけようとします。リモートブランチで機能する必要があります。ローカルコピーは使用できません。

これは私が扱うものです:

git rev-parse HEAD | xargs git name-rev

オプションで、出力を取り除くことができます。

git rev-parse HEAD | xargs git name-rev | cut -d' ' -f2 | sed 's/remotes\/origin\///g'

0

誰かがブランチを見つけることができない同じ問題に直面するべきだと思いますが、実際には1つのブランチに存在しています。

最初にすべてをプルするほうがよいでしょう。

git pull --all

次に、ブランチ検索を実行します。

git name-rev <SHA>

または:

git branch --contains <SHA>

0

OPが特定のコミットが作成されたときにブランチがたどった履歴を特定しようとしている場合(「SHA-1ハッシュ値を指定すると、コミットがどのブランチからのものであるかを見つける」)、reflogがないともありません。どの名前付きブランチがどのコミット履歴にバインドされたかを示すGitオブジェクトデータベースのレコード

(コメントへの回答として、これを回答として投稿しました。)

うまくいけば、このスクリプトは私の要点を示しています。

rm -rf /tmp/r1 /tmp/r2; mkdir /tmp/r1; cd /tmp/r1
git init; git config user.name n; git config user.email e@x.io
git commit -m"empty" --allow-empty; git branch -m b1; git branch b2
git checkout b1; touch f1; git add f1; git commit -m"Add f1"
git checkout b2; touch f2; git add f2; git commit -m"Add f2"
git merge -m"merge branches" b1; git checkout b1; git merge b2
git clone /tmp/r1 /tmp/r2; cd /tmp/r2; git fetch origin b2:b2
set -x;
cd /tmp/r1; git log --oneline --graph --decorate; git reflog b1; git reflog b2;
cd /tmp/r2; git log --oneline --graph --decorate; git reflog b1; git reflog b2;

出力には、「Add f1」を使用したコミットがリモートクローン/ tmp / r2のブランチb1またはb2のどちらから行われたかを知る方法がないことが示されています。

(ここの出力の最後の行)

+ cd /tmp/r1
+ git log --oneline --graph --decorate
*   f0c707d (HEAD, b2, b1) merge branches
|\
| * 086c9ce Add f1
* | 80c10e5 Add f2
|/
* 18feb84 empty
+ git reflog b1
f0c707d b1@{0}: merge b2: Fast-forward
086c9ce b1@{1}: commit: Add f1
18feb84 b1@{2}: Branch: renamed refs/heads/master to refs/heads/b1
18feb84 b1@{3}: commit (initial): empty
+ git reflog b2
f0c707d b2@{0}: merge b1: Merge made by the 'recursive' strategy.
80c10e5 b2@{1}: commit: Add f2
18feb84 b2@{2}: branch: Created from b1
+ cd /tmp/r2
+ git log --oneline --graph --decorate
*   f0c707d (HEAD, origin/b2, origin/b1, origin/HEAD, b2, b1) merge branches
|\
| * 086c9ce Add f1
* | 80c10e5 Add f2
|/
* 18feb84 empty
+ git reflog b1
f0c707d b1@{0}: clone: from /tmp/r1
+ git reflog b2
f0c707d b2@{0}: fetch origin b2:b2: storing head

両方の場合の出力git log 80c10e5..HEAD --ancestry-path --merges --oneline --color | tail -n 1git log 086c9ce..HEAD --ancestry-path --merges --oneline --color | tail -n 1コマンドは何ですか?
Eugen Konkov

もちろん、SHAはコマンドが実行されるたびに変更され、コマンドを再スペルするために、新たな実行でHEAD ^ 1およびHEAD ^ 2を使用しました。コマンド出力は、次のとおりです。$ git log HEAD^1..HEAD --ancestry-path --merges --oneline --color | tail -n 1どの利回り376142d merge branches$ git log HEAD^2..HEAD --ancestry-path --merges --oneline --color | tail -n 1利回り376142d merge branches -マージ(私が主張したよう)要約を、コミットされショーマージが作成されたときに、おそらく、マージの分岐履歴を難読化、上書きすることができます。
qneill 2018

0

TL; DR:

シェルの終了ステータスが気になる場合は、以下を使用してください。

  • branch-current -現在のブランチの名前
  • branch-names -クリーンなブランチ名(1行に1つ)
  • branch-name -ブランチが1つだけ返されるようにする branch-names

とはどちらも引数としてcommit branch-namebranch-names受け入れ、HEAD何も指定されていない場合はデフォルトになります 。


スクリプトで役立つエイリアス

branch-current = "symbolic-ref --short HEAD"  # https://stackoverflow.com/a/19585361/5353461
branch-names = !"[ -z \"$1\" ] && git branch-current 2>/dev/null || git branch --format='%(refname:short)' --contains \"${1:-HEAD}\" #"  # https://stackoverflow.com/a/19585361/5353461
branch-name = !"br=$(git branch-names \"$1\") && case \"$br\" in *$'\\n'*) printf \"Multiple branches:\\n%s\" \"$br\">&2; exit 1;; esac; echo \"$br\" #"

1つのブランチからのみ到達可能なコミット

% git branch-name eae13ea
master
% echo $?
0
  • STDOUTへの出力
  • 終了値は0です。

複数のブランチから到達可能なコミット

% git branch-name 4bc6188
Multiple branches:
attempt-extract
master%
% echo $?
1
  • STDERRへの出力
  • 終了値は1です。

終了ステータスのため、これらは安全に構築できます。たとえば、リモートをフェッチに使用するには:

remote-fetch = !"branch=$(git branch-name \"$1\") && git config branch.\"$branch\".remote || echo origin #"

-1

ローカルブランチを見つけるには:

grep -lR YOUR_COMMIT .git/refs/heads | sed 's/.git\/refs\/heads\///g'

リモートブランチを見つけるには:

grep -lR $commit .git/refs/remotes | sed 's/.git\/refs\/remotes\///g'

1
あなたの例のいくつかの説明は素晴らしいでしょう
Eugen Konkov '23

-4

一致するハッシュが見つかるまでツリー全体を検索することは別として、いいえ。


7
厳密に言って、gitがその情報を永続的に保存しないことは事実ですが、それでもそれを見つけることは非常に可能です。私の答えを見てください。
Cascabel
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.