Флант corporate blog
Programming
Git
Development Management
25 October 2019

Мой любимый Git-коммит

Original author: David Thompson
Translation
Прим. перев.: Эта публикация британского программиста, ставшая настоящим хитом в англоязычном интернете, ссылается на Git-коммит 6-летней давности. Он был зафиксирован в одном из открытых репозиториев Government Digital Service — службы, занимающейся развитием цифровых услуг в Великобритании и поддерживающей проект GOV.UK. Сам коммит интересен не столько изменениями в коде, сколько сопровождающим их описанием…


Картинка из xkcd #1296

Я обожаю описания коммитов в Git. При правильном применении их можно назвать одним из самых мощных инструментов по документированию эволюции кодовой базы за время ее существования. Свою точку зрения хочу проиллюстрировать на примере моего самого любимого описания.

Этот коммит относится ко времени, когда я работал в Government Digital Service. Его автором является разработчик по имени Dan Carley, и у него довольно непримечательное заглавие: «Конвертировал шаблон в US-ASCII, чтобы исправить ошибку».

«Я внедрил несколько тестов в ветку feature для соответствия содержимому `/etc/nginx/router_routes.conf`. Они хорошо работали, если запускались командами `bundle exec rake spec` или `bundle exec rspec modules/router/spec`. Но при запуске `bundle exec rake` каждый should-блок завершался с ошибкой:

    ArgumentError:
      invalid byte sequence in US-ASCII

В конечном итоге я обнаружил, что после исключения выражения `.with_content(//)` все ошибки уходят. Что в файле спецификации нет никаких странных символов. А также то, что его можно воспроизвести, вызвав Puppet в том же интерпретаторе:

    rake -E 'require "puppet"' spec

Этот шаблон, похоже, является единственным файлом в нашей кодовой базе с кодировкой ‘utf-8’. Все остальные файлы в ‘us-ascii’:

    dcarley-MBA:puppet dcarley$ find modules -type f -exec file --mime {} \+ | grep utf
    modules/router/templates/routes.conf.erb:                                         text/plain; charset=utf-8

Попытка перекодировать его в US-ASCII завершилась неудачно из-за одного символа, выглядящего как пробел:

    dcarley-MBA:puppet dcarley$ iconv -f UTF8 -t US-ASCII modules/router/templates/routes.conf.erb 2>&1 | tail -n5
      proxy_intercept_errors off;
 
      # Set proxy timeout to 50 seconds as a quick fix for problems
      #
    iconv: modules/router/templates/routes.conf.erb:458:3: cannot convert

После его замены (вручную) файл снова стал ‘US-ASCII’:

    dcarley-MBA:puppet dcarley$ file --mime modules/router/templates/routes.conf.erb
    modules/router/templates/routes.conf.erb: text/plain; charset=us-ascii

Теперь тесты работают! Целый час моей жизни не вернуть...»

В оригинале

Convert template to US-ASCII to fix error


I introduced some tests in a feature branch to match the contents of
`/etc/nginx/router_routes.conf`. They worked fine when run with `bundle exec
rake spec` or `bundle exec rspec modules/router/spec`. But when run as
`bundle exec rake` each should block failed with:

    ArgumentError:
      invalid byte sequence in US-ASCII

I eventually found that removing the `.with_content(//)` matchers made the
errors go away. That there weren't any weird characters in the spec file. And
that it could be reproduced by requiring Puppet in the same interpreter with:

    rake -E 'require "puppet"' spec

That particular template appears to be the only file in our codebase with an
identified encoding of `utf-8`. All others are `us-ascii`:

    dcarley-MBA:puppet dcarley$ find modules -type f -exec file --mime {} \+ | grep utf
    modules/router/templates/routes.conf.erb:                                         text/plain; charset=utf-8

Attempting to convert that file back to US-ASCII identified the offending
character as something that looked like a whitespace:

    dcarley-MBA:puppet dcarley$ iconv -f UTF8 -t US-ASCII modules/router/templates/routes.conf.erb 2>&1 | tail -n5
      proxy_intercept_errors off;

      # Set proxy timeout to 50 seconds as a quick fix for problems
      #
    iconv: modules/router/templates/routes.conf.erb:458:3: cannot convert

After replacing it (by hand) the file identifies as `us-ascii` again:

    dcarley-MBA:puppet dcarley$ file --mime modules/router/templates/routes.conf.erb
    modules/router/templates/routes.conf.erb: text/plain; charset=us-ascii

Now the tests work! One hour of my life I won't get back..



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

Почему мне нравится этот коммит


Бесчисленное число раз я приводил его как пример того, на что способны описания коммитов. Он в чем-то забавен из-за соотношения изменений в коде и размера описания, но нравится он мне вовсе не поэтому.

В другой компании, у другого разработчика, все сообщение коммита могло бы свестись к фразам вроде «заменил пробел», «исправил ошибку» или (в зависимости от культуры команды) к выпадам в сторону изобретателя неразрывных пробелов. Вместо этого Дэн нашел время, чтобы создать подробное описание, полезное для окружающих. Я хотел бы остановиться на причинах, по которым считаю этот коммит действительно хорошим примером.

Раскрывает причину внесенных изменений


Лучшие описания коммитов не только повествуют о том, что изменилось, но и объясняют, почему. В нашем случае:

Я внедрил несколько тестов в ветку feature для соответствия содержимому `/etc/nginx/router_routes.conf`. Они хорошо работали, если запускались командами `bundle exec rake spec` или `bundle exec rspec modules/router/spec`. Но при запуске `bundle exec rake` каждый should-блок завершался с ошибкой:

    ArgumentError:
      invalid byte sequence in US-ASCII

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

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

Хорошо подходит для поиска


Одним из ключевых элементов данного описания является сама ошибка, с которой начались дальнейшие поиски:

ArgumentError:
invalid byte sequence in US-ASCII

Любой человек, столкнувшийся с этой ошибкой, может выполнить поиск по кодовой базе, либо запустив git log --grep "invalid byte sequence", либо с помощью GitHub'овского поиска по коммитам. На самом деле, судя по результатам поиска, многие так уже поступили и выяснили, кто и когда сталкивался с этой проблемой и как ее решили в итоге.

Обеспечивает полноту картины


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

В конечном итоге я обнаружил, что после исключения выражения `.with_content(//)` все ошибки уходят. Что в файле спецификации нет никаких странных символов. А также то, что его можно воспроизвести, вызвав Puppet в том же интерпретаторе.

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

Делает всех чуточку умнее


Дэн здесь сделал одну вещь, которую я очень ценю: привел все команды, которые выполнял на каждой стадии. Это отличный и доступный способ распространения знаний в команде. Читая его описание коммита, можно узнать много нового об инструментарии Unix:

  • в find можно передавать аргумент -exec, чтобы выполнять команду с каждым найденным файлом;
  • добавление \+ в конце команды делает нечто очень интересное (передает несколько имен файлов в команду file, а не выполняет команду по разу для каждого файла);
  • file --mime позволяет узнать MIME-тип файла;
  • существует утилита iconv.

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

Развивает сопереживание и доверие


Теперь тесты работают! Целый час моей жизни не вернуть...

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

Теперь представьте похожее сообщение, прикрепленное ко временному хаку или фрагменту кода-прототипа, который попал в production и «пустил там корни» (как это часто бывает с такими фрагментами). Подобное описание коммита напоминает всем, что за каждым изменением стоит человек, принимающий лучшее решение из возможных с учетом информации, доступной на тот момент.

Хорошие коммиты важны


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

Если вы хотите узнать немного больше о плюсах хороших описаний коммитов и о некоторых инструментах, облегчающих структурирование правок, могу порекомендовать следующие материалы:


P.S. от переводчика


Читайте также в нашем блоге:


+131
44.7k 175
Comments 93