rebase 作用

Rebase 是将一个分支的所有更改重新应用到另一个分支的最新状态上。使你的分支看起来像是在目标分支的最新提交之后创建的。
在这里插入图片描述

(heads/dev) git rebase master 详细工作原理

  1. Git 会检查dev是否有未提交的更改,如果你有未提交的修改,Git 会尝试保留它们,如果这些修改与即将 rebase 的内容冲突,则会提示错误并中止。
  2. Git 首先会找到devmaster分支的最近共同祖先提交。把共同祖先提交dev最新提交的每个提交都换为一个补丁,并将这些补丁依次应用到master最新提交上。如果某个补丁应用失败(如冲突),Git 会暂停 rebase 并提示你解决冲突,解决冲突后,使用 git add . 标记解决,然后运行 git rebase --continue 继续。也可以选择跳过某次提交(–skip)或中止整个 rebase(–abort)。
  3. 所有补丁成功应用后,Git 会更新dev的指针HEAD,使其指向新的提交。
  4. 由于提交历史已改变,远程仓库上的 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-date2005/Git v1.0
--committer-date-is-author-date2008/Git v1.6.0
--continue2005/Git v1.0
--skip2005/Git v1.0
--abort2005/Git v1.0
--signoff2007/Git v1.5.0
--onto <newbase>2005/Git v1.0
--interactive/-i2007/Git v1.5.4
--keep-empty2007/Git v1.5.0
--no-ffGit v1.0 + 支持
--autosquash/-a2010/Git v1.7.0
--rebase-merges/-r2012/Git v1.8.5
--preserve-merges2010/Git v1.7.0(引入)
2012/Git v1.8.5(被 --rebase-merges 替代)
2014/Git v2.0(标记为 deprecated)
--force-rebaseGit 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 dateauthor 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 分支中从 developfeature 的所有提交,重新应用到 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导致源分支修改丢失

Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐