В компании, в которой я работаю в настоящее время, мы используем при
разработке довольно распространённую модель ветвления, а в качестве
инструмента для стандартизации работы по этой схеме git-flow. Так же мы
дополнили эту схему ещё одной веткой — staging
. Это временная ветка, в
которую сливаются feature branches
, и на основе неё делаются
промежуточные релизы на тестовый сервер. Естественно, всё, что
происходит в этой ветке, нужно для предварительного просмотра и
тестирования выполненных задач и никак не должно попадать ни в основную
ветку разработки, ни в master, то есть в итоговый релиз. В принципе,
схема работы достаточно удачная. Она упрощает взаимодействие и работу
большой команды с разным навыком работы с git, и нештатные ситуации
случаются достаточно редко, но зато, если случаются, то это запоминается
надолго.
Началось всё с того, что мы стали замечать, что в master
или в develop
ветку начинают попадать коммиты из ветки staging
. Самые распространённые
из них — это мержи веток с задачами. Первый раз решили, что кто-то по
невнимательности примержил стейджинг в ветку с задачей и потом вылил,
разбираться точно как и кто не стали, просто всем ещё раз рассказали как
нужно вести разработку и посоветовали внимательнее следить за тем, что
они делают.
Затем история повторилась, но уже в другой команде с другими людьми. Стали копать, выяснили, что и раньше такое было, просто никто не замечал лишних коммитов в истории, потому что в принципе код работал, тесты проходили и ладно.
Разгадка проста и понятна сразу, кто-то примержил staging в ветку со
своей задачей, а потом через некоторое время, когда она вышла в релиз,
все нежелательные коммиты и попали в develop
, а потом — в master
. Но
как? Если первый раз нам удалось найти злополучный коммит вида Merge
branch staging into 'feature/fourth'
, то в последний раз во всей истории
всё было чисто. Каждый участник команды говорил, что он всё делал по
инструкции и по модели ветвления.
Те кто знаком с тем, как происходит мерж веток в git, наверное, уже догадались почему так. А остальным я продемонстрирую на примере.
Мы имеем новый репозиторий с несколькими коммитами в master
ветку и
одним в develop
Далее создадим новую задачу(first
), закоммитим в неё первый коммит и
опубликуем.
1 2 3 4 5 |
|
То же самое сделаем для second
1 2 3 4 5 |
|
Теперь менеджер попросил нас вылить вторую задачу на тестовый сервер:
1 2 3 4 |
|
Но, предположим, у нас произошла ошибка в приложении, связанная только с тестовым сервером и другого программиста попросили её исправить:
1 2 3 4 |
|
Далее нас попросили вылить на тестовый сервер первую задачу. Для этого
мы перешли в staging
, обновили его и влили в него первую задачу:
1 2 3 4 5 6 7 |
|
Пока всё верно. От ветки develop
сделаны две задачи. В ветку staging
влиты обе ветки с задачами и есть ещё один коммит нужный только для неё.
Мы возвращаемся к разработке второй задачи, но нас кто-то отвлёк и случайно получается, что “на автомате из истории” мы вполняем такую последовательность комманд:
1 2 |
|
И ничего вроде бы страшного не произошло, в дальнейшей рутине мы можем ничего не заметить. Так называемый мерж коммит не создался, потому что мерж прошёл в режиме fast-forward
.
История, если бы в ней не было коммита Staging fixed
, тоже сильно не
изменилась.
1 2 3 4 5 6 7 8 9 |
|
Но кто смотрит историю после перехода в ветку? Поэтому вы продолжаете работу. Делаем ещё один коммит в первую задачу (хотя в реале их может быть гораздо больше) и публикуем её.
1 2 3 4 |
|
Никаких подозрительных сообщений в консоли. Всё вроде бы нормально. Поэтому мы продолжаем спокойно спать по ночам, а остальная комманда работать над проектом, потому что по сути только наша ветка содержит сейчас стейджинг.
Хотя уже по графику видно, что произошёл некоторый факап, но когда веток и людей много этого незаметно, да и кто смотрит графики.
Затем нас просят выпустить первую задачу и сделать релиз, что мы и делаем:
1 2 3 4 5 |
|
Ну вот и всё. Полный фарш. В релиз попало то, что было в staging
. В истории всё чисто с точки зрения того, что нет мерж коммита:
1 2 3 4 5 6 7 8 9 10 11 12 |
|
Если посмотреть reflog, то вот те строчки, которые были сгенерированы во время выполнения ошибочной команды:
1 2 3 |
|
Тоже ничего необычного.
Причина такого поведения — это fast-forward мерж. При таком слиянии в случае, если это возможно, указатель ветки просто перемещается на то же место, куда указывает ветка, которая вливается:
1 2 |
|
Как исправить получившуюся ситуацию? Никак. Можно попробовать найти
ветку, в которую влит staging
и попробовать откатить её слияние в
develop
,
а также удалить коммиты с релизом и почистить все ветки, но это долго и
сложно, особенно если веток с задачами много.
Что делать чтобы такое не произошло?
Что делать, чтобы такое не произошло?
- Внимательно следить за исполняемыми командами.
- Если используется git-flow, то использовать его команды для обновления и публикации веток.
- Использовать либо полный синтаксис команды
git push/pull
, либо полностью сокращённый синтаксис без указания веток. Потому что в ситуации из приведённого примера не указывается, в какую ветку слить изменения, поэтому так и получилось, что информация изstaging
попала в ветку с задачей.