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