45

When I run git diff, the output begins with:

diff --git a/foo/bar b/foo/bar 

If I try to run plain old diff --git, I'm told that the --git option doesn't exist (obviously, I guess, it would seem silly for a low-level tool to know about a specific DVCS). There's no mention of it in the man page as well. Where does this come from?

3
  • 1
    It is confusing indeed how git includes these commands in such a weird way. Commented Oct 3, 2016 at 15:06
  • 4
    The particular output is added here:github.com/git/git/commit/… and the reasoning for it is buried somewhere in here: gelato.unsw.edu.au/archives/git/0505/3812.html Commented Oct 3, 2016 at 16:00
  • Someone removed it, but I originally had an osx tag to indicate that this was the diff that ships with macOS, and the GNU tools might differ. Commented Oct 3, 2016 at 16:21

3 Answers 3

34

It's an "imaginary diff option", used to indicate to the reader that it's not just the output of running the diff command. For example, in git's own git repo:

$ git diff HEAD~1..HEAD | head diff --git Documentation/git.txt Documentation/git.txt index bd659c4..7913fc2 100644 --- Documentation/git.txt +++ Documentation/git.txt @@ -43,6 +43,11 @@ unreleased) version of Git, that is available from the 'master' branch of the `git.git` repository. Documentation for older releases are available here: +* link:v2.10.0/git.html[documentation for release 2.10] + $ 

The diff command itself, if you invoked it with the same file name twice, would show no differences. git presumably creates temporary files corresponding to two different versions of Documentation/git.txt and feeds them to diff -- but the names of those temporary files would not be useful. I think git diff massages the output of diff to make it more meaningful to the reader. (This speculation was not entirely correct. See below.)

Diving into the git source code, diff.c has the string "diff --git" hardwired as a string literal:

strbuf_addf(&header, "%s%sdiff --git %s %s%s\n", line_prefix, meta, a_one, b_two, reset); 

And looking into the history of diff.c for the earliest version that contains that string:

$ git log -n 1 b58f23b3 commit b58f23b38a9a9f28d751311353819d3cdf6a86da Author: Junio C Hamano <[email protected]> Date: 2005-05-18 09:10:47 -0700 [PATCH] Fix diff output take #4. This implements the output format suggested by Linus in <[email protected]>, except the imaginary diff option is spelled "diff --git" with double dashes as suggested by Matthias Urlichs. Signed-off-by: Junio C Hamano <[email protected]> Signed-off-by: Linus Torvalds <[email protected]> $ 

Presumably <Pine.LNX...> is the message-id of some email message in a mailing list somewhere. In any case, this commit message makes it clear that diff --git is an "imaginary diff option".

This email message, cited by nos in a comment, appears to be part of the discussion that led to this. Update: That link is now dead, and I don't know whether the archive is available elsewhere.

UPDATE: I speculated above that git diff massages the output of diff, adding this information. I just tried running git diff under strace. It doesn't actually invoke the diff command, or any other command. Rather, all the output is printed by the git process itself, and apparently it computes the differences internally. This behavior might also depend on the version of git (I'm using 2.23.0), the diff command(s) available, and the arguments used.

I'll note that GNU diff has a --label=LABEL option that could be used for this kind of thing:

'-L LABEL' '--label=LABEL' Use LABEL instead of the file name in the context format (*note Context Format::) and unified format (*note Unified Format::) headers. *Note RCS::. 

but git diff doesn't use it, at least in the one case I tried, and I don't see a reference to it in the git sources.

Sign up to request clarification or add additional context in comments.

1 Comment

3

The --git is to mean that diff is in the "git" diff format. It doesn't refers to and option of the /usr/bin/diff command You can find the list of diff format documentation. Other formats are:

  • diff --combined
  • diff --cc
  • diff --summary

Comments

1

As Keith mentioned, in GNU diff (check your version with diff -v), you can have git-style patches by using --label like so:

a single file from a backup

diff -u --label a/path/to/file.ext --label b/path/to/file.ext path/to/file.ext~ path/to/file.ext 

or from STDIN

command_that_outputs_previous_version | diff -u --label a/path/to/file.ext --label b/path/to/file.ext - path/to/file.ext 

You can use those commands in a loop of files from find, etc. Where one side of a comparison does not exist, e.g. new files, compare with /dev/null.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.