Pull to refresh

Comments 52

Проблема в том, что "фича" это не всегда кусок кода. Это может быть большая задача по смене интерфейсов, раскиданных по куче разных файлов. И просто так обернуть в if это не выйдет.


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


Так же мне не понятно почему хранить ветку на сервере это плохо? Что бы мне поработать на другой машине, мне нужно пушнуть ветку на свой хостинг?


Ну и последнее. Каждый рабочий день я начинаю с того, что делаю ребейз своей текущей задачи на dev. Это ведь не сложно, верно?

Ну и последнее. Каждый рабочий день я начинаю с того, что делаю ребейз своей текущей задачи на dev. Это ведь не сложно, верно?

Если там конфликты в том месте, которое вы активно (т.е. в нескольких коммитах) редактировали, то вы имеете хорошие шансы получить цепочку конфликтов при rebase и делать кучу бесполезных действий для их решения. И даже если конфликтов как бы нет, есть шансы сделать изменения некорректными и не заметить: к примеру, если функция была удалена в файле, который вы не меняли, а вы её у себя используете. Заметить при тестах и исправить ситуацию одним изменением легко, исправить по всей ветке — не очень. Поэтому я в своё время уговорил команду Neovim, что для больших PR можно (и нужно) делать merge, а не rebase. А у себя (и в wiki Neovim) имею команду git ri, которая как бы rebase --interactive, только ничего никуда не переносит, лишь даёт отредактировать историю либо с начала ветки, либо с последнего merge.

Думаю, что «это ведь не сложно» — это сарказм.


Не могли бы вы поделиться кодом вашей команды (алиаса) git ri?

цепочку конфликтов

Для этого был придуман rerere.


исправить по всей ветке — не очень

Делайте коммиты с исправлениями, затем rebase + fixup.
Но серебренной пули не бывает, если ветка действительно огромная, то почему бы и простой мерж не использовать?

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

А зачем нужна настоящая история? Кому какое дело до того, от какого коммита я начал работать? Зачем кому-то нужен в истории коммит и моими отладочными сообщениями?
История должна быть читаема, каждый коммит должен собираться и работать. Это главное.


Я не топлю за линейную историю, нет. Я не мержу ветки через ff. Я только поддерживаю актуальность своей через rebase.

rerere у меня включён. Но я ни разу не видел, чтобы он сработал против «цепочки конфликтов», и не знаю, с чего бы он вообще должен бы сработать на ней: никогда нет никаких «recorded resolutions» для первого rebase (а цепочка конфликтов, тем не менее, есть), их никогда и не будет, если в начале цепочки конфликтов после следующего rebase в конфликтующий код вносятся изменения (что, скорее всего, так).


А «почему не использовать»: не везде разрешено. Кроме того, конкретно в Neovim для меня изменение означало, что я всегда могу использовать merge для больших веток, независимо от того, есть ли там мешающие конфликты или merge требуется для других целей (например, потому что иначе не пройдёт проверка clint.py). git ri я и так всегда использую до последнего во всех проектах (пока у меня нет причин хотеть быть основанным на последнем master).




Исправления, затем rebase+fixup? Чем это поможет? Вот люди переименовали в master функцию foo в функцию bar, я её использовал в коммите X, а потом в коммите Y решил, что здесь больше подойдёт функция baz. Если нет конфликтов после rebase и нет проваленных тестов (а их нет, т.к. переименованная функция более не используется, а использовалось в новом коде, который в master отсутствует и конфликтов не добавляет), то «исправления, затем rebase+fixup» не поможет, нет причин делать исправления. Поможет, если я буду запускать тесты после каждого коммита из rebase, но это именно то, что я имею ввиду под «не очень».


И, самое главное: зачем нужна «настоящая история изменений»: попробуйте делать bisect с точностью до конкретного коммита конкретной feature ветки, а не с точностью до коммитов слияний. Если вы пропустили такую проблему при rebase, то у вас куча коммитов в результате не скомпилируется, а более всего подверженные проблеме длинные ветки так же чаще всего добавляют проблем.


Поэтому никогда никаких rebase, пока я могу их не делать. И git ri, поскольку авторы git обожают сваливать в одну кучу слабо связанную (семантически) функциональность, ещё иногда её даже не позволяя использовать отдельно. К тому же, даже если я хочу именно изменить историю и перенести ветку, гораздо проще сначала только изменить историю, потом только перенести ветку: так легче исправлять свои ошибки, и легче их вообще увидеть (у меня тут конфликт, потому что я промахнулся с тем, куда делать squash/fixup, или потому что в master что‐то поменяли?).

Сколько разработчиков, столько и мнений. И нет ни одного правильного. Кому как удобнее.


я её использовал в коммите X, а потом в коммите Y решил, что здесь больше подойдёт функция baz.

Значит это изменение нужно добавить в коммит X. Например разработчики git или linux не примут такой патч в одной серии, а попросят причесать историю.

Здесь не только «кому как удобнее», есть ещё и объективные показатели. У разных разработчиков разные приоритеты этих показателей, а в разных проектах разные вероятности различного рода конфликтов, но «правильный» ответ под конкретную ситуацию найти можно. Возможно, наши споры помогут кому‐то это сделать.


По поводу добавления изменения в X: я иногда оставляю изменения с неправильной концепцией в ветке просто чтобы показать reviewer’у, что «я проверил эту альтернативу (другую зависимость, другой подход к созданию новой функциональности, …), и она не работает». Пояснения либо в описании изменения, либо в комментариях PR, но не в комментариях кода, если только нет оснований полагать, что кто‐то не должен пытаться использовать эту альтернативу опять. Тут чисто вопрос какие формы коммуникации в команде приемлемы — где провальные решения предполагается документировать и предполагается ли их документировать вообще; ну и вопрос, насколько причёсанная история нужна, тоже.

Мне казалось, первое апреля далеко.


Если по пунктам:


  1. А чем собственно плоха система "1 задача — 1 ветка"? Проблема с merge conflicts в случае единой ветки разработки никуда не исчезает же, просто тонким слоем размазывается по всей истории коммитов. Ну и плюс правило "последний коммит в фичаветке — это мердж из мастера" это уже давно хороший тон.
  2. Код ревью каждого отдельного коммита — это то, с чем справится pyflakes / статический анализатор. Без общего контекста задачи ревьюер на большее не способен.
  3. Точечный перенос коммитов из ветки develop в master не работает. Нарушение хронологии приводит к тому, что ответственный за это будет 40 часов в неделю пытаться разрулить какие-то конфликты. Оно ему надо?
  4. if(FEATURE_ENABLED) работает только в вакууме. Пример — практически любое изменение структуры БД.
  5. Один поломанный коммит ленивого разраба внезапно убивает тесты / CI для всех последующих. За день до релиза вероятность этого увеличивается до 100%.
  6. И наконец, где при такой схеме бедному разработчику хранить коммиты с шикарными описаниями "test" и "dummy", особенно если он работает из более чем одного места?

В качестве бонуса: могу ошибаться, но изменившаяся индентация вокруг if(FEATURE_ENABLED) делает бесполезным git blame.


P.S: CVS в 2017? Не-не-не, Дэвид Блейн

В плюс ко всему, что написали господа выше — если так сильно хочется иметь отключаемые в реалтайме фичи — нет никакой проблемы сделать if (SOME_FEATURE) вашим первым коммитом в собственной feature-ветке. И да, если у вас "долгоживущие ветки", значит вы плохо поделили задачи, и они у вас слишком большие. Разделите задачи так, чтобы каждую можно было сделать за день, а мердж конфликтов дневных изменений — не такая и архисложная задача, как показывает практика.

В оригинале эта статья написана была 9 апреля (может весь апрель никому не верь?).
И выше написанных вопросов ему не задали.
И с автором тут не по обсуждать тоже, перевод…

Теперь не опытные ребята из ру-сообщества прочитают эту статью и внедрят где-то, мде :(
а тем временем 12+ и 1- у статьи, 14 в закладках…

Господи, и правда ведь… Ждем волны вопросов на собеседованиях: " вы используете gitFlow? Фу, это вызывает кучу проблем, о которых я читал".

Статья лучших советов для претендентов на премию Дарвина.
Худший вид костылей (ветвление на флагах), худший вид фальсификации истории изменений (rebase), худший вариант покрытия тестами (удвоение на каждую фичу).
Следуйте всем этим рекомендациям, если хотите развести Г-код, провалить проект и научиться повторять это на регулярной основе со 100% гарантией.
Этот метод контроля версий следовало бы назвать методом трех хромосом, но такое незаслуженно обидит страдающих синдромом Дауна…

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

У корпоративных блогов до некоторого порога число плюсов и добавлений в закладки никак не коррелирует с качеством статьи.
Так что все не настолько плохо.
Возможно многие плюсуют и вносят в закладки не потому, что согласны с автором, а потому что сделана попытка выявить и обобщить проблемы. Некоторые поверхностные публикации про git создают обманчивое впечатление беспроблемности.
Ну, а Вас не удивляет, что примерно так же, например, Google пишет Chrome? И trunk-based разработка у них есть, и флаги для включения фич — об этом есть видео на Youtube, можете посмотреть.
Нет, не удивляет. В гугле тоже могут использовать плохие практики, как и в любом другом месте.

А еще у гугла и фейсбука монорепозитории на стопицот гигабайт. И что теперь, всем так же делать предлагаете? :-)

Нет, им нужны флаги для включения фич в Chrome, поэтому в Chrome флаги у них есть.
Я честно говоря проблемы с GitFlow встречал только при работе с говнокодом.
Когда был один God Object, который изменялся 5 программистами при добавлении новых фич.
Т.к. мне не хотелось лезть в ад merge, я свои фичи выделял в отдельные классы и старался их вызывать минуя God Object.
В таком виде GitFlow хорошо работал.
Я не мешал другим, они не мешали мне. :-)
Любой подход хорош в своем контексте.

Описанный здесь подходит в простых проектах в редкими изменениями.
В сложных проектах с большим количеством изменений, не могу представить альтернатив nvie.com/posts/a-successful-git-branching-model.

Соотношение простых проектов к сложным? Думаю, большинство простые. С учетом парадигм devops, Conf-as-code, Infra-as-code репозитарии плодятся как кролики. Далеко не во всех нужно применять строгие санитарные правила.

Для простых проектов есть GitHub Flow и GitLab Flow, но они и на сложных хорошо работают.


Правила хороши тем, что стандартизируют процесс. Если у вас много проектов и в каждом свои правила, поддерживать их станет значительно сложнее.

Да, это как бы первоисточник.
А как будут выглядеть эти if-ы если разные фичи меняют один код? Что-то не совсем понятно, что и в какой if пойдёт и как потом включить обе фичи одновременно.

Видимо, будет комбинаторный взрыв if-ов.

Проблемы со слиянием (merge или rebase — не суть) веток возникают тогда, когда ветки живут долго и сильно расходятся с master-веткой. Если дробить мелко, проблем вообще не возникает — если конфликты и есть, то они почти всегда тривиальны. Если же возникает редкая ситуация, когда конфликты нетривиальны, то в любом случае мержить должны оба разработчика вместе — каждый добавил что-то свое, и тут уже надо разобраться, как правильно объединить изменения (которые вполне могут оказаться противоречивыми). При этом можно легко параллельно работать хоть с 10 фиче-ветками, что для крупного проекта — совершенно нормальная ситуация.


С фичефлагами получится, что сначала оба разработчика пишут if (feature_a) и if (feature_b), а потом кому-то (очевидно, обоим вместе) придется написать if (feature_a && feature_b). В случае с нетривиальным конфликтом ситуация никак не улучшается. Но при этом:


Если ведётся разработка двух взаимозависимых фич — на время разработки вам понадобится 4 теста для всех их комбинаций.

А если ведется разработка 10 фич, при этом взаимозависимость тривиальная и все мержится без конфликтов? :-) А что делать со всякими декларативными штуками, типа конфигов в json?


Еще, такой подход фактически вносит запрет рефакторинга. Как метод переименовать, например?

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

Поэтому работать надо через «интерфейсы»
Для чего придумали «страшное» слово «инкапсуляция»
<:o)

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

«Интерфейс» это «контракт», если он меняется, то это значит, что поменялось что-то глобальное. Т.е. как минимум перед «рубить с плеча» изменения должны помечаться как depricated.
А при «переименовании»/«удалении» возможно нужно просто создать новый интерфейс?!

Если это не публичное API, а исключительно внутренний интерфейс, зачем такие сложности? Обсудили в команде, взяли и поменяли.


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

А какая разница публичное или нет API?!
Если в команде более двух человек, то лучше придерживаться определенных правил при разработке.
В частности при проектировании и изменении интерфейсов.
Иначе придется решать конфликт, конфликтов слияний. :-)

Естественно. Поэтому
1) делается ветка production != master. (Ну или develop и production = master, тут уж дело вкуса)
2) прежде чем вливать фиче-ветку в мастер, всегда сначала делается rebase на мастер, после чего заново прогоняются все тесты. Конечно, теоретически возможна ситуация, когда, пока разрешал одни конфликты, появляются новые, но на практике вероятность такой ситуации близка к нулю. Я такое встречал один раз лет за 10.

А зачем тут вообще нужен git? Сетевая шара, куда разрабы копипастят свои наработки, реализует все ровно тоже самое, только без git :D

Google Doc. Там и версии хранятся, и видно кто над чем работает!

Когда-то, на рубеже веков, мы так и работали — rsync на машины остальных разрабов.


Читал и ностальгировал.

Rsync в 98 году появился, через 8 лет после CVS.

Но тем не менее, в том коллективе, где я был молодым специалистом, было принято именно так. Видимо, хипстеры и тогда были.


С ужасом представляю, что они использовали в 97

А как у вас мерж происходил то? Rsync просто перезатирает файлы, он не накладывает патчи.

— Мужики, я работаю в oic/lib/
— Хорошо


....


— Мужики, никто oic/lib/bibl_stroki.c не трогал последние два дня?
— Я!
— И я!
— Мля!


Как-то так.

Когда я уходил, тимлид (точнее, Ведущий Специалист) что-то начинал разбираться с SVN. Но это уже без меня было.

  1. Использование какой бы то ни было стратегии без понимания какие проблемы она решает и какие недостатки и ограничения имеет тоже не самый лучший вариант. У нас были прецеденты, когда люди использовали гит и git-flow, но совершенно не понимали зачем. И на самом деле им это было не нужно. Мастера с тегами хватало за глаза.
  2. Выбор стратегии — это больная тема. После некоторых реформ мы для себя выбрали слегка расширенный GitFlow, так как стратегии "хватит мастера" и "каждому заказчику по ветке" совсем не работали и создавали еще больше хаоса. Пришлось некоторых долго обучать
  3. ThreeFlow для нас не подходит, так как есть внешние зависимости и инсталляции очень старых версий, которые по лицензионным причинам получают только критические фиксы, но никак не новые фичи. Хотя для новых продуктов есть мысль использовать ***Flow: по ветке на каждое окружение на котором будет выполняться код. Например, dev, alpha, beta, pre-release, release. 5 веток лишь для примера, каждый может для себя разыграться от OneFlow, и только ставить тэг на то, что пошло в продакшен, или 100500Flow, если хватит ресурсов компании. :)
  4. И да, интеграция feature веток может быть болью (но мы не испытываем проблем с этим, главное интегрироваться часто), но и отключенная флагом функциональность тоже может принести немало боли, когда код покрывается if-ами, конфиги флагами, и неявно влияет на выполнение включенного.
По-сути стараемся решить одну проблему: мердж двух сильно отличающихся веток в develop может вызвать много конфликтов

Добавляя несколько новых:
— Свитчи: не только будут разбросаны по всему проекту, но не понятно как использовать с html, css файлами и другими, которые не содержат кода
— Также подразумевает что часть времени разработчиков будет тратиться на очистку проекта от старого кода: код со свитчами, ссылки на устаревшие файлы и тд, что тоже может быть не весьма очевидно
— Невозможно оттестировать и зарелизить только одну фичу продолжая разработку над другими
— GitFlow удобно использовать с CI: 'develop' деплоится на staging автоматически при мердже и фичи можно демонстрировать продуктовой команде. В вышеописанном сценарии это невозможно делать не переключая свитчи и не делая новый комит, тем самым сводя на нет идею production-ready мастера
ThreeFlow крайне усложняет ревью и в мастер ветке всегда потенциально неработающий код. Куда надежней для каждой фичи создавать отдельную ветку, над которой легко можно сделать ревью и смерджить в девелоп.
Неплохой механизм, но в каких-то замкнутых на себя продуктах или маленьких утилитах а ля shell скриптов.
А когда, каскадно изменяюсятся схемы БД (а то и 2-3), пакеты etl, аналитические кубы и отчёты, rest-сервисы и т.д и т.п. и e.t.c. и всё должно проходить через жёсткий code review, то git flow предпочтительней.
#imho

работаю в компании, которая использует такой подход. С маленькими фичами это более-менее норм (главный минус – засорение кода всякими временными/недоработанными фичами). Но если задача вырастает за пределы одного файла – то начинается ад. Флаг надо пробрасывать везде, другие девелоперы вынуждены вместо одного мерджа постоянно поддерживать две ветки кода, "выключенный" код, тем не менее, легко может что-то поломать. Если речь про web/JS проект – не получится добавлять "дебажный" код, т.к. он станет виден пользователям. И т.д. и т.п.

Работаем два года по GitFlow (на самом деле, rebase flow) в команде из 5 разработчиков над относительно крупным проектом с высокой плотностью как мелких, так и крупных задач. Все очень легко и понятно, возможные нечастые конфликтные ситуации (случаются не часто) обсуждаются в команде и легко решаются. Накладные расходы на содержание feature веток минимальные. Поэтому я как то в упор не вижу проблем, описанных автором и не понимаю, зачем так жестко критиковать хорошо зарекоммендовавший себя за много лет механизм.
Sign up to leave a comment.