Git中merge与rebase的区别

无论是 rebase 还是 merge,在执行 pull 时都不会“自动抹掉”你的本地工作成果 —— 在这两种情况下,你的提交记录都会保留在仓库中(要么在分支历史中,要么在 reflog 存活期间以旧的 SHA 形式存在)。

  • pull.rebase false(merge)git pull 会生成一个 merge commit,你的提交和远程提交 不会被覆盖或重写,分支历史只是简单地 合并 到一起。从视觉上看,“更安全”:你清晰地看到两条分支交汇的路径。
  • pull.rebase true(rebase):你的本地提交会被 复制覆盖 在远程提交之上(生成新的 SHA 值)。提交内容通常保持一致,但在成功 rebase 后,旧的提交可能仅保留在 git reflog 中 —— 这是正常的,如果操作出错,你可以从 reflog 中 恢复(例如使用 git reset --hard 回到某个 ref)。

如果你最关心的是“不丢失工作成果”:

  1. 在执行高风险操作前 —— 先提交(或使用 git stash)并可选创建一个独立的备份分支(如 git branch backup-tgisn-46),这是廉价且安全的备份。
  2. 不要混淆“丢失工作成果”与这些命令,比如 git reset --hard无必要时的 force pushgit clean -fd
  3. 在 rebase/merge 后的几天内,避免执行激进的 git gc —— 因为 reflog 会保留恢复路径。

对于“不丢失工作成果,同时不严重复杂化历史”的场景,建议设置:git config pull.rebase false —— 当出现冲突时,你总会得到一个 merge,不会重写本地提交。如果你已经习惯 rebase(如过去使用 pull --rebase)—— 可以保留 pull.rebase true,但切勿在没有协商的情况下对公共分支执行 push --force

总结: 选择 pull 策略本身不会导致工作成果丢失;真正的风险来自其他命令force push;为安心起见,在执行不确定操作前先提交 + 创建备份分支


以下是与你遇到的相同场景:一个共同提交 C,在 origin 上有五个提交 r1…r5,在本地只有一个提交 L(你的工作成果)。

1. pull 之前(分支已发散)

gitGraph
  commit id: "C (共同)"
  branch local
  checkout local
  commit id: "L (我的提交)"
  checkout main
  commit id: "r1"
  commit id: "r2"
  commit id: "r3"
  commit id: "r4"
  commit id: "r5"

含义:本地分支的末端是 L,主分支末端是 r5,共同祖先为 C无论哪种方式,你的工作成果都不会丢失 —— 只是合并历史的方式不同


2. 执行 git pull 且不启用 rebase(pull.rebase false → merge)

gitGraph
  commit id: "C"
  branch local
  checkout local
  commit id: "L"
  checkout main
  commit id: "r1"
  commit id: "r2"
  commit id: "r3"
  commit id: "r4"
  commit id: "r5"
  checkout local
  merge main
  commit id: "M (merge commit)"

生成一个 merge commit M,它有两个父提交(Lr5)。提交 Lr1…r5 作为对象依然存在;历史是分支状,没有重写。


3. 执行 git pull 且启用 rebase(pull.rebase true → rebase)

gitGraph
  commit id: "C"
  commit id: "r1"
  commit id: "r2"
  commit id: "r3"
  commit id: "r4"
  commit id: "r5"
  commit id: "L′ (相同补丁,新 hash)"

历史变为线性:你的工作成果位于远程提交之上。L 的历史中出现了一个新的提交 L′(相对于 r5 的补丁相同,但 hash 不同);旧的 L 会暂时保留在 git reflog 中,直到你手动清理 reflog expire


简而言之: merge 是 分叉 + merge 节点;rebase 是 一条直线,你的提交“覆盖”在远程之上。在两种正常场景下,文件变更内容都不会丢失;区别仅在于历史形态rebase 后本地提交的 hash