特定のファイルへの変更を含むGitブランチを検索します


88

私は57の地方支部を持っています。そのうちの1つで特定のファイルに変更を加えたことは知っていますが、どれがどれかわかりません。特定のファイルへの変更が含まれているブランチを見つけるために実行できるコマンドはありますか?

回答:


87

FILENAMEへの変更を含むすべてのブランチを検索します((記録されていない)分岐点の前であっても)

FILENAME="<filename>"
git log --all --format=%H $FILENAME | while read f; do git branch --contains $f; done | sort -u

手動で検査:

gitk --all --date-order -- $FILENAME

マスターにマージされていないFILENAMEへのすべての変更を検索します。

git for-each-ref --format="%(refname:short)" refs/heads | grep -v master | while read br; do git cherry master $br | while read x h; do if [ "`git log -n 1 --format=%H $h -- $FILENAME`" = "$h" ]; then echo $br; fi; done; done | sort -u

このコマンドでFILENAME以外のものを置き換える必要がありますか?57のブランチ名すべてを返します。
ダスティン

@Dustin:57のブランチすべてにそのファイル名が含まれている場合、57のブランチすべてにそのファイル名を含む変更が含まれます。ブランチは、ブランチを作成する前にそのリビジョンが存在していた場合でも、そのブランチで到達可能な最も古いリビジョンから開始します(ブランチはある意味で遡及的に作成されます)。問題をより適切に定義する必要があると思います。変化が何であるか知っていますか?git log -Schange …またはを使用できますかgit log --grep LOGMESSAGE …(…は、前述のコマンドの残りの部分を表します)。
セスロバートソン

2
@Dustin:別のオプションを使用gitk --all -- filenameすると、そのファイルへのすべての変更がグラフィカルに表示されます。問題のコミットを特定できれば、それを使用git branch --containsして、コミットが移行されたブランチを確認できます。問題のコミットが最初に作成されたブランチを確認したい場合は、google git-what-branchを実行しますが、早送りマージによってその情報が不明瞭になる可能性があることに注意してください。
セスロバートソン

@Seth:コミットメッセージや正確なコード変更を思い出せませんでした。私はただ一般的な考えを持っています。問題は、まだマスターとマージされていないことです。そのため、gitkを使用するには、各ブランチをチェックアウトして、探しているものを見つける必要があります。「git、分岐点以降にFILENAMEに変更を加えた分岐を表示してください」と言えばいいのですが
Dustin

1
あなたはより効率的に最初の行を書くことができますgit log --all --format='--contains %H' "$file" | xargs git branch
kojiro 2014年

52

あなたに必要なのは

git log --all -- path/to/file/filename

ブランチをすぐに知りたい場合は、次を使用することもできます。

git log --all --format=%5 -- path/to/file/filename | xargs -I{} -n 1 echo {} found in && git branch --contains {}

さらに、名前を変更した場合は--follow、Gitlogコマンドに含めることをお勧めします。


15
それはコミットを示しますが、彼はどのブランチに尋ねました。--sourceそこにを追加すると、あなたは金色になります。
Karl Bielefeldt

ありがとう、でもそれが各コミットのすべてのブランチを示しているとは思いません。しかし、それは役に立ちます。
Adam Dymitruk 2011

1
本当ですが、この特定のケースでは、彼は1つだけを探していました。
Karl Bielefeldt

ところでasp.netパスのためのAppName /コントローラ/ XController.csのような形式にする必要があります
アリカラカ

8

これは適切な解決策がなくてもまだ問題のようです。コメントするのに十分なクレジットがないので、ここに私の小さな貢献があります。

Seth Robertsonの最初の解決策は私にとってはうまくいきましたが、ローカルブランチしか提供されませんでした。その中には、おそらく安定したブランチからのマージが原因で、多くの誤検知がありました。

Adam Dymitrukの2番目のソリューションは、私にはまったく機能しませんでした。手始めに、-format =%5とは何ですか?それはgitによって認識されず、それについて何も見つけることができず、他のフォーマットオプションで動作させることができませんでした。

しかし、彼の最初のソリューションを--sourceオプションと単純なgrepと組み合わせると、役に立ちました。

git log --all --source -- <filename> | grep -o "refs/.*" | sort -u

これにより、いくつかのリモートタグとブランチ、およびファイルに最新の変更を加えた1つのローカルブランチが得られます。これがどれほど完全かわからない。

@nealmcbの要求に従って更新し、最新の変更でブランチをソートします。

まず、grepを「refs / heads /.*」に変更できます。これにより、ローカルブランチのみが提供されます。ブランチが数個しかない場合は、次のように各ブランチの最新のコミットを調べることができます。

git log -1 <branch> -- <filename>

より多くのブランチがあり、これを本当に自動化したい場合は、xargs、gitログフォーマット、および別の並べ替えを使用して2つのコマンドをこのワンライナーに組み合わせることができます。

git log --all --source -- <filename> | grep -o "refs/heads/.*" | sort -u | xargs -I '{}' git log -1 --format=%aI%x20%S '{}' -- <filename> | sort -r

これにより、次のような出力が得られます。

2020-05-07T15:10:59+02:00 refs/heads/branch1
2020-05-05T16:11:52+02:00 refs/heads/branch3
2020-03-27T11:45:48+00:00 refs/heads/branch2

よかった。ありがとう。では、最新の変更で並べ替えてみませんか?
nealmcb

1

私はこの質問が古くからあることを知っていますが、私は自分自身の解決策を開発する前にそれに戻ってきました。マージベースの使用のおかげで、不要なブランチが除外され、よりエレガントに感じます。

#!/bin/bash

file=$1
base=${2:-master}

b=$(tput bold) # Pretty print
n=$(tput sgr0)

echo "Searching for branches with changes to $file related to the $base branch"

# We look through all the local branches using plumbing
for branch in $(git for-each-ref --format='%(refname:short)' refs/heads/); do
  # We're establishing a shared ancestor between base and branch, to only find forward changes.  
  merge_base=$(git merge-base $base $branch)
  # Check if there are any changes in a given path.
  changes=$(git diff $merge_base..$branch --stat -- $file)

  if [[ ! -z $changes ]]; then
    echo "Branch: ${b}$branch${n} | Merge Base: $merge_base"
    # Show change statistics pretty formatted
    git diff $merge_base..$branch --stat -- $file
  fi
done

git-find-changes(実行可能権限を使用して)としてPATHに配置すると、次のコマンドで呼び出すことができます。git find-changes /path

の出力例 git find-changes app/models/

Branch: update_callbacks | Merge base: db07d23b5d9600d88ba0864aca8fe79aad14e55b
 app/models/api/callback_config.rb | 28 ++++++++++++++++++++++++++++
 1 file changed, 28 insertions(+)
Branch: repackaging | Merge base: 76578b9b7ee373fbe541a9e39cf93cf5ff150c73
 app/models/order.rb                 | 38 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 38 insertions(+)

非常に興味深いスクリプト。賛成。それはshow-changesまたはfind-changesですか?
vonC

@VonCのおかげで、使用法が修正され、どこにでもあるはずです
Marcin Raczkowski

0

以下は、エレガントでないブルートフォース方式ですが、機能するはずです。現在使用しているブランチが切り替わるため、コミットされていない変更を最初に隠しておくようにしてください。

for branch in $(git for-each-ref --format="%(refname:short)" refs/heads); do
    git checkout $branch && git grep SOMETHING
done

1
なぜなら、あなたが使用できる変更を知っているならgit log -S
セスロバートソン

どのシェルを想定していますか?バッシュ?
PeterMortensen18年

POSIXで機能するはずのバシズムはありません。for-each-refそれでもそのshortフラグを尊重するかどうかはわかりませんが。そうは言っても、私の答えは無視してください。他の答えの方が良いです。
whiteinge
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.