Skip to content
ExponaBLOG
GIT & GITHUB FOR PROFESSIONAL DEVELOPERS · DAY 029 / 100

git push --force-with-lease: what developers should know

Force-push without destroying teammates' work.

Expona Admin7 min read

You've rebased your feature branch to clean up five messy commits, but now Git won't let you push because the remote has moved. Force-pushing feels like the answer, but you're worried about wiping out a teammate's work. Enter git push --force-with-lease: a safer way to rewrite history without destroying your team's contributions.

Why force-push exists (and why it's dangerous)

When you rebase, amend, or squash commits on a branch you've already pushed, the local history diverges from the remote. Git won't let you push normally because it detects a non-fast-forward situation—the remote has commits you don't have locally. The solution is force-push, which overwrites the remote branch with your local version.

The problem: git push --force is blunt. It rewrites the remote branch regardless of what's there. If a teammate pushed new commits while you were rebasing, your force-push erases their work with no warning. They pull, find their commits gone, and spend the afternoon recovering from the git history ruins.

This is the scenario we all dread: a silent data loss that cascades through the team. That's where --force-with-lease comes in.

Refuses if the remote changed unexpectedly

git push --force-with-lease is a guard rail. Before overwriting the remote, it checks: "Is the remote exactly what I last saw?" If the answer is no—if someone pushed new commits—the push is rejected with a clear error.

Here's the flow in practice:

  1. You fetch your feature branch and see the remote is at commit abc123.
  2. You rebase locally, rewriting history. Your local branch is now at commit def456.
  3. You run git push --force-with-lease.
  4. Git checks: "Does the remote still point to abc123?" Yes, it does.
  5. Push succeeds. Your rebased history is now on the remote.

Now imagine a teammate pushed a new commit while you were rebasing:

  1. The remote moved from abc123 to xyz789.
  2. You run git push --force-with-lease.
  3. Git checks: "Does the remote still point to abc123?" No, it's at xyz789.
  4. Push is rejected. You're forced to pull, merge or rebase their commits, and handle the conflict properly.

The rejection is intentional and protective. It prevents you from accidentally erasing work.

Safer than --force (the comparison)

git push --force-with-lease is safer because it remembers the remote state. git push --force doesn't care—it just overwrites.

Let's compare them in a real scenario. You and a teammate are working on a feature branch called feature/payments:

bash
# Initial state: you and your teammate both see the same commit
git log -1 --oneline
# abc123 Add payment gateway integration

# You rebase to clean up your local commits
git rebase -i HEAD~3
# You're now at def456

# Meanwhile, your teammate pushed a new commit
# Remote is now at xyz789 (their new commit)

If you use git push --force:

bash
git push --force
# Your local commits (def456) overwrite the remote
# Your teammate's commits (xyz789) are gone
# They pull and lose their work

If you use git push --force-with-lease:

bash
git push --force-with-lease
# Git checks: "Is remote at abc123?" No, it's at xyz789
# error: failed to push some refs to 'origin'
# Push rejected. You're alerted to the conflict.

The difference is clear: --force-with-lease protects your team by refusing to proceed silently.

Needed after rebasing your own branch

git push --force-with-lease is the standard tool for pushing after a rebase. If it's your branch, if you're rebasing your own commits, and if no one else is working on that branch, --force-with-lease is the right choice. It's fast, safe, and expected in professional workflows.

Common scenarios where you'll use it:

  • Cleaning up commit messages: You amended the last commit with git commit --amend, changing the message. Push with --force-with-lease to update the remote.
  • Squashing commits before merge: You rebased and squashed three messy commits into one clean commit. --force-with-lease pushes the squashed version.
  • Reordering commits: You used interactive rebase to reorganize commits logically. Push with --force-with-lease to sync the remote.
  • Fixing a mistake: You pushed a commit with a typo, realized it mid-review, amended it locally, and now need to push the corrected version.

Example workflow:

bash
# Create a feature branch and make commits
git checkout -b feature/auth
git commit -m "Add login endpoint"
git commit -m "Add session storage"
git push -u origin feature/auth

# Later: realize the first commit message is unclear
git rebase -i HEAD~2
# Edit: change "Add login endpoint" to "Add POST /auth/login endpoint"

# Now your local branch is rebased, but the remote still has the old version
# Push with --force-with-lease
git push --force-with-lease

# The remote now has your improved commits
# Your PR reviewers see the clearer history

This is such a common pattern that many teams make it standard practice: always use --force-with-lease when pushing after any rebase, unless you're explicitly shared the branch with teammates who are also committing to it.

Never force-push main

This is the golden rule: never force-push main, master, or any long-lived branch. Not with --force, not with --force-with-lease, not ever.

Why? Because main is shared by the entire team. It's the source of truth. If you force-push it, you're rewriting history that other developers have already pulled. They'll face merge conflicts, lost commits, or corrupted local branches. CI/CD pipelines might break. Deployments could fail mid-rollout.

Long-lived branches like develop, staging, or release/* have the same restriction. They're integration points, not personal sandboxes.

The rule is simple: force-push only on feature branches, and only when you're confident no one else is committing to them. If there's any doubt, communicate with your team first.

If you need to undo a commit on main, use git revert instead:

bash
# Wrong: don't do this
git push --force-with-lease origin main

# Right: use revert instead
git revert abc123  # Creates a new commit that undoes abc123
git push origin main

git revert preserves history. Everyone pulling main gets the undo commit, not a rewritten history. It's the professional approach.

Common mistakes

Mistake 1: Thinking --force-with-lease is completely safe. It's safer than --force, but it's not foolproof. If two teammates rebase and push at the exact same moment, one will win and the other will see a rejection. The rejection is good—it forces you to communicate. But understand that --force-with-lease is a safety net, not an invisibility cloak.

Mistake 2: Using it on branches you don't fully own. If your branch is a team collaboration where multiple people commit directly, --force-with-lease might reject your push even when you intended to rebase. In those cases, talk to the team first. Decide together whether to rebase or merge.

Mistake 3: Aliasing --force to --force-with-lease without thinking. Some developers add git config alias.pushf 'push --force-with-lease' to make force-push faster. This is useful, but it can create a false sense of security. The habit might carry over to main if you're not careful. Be explicit about which branch you're pushing.

Mistake 4: Not fetching before force-pushing. --force-with-lease uses the last fetched remote state as its reference. If you haven't fetched in hours, your "safe" reference might be stale. Before force-pushing, always run git fetch origin to sync your local knowledge of the remote.

bash
# Before force-pushing, always fetch first
git fetch origin
git rebase origin/main
git push --force-with-lease

Key takeaways

  • git push --force-with-lease compares your local branch to the remote state you last observed. If they match, it pushes. If the remote has changed, it rejects the push and protects your team.
  • Use --force-with-lease after rebasing, amending, or squashing commits on your own feature branches. It's the professional standard.
  • --force-with-lease is safer than --force, but it's not a substitute for communication. On shared branches, talk to your team before rebasing.
  • Never force-push main, develop, or any long-lived branch. Use git revert instead to undo commits with preserved history.
  • Always fetch before force-pushing: git fetch origin ensures your safety check is based on the latest remote state.
  • Rejection from --force-with-lease is a feature, not a bug. It's telling you to communicate and sync with your team.
ShareXLinkedInReddit

Found this useful? Support the writing.

Buy me a coffee
Written by
Expona Admin
Site administrator

Comments

Loading comments…

Leave a comment

Comments are reviewed before they appear. Be kind and stay on topic.

Related articles