这一篇在干嘛?
一个人用 Git 不难,难的是多人协作。这一篇讲清楚协作时最烧脑的两个概念——远程分支(
origin/main到底是啥)和变基(rebase),以及那条著名的黄金法则。对应《Pro Git》第 3 章后半部分。
远程分支:远程仓库状态的「本地书签」
克隆仓库后,你的本地其实有两套分支:
- 本地分支:
main等,你直接在上面干活、移动它。 - 远程跟踪分支:形如
origin/main,是上次与远程同步时远程 main 所指位置的本地书签。你不能直接移动它,只有git fetch/git push时由 Git 更新。
远程仓库: main ──▶ C4
你的本地: origin/main ──▶ C4(书签)
main ──▶ C3(你本地落后一步)git fetch origin 会更新所有 origin/* 书签到远程的最新状态。此后 origin/main 才真正反映远程现状。
查看完整分支图景
git branch -a列出本地与远程跟踪分支;git log --oneline --graph --all直观看两边的分叉。
跟踪分支:让 push/pull 少打字
新建本地分支推上去时,加 -u 建立关联(tracking):
git checkout -b feature-login
git push -u origin feature-login之后这个分支上的 git push、git pull 不用再写 origin 和分支名,Git 自动知道推到哪、从哪拉。
删除远程分支(分支的活干完了):
git push origin --delete feature-login这只是删掉远程的指针,本地对应分支要单独删。
变基(rebase):另一种整合方式
整合两个分叉分支有两条路:merge 和 rebase。
merge 把两边快照合在一起生成合并提交;rebase 则是把你分支上的提交逐个「摘下来」,重放到目标分支最新提交之上,看起来就像你从一开始就是基于最新代码开发的。
git checkout feature
git rebase main # 把 feature 的提交重放到 main 之上
git checkout main
git merge feature # 变基后合并必然是快进,历史变成一条直线变基的收益:提交历史干净、呈线性——尤其适合给别人的项目提交代码前,先把自己的工作整理到最新基底上。
更顺手的写法
git rebase main feature一条命令完成「切到 feature 再变基」,省两次 checkout。
黄金法则:不要对公开的提交变基
变基的实质是丢弃旧提交、创建内容相同但哈希不同的新提交。如果这些旧提交已经推送到远程、且别人已经基于它们开发了,你变基后强推,对方的仓库会凭空多出一堆「幽灵重复提交」,场面极度混乱。
黄金法则(背下来)
只对尚未推送、或确认没有别人基于其开发的本地提交执行变基。已推送到公共仓库的提交,一律只用 merge。
一句话判断:提交离开过你的电脑吗?离开了就别 rebase 它。
如果团队真的有人强推了变基历史,你拉取后用 git pull --rebase 而不是普通 pull,Git 靠 patch-id 能识别出「内容相同的重复提交」并只保留一份,把伤害降到最低。
merge 还是 rebase?
两种哲学没有标准答案:
- 历史是实际发生过的事实 → 用 merge,保留真实的并行与合并痕迹。
- 历史是讲给后来人听的故事 → 用 rebase,整理成干净的直线。
实用主义结论:自己的私有分支随便 rebase 整理,公共分支一律 merge,两种好处都拿到。
小结
origin/main是远程状态的本地书签,fetch负责更新它。push -u建立跟踪关系,之后 push/pull 免参数。- rebase = 把自己的提交重放到新基底上,得到线性历史。
- 黄金法则:公开提交不 rebase;私有提交随意 rebase。
- push 被拒的标准动作:先 pull(或 pull —rebase)再 push。
学完你会得到:
- 「书签」模型让 origin/* 不再神秘
- 跟踪分支省掉一半协作命令
- 一条能避免团队事故的黄金法则
自测
自测
origin/main存在于远程服务器上还是你的本地仓库里?谁能移动它?git fetch之后你的main会自动前进吗?和git pull的区别在哪?- 为什么变基后的提交哈希和原来的不一样?
- 同事对公共分支强推了变基历史,你本地出现重复提交,怎么处理最合适?
- 写出「新建分支、推送并建立跟踪」的完整命令。