“@@…@@”在svn diff或git diff中的元行有什么意义?

72

当我使用 svn diffgit diff 命令时,它会显示如下行:

@@ -1,5 +1,9 @@

它们是指什么?


Superset: https://dev59.com/i3E85IYBdhLWcg3w9odJ#31615438 - Ciro Santilli OurBigBook.com
3个回答

76
那些被称为分块头部(chunk headers),并包含范围信息。
它们被双 @ 符号 @@ 包围。格式如下:
@@ -l,s +l,s @@

其中l表示起始行号,s表示每个文件相应更改块适用于的行数。 -表示原始文件,+表示新(修改后)文件。请注意,它不仅显示受影响的行,还显示上下文行。

-1,5在原始文件中(由-表示)。 它显示第一行是起点,受影响/上下文行数为5行。

+1,9在新(修改后)文件中(由+表示),同样第一行是起点,受影响/上下文行数为9行。

更多详情请参见:http://en.wikipedia.org/wiki/Diff#Unified_format


所以这些数字是指代码块和上下文吗?也就是说,git 打印的行是代码块(修改过的)加上之前 3 行和之后 3 行的上下文。因此,行的范围从上下文的开始到上下文的结束,即从第一个修改行之前的 3 行到最后一个修改行之后的 3 行? - Will
3
@Will 让我进一步澄清。当你看到像“-1,5”和“+1,9”这样的东西时,它真的很简单。数字“1”表示两个文件的起始行号,“5”表示(原始文件中未更改的行数+已删除的行数),“9”表示(新文件中未更改的行数+已添加的行数)。因此,你可以有一个包含5行的文件,你开始不做任何操作,然后在新提交中添加4行,你的差异将如上所示。 - Marius Mucenicu

28

简单示例分析

格式基本上与 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 意味着第二个文件中的这一部分从第1行开始,总共显示4行。因此它显示第1到第4行。

    + 表示“新”。

    由于删除了2行,因此我们只有4行! 新块只是:

    1
    4
    5
    6
    

@@ -11,6 +9,4 @@ 第二个块的类比如下:

  • 在旧文件中,我们有6行,从旧文件的第11行开始:

    11
    12
    13
    14
    15
    16
    
  • 在新文件中,我们有4行,从新文件的第9行开始:

    11
    12
    13
    16
    

    请注意,因为我们已经在之前的块中删除了2行(2和3),所以第11行是新文件的第9行。

代码块头部

根据您的 Git 版本和配置,您还可以在 @@ 行旁边得到一行代码,例如以下代码中的 func1() {

@@ -4,7 +4,6 @@ func1() {

可以通过普通diff命令的-p标志来获得此信息。

例如:旧文件:

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 -U0 <(seq -w 16) <(seq -w 16 | sed 's/10/hack/')

其中:

  • -U0:使用 0 行上下文
  • 第二个文件将 10 替换为 hack

在这种情况下,差异输出如下:

@@ -10 +10 @@
-10
+hack

因此我们知道,当只有一行更改时,符号表示将被概括为仅显示一个数字而不是m,n对。

此行为已在Todd's answer引用的文档中进行了记录:

如果 hunk 只包含一行,则仅显示其起始行号。否则,其行数看起来像 start,count。空的 hunk 被认为从其下一行开始。

而单行 hunk 的添加和删除看起来像这样,删除:

diff -U0  <(seq -w 16) <(seq -w 16 | grep -Ev '^(10)$')

输出:

@@ -10 +9,0 @@
-10

附加:

$ diff -U0 <(seq -w 16 | grep -Ev '^(10)$') <(seq -w 16)

输出:

@@ -9,0 +10 @@
+10

在 diff 3.8 和 Ubuntu 22.10 上进行了测试。


2
这可能是关于diff hunk的最好解释。 - mahonya
嗯,我有一个UserDefinedStitcher,并且我认为它告诉我我的更改在第20行,或者说从第6行开始的20行之后。(第6行是说UserDefinedStitcher的那一行。)但这把我带到了第26行,而我的更改在第23行。所以看起来git错了3行。发生了什么? - Will
@Will 请提供一个最小可重现的示例。 - Ciro Santilli OurBigBook.com
啊,我明白了,20是文件开头的绝对行号。而第20行是所显示上下文的开头行,我的更改在上下文中往下3行,因此是第23行。呼! :) - Will

5

这些描述了受差异块影响的行。在您的情况下,它意味着该差异块影响从第1行开始的5行,导致从第1行开始的替换长达9行。

请注意,这是统一的差异格式使用的格式。 "传统"差异格式使用不同的模型(但现在谁还使用传统的差异呢?)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接