Что означает вывод "diff - git" в "git diff"?

Когда я запускаю git diff, вывод начинается с:

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

Если я попытаюсь запустить простой старый diff --git, мне сказали, что параметр --git не существует (очевидно, я думаю, было бы глупо для инструмента низкого уровня знать о конкретном DVCS). Там нет упоминания об этом на странице man. Откуда это происходит?

Ответ 1

Это "опция воображаемого различия", используемая для указания читателю, что это не просто результат выполнения команды diff. Например, в git собственный репозиторий git:

$ 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]
+
$ 

Сама команда diff, если вы вызывали ее с одним и тем же именем файла дважды, не показала бы различий. git предположительно создает временные файлы, соответствующие двум различным версиям Documentation/git.txt, и передает их в diff - но имена этих временных файлов не будут полезны. Я думаю, что git diff массирует вывод diff, чтобы сделать его более значимым для читателя. (Это предположение не совсем верно. См. ниже.)

Погружаясь в исходный код git, diff.c содержит строку "diff --git", зашитую в виде строкового литерала:

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

И изучаем историю diff.c самой ранней версии, содержащей эту строку:

$ 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]>
$ 

Предположительно <Pine.LNX...> - это идентификатор сообщения электронной почты в списке рассылки. В любом случае, это сообщение о фиксации проясняет, что diff --git является "воображаемой опцией сравнения".

Это электронное сообщение, на которое ссылается nos в комментарии, является частью обсуждения, которое привело к этому.

ОБНОВЛЕНИЕ: Я размышлял выше, что git diff массирует вывод diff, добавляя эту информацию. Я только что попытался запустить git diff под strace. На самом деле он не вызывает команду diff или любую другую команду. Скорее, весь вывод печатается самим процессом git, и, очевидно, он вычисляет различия внутри. Это поведение также может зависеть от версии git (я использую 2.23.0), доступных команд diff и используемых аргументов.

Я отмечу, что в GNU diff есть опция --label=LABEL, которую можно использовать для таких вещей:

'-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::.

но git diff не использует его, по крайней мере, в одном случае, который я пробовал, и я не вижу ссылки на него в источниках git.

Ответ 2

--git означает, что diff находится в формате git "diff. Он не ссылается и не на команду команды /usr/bin/diff. Вы можете найти список diff format. Другие форматы:

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

Ответ 3

Как упоминал Кит, в GNU diff (проверьте свою версию с diff -v) вы можете использовать патчи в стиле git, используя --label, например так:

один файл из резервной копии

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

или из STDIN

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

Вы можете использовать эти команды в цикле файлов из find и т.д. Там, где одна сторона сравнения не существует, например, новые файлы, сравните с /dev/null.