Сравнение изменений с использованием git diff

Сравнение — это функция, анализирующая два входных набора данных и отображающая различия между ними. git diff представляет собой многоцелевую команду Git, которая инициирует функцию сравнения источников данных Git — коммитов, веток, файлов и т. д. В этом документе описываются типичные варианты вызова git diff и схемы рабочего процесса сравнения. Зачастую вместе с командой git diff используются git status и git log для анализа текущего состояния репозитория Git.

Чтение вывода команды diff

Формат вывода необработанных данных

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

$:> mkdir diff_test_repo
$:> cd diff_test_repo
$:> touch diff_test.txt
$:> echo "this is a git diff test example" > diff_test.txt
$:> git init .
Initialized empty Git repository in /Users/kev/code/test/.git/
$:> git add diff_test.txt
$:> git commit -am"add diff test file"
[main (root-commit) 6f77fc3] add diff test file
1 file changed, 1 insertion(+)
create mode 100644 diff_test.txt

Если выполнить git diff на этом этапе, команда ничего не выведет. Это ожидаемая ситуация, поскольку в репозитории отсутствуют изменения для сравнения. После создания репозитория и добавления файла diff_test.txt можно отредактировать его содержимое и поэкспериментировать с выходными данными команды сравнения.

$:> echo "this is a diff example" > diff_test.txt

При выполнении этой команды содержимое файла diff_test.txt будет изменено. После этого можно просмотреть изменения и проанализировать выходные данные. Теперь при выполнении git diff мы получим следующие выходные данные:

diff --git a/diff_test.txt b/diff_test.txt
index 6b0c6cf..b37e70a 100644
--- a/diff_test.txt
+++ b/diff_test.txt
@@ -1 +1 @@
-this is a git diff test example
+this is a diff example

А теперь подробно рассмотрим выходные данные сравнения.

1. Входные данные сравнения

diff --git a/diff_test.txt b/diff_test.txt

В этой строке отображаются входные данные сравнения. Как видите, для сравнения переданы файлы a/diff_test.txt и b/diff_test.txt.

2. Метаданные

index 6b0c6cf..b37e70a 100644

В этой строке отображаются внутренние метаданные Git. Скорее всего, они вам не понадобятся. Номера в этих выходных данных соответствуют хеш-идентификаторам версий объектов Git.

3. Маркеры изменений

--- a/diff_test.txt
+++ b/diff_test.txt

Эти строки представляют собой легенду обозначений для каждого источника входных данных сравнения. В данном случае изменения из файла a/diff_test.txt помечаются символом ---, а из файла b/diff_test.txt — символом +++.

4. Сравниваемые фрагменты

Остальные выходные данные сравнения — это список сравниваемых фрагментов. При сравнении отображаются только разделы файла, в которых есть изменения. В данном примере имеется только один такой фрагмент, поскольку обрабатывается простой сценарий. Фрагменты имеют собственную ограниченную семантику вывода.

@@ -1 +1 @@
-this is a git diff test example
+this is a diff example

Первая строка — это заголовок фрагмента. К началу каждого фрагмента добавляется заголовок, ограниченный символами @@. Заголовок кратко описывает изменения в файле. В нашем простом примере заголовок -1 +1 означает, что имеются изменения в первой строке. В реальных случаях заголовок может выглядеть так:

@@ -34,6 +34,8 @@

В данном примере заголовка было извлечено 6 строк начиная со строки 34. Кроме того, после строки 34 было добавлено 8 строк.

Остальное содержимое фрагмента сравнения — это недавние изменения. Каждой измененной строке предшествует символ + или -, указывающий на источник входных данных сравнения. Как уже упоминалось, символ - указывает на изменения в файле a/diff_test.txt, а + — на изменения в файле b/diff_test.txt.

Подсветка изменений

1. git diff --color-words

Кроме того, команда git diff имеет специальный режим подсветки изменений с повышенной детализацией: ‐‐color-words. В этом режиме добавленные и удаленные строки отделяются пробелами, а затем выполняется их сравнение.

$:> git diff --color-words
diff --git a/diff_test.txt b/diff_test.txt
index 6b0c6cf..b37e70a 100644
--- a/diff_test.txt
+++ b/diff_test.txt
@@ -1 +1 @@
this is agit difftest example

Теперь в выходных данных отображаются только измененные слова с цветовой подсветкой.

2. git diff-highlight

При клонировании источника Git появляется подкаталог с именем contrib. Он содержит набор связанных с Git инструментов и различные данные, которые пока еще не были включены в ядро Git. В их число входит скрипт Perl под названием diff-highlight. Diff-highlight попарно сопоставляет совпадающие строки выходных данных сравнения и подсвечивает измененные фрагменты внутри слов.

$:> git diff | /your/local/path/to/git-core/contrib/diff-highlight/diff-highlight
diff --git a/diff_test.txt b/diff_test.txt
index 6b0c6cf..b37e70a 100644
--- a/diff_test.txt
+++ b/diff_test.txt
@@ -1 +1 @@
-this is a git diff test example
+this is a diff example

Теперь сравниваемые строки объединены в пары для определения наименьших возможных изменений.

Сравнение двоичных файлов

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

$:> git diff
Binary files a/script.pdf and b/script.pdf differ

В Git есть функция, с помощью которой можно указать команду оболочки для преобразования содержимого двоичных файлов в текст до начала сравнения. Для этого потребуется выполнить небольшую настройку. Для начала необходимо указать фильтр textconv, описывающий процесс преобразования определенного типа двоичного файла в текст. В данном случае используется простой инструмент pdftohtml (доступный в Homebrew), который позволяет преобразовывать файлы PDF в удобный для восприятия формат HTML. Его можно назначить отдельному репозиторию в файле .git/config или глобально в файле ~ /.gitconfig

[diff "pdfconv"]
textconv=pdftohtml -stdout

Затем необходимо связать с фильтром pdfconv один или несколько шаблонов файлов. Для этого необходимо создать файл .gitattributes в корневом каталоге репозитория.

*.pdf diff=pdfconv

После настройки команда git diff сначала обрабатывает двоичный файл с помощью настроенного скрипта конвертера, а затем выполняет сравнение выходных данных конвертера. Этот метод можно использовать для эффективного сравнения любых двоичных файлов, например ZIP, JAR и других архивов. Используя инструмент unzip -l (или аналогичный) вместо pdf2html, можно просмотреть, какие пути были добавлены в коммит или удалены из него по сравнению с другим коммитом. Утилиту exiv2 можно использовать для просмотра изменений метаданных, например размеров изображения. Существуют инструменты для преобразования .odf, .doc и других форматов документов в простой текст. В крайнем случае команда может работать с двоичными файлами, для которых формальных конвертеров не существует.

Сравнение файлов: файл git diff

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

git diff HEAD ./path/to/file

В этом примере выполняется сравнение для файла ./path/to/file. Рабочий каталог сравнивается с разделом проиндексированных файлов и выводятся изменения, которые еще не были проиндексированы. По умолчанию git diff выполняет сравнение с HEAD. Если опустить аргумент HEAD в приведенном выше примере и выполнить команду git diff ./path/to/file, это не повлияет на результат.

git diff --cached ./path/to/file

При вызове git diff с использованием параметра --cached сравниваются проиндексированные изменения и локальный репозиторий. Параметр --cached синонимичен параметру --staged.

Сравнение всех изменений

При вызове git diff без указания пути к файлу выполняется сравнение всех изменений в репозитории. Команды из приведенных выше примеров можно вызвать без аргумента ./path/to/file и получить аналогичные результаты для всех файлов в локальном репозитории.

Изменения после последнего коммита

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

git diff

Сравнение файлов в двух коммитах

Команде git diff можно передать ссылки на коммиты Git для сравнения. Возможные варианты ссылок — HEAD, теги и имена веток. Каждый коммит в Git имеет идентификатор, который можно получить с помощью команды git log. Этот идентификатор коммита тоже можно передать в git diff.

git log --prety=oneline
957fbc92b123030c389bf8b4b874522bdf2db72c add feature
ce489262a1ee34340440e55a0b99ea6918e19e7a rename some classes
6b539f280d8b0ec4874671bae9c6bed80b788006 refactor some code for feature
646e7863348a427e1ed9163a9a96fa759112f102 add some copy to body

$:> git diff 957fbc92b123030c389bf8b4b874522bdf2db72c ce489262a1ee34340440e55a0b99ea6918e19e7a

Сравнение веток

Сравнение двух веток

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

git diff branch1..other-feature-branch

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

git diff branch1...other-feature-branch

Оператор «три точки» инициирует сравнение путем изменения первого параметра ввода branch1. Параметр branch1 преобразуется в ссылку на родительский коммит, общий для двух входных объектов сравнения. Это общий предок ветки branch1 и другой функциональной ветки. Последний параметр ввода остается без изменений — это последний коммит другой функциональной ветки.

Сравнение файлов из двух веток

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

git diff main new_branch ./diff_test.txt

Резюме

На этой странице были рассмотрены процесс сравнения в Git и команда git diff. Мы объяснили, как читать вывод команды git diff и различные виды выходных данных. В примерах было показано, как изменить выходные данные git diff с помощью подсвечивания и использования цветов. Кроме того, были рассмотрены различные стратегии сравнения, например сравнение файлов в разных ветках и конкретных коммитах. Наряду с git diff также использовались команды git log и git checkout.

Готовы изучить Git?

Ознакомьтесь с этим интерактивным обучающим руководством.

Начните прямо сейчас