Git: удаление веток, слияние и отмена неудачного push
August 2, 2026 · – посетителей
Эти три вещи всплывают постоянно, и почему-то команды никак не запоминаются от раза к разу. Так что вот они, записанные как следует.
Удаление ветки
git branch -d feature-x
Это безопасный вариант — Git сначала проверяет и откажется, если в feature-x есть коммиты, которые так и не попали в вашу текущую ветку. Если вы уверены, можно надавить сильнее: (1)
git branch -D feature-x
Правда, это удаляет её только локально. Если ветка есть и на удалённом репозитории (скажем, на GitHub), там её нужно удалять отдельно:
git push origin --delete feature-x
Стоит знать одну вещь: удаление ветки на самом деле не удаляет её коммиты. Они просто становятся недостижимыми и лежат в репозитории, пока сборщик мусора Git рано или поздно их не выметет, а это может занять некоторое время. Так что git branch -D прощает больше, чем кажется — если вы удалили не ту ветку, обычно всё ещё есть путь назад (подробнее об этом в разделе про reflog ниже). Я бы не полагался на это как на план, но полезно знать, что такая возможность есть.
Слияние веток
Обычная схема такая: переключитесь на ветку, в которую хотите влить изменения, а затем влейте в неё другую.
git checkout main
git merge feature-x
Что произойдёт дальше, зависит от того, ушла ли main вперёд с момента, когда вы от неё отделились. Если нет, Git просто сдвигает указатель main вперёд до feature-x — это fast-forward, без какого-либо merge-коммита. Если main за это время продвинулась, Git создаёт настоящий merge-коммит, который связывает обе истории вместе (2).
Иногда такой merge-коммит нужен, даже если fast-forward был бы возможен — он оставляет в истории видимую отметку о том, что feature-ветка существовала и была слита, а не просто тихо растворилась в изменениях. Для этого:
git merge --no-ff feature-x
Если одни и те же строки были изменены с обеих сторон, Git останавливается и оставляет конфликт вам на разбор:
git status
Эта команда покажет, в каких файлах конфликт. Откройте каждый из них, вы увидите маркеры <<<<<<<, ======= и >>>>>>> вокруг конкурирующих изменений — выберите, что действительно должно остаться, удалите маркеры, а затем:
git add resolved-file.txt
git commit
А если всё превращается в бардак, который того не стоит, можно просто отступить от всей затеи:
git merge --abort
Это вернёт всё в точности к тому состоянию, что было до начала слияния.
Отмена неудачного push
Именно из-за этого люди чаще всего паникуют, и, честно говоря, паника обычно не оправдана — но вот какое именно решение вы выберете, здесь действительно имеет значение.
Если есть хоть малейший шанс, что кто-то уже сделал pull этой ветки, не трогайте историю. Вместо этого добавьте новый коммит, который отменяет старый:
git revert <bad-commit-sha>
git push
Это скучный, но всегда безопасный вариант. Он ничего не переписывает — просто добавляет сверху коммит, который отменяет ошибку, так что история у всех остаётся синхронизированной, и никому не нужно делать ничего особенного на своей стороне (3).
Если ветка действительно только ваша и никто ещё не сделал pull, можно перемотать назад и переписать историю: (4)
git reset --hard <last-good-commit-sha>
git push --force-with-lease
Используйте --force-with-lease, а не голый --force, хотя бы просто по привычке. Разница важнее, чем кажется: --force-with-lease проверяет, что никто не пушил в ветку с момента вашего последнего fetch, и откажется, если кто-то это сделал. Голый --force не проверяет вообще ничего — он с готовностью перезапишет чужую работу без единого предупреждения (5).
А если вы смотрите в терминал, пытаясь вспомнить, каким вообще был последний нормальный коммит — git log тут не поможет, поскольку он показывает только коммиты, достижимые из вашего текущего положения, а туда не входит то, от чего вы уже отреклись через reset. Что вам действительно нужно:
git reflog
Она показывает каждую точку, на которую в последнее время указывала ваша ветка, включая те, что выпали из обычной истории. Прокрутите назад к моменту до того, как всё пошло не так, а затем: (6)
git reset --hard HEAD@{2}
(подставьте вместо этого позицию или SHA, которые действительно подходят вашему случаю). Reflog хранится локально на вашей машине и обычно держит записи около 90 дней, так что это не столько «аварийная отмена для неудачных push», сколько общая страховочная сетка на случай «кажется, я только что что-то сломал» — стоит помнить, что она существует, даже вне этой конкретной ситуации.
Заключительная мысль
Все эти три случая опираются на один и тот же факт: Git почти никогда не выбрасывает что-либо немедленно. Удалённые ветки, сброшенные коммиты, старые позиции на ветке — всё это задерживается дольше, чем кажется. Именно это и делает -D, reset --hard и force-push достаточно безопасными для повседневного использования — при условии, что вы знаете, куда смотреть, если один из них окажется ошибкой.
По теме
- Понимание Make — что на самом деле запускает пересборку
Дополнительное чтение
- git-branch — создание, просмотр списка и удаление веток.
- git-merge — стратегии слияния и разрешение конфликтов.
- git-revert — отмена коммитов путём создания новых.
- git-reset — перемещение указателя ветки, с разницей между
--soft,--mixedи--hard. - git-push: --force-with-lease — почему это безопаснее, чем
--force. - git-reflog — восстановление коммитов, которые больше не отображаются в обычной истории.
Комментарии