Jak używać
- Skopiuj polecenie instalacji i sprawdź źródła przed instalacją we własnym środowisku agenta.
- W oryginale sprawdź wymagane narzędzia, dane dostępowe i obsługiwane środowiska.
- Opisz dane wejściowe i oczekiwany rezultat; porównaj wynik ze źródłami.
npx skills add https://github.com/happyplum/workskills --skill linearize-commitsPrzed rozpoczęciem
- Instalacja nie obejmuje subskrypcji modelu, limitu API ani uprawnień do plików.
- Gwiazdki i instalacje pokazują aktywność, a nie niezależny test jakości lub bezpieczeństwa.
Treść z repozytorium z zachowaniem nagłówków, przykładów, kodu, tabel, linków i obrazów.
线性化提交整理
目标:把 worktree 或功能分支的提交历史整理成一串线性、颗粒度合适、信息规范的提交。整理本身就是完整交付;如用户同时要求合并,再以 fast-forward 方式并入目标分支(未指定时为主干)。
适用形态:
- 整理并合并:整理分支历史后并入目标分支——目标分支由用户指定,未指定时默认为主干
- 纯整理:只重写分支历史,不合并——包括整理某个 hash 之后的提交、整理已推送的分支(整理后需 force-push)
这类工作的价值在于:主干历史是团队理解演进过程、二分定位问题、异常时按提交粒度回退的事实源。颗粒度合适的直接含义是——任意一条提交出问题时,单独 revert 它就能安全回退,不牵连无关改动。整理过的历史应当读起来像一份精心撰写的变更叙述,而不是开发过程的实况录像。所以整理时的每一个判断——哪些提交合并、合并到哪、信息怎么写——都要站在「半年后读这段历史或紧急回退的人」的立场上做。
四条不可妥协的原则贯穿全流程:
- 不丢作者:合并提交必须保留原始开发者的归属(见「保留作者归属」),整理人是编辑不是作者。
- 不跳检查:任何提交都不允许
--no-verify绕过项目 git hooks;hook 失败就修原因,不绕过。 - 不动代码:整理只改历史结构,最终 tree 必须与整理前逐字节一致(见「验证」)。
- 执行不外包:盘点、分组判断、rebase / 重写、tree 验证必须全部由当前会话亲自执行,不得委派子代理。历史整理的正确性依赖对全部上下文(每个 diff、hook 行为、冲突语义、归属安排)的连续把握,委派产生的上下文断层会直接导致功能偏移或归属丢失;子代理的「完成」回报也无法替代亲自跑出的
git diff空结果。
前置检查
git status确认工作区干净;有未提交改动先请用户处理,不要擅自 stash 后继续。- 确认整理范围的下界(base):用户给了 hash 就用它(只重写该 hash 之后的历史);没给、且整理目标相对某个目标分支时,用
git merge-base HEAD <目标分支>。目标分支由用户指定;未指定时默认为主干,主干名从git symbolic-ref refs/remotes/origin/HEAD或main/master/trunk中辨认,不确定就问用户。 - 确认整理对象:当前分支,还是某个 worktree / 其他分支。跨 worktree 时先
git worktree list定位,可以直接在目标 worktree 目录里操作,或git checkout对应分支,不要在错误的 checkout 上动手。 - 创建备份引用并告知用户:
git branch backup/<分支名>-pre-linearize <当前HEAD>(分支名冲突时追加日期后缀)。这是整理过程中的回退点,验证通过后按「验证」一节清理。 - 已推送的分支单独确认:分支已 push 过时,整理后的 force-push 会重写远程历史——必须先确认该分支是本人独占(无他人基于它开发),并得到用户对 force-push 的明确同意;推送时用
--force-with-lease(远端若被他人更新会拒绝),不用裸--force。共享分支禁止重写,直接报告冲突并停止。
工作流程
1. 盘点
# base 为用户指定的 hash,或与主干的 merge-base
git log --reverse --format='%h %s' <base>..HEAD
git show --stat <每个提交> # 了解每个提交实际改了什么只看 message 会误判——「fix typo」可能混着逻辑改动,「wip」可能是半个功能。逐一看 diff 统计,必要时看完整 diff。
2. 分组与方案
按「独立意图」把提交分组(准则见下节),产出目标提交序列:
原历史(8) -> 目标历史(3)
a1b2c3d feat: add auth ┐
e4f5g6h fix typo ├> feat(auth): 实现登录认证
i7j8k9l fix lint ┘
...历史重写不可逆,方案必须先展示给用户确认再执行。 方案里写清每条目标提交的 message 和它吞掉了哪些原提交,让用户能一眼发现分错组的地方。
3. 执行重写
两种路径,按场景选:
- 分组边界与原提交对齐(只是 squash / reword / 重排)→
GIT_SEQUENCE_EDITOR脚本化的git rebase -i <base>,保留原 diff 边界,最快最稳。 - 需要跨提交重新切分(一个提交拆两个、两个提交各取一半)→
git reset --soft <base>后按分组逐批git add(必要时git add -p)重新提交。慢但边界完全可控。
Windows 下写 GIT_SEQUENCE_EDITOR 时注意用能在非交互 shell 里跑的脚本(如 node -e "..." 或一个小 ps1/sh),不要依赖交互编辑器。rebase 冲突时不要猜,停下看冲突内容,按目标分组的语义解决。
任何 `git commit` 都不得加 `--no-verify`。 项目的 pre-commit / commit-msg hooks(lint、类型检查、信息格式校验)是质量门的一部分,整理出的每条提交都必须真实通过它们。hook 失败时修复导致失败的内容再提交;如果整理前旧历史本身就通不过当前 hook(例如中途改过 lint 规则),把这一情况报告给用户,由用户决定,而不是自行绕过。
保留作者归属
整理提交是在编辑别人的工作成果,归属信息不能丢:
- rebase / squash 时 git 默认保留 author,只更新 committer——这是正确行为,不要用
--reset-author或--amend --author=...改掉原作者。 - squash 的多个提交若作者不同,选主体意图的作者作为 author,其余作者以
Co-authored-by: 名字 <邮箱>trailer 追加到提交信息末尾;作者完全并列、无法分出主体时,优先考虑不合并这组提交。 - 走 reset 路径重新创建提交时,每条必须用
--author="原名字 <原邮箱>"恢复原作者,日期可用--date保留原提交时间。 - worktree 场景下分支可能来自多位开发者,分组盘点时顺手记录每条提交的作者,方案里标注每条目标提交的作者与 Co-authored-by 安排,随方案一起给用户确认。
4. 验证
这是硬性验收点,不允许跳过:
git diff <备份引用> HEAD # 必须为空——整理只动历史,不动最终代码再逐文件核验一次(git diff --stat 为空即文件级一致),并跑项目的最小验证(类型检查或受影响测试),确认整理后的分支在功能上与整理前等价。
一致性确认后删除备份引用:git branch -D backup/<分支名>-pre-linearize。核验通过意味着新历史与原历史逐文件一致,备份已完成使命,不留在分支列表里制造噪音。最终报告里仍附上原 HEAD 的 SHA(reflog 中仍可追溯)。若 tree 不一致,立即用备份引用恢复(git reset --hard <备份引用>)并排查,此时备份绝不能删。
5. 并入目标分支(可选,仅在用户要求时)
git rebase <目标分支> # 接到目标分支最新,保持线性
git checkout <目标分支> && git merge --ff-only <branch>目标分支由用户指定,未指定时为主干。--ff-only 保证不产生 merge commit。用户只要求「整理」时到第 4 步就停,合并与推送都留给用户。分支已推送过、用户要求同步远端时,确认前置检查第 5 条后用 git push --force-with-lease;用户没要求推送就不推。
颗粒度准则(本 skill 的核心判断)
一个提交 = 一个可独立理解、可独立 revert 的意图。
应合并的(太细的典型):
- fixup 类:修 typo、修 lint、修 CI、补漏提交的文件、「address review comments」——它们是上一意图的补丁,不是独立意图
- WIP / checkpoint /「先提交一下」类
- 同一意图的连续小步:刚加了函数马上修它的 bug,bug 从未存在于任何值得停留的历史点上
不应合并的(防止太粗):
- 不同模块或不同意图的改动,即使时间上相邻
- 「功能 + 配套重构」「实现 + 测试」是否合并取决于 revert 语义:回滚功能时测试必然一起回滚,可合并;重构独立成立,分开
- 作者不同且贡献并列的提交——合并会模糊归属(见「保留作者归属」)
- 判断测试:能否不用「和 / 并且 / 顺便」描述这条提交?线上出问题时单独 revert 它是否合理、会不会牵连无关改动? 两问有一问答不上来,说明分组错了
太粗的处理:单个提交混了多个意图时,走第 3 步的 reset 路径拆分,而不是为了「保持提交数少」而容忍。
提交信息格式
type(scope): 中文描述- type:
feat/fix/refactor/perf/docs/test/chore/build/ci/style - scope:模块名,小写英文,取自目录或模块名(如
auth、api-service、telemetry)。一条提交只取最主要的一个 scope,不堆叠;纯仓库级改动可用repo、deps - 描述:中文,动词开头(增加 / 支持 / 修复 / 移除 / 抽出 / 统一……),说清做了什么而不是怎么做的;不加句号;不超过 50 字
示例(取自真实项目历史):
feat(telemetry): 增加端到端反代可观测性
feat(codex): 支持额度重置积分的查询、消耗与账号入口
fix(test): 测试隔离预检对 worktree junction 透明
fix(model-block): 移除隐式账号模型封禁排程
feat(ui): 用 data-state 隐藏未激活的供应商标签页如果项目已有自己的提交信息约定(看主干近期历史),项目约定优先于本格式,格式服务于一致性。
安全红线
- 已推送且可能共享的分支:force-push 前必须得到用户明确确认,且只用
--force-with-lease - 备份引用在验证通过前必须一直有效;验证通过、文件一致性确认后按流程删除备份,不遗留也不提前删
- 只重写 base 之后的本分支历史,绝不动已并入目标分支或主干的公共历史
- 任何提交不得
--no-verify;不得用--amend --reset-author、--author覆盖原作者 - rebase / 重写 / 验证不委派子代理,由当前会话亲自执行并亲自核对结果
- 用户没要求合并时,整理完就停——不擅自执行 merge 或 push


