how/совместная работа
Зачем существует --force-with-lease, как именно он защищает от затирания чужих коммитов, и почему фоновый fetch может его обмануть. Три зоны, пять сценариев.
git push --force - один из тех инструментов, который не
надо использовать, пока не понимаешь, что он делает. Затирает
удалённую историю своей молча, даже если кто-то запушил туда после
тебя. Один неудачный push - и чужие коммиты исчезают из общего
remote'а.
git push --force-with-lease - безопасный аналог: проверяет, что
удалённая ветка - та же, что ты последний раз видел через
git fetch. Если нет - отказывается.
Чтобы это работало, в Git'е существует три зоны, не две:
fetch. Это не
remote, это твоё представление о remote.Жми ▶ - посмотрим, как эти три ссылки расходятся и почему одна из них может тебя предать.
Базовая ситуация. Ты только что сделал коммит на feat, rebase не делал, никто другой в feat не пушил.
local feat = X
origin/feat (tracking) = X
remote feat = X
git push идёт как обычный fast-forward: твой local ушёл на один
коммит вперёд, remote - предок. Никакого force здесь не нужно, никаких
ловушек.
С этого начинаются все три зоны: local, origin/feat, remote.
Дальше будем смотреть, как они расходятся.
итого
Что важно запомнить:
--force затирает remote молча. Если между твоим последним fetch
и push кто-то закоммитил в эту же ветку - его коммит исчезает,
никаких предупреждений.--force-with-lease берёт SHA из твоего
refs/remotes/origin/feat (что ты последний раз видел) и
сравнивает с реальным SHA на remote'е. Расходятся - отказ
«stale info», чужой коммит спасён.refs/remotes/origin/feat
молча обновился до чужого свежего SHA. Lease совпадает с remote,
force проходит, чужой коммит затёрт.git push --force-with-lease=feat:<sha>, где <sha> - тот,
который ты сам видел и осознанно решил перезаписать. Сравнение
идёт с этим SHA, а не с remote-tracking ref.main/master force-push должен быть запрещён branch
protection'ом - страховка снизу, чтобы ничьи случайные пальцы не
дотянулись.Правило для пальцев: никогда --force, всегда
--force-with-lease. Удобно завести алиас:
git config --global alias.pushf 'push --force-with-lease'