Привычный хаос в названиях коммитов. Знакомая картина?

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

Меня зовут Ержан Ташбенбетов, я работаю в одной из команд Яндекс.Маркета. И сегодня я расскажу читателям Хабра, какие инструменты для создания осмысленных коммитов мы используем в команде. Приглашаю присоединиться к обсуждению этой темы.


Отсутствие договоренностей при наименования коммитов затрудняет работу с историей в Git. Такое было в нашей команде. До использования общего для всех регламента и внедрения автоматизации типичные коммиты выглядели следующим образом:

SECRETMRKT-700: пропали логотипы партнеров
Приложение падает, поправил.
SECRETMRKT-701, SECRETMRKT-702: Отцентрировал картинки на всех ...

Во-первых, каждый разработчик писал сообщения как хотел: кто-то описывал задачу, кто-то перечислял внесенные изменения, кто-то использовал генератор случайных фраз. Всё было вразнобой. Во-вторых, номера задач, присутствовавшие в коммитах, часто укорачивали полезный текст. Всё это мешало эффективно работать с историей в Git.

По этой причине мы внедрили в команде стандарт Conventional Commits, стали генерировать коммиты в консольной утилите commitizen и проверять результат с помощью commitlint. В результате коммиты изменились и стали выглядит так:

refactor(tutorial): оптимизировать работу эпиков в тултипах
feat(products): добавить банер с новогодними скидками
fix(products): исправить в банере формат даты

Читать историю и распознавать внесенные изменения стало проще. Мы не отказались от указания номеров задач, всё аккуратно перенесено внутрь коммитов согласно конвенции Conventional Commits.

Дальше я расскажу, как добиться схожего порядка в Git.



Лучшие практики, рекомендации и распространенные решения при наименовании коммитов


Если попробовать разобраться в том, какие практики применяются в индустрии, то можно обнаружить следующие варианты:

  • Статьи с общими советами по написанию коммитов. По большей части они вполне логичны и неплохо раскрывают тему, но чувствуется беспорядочность и отсутствие комплексного решения вопроса.
  • Стандарты по написанию коммитов. Их немного. Они представляют собой документы с четким перечнем правил, довольно часто написанных специально для крупной библиотеки или фреймворка. Эти стандарты подкупают системным подходом, популярностью и поддержкой в open-source сообществе.

Нам нужно больше порядка в коммитах!

Методология Conventional Commits выделяется на фоне других стандартов и заслуживает пристального изучения по ряду причин:

  1. Она хорошо документирована и проработана. В её спецификации даны ответы на наиболее распространенные вопросы.
  2. Создатели конвенции вдохновились требованиями к написанию коммитов, которые используются в популярном и проверенном временем фреймворке AngularJS.
  3. Правил конвенции придерживаются несколько крупных и популярных open-source библиотек (таких как yargs и lerna).
  4. К плюсам отнесу подготовку к автоматическому формированию Release Notes и Change Log.

Пример коммита по этому стандарту:

fix(products): поправить длину строки с ценой

Часть заголовков неправильно отображается в мобильной версии из-за ошибок
в проектировании универсальных компонентов.

МЕТА ДАННЫЕ: SECRETMRKT-578, SECRETMRKT-602



Основные тезисы Conventional Commits


  • Разработчик должен придерживаться следующей структуры коммитов:
    <type>(<scope>): <subject>

    <body>

    <footer>
  • У коммита должен быть заголовок, может быть тело и нижний колонтитул.
  • Заголовок коммита должен начинаться с типа (type), указывающего на специфику внесенных в кодовую базу изменений, и завершаться описанием.
  • Наряду с обязательными feat, fix (использование которых строго регламентировано), допускаются и другие типы.
  • У коммита может быть область (scope). Она характеризует фрагмент кода, которую затронули изменения. Область следует за типом коммита. Стандарт не регламентирует четкий список областей. Примеры областей: eslint, git, analytics и т.д.
  • Описание коммита должно быть сразу после типа/области.
  • Тело коммита может быть использовано для детализации изменений. Тело должно быть отделено от описания пустой строкой.
  • Нижний колонтитул следует использовать для указания внешних ссылок, контекста коммита или другой мета информации. Нижний колонтитул должен быть отделен от тела пустой строкой.


Кроме перечисленых в конвенции правил мы используем следущие популярные рекомендации:


  • В теле коммита пишем что было изменено и почему.
  • Используем следующие типы коммитов:
    build Сборка проекта или изменения внешних зависимостей
    ci Настройка CI и работа со скриптами
    docs Обновление документации
    feat Добавление нового функционала
    fix Исправление ошибок
    perf Изменения направленные на улучшение производительности
    refactor Правки кода без исправления ошибок или добавления новых функций
    revert Откат на предыдущие коммиты
    style Правки по кодстайлу (табы, отступы, точки, запятые и т.д.)
    test Добавление тестов
  • Пишем описание в повелительном наклонении (imperative mood), точно также как сам Git.
    Merge branch 'fix/SECRETMRKT-749-fix-typos-in-titles'
  • Не закачиваем описание коммита знаками препинания.




Стандарт коммитов Conventional Commits используют котрибьюторы lerna



Как просто перейти на правильное наименование коммитов?


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



Настроим утилиту commitizen


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

  1. Установим утилиту commitizen глобально (вам могут потребоваться права администратора).

    npm i -g commitizen
  2. Следом установим адаптер cz-customizable. Он нужен для настройки шаблона с вопросами, которым пользуется утилита commitizen.

    npm i -D cz-customizable
  3. Создадим файл commitizen.js, он нужен для настройки cz-customizable. Поместим созданный файл в директорию ./config/git. Рекомендую не захламлять корень проекта конфигурационными файлами и стараться группировать файлы в подготовленной для этого папке. Содержимое:

    Показать commitizen.js
    "use strict";
    
    module.exports = {
      // Добавим описание на русском языке ко всем типам
      types: [
        {
          value: "build",
          name: "build:     Сборка проекта или изменения внешних зависимостей"
        },
        { value: "ci", name: "ci:        Настройка CI и работа со скриптами" },
        { value: "docs", name: "docs:      Обновление документации" },
        { value: "feat", name: "feat:      Добавление нового функционала" },
        { value: "fix", name: "fix:       Исправление ошибок" },
        {
          value: "perf",
          name: "perf:      Изменения направленные на улучшение производительности"
        },
        {
          value: "refactor",
          name:
            "refactor:  Правки кода без исправления ошибок или добавления новых функций"
        },
        { value: "revert", name: "revert:    Откат на предыдущие коммиты" },
        {
          value: "style",
          name:
            "style:     Правки по кодстайлу (табы, отступы, точки, запятые и т.д.)"
        },
        { value: "test", name: "test:      Добавление тестов" }
      ],
    
      // Область. Она характеризует фрагмент кода, которую затронули изменения
      scopes: [
        { name: "components" },
        { name: "tutorial" },
        { name: "catalog" },
        { name: "product" }
      ],
    
      // Возможность задать спец ОБЛАСТЬ для определенного типа коммита (пример для 'fix')
      /*
      scopeOverrides: {
        fix: [
          {name: 'style'},
          {name: 'e2eTest'},
          {name: 'unitTest'}
        ]
      },
      */
    
      // Поменяем дефолтные вопросы
      messages: {
        type: "Какие изменения вы вносите?",
        scope: "\nВыберите ОБЛАСТЬ, которую вы изменили (опционально):",
        // Спросим если allowCustomScopes в true
        customScope: "Укажите свою ОБЛАСТЬ:",
        subject: "Напишите КОРОТКОЕ описание в ПОВЕЛИТЕЛЬНОМ наклонении:\n",
        body:
          'Напишите ПОДРОБНОЕ описание (опционально). Используйте "|" для новой строки:\n',
        breaking: "Список BREAKING CHANGES (опционально):\n",
        footer:
          "Место для мета данных (тикетов, ссылок и остального). Например: SECRETMRKT-700, SECRETMRKT-800:\n",
        confirmCommit: "Вас устраивает получившийся коммит?"
      },
    
      // Разрешим собственную ОБЛАСТЬ
      allowCustomScopes: true,
    
      // Запрет на Breaking Changes
      allowBreakingChanges: false,
    
      // Префикс для нижнего колонтитула
      footerPrefix: "МЕТА ДАННЫЕ:",
    
      // limit subject length
      subjectLimit: 72
    };


  4. Добавим в package.json ссылки на cz-customizable и созданный ранее конфигурационный файл:

    Показать часть package.json
    {
      "config": {
        "commitizen": {
          "path": "node_modules/cz-customizable"
        },
        "cz-customizable": {
          "config": "config/git/commitizen.js"
        }
      },
    }

  5. Давайте проверим получившийся результат. Наберите в терминале следующую команду:

    git cz

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

Обязательно посмотрите на пример работы настроенной утилиты commitizen и подключенного к нему адаптера cz-cusomizable



Настроим утилиты husky и commitlint


  1. Установим в проект husky и commitlint:

    npm i -D husky @commitlint/cli
  2. С помощью husky добавим проверку коммитов. Для этого в package.json сразу после скриптов добавим следующий хук и укажем в нем ссылку на файл commitlint.js:

    Показать часть package.json
    {
      "scripts": {
        "test": "echo \"Error: no test specified\" && exit 1"
      },
      "husky": {
        "hooks": {
          "commit-msg": "commitlint -E HUSKY_GIT_PARAMS -g './config/git/commitlint.js'"
        }
      },
      "devDependencies": {
        "@commitlint/cli": "^7.2.1",
        "husky": "^1.1.3",
    }


  3. Создадим файл commitlint.js, необходимый для корректной работы линтера. Поместим созданный файл в директорию ./config/git. Содержимое файла:

    Показать commitlint.js
    // Файл создан на основе @commitlint/config-conventional
    
    module.exports = {
      rules: {
        // Тело коммита должно начинаться с пустой строки
        "body-leading-blank": [2, "always"],
    
        // Нижний колонтитул коммита должен начинаться с пустой строки
        "footer-leading-blank": [2, "always"],
    
        // Максимальная длина заголовка 72 символа
        "header-max-length": [2, "always", 72],
    
        // Область всегда только в нижнем регистре
        "scope-case": [2, "always", "lower-case"],
    
        // Описание не может быть пустым
        "subject-empty": [2, "never"],
    
        // Описание не должно заканчиваться '.'
        "subject-full-stop": [2, "never", "."],
    
        // Тип всегда только в нижнем регистре
        "type-case": [2, "always", "lower-case"],
    
        // Тип не может быть пустым
        "type-empty": [2, "never"],
    
        // Перечислим все возможные варианты коммитов
        "type-enum": [
          2,
          "always",
          [
            "build",
            "ci",
            "docs",
            "feat",
            "fix",
            "perf",
            "refactor",
            "revert",
            "style",
            "test"
          ]
        ]
      }
    };



Всё. Теперь все коммиты будут проверяться перед отправкой в репозиторий :)

Обязательно посмотрите на пример работы настроенной утилиты commitlint



Так что выбрать commitizen или commitlint?


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


Почему стандарты рекомендуют использовать повелительное наклонение?


Это крайне интересный вопрос. Коммит это изменение кода, сообщение в коммите можно расценивать как инструкцию по изменению этого кода. Сделать, изменить, добавить, обновить, поправить? — всё это конкретные инструкции для разработчика.

Кстати, повелительное наклонение рекомендовано в самой системе версионирования Git:

[[imperative-mood]]
Describe your changes in imperative mood, e.g. "make xyzzy do frotz"
instead of "[This patch] makes xyzzy do frotz" or "[I] changed xyzzy
to do frotz", as if you are giving orders to the codebase to change
its behavior.


Зачем придерживаться каких-либо конвенций? Стоит ли тратить на это время? Какой в этом профит?


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

Попробуйте и поделитесь результатом.


Полезные ссылки:


Комментарии (64)


  1. jreznot
    03.12.2018 10:42
    +3

    Отличный материал по теме chris.beams.io/posts/git-commit


    1. tashbenbetov Автор
      03.12.2018 12:26

      Спасибо, согласен с вами, хорошая статья. Добавил к полезным ссылкам.


    1. ilammy
      03.12.2018 18:44
      +1

      И ещё туда же, по приёмам работы с git в целом: sethrobertson.github.io/GitBestPractices



  1. danfe
    03.12.2018 11:31

    image


  1. hdfan2
    03.12.2018 11:35

    По-моему, если у вас большинство комментариев типа «поправил баг» и «небольшое изменение», то у вас куда более серьёзные проблемы. Нужно начинать с них, требуя у разрабов понятного описания (возможно, с обязательной ссылкой на задачу в багтрекере), а потом уже возиться с оформлением. Или делать это одновременно, но описание должно быть приоритетней.


    1. tashbenbetov Автор
      03.12.2018 12:45

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


  1. multiprogramm
    03.12.2018 12:04

    fix(products): поправить длину строки с ценой

    Часть заголовков неправильно отображается в мобильной версии из-за ошибок
    в проектировании универсальных компонентов.

    МЕТА ДАННЫЕ: SECRETMRKT-578, SECRETMRKT-602

    Мне кажется, что тут возникла небольшая ошибка. Коммит — не то, что должно быть сделано, а то, что уже сделано. Что нужно сделать должно быть написано в таске где-то или в требованиях. Как я понял, в этом примере такая информация находится в SECRETMRKT-578, SECRETMRKT-602. Т.е. верный вариант будет
    fix(products): поправлена длина строки с ценой

    Часть заголовков неправильно отображались в мобильной версии из-за ошибок
    в проектировании универсальных компонентов.

    МЕТАДАННЫЕ: SECRETMRKT-578, SECRETMRKT-602

    И тогда автоформирование Change Log уже взлетит само собой.


    1. vUdav
      03.12.2018 12:37

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


      1. VolCh
        03.12.2018 13:04

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


      1. jsirex
        03.12.2018 13:07
        +1

        Предположу, что так сделано из-за идеи в гите с переписыванием истории коммитов. В английском варианте:
        If I (merge|cherry-pick|rebase|use|...) this commit it will (commit message):
        If I use this commit it will «Add logout button to home page».

        Это позволяет мейнтейнерам буквально по кусочкам собирать нужную цепочку из сотен коммитов и веток.

        По-русски, наверное, стоит перефразирвать, т.к. слова меняются из-за склонения и времени.


        1. dolbnya
          03.12.2018 13:28

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


          1. powerman
            03.12.2018 21:33
            +1

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


            1. Nalivai
              03.12.2018 23:25

              Так никто так коммит в разговоре не описывает, ни по-русски, ни по английски. Но соглашение уже как бы выбрано, так что или иму следуем, или все переделываем.


            1. funca
              04.12.2018 00:14

              Инфинитив удобно использовать в названиях pull/merge реквестов, как отражение самих задач для разработки (сделать, добавить, исправить, ...). Они в свою очередь порождают рабочие ветки в git, а по завершении (squash & merge) сопровождаются комментарием в нужном стиле и аккуратно укладываются в master.

              Правки внутри рабочих веток удобно именовать в стиле бортового журнала (т.е. как угодно), т.к. они отражают ваш путь решения задачи. Чем сложнее задача, тем путь может быть более удивительными и непредсказуемым. Здесь главное не мешать творческому процессу — чем меньше церимоний тем лучше. Во время squash все эти шаги будут удалены или переписаны.

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


    1. 1KoT1
      04.12.2018 06:40

      Как по мне, на английском языке коммиты в повелительном наклонении воспринимаются хорошо. Само собой получается так их писать.
      А на русском выглядит очень странно. Да.


  1. worldmind
    03.12.2018 15:04
    +1

    Погуглил — есть тулзы и на других языках (питон например), если кому не охота `npm` юзать по причинам частых проблем с безопасностью или отсутствием необходимости иметь npm.


  1. ilyarsoftware
    03.12.2018 17:40
    +1

    Отличный материал, спасибо! Есть вопросы:
    1. Список изменений (changelog.md) генерируете на основе истории или нет (есть мнение, что это не лучший способ), какой подход у вас к созданию и поддержке истории изменений?
    2. Применяете git-flow или свой поход? Расскажите подробнее.
    3. Интересно как относитесь к линейной истории это полезно или нет? Мое мнение, что линейная или частично линейная история дает массу профитов и даже применяя git-flow история может быть линейная, если приложить немного усилий, но мало кто видит в этом преимущества, давно хочу понять почему. На текущий момент гипотиреоза в том, что мало кто использует историю как инструмент анализа или может быть есть иной способ сохранить блейм или анализировать историю в незавидности от ее линейности.


    1. ilammy
      03.12.2018 18:40
      +2

      По поводу истории изменений, можно я вклинюсь с отличным описанием того, почему её следует поддерживать вручную?

      keepachangelog.com/en/1.0.0


    1. tashbenbetov Автор
      03.12.2018 18:47
      +1

      Спасибо. Могу поделиться опытом нашей команды:

      1. Change Log не ведем, есть Release Notes. Перед каждым Pull Request-ом разработчик заполняет в файле ReleaseNotes.md следующие пункты:
      — New (Что нового? (фичи, новая функциональность));
      — Improvements (Какие улучшения мы добавили в существующие фичи);
      — Fixes (Список исправленных багов);
      — Operations (Eslint, обновление библиотек и т.д.).

      На основе этого файла формируются Release Notes каждой версии. Этот документ смотрят QA специалисты. После публикации версии содержимое файла ReleaseNotes.md обнуляется.

      2. Выбрали классический git-flow (хотя сам я сторонник другого ветвления). Это правильно по многим причинам, но для меня главная — открытость к ротациям в команде. Отраслевые стандарты позволяют свести начальный инструктаж к минимуму.

      3. Не задумывался линейна или не линейная история. Использую в работе удобный GitKraken, всё наглядно. За ссылки благодарю, изучу внимательно этот вопрос.


      1. ilyarsoftware
        03.12.2018 20:10

        1. Перед каждым Pull Request-ом разработчик заполняет в файле ReleaseNotes.md

        Это один файл на проект? Учитывая конвенцию и генерацию коммитов что мешает это файл формировать автоматически?

        2. Выбрали классический git-flow (хотя сам я сторонник другого ветвления)

        Другого ветвления, это какого?
        Учитывая Ваш опыт применения git-flow, представите, что будет с историей, если каждый разработчик будет синхронизировать свою рабочую ветку не слиянием с develop, а через перемещение git pull --rebase origin develop?


      1. Sap_ru
        04.12.2018 00:02

        Ай ай ай, бесплатный GitKraken запрещён для коммерческого использования


        1. kost
          04.12.2018 02:32

          Есть же и платные (Pro/Enterprise) версии: www.gitkraken.com/pricing



    1. erlyvideo
      03.12.2018 22:29

      мы стараемся придерживаться строго линейной истории, но вот недавно перешли со строгого --no-ff на строгий --ff, что бы были видны мерж коммиты.

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


      1. poxvuibr
        03.12.2018 23:44

        --ff делает так, чтобы были видны мёрж коммиты?


  1. arTk_ev
    03.12.2018 19:50

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


    1. ilyarsoftware
      03.12.2018 19:58

      Мой опыт говорит обратное, если вести историю по правилам, то как минимум можно воспользоватся git changelog, дает вполне адекватный материал, который можно обработать в ручном или полу-автоматическом режиме. Например применить агрегацию и фильтрацию на основе типов. Мы это делаем руками, надеюсь есть инструмент о котором я еще не знаю.


      1. arTk_ev
        03.12.2018 21:29

        Я немного о другом.
        Типичный случай. Нужно пофиксить сложный баг — в первую очередь иду смотреть историю гита, анотации. Если микрокомиты с тегами — то все легко, сразу видно коммит в имени которого сразу прикреплен номер таски по которому эти изменения были сделаны и почему, даже если они были сделаны 5 лет назад. А уже в таске все прописано, аналитика, какие кейсы для воспроизведения, и почему конкретно было принято такое решение.
        А если это левый мердж, в котором под сотню ченджей, без тикета и тегов — то и смотреть бесполезно.
        А список ченджей он никому то и не нужен, написать можно всякое


        1. ilyarsoftware
          04.12.2018 12:05

          Аннотации или git blame это отдельная история в теории за его формирование отвечает правила по оформлению кода и текущие конвенции не решают этот вопрос полностью, в общем это отдельная тема.

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

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

          Но это не решает вопроса аннотации тут нужен опыт, дополнительная конвенция или правила по оформлению кода которые это учитывают.


  1. f0y
    03.12.2018 19:56
    +3

    Мы тоже хотели навести порядок в коммитах, но потом поняли что мы не смотрим историю. Зачастую, когда смотришь историю, интересен ответ не "что было сделано?", а "почему так было сделано?". На второй вопрос можно получить ответ из постановки задачи и из инструмента для код ревью. Для того чтобы найти и то и другое нам достаточно номера тикета в коммите.


    1. erlyvideo
      03.12.2018 22:37

      а часто делаете git bisect?


      1. f0y
        03.12.2018 22:41

        Очевидно что нет)


    1. bogolt
      04.12.2018 01:39

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


  1. Sap_ru
    03.12.2018 20:19

    Не хватает возможность описывать смешанные типы и области для коммитов.
    Области по своей природе могут смешанными при каких-то сложные и больших правках. Переход на новые библиотеки, утилиты сборки, какой-то глобальный рефакторинг и т.п.
    Смешанные типы это в общем случае плохо, но для маленьких проектов практически неизбежно, т.к. строгое следование лучшим практикам может трудоёмкость в небеса и сделать такие проекты бессмысленными.
    В таких случаях лучше предусмотреть возможность.
    Кстати, в какой-то момент времени оказалось, что комментарии коммитов этого хорошо, но нужен внятный независимый ченжлог. Прикрутил его формирование по коммитам. А потом оказалось, что удобнее сделать наоборот — генерировать комментарии по изменение ченжлога. Нужно сказать, что некоторое время было прямо счастье. И в больших и в маленьких и даже в микро-проектах дописывает правишь текстовый ченжлог (по правилам -с разделением на фичи/баги и т.п.), потом делаешь коммит и комментарий генерируется из изменений ченж-лога. Одновременно переформатируется сам ченжлог — добавляется информации о дате коммита, номере сборки, статусе релез/дебаг и т.п. А при коммите в релиз всё это автоматически собирается (от прошлого релиза) ещё раз переформатируется, собирается в один большой список изменение, снабжается версией, генерируется комментарий в коммит. Очень удобно было! Имеешь текстовый файл с описанием основных изменений, имеешь список изменений для релизов и т.п.
    Но всё держалось на мега-скрипте для баша, который со временем превысил предел сложности, развалился не несколько версий и т.п. А духу и времени всё это облагородить и переписать на каком-нибудь пайтоне не находится. В результате в новых проектах снова обычные комментарии к коммитам :(


    1. powerman
      03.12.2018 22:17
      +1

      Смешанные области просто не надо указывать вообще. Смысл указания области в том, чтобы можно было легко пропускать коммиты, которые явно не представляют интереса. Если сложно чётко описать, что затрагивает коммит, а что нет — просто не надо указывать ничего. Если коммит затрагивает пару областей — никто не запрещает указать обе через запятую: "fix(this,that): something".


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


      В таких случаях лучше предусмотреть возможность.

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


      1. Sap_ru
        04.12.2018 00:15
        -1

        Ну, почему же. Описать можно. Просто коммит может затрагивать две области.
        Что значит забить на стандарт? Никто не призывает «забить». Но под стандарт пуштся парсеры и утилиты. И если в реальном мире есть какая-то ситуация, а стандарт её не предусматривает, то это хреновый стандарт и от него будут в этой ситуации отступать. Или просто будут использовать какие-то другие соглашения.
        Стандарт, он не для того, чтобы разработчиков дрессировать. Он для того, чтобы можно было различные утилиты совместимым образом автоматизировать. А вопросы, что и когда можно, а что нельзя решают договорённостями в каждой конкретной команде под её конкретные потребности.
        Вот, я например, не могут делать один коммит на одну область/тип. Просто потому, что нет у меня таких ресурсов под такие небольшие проекты. И это популярная ситуация. На самом деле матёрый энтерпрайз это скорее исключение, чем правило и большинство команды вынуждено идти на компромисы. По крайней мере до тей пор, пока проекты не достигнут определённой степени зрелости и/или коммерческого успеха. Значит они (и я в их числе) будут городить свои костыли. Писать несколько областей или типов через запятую, скорее всего. И все утилиты я будут пилить под это. Но это рушит совместимость, обесценивает и ограничивает стандарт. А если окажется, что что-то стандартное я допилить не могу, то я просто не будут использовать этот стандарт и будут искать что-то другое.
        Меня всегда удивляет, когда разрабатывают стандарт, но не закладывают каких-то очевидных расширений в него.


  1. powerman
    03.12.2018 22:08
    +2

    Стандарт допускает следующие типы коммитов:

    Это не совсем так. Стандарт (текущая версия v1.0.0-beta.2) определяет два особых типа (feat и fix) и отдельно все остальные. Для остальных приведены несколько примеров, но не более того.


    Описание коммита не должно закачиваться знаками препинания.

    IMHO здраво, но стандарт этого не требует, хотя примеры написаны в этом стиле.


    В описание необходимо использовать повелительное наклонение (imperative mood), точно такое же, какое использует сам Git.

    IMHO плохая идея, и стандарт этого даже не упоминает. Более того, многие примеры явно не в этом стиле: "feat(lang): added polish language", "fix: minor typos in code"…


    Я бы не придирался, если бы Вы сказали, что описанное — это ваше внутреннее соглашение, но ведь Вы поместили все эти пункты под заголовок "Основные тезисы Conventional Commits", что явно не соответствует истине.


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

    А вот это явно противоречит и духу и букве стандарта. Стандарт рекомендуется применять в момент ручного squash фиче-бранча. Нигде не рекомендуется использовать его для каждого коммита внутри фиче-бранча (и это очень здраво). Не уверен, возможно ли ограничить упомянутые утилиты исключительно этими squashed коммитами в master, но в их использовании нет реальной необходимости если не принуждать разработчиков каждый коммит в их фиче-бранчах оформлять в этом стиле.


    Вообще, основная польза этой спецификации не в том, что она задаёт правила оформления коммитов, а в том, что она приводит к линейной истории, состоящей из осмысленных и цельных изменений, которую можно обрабатывать утилитами для автоматизации механических действий вроде подготовки changelog или выбора номера следующей версии для релиза. Иными словами, суть спецификации составляют 4 термина: squash, feat, fix, BREAKING CHANGE — именно они создают ценность. Всё остальное можно поменять, и ничего принципиально не изменится.


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


    1. tashbenbetov Автор
      03.12.2018 23:29

      Спасибо за комментарий! Действительно часть советов и рекомендаций ошибочно попала в блок тезисов конвенции Conventional Commits. Внес корректировки. Благодарю за внимательное прочтение статьи. Ни в коем случае не хотел ввести кого-то в заблуждение. Сам люблю порядок и ценю точность формулировок.


  1. BalinTomsk
    03.12.2018 22:14

    deleted


  1. marshinov
    04.12.2018 00:15
    +1

    А если просто <НОМЕР-ЗАДАЧИ-В-ТРЕКЕРЕ> и сквошить все комиты? 1 комит — 1 задача. Кому интересно, пойдет в джиру и посмотрит, не?


    1. ashumkin
      04.12.2018 19:37
      +1

      Лично я против. Это смена контекста. К тому же, возможно, такое, что тикет переоткрывали не раз, и тогда придётся сравнивать время комментариев и коммита.
      Джира может быть и недоступна по разным причинам (работаю дома, интернет отвалился, etc).
      Ну, а кроме того, убеждён, что человек, пишущий осмысленный текст, чётче начинает понимать, что же он сделал, и, возможно, даже поймёт, что сделал не всё или не так


  1. Xandrmoro
    04.12.2018 02:36
    +1

    #номер_стори название стори
    Зачем придумывать велосипеды? (и да, сквошить все чейнджи в один коммит при PR, чтобы не мусорить в мейне, и нет, имена коммитов в фичабранче не интересуют вообще никого и никогда)



  1. Zuy
    04.12.2018 07:17

    Поддержу коллег выше. Коммит должен иметь форму: номер тикета: название тикета.
    Один коммит должен относиться к одному тикету. Если у вас тикеты связаны между собой то линкуйте их в Jira или что там у вас еще. Тикет — единственное место, куда кто-то еще смотрит. Коммит мессадж никто не читает.


    1. valery1707
      04.12.2018 11:19

      Коммит должен иметь форму: номер тикета: название тикета.

      Название тикета может не отражать изменений которые были внесены для исправления этого тикета.


      Один коммит должен относиться к одному тикету.

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


      1. VolCh
        04.12.2018 18:27

        Несколько коммитов на тикет не нарушают правила «Один коммит должен относиться к одному тикету»


        1. valery1707
          04.12.2018 18:38

          Но нарушают предыдущее Коммит должен иметь форму: номер тикета: название тикета.
          Или вы видите смысл в нескольких коммитах с одинаковым комментарием?


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


          Но что делать когда каждый тикет описывает свою проблему часть которой фиксит твой коммит?


      1. Zuy
        05.12.2018 02:20

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

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

        В описанном в статье виде получается часть информации в тикете, а часть в коммите.


  1. OpieOP
    04.12.2018 07:40

    «Крит пофикшен асапом»
    Боже, что это за латынь?


    1. hdfan2
      04.12.2018 15:25

      Глокая куздра штеко пофиксила крит и кудрячит асапа.


  1. pphilips
    04.12.2018 09:10

    Раз git flow упомянут, может стоит упомянуть и trunk based подход? barro.github.io/2016/02/a-succesful-git-branching-model-considered-harmful
    trunkbaseddevelopment.com


  1. dremlin2000
    04.12.2018 09:11

    Если вы делаете agile/scrum в команде, то любая story/задача/баг whatever, должна быть на канбан борде с уникальным номером. Как правило, мы в команде указываем номер story с тайтлом при коммите. Так что никаких вопросов не возникает у членов команды. А если же у вас каждый разраб делает комиты и никто потом не может понять что именно правилось и для чего, то здесь пару проблем. 1-ая — вы не делаете agile и каждый разраб получает задачи индивидуально, 2-ая — вы не делает pair programming/mobbing/code review в команде. И как результат, очень слабая коммуникация внутри команды.


    1. VolCh
      04.12.2018 18:29

      Канбан или скрам разве диктуют универсальный номер?


      1. dremlin2000
        05.12.2018 00:21

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


  1. le1ic
    04.12.2018 10:10

    Все правильно пишут про номера тикетов. Разумное именование коммитов — утопия, под которую можно подвести только процентов 50% изменений.

    Мы в компании пользуемся гитхабом, и там метаинформация побогаче. PR линкуется к тикету или связанным тикетам. Тикет рассказывает, ЧТО мы делаем / фиксим. В описании PR я кратко описываю КАК мы это делаем (если это не очевидное устранение, допустим, опечатки). Таким образом остаются какие-то более-менее адекватные следы.


    1. VolCh
      04.12.2018 18:31

      Под конкретный тикет определить каждый коммит тоже может быть затруднительно, особенно если треккер не поддерживает иерархии типа эпик-стори-таск-подтаск, а чисто плоский списко тасков


  1. ShinRa
    04.12.2018 10:32

    Спасибо, полезная статья. Честно говоря на работе уже кровь течет из глаз, когда в очередной раз видишь такие коммиты:
    fix
    fix
    fix
    done


    1. ilyarsoftware
      04.12.2018 12:07

      Согласен, в таких случаях отправляю автора коммитов читать git rebase: порядок в локальных ветках.


      1. VolCh
        04.12.2018 18:32

        rebase как любое переписівание истории — опасная штука.


        1. ilyarsoftware
          04.12.2018 19:34

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


  1. lesenoklenok
    04.12.2018 10:38

    Спасибо, очень полезная статья.


  1. Agel_Nash
    05.12.2018 00:55

    Не удалось подружиться из-за commit.gpgsign=true
    Хуки запускаются до того, как будет введет пароль


  1. BekoBou
    06.12.2018 12:49

    А вы как-то правите комментарии при слиянии веток?


    Я про вот это сообщение по умолчанию — Merge branch '<merged-branch>' into '<branch>'


    P.S. С сообщения к коммитам в представленном репозитории очень толсто получилось.