Искусство Коммитов
Комментарий к коммиту, возможно, является самой важной его частью, так как это единственное место, где написано не только что изменилось, но и зачем.
— из комментов
Хороший комментарий к коммиту — короткий. И не только потому что краткость — сестра. Сообщения к коммитам чаще всего читают в логе изменений, где их будет много. Рассматривайте каждое сообщение как заголовок новости в интернете: оно должно быть достаточно коротким чтобы вы могли быстро пролистывать новости и содержать ровно столько информации чтобы вы могли найти важное лично для вас. Если у вас в команде больше пары программистов, то лог коммитов позволяет быть в курсе того, что происходит в проекте. Git не накладывает ограничений на длину сообщения, после краткого анонса вы можете добавить несколько параграфов текста:
Updated Ruby on Rails version because security
Bumped Rails version to 3.2.11 to fix JSON security bug.
See also http://weblog.rubyonrails.org/2013/1/8/Rails-3-2-11-3-1-10-3-0-19-and-2-3-15-have-been-released/
Обратите внимание, что сообщение целиком содержит довольно много информации, а первая строка — краткую выжимку. Потому что в логе вы увидите только первую строку:
commit f0c8f185e677026f0832a9c13ab72322773ad9cf
Author: David Demaree
Date: Sat Jan 3 15:49:03 2013 -0500
Updated Ruby on Rails version because security
Ваш любимый текстовый редактор
git интегрируется как с консольными редакторами (vim, emacs), так и с графическими (Atom, Sublime, TextMate). Вызванный без --message git передаст заготовку текста настроенному редактору. После редактирования сообщения достаточно сохранить открытый файл и закрыть редактор, git определит что сообщение было изменено и использует его. Пример интеграции git с Atom:
$: git config --global core.editor "atom --wait"
Для каждого редактора нужны свои ключи командной строки, и в справке GitHub вы можете найти хороший обзор как настраивать популярные текстовые редакторы.
Комментарий к коммиту
Кода вы пишите комментарий к коммиту, я рекомендую придерживаться следующих правил:
- Несите пользу
Помните, что назначение комментария — дать вашим коллегам понять, что происходит в проекте. Поставьте себя на место читателя и подумайте, как лучше охарактеризовать зачем был сделан этот коммит.
- Остерегайтесь графоманства
Часто нам хочется написать «дурацкие баги» или «исправил проблему». Не поддавайтесь этой слабости, старайтесь максимально четко и ясно напсать что и зачем было сделано.
- Линкуйте информацию
Если коммит связан с какой-то внешней информацией — багрепортом, статьей в вики или чем-нибудь еще, то очень хорошей идеей будет явно указать это в комментарии к коммиту,например такМногие багтрекеры (включая встроенный в github) интегрируются с git и автоматически помечают баги как исправленные, если встречают в комментарии к коммиту номер этого бага вместе с зарезервированным словом, таким как fixes в этом примере.Replace jQuery onReady listener with plain JS; fixes #1357
- Будьте (достаточно) подробны
Не пишите что поменялось — это всегда видно по диффам. Пишите зачем были внесены изменения. Это как раз то, что по диффам не видно. Старайтесь уместить первую строку в 70 символов — дополнительную информацию всегда можно написать отдельным параграфом после пустой строки.
- Будьте последовательны
Чтобы ваш лог изменений читался как единая новостная лента — уделите немного времени, чтобы объяснить команде как лучше писать комментарии для коммитов. Хорошей идеей будет создать страницу в вашей вики (у вас ведь есть внутренняя вики?) с примерами хороших и плохих комментариев.
- Используйте глаголы
Часто возникает соблазн написать комментарий к коммиту вида «исправления». Но помните, что лог изменений — это история ваших действий над проектом, а действия лучше всего описывать глаголами. Если этого не делать, то очень легко деградировать до таких воткомментариевКроме того, этого очень простое правило, которому легко следовать: «я только что поменял код. Что и зачем я сделал?»,# Making the last homepage update before releasing the new site $: git commit -m "Version 1.0" # Ten minutes later, after discovering a typo in your CSS $: git commit -m "Version 1.0 (really)" # Forty minutes later, after discovering another typo $: git commit -m "Version 1.0 (oh FFS)"
например$: git commit -m "Update homepage for launch" $: git commit -m "Fix typo in screen.scss" $: git commit -m "Fix misspelled name on about page"
Ваши комментарии?
Надеюсь, этот перевод будет полезен многим хабрачитателям. Я как разработчик разделяю мнение автора и с удовольствием обсужу в комментах непростой вопрос создания читаемого лога коммитов.
Комментарии (32)
Zapped
08.02.2016 11:16+4очень мне нравятся в этом плане исходники самого Git:
бывает,в файле изменена одна строка, а коммент - простыня на 20 строкgit log -1 -p d69360c6b17d1693a60b9f723a3ef5129a62c2e5"
commit d69360c6b17d1693a60b9f723a3ef5129a62c2e5 Author: Ben Walton <bdwalton@gmail.com> Date: Mon Dec 22 15:25:44 2014 -0800 t0090: tweak awk statement for Solaris /usr/xpg4/bin/awk The awk statements previously used in this test weren't compatible with the native versions of awk on Solaris: echo "dir" | /bin/awk -v c=0 '$1 {++c} END {print c}' awk: syntax error near line 1 awk: bailing out near line 1 echo "dir" | /usr/xpg4/bin/awk -v c=0 '$1 {++c} END {print c}' 0 Even though we do not cater to tools in /usr/bin on Solaris that have and are overridden by corresponding ones in /usr/xpg?/bin, in this case, even the XPG version does not work correctly. With GNU awk for comparison: echo "dir" | /opt/csw/gnu/awk -v c=0 '$1 {++c} END {print c}' 1 which is what this test expects (and is in line with POSIX; non-empty string is true and an empty string is false). Work this issue around by using $1 != "" to state more explicitly that we are skipping empty lines. Helped-by: Jonathan Nieder <jrnieder@gmail.com> Signed-off-by: Ben Walton <bdwalton@gmail.com> Reviewed-by: Jonathan Nieder <jrnieder@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> diff --git t/t0090-cache-tree.sh t/t0090-cache-tree.sh index 067f4c6..601d02d 100755 --- t/t0090-cache-tree.sh +++ t/t0090-cache-tree.sh @@ -22,7 +22,7 @@ generate_expected_cache_tree_rec () { # ls-files might have foo/bar, foo/bar/baz, and foo/bar/quux # We want to count only foo because it's the only direct child subtrees=$(git ls-files|grep /|cut -d / -f 1|uniq) && - subtree_count=$(echo "$subtrees"|awk -v c=0 '$1 {++c} END {print c}') && + subtree_count=$(echo "$subtrees"|awk -v c=0 '$1 != "" {++c} END {print c}') && entries=$(git ls-files|wc -l) && printf "SHA $dir (%d entries, %d subtrees)\n" "$entries" "$subtree_count" && for subtree in $subtrees
Lol4t0
08.02.2016 13:02+2Все зависит от изменений. Что вы напишете к коммиту с исправлением опечатки Nmae на Name?
Zapped
08.02.2016 13:07+2я-то так и напишу, но приводить для примера в статье, озаглавленной «Искусство коммита» («The Art of the Commit»), не стал бы :)
Lol4t0
08.02.2016 13:20+2Хорошо, как правильно написать? Написать сочинение по изменению, которое исправляет серьезный баг горзадо проще, чем по такой мелочи.
Zapped
08.02.2016 13:35Не думаю, что стоит впадать в крайности и описывать зачем исправлялась опечатка :) По-моему, это вещь очевидная и текста
Исправить опечатку: имя локального параметра должно быть Name, а не Nmae
кажется, вполне хватит.
Но и я придерживаюсь мнения, что писать «сочинение» писать нужно не только по серьёзным багам. Стоит всё же думать о том, что то, что понятно сегодня, может быть (и будет) забыто и непонятно самому себе через месяц/полгода/год, а другим и то вовсе непонятно.Lol4t0
08.02.2016 17:32+1В целом, я тоже выступаю за развернутые сообщения, но в них не должно быть воды. Если нечего сказать, то ничего говорить не нужно.
Randl
08.02.2016 20:36+3Хм, а зачем? Текста
Исправил опечатку
по-моему хватит. Если интересно какую именно (с чего бы?), смотрим диффы.Zapped
09.02.2016 01:10+1ну, меня не убудет написать какая именно опечатка была исправлена
*и мне кажется, эта информация может быть полезна для околоконтекстного поиска, когда она является опорной для поиска других изменений…
Regis
08.02.2016 17:17-2А по мне вся эта простыня — плохой пример.
Этому тексту самое место в багтрекере, как мне кажется.Lol4t0
08.02.2016 17:31+1Почему бы ему не быть и там и тут? Чтобы быстро оценить ситуацию все равно удобнее сомтреть git log --oneline
Zapped
08.02.2016 18:27+5не согласен
метаданные к изменениям кода должны быть там, где они управляются — в SCM
зачем в описании ошибки (в багтрекере) — описание того, как и зачем меняется код?
кроме того, ошибка может затрагивать несколько версий продукта, несколько его платформ, etc
развивая тему:
при работе с историей кода, лезть ещё в багтрекер (и хорошо ещё, если с ним есть интеграция), сопоставлять даты комментариев (вы же в комментАриях будете писать как вы меняли код?) с датой самого коммита? нет, увольте…
MANIAK_dobrii
08.02.2016 12:36+1Тут помогает разумное использование трекера задач и чего-то вроде git-flow, когда на каждую таску есть ветка. Лень никто никогда не отменят, даже у самых занудных разработчиков, себя я спас от приступов лени, написав pre-commit скрипт, который из названия текущей ветки выдирает айди задачи в таск трекере и прилепляет перед сообщением.
На самом деле многое зависит от команды и проекта, но, в целом, в статье рекламируется отличная практика.
michael_vostrikov
08.02.2016 12:44+4Не пишите что поменялось — это всегда видно по диффам
Думаю, писать что поменялось тоже нужно. Это полезно, когда надо найти конкретный коммит из разряда «точно помню, что-то где-то я такое делал», или точную дату изменений. Смотреть дифф каждого коммита утомительно. А подробный ответ на вопрос зачем обычно есть в таск-трекере. Я обычно пишу как в последнем пункте — «что и зачем я сделал» в сжатом виде. А так со всем согласен, правильно написано.tyomitch
08.02.2016 18:47Найти коммит, когда известно, что поменялось, помогает
git blame
.
Так что ещё и в commit message это вписывать незачем.michael_vostrikov
08.02.2016 19:02Код может несколько раз измениться, или вообще быть вынесен в другой файл.
tyomitch
08.02.2016 19:12Аргументом для
git blame
можно указать любую историческую версию.Zapped
09.02.2016 01:02а вот как раз чтобы найти эту историческую версию, надо прошерстить
git log
)))
и хорошо, если можно использоватьgit log -S/-G
(если помнишь что именно изменялось)
а при указанном подходе — почти точно поможетgit log --grep
впрочем, тогдаgit blame
уже будет не нужен
cemick
08.02.2016 13:00+5Не знаю, что в книге, но в выжимке капитанство. В принципе это давно стандарт, например, вот правила на которые мы ориентируемся kernel.org
Хотел бы только добавить, что важно писать не только «зачем», но и «мотивацию». Между «зачем» и «мотивация» на самом деле большая разница. Из мотивации можно выяснить точку зрения автора коммита. Часто бывает неочевидно, почему для решения был выбран именно «вот такой» подход. Дам ссылку на наш опыт насаживания подобного подхода написания текста коммитов Что дал переход с SVN на Git или Git как ключ для синергии хороших практик
seregamorph
08.02.2016 18:05Небольшой оффтоп.
Долгое время сидели на gerrit (обертка над git), его идеология отличается от github-подобных систем тем, что один смысловой changeset — это один коммит, если есть правки после ревью, делается amend/squash, а ревью идет между ревизиями одного changeset. После ревью в основную ветку попадает ровно один коммит.
Так вот это я к тому, что когда изменения по одному тикету размазаны на несколько коммитов, очень неудобно смотреть лог, когда подряд идут коммиты с одним именем, скажем «PROJ-123 fixsmth».Zapped
09.02.2016 00:55я в случаях, когда тикет размазан по нескольким коммитам, пишу
issue #N: бла-бла
issue #N: бла-бла-2
и последний коммит уже
fixed #N: <summary>
(и если их больше двух, то обычно вливаю в master с --no-ff)
BalinTomsk
08.02.2016 19:28Пройдя через несколько крупных компаний пришел к такому темплейту:
JIRA 3718: Service failure with error: 0x0023 — Add guard to check pointer — номер тикета, его заголовок и что сделано в сабмите.
to CL2012 (main), 2021(release 1.1.3), 2023(accepted 1.1.3) — Если была интергация/merge в другие ветки, то номера всех изменений и номера изменений связанных с этим тикетом.
Codeline: 1.1.5 — версия продукта, для которого было сделано изменение
Code review: 4023 — номер преревью, где само изменение было обсуждено, с другими девелоперами и отвественными работниками
Problem: Service failed because pointer was not verified.
Fixed: Add guard to check pointer
Tested:
— Created database
— Run Server
— Pass all unit test
Docs: www.company.com/KB45034
Myshov
09.02.2016 19:35+1Еще есть такая забавная штука :)
git commit -m '$(curl -s http://whatthecommit.com/index.txt)'
Rathil
Я с телефона, извините, не могу ЛС написать.
Измените с " Как оформять коммиты, чтобы потом не было больно"
На «Как оформлять коммиты, чтобы потом не было больно».
AllRight88
Спасибо, исправил! До заголовка спеллчекер не добрался :)