Git 笔记:将一段旧历史压缩成一个提交
一、当前 Git 图(按你给的顺序)
现在历史是:git log --oneline --graph --decorate --all
c7a62a0
7cda46d
3340514
418ec0d
81ca762
a66af0e
fdacbcc
18ab314
9c815a8
25f8409
721bef7
6fb7708
c8ea573
76e802e
你要压缩的是这一段:
9c815a8
25f8409
721bef7
6fb7708
也就是说:
- 18ab314 要保留
- c8ea573 也要保留
- 中间这 4 个提交压缩成 1 个新的提交
二、压缩完成后应该长什么样
压缩后,Git 图应该变成:
c7a62a0
7cda46d
3340514
418ec0d
81ca762
a66af0e
fdacbcc
18ab314
<新的压缩提交>
c8ea573
76e802e
这意味着:
- 原来的 9c815a8 / 25f8409 / 721bef7 / 6fb7708 不再单独出现
- 它们被一个新提交替代
- 18ab314 以及更上面的提交都继续保留
三、核心思路
这次压缩其实不是普通 merge,而是:
- 先取这 4 个提交里最老的那个提交的父提交
- 再取这 4 个提交里最新的那个提交
- 在最新提交上建立临时分支
- 用 git reset --soft 把这 4 个提交的所有变化重新打成 1 个提交
- 再把主分支上它后面的提交重新接回去
四、关键边界
这次要压缩的是:
6fb7708
721bef7
25f8409
9c815a8
注意 Git 图里是:
- 上面新
- 下面旧
所以这 4 个提交中:
- 最旧的是:6fb7708
- 最新的是:9c815a8
而 6fb7708 的父提交是:
- c8ea573
所以我们实际上要压缩的是:
(c8ea573, 9c815a8]
五、完整操作步骤
第 1 步:确认当前工作区干净
git switch master
git status
要求:
- 工作区必须干净
- 否则不要继续
第 2 步:先做备份
git branch backup/master-before-4commit-squash
git tag backup-before-4commit-squash-2026-04-18
作用:
- 给当前 master 做一个安全快照
- 失败时可以一键恢复
第 3 步:从最新提交 9c815a8 建临时分支
git switch -c squash-4commits 9c815a8
第 4 步:把这 4 个提交压成一个提交
git reset --soft c8ea573
git commit -m "squash: consolidate commits from 6fb7708 through 9c815a8"
git reset --soft c8ea573
作用:
- 把当前分支指针回退到 c8ea573
- 但保留 index 和工作区的改动
结果就是:
Git 会把:
6fb7708
721bef7
25f8409
9c815a8
这些提交带来的全部变化,重新视为"一次待提交改动"。
git commit -m "..."
作用:
- 把刚才这批改动一次性重新提交
- 所以原来那 4 个提交,就被压成了 1 个新提交
压缩后,这条临时分支会变成:
<新的压缩提交>
c8ea573
76e802e
七、把主线后续提交重新接上
此时主分支 master 还是原来的样子:
c7a62a0
7cda46d
3340514
418ec0d
81ca762
a66af0e
fdacbcc
18ab314
9c815a8
25f8409
721bef7
6fb7708
c8ea573
76e802e
而你想保留的是:
- 18ab314 以及它上面的所有提交
所以接下来:
第 5 步:切回 master
git switch master
第 6 步:把 9c815a8 之后的提交重新挂到新提交后面
git rebase --onto squash-4commits 9c815a8 master
在这里:
- newbase = squash-4commits
- upstream = 9c815a8
- branch = master
它的意思是:
把 master 上 在 9c815a8 之后 的所有提交:
18ab314
fdacbcc
a66af0e
81ca762
418ec0d
3340514
7cda46d
c7a62a0
重新接到:
- squash-4commits 的新压缩提交后面
八、压缩后的最终结构
执行完成后,Git 图会变成:
c7a62a0
7cda46d
3340514
418ec0d
81ca762
a66af0e
fdacbcc
18ab314
<新的压缩提交>
c8ea573
76e802e
九、如何验证是否成功
git log --oneline --graph --decorate --all
预期:
- 原来那 4 个提交不再单独出现
- 被 1 个新提交替代
- 后续正式提交还在
2. 对比压缩前后的最终代码内容
如果你做过备份:
git diff --stat backup/master-before-4commit-squash..master
结果解释
- 没有输出
- 说明只是历史被整理
- 最终代码没变
- 有输出
- 说明代码内容变化了
- 需要进一步检查
示例
git图
749b23b
90c2825
9cdeda3
c607b90
f21189b
b7a89aa
27f5580
557a79f
98ce32b
压缩四次提交为一个提交
c607b90
f21189b
b7a89aa
27f5580
结果
749b23b
90c2825
9cdeda3
<新的压缩提交>
557a79f
98ce32b
git switch master
git status
git branch backup/master-before-4commit-squash
git tag backup-before-4commit-squash
git switch -c squash-4commits c607b90
git reset --soft 557a79f
git commit -m "squash: consolidate commits from 27f5580 through c607b90"
git switch master
git rebase --onto squash-4commits c607b90 master
git log --oneline --graph --decorate --all
git diff --stat backup/master-before-4commit-squash..master