4.1 remote、fetch、pull、push 的真身


4.1 remote、fetch、pull、push 的真身

本节摘要:网络命令只做两件事——传输对象、更新引用。remote 是配置里的昵称地址簿,fetch 下行同步并更新远程跟踪引用,pull 是 fetch 加合并,push 上行对象并请求挪动远端分支。理解"请求"二字,推送被拒就不再令人困惑。

学习目标

先交代一个容易忽略的事实:Git 本身只是一个本地工具,网络能力是它后来长出的部分,而且长得极其克制——四条网络命令共享同一套"传对象、挪引用"的极简内核,没有任何一条命令会替你做合并决策。正因如此,学远程命令的正确姿势不是背参数,而是先想清楚"哪边是本地、哪边是远端、对象往哪个方向流、引用由谁更新"这四个问题。本节结束时你应当能够:

  1. 能查看 remote 配置并理解 fetch 与 push 可能指向不同地址
  2. 能描述 fetch 具体更新了哪些引用、没动哪些
  3. 能解释推送被拒的原因并按规范流程处理
  4. 能为团队选定 pull 的默认合并策略并说明理由

一、remote:一本地址簿

克隆或添加远端后,全部配置都摊在配置文件里,可以直接取证:

git remote -v # origin https://example.com/team/project.git (fetch) # origin https://example.com/team/project.git (push)

origin 不是关键字,只是默认昵称。fetch 与 push 地址分开配置是有意设计——镜像工作流里可以"从上游拉、往自己维护的仓库推";同一仓库也能登记多个远端(git remote add upstream ...),Fork 工作流(第 5 章)正是靠双远端运转。昵称之后,所有远程引用统一挂在 refs/remotes/<昵称>/ 命名空间下——这就是 origin/main 这种写法的全名。

二、fetch:只拿证据,不动现场

fetch 干两件事:把远端有而本地没有的对象下载进对象库;把本地的 refs/remotes/origin/* 引用更新为远端各分支当前指向。它不碰你的工作区、不碰本地分支、不碰 index——是最安全的网络操作,随时可执行。

git fetch origin # From https://example.com/team/project.git # a1b2c3d..e5f6a7b main -> origin/main git status -sb # ## main...origin/main [behind 2]

behind 2 表示远端跟踪引用比你本地 main 多两个提交——注意此刻对象已经在你库里了,只是还没合入。想看新到了什么:

git log main..origin/main --oneline # 远端新提交清单 git diff main origin/main # 快照差异

这个"先 fetch 再观察后合并"的节奏,是团队协作的黄金动作。它把"接收别人的变更"从一次黑盒跳变,分解成了可审查的两步。

三、pull:两步并一步的取舍

git pull 等于 fetch 之后自动对配对的本地分支执行 merge(或 rebase,取决于配置)。省事的代价是跳过了上面那个审查窗口——尤其多人同库高频推送的团队,盲目 pull 会把半懂状态的历史直接搅进本地。两个建议:其一,团队统一配置 git config pull.rebase true,pull 变成 fetch 加 rebase,历史更线性,也避免了大量无意义的 merge commit;其二,冲突多发的仓库干脆禁用 pull,改为显式的 fetch 加 merge/rebase 两步。

pull 的分发风险还有一个隐蔽形态:fast-forward 式 pull 在你本地"恰好"也有新提交时会静默升级成三方合并并可能弹冲突,惊慌中的随手解决容易埋错。回到第 3 章的原则——冲突解决前先 git log --merge -p 看清双方各自改了什么。

四、push:一次"请求"而非"命令"

push 把本地对象上传,然后请求远端把它某分支的引用挪到你的提交。远端有权拒绝,最常见两类拒绝:

非快进拒绝:远端分支有你没有的提交(同事先推了)。这是引用模型的必然——远端把 main 从 X 挪到你的 Y,若 X 不是 Y 的祖先,除非强推否则是危险操作,服务端默认拒绝。规范处理:

git fetch origin git rebase origin/main # 把你的提交复印到同事的新顶点之后 git push origin main # 再推 现在是快进

权限拒绝:受保护分支(通常 main/release)不允许直接推。这是平台层的引用保护,对应第 5 章的功能分支工作流——推到自己的分支,走合并请求进门。

强推的安全阀再强调一次:git push --force-with-lease origin dev,仅当远端 dev 仍是你记忆中的位置才覆盖,防止踩掉同事刚推的工作。裸的 --force 只该出现在确定个人独占的分支上。

⚠️ 常见坑:pull 下来的合并冲突解决到一半取消(Ctrl-C 或关窗口),index 停在三舞台状态,之后的 status 全是 U 状态码。复原办法:git merge --abort。养成"合并/变基中途不看懂 status 不动手"的习惯。

💡 关键直觉:把远端想成"同事的硬盘镜像"。fetch 是抄录他最新的书签位置(顺便把缺页复印过来),push 是请求他更新书签。你的本地 main 与他的 main 之间唯一的正式通道,就是你自己执行的 merge 或 rebase——Git 从不自动替你合并任何东西。

本节要点回顾

  • remote 是地址簿:昵称加可选的双地址,多远端支撑 Fork 工作流。
  • fetch 零风险:只下行对象、只更新远程跟踪引用,现场纹丝不动。
  • pull 有取舍:建议团队统一 rebase 模式或干脆显式两步。
  • push 是请求:非快进与保护分支是两类常规拒绝,规范应答是 fetch 加 rebase 再推。
  • 强推有护栏:force-with-lease 应成为肌肉记忆。

下一节把 origin/main 这个概念拆到底——三层分支命名与跟踪关系。


作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U