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 достаточно безопасными для повседневного использования — при условии, что вы знаете, куда смотреть, если один из них окажется ошибкой.

По теме

Дополнительное чтение

  1. git-branch — создание, просмотр списка и удаление веток.
  2. git-merge — стратегии слияния и разрешение конфликтов.
  3. git-revert — отмена коммитов путём создания новых.
  4. git-reset — перемещение указателя ветки, с разницей между --soft, --mixed и --hard.
  5. git-push: --force-with-lease — почему это безопаснее, чем --force.
  6. git-reflog — восстановление коммитов, которые больше не отображаются в обычной истории.

Комментарии