指尖上的记忆指尖上的记忆
首页
  • 基础
  • Laravel框架
  • Symfony框架
  • 基础
  • Gin框架
  • 基础
  • Spring框架
  • 命令
  • Nginx
  • Ai
  • Deploy
  • Docker
  • K8s
  • Micro
  • RabbitMQ
  • Mysql
  • PostgreSsql
  • Redis
  • MongoDb
  • Html
  • Js
  • 前端
  • 后端
  • Git
  • 知识扫盲
  • Golang
🌟 gitHub
首页
  • 基础
  • Laravel框架
  • Symfony框架
  • 基础
  • Gin框架
  • 基础
  • Spring框架
  • 命令
  • Nginx
  • Ai
  • Deploy
  • Docker
  • K8s
  • Micro
  • RabbitMQ
  • Mysql
  • PostgreSsql
  • Redis
  • MongoDb
  • Html
  • Js
  • 前端
  • 后端
  • Git
  • 知识扫盲
  • Golang
🌟 gitHub

git之pull报错问题

  • 1.今天在做code review的时候,发现个问题,开发修改了代码,然后我拉取的时候一直报:
    • hint: You have divergent branches and need to specify how to reconcile them. hint: You can do so by running one of the following commands sometime before hint: your next pull: hint: hint: git config pull.rebase false # merge (the default strategy) hint: git config pull.rebase true # rebase hint: git config pull.ff only # fast-forward only hint: hint: You can replace "git config" with "git config --global" to set a default hint: preference for all repositories. You can also pass --rebase, --no-rebase, hint: or --ff-only on the command line to override the configured default per hint: invocation. Need to specify how to reconcile divergent branches.

    • 这个很奇怪,我本地没有任何修改,怎么就报这个呢,后来才知道,我之前做过一次git pull(习惯性pull一下最新代码),但是Git 可能在后台帮我生成了一个 merge commit(未提交状态)。 所以现在本地分支比远程“多了一个提交”,哪怕自己没改代码。 这个报错是因为在 git pull 的时候,本地分支和远程分支产生了 分歧 (divergent branches),Git 不知道是想用 merge、rebase 还是只允许 fast-forward。

    • 通过如下命令可以查看本地状态:

      git status
      git log --oneline --graph --decorate -n 10
      

报错信息已经给出了三种解决方式:

1. 直接指定一次性解决方式
  • 合并 (merge, 默认行为):

    git pull --no-rebase
    

    会生成一个 merge commit。

  • 变基 (rebase):

    git pull --rebase //我使用这种方式解决问题,非常有用
    

    会把本地提交“放到”远程提交之后,保持提交线性。

  • 只允许快进 (fast-forward only):

    git pull --ff-only
    

    如果不能直接快进,就会报错,不会自动合并。

2. 永久修改配置

如果想以后都用某种策略,可以设置 git config:

  • 所有仓库都生效(推荐,除非某仓库有特殊需求):

    git config --global pull.rebase false   # 默认 merge
    git config --global pull.rebase true    # 默认 rebase
    git config --global pull.ff only        # 只允许 fast-forward
    
  • 只对当前仓库生效:

    git config pull.rebase true
    

git pull --no-rebase 和 --rebase的区别:

这两个参数就是 Git 在遇到“本地有提交 + 远程也有提交”时,如何把两边历史对齐的两种方式:

1. git pull --no-rebase (默认行为:merge)

  • 做法:先 git fetch,然后把远程分支合并进来,生成一个新的 merge commit。
  • 结果:
    • 提交历史可能出现分叉。
    • 会多一个 “Merge branch 'xxx' of origin/xxx” 的提交。
  • 优点:
    • 历史完整,能看出谁在什么时候合并了远程代码。
  • 缺点:
    • 历史不够线性,可能很多 merge commit,看起来杂乱。

📌 举个例子:

A---B---C (你的本地提交)
     \
      D---E (远程提交)

执行 git pull --no-rebase 后:

A---B---C---M (merge commit)
     \     /
      D---E

2. git pull --rebase (历史线性化:rebase)

  • 做法:先 git fetch,然后把你本地的提交“拿掉”,把远程的提交放进来,再把你的提交“重新应用”在远程提交之后。
  • 结果:
    • 提交历史是直线的。
    • 不会生成额外的 merge commit。
  • 优点:
    • 历史干净,容易阅读。
  • 缺点:
    • 会改写提交的 hash(因为 rebase 会重放提交)。
    • 如果已经 push 过,再 rebase 可能要强推(git push -f),这对协作有风险。

📌 举个例子:

A---B---C (你的本地提交)
     \
      D---E (远程提交)

执行 git pull --rebase 后:

A---B---D---E---C' (C 被“重放”,变成新的提交 C')

🔑 总结

  • --no-rebase:保留真实的合并历史,适合强调“分支合并点”的团队。
  • --rebase:让历史线性、干净,适合强调“整洁提交线”的团队。

👉 通常:

  • 开源项目 / 大团队:偏向 merge(避免重写别人提交的历史)。
  • 小团队 / 自己的项目:偏向 rebase(历史整洁)。

git pull --ff-only的理解:

🚀 什么是 fast-forward (快进合并)

Git 有两种主要的合并方式:

  1. 普通合并 (merge)

    • 如果两个分支有分叉,Git 会创建一个新的 merge commit 来把两条线合并在一起。
  2. 快进合并 (fast-forward)

    • 如果当前分支的 HEAD 落后于远程分支,而且 本地没有额外的提交,Git 就可以“直接把 HEAD 向前移动到远程最新提交”。
    • 这种情况不需要生成新的 commit,历史就像直接从远程走过来的一样。

📌 举个例子

远程分支:

A---B---C---D (origin/main)

本地分支:

A---B---C (main)

这时执行:

git pull --ff-only

Git 会直接把 main 指针移动到 D,结果是:

A---B---C---D (main, origin/main)

没有产生额外的 commit,历史是线性的。

🛑 如果不能快进会怎样?

比如本地有提交:

A---B---C---X (main)
     \
      D---E (origin/main)

这种情况 没法快进(因为有分叉), 执行 git pull --ff-only 会报错:

fatal: Not possible to fast-forward, aborting.

这样避免了 Git 自动生成 merge commit,让你自己决定是要 --rebase 还是 --no-rebase。

✅ 总结理解

  • git pull --ff-only = 只允许快进更新,不允许自动 merge。
  • 适用场景:
    • 你本地没有提交,只是想更新远程代码。
    • 想确保历史干净,不要多余的 merge commit。
  • 好处:安全、整洁。不会悄悄帮你合并。
  • 坏处:如果有分叉,它会报错,你得自己决定怎么解决。

和 git pull的区别:

1️⃣ git pull 默认行为
  • 默认其实是相当于:
git fetch
git merge origin/当前分支
  • 也就是说,如果本地和远程有分歧(divergent branches),Git 会 生成一个 merge commit 来合并两边的历史。
  • 优点:保证不会丢提交,安全
  • 缺点:可能产生额外的 merge commit,历史不够干净
2️⃣ git pull --ff-only
  • 只允许 快进更新,不会生成 merge commit
  • 如果本地分支有任何提交(包括 Git 自动生成的 merge commit),就会报错
  • 优点:历史干净、线性
  • 缺点:不是快进的情况必须手动处理
3️⃣ 为什么不直接用 git pull?
  • 直接 git pull 会自动 merge,如果你本地有 意外的 commit(例如 Git 自动生成的 merge commit),就可能:
    1. 生成新的 merge commit
    2. 导致历史不干净
  • 有些团队或个人非常强调 提交历史线性,不希望出现多余的 merge commit,这时候就会选择 --ff-only 或 --rebase
4️⃣ 总结理解
命令本地干净本地有提交历史结果安全性/清洁度
git pull✅✅merge commit 可能出现安全,但历史可能杂乱
git pull --ff-only✅❌(报错)快进,历史线性历史干净,但不能有本地提交
git pull --rebase✅✅历史线性历史干净,但重写本地提交,需注意 push

💡 核心理解:

  • git pull = 安全默认,但可能产生 merge commit
  • --ff-only = 历史干净,但严格要求本地无提交
  • --rebase = 历史干净,可处理本地提交,但改写历史