How do I properly force a Git push?

Learn how do i properly force a git push? with practical examples, diagrams, and best practices. Covers git, push, git-push development techniques with visual explanations.

How to Properly Force a Git Push

Hero image for How do I properly force a Git push?

Learn when and how to use git push --force or git push --force-with-lease safely, understanding the risks and best practices for overwriting remote Git history.

In Git, pushing changes to a remote repository typically involves adding new commits to the branch's history. However, there are scenarios where you might need to overwrite the remote history entirely, such as after a git rebase or git commit --amend. This is where a 'force push' comes into play. While powerful, it's a command that should be used with caution due to its potential to erase work for other collaborators.

Understanding the Risks of Force Pushing

When you perform a standard git push, Git ensures that your local branch's history is a direct descendant of the remote branch's history. If it's not, Git rejects the push, prompting you to git pull first. A force push bypasses this check, telling Git: 'I know my history doesn't match, but trust me, this is the correct history, and you should overwrite whatever is currently on the remote.'

The primary risk is that if another developer has pulled the old remote history, made changes, and then you force push, their subsequent push will fail, and they might lose their work if they're not careful. It's crucial to communicate with your team before force pushing to a shared branch.

flowchart TD
    A[Local Repository] --> B{Perform Rebase/Amend?}
    B -- Yes --> C[Local History Diverges]
    B -- No --> D[Standard Push]
    C --> E{Remote History Updated by Others?}
    E -- Yes --> F["Risk of Overwriting (Use --force-with-lease)"]
    E -- No --> G["Safer to Force Push (Still Caution)"]
    F --> H["git push --force-with-lease"]
    G --> I["git push --force"]
    H --> J[Remote History Overwritten]
    I --> J

Decision flow for when to use different types of force push.

When to Use git push --force

The git push --force command is the most aggressive way to overwrite remote history. It unconditionally replaces the remote branch with your local branch. This is generally acceptable only in a few specific scenarios:

  1. Your personal feature branch: If you are working on a branch that no one else has pulled or is collaborating on, force pushing after a rebase or amend is usually safe.
  2. After a git rebase: When you rebase your branch onto an updated main or develop branch, your local history changes. To reflect this new, cleaner history on the remote, you'll need to force push.
  3. Correcting a sensitive commit: If you accidentally committed sensitive information (e.g., passwords) and have rewritten history to remove it, a force push is necessary to cleanse the remote history. However, be aware that the old commit might still exist in Git's reflog for a period.

Never use git push --force on shared branches (like main, develop) without explicit team consensus and coordination.

git push origin <branch-name> --force

Using git push --force to overwrite remote history.

The Safer Alternative: git push --force-with-lease

Introduced in Git 1.8.5, git push --force-with-lease is a much safer alternative to git push --force. It performs the force push only if the remote branch's history is exactly what you expect it to be. Specifically, it checks two things:

  1. The remote tracking branch's SHA-1: It ensures that the remote branch's SHA-1 hash is the same as the one your local repository last fetched.
  2. The remote branch's ref: It ensures that the remote branch's reference hasn't been updated by someone else since your last fetch.

If either of these conditions is not met, meaning someone else has pushed to the remote branch since you last fetched, git push --force-with-lease will fail, preventing you from accidentally overwriting their work. This makes it the preferred method for force pushing in collaborative environments.

git push origin <branch-name> --force-with-lease

Using git push --force-with-lease for a safer force push.

Handling Non-Bare Repositories

When pushing to a non-bare Git repository (a repository with a working directory, often used for deployment), Git will typically reject a push that would update the currently checked-out branch. This is because updating the branch would change the files in the working directory without Git being able to update them automatically, leading to a desynchronized state. If you absolutely must push to a non-bare repository's checked-out branch, you can configure it to allow this, but it's generally not recommended for production environments.

To allow pushes to the current branch in a non-bare repository, you can set the receive.denyCurrentBranch configuration option to ignore or warn:

git config receive.denyCurrentBranch ignore

However, a better practice for deployment is to use a bare repository as the central remote and then use git pull or git checkout on the deployment server, or use a post-receive hook to update the working directory.

1. Step 1: Rebase or Amend Your Commits

First, perform the operation that necessitates a force push, such as git rebase -i main to reorder or squash commits, or git commit --amend to modify the last commit.

2. Step 2: Fetch Latest Remote State (Crucial for --force-with-lease)

Before force pushing, always run git fetch origin to update your local knowledge of the remote repository. This is especially important for git push --force-with-lease to work correctly.

3. Step 3: Communicate with Your Team (If on a Shared Branch)

If you are force pushing to a branch that others might have pulled, inform your team members about the impending history rewrite. Advise them to git fetch and then git reset --hard origin/<branch-name> or git pull --rebase to synchronize their local branch with the new remote history.

4. Step 4: Execute the Force Push

Use git push origin <branch-name> --force-with-lease for safety. If you are absolutely certain no one else has touched the branch and you understand the risks, git push origin <branch-name> --force can be used.

5. Step 5: Verify Remote History

After pushing, you can verify that the remote history has been updated as expected by checking the remote repository's commit history (e.g., on GitHub, GitLab, or Bitbucket).