Force-Push Safety Mechanisms in no-mistakes: Preventing Data Loss During Git Operations

The no-mistakes repository prevents data loss during force-pushes by implementing a multi-layered safety system that leases the remote HEAD, performs fast-path checks, and validates that no upstream commits would be discarded using patch-ID comparison before allowing the operation.

Accidental force-pushes that overwrite collaborative work are a persistent risk in automated CI/CD pipelines. The no-mistakes tool implements robust force-push safety mechanisms that analyze the remote state and local changes to prevent silent data loss. These protections reside in internal/pipeline/steps/forcepush.go and ensure that automated rewrite operations never discard unrecognized upstream commits.

Remote-Head Lease and Fast-Path Validation

The safety workflow begins by establishing a lease on the remote state to determine if the push is safe to proceed.

Capturing the Remote SHA

The lsRemoteSHA function executes git ls-remote to capture the current remote SHA before any push operation. This value serves as the foundation for the remote-head lease mechanism. If the remote has not moved since the pipeline last observed it (lastSeenSHA), the system grants permission to proceed because the pipeline already possesses complete knowledge of the remote history.

Fast-Path Exit Conditions

Before performing expensive content analysis, resolveForcePushDecision checks two deterministic conditions:

  • New branch: When ls-remote returns no SHA, the branch does not exist on the remote, so the system performs a normal push instead of a force-push.
  • Up-to-date: If the remote SHA already matches the newHeadSHA, the operation exits early with no action required.

Content-Based Safety Net

When the remote has advanced out-of-band (the remote SHA differs from lastSeenSHA), the system performs a deep validation to ensure no commits would be permanently lost.

Detecting Dropped Commits with Patch-ID

The remoteCommitsNotIncorporated function fetches the remote tip into FETCH_HEAD without disturbing remote-tracking refs. It then executes:

args := []string{
    "rev-list", "--cherry-pick", "--right-only",
    fmt.Sprintf("%s...%s", newHeadSHA, remoteSHA),
}
if baseSHA != "" && !git.IsZeroSHA(baseSHA) {
    // Exclude the known base history so we don’t flag our own rewrites
    args = append(args, "^"+baseSHA)
}
out, err := gitRun(args...)

This command identifies commits reachable from the remote that are not represented in the new head by patch-ID—meaning the actual code changes are unique and would be lost if the push proceeded.

Excluding Legitimate Rewrites

The mechanism distinguishes between dangerous data loss and legitimate history rewrites. By appending ^+baseSHA to the rev-list arguments, the system excludes commits that are ancestors of the run's base commit. This ensures that amends, autofixes, and other pipeline-generated rewrites are not flagged as data loss, while genuine upstream contributions are protected.

Enforcement and Error Handling

If the content analysis returns any commits, the system raises a forcePushWouldDiscardError. This error includes the offending SHAs and explains that the push would discard upstream work, causing the pipeline to abort immediately.

// Example: deciding whether a force‑push is safe
remoteSHA, err := lsRemoteSHA(gitRun, remoteURL, ref)
if err != nil { … }

decision, err := resolveForcePushDecision(
    gitRun,
    remoteURL,
    ref,
    newHeadSHA,   // the SHA we intend to push
    lastSeenSHA, // the remote SHA last observed by the pipeline
    baseSHA,     // the base commit of the run
)
if err != nil {
    // err will be *forcePushWouldDiscardError* if the push would lose data
    log.Fatalf("push refused: %v", err)
}
if decision.upToDate {
    fmt.Println("Remote already at the desired head – nothing to do.")
} else if decision.newBranch {
    fmt.Println("Branch does not exist remotely – performing a normal push.")
} else {
    fmt.Printf("Force‑push allowed (remote lease %s).\n", shortSHA(decision.remoteSHA))
}

Verification Through Integration Tests

The safety guarantees are enforced through comprehensive tests in internal/pipeline/steps/forcepush_safety_test.go and internal/pipeline/steps/forcepush_decision_test.go:

  • TestCIStep_CommitAndPush_RefusesToClobberUnseenUpstreamCommit: Verifies that CI autofix runs refuse to overwrite remote-only commits.
  • TestPushStep_RefusesToClobberAdvancedUpstreamBranch: Confirms the push step blocks force-pushes when the remote has advanced.
  • TestForcePushRun_RefusesToClobberOutOfBandBranchCommit: Validates that the combined rebase+push flow respects safety guarantees.

Summary

  • Force-push safety mechanisms in no-mistakes rely on remote-head leases to establish trust boundaries.
  • Content validation uses git rev-list --cherry-pick to compare patch-IDs and detect commits that would be lost.
  • The system distinguishes between legitimate pipeline rewrites and dangerous upstream overwrites by excluding the base commit history.
  • A forcePushWouldDiscardError aborts the operation when data loss is detected.
  • Integration tests verify protection against out-of-band branch advances and unseen upstream commits.

Frequently Asked Questions

What happens if the remote branch advances while the pipeline is running?

If the remote SHA no longer matches the lastSeenSHA, the resolveForcePushDecision function triggers remoteCommitsNotIncorporated to verify that no new remote commits would be discarded. If any are found, a forcePushWouldDiscardError is raised and the push aborts.

How does no-mistakes distinguish between legitimate rewrites and data loss?

The system uses the baseSHA parameter to exclude the pipeline's own history from the safety check. By passing ^+baseSHA to git rev-list, it ignores commits that are ancestors of the run's base, allowing amends and autofixes while blocking deletion of external contributions.

Where is the core force-push logic implemented?

The primary implementation resides in internal/pipeline/steps/forcepush.go, which contains the resolveForcePushDecision function and the remoteCommitsNotIncorporated helper that performs the patch-ID comparison.

How does the tool handle new branches that don't exist on the remote?

When lsRemoteSHA detects no remote SHA for the reference, the system classifies this as a new branch scenario and performs a normal push rather than a force-push, eliminating the risk of overwriting non-existent history.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →