# How no-mistakes Prevents Accidental Data Loss With Force-Pushes

> Learn how no-mistakes pipeline prevents accidental data loss. It anchors force-pushes to remote SHAs and rejects operations that discard commits, ensuring data integrity.

- Repository: [Kun Chen/no-mistakes](https://github.com/kunchenguid/no-mistakes)
- Tags: how-to-guide
- Published: 2026-07-14

---

**The no-mistakes pipeline prevents accidental data loss by anchoring force-pushes to a previously observed remote SHA and refusing the operation when patch-id analysis detects commits that would be discarded.**

The `kunchenguid/no-mistakes` repository implements a CI/CD pipeline that treats every `git push --force` as a potential data-loss hazard. Before executing any forced update, the system runs a comprehensive safety decision routine that verifies no upstream work would be overwritten. This automated approach ensures that **preventing accidental data loss with force-pushes** is enforced at the infrastructure level, eliminating reliance on error-prone manual checks.

## The Safety Decision Routine in forcepush.go

The core protection logic resides in [`internal/pipeline/steps/forcepush.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/pipeline/steps/forcepush.go), where the `resolveForcePushDecision` function implements a seven-step verification process. This routine determines whether a force-push would discard commits that exist on the remote but not in the local pipeline state.

### Resolving the Remote Reference

First, the `lsRemoteSHA` function queries the remote for the current HEAD of the target reference. This establishes the ground truth for what currently exists on the remote server.

- If the reference does not exist, the push is treated as a **new branch** creation (`newBranch: true`)
- If the remote SHA matches the intended new head exactly, the operation is a **no-op** (`upToDate: true`)

### Validating the Push Anchor

The pipeline maintains a `lastSeenSHA` representing the tip of the remote branch as observed during the last successful operation. When the current remote SHA equals this `lastSeenSHA`, the force-push is permitted because only the pipeline's own history would be rewritten.

This **anchor validation** ensures the pipeline never trusts a freshly fetched tip without verifying it matches the previously recorded state.

### Detecting Divergence with Patch-ID Comparison

When the remote has moved since the pipeline last observed it, the system must verify that all commits now on the remote are already incorporated into the new head. The `remoteCommitsNotIncorporated` function handles this detection by:

1. Fetching the remote tip into `FETCH_HEAD`
2. Running `git rev-list --cherry-pick --right-only newHead...remote` to identify commits present on the remote but absent from the new head
3. Using patch-id comparison that is **robust to rebases**—recognizing that rebases rewrite commit SHAs but preserve the underlying changes

The `--cherry-pick` flag ensures the comparison uses patch-id semantics rather than strict SHA matching, allowing legitimate rebases while catching true data loss.

### Refusing Unsafe Operations

If the `dropped` commit list is non-empty, the system returns a `forcePushWouldDiscardError`. The error's `Error()` method assembles a human-readable message listing sample SHAs and explaining that the push would discard upstream work.

The calling push step receives either a `forcePushDecision` struct (indicating safety) or this error, aborting the push immediately when data loss is detected.

## Code Implementation Details

The safety routine is invoked from the push step as follows:

```go
decision, err := resolveForcePushDecision(
    gitRun,                 // thin wrapper around git commands
    pushURL,                // remote URL
    ref,                    // e.g., "refs/heads/main"
    newHeadSHA,             // SHA intended to be pushed
    lastSeenSHA,            // SHA the pipeline last observed
    baseSHA,                // base of the run for cherry-pick exclusion
)
if err != nil {
    // Error will be *forcePushWouldDiscardError when commits would be lost
    return fmt.Errorf("cannot push: %w", err)
}
if decision.upToDate {
    return nil // Nothing to do—remote already matches
}
if decision.newBranch {
    // Push new branch normally
    gitRun("push", pushURL, fmt.Sprintf("%s:%s", newHeadSHA, ref))
}

```

For diagnostic purposes, you can check which commits would be discarded:

```go
dropped, _ := remoteCommitsNotIncorporated(
    gitRun,
    pushURL,
    ref,
    newHeadSHA,
    remoteSHA,
    baseSHA,
)
if len(dropped) > 0 {
    fmt.Printf("Commits that would be discarded:\n")
    for _, c := range dropped {
        fmt.Println(shortSHA(c))
    }
}

```

## Three Safety Invariants

The logic in [`internal/pipeline/steps/forcepush.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/pipeline/steps/forcepush.go) enforces three critical invariants:

1. **Never discard upstream work** – Any commit appearing only on the remote must be merged or rebased before a force-push is allowed.

2. **Anchor the lease to the last observed remote SHA** – The pipeline verifies the remote hasn't changed unexpectedly since the last observation, preventing race conditions where new commits appear between check and push.

3. **Use patch-id semantics** – The `--cherry-pick` comparison recognizes that rebased commits contain identical changes despite different SHAs, reducing false positives while maintaining protection against actual data loss.

When these invariants are violated, users see an error message similar to:

```

refusing to force-push refs/heads/main: remote head abc1234 carries 3 commit(s) the pipeline never incorporated (e.g. def5678, 9ab0c1); pushing would discard upstream work. Re-fetch and rebase onto the current remote, or push manually if this overwrite is intended.

```

## Summary

- The `resolveForcePushDecision` function in [`internal/pipeline/steps/forcepush.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/pipeline/steps/forcepush.go) acts as a gatekeeper for all force-push operations.
- **Patch-id comparison** via `git rev-list --cherry-pick` distinguishes between harmless rebases and dangerous data loss.
- The `lastSeenSHA` anchor prevents race conditions where remote commits appear during pipeline execution.
- When unincorporated commits are detected, `forcePushWouldDiscardError` aborts the push with specific commit SHAs listed.
- This protection is verified by regression tests including `TestCIStep_CommitAndPush_RefusesToClobberUnseenUpstreamCommit`.

## Frequently Asked Questions

### What happens if the remote branch does not exist yet?

When `lsRemoteSHA` determines the reference does not exist on the remote, the system sets `newBranch: true` and allows the push to proceed normally. Since there is no existing history to overwrite, there is no risk of data loss.

### How does no-mistakes distinguish between rebased commits and truly lost commits?

The `remoteCommitsNotIncorporated` function uses `git rev-list --cherry-pick`, which compares commits by **patch-id** rather than SHA. This means rebased commits that contain identical changes are recognized as incorporated, while commits with unique changes that exist only on the remote are flagged as potential data loss.

### What error message appears when a force-push is blocked?

The system returns a `forcePushWouldDiscardError` with a message identifying the remote head SHA and listing specific commits that would be discarded. The error suggests re-fetching and rebasing onto the current remote, or pushing manually if the overwrite is truly intended.

### Can I override the safety check if I need to force-push intentionally?

The pipeline blocks the operation and returns an error, but the error message explicitly mentions that you can **push manually** if the overwrite is intended. This requires deliberate action outside the automated pipeline, ensuring force-pushes are never accidental.