diff --git a/skills/rebasing-with-git/SKILL.md b/skills/rebasing-with-git/SKILL.md new file mode 100644 index 0000000000000000000000000000000000000000..b694c359e355d7adc1afafca3683b51d9497ad39 --- /dev/null +++ b/skills/rebasing-with-git/SKILL.md @@ -0,0 +1,176 @@ +--- +name: rebasing-with-git +description: 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. +license: GPL-3.0-or-later +metadata: + author: Amolith +--- + +## General principles + +- **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)). +- **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. +- **Dirty worktree**: if uncommitted changes exist when a rebase is requested, ask the user how to proceed before doing anything. +- **In-progress rebase**: if `.git/rebase-merge` or `.git/rebase-apply` exists (or the worktree-local equivalents under `.git/worktrees//`), read the state—conflicts, staged changes, progress through the todo—and offer to continue or abort based on what you find. +- **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. +- **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. + +## Repo layout detection + +Before starting, determine the layout: + +1. **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. + +2. **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`. + +3. **Branch-based**: a normal clone with a single worktree. Use `git switch` to change branches. + +## Upstream remote and canonical branch + +For contributed-to projects, the upstream remote is named `upstream`. For the user's own projects, inspect `git remote -v` to identify the hosting remote. + +Determine the canonical branch: + +```sh +git symbolic-ref refs/remotes//HEAD | sed 's|refs/remotes//||' +``` + +Fallback if the ref is not set: + +```sh +git remote show | grep 'HEAD branch' | sed 's/.*: //' +``` + +## Simple rebase + +1. `git fetch ` +2. `GIT_EDITOR=true git rebase /` +3. Handle conflicts if they arise (see [Handling conflicts](#handling-conflicts)). +4. Run checks. Stop. + +## Handling conflicts + +1. **Stop immediately.** Do not resolve without user confirmation. +2. Run `git status` and examine every conflicting file thoroughly. +3. Present to the user: + - What the local changes are doing and why they were made + - What the incoming changes are doing and why + - Why the two sides conflict + - Possible resolution strategies, with a light recommendation and brief reasoning for the recommended approach +4. **Wait for the user to confirm or direct** a resolution. +5. After resolving: `git add` the resolved files, then `GIT_EDITOR=true git rebase --continue`. + +## Fork rebase: feature branches + +The user will already be in the correct worktree or have the branch checked out. Rebase only the current branch. + +1. `git fetch upstream` +2. Check divergence: `git log --oneline upstream/..HEAD` +3. `GIT_EDITOR=true git rebase upstream/` +4. Resolve conflicts per [Handling conflicts](#handling-conflicts). +5. Run format/lint/typecheck. +6. **Stop and wait.** The user may want to test manually, push, or move on. + +## Fork rebase: drop-and-repick (personal branch) + +This 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. + +**Do not start the rebase immediately.** Analyze and confirm first. + +### Step 1: Verify feature branches are rebased + +For each local feature branch (exclude the canonical branch and the current personal branch), check whether it has already been rebased onto upstream: + +```sh +git log --oneline upstream/.. +``` + +If any feature branch appears to need rebasing, warn the user or remind them to do it first. + +To enumerate branches: use `wt l` or `git worktree list` in worktree layouts, `git branch` in branch-based layouts. + +### Step 2: Examine the personal branch + +```sh +git log --oneline upstream/..HEAD +``` + +### Step 3: Correlate personal commits to feature branches + +For each feature branch, find its commits beyond upstream: + +```sh +git log --oneline --reverse upstream/.. +``` + +The **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. + +**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. + +If matches are ambiguous (e.g. multiple commits with very similar subjects across branches), flag this to the user before proceeding. + +Commits in the personal branch that match no feature branch are personal-only customizations. They stay. + +### Step 4: Present the plan + +Show the user: + +- **Commits to drop**: hash, subject, which feature branch they correspond to +- **Commits to keep**: hash, subject (personal-only customizations) +- **Feature branches to re-pick**: branch name, commit count, planned re-pick order + +Preserve the order the feature-branch commits originally appeared in the personal branch. Consistent ordering lets rerere help with any previously-resolved conflicts. + +**Wait for explicit confirmation before proceeding.** + +### Step 5: Rebase with drops + +Build a sed command to change `pick` to `drop` for each identified commit. Use short hashes from `git log --oneline`; these match the abbreviation the rebase todo uses. + +```sh +GIT_EDITOR=true \ +GIT_SEQUENCE_EDITOR="sed -i -e 's/^pick /drop /' -e 's/^pick /drop /'" \ + git rebase -i upstream/ +``` + +If personal-only commits conflict during this rebase, handle per [Handling conflicts](#handling-conflicts). + +### Step 6: Re-pick from feature branches + +For each feature branch, in the order confirmed in step 4: + +1. Get commits oldest-first: + ```sh + git log --oneline --reverse upstream/.. + ``` + +2. **If the branch has a single commit**, cherry-pick it: + ```sh + git cherry-pick + ``` + +3. **If the branch has multiple commits**, cherry-pick the first, then fixup the rest: + ```sh + git cherry-pick + git cherry-pick --no-commit + git commit --amend --no-edit + git cherry-pick --no-commit + git commit --amend --no-edit + ``` + Continue for all remaining commits. + +4. **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`. + +5. Run format/lint/typecheck after completing each feature branch's re-pick. + +### Step 7: Final verification + +1. Review the log: + ```sh + git log --oneline upstream/..HEAD + ``` + Confirm the expected structure: personal-only commits and one squashed commit per re-picked feature branch, in the expected order. + +2. Run the full test suite. + +3. **Stop and wait.**