交互式变基中pick保留提交,squash合并到前一提交;merge --squash仅取内容不改历史;rebase后push需--force-with-lease;压缩时需手动编辑commit message并保留Co-authored-by等关键信息。

git rebase -i 后怎么选 pick/squash?
交互式变基是压缩提交最直接的方式,关键在编辑器里那几行命令的含义。你看到的每行开头是 pick,它代表“保留这个提交”,而 squash(或简写 s)才是合并动作——但必须作用于“它前面那个提交”。
常见错误是把第一个提交改成 squash,结果 Git 报错 Cannot squash without a previous commit。因为 squash 不是独立操作,它需要一个“被合并到”的目标。
- 想把第2、3、4个提交压进第1个:把第2–4行的
pick改成squash,第1行保持pick - 想把最后3个压成一个新提交(不关联前面的):把倒数第3行留
pick,后两行改s - 编辑保存后,Git 会打开另一个编辑器让你重写合并后的提交信息,删掉不需要的行即可
git merge --squash 适合什么场景?
它不产生合并提交,而是把目标分支所有变更以“未暂存更改”形式拉到当前工作区,等你手动 git add 和 git commit。和 rebase -i 的根本区别在于:它不改历史指针,只取内容。
适合这些情况:
- 你正在 feature 分支开发,但不想暴露中间调试提交,又不愿/不能对已推送的历史做
rebase(比如多人协作中该分支已被他人基于开发) - 临时整合某个远程分支的全部改动,但不确定是否要长期合并,先拿过来试跑
- 参数上注意:
git merge --squash origin/dev不会自动切换分支,也不会动 HEAD,只是把变更解包到当前工作区
rebase 后 push 失败:non-fast-forward 拒绝怎么办?
这是最常卡住人的点:rebase 改写了本地提交哈希,远程仓库拒绝覆盖已有历史。不是配置问题,是 Git 在保护协作安全。
- 确认没人基于你即将 force-push 的提交继续开发(尤其团队中)
- 用
git push --force-with-lease,比裸--force安全:它会检查远程最新提交是否仍是你上次 fetch 时的状态,防止误覆盖他人新提交 - 如果已有人基于旧提交工作,别硬推;改用
merge --squash或协调重新基线 - 某些托管平台(如 GitHub)默认禁用 force-push,需在仓库设置里开启 “Allow force pushes”
commit message 会被怎么处理?
压缩过程不是简单拼接。用 rebase -i 时,Git 会把所有被 squash 提交的 message 全部塞进编辑器供你删改;用 merge --squash 时,则完全不带任何原 message,全靠你手写。
- 被
squash的提交里如果有fix: xxx或chore:这类前缀,别直接全删——它们可能影响自动化流程(如生成 changelog) - 如果原提交里有
Co-authored-by:行,记得保留在最终 message 里,否则贡献者信息会丢失 - 大量压缩后 message 冗长?可以加
-m "refactor: unify auth flow"覆盖默认编辑器行为,跳过二次编辑
真正麻烦的不是操作步骤,是判断“该不该压”:功能没合入主干前压,没问题;已经合入、别人又基于它开发了,再压就是给别人添麻烦。历史可读性和协作成本之间,得自己掂量。










