外观
07 · 远程同步
远程是别人能看见的那份历史。fetch 只更新你的「望远镜」,push 才改服务器。大多数「把远程搞坏了必须重拉项目」都发生在这一章。
git fetch
作用: 从远程把新提交、新分支、新标签下载下来,更新 origin/* 这些远程跟踪分支。
改动范围: 仅远程跟踪分支。不动当前工作区,不移动你的 main。
典型场景: 先看看远程发生了什么,再决定 merge 还是 rebase;CI 合了 PR 之后更新本地望远镜;清理已经在远程删掉的分支缓存。
常用写法:
bash
git fetch origin
git fetch --all
git fetch --prune # 远程已删的分支,本地 origin/xxx 也删掉
git fetch origin pull/123/head:pr-123 # 有的托管平台可这样取 PR看远程比我多了什么:
bash
git log --oneline HEAD..origin/main
git diff HEAD...origin/main不要这样用: 把 fetch 和 pull 当成一回事,以为 fetch 之后工作区代码会变。
做错了怎么办: fetch 几乎无害。prune 多删了跟踪分支,再 fetch 一次即可(远程还在的话)。
git pull
作用: fetch + 把远程跟踪分支合进当前分支。默认是 merge;若配置了 pull.rebase=true 则是 rebase。
改动范围: 远程跟踪分支 + 本地当前分支(可能产生合并提交或改写本地未推送提交)。
典型场景: 自己的功能分支或刚 switch 到 main,要把远程已有更新拿进来。
常用写法:
bash
git pull
git pull --ff-only # 只能快进,否则失败(适合更新 main)
git pull --rebase
git pull origin main更稳妥、可拆开决策的写法:
bash
git fetch origin
git log --oneline --graph HEAD...origin/main
git rebase origin/main # 或 git merge origin/main不要这样用:
- 本地有未提交改动时盲目 pull(先 commit 或 stash)。
- 在已经分叉的
main上pull出一堆只有你自己懂的合并提交。用--ff-only,失败再想为什么本地main会分叉。 - 把
pull --rebase用在别人也在写的共享分支上,等于改写已推送历史。
做错了怎么办:
- 合并冲突:
git merge --abort或git rebase --abort(看status提示你在哪种状态)。 - pull 产生了不想要的合并提交且未再 push:
git reset --hard ORIG_HEAD。
git push
作用: 把本地提交上传到远程,并更新远程分支指针。
改动范围: 远程。 本地不动。
典型场景: 功能分支第一次上台;日常同步;PR 更新。
常用写法:
bash
git push -u origin HEAD # 推当前分支并建立跟踪
git push
git push origin main
git push origin --delete feature/login
git push origin v1.2.0 # 推一个标签,见第 10 章rejected (non-fast-forward) 表示远程有你没有的提交。这是保护,不是故障:
bash
git fetch origin
git log --oneline --graph HEAD...origin/main
# 然后 merge 或 rebase,再普通 push不要这样用: 看到 rejected 就 --force。那会丢掉远程上你还没拿回来的提交。
git push --force-with-lease(相对安全的强制推送)
作用: 仅当远程分支仍是你上次 fetch 见到的那个尖端时,才允许非快进更新。
改动范围: 远程历史改写。
典型场景: 你独享的 feature/login 上做了 rebase / amend,需要更新 PR。
bash
git fetch origin
git push --force-with-lease origin feature/logingit push --force · 危险
无条件把远程指针挪到你本地。远程上比你新的提交会变成无人引用(托管平台有时还能在网页上找到 SHA,Git 本身不保证)。
不要对 main / master / release/* 使用。很多平台会保护默认分支,直接拒绝。
做错了怎么办: 见 急救手册 · force push 覆盖了别人的提交。预防手段就是永远用 --force-with-lease,并且先 fetch。
跟踪关系断了
git status 说 no upstream:
bash
git push -u origin HEAD
# 或本地已有远程分支:
git branch -u origin/feature/loginahead 2, behind 3:两边都有独有提交,先 fetch,再 rebase 或 merge,再 push。不要 force。
推到了错误的远程或错误的分支
bash
git remote -v
git branch -vv- URL 错了:
git remote set-url origin <正确地址>,再推一次。 - 分支名错了:在正确分支上推,必要时
git push origin --delete 错的分支(确认没人在用)。 - 提交不该公开:按泄露处理(密钥轮换),再考虑是否删除远程分支。历史一旦 push,假设已经被人拉走过。
和托管平台的关系
GitHub / GitLab / Gitee 的「保护分支」会禁止直接 push main,或禁止 force push。这是好事。日常应:
- 在功能分支上开发并 push。
- 开 Pull / Merge Request。
- 审查通过后由平台合并。
- 本地
switch main && git pull --ff-only。
网页上点的 Rebase / Squash merge,会在远程产生新的 SHA。本地旧的功能分支不要再 merge 回 main,直接更新 main 后删本地分支。
上一章:06 · 改写历史 · 下一章:08 · 暂存工作区与多工作树