你收到一封来自“开源厨房”的邀请函:全球各地的大厨们共用一本《招牌菜谱》,谁都能贡献新菜,但不能直接改写总谱——万一弄坏了,全世界分店都会跟着翻车。于是你学会了第一步:开分店。把总谱复印一份带回自己的厨房,在独立实验台上反复试菜;试出满意的作品后,把新菜连同一张推荐卡递回总店,请主厨团队品鉴、评审、收录。这就是开源世界最经典的协作方式——Fork 与 Pull Request(PR)。Fork 不是简单的“复制”,而是你拥有完全自主权的平行厨房;Feature 分支是你的实验台;Rebase 是整理做菜记录的流水账;PR 是那道通往总店的传菜口。整个流程环环相扣:同步、分支、变基、提审、抗冲突、守规矩、多沟通、收尾合并。这篇文章不讲晦涩的 Git 原理,而是带你在“分店到总店”的完整旅程中,掌握这套让百万级开源社区稳定运转的协作密码。
对 AI 从业者而言,Fork 与分支策略是你参与开源项目、向优秀框架贡献代码的“入场券”。掌握它,你提交的每一份 PR 都会被维护者认真对待,你的工程协作能力也能直接迁移到任何团队协作场景。
可视化演示
动态展示Fork仓库同步、Feature分支命名、Rebase线性历史与冲突解决分支清理。
本节配有交互动效(进入视口后自动加载,约 3KB)。
Fork仓库同步
开分店的第一步,不是埋头做菜,而是把总店菜谱完整复印一份,并和总店时刻保持热线联系。放在 Git 世界里,“开分店”这个动作就是 Fork:在 GitHub 上点击一下,上游仓库(Upstream)的完整代码快照便复制到你的个人账户下,成为你可自由改动的平行仓库。
得到了 Fork 副本后,还要把它搬回本地电脑——git clone。此时你眼前出现三个“仓库”:上游总店、你的云端分店、你的本地备菜桌。初学者最常犯的错,是把这三个混为一谈。为此 Git 引入了“远端别名”:默认情况下,clone 下来的仓库把分店地址记作 origin,而总店地址需要你手动加一条热线——git remote add upstream <总店URL>。
有了 upstream 这条热线,日常同步就很机械了:git fetch upstream,让跑腿员把总店最新改动取回本地但先不动你的工作;然后 git merge upstream/main,把新菜谱誊抄到自己的分支上。一条公式概括这三者关系:
记住这套“复印-热线-誊抄”的节奏:先 Fork 保证每个分店互不干扰,再靠 upstream 保持和总店同频。菜谱永远保鲜,分店就不会越做越偏。
- U_upstream(上游仓库)代表总店的官方菜谱库,URL 被记录在
upstream这个别名下,是所有分店同步的源头。 - fetch(拉取)派跑腿小哥把总店新增的提交原封不动取回本地,但只更新远端追踪引用,不自动触碰你的工作区。
- O_origin(个人 Fork 远端)你在云端的平行分店,clone 后默认叫
origin,是你平时推送代码的去处。 - merge(合并)把同步下来的上游更新真正并入本地分支,完成“誊抄新菜谱”这一步。
Feature分支规范
分店内部,不是说随便找口锅就能开火。聪明的主厨会开辟独立的“新菜试验台”,每道实验菜独占一台,绝不和店里的日常出品混在一起。这个试验台,就是 Feature 分支。
Feature 分支唯一的使命是完成某个独立功能。约定俗成的命名格式是 feature/主题-编号,例如 feature/user-login-1024,像给试验台贴标签,一看就知道这盆菜在做什么。它的生存周期很短:从最新 main 上切出,开发完、合并完、立刻删除,绝不让它变成第二个“长期乱炖台”。
更深层的理由是“单一职责原则”:一个分支只解决一个问题,PR、回滚、审查、冲突排查才能精准。如果在一个分支里既加新模型、又改配置、还顺手修了格式,出了问题连回滚范围都说不清。分支名本身也是一份元数据,辅助代码评审人快速判断变更意图。
试验台用后即清、一菜一台,是分店能同时开三十个灶台而不乱套的根基。Feature 分支越规范,后面的 PR 评审和冲突排查就越轻松。
B_k 是第 k 个功能分支,feature 是类型前缀,task-k 是任务标识,括号强调“一灶一菜”的约束。- B_k(第 k 个功能分支)表示仓库中第 k 个并行存在的 Feature 分支,彼此独立、互不干扰。
- 分支类型前缀(feature)规范要求分支名以
feature/开头,标明这是功能研发分支,而不是 hotfix 或 release。 - task-k(任务标识)对应 issue 编号或简短主题词,让分支名自带“做什么事”的信息。
- 括号约束(单一职责)强调一个分支只承载一个任务,成功合并即完成任务使命,立刻清理。
Rebase变基
传菜的第一天,主厨就教你一条厨房铁律:做菜日志必须是一条流水账,是什么顺序就把每步记成一行,不要横生枝节。Git 里让历史保持“流水账”的利器,叫 Rebase(变基)。
Merge 会把两条历史像河流交汇一样保留分叉,虽然真实记录了“这里岔开过”,看多了却像一团毛线。Rebase 则把 feature 分支上的提交“摘下来”,再一个一个重放到主干最新提交之后——仿佛这些提交本来就站在最新主干之上。于是历史变成一条干净的直线。
执行 git rebase main 时实际发生三件事:找分叉点、暂存你的提交、在主线顶端重放。要记住变基的黄金法则:不要 Rebase 一个已经被其他人克隆或基于它的公共分支,否则等于把你的流水账和别人的记账本拆成两本对不上的账。流水账式的历史,让后续每个分店 review、回滚、定位问题都省力得多。
- F(原 Feature 分支)待变基的本地功能分支,包含若干基于旧基线的提交,像一叠旧菜单。
- M_head(主干最新提交)变基的目标基点,通常是 rebase 时 main 分支的 HEAD,表示“最新菜谱版本”。
- Replay(重放)把 F 上的提交逐个取出、以 M_head 为新基底依次重新应用,遇到冲突则暂停等待人工裁决。
- F'(变基后的分支)新分支看起来就像直接长在最新 main 上,历史呈线性,没有分叉毛边。
PR提交流程
新菜在试验台上定型后,分店把它装盘,递到总店的“出菜口”,并附上一张推荐卡:菜名、思路、试吃记录、注意事项。这张推荐卡,就是 Pull Request——你想请求总店“拉取”你的改动。
实际操作分几步:先把 feature 分支推送到你的 Fork 远端(git push origin feature/xxx),让总店能看到你的分支;然后到 GitHub 上发起 PR,选择基分支(上游 main)和比较分支(你的 feature)。这时系统会立刻比较两边的差异,提示哪些文件被改动、能否自动合并。
一份高质量 PR 不只是代码,还需要清晰的描述:为什么要做、怎么实现、如何测试、影响了哪些模块。这些描述相当于推荐卡上的“试吃心得”,直接决定评审人的心情与效率。写完描述后,请至少一位维护者或资深同事 Review,也就是请总店品鉴团试吃。
出菜口是总店唯一认可的入口,把卡片写好、菜装盘精美,总店才有可能收下你的心意。反过来,一张没有描述的 PR,就像一盘没有菜名的菜,评审人连夹筷子的欲望都没有。
- B_push(推送的分支)你的 feature 分支推送到 Fork 远端后,成为 PR 的比较来源,是“菜本身”。
- D_desc(变更描述)PR 标题与正文,解释为什么做、怎么做、影响范围,是评审者的第一印象。
- R_review(评审人)被指定做代码评审的人,拥有批准或请求修改的权利,决定 PR 能否合并。
- 三元组结构一个合格 PR = 清晰分支 + 完整描述 + 明确评审,三者缺一不可。
冲突处理策略
即使分店和总店保持同步,厨房里仍可能发生“撞车”:你在这道菜里放了两勺糖,另一个分店也在这道菜里放了一勺,总店不知道该听谁的。在 Git 里,这就是合并冲突。
冲突的本质是双方修改了同一块区域:同一文件的同一段代码被不同提交以不同方式改动。Git 能自动合并互补的改动,但遇到真正重叠的修改时,它不敢替你决定,只能把两个版本都摆出来喊你拍板。
冲突最常在 rebase 或 merge 执行中爆发。面对冲突无需慌,流程固定:git status 查看冲突文件 → 打开文件找到 <<<<<<< 标记 → 手动保留正确的版本并删除标记 → git add 标记为已解决 → 继续 rebase/merge。冲突解决后必须回归验证,跑一遍相关测试,因为手工合并有可能在逻辑上引入“新菜谱与旧流程不搭”的问题。
撞车不可怕,可怕的是发现撞车后还要硬开,把两套做法糊在一起就上菜。所以遇到冲突先停车,看清楚双方意图再决定去留。频繁 fetch upstream 并 rebase,能让每次冲突的“撞车面积”小到几乎感觉不到。
- Δ_mine(你的改动集合)当前分支相对公共基线修改过的全部区域,相当于你这道菜的改动清单。
- Δ_theirs(他人改动集合)目标分支(如 main 或对方分支)相对同一基线修改过的区域,是另一份改动清单。
- 交集非空(重叠区域)两份清单有重合,Git 无法自动决定取舍,只能把两个版本同时摆出来。
- 冲突结果重合即触发冲突标记,需要人工介入解决,这是 Git 对“不确定”的诚实表达。
分支保护规则
总店不会让任何人直接改写招牌菜谱,再资深的厨师也得走“提交推荐卡→品鉴团通过→后厨统一下笔”的流程。Git 平台把这种约束变成了硬规则:分支保护。
保护规则一般加在 main(或 master)上,最常见的有三条:第一,禁止直接推送,任何改动必须通过 PR 进入;第二,设置评审门槛,比如至少一位 Approved 才算有效审批;第三,CI(持续集成)必须跑通,相当于总店自动先做一轮“食材安全检测”。
分支保护的价值是让“最后一公里”变得可审计、可追溯:谁改的、为什么改、什么时候改、测试是否通过,全部有记录。配合不同的合并类型——Squash(压缩成单提交)、Rebase Merge(保留提交重放)、Merge Commit(保留分叉)——团队可以决定总店菜单的历史呈现方式。
后厨安全规定的本质不是限制自由,而是守护那条所有人赖以吃饭的招牌主干。理解分支保护,你就明白“守规矩”其实是对每位分店厨师负责。
- Review ≥ 1(评审通过)至少一位维护者审阅代码且状态为 Approved,等于总店品鉴团有人举了“同意”牌。
- CI = Pass(测试通过)自动构建与测试全部绿色,相当于食材安全检测过关,不存在“带病上桌”。
- 逻辑与(∧)两个条件必须同时成立,任何一项不满足都无法合并,避免“代码没问题但没人看”或“有人点头但测试挂了”。
- 双向蕴含(⇔)可合并当且仅当两个条件都满足,这是保护规则的核心判定式,给团队注入确定性。
协作沟通机制
厨房墙上的对讲机,从来不只是用来点单——评审人说“这菜偏咸”,你在对讲机里回“已减盐,重新出锅”,一来一回之间,菜品的默契就这么诞生了。在 PR 里,这个对讲机就是评论系统。
现代开源协作里,代码评审是一场围绕 PR 的持续对话。评审人提出 inline 评论(在具体代码行上留言),开发者解释创意、承认问题、修改后再 push 新提交;这些新提交会自动更新到同一个 PR 上,CI 也会自动重新跑一遍。整个过程循环往复,直到所有评论解决、评审通过。
为了保证效率,团队通常会约定:评论尽量具体可执行,不要说空话;开发者每条评论都要回复(哪怕只是说明为何不修改);一个 PR 的评论轮次尽量控制在 3 轮以内,超过则说明需求或拆分方式有问题。
对讲机的价值不在于通话,而在于把争执留在厨房里、把默契送上餐桌。一次彬彬有礼的 PR 对话,往往比代码本身更能建立信任——这在开源社区里就是你的“厨师声望”。
- Review(评审反馈)评审人在 PR 上留言指出问题,循环的起点,信息要具体到能落地执行。
- Fix(修改代码)开发者针对评论修改代码,并补充相应解释,等于“已按建议减盐”。
- Rebase(整理历史)修改后用 rebase 重放提交,使 PR 历史保持线性整洁,方便下一轮评审继读。
- CI 与 Approval(验证与放行)CI 重新跑通,评审人最终批准,循环终止,PR 进入合并队列。
合并落地实践
总店品鉴团举手表决通过,新菜正式写入招牌菜谱。可故事没结束:总店更新了菜单,你分店的菜谱还停在旧版本上;你试验台上的锅也要腾出来给下一位厨师。合并落地,是每个 PR 的真正句号。
合并完成后,第一件事是同步:git pull 拉回最新 main,git push 把你的 Fork 也追平到最新,让分店不再停留在过时快照上。第二件事是清理:git branch -d feature/xxx 删除本地已合并分支,GitHub 上也有 "Delete branch" 按钮删除远端分支,避免试验台堆积成山。
如果合并类型是 Squash,还可以把 feature 分支上十几个“wip(半成品)”小提交压缩成一个语义完整的提交。压缩后主干历史依然一行一事,方便以后用 git bisect 等工具精确定位问题。
从 Fork 开张到合并收尾,分店和总店都恢复整洁而同步的起点——下一道新菜,随时可以从这条新鲜主线上再次出发。养成“合并即同步、同步即清理”的习惯,你的仓库将永远保持一眼能看懂的健康状态。
⊕ 表示“干净追加”,不带分叉毛边。- H_old(合并前主干)main 分支未被合并时的提交序列,是总店当前的完整菜单。
- Squash(B)(压缩后的功能提交)把 feature 分支上多个零散提交压缩成一个语义完整的提交,像把十几条碎笔记整理成一页正式菜谱。
- ⊕(干净追加)新提交落到主干末尾,不产生分叉节点,历史保持单线演进。
- H_new(合并后主干)包含新功能且保持线性整洁的主干状态,后续分支从这里切出永远干净。
AI 应用场景
开源AI框架的模型贡献
阶段:开源协作 / 代码贡献
解决的问题:AI 工程师想给 HuggingFace Transformers、PyTorch 等开源框架加入新模型或新算子,但直接改主仓库风险极高。传统方式是通过邮件私聊维护者,效率低且容易扯皮;用 Fork 与分支策略后,所有变更都透明地走 PR 流程,评审记录和 CI 结果全部留痕,维护者也能安心放行。
具体案例:你为 Transformers 新增一个轻量注意力机制。先在 GitHub 上 Fork 官方仓库,clone 到本地后创建 feature/light-attention-152 分支,开发完成后 rebase 到最新 main,推送并提交 PR。评审人给出“补充消融实验”的评论,你修改后重推,CI 自动跑测试,最终合并。你的模型随下一次版本发布被全世界下载——这正是“分店新菜”被总店收录的全过程。
企业AI平台的多团队协同
阶段:工程落地 / 内部基础平台建设
解决的问题:大企业内部多个算法团队共享一套特征平台代码,过去直接往主干推代码,经常互相踩踏、发布事故频发。引入 Fork 与分支策略后,每个团队维护自己的 Fork,通过受保护分支 + 评审 + CI 的 PR 流程合入,冲突和事故大幅下降。
具体案例:算法 A 组开发新的特征抽取逻辑,算法 B 组并行优化存储引擎。两组各自在 feature 分支上工作,频繁与 upstream 同步;B 组碰了 A 组正在改的文件时,冲突在 rebase 时及时爆发、当场解决,而不是上线前夜才发现。合并后各组同步主干,历史干净可审计。
Python 演示
"""Fork与分支协作流程模拟器模拟两位开发者在开源仓库上的协作:Fork -> Feature分支 -> Rebase -> PR合并。""" class Commit: def __init__(self, cid, message, branch): self.cid = cid self.message = message self.branch = branch class Repository: """简化版仓库:保存所有提交和各分支的提交ID列表""" def __init__(self, name): self.name = name self.commits_map = {} self.branch_ids = {"main": []} def add_commit(self, cid, message, branch): commit = Commit(cid, message, branch) self.commits_map[cid] = commit self.branch_ids.setdefault(branch, []).append(cid) return commit def sync_fork(fork_repo, upstream_repo): """模拟 git fetch upstream && git rebase upstream/main""" fork_repo.branch_ids["main"] = upstream_repo.branch_ids["main"][:] for cid in upstream_repo.commits_map: fork_repo.commits_map[cid] = upstream_repo.commits_map[cid] def make_pr(developer_name, fork_repo, feature_branch): """模拟提交PR:把feature分支的提交并入main""" feature_ids = fork_repo.branch_ids.get(feature_branch, []) fork_repo.branch_ids["main"].extend(feature_ids) fork_repo.branch_ids.pop(feature_branch, None) return f"PR from {developer_name}: {len(feature_ids)} commits merged" def main(): upstream = Repository("total/main") upstream.add_commit(1, "init repo", "main") alice_fork = Repository("alice/fork") sync_fork(alice_fork, upstream) alice_fork.add_commit(2, "feat: add tokenizer", "feature/tokenizer") alice_fork.add_commit(3, "feat: add model config", "feature/tokenizer") # 上游在此期间新增了一个修复 upstream.add_commit(4, "fix: typo in readme", "main") # Alice Rebase 到最新 main,然后发 PR 合并 sync_fork(alice_fork, upstream) alice_ids = alice_fork.branch_ids["feature/tokenizer"] alice_fork.branch_ids["feature/tokenizer"] = alice_fork.branch_ids["main"][:] + alice_ids print(make_pr("Alice", alice_fork, "feature/tokenizer")) # 合并回上游主干 upstream.branch_ids["main"] = alice_fork.branch_ids["main"][:] print("upstream main:", upstream.branch_ids["main"]) for cid in upstream.branch_ids["main"]: c = upstream.commits_map[cid] print(f" commit {c.cid}: {c.message} [{c.branch}]") if __name__ == "__main__": main()
upstream.add_commit(1, "init repo", "main")总店菜谱库的起点,相当于定下第一版招牌菜谱。sync_fork(alice_fork, upstream)模拟git fetch upstream加git rebase upstream/main,把上游最新改动同步进 Fork。alice_fork.add_commit(2, "feat: add tokenizer", "feature/tokenizer")Alice 在专属试验台上开发新功能,提交记录在 feature 分支。alice_fork.branch_ids["feature/tokenizer"] = alice_fork.branch_ids["main"][:] + alice_ids模拟 Rebase:把 feature 提交整体重放到最新 main 之后,形成线性历史。make_pr("Alice", alice_fork, "feature/tokenizer")模拟 PR 合并:feature 分支的提交被并入主干,分支使命完成并移除。upstream.branch_ids["main"] = alice_fork.branch_ids["main"][:]总店正式收录新菜,上游主干前进到 Alice 合并后的状态。for cid in upstream.branch_ids["main"]遍历并打印主干提交,验证历史是否保持整洁线性。
常见误区
误区“反正我有 Fork,直接在 main 上开发完再发 PR 不就行了吗?何必多开一个分支,步骤又多又麻烦。”
正解main 是受保护的主干,直接在上面开发会让所有改动物理上纠缠在一起,无法独立评审、无法并行、无法按功能回滚。正确做法是每个任务开一个 feature 分支,就像每道新菜独占一个试验台。即使你只是修一个 typo,也应该走“切分支 → 改 → 合并 → 删分支”的完整循环,而不是图省事往主干上堆。
为何常见:很多新手是从单人项目过来的,单人仓库里直接 commit 到 master 完全没压力,于是把这种习惯带到了多人协作场景,直到第一次被分支保护规则挡住才意识到问题。
误区“rebase 是不是把我的提交都丢了?看到操作提示里的 dropping 字样直接吓退,再也不敢用。”
正解Rebase 是“重放”而不是“删除”。它把你的提交从旧基点上摘下来,再逐个应用到新基点上;原来的提交对象被新提交替代,但变更内容一行不少。真正的危险只发生在对“已公开共享的分支”做 rebase 时——别人基于旧提交工作,你重写后两条历史对不上,才会造成重复提交和二次冲突。
为何常见:把 rebase 和 git reset --hard、git clean 等破坏性操作混为一谈,加上终端里"drop"这样的英文单词容易引发恐慌,一遇到就本能地抗拒。
误区“只要在合并前统一处理一次冲突就够了,平时频繁从 upstream 拉更新是在浪费时间。”
正解恰恰相反,越晚同步,冲突面积越大、定位越难。一次集中的大冲突可能涉及十几个文件,你根本记不清每个文件当时为什么这么写;而频繁 fetch upstream 并 rebase,每次只引入少量新提交,冲突面小且可逐步消化。就像分店应该每天跟总店对一次菜谱,而不是攒一年才对账。
为何常见:人们本能地害怕打断手头工作,觉得同步会带来“额外负担”,却没算清集中解决大冲突的时间成本远高于日常小同步。
误区“反正 PR 已经合并了,我的 Fork 和本地分支留在原地也不碍事,等下次要改再说。”
正解合并后不清洗,下次开发时你会从一个过时基点重新起步,很快又产生大量伪冲突。正确姿势是合并后立刻 git pull 同步本地 main、git push 同步 Fork 远端、删除已合并的 feature 分支(本地和远端都删)。让分店始终保持与总店同一版本,下一道菜才能在最新鲜的主线上开火。
为何常见:清理属于“看不见的收益”,人们很难感知旧分支带来的隐形成本,直到某一天仓库里堆着上百个无人认领的分支时才追悔莫及。
误区“我辛辛苦苦提交了 20 次,squash 一下全变成 1 次,我的工作量是不是就没了?”
正解合并的是“提交粒度”而不是“工作量”。“模型实验 v1、v2、v3、改格式、修 typo”这一串碎提交对后续读者毫无价值,压缩成一个“实现轻量注意力机制”的完整提交反而更清晰。若要保留细粒度历史,团队可以选择 Rebase Merge;但把“提交数量”等同于“贡献大小”,是把手段当成了目的。
为何常见:刚学 Git 的人会在意提交数量,觉得那是自己的“工作脚印”。实际上,对维护者来说,一条干净、语义完整的历史才是真正的贡献。
面试题
Q1. 在 Fork 工作流中,"upstream"这个远端通常指向
- A.自己账户的 Fork 仓库
- B.原作者的官方仓库← 正确答案
- C.本地克隆的工作仓库
- D.公司内部的代码镜像
答案:B。upstream 在 Fork 工作流中专指“总店”——你 Fork 的那个原始官方仓库。origin 才指向你自己的 Fork,local 是本地工作区。开分店时,总店菜谱的地址就是 upstream,必须手动添加并持续从它拉取更新。
Q2. 下列哪项是规范的 Feature 分支命名
- A.主干分支 main 原名
- B.feat/order-123← 正确答案
- C.临时测试 test 名
- D.备份分支 backup 名
答案:B。Feature 分支推荐用 feature/xxx 或 feat/xxx 加任务编号/主题命名,像试验台标签一样一眼看出在做什么。main、test、backup 这类名字要么是保护分支,要么语义含糊,无法承载“这一个分支只做一件事”的约束。
Q3. 执行 git rebase main 后,feature 分支发生了什么
- A.将 main 并入 feature 保留分叉提交
- B.将 feature 重放到 main 形成线性历史← 正确答案
- C.彻底删除 feature 的所有历史提交
- D.仅更新 main 分支的云端引用
答案:B。Rebase 是把 feature 的提交“摘下来”再逐个重放到 main 最新提交之后,像把散落在外的买菜单据重新按时间整理进总账,历史变成单线。它不会删除提交内容,只是换了一个基底;更不会更新云端。
Q4. 分支保护规则下,main 分支通常不允许
- A.发起合并代码的 PR 请求
- B.绕过评审直接推送代码← 正确答案
- C.在 PR 下方发表评论
- D.查看分支提交历史
答案:B。分支保护的核心是禁止直推主干,所有改动必须走 PR + 评审 + CI 的流程,相当于总店菜谱不能被人随手改写。发起 PR、评论、查看历史都是正常操作,不受保护规则限制。
Q5. 下列哪些情况会导致合并冲突
- A.两人改了同一文件同一区域← 正确答案
- B.一人删除文件一人修改它← 正确答案
- C.两人各自添加不同的新文件
- D.两人修改完全不同的文件
答案:AB。冲突的本质是改动集合存在交集。同区域修改和“删除 vs 修改”都构成重叠,Git 无法自动取舍;而添加不同新文件、修改不同文件属于互补改动,Git 能轻松自动合并,就像两个厨房一个添新锅一个换新勺,互不干扰。
Q6. git fetch upstream 与 git pull 的本质区别是
- A.fetch 仅更新远端追踪引用不自动合并← 正确答案
- B.pull 不会触发任何网络请求
- C.fetch 会删除本地全部提交
- D.pull 无需配置任何远程
答案:A。fetch 只把总店新改动取回本地(更新远端追踪引用),完全不动你的工作区,像跑腿小哥把新菜谱放到门口先不进门;pull 等于 fetch + merge,会直接把改动合并进当前分支。一般新手同步上游建议先 fetch 看清楚再决定怎么合,避免被动接受一堆改动。
Q7. 某同事把已经推送到共享 Fork 的 feature 分支执行了 rebase,最可能的后果是
- A.远端分支会自动同步新历史
- B.其他人基于旧基线工作会再次冲突← 正确答案
- C.分支保护规则自动失效
- D.CI 测试会自动跳过变更
答案:B。这正是“变基黄金法则”禁止的事——rebase 已公开的分支会重写提交哈希。别人的本地分支仍基于旧提交,当他们再推或合并时,新旧两套提交会同时存在,造成重复提交和二次冲突。远端不会自动同步,保护规则与 CI 正常运行,说明“公共分支只追加、不重写”是铁律。
Q8. 下列场景中,适合用 Squash 合并的是
- A.功能分支包含多个临时小提交← 正确答案
- B.希望保留每个精细提交痕迹
- C.团队偏好干净简洁的主干历史← 正确答案
- D.需要审计每一步中间过程
答案:AC。Squash 把一组碎提交压缩成一个语义完整的提交,适合“多个 wip 小提交 + 团队追求主干整洁”的场景。如果团队或法规需要审计每个中间步骤、保留精细历史,则要用 Rebase Merge 或普通 Merge Commit。选型没有绝对对错,取决于总店菜单想以什么形态呈现。
Q9. 解决冲突后执行 git rebase --continue,会发生什么
- A.直接推送 PR 到远端分支
- B.继续应用后续剩余提交← 正确答案
- C.放弃所有未提交的本地修改
- D.重置当前分支到最新 main
答案:B。rebase 是逐提交重放,遇到冲突会暂停在“当前提交”上。你解决冲突并 git add 后,--continue 表示“这盘菜我处理好了,继续做下一道”,把剩余提交依次重放完。它不会推送远端,也不会丢弃未提交修改,更不会重置分支。
Q10. 发起 PR 前,下列哪些检查是必要的
- A.分支已 rebase 到最新 main← 正确答案
- B.本地与 CI 测试均已通过← 正确答案
- C.写清楚变更目的与影响范围← 正确答案
- D.删除本地全部历史遗留分支
答案:ABC。一次合格的 PR 必须在最新基线上提交(rebase),必须有测试通过作为质量兜底,必须用描述告诉评审人“为什么改、怎么改、影响什么”。删除历史遗留分支是合并完成之后的清理动作,与“发起 PR 之前”无关,提前删反而可能误伤未完成的工作。