skip to content

How can git push --force-with-lease still overwrite a teammate's commits?

level: seniorimportance: should knowfreq 30%

answer

  1. the lease checks information, not action
  2. any fetch refreshes the tracking ref
  3. a background fetch renews it for you
  4. one flag checks integration instead
  5. or name the expected value yourself

basics

~20 s

Its lease is checked against your remote-tracking ref, which any background fetch updates. If something fetched a teammate's push without you looking at it, the lease matches and the forced update discards their work. --force-if-includes closes that gap.

solid answer

~40 s

`--force-with-lease` asserts that the remote ref still equals `refs/remotes/origin/<branch>`. That ref is updated by *any* fetch — an editor polling the remote, a shell prompt helper, a scripted `git fetch --all`, a pull in another worktree. When that happens, your tracking ref silently advances to include a teammate's commit you have never seen; the lease now matches the remote, the push is accepted, and their commit is dropped exactly as bare `--force` would have dropped it. `--force-if-includes`, added in Git 2.30 and meaningful only alongside `--force-with-lease`, asks a different question: has the tip of the remote-tracking ref actually been integrated into the local branch, judged from that branch's reflog? A fetch alone does not satisfy that; rebasing or merging onto it does. The other robust option is to pin the expected value with `--force-with-lease=<ref>:<sha>`.

code

bash · 1 line
bash
git push --force-with-lease --force-if-includes origin feature/api

go deeper

for a junior

You are unlikely to be asked this. Recall only that --force-with-lease is safer than --force and that fetching before pushing is the habit that matters.

for a middle

Explain that the lease compares against the remote-tracking ref, and that anything performing a fetch updates that ref, so the assertion can be satisfied by information you never looked at.

for a senior

Name the concrete failure sequence and both mitigations — the integration check introduced in Git 2.30 and an explicitly pinned expected value — and note that client-side flags never enforce policy.

for a principal

Decide where the guarantee lives: courtesy flags on developer machines versus refusal of non-fast-forward updates at the receiving repository, and what automation is allowed to force-push at all.

## The gap in one paragraph `--force-with-lease` compares the remote ref against your remote-tracking ref. It is checking *freshness of information*, not *whether you did anything about it*. Those come apart the moment something other than a deliberate `git fetch` updates your tracking refs — and on a modern developer machine, several things do. ## How the accident happens 1. You fetch, then start an interactive rebase of `feature/api` and leave it half-done. 2. A teammate pushes a hotfix commit to the same branch. 3. Your editor's periodic fetch, or a `git fetch --all` from a script, updates `refs/remotes/origin/feature/api` to include that commit. 4. You finish the rebase and run `git push --force-with-lease`. 5. The lease compares the remote ref to your tracking ref. They match — the tracking ref was refreshed for you. The push is accepted. 6. The teammate's commit is no longer reachable from the branch. Nothing warned you, because from the lease's point of view your information was current. The information was current; your *branch* was not. ## What --force-if-includes checks instead `--force-if-includes` was added in Git 2.30 and is meaningful only in combination with `--force-with-lease`. Rather than comparing ref values, it asks whether the commit the remote-tracking ref points at has actually been incorporated into the local branch you are pushing — determined by checking whether that commit is reachable from an entry in the local branch's reflog. The distinction is exactly the one that matters: a fetch updates a remote-tracking ref but leaves no trace in your branch's reflog, so it does not satisfy the check. Rebasing your branch onto the fetched tip, or merging it in, does. In effect the flag says "force only if my branch was built on top of what the remote currently has". Because it is meaningful only with a lease, request both explicitly rather than relying on defaults: `git push --force-with-lease --force-if-includes origin feature/api` ## The other robust answer Pin the expectation yourself: `git push --force-with-lease=feature/api:<sha> origin feature/api`, where `<sha>` is the remote tip you personally inspected. Nothing that happens to your tracking refs can change a value you typed. This is verbose but bulletproof, and it is the right form inside automation, where background fetches are common and a wrong force-push is expensive. ## What none of it fixes All three variants only decide whether *this* push should be accepted. None of them helps the people who already fetched the pre-rewrite branch: their local branches still descend from commits that no longer exist upstream, and they must reset or rebase onto the new tip rather than merge. And none of them is a substitute for enforcement — a client-side flag is a courtesy, so branches that must never be rewritten should be protected at the receiving repository, where no client flag can bypass the rule. ## Demonstrating it in an interview The answer that lands is the mechanism, not the flag name: "the lease is a check on my *information*, and information can be refreshed without me. `--force-if-includes` checks my *branch* instead — whether what the remote has was actually integrated into what I am about to push — and an explicit expected value achieves the same thing by taking the tracking ref out of the loop."

  • Why does a plain fetch not satisfy --force-if-includes?
    Because it checks whether the remote-tracking tip is reachable from the local branch's reflog — that is, whether your branch was actually built on it. A fetch only moves the remote-tracking ref; it leaves the local branch untouched, so nothing in that branch's history reflects the new commit.
  • What kinds of tools update remote-tracking refs without you noticing?
    Editors that poll the remote, shell prompts showing ahead/behind counts, scheduled `git fetch --all` scripts, and a pull run in another worktree of the same repository. Any of them can silently renew a lease you thought was pinned to what you inspected.
  • How would you make automation force-push safely?
    Read the remote tip explicitly, then pass it as `--force-with-lease=<ref>:<sha>`, so the assertion is a value the job chose rather than whatever the tracking ref happens to hold. In CI, background fetches and shared checkouts make the defaulted form genuinely unreliable.

saying these in an interview costs you the question

  • Believes --force-with-lease cannot lose commits
  • Thinks a fetch counts as having integrated the change
  • Confuses freshness of tracking refs with local integration
  • Assumes client-side flags enforce branch policy
  • Uses defaulted leases in automation with shared checkouts

context