Irreversible: rebase rewrites history; once pushed to the remote or the backup is deleted, it cannot be recovered — this is the number one property of this skill. All three hard rules exist as its fallback: always create a backup branch (the only undo path), always use the source branch's latest remote version (to avoid irreversibly burning a stale base into history), and always stop and ask when uncertain about conflicts (a wrong guess means irreversibly losing code).
🔴 Hard rules (irreversible fallback; violating them means failure, cannot be skipped)
- Always create a backup branch. Before rebase starts,
git branch backup/<当前分支>-<时间戳>, never skip under any circumstances — this is the only undo path for rebase. - Always use the source branch's latest remote version. Before rebase,
git fetch, withorigin/<源分支>as the base, do not use a stale local copy (a stale base is equally irreversible after replay). - Always stop and ask when uncertain about conflicts. If both sides substantively change the same logic → 🔴 STOP + AskUserQuestion, do not autonomously guess and pick one side (a wrong guess means irreversibly losing code).
Workflow
1. Get parameters + pre-checks
SRC=<源分支> # 缺省 → 报错要求用户显式指定,不代入 main/master 默认值
CUR=$(git branch --show-current)
git status --porcelain # 必须干净;脏则先 git-commit 或 git stash(记下,rebase 后 pop)
✅ Completion criteria:SRC is non-empty and git status --porcelain has no output (or dirty changes have been committed/stashed).
2. 🔴 Create backup branch (hard rule 1)
git branch "backup/${CUR}-$(date +%Y%m%d-%H%M%S)"
Echo the backup branch name. Optionally enable rerere to remember conflict resolutions (see references/conflict-resolution.md §rerere)。
✅ Completion criteria:git branch exit code 0 and the backup branch name has been echoed; on failure (e.g. duplicate name) → retry per the failure handling table, and if it still fails, STOP and do not proceed to step 3.
3. Pull the source branch's latest remote + execute
git fetch origin "$SRC"
git rebase "origin/$SRC"
✅ Completion criteria:git fetch exit code 0;git rebase has finished running — if there are no conflicts, go directly to step 5; if there are conflicts, go to step 4.
4. Conflict loop (semi-automatic)
Judge each conflicted file according to the table below.Inversion: under rebase, --ours/--theirs and merge point to opposite branches; this is the most error-prone judgment between the two skills, consult the table rather than relying on memory. In rebase, --ours=source branch/base (newbase),--theirs=the commit from the current branch being replayed; merge is the opposite direction, see git-merge detailed table。
| Case | Semantics | Command (rebase context) |
|---|---|---|
| Only thecurrent branchchanged this file | The current branch takes precedence | git checkout --theirs <file> ← theirs=the commit from the current branch being replayed |
| Only thesource branchchanged this file | The source branch takes precedence | git checkout --ours <file> ← ours=source branch/base (newbase) |
| Both sides substantively changethe same logic | Uncertain | 🔴 STOP, use AskUserQuestion to list the conflicting hunks and let the user decide, do not act autonomously |
Judging "has substantive changes":git log origin/$SRC..<backup 分支> -- <file> Check whether the current branch side has commits for this file (empty = only the source branch touched it). Direction-agnostic criteria skeleton (pre-checks/substantive-change criteria/conflict loop steps) + -s ours Single source of truth for poison warnings see git-merge's references/conflict-resolution.md §core / §poison; the rebase-side reversal table is half-visible on this side references/conflict-resolution.md。
After resolving one file:
git add <file>
git rebase --continue # 全部解完后
git add Before git diff --check confirm there are no residual <<<<<<</=======/>>>>>>> markers in the file.
✅ Completion criteria: all conflict files have been judged and add, no residual conflict markers,git rebase --continue has finished running (rebase state ended, back to the branch's normal state).
5. Complete
git log --oneline -5 # 确认重放结果
Echo: rebase complete + backup branch name (can be git branch -D deleted after verification passes; keep before verification). Branches already pushed to remote need git push --force-with-lease(only overwrite if the remote is still in the state you last saw; 🔴 no bare --force, for the accompanying approach see references/recovery.md §push)。
✅ Completion criteria:git log --oneline -5 shows the expected replay result,git status --porcelain is clean, backup branch still exists (not deleted).
Failure handling (trigger condition → first-line fix → fallback if still failing)
| Trigger condition | First-line fix | Fallback if still failing |
|---|---|---|
| Creating backup branch fails (name collision) | Add seconds to timestamp/add -2 and retry |
Cannot create → STOP, no rebase without a backup |
| Unsure about a rebase conflict | 🔴 STOP + AskUserQuestion list hunks | User is also unsure → git rebase --abort restore original state, keep backup, report "manual intervention needed" |
--continue reports "no changes" |
This file should be an empty commit → git rebase --skip |
still messy after skip → abort to restore |
| Want to give up midway through replay | git rebase --abort(back to before rebase) |
abort also fails → git reset --hard backup/<...> restore using backup |
| Only realize the wrong choice after rebase is done | git reset --hard backup/<...> roll back |
Backup also deleted → git reflog find the pre-rebase HEAD (see recovery) |
| Current branch already pushed to remote and shared by others | Inform that rebase rewrites history and will cause others --force conflicts afterward, continue only after confirmation |
User does not accept → switch to git-merge |
| fetch fails (network/permissions) | Retry fetch; confirm the remote name is correct | Cannot fetch → STOP, use the source branch's latest remote version instead of a stale local copy (hard rule 2) |
Honest boundaries
- Semi-automatic, not fully automatic: only "one-sided changes" can be machine-determined and checked out; semantic conflicts where both sides changed must be handled manually.
- Mandatory backup only protects local history; for branches already pushed to remote and pulled by others, after rebase you still need
--force-with-leasepush, which may affect collaborators (will be disclosed). - Does not handle rebase
-iinteractive (changing commit order/squash), that is another scenario. - The "substantive change" determination is based on commit history; extreme scenarios (multiple files changed in the same commit) may be misjudged → fall into the "unsure" branch and stop to ask.