diff --git a/web/learn/concepts/git/git-rerere.mdx b/web/learn/concepts/git/git-rerere.mdx new file mode 100644 index 00000000..0d00c791 --- /dev/null +++ b/web/learn/concepts/git/git-rerere.mdx @@ -0,0 +1,125 @@ +--- +sidebar_position: 6 +--- + +import DefinitionCard from "@site/src/components/DefinitionCard"; + +# What is Git Rerere? + +_Git rerere records how you resolved a merge conflict and reuses that resolution when the same conflict returns._ + +## Introduction + +**Rerere** stands for reuse recorded resolution. When a merge or [rebase](./merge-vs-rebase) hits the same conflict again, Git can apply the resolution you already chose instead of asking you to edit the markers by hand. + +That matters when a long-lived branch keeps meeting the same overlapping edits on `main`, or when you rebuild an integration branch after dropping one topic. You still review the result. You stop retyping the same fix. + +## Understanding the Concept + +Turn the feature on with: + +```bash +git config --global rerere.enabled true +``` + +You can also turn it on for one repo by creating the `rr-cache` directory under the repo's common Git directory. The config setting is clearer and applies everywhere you work. + +When a conflict appears, Git stores the conflicted file as a **preimage** under `$GIT_COMMON_DIR/rr-cache/`. After you fix the conflict and rerere runs again, normally while you commit or continue, Git stores the fixed content as a **postimage**. Later, when a new conflict matches the earlier one, Git runs a three-way merge of the preimage, the postimage, and the new conflicted file. The [`git rerere`](https://git-scm.com/docs/git-rerere) manual covers that reuse path. + + + + + +{/* TODO: Add a diagram of conflicted file to preimage in the common rr-cache, hand resolve to postimage, later matching conflict to three-way reuse in the working tree. */} + +Merge and rebase call rerere for you once it is on. You do not need to run `git rerere` on every conflict. By default, rerere updates only the working-tree file, so you still check it and run `git add`. If [`rerere.autoUpdate`](https://git-scm.com/docs/git-config#Documentation/git-config.txt-rerereautoUpdate) is on, Git also stages a clean reuse for you. + +| Artifact | Meaning | +| --- | --- | +| Preimage | Conflicted state with markers | +| Postimage | Hand-resolved file content | +| `$GIT_COMMON_DIR/rr-cache/` | Repo-wide cache shared by [linked worktrees](./git-worktrees) | + +## Applying It in Practice + +Rebase a long-lived feature branch onto current `main`: + +```bash +git fetch origin +git switch feature/long-lived +git rebase origin/main +``` + +When the rebase stops on a conflict, list the paths whose preimages rerere recorded: + +```bash +git rerere status +``` + +Inspect the delta from the recorded conflict to your current working resolution before you stage: + +```bash +git rerere diff +``` + +A typical first encounter prints `Recorded preimage for FILE`. After you resolve, stage, and continue, Git prints `Recorded resolution for FILE`. On a later rebase that hits a matching conflict, Git prints `Resolved FILE using previous resolution` and removes the conflict markers from the working tree. You still check the result. Without `rerere.autoUpdate`, you still run `git add` before continuing: + +```bash +git add path/to/file +git rebase --continue +``` + +If you abort a merge or rebase, Git clears the in-progress rerere state for that attempt. To drop a recorded resolution while that conflict is still open, run: + +```bash +git rerere forget path/to/file +``` + +Paths that still need a hand fix after autoresolve, including cases rerere cannot track such as conflicting submodules, show up with: + +```bash +git rerere remaining +``` + +## Engineering Considerations + +Rerere helps when the same text conflict returns across many updates. A long-lived feature branch rebased against a moving `main` often replays older commits through the same overlapped hunks. Without a cache, you fix those hunks on every rebase. + +With rerere on, you often fix a recurring conflict only once. Later rebases reuse the postimage when the three-way merge resolves cleanly. + +A common alternative to repeated merges is a test merge into current `main`. You resolve, verify, then reset the merge so the branch history stays free of intermediate merge commits. When you later rebase onto `main` or do the final merge, the earlier postimage often applies again. That is how a conflicted merge can become a linear rebase without redoing the same hand edits. + +Treat an autoresolved file like any other conflict resolution. Read the combined diff, run the tests that cover the overlapped code, and only then stage. A reused postimage is a prior judgment applied to new parents. The surrounding code may have changed enough that the old answer is wrong. + +For agent-produced conflicts, keep the same review bar described in [How to Fix Merge Conflicts Created by Coding Agents](/learn/how-to/merge-conflicts-with-coding-agents). + +Rerere depends on conflict markers in the file. If the file already contains lines that look like markers, recording can fail. Raise `conflict-marker-size` in `.gitattributes` for those paths when that happens. + +## Scaling and Operations + +Teams that merge many topic branches into one integration branch for testing benefit from the same cache. If the aggregate build fails, you rewind the integration tip, drop the bad topic, and merge the remaining branches again. Rerere re-applies the resolutions you already paid for on the branches that remain. + +Linked worktrees in one repo share `$GIT_COMMON_DIR/rr-cache`, so a resolution recorded in one worktree is available in the others. The [git-worktree](https://git-scm.com/docs/git-worktree) docs explain how those worktrees point at that common Git directory. Separate clones do not share the cache unless you copy it on purpose. + +Prune stale cache entries with: + +```bash +git rerere gc +``` + +By default, `gc.rerereResolved` keeps completed resolutions for 60 days and `gc.rerereUnresolved` drops abandoned preimages after 15 days. Adjust those values when your integration cycle is longer than the defaults. + +Do not treat the rerere cache as shared team state across clones unless you copy it on purpose. Enable `rerere.enabled` in shared setup docs so every machine that rebases the same [pull-request stacks](./stacked-prs) builds a useful cache. + +## Next Steps + +- [Cherry-pick vs Rebase](./cherry-pick-vs-rebase): distinguish selected patch copying from branch rewriting +- [Stacked PR Workflow](/learn/workflows/git/stacked-pr): apply rebasing to a pull-request stack +- [Auto-Rebasing AI Workspaces](/learn/how-to/auto-rebase-ai-branches): keep dependent branches current without treating a rebase as approval +- [Parallel Development Workflow](/learn/workflows/git/parallel-development): combine concurrent branches with an integration policy diff --git a/web/learn/concepts/git/index.mdx b/web/learn/concepts/git/index.mdx index acabf8f3..f3df0f62 100644 --- a/web/learn/concepts/git/index.mdx +++ b/web/learn/concepts/git/index.mdx @@ -35,6 +35,11 @@ Start with Git's data model, then learn how to manage parallel and dependent bra href: "/learn/concepts/git/merge-vs-rebase", label: "Merge vs Rebase", }, + { + type: "link", + href: "/learn/concepts/git/git-rerere", + label: "What is Git Rerere?", + }, { type: "link", href: "/learn/concepts/git/cherry-pick-vs-rebase", diff --git a/web/learn/concepts/git/merge-vs-rebase.mdx b/web/learn/concepts/git/merge-vs-rebase.mdx index f9a792e9..ed40f3ca 100644 --- a/web/learn/concepts/git/merge-vs-rebase.mdx +++ b/web/learn/concepts/git/merge-vs-rebase.mdx @@ -109,7 +109,7 @@ Each option throws away something different. Merge commits keep the shape. Squas Block force pushes on shared branches. If feature branches can be rewritten, say so out loud, so reviewers know whether it is safe to build on one. -After a big rebase, use `git range-diff` to check the rewritten series still says what you meant. Run the full test suite after you resolve conflicts, whichever strategy you picked. +After a big rebase, use `git range-diff` to check the rewritten series still says what you meant. Run the full test suite after you resolve conflicts, whichever strategy you picked. When the same conflict keeps returning on a long-lived branch, [git rerere](./git-rerere) can reuse the resolution you already chose. ## Next Steps diff --git a/web/learn/how-to/auto-rebase-ai-branches.md b/web/learn/how-to/auto-rebase-ai-branches.md index 3aa578ff..d11580b2 100644 --- a/web/learn/how-to/auto-rebase-ai-branches.md +++ b/web/learn/how-to/auto-rebase-ai-branches.md @@ -65,7 +65,7 @@ After every rebase: 1. Read the new diff against the intended base. 2. Re-run the relevant tests. -3. Treat conflict resolutions as new code under review. +3. Treat conflict resolutions as new code under review. [Git rerere](/learn/concepts/git/git-rerere) can reuse a prior resolution across rebases, and that reused result still needs the same review. ```bash git diff origin/main...HEAD @@ -103,4 +103,5 @@ Pending working-copy edits can block or complicate synchronization. Commit, move - [What Are Stacked PRs in AI-Assisted Development](/learn/stacked-prs) - [How to Fix Merge Conflicts Created by Coding Agents](/learn/how-to/merge-conflicts-with-coding-agents) - [Merge vs Rebase](/learn/concepts/git/merge-vs-rebase) +- [What is Git Rerere?](/learn/concepts/git/git-rerere) - [Workspaces](/docs/concepts/workspaces) diff --git a/web/learn/how-to/merge-conflicts-with-coding-agents.md b/web/learn/how-to/merge-conflicts-with-coding-agents.md index 3ce74754..ccf2d00a 100644 --- a/web/learn/how-to/merge-conflicts-with-coding-agents.md +++ b/web/learn/how-to/merge-conflicts-with-coding-agents.md @@ -69,6 +69,8 @@ git rebase --abort Restarting the agent on current `main` can be cheaper than preserving a small obsolete patch. Compare old and new intended behavior before discarding work. +When the same conflict returns across many rebases, enable [git rerere](/learn/concepts/git/git-rerere) so Git can reuse a resolution you already chose. Still review the autoresolved file before you continue. + ## Agent-assisted resolution You can ask an agent to resolve conflicts, but you must review the result. Provide: @@ -110,4 +112,5 @@ When a bookmark conflict appears after remote updates, resolve it from the botto - [Auto-Rebasing AI Workspaces](/learn/how-to/auto-rebase-ai-branches) - [Parallel Coding Agents Without Branch Chaos](/learn/parallel-coding-agents) - [Merge vs Rebase](/learn/concepts/git/merge-vs-rebase) +- [What is Git Rerere?](/learn/concepts/git/git-rerere) - [Merging Workspaces](/docs/tutorials/merging-workspaces) diff --git a/web/sidebarsLearn.ts b/web/sidebarsLearn.ts index bb41b27a..9a7f66e6 100644 --- a/web/sidebarsLearn.ts +++ b/web/sidebarsLearn.ts @@ -36,6 +36,7 @@ const sidebars: SidebarsConfig = { 'concepts/git/git-worktrees-for-ai', 'concepts/git/git-worktrees-vs-clones', 'concepts/git/merge-vs-rebase', + 'concepts/git/git-rerere', 'concepts/git/cherry-pick-vs-rebase', 'concepts/git/stacked-prs', 'concepts/git/stacked-prs-ai-assisted',