跳到正文
返回博客列表

博客文章

什么是PR:从一次分支合并到发布流程讲清楚

2026-04-23

目录

    1. 这篇文章想讲什么

    今天我第一次完整走了一遍比较标准的 GitHub 协作流程:

    • 把一个历史分支重新命名成更清晰的功能分支
    • 从功能分支发起 PR
    • 处理 Cloudflare Pages 的构建失败
    • 等检查通过后,再把代码合并进 master

    这一套流程做完之后,我发现很多人第一次接触 PR 时,真正困惑的通常不是“按钮在哪里”,而是三个更底层的问题:

    • PR 到底是什么
    • 为什么不能直接把代码推到 master
    • PR 在原理上到底做了什么

    所以这篇文章不只记录操作步骤,更想把背后的逻辑讲清楚。


    2. 什么是 PR

    PRPull Request,在 GitHub 里,它的意思可以直接理解成:

    我在一个分支上完成了一组改动,现在正式请求把这些改动合并到另一个分支。

    比如这次我的流程里,源分支是:

    feature/runtime-mobile-performance

    目标分支是:

    master

    那么这次 PR 的含义就是:

    我请求把 feature/runtime-mobile-performance 里的改动,合并到 master

    注意,PR 不是“把代码上传到 GitHub”。

    代码在 git push 的时候就已经上传了。

    PR 做的是另一件事:

    把“上传的代码”变成“等待审核和合并的改动提案”。

    也就是说,push 解决的是“代码到了远端没有”,PR 解决的是“这组代码要不要进主分支,以及怎么进”。


    3. 为什么要做 PR,而不是直接改 master

    如果只是自己写一个很小的项目,直接在 master 上提交并不是技术上不可以。
    但只要项目开始进入“持续维护”和“持续发布”的状态,PR 的价值就会迅速变大。

    最核心的原因有四个。

    3.1 PR 让改动有边界

    一个功能、一组修复、一次重构,都应该有比较清晰的改动范围。

    比如这次分支名从 optimization 改成 feature/runtime-mobile-performance,本质上就是在表达:

    这个分支负责的是“运行时重构 + 移动端性能优化”这一组工作,而不是一些模糊的杂项修改。

    当改动是有边界的,后续代码审查、回滚、问题定位都会简单很多。

    3.2 PR 让合并动作变成可审查事件

    没有 PR 的情况下,改动会直接进入 master

    有了 PR 之后,合并之前会先出现一个明确的检查窗口:

    • 这次改了什么
    • 改动文件有哪些
    • 检查是否通过
    • 有没有明显风险

    就算是单人开发,这个窗口也有价值。因为它把“写代码”和“决定上线”拆成了两个动作。

    3.3 PR 让自动化检查有落点

    这次最直观的例子就是 Cloudflare Pages。

    我在本地构建是通过的,但 PR 检查里,Cloudflare 一开始失败了。失败的原因不是页面逻辑本身,而是:

    package.jsonpackage-lock.json 不同步,导致 Cloudflare 在干净环境里执行 npm ci 时报错。

    如果没有 PR,这个问题很可能会等到代码已经进入 master 之后才暴露。
    但因为有 PR,问题被提前拦在了合并前。

    3.4 PR 让发布分支保持稳定

    今天最终定下来的策略是:

    • 日常开发放在 feature/* 分支
    • 合并后进入 master
    • Cloudflare 以 master 作为生产发布分支

    这个策略的重点不是“多开一个分支”,而是:

    只有经过检查并完成合并的代码,才进入生产发布链路。

    这比“所有开发都直接堆进 master”更稳。


    4. PR 的原理到底是什么

    很多人第一次用 PR,会误以为 PR 是 GitHub 特有的“魔法操作”。

    其实不是。

    PR 的底层建立在 Git 原本就有的两件事上:

    • 分支
    • 提交差异比较

    GitHub 只是把这两件事做成了一个可视化工作流。

    4.1 分支本质上是提交历史的指针

    在 Git 里,一个分支名,本质上只是“指向某个提交”的引用。

    比如:

    • master 指向线上稳定代码所在的提交
    • feature/runtime-mobile-performance 指向功能开发中的最新提交

    当这两个分支各自继续提交时,它们就会沿着不同的提交链向前移动。

    PR 做的第一件事,就是把这两条提交链拿出来比较。

    4.2 PR 比较的是“源分支相对目标分支多出来的提交和文件改动”

    当我在 GitHub 上选择:

    • base: master
    • compare: feature/runtime-mobile-performance

    GitHub 实际上是在问:

    相比 masterfeature/runtime-mobile-performance 多了哪些提交,最终会带来哪些文件差异?

    这些差异会被展示成:

    • commit 列表
    • file diff
    • 可否自动合并
    • 是否存在冲突

    所以 PR 页面本质上是一份“合并影响报告”。

    4.3 “Able to merge” 的意思是什么

    PR 页面里显示 Able to merge,并不表示“代码一定没问题”。

    它只表示一件事:

    Git 能自动把这两个分支的文本改动合并起来,没有出现需要人工处理的冲突。

    它解决的是“能不能合”,不是“应不应该合”。

    是否应该合,还要看:

    • 自动化检查是否通过
    • 改动是否符合预期
    • 发布风险是否可接受

    4.4 检查通过后,合并本质上是在更新目标分支指针

    当 PR 被 merge 之后,结果并不是 GitHub 把文件一行一行“搬过去”。
    更准确地说,是:

    GitHub 根据你选择的合并策略,生成新的提交关系,然后把 master 指向新的提交。

    如果用的是 Squash and merge,它会把源分支上的一组提交压成一个新的提交,再把这个新提交放进 master

    这样做的好处是,master 的历史会更干净。

    尤其是功能分支上有很多临时提交时,压缩后更适合作为长期维护的主历史。


    5. 结合今天这次操作,PR 实际是怎么落地的

    今天这次流程,大致是这样:

    5.1 先把原分支改成更清晰的名字

    原来的分支叫 optimization

    这个名字的问题是太泛,别人以后看到时很难知道它到底改了什么。

    所以先把它改成:

    feature/runtime-mobile-performance

    这样分支名本身就带上了改动边界。

    5.2 把 origin/master 合进功能分支

    这一步的目的,不是把功能分支提前合并掉,而是:

    先把目标分支的最新内容同步到当前分支,尽量在发 PR 前解决潜在冲突。

    这样 PR 页面的 diff 会更干净,后面合并也更稳。

    5.3 推送分支,创建 PR

    推送之后,GitHub 就可以基于这两个分支生成比较页面。

    这时 PR 正式成立,但还没有完成合并。

    5.4 让自动化检查先跑完

    这次 Cloudflare Pages 一开始失败了。
    从日志里定位下来,问题不是 Astro 页面构建逻辑,而是:

    • Cloudflare 使用 npm ci
    • npm ci 依赖严格一致的 lockfile
    • 当前 lockfile 不完整,导致依赖解析失败

    也就是说,这次 PR 发挥的作用不是“展示按钮”,而是提前暴露了发布链路里的真实问题。

    5.5 修复检查,再合并

    等 Cloudflare 检查变绿之后,PR 才真正进入可合并状态。

    这时再执行 Squash and merge,逻辑就完整了:

    • 功能在分支里开发
    • 风险在 PR 里暴露
    • 发布前检查通过
    • 通过后再进入 master

    这就是一个规范的工程闭环。


    6. PR 和发布流程是什么关系

    很多人把 PR 理解成“代码协作工具”,这是对的,但还不够完整。

    从工程角度看,PR 更重要的作用是:

    把开发分支和发布分支之间,插入一道明确的质量闸门。

    在今天这个项目里,这道闸门前面是:

    • feature/runtime-mobile-performance

    这道闸门后面是:

    • master
    • Cloudflare 生产部署

    也就是说,PR 不只是“方便看 diff”,它还是开发流和发布流之间的连接器。

    如果没有 PR,这两者之间就几乎是直通的。
    一旦有了 PR,部署系统、构建系统、代码审查系统,就都能挂在这里一起起作用。


    7. 我现在对 PR 的理解

    做完今天这一整套之后,我觉得 PR 最准确的理解不是“GitHub 上的一个页面”,而是:

    一次正式的合并申请,一份改动影响报告,以及一道进入发布分支前的检查门。

    它把原本混在一起的几件事拆开了:

    • 开发,在功能分支里进行
    • 比较,在 PR 页面里完成
    • 检查,在自动化系统里执行
    • 合并,在确认无误后发生
    • 发布,在目标分支更新后触发

    这也是为什么 PR 会成为现代软件工程里非常常见、非常稳定的一种实践。

    它不是为了把流程变复杂,而是为了让复杂性有地方被看见、有地方被拦住。


    8. 结语

    如果只从表面上看,PR 似乎只是 GitHub 上一个绿色按钮前后多出来的一层页面。
    但只要真正走过一遍,就会发现它解决的是工程里非常核心的问题:

    • 改动如何被清晰表达
    • 风险如何在合并前暴露
    • 代码如何以更稳定的方式进入发布链路

    今天这次操作,本质上不是“学会了怎么点 PR 按钮”,而是第一次把分支开发、自动化检查、合并策略和生产发布这几件事连成了一条完整链路。

    这比单纯记住几个 Git 命令更重要。