git 变基:git rebase
rebase 作用
Rebase 是将一个分支的所有更改重新应用到另一个分支的最新状态上。使你的分支看起来像是在目标分支的最新提交之后创建的。

(heads/dev) git rebase master 详细工作原理
- Git 会检查
dev是否有未提交的更改,如果你有未提交的修改,Git 会尝试保留它们,如果这些修改与即将 rebase 的内容冲突,则会提示错误并中止。 - Git 首先会找到
dev和master分支的最近共同祖先提交。把共同祖先提交到dev最新提交的每个提交都换为一个补丁,并将这些补丁依次应用到master的最新提交上。如果某个补丁应用失败(如冲突),Git 会暂停 rebase 并提示你解决冲突,解决冲突后,使用git add .标记解决,然后运行git rebase --continue继续。也可以选择跳过某次提交(–skip)或中止整个 rebase(–abort)。 - 所有补丁成功应用后,Git 会更新
dev的指针HEAD,使其指向新的提交。 - 由于提交历史已改变,远程仓库上的
dev分支与本地不一致,必须使用强制推送。推荐使用git push --force-with-lease,而不是git push --force。
常见用法
(heads/dev) git rebase origin/release ✅ 将当前分支(dev)的提交“重新应用”到 origin/release 分支的最新提交之上。
(heads/dev) git rebase -i origin/release ✅ 交互式 rebase
(heads/dev) git rebase -i HEAD~3 ✅ 交互式整理最近3个提交(以HEAD~3为基准)
git rebase -i 详解
git rebase发生冲突时 ☞ 撤销rebase
git rebase发生冲突时 ☞ 解决冲突
常用参数
| 参数 | Git 引入年份/最低版本 |
|---|---|
--exec "echo hahah" | 2005/Git v1.0 |
--ignore-date | 2005/Git v1.0 |
--committer-date-is-author-date | 2008/Git v1.6.0 |
--continue | 2005/Git v1.0 |
--skip | 2005/Git v1.0 |
--abort | 2005/Git v1.0 |
--signoff | 2007/Git v1.5.0 |
--onto <newbase> | 2005/Git v1.0 |
--interactive/-i | 2007/Git v1.5.4 |
--keep-empty | 2007/Git v1.5.0 |
--no-ff | Git v1.0 + 支持 |
--autosquash/-a | 2010/Git v1.7.0 |
--rebase-merges/-r | 2012/Git v1.8.5 |
--preserve-merges | 2010/Git v1.7.0(引入) 2012/Git v1.8.5(被 --rebase-merges 替代) 2014/Git v2.0(标记为 deprecated) |
--force-rebase | Git v1.8.5+ 后更安全 |
-i
进入交互模式,手动编排提交
–exec
在交互式变基过程中,对每个提交应用后执行指定命令(如测试、lint)
git rebase -i HEAD~3 --exec "echo hahah" ✅
📌 弹出文件
pick be04f1b update
exec echo hahah
pick ddd538d update
exec echo hahah
pick a1c019c update
exec echo hahah
# $ git rebase -i HEAD~3 --exec "echo hahah"
# hint: Waiting for your editor to close the file... Can't find filter element
# Can't find filter element
# Executing: echo hahah
hahah
# Executing: echo hahah
hahah
# Executing: echo hahah
hahah
# Successfully rebased and updated refs/heads/dev.
–ignore-date
📌git rebase 会更新 committer date,不会更新 author date。
📌 --ignore-date 不仅更新 committer date,还会更新 author date,让整个提交的时间看起来就像“现在写的”。
# $ git log --pretty=format:"%<(10)%h | %<(20)%D | %<(20)%ai | %<(20)%ci | %s"
# 6ed3bac | HEAD -> dev | ⚠️2025-06-28 14:43:54 +0800 | ⚠️2025-06-28 14:43:54 +0800 | update 5
# zhang@zhangziwa MINGW64 /d/gitPrac/ckck (dev)
$ git rebase release --ignore-date ✅ 不仅更新 committer date,还会更新 author date
# Current branch dev is up to date, rebase forced.
# Successfully rebased and updated refs/heads/dev.
# $ git log --pretty=format:"%<(10)%h | %<(20)%D | %<(20)%ai | %<(20)%ci | %s"
# e3f5262 | HEAD -> dev | ⚠️2025-06-28 14:53:19 +0800 | ⚠️2025-06-28 14:53:19 +0800 | update 5
–committer-date-is-author-date
📌让 committer date 与 author date 一致,统一时间戳。
# $ git log --pretty=format:"%<(10)%h | %<(20)%D | %<(20)%ai | %<(20)%ci | %s"
# 6ed3bac | HEAD -> dev |⚠️2025-06-28 14:43:54 +0800 |⚠️2025-06-28 14:43:54 +0800 | update 5
$ git rebase release --signoff ✅ 更新 committer date,不会更新 author date
# $ git log --pretty=format:"%<(10)%h | %<(20)%D | %<(20)%ai | %<(20)%ci | %s"
# 815ac13 | HEAD -> dev |⚠️2025-06-28 14:43:54 +0800 |⚠️2025-06-28 15:15:58 +0800 | update 5
$ git rebase release --committer-date-is-author-date ✅ 让 committer date 与 author date 一致,统一时间戳
# $ git log --pretty=format:"%<(10)%h | %<(20)%D | %<(20)%ai | %<(20)%ci | %s"
# 6ed3bac | HEAD -> dev |⚠️2025-06-28 14:43:54 +0800 |⚠️2025-06-28 14:43:54 +0800 | update 5
–continue,–skip,–abort
git rebase 过程中用于处理冲突或中断操作时,有如下3个操作
git rebase --continue ✅ 解决冲突并继续
git rebase --skip ✅ 跳过当前正在处理的提交,不将其应用到新的基础上
git rebase --abort ✅ 中止整个变基
–signoff
给每个提交添加 Signed-off-by: 签名行
# $ git log --pretty=format:"%<(10)%h | %<(20)%D | %<(20)%ai | %<(20)%ci | %s"
# 6ed3bac | HEAD -> dev | 2025-06-28 14:43:54 +0800 | 2025-06-28 14:43:54 +0800 | update 5
$ git rebase release --signoff ✅
# Current branch dev is up to date, rebase forced.
# Successfully rebased and updated refs/heads/dev.
# $ git log --pretty=format:"%<(10)%h | %<(20)%D | %<(20)%ai | %<(20)%ci | %s - %b"
# 405bb6c | HEAD -> dev | 2025-06-28 14:43:54 +0800 | 2025-06-28 15:03:48 +0800 | update 5 - ⚠️Signed-off-by: zhangziwa <zhangziwa@qq.com>
–onto
git rebase --onto main develop feature,将 feature 分支中从 develop 到 feature 的所有提交,重新应用到 main 上
–keep-empty
Git 默认会忽略所有空提交,加上 --keep-empty 后,Git 在重写历史时会保留这些空提交,不会自动跳过它们。
–no-ff
变基时禁用快进合并(保留合并提交)
–autosquash
当你使用 git commit --fixup 或 git commit --squash <commit> 创建了“修复提交”后,使用 git rebase -i --autosquash 自动识别并合并 fixup/squash 提交。
–rebase-merges,–preserve-merges(已废弃)
--rebase-merges 在变基时记住你以前是怎么合并分支的,避免历史变得混乱或丢失重要信息。
--preserve-merges 也是相同思路,但是已弃用。
原始结构如下:
A---B---C---D <-- main
\
E---F---M <-- feature
git rebase main ✅
A---B---C---D <-- main
\
E'--F'--M' <-- feature 📝E'相对于E表示sha变了
git rebase --preserve-merges main(已废弃) ✅
A---B---C---D <-- main
\ \
E'---F'---M' <-- feature M'是对原始M的“复制”,可能无法准确反映合并逻辑,已废弃
git rebase --rebase-merges main ✅
A---B---C---D <-- main
\ \
E'---F'---M' <-- feature M'是通过重新执行合并生成的新提交
git merge main ✅
A---B-----C----D <-- main
\ \
D---E---M---N <-- feature
git merge feature
A---B---C---D---N <-- main ✅
\ /
E---F---M <-- feature
–force-rebase
--force-rebase 的作用是:即使提交已经存在于目标分支中,也强制重新 apply 所有提交。
依赖push --force-with-lease逻辑.
原始结构:
A---B---C <-- main
\
D---E <-- feature
git rebase main
A---B---C <-- main
\
D---E <-- feature (无变化)
git rebase --force-rebase main ✅
A---B---C <-- main
\
D'---E' <-- feature
使用场景
github上一次基于rebase的PR提交
rebase导致源分支修改丢失
更多推荐
所有评论(0)