# Force push _Удалённые репозитории · GitLab Knowledge Base_ **TL;DR:** `git push --force` затирает удалённую историю своей. `git push --force-with-lease` делает то же, но отказывает, если кто-то успел запушить туда после твоего последнего fetch. Используй всегда `--force-with-lease`. Обычный push требует fast-forward: удалённая ветка должна быть предком твоей локальной. Это защита от случайной потери чужих коммитов. Иногда защиту нужно обойти - например, после локального rebase, amend или interactive rebase ([interactive-rebase](/courses/git/kb/interactive-rebase.md)) SHA коммитов изменились, и обычный push отказывается: ``` ! [rejected] feat -> feat (non-fast-forward) ``` Здесь приходит force-push. ## --force: тупой и опасный ```bash git push --force origin feat ``` Что делает: говорит remote'у «забудь, что у тебя там было, поставь ровно мою историю». Если кто-то другой запушил коммит между твоим последним fetch и push'ем - его коммит **исчезает**. Не сразу заметишь: его клон ещё содержит этот коммит, но в общем remote'е его уже нет. Это и есть «forge force-push накосячил» - типичная катастрофа в командной работе. ## --force-with-lease: безопасный ```bash git push --force-with-lease origin feat ``` Что делает: говорит remote'у «перезапиши ветку, **но только если её текущий SHA = тому, что я последний раз видел через fetch**». Если SHA отличается - значит кто-то запушил после тебя, и force отменяется. ``` ! [rejected] feat -> feat (stale info) ``` В этом случае: сделай `git fetch`, посмотри, что прилетело, реши что с этим делать (обычно rebase своих коммитов поверх новых), и повтори force-with-lease. **Правило: никогда `--force`, всегда `--force-with-lease`.** Можно настроить алиас, чтобы пальцы автоматически шли в правильную сторону: ```bash git config --global alias.pushf 'push --force-with-lease' ``` Или ещё параноидальнее: с явной проверкой SHA, который ты ожидаешь: ```bash git push --force-with-lease=feat:abc123 origin feat ``` ## Когда force нужен - **После rebase своей feature-ветки.** Это штатный сценарий. - **После amend последнего коммита запушенной feature-ветки.** - **После interactive rebase для очистки истории перед PR.** Все три - только на ветках, которые видишь ты один. На `main`, `master`, `develop` force-push запрещён branch-protection правилами форджа. ## Когда force НЕ нужен - «Запушил с ошибкой в commit message» - обычно проще оставить, или исправить новым коммитом. Force не за этим. - «Хочу удалить из истории секрет» - недостаточно. См. [git-filter-repo](/courses/git/kb/git-filter-repo.md), плюс ротируй секрет в любом случае. - «Не разобрался с merge» - нет, делай merge или rebase, не force. ## Branch protection: сетка снизу На GitHub/GitLab у защищённых веток (main, master, release/*) можно включить: - Запрет force-push. - Запрет прямого push (только через PR). - Требование зелёного CI и аппрувов. Это страховка от человеческой ошибки. Включай её на main всегда, даже в маленьких командах. ## Подводные камни - **Фоновый fetch может обмануть `--force-with-lease`.** Lease без явного SHA сравнивается с твоим remote-tracking ref'ом (`refs/remotes/origin/feat`). Обычно «давно не fetch'ил» - это хорошо: lease видит старый SHA, не совпадает с реальным remote, push отклоняется со `stale info`. Опасный сценарий - когда что-то делает fetch без тебя (IDE, watcher, параллельный терминал): remote-tracking ref молча обновляется до свежего чужого SHA, lease совпадает, force проходит и затирает их коммиты. Защита - использовать явный SHA: `git push --force-with-lease=feat:`, где `` - то, что ты сам видел через `git fetch` и осознанно решил перезаписать. - **На некоторых форджах reflog хранится 30+ дней.** Если кого-то случайно перезаписали - обычно SHA можно восстановить из reflog форджа или из локального клона коллеги. - **Force-push ломает чужие watch'и.** Если кто-то ребейзится на твою ветку (stacked PRs), force-push заставит его тоже ребейзиться. В stacked-workflow это норма, но предупреждай. ## Команды ```bash git push --force-with-lease ``` Безопасный force: отказ, если remote ушёл вперёд ```bash git push --force ``` Тупой force: затирает чужие коммиты молча. ИЗБЕГАТЬ ```bash git config --global alias.pushf 'push --force-with-lease' ``` Алиас, чтобы пальцы шли в правильную сторону ```bash git fetch && git push --force-with-lease ``` Свежий lease перед force ## См. также - [git push](/courses/git/kb/push.md) - [git rebase](/courses/git/kb/rebase.md) - [Interactive rebase](/courses/git/kb/interactive-rebase.md)