August 2021 by Bruno Brito

Force Push in Git - Everything You Need to Know

We have all been there — you’re ready to transfer your work from your local repository to a remote repo, only to realize that the trusted git push command is not doing the job.

You may have heard about the --force flag command before, and maybe that has even saved your day in the past. But do you understand how “Force Push” works in the background? Do you know when to avoid it?

If not, don’t worry — after reading this article, you will.

We will break it down into 6 parts:

  1. Why is git push not working?
  2. What happens when you Force Push
  3. Is Force Push bad practice? What can I do instead?
  4. When should I use Force Push?
  5. How to recover from a Force Push disaster
  6. How to prevent a Force Push mishap in the future

Let’s dive in!

1. Why is git push not working?

Here’s a simple scenario: you are working on the same branch as Joe. You both pulled the latest version from the remote repository in the morning and started working. So far, so good.

Joe has finished his task and pushed his work to the remote repo. Joe is on his way to the gym and you carry on with your assignment. You conclude your work, and now just need to run git push to end your day.

Sadly, an error message is displayed in your terminal window, similar to this:

! [rejected]   main -> main (fetch first)
error: failed to push some refs to ...
hint: Updates were rejected because the remote contains work that you do
hint: not have locally. This is usually caused by another repository pushing
hint: to the same ref. You may want to first integrate the remote changes
hint: (e.g., 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.

Well, why is it not working?

Unlike other version control systems, Git does not allow any conflicts on the remote repository. This is a good thing because it reassures you that the repo is in a healthy state at all times.

You won’t be overwriting commits from the team by accident but, at the same time, this means you will always need to pull any outstanding changes before pushing your work. And since Joe committed his work in the meantime, the repo’s history changed and you aren’t up to date anymore.

If you have a look at Git’s official documentation, you will quickly notice that you can force this command. You can use the --force flag (or -f for short).

This can look like an easy workaround when the git push command does not work, but it is rarely recommended — it’s not the default behavior for a reason.

In the scenario above, if you force push your work, you will erase Joe’s commit from the remote repo. Joe won’t be happy when he’s back from the gym!

Does this mean that we should avoid Force Pushing at all costs? Not necessarily. Let’s start by understanding what’s happening in the background…

2. What happens when you Force Push

Every time you Force Push, you’re basically rewriting history. Ever seen a movie where the character goes back in time, changes history, and everything goes well? Me neither.

Whenever you run the git push command, Git has a look at your local repository and copies to the remote side whatever is missing. This includes commits, trees, blobs, and tags (the last of which are not pushed by default).

After copying the missing content, Git attempts to overwrite the current master with the latest commit. This overwrite is allowed if the change is a “fast forward”, that is, if the old master commit is an ancestor of the new master commit.

If there is a linear path, the command succeeds. When it’s not allowed (most likely because the remote repo looked different from yours, apart from your new commits), the command fails.

The command will always succeed, however, if you resort to the --force flag. You will overwrite the remote’s commit history with your local one, regardless of how different it looks.

As you can see, this is a powerful command — but, as a famous web-slinger once taught us, "with great power comes great responsibility".

So should you use it?

3. Is Force Push bad practice? What can I do instead?

There are some situations where running git push --force actually makes sense, but on most occasions, you should stay away from typing it. It’s rarely the best approach to the problem.

There are 2 big reasons for this:

  1. There’s a high chance you overwrite commits from your colleagues, resulting in lost work;
  2. There’s a high chance your colleagues will be developing their work based on the old commit history.

In short, even if you get away with Force Pushing once or twice, it’s only a matter of time until something goes wrong. Time to look for an alternative!

Force with Lease — a safer alternative

To make sure you don’t ever overwrite your teammate’s commits, you can have a look at --force-with-lease flag, which is essentially a safer, lesser-known, option.

If somebody has updated the branch upstream while you were working on something, you can rest assured that everything will be intact, as the command will fail and prompt you to fetch first. This way, everyone’s work is preserved.

In our Git client, this was integrated into Tower’s 6.3 release so that our users always have their seatbelts on!

Force Push with Lease in Tower


Executing git push --force-with-lease by default is something we would recommend 99% of the time, but there are still situations where Force Pushing could make sense.

Let’s look into them now.

Not a Tower user yet? You can download our 30-day free trial and test Force Push with Lease in Tower yourself!


Try Tower Now


4. When should I use Force Push?

As a rule of thumb, you should only Force Push when you’re absolutely sure you know what you’re doing.

Here are a couple of scenarios where Force Push would make sense:

Scenario: sensitive information uploaded to the repo by accident

You noticed there’s a file that contains sensitive information (eg: a password). You don’t want that information publicly accessible and you want to delete that file altogether. This happened 6 commits ago.

You could use Interactive Rebase to remove that commit from your project, and then you would have to Force Push it to the remote repository to make sure that it is deleted for everyone else when your colleagues update the local version via git pull.

This way, the sensitive information will eventually disappear. Please keep in mind that, if this was a pull request from someone else, that request will still be visible until the original author deleted it.

Scenario: you don’t want to deal with merge conflicts

Things got messy, but the working version in your local machine is the one that should be going forward — you know it, and your team knows it. If you want to prioritize your local branch over the remote one, overwriting any commits made along the way, then by all means go for it.

In a less extreme situation, Force Pushing can still be appropriate. Sometimes we're simply working on a private branch that should not be used by anyone else. Before merging/moving to a branch that a group of people collaborate on, it may make sense to perform a little clean-up and force push (this is also a common use case for pull requests in open source projects).

As you can see, in some situations Force Pushing can be your friend. If you are using Tower, our Git client, the “force” flag is available as an option in Tower's Push dialog:

Force Push in Tower

5. How to recover from a Force Push disaster

An accidental Force Push can happen to any developer, no matter how experienced. Luckily, like most things in Git, there’s (almost) always a way to get your work back.

If you are currently in the middle of a Force Push panic attack, don’t keep it to yourself. Let the team know, to make sure that no one messes with the repository. And, if possible, don’t close the terminal window.

If you are aware of a colleague who is working on the same repo, start by asking if he/she has pulled a recent version of the branch just before you messed it up. If so, you are one push --force away from restoring things back to normal.

If you weren’t so lucky, have a look at your terminal window (if it is still open). In the output of git push --force, find a line similar to this:

+ last-good-commit...f00f00ba main -> main (forced update)

In this example, "last-good-commit" is your last good commit before everything went wrong. Simply run git push --force origin last-good-commit:main to restore everything as it was.

Did you already close the terminal? Time to learn about Git Reflog.

Recovering your work with Git Reflog

Git Reflog is a very handy command that outputs a detailed history of your repository. Each line is a reference log (reflog, get it?) listing any updates to branches and other references. This can be very useful when it’s time to specify an old value of a reference.

We will have to start by running git reflog and finding the line where everything was fine and dandy. You will have an output similar to this:

1ff3ff5 (HEAD -> main, origin/main) HEAD@{0}: commit: Add more content to page
9f8bf71 HEAD@{1}: commit: Add CTA button
4e12f64 HEAD@{2}: commit: Add reset.css
549c6f0 HEAD@{3}: commit: Add h1 title
e0fcb3b HEAD@{4}: commit: Add info to document
(END)


You will see the term “HEAD” a lot. This is the tip of the branch you’re currently on. Next to it, you will find numbers, like HEAD@{3}, which represent the number of steps until that action.

To roll back to the state we want, we could run git reset --hard HEAD@{3} and run git push--force again.

Restoring a branch deleted with Force Push

In a more extreme scenario, where the branch has been deleted, it is still possible to recover your work. We will need to find the commits, just like in the previous example, but we will use a different tool: git-fsck.

Git performs many actions in the background to prevent the loss of information. When you run this command, you can access 2 things:

  1. Dangling blob: a change that reached the staging area but never got committed.
  2. Dangling commit: a commit that isn’t directly linked to by any child commit, branch, tag, or other reference.

Since your branch is now gone, you’re looking for dangling commits. You can run git fsck —-lost-found to track them down.

Finally, just like in the previous step, you will need to find the commit before the disaster happened, reset to that commit via git reset, and run git push--force again.

6. How to prevent a Force Push mishap in the future

As a rule, try to avoid Force Pushing into any important branches, like main. It’s always a good idea to avoid any sort of experiments in the repository’s main branch.

This is great advice but, unfortunately, easy to forget. So, to make sure you minimize the chances of facing another Force Push disaster, do the following:

Default to --force-with-lease as much as you can

As mentioned in Chapter 3, --force-with-lease is like --force with a safety vest. The command will always fail if someone has pushed to the same branch you were working on and you were out of date. If you rely on the command line, that’s a good default to bank on.

You can set up a new alias in your “gitconfig” file to run this command without typing so many characters. If you have never edited this file, it is usually located at ~/.gitconfig on UNIX systems and C:\Users\\.gitconfig on Windows.

After opening it, have a look and see if you have any [alias] section already in place. If it doesn’t exist, simply add this to the end of the file:

[alias]
    pfl = push --force-with-lease

If you have Zsh and Oh My Zsh installed, there’s already an alias created for you: ggfl.

If you’re using our Git client exclusively, you don’t have to worry: whenever you force push and there’s already a newer commit on the remote, you will be presented with a warning. This way, you will always be aware the remote repository has changed and can act accordingly.

If you combine a Git GUI like Tower with the CLI, there’s one thing you should keep in mind. When Tower is running in the background, it automatically fetches a remote. If your colleague makes changes, Tower auto-fetches and you run push --force-with-lease on the CLI, you will still overwrite these commits. For this reason, we check if there are unmerged commits on the remote branch and present a warning if we find any.

Use Protected Branches

If you’re hosting your remote repository on GitHub, you can use GitHub’s Protected Branches.

By default, GitHub will block force pushes on all protected branches, so you will just need to decide which branches should be protected. You can read GitHub’s documentation to learn how to create a branch protection rule.

Protected branches are available in public repositories with GitHub Free and GitHub Free for organizations, and in public and private repositories with GitHub Pro, GitHub Team, GitHub Enterprise Cloud, and GitHub Enterprise Server.

If you ever need to fix anything, you can still allow force pushes temporarily — just keep in mind that anyone with push access will be able to do this.

GitLab has a similar feature, available in all tiers. The default branch for your repository is protected by default.

Final thoughts

In conclusion, Force Push is a very powerful command in Git — we just have to make sure we use it with care (Tower will always warn you in case something risky is about to happen).

In this article, we have presented the risks of Force Pushing, scenarios where it is a necessity, and how to recover (or prevent) disasters in the future. We have also learned about a safer alternative (--force-with-lease) that you can default to on most occasions.

If you got this far, congrats! You are officially a Force Push ninja!

Your Download is in Progress…

Giveaways. Cheat Sheets. eBooks. Discounts. And great content from our blog!