远程协作实用指南:remote / fetch / pull / push / PR
远程(remote)只是一个有名字的 URL。搞清 fetch 与 pull 的区别、push 被拒时该做什么、fork 之后怎么贴回上游,远程协作就再没有玄学。
最后更新:2026-10-30
三句话理解远程协作
- 远程(remote)只是一个「有名字的 URL」,
origin是默认名字,不是特殊分支。 - 本地分支跟踪远程分支(
origin/main),git status里的 ahead / behind 就是在比这两者。 fetch只把远程更新拉到本地引用,不动工作区;pull=fetch+ 合并(merge 或 rebase)。
下面从 remote 管理讲到 fork 同步与 PR 实践。
管好你的 remote
git remote -v # 看名字与 URL
git remote add upstream https://github.com/orig/repo.git
git remote rename origin old-origin
git remote set-url origin git@github.com:me/repo.git # 切到 SSH
git remote remove upstream
git remote show origin # 看跟踪关系与已过期的分支多远程是常态:fork 协作时 origin 指向你自己的 fork,upstream 指向原仓库。改动前先 git remote -v 确认自己推的是哪个。
fetch / pull / pull --rebase 到底差在哪
| 命令 | 行为 |
|---|---|
| git fetch | 只更新 origin/* 引用,工作区与本地分支不变(最安全) |
| git pull | fetch + merge,会产生一个合并提交,历史出现分叉 |
| git pull --rebase | fetch + rebase,把你的提交挪到远程最新之后,保持线性历史 |
| git pull --ff-only | 只允许快进,无法快进就报错(防止意外的合并提交) |
建议:日常用 git pull --rebase(或配置 pull.rebase=true);不确定时先 git fetch,看清差异再决定合并方式。
push 与跟踪分支
git push -u origin feat/login # 首次推送并建立跟踪关系
git push # 之后直接推
git push origin --delete feat/x # 删除远程分支
git branch -vv # 查看每个分支跟踪谁- 跟踪关系决定
git push/git pull的默认目标,没有跟踪就要每次写明远程与分支 - non-fast-forward 被拒 = 远程有你本地没有的提交;先
pull --rebase再推,别急着--force --force-with-lease比--force安全:远程被别人更新过就会拒绝,不会静默覆盖
fork 之后怎么同步上游
git remote add upstream https://github.com/orig/repo.git
git fetch upstream
git switch main
git rebase upstream/main # 或 git merge upstream/main
git push origin main在自己的功能分支上定期 rebase 上游,能显著减少 PR 冲突。注意:rebase 之后推自己的分支需要 --force-with-lease(只影响你自己的 fork,安全)。
PR / MR 实践
- 小 PR:一个 PR 只做一件事,评审时间与缺陷率都随体积上升
- 描述写清:改了什么、为什么改、怎么验证(截图 / 复现步骤)
- 提交前自查:本地跑测试、
git diff upstream/main...看净变更、清掉调试代码 - 合并方式:Squash merge 保留干净主线;Merge commit 保留完整分支历史;Rebase merge 线性但改写 SHA
- 合并后删分支:远程与本地都删,避免僵尸分支
常见坑
- force push 覆盖队友:共享分支禁用
--force;必须用时改用--force-with-lease并提前通知 - push 被拒就直接 force:先
git log origin/main..main看清是谁的提交 - 在 detached HEAD 上提交:提交不在任何分支上,切走就像「丢了」;用
git switch -c fix接住 - pull 产生一堆 merge commit:配
pull.rebase=true,或统一用git pull --rebase - 误删远程分支:在 reflog 里找到 sha,用
git push origin <sha>:refs/heads/<branch>恢复
常见问题
git fetch 和 git pull 到底差在哪?
fetch 只下载远程更新到 origin/* 引用,不改你的工作区和本地分支;pull 等于 fetch + 合并(默认 merge,可配 rebase)。想先看清再决定,就先 fetch,再用 git log HEAD..origin/main 看差异。
为什么 git push 被拒绝(non-fast-forward)?
远程分支上有你本地没有的提交,直接推会覆盖别人的工作,Git 因此拒绝。正确做法是先 git pull --rebase 把自己的提交挪到最新之后,解决冲突后再推;只有确认远程没有需要保留的提交时,才考虑 --force-with-lease。
fork 之后怎么同步上游仓库?
加一个 upstream 远程指向原仓库,git fetch upstream,然后在 main 上 git rebase upstream/main(或 merge),最后 git push origin main。在自己的功能分支上定期 rebase 上游,能大幅减少 PR 冲突。