git-diff的手册页相当长,并且解释了许多对于初学者来说似乎不需要的情况。例如:
git-diff
git diff origin/master
在我的mac上:
info diff然后选择:Output formats - > Context - > Unified format - > Detailed Unified:
info diff
Output formats
Context
Unified format
Detailed Unified
或gnu上的网络男人差异,按照相同的路径到相同的section:
文件:diff.info,节点:详细 统一,下:示例统一,上: 统一格式的< / p > 统一格式详细说明 ...................................... p > 开始统一输出格式 带有两行标题,看起来 这样的:< / p > --- FROM-FILE FROM-FILE-MODIFICATION-TIME +++ TO-FILE TO-FILE-MODIFICATION-TIME 时间戳看起来像' 2002-02-21 23:30:39.942229878 -0800'表示 日期,时间带分数 你可以改变标题的内容 使用'——label= label '选项;看到 *注意替代名称::. 接下来是一块或多块的 差异;每个大块显示一个区域 文件不同的地方。统一 格式块如下所示: @@ FROM-FILE-RANGE TO-FILE-RANGE @@ LINE-FROM-EITHER-FILE LINE-FROM-EITHER-FILE... 两个文件共用的行 以空格字符开始。的 这两条线实际上是不同的 两个文件包含以下内容之一 指示器字符在左侧打印 列:< / p > < p >“+” 在第一个文件中添加了一行 < p >“-” . .
文件:diff.info,节点:详细 统一,下:示例统一,上: 统一格式的< / p >
统一格式详细说明 ...................................... p >
开始统一输出格式 带有两行标题,看起来 这样的:< / p >
--- FROM-FILE FROM-FILE-MODIFICATION-TIME +++ TO-FILE TO-FILE-MODIFICATION-TIME
时间戳看起来像' 2002-02-21 23:30:39.942229878 -0800'表示 日期,时间带分数
你可以改变标题的内容 使用'——label= label '选项;看到 *注意替代名称::.
@@ FROM-FILE-RANGE TO-FILE-RANGE @@ LINE-FROM-EITHER-FILE LINE-FROM-EITHER-FILE...
两个文件共用的行 以空格字符开始。的 这两条线实际上是不同的 两个文件包含以下内容之一 指示器字符在左侧打印 列:< / p > < p >“+” 在第一个文件中添加了一行 < p >“-”
默认的输出格式(如果你想查找更多信息,它最初来自一个名为diff的程序)被称为“统一差异”。它包含了4种不同类型的行:
diff
+
-
我建议您练习阅读文件的两个版本之间的差异,以便您确切地知道所更改的内容。这样,当你看到它的时候,你就会知道发生了什么。
从你的问题中不清楚你觉得diff的哪一部分令人困惑:实际的diff,还是git打印的额外头信息。以防万一,这里有一个快速的标题概述。
第一行是类似diff --git a/path/to/file b/path/to/file的东西——显然它只是告诉你diff的这一部分是用于哪个文件的。如果你设置布尔配置变量diff.mnemonic prefix, a和b将被更改为更有描述性的字母,如c和w(提交和工作树)。
diff --git a/path/to/file b/path/to/file
diff.mnemonic prefix
a
b
c
w
接下来,是“模式行”——这些行描述了不涉及更改文件内容的任何更改。这包括新建/删除文件,重命名/复制文件,以及权限更改。
最后,有一行像index 789bd4..0afb621 100644。您可能永远不会关心它,但这些6位十六进制数字是该文件的旧blob和新blob的缩写SHA1哈希值(blob是存储原始数据(如文件内容)的git对象)。当然,100644是文件的模式——最后三位数字显然是权限;前三个给出额外的文件元数据信息(这是我的描述)。
index 789bd4..0afb621 100644
100644
在这之后,你就可以得到标准的统一差异输出(就像经典的diff -U一样)。它被分割成块——块是文件中包含更改及其上下文的部分。每个块之前都有一对---和+++行,表示有问题的文件,然后实际的diff是(默认情况下)在-和+行两侧的三行上下文,显示删除/添加的行。
diff -U
---
+++
让我们来看一个来自git历史的高级diff的例子(在在git中提交1088261f。git存储库中):
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] == '-') {
让我们逐行分析这个补丁。
——git a/builtin-http-fetch.c b/http-fetch.c
diff --git a/file1 b/file2
a/
b/
--git
接下来是一个或多个扩展标题行。前三个
相似度指数95% 从builtin-http-fetch.c重命名 rename to http-fetch.c
builtin-http-fetch.c
http-fetch.c
指数f3e63d7 . .e8f44ba 100644
git am --3way
接下来是两行统一差异头
——a/builtin-http-fetch.c +++ b/http-fetch.c
/dev/null
diff.mnemonicPrefix
c/
i/
w/
o/
@@ from-file-range to-file-range @@ [header]
-<start line>,<number of lines>
+<start line>,<number of lines>
如果是C文件(如GNU diff中的-p选项),则可选标头显示每次更改发生的C函数,如果有,则显示其他类型文件的等效函数。
-p
接下来是文件差异的描述。两个文件共用的行都以空格字符开头。两个文件之间实际不同的行在左侧打印列中有以下指示符之一:
'+'——在第一个文件中添加了一行。
'-'——从第一个文件中删除一行。
例如,第一个chunk
#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;行被添加。
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;
文件末尾没有换行符
作为Donal Fellows说,最好在现实生活中的例子中练习阅读差异,在那里你知道你改变了什么。
引用:
这里有一个简单的例子。
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
下面是解释:
a/ b/
10ff2df..84d4fa2
--- a/file +++ b/file
@@ -1,5 +1,5 @@
@@ -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
@@ -1,2 +3,4 @@部分的差异
@@ -1,2 +3,4 @@
我花了一些时间来理解这一部分,所以我创建了一个最小的示例。
格式基本与diff -u统一差分相同。
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,4 @@
-1,6意味着第一个文件的这一部分从第1行开始,总共显示6行。因此它显示了第1行到第6行。
-1,6
1 2 3 4 5 6
-表示“旧的”,因为我们通常调用它作为diff -u old new
diff -u old new
+1,4意味着第二个文件的这一部分从第1行开始,总共显示4行。因此它显示了第1行到第4行。
+1,4
+表示“新”。
我们只有4行而不是6行,因为2行被删除了!新帅哥只是:
1 4 5 6
@@ -11,6 +9,4 @@ for the second hunk is analogous:
@@ -11,6 +9,4 @@
on the old file, we have 6 lines, starting at line 11 of the old file:
11 12 13 14 15 16
on the new file, we have 4 lines, starting at line 9 of the new file:
11 12 13 16
注意,第11行是新文件的第9行,因为我们已经在前一个块上删除了2行:2和3
11
大块头
根据你的git版本和配置,你也可以在@@行旁边得到一个代码行,例如:
@@
@@ -4,7 +4,6 @@ func1() {
这也可以通过普通diff的-p标志获得。
例如:旧文件:
func1() { 1; 2; 3; 4; 5; 6; 7; 8; 9; }
如果我们删除行6, diff显示:
6
@@ -4,7 +4,6 @@ func1() { 3; 4; 5; - 6; 7; 8; 9;
注意,这不是func1的正确行:它跳过了1和2行。
func1
1
2
这个很棒的特性通常会准确地告诉每个块属于哪个函数或类,这对于解释差异非常有用。
如何选择头文件的算法将在:在git差异块头摘录从哪里来?