Git: Force push safely with --force-with-lease
and --force-if-includes
When you push, Git checks that you are only adding commits to the remote branch. If you try to push an out-of-date branch, it will fail:
$ git push
To github.com:adamchainz/example.git
! [rejected] camembert -> camembert (non-fast-forward)
error: failed to push some refs to 'github.com:adamchainz/example.git'
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart. Integrate the remote changes (e.g.
hint: 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.
This protection kicks in after you remove or rebuild commits in your local branch, such as after git commit --amend
or git rebase
.
Git says the push is “non-fast-forward”. Fast-forward pushes only add to the branch history, like fast-forwarding a movie to the next scene. Non-fast-forward pushes remove, or “rewind”, some commits before adding new ones.
The output hint tells you to merge the remote changes with git pull
. Sometimes, this is what you want to do, such as when pushing to a shared release branch. But sometimes, it’s not, such as when you have amended a commit, rebased your branch, or removed commits. In those cases, use the Jedi-esque force push, enabled with -f
(--force
):
$ git push -f
...
To github.com:adamchainz/example.git
+ 1fd4fb8...e025fa5 camembert -> camembert (forced update)
A force push bypasses the fast-forward protection and always updates the remote branch, no questions asked. That allows you to proceed, although it carries the risk of potentially losing work. If someone else has pushed new commits to the remote branch, a force push will remove them without any indication!
To guard against unintentional commit removals, use the alternative option --force-with-lease
. This mode requires that you have already fetched the remote branch’s latest commit.
Improve the “lease” protection with --force-if-includes
. This option requires that you have also checked out the remote branch’s latest commit.
--force-with-lease
provides some guarantee that you have considered any extra commits on the remote. But its protection is weak because you can fetch a commit without looking at it. --force-if-includes
adds strength because it also ensures you have checked out the latest commit, as would happen with a git pull
. Thus, you would have considered it when taking an action like rebasing.
Use both protective options together:
$ git push --force-with-lease --force-if-includes
That’s a bit long to type. It’s best to wrap it up in a shell alias.
oh-my-zsh’s Git aliases have this available as:
$ gpf
Short for “git push force”.
One summary email a week, no spam, I pinky promise.
Related posts:
- Git: Don’t create
.gitkeep
files, use.gitignore
instead - Git: How to skip hooks
- Git: Show a commit message or subject
Tags: git