Git push force vs force-with-lease: When and Why to use each

Full stack engineer but passionnated by front-end Angular Expert / NX / JavaScript / Node / Redux State management / Rxjs
Search for a command to run...

Full stack engineer but passionnated by front-end Angular Expert / NX / JavaScript / Node / Redux State management / Rxjs
No comments yet. Be the first to comment.
A structured approach to Angular applications with Ngrx Signal Store

The useEffect hook is fundamental to React functional components, but its behaviour changes dramatically based on how you handle the dependencies array. Let's explore the three main patterns and when to use each one. useEffect without dependencies ar...

Git worktree is a Git feature that allows you to check out multiple branches at once in different directories, without cloning the repository again. This powerful capability transforms how developers handle parallel development workflows. The Problem...

Ever needed to create a union type from an array of objects in TypeScript? There's an elegant solution using the [number] index signature notation that can save you from maintaining duplicate type definitions. The Problem Let's say you have an array ...
![TypeScript's [number] Index Signature: Extract Union Types from Arrays](/_next/image?url=https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1752960594694%2Fe2be9492-869f-4169-bb1a-950ee81a3887.png&w=3840&q=75)
When working with Git in collaborative environments, you'll inevitably encounter situations where you need to overwrite remote history. Two commands come into play: git push --force and git push --force-with-lease. Understanding the difference between these commands can save you from accidentally destroying your teammates' work.
In professional development environments, clean Git history isn't just a preference, it's a requirement for maintainable codebases. Many teams follow a "one logical commit per feature" guideline, where each merge to the main branch represents a single, complete change. This approach makes code reviews more focused, rollbacks (git revert) cleaner, and debugging significantly easier when you need to trace issues months later. (git bisect)
During development, however, your feature branch accumulates multiple commits: initial implementations, bug fixes, code review responses, and style adjustments. Before merging, teams typically require you to squash these commits into a coherent story or rebase onto the latest main branch to avoid merge commits that clutter the project history.
Additionally, as main branch development continues, your feature branch falls behind. Rebasing your work onto the current main branch creates a linear history that's easier to follow than a web of merge commits. Some teams also enforce commit message standards or require sign-offs that weren't present in your original commits, necessitating history rewrites to meet project guidelines.
These practices, rebasing, squashing, and amending, all change commit hashes, creating the divergence that requires force pushing to update the remote repository.
Push force can be scary at the beginning but when you are used to it, it's pretty easy !
The git push --force command overwrites the remote branch with your local version, regardless of what changes might exist on the remote. This brute-force approach can lead to serious problems in team environments.
A good rule to follow is to only force push on your own feature branch, but sometimes you work on a bigger branch with a colleague
# Dangerous - overwrites everything on remote
git push --force origin feature-branch
Consider this scenario: You're working on a feature branch, and a colleague pushes some critical bug fixes while you're doing a rebase. If you force push without checking, you'll completely erase their work.
# Timeline of disaster:
# 1. You start with commit A
# 2. Colleague pushes commit B to remote
# 3. You rebase locally, creating commit A'
# 4. You force push, replacing A-B with just A'
# 5. Colleague's work (commit B) is gone forever
The --force-with-lease option provides a safety net. It only allows the force push if your local reference matches what's currently on the remote. If someone else has pushed changes since your last fetch, the command will fail.
# Safer - checks remote state first
git push --force-with-lease origin feature-branch
Here's how it protects you:
# Safe scenario:
git fetch origin # Get latest remote state
git rebase origin/main # Rebase your work
git push --force-with-lease origin feature-branch # Safe to push
# Protected scenario:
# Someone pushed while you were rebasing
git push --force-with-lease origin feature-branch
# Error: Updates were rejected because the remote contains work
# Traditional force push (dangerous)
git push --force origin feature-branch
# Force with lease (safer)
git push --force-with-lease origin feature-branch
Here's a typical development workflow using force-with-lease:
# 1. Fetch latest changes
git fetch origin
# 2. Rebase your feature branch
git checkout feature-branch
git rebase origin/main
# 3. Safely force push
git push --force-with-lease origin feature-branch
When force-with-lease rejects your push, here's how to handle it:
# Force-with-lease failed - someone pushed changes
git fetch origin
git log origin/feature-branch --oneline # See what changed
git rebase origin/feature-branch # Incorporate new changes
git push --force-with-lease origin feature-branch # Try again
--force-with-lease when:--force only when:Force-with-lease should be your default choice for overwriting remote history. It provides the same functionality as force push while protecting against the most common cause of lost work: accidentally overwriting changes you haven't seen.
The extra safety check takes virtually no additional time and can save hours of recovery work. In collaborative environments, this small change in habit can prevent significant frustration and potential data loss.
Make force-with-lease your standard practice, and reserve regular force push for those rare situations where you're absolutely certain about the state of the remote repository.