How the no-mistakes Push Step Handles Failures and Conflicts

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, 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.

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 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):

  • 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:

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.

// 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.

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.

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 →