关于 stack-rebase
stack-rebase 是用于已发布 Git 分支栈的技能,帮助开发者在基准分支或栈内提交变化后级联变基。它还指导冲突处理、分支推送及相关 PR 基准更新。
主要功能
- 01识别变基触发原因
- 02使用 --update-refs 级联变基
- 03处理或中止冲突变基
- 04使用 --force-with-lease 推送分支
- 05更新并核验 PR 基准
适用场景
- 01栈中首个 PR 合并到 master 后调整后续分支
- 02master 前进后让分支栈纳入新提交
- 03中间切片修改后更新其后续分支
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ athola/ claude-night-market --skill stack-rebase安装后在 Claude Code 中输入/stack-rebase确认已加载。
详细介绍
Stack Rebase
在基础 PR 合并或上游基础分支发生变化后,级联 rebase 整个 PR 堆栈。
适用场景
在以下任一情况下运行 stack-rebase:
- 堆栈中的第一个 PR 已合并到
master;第二个 PR 现在需要直接以master为目标分支 master已前进,堆栈分支需要纳入新提交- 堆栈中间的 PR 已修订,后续分支需要获取这些更改
不适用场景
- 堆栈从未发布过(使用
sanctum:stack-push) - 堆栈尚不存在(使用
sanctum:stack-create)
前置条件
- 所有切片分支都在本地存在(
git branch --list) - 远程状态为最新(
git fetch origin) - 工作区干净(
git status) - Git 2.38+,以支持
--update-refs
必需的进度跟踪
开始前创建以下进度项:
stack-rebase:fetch-completestack-rebase:trigger-identifiedstack-rebase:rebase-completestack-rebase:conflicts-resolvedstack-rebase:force-pushedstack-rebase:prs-updated
步骤 1:获取远程状态(fetch-complete)
git fetch origin
如果已合并的 PR 分支仍存在于远程,请注意 GitHub 会在合并后保留该分支。 已合并的分支本身不再是有效的堆栈基础。
步骤 2:确定触发原因(trigger-identified)
确定发生了什么变化:
情况 A,基础 PR 已合并到 master:
原本作为“根”的切片现在已进入 master。
所有剩余切片都需要 rebase 到 master 上。
# Confirm the merged branch is now in master
git branch -r --merged origin/master | grep "${MERGED_BRANCH}"
情况 B,master 已前进:
切片落后于 master,但堆栈拓扑结构未变。
将根切片 rebase 到 master 上;--update-refs 会连带更新所有后续分支。
情况 C,堆栈中间的分支已修订: 某个切片已修改。 所有后续切片都需要 rebase 到该切片上。
步骤 3:运行级联 rebase(rebase-complete)
情况 A 和 B:将根切片 rebase 到 master 上
STACK=stack/my-feature
BASE=master
# Check out the root slice
ROOT_SLICE=$(git branch --list "${STACK}/*" \
| sed 's/^[* ]*//' | sort | head -1)
git checkout "${ROOT_SLICE}"
# Rebase with --update-refs rewrites all stack branches
git rebase --update-refs origin/${BASE}
--update-refs 会扫描 reflog,并更新所有指向正在 rebase 的提交的本地分支引用。
堆栈中的所有切片分支都会在一次操作中重写。
情况 C:从堆栈中间的切片开始 rebase
# Check out the first slice BELOW the amended one
CHILD_SLICE=stack/my-feature/add-api # example
git checkout "${CHILD_SLICE}"
git rebase --update-refs stack/my-feature/add-schema
jj 加速方式(如果可用)
# jj rebases all descendants automatically on any change
# To rebase the whole stack onto master:
jj rebase -d master \
-r "ancestors(${STACK}/add-ui) & !ancestors(master)"
步骤 4:解决冲突(conflicts-resolved)
如果 rebase 因冲突而暂停:
# See which file conflicts
git status
# After resolving each file:
git add <resolved-file>
git rebase --continue
重复上述操作,直到 rebase 完成。 如果冲突过于复杂,请中止并进行调查:
git rebase --abort
然后检查冲突提交之间的差异,再重试。
步骤 5:强制推送更新后的分支(force-pushed)
成功 rebase 后,推送所有切片分支。
使用 --force-with-lease,以防护上次获取后远程发生的更改:
for branch in $(git branch --list "${STACK}/*" \
| sed 's/^[* ]*//' | sort); do
git push --force-with-lease origin "${branch}"
echo "force-pushed: ${branch}"
done
切勿使用 --force(它会取消远程更改防护)。
jj 加速方式(如果可用)
jj git push --all --allow-new
步骤 6:更新 PR 基础分支(prs-updated)
仅适用于情况 A:根切片合并后,如果你将剩余切片 rebase 到 master 上,堆栈中的下一个 PR 现在会指向错误的基础分支。
使用 GitHub CLI 更新其基础分支:
NEXT_PR=456 # PR number of the new stack root
gh pr edit "${NEXT_PR}" --base master
对于堆栈中更靠后的 PR,其基础分支仍是前一个切片分支;--update-refs 已重写该分支,因此无需修改基础分支。
验证整个堆栈是否一致:
for branch in $(git branch --list "${STACK}/*" \
| sed 's/^[* ]*//' | sort); do
pr_num=$(gh pr list --head "${branch}" \
--json number,baseRefName \
--jq '.[0] | "#\(.number) base=\(.baseRefName)"')
echo "${branch}: ${pr_num}"
done
防止冲突的技巧
- 保持切片较小:每个 PR 越小,rebase 时发生冲突的范围就越小
- 经常 rebase:每天 rebase 到刚合并的 master 上,比解决一周积累的偏差更省事
- 避免修改已进入评审的提交;优先使用 fixup 提交,并在合并时压缩提交
备注
git rebase --update-refs需要 Git 2.38+;运行前使用git version确认- 如果无法使用
--update-refs,请按从根到顶端的顺序,手动检出并 rebase 每个切片分支 - 强制推送后,GitHub 会自动将 PR 评审标记为过期;请提醒评审者重新批准
stack-push技能说明了如何在 rebase 更改 PR SHA 后重新发布堆栈摘要评论
退出标准
- 在 rebase 开始前创建全部 6 个进度项(从
stack-rebase:fetch-complete到stack-rebase:prs-updated),并按顺序标记为已完成 - 在确定并归类 rebase 触发条件为 Case A、B 或 C 之前,
git fetch origin已完成 - 对于 Case A 和 B,
git rebase --update-refs完成且未中止;如果发生冲突, 继续操作前先逐一解决冲突 - 使用
--force-with-lease强制推送所有切片分支;绝不使用普通的--force - 仅对于 Case A:使用
gh pr edit <next-pr> --base master更新 新堆栈根分支的目标基准,并通过gh pr list的输出验证完整堆栈拓扑