gitgit-diffgit-apply

Why does git-diff produce trailing whitespaces by default on its own empty lines?


I became aware of this because a pre-commit config started checking for the trailing-whitespace condition (the generated diff in question is itself part of a repo so a git commit catches the condition of the whitespaces).

I basically refer to all the empty lines in a default git diff output which are not part of patching itself; e.g. all the empty lines before a diff --git a ... line; they always contain 1 whitespace between the 2 newlines.


I believe they are produced when it shows the surrounding relevant code which is not part of patching, for readability, but those lines in the files compared themselves do not have whitespaces!


e.g. after changing a file with contents:

hello = "Hellow Stack Overflow"

print(hello)

quit()

git diff output:

diff --git a/1.py b/1.py
index da132e0..4fdf846 100644
--- a/1.py
+++ b/1.py
@@ -1,4 +1,4 @@
-hello = "Hellow Stack Overflow"
+hello = "Hello Stack Overflow"
 
 print(hello)
 

(the line before print(hello) and the line after print(hello) in the patch have a whitespace each (and removing the whitespaces: the patch still works))


Solution

  • This is a great example. Here's the original diff again except that I've added \$ to the end of each line for visibility:1

    diff --git a/1.py b/1.py\$
    index da132e0..4fdf846 100644\$
    --- a/1.py\$
    +++ b/1.py\$
    @@ -1,4 +1,4 @@\$
    -hello = "Hellow Stack Overflow"\$
    +hello = "Hello Stack Overflow"\$
     \$
     print(hello)\$
     \$
    

    git diff uses a form of unified diff with context, and by default, has -U3 set: it should use "three lines of context" above and below the diff hunk's changes. Here, the change is to line 1, so there aren't three lines above to include in the first place, but there are three lines below (in fact there are four, so git diff can cut one off with -U3).

    In the diff output, modified lines are prefixed with + or - to indicate an added or removed line, and an unchanged context line is prefixed with a single blank. Some naïve consumers of unified diffs could get upset if the blank before a context line is missing, so Git generates the standard form.

    You can use -U0 to select no-lines-of-context, if you like. As you noted in a comment, git apply itself (and other Git-suite programs) typically don't mind if a context line loses its leading space, so you can instead strip these spaces if you want the context, but dislike the rigid format—but it's a bit tricky to know when the context ends (you must use the @@ lines to keep count, so don't use these with --recount).


    1The BSD vis program does this with the -l option.