返回博客

git fetch 显示 [new branch] 不是真分叉,是你自己在两台机器上重复提交了

服务器上有一个 PHP 项目,长期以来的工作方式是"SSH 进去直接改代码",偶尔也会在本地 clone 一份改完再推。某天终于想规范化,打算把两侧历史合并到远端。一跑 git fetch,傻眼了:

$ git fetch origin
 * [new branch]      master     -> origin/master

[new branch]?master 从来都在啊,怎么变成新分支了?紧接着一看数量:

$ git rev-list --left-right --count origin/master...HEAD
21      19

远端 21 个 commit,本地 19 个——看起来是经典的分叉,两侧都有独立进展,似乎该 rebase 或 merge。

但事情没那么简单。

现象

  • git push 报 non-fast-forward,无法直接推
  • git fetch 显示 [new branch] origin/master,说明本地从未配置过 upstream
  • 两侧各有一批"独有"commit,subject 列表却高度相似
  • 你确信这段时间只有自己一个人在改代码

根因

这不是分叉,而是重复提交

场景还原:同一个人在两个工作副本(比如本机和服务器)对同一批文件各自做了 commit,commit message 相同但 SHA 完全不同。Git 看到的是两条平行历史,实际上业务代码字节级完全一致。

[new branch] origin/master 这个提示更是个迷惑项——它不是说远端分支被重建了,而是说本地 .git/config 里从未配置 [branch "master"] 的 upstream,导致本地 master 从未跟踪过 origin/master,fetch 时才把远端当新分支处理。

坑:直觉告诉你「分叉了,merge 一下」

两侧大量同 subject commit + merge → 产生一堆空冲突或重复历史。 rebase 同理,会触发大量 "empty commit"。 force push 更危险,直接覆盖远端——如果你判断错了,对方的真实工作就没了。 在确认根因之前,三种操作全部应该冻结。

诊断方法(只读,零风险)

四步快速确认,全部是读操作,不改任何状态。

Step 1:列出双方独有 commit

git log origin/master --not HEAD --oneline   # 远端独有
git log HEAD --not origin/master --oneline   # 本地独有

Step 2:检查作者分布

git log origin/master --not HEAD --format='%an' | sort -u
git log HEAD --not origin/master --format='%an' | sort -u

两侧作者集合一致,且只有你一个人 → 强烈怀疑重复提交。

Step 3:subject 配对

git log origin/master --not HEAD --format='%s' | sort > /tmp/remote-subjects.txt
git log HEAD --not origin/master --format='%s' | sort > /tmp/local-subjects.txt
diff /tmp/remote-subjects.txt /tmp/local-subjects.txt

diff 输出几乎为空 → 确证。

Step 4:业务代码字节级比对

git diff origin/master HEAD -- path/to/key-file.php

输出为空 → 业务代码 100% 一致,分叉是假象。

正解

确认是重复提交后,标准处理路径:

# 1. stash 保护 working tree
git stash push --include-untracked --message "pre-align"
 
# 2. 基于远端 master 建对齐分支
git checkout -b align-master origin/master
 
# 3. cherry-pick 真正独有的 commit(subject 在远端没有对应的那批)
git cherry-pick <真正独有的 commit SHA>
# 若提示 "empty commit" → 说明远端已有相同改动,跳过
git cherry-pick --skip
 
# 4. fast-forward 推送
git push origin align-master:master
 
# 5. 本地 master 对齐
git checkout master
git reset --hard align-master
git branch -d align-master
 
# 6. 恢复 working tree
git stash pop
正解:cherry-pick 真正独有的 commit,fast-forward push

不 merge、不 rebase、不 force push。找出两侧 subject 不重叠的那批 commit(真正独有的工作),cherry-pick 到对方基础上,再 fast-forward 推送。全程无破坏性操作,生产 working tree 不受影响。

顺手修掉 upstream 缺失问题
git branch --set-upstream-to=origin/master master

以后 git status 就能正确显示 ahead/behind,不会再有 [new branch] 的误导。

一句话外卖

[new branch] origin/master 加上"只有我一个人改",先怀疑是重复提交,跑四步只读诊断,确认根因再动手,比直觉 rebase 安全一百倍。