# How gh-stack Handles Rebase Conflicts Using Git rerere

> Discover how gh-stack automatically resolves rebase conflicts using Git rerere. Learn how it records and reapplies resolutions for smoother workflows.

- Repository: [GitHub/gh-stack](https://github.com/github/gh-stack)
- Tags: internals
- Published: 2026-08-02

---

**gh-stack automates rebase conflict resolution by enabling Git's *rerere* (reuse recorded resolution) feature, which records previous fixes and replays them during cascading rebases, falling back to manual intervention only when encountering previously unseen conflicts.**

gh-stack is a GitHub CLI extension that manages stacked pull requests. When you rebase complex stacks of dependent branches, merge conflicts are inevitable. According to the `github/gh-stack` source code, the tool integrates deeply with Git's built-in rerere mechanism to remember how you resolved conflicts once and automatically apply those resolutions to future rebases.

## Enabling rerere Before Rebase Operations

Before any command that might trigger a rebase, gh-stack ensures the repository is configured to record conflict resolutions. This happens through the `ensureRerere` helper function.

### Checking Repository Configuration

The tool first queries the repository state using `IsRerereEnabled`, which inspects Git's configuration for the `rerere.enabled` setting. In [`internal/git/gitops.go`](https://github.com/github/gh-stack/blob/main/internal/git/gitops.go) (lines 282-306), this check determines whether the automation layer can rely on recorded resolutions or needs to prompt the user.

### Prompting the User

If rerere is disabled, `ensureRerere`—implemented in [`cmd/utils.go`](https://github.com/github/gh-stack/blob/main/cmd/utils.go)—interactively asks: **"Enable git rerere to remember conflict resolutions?"** The function accepts a boolean `true` default, allowing users to simply press Enter to enable the feature.

```go
// cmd/utils.go – ensureRerere workflow
if !git.IsRerereEnabled() {
    ok, err := cfg.Confirm("Enable git rerere to remember conflict resolutions?", true)
    if err != nil { return err }
    if ok {
        if err := git.EnableRerere(); err != nil { return err }
    } else {
        git.SaveRerereDeclined()
    }
}

```

### Persisting User Preferences

When a user declines to enable rerere, `SaveRerereDeclined` stores this preference to prevent repetitive prompting across command invocations. Conversely, accepting the prompt triggers `EnableRerere`, which sets both `rerere.enabled` and `rerere.autoupdate` to `true` in the Git configuration. The `autoupdate` flag is critical—it automatically stages files that rerere resolves, removing the need for manual `git add` operations during automated rebases.

## Automatic Conflict Resolution During Rebases

When a cascading rebase encounters a conflict that has been resolved before, gh-stack leverages the recorded resolution without human intervention.

### The tryAutoResolveRebase Loop

In [`internal/git/git.go`](https://github.com/github/gh-stack/blob/main/internal/git/git.go) (lines 114-138), the `tryAutoResolveRebase` function implements a retry loop that attempts to continue the rebase automatically. Because `rerere.autoupdate` is enabled, Git stages any resolved files automatically, allowing `git rebase --continue` to proceed immediately.

```go
// internal/git/git.go – automatic resolution loop
func tryAutoResolveRebase() error {
    for i := 0; i < 1_000; i++ {
        if err := git.RebaseContinue(); err != nil { return err }
        // If no more conflicts exist, the rebase completes automatically
        if !git.IsRebaseInProgress() { return nil }
    }
    return fmt.Errorf("rebase not auto-resolved after many attempts")
}

```

The loop caps at **1,000 attempts** to prevent infinite retries if a conflict remains unresolvable. Each iteration relies on Git's rerere database to match the current conflict markers against previously recorded resolutions.

### How rerere.autoupdate Stages Resolved Files

The `rerere.autoupdate` configuration set during initialization ensures that when rerere successfully resolves a conflicted file, Git immediately stages that file to the index. This eliminates the manual `git add` step that would otherwise interrupt an automated rebase flow, allowing `tryAutoResolveRebase` to call `RebaseContinue` repeatedly until the operation completes or hits a new, unrecorded conflict.

## Integration Points in gh-stack Commands

The `ensureRerere` function is invoked defensively before any operation that might trigger complex rebasing:

- **[`cmd/init.go`](https://github.com/github/gh-stack/blob/main/cmd/init.go)** (line 70): Enables rerere when initializing a new stack.
- **[`cmd/rebase.go`](https://github.com/github/gh-stack/blob/main/cmd/rebase.go)** (line 128): Prepares conflict resolution before rebasing the entire stack onto a new base.
- **[`cmd/sync.go`](https://github.com/github/gh-stack/blob/main/cmd/sync.go)** (line 104): Ensures rerere is active before synchronizing branch dependencies.

This consistent pre-flight check guarantees that users won't lose conflict resolution history mid-operation.

## Manual Resolution Fallback

When rerere encounters a conflict it has not seen before—or when the context has changed significantly enough that the recorded resolution no longer applies—gh-stack stops the automation and presents the conflict to the user. After manual resolution and staging, the standard rebase continue flow resumes. Any new resolution you create is automatically recorded by rerere for future use, expanding the database of known fixes.

You can also enable rerere manually outside of gh-stack to achieve the same effect:

```bash

# Manual configuration equivalent to gh-stack's EnableRerere

git config --global rerere.enabled true
git config --global rerere.autoupdate true

```

## Summary

- **gh-stack** integrates Git's rerere feature to automate conflict resolution during stacked branch rebases.
- The **`ensureRerere`** function in [`cmd/utils.go`](https://github.com/github/gh-stack/blob/main/cmd/utils.go) prompts users to enable rerere before any rebase operation, setting `rerere.enabled` and `rerere.autoupdate`.
- **`tryAutoResolveRebase`** in [`internal/git/git.go`](https://github.com/github/gh-stack/blob/main/internal/git/git.go) implements a capped retry loop (1,000 attempts) that automatically continues rebases when rerere resolves conflicts.
- **`rerere.autoupdate`** stages resolved files automatically, removing manual intervention from the automated flow.
- If rerere cannot resolve a conflict, gh-stack falls back to manual resolution, with new fixes recorded for future automation.
- The tool invokes these checks consistently across `init`, `rebase`, and `sync` commands to ensure the feature is active before conflicts arise.

## Frequently Asked Questions

### What is Git rerere and why does gh-stack use it?

Git rerere (reuse recorded resolution) is a Git feature that automatically remembers how you resolved a conflict and reapplies that resolution when the same conflict appears again. gh-stack uses it because stacked pull requests require frequent rebasing of dependent branches, and rerere eliminates the tedious repetition of resolving the same merge conflicts across multiple branches.

### How do I disable the rerere prompt in gh-stack?

If you choose not to enable rerere when prompted, gh-stack calls `SaveRerereDeclined` to persist your preference, preventing future prompts. To reverse this decision and enable rerere later, you can run `git config rerere.enabled true` manually, or delete the stored preference in gh-stack's configuration storage to trigger the prompt again on the next rebase operation.

### What happens if rerere resolves a conflict incorrectly?

If rerere applies a recorded resolution that is no longer correct due to code changes, the resulting conflict markers or incorrect merge will cause the rebase to fail tests or compilation. In this case, you should resolve the conflict manually, update the rerere cache by resolving it correctly, and commit the proper resolution. The next rebase will record the corrected resolution.

### Why does tryAutoResolveRebase limit retries to 1,000 attempts?

The 1,000-attempt limit in `tryAutoResolveRebase` serves as a safety guard against infinite loops. In pathological cases where rerere repeatedly resolves a conflict in a way that immediately re-creates the same conflict (or when Git's state machine enters an unexpected cycle), the cap ensures the process terminates with an error rather than hanging indefinitely. In practice, most auto-resolved rebases complete in fewer than ten iterations.