SYNOPSIS
git diff
*
DESCRIPTION
diffコマンド gitdiff-index
と git
diff-files
と git
diff-tree
は、 diff
出力を表示する前に、従来とは異なる方法で検出した差異を操作するように指示できます。この操作を総称して「diffcore変換」(diffcore transformation)と呼びます。この短いノートでは、それらが何であるか、およびそれらを使用して、従来の種類よりも理解しやすい diff
出力を生成する方法について説明します。
The chain of operation
git
diff-
* ファミリの仕事は、まずは2つのファイルセットを比較することです:
-
git
diff-index
は、 (--cached
フラグが使用されていない場合)ツリーオブジェクトと作業ディレクトリの内容を比較するか、または(--cached
フラグが使用されている場合)ツリーオブジェクトとインデックスファイルの内容を比較します。 -
git
diff-files
は、インデックスファイルと作業ディレクトリの内容を比較します。 -
git
diff-tree
は、2つのツリーオブジェクトの内容を比較します。
これらすべての場合において、コマンド自体は、最初にオプションで、コマンドラインで指定されたパススペックによって2つのファイルの組を限定し、結果として得られる2つのファイルの組の対応するパスを比較します。
パススペックは、 diffが動作する範囲を制限するために使用されます。 これらは、 指定されたパス名の組の外側にあるファイル・ペア(filepairs)を削除します。 たとえば、 入力されたファイルペアの組に以下が含まれていたとして:
:100644 100644 bcd1234... 0123456... M junkfile
…が、 しかし、 コマンドの呼び出しが git
diff-files
myfile
であった場合、 myfile
のみが考慮されるため、 junkfile
のエントリはリストから削除されます。
比較の結果は、これらのコマンドから、 `-p` オプションが使用されていない場合に出力されるものと同様の形式で、内部的に「diffcore」と呼ばれるものに渡されます。例えば
in-place edit :100644 100644 bcd1234... 0123456... M file0
create :000000 100644 0000000... 1234567... A file4
delete :100644 000000 1234567... 0000000... D file5
unmerged :000000 000000 0000000... 0000000... U file6
diffcoreメカニズムには、そのような比較結果のリストが提供され(それぞれが「ファイルペア」(filepair)と呼ばれますが、この時点ではそれぞれ1つのファイルについて話します)、そのようなリストを別のリストに変換します。現在、そのような変換(transformations)は5つあります:
-
diffcore-break
-
diffcore-rename
-
diffcore-merge-broken
-
diffcore-pickaxe
-
diffcore-order
-
diffcore-rotate
これらは順番に適用されます。 git
diff-
* コマンド群の探索のファイルペアのセットは、diffcore-breakへの入力として使用されます。diffcore-breakからの出力は、次の変換への入力として使用されます。そして、最終結果が出力ルーチンに渡され、diff-raw形式(マニュアルの git
diff-
* コマンド の「Output format」セクションを参照)またはdiff-patch形式のいずれかが生成されます。
diffcore-break: 完全な書き換えを分割するため
操作チェーンの1番目の変換(transformation)はdiffcore-breakで、 git
diff-
* コマンド群の -B
オプションによって制御されます。これは、「完全な書き換え」を表すファイルペアを検出し、そして、そのようなファイルペアを削除と作成を表す2つのファイルペアに分割するために使用されます。例えば、入力に以下のファイルペアが含まれている場合:
:100644 100644 bcd1234... 0123456... M file0
そして、ファイル "file0" が完全に書き換えられたことを検出すると、以下のように変更されます:
:100644 000000 bcd1234... 0000000... D file0
:000000 100644 0000000... 0123456... A file0
ファイルペアを切断する(break)目的で、diffcore-breakは、変更前後のファイルの内容(つまり、上記の例では、SHA-1コンテンツIDとして bcd1234.
.. と 0123456.
.. を持つコンテンツ)の間の変更の程度を調べます。元のコンテンツの削除と新しい素材の挿入の量が合計され、「ブレークスコア」(break score)を超えると、ファイルペアが2つに分割されます。ブレークスコアのデフォルトは、元のサイズと結果の小さい方のサイズの50%であり(つまり、編集によってファイルが縮小される場合は、結果のサイズが使用されます。編集によってファイルが長くなる場合は、元のサイズが使用されます)、 -B
オプションの後に数字を付けることでカスタマイズできます(たとえば、 -B75
で75%にするように指示します)。
diffcore-rename: 名前変更とコピーを検出するため
この変換(transformation)は、名前変更とコピーを検出するために使用され、 git
diff-
* コマンド群の -M
オプション(名前変更検出用)と -C
オプション(コピーも検出するため)によって制御されます。入力にこれらのファイルペアが含まれている場合:
:100644 000000 0123456... 0000000... D fileX
:000000 100644 0000000... 0123456... A file0
ここで、削除されたファイルfileXの内容は、作成されたファイルfile0の内容と十分に類似しているため、名前変更検出はこれらのファイルペアをマージして以下を作成します:
:100644 100644 0123456... 0123456... R100 fileX file0
-C
オプションを使用すると、変更されたファイルと削除されたファイル( --find-copies-harder
オプションが使用されている場合は、変更されていないファイルも)の元の内容が、名前変更/コピー 操作のソースファイルの候補と見なされます。入力がこれらのファイルペアのようなものである場合、変更されたファイルfileYと新しく作成されたファイルfile0について以下のようになります:
:100644 100644 0123456... 1234567... M fileY
:000000 100644 0000000... bcd3456... A file0
fileYの元の内容とfile0の結果の内容が比較され、それらが十分に類似している場合は、以下のように変更されます:
:100644 100644 0123456... 1234567... M fileY
:100644 100644 0123456... bcd3456... C100 fileY file0
名前の変更とコピーの検出の両方で、diffcore-breakで使用されるのと同じ「変更の範囲」(extent of changes)アルゴリズムを使用して、2つのファイルが「十分に類似」しているかどうかを判断し、デフォルトの50%とは異なる類似スコアを使用するようにカスタマイズできます。 -M
または -C
オプションの後に番号を付けます(たとえば、 -M8
で 8/10 = 80% にするように指示します)。
注意: 名前変更検出が有効で、 コピー検出とブレーク検出の両方が無効の場合、 名前変更検出は、 ファイル名が同じままでディレクトリ間で移動されたかどうかを最初にチェックする予備ステップを追加します。 あるディレクトリに追加されたファイルが、 別のディレクトリから削除された同じ名前のファイルと十分に類似している場合、 それらは名前変更としてマークされ、 後の二次的なステップ(すべての一致しないファイルをペアごとに比較して、 コンテンツの類似度が最も高い「最適な」一致を見つけるステップ)から除外されます。 たとえば、 削除された docs/ext.txt
と追加された docs/config/ext.txt
が十分に類似している場合、 それらは名前変更としてマークされ、 削除された docs/ext.txt
とさらに類似している可能性のある追加された docs/ext.md
が後のステップで名前変更先として考慮されるのを防ぎます。 このため、 予備の「同じファイル名を一致させる」ステップでは、 ファイルのペアを名前変更としてマークし、 他のより良い一致の候補を考慮するのを止めるために、 少し高い閾値を使用します。 この予備パス(preliminary pass)では、 1ファイルあたり最大で1回の比較が行われます。 そのため、 正確な名前変更検出後にディレクトリ階層全体に複数の ext.txt
ファイルが残っている場合、 これらのファイルに対してこの予備ステップがスキップされることがあります。
注意: -C
オプションを --find-copies-harder
オプションとともに使用すると、 git
diff-
* コマンド群は、変更されていないファイルペアと変更されたファイルペアをdiffcoreメカニズムに送ります。これにより、コピー検出器は、ファイルの速度を低下させる代わりに、変更されていないファイルをコピーソース候補と見なすことができます。 --find-copies-harder
がないと、 git
diff-
* コマンド群は、コピーされたファイルがたまたま同じチェンジセットで変更された場合にのみコピーを検出できます。
diffcore-merge-broken: 完全な書き換えを元に戻すため
この変換は、diffcore-breakによって分割したファイルペアをマージするために使用され、 diffcore-rename によって rename/copy に変換されず、単一の変更に戻されます。これは、diffcore-breakが使用されている場合は常に実行されます。
分割したファイルペアをマージする目的で、 diffcore-break および diffcore-rename で使用されるものとは異なる「変更の範囲」の計算を使用します。オリジナルからの削除のみをカウントし、挿入はカウントしません。100行のドキュメントから10行だけを削除した場合、新しい1000行のドキュメントを作成するために910行を追加しても、完全な書き換えは行われたとは見なしません。 diffcore-break は、 diffcore-renameがそのようなファイルペアを 名前変更/コピー 検出の候補と見なすのを助けるためにそのような場合のを分割しますが、その方法で分割したファイルペアが他のファイルペアと一致して 名前変更/コピー を作成しなかった場合、この変換でそれらをマージして「元の変更」に戻します 。
「変更の範囲」パラメータは、 -B
に2番目の数値を指定することで、デフォルトの80%から微調整できます(つまり、元のマテリアルの80%以上が削除されない限り、分割されたペアは1つの変更にマージされます)。以下のように指定できます:
-
-B50/60
(diffcore-breakに50%の「ブレークスコア」を与え、diffcore-merge-brokenに60%を与えます)。 -
-B/60
(上記と同じです。diffcore-breakのデフォルトは50%であるため)。
以前の実装では、 壊れたペア(破壊的な変更)は個別の作成パッチと削除パッチとして残されていました。 これは不要なハックであり、 最新の実装ではすべての壊れたペアを常に修正として統合します。 ただし、 完全な書き換えの場合にレビューを容易にするため、 結果として出力されるパッチは異なる形式で表示されます。 具体的には、 古いバージョンの内容全体を -
で始まる行として表示し、 その後に新しいバージョンの内容全体を +
で始まる行として表示します。
diffcore-pickaxe: 指定の文字列(string)の追加/削除の検知のため
この変換により、 ファイル・ペアの組が、 特定の方法でプリ・イメージとポスト・イメージの間で指した文字列を変更するものに制限されます。 -S
<block-of-text> および -G
<regular-expression> オプションは、 これらの文字列を検索するさまざまな方法を指定するために使用されます。
-S
<block-of-text> は、 指定されたテキストのブロックの出現回数がプリ・イメージとポスト・イメージで異なるファイル・ペアを検出します。 定義上、 ファイル内の移動は検出されません。 また、 チェンジ・セットが対象の文字列に影響を与えずにファイルを大規模に移動すると、 通常どおり diffcore-rename が開始され、-S
はファイル・ペアを省略します(その文字列の出現回数は、名前変更で検出されたファイル・ペアで変更されなかったため)。 --pickaxe-regex
と一緒に使用する場合、<block-of-text> は、 リテラル文字列ではなく、 マッチする拡張POSIX正規表現として扱います。
-G
<regular-expression> (grep文法)は、 指定された正規表現にマッチする行が追加または削除されたテキスト差分を持つファイル・ペアを検出します。 これは、 ノイズであるファイル内の移動(またはrename-detectionが同じファイルと見なすもの)を検出することを意味します。 実装は diff を2回実行して greps しますが、 これは非常にコストがかかる可能性があります。 高速化のため、 textconv フィルタがないバイナリ・ファイルは無視されます。
-S
または -G
を --pickaxe-all
なしで使用すると、それぞれの基準に一致するファイルペアのみが出力に保持されます。 --pickaxe-all
が使用されている場合、1つのファイルペアでもチェンジセット内のそれぞれの基準に一致すると、チェンジセット全体が保持されます。この振る舞いは、チェンジセット全体のコンテキストでの変更のレビューを容易にするために設計されています。
diffcore-order: ファイル名に基づいて出力をソートするため
これは、ユーザー(またはプロジェクト)の好みに応じてファイルペアを並べ替えるために使用され、 git
diff-
* コマンド群の -O
オプションによって制御されます。
これは、各行がシェルグロブパターンであるテキストファイルを取ります。ファイルの前の行のグロブパターンに一致するファイルペアは、後の行に一致するファイルペアの前に出力され、どのグロブパターンにも一致しないファイルペアは最後に出力されます。
例として、コアGitの一般的な orderfile は、 おそらく以下のようになります:
README
Makefile
Documentation
*.h
*.c
t
diffcore-rotate: 出力開始パス(path)を変更するため
この変換は1つのパス名を取り、ファイルペアのセットをローテーションして、指定されたパス名のファイルペアが最初に来るようにします。オプションで、その前にあるパスを破棄します。これは、 --skip-to
および --rotate-to
オプションを実装するために使用されます。指定されたパス名がファイルペアのセットにない場合はエラーになりますが、 git
log
ファミリーのコマンドで使用するとエラーになることはありません。 git
log
コマンドで表示されるすべてのコミットによって特定のパスが変更されることを期待するのは不合理だからです。このため、 git
log
と一緒に使用すると、指定されたパス名と同じように並べ替えられるファイルペア、または最初に並べ替えられるファイルペアが出力の開始場所になります。
この変換をdiffcore-orderと組み合わせて使用すると、diffcore-orderが有効な場合、この変換への入力がソートされない可能性があるため、予期しない結果が生成されます。
SEE ALSO
GIT
Part of the git(1) suite