在多人协作开发(尤其是参与开源项目或团队公共项目)时,直接向官方仓库推送代码是不太现实的——普通开发者通常没有上游仓库的写权限,就算有,每个人往上一通推,代码冲突和稳定性问题也够呛。还有一个常被忽略的原因:分支管理。上游仓库需要保持分支整洁,只保留主分支、开发分支等核心分支,如果每个开发者的个人分支都往上堆,很快就会乱成一锅粥。
所以日常开发用的是 Fork 工作流:先把官方仓库 Fork 到自己名下当「个人开发中转站」,在自己的仓库里随便建分支、搞开发,完事后通过 MR/PR 提交审核。这样既不影响上游仓库的分支整洁性,也有独立的开发空间。这个流程大家都很熟悉,但有个细节容易踩坑——本地 git push 时,代码到底推送到哪?
问题场景
前几天遇到一个情况:本地执行 git push 后,代码并没有推送到自己的 Fork 仓库(origin),而是跑到了上游仓库(upstream)。
查看远程配置:
1 | origin git@192.168.0.61:A11770/AndroidPackages.git (fetch) |
简单说明下:
origin:自己 Fork 的个人仓库,开发代码应该推到这里upstream:原始公共仓库,只用来拉取更新,不应该随便推送
核心概念
Git 允许绑定多个远程仓库,通过别名区分:origin 是默认的(一般是自己 Fork 来的仓库),upstream 是上游原始仓库(只用来同步代码,不往这推)。查看命令:
1 | git remote -v |
每个本地分支还可以绑定一个「远程仓库 + 远程分支」的关系,叫上游跟踪分支。用 git branch -vv 查看,输出中 [origin/分支名] 或 [upstream/分支名] 就是这个绑定关系。Git 执行无参数的 git push 时,会优先读取分支绑定的上游仓库,绑定了哪个就推到哪个。
另外还有一个 remote.pushDefault 配置项,用于设置没有绑定分支时的默认推送目标:
1 | git config remote.pushDefault origin |
优先级从高到低依次是:分支自身绑定 > pushDefault 配置 > 默认 origin。所以只要分支已经绑定了上游仓库,pushDefault 就完全不起作用。
还有一个关键参数 -u(即 --set-upstream):
1 | git push -u origin 分支名 |
它的作用有两个——把代码推送到指定远程仓库,并且永久绑定当前分支与该远程分支的跟踪关系。绑定之后,后续直接执行 git push 或 git pull 就行了。
排查步骤
遇到推送异常时,按下面几步排查:
第一步:确认远程仓库
1 | git remote -v |
区分哪些是自己的仓库,哪些是上游仓库。
第二步:查看分支绑定关系(核心)
1 | git branch -vv |
输出示例:
1 | * develop-vms-2.1 xxxxxxx [upstream/develop-vms-2.1] 提交信息 |
看方括号里的内容:
- 显示
upstream→ 推送到上游仓库(这就是问题所在) - 显示
origin→ 推送到自己 Fork 仓库(正确状态)
第三步:精确查看当前分支绑定
1 | git config --get branch.$(git rev-parse --abbrev-ref HEAD).remote |
输出 upstream 或 origin,一目了然。
解决方案
场景一:已绑定 upstream,但 origin 上有对应分支
重新绑定到 origin 即可:
1 | git branch --set-upstream-to=origin/分支名 |
场景二:已绑定 upstream,origin 上没这个分支(最常见)
会报错:
1 | fatal: the requested upstream branch 'origin/xxx' does not exist |
原因是这个分支从来没推送到过 Fork 仓库,origin 上自然不存在。解决办法就是首次推送并绑定:
1 | git push -u origin 分支名 |
搞定之后,以后直接 git push 就会推到自己仓库了。
场景三:从 upstream 新拉一个分支到本地,再同步到 origin
完整流程走一遍:
1 | # 拉取上游最新信息 |
常见误区
| 误区 | 真相 |
|---|---|
配置 pushDefault 就能改掉已有分支的推送目标 |
该配置只对没有上游绑定的分支生效 |
| origin 一定是默认推送仓库 | 推送目标由分支自身的绑定关系决定 |
-u 参数可有可无 |
-u 是首次推送新分支时的关键参数,不加的话后续无法无参数推送 |
git branch -vv 的显示会被全局配置影响 |
显示内容只由分支自身配置决定 |
命令速查
| 命令 | 作用 |
|---|---|
git remote -v |
查看所有远程仓库 |
git branch -vv |
查看所有分支的上游绑定关系 |
git config remote.pushDefault origin |
设置默认推送仓库(仅对未绑定分支生效) |
git branch --set-upstream-to=origin/分支名 |
修改已有分支的绑定目标 |
git push -u origin 分支名 |
首次推送到 origin 并永久绑定 |
git fetch upstream |
拉取上游仓库最新内容 |
git checkout -b 分支 upstream/分支 |
基于上游分支创建本地分支 |
总结一下:Fork 开发流中 git push 推错地方,根本原因就是本地分支绑错了上游跟踪仓库。遇到问题时先用 git branch -vv 检查绑定关系,然后用 --set-upstream-to 或者 push -u 修正即可。