のマニュアルページgit-diff
はかなり長く、初心者には必要ないと思われる多くのケースを説明しています。例えば:
git diff origin/master
git履歴からの高度な差分の例を見てみましょう(git.gitリポジトリのcommit 1088261f):
diff --git a/builtin-http-fetch.c b/http-fetch.c
similarity index 95%
rename from builtin-http-fetch.c
rename to http-fetch.c
index f3e63d7..e8f44ba 100644
--- a/builtin-http-fetch.c
+++ b/http-fetch.c
@@ -1,8 +1,9 @@
#include "cache.h"
#include "walker.h"
-int cmd_http_fetch(int argc, const char **argv, const char *prefix)
+int main(int argc, const char **argv)
{
+ const char *prefix;
struct walker *walker;
int commits_on_stdin = 0;
int commits;
@@ -18,6 +19,8 @@ int cmd_http_fetch(int argc, const char **argv, const char *prefix)
int get_verbosely = 0;
int get_recover = 0;
+ prefix = setup_git_directory();
+
git_config(git_default_config, NULL);
while (arg < argc && argv[arg][0] == '-') {
このパッチを1行ずつ分析してみましょう。
最初の行
diff --git a / builtin-http-fetch.cb / http-fetch.cは、形式の「gitdiff」ヘッダー
diff --git a/file1 b/file2
です。名前の変更/コピーが含まれていない限り、ファイル名a/
とb/
ファイル名は同じです(この場合のように)。これ--git
は、diffが「git」diff形式であることを意味します。
次は、1つ以上の拡張ヘッダー行です。最初の3つ
類似性指数95% 組み込みから名前を変更-http-fetch.c http-fetch.cに名前を変更します
builtin-http-fetch.c
ファイルの名前がからに変更されhttp-fetch.c
、これら2つのファイルが95%同一である(この名前変更の検出に使用された)ことを教えてください。インデックスf3e63d7..e8f44ba100644与えられたファイルのモード(
100644
シンボリックリンクなどではなく通常のファイルであり、実行可能許可ビットがないことを意味します)、およびpreimage(与えられた変更前のファイルのバージョン)とpostimage(変更後のファイルのバージョン)。この行はgit am --3way
、パッチ自体を適用できない場合に3方向マージを試行するために使用されます。次は2行の統一されたdiffヘッダーです
--- a / builtin-http-fetch.c +++ b / http-fetch.c結果と比較すると
diff -U
、ソース(preimage)およびdestination(postimage)ファイル名の後にfrom-file-modification-timeもto-file-modification-timeもありません。ファイルが作成された場合、ソースは/dev/null
;です。ファイルが削除された場合、ターゲットは/dev/null
です。構成変数をtrueに設定するdiff.mnemonicPrefix
a/
b/
c/
i/
w/
o/
次に、1つ以上の違いがあります。各ハンクは、ファイルが異なる1つの領域を示しています。統一フォーマットのハンクは、次のような行で始まります
@@ -1,8 +1,9 @@また
@@ -18,6 +19,8 @@ int cmd_http_fetch(int argc、const char ** argv、..。の形式です
@@ from-file-range to-file-range @@ [header]
。from-file-rangeはの形式-<start line>,<number of lines>
で、to-file-rangeは+<start line>,<number of lines>
です。スタートラインとライン数はどちらも、それぞれプリイメージとポストイメージのハンクの位置と長さを示します。行数が表示されていない場合は、1であることを意味します。
オプションのヘッダーは、Cファイル(-p
GNU diffのオプションなど)の場合は各変更が発生するC関数、または他のタイプのファイルの場合は同等の関数を示します。
次に、ファイルの違いについて説明します。両方のファイルに共通の行は、スペース文字で始まります。2つのファイル間で実際に異なる行には、左側の印刷列に次のいずれかの標識文字があります。
'+'-ここで最初のファイルに行が追加されました。
'-'-ここで最初のファイルから行が削除されました。
したがって、たとえば、最初のチャンク
#include "cache.h"
#include "walker.h"
-int cmd_http_fetch(int argc, const char **argv, const char *prefix)
+int main(int argc, const char **argv)
{
+ const char *prefix;
struct walker *walker;
int commits_on_stdin = 0;
int commits;
これは、cmd_http_fetch
に置き換えられmain
、そのconst char *prefix;
行が追加されたことを意味します。
つまり、変更前の「builtin-http-fetch.c」ファイルの適切なフラグメントは次のようになりました。
#include "cache.h"
#include "walker.h"
int cmd_http_fetch(int argc, const char **argv, const char *prefix)
{
struct walker *walker;
int commits_on_stdin = 0;
int commits;
変更後、現在の「http-fetch.c」ファイルのこのフラグメントは、代わりに次のようになります。
#include "cache.h"
#include "walker.h"
int main(int argc, const char **argv)
{
const char *prefix;
struct walker *walker;
int commits_on_stdin = 0;
int commits;
\ファイルの終わりに改行がありません行が存在します(例ではdiffではありません)。
Donal Fellowsが言ったように、実際の例で差分を読む練習をするのが最善です。そこでは、自分が何を変えたかを知っています。
参照:
@@ -1,2 +3,4 @@
差分の一部
この部分を理解するのに少し時間がかかったので、最小限の例を作成しました。
フォーマットは基本的にdiff -u
統一された差分と同じです。
例えば:
diff -u <(seq 16) <(seq 16 | grep -Ev '^(2|3|14|15)$')
ここでは、2、3、14、15行目を削除しました。出力:
@@ -1,6 +1,4 @@
1
-2
-3
4
5
6
@@ -11,6 +9,4 @@
11
12
13
-14
-15
16
@@ -1,6 +1,4 @@
意味:
-1,6
これは、最初のファイルのこの部分が1行目から始まり、合計6行を示していることを意味します。したがって、1行目から6行目が表示されます。
1
2
3
4
5
6
-
通常はとして呼び出すため、「古い」を意味しdiff -u old new
ます。
+1,4
これは、2番目のファイルのこの部分が1行目から始まり、合計4行を示していることを意味します。したがって、1行目から4行目が表示されます。
+
「新しい」を意味します。
2行が削除されたため、6行ではなく4行しかありません。新しいハンクは次のとおりです。
1
4
5
6
@@ -11,6 +9,4 @@
2番目のハンクは類似しています:
古いファイルには、古いファイルの11行目から6行あります。
11
12
13
14
15
16
新しいファイルには、新しいファイルの9行目から始まる4行があります。
11
12
13
16
11
前のハンクの2行(2行と3行)が既に削除されているため、行は新しいファイルの9行目であることに注意してください。
ハンクヘッダー
gitのバージョンと構成によっては、行の横にコード行を表示することもできます@@
。たとえば、次のようになりfunc1() {
ます。
@@ -4,7 +4,6 @@ func1() {
これは-p
、プレーンのフラグを使用して取得することもできますdiff
。
例:古いファイル:
func1() {
1;
2;
3;
4;
5;
6;
7;
8;
9;
}
行を削除する6
と、差分は次のようになります。
@@ -4,7 +4,6 @@ func1() {
3;
4;
5;
- 6;
7;
8;
9;
これは正しい行ではないことに注意してください:行とfunc1
をスキップしました。1
2
この素晴らしい機能は、多くの場合、各ハンクがどの関数またはクラスに属しているかを正確に示します。これは、差分を解釈するのに非常に役立ちます。
ヘッダーを選択するアルゴリズムが正確にどのように機能するかについては、次の場所で説明されています。git diff hunkヘッダーの抜粋はどこから来ていますか?
これが簡単な例です。
diff --git a/file b/file
index 10ff2df..84d4fa2 100644
--- a/file
+++ b/file
@@ -1,5 +1,5 @@
line1
line2
-this line will be deleted
line4
line5
+this line is added
説明は次のとおりです。
--git
はコマンドではありません。これは、diffのgitバージョン(unixではない)であることを意味します。a/ b/
ディレクトリであり、本物ではありません。同じファイルを処理する場合に便利です(私の場合、a /はインデックスにあり、b /は作業ディレクトリにあります)10ff2df..84d4fa2
これら2つのファイルのBLOBIDです100644
は「モードビット」であり、これが通常のファイル(実行可能ファイルでもシンボリックリンクでもない)であることを示します。--- a/file +++ b/file
マイナス記号は、a /バージョンでは線を示していますが、b/バージョンでは欠落しています。プラス記号は、a /にはないが、b /には存在する行を示します(私の場合、---は削除された行を意味し、+++はb /に追加された行を意味し、これは作業ディレクトリのファイルです)@@ -1,5 +1,5 @@
これを理解するには、大きなファイルで作業することをお勧めします。異なる場所で2つの変更がある場合、@@ -1,5 +1,5 @@
;のような2つのエントリを取得します。ファイルline1...line100があり、line10を削除し、新しいline100を追加するとします。次のようになります。@@ -7,7 +7,6 @@ line6 line7 line8 line9 -this line10 to be deleted line11 line12 line13 @@ -98,3 +97,4 @@ line97 line98 line99 line100 +this is new line100
diff
デフォルトの出力形式(元々は、より多くの情報を探したい場合と呼ばれるプログラムから取得されます)は、「統合差分」と呼ばれます。これには、基本的に4つの異なるタイプの行が含まれています。
+
。-
、およびで始まる削除行何を変更したかが正確にわかっているファイルの2つのバージョン間の差分を読み取る練習をすることをお勧めします。そのように、あなたはそれを見たときに何が起こっているのかを認識するでしょう。
私のMacの場合:
info diff
次に、次を選択します:Output formats
-> Context
-> Unified format
-> Detailed Unified
:
または、同じセクションへの同じパスをたどるgnuのオンライン差分:
ファイル:diff.info、ノード:詳細ユニファイド、次:例ユニファイド、アップ:ユニファイドフォーマット
統一フォーマットの詳細な説明.....................................。
統合された出力形式は、次のような2行のヘッダーで始まります。
--- FROM-FILE FROM-FILE-MODIFICATION-TIME +++ TO-FILE TO-FILE-MODIFICATION-TIME
タイムスタンプは「2002-02-2123:30:39.942229878 -0800」のようになり、日付、秒の小数部の時刻、およびタイムゾーンを示します。
`--label =LABEL'オプションを使用してヘッダーの内容を変更できます。*注別名::を参照してください。
次に、1つ以上の違いがあります。各ハンクは、ファイルが異なる1つの領域を示しています。統一フォーマットのハンクは次のようになります。
@@ FROM-FILE-RANGE TO-FILE-RANGE @@ LINE-FROM-EITHER-FILE LINE-FROM-EITHER-FILE...
両方のファイルに共通の行は、スペース文字で始まります。2つのファイル間で実際に異なる行には、左側の印刷列に次のいずれかの標識文字があります。
`+'ここで最初のファイルに行が追加されました。
`-'ここで最初のファイルから行が削除されました。
あなたの質問から、あなたが混乱していると思う差分の部分がはっきりしていません:実際の差分、またはgitが出力する追加のヘッダー情報。念のため、ヘッダーの概要を以下に示します。
最初の行は次のようなものですdiff --git a/path/to/file b/path/to/file
-明らかに、diffのこのセクションがどのファイル用であるかを示しているだけです。ブール構成変数を設定するdiff.mnemonic prefix
と、a
andはand (コミットおよび作業ツリー)のb
ようなより説明的な文字に変更されます。c
w
次に、「モード行」があります。これは、ファイルの内容の変更を伴わない変更の説明を提供する行です。これには、新規/削除されたファイル、名前が変更された/コピーされたファイル、および権限の変更が含まれます。
最後に、のような行がありindex 789bd4..0afb621 100644
ます。おそらく気にしないでしょうが、これらの6桁の16進数は、このファイルの新旧のblobのSHA1ハッシュの省略形です(blobは、ファイルの内容などの生データを格納するgitオブジェクトです)。そしてもちろん、これ100644
はファイルのモードです。最後の3桁は明らかに権限です。最初の3つは、追加のファイルメタデータ情報を提供します(それを説明するSO投稿)。
その後、標準の統合diff出力に進みます(クラシックと同じようにdiff -U
)。ハンクに分割されます。ハンクは、変更とそのコンテキストを含むファイルのセクションです。各ハンクの前には、問題のファイルを示す1対の行が---
あり+++
、実際の差分は、(デフォルトでは)との両側にある3行のコンテキストであり-
、+
行は削除/追加された行を示します。