Какая практика git commit лучше?

Я искренне верю, что иметь один коммит по одной проблеме — это хорошая практика. Я уверен, что читал это где-то в статье типа «Лучшие практики».

Таким образом, мой рабочий процесс был следующим:

  • Для новой проблемы я создаю новую локальную ветку с git checkout -b new-issue.
  • Зафиксируйте в нем все изменения. Иногда это требует множества коммитов.
  • Когда закончу, я squash коммитов и rebase их в текущую тематическую ветку.
  • Если что-то пойдет не так, я могу git revert зафиксировать, найти ошибку, исправить ее и закоммитить новый патч в тематическую ветку. Я не буду менять историю удаленного репозитория.

Но сегодня я был удивлен, услышав следующий рабочий процесс:

  • Создайте новую ветку для новой проблемы.
  • Вложите в него все.
  • Используйте merge --no-ff, чтобы объединить ветку задачи с тематической веткой (так что у нас будет «слияние-фиксация», которую мы можем revert).
  • Если что-то пойдет не так, мы можем использовать git bisect, чтобы найти ошибку.

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

Согласно второму подходу у нас будет очень запутанная история, с кучей некрасивых, ненужных слияний и коммитов только для одной задачи. Однако мы можем использовать git bisect для поиска ошибок. (Возможно, это лучше для рефакторинга?)


  • Какие плюсы и минусы вы видите для обоих подходов?

  • Какой подход вы используете и почему?

  • Использовали ли вы на практике git bisect для поиска ошибок? (Я не…)


person Viacheslav Kondratiuk    schedule 21.03.2013    source источник
comment
Вы можете использовать опцию --first-parent для git log, чтобы скрыть отдельные коммиты в объединенных ветвях. Совсем не грязно.   -  person Zaz    schedule 09.07.2014


Ответы (2)


В конце концов, это в значительной степени вопрос личного вкуса ... могу только объяснить свой вкус (и немного оправдать его).

Я склонен держать отдельные коммиты рядом, даже если они просто «Исправьте глупые опечатки». Любое «переписывание истории» создает коммиты, которых никогда раньше не было, поэтому они гарантированно никогда не проверялись. Кроме того, минимальные коммиты делают git bisect чрезвычайно полезным, когда ошибка всплывает позже. Лучше иметь возможность сузить его до нескольких измененных строк, чем до недельной работы, спрессованной вместе.

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

person vonbrand    schedule 21.03.2013
comment
Вы когда-нибудь использовали git bisect? Также, допустим, я разрабатываю новый модуль для одного из проектов, я сделал много коммитов и сохранил их в истории. Когда мне понадобится этот модуль в другом проекте, я скопирую его и создам только один коммит. - person Viacheslav Kondratiuk; 22.03.2013
comment
@viakondratiuk, не часто. Но когда мне нужно было выяснить, что сломало прекрасную сборку, это позволило мне найти виновника за несколько попыток. Я никогда даже не пытался искать вручную. - person vonbrand; 22.03.2013

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

  1. создать новую ветку темы
  2. сделать кучу коммитов
  3. just before merging back to the parent branch, clean up the commits:
    • rebase onto the latest version of the parent branch
    • исправление опечатки в сквоше
    • разделить коммиты, делающие несколько вещей одновременно, на отдельные коммиты
    • изменить порядок коммитов, чтобы рецензенту было легче понять последовательность изменений
    • и т.п.
  4. объединиться с --no-ff в родительскую ветку

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

*   354b644 Merge branch 'topic3'
|\
| * 54527e0 remove foo now that it is no longer used
| * 1ef3dad stop linking against foo
| * 7dfc7e5 wrap lines longer than 80 characters, no other changes
| * b45fbcf delete end-of-line whitespace, fix indendataion
|/
*   db13612 Merge branch 'topic2'
|\
| * 961eebf unbreak build by adding a missing semicolon
|/
*   a5b6b16 Merge branch 'topic1'
|\
... (more history not shown)

Приведенный выше график имеет все те же преимущества подхода №1:

  • Вы можете использовать аргумент --first-parent для git log, чтобы получить краткую сводку, похожую на то, что вы получили бы при подходе № 1:

    * 354b644 Merge branch 'topic3'
    * db13612 Merge branch 'topic2'
    * a5b6b16 Merge branch 'topic1'
    ... (more history not shown)
    
  • Вы по-прежнему можете легко просмотреть все изменения, сделанные в тематической ветке. Например, git diff 354b644^..354b644 покажет вам, что было изменено для темы №3.

Но вы получаете преимущества, которые подход № 1 не может вам дать:

  • Историю намного легче просматривать: коммиты b45fbcf и 7dfc7e5 (для ветки topic3) вносят много шума, но не изменяют логику. Кто-то пытается ответить на вопрос: «Какие логические изменения были внесены в тему № 3?» было бы трудно копаться в этом шуме, если бы все эти коммиты были сжаты в один.
  • Коммиты слияния хорошо определяют контекст для серии коммитов в объединенной ветке (например, эта группа коммитов была сделана для решения темы № 3).
  • Более точная детализация коммитов облегчает понимание того, почему было сделано то или иное изменение, что может помочь отличить случайные изменения от преднамеренных, но незаметных.
  • Если над веткой сотрудничали несколько человек, вы можете увидеть, кем они были и какой вклад внес каждый из них.
  • Количество коммитов в объединенной тематической ветке дает вам приблизительное представление о том, сколько было изменено.
  • Временной диапазон коммитов может предоставить полезный контекст.
  • Вы можете легко выбрать конкретное изменение, внесенное в другую ветку (например, выбрать минимальное изменение, необходимое для исправления ошибки в ветке релиза).

Есть один недостаток, о котором я могу думать: может быть сложно настроить ваши инструменты разработки программного обеспечения, чтобы они следовали только пути первого родителя и игнорировали все эти промежуточные коммиты. Например, нет аргумента --first-parent для git bisect. Кроме того, я недостаточно знаком с Jenkins, чтобы понять, насколько легко настроить его для определения приоритета создания и тестирования пути от первого родителя над всеми остальными коммитами.

person Richard Hansen    schedule 30.03.2013