引言
在Git 场景化实战指南:从菜鸟到高手的完整攻略中,我们学习了 Git 的基础操作和常见工作流程。现在让我们深入探讨两个高级但极其实用的 Git 功能:储藏(stash) 和变基(rebase) 。掌握这些技巧将显著提升你的 Git 工作流效率!
stash 储藏操作
场景:
你正在开发一个功能,但突然需要切换到另一个紧急任务。,这时就需要用到git stash操作来临时保存当前的工作进度了
具体操作步骤:
csharp
# 1. 你要在 feature 分支上开发用户登录功能,首先切换到这个分支
git checkout feature
# 2. 你在login.js文件里面写了对应的登录验证代码
echo "// 登录验证代码" >> login.js
#把刚刚写的代码提交到暂存区
git add login.js
# 注意:还没有 git commit,因为功能没写完
# 3. 突然接到紧急任务:修复主分支的 bug
# 你不能提交,因为功能没写完
# 你也不能切换分支,因为有未提交的修改
# 4. 使用 git stash 临时保存
git stash # 保存当前工作进度
# 5. 现在可以切换分支了
git checkout main
# 6. 修复紧急 bug
# ... 修复代码 ...
git add .
git commit -m "hotfix: fix critical bug"
# 7. 回到功能分支继续开发
git checkout feature
git stash pop # 恢复之前的工作进度
❓为什么不能直接切换分支:
- Git 不允许在有未提交修改时切换分支
- 这是为了保护你的工作不被丢失
- git stash 提供了一个安全的临时保存方案
rebase 变基操作
1.什么是变基(Rebase)?
变基(Rebase) 是 Git 中的一个重要操作,它的本质是**「重新基于最新代码来应用你的更改」**。
2.基本变基操作
bash
git checkout feature # 切换到 feature 分支
git rebase main # 将当前分支feature变基到 main 分支
实际效果:
变基前:
css
A---B---C feature
/
D---E---F---G main
变基后:
css
A'--B'--C' feature
/
D---E---F---G main
3.git rebase main
详解
-
将当前分支(feature)的提交"重新应用"到
main
分支的最新提交G之上 -
这个过程会:
- 找到两个分支的共同祖先E
- 提取当前分支feature 的所有新提交A,B,C
- 将这些提交F和G 逐个应用到
main
分支的顶端 - 创建新的提交A',B',C'
注意: 变基操作是在代码提交后,是你已经把A,B,C执行了commit后的操作,它的作用是整理、修改和优化提交历史,使其更加清晰和有条理。
变基前的提交A,B,C 和变基后的提交A',B',C' 内容相同但用来标识每次提交的哈希值不同
4.rebase 的使用场景:
场景1:你的分支落后了,需要同步最新代码
bash
# 情况:你一周前从主分支创建了功能分支
# A---B---C feature
# /
# D---E---F---G main
# 现在主分支有了很多新更新,你的分支落后了
git log --oneline --graph
#log:显示提交历史
#--oneline:每个提交只显示一行(缩短的哈希值 + 提交信息)
#--graph:用 ASCII 图形显示分支和合并历史
显示出的提交历史示例:

解读这个图形:
*
表示一个提交|
和/
表示分支的分叉和合并关系(HEAD -> feature)
表示当前在 feature 分支(main)
表示 main 分支的位置
执行变基操作 git rebase main
,这个命令的意思是: "将 当前feature 分支的提交重新应用到 main 分支的最新状态之上"
变基后的结果

现在的状态:
-
变成了线性历史:没有分支分叉了
-
feature 分支现在基于最新的 main:
- 原来的提交 def5678 和 abc1234 被重新应用
- 它们现在位于 main 分支的所有更新之后
-
提交顺序(从新到旧):
- abc1234 (feature的最新功能)
- def5678 (feature的较旧功能)
- xyz9999 (main的最新更新)
- uvw8888 (main的另一个更新)
- rst7777 (main的第三个更新)
- mno7890 (一周前的共同基础)
场景2:你的提交历史太乱了,想整理一下
bash
# 情况:你开发了一个功能,但提交了很多次,历史很乱
# 1. 查看最近的6个提交,一行显示一个
git log --oneline -6
# abc1234 修复按钮样式
# def5678 添加错误处理
# ghi9012 修复bug
# jkl3456 添加注释
# mno7890 优化性能
# pqr1234 实现登录功能
操作: 这时你输入git rebase -i HEAD~6
,表示你要交互式(interactive )地对当前(HEAD所指向)的分支的这六个提交做变基操作,这时Git 会打开文本编辑器 (如 Vim、VSCode、Nano等),显示类似这样的内容:
pick pqr1234 提交信息5
pick mno7890 提交信息4
pick jkl3456 提交信息3
pick ghi9012 提交信息2
pick def5678 提交信息1
pick abc1234 提交信息0
你可以修改每行前的命令:
pick
→ 保留这个提交reword
→ 修改提交信息edit
→ 暂停并修改提交内容squash
→ 合并到前一个提交fixup
→ 合并但丢弃信息drop
→ 删除这个提交
保存退出后,Git 会按照你的指示重新组织提交历史
💡 实用技巧
如果想操作所有提交:
css
# 从第一个提交开始操作所有历史
git rebase -i --root
如果想操作特定数量的提交:
bash
# 操作最近3个提交
git rebase -i HEAD~3
# 操作最近10个提交
git rebase -i HEAD~10
如果想操作到某个特定提交:
bash
# 操作直到提交abc1234(不包括abc1234)
git rebase -i abc1234^
# abc1234^ 表示 abc1234 的父提交
#相当于 abc1234 的前一个提交
⚠️ 重要提醒
只对尚未推送到远程仓库的本地提交使用交互式变基! 因为变基会重写提交历史,如果已经推送了,会给协作者带来麻烦。
特性 | 普通变基 (git rebase ) |
交互式变基 (git rebase -i ) |
---|---|---|
操作方式 | 自动完成 | 手动交互选择 |
修改历史 | 通常不修改提交内容 | 可以修改提交内容和信息 |
使用场景 | 同步代码、整理分支 | 精细修改提交历史 |
风险等级 | 中等 | 高 |
场景3:你想修改某个提交的信息
bash
# 情况:你发现某个提交的信息写错了
# 1. 查看提交
git log --oneline -3
# abc1234 修复登录bug
# def5678 添加用户注册
# ghi9012 初始化项目
# 2. 交互式 rebase
git rebase -i HEAD~3
# 3. 编辑器打开,按照时间顺序从上到下显示(和git log顺序不一样)
# pick ghi9012 初始化项目
# pick def5678 添加用户注册
# pick abc1234 修复登录bug
# 4. 你想修改第二个提交的提交信息,你就要把第二条提交记录前面的单词pick(保留这个提交)改成reword(修改提交信息),也就是你要这么写:
# pick ghi9012 初始化项目
# reword def5678 添加用户注册
# pick abc1234 修复登录bug
# 5. 保存后,Git 会让你重新编辑第二个提交的信息
# 你改为:"实现用户注册功能"
# 6. 结果:
git log --oneline -3
# abc1234 修复登录bug
# def5678 实现用户注册功能
# ghi9012 初始化项目
场景4:你想删除某个提交
bash
# 情况:你提交了一个测试文件,现在想删除这个提交
# 1. 查看提交
git log --oneline -4
# abc1234 添加测试文件
# def5678 实现核心功能
# ghi9012 添加配置文件
# jkl3456 初始化项目
# 2. 交互式 rebase
git rebase -i HEAD~4
# 3. 编辑器打开:
# pick jkl3456 初始化项目
# pick ghi9012 添加配置文件
# pick def5678 实现核心功能
# pick abc1234 添加测试文件
# 4. 你想删除最后一个提交,改为:
# pick jkl3456 初始化项目
# pick ghi9012 添加配置文件
# pick def5678 实现核心功能
# drop abc1234 添加测试文件
# 5. 结果:测试文件的提交被删除了
git log --oneline -3
# def5678 实现核心功能
# ghi9012 添加配置文件
# jkl3456 初始化项目
为什么需要 Rebase?
问题:提交历史太乱
markdown
# 没有 rebase 的历史(看起来像这样):
* abc1234 修复小bug ← 琐碎的提交
* def5678 添加注释 ← 琐碎的提交
* ghi9012 修复另一个bug ← 琐碎的提交
* jkl3456 优化代码 ← 琐碎的提交
* mno7890 实现功能 ← 主要的提交
问题在于:
- 5个提交其实都是为了完成同一个功能
- 包含了很多琐碎的中间步骤
- 历史记录冗长且难以阅读
- 代码审查时需要看很多小提交
整理后的清晰历史
markdown
# 使用 rebase 整理后:
* mno7890 实现完整功能 ← 一个清晰的提交
好处:
- 一个提交代表一个完整的功能
- 历史简洁明了
- 更容易理解代码变更
- 便于代码审查和问题排查
✅ 总结
Rebase 整理历史就像是:
- 从"过程记录"到"成果展示"
- 从"零散零件"到"完整产品"
- 从"草稿笔记"到"正式文档"
让提交历史更有意义,而不仅仅是记录每一个微小的更改!