Человеческая страница для git-diff
довольно длинная и объясняет многие случаи, которые, как представляется, не нужны новичкам. Например:Как читать выходные данные от git diff?
git diff origin/master
Человеческая страница для git-diff
довольно длинная и объясняет многие случаи, которые, как представляется, не нужны новичкам. Например:Как читать выходные данные от git diff?
git diff origin/master
Давайте посмотрим на пример передовой дифф из истории мерзавца (в 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% (что было использовано для обнаружения этого переименования). 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 лучше практиковать чтение на примерах посмотреть различие в реальной жизни, где вы знаете, что вы изменили.
Литература:
Хороший пример. –
спасибо. этот пример очень поучителен, легко понять роль различных понятий patch/commit. – poseid
Очень приятно, я не совсем понял, что diff.mnemonicprefix - это то, что искать на странице git config man. –
На мой макинтош:
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...
линии, общие для обоих файлов начинаются с символа пробела. В линии, которые на самом деле различаются между два файлом имеет один из символов индикатора следующих в левой колонке печати :
`+» линии была добавлена здесь к первому файлу.
`- ' Линия была удалена здесь из первого файла.
Обратите внимание, что git не печатает часть «XXX-FILE-MODIFICATION-TIME», так как это не имеет смысла для системы контроля версий. Для сравнения файлов на файловой системе timestams может функционировать как «бедный человек». –
Формат вывода по умолчанию (который первоначально поступает из программы, известной как diff
, если вы хотите найти дополнительную информацию) известен как «унифицированный diff».Оно содержит по существу 4 различных типов линий:
+
,-
иЯ советую вам практиковать чтение разностей между двумя версиями файла, где вы точно знаете, что изменили. Таким образом вы узнаете, что происходит, когда вы это видите.
+1: предложение о практике очень хорошее - возможно, намного быстрее, чем пытаться навязчиво читать документацию. – Cascabel
Непонятно из вашего вопроса, какая часть различий вы находите запутанной: фактический 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 является (по умолчанию) тремя линиями контекста с обеих сторон линий -
и +
, показывающими удаленные/добавленные строки.
++ для строки 'index'. Подтверждено с помощью 'git hash-object./File' –
Вот простой пример.
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
@@ -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?
Это для тех, кто еще не совсем понял.В '@@ -1,6 +1,4 @@' PLS не читать '-1' как' минус один' или '+ 1', а' plus one' вместо этого читать это как «строка с 1 по 6» в старый (первый) файл. Обратите внимание, здесь '- подразумевается« старый », а не минус. Кстати, спасибо за разъяснение ... хаос. – dkjain
из этого @@ -1,8 +1,9 @@ можно интерпретировать то, что на самом деле произошло. например, 1) добавлена одна строка 2) одна строка изменяется и добавляется одна строка и так далее. Или это по-другому, так как должен быть способ получить их как git diff. Соответствие определяет, какие строки были изменены в коде. Пожалуйста, помогите мне, поскольку мне действительно нужно разобраться –
с помощью другого текстового редактора @ ... @ диапазон обозначения для чисел линии стали очевидными. – poseid