PyVCS. Распределенная система контроля версий
Возможно вы знаете, что Линус Торвальдс написал Git с нуля, а также как сильно он его любит (если вам интересна последовательность событий, которая привела к появлению Git, то можно начать с этого сообщения Линуса в почтовой рассылке ядра Linux):
Actually I’m proud of git. I want to say this. The fact that I had to write git was accidental, but Linux, the design came from a great mind, and that great mind was not mine. I mean you have to give credit for the design of Linux to Kernighan and Ritchie and Thompson. I mean there’s a reason I like Unix and I wanted to redo it. I do want to say that git is a design that is mine and unique, and I’m proud of the fact that I can damn well also do good design from scratch.
Но многие начинающие программисты, и не только, ненавидят Git. Им кажется, что Git это какая-то сложная, запутанная система, при использовании которой постоянно возникают какие-то ошибки, да и вообще «Зачем этот Git нужен?». Обычно эта ненависть вызвана простым непониманиме работы Git’а.
Чтобы устранить это непонимание мы напишем свою систему контроля версий PyVCS, реализующую небольшое подмножество команд Git’а.
Содание репозитория
Вы уже знаете, что выполнение команды git init приводит к созданию нового репозитория в указанном каталоге (текущем по умолчанию). Все данные репозитория обычно расположены в каталоге .git (имя которого можно изменить через переменную окружения GIT_DIR ). Давайте попробуем воссоздать минимально необходимую структуру репозитория:
В последующих заданиях будет объяснено назначение каждого созданного каталога и файла, хотя уже должно быть очевидно, что .git/config хранит настройки конткретного репозитория, а .git/description описание. Подробно со структурой каталога .git можно ознакомиться здесь.
Вашей задачей является автоматизировать этот процесс и реализовать команду pyvcs init , которая создает новый пустой репозиторий в указанном каталоге (по умолчанию в текущем). В первую очередь запустите тесты, чтобы понять над какими функциями в этом задании вам предстоит работать:
После завершения работы над соответствующими функциями выполните следующую команду для установки пакета в вашем виртуальном окружении:
Хранение файлов
Разберемся с тем как Git хранит ваши данные. Git является контентно-адресуемым хранилищем данных, другими словами, Git представляет собой хранилище по типу ключ-значение. Ключом выступает хеш посчитанный от данных, а значением сами данные. Итак, когда вы добавляете новый файл в репозиторий, то от содержимого файла считается хеш-сумма по алгоритму SHA-1 (хотя уже доступна возможность использовать SHA2-256 из-за коллизий в SHA-1), два первых символа которой становятся именем директории в каталоге objects , а остальные символы именем файла, чье содержимое записывается в сжатом виде с помощью библиотеки zlib (подробно о работе zlib можно почитать тут) и называется блобом (blob, binary large object). Рассмотрим простой пример:
Еще раз отметим, что Git является контентно-адресуемым хранилищем, таким образом, если у нас будет два файла с одинаковым содержимым, то у них будет одинаковый идентификатор (ключ), а соответственно их содержимое будет представлено одним и тем же блобом:
Давайте самостоятельно попробуем посчитать хеш-сумму и сжать содержимое цитаты из примера:
Отметим, что данные добавляются к заголовоку, который состоит из типа (существует 4 типа объектов: блобы, коммиты, деревья и теги) и длины записываемых данных.
Вы могли заметить, что отличаются первые два байта в шестнадцатеричном представлении сжатых данных (7801 и 789с), это связано с использованием разных уровней сжатия (изменить уровень сжатия можно в файле конфигурации указав значение переменной core.compression ):
- 78 01 — No Compression/low
- 78 9C — Default Compression
- 78 DA — Best Compression
Вашей задачей является реализовать команду pyvcs hash-object с поддержкой флага на запись -w . Для запуска тестов измените версию пакета в файле pyvcs/__init__.py на 0.2.0.
Восстановление файлов
Мы научились создавать блобы, чтобы вывести их содержимое Git предоставляет команду cat-file (флаг -p означает pretty , то есть, понятный вывод содержимого объекта):
С ее помощью мы можем легко восстанавливать содержимое файлов, если они были удалены:
Работа этой команды зеркальна по отношению к hash-object , мы должны разобрать заголовок и вывести содержимое:
Вашей задачей является реализовать команду pyvcs cat-file с поддержкой флага -p . Для корректной работы cat-file вам также потребуется реализовать ряд вспомогательных функций. Также не забудьте изменить версию пакета на 0.3.0 для запуска тестов.
Добавление в индекс
Индекс (index) или область подготовленных файлов (staging area) является временным «снимком» текущего состояния вашего репозитория, то есть, содержит те изменения, которые вы собираетесь включить в коммит. Таким образом, вы делаете коммит содержимого индекса, а не вашей рабочей директории:

Добавить файл в индекс можно с помощью команды update-index , более дружелюбной версией которой является команда add , а просмотреть состояние индекса с помощью команд ls-files или status :
Индекс является бинарным файлом и имеет следующий формат:
Для простоты будем использовать вторую версию без расширений. Каждая запись имеет следующий формат:
Чем отличается ctime от mtime?
mtime это время последнего изменения файла (его содержимого), а ctime это время либо последнего изменения файла, либо последнего изменения его атрибутов, например, прав доступа или владельца. Также у файлов есть еще параметр atime , который содержит время последнего доступа к файлу (чтение, запись, выполнение).
Чтобы определить, был ли изменен файл, Git сравнивает его текущее состояние, хеш и имя с сохраненными в индексе, если они совпадают, то файл считается без изменений.
Получить состояние файла можно с помощью фунции stat из модуля os :
Для простоты будем полагать время последнего изменения и модификации в наносекундах равными 0. Также следует обратить внимание, что под inode (уникальный идентификатор файла) выделено 4 байта, хотя даже в нашем примере этого недостаточно.
Для упаковки и распаковки бинарных данных удобно использовать модуль struct:
В примере L3sd указывает на формат упаковываемых данных, L — беззнаковое длинное целое (4 байта), 3s — 3 однобайтовых символа, d — вещественное число двойной точности.
От вас требуется реализовать команды update-index с обязательным параметром —add и ls-files с опциональным флагом -s , который позволяет получить более подробную информацию о записях в индексе:
Вывод состоит из четырех столбцов:
- права доступа на файл (если вы впервые столкнулись с концепцией прав, то почитайте вот эту статью). Git различает только 644 (не исполняемый) и 755 (исполняемый);
- хеш-сумма (имя/идентификатор объекта);
- наличие конфликтов при слиянии веток (0 — конфликтов нет);
- путь к файлу.
Для запуска тестов измените версию пакета на 0.4.0.
Сохранение индекса
Для сохранения текущего состояния индекса используется команда write-tree :
В результате будет создан объект дерево, который имеет такую же структуру как и блоб:
где каждая запись имеет следующий вид (разделителя между записями нет — следующая запись начинается сразу как заканчивается предыдущая):
В результате мы получили новый объект, который можем просмотреть с помощью команды cat-file :
Выводятся права доступа, тип объекта (blob, tree, commit, tag), идентификатор объекта и имя файла. Этой информации должно быть достаточно, чтобы восстановить файл: мы знаем его имя, содержимое и является ли он исполняемым:
Итак, блоб хранит содержимое файла, но не «знает» ни имени, ни прав. В свою очередь tree-объекты хранят имя и права.
Давайте рассмотрим пример с созданием директорий:
Блобы и tree-объекты можно сравнить со структурой файловой системы — блобы это файлы, а tree — каталоги.
Вашей задачей является реалиовать команду write-tree для сохранения индекса и создания tree-объекта.
Создание коммитов
Мы научились создавать tree-объекты, которые являются снимками состояния вашего рабочего каталога. Не хватает информации о том, почему этот снимок был сделан. Мы можем добавить эту информацию с помощью команды commit-tree :
Мы создали коммит, который включает ссылку на tree-объект, автора и коммитера (имя, адрес электронной почты и Unix timestamp) и описание коммита. Найти описание разницы между автором и коммитером можно тут:
You may be wondering what the difference is between author and committer. The author is the person who originally wrote the work, whereas the committer is the person who last applied the work. So, if you send in a patch to a project and one of the core members applies the patch, both of you get credit — you as the author, and the core member as the committer.
Давайте добавим еще один файл и создадим новый коммит, таким образом, у нас образуется история изменений:
Единственным изменением по сравнению с предыдущей командой является указателя родительского коммита с помощью флага -p (parent):
История изменений можно отобразить с помощью команды log :
Вашей задачей является реализовать команду commit-tree :
Создание ссылок и веток
Мы разобрались с назначением .git/objects , давайте теперь разберемся с назначением .git/refs . В этом каталоге есть два подкаталога heads и tags . Первый хранит ссылки на ветки, которые можно создать с помощью команды update-ref :
Итак, мы создали ссылку на коммит 0de19. ac с именем master (ветку master ) и можем использовать ее вместо идентификатора коммита, например, в командах cat-file или log .
Если мы попробуем просмотреть историю указав ветку master , то не увидим всей истории:
Нам необходимо вручную обновить сслыку на мастер-ветку:
Давайте создадим еще одну ветку:
Обратите внимание, что мы находимся на мастер-ветке. Текущая ветка (положение в истории) определяется содержимым HEAD :
С помощью команды symbolic-ref мы можем сделать текущей ветку dev :
Вашей задачей является реализация команд update-ref , rev-parse , symbolic-ref , commit .
Переключение на коммиты и ветки
Для переключения между коммитами и ветками используется команда git checkout , например, рассмотрим пример переключения на ветку dev :
dev указывает на предыдущий коммит, в котором еще не был добавлен файл isle_of_dogs.txt . Упрощая, можем считать, что команда checkout коммит_или_ветка приводит к удалению всего текущего содержимого каталога, за исключением файлов, которые не были добавлены в индекс (выполнив команду git status вы можете их увидеть под именем untracked files), после чего происходит поиск tree-объекта, на который указывает коммит, его рекурсивный обход и восстановление всех блобов в рабочем каталоге. Наконец мы обновляем содержимое HEAD .
Вашей задачей является реализовать команду checkout с возможность переключения как на ветку, так и на указанный коммит.
Что делает git rev-parse?
Я прочитал справочную страницу, но это вызвало больше вопросов, чем ответов. Вещи как:
Выбрать и параметры массажа
Массаж ? Что это значит?
Я использую в качестве резольвера (для SHA1) спецификаторов ревизии, как
Это цель команды? Если нет, то даже правильно ли использовать его для достижения этой цели?
git rev-parse является вспомогательной plumbing командой, в основном используемой для манипуляций.
Одним из распространенных применений git rev-parse является печать хэшей SHA1 с указанием ревизии. Кроме того, он имеет различные параметры для форматирования этого вывода, например, —short для печати более короткого уникального SHA1.
Также есть и другие варианты использования (в скриптах и других инструментах, построенных поверх git), для которых я использовал:
- —verify проверить, что указанный объект является допустимым объектом git.
- —git-dir для отображения абс / относительный путь .git каталога.
- Проверка, что вы в данный момент находитесь в репозитории, используя —is-inside-git-dir или внутри рабочего дерева, используя —is-inside-work-tree
- Проверка, является ли репо голым, используя —is-bare-repository
- Печать SHA1 хэшей ветвей ( —branches ), тегов ( —tags ) и ссылок также может быть отфильтрована на основе удаленного (с использованием —remote )
- —parse-opt нормализовать аргументы в скрипте (вроде как getopt ) и вывести строку вывода, которую можно использовать с eval
Massage просто подразумевает, что можно преобразовать информацию из одной формы в другую, то есть команду преобразования. Вот несколько быстрых примеров, о которых я могу подумать:
- имя ветви или тега в SHA1 коммита, на которое он указывает, чтобы его можно было передать сантехнической команде, которая принимает только значения SHA1 для коммита.
- диапазон ревизий A..B для git log или git diff в эквивалентных аргументах для базовой сантехнической команды как B ^A
Просто для того, чтобы уточнить этимологию имени команды rev-parse , Git последовательно использует термин rev в сантехнических командах как сокращение от «revision» и обычно означает 40-символьный хэш SHA1 для фиксации. Команда, rev-list например, печатает список хешей фиксации из 40 символов для ветви или чего-либо еще.
В этом случае имя может быть расширено до parse-a-commitish-to-a-full-SHA1-hash . В то время как команда имеет несколько вспомогательных функций, упомянутых в ответе Tuxdude, ее тезка, по-видимому, является прецедентом преобразования удобной для пользователя ссылки, такой как имя ветви или сокращенный хеш, в однозначный 40-символьный хеш SHA1, наиболее полезный для многих программ / сантехники. цели.
Я знаю, что думал, что это было «обратным анализом» чего-то довольно долгое время, прежде чем я понял это и испытал те же проблемы с пониманием терминов «массаж» и «манипуляция» 🙂
Во всяком случае, я нахожу это понятие «анализ-пересмотр» удовлетворительным образом обдумать это и надежной концепцией доведения этой команды до ума, когда мне нужны такие вещи. Часто в сценариях Git вы принимаете удобную для пользователя ссылку на коммит в качестве пользовательского ввода и обычно хотите, чтобы она была преобразована в проверенную и однозначную рабочую ссылку как можно скорее после ее получения. В противном случае входной перевод и проверка имеют тенденцию распространяться через сценарий.
Русские Блоги
Gitk — это самая ранняя реализация графического программного обеспечения браузера Git-репозитория, основанная на реализации tcl / tk, поэтому gitk очень лаконичен и сам по себе написан сценарием tcl из 10 000 строк. Код gitk был помещен в тот же репозиторий, что и код Git, Gitk выпускается вместе с Git и может запускаться без специальной установки. Gitk может отображать диаграмму ветвления коммита, и он может показывать коммит, файлы, различия между версиями и т. д.
Когда вы вызываете gitk в репозитории, вы просматриваете репозиторий и отображаете его диаграмму ветви коммитов. Gitk может быть вызван с различными параметрами, как инструмент командной строки.
- Показать все ветки.
- Показаны заявки с 2 недель.
- Показать коммиты для определенных каталогов и файлов (включая каталог / scsi и каталог drivers / scsi) начиная с этапа (v2.6.12).
На следующем рисунке показано выполнение gitk -all в репозитории DEMO.

Видимые ссылки в разных цветах и формах можно увидеть на рисунке выше:
Зеленая ветка мастера.
Желтые вехи hello_1.0 и old_practice.
Графический инструмент: gitg
gitg — это браузерное программное обеспечение Git, реализованное с использованием графической библиотеки GTK +.
Установить gitg в Linux очень просто: например, в Debian или Ubuntu, просто запустите следующую команду, чтобы установить его.
После установки вы можете найти gitg в пути к исполняемому файлу.
Чтобы продемонстрировать, что gitg имеет функцию фиксации, сначала внесите некоторые изменения в рабочую область.
- Удалите неиспользуемый файл hello.h.
- Добавьте строку в файл README.
- Статус текущего рабочего пространства.
Теперь вы можете выполнить команду gitg в рабочей области.
На следующем рисунке показан интерфейс по умолчанию для gitg, показывающий карту ветвей фиксации, информацию о фиксации выбранного коммита и список измененных файлов.

На рисунке выше вы можете видеть идентификацию статуса (включая ссылки), отображаемую разноцветными метками:
Оранжевая мастерская ветка.
Желтые вехи hello_1.0 и old_practice.
И белая метка, показывающая невременный статус рабочего пространства.
При нажатии на вкладку «дерево» в окне ниже gitg отобразится дерево каталогов этого коммита.

Функция коммитов является основной особенностью gitg. Нажмите вкладку фиксации в верхнем окне gitg, чтобы отобразить следующий интерфейс.

В нижнем левом окне отображаются локальные изменения, которые не были обновлены в области подготовки. Щелкните правой кнопкой мыши и выберите «Сцена» во всплывающем меню.

После добавления файла README во временную область хранения вы увидите, что файл README появляется в правом нижнем окне.

На этом этапе, если вы вернетесь в интерфейс просмотра истории отправки, вы увидите, что на вкладке «stash» появляются две вкладки «staged» и «unstaged», которые показывают состояние промежуточной области и рабочей области, соответственно.

После выбора файла, который будет отправлен (добавлен во временную область хранения) через интерфейс gitg, выполните коммит.

В нижней части диалогового окна с инструкциями по отправке есть два параметра: если выбран параметр «Добавить подписку», соответствующий текст описания будет автоматически добавлен в журнал отправки. На рисунке ниже вы можете видеть, что отправка только что отображалась в верхней части истории отправлений, и текст описания с подписью отображается в описании отправления.

Инструмент командной строки
Предыдущие практические материалы были в основном линейными и не были сложными для изучения. Чтобы быть ближе к реальному и лаконичному, вы можете локально клонировать этот образец репозитория следующим образом.
Запустите команду gitg, чтобы отобразить диаграмму фиксации.

Разве это не что-то вроде "гламурного взгляда скрамблера". Если отправка представлена кругом, отмеченным вехами, если вы немного ее упорядочите, вы увидите более простую диаграмму взаимосвязи представления ниже.

Большинство команд Git могут использовать версию фиксации в качестве параметра (например, git diff <commit-id>), а некоторые команды принимают диапазон версий в качестве параметра (например, git log <rev1> .. <rev2>). У коммитов Git есть различные представления, и сфера коммитов одинакова. Давайте рассмотрим представление версий Git и диапазон версий с помощью двух команд: git rev-parse и git rev-list.
Обозначение версии: git rev-parse
Команда git rev-parse — это низкоуровневая команда Git, которая очень богата (или грязна) и используется многими скриптами или инструментами Git.
Вы можете отобразить местоположение репозитория Git (—git-dir), глубину текущего каталога рабочей области (—show-cdup) и даже использовать его для анализа аргументов командной строки (—parseopt) в приложениях, не зависящих от Git.
Эта команда отображает ссылки в текущем хранилище.
- Показать ветки.
- Показать вехи.
- Показать все ссылки, определенные.
Ссылки в каталоге refs / remotes / становятся удаленными ветвями (или удаленными ссылками).
Другой важной функцией команды git rev-parse является представление выражения объекта Git в виде соответствующего значения хеш-функции SHA1. Для репозитория gitdemo-commit-tree, клонированного в этом разделе, выполните следующие действия.
- Отображает хеш-значение SHA1, соответствующее HEAD.
- Вывод команды git description также может отображаться как хэш SHA1.
- Вы можете отобразить хэш SHA1 для нескольких выражений одновременно.
Следующая операция показывает, что как master, так и refs /heads / master можно использовать для ссылки на главную ветвь.
- Первые несколько цифр хеш-значения могут использоваться для ссылки на все хеш-значение.
- Оба представления вех указывают на один и тот же объект.
Объект-веха не обязательно является коммитом, это может быть объект Tag. Объект Tag содержит описание или подпись, а также содержит указатель на соответствующую отправку.
- Когда веха A указывает на объект Tag вместо коммита, следующие три нотации могут использоваться для указания коммита, соответствующего вехе.
Фактически, следующий синтаксис также может быть применен непосредственно к легким вехам (указывающим непосредственно на веху фиксации) или к самой фиксации.
- Первый родительский коммит — это коммит, на который указывает Б.
Вспоминая предыдущее введение, оператор ^ представляет родительский коммит. Если у коммита есть несколько родительских коммитов, вы можете указать количество родительских коммитов, следуя за цифрой ^, за которой следует число. ^ Эквивалентно ^ 1. И B ^ 0 представляет объект Commit, на который указывает B (потому что B является объектом Tag).
- Более сложные обозначения.
Последовательные символы размещаются по очереди в подчинении родителей и предков. Число после ^ представляет родительский коммит коммита.
- Отображается дерево каталогов, соответствующее Milestone A. Следующие два способа написания хороши.
- Отобразить файлы в дереве.
- Файлы в промежуточной области такие же, как и в заголовке.
- Вы также можете отображать коммиты, ища строки в журнале коммитов.
- Тогда есть синтаксис, связанный с reflog
Обозначение диапазона версий: git rev-list
Некоторые команды Git могут использовать диапазон версий в качестве параметра. Команда git rev-list может помочь изучить различные синтаксисы диапазона версий Git.

- Идентификатор фиксации может фактически представлять список версий. Значение: все исторические коммиты, начиная с этой версии.
- Две или более версии, эквивалентные объединению списков, на которые ссылаются, когда каждая версия используется отдельно.
- Префикс версии со знаком (^) означает отрицание, что исключает эту версию и ее историческую версию.
- Эквивалентное «точечное» представление выше. Соединение двух версий с двумя точками, такими как G..D, эквивалентно ^ G D.
Версия перевернута, и порядок параметров не важен, но важен порядок версий до и после «точечной» записи.
- Синтаксис: ^ B C
- Синтаксис: C ^ B
- Синтаксис: B..C эквивалентен ^ B C
- Синтаксис: C..B эквивалентен ^ C B
Смысл трехточечной записи в том, что обе версии доступны совместно.
F, I и J, к которым могут обращаться B и C, исключаются.
- Трехточечная запись, порядок двух версий не имеет значения.
На самом деле r1 . r2 эквивалентно r1 r2 — not $ (git merge-base —all r1 r2), независимо от порядка.
- История коммита, кроме самого себя, представлена синтаксисом r1 ^ @.
- Сам коммит не включает свой исторический коммит, который представлен синтаксисом r1 ^!
Просмотр логов: git log
Параметр представляет диапазон версий
При вызове без каких-либо параметров это эквивалентно использованию параметра HEAD по умолчанию, который отображает все исторические коммиты, к которым может получить доступ текущий HEAD. Вы также можете использовать обозначение диапазона версий, описанное выше, например:
Отображение отраслевой диаграммы
Вызов git log с параметром —graph может отобразить граф коммитов символьного интерфейса, и разные ветви могут быть представлены разными цветами. Если вы хотите видеть график отношений фиксации каждый раз, когда просматриваете журнал, вы можете установить псевдоним и вызвать его с псевдонимом.
После определения псевдонима вы можете использовать команду alias каждый раз, когда хотите автоматически отобразить диаграмму отношений отправки:
Показать последние журналы
Вы можете использовать параметр- <n> (<n> — число) для отображения последних журналов <n>. Например, следующая команда отображает последние 3 журнала.
Показать конкретные изменения для каждого коммита
Используйте параметр -p для отображения изменений при отображении журнала.
Поскольку это изменение двоичного файла, содержимое изменения не отображается по умолчанию. Файлы diff в Git обеспечивают поддержку двоичных файлов.
Показать сводку изменений для каждого коммита
Использование параметра -p делает вывод журнала очень избыточным.Если вам не нужно знать конкретные изменения и просто хотите знать, какие файлы являются изменениями, вы можете использовать параметр —stat. Сводная информация об изменениях выглядит как выходные данные команды diffstat для Linux.
Пользовательский вывод
Команда дифференциального вывода Git предоставляет множество шаблонов вывода на выбор, и вы можете выбрать избыточное отображение или упрощенное отображение в соответствии с вашими потребностями.
- Параметр —pretty = raw отображает необработанные данные. Может быть отображен идентификатор дерева, соответствующий представлению.
- Параметр —pretty = fuller будет отображать как автора, так и отправителя, которые могут отличаться.
- Параметр —pretty = oneline, очевидно, обеспечит наиболее упорядоченный вывод журнала. Вы также можете использовать параметр —oneline, эффект аналогичен.
Если вы хотите только просмотреть и проанализировать определенный коммит, вы также можете использовать команду git show или git cat-file.
- Используйте git show, чтобы отобразить этап D и его коммит:
- Используйте git cat-file для отображения вехи D и ее коммита.
Параметр -p означает симпатичный вывод.
Сравнение различий: git diff
Функция сравнения различий в Git неоднократно затрагивалась в предыдущей практике, особенно в соответствующих главах, посвященных области временного хранения, в которых основное внимание уделялось тому, как команда git diff сравнивает рабочее пространство, область временного хранения и хранилище.
Сравните Milestone B и Milestone A с помощью команды: git diff B A
Сравните рабочее пространство и этап A с помощью команды: git diff A
Сравните область подготовки и этап A с помощью команды: git diff –cached A
Сравните рабочую область и область подготовки с помощью команды: git diff
Чтобы сравнить область временного хранения с HEAD, используйте команду: git diff -cached
Сравните рабочее пространство и HEAD с помощью команды: git diff HEAD
Сравнение различий файлов между версиями в Git
Сравнение различий также может использовать параметр пути для отображения только различий в файлах по этому пути между различными версиями. Синтаксический формат:
Сравнение не-Git каталогов / файлов
Команда git diff также может быть выполнена вне репозитория Git, сравнивая не-Git каталоги, как команда GNU diff. Эта функция предоставляется, потому что команда сравнения Git diff более мощная и обеспечивает расширенную поддержку сравнения GNU diff.
Расширенный разностный синтаксис
Git расширяет синтаксис дифференциального сравнения GNU, обеспечивая поддержку переименования, двоичных файлов и изменений прав доступа к файлам.
Пословное сравнение вместо построчного сравнения по умолчанию
Сравнение различий в Git — это построчное сравнение по умолчанию, которое отображает строку до и после изменения, соответственно. Вам нужно тщательно определить, где находится изменение. Git также предоставляет результаты сравнения по словам, которые предпочитают некоторые люди. Используйте параметр —word-diff для отображения пословных сравнений.
Отображаемое выше различие между словами отображается в цвете: удаленное содержимое [-. -] отображается красным, а добавленное содержимое <+ . +>— зеленым.
Обратный путь в файле: git blame
Если в процессе разработки программного обеспечения обнаружена ошибка и обнаружен конкретный код, команда отслеживания файлов Git может указать, кто в какое время и в какой версии представил ошибку.
Когда вы выполняете команду git blame для файла, файл будет отображаться построчно.В начале каждой строки показывается версия, в которой эта строка была впервые введена и кем.
Чтобы увидеть только несколько строк, используйте параметр -L n, m следующим образом:
Бинарный поиск: git bisect
Предыдущая прослеживаемость файла основана на обнаруженной проблеме (ошибка) (в коде), и затем человек (отправитель) может быть найден через неправильную строку (код) и доску (образование или наказание). Итак, как найти проблему? Команда бинарного поиска Git может помочь.
Бинарный поиск не таинственный и не панацея, он основан на тестировании. Фактически, каждый, кто тестировал программное обеспечение, использовал его: «В последней версии есть ошибка, но в версии для определенного клиента такой проблемы нет, поэтому проблема должна заключаться в представлении кода между ними. Вверх ".
Команда git bisect, предоставляемая Git, основана на репозитории, автоматизированном поиске проблем и поиске рабочего процесса. Это заменяет обширное тестирование программного обеспечения в традиционном тестировании программного обеспечения, которое не может найти код для версии выпуска программного обеспечения.
Выполните бинарный поиск. После обнаружения проблемы вы должны сначала найти правильную версию. Если обнаруженная вами проблема неверна в самой ранней версии программного обеспечения, то нет необходимости выполнять бинарный поиск. Честно отлаживайте ее. Но если вы можете найти правильную версию, то есть проблема не возникает в этой правильной версии, то вы можете использовать команду git bisect для выполнения двоичного поиска в хранилище:
Рабочая область переключается на середину известных «хорошая версия» и «плохая версия».
Выполните тест, проблема воспроизводится, и текущая версия репозитория — «плохая версия». Если проблема не воспроизводится, пометьте текущую версию как «хорошую версию».
Повторяйте 1-2, пока не найдете первую версию, вызвавшую проблему.
Ниже приведена принципиальная схема примера репозитория, помеченного идентификатором отправки.В этом примере репозитория тестируется процесс двоичного поиска: сначала последний коммит (HEAD) помечается как «плохой», коммит G является хорошим, а затем путем поиска выполняется поиск окончательного местоположения. Отправить (B).

Основа определения плохих коммитов в следующем эксперименте проста: если вы включите файл B.txt в каталог doc /, эта версия будет «плохой».
Давайте начнем с ручного теста (посмотрите на наличие doc / B.txt) и воспользуемся двоичным поиском Git, чтобы найти «проблемную» версию.
- Сначала убедитесь, что вы работаете над основной веткой.
- Начать бинарный поиск.
- Текущая версия является «плохим коммитом», потому что файл doc / B.txt существует. Версия G является «хорошим коммитом», потому что нет файла doc / B.txt.
- Пометить текущую версию (HEAD) как «плохой коммит», а версию G как «хороший коммит».
- Автоматически найти C коммит. Нет файла doc / B.txt также является хорошим представлением.
- Теперь нацеленная на версию D, это также «хороший коммит».
- Пометить текущую версию (отправка D) как «Хорошая отправка».
- Теперь нацеленная на B-версию, это «плохой коммит».
- Теперь ориентируясь на версию E, это «хороший коммит». Когда E помечен как хороший коммит, вывод показывает, что была найдена ближайшая версия, которая успешно ввела плохой коммит.
- Окончательное местоположение плохого коммита определяется ссылкой refs / bisect / bad. Вы можете переключиться на эту версию следующим образом.
- После обнаружения и исправления ошибки, отмените бинарный поиск временных файлов и ссылок, оставленных в хранилище.
После отмены бинарного поиска хранилище переключается обратно на ветку, в которой был выполнен бинарный поиск.
Что делать, если вы пометили «хороший коммит» как «плохой коммит»?
В процессе выполнения бинарного поиска, если вы случайно допустили ошибки, вы можете пометить «хорошие коммиты» как «плохие коммиты» или наоборот. Это приведет к тому, что предыдущий процесс поиска будет отменен. Бинарный поиск в Git позволяет возобновить процесс поиска.
- Например, отправка E изначально была «хорошей версией», но была неправильно помечена как «плохая версия».
- Используйте команду git bisect log для просмотра записей журнала двоичного поиска.
Сохраните журнал бинарного поиска в файле.
- Отредактируйте этот файл и удалите строку, в которой записано неправильное действие.
Строки, начинающиеся со знака фунта (#), являются комментариями.
- Завершить предыдущий бинарный поиск.
- Восстановление прогресса через файлы журнала.
- Возвращаясь к коммиту E снова, на этот раз не пометьте это неправильно.
Бинарный поиск с использованием автоматических тестов
Команда двоичного поиска в Git поддерживает подкоманду run, которая может запускать сценарий автоматического тестирования.
Если код выхода скрипта равен 0, тестируемая версия является «хорошей версией».
Если код выхода скрипта 125, проверяемая версия пропускается.
Если код выхода скрипта от 1 до 127 (кроме 125), тестируемая версия является «плохой версией».
В этом примере написание автоматизированного теста слишком просто: это всего лишь оценка того, существует ли файл. Если он существует, он возвращает код ошибки 1, а если он не существует, он возвращает код ошибки 0.
Тестовый скрипт good-or-bad.sh выглядит следующим образом:
Выполнить бинарный поиск с помощью этого автоматизированного скрипта очень просто.
- Начните новый раунд бинарного поиска от известного мастера плохой версии и хорошей версии G.
- Для автоматического тестирования используйте скрипт good-or-bad.sh.
- Целевой «плохой версией» является B.
Получить историческую версию
Извлечение файлов в хронологическом представлении — это не что иное, как операция в следующей таблице: она много раз использовалась в предыдущих практиках и не будет повторяться.