Как оформлять коммиты, чтобы потом не было больно

http://alistapart.com/article/the-art-of-the-commit
  • Перевод
Несколько дней назад David Demaree, главный по Typekit в Adobe, издал крутую книжку "git для людей". Чтобы привлечь к ней внимание, он опубликовал выжимку самой, на мой взгляд, интересной главы — как оформлять коммиты чтобы и волки были целы, и овцы сыты, и песец не пришел. А я за эти выходные подготовил выжимку из выжимки — сокращенный и адаптированный перевод, чтобы можно было быстро прочитать и добавить в копилку своего опыта самое ценное.

Искусство Коммитов



Комментарий к коммиту, возможно, является самой важной его частью, так как это единственное место, где написано не только что изменилось, но и зачем.

— из комментов

Хороший комментарий к коммиту — короткий. И не только потому что краткость — сестра. Сообщения к коммитам чаще всего читают в логе изменений, где их будет много. Рассматривайте каждое сообщение как заголовок новости в интернете: оно должно быть достаточно коротким чтобы вы могли быстро пролистывать новости и содержать ровно столько информации чтобы вы могли найти важное лично для вас. Если у вас в команде больше пары программистов, то лог коммитов позволяет быть в курсе того, что происходит в проекте. 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 вы можете найти хороший обзор как настраивать популярные текстовые редакторы.

Комментарий к коммиту


Кода вы пишите комментарий к коммиту, я рекомендую придерживаться следующих правил:

  • Несите пользу

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

  • Остерегайтесь графоманства

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

  • Линкуйте информацию

    Если коммит связан с какой-то внешней информацией — багрепортом, статьей в вики или чем-нибудь еще, то очень хорошей идеей будет явно указать это в комментарии к коммиту,
    например так
    Replace jQuery onReady listener with plain JS; fixes #1357
    
    Многие багтрекеры (включая встроенный в github) интегрируются с git и автоматически помечают баги как исправленные, если встречают в комментарии к коммиту номер этого бага вместе с зарезервированным словом, таким как fixes в этом примере.

  • Будьте (достаточно) подробны

    Не пишите что поменялось — это всегда видно по диффам. Пишите зачем были внесены изменения. Это как раз то, что по диффам не видно. Старайтесь уместить первую строку в 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"
    


Ваши комментарии?


Надеюсь, этот перевод будет полезен многим хабрачитателям. Я как разработчик разделяю мнение автора и с удовольствием обсужу в комментах непростой вопрос создания читаемого лога коммитов.

Voximplant

176,00

Облачная платформа голосовой и видеотелефонии

Поделиться публикацией

Похожие публикации

Комментарии 32
    0
    Я с телефона, извините, не могу ЛС написать.
    Измените с " Как оформять коммиты, чтобы потом не было больно"
    На «Как оформлять коммиты, чтобы потом не было больно».
      +1
      Спасибо, исправил! До заголовка спеллчекер не добрался :)
      +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
      



      Вот это — искусство, а не «ваши»:
      git commit -m "Update homepage for launch"
      

      ;)
      *как по мне, это плохой пример*

      P.S. Вы бы прогнали статью через спеллчекер, уж больно много опечаток
        +1
        Да, зря на вычитку понадеялся. Прогнал, все исправил, спасибо!
          +2
          Все зависит от изменений. Что вы напишете к коммиту с исправлением опечатки Nmae на Name?
            +2
            я-то так и напишу, но приводить для примера в статье, озаглавленной «Искусство коммита» («The Art of the Commit»), не стал бы :)
              +2
              Хорошо, как правильно написать? Написать сочинение по изменению, которое исправляет серьезный баг горзадо проще, чем по такой мелочи.
                0
                Не думаю, что стоит впадать в крайности и описывать зачем исправлялась опечатка :) По-моему, это вещь очевидная и текста
                Исправить опечатку: имя локального параметра должно быть Name, а не Nmae
                кажется, вполне хватит.
                Но и я придерживаюсь мнения, что писать «сочинение» писать нужно не только по серьёзным багам. Стоит всё же думать о том, что то, что понятно сегодня, может быть (и будет) забыто и непонятно самому себе через месяц/полгода/год, а другим и то вовсе непонятно.
                  +1
                  В целом, я тоже выступаю за развернутые сообщения, но в них не должно быть воды. Если нечего сказать, то ничего говорить не нужно.
                    +3
                    Хм, а зачем? Текста
                    Исправил опечатку
                    по-моему хватит. Если интересно какую именно (с чего бы?), смотрим диффы.
                      +1
                      ну, меня не убудет написать какая именно опечатка была исправлена

                      *и мне кажется, эта информация может быть полезна для околоконтекстного поиска, когда она является опорной для поиска других изменений…
              –2
              А по мне вся эта простыня — плохой пример.

              Этому тексту самое место в багтрекере, как мне кажется.
                +1
                Почему бы ему не быть и там и тут? Чтобы быстро оценить ситуацию все равно удобнее сомтреть git log --oneline
                  +5
                  не согласен

                  метаданные к изменениям кода должны быть там, где они управляются — в SCM
                  зачем в описании ошибки (в багтрекере) — описание того, как и зачем меняется код?
                  кроме того, ошибка может затрагивать несколько версий продукта, несколько его платформ, etc

                  развивая тему:
                  при работе с историей кода, лезть ещё в багтрекер (и хорошо ещё, если с ним есть интеграция), сопоставлять даты комментариев (вы же в комментАриях будете писать как вы меняли код?) с датой самого коммита? нет, увольте…
                    0
                    В IDE типа JetBrains IDEA — все перечисленные вами вещи (в частности сопоставление изменений и строк) делаются за пару кликов. Совершенно не проблема.
                      +1
                      Ну, каждый о своём… не у всех IDE — IDEA
                +1
                Тут помогает разумное использование трекера задач и чего-то вроде git-flow, когда на каждую таску есть ветка. Лень никто никогда не отменят, даже у самых занудных разработчиков, себя я спас от приступов лени, написав pre-commit скрипт, который из названия текущей ветки выдирает айди задачи в таск трекере и прилепляет перед сообщением.

                На самом деле многое зависит от команды и проекта, но, в целом, в статье рекламируется отличная практика.
                  +4
                  Не пишите что поменялось — это всегда видно по диффам

                  Думаю, писать что поменялось тоже нужно. Это полезно, когда надо найти конкретный коммит из разряда «точно помню, что-то где-то я такое делал», или точную дату изменений. Смотреть дифф каждого коммита утомительно. А подробный ответ на вопрос зачем обычно есть в таск-трекере. Я обычно пишу как в последнем пункте — «что и зачем я сделал» в сжатом виде. А так со всем согласен, правильно написано.
                    0
                    Найти коммит, когда известно, что поменялось, помогает git blame.
                    Так что ещё и в commit message это вписывать незачем.
                      0
                      Код может несколько раз измениться, или вообще быть вынесен в другой файл.
                        0
                        Аргументом для git blame можно указать любую историческую версию.
                          0
                          а вот как раз чтобы найти эту историческую версию, надо прошерстить git log
                          )))

                          и хорошо, если можно использовать git log -S/-G
                          (если помнишь что именно изменялось)
                          а при указанном подходе — почти точно поможет git log --grep


                          впрочем, тогда git blame уже будет не нужен
                    +4
                    Для плохих коммитов есть github.com/jayphelps/git-blame-someone-else :D
                      +5
                      Не знаю, что в книге, но в выжимке капитанство. В принципе это давно стандарт, например, вот правила на которые мы ориентируемся kernel.org

                      Хотел бы только добавить, что важно писать не только «зачем», но и «мотивацию». Между «зачем» и «мотивация» на самом деле большая разница. Из мотивации можно выяснить точку зрения автора коммита. Часто бывает неочевидно, почему для решения был выбран именно «вот такой» подход. Дам ссылку на наш опыт насаживания подобного подхода написания текста коммитов Что дал переход с SVN на Git или Git как ключ для синергии хороших практик

                        0
                        Небольшой оффтоп.
                        Долгое время сидели на gerrit (обертка над git), его идеология отличается от github-подобных систем тем, что один смысловой changeset — это один коммит, если есть правки после ревью, делается amend/squash, а ревью идет между ревизиями одного changeset. После ревью в основную ветку попадает ровно один коммит.
                        Так вот это я к тому, что когда изменения по одному тикету размазаны на несколько коммитов, очень неудобно смотреть лог, когда подряд идут коммиты с одним именем, скажем «PROJ-123 fixsmth».
                          0
                          я в случаях, когда тикет размазан по нескольким коммитам, пишу
                          issue #N: бла-бла
                          issue #N: бла-бла-2
                          и последний коммит уже
                          fixed #N: <summary>
                          (и если их больше двух, то обычно вливаю в master с --no-ff)
                          0
                          Пройдя через несколько крупных компаний пришел к такому темплейту:

                          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
                            +1
                            Простите, снова не выдержал.

                              +1
                              удачи в командной разработке или вхождению в новый (для Вас) старый проект, который «оформлялся» подобным образом
                                0
                                Так я не спорил с вашей статьей и поддерживаю вас, сам стараюсь писать полноценно. (Просто смешную пикчу запостить не выдержал)
                                  0
                                  JFI: статья не моя ;)
                              +1
                              Еще есть такая забавная штука :)

                              git commit -m '$(curl -s http://whatthecommit.com/index.txt)'
                              

                              Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                              Самое читаемое