Комментарии 24
Как я уже говорил в обсуждении ThreeFlow (начало здесь) просто разрешите merge, и никогда не делайте rebase для больших ветвей, за исключением редактирования истории (в смысле rebase --interactive
, но без собственно rebase
; у mercurial на это есть histedit, для git’а пришлось написать длинный alias, который определяет, с каким аргументами нужно вызвать rebase --interactive
, чтобы ничего никуда не переносить и, к тому же, не уничтожить случайно слияния). «Периодический rebase» с лёгкостью незаметно переведёт пачку коммитов в ещё менее рабочее состояние, чем они были до этого, что отрицательно скажется на точность bisect, если в ветке найдутся ошибки.
Сливание пачки в один коммит решает эту проблему.
Что касается rebase, его делает автор изменений, убедившись, что все работает на свежем мастере. Разрешение конфликтов мало чем отличается от такового в случае merge, но в последнем мы получаем два коммита на одно изменение, что добавляет хаоса в проект.
Куда сливать пачку коммитов? Предполагается сливать master в длинную ветку, пока она не готова, если такое слияние зачем‐то требуется (возникли конфликты, был проведён рефакторинг, …), а не длинную ветку в master. Гарантировать работоспособность коммитов не нужно, но не нужно и делать их менее рабочими, чем они есть. Полный squash — это та же самая потеря точности bisect. А при rebase без squash будут цепочки конфликтов.
Относительно хаоса: а зачем вы используете историю, что оно вас волнует? Я вижу основные три применения: annotate, bisect при проблемах и создание списка изменений. Для bisect чем больше коммитов, тем лучше (если они, конечно, достаточно рабочие). Для annotate тоже. Для списка изменений git вполне позволяет вам пройтись только по «первым родителям», которыми будут слияния веток в master, а не слияния master в ветки, так что это только вопрос «насколько адекватны описания слияний».
Инкрементальную, одномерную последовательность коммитов намного легче анализировать.
Может и кажется, что легче, но если вы не делаете ещё и squash, то это абсолютно бесполезно, потому как вы анализируете не то, что реально было, а конфликты никуда не деваются, просто теперь размазаны и логику их разрешений опять никто не объснит. А если вы делаете, то вы получаете последовательность огромных патчей, из описания которой значительная часть логики автора пропала при squash; и, дополнительно, логику автора для разрешения конфликтов никто не объясняет и тут, просто теперь все притворяются, что никаких конфликтов не было.
И, самое весёлое, последовательность сплюснутых огромных коммитов в виде патчей соответствует последовательности разниц (в виде патчей) между первыми родителями при использовании слияний. Т.е. вы для «лёгкости анализа» зазря выкидываете кучу информации, ничего взамен реально не получая.
Коммиты нужно стараться минимизировать, это упростит код ревью и сделает историю более подробной и понятной (для аннотаций и bisect в том числе). Конечно такая организация требует дополнительных усилий, как и поддержание чистоты кода.
На review идёт уже результат слияния, он ничем не отличается от результата rebase+squash, кроме того, что вместо одного коммита с одним описанием есть последовательность. История со слияниями более подробна, понятность также ограничена авторами изменений и не всегда сильно страдает, а усилий нужно делать меньше. Понять «о чём думал автор» в случае спорных решений легче при последовательности изменений с описаниями, а сама модель более лояльна к большим изменениям, которые нельзя минимизировать.
Однако большие изменения возникают не сами по себе, а из подхода к разработке. Введение feature-toggle'ов позволяет коммитить частично готовый функционал (например набор оттестированных классов/функций), что способствует работе со свежим мастером и быть в курсе изменений в нем. Также большие изменения почти неизбежны при работе с legacy (читай «говно-») кодом, который требует обширного рефакторинга, но после некоторого времени, при правильном подходе, эта проблем уходит.
Тут конечно дело вкуса. Для большого, динамично развивающегося проекта я выбираю trunk-based с feature-toggle'ми.
Feature-toggl’ы не всегда возможны и увеличивают затраты на разработку — их нужно создавать, их нужно убирать, с ними нужно научить работать CI. Review тоже придётся делать чаще, при этом не обладая всей картиной: уже готовые классы и описание задачи reviewer увидит сразу, а насколько готовые классы оптимальны для задачи — нет, нужно выспрашивать у автора, какая картина у него в голове; к тому же я не удивлюсь, если в ходе работы над сложной задачей разработчик часто сначала будет допиливать что может до включения в master, а потом выпиливать это обратно. И это в дополнение к затратам на поддержание «чистоты» истории. А refactoring требуется не только legacy, хотя обширный, может, и реже — смотря что не учли при разработке архитектуры. В trunk-based с флагами я пока вижу только «давайте увеличим трудозатраты программистов и reviewer’ов (часто — других программистов) на то, чтобы тимлид смог читать „чистую“ историю».
У нас плоская структура (Scrum), тимлида как такового нет, есть более опытные разработчики и менее опытные. Историю читают все. Знания шарятся между всеми разработчиками проекта (уменьшаем bus-factor) в том числе посредством код ревью. Для эффективности этого процесса нужно минимизировать изменения, иначе код ревью превращается в проверку код-стайла, так как понять суть изменений слишком сложно.
Для долгоживущего проекта время разработки не критично, критично время внесения изменений. И feature toggl'ы — позволяют поддерживать это время на приемлемом уровне, так же как и SOLID, юнит тесты, TDD.
CI можно гонять для всех юнит тестов и для интеграционных тестов продакшн конфигурации. Но это отдельная тема.
Относительно хаоса: а зачем вы используете историю, что оно вас волнует?
Да просто посмотреть лог за неделю, что было сделано. Приятнее видеть список, а не гордиев узел из мердж коммитов.
Коммит должен представлять законченный набор изменений. Если это так, то имеет смысл влить его в мастер, а не держать в ветке.
Я собственно веду к подходу trunk-based разработки, к которому в итоге пришел за много лет, так как этот подход дает стабильный мастер (с возможностью релиза с любого коммита) при большом количестве ежедневных изменений, простоту код-ревью, список изменений понятный каждому участнику проекта.
Такой перевод очень больно читать. Я пока понял, что "фиксация" — это коммит, думал, что я вообще в Алису в стране чудес попал
А «запрос слияния» и «ствол» как вам? ))))
Спорщики забывают о том, что слово «commit» используется в нескольких значениях: как процесс (глагол), результат этого процесса (существительное) и даже состояние (в некотором смысле, прилагательное). Процесс создания коммита правильнее называть фиксацией. Сам результат уже принято называть просто коммитом. Попытки категорически избегать слова «фиксация» могут привести к появлению нелепых формулировок вроде «коммичения». Изменения могут быть либо закоммичены, либо зафиксированы — оба варианта выглядят приемлемо.
Там ровно такое же код ревью, ровно такой же PR с обсуждением и так далее.
Master — продакшен
Dev — стейдж
GitFlow на хабре
В случае GitFlow проблема возникает только в dev'е, а мастер всегда рабочий (ну, во всяком случае чаще).
В вашем случае если ошибку упустили на ревью, если не обнаружили на тестах ДО слияния, то оно вполне может попасть на прод.
Перешли в компании на этот подход, избавились от develop. Стало проще делать релизы.
GitHub Flow