git rebase
git rebase 是 Git 中非常强大但也需要谨慎使用的命令,主要用于"整理提交历史",它的核心作用是:把一个分支的提交"挪到"另一个分支上去,并重放这些提交,从而让提交历史更清晰、线性。
一、什么时候使用 git rebase
1. 保持提交历史整洁
当你的 feature 分支落后于主分支(如 main 或 develop)时,可以使用 rebase 将最新的主分支变更"融合"进来,而不是用 merge。
css
bash
复制编辑
git checkout feature
git rebase main
相比于 merge,这不会产生额外的 merge commit,提交历史更干净、线性,便于 review 和回溯。
2. 整理提交(交互式 rebase)
在本地开发过程中,可能提交了一堆小的 commit,例如修 bug、调试等,可以通过交互式 rebase 合并它们。
css
bash
复制编辑
git rebase -i HEAD~5
你可以选择:
- squash(合并)
- reword(修改 commit message)
- drop(删除提交)
使用场景: 在提交代码前进行"美化",比如准备 push 到远程或提 PR 前。
3. 修改历史提交信息
例如你想修改上一次提交的 message:
css
bash
复制编辑
git commit --amend
# 或者
git rebase -i HEAD~2
4. 拉取远程分支时保持线性历史
默认情况下 git pull 是 fetch + merge,可以使用:
css
bash
复制编辑
git pull --rebase
这样在拉取别人推送的提交时,会自动把你本地的 commit "重放"在最新的远程提交后,避免产生 merge commit。
二、常见使用场景总结
| 使用场景 | 是否适合使用 rebase | 说明 |
|---|---|---|
| 本地开发整理提交历史 | ✅ 是 | 使用 git rebase -i 美化 commit |
| Feature 分支同步主干代码 | ✅ 是 | git rebase main 保持提交线性 |
| 修复远程 push 错误提交 | ❌ 慎用 | 若已推送,rebase 后需强推,可能影响他人 |
| 多人协作的公共分支 | ❌ 慎用 | rebase 会更改历史,其他人会冲突或丢失历史 |
| 自动化 CI/CD 项目 | ✅ 可用 | 在构建前保持提交整洁,提升可读性 |
三、注意事项
- 不要对已推送的公共分支执行 rebase!
因为 rebase 会重写历史,如果别人已经基于你原来的提交开发了,会导致冲突和混乱。 - 本地分支尚未推送前,可以放心使用
rebase。
git rebase --continue:解决冲突后继续 rebase
-
作用: 当你解决了当前的冲突并 git add 所有冲突文件后,继续执行 rebase 剩下的提交。
-
使用场景: 你已经解决了当前冲突,想让 rebase 接着进行:
csharp
bash
# 解决冲突
git add .
# 继续 rebase
git rebase --continue
git rebase --skip:跳过当前这个有问题的提交
-
作用: 不处理当前冲突的提交,直接跳过它(即忽略当前这次提交)。
-
使用场景: 如果你觉得当前这个提交无关紧要、不重要,可以直接跳过它:
css
git rebase --skip
- 注意: 这个提交就会从 rebase 后的新历史中消失。
git rebase --abort:放弃 rebase,恢复到操作前的状态
-
作用: 取消当前的 rebase 操作,把代码恢复到 rebase 之前的状态。
-
使用场景: 如果你发现冲突太复杂、搞错了分支、rebase 不适合当前情况,可以"后悔":
c
git rebase --abort
三者对比总结:
| 命令 | 场景 | 行为 | 说明 |
|---|---|---|---|
git rebase --continue |
你解决了冲突 | 继续 rebase | 常用 |
git rebase --skip |
不想保留当前冲突的提交 | 跳过当前提交 | 会丢弃该次提交 |
git rebase --abort |
想放弃 rebase | 还原到原始状态 | 安全回退 |
冲突解决三种方案演示
1. 使用 --continue:解决冲突后继续 rebase
步骤:
csharp
# 1.手动编辑把冲突解决掉:
# 2.添加解决后的文件
git add file.txt
# 3.继续 rebase
git rebase --continue
2. 使用 --skip:跳过当前提交,不保留这个提交
css
git rebase --skip
结果: feature 分支当前这次提交被跳过,不再出现在 rebase 后的提交历史中。
3. 使用 --abort:放弃 rebase,回到 rebase 之前的状态
c
git rebase --abort
结果: Git 会将 feature 分支还原到 rebase 前的状态,什么也不会变动。
总结图示(冲突后你可以做什么)
css
[冲突发生]
↓
解决冲突?
↓
[是] → git add → git rebase --continue → ✅ 继续
[否] → 想放弃? → git rebase --abort → 🔙 撤销
→ 想跳过? → git rebase --skip → 🚫 忽略该提交
rebase commit合并
例如,你最近提交了 3 次:
lua
git log --oneline
e8f1d23 修改样式
a4b5c67 修复 Bug
9bd4e11 新增功能
你想把这三个合并成一个提交。
操作步骤如下:
第一步:使用交互式 rebase
css
git rebase -i HEAD~3
HEAD~3 表示你要修改最近的 3 个提交。
第二步:修改指令,把除了第一个保留为 pick,其余改为 squash(或 s)
编辑器打开后类似这样:
pick 9bd4e11 新增功能
pick a4b5c67 修复 Bug
pick e8f1d23 修改样式
你改成这样 👇:
pick 9bd4e11 新增功能
squash a4b5c67 修复 Bug
squash e8f1d23 修改样式
第三步:修改最终的提交信息(可选)
下一步 Git 会让你输入合并后的提交信息,你可以自定义,比如:
新增功能、修复 bug、调整样式
保存退出(一般是 :wq 或 Ctrl+S + Ctrl+W depending on your editor)。
第四步:完成后检查
lua
git log --oneline
你会看到这三个提交合并成了一个新的 commit,提交 ID 也变了。
指令总结
| 指令 | 含义 | 用途 |
|---|---|---|
pick |
保留这个提交 | 默认操作 |
reword |
修改提交信息,但保留代码 | 改 message 不改内容 |
edit |
暂停在此提交,允许修改内容 | 想修改该次提交的代码 |
squash |
合并当前提交到上一个,合并提交信息 | 压缩多个 commit(保留 message) |
fixup |
合并当前提交到上一个,丢弃提交信息 | 快速合并,不留痕迹 |
drop |
删除该次提交 | 不保留 |
技能总结
| 类别 | 命令 | 简要说明 |
|---|---|---|
| 基础 | git rebase main |
把当前分支放到 main 后 |
| 冲突处理 | --continue / --skip / --abort |
继续 / 跳过 / 取消 |
| 交互式 | -i HEAD~N |
编辑最近 N 次提交 |
| 修改行为 | pick reword edit squash fixup drop |
控制每一个提交 |
| 安全替代 | git pull --rebase |
拉取代码避免 merge commit |
rebase常见编辑器操作方式(根据你默认的 Git 编辑器不同)
1. 如果打开的是 Vim(Git 默认编辑器)
Vim 是 Git 默认使用的终端编辑器。
-
初始是"命令模式",不能直接输入内容。
-
你需要按:
css
i ← 进入插入模式(insert mode)
-
然后你就可以移动光标,把 pick 改成 squash 等。
-
修改完成后:
ruby
Esc ← 退出插入模式
:wq ← 保存并退出(输入冒号后输入 wq,然后回车)
Vim 快速操作流程回顾:
| 操作 | 键盘操作 |
|---|---|
| 进入插入模式 | i |
| 退出插入模式 | Esc |
| 保存并退出 | :wq + 回车 |
| 退出不保存 | :q! + 回车 |
rebase后 git push -f 使用场景
git push -f 是强制把你本地的分支覆盖远程分支,即使两者提交历史不一致。
1. rebase 或修改历史之后需要强推
举例:
你在本地对提交历史做了如下操作:
css
git rebase -i HEAD~3
# 或
git commit --amend
这些命令会修改 commit 的历史(提交 ID 会改变), 这时候如果你尝试推送:
perl
git push
Git 会提示:
css
! [rejected] main -> main (non-fast-forward)
此时你需要:
perl
git push -f
来强制用你的本地历史覆盖远程分支。
更安全的替代: git push --force-with-lease
csharp
git push --force-with-lease
总结
| 使用场景 | 是否用 -f |
原因 |
|---|---|---|
| 本地 rebase 后推送 | ✅ 是 | 本地提交 ID 改变了 |
| 修改历史删除敏感信息 | ✅ 是 | 覆盖远程历史 |
| 重置分支到早期状态 | ✅ 是 | 压缩/清理提交 |
| 正常协作开发 | ❌ 否 | 会影响他人 |
公共分支(如 main) |
❌ 否 | 高风险,避免使用 |
git commit --amend 是一个非常实用的 Git 命令,它用于修改最近的一次提交。
sql
git commit --amend
运行后 Git 会打开你的编辑器(如 Vim 或 VS Code),让你修改提交信息。 内容不变,只有 message 被改。
1. 修改上一次提交的 commit message(但内容不变)
sql
git commit --amend
运行后 Git 会打开你的编辑器(如 Vim 或 VS Code),让你修改提交信息。 内容不变,只有 message 被改。
2. 补充忘记添加的文件进上一次提交
你提交了代码,但忘记加某个文件,可以这样做:
csharp
# 添加漏掉的文件
git add forgotten-file.js
# 修改上一次提交,加入刚刚添加的文件
git commit --amend
这会把新加的内容合并进上一条提交,而不是生成一个新的提交。
3. 调整提交内容或格式(比如改文件名、修 typo)
可以在提交后马上发现错误,修复后:
sql
# 修 typo 后重新 add
git add .
# 用 amend 覆盖上一次提交
git commit --amend
提交历史发生了什么?
执行 git commit --amend 后:
-
原来的提交会被 删除
-
Git 创建一个新的提交(包含你改后的内容和信息)
-
新提交 ID 会改变
所以如果你已经 git push 过了,就需要用:
perl
git push -f
✅ 总结口诀
| 用途 | 命令 | 说明 |
|---|---|---|
| 改 message | git commit --amend |
不用 add,只改文字 |
| 补充文件 | git add file && git commit --amend |
把文件合进上一提交 |
| 改了历史 | git push -f |
修改了提交 ID,需要强推 |
如果你 本地删除了一个分支 ,而且线上(远程)也没有备份记录 ,那就相当于这个分支被彻底删了 ------ 除非你有"找得回"的线索,比如分支上的 commit 还没被 Git 的垃圾回收清理掉。
git操作中误删本地commit后:
1. 你是否还记得该分支的提交哈希(commit id)?
- 如果你有记录下来的 commit id,可以直接恢复:
css
git checkout -b 恢复的分支名 提交ID
2. 你是否曾经切换到这个分支、做过提交?
即使你删除了分支,Git 也会暂时保留它的历史在 reflog 中(默认保留 90 天)。这时候你就有救!
恢复本地已删除的分支的步骤(用 git reflog):
第一步:查看最近 Git 操作记录
git reflog
你会看到类似这样的输出:
less
a1b2c3d HEAD@{0}: checkout: moving from feature-abc to main
e4f5g6h HEAD@{1}: commit: 完成了按钮功能
...
你可以从这里找到你曾经在该分支上提交的 commit id(比如 e4f5g6h)。
第二步:基于旧的 commit 恢复分支
css
git checkout -b 新分支名 e4f5g6h
✅ 恢复成功!
🧪 补充技巧(恢复"最近删除的分支"):
你也可以用这个命令找回被删除的分支最近的 commit:
css
git fsck --lost-found
它会列出所有"悬空"对象,你可以从中找到对应的提交,再手动 checkout 回来。
✅ 总结操作指令:
| 场景 | 命令 | 说明 |
|---|---|---|
| 查找历史提交 | git reflog |
找到被删分支的提交 ID |
| 恢复分支 | git checkout -b 新分支 提交ID |
基于旧提交创建新分支 |
| 列出悬空对象 | git fsck --lost-found |
高级用法,找回"孤儿提交" |