# How the Branch Synchronization Service Handles Blocked States Without Force-Pushing in no-mistakes

> Discover how no-mistakes branch synchronization safely handles blocked states without force-pushing. Get explicit remediation plans for non-fast-forward scenarios.

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

---

**The branch synchronization service in no-mistakes never force-pushes; instead, it classifies every non-fast-forward scenario as a blocked state and returns a safe, non-destructive plan with explicit remediation instructions.**

The `no-mistakes` repository implements a branch synchronization service that acts as the single authority for moving worktrees toward published pipeline commits. Unlike traditional Git workflows that might resolve conflicts with force-pushes, this service treats any situation requiring non-fast-forward updates as a **blocked state** requiring user intervention. By analyzing the relationship between local branches, remote state, and pipeline metadata in [`internal/branchsync/sync.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/branchsync/sync.go), the service ensures data integrity through explicit classification rather than destructive operations.

## Detecting Blocked States During Inspection

All state inspection happens in `(*Service).inspect` (lines [601‑679](https://github.com/kunchenguid/no-mistakes/blob/main/internal/branchsync/sync.go#L601-L679)), which builds a comprehensive `State` object tracking local branches, pipeline runs, and remote bindings. The function uses this data to classify the relationship between the current worktree and the target commit, determining whether synchronization can proceed safely.

### Pipeline-Owned Run Detection

When a pipeline run is still active, the service immediately blocks synchronization through `classifyPipelineOwned` (lines [1009‑1020](https://github.com/kunchenguid/no-mistakes/blob/main/internal/branchsync/sync.go#L1009-L1020)). This returns `StatePipelineOwned` (blocked), preventing any modifications while the pipeline maintains custody of the branch. This check ensures that concurrent pipeline operations never conflict with local synchronization attempts.

### Relation Classification and Divergence Handling

For completed runs where the pipeline has published a commit, `classifyRelation` (lines [998‑1054](https://github.com/kunchenguid/no-mistakes/blob/main/internal/branchsync/sync.go#L998-L1054)) determines the relationship between local and remote state:

- **Equal**: Returns `StateSynchronized`—no work needed.
- **Behind**: Returns `StateBehind`—eligible for fast-forward.
- **Ahead**: Returns `StateLocalAhead`—blocked until the user runs the pipeline.
- **Diverged**: Returns `StateDiverged`—blocked unless `equivalentDivergence` (lines [616‑674](https://github.com/kunchenguid/no-mistakes/blob/main/internal/branchsync/sync.go#L616-L674)) proves the merge tree preserves the remote head.

When diverged, the service only permits an *equivalent-diverge* fast-forward if the tree hashes match, ensuring no remote commits are lost.

## Refresh: Read-Only Remote Validation

The `Refresh` method (lines [8‑76](https://github.com/kunchenguid/no-mistakes/blob/main/internal/branchsync/sync.go#L8-L76)) performs a read-only validation pass using `git ls-remote` to inspect the live remote HEAD. If the remote state differs from the stored push binding, the function returns a blocked plan without modifying any files or refs:

- **Remote missing**: Returns `StateRemoteMissing` (blocked)
- **Remote advanced**: Returns `StateRemoteAdvanced` (blocked) 
- **Remote rewritten**: Returns `StateRemoteRewritten` (blocked)

Each blocked result includes a `Safety` code (such as `blocked_remote_advanced` or `blocked_remote_rewritten`) and a `NextAction` suggestion like `no-mistakes sync --check`. This validation ensures the service never operates on stale remote information.

```bash

# Shows the current state; may suggest a fast-forward or a blocked reason

no-mistakes sync --check

```

## Apply: Strict Safety Enforcement

The `Apply` method (lines [32‑84](https://github.com/kunchenguid/no-mistakes/blob/main/internal/branchsync/sync.go#L32-L84)) implements the actual synchronization logic with strict pre-conditions. The method first repeats the same pre-checks as `Refresh`, and if the plan's `Safety` value is not `SafetySafeFastForward` or `SafetySafeEquivalentAdvance`, it immediately returns the blocked `State` (lines [45‑47](https://github.com/kunchenguid/no-mistakes/blob/main/internal/branchsync/sync.go#L45-L47)).

When conditions permit safe advancement, the service performs only:

1. **Strict fast-forward**: `git merge --ff-only` when behind
2. **Anchor-based reset**: For equivalent-diverge cases (lines [92‑100](https://github.com/kunchenguid/no-mistakes/blob/main/internal/branchsync/sync.go#L92-L100))

If the remote state changes between refresh and apply (e.g., history is rewritten during the operation), the function returns `blocked_remote_changed_before_apply` (lines [71‑73](https://github.com/kunchenguid/no-mistakes/blob/main/internal/branchsync/sync.go#L71-L73)) and exits without modifying the repository.

```bash

# Will fast-forward only when StateBehind and clean

no-mistakes sync

```

## Recover: Handling Terminal Runs Without Pushing

When a run terminates (completes, fails, or cancels) without pushing the pipeline head, the branch becomes stranded. The `Recover` method (lines [30‑55](https://github.com/kunchenguid/no-mistakes/blob/main/internal/branchsync/sync.go#L30-L55)) provides safe custody return through several paths:

- **Equal/Ahead**: Anchors the preserved head locally without moving the worktree
- **Behind & Clean**: Fast-forwards to the preserved head via `recoverFastForward`
- **Behind & Dirty**: Blocks with instructions to commit or stash first
- **Diverged**: Returns `blocked_recover_diverged` and requires manual reconciliation

All recovery paths manipulate only the **gate** repository using compare-and-swap updates (`git update-ref …`) and never push to the remote, guaranteeing no accidental overwrites.

```bash

# Returns custody without a push; use --keep-local to keep current HEAD

no-mistakes sync --recover
no-mistakes sync --recover --keep-local

```

## Why Force-Push Is Never an Option

The architecture treats any non-fast-forward push as *potential data loss*. The `CanApply` helper (lines [13‑18](https://github.com/kunchenguid/no-mistakes/blob/main/internal/branchsync/sync.go#L13-L18)) gates the `Apply` method to safe moves only, while the `blockedPlan` utility (lines [113‑119](https://github.com/kunchenguid/no-mistakes/blob/main/internal/branchsync/sync.go#L113-L119)) standardizes error reporting for every blocked path. By refusing destructive operations and returning detailed `State` objects with specific `Safety` codes, the CLI informs users exactly why operations cannot proceed and how to resolve conflicts.

```bash

# The service will refuse; user must reconcile manually

no-mistakes sync

# Output (example):

# State: blocked_diverged

# Action: inspect_and_reconcile_manually

# Command: git log --oneline --left-right HEAD...refs/no-mistakes/sync-anchor/<runID>

```

## Summary

- The **branch synchronization service** in `kunchenguid/no-mistakes` classifies every non-fast-forward scenario as a blocked state rather than performing destructive operations.
- **State inspection** in `(*Service).inspect` identifies pipeline-owned runs, divergence, and remote changes before any modifications occur.
- **Refresh validation** performs read-only checks via `git ls-remote` to detect remote advancement or rewriting without modifying local state.
- **Apply enforcement** requires `SafetySafeFastForward` or `SafetySafeEquivalentAdvance` status, returning blocked states if pre-conditions change during execution.
- **Recover logic** handles terminal runs through anchor-based updates in the gate repository, never pushing to remote branches.
- **No force-push guarantee** is enforced by the `CanApply` helper and `blockedPlan` utility, ensuring data integrity through explicit user intervention.

## Frequently Asked Questions

### What triggers a blocked state in no-mistakes branch synchronization?

A blocked state occurs when the service detects any condition that would require a non-fast-forward update to synchronize the worktree. Common triggers include: the local branch being ahead of the remote (`StateLocalAhead`), diverged history that fails `equivalentDivergence` checks (`StateDiverged`), active pipeline runs (`StatePipelineOwned`), remote branches that advanced or were rewritten, or dirty worktrees during recovery operations. Each blocked state returns a specific `Safety` code and `NextAction` recommendation rather than modifying the repository.

### How does the service handle divergent branches without force-pushing?

When `classifyRelation` detects divergence (lines [998‑1054](https://github.com/kunchenguid/no-mistakes/blob/main/internal/branchsync/sync.go#L998-L1054)), the service invokes `equivalentDivergence` (lines [616‑674](https://github.com/kunchenguid/no-mistakes/blob/main/internal/branchsync/sync.go#L616-L674)) to check if the merge tree preserves the remote head. Only if the trees are equivalent does it permit an `anchor`-based reset classified as `SafetySafeEquivalentAdvance`. Otherwise, it returns `StateDiverged` with a blocked status and instructions to manually reconcile using commands like `git log --oneline --left-right HEAD...refs/no-mistakes/sync-anchor/<runID>`.

### What happens if the remote branch changes during synchronization?

The `Apply` method implements double-check locking: it re-validates remote state after the initial `Refresh` check. If the remote HEAD changes between validation and application—whether through new commits or history rewriting—the service detects this at lines [71‑73](https://github.com/kunchenguid/no-mistakes/blob/main/internal/branchsync/sync.go#L71-L73) and returns `blocked_remote_changed_before_apply`. This prevents race conditions where the service might accidentally overwrite commits published between the check and the push.

### Can I recover a failed pipeline run without losing local changes?

Yes, the `Recover` method handles terminal runs (completed, failed, or cancelled) through safe custody transfer. If the worktree is clean and behind the preserved pipeline head, it fast-forwards via `recoverFastForward`. If diverged, it blocks with `blocked_recover_diverged` and requires manual reconciliation. You can also use the `--keep-local` flag to anchor the preserved head without moving your current worktree, ensuring local changes remain intact while returning custody to the gate repository.