削除した行を「git blame」するにはどうすればよいですか?


506

git blame変更および追加された行には最適ですが、特定の以前のコミットに存在していた行が最終的に削除された場合、どうすれば見つけられますか。と思っていますがbisect、もっと便利なものを期待していました。

(あなたが尋ねる前に:この場合、私はa git log -pを実行してコード行を検索し、(a)ある馬鹿が前のコミットで重要な行を削除したばかりで、(b)私はその馬鹿でした。)


4
マージ中の削除(競合)を表示するか、または同様に表示したいかを明確にする回答付きのフォローアップがありますgit log -S<string> /path/to/file-c-cc
cfi

3
である必要が-cあり--ccます。@Steen:正解、指摘してくれてありがとう!愚かな見落とし。コメントを編集したいです。新しいものを追加してから、私のものを削除してから、自分のものを削除するのは、とても面倒です:)
cfi

4
私の願いはgit blame(おそらくで削除された行表示するオプションだろう取り消し線、それらが削除されたリビジョンまたは赤のテキスト)。
Craig McQueen

書くのは難しいですか?Gitの内部についてはあまり知りません。
Malvolio 2016

回答:


636

行の内容がわかっている場合、これは次の場合の理想的な使用例です。

git log -S <string> path/to/file

これは、その文字列のインスタンスを導入または削除するコミットを示しています。-G<regex>正規表現で同じことをするものもあります!詳細についてman git-logは、-Gおよび-Sオプション、またはツルハシ(これらの機能のわかりやすい名前)を参照して検索してください。

この-Sオプションは、実際にはgit-blameマンページのヘッダーの説明セクションにも記載されていgit log -S...ます。ここでは、を使用した例が示されています。



37
1年以上Gitを使用した後でも、Gitには、ほとんどすべての使用シナリオに対処するためのコマンド/オプションが常にどこかにあることに驚かされます。これを共有してくれてありがとう、まさに今必要なものです!
Pascal Bourque

22
この方法は以前はうまくいきましたが、今、行が削除されたコミットが見つからない場合がありました。問題の行がマージコミットで削除されたことが判明しました-それは失敗を説明しますか?(git blame --reverseただし、メソッドはそれを見つけました。)
アンチノーム2013年

9
@antinomeマージからのコミットを表示するには、-cオプションを追加で使用します。
雲仙14年

2
マンページの「-s」でctrl + fを実行しても何も見つかりませんでした。ページのどこに表示されますか?私はgit 1.8.5.2を使用しています
temporary_user_name

135

あなたが本当に欲しいのは

git blame --reverse START..END filename

マンページから:

履歴を後方ではなく前方に移動します。行が表示されたリビジョンを表示する代わりに、行が存在した最後のリビジョンを表示します。これには、START..ENDのような一連のリビジョンが必要です。

を使用git blame reverseすると、行が表示された最後のコミットを見つけることができます。その後に続くコミットを取得する必要があります。

次のコマンドを使用して、リバースされたgitログを表示できます。表示される最初のコミットはその行が最後に表示される時間であり、次のコミットは変更または削除されたときです。

git log --reverse --ancestry-path COMMIT^..master

14
線が追加されたブランチから、線が欠落しているブランチに複数のマージがある場合(または、系統にSTARTからENDまでの複数のパスがある場合)は、git blame --reverse時系列のマージ前のリビジョンを表示します最後に、最初のマージ前の改訂ではなく、ラインを採用しないことが決定されました。最新のものではなく、行が存在しなくなった最も早いリビジョンを見つける方法はありますか?
rakslice 2013年

2
@rakslice、そのため、非難--reverse --first-parentを使用できますが、少し優れています。
max630

17

カスカベルの答えを完成させるために:

git log --full-history -S <string> path/to/file

ここで述べたのと同じ問題がありましたが、ブランチからのマージコミットが元に戻されてマージされ、問題の行を効果的に削除したため、行が欠落していることがわかりました。--full-historyこれらのコミットをスキップフラグ防止。


9

gitの責任の--reverseはあなたを得ることができます近い行が削除されている場所へ。しかし、実際にその行が削除されたリビジョンを指しているわけではありません。行が存在した最後のリビジョンを指します。次に、次のリビジョンがプレーンコミットである場合、幸運であり、削除リビジョンを取得しました。OTOH、次のリビジョンがマージコミットである場合、物事は少しワイルドになる可能性があります。

difflameを作成するための取り組みの一環として、私はこの非常に問題に取り組んだので、既にボックスにPythonがインストールされていて、それを試してみるつもりなら、それ以上待たずにそれがどうなるかを知らせてください。

https://github.com/eantoranz/difflame


0

マージコミットに隠された変更について

マージコミットでは、Gitログ出力から変更が自動的に非表示になります。つるはし逆責めの両方で変更は見つかりませんでした。だから私が欲しかった行が追加されて後で削除され、それを削除したマージを見つけたかったのです。ファイルgit log -p -- path/file履歴には、追加されていることが示されているだけです。これが私が見つけた最良の方法です:

git log -p -U9999 -- path/file

変更を検索してから、「^ commit」を逆方向に検索します。最初の「^ commit」は、ファイルに最後にその行があったコミットです。2番目の「^ commit」は非表示になった後です。2番目のコミットはそれを削除したものかもしれません。これ-U9999は、ファイルがすべて最大9999行であると想定して、(ファイルが変更されるたびに)ファイルの内容全体を表示するためのものです。

ブルートフォースを介して関連するマージを検索します(可能な各マージコミットを最初の親と比較し、大量のコミットに対して実行します)

git log --merges --pretty=format:"git diff %h^...%h | grep target_text" HEAD ^$(git merge-base A B) | sh -v 2>&1 | less

(リビジョンフィルターをさらに制限してみましたが、問題が発生したためお勧めしません。探していた追加/削除の変更は、異なる時点でマージされた異なるブランチにあり、A ... Bには含まれていませんでした変更が実際にメインラインにマージされたとき。)

次の2つのコミットを使用してGitツリーを表示します(複雑なGit履歴の多くを削除します)。

git log --graph --oneline A B ^$(git merge-base A B) (Aは上記の最初のコミット、Bは上記の2番目のコミットです)

Aの履歴とBの履歴からAとBの両方の履歴を差し引いたものを表示します。

代替バージョン(通常のGit履歴ツリーではなく、より直線的にパスを表示するように見えますが、通常のgit履歴ツリーを好みます):

git log --graph --oneline A...B

2つのドットではなく3つ-3つのドットは「r1 r2 --not $(git merge-base --all r1 r2)を意味します。これは、r1(左側)またはr2(右側)のいずれかから到達可能なコミットのセットです。サイド)、しかし両方からではありません。」-ソース: "man gitrevisions"

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.