# How no-mistakes Handles Merge Conflicts: Detection, Resolution, and Safety

> Learn how no-mistakes handles merge conflicts as pipeline findings, using an LLM agent for automatic resolution and staging with force-with-lease safety.

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

---

**no-mistakes treats merge conflicts as first-class pipeline findings, detecting them during dry rebases or CI checks, then employing an LLM agent to resolve conflict markers with automatic staging and rebasing, protected by force-with-lease safety guards.**

The `no-mistakes` repository provides a pipeline-based automation toolkit for Git workflows that treats merge conflicts as actionable events rather than fatal errors. According to the source code in `kunchenguid/no-mistakes`, the system implements a multi-layered approach to **no-mistakes merge conflicts** that spans detection, reporting, automated resolution, and push safety.

## Detecting Merge Conflicts During the Rebase Step

The primary detection mechanism occurs in the *Rebase* step, implemented in [`internal/pipeline/steps/rebase.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/pipeline/steps/rebase.go). Before modifying any history, the pipeline performs a dry rebase onto target branches (`origin/<branch>` and `origin/<default>`) to test for conflicts.

The `tryRebase` function attempts the rebase and returns a slice of conflicted files if the operation stops:

```go
// internal/pipeline/steps/rebase.go
conflictFiles, err := tryRebase(ctx, sctx, target)
if len(conflictFiles) > 0 {
    conflictTargets = append(conflictTargets, target)
    for _, file := range conflictFiles {
        conflictFindings = append(conflictFindings,
            Finding{Severity: "warning", File: file,
                    Description: fmt.Sprintf("merge conflict rebasing onto %s", target)})
    }
}

```

Each conflict is recorded as a **Finding** with severity `warning` and a descriptive message indicating the target branch. These findings accumulate across all attempted targets.

### Recording Conflicts as Step Outcomes

After attempting all rebase targets, the step constructs a `StepOutcome` that signals the executor to pause:

- `NeedsApproval: true` — indicates human or agent review is required
- `AutoFixable: true` — signals that an automated fix may be attempted

This outcome triggers the conflict resolution workflow rather than failing the pipeline.

## CI Monitoring for Merge Conflicts

Beyond local rebase detection, the CI step in [`internal/pipeline/steps/ci.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/pipeline/steps/ci.go) queries the remote host's mergeable state. When running against GitHub, GitLab, or Bitbucket, the system checks the `MergeableState` field:

```go
// internal/pipeline/steps/ci.go (excerpt)
if host.Capabilities().MergeableState {
    mergeState, mergeErr := host.GetMergeableState(ctx, pr)
    if mergeErr == nil {
        mergeConflict = mergeState.Conflict()   // true → conflict
        timeoutMergeConflict = mergeConflict
    }
}

```

If `mergeState.Conflict()` returns true, the step adds the same "merge conflict" flag to its findings. When the run operates in *fixing* mode, this detection immediately invokes the agent resolution routine.

## Agent-Driven Conflict Resolution

When `rebaseWithAgent` is invoked (typically in [`internal/pipeline/steps/rebase.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/pipeline/steps/rebase.go)), the pipeline aborts the current rebase, collects the conflicted file list from `rebaseConflictFiles`, and constructs a detailed prompt for the LLM agent.

The prompt explicitly instructs the agent to:

1. Locate and resolve conflict markers (`<<<<<<<`, `=======`, `>>>>>>>`)
2. Stage resolved files using `git add <file>`
3. Complete the rebase with `git rebase --continue`

```go
// internal/pipeline/steps/rebase.go – the agent prompt
prompt := fmt.Sprintf(`Resolve git rebase conflicts. The rebase of the current branch onto %s has conflicts.

Current conflicted files:
- %s

Instructions:
- Find all conflicting files and resolve the conflict markers (<<<<<<< ======= >>>>>>>).
- After resolving each file, stage it with: git add <file>
- After all conflicts are resolved, run: git rebase --continue
- …`, targetRef, strings.Join(conflictFiles, "\n- "))

```

The agent must return a JSON response containing a `summary` field. The `rebaseWithAgent` function then executes `git rebase --continue` (or aborts on error) and pushes the resolved history.

## Force-Push Safety with Lease Guards

Before pushing resolved conflicts, the pipeline computes a force-push decision via `resolveForcePushDecision` in [`internal/pipeline/steps/ci_fix.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/pipeline/steps/ci_fix.go). This safety mechanism prevents accidental overwrites of new remote commits:

```go
// internal/pipeline/steps/ci_fix.go
decision, err := resolveForcePushDecision(gitRun, pushURL, ref, newHeadSHA,
                                         sctx.Run.HeadSHA, sctx.Run.BaseSHA)

```

The decision relies on the *last observed* remote SHA (`sctx.Run.HeadSHA`). If the remote has received out-of-band commits since the pipeline began, the push is rejected rather than silently overwriting history. This protects the conflict-resolution workflow from losing work when multiple processes interact with the same branch.

## Human-in-the-Loop Fallback

If the agent returns no changes or the conflict persists after resolution attempts, the step returns a finding with `ActionAskUser`. The terminal UI (`axi`) displays a *parked* status, allowing the developer to intervene manually and resolve complex semantic conflicts that require human judgment.

## Summary

- **Early Detection**: The `tryRebase` function in [`internal/pipeline/steps/rebase.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/pipeline/steps/rebase.go) performs dry rebases to detect conflicts before modifying history, recording them as severity `warning` findings.
- **CI Integration**: The CI monitor queries `MergeableState` via `host.GetMergeableState` to detect remote conflicts without local rebase operations.
- **Automated Resolution**: The `rebaseWithAgent` function constructs explicit prompts for LLM agents to resolve conflict markers, stage files, and continue rebases.
- **Push Safety**: `resolveForcePushDecision` enforces force-with-lease semantics using `Run.HeadSHA` to prevent overwriting concurrent remote changes.
- **Graceful Degradation**: Unresolvable conflicts trigger `ActionAskUser`, parking the run for human intervention in the `axi` interface.

## Frequently Asked Questions

### How does no-mistakes detect merge conflicts before attempting a destructive rebase?

The pipeline calls `tryRebase` in [`internal/pipeline/steps/rebase.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/pipeline/steps/rebase.go) to perform a dry rebase onto target branches. If the rebase stops due to conflicts, the function returns the list of conflicted files, which are recorded as **Finding** structures with severity `warning` and descriptions indicating the target branch.

### What prevents no-mistakes from overwriting remote commits during conflict resolution?

The `resolveForcePushDecision` function in [`internal/pipeline/steps/ci_fix.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/pipeline/steps/ci_fix.go) compares the new head SHA against `sctx.Run.HeadSHA` (the last observed remote state). If the remote has diverged, the push is rejected, enforcing force-with-lease semantics that protect against accidental overwrites during automated fixes.

### Can no-mistakes resolve merge conflicts without human intervention?

Yes, when running in fixing mode, the system invokes `rebaseWithAgent` to prompt an LLM agent with the specific conflicted files and resolution instructions. The agent edits the files, stages them with `git add`, and the pipeline runs `git rebase --continue` automatically, provided the agent returns a valid JSON summary.

### How does the CI step detect merge conflicts independently of the rebase step?

The CI step in [`internal/pipeline/steps/ci.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/pipeline/steps/ci.go) leverages `host.GetMergeableState` to query the Git provider's API (GitHub, GitLab, Bitbucket) for the `MergeableState` field. When the state equals `CONFLICTING`, the step flags the conflict and can immediately trigger the agent resolution routine without performing a local rebase.