Работа над ошибками в коммитах
То, как написаны сообщения коммитов, тоже может подчиняться определённым правилам. Иногда эти правила продиктованы культурой команды, а иногда техническими ограничениями.
Например, в выводе команды git log --oneline
умещается максимум 7272 первых символа сообщения, поэтому многие правила включают пункт: «Сообщение не должно быть длиннее 7272 символов».
В этом уроке рассмотрим несколько популярных подходов к оформлению сообщений коммитов. Но сначала разберём, почему такие сообщения важны и зачем соблюдать правила их оформления.
Зачем вообще писать сообщения
У каждого коммита в Git есть сообщение — то, что передаётся после параметра -m
. Например: git commit -m "Добавить урок про оформление сообщений коммитов"
.
Сообщения коммитов можно сравнить с надписями на коробках в кладовке. Если надписей нет, то нужную коробку будет сложно найти: придётся заглянуть в каждую, чтобы понять, что там. А если надписи есть, то нужная найдётся сразу.
Как и надпись на коробке, сообщение коммита должно помочь определить, что внутри. Например, надпись на коробке «всякое разное» не очень полезная. Сообщение коммита «небольшие исправления» тоже: непонятно, что было исправлено в таком коммите и зачем.
Есть общие рекомендации по тому, как правильно составить сообщение. Оно должно быть:
Вот пример полезного сообщения в репозитории новостного сайта: Исправление опечатки в заголовке главной страницы на хорватском
. Такое сообщение даёт много информации:
Исправление опечатки
значит, что исправлена ошибка, которая была допущена при наборе. Такое исправление не меняет смысл. То есть, например, главному редактору не нужно перепроверять этот заголовок.На хорватском
говорит о том, что переводчикам на другие языки этот коммит можно смело пропускать.В заголовке главной страницы
указывает, где произошли изменения. Если, например, кто-то зайдёт на сайт и ему не понравится новый заголовок, он легко найдёт по истории (git log
) автора этого коммита и спросит у него, почему заголовок теперь такой.
Пример плохого сообщения для того же коммита: Исправлена опечатка
. Это сообщение даёт мало информации. В такой коммит придётся «заглядывать» — разбираться, что именно поменялось и зачем.
Стили оформления
Все люди разные и у всех есть предпочтения — в том числе, как формулировать сообщения коммитов. Кто-то использует инфинитивы: Исправить сообщение об ошибке E123
, кто-то — глаголы в прошедшем времени: Исправил…
, кто-то — существительные: Исправление…
.
Без единообразия коммитов нет и эффективной работы в Git. Это может показаться мелочью, но когда коммиты с сообщениями в разных стилях идут друг за другом, их может быть сложно читать.
Чтобы упростить работу, команды или даже целые компании часто договариваются об определённом стиле (то есть о правилах) оформления сообщений коммитов.
Например, правила могут быть такие:
- длина сообщения от 3030 до 7272 символов;
- первое слово — глагол в инфинитиве («исправить», «дополнить», «добавить» и другие);
- и так далее.
Есть много подходов к оформлению сообщений коммитов, но мы расскажем о нескольких популярных. Их используют как отдельные команды, так и целые проекты.
Корпоративный
Во многих компаниях применяется Jira — система для организации проектов и задач. У каждой задачи в Jira есть идентификатор из нескольких заглавных латинских букв и номера. Например, LGS-239
значит, что это 239239-я задача в проекте LGS (сокращение от англ. logistics — «логистика»).
В корпоративном стиле в начале сообщения обычно указывают Jira-ID, а после — текст сообщения.
$ git commit -m "LGS-239: Дополнить список пасхалок новыми числами"
Какие-то команды могут договариваться, с какой части речи начинать сообщение и какой длины оно должно быть, какие-то — нет. Но требование о наличии Jira-ID обычно строгое: оно позволяет автоматически связывать коммиты с задачами и проектами.
Conventional Commits
Стандарт Conventional Commits (англ. «соглашение о коммитах») отличается качественной документацией и подробной проработкой. Он подходит для репозиториев с исходным кодом программ. Использовать его для других типов проектов (например, для перевода книги) было бы неудобно.Conventional Commits предлагает такой формат коммита: <type>: <сообщение>
. Первая часть type
— это тип изменений. Таких типов достаточно много. Вот два примера:
feat
(сокращение от англ. feature) — для новой функциональности;fix
(от англ. «исправить», «устранить») — для исправленных ошибок.
Более подробный список можно увидеть на сайте с описанием этого стиля.
Например, сообщение может быть таким.
git commit -m "feat: добавить подсчёт суммы заказов за неделю"
GitHub-стиль
GitHub можно использовать не только для хранения файлов проекта, но и для ведения списка задач (англ. issue) этого проекта. Если коммит «закрывает» или «решает» какую-то задачу, то в его сообщении удобно указывать ссылку на неё. Для этого в любом месте сообщения нужно указать #<номер задачи>
. Например, вот так.
$ git commit -m "Исправить #334, добавить график температуры"
В таком случае GitHub свяжет коммит и задачу.
Как исправить коммит
Иногда в только что выполненном коммите нужно что-то поменять: например, добавить ещё пару файлов или заменить сообщение на более информативное.
В таком случае можно внести правки в уже сделанный коммит с помощью опции --amend
(от англ. amend — «исправить», «дополнить») у команды commit
: git commit --amend
. Разберём, как она работает.
💡 Важно: опция--amend
работает только с последним коммитом (HEAD
). Для исправления более ранних коммитов есть другие команды. Мы рассмотрим их в следующих модулях курса.
Подготавливаем репозиторий
Создайте тренировочный репозиторий для отработки команды.
$ mkdir ~/dev/commit-amend-fun $ cd ~/dev/commit-amend-fun $ git init # пропустим вывод git init
Дополнить коммит новыми файлами — git commit --amend --no-edit
Представьте, что делаете небольшой сайт и для этого создали файл-страницу main.html
, а также файл со стилями common.css
.
$ touch main.html $ touch common.css # дальше отредактировали оба файла
В какой-то момент вы забыли о файле common.css
и добавили в коммит только main.html
.
$ git add main.html $ git commit -m "Добавить главную страницу" $ git log --oneline 777fec3 Добавить главную страницу
Файл common.css
так и остался «висеть» в untracked
. В этом легко убедиться, если вызвать git status
.
Дополните последний коммит забытым файлом common.css
с помощью опции --amend
.
$ git add common.css # добавили файл common.css в список на коммит как обычно # но вместо команды commit -m '...' # будет: $ git commit --amend --no-edit $ git log --oneline 8340eb2 Добавить главную страницу # коммит в истории всё ещё один (но у него новый хеш)
С опцией --amend
команда commit
не создаст новый коммит, а дополнит последний, просто добавив в него файл common.css
. При этом хеш последнего коммита изменится, потому что изменился список файлов в коммите.Обратите внимание на опцию --no-edit
. Она сообщает команде commit
, что сообщение коммита нужно оставить как было.
Точно так же можно добавить не новый файл, а дополнительные изменения в уже добавленном в коммит файле.
# ещё раз отредактировали main.html $ git add main.html # добавили в список на коммит $ git commit --amend --no-edit
💡 Что же выбрать: новый коммит или--amend
?
В нашем примере вместо изменения последнего коммита можно было также выполнить новый коммит с одним файломcommon.css
. Кажется, что так проще, но добавить изменения в уже существующий коммит может быть правильнее.
Например, через месяц кто-то захочет просмотреть историю изменений. Намного проще понять, что изменилось, если оба файла находятся в одном коммите. Иначе коммит со второй порцией изменений придётся искать.
Изменить сообщение коммита — git commit --amend -m "Новое сообщение"
Может быть и так, что добавлять новые файлы в коммит не нужно, зато понадобилось изменить сообщение.
Допустим, хочется заменить сообщение Добавить главную страницу
на Добавить главную страницу и стили
. Сделать это можно через commit --amend
с флагом -m
.
$ git commit --amend -m "Добавить главную страницу и стили" $ git log --oneline a31fa24 Добавить главную страницу и стили
Хеш коммита снова поменялся, потому что изменились сообщение и время коммита. При этом файлы в коммите остались те же: main.html
и common.css
.
Как откатиться назад, если «всё сломалось»
На разных этапах работы с Git могут происходить похожие ситуации:
- В список на коммит попал лишний файл (например, временный). Нужно «вынуть» его из списка.
- Последние несколько коммитов ошибочные: например, сделали не то, что было нужно, или нарушили логику. Хочется «откатить» сразу несколько коммитов, вернуть «как было вчера».
- Случайно изменился файл, который вообще не должен был меняться. Например, вы открыли не тот файл в редакторе и начали его исправлять.
В этом уроке рассмотрим такие случаи и научим вас «откатывать» нежелательные изменения.
Выполнить unstage изменений — git restore --staged <file>
Допустим, вы создали или изменили какой-то файл и добавили его в список «на коммит» (staging area) с помощью git add
, но потом передумали включать его туда. Убрать файл из staging поможет команда git restore --staged <file>
(от англ. restore — «восстановить»).
В терминале это будет выглядеть примерно так.
$ touch example.txt # создали ненужный файл $ git add example.txt # добавили его в staged $ git status # проверили статус Changes to be committed: (use "git restore --staged <file>..." to unstage) new file: example.txt $ git restore --staged example.txt $ git status # проверили статус Untracked files: (use "git add <file>..." to include in what will be committed) example.txt no changes added to commit (use "git add" and/or "git commit -a") # файл example.txt из staged вернулся обратно в untracked
Вызов git restore --staged example.txt
перевёл example.txt
из staged
обратно в untracked
.
Чтобы «сбросить» все файлы из staged
обратно в untracked
/modified
, можно воспользоваться командой git restore --staged .
: она сбросит всю текущую папку (.
).
«Откатить» коммит — git reset --hard <commit hash>
Иногда нужно «откатить» то, что уже было закоммичено, то есть вернуть состояние репозитория к более раннему. Для этого используют команду git reset --hard <commit hash>
(от англ. reset — «сброс», «обнуление» и hard — «суровый»).
$ git log --oneline # хеш можно найти в истории 7b972f5 (HEAD -> master) style: добавить комментарии, расставить отступы b576d89 feat: добавить массив Expenses и цикл для добавления трат # вот сюда и вернёмся 4b58962 refactor: разделить analyzeExpenses() на countSum() и saveExpenses() $ git reset --hard b576d89 # теперь мы на этом коммите HEAD is now at b576d89 feat: добавить массив Expenses и цикл для добавления трат
Теперь коммит b576d89
стал последним: вся дальнейшая разработка будет вестись от него. Файл также вернулся к тому состоянию, в котором был в момент этого коммита. А коммит 7b972f5
Git просто удалил. Это можно проверить, снова запросив лог. Он покажет следующее.
$ git log --oneline b576d89 (HEAD -> master) feat: добавить массив Expenses и цикл для добавления трат 4b58962 refactor: разделить analyzeExpenses() на countSum() и saveExpenses()
Вот так схематично выглядит весь процесс «отката» с помощью git reset --hard <hash>
.
«Откатить» изменения, которые не попали ни в staging, ни в коммит, — git restore <file>
Может быть так, что вы случайно изменили файл, который не планировали. Теперь он отображается в Changes not staged for commit
(modified
). Чтобы вернуть всё «как было», можно выполнить команду git restore <file>
.
# случайно изменили файл example.txt $ git status On branch main Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git restore <file>..." to discard changes in working directory) modified: example.txt $ git restore example.txt $ git status On branch main nothing to commit, working tree clean
Изменения в файле «откатятся» до последней версии, которая была сохранена через git commit
или git add
.
- Команда
git restore --staged <file>
переведёт файл изstaged
обратно вmodified
илиuntracked
. - Команда
git reset --hard <commit hash>
«откатит» историю до коммита с хешем<hash>
. Более поздние коммиты потеряются! - Команда
git restore <file>
«откатит» изменения в файле до последней сохранённой (в коммите или в staging) версии.