2010-03-27 6 views
197

Человеческая страница для git-diff довольно длинная и объясняет многие случаи, которые, как представляется, не нужны новичкам. Например:Как читать выходные данные от git diff?

git diff origin/master 
+1

с помощью другого текстового редактора @ ... @ диапазон обозначения для чисел линии стали очевидными. – poseid

ответ

380

Давайте посмотрим на пример передовой дифф из истории мерзавца (в commit 1088261f in git.git repository):

diff --git a/builtin-http-fetch.c b/http-fetch.c 
similarity index 95% 
rename from builtin-http-fetch.c 
rename to http-fetch.c 
index f3e63d7..e8f44ba 100644 
--- a/builtin-http-fetch.c 
+++ b/http-fetch.c 
@@ -1,8 +1,9 @@ 
#include "cache.h" 
#include "walker.h" 

-int cmd_http_fetch(int argc, const char **argv, const char *prefix) 
+int main(int argc, const char **argv) 
{ 
+  const char *prefix; 
     struct walker *walker; 
     int commits_on_stdin = 0; 
     int commits; 
@@ -18,6 +19,8 @@ int cmd_http_fetch(int argc, const char **argv, const char *prefix) 
     int get_verbosely = 0; 
     int get_recover = 0; 

+  prefix = setup_git_directory(); 
+ 
     git_config(git_default_config, NULL); 

     while (arg < argc && argv[arg][0] == '-') { 

Позволяет анализировать этот патч построчно.

  • Первая строка

    diff --git a/builtin-http-fetch.c b/http-fetch.c
    является «мерзавец Diff» заголовка в виде diff --git a/file1 b/file2. Имена файлов a/ и b/ совпадают, если не используется переименование/копирование (как в нашем случае). Значение --git означает, что diff находится в формате «git» diff.

  • Далее представлены одна или несколько линий расширенного заголовка.Первые три

    similarity index 95% 
    rename from builtin-http-fetch.c 
    rename to http-fetch.c
    говорят нам, что файл был переименован из builtin-http-fetch.c в http-fetch.c и что эти два файла идентичны на 95% (что было использовано для обнаружения этого переименования).

    Последняя строка в расширенном заголовке diff, которая является
    index f3e63d7..e8f44ba 100644
    , рассказывает нам о режиме данного файла (100644 означает, что это обычный файл, а не, например, символическая ссылка, и что он не имеет исполняемого разрешающего бита) и об укороченном хэше preimage (версия файла перед данным изменением) и postimage (версия файла после изменения). Эта строка используется git am --3way, чтобы попытаться выполнить трехстороннее слияние, если патч не может применяться сам.

  • Далее идет две строки объединены дифф заголовок

    --- a/builtin-http-fetch.c 
    +++ b/http-fetch.c
    По сравнению с diff -U результате он не имеет из-файла-модификации времени, ни к-файлу-модификации времени после источника (прообразом) и назначения (postimage) имена файлов. Если файл был создан, источник будет /dev/null; если файл был удален, цель равна /dev/null.
    Если установить diff.mnemonicPrefix переменные конфигурации в TRUE, вместо a/ и b/ префиксов в этом заголовке две строки вы можете иметь вместо c/, i/, w/ и o/ как префиксы, соответственно чем сравнивать; см. git-config(1)

  • Далее идут один или несколько кусков различий; каждый кусок показывает одну область, где файлы отличаются. Унифицированные форматы ханков начинаются с строки, как

    @@ -1,8 +1,9 @@
    или
    @@ -18,6 +19,8 @@ int cmd_http_fetch(int argc, const char **argv, ...
    Это формат @@ from-file-range to-file-range @@ [header]. Диапазон from-file находится в форме -<start line>,<number of lines>, а для-file-range - +<start line>,<number of lines>. Как начальная строка, так и количество строк указывают на положение и длину куска в прообразе и постимаже соответственно. Если число строк не показано, это означает, что оно равно 0.

    Необязательный заголовок показывает функцию C, где происходит каждое изменение, если это файл C (например, -p в GNU diff) или эквивалент, если таковые имеются, для других типов файлов.

  • Далее идет описание того, где файлы отличаются. Линии, общие для обоих файлов, начинаются с символа пробела. Линии, которые действительно отличаются между двумя файлами, имеют один из следующих индикаторных символов в левой колонке печати:

    • '+' - Здесь была добавлена ​​строка для первого файла.
    • '-' - Здесь была удалена строка из первого файла.


    Так, например, первый блок

    #include "cache.h" 
    #include "walker.h" 
    
    -int cmd_http_fetch(int argc, const char **argv, const char *prefix) 
    +int main(int argc, const char **argv) 
    { 
    +  const char *prefix; 
         struct walker *walker; 
         int commits_on_stdin = 0; 
         int commits; 
    

    cmd_http_fetch означает, что был заменен main, и что был добавлен const char *prefix; линии.

    Другими словами, перед изменением, соответствующий фрагмент затем файл «встроенные-клиента-fetch.c» выглядел следующим образом:

    #include "cache.h" 
    #include "walker.h" 
    
    int cmd_http_fetch(int argc, const char **argv, const char *prefix) 
    { 
         struct walker *walker; 
         int commits_on_stdin = 0; 
         int commits; 
    

    После изменения этого фрагмента теперь «HTTP-выборки. файл с»выглядит следующим образом, вместо:

    #include "cache.h" 
    #include "walker.h" 
    
    int main(int argc, const char **argv) 
    { 
         const char *prefix; 
         struct walker *walker; 
         int commits_on_stdin = 0; 
         int commits; 
    
  • Там может быть

    \ No newline at end of file
    линия присутствует (не в пример дифф).

Как Donal Fellows said лучше практиковать чтение на примерах посмотреть различие в реальной жизни, где вы знаете, что вы изменили.

Литература:

+9

Хороший пример. –

+5

спасибо. этот пример очень поучителен, легко понять роль различных понятий patch/commit. – poseid

+0

Очень приятно, я не совсем понял, что diff.mnemonicprefix - это то, что искать на странице git config man. –

5

На мой макинтош:

info diff затем выберите: Output formats ->Context ->Unified format ->Detailed Unified:

Или online man diff на гну следуя тому же пути к той же секции:

Файл: diff.info, Узел: Подробный Единый, Следующий: Пример Унифицированный, U p: Унифицированный формат

Подробное описание унифицированного формата ............................................ ...

унифицированный формат вывода начинается с заголовком две строки, которая выглядит так:

--- FROM-FILE FROM-FILE-MODIFICATION-TIME 
+++ TO-FILE TO-FILE-MODIFICATION-TIME 

метка времени выглядит как `2002-02-21 23: 30: +39,942229878 -0800 ', чтобы указать дату, время с дробным секунд и часовой пояс.

Вы можете изменить содержимое заголовка с опцией `--label = LABEL '; см. * Примечание Альтернативные имена ::.

Далее идут один или несколько кусков отличия; каждый кусок показывает одну область , где файлы отличаются. скряга унифицированный формат выглядит следующим образом:

@@ FROM-FILE-RANGE TO-FILE-RANGE @@ 
    LINE-FROM-EITHER-FILE 
    LINE-FROM-EITHER-FILE... 

линии, общие для обоих файлов начинаются с символа пробела. В линии, которые на самом деле различаются между два файлом имеет один из символов индикатора следующих в левой колонке печати :

`+» линии была добавлена ​​здесь к первому файлу.

`- ' Линия была удалена здесь из первого файла.

+1

Обратите внимание, что git не печатает часть «XXX-FILE-MODIFICATION-TIME», так как это не имеет смысла для системы контроля версий. Для сравнения файлов на файловой системе timestams может функционировать как «бедный человек». –

11

Формат вывода по умолчанию (который первоначально поступает из программы, известной как diff, если вы хотите найти дополнительную информацию) известен как «унифицированный diff».Оно содержит по существу 4 различных типов линий:

  • контекста линии, которые начинаются с одного пространства,
  • вставки линий, которые показывают линию, которая была вставлена, которые начинаются с +,
  • удаления линии , которые начинаются с - и
  • линии метаданных, которые описывают более высокие вещи на уровне, как файл, который это говорит о том, какие варианты были использованы для создания различий, изменилось ли файл его разрешения и т.д.

Я советую вам практиковать чтение разностей между двумя версиями файла, где вы точно знаете, что изменили. Таким образом вы узнаете, что происходит, когда вы это видите.

+4

+1: предложение о практике очень хорошее - возможно, намного быстрее, чем пытаться навязчиво читать документацию. – Cascabel

3

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

Первая строка - это что-то вроде diff --git a/path/to/file b/path/to/file - очевидно, это просто говорит вам, в каком файле находится этот раздел разности. Если вы установите логическую конфигурационную переменную diff.mnemonic prefix, то a и b будут изменены на более описательные буквы, такие как c и w (commit and work tree).

Далее появятся строки «линии режима», в которых вам даются описания любых изменений, которые не связаны с изменением содержимого файла. Это включает в себя новые/удаленные файлы, переименованные/скопированные файлы и изменения прав доступа.

Наконец-то есть линия, такая как index 789bd4..0afb621 100644. Вы, вероятно, никогда не будете заботиться об этом, но эти шестизначные шестнадцатеричные числа являются сокращенными хэшами SHA1 старого и нового blob для этого файла (блоб - это git-объект, хранящий необработанные данные, такие как содержимое файла). И, конечно же, 100644 - это режим файла - последние три цифры - это, очевидно, разрешения; первые три дают дополнительную информацию о метаданных файла (SO post describing that).

После этого вы подключаетесь к стандарту унифицированного выходного сигнала (как и классический diff -U). Он разбит на ханки - кусок - это раздел файла, содержащий изменения и их контекст. Каждому столбцу предшествует пара строк --- и +++, обозначающая файл, о котором идет речь, тогда фактический diff является (по умолчанию) тремя линиями контекста с обеих сторон линий - и +, показывающими удаленные/добавленные строки.

+0

++ для строки 'index'. Подтверждено с помощью 'git hash-object./File' –

15

Вот простой пример.

diff --git a/file b/file 
index 10ff2df..84d4fa2 100644 
--- a/file 
+++ b/file 
@@ -1,5 +1,5 @@ 
line1 
line2 
-this line will be deleted 
line4 
line5 
+this line is added 

Вот объяснение (подробности см here).

  • --git не команда, это означает, что это версия мерзавец из Diff (не Unix)
  • a/ b/ являются каталоги, они не являются реальными. это просто удобство, когда мы имеем дело с тем же файлом (в моем случае/находится в индексе и б/находится в рабочем каталоге)
  • 10ff2df..84d4fa2 являются BLOB идентификаторы этих 2 файлов
  • 100644 является «биты режима» что это обычный файл (не исполняемый, а не символический)
  • --- a/file +++ b/file минус-знаки показывают строки в версии a /, но отсутствуют в b/версии; и плюс знаки показывают строки, отсутствующие в /, но присутствующие в b/(в моем случае --- означает, что удаленные строки и +++ означают добавленные строки в b /, и этот файл в рабочем каталоге)
  • @@ -1,5 +1,5 @@ для того, чтобы понимайте это, лучше работать с большим файлом; если у вас есть два изменения в разных местах, вы получите две записи, такие как @@ -1,5 +1,5 @@; Предположим, у вас есть файл line1 ... line100 и удален LINE10 и добавить новый line100 - вы получите:
@@ -7,7 +7,6 @@ line6 
line7 
line8 
line9 
-this line10 to be deleted 
line11 
line12 
line13 
@@ -98,3 +97,4 @@ line97 
line98 
line99 
line100 
+this is new line100 
+2

Это действительно очень краткий ответ, сравниваемый (и тот, который я предпочитаю) с выбранный ответ – dkjain

+0

Найти этот ответ очень полезно. – kta

39

@@ -1,2 +3,4 @@ часть diff

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

Формат в основном тот же 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 
    2 
    3 
    4 
    5 
    6 
    

    - означает "старый", как мы обычно вызовите его как diff -u old new.

  • +1,4 говорит, что этот фрагмент соответствует строкам с 1 по 4 второго файла.

    + означает «новый».

    У нас только 4 линии вместо 6, потому что были удалены 2 линии! Новый ломоть просто:

    1 
    4 
    5 
    6 
    

@@ -11,6 +9,4 @@ для второй ломоть аналогично:

  • на старом файле, у нас есть 6 строк, начиная со строки 11 старого файла:

    11 
    12 
    13 
    14 
    15 
    16 
    
  • на новый файл, у нас есть 4 строки, начиная со строки 9 нового файла:

    11 
    12 
    13 
    16 
    

    Обратите внимание, что линия 11 является девятой строке нового файла, потому что мы уже удалили 2 строки на предыдущей ломоть: 2 и 3.

Заголовок Hunk

В зависимости от вашей версии и конфигурации git вы также можете получить строку кода рядом с линией @@, например func1() { в:

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

Это также может быть получен с -p флагом простого diff.

Пример: старый файл:

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 ,

Эта удивительная функция часто сообщает точно, к какой функции или классу относится каждый кусок, что очень полезно для интерпретации diff.

Как алгоритм выбора заголовка работает точно обсуждается на: Where does the excerpt in the git diff hunk header come from?

+5

Это для тех, кто еще не совсем понял.В '@@ -1,6 +1,4 @@' PLS не читать '-1' как' минус один' или '+ 1', а' plus one' вместо этого читать это как «строка с 1 по 6» в старый (первый) файл. Обратите внимание, здесь '- подразумевается« старый », а не минус. Кстати, спасибо за разъяснение ... хаос. – dkjain

+0

из этого @@ -1,8 +1,9 @@ можно интерпретировать то, что на самом деле произошло. например, 1) добавлена ​​одна строка 2) одна строка изменяется и добавляется одна строка и так далее. Или это по-другому, так как должен быть способ получить их как git diff. Соответствие определяет, какие строки были изменены в коде. Пожалуйста, помогите мне, поскольку мне действительно нужно разобраться –

Смежные вопросы