Анализ истории изменений
Программирование — это не только написание новых программ, но и постоянный анализ уже написанного кода. Иногда код понятен и без слов — и это хороший код.
Но так происходит не всегда. Код может вызывать вопросы. Почему он написан именно так, кто его написал и когда.
Ответить на эти вопросы помогает история изменений. Хорошо сделанные коммиты имеют понятное описание, и каждый из них делает ровно одну законченную вещь — в таком случае история становится мощным инструментом для анализа кода. Именно поэтому так важно хорошо понимать философию Git и следовать лучшим практикам при работе с ним.
Git предоставляет целую пачку команд со множеством опций, позволяющих вытащить невероятное количество информации и показать все, что скрыто. С ними мы познакомимся в этом уроке.
Команда git log
Самая простая аналитика выполняется командой git log. Она показывает список всех выполненных коммитов, отсортированных по дате добавления. Сверху мы видим самые последние коммиты:
git log
# Ниже неполный вывод истории проекта
commit 5120bea3e5528c29f8d1da43731cbe895892eb6d
Author: tirion <tirion@got.com>
Date: Thu Sep 17 18:04:19 2020 -0400
add new content
commit e6f625cf8433c8b1f1aaed58cd2b437ec8a60f27
Author: tirion <tirion@got.com>
Date: Thu Sep 17 16:14:09 2020 -0400
add INFO.md
commit 273f81cf2117044f1973ea80ce1067a94bea3f80
Author: tirion <tirion@got.com>
Date: Thu Sep 17 16:08:39 2020 -0400
remove NEW.md
# Этот вывод показывается через пейджер
Из этого вывода мы можем узнать кто, когда и какие коммиты делал. Если коммиты оформлены хорошо, то по их описанию уже многое понятно. Оформление коммитов — отдельная тема, которую мы рассмотрим позже.
У команды git log есть полезный флаг -p, который сразу выводит диф для каждого коммита. . Диф это список изменений в том виде, в котором их печатает git diff. Строку со знаком - коммит удалил, а строку со знаком + добавил.
Команда git show
У каждого коммита есть уникальный набор символов, его идентификатор (еще говорят «хеш»). С помощью хеша можно посмотреть все изменения, сделанные в рамках одного коммита:
git show 5120bea3e5528c29f8d1da43731cbe895892eb6d
# Тут выводится диф между этим коммитом и предыдущим
diff --git a/INFO.md b/INFO.md
index d5225f8..40f51f1 100644
--- a/INFO.md
+++ b/INFO.md
@@ -1 +1,2 @@
git is awesome!
+new line
diff --git a/README.md b/README.md
index ffe7ece..00fd294 100644
--- a/README.md
+++ b/README.md
@@ -1 +1 @@
-Hello, Hexlet!
+Hello, Hexlet! How are you?
# Здесь мы видим, что было изменено этим коммитом
Перед изменениями каждого файла Git печатает служебные строки. В примере выше diff --git a/INFO.md b/INFO.md и пара --- a/INFO.md, +++ b/INFO.md называют файл до правки и после нее, а в строке index d5225f8..40f51f1 100644 стоят сокращенные хеши его содержимого до и после коммита и режим доступа 100644, то есть обычный файл без права на запуск. Заголовок @@ -1 +1,2 @@ показывает, какой кусок файла изменился. В старой версии кусок начинался с первой строки и занимал одну строку, а в новой начинается там же и занимает две, потому что коммит дописал new line.
Хеши коммитов в Git очень длинные, и ими бывает неудобно пользоваться. Поэтому разработчики Git добавили возможность указывать только часть хеша. Достаточно взять первые семь символов и подставить их в ту команду, которая работает с коммитами:
Чаще всего вам не придется высчитывать их самим. Большая часть команд Git выводит хеш коммита в сокращенном варианте, облегчая его использование. Обычно семи символов достаточно: Git сам подбирает длину сокращения так, чтобы оно оставалось уникальным, и в очень больших репозиториях выводит больше символов. Если указать слишком короткий префикс, Git ответит short object ID ... is ambiguous, и тогда нужно добавить символов.
Команда git blame
А что если мы не знаем коммита, но нам интересно, кто последним менял конкретную строчку в файле? Для этого подойдет команда git blame <путь до файла>. Эта команда выводит файл и рядом с каждой строчкой показывает того, кто ее менял и в каком коммите:
git blame INFO.md
e6f625cf (tirion 2020-09-17 16:14:09 -0400 1) git is awesome!
5120bea3 (tirion 2020-09-17 18:04:19 -0400 2) new line
Важно помнить, что изменение строчки это не то же самое, что ее написание. Вполне возможно, что программист исправил небольшую опечатку, а саму строчку написал кто-то до него. Имея такой вывод, уже легко пойти дальше и изучить конкретный коммит.
Команда git grep
Команда git grep ищет совпадение с указанной строкой во всех файлах проекта. Это очень удобная команда для быстрого анализа из терминала. Она удобнее обычного grep, потому что знает про игнорирование и не смотрит в директорию .git, а еще умеет искать по истории:
git grep line
INFO.md:new line
# Флаг `i` позволяет искать без учета регистра
git grep -i hexlet
README.md:Hello, Hexlet! How are you?
Команда умеет искать не только в текущем состоянии файлов, но и внутри конкретного коммита или по всей истории сразу. Эти режимы разобраны по ссылке «Поиск по коду и истории» в дополнительных материалах.
Ниже запись сессии, где все четыре команды идут подряд на одном репозитории. Смотрите, как одна команда подхватывает вывод другой: git log дает хеш, git show раскрывает по нему изменения, git blame указывает на строку, а git grep находит ее по тексту:
Обратите внимание: в записи использованы другой репозиторий и настроенный в конфиге Git сокращенный формат вывода, поэтому git log и git show показывают коммиты одной строкой. У вас содержимое файлов, хеши и формат вывода будут такими, как в примерах выше.
GitHub
В простых ситуациях анализировать проект можно прямо на GitHub. Он позволяет просматривать историю коммитов, изменения в конкретном коммите и многое другое.
Дополнительные материалы
Самостоятельная работа
- Выполните все команды из урока в нашем репозитории
- Изучите историю репозитория ru-local-communities