1---
2name: rebasing-with-git
3description: Guides git rebase workflows including simple rebases and complex fork rebases with drop-and-repick for personal integration branches. Use when the user asks to rebase, mentions rebasing, needs help with rebase conflicts, or asks to pull feature branch changes into a personal branch. Supports branch-based repos, worktrees, and wt-managed bare repos.
4user-invocable: true
5license: LicenseRef-MutuaL-1.2
6metadata:
7 author: Amolith <amolith@secluded.site>
8---
9
10## General principles
11
12- **Non-interactive rebases**: prefix with `GIT_EDITOR=true`. For interactive rebases that edit the todo, also set `GIT_SEQUENCE_EDITOR` (see [drop-and-repick](#step-5-rebase-with-drops-and-break)).
13- **Never push** unless the user explicitly says to. If they say "force push", use `--force-with-lease`. Do not suggest pushing. When work is complete, stop.
14- **Dirty worktree**: if uncommitted changes exist when a rebase is requested, ask the user how to proceed before doing anything.
15- **In-progress rebase**: if `.git/rebase-merge` or `.git/rebase-apply` exists (or the worktree-local equivalents under `.git/worktrees/<name>/`), read the state—conflicts, staged changes, progress through the todo—and offer to continue or abort based on what you find.
16- **rerere**: the user has `rerere` enabled. If a conflict is auto-resolved by rerere, note this to the user and verify the auto-resolution looks correct before continuing.
17- **Checks**: read the project's `agents.md` for build/lint/format/test commands. Run format, lint, and typecheck after each logical step. Run the full test suite only at the end of the entire operation.
18
19## Repo layout detection
20
21Before starting, determine the layout:
22
231. **wt-managed bare repo**: `../.bare` is a directory. Worktrees are siblings of `.bare/`. Use `wt l` to list worktrees, `cd ../branch-name` to navigate. Add: `wt a name -b`. Remove: `wt r name -b`. If `wt` is not installed, fall back to `git worktree` commands.
24
252. **Legacy worktree layout**: `git worktree list` shows multiple entries but `../.bare` does not exist. Worktrees are sibling directories. Navigate with `cd ../name`. Use `git worktree add`/`remove`.
26
273. **Branch-based**: a normal clone with a single worktree. Use `git switch` to change branches.
28
29## Upstream remote and canonical branch
30
31For contributed-to projects, the upstream remote is named `upstream`. For the user's own projects, inspect `git remote -v` to identify the hosting remote.
32
33Determine the canonical branch:
34
35```sh
36git symbolic-ref refs/remotes/<remote>/HEAD | sed 's|refs/remotes/<remote>/||'
37```
38
39Fallback if the ref is not set:
40
41```sh
42git remote show <remote> | grep 'HEAD branch' | sed 's/.*: //'
43```
44
45## Simple rebase
46
471. `git fetch <remote>`
482. `GIT_EDITOR=true git rebase <remote>/<canonical>`
493. Handle conflicts if they arise (see [Handling conflicts](#handling-conflicts)).
504. Run checks. Stop.
51
52## Handling conflicts
53
541. **Stop immediately.** Do not resolve without user confirmation. **Never skip a commit.** If a commit seems too complex to resolve, present what you see and ask the user—they may know the exact resolution.
552. Run `git status` and examine every conflicting file thoroughly.
563. Present to the user:
57 - What the local changes are doing and why they were made
58 - What the incoming changes are doing and why
59 - Why the two sides conflict
60 - Possible resolution strategies, with a light recommendation and brief reasoning for the recommended approach
614. **Wait for the user to confirm or direct** a resolution.
625. After resolving: `git add` the resolved files, then `GIT_EDITOR=true git rebase --continue`.
63
64### Bulk mechanical changes (import renames, formatting, etc.)
65
66Large-scale rename or formatting commits often produce massive conflict diffs that obscure the actual change. The typical resolution pattern is:
67
681. Check out HEAD's version of the affected files: `git checkout HEAD -- <paths>`
692. Re-apply the mechanical transformation (e.g. `fd <pattern> -x sd '<old>' '<new>'`)
703. Run the project's formatter
714. `git add` and continue
72
73**Do not attempt to hand-resolve hundreds of conflicting hunks.** Recognize when a commit is mechanical in nature, describe it to the user, and ask how they want to re-apply the transformation.
74
75## Fork rebase: feature branches
76
77The user will already be in the correct worktree or have the branch checked out. Rebase only the current branch.
78
791. `git fetch upstream`
802. Check divergence: `git log --oneline upstream/<canonical>..HEAD`
813. `GIT_EDITOR=true git rebase upstream/<canonical>`
824. Resolve conflicts per [Handling conflicts](#handling-conflicts).
835. Run format/lint/typecheck.
846. **Stop and wait.** The user may want to test manually, push, or move on.
85
86## Fork rebase: drop-and-repick (personal branch)
87
88This workflow is **always explicitly requested** by the user (e.g. "rebase on main, then pull changes back from feature branches"). The current branch/worktree is the personal branch.
89
90**Do not start the rebase immediately.** Analyze and confirm first.
91
92### Step 1: Verify feature branches are rebased
93
94For each local feature branch (exclude the canonical branch and the current personal branch), check whether it has already been rebased onto upstream:
95
96```sh
97git log --oneline upstream/<canonical>..<branch>
98```
99
100If any feature branch appears to need rebasing, warn the user or remind them to do it first.
101
102To enumerate branches: use `wt l` or `git worktree list` in worktree layouts, `git branch` in branch-based layouts.
103
104### Step 2: Examine the personal branch
105
106```sh
107git log --oneline upstream/<canonical>..HEAD
108```
109
110### Step 3: Correlate and categorize personal commits
111
112Each commit in the personal branch falls into one of three categories:
113
1141. **Feature branch representation**: matches a feature branch, drop and re-pick fresh
1152. **Already merged upstream**: exists in upstream's history, drop without re-picking
1163. **Personal-only**: matches nothing, stays as-is
117
118#### 3a: Match commits to feature branches
119
120For each feature branch, find its commits beyond upstream:
121
122```sh
123git log --oneline --reverse upstream/<canonical>..<branch>
124```
125
126The **oldest** commit's subject line identifies the feature branch in the personal branch. Search the personal branch log for a commit with the same subject. If found, that personal commit is a squashed (fixup'd) representation of the entire feature branch and should be dropped during rebase, then the feature branch re-picked fresh.
127
128**Only** branches with at least one commit ahead of upstream whose subject matches a commit in the personal branch should be included. Branches with no matching commit in personal are not represented there and should be ignored unless the user explicitly says to include new ones.
129
130#### 3b: Detect commits merged upstream
131
132For each unmatched commit in the personal branch, check if it was merged upstream:
133
134```sh
135git log --oneline --grep="<subject>" upstream/<canonical>
136```
137
138If the subject appears in upstream's history, the commit is likely merged and can be dropped without re-picking. Mark it as "merged upstream."
139
140#### 3c: Request user categorization for ambiguous commits
141
142After automatic correlation, some commits may remain ambiguous:
143
144- Subject matches multiple feature branches
145- Subject partially matches but isn't exact
146- No match found, but commit doesn't look like a personal customization
147
148**Do not guess.** Present all unmatched/ambiguous commits to the user and ask them to categorize each as:
149
150- **(a) Merged upstream** — drop without re-picking
151- **(b) Feature branch** — specify which branch; drop and re-pick
152- **(c) Personal-only** — keep as-is
153
154Wait for the user to respond before proceeding to Step 4.
155
156### Step 4: Present the plan
157
158Show the user:
159
160- **Commits to drop**: hash, subject, which feature branch they correspond to
161- **Commits to keep**: hash, subject (personal-only customizations)
162- **Feature branches to re-pick**: branch name, commit count, planned re-pick order
163
164Preserve the order the feature-branch commits originally appeared in the personal branch. Consistent ordering lets rerere help with any previously-resolved conflicts.
165
166**Wait for explicit confirmation before proceeding.**
167
168### Step 5: Rebase with drops and break
169
170The rebase todo must be structured as: **drop → break → pick**. The drops remove stale feature-branch commits, the break pauses the rebase so fresh cherry-picks can be inserted, and the remaining picks replay personal-only commits on top.
171
172Build a sed command that:
173
1741. Changes `pick` to `drop` for each identified commit
1752. Inserts a `break` line after the last `drop`, before the first remaining `pick`
176
177Use short hashes from `git log --oneline`; these match the abbreviation the rebase todo uses.
178
179```sh
180GIT_EDITOR=true \
181GIT_SEQUENCE_EDITOR="sed -i \
182 -e 's/^pick <hash1>/drop <hash1>/' \
183 -e 's/^pick <hash2>/drop <hash2>/' \
184 -e '/^drop <hash2>/a break'" \
185 git rebase -i upstream/<canonical>
186```
187
188Where `<hash2>` is the last commit being dropped (use `/a break` to append after it). If drops are non-contiguous in the todo, insert the break after the last one.
189
190The rebase will process the drops, then pause at the `break`. If personal-only commits conflict during the rebase (before or after the break), handle per [Handling conflicts](#handling-conflicts).
191
192### Step 6: Re-pick from feature branches (during break)
193
194The rebase is paused. Cherry-pick feature branches back in now, before the personal-only commits are replayed.
195
196For each feature branch, in the order confirmed in step 4:
197
1981. Get commits oldest-first:
199
200 ```sh
201 git log --oneline --reverse upstream/<canonical>..<branch>
202 ```
203
2042. **If the branch has a single commit**, cherry-pick it:
205
206 ```sh
207 git cherry-pick <hash>
208 ```
209
2103. **If the branch has multiple commits**, cherry-pick the first, then fixup the rest:
211
212 ```sh
213 git cherry-pick <first-hash>
214 git cherry-pick --no-commit <second-hash>
215 git commit --amend --no-edit
216 git cherry-pick --no-commit <third-hash>
217 git commit --amend --no-edit
218 ```
219
220 Continue for all remaining commits.
221
2224. **If `cherry-pick --no-commit` hits a conflict**: resolve per [Handling conflicts](#handling-conflicts), `git add` resolved files, then `git cherry-pick --quit` to clear the cherry-pick state while preserving staged changes, then `git commit --amend --no-edit`.
223
2245. Run format/lint/typecheck after completing each feature branch's re-pick.
225
226### Step 7: Continue the rebase
227
228After all feature branches are re-picked:
229
230```sh
231GIT_EDITOR=true git rebase --continue
232```
233
234This replays the personal-only commits on top of the freshly cherry-picked feature work. Handle conflicts per [Handling conflicts](#handling-conflicts).
235
236### Step 8: Final verification
237
2381. Review the log:
239
240 ```sh
241 git log --oneline upstream/<canonical>..HEAD
242 ```
243
244 Confirm the expected structure: personal-only commits and one squashed commit per re-picked feature branch, in the expected order.
245
2462. Run the full test suite.
247
2483. **Stop and wait.**