Хабрахабр

[Перевод] Как следует писать комментарии к коммитам

Предисловие от переводчика

На протяжении многих лет разработки ПО, будучи участником многих команд, работая с разными хорошими и опытными людьми, я часто наблюдал (да и чего греха таить, до определенного момента — создавал) одну и ту же проблему — тотальный бардак в репозитории. Каждый писал комментарии к коммитам в своем стиле (и хорошо, если постоянно в одном); половина комментариев была бесполезна (из разряда "это мост"), половина оставшейся половины — едва понятна.

Всего 7 простых и коротких правил, и — о чудо — смотреть на историю коммитов стало не только полезно, но и приятно. И вот в один прекрасный момент я увидел данную статью, до перевода которой у меня наконец дошли руки. Какие-то не сильно релевантные вещи, упоминаемые автором, могли потерять актуальность, но суть статьи — ничуть. Ничего революционного, все довольно очевидно, но сформулировано и резюмировано просто отлично.
Хочу заметить, что это статья 2014 года.

Введение: чем важны хорошие комментарии

Если вы заглянете в случайный Git-репозиторий, то, скорее всего, обнаружите, что в истории коммитов там в какой-то мере бардак. Например, взгляните на эти перлы из того времени, когда я начинал коммитить в репозиторий Spring:

$ git log --oneline -5 --author cbeams --before "Fri Mar 26 2009" e5f4b49 Re-adding ConfigurationPostProcessorTests after its brief removal in r814. @Ignore-ing the testCglibClassesAreLoadedJustInTimeForEnhancement() method as it turns out this was one of the culprits in the recent build breakage. The classloader hacking causes subtle downstream effects, breaking unrelated tests. The test method is still useful, but should only be run on a manual basis to ensure CGLIB is not prematurely classloaded, and should not be run as part of the automated build.
2db0f12 fixed two build-breaking issues: + reverted ClassMetadataReadingVisitor to revision 794 + eliminated ConfigurationPostProcessorTests until further investigation determines why it causes downstream tests to fail (such as the seemingly unrelated ClassPathXmlApplicationContextTests)
147709f Tweaks to package-info.java files
22b25e0 Consolidated Util and MutableAnnotationUtils classes into existing AsmUtils
7f96f57 polishing

Жуть. Сравните с этими, более свежими, коммитами в том же репозитории:

$ git log --oneline -5 --author pwebb --before "Sat Aug 30 2014" 5ba3db6 Fix failing CompositePropertySourceTests
84564a0 Rework @PropertySource early parsing logic
e142fd1 Add tests for ImportSelector meta-data
887815f Update docbook dependency and generate epub
ac8326d Polish mockito usage

Какой вариант вы бы предпочли?

Первые разнятся по длине и стилю, вторые — лаконичные и однородные.
Первое получается само собой, второе пишется осознанно.

Отличные примеры — ядро Linux и сам Git. И хотя история коммитов многих репозиториев выглядит подобно первому варианту, есть исключения. Посмотрите также на Spring Boot или любой другой репозиторий, которым занимается Tim Pope.

Различия в ревизиях показывают, что изменилось, но только комментарий может внятно объяснить — почему. Участники этих проектов знают, что хорошо написанный комментарий к коммиту — это лучший способ рассказать о контексте сделанных изменений другим разработчикам (а также самим себе — в будущем). Peter Hutterer хорошо сказал об этом:

Мы не можем полностью ее избежать, поэтому наши усилия должны быть сосредоточены на минимизации этих затрат. Восстановление обстоятельств написания код — расточительная трата времени. Следовательно, они показывают, хорошо ли программист работает в команде. Именно для этого и нужны комментарии к коммитам.

Если вы не особо задумывались о том, каким должен быть первоклассный комментарий коммита — вероятно, вы не слишком часто использовали git log и похожие инструменты. Тут замкнутый круг: так как история коммитов неструктурированная и разнородная, ей не пользуются и не уделяют внимания. А из-за того, что ей не пользуются и не уделяют внимания, она остается неструктурированной и разнородной.

Оживают команды git blame, revert, rebase, log, shortlog и прочие. Но хорошо оформленная история репозитория — вещь прекрасная и полезная. Разобраться, почему что-то случилось [в коде] месяцы или годы назад становится не только возможно, но и удобно. Появляется смысл просматривать чужие коммиты и пулл-реквесты, и, внезапно, при этом теперь не требуется помощь их авторов.

Стоит потратить время на то, чтобы научиться сохранять в ней порядок. Долгосрочный успех проекта зависит (помимо всего прочего) от того, насколько его удобно поддерживать, а история коммитов — один из самых мощных инструментов мейнтенера. Сначала это может причинять некоторые неудобства, но потом войдет в привычку и, в конце концов, станет источником гордости и продуктивной работы всех участников.

Есть и другие важные вещи, например, объединение коммитов, которые здесь не рассматриваются. Эта статья затрагивает лишь самую базовую составляющую ведения добротной истории, а именно — как следует писать комментарий к отдельному коммиту.

Конечно, есть разные версии таких соглашений, но большинство разработчиков придерживаются мнения, что выбрать один вариант и следовать ему — гораздо лучше, чем неразбериха, когда каждый пишет в своем стиле. В большинстве языков программирования есть хорошо описанные общепринятые соглашения, формирующие характерный стиль [написания кода], как то —  имена переменных, правила форматирования и так далее.

Чтобы история репозитория была полезной, команда должна прийти к соглашению как минимум по трем следующим пунктам. Подход команды к описанию коммитов должен быть точно таким же.

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

А чего там не должно быть? Содержимое. Какая именно информация должна (если вообще должна) содержаться в теле комментария?

Метаданные. Как следует ссылаться на ID задач, номера пулл-реквестов и т.д.?

На самом деле, они частично вытекают из того, как работают некоторые команды Git. К счастью, уже существуют соглашения о написании содержательного комментария. Просто следуйте семи правилам ниже — и будете на шаг ближе к истории коммитов, достойной профессионала.
Вам не нужно изобретать велосипед.

Семь правил классного комментария к коммиту

Помните: Все это уже было сказано раньше.

  1. Отделяйте заголовок от тела пустой строкой
  2. Ограничивайте заголовок 50 символами
  3. Пишите заголовок с заглавной буквы
  4. Не ставьте точку в конце заголовка
  5. Используйте повелительное наклонение в заголовке
  6. Переходите на следующую строку в теле на 72 символах
  7. В теле отвечайте на вопросы что и почему, а не как

Например:

Резюмируйте изменения в 50 символах или меньше Тут объясните их более детально, если необходимо. Выполняйте
переносы строк примерно на 72 символах. В некоторых ситуациях
первая строка комментания считается его заголовком, а все остальное - телом. Крайне важно отделять оделять одно от другого
пустой строкой (если у сообщения вообще есть тело, конечно);
различные инструменты типа `log`, `shortlog`и `rebase` не поймут
вас, если заголовк и тело не будут отделены. Объясните здесь, какую проблему решает этот коммит. Уделите больше внимания тому, почему вы внесли эти изменения, а не тому, как именно вы это сделали (это объяснит за вас код).
Есть ли сайд-эфффекты или другие неочевидные последствия у этих изменений? Если да, это нужно объяснить здесь. Параграфы разделяются пустыми строками. - Можно делать маркированные списки - Обычно в качестве маркера списка используется звездочка или тире с пробелом перед ними; но тут есть разные соглашения Если у вас есть баг-трекер [или система управления проектами],
поместите ссылки на задачи в конце текста таким образом: Решено: #123
Смотрите также: #456, #789

Оригинал

Summarize changes in around 50 characters or less More detailed explanatory text, if necessary. Wrap it to about 72
characters or so. In some contexts, the first line is treated as the
subject of the commit and the rest of the text as the body. The
blank line separating the summary from the body is critical (unless
you omit the body entirely); various tools like `log`, `shortlog`
and `rebase` can get confused if you run the two together. Explain the problem that this commit is solving. Focus on why you
are making this change as opposed to how (the code explains that).
Are there side effects or other unintuitive consequences of this
change? Here's the place to explain them. Further paragraphs come after blank lines. - Bullet points are okay, too - Typically a hyphen or asterisk is used for the bullet, preceded by a single space, with blank lines in between, but conventions vary here If you use an issue tracker, put references to them at the bottom,
like this: Resolves: #123
See also: #456, #789

1. Отделяйте заголовок от тела пустой строкой

Из мануала к команде git commit:

Текст до первой пустой строки в комментарии считается заголовком коммита и используется в разных командах Git. Хотя это не обязательно, но хорошей идеей будет начинать комментарий к коммиту с одной короткой (менее 50 символов) строки, обобщающей сделанные изменения, затем пустая строка и затем более подробное описание. Например, Git-format-patch(1) превращает коммит в email; команда использует заголовок коммита для темы письма и остальной текст — для тела письма.

Во-первых, не каждый коммит требует заполнения и заголовка, и тела. Иногда одной строчки вполне достаточно, особенно когда изменения настолько малы, что никакой дополнительной информации о них не требуется. Например:

Fix typo in introduction to user guide

Сказанного достаточно; если пользователь захочет узнать, что именно за опечатка была исправлена, он может просто посмотреть на сами изменения, используя git show или git diff, или git log -p.

Если вы коммитите что-то в этом роде с помощью командной строки, удобно будет использовать опцию -m для git commit:

$ git commit -m "Fix typo in introduction to user guide"

Однако, когда коммит заслуживает некоторых объяснений и описания ситуации, вам нужно записать их в тело комментария. Например:

Derezz the master control program MCP turned out to be evil and had become intent on world domination.
This commit throws Tron's disc into MCP (causing its deresolution)
and turns it back into a chess game.

Комментарии, у которых есть тело, не так удобно писать с помощью опции -m. Будет лучше использовать для этого текстовый редактор. Если вы еще не настроили редактор для использования с Git, прочтите этот раздел книги Pro Git.

Вот полная запись о коммите:
В любом случае, разделение заголовка и тела комментария окупится при просмотре лога.

$ git log
commit 42e769bdf4894310333942ffc5a15151222a87be
Author: Kevin Flynn <kevin@flynnsarcade.com>
Date: Fri Jan 01 00:00:00 1982 -0200 Derezz the master control program MCP turned out to be evil and had become intent on world domination. This commit throws Tron's disc into MCP (causing its deresolution) and turns it back into a chess game.

А вот команда git log --oneline, которая выводит только строку заголовка:

$ git log --oneline
42e769 Derezz the master control program

Или git shortlog, которая группирует коммиты по автору, опять же, для краткости показывает только заголовок:

$ git shortlog
Kevin Flynn (1): Derezz the master control program Alan Bradley (1): Introduce security program "Tron" Ed Dillinger (3): Rename chess program to "MCP" Modify chess program Upgrade chess program Walter Gibbs (1): Introduce protoype chess program

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

2. Ограничивайте заголовок 50 символами

Технически, выйти за 50 символов можно, но не рекомендуется. Эта длина заголовка гарантирует его читабельность, а также заставляет автора задуматься о самой краткой и четкой формулировке для описания происходящего.

Стремитесь делать атомарные коммиты (это тема для отдельного поста). Подсказка: если вам тяжело резюмировать итоги работы, возможно, в одном коммите содержится слишком много изменений.

Интерфейс GitHub’а поностью поддерживает эти соглашения. Он предупредит вас, если вы выйдете за пределы лимита в 50 символов:

И обрежет все заголовки длиннее 72 символов, подставив троеточие:

Так что стремитесь к 50 символам, но учтите, что 72 — это строгое ограничение.

3. Пишите заголовок с заглавной буквы

Тут все просто. Начинайте все заголовки с заглавной буквы.

Например:

  • Accelerate to 88 miles per hour

Вместо:

  • accelerate to 88 miles per hour

4. Не ставьте точку в конце заголовка

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

Например:

  • Open the pod bay doors

Вместо:

  • Open the pod bay doors.

5. Используйте повелительное наклонение в заголовке

Повелительное наклонение буквально означает: форма глагола, выражающая волеизъявления (приказ, просьбу или совет). Несколько примеров:

  • Clean your room (приберись в комнате)
  • Close the door (закрой дверь)
  • Take out the trash (вынеси мусор)

Каждое из семи правил, о которых вы сейчас читаете, написано в повелительном наклонении («Переходите на следующую строку в теле на 72 символах» и т.д.).

пер.]. Эта форма может звучать немного грубо, и поэтому не так часто используется [в английском языке — прим. Одна из причин — тот факт, что сам Git использует повелительное наклонение, когда создает коммиты от вашего имени.
Например, при использовании git merge по умолчанию добавится такое сообщение:
Но она идеально подходит для заголовка коммита.

Merge branch 'myfeature'

А при использовании git revert:

Revert "Add the thing with the stuff" This reverts commit cc87791524aedd593cff5a74532befe7ab69ce9d.

Или при клике на кнопку «Merge» в интерфейсе пулл-реквеста в GitHub:

Merge pull request #123 from someuser/somebranch

Так что, когда вы пишите собственные сообщения к коммиту в повелительном наклонении, вы следуете правилам, заложенным в сам Git. Например:

  • Refactor subsystem X for readability
  • Update getting started documentation
  • Remove deprecated methods
  • Release version 1.0.0

Такой способ может поначалу показаться неудобным. Мы больше привыкли использовать изъявительное наклонение, которое скорее сообщает о фактах. Поэтому сообщения коммитов часто оказываются примерно такими:

  • Fixed bug with Y
  • Changing behavior of X

А иногда заголовки просто описывают содержимое коммита:

  • More fixes for broken stuff
  • Sweet new API methods

Есть простое правило, которое позволит вам избегать ошибок.

Правильно составленный заголовок коммита должен завершать следующее предложение:

  • If applied, this commit will <заголовок коммита>

Например:

  • If applied, this commit will refactor subsystem X for readability
  • If applied, this commit will update getting started documentation
  • If applied, this commit will remove deprecated methods
  • If applied, this commit will release version 1.0.0

If applied, this commit will merge pull request #123 from user/branch

Убедитесь, что глаголы в других, не повелительных, наклонениях здесь не сработают:

  • If applied, this commit will fixed bug with Y
  • If applied, this commit will changing behavior of X
  • If applied, this commit will more fixes for broken stuff
  • If applied, this commit will sweet new API methods

В теле коммита это необязательно. Помните: использование повелительного наклонения важно только в заголовке коммита.

6. Переходите на следующую строку в теле на 72 символах

Сам Git не расставляет переносы строк автоматически. Редактируя тело комментария, вы должны помнить о правой границе и ставить переносы строк вручную.

Рекомендуется переходить на следующую строку на 72 символах, чтобы Git мог свободно расставлять отступы и всё еще влезать в сумме в 80 символов.

Довольно легко настроить, скажем, Vim, на перенос строки на 72 символах для написания сообщения к коммиту. С этим может помочь хороший текстовый редактор. (прим. Однако, так сложилось, что IDE ужасно плохо поддерживают умные переносы строк для сообщений к коммитам (хотя последние версии IntelliJ IEDA наконец стали лучше в этой части). — возможно, на текущий момент все обстоит гораздо лучше).
пер.

7. В теле отвечайте на вопросы «что» и «почему», а не «как»

В этом коммите из репозитория Bitcoin дано отличное объяснение, что и почему изменилось:

commit eb0b56b19017ab5c16c745e6da39c53126924ed6
Author: Pieter Wuille <pieter.wuille@gmail.com>
Date: Fri Aug 1 22:57:55 2014 +0200 Simplify serialize.h's exception handling Remove the 'state' and 'exceptmask' from serialize.h's stream implementations, as well as related methods. As exceptmask always included 'failbit', and setstate was always called with bits = failbit, all it did was immediately raise an exception. Get rid of those variables, and replace the setstate with direct exception throwing (which also removes some dead code). As a result, good() is never reached after a failure (there are only 2 calls, one of which is in tests), and can just be replaced by !eof(). fail(), clear(n) and exceptions() are just never called. Delete them.

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

Обычно, код говорит сам за себя в этом смысле (а если он настолько сложен, что требуются пояснения, то для этого есть комментарии в нем самом). В большинстве случаев вы можете опустить подробности того, как именно были внесены изменения.

Сосредоточьтесь в первую очередь на пояснении причин, по которым были внесены изменения — опишите ситуацию до внесения изменения (и что было с ней не так), ситуацию после и то, почему вы выбрали именно такой способ решения задачи.

Может быть, в будущем вы поблагодарите сами себя за это!

Подсказки

Полюбите командную строку. Забудтье про IDE.

Есть множество причин — по количеству команд Git — использовать командную строку по максимуму. Git — безумно мощный инструмент; IDE — тоже, но каждая по-своему. Я ежедневно пользуюсь IntelliJ IDEA, часто имел дело и с другими (например, Eclipse), но никогда не видел, чтобы интеграция Git в IDE могла сравниться по простоте и возможностям с командной строкой (как только вы с ней разберетесь).

Но все гораздо хуже, когда вы пытаетесь с помощью IDE сделать коммит, слияние, перебазирование (rebase) или сложный анализ истории коммитов. Определенные возможности IDE по контролю версий просто неоценимы, например автоматическое выполнение git rm, когда вы удаляете файл, или других нужных git-штук, когда вы его переименовываете.

Когда требуется раскрыть полный потенциал Git, командной строке нет равных.
Помните, что используете ли вы Bash, Zsh или Powershell — существуют скрипты автодополнения команд, избавляющие вас от болезненной необходимости запоминать все подкоманды и опции.

Прочтите книгу Pro Git

Великолепная книга Pro Git (также на русском языке — прим. пер) есть в свободном доступе. Воспользуйтесь этим!

Теги
Показать больше

Похожие статьи

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Кнопка «Наверх»
Закрыть