A gentler force push on git: Force-with-lease
I currently work at Experimental Systems and Technology Lab where we build web applications. For development, we use git for version control — for the record, git is fantastic in enabling collaborative work. In our team, we use feature branches in our development workflow, and do pull requests for code review by other team members.
A typical feature would be developed in this manner:
- Pick up a feature, create local feature branch.
- Do the necessary changes, commit to local feature branch.
- Push a local branch to the remote, then open a pull request for team members’ review.
- Update local branch with members’ comments and update the pull request.
- Merge pull request into
In most typical scenarios, this works well. However, code review often results in me having to amend or squash my commit(s). Because of that, we can’t do a simple
git push to update the feature branch; rather we have to do
git push --force (or
git push -f).
When we do a
git push --force, this is the first thing that comes to mind:
And of course, a horror story: Jenkins developer accidentally forced pushed to 150+ github repos. Many have sworn off it, but others do recommend to do it under controlled conditions.
Here is a guide on how to do a proper force push.
A safer alternative: force-with-lease
A force push overwrites a remote branch with your local branch, regardless of the status of that remote branch (more on force push here). This is not ideal in a team scenario as it might result in one developer overwriting other developers’ commits (this could happen when the developer forgot to do a
git pull to fetch the newer commits).
Enter the safer alternative:
git push --force-with-lease
Force with lease gives you the flexibility to override new commits on your remote branch, whilst protecting your old commit history:
- If you rebased and squashed/edited/created new commits, you will be able to update the remote branch.
- If new commits are added to the remote branch (by some team member), this command would not update the remote branch (and not overwrite any work).
This option allows you to say that you expect the history you are updating is what you rebased and want to replace. If the remote ref still points at the commit you specified, you can be sure that no other people did anything to the ref. It is like taking a “lease” on the ref without explicitly locking it, and the remote ref is updated only if the “lease” is still valid.
Moving towards force-with-lease
git push -f to
git push --force-with-lease can be challenging - who likes typing extra characters anyway?
Optional: Github now allows admins to disable force push on a protected branch. This might cause some inconvenience at the start, but in the long run we can prevent screw-ups from happening again.