Как стать автором
Обновить

Уроки Git-хаоса: форс-ресет, удалённые ветки и GitLab

Уровень сложностиПростой
Время на прочтение5 мин
Количество просмотров3.2K

Привет! Я старший fullstack-разработчик в крупной b2b-команде, где мы активно развиваем IT турпродукты и сопровождаем легаси-проекты. Недавно мне довелось временно заменить тимлида — он ушёл в отпуск, оставив напоследок фразу: «Ты не будешь деплоить».

Спойлер: деплоил. И не просто деплоил, а чуть не похоронил релиз из-за одного неосторожного git reset --hard. К счастью, всё закончилось хорошо — но пришлось восстановливать ветки из GitLab’а, бороться с удалённой историей и вручную черри-пикать задачи.

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

🧩 Контекст и старт релиза

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

Перед уходом он, с лёгкой иронией, сказал:
«Ты не будешь деплоить».

Как показало утро — деплоить как раз мне и придётся.

📌 Что происходит

На дейлике быстро становится ясно: релиз всё-таки на мне.
Это не что-то экстраординарное — раньше я релизил в прод, но уже больше года этим не занимался. За это время команда, процессы и репозиторий изменились.

Я смотрю на текущую релизную ветку, которую успел собрать тимлид, и понимаю — её нужно разделить на две части:

  1. Релиз с накопившимися небольшими задачами, не входящими в эпики — чтобы быстрее выгрузить то, что уже протестировано и готово.

  2. Отдельный релиз, содержащий только один эпик — он всё ещё нестабилен, требует доработок и не должен попадать на прод случайно.

Обсуждаю идею с командой — получаю согласие. План простой:

  • откатить релизную ветку до нужного состояния;

  • по частям пересобрать два релиза;

  • залить по очереди.

Выглядит буднично и несложно. И я, не особенно напрягаясь, приступаю.

🚨 Начало проблем

В какой-то момент — почти на автопилоте — я выполняю команду:

git reset --hard origin/master

Моя мысль была простая: «обнулю релизную ветку, и соберу всё по новой, руками доберу нужные задачи».
Но спустя минуту я начинаю искать те самые ветки, из которых пришли задачи, чтобы пересобрать релиз...
…а их нет.

🤦 Почему нет веток?

Тут я вспоминаю один спор с тимлидом. Мы долго обсуждали, стоит ли удалять ветки после мержа. В итоге пришли к соглашению: если задача смержена в релизную ветку — удаляем ветку.

В прод это попадёт из релиза, а значит, в git у нас не будет лишнего хлама.

Но: релизная ветка — это не master, это временная сборка, которая может быть переписана.
А я только что затёр её состояние хард-ресетом.

💡 Осознание

  • Истории изменений нет.

  • Оригинальные ветки удалены.

  • git log ничего не показывает — релизная ветка теперь просто копия master.

  • git reflog — локальная история, но она не спасает, если ветка была перезаписана и пушнута с --force.

Всё, что было смержено и ещё не ушло на прод — оказалось уничтожено.
А продакшен-готовый релиз — должен быть сегодня.

Паника? Немного. Но я начинаю думать, где остались следы.

🔍 Поиск решений и восстановление: 3 пути, которые я попробовал

В голове быстро оформляется три возможных способа хоть как-то восстановить утраченные изменения:

✅ 1. Стенд и тестировщики — может, там остались живые ветки

Проверяю, не остались ли локальные копии удалённых веток:

  • на QA-стенде (вдруг туда накатывался конкретный коммит),

  • у тестировщиков (бывает, у них что-то закэшено в локальных репах).

Ответ — нет. Никто не держит эти ветки у себя, и на стенд накатывали уже собранный релиз. Следов не осталось.

✅ 2. Разработчики — возможно, у кого-то локально остались ветки

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

Я проверяю MR и вижу, кто автор. Минус: он в отпуске.
Нехорошо тревожить по пустякам (хотя это не пустяк, конечно).

К счастью, над задачей работали вдвоём. Пишу второму разработчику.
Ответ: «Я сейчас у врача, смогу посмотреть через пару часов».

На этом моменте я ставлю вторую попытку на паузу и переключаюсь на оставшиеся части релиза.

✅ 3. GitLab — последнее убежище истории

Остаётся последний шанс: Merge Request в GitLab.
Да, ветки удалены. Да, в Git их уже нет.
Но GitLab умеет сохранять сравнение веток, даже если сами ветки удалены.

Я открываю MR на удалённую ветку — и вижу:

  • diff между веткой и целевой (master) живой

  • все изменения, коммиты, комментарии — доступны

Это значит, что при желании, я могу вручную собрать эти коммиты, просто копируя diff кусками.
Это не идеально, но это шанс спасти релиз.


В это время поступает ответ от разработчика: одна из веток — сохранилась у него локально. Ура.
Но вторая — уже точно утрачена. Её нет ни у кого.

GitLab остаётся единственным источником для её восстановления.


🛠 Параллельно: фронтовая релизная ветка

Пока я разбирался с бэком, вспоминаю: есть ещё фронтовая релизная ветка.
К счастью, там я не делал reset --hard.

Но проблема с удалёнными ветками — та же. Задачи были смержены, ветки удалены, история отсутствует.

Решение:

  • вручную пересоздаю нужные ветки

  • поднимаю дифф из старых задач

  • cherry-pick'аю изменения обратно

  • одна из задач оказалась зависима от изменений в эпике (которые в другом релизе!) — пришлось вручную вырезать эту зависимость

Ещё одна задача попала в релиз недоделанной. Её убираю из релизной ветки и отправляю обратно на доработку.

В итоге мне удалось:

  • разделить фронт на два релиза

  • собрать релиз с «малыми» задачами

  • отложить эпик на следующий виток

🛠 Восстановление бэковского релиза вручную через GitLab

На этом этапе часть задач по фронту уже спасена. Осталась проблема: бэковый релиз, в который я сделал git reset --hard и уронил всю историю. Напомню:

  • ветки с задачами были удалены сразу после мержа в релизную ветку;

  • один разработчик был в отпуске, второй смог восстановить только одну задачу;

  • вторую ветку не удалось найти ни у кого — она ушла в небытие.

💡 GitLab — последняя надежда

Проверяю Merge Request, который когда-то мержил вторую задачу.
Сами ветки уже удалены, но GitLab по-прежнему показывает:

  • diff между удалённой веткой и master,

  • все изменённые файлы,

  • старый коммит с идентификатором,

  • комментарии к MR.

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

🧵 Вручную собираю изменения

Вариантов немного:

  1. Создаю новую ветку от master: git checkout -b restore-lost-task

  2. Перехожу в MR, открываю вкладку "Changes".

  3. Файл за файлом, правка за правкой — воссоздаю изменения вручную:

    • копирую код из GitLab,

    • вставляю в IDE,

    • коммитю по логике задачи.

Да, это долго. Да, это неудобно.
Но когда речь идёт о продакшен-релизе, у которого сегодня дедлайн, — считаешь каждую строчку.

✅ Результат: задача восстановлена, релиз собран

После ручной реконструкции:

  • проверяю локально, что поведение корректно;

  • прокидываю ветку в релизную;

  • уведомляю команду и QA: задача восстановлена, можно тестировать.

Спустя несколько итераций и сверок, релиз бэка собран заново — уже без потерь.

⚖️ Выводы и личные уроки

Этот релиз стал для меня хорошим напоминанием:

  • 🔥 git reset --hard на релизной ветке — очень плохая идея, особенно если ветки уже удалены.

  • 🔒 Удаление веток после мержа — удобно, но опасно, если прод ещё не обновился.

  • 🧰 GitLab — это не только CI/CD, но и ценнейшее хранилище истории:

    • diff’ы остаются даже после удаления веток;

    • коммиты видны;

    • можно восстановить почти всё руками.

  • 💬 Не стоит стесняться пинговать коллег, даже если они «в отпуске» — но лучше иметь бэкапы по процессу.

❓ Вопрос к читателям

Мне интересно — как бы вы поступили в такой ситуации?

  • Можно ли было восстановить ветку через reflog, gitlab API или ещё как-то, о чём я не знал?

  • Может, вы используете другие подходы к управлению релизными ветками?

  • Стоит ли автоматизировать часть процессов (например, авто-бэкап перед reset / merge)?

Если у вас есть опыт с подобными граблями — напишите, будет круто сравнить.

Теги:
Хабы:
0
Комментарии22

Публикации

Ближайшие события