web-dev-qa-db-ja.com

Gitは、あるファイルから別のファイルへの単一の関数の移動を実際に追跡できますか?もしそうなら、どのように?

あるファイルから別のファイルに単一の関数を移動すると、Gitがそれを追跡できるという声明に何度か出くわしました。たとえば、 このエントリ は、「関数をあるファイルから別のファイルに移動すると、Gitは移動中のその単一の関数の履歴を教えてくれるとLinusは言っています。」

しかし、私はGitの内部設計のいくつかについて少し認識しており、これがどのように可能であるかわかりません。だから私は疑問に思っています...これは正しいステートメントですか?もしそうなら、これはどのように可能ですか?

私の理解では、Gitは各ファイルのコンテンツをBlobとして格納し、各Blobは、そのコンテンツとサイズのSHAハッシュから生じるグローバルに一意のIDを持っています。Gitはフォルダーをツリーとして表します。任意ファイル名情報はBlobではなくTreeに属しているため、たとえばファイルの名前変更は、BlobではなくTreeへの変更として表示されます。

したがって、20個の関数を含む「foo」というファイルと5個の関数を含む「bar」というファイルがあり、関数の1つをfooからbarに移動すると(それぞれ19と6になります)、その関数をあるファイルから別のファイルに移動したことをGitはどのように検出できますか?

私の理解では、これにより2つの新しいblobが存在します(1つは変更されたfoo用、もう1つは変更されたbar用)。関数が1つのファイルから別のファイルに移動されたことを示すためにdiffを計算できることに気付きました。しかし、関数に関する履歴がfooではなくbarに関連付けられる可能性があるかどうかはわかりません(とにかく自動的ではありません)。

Gitが実際に単一ファイルの内部を調べ、関数ごとにblobを計算する場合(可能な言語を解析する方法を知っている必要があるため、これはクレイジー/実行不可能です)、それから私はこれがどのように可能であるかを見ることができました。

それで...ステートメントは正しいかどうか?そしてそれが正しければ、私の理解に欠けているものは何ですか?

67
Charlie Flowers

この機能は、git blame-Cを介して提供されます

-Cオプションは、レビュー対象のファイルと同じチェンジセットで変更されたファイル内のテキストのチャンクの追加または削除の間の一致を見つけようとするようにgitを駆動します。追加の-CCまたは-CCCは、検索を拡張します。マニュアルページのgithelpblameと入力します。

Git blame -Cを使用してテストリポジトリを試してみると、移動したばかりのコードのブロックが、それが属していた元のファイルに由来していることがわかります。

28
JN Avila

Git 2.15、git diffがサポートされるようになりました--color-movedオプションを使用した移動行の検出。これは、ファイル間の移動に対して機能します。

明らかに、色付きの端末出力で機能します。私の知る限り、プレーンテキストのパッチ形式で移動を示すオプションはありませんが、それは理にかなっています。

デフォルトの動作については、

git diff --color-moved

このコマンドは、現在nodefaultplainzebra、およびdimmed_zebragit help diffを使用して最新のオプションとその説明を入手してください)。例えば:

git diff --color-moved=zebra

howについては、 機能の作者によるこのメール交換 からある程度の理解を得ることができます。

12
vas

この機能の一部はgit gui blame(+ファイル名)にあります。ファイルの行の注釈が表示され、それぞれがいつ作成され、いつ最後に変更されたかを示します。ファイル間でのコード移動の場合、元のファイルのコミットが作成として表示され、現在のファイルに追加されたコミットが最終変更として表示されます。それを試してみてください。

私が本当に望んでいるのは、git logを引数としてファイルパスに加えて行番号の範囲を指定することです。そうすると、このコードブロックの履歴が表示されます。ドキュメントが正しければ、そのようなオプションはありません。はい、Linusの声明から、私もそのようなコマンドはすぐに利用できるはずだと思います。

5
Paŭlo Ebermann

gitは実際には名前の変更を追跡しませんまったく。名前の変更は、削除と追加だけです。それだけです。名前の変更を表示するツールは、この履歴情報からそれらを再構築します。

そのため、追跡機能の名前変更は、事後に各コミットですべてのファイルの差分を分析するという単純な問題です。それについて特に不可能なことは何もありません。既存の名前変更追跡は、ファイルの名前変更だけでなく、ファイルにいくつかの変更が加えられる「ファジー」名前変更をすでに処理しています。これには、ファイルの内容を確認する必要があります。関数の名前変更も探すのは簡単な拡張です。

ただし、基本のgitツールが実際にこれを行うかどうかはわかりません。言語に依存しないようにしようとしており、関数の識別は言語に依存しません。

3
bdonlan

特定の行がfooから消え、barに再表示されたことを示すgit diffがあります。同じコミットでこれらのファイルに他の変更がない場合、変更を簡単に見つけることができます。

知的gitクライアントは、あるファイルから別のファイルに行がどのように移動したかを示すことができます。言語対応IDEは、この変更を特定の機能に対応させることができます。

ファイルの名前が変更されると、非常によく似たことが起こります。ある名前で消えて別の名前で再び表示されますが、適切なツールであれば、それを認識して名前の変更として表すことができます。

2
9000