Git-メソッド/関数の変更履歴を表示するにはどうすればよいですか?


91

そのため、ファイルの変更履歴を表示する方法に関する質問を見つけましたが、この特定のファイルの変更履歴は非常に大きく、特定のメソッドの変更にのみ関心があります。それで、その特定の方法だけの変更履歴を見ることが可能でしょうか?

コードを分析するにはgitが必要であり、分析は言語によって異なることはわかっていますが、メソッド/関数の宣言はほとんどの言語で非常によく似ているため、誰かがこの機能を実装していると思います。

私が現在使用している言語はObjective-Cで、現在使用しているSCMはgitですが、この機能がSCM /言語に存在するかどうかを知りたいと思います。


1
Git GSoGプロポーザルでこのような機能を見てきました。
Vi。

これはあなたが話していた提案ですか?lists-archives.org/git/...
エリックB


@lpappここでの質問は10か月前に行われました。他の質問は、この質問の重複としてマークする必要があります(まったく重複している場合)。
ダーティフロー

2
@lpappこれらは2つのまったく異なる質問です。関数名を特定の範囲の行に解決するスクリプトを作成し、その質問の手法を使用してそれらの行の履歴を取得することもできますが、それ自体ではこの質問には答えられません。
エリックB

回答:


97

の最近のバージョンでgit logは、特殊な形式の-Lパラメータが学習されました。

-L:<関数名>:<ファイル>

内で指定された行範囲"<start>,<end>"(または関数名regex <funcname>)の変化を追跡します<file>。パススペックリミッターを指定することはできません。これは現在、単一のリビジョンから始まるウォークに制限されています。つまり、ゼロまたは1つの正のリビジョン引数のみを与えることができます。このオプションは複数回指定できます。
... andの代わりに指定した
場合、これは、と一致する最初のfuncname行から次のfuncname行までの範囲を示す正規表現です。前の範囲がある場合は最後から検索し、そうでない場合はファイルの先頭から検索します。ファイルの先頭から検索します。“:<funcname>”<start><end><funcname>“:<funcname>”-L“^:<funcname>”

つまりgit log -L :myfunction:path/to/myfile.c、Gitにを依頼すると、その関数の変更履歴が喜んで出力されます。


15
これはそのままでObjective-Cで機能する可能性がありますが、他の言語(Python、Rubyなど)でこれを行う場合は、Gitが関数/メソッドを認識するために.gitattributesファイル内に適切な構成を追加する必要がある場合があります。その言語での宣言。Pythonの場合は* .py diff = pythonを使用し、Rubyの場合は* .rb diff = ruby​​を使用
samaspin

1
gitは関数をどのようにトレースしますか?
nn0p 2017年

@ nn0pいくつかの言語の構文知識を持ち、関数を分離して彼女の変更を追跡する方法を知っていると思います。
JasonGenX 2018年

4
@samaspinのコメントを拡張して、他の言語については、こちらのドキュメントを参照できます:git-scm.com/docs/gitattributes#_generating_diff_text
edhgoose

これは、ScalaやJavaなどの言語やネストされた中かっこを使用するCでも機能しません(正規表現は一般にそれを処理できません)。また、関数がファイル内で移動されると、開始、終了フォームも機能しません。同じコミットで変更されました。
ロビングリーン

16

使用すると、git gui blameスクリプトでの使用を行うことは困難である、としながらgit log -Gおよびgit log --pickaxeメソッドの定義が現れたり消えたときにそれぞれがお見せすることができ、私は彼らがに行われたすべての変更リストにするどのような方法発見していないあなたの方法のを。

ただし、gitattributesおよびtextconvプロパティを使用して、まさにそれを行うソリューションを組み合わせることができます。これらの機能は元々バイナリファイルの操作を支援するためのものでしたが、ここでも同様に機能します。

重要なのは、Gifで、diff操作を行う前に、関心のある行を除くすべての行をファイルから削除することです。するとgit loggit diffなどあなたが興味を持っている領域のみが表示されます。

これが私が別の言語で行うことの概要です。必要に応じて調整できます。

  • 1つの引数(ソースファイルの名前)を取り、そのファイルの重要な部分のみを出力する(または興味深いファイルがない場合は何も出力しない)短いシェルスクリプト(または他のプログラム)を記述します。たとえば、sed次のように使用できます。

    #!/bin/sh
    sed -n -e '/^int my_func(/,/^}/ p' "$1"
  • textconv新しいスクリプトのGit フィルターを定義します。(詳細については、gitattributesmanページを参照してください。)フィルターの名前とコマンドの場所は、任意の名前にすることができます。

    $ git config diff.my_filter.textconv /path/to/my_script
  • 問題のファイルの差分を計算する前に、そのフィルターを使用するようにGitに指示します。

    $ echo "my_file diff=my_filter" >> .gitattributes
  • ここで-G.(に注意.)を使用して、フィルターが適用されたときに目に見える変更を生成するすべてのコミットを一覧表示すると、関心のあるコミットが正確に得られます。など、Gitのdiffルーチンを使用する他のオプション--patchは、この制限されたビューも取得します。

    $ git log -G. --patch my_file
  • ほら!

フィルタースクリプトで最初の引数としてメソッド名(および2番目の引数としてファイル)を取ることは、1つの便利な改善点です。これによりgit config、スクリプトを編集する必要がなく、を呼び出すだけで目的の新しいメソッドを指定できます。たとえば、次のように言うことができます。

$ git config diff.my_filter.textconv "/path/to/my_command other_func"

もちろん、フィルタースクリプトは、好きなことを実行したり、引数を追加したり、何でも実行できます。ここで示したものをはるかに超える柔軟性があります。


1
複数の引数を取ることは私にとってはうまくいきませんでしたが、関数名をハードに入れることはうまくいき、これは本当に素晴らしいです!
qwertzguy 14

素晴らしいですが、さまざまな方法を切り替えるのはどれほど便利であると思いますか。また、Cのような関数全体を引き出すことができるプログラムを知っていますか?
nafg 2015年

12

git logには '-G'オプションがあり、すべての違いを見つけることができます。

-G追加または削除された行が指定されたと一致する違いを探し<regex>ます。

気になる関数名の適切な正規表現を指定してください。例えば、

$ git log --oneline -G'^int commit_tree'
40d52ff make commit_tree a library function
81b50f3 Move 'builtin-*' into a 'builtin/' subdirectory
7b9c0a6 git-commit-tree: make it usable from other builtins

5
私はコマンドを実行しませんでしたが、このコマンドはメソッド/関数全体ではなく、正規表現に一致する行に触れるコミットのみを表示するように見えます。
Erik B

より多くのコンテキストが必要な場合は、次のもの--onelineで置き換えることができます-p
lfender6445

3
しかし、メソッドに20行の変更が加えられた場合はどうなるでしょうか。
nafg

+1。私にとって、トップの回答は機能しましたが、最新のコミットのみを示しました。おそらく、リベースまたは関数が数回移動したためか、確かではありません。関数の代わりに実際のコード行を検索することで(1行ですが)この回答により、探しているコミットを簡単に見つけることができました。ありがたいことに、私はたいてい有用なコミットメッセージを書きます!
Dave S

11

あなたができる最も近いことは、ファイル内の関数の位置を決定することです(たとえば、関数i_am_buggyがの241-263行にあるとしましょうfoo/bar.c)。次に、次の効果を実行します。

git log -p -L 200,300:foo/bar.c

これにより、開きが少なくなります(または同等のポケットベル)。これで入力/i_am_buggy(または同等のポケットベル)して、変更のステップ実行を開始できます。

これは、コードスタイルによっては機能する場合もあります。

git log -p -L /int i_am_buggy\(/,+30:foo/bar.c

これにより、その正規表現の最初のヒット(理想的には関数宣言)からの検索が、その後の30行に制限されます。検出が終了引数はまた、正規表現することができ、その正規表現のではiffier命題です。


甘い!参考までに、これはGit v1.8.4の新機能です。(私はアップグレードする必要があると思います。)より正確な解決策はいいですが...誰かがPaul Whittakerの答えをスクリプト化するようなものです。
グレッグ価格

@GregPrice どうやら検索の端は正規表現さえあり得るので、少なくとも多少正確な開始点を持つことができます。
2014

ああすごい。実際、独自の正規表現を作成する代わりに-L ":int myfunc:foo/bar.c"、その名前の関数だけを言って制限することができます。これは素晴らしいです-ポインタをありがとう!関数の検出だけがもう少し信頼性が高かった場合
Greg Price

3

正しい方法はgit log -L :function:path/to/fileeckes answerで説明されているように使用することです。

ただし、さらに、関数が非常に長い場合、これらの行の1つだけに触れる可能性があるコミットごとに、変更されていない関数行全体ではなく、さまざまなコミットによって導入された変更のみを表示したい場合があります。普通のようにdiffように。

通常git logはとの違いを表示できます-pが、では機能しません-L。したがって、grep git log -L関係する行とコミット/ファイルヘッダーのみを表示して、それらをコンテキスト化する必要があります。ここでのトリックは--color、正規表現でスイッチを追加して、端末の色付きの線のみを一致させることです。最後に:

git log -L :function:path/to/file --color | grep --color=never -E -e "^(^[\[[0-9;]*[a-zA-Z])+" -3

^[実際のリテラルである必要があることに注意してください^[。これらは、bashで^ V ^ [を押すことで入力できます。つまり、Ctrl+ VCtrl+ [です。ここで参照

また、最後の-3スイッチでは、一致した各行の前後に3行の出力コンテキストを出力できます。必要に応じて調整してください。


2

git blameは、ファイルの各行を最後に変更したユーザーを示します。関数の外の行の履歴を取得しないように、調べる行を指定できます。


4
git gui blame古いリビジョンをナビゲートすることができます。
Vi。

0
  1. eckesの回答にgit log -L :<funcname>:<file>示されているとおりに機能履歴を表示し、 git docに

    何も表示されない場合は、カスタムのhunk-headerの定義を参照し*.java diff=javaて、.gitattributes ファイルに何かを追加し、言語をサポートしてください。

  2. コミット間の関数履歴を表示 git log commit1..commit2 -L :functionName:filePath

  3. オーバーロードされた関数の履歴を表示します(同じ名前の関数が多数存在する場合がありますが、パラメーターが異なります)。 git log -L :sum\(double:filepath

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