web-dev-qa-db-ja.com

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

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

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

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

76
Erik B

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

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

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

言い換えると、Gitにgit log -L :myfunction:path/to/myfile.cを要求すると、その関数の変更履歴が喜んで出力されるようになります。

71
eckes

git gui blameをスクリプトで使用するのは困難です。また、git log -Ggit log --pickaxeは、メソッド定義が表示されたり消えたりしたときにそれぞれ表示できますが、それらを作成する方法は見つかりませんでしたメソッドのbodyに加えられたすべての変更をリストします。

ただし、gitattributestextconvプロパティを使用して、まさにそれを行うソリューションをまとめることができます。これらの機能は元々、バイナリファイルでの作業を支援することを目的としていましたが、ここでも同様に機能します。

重要なのは、diff操作を実行する前に、Gitに関心のある行を除くすべての行をファイルから削除させることです。 git loggit diffなどには、関心のあるエリアのみが表示されます。

これが私が別の言語で行うことの概要です。自分のニーズに合わせて微調整できます。

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

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

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

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

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

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

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

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

15
Paul Whittaker

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
10
lht

あなたができる最も近いことは、ファイル内の関数の位置を決定することです(たとえば、関数i_am_buggyfoo/bar.cの行241-263にあります)、次に何かを実行します:

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行に制限されます。終了引数は正規表現にすることもできますが、正規表現でthatを検出するのはより簡単です。

9
badp

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

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

通常、git log-pとの違いを表示できますが、-Lでは機能しません。したがって、関連する行とコミット/ファイルヘッダーのみを表示してそれらをコンテキスト化するには、grepgit 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 + V、 Ctrl + [。参照 ここ

また、最後の-3スイッチを使用すると、一致する各行の前後に3行の出力コンテキストを出力できます。必要に応じて調整することもできます。

3
Hazzard17

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

2
Will