Справочная страница для git-diff
довольно длинная, и объясняет много случаев, которые не кажутся необходимыми для начинающего. Например:
git diff origin/master
Справочная страница для git-diff
довольно длинная, и объясняет много случаев, которые не кажутся необходимыми для начинающего. Например:
git diff origin/master
Ответы:
Давайте рассмотрим пример расширенного diff из истории git (в коммите 1088261f в репозитории git.git ):
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.cb / http-fetch.cэто заголовок "git diff" в форме
diff --git a/file1 b/file2
. a/
И b/
имена файлов являются одинаковыми , если переименовать / копировать не участвует (как в нашем случае). Это --git
означает, что diff находится в формате «git» diff.Далее идет одна или несколько расширенных строк заголовка. Первые три
индекс сходства 95% переименовать из встроенного-http-fetch.c переименовать в http-fetch.cскажите нам, что файл был переименован из
builtin-http-fetch.c
в http-fetch.c
и что эти два файла идентичны на 95% (что использовалось для обнаружения этого переименования). индекс f3e63d7..e8f44ba 100644расскажите нам о режиме данного файла (это
100644
означает, что это обычный файл, а не, например, символическая ссылка, и что он не имеет исполняемого бита разрешения), и о сокращенном хеше preimage (версия файла перед данным изменением) и postimage ( версия файла после изменения). Эта строка используется, git am --3way
чтобы попытаться выполнить трехстороннее слияние, если патч не может быть применен сам по себе.Далее идет двухстрочный унифицированный заголовок diff
--- a / builtin-http-fetch.c +++ b / http-fetch.cПо сравнению с
diff -U
результатом он не имеет ни времени изменения файла, ни времени изменения файла после исходного (preimage) и конечного (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]
. Диапазон от файла находится в форме -<start line>,<number of lines>
, и диапазон файла - +<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;
строка была добавлена.
Другими словами, перед изменением соответствующий фрагмент файла 'builtin-http-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-fetch.c выглядит следующим образом:
#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;
Там может быть
\ Нет новой строки в конце файластрока присутствует (это не в примере diff).
Как сказал Донал Феллоуз , лучше всего практиковаться в чтении различий на реальных примерах, где вы знаете, что вы изменили.
Ссылки:
git blame -C -C
, вот как это работает; это Git дизайнерское решение. Формат git diff просто показывает индекс сходства (или различий) для пользователя.
[header]
ближайший предшествующий, как с началом функции, которая предшествует ломоть. В большинстве случаев эта строка содержит имя функции, в которой находится фрагмент diff. Это настраивается с помощью diff
атрибута gitattribute для драйвера diff и драйвера diff, включая xfuncname
переменную конфигурации.
@@ -1,2 +3,4 @@
часть различий
Эта часть заняла у меня некоторое время, чтобы понять, поэтому я создал минимальный пример.
Формат в основном такой же, как diff -u
унифицированный diff.
Например:
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 по 6.
1
2
3
4
5
6
-
означает «старый», как мы обычно называем это diff -u old new
.
+1,4
означает, что этот фрагмент второго файла начинается со строки 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
является 9-й строкой нового файла, потому что мы уже удалили 2 строки в предыдущем блоке: 2 и 3.
Hunk header
В зависимости от вашей версии и конфигурации git, вы также можете получить строку кода рядом со @@
строкой, например, func1() {
в:
@@ -4,7 +4,6 @@ func1() {
Это также можно получить с -p
флагом равнины diff
.
Пример: старый файл:
func1() {
1;
2;
3;
4;
5;
6;
7;
8;
9;
}
Если мы удалим строку 6
, diff покажет:
@@ -4,7 +4,6 @@ func1() {
3;
4;
5;
- 6;
7;
8;
9;
Обратите внимание, что это неправильная строка func1
: пропущенные строки 1
и 2
.
Эта удивительная особенность часто говорит точно, к какой функции или классу принадлежит каждый кусок, что очень полезно для интерпретации различий.
Как именно работает алгоритм выбора заголовка, обсуждается здесь: Откуда взята выдержка из заголовка git diff hunk?
@@ -1,6 +1,4 @@
pls не читайте -1
как minus one
или +1
как plus one
вместо этого читайте это как line 1 to 6
в старом (первом) файле. Обратите внимание, здесь - implies "old"
не минус. Кстати, спасибо за разъяснения ... хааш.
+1,4
говорит, что этот фрагмент соответствует строки 1-4 второго файла ». Это связано с тем, что +1,4
могут ссылаться на не зависящие от контекста строки. Скорее, на +1,4
самом деле « » означает, что « в этой« версии »файла есть 4
строки (т.е. строки контекста) . Важно понимать значение +
, -
и <whitespace>
в начале этих строк, поскольку это относится к интерпретации фрагментов. Более наглядный пример: youtube.com/watch?v=1tqMjJeyKpw
Вот простой пример.
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
Вот объяснение (подробности см. Здесь ).
--git
это не команда, это означает, что это git-версия diff (не unix)a/ b/
каталоги, они не настоящие. это просто удобство, когда мы имеем дело с одним и тем же файлом (в моем случае 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
644
) должны быть прочитаны в восьмеричном виде (значения: 1, 2, 4 соответственно разрешения eXecute, Write и Read) и соответствуют в этом порядке Владельцу (Пользователь), затем Группе, затем Другим разрешениям. Таким образом, короче говоря, 644
это означает, что если оно написано символически u=rw,og=r
, оно доступно для чтения всем, но доступно только для владельца. Другие цифры слева кодируют другую информацию, например, если это символическая ссылка и т. Д. Значения можно увидеть github.com/git/git/blob/… , первая 1 в этой позиции - «обычный файл».
Формат вывода по умолчанию (который изначально исходит из программы, известной как « diff
поиск дополнительной информации») известен как «унифицированный diff». Он содержит по существу 4 различных типа линий:
+
,-
, иЯ советую вам практиковать чтение различий между двумя версиями файла, где вы точно знаете, что изменили. Таким образом, вы узнаете, что происходит, когда увидите это.
На моем Mac:
info diff
затем выберите: Output formats
-> Context
-> Unified format
-> Detailed Unified
:
Или в режиме онлайн, введите diff для gnu по тому же пути:
Файл: diff.info, узел: подробный унифицированный, следующий: пример унифицированный, вверх: унифицированный формат
Подробное описание единого формата ......................................
Унифицированный формат вывода начинается с двухстрочного заголовка, который выглядит следующим образом:
--- FROM-FILE FROM-FILE-MODIFICATION-TIME +++ TO-FILE TO-FILE-MODIFICATION-TIME
Отметка времени выглядит как `2002-02-21 23: 30: 39.942229878 -0800 ', чтобы указать дату, время с долями секунды и часовой пояс.
Вы можете изменить содержимое заголовка с помощью опции --lala = LABEL; см. * Примечание к альтернативным именам ::.
Далее следуют один или несколько кусков различий; каждый блок показывает одну область, где файлы отличаются. Единицы унифицированного формата выглядят так:
@@ FROM-FILE-RANGE TO-FILE-RANGE @@ LINE-FROM-EITHER-FILE LINE-FROM-EITHER-FILE...
Общие для обоих файлов строки начинаются с пробела. Строки, которые на самом деле различаются между двумя файлами, имеют один из следующих символов индикатора в левом столбце печати:
`+ 'Здесь добавлена строка в первый файл.
`- 'Здесь удалена строка из первого файла.
Из вашего вопроса неясно, какую часть различий вы находите непонятной: фактическую разность или дополнительную информацию заголовка, которую печатает git. На всякий случай вот краткий обзор шапки.
Первая строка выглядит примерно так diff --git a/path/to/file b/path/to/file
- очевидно, она просто говорит вам, для какого файла предназначен этот раздел diff. Если вы установите логическую переменную конфигурации diff.mnemonic prefix
, то a
и b
будет изменено на более описательные буквы, такие как c
и w
(коммит и дерево работ).
Далее, есть «строки режима» - строки, дающие вам описание любых изменений, которые не связаны с изменением содержимого файла. Это включает новые / удаленные файлы, переименованные / скопированные файлы и изменения разрешений.
Наконец, есть такая строка index 789bd4..0afb621 100644
. Вы, вероятно, никогда об этом не позаботитесь, но эти шестизначные шестнадцатеричные числа - это сокращенные SHA1-хэши старых и новых больших двоичных объектов для этого файла (большой двоичный объект - это git-объект, хранящий необработанные данные, например содержимое файла). И, конечно же, режим 100644
файла - последние три цифры, очевидно, являются разрешениями; первые три дают дополнительную информацию о метаданных файла (так описывает сообщение ).
После этого вы переходите к стандартному унифицированному выводу различий (как в классическом diff -U
). Он разделен на фрагменты - блок - это раздел файла, содержащий изменения и их контекст. Каждый ломоть предшествует парой ---
и +++
линий , обозначающего файл в вопросе, то фактический дифференциал есть (по умолчанию) трех строк контекста по обе стороны от -
и +
линий , показывающих удаленные / добавлены линии.
index
строки. Подтвержденоgit hash-object ./file