Антипаттерны контроля версий

Просматривая репозитории кода различных проектов всё время сталкиваешься с одними и теми же вещами, которые никак нельзя назвать результатом применения «правильных» практик. Суть и порочная природа их очевидны, что не мешает даже самым трезвым из нас периодически оступаться. Можно вспомнить самые типичные из них.

Таинственный коммит

Суть: Комментарий к коммиту не несёт полезной информации либо вовсе отсутствует.

Причины: Лень и ничего больше.

Проблемы: О назначении коммита можно судить лишь ознакомившись с набором изменений входящих в него. Как следствие, постоянные трудности при поиске определённых коммитов, попытках переноса коммитов между ветками и т.п. Каждый раз когда вы хотите что-то сделать с коммитом неизбежно возникает вопрос: «А тот ли это коммит, который мне нужен?»

Решения: Пишите, мать вашу, комментарии! Желательно более предметные чем «bug fixed» или «some stuff added».

Многоцелевой «баллистический» коммит

Суть: Коммит содержит набор изменений не связанных между собой.

Причины: Лень, недостаточный опыт эксплуатации систем контроля версий.

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

Решения: По хорошему любой несервисный коммит (не связанный с созданием/слиянием веток и т.п.) должен иметь целью одно из трёх действий: добавление новой функциональности, выполнение рефакторинга, исправление дефекта. Дробя коммиты по содержимому мы естественным образом реализуем принцип «разделяй и властвуй». Не бойтесь сделать несколько коммитов вместо одного. Система контроля версий от этого не лопнет, а вы в перспективе только выиграете.

Выгребная яма

Суть: Репозиторий содержит множество файлов, контроль версий для которых не оправдан разумными причинами.

Причины: Лень, недостаточная осведомлённость о назначении и принципах работы систем контроля версий.

Проблемы: Засорение репозитория временными файлами, файлами IDE не несущими полезной информации, бинарными файлами сборок (в совсем запущенных случаях). Ситуация с бинарными файлами осложняется тем, что для них проблематично отслеживание изменений. И даже когда в репозитории находятся только действительно нужные бинарные файлы (сторонние библиотеки, ресурсы приложения и т.п.), если объём и количество их велико и они часто меняются, то размер репозитория может очень быстро вырасти до непристойных размеров.

Решения: Пользуйтесь средствами типа того же .gitignore, чтобы в репозиторий попадало только то чему там место. Иногда (хотя и редко) бывает полезно хранить ресурсы отдельно, не выполняя для них контроль версий.

Черенок

Суть: Использование веток сведено к минимуму и от них отказываются даже в тех случаях когда они показаны, практически вся разработка ведётся на trunk’е.

Причины: Лень, недостаточный опыт эксплуатации систем контроля версий.

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

Решения: Учиться, учиться и учиться. Есть много материалов хорошо разъясняющих что, зачем и как.

Заросли

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

Причины: После subversion простота и легковесность веток в том же git безусловно воодушевляет и мотивирует на великие свершения.

Проблемы: При большом числе веток и интенсивном их пересечении восприятие основного тренда разработки может быть сильно затруднено. Также растёт вероятность допущения ошибок при работе с ветками.

Решения: Разумеется ветки полезны и отказываться от них нет смысла. Но не следует делать простые вещи сложными путями. В git например есть fast-forward merging, который позволяет скрыть следы того, что ветка вообще была. А применение иерархии параллельных веток с последовательным слиянием позволяет упростить trunk, не засоряя его кучей feature branch’ей. Репозиторий postgresql хороший пример того, что даже в крупном проекте trunk может быть прямым и изящным.

Блуждающий ствол

Суть: Использование нетрадиционных подходов при управлении основными ветвями разработки.

Причины: Недостаточный опыт эксплуатации систем контроля версий.

Проблемы: Если вы создали некоторую структуру веток, а потом не знаете как сделать с ними простые вещи типа релиза, то вы определённо делаете что-то не так.

Решения: Можно выделить два типичных подхода к организации основных ветвей разработки. Подход номер раз: Стабильный trunk. На trunk’е всегда стабильный код, который собирается, проходит тесты и прочее. Разработка ведётся на дополнительных ветвях. Как только всё необходимое в такой ветке реализовано и проверено ветка сливается на trunk. Возможна многоуровневая иерархия таких веток, что позволяет работать даже с очень большими объёмами кода. По ходу разработки на trunk’е появляются тэги версий. Подход номер два: Активный trunk. На trunk’е самый последний код, который может даже не собираться. По мере реализации функциональности от trunk’а отделяются ветки версий. В дальнейшем в них заносятся только исправления и на них же появляются тэги версий. Первый подход удобен для изоляции изменений, второй — для поддержки множества версий. Необходимость в более сложных вариациях на практике возникает редко.

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