Git сравнить 2 файла
Перевод второй части статьи «How to Use Git and Git Workflows – a Practical Guide».
В первой части статьи мы рассмотрели установку Git и настройку аккаунта на GitHub, создание нового репозитория на GitHub, клонирование репозитория, ветвление. Также мы научились просматривать текущее состояние проекта и сделали свой первый коммит.
В этой части мы рассмотрим:
Сравнение файлов из двух веток
Чтобы сравнить конкретный файл в разных ветках, передайте команде git diff путь к файлу в качестве третьего аргумента.
Время похвалить себя
Остановитесь на мгновение и похвалите себя за приложенные умственные усилия. Вы уже научились разбираться в выводе команды diff. Теперь, зная основы, можно легко изучить еще несколько команд…
От редакции Techrocks. Возможно, вас также заинтересует статья «Команда diff в Linux: сравниваем два файла».
Comparing files between two different commits
git diff can be passed Git refs to commits to diff. Some example refs are, HEAD , tags, and branch names. Every commit in Git has a commit ID which you can get when you execute GIT LOG . You can also pass this commit ID to git diff .
2. git diff-highlight
При клонировании источника Git появляется подкаталог с именем contrib. Он содержит набор связанных с Git инструментов и различные данные, которые пока еще не были включены в ядро Git. В их число входит скрипт Perl под названием diff-highlight. Diff-highlight попарно сопоставляет совпадающие строки выходных данных сравнения и подсвечивает измененные фрагменты внутри слов.
Теперь сравниваемые строки объединены в пары для определения наименьших возможных изменений.
Comparing branches
Как вносить изменения в стейджинг
Чтобы показать всю пользу стейджинга, давайте внесем в него наши изменения при помощи команды git add :
Теперь эти изменения готовы к коммиту. Но прежде чем сделать коммит, давайте изменим кое-что в файле chapter-1.txt.
Я полностью заменю содержимое этого файла новым текстом.
Примечание. Я использую оператор перенаправления > , а не >> . Первый заменяет содержимое файла новым содержимым, а второй добавляет текст в конец существующего файла.
В выводе git status мы видим, что у нас есть и подготовленные, и неподготовленные изменения («Changes to be committed» и «Changes not staged for commit»).
Хотя в самом файле содержится один вариант текста, Git отслеживает для нас оба изменения. Даже несмотря на то, что это изменения одних и тех же строк!
Но приведенный выше вывод команды не дает нам информации о том, что это были за изменения. Мы знаем лишь об их существовании.
Чтобы просмотреть эти изменения, давайте сначала воспользуемся командной строкой (сам я никогда не применяю ее с этой целью), а затем используем GUI (что куда удобнее).
1. git diff --color-words
Кроме того, команда git diff имеет специальный режим подсветки изменений с повышенной детализацией: ‐‐color-words . В этом режиме добавленные и удаленные строки отделяются пробелами, а затем выполняется их сравнение.
Теперь в выходных данных отображаются только измененные слова с цветовой подсветкой.
Резюме
На этой странице были рассмотрены процесс сравнения в Git и команда git diff . Мы объяснили, как читать вывод команды git diff и различные виды выходных данных. В примерах было показано, как изменить выходные данные git diff с помощью подсвечивания и использования цветов. Кроме того, были рассмотрены различные стратегии сравнения, например сравнение файлов в разных ветках и конкретных коммитах. Наряду с git diff также использовались команды git log и git checkout .
Для вывода изменений в файлах по сравнению с последним коммитом, используется git diff без параметров:
Команда выводит изменения в файлах, которые еще не были добавлены в индекс. Сравнение происходит с последним коммитом.
Raw output format
The following examples will be executed in a simple repo. The repo is created with the commands below:
If we execute git diff at this point, there will be no output. This is expected behavior as there are no changes in the repo to diff. Once the repo is created and we've added the diff_test.txt file, we can change the contents of the file to start experimenting with diff output.
Executing this command will change the content of the diff_test.txt file. Once modified, we can view a diff and analyze the output. Now executing git diff will produce the following output:
Let us now examine a more detailed breakdown of the diff output.
Сравнение коммитов
Команда git diff позволяет сравнивать два различных коммита. Сначала нужно определить хеш (ID) коммитов, которые требуется сравнивать. Можно воспользоваться командой git log, чтобы вывести список коммитов и их идентификаторы:
Теперь сравним два коммита. Для этого в качестве первого аргумента команде git diff указывается хеш первого коммита, а вторым аргументом хеш второго коммита, например:
Сравнение файлов: файл git diff
В команде git diff можно указать явный путь к файлу. Если в git diff указан путь к файлу, выполняется сравнение этого файла. Более подробно этот процесс показан на примерах ниже.
В этом примере выполняется сравнение для файла ./path/to/file . Рабочий каталог сравнивается с разделом проиндексированных файлов и выводятся изменения, которые еще не были проиндексированы. По умолчанию git diff выполняет сравнение с HEAD . Если опустить аргумент HEAD в приведенном выше примере и выполнить команду git diff ./path/to/file , это не повлияет на результат.
При вызове git diff с использованием параметра --cached сравниваются проиндексированные изменения и локальный репозиторий. Параметр --cached синонимичен параметру --staged .
Comparing all changes
Invoking git diff without a file path will compare changes across the entire repository. The above, file specific examples, can be invoked without the ./path/to/file argument and have the same output results across all files in the local repo.
Comparing two branches
Branches are compared like all other ref inputs to git diff
This example introduces the dot operator. The two dots in this example indicate the diff input is the tips of both branches. The same effect happens if the dots are omitted and a space is used between the branches. Additionally, there is a three dot operator:
The three dot operator initiates the diff by changing the first input parameter branch1 . It changes branch1 into a ref of the shared common ancestor commit between the two diff inputs, the shared ancestor of branch1 and other-feature-branch. The last parameter input parameter remains unchanged as the tip of other-feature-branch.
Как запушить коммит на GitHub
У нас есть новый коммит на нашей локальной машине. Теперь нам нужно обновить наш «источник истины» — удаленный origin -репозиторий (GitHub).
В настоящее время локально мы находимся в ветке main . Нам нужно сообщить GitHub-у, чтобы он обновил собственную ветку main этим новым коммитом.
Для этого используется команда git push (push — «толкать, пихать»). Мы можем указать, куда именно мы хотим запушить коммит и в какую конкретно ветку.
Здесь мы запушили изменения в origin (GitHub), в ветку main .
Вывод команды сообщает нам об операциях с файлами, которые пришлось совершить Git, а последняя строка говорит о том, какие коммиты были запушены и куда:
Мы видим, что мы запушили нашу ветку main в ветку main на GitHub.
Если мы посмотрим лог проекта ( git log ), мы заметим, что теперь ветки main и в локальном репозитории, и в origin нацелены на один и тот же коммит.
В общем, в origin (GitHub) в ветке main ( origin/main ) последним коммитом в истории теперь выступает наш коммит.
Если бы мы работали совместно с другими людьми, они теперь могли бы вытащить последние изменения из GitHub-репозитория на свои машины и тоже начать редактировать Главу 1.
Формат вывода необработанных данных
Следующие примеры будут выполнены в простом репозитории. Репозиторий создается с помощью перечисленных ниже команд:
Если выполнить git diff на этом этапе, команда ничего не выведет. Это ожидаемая ситуация, поскольку в репозитории отсутствуют изменения для сравнения. После создания репозитория и добавления файла diff_test.txt можно отредактировать его содержимое и поэкспериментировать с выходными данными команды сравнения.
При выполнении этой команды содержимое файла diff_test.txt будет изменено. После этого можно просмотреть изменения и проанализировать выходные данные. Теперь при выполнении git diff мы получим следующие выходные данные:
А теперь подробно рассмотрим выходные данные сравнения.
В этой строке отображаются входные данные сравнения. Как видите, для сравнения переданы файлы a/diff_test.txt и b/diff_test.txt .
Сравнение с последним коммитом, включая файлы в индексе
Если вы изменили какие-нибудь файлы в вашем рабочем каталоге и добавили один или несколько из них в индекс (с помощью git add ), то команда git diff не покажет изменения в этих файлах. Чтобы показать изменения в файлах, включая файлы, добавленные в индекс, используется ключ --cached :
Изменения после последнего коммита
По умолчанию команда git diff выводит все неподтвержденные изменения, внесенные после последнего коммита.
Сравнение двух веток
Для вывода всех изменений между концами двух веток, необходимо для git diff указать имена веток:
2. Метаданные
В этой строке отображаются внутренние метаданные Git. Скорее всего, они вам не понадобятся. Номера в этих выходных данных соответствуют хеш-идентификаторам версий объектов Git.
Сравнение веток
Как просматривать разницу между изменениями в Git
Чтобы увидеть изменения, нам нужно просмотреть в Git diff.
diff (сокр. от difference, «разница») — это разница между двумя наборами изменений. Это может быть разница между подготовленными и неподготовленными изменениями или же разница между коммитами.
Чтобы посмотреть diff в командной строке, используется команда git diff .
Мы рассмотрим этот маленький пример чисто для полноты картины. Но нас интересует эффективная работа с Git. А когда ваши изменения приобретают достойный объем и разбросаны по множеству файлов, пользоваться командной строкой для их просмотра становится неудобно.
Мой терминал пытается расцвечивать результат для улучшения читаемости. В выводе команды мы видим название файла, который изменился (chapter-1.txt), а под ним — собственно изменения. Давайте обратим внимание на следующие строки:
Строки, начинающиеся со знака минус ( - ), — это строки, которые мы полностью удалили. Строки, начинающиеся со знака плюс ( + ) — те, которые мы добавили.
Когда у вас много файлов и много изменений в каждом, этот вывод быстро становится неудобочитаемым. Есть лучший способ просматривать изменения — при помощи графического интерфейса. Моей карьере уже почти десять лет, но я все равно для просмотра diff-ов пользуюсь простой программой с GUI.
Программа, которой пользуюсь я, называется GitX. Она давно вышла в тираж и уже даже не поддерживается. Но для просмотра diff-ов годится.
Я не то чтобы рекомендовал вам именно эту программу, но она бесплатная, так что можете попробовать. Еще есть десктопный клиент для GitHub. Сам я никогда им не пользовался, но это, вероятно, хороший вариант.
Итак, после этого маленького отступления, давайте посмотрим, как выглядит diff в моем инструменте.
Для начала, с правой стороны, в подготовленных изменениях мы видим наше вставленное второе предложение:
Подготовленные изменения в GitX
В неподготовленных изменениях с левой стороны мы видим полное удаление двух строк и добавление новой строки:
Неподготовленные изменения в GitX
Это соответствует тем командам, которые мы выполняли.
При помощи программы с графическим интерфейсом разобраться в изменениях куда проще. Эта программа также позволяет быстро переключаться между подготовленными и неподготовленными файлами, просто перетаскивая их. Я даже могу вернуть из стейджинга отдельные строки в файле.
Использование командной строки в данном случае не дает никаких дополнительных преимуществ, но вы можете пользоваться тем инструментом, который вам больше нравится.
Итак, мы рассмотрели, как работает стейджинг и Git diff. Теперь давайте сбросим наши неподготовленные изменения, чтобы вернуться и закоммитить наше первое изменение.
Последний вывод git status , собственно, подсказывал нам, что мы можем это сделать при помощи команды git restore . Мы можем передать этой команде путь к файлу или поставить точку, чтобы «захватить» всю директорию.
Если мы проверим статус еще раз, мы увидим, что вернулись к нашим подготовленным изменениям и готовы к коммиту.
Примечание. Git позволяет коммитить только те изменения, которые находятся в стейджинге (т. е. подготовленные). Поэтому мы могли бы оставить неподготовленные изменения в нашей рабочей директории и это никак не помешало бы процедуре коммита.
Но в таком случае нам было бы менее удобно работать с изменениями в будущем, так что имело смысл просто сбросить ненужное, чтобы рабочая директория была в хорошей форме.
Проверяем статус проекта еще раз и видим, что наша ветка на 1 коммит опережает origin/main :
Давайте теперь запушим изменения:
Сравнение всех изменений
При вызове git diff без указания пути к файлу выполняется сравнение всех изменений в репозитории. Команды из приведенных выше примеров можно вызвать без аргумента ./path/to/file и получить аналогичные результаты для всех файлов в локальном репозитории.
Совместная работа в Git
Пока мы рассматривали простейший случай: работу одного человека в одной ветке.
Но обычно над проектами работают по нескольку человек, и веток у них может быть много. И тут проявляется настоящая мощь Git: эта система делает возможным сотрудничество и отслеживание изменений во времени.
Пока давайте продолжим работать так, как будто мы — единственный человек в проекте, но немного подгоним наш рабочий процесс, чтобы подготовиться к изменению ситуации.
В целом, хорошим тоном считается НЕ работать напрямую в ветке main .
Главная ветка призвана быть «источником истины» для проекта, и изменения, вносимые в нее, должны тщательно проверяться. Любое изменение в origin/main становится источником истины для любого человека, работающего над этим проектом, поэтому все изменения вносятся обдуманно и после код-ревью.
Вместо того чтобы работать непосредственно в main , давайте сделаем ответвление и создадим собственную ветку для того функционала, над которым работаем (feature branch). Все внесенные изменения мы потом сольем (смержим, merge ) обратно в main.
Многовато терминологии. Давайте будем продвигаться постепенно, разбирая каждый шаг.
Comparing files from two branches
To compare a specific file across branches, pass in the path of the file as the third argument to git diff
Подсветка изменений
Сравнивать только изменения в файлах (игнорировать новые и удаленные файлы)
Чтобы исключить из сравнения новые и удаленные файлы, можно воспользоваться опцией --diff-filter , которая позволяет выбирать какие именно изменения (файлы) нужно сравнивать.
Чтобы выполнить сравнение только изменений внутри файлов (игнорируя новые, удаленные, переименованные файлы) используется ключ Modified (M) — --diff-filter=M :
Бывает, работаешь с Git и вдруг задумываешься: а те ли изменения внес в стейджинг? Или, бывает, хочешь посмотреть, чем изменения, которые собираешься закоммитить, отличаются от последнего коммита. Или возникает необходимость сравнить две ветки, два коммита или файла.
Все это распространенные задачи при работе с системой контроля версий. К счастью, все они решаются. А поможет в этом команда git diff.
Давайте разберем работу этой команды на простом примере. Тема несложная, просто читайте по порядку.
Заключение
Надеюсь, эта статья поможет вам сделать следующий коммит более точно и аккуратно. При работе с Git важен настрой. Действуйте уверенно, и научитесь многому на собственных ошибках.
3. Markers for changes
These lines are a legend that assigns symbols to each diff input source. In this case, changes from a/diff_test.txt are marked with a --- and the changes from b/diff_test.txt are marked with the +++ symbol.
Сравнение двух веток
Ветки сравниваются с помощью команды git diff точно так же, как любые другие входные ссылки.
В этом примере демонстрируется оператор точка. Две точки показывают, что сравниваются последние коммиты двух веток. Тот же результат можно получить, если опустить точки и поставить пробел между именами веток. Кроме того, можно использовать трехточечный оператор:
Оператор «три точки» инициирует сравнение путем изменения первого параметра ввода branch1 . Параметр branch1 преобразуется в ссылку на родительский коммит, общий для двух входных объектов сравнения. Это общий предок ветки branch1 и другой функциональной ветки. Последний параметр ввода остается без изменений — это последний коммит другой функциональной ветки.
Ветки отдельных функций в Git
Для начала давайте сделаем ответвление main и создадим отдельную ветку для нашей функции.
Делая ответвление ветки, вы создаете копию этой ветки в ее состоянии на текущий момент. После этого вы можете вносить любые изменения в свою ветку, и это не отразится на исходной.
Чтобы это проверить, давайте создадим новую ветку chapter-2. Для этого мы используем команду git checkout с флагом -b и указываем имя новой ветки:
Обратите внимание, что в строке предложения терминал теперь показывает название новой ветки, chapter-2. Изменения, которые мы внесем в chapter-2, никак не заденут main . У нас по сути появилась новая песочница, где мы можем менять что угодно, не рискуя навредить main.
«Под капотом» здесь происходят любопытные вещи, но для целей этого руководства нам нужно лишь знать, что в Git «checkout» означает «сделай так, чтобы мой локальный проект выглядел в точности так же, как весь проект выглядел в определенный момент». Можете считать, что ветка — указатель, указывающий на определенный момент в Git-истории.
При этом происходит много всего другого, но пока вам хватит и этого определения.
Итак, у нас есть новая ветка и пока что она идентична main (мы же еще не вносили никаких изменений).
Теперь давайте повторим то, что мы уже делали прежде. Создадим новый файл chapter-2.txt, поместим в него кое-какой контент и закоммитим:
Тут ничего нового, все то же, что и с Главой 1.
Теперь у нас в ветке chapter-2 есть новый коммит. Давайте посмотрим, как выглядит лог проекта.
В логе мы видим, что последний коммит показывается сверху, а HEAD опять отличается от origin . И это естественно, ведь наших локальных изменений еще нет на GitHub.
Теперь нам нужно вставить наши новые изменения в ветку main . Этим мы займемся в следующей части.
Diffing is a function that takes two input data sets and outputs the changes between them. git diff is a multi-use Git command that when executed runs a diff function on Git data sources. These data sources can be commits, branches, files and more. This document will discuss common invocations of git diff and diffing work flow patterns. The git diff command is often used along with git status and git log to analyze the current state of a Git repo.
Summary
This page disscused the Git diffing process and the git diff command. We discussed how to read git diff output and the various data included in the output. Examples were provided on how to alter the git diff output with highlighting and colors. We discussed different diffing strategies such as how to diff files in branches and specific commits. In addition to the git diff command, we also used git log and git checkout .
Сравнение — это функция, анализирующая два входных набора данных и отображающая различия между ними. git diff представляет собой многоцелевую команду Git, которая инициирует функцию сравнения источников данных Git — коммитов, веток, файлов и т. д. В этом документе описываются типичные варианты вызова git diff и схемы рабочего процесса сравнения. Зачастую вместе с командой git diff используются git status и git log для анализа текущего состояния репозитория Git.
Diffing binary files
In addition to the text file utilities we have thus far demonstrated, git diff can be run on binary files. Unfortunately, the default output is not very helpful.
Git does have a feature that allows you to specify a shell command to transform the content of your binary files into text prior to performing the diff. It does require a little set up though. First, you need to specify a textconv filter describing how to convert a certain type of binary to text. We're using a simple utility called pdftohtml (available via homebrew) to convert my PDFs into human readable HTML. You can set this up for a single repository by editing your .git/config file, or globally by editing ~ /.gitconfig
Then all you need to do is associate one or more file patterns with our pdfconv filter. You can do this by creating a .gitattributes file in the root of your repository.
Once configured, git diff will first run the binary file through the configured converter script and diff the converter output. The same technique can be applied to get useful diffs from all sorts of binary files, for example: zips, jars and other archives: using unzip -l (or similar) in place of pdf2html will show you paths that have been added or removed between commits images: exiv2 can be used to show metadata changes such as image dimensions documents: conversion tools exist for transforming .odf, .doc and other document formats to plain text. In a pinch, strings will often work for binary files where no formal converter exists.
Comparing files: git diff file
The git diff command can be passed an explicit file path option. When a file path is passed to git diff the diff operation will be scoped to the specified file. The below examples demonstrate this usage.
This example is scoped to ./path/to/file when invoked, it will compare the specific changes in the working directory, against the index, showing the changes that are not staged yet. By default git diff will execute the comparison against HEAD . Omitting HEAD in the example above git diff ./path/to/file has the same effect.
When git diff is invoked with the --cached option the diff will compare the staged changes with the local repository. The --cached option is synonymous with --staged .
Как запушить коммит на GitHub
У нас есть новый коммит на нашей локальной машине. Теперь нам нужно обновить наш «источник истины» — удаленный origin -репозиторий (GitHub).
В настоящее время локально мы находимся в ветке main . Нам нужно сообщить GitHub-у, чтобы он обновил собственную ветку main этим новым коммитом.
Для этого используется команда git push (push — «толкать, пихать»). Мы можем указать, куда именно мы хотим запушить коммит и в какую конкретно ветку.
Здесь мы запушили изменения в origin (GitHub), в ветку main .
Вывод команды сообщает нам об операциях с файлами, которые пришлось совершить Git, а последняя строка говорит о том, какие коммиты были запушены и куда:
Мы видим, что мы запушили нашу ветку main в ветку main на GitHub.
Если мы посмотрим лог проекта ( git log ), мы заметим, что теперь ветки main и в локальном репозитории, и в origin нацелены на один и тот же коммит.
В общем, в origin (GitHub) в ветке main ( origin/main ) последним коммитом в истории теперь выступает наш коммит.
Если бы мы работали совместно с другими людьми, они теперь могли бы вытащить последние изменения из GitHub-репозитория на свои машины и тоже начать редактировать Главу 1.
Как сравнивать подготовленные к коммиту изменения
Прежде чем сделать коммит, можно сравнить изменения, внесенные в стейджинг, с последним коммитом. Для этого нужно добавить флаг --staged или --cached . Мне нравится --staged , потому что он какой-то более осмысленный. Но если вы предпочитаете --cached , можете смело им пользоваться.
Давайте рассмотрим это на примере. Для начала сделаем коммит наших подготовленных (отправленных в стейджинг) изменений в репозиторий cat_vs_dog. Если не помните, что у нас в стейджинге, напомню: там файлы просто представляются как котенок и щенок (kitty и puppy).
Мы также хотели заменить «puppy» на «pup», но это изменение пока не в стейджинге.
Для начала сделаем коммит подготовленных изменений:
Теперь внесем в стейджинг изменение «puppy» на «pup». После этого запускаем команду git diff --staged . Она выведет разницу между стейджингом и последним коммитом.
- Версия A — последний коммит, содержащий строку «my name is puppy» в dog.txt
- Версия B — стейджинг, отличающийся от последнего коммита. «puppy» сменился на «pup» в dog.txt.
Из вывода diff мы видим, что именно мы изменили и внесли в стейджинг: в версии A было «my name is puppy», а в версии B у нас уже «my name is pup».
Надеюсь, теперь вы можете и сами сравнивать изменения и читать вывод diff. Вообще это супермощная команда, позволяющая сравнивать очень многие вещи многими способами.
Reading diffs: outputs
4 сравнения diff, которые стоит знать
Запустив команду git diff HEAD , вы сможете сравнить изменения, как попавшие, так и не попавшие в стейджинг, с последним коммитом.
Вы также можете запустить команду git diff , чтобы сравнить изменения в первой ветке с изменениями во второй. При сравнении веток порядок имеет значение, от него зависит то, что вы получите в выводе.
Примечание: сравнение веток затрагивает только коммиты. Другие изменения, как в стейджинге, так и нет, не учитываются.
Для сравнения двух коммитов можно использовать команду git diff . Как и при сравнении веток, здесь важен порядок указания коммитов.
Следующие команды можно запускать для сравнения изменений в конкретном файле:
- git diff HEAD
- git diff
- git diff --staged или git diff --cached
- git diff
- git diff
Highlighting changes
1. Comparison input
This line displays the input sources of the diff. We can see that a/diff_test.txt and b/diff_test.txt have been passed to the diff.
Сравнение файлов между двумя ветками
Чтобы сравнить конкретные файлы между двумя ветками используется команда:
Вместо branch1, branch2 нужно указать название веток, а вместо myfile.cpp путь до сравниваемого файла. Через пробел можно добавить еще файлы для сравнения.
4. Diff chunks
The remaining diff output is a list of diff 'chunks'. A diff only displays the sections of the file that have changes. In our current example, we only have one chunk as we are working with a simple scenario. Chunks have their own granular output semantics.
The first line is the chunk header. Each chunk is prepended by a header inclosed within @@ symbols. The content of the header is a summary of changes made to the file. In our simplified example, we have -1 +1 meaning line one had changes. In a more realistic diff, you would see a header like:
In this header example, 6 lines have been extracted starting from line number 34. Additionally, 8 lines have been added starting at line number 34.
The remaining content of the diff chunk displays the recent changes. Each changed line is prepended with a + or - symbol indicating which version of the diff input the changes come from. As we previously discussed, - indicates changes from the a/diff_test.txt and + indicates changes from b/diff_test.txt .
4. Сравниваемые фрагменты
Остальные выходные данные сравнения — это список сравниваемых фрагментов. При сравнении отображаются только разделы файла, в которых есть изменения. В данном примере имеется только один такой фрагмент, поскольку обрабатывается простой сценарий. Фрагменты имеют собственную ограниченную семантику вывода.
Первая строка — это заголовок фрагмента. К началу каждого фрагмента добавляется заголовок, ограниченный символами @@ . Заголовок кратко описывает изменения в файле. В нашем простом примере заголовок -1 +1 означает, что имеются изменения в первой строке. В реальных случаях заголовок может выглядеть так:
В данном примере заголовка было извлечено 6 строк начиная со строки 34. Кроме того, после строки 34 было добавлено 8 строк.
Остальное содержимое фрагмента сравнения — это недавние изменения. Каждой измененной строке предшествует символ + или - , указывающий на источник входных данных сравнения. Как уже упоминалось, символ - указывает на изменения в файле a/diff_test.txt , а + — на изменения в файле b/diff_test.txt .
git diff – универсальная diff-команда
Команда git diff выводит изменения между вашей текущей рабочей директорией и стейджингом.
От редакции Techrocks. О том, что такое стейджинг, можно почитать в статье «Git: руководство для начинающих. Разбираемся с основными концепциями системы контроля версий».
Рассмотрим пример. Я создала Git-репозиторий cat_vs_dog . Нет, это не официальный репозиторий, но довольно серьезный)
Затем я создала два файла: cat.txt и dog.txt.
Каждый из файлов представляется нам:
Меня зовут Kitty
Меня зовут puppy
Затем я поместила эти изменения в стейджинг при помощи команды
Хотите убедиться, что они уже там? Используйте команду git status . Она покажет, какие изменения готовы к коммиту.
Допустим, после этого я захотела изменить имя собаки: вместо «puppy» назвать ее «pup».
Если бы до этого я запустила команду git diff , она бы ничего не показала. Угадаете, почему? Если нет — ничего страшного, сейчас все поймете.
Итак, я изменила «puppy» на «pup».
Прежде чем внести изменения в стейджинг, я хочу посмотреть, что именно поменялось в моей рабочей директории по сравнению с изменениями, уже внесенными в стейджинг.
Для этого я запускаю команду git diff . Ниже вы можете видеть ее вывод.
В этом вроде как есть смысл, но все равно вывод не слишком понятен, правда? Не пугайтесь, сейчас все разберем.
Ранее мы запускали git diff и не получали в выводе ничего. Дело в том, что git diff показывает разницу между рабочей директорией и стейджингом. Но на тот момент мы просто внесли файлы в стейджинг и ничего в них не меняли. Поэтому между рабочей директорией и стейджингом попросту не было никаких различий.
Чтение вывода команды diff
3. Маркеры изменений
Эти строки представляют собой легенду обозначений для каждого источника входных данных сравнения. В данном случае изменения из файла a/diff_test.txt помечаются символом --- , а из файла b/diff_test.txt — символом +++ .
Добавляем еще один коммит в Git
Прежде чем приступить к теме коллаборации, давайте внесем еще одно маленькое изменение. Посмотрим, что происходит, когда мы редактируем уже существующий файл.
Добавим в наш текстовый файл еще одну строку:
Команда cat позволяет нам просмотреть файл. Мы видим, что теперь в нем две строки.
Давайте еще раз проверим статус нашего Git-репозитория:
В самом верху написано, что наша ветка полностью соответствует origin/main .
Это может показаться странным, ведь мы только что изменили файл. Но здесь Git сравнивает только коммиты, которые мы совершили, с коммитами в origin/main (а не изменения вообще).
В следующем разделе дается немного больше информации:
Git сообщает, что у нас есть изменения, не подготовленные к коммиту. И прежде чем мы сможем сделать коммит набора правок, нам сначала нужно подготовить их, внеся в стейджинг.
Сравнение двоичных файлов
Наряду с описанными возможностями обработки текстовых файлов команда git diff может работать с двоичными файлами. К сожалению, в этом случае использовать формат вывода по умолчанию не слишком продуктивно.
В Git есть функция, с помощью которой можно указать команду оболочки для преобразования содержимого двоичных файлов в текст до начала сравнения. Для этого потребуется выполнить небольшую настройку. Для начала необходимо указать фильтр textconv, описывающий процесс преобразования определенного типа двоичного файла в текст. В данном случае используется простой инструмент pdftohtml (доступный в Homebrew), который позволяет преобразовывать файлы PDF в удобный для восприятия формат HTML. Его можно назначить отдельному репозиторию в файле .git/config или глобально в файле ~ /.gitconfig
Затем необходимо связать с фильтром pdfconv один или несколько шаблонов файлов. Для этого необходимо создать файл .gitattributes в корневом каталоге репозитория.
После настройки команда git diff сначала обрабатывает двоичный файл с помощью настроенного скрипта конвертера, а затем выполняет сравнение выходных данных конвертера. Этот метод можно использовать для эффективного сравнения любых двоичных файлов, например ZIP, JAR и других архивов. Используя инструмент unzip -l (или аналогичный) вместо pdf2html, можно просмотреть, какие пути были добавлены в коммит или удалены из него по сравнению с другим коммитом. Утилиту exiv2 можно использовать для просмотра изменений метаданных, например размеров изображения. Существуют инструменты для преобразования .odf, .doc и других форматов документов в простой текст. В крайнем случае команда может работать с двоичными файлами, для которых формальных конвертеров не существует.
1. git diff --color-words
git diff also has a special mode for highlighting changes with much better granularity: ‐‐color-words . This mode tokenizes added and removed lines by whitespace and then diffs those.
Now the output displays only the color-coded words that have changed.
2. git diff-highlight
If you clone the git source, you’ll find a sub-directory called contrib. It contains a bunch of git-related tools and other interesting bits and pieces that haven’t yet been promoted to git core. One of these is a Perl script called diff-highlight. Diff-highlight pairs up matching lines of diff output and highlights sub-word fragments that have changed.
Now we’ve pared down our diff to the smallest possible change.
Сравнение файлов в двух коммитах
Команде git diff можно передать ссылки на коммиты Git для сравнения. Возможные варианты ссылок — HEAD , теги и имена веток. Каждый коммит в Git имеет идентификатор, который можно получить с помощью команды git log . Этот идентификатор коммита тоже можно передать в git diff .
Разбираем вывод git diff пошагово
Строка 1. Это две версии одного файла. Git называет их A (первая версия) и B (вторая версия).
- A – старая версия файла
- B – новая версия файла
Строка 2. Мета-данные файла. Они вряд ли вам пригодятся. Два первых числа — хеши двух сравниваемых файлов. 100644 — внутренний идентификатор режима файла.
Строка 3. Git приписал знак минус (-) версии A и знак плюс (+) версии B.
Строка 4. Обычно Git показывает не целый файл, а отрывки с измененными строками.
- Строка, начинающаяся с символа (-), взята из версии A
- Строка, начинающаяся с символа (+), взята из версии B
Помимо измененных строк вы также увидите строки кода до и после изменений — для понимания контекста.
Строка 5. Каждый отрывок начинается с заголовка. Заголовок обозначается символами @@ в начале и конце. Между ними идут два набора чисел. Видите -1 и +1?
- -1 означает, что из версии A извлечена одна строка, начиная со строки 1
- +1 означает, что из версии B извлечена одна строка, начиная со строки 1
Если бы у нас были наборы чисел -3,4 +3,2, тогда это означало бы следующее:
- -3,4 — из версии A извлечено 4 строки, начиная со строки 3
- +3,2 — из версии B извлечено 2 строки, начиная со строки 3
No newline at the end of the file. Эта фраза говорит нам о том, что после измененных строк других строк нет. То есть в этом примере я добавила только одну строку в файл и изменяла ее же. После нее ничего другого нет.
Changes since last commit
By default git diff will show you any uncommitted changes since the last commit.
Исключить некоторые файлы из сравнения
Иногда нужно выполнить git diff , но исключить один или несколько файлов, чтобы команда git diff их проигнорировала. Для этого используется запись вида ’:(exclude)имя_файла’ или короткая запись ’:!имя_файла’
Или более короткая запись:
2. Meta data
This line displays some internal Git metadata. You will most likely not need this information. The numbers in this output correspond to Git object version hash identifiers.
Читайте также: