# How the no-mistakes Push Step Handles Failures and Conflicts

> Discover how the no-mistakes push step reliably handles failures and conflicts using force-with-lease, prevents silent overwrites, redacts sensitive URLs, and automatically reconciles stale records.

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

---

**The no-mistakes push step uses force-with-lease to prevent silent overwrites of remote history, redacts sensitive URLs in all error messages, and automatically reconciles stale database records on retry.**

The push step in `kunchenguid/no-mistakes` serves as the final safeguard in the CI/CD pipeline. Located in [`internal/pipeline/steps/push.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/pipeline/steps/push.go), this component orchestrates formatting, evidence staging, and remote synchronization while maintaining strict safety guarantees. Understanding how the no-mistakes push step handles failures and conflicts reveals a defensive design philosophy that prioritizes data integrity over convenience.

## Push Step Architecture and Responsibilities

The push step executes four distinct phases before updating system state. Each phase contains specific failure modes and recovery behaviors defined in [`internal/pipeline/steps/push.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/pipeline/steps/push.go).

### Formatter and Evidence Staging

The step begins by running an optional formatter via `runStepShellCommand`. If this returns a non-zero exit code, the error is logged as a **warning** but explicitly does not abort the step—the push proceeds regardless of formatting success.

Next, `stageInRepoEvidence` handles test-evidence artifacts. If the evidence directory is ignored by `.gitignore` or cannot be added, the step aborts immediately and propagates the error. This prevents silent omissions of critical test data. The tests `TestPushStep_ForceAddsInRepoEvidenceArtifacts` and `TestPushStep_DoesNotForceAddIgnoredEvidenceDirectory` in [`internal/pipeline/steps/push_test.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/pipeline/steps/push_test.go) verify these behaviors.

### Committing Agent Changes

After staging, the step attempts to commit any agent-generated changes. If `git add` or `git commit` fails—for example, if the repository is in a bad state—the error is wrapped with context (`stage agent changes: %w`) and returned immediately. The push to remote is never attempted when local commits fail.

## Conflict Resolution Strategy

The no-mistakes push step does **not** attempt automatic rebasing or merging. Instead, it relies on **force-with-lease** to guarantee safety when overwriting existing branches.

### Remote SHA Verification

Before pushing, the step queries the remote for the current SHA using `git.LsRemote` (lines 70-74 in [`push.go`](https://github.com/kunchenguid/no-mistakes/blob/main/push.go)):

- If `upstreamSHA` is empty, the branch is new and a normal push executes.
- If `upstreamSHA` exists, the step prepares a force-with-lease push.

### Force-With-Lease Implementation

When the target branch exists, the step invokes `git.Push` with `forceWithLease=true` (lines 75-79), constructing the Git command:

```bash
git push --force-with-lease=<ref>:<expectedSHA>

```

This ensures Git rejects the push if the remote branch has moved since the SHA was read, yielding the error: "remote ref does not match expected SHA". This mechanism prevents the pipeline from accidentally overwriting commits created by parallel processes.

```go
// Simplified excerpt from internal/pipeline/steps/push.go
upstreamSHA, lsErr := git.LsRemote(ctx, sctx.WorkDir, pushURL, ref)
if lsErr != nil {
    return nil, fmt.Errorf("ls-remote %s: %w", pushTarget, lsErr)
}

if upstreamSHA != "" {
    // Existing branch – safe force push
    if err := git.Push(ctx, sctx.WorkDir, pushURL, ref, upstreamSHA, true); err != nil {
        return nil, fmt.Errorf("push to %s: %w", pushTarget, err)
    }
} else {
    // New branch – regular push without force
    if err := git.Push(ctx, sctx.WorkDir, pushURL, ref, "", false); err != nil {
        return nil, fmt.Errorf("push to %s: %w", pushTarget, err)
    }
}

```

## Error Handling and Security Mechanisms

All Git errors are wrapped with descriptive context and subjected to URL redaction before propagation.

### Credential Redaction

The `safeurl.Redact` function processes all error messages containing URLs. This prevents credential leakage when authentication fails or when the remote is unreachable. The test `TestPushStep_RedactsForkURLInGitErrors` confirms that fork URLs containing tokens are sanitized in error output.

### Specific Error Patterns

- **Remote lookup failure**: Returns `ls-remote <target>: %w` without falling back to blind push
- **Push failure**: Returns `push to <target>: %w` with redacted URL
- **Local ref update failure**: Returns `update local branch ref: %w` and skips database updates to preserve consistency

## Database Reconciliation and Stale State Recovery

After a successful push, the step handles potential database race conditions. If the run's `HeadSHA` stored in the database differs from the actual local `HEAD` (for example, due to a failed previous `UpdateRunHeadSHA` attempt), the step re-reads the local ref and updates the database accordingly (lines 92-101).

The test `TestPushStep_ReconcilesStaleDatabaseHeadSHA` verifies this behavior, ensuring that retries operate on consistent state even when previous attempts partially failed.

## Summary

- **Force-with-lease protection**: The step only overwrites remote branches when it can verify the previous SHA, preventing accidental history loss.
- **Graceful degradation**: Formatter failures are logged but non-blocking, while staging and commit errors halt execution immediately.
- **Security by default**: All URLs in error messages are redacted via `safeurl.Redact` to prevent credential exposure.
- **State consistency**: The step automatically reconciles stale `HeadSHA` values in the database after successful pushes.
- **Explicit error propagation**: Every failure mode returns wrapped, contextual errors rather than silently retrying or falling back to unsafe operations.

## Frequently Asked Questions

### What happens if the formatter fails during the push step?

Formatter failures are logged as warnings but do not abort the step. The push proceeds regardless of formatting success, ensuring that code changes reach the remote even when formatting tools encounter issues. This behavior is implemented in lines 24-33 of [`internal/pipeline/steps/push.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/pipeline/steps/push.go).

### How does no-mistakes prevent accidental overwrites of remote branches?

The step queries the remote SHA using `git.LsRemote` before pushing. If the branch exists, it uses `git push --force-with-lease=<ref>:<expectedSHA>` instead of a standard force push. Git aborts the operation if the remote branch has moved since the query, preventing silent overwrites of concurrent commits.

### Why does the push step update the database HeadSHA after a successful push?

The step reconciles the database record with the actual repository state to handle retry scenarios. If a previous run failed after pushing but before updating the database, the stored `HeadSHA` becomes stale. The step detects this mismatch (lines 92-101) and calls `sctx.DB.UpdateRunHeadSHA` to ensure consistency before completing.

### How are credentials protected when push operations fail?

All error messages containing URLs are processed through `safeurl.Redact` before being returned. This function strips credentials from fork URLs and remote endpoints, ensuring that authentication tokens or passwords never appear in logs or error traces when network or permission errors occur.