Pull to refresh

Comments 41

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

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

А ещё это помогает в геймификации процесс программирования. К примеру я играю сам с собой в игру, мол, чем больше у меня зелёных квадратиков на GitHub и чем они зеленее, тем лучше. Лучшая стратегия победы в такой игре это делать каждый день минимум один коммит, и тогда ты точно побеждаешь, но вот реальность показывает что это делать не просто. И развивать самодисциплину - то ещё испытание. Но чем меньше коммиты тем проще это делать, тем проще себя мотивировать и проще получать удовольствие от того что коммиты сделаны :) А после этого хочется делать ещё коммитов и ещё :)

А ещё это помогает следовать принципу атомарной ответственности в задачах, если привязывать каждый коммит к конкретной задаче (issue), никогда нельзя будет сделать так, чтобы в нём содержался код связанный с несколькими задачами, это тоже дополнительно дисциплинирует и делает процесс разработки максимально прозрачным. То есть можно будет потом сделать roadmap/project, из которого можно перейти на конкретные issues, а оттуда на конкретные коммиты которые делались в рамках этой задачи.

Хе-хе. Я тоже играю в эту игру. Дофаминовый майнинг.

Тогда вот, хвастаюсь своими достижениями :)

P.S.
В моём первом комментарии опечатка: "коммент" "коммит"

Круто, да. Но мой кумир - Андрей Ситник.

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

Так squash убивает машину времени. Меня, как археолога, это обламывает.

На самом деле все прежние коммиты в git остаются - просто их так легко через git log <ref> не увидеть, но при желании отыскать их обратно несложно.

Так ведь это до git gc, после чего уже не факт, что они останутся.

Если оставлять именованные ветки – то останутся. Чисто для археологов.

Если оставлять именованные ветки, то в чем смысл их сквашить в вливать одним коммитом? Зачем на ровном месте делать проблемы?

В душе не знаю. Мне вообще после hg гитовские ветки кажутся каким-то нелепым убожеством: вместо полноценных веток (где ветка – это все коммиты, сделанные в неё, а не только указатель на последний) – какие-то тэги на конец ветки. Мало-мальски ситуацию выправляет запрет fast-forward merge (тогда в git log можно будет показывать только первого родителя), но это (по сравнению с фильтром по веткам) костыль.

А я считаю нужно законодательно запретить плодить коммиты на каждое телодвижение и 100500 фиксов во время ревью/тестирования. Потом черт ногу сломит найти в истории что с чем связано.

Запретите fast-forward merge в мастер или куда вы там вливаете изменения – и будет вам счастье: всегда достаточно посмотреть ровно один коммит с мёржем.

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

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

Но может зависеть от репозитория, с которым вы работаете.

Сквош можно делать после ревью. Понятное дело, что сквош-ребейз-форспуш возможны только вместе, но тут уже зависит от нужной степени педантичности на проекте. Я когда-то на аутсорсе приложил руку к одному гугловому проекту и мне очень понравился подход одна фича - один коммит. Крайне удобно при нормальном CD делать автоматический changelog. Ну и при использовании blame сразу понятно, откуда растут ноги у кода.

Вместо автоматического changelog-а лучше бы просто с каждым PR в него добавлять нужный текст, над которым гораздо больше контроля. И вы во фразе "одна фича - один коммит" пропустили слово merge :) "Одна фича - один merge-коммит".

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

Мерж коммиты не нужны. Fast forward справится после ребейза.

Текст в changelog писать вручную, который будет дублировать историю в гите? Зачем? А если реверт или черри пик? А когда больше 1 человека будет править текстовый файл с историей - привет постоянные мерж конфликты? Не нужно усложнять :)

С fast-forward после ребейза вы теряете информацию о том, какие коммиты к каким задачам относятся. Мердж-коммит как раз и содержит ссылку на задачу в трекере.

Текст в changelog писать вручную, который будет дублировать историю в гите?

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

А когда больше 1 человека будет править текстовый файл с историей - привет постоянные мерж конфликты?

Поэтому перед мерджем ветки делается ее ребейз на текущий мастер и автор PR решает конфликты. Ему лучше знать, что оставить. История выходит линейная, легкая к разборам. А в вашей ситуации что получится?

  • Реализована фича X

  • ...

  • Revert "Реализована фича X"

  • ...

  • Опять реализована фича X, но без Y

  • ...

  • Исправление к реализации фичи X, добавили Z

И как из этого понять, реализована фича X или нет?

Каким образом мерж коммит получает ссылку на задачу в трекере? Я много где видел другую практику - айди тикета писать вначале коммита, например в квадратных скобках.

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

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

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

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

Поддержание собираемости -- это не оверхед, а инвестиции в будущее на упрощение разбора возможных неочевидных регрессий из-за ваших изменений.

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

Атомарный коммит ценен сам по себе.

Проект на этой версии собирается, работает, тесты проходит.

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

Но повторюсь, коммит должен быть рабочим. Иначе это херня на палочке.

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

А может содержать четверть шага для подготовки к фиче: несколько строчек метода, который не работоспособен, но нигде ещё и не вызывается. Параметры в конфиге, которые ещё нигде не используются и так далее. О том-то у меня и была речь - насколько он должен быть "атомарным". Если это фича целиком, и это не фича из пары строчек, то это уже в общем-то и не атомарный коммит.

Для меня атомарные коммиты ценны в первую очередь во время ревью. Это как аксиомы или теоремы, при доказательстве которых можно опираться на предыдущие.

Можно сделать ревью одного коммита, в котором будет какой-то rest-клиент с кучкой бойлерплейта, json-кодеками, тестами и т.п.

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

И при ревью бизнес-логики уже не думать о клиенте. Я это смотрел там все хорошо. Или за меня кто-то уже посмотрел и там все хорошо.

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

У вас коммит с нерабочей функцией, но которую ещё никто не использует. Это нормально. Но вы же ее будете доделывать? Так докиньте изменения в этот самый коммит. Тесты для нее туда же. У вас же есть в руках инструмент под названием rebase.

Другим разработчикам совсем не интересен полет вашей мысли. При ревью им не важно как вы к этому пришли, важен конечный результат. Так перепишите историю через rebase, разбив задачку на какие-то логические шаги. Универсального рецепта никто вам не даст.

Для меня атомарные коммиты ценны в первую очередь во время ревью.

А разве вы их детализируете во время ревью? Ревью ведь обычно делается уже по финальному результату, где все коммиты собраны в один pr, который знаменует собой какую-то стадию готовности

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

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

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

По вашей логике аксиомы и теоремы были доказаны без предварительных ошибочных вычислений/мыслей ... то есть Пифагор такой сел за вечер и написал аксиому, я думаю он сначала сделал сотни ошибочных вычислений/набросков (в нашей терминологии коммиты) прежде чем получил верный результат (в нашей терминологии сложилась картина всей фичи + доехало финальное ТЗ). Я всегда раньше старался обновлять коммиты через амменд, потом форс пуш, но забил, ибо всё равно финальный МР показывает всё в одной куче и потом при мерже всё засквошится.

Ваша мысль понятна на самом деле, просто это очень сложно соблюдать, банально код не собирается в вечер пятницы и такой полурабочий код пушишь в ремот на случай если винт отъедет на выходных, чтобы был бэкап на сервере, а в понедельник уже лень аммендить/форспушить/берейзить ))

По вашей логике аксиомы и теоремы были доказаны без предварительных ошибочных вычислений/мыслей

А вы изучали только доказательство теоремы Пифагора или же еще все неудачные попытки ее доказать?

и такой полурабочий код пушишь в ремот на случай если винт отъедет на выходных, чтобы был бэкап на сервере, а в понедельник уже лень аммендить/форспушить/берейзить ))

А вот это недостаток распространившейся модели использования git, которая стала чрезмерно централизованной. Кто мешает иметь 'чистовой' репозитарий + по репозитарию на каждого разработчика, куда он и будет пушать для бакапных целей? Ну или хотя бы просто еще один 'черновой'?

И да, потому merge request слать так, как оно и задумывалось - из своего репозитария в репозитарий инженера по сборке и тестирования, чтобы он все это у себя собрал, протестировал и только после этого влил в 'чистовой'.
Заодно 'чистовой' не будет засоряться всякими левыми ветками.

Первый раз такое вижу в рамках одного проекта внутри компании, а где такое практикуется если не секрет, чтобы на проекте у каждого разработчика были копии репозитория с которыми они работают и через него делают МР в основной репо ? Сам так делал только с публичными чужими проектами через форк, потом в нем фикс/фича и с него делал МР в основной репозиторий, но это скорее исключение из правил.

Я тоже не видел. Хотя оно часть описываемых проблем с замусориванием репы вполне бы решило.

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

Имхо, здесь принцип common sense: скажем, 100500 файлов в одном коммите это беда. Но и 9000 коммитов это тоже беда. Благо есть каждодневные скрамы, до чего-то да можно договориться)

Тоже не совсем согласен. У нас подход атомарная фича ветка, если что-то пошло не так, то ее можно откатить. А коммиты в фиче ветке идут хаотично, потому что ТЗ меняется + QA может найти баги, но во время принятия МР/ПР в основную ветку это всё сквошится (квасится) средствами CI. Если что-то нужно добавить в фиче ветку не относящееся к ней, то заводится отдельный тикет-ветка и через основную подливается через мерж/рэбейз (кому как удобно).

У нас подход атомарная фича ветка

Неужели кто-то еще по-другому работает? Тут проблема часто в другом. Процесс написания кода для отдельной feature редко когда линейный. Какой-то отдельный кусок кода может переписываться несколько раз, или добавляться, а потом удаляться - и отправлять в PR всё это отдельными "атомарными" коммитами это как-то нехорошо (кому охота на ревью разбираться в этих твоих душевных метаниях , что были пока ты код писал). Но при этом еще часто в ветке есть коммиты которые к самой фиче не относятся (самый простой пример это форматирование уже имеющегося кода) и они идут вперемешку с "feature" коммитами. Поэтому простой squash ветки перед PR тоже, получается, идея не очень хорошая. Единственный вариант, который приходит на ум это делать еще одну вспомогательную ветку, потом накатывать в неё cherry-pick из рабочей feature-ветки так чтобы коммиты оказались логически упорядочены, а потом делать отдельные squash-и для отдельных, логически связанных цепочек коммитов. Но это может быть достаточно трудоёмкий процесс.

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

проекты разные, и нет единого понимания атомарности, и поэтому нет лучшего или худшего подхода

  1. Размер проекта

  2. Скорость разработки

  3. Сложность изменений

  4. Количество разработчиков и команд

  5. Распределение ответственности между ними

  6. Особенности тестирования

  7. И прочее

Все круто, но рефакторинг. Переименование метода. Изменение сигнатуры функции. Разбиение класса на несколько или объединение классов. Изменение структуры исходного когда. Создание финики или наоборот избавление от неё. Изменение структуры наследования сложных объектов. Это всё атомарно? Ха! А отменить такое можно? А перенести такое изменение в другое место истории? А если рефакторинг делается периодически?

В режиме "ковровое бомбометание" спасает "trunk based development".

Да, но в случае регулярных рефакторингов, которые )при правильной организации) очень хорошо влияют на поддерживаемость кода, уменьшая проклятье легаси, рассказы про обязательную необходимость атомарный комитов становятся сказками.
А без периодического рефакторинга любой сколько-либо сложный проект очень быстро превращается в лютое устаревшее "легаси".
А если идёт хорошая и динамичная работа, то рефакториниги могут быть и еженедельными.

Без squash история проекта превращается в изрядную помойку. Когда у тебя на работе 25 микросервисов, можно просто утонуть в этих ваших "атомарных коммитах". Атомарной, то есть вполне понятной и завершённой, должна быть задача. И принцип "одна задача - один коммит в master/develop"

Sign up to leave a comment.

Articles