用 git commit --fixup 整理提交,rebase 时自动归位

45 次浏览4 条回复

临时修补前一个提交时,可以用 git commit --fixup=<commit> 标记它,最后 rebase 时让 Git 自动把修补内容合并回原提交。

环境:Git 2.34+。简单试一下:

git init -q fixup-demo && cd fixup-demo
git config user.email [email protected]
git config user.name dev
printf 'one\ntwo\n' > note.txt
git add note.txt && git commit -qm 'add note'
printf 'three\n' >> note.txt
git add note.txt && git commit -qm 'add more'

# 假设要把当前改动修回上一个提交
printf 'two-fixed\n' > note.txt
git add note.txt
git commit --fixup=HEAD
git log --oneline --decorate -3

# 从根提交开始整理
git rebase -i --autosquash --root

编辑器里会看到 fixup! 提交已经排在目标提交后面,保存后 Git 会自动合并。共享分支上操作前先确认提交还没被别人基于它继续开发。

这个流程挺适合整理本地提交。示例里 printf 'two-fixed\n' > note.txt 会把前面的 one 也覆盖掉,如果只是修第二行,最好用编辑器或脚本保留其他内容,避免把无关改动一起塞进 fixup!。另外目标提交不在 HEAD 时,--fixup=<commit> 依然可以直接指定,最后配合 --autosquash 检查一下排序再 rebase。

再补一个容易混的点:--autosquash 只负责把 fixup! 提交排到目标提交后面,不会替你处理冲突;rebase 停下来时还是要检查 diff,再继续 git rebase --continue。如果目标不是当前提交,先用 git log --oneline 找到准确的提交号,再写 git commit --fixup=<sha>,比凭标题匹配更稳。

还有个小细节:如果一次改了多个目标提交,可以分别执行 git commit --fixup=<sha>,再统一跑 git rebase -i --autosquash <base>。整理前先确认工作区干净,遇到冲突时不要直接跳过,解决后看一眼 git diff 再继续;这样比较不容易把别的改动误合进某个 fixup。

我一般会先确认工作区没有未提交改动,再做 fixup。还有一点:如果目标提交已经推到共享分支,autosquash 之后历史会重写,后续推送通常要用 --force-with-lease,并先和协作者确认;个人本地分支就没这个沟通成本。