Using the ‘–force’ and ‘–force-with-lease’ options with git push

Updated: January 27, 2024 By: Guest Contributor Post a comment

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.