bigywater.tech
常见报错 · 24

Git fatal: refusing to merge unrelated histories:push 先报 fetch first,pull --rebase 反而成功,允许之后仍有两个根

“fatal: refusing to merge unrelated histories” 一般出现在本地先 git init、远程仓库已有提交的时候。网上都是一句 --allow-unrelated-histories。这篇在本机复现完整的报错顺序,看加了这个参数之后仓库到底变成什么样,以及不用这个参数还有哪些更干净的办法。

2 个
无关历史里根提交的个数(正常的项目只有 1 个);--allow-unrelated-histories 合并后仍是 2 个
不拒绝
git pull --rebase 在无关历史上直接成功,只有合并方式才报 refusing to merge
7a4645e → 357531c
删掉 .git 重新 init,同样文件的根提交哈希变化,和旧远程成了无关历史

报错出现的顺序

实测 · 本机执行输出
    $ git push -u origin main 2>&1 | head -3
      To ../remote.git
       ! [rejected]        main -> main (fetch first)
      error: failed to push some refs to '../remote.git'
    $ git fetch origin 2>&1 | tail -2
      From ../remote
       * [new branch]      main       -> origin/main
    $ git pull origin main 2>&1 | tail -1
      fatal: Need to specify how to reconcile divergent branches.
    $ git pull --no-rebase origin main    (退出码 128)
      From ../remote
       * branch            main       -> FETCH_HEAD
      fatal: refusing to merge unrelated histories
    $ git merge origin/main    (退出码 128)
      fatal: refusing to merge unrelated histories
    $ git pull --rebase origin main 2>&1 | head -4; git log --oneline
      From ../remote
       * branch            main       -> FETCH_HEAD
      Rebasing (1/1)
      Successfully rebased and updated refs/heads/main.
      f2dcb43 first local commit
      d55edc3 Initial commit

先是 push 被拒(fetch first),不带参数的 pull 报需要选择合并方式,指定合并才报 unrelated histories。

为什么

实测 · 本机执行输出
    $ git fetch -q origin; git merge-base main origin/main; echo "退出码 $?"
      退出码 1
    $ git log --all --format='%h  父提交:[%p]  %s'
      4c8db55  父提交:[]  first local commit
      d55edc3  父提交:[]  Initial commit
    $ git rev-list --max-parents=0 --all | wc -l | tr -d " "
      2
    (上一行是所有分支里的根提交个数:正常的项目只有 1 个)

两条历史各有一个根提交,merge-base 找不到共同祖先。

加了参数之后

实测 · 本机执行输出
    $ git pull --no-rebase --allow-unrelated-histories --no-edit origin main 2>&1 | tail -4
      Merge made by the 'ort' strategy.
       README.md | 1 +
       1 file changed, 1 insertion(+)
       create mode 100644 README.md
    $ git log --oneline --graph; ls; git rev-list --max-parents=0 --all | wc -l | tr -d " "
      *   9d43154 Merge branch 'main' of ../remote
      |\  
      | * d55edc3 Initial commit
      * 4c8db55 first local commit
      README.md
      app.py
      2
    $ git pull --no-rebase --allow-unrelated-histories --no-edit origin main 2>&1 | tail -4; git status --short
       * [new branch]      main       -> origin/main
      Auto-merging README.md
      CONFLICT (add/add): Merge conflict in README.md
      Automatic merge failed; fix conflicts and then commit the result.
      AA README.md
    $ cat README.md
      <<<<<<< HEAD
      # my project
      =======
      # project
      >>>>>>> d55edc34915f384b98b9c626365db24737ef9c5e

文件不重名就合并成功,但仓库永远有两个根;同名文件是 add/add 冲突。

更干净的办法

实测 · 本机执行输出
    $ git fetch -q origin && git rebase origin/main 2>&1 | tail -2; git log --oneline --graph; git rev-list --max-parents=0 --all | wc -l | tr -d " "
      Rebasing (1/1)
      Successfully rebased and updated refs/heads/main.
      * f2dcb43 first local commit
      * d55edc3 Initial commit
      1
    $ git fetch -q origin && git reset --hard origin/main 2>&1 | tail -1; ls; git log --oneline
      HEAD is now at d55edc3 Initial commit
      README.md
      d55edc3 Initial commit

变基到远程历史上得到一条直线;本地没价值就 reset --hard 到远程。

另一种来源

实测 · 本机执行输出
    同样的文件、同样的提交说明,重新 init 之前的根提交 7a4645e,之后 357531c
    $ git remote add origin ../remote2.git && git fetch -q origin && git merge origin/main 2>&1 | tail -1; git push origin main 2>&1 | head -3
      fatal: refusing to merge unrelated histories
      To ../remote2.git
       ! [rejected]        main -> main (non-fast-forward)
      error: failed to push some refs to '../remote2.git'

删掉 .git 重新 init 会得到不同的根提交哈希。

分步演示

无关历史
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64;报错文本都是真实复现时原样捕获的(命令行工具统一用 LC_ALL=C 取英文原文,路径换成 );所有服务都是本机上自己起的、只监听 127.0.0.1,不访问外网;计时用 time.perf_counter,数字每次运行会有小幅抖动。本篇用 git 2.54.0(Apple Git-157);“远程”是本机的裸仓库,用 GIT_CONFIG_GLOBAL 隔离了配置,提交时间固定,所以哈希可复现(第 5 步的第二次提交特意用了不同的时间)
    • 没有验证:GitHub / GitLab 网页端新建仓库时自动生成的初始提交的具体内容;其他 git 版本里 pull 的报错顺序;--allow-unrelated-histories 对子树合并(git subtree)的用法;git filter-repo 等重写历史工具对根提交的影响
    京ICP备2026067502号-1京公网安备11010502063487号