72

When I use svn diff or git diff it shows lines like:

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

What do they mean?

Ciro Santilli OurBigBook.com
  • 347,512
  • 102
  • 1,199
  • 985
vietstone
  • 8,784
  • 16
  • 52
  • 79

3 Answers3

76

Those are called (c)hunk headers and contain the range information.

They are surrounded by double at signs @@. They are of the format:

@@ -l,s +l,s @@

where l is the starting line number and s is the number of lines the change (c)hunk applies to for each respective file. The - indicates the original file and the + indicates the new (modified) file. Note that it not only shows affected lines, but also context lines.

The -1,5 is in the original file (indicated by the -). It shows that that first line is the start and 5 affected / context lines

The +1,9 is in the new (modified) file (indicated by the +) and again first line is the start and 9 affected / context lines.

More details here: http://en.wikipedia.org/wiki/Diff#Unified_format

Martin Geisler
  • 72,968
  • 25
  • 171
  • 229
manojlds
  • 290,304
  • 63
  • 469
  • 417
  • So the numbers refer to the hunk + context? i.e. the lines printed by git are the hunk (changed) lines plus 3 lines before and 3 lines after the hunk (changed) lines. So the range of lines is from start of context to end of context, i.e. from 3 lines before the first changed line to 3 lines after the last changed line? – Will Aug 24 '17 at 16:11
  • 3
    @Will let me disambiguate further. When you see something like `-1,5` and `+1,9` it's really simple. The `1` indicates the starting line number in both and the `5` indicates (the number of unchanged lines + number of deleted lines from the original file) and the `9` indicates (the number of unchanged lines + number of added lines in the new file). So you could have something like a file with 5 lines you start with and do nothing with them, and add 4 lines afterwards in a new commit and your diff will look like above. – Marius Mucenicu Oct 03 '18 at 12:25
28

Simple example analysis

The format is basically the same the diff -u unified diff.

For instance:

diff -u <(seq 16) <(seq 16 | grep -Ev '^(2|3|14|15)$')

Here we removed lines 2, 3, 14 and 15. Output:

@@ -1,6 +1,4 @@
 1
-2
-3
 4
 5
 6
@@ -11,6 +9,4 @@
 11
 12
 13
-14
-15
 16

@@ -1,6 +1,4 @@ means:

  • -1,6 means that this piece of the first file starts at line 1 and shows a total of 6 lines. Therefore it shows lines 1 to 6.

    1
    2
    3
    4
    5
    6
    

    - means "old", as we usually invoke it as diff -u old new.

  • +1,4 means that this piece of the second file starts at line 1 and shows a total of 4 lines. Therefore it shows lines 1 to 4.

    + means "new".

    We only have 4 lines instead of 6 because 2 lines were removed! The new hunk is just:

    1
    4
    5
    6
    

@@ -11,6 +9,4 @@ for the second hunk is analogous:

  • 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
    

    Note that line 11 is the 9th line of the new file because we have already removed 2 lines on the previous hunk: 2 and 3.

Hunk header

Depending on your git version and configuration, you can also get a code line next to the @@ line, e.g. the func1() { in:

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

This can also be obtained with the -p flag of plain diff.

Example: old file:

func1() {
    1;
    2;
    3;
    4;
    5;
    6;
    7;
    8;
    9;
}

If we remove line 6, the diff shows:

@@ -4,7 +4,6 @@ func1() {
     3;
     4;
     5;
-    6;
     7;
     8;
     9;

Note that this is not the correct line for func1: it skipped lines 1 and 2.

This awesome feature often tells exactly to which function or class each hunk belongs, which is very useful to interpret the diff.

How the algorithm to choose the header works exactly is discussed at: Where does the excerpt in the git diff hunk header come from?

One line hunk summarized notation

This is very rare, but consider:

diff -U0 <(seq -w 16) <(seq -w 16 | sed 's/10/hack/')

where:

  • -U0: use 0 lines of context
  • second file replaces 10 with hack

The diff output in that case is:

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

So we understand that when there's a single line change, the notation gets summarized to showing just one number instead of the m,n pair.

This behavior is documented in the documentation quoted by Todd's answer:

If a hunk contains just one line, only its start line number appears. Otherwise its line numbers look like start,count. An empty hunk is considered to start at the line that follows the hunk.

And single line hunk addition and removal look like this, removal:

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

output:

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

addition:

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

output:

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

Tested on diff 3.8, Ubuntu 22.10.

Ciro Santilli OurBigBook.com
  • 347,512
  • 102
  • 1,199
  • 985
  • 2
    This is probably the best explanation of the diff hunk. – mahonya Sep 04 '15 at 14:12
  • Well, I have this @@ -20,7 +20,8 @@ UserDefinedStitcher and I thought perhaps it was telling me that my changes were at line 20, or rather, 20 lines onwards from Line 6. (Line 6 is the line that says UserDefinedStitcher.) But this takes me to Line 26, yet my changes were on Line 23. So it would seem that git is out by 3 lines. What is going on? – Will Aug 24 '17 at 15:41
  • @Will please produce a minimal reproducible example. – Ciro Santilli OurBigBook.com Aug 24 '17 at 15:51
  • Ah, I see that 20 is an ABSOLUTE line number from the beginning of the file. And Line 20 is the line at the beginning of the context shown, and my change is 3 lines down in the context, hence Line 23. Phew! :) – Will Aug 24 '17 at 15:55
5

These describe the lines affected by the diff hunk. In your case, it means the hunk affects 5 lines starting from line 1, resulting in a replacement starting at line 1 which is 9 lines long.

Note that this is the format used by the unified diff format. The "classical" diff format uses a different model (but who uses classical diff these days?).

fge
  • 119,121
  • 33
  • 254
  • 329