Introduction
When you’re working with Git, sometimes you may need to overwrite the history on the remote repository for various reasons, such as fixing mistakes or cleaning up commits. This is where the --force
and --force-with-lease
options for git push
come into play. In this tutorial, we’ll delve into what each of these options does, why you might use them, and how to use them safely with practical examples.
Before applying these options, it’s important to understand that they can overwrite changes on the remote repository, which can potentially result in lost work for you or your teammates. Therefore, they must be used with caution.
Understanding Git Push
Let’s start with a basic understanding of git push
. It’s the command used to update the remote repository with the contents of the local branch.
git push origin my-branch
Why You Might Need –force
Sometimes, your local history may diverge significantly from the remote history. This might occur after a rebase, a commit amendment, or an interactive rebase that has altered the commit history. By default, Git rejects these kinds of non-fast-forward updates to help protect against unintentional data loss. Here’s where --force
comes in.
Using –force
The --force
option overrides this protection. It tells Git to proceed with the push, even if it would result in the remote losing commits. Here’s how it’s used:
git push origin my-branch --force
When this command is used, Git doesn’t care if the push deletes commits on the remote or creates a completely different set of commits. It replaces whatever is in the remote repository with what is in your local repository.
Example 1: Overwriting a Mistaken Commit
Imagine you’ve accidentally committed wrong files to your branch. You fix the commit locally using git commit --amend
or an interactive rebase. To update the remote branch, you would use:
git push origin my-branch --force
Output indicating successful force-push:
+ c0ffee1...deadbeef my-branch -> my-branch (forced update)
Why –force-with-lease?
Using --force
can pose a problem if someone else has pushed changes to the same branch after your last fetch or pull, because it can overwrite their commits. This is where --force-with-lease
provides a safer alternative. It checks whether the remote branch points to the same commit as your local copy. If it doesn’t, because someone else has pushed changes, the operation will be aborted, protecting other collaborators’ work.
Using –force-with-lease
The usage is very similar to --force
, but safer:
git push origin my-branch --force-with-lease
The command will ensure that you don’t accidentally overwrite changes that you’re not aware of on the remote branch.
Example 2: Ensuring You Don’t Overwrite Others’ Work
If your colleague has pushed changes but you haven’t pulled them yet, the following sequence of commands will illustrate how --force-with-lease
prevents overwriting their work:
# You try to force push your changes
git push origin my-branch --force-with-lease
# Output if someone else has pushed changes
! [rejected] my-branch -> my-branch (stale info)
error: failed to push some refs to '[email protected]:your/repo.git'
Refining –force-with-lease
Further protection can be specified by including the commit SHA of the remote tracking branch:
git push origin my-branch --force-with-lease=origin/my-branch:expected_remote_sha
This variant of --force-with-lease
not only ensures that the remote branch hasn’t moved, but that it still points at a specific commit. If someone else has pushed, even if you’ve recently fetched, you’ll be warned before you can override their changes.
Advanced Tips
Recovering from a Force Push
If you accidentally force push the wrong commits, you can recover provided you still have the correct commits locally or if another member has them:
# If you have the commits
$ git push origin +correct_commit_sha:my-branch
# If another member has the commits
# First retrieve the changes from the remote
$ git fetch member
# Then push the correct history
$ git push origin +member/my-branch:my-branch
Automate Safety Checks
To avoid the need to rely on memory for safety checks, you can use Git hooks. For instance, a pre-push hook can be configured to reject force pushes to certain protected branches like master
or main
.
Conclusion
In conclusion, while both --force
and --force-with-lease
allow you to overwrite the git history on remote repositories, the latter is the safer option since it checks for additional updates on the remote before proceeding. Regardless, both options should be used sparingly and always with the awareness of the potential impact on your team.