# How the No-Mistakes Force‑Push Safety System Prevents Data Loss

> Prevent data loss with the no-mistakes force-push safety system. It intelligently detects upstream commits, aborting pushes to protect your work.

- Repository: [Kun Chen/no-mistakes](https://github.com/kunchenguid/no-mistakes)
- Tags: deep-dive
- Published: 2026-07-19

---

**The no‑mistakes force‑push safety system prevents data loss by re‑reading the remote branch state, classifying the push type, and running a patch‑ID‑aware comparison to detect any upstream commits not present in the new local history, aborting the push with a structured error instead of silently overwriting work.**

The `no‑mistakes` pipeline is an open‑source tool that eliminates accidental data loss during destructive Git operations. Its force‑push safety mechanism is implemented in [`internal/pipeline/steps/forcepush.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/pipeline/steps/forcepush.go) and enforces a strict defensive sequence that verifies every forced push against the live remote state. By anchoring decisions to the last observed remote SHA and comparing patch IDs rather than simple commit hashes, the system distinguishes harmless rebases from genuine upstream work that would be discarded.

## Core Safety Checks in [`internal/pipeline/steps/forcepush.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/pipeline/steps/forcepush.go)

### Re‑Reading the Remote Head with `lsRemoteSHA`

The first defensive step is `lsRemoteSHA`, defined around lines 96‑108, which contacts the remote via `git ls‑remote` to obtain the current SHA of the target branch. This fresh read guarantees the pipeline validates against live remote state rather than stale local tracking refs.

### Classifying Push Intent

Before running expensive comparisons, the pipeline classifies the push into one of three categories in [`internal/pipeline/steps/forcepush.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/pipeline/steps/forcepush.go) (lines 71‑80):

- **New branch** (`newBranch: true`): The branch does not exist remotely, so no upstream history is at risk.
- **Up‑to‑date** (`upToDate: true`): The remote already points at the intended head, making the operation a no‑op.
- **Requires verification**: The push is destructive and proceeds to the full safety check.

### Detecting Out‑of‑Band Changes

When the live remote SHA differs from the last‑seen SHA, the function `remoteCommitsNotIncorporated` is invoked (lines 82‑86). It fetches the remote tip without altering remote‑tracking refs and executes `git rev‑list` with `--cherry‑pick` to list commits that are *right‑only*—present on the remote but absent from the new local head (lines 30‑40).

Because this comparison is **patch‑ID aware**, rebased commits that preserve the exact same diff content are considered already incorporated. Only commits representing genuinely new upstream work are flagged as dropped.

### Excluding Known History with `baseSHA`

If the caller supplies a `baseSHA`, the pipeline excludes that SHA’s ancestors from the comparison (lines 35‑38). This allows legitimate rewrites the pipeline already knows about—such as automated amends or autofixes—to pass validation without triggering false positives.

### Aborting Unsafe Pushes with `forcePushWouldDiscardError`

If any remote commits remain unincorporated after filtering, the pipeline returns a `forcePushWouldDiscardError` (lines 24‑43). The error carries a descriptive message and lists sample SHAs of the commits that would be lost. The pipeline aborts the push and surfaces a finding rather than silently overwriting work.

When no dropped commits are detected, the decision is returned with the remote SHA recorded, and the caller proceeds with the force‑push (lines 90‑92).

## Practical Code Examples from the `no‑mistakes` Pipeline

### Example 1: Determining a Safe Push Decision

```go
// gitRun is a wrapper around git commands (provided by the pipeline)
decision, err := resolveForcePushDecision(
    gitRun,
    pushURL,          // remote URL
    "refs/heads/feature",
    newHeadSHA,       // SHA we intend to push
    lastSeenSHA,      // SHA we previously saw on the remote
    baseSHA,          // SHA of the branch base used for the run
)
if err != nil {
    // err will be of type *forcePushWouldDiscardError if the push would lose data
    log.Fatalf("cannot push: %v", err)
}
if decision.newBranch {
    fmt.Println("Branch does not exist remotely – safe to push.")
} else if decision.upToDate {
    fmt.Println("Remote already at desired HEAD – nothing to do.")
} else {
    fmt.Printf("Safe force‑push anchored at %s\n", decision.remoteSHA)
}

```

### Example 2: Handling a Rejected Force‑Push

```go
if discardErr, ok := err.(*forcePushWouldDiscardError); ok {
    fmt.Printf("Push rejected: %s\n", discardErr.Error())
    // Show the user the commits that would be lost
    for _, sha := range discardErr.dropped {
        fmt.Printf("- %s\n", sha)
    }
    // The caller can now surface a finding or ask the user to rebase.
}

```

## Key Design Principles Behind No‑Mistakes Data Loss Prevention

- **Live remote verification**: Every force‑push decision is anchored to a fresh `git ls‑remote` read rather than cached local state.
- **Patch‑ID intelligence**: Using `git rev‑list --cherry‑pick` means rebased or amended commits with identical patches do not block pushes.
- **Explicit failure mode**: Unsafe pushes fail fast with a structured `forcePushWouldDiscardError` that includes the specific SHAs at risk.
- **Configurable history windows**: The `baseSHA` parameter lets the pipeline distinguish expected local rewrites from unexpected upstream changes.

## Summary

- The no‑mistakes force‑push safety system lives in [`internal/pipeline/steps/forcepush.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/pipeline/steps/forcepush.go) and prevents silent overwrites of upstream work.
- `lsRemoteSHA` refreshes remote state via `git ls‑remote` before any comparison begins.
- Pushes are classified as new‑branch, up‑to‑date, or requiring full verification against the live remote head.
- `remoteCommitsNotIncorporated` uses `git rev‑list --cherry‑pick` to perform patch‑ID‑aware detection of unincorporated remote commits.
- A supplied `baseSHA` excludes known ancestors, reducing false positives for legitimate rewrites.
- If unincorporated commits remain, a `forcePushWouldDiscardError` aborts the push and surfaces the dropped commit SHAs.

## Frequently Asked Questions

### What happens if the target branch does not exist or is already up to date?

If the branch does not exist remotely, the pipeline marks the push as `newBranch: true` and allows it without further checks. If the remote already points at the new head, the push is marked `upToDate: true` and skipped as a no‑op. Both cases bypass the expensive patch‑ID comparison because no upstream history can be lost.

### How does patch‑ID comparison differ from checking raw commit SHAs?

A raw SHA check would flag every rebased commit as missing and potentially lost. The no‑mistakes pipeline instead uses `git rev‑list --cherry‑pick`, which computes **patch IDs** based on the actual diff content. If a commit was rebased or amended but its patch ID is unchanged, it is treated as incorporated. Only commits with genuinely new patch IDs are considered dropped upstream work.

### Can automated rewrites or autofixes still pass the safety check?

Yes. When the caller supplies a `baseSHA`, the pipeline excludes that SHA’s ancestors from the comparison. This lets intended rewrites—such as automated amends performed earlier in the pipeline—pass validation, while still catching new out‑of‑band commits pushed by other collaborators.

### Where is the force‑push error defined, and how does the pipeline report dropped commits?

The `forcePushWouldDiscardError` is constructed in [`internal/pipeline/steps/forcepush.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/pipeline/steps/forcepush.go) when unincorporated remote commits are detected. The error carries a slice of dropped commit SHAs, and the pipeline surfaces them directly in the failure message so users know exactly which upstream work would have been erased.