首页
/ PHP 源码发行完整流程解析:分支模型、版本号文件、makedist 打包签名与发布公告

PHP 源码发行完整流程解析:分支模型、版本号文件、makedist 打包签名与发布公告

2026-09-05 14:38:35作者:董灵辛Dennis

本文基于 PHP 源码仓库(php-src)中官方维护的发行流程文档 docs/release-process.md 撰写,系统讲解发布经理(Release Manager, RM)如何将规范仓库中的代码按节奏打包成可分发的发布版本:从发布日历与分支模型,到修改版本号、GPG 签名、生成三格式 tarball,再到更新官网仓库与邮件公告的完整操作链。读完本文,你将理解 PHP 每次 alpha/beta/RC/GA 版本背后完整的工程化流程,并能对照仓库中的 打包脚本校验脚本 验证其中每一步的实际行为。

一、发布节奏:GA 日、20 周预发布周期与 RC 制度

PHP 项目的版本发布遵循固定日历:

  • GA(General Availability,正式发布):每个主/次版本(major/minor)的 GA 版本在每年 11 月第四个星期四 发布。
  • 补丁版本:GA 之后每 4 周 发布一个补丁级别版本,且每个补丁版本发布前 两周 至少发布一个 RC(Release Candidate)。
  • 预发布周期:每个主/次版本在 GA 前经历 20 周 的预发布周期,通常从 7 月第二个星期四的第一个 alpha 开始(从 GA 日期倒推)。该周期至少包含:
    • 3 个 alpha 版本
    • 3 个 beta 版本
    • 4 个 release candidate(自 PHP 8.4 起,X.Y.0 的 RC 固定为 4 个,不再是最初文档时代的 6 个)

术语约定:alpha、beta、RC 统称 non-stable(非稳定版) 发布,GA 为 stable(稳定版) 发布。两个非稳定阶段(GA 前的预发布阶段,与 GA 后的补丁 RC)的打包步骤略有差异,流程文档在各步骤中明确标注了差异点。

二、Git 分支模型:四级分支与 -dev 版本号铁律

理解 PHP 发布流程的关键是分支层级。从流程文档可以归纳出四级分支结构:

分支 示例 生命周期 是否推送到远端
主干分支 master 永远指向下一个主/次版本
版本分支(version branch) PHP-8.2 该主/次版本的整个维护期
补丁级版本分支(patch-level) PHP-8.2.8 从版本分支切出,承载该补丁版本 RC/GA 前的关键修复
本地发布分支(release branch) php-8.2.8RC1-local-release-branch 仅用于打 tag 与改版本号 仅本地,严禁推送

版本号规则是这套模型的核心不变式:只有发布 tag 上的版本号不带 -dev 后缀master、所有版本分支与补丁级分支上的版本号永远以 -dev 结尾。在当前仓库中可以直接验证这一规则:

三个文件必须保持一致,这也正是发布流程中"bump 版本号"步骤要同时修改这三个文件的原因。

三、发布纪律:文档总结的 12 条通用守则

流程文档在开头给出了 12 条贯穿所有发布的通用守则,这些是踩过坑之后的经验结晶,值得逐条保留:

  1. 不要在周五、周六、周日发布——这会让遵循标准工作周的下游用户没有处理时间。惯例是尽量在星期四发布。
  2. 提前两天打包:如果星期四发布,就星期二打包(打包日)。同时要留意时区。
  3. 确认 CI 全绿。建议在打包日前几天检查构建状态,为排查失败、与作者沟通、提交修复留出时间。
  4. 严格逐步执行。拿不准时先问上一任 RM;涉及官网仓库(web-phpweb-php-distributions)的步骤时,最好有 webmaster 团队成员在场。
  5. 核验 tag,确保所有 tag 正确打上。
  6. 存在专门的 PHP release Docker 镜像可辅助发布工作(流程文档指向了 sgolemon 的 php-release 镜像及其 fork)。
  7. 发布经理之间通过 release-managers@php.net 邮件组沟通。
  8. 文档中提到的"仓库"均指规范源仓库(php 组织下的 php-src 等)。
  9. 把远端命名为 origin 以外的名字,避免凭肌肉记忆误推送。
  10. 建议在全局 ~/.gitconfig 中配置 conditional includes,为本地 PHP 仓库单独设置正确的 user.nameuser.emailuser.signingKey
  11. 占位符 php-X.Y.ZRCn 中的 RCn 不一定是 RC 编号,也可能是 php-8.4.0alpha1php-8.4.0beta2php-8.4.0(首个 GA)、php-8.4.9(周期性 bugfix 或安全版本)等任意发布形态。
  12. 熟悉并遵守"向上合并(merging upwards)"规程:修复先进入最低分支,再逐级合并到 master

四、打包一个非稳定版发布(alpha/beta/RC)

4.1 完整操作步骤

非稳定版发布的打包流程共 17 步(原文档步骤编号有跳跃,此处按顺序整理):

  1. 确认 CI 通过(见上文守则 3)。

  2. 运行 credits 脚本:在 php-src 中执行 ./scripts/dev/credits,并提交对 ext/standard 下 credits 文件的改动。该脚本从各 ext/*/CREDITSsapi/*/CREDITS 文件重新生成 ext/standard/credits_ext.hext/standard/credits_sapi.h(见 scripts/dev/credits)。很少产生实际改动,git diff 为空时无需担心。

  3. 从版本分支切出本地发布分支,这里预发布前后做法不同:

    • GA 前(pre-GA):alpha/beta 阶段没有版本分支,以 master 充当版本分支,仅本地建分支、不推送

      git checkout -b php-X.Y.0alpha1-local-release-branch upstream/master
      

      首个 RC 时要创建(并推送)正式版本分支(如 PHP-8.2,见下文"分支切分"一节)。最后一个 RC 及 GA 走 GA 后流程;在那之前,RC 的本地发布分支都从该版本分支切出,同样不推送

      git checkout -b php-X.Y.0RC3-local-release-branch upstream/PHP-X.Y
      

      注意:GA(PHP X.Y.0)的补丁级版本分支是在最后一个计划内 RC(当前为 RC4)发布时创建的。GA 后若 PHP X.Y 分支再收到修复,不会进入已定型的 X.Y.0;若回归问题值得纳入 X.Y.0,则按普通补丁流程先合并到 PHP X.Y,再 cherry-pick 到 X.Y.0 分支。

    • GA 后(post-GA):随每个非稳定 RC 创建(并推送)新的补丁级版本分支。例如构建 PHP 8.2.8RC1 时,从 PHP-8.2 切出 PHP-8.2.8 并推送,该分支用于在 GA 前提交关键 bug/安全修复:

      git checkout -b PHP-X.Y.Z upstream/PHP-X.Y
      git push upstream PHP-X.Y.Z
      

      再从中切出仅本地的发布分支(不推送):

      git checkout -b php-X.Y.ZRC1-local-release-branch upstream/PHP-X.Y.Z
      
  4. 修改版本号。在本地发布分支中更新 main/php_version.hZend/zend.hconfigure.ac,可能还有 NEWS。NEWS 的日期写公告日(周四),而不是打标日(周二)。版本字符串禁止缩写、禁止用连字符分隔:

    #define PHP_VERSION "7.4.22RC1"   /* 正确 */
    #define PHP_VERSION "7.4.22-RC1"  /* 错误 */
    

    两条特殊规则:

    • Zend/zend.h 中的 ZEND_VERSION 只在准备 RC 与 GA 时更新,alpha/beta 不动它;
    • pre-GA 的第一个 RC 还必须提升 Zend/zend_extensions.hZend/zend_modules.hmain/php.h 中的 API 版本号(因为每次 API 提升都会迫使所有扩展重编译,alpha→beta→RCn 之间可以保持不变或少量提升);RC1 之后不得再提升 API 版本
  5. 编译并跑 make test,ZTS(Zend Thread Safety)与 non-ZTS 各一遍,且使用正确版本的 Bison 与 re2c(例如 PHP 8.5 至少要求 Bison 3.0.0、re2c 1.0.3):

    # With ZTS
    make distclean || \
    ./buildconf --force \
        && ./configure --enable-zts --disable-all --enable-debug --enable-opcache-jit \
        && make -j$(nproc) \
        && make test TEST_PHP_ARGS="-q -j$(nproc)" \
        || ./sapi/cli/php -v
    
    # Without ZTS
    make distclean || \
    ./buildconf --force \
        && ./configure --disable-all --enable-debug --enable-opcache-jit \
        && make -j$(nproc) \
        && make test TEST_PHP_ARGS="-q -j$(nproc)" \
        || ./sapi/cli/php -v
    
  6. 每次构建后检查 ./sapi/cli/php -v 输出,确认版本号与目标发布一致。

  7. 一切正确后提交到本地发布分支:

    git add -p
    git commit --gpg-sign=YOURKEYID -m "Update versions for PHP X.Y.ZRCn"
    
  8. 打 GPG 签名 tag:

    git tag -s -u YOURKEYID php-X.Y.ZRCn -m "Tag for php-X.Y.ZRCn"
    
  9. pre-GA 专属:切回 master(alpha/beta)或 PHP-X.Y(RC),为新版本更新 NEWS 并提交,例如:

    git add -p
    git commit --gpg-sign=YOURKEYID -m "[ci skip] Update NEWS for PHP X.Y.0 alpha2"
    

    NEWS 是在下一轮 tag 周期开始时更新的——例如"Update NEWS for PHP 8.2.0 alpha2" 这笔提交是在打 alpha1 tag 时随附发出的。

  10. GA 后的补丁 RC 与最后一个 pre-GA RC:切回版本分支(如 PHP-8.2),把 main/php_version.hZend/zend.hconfigure.acNEWS 中的版本号 bump 到下一个 -dev(如 8.2.1RC1 发布后应改为 8.2.2-dev)。无论是否真的会发新 RC 都要做,这保证 version_compare() 行为正确。提交信息形如 "PHP-X.Y is now for PHP X.Y.Z-dev"。版本分支与 master 上这三个文件的版本号永远-dev 结尾,只有 tag 例外。

  11. 向上合并:把 PHP-X.Y 一路合并到 master

    git switch PHP-X.Y+1 # 从发布分支开始
    git merge PHP-X.Y
    # repeat             # 逐级向上合并
    git switch master
    git merge PHP-X.Y+n  # 最新的发布分支
    

    解决冲突时,在 PHP-X.Y+1master 上采用 --ours(忽略来自 PHP-X.Y 的版本号改动):

    git checkout --ours main/php_version.h Zend/zend.h configure.ac
    git add main/php_version.h Zend/zend.h configure.ac
    git merge --continue
    

    同时要按照 PHP wiki 的 Git FAQ 为 NEWS 文件配置专用 merge driver。

  12. 推送到 php-src

    git push upstream php-X.Y.ZRCn # tag
    git push upstream PHP-X.Y.Z    # 补丁级版本分支(自 GA 前最后一个 RC 开始)
    git push upstream PHP-X.Y      # 版本分支(分支切出之后)
    git push upstream master       # 主干(分支切出之前)
    

    严禁使用 --tags 推送(会带上所有本地 tag);本地发布分支绝不推送。

  13. 生成发行包:用发布 tag 导出源码树、生成 configure 脚本、构建并压缩三个 tarball(.tar.gz.tar.bz2.tar.xz):

    ./scripts/dev/makedist php-X.Y.ZRCn
    
  14. 签名并生成 manifest

    ./scripts/dev/gen_verify_stub X.Y.ZRCn YOURKEYID > php-X.Y.ZRCn.manifest
    
  15. 若安装了 GitHub 命令行工具,创建公开 Gist 托管 manifest:

    gh gist create --public php-X.Y.ZRCn.manifest
    
  16. 用 scp/rsync 等方式把 tarball 拷到 downloads.php.net 上的 public_html/(目录不存在则创建并设为 0755):

    scp php-X.Y.ZRCn.tar.* downloads.internal.php.net:~/public_html/
    

    完成后文件可通过 downloads.php.net 上 ~yourname/ 路径访问。

  17. 打 tag 后联系 release-managers@php.net 邮件组以制作 Windows 二进制;完成后在 windows.php.net/qa/ 可获取。示例的"ready for builds"通知邮件:

    Subject: PHP 8.1.6RC1 ready for builds
    
    Hi, all!
    
    Tag: php-8.1.6RC1
    Tarballs: https://downloads.php.net/~ramsey/
    Manifest: <gist 链接>
    
    Cheers,
    Ben
    
    << PASTE FULL MANIFEST CONTENTS HERE >>
    

4.2 源码印证:makedist 与 gen_verify_stub 到底做了什么

scripts/dev/makedist 是发行包生成的核心脚本,从源码可以确认其完整行为链:

  • 要求 GNU tar——若检测到 bsdtar 直接报错退出(scripts/dev/makedist)。tag 命名必须符合 php-X.Y.Z[alpha|beta|RC] 或分支 PHP-X.Y[.Z] 约定;
  • git archive 把指定 tag/分支导出为纯净源码树(scripts/dev/makedist);
  • 在导出树中执行 ./buildconf --force 生成 configure 脚本,使安装包无需 autoconf;再执行 scripts/dev/genfiles 预生成词法/语法分析器文件,使安装不再依赖 bison 与 re2c(scripts/dev/makedist);
  • 下载 PEAR 的 phar 归档放入包内(scripts/dev/makedist);
  • 将包内所有文件的修改/访问时间重置为该 tag 对应提交的日期,保证 tarball 可复现构建(scripts/dev/makedist);
  • 依次生成 .tartar.gz(gzip -9)→ tar.bz2(bzip2 -9)→ tar.xz(xz -9),每种都计算 md5 并做完整性校验(scripts/dev/makedist)。

scripts/dev/gen_verify_stub 则负责生成公告所需的校验信息:对三个 tarball 逐一执行 gpg --armor --detach-sign(可用第二个参数指定 -u <GPG_USER> 身份),随后输出每个 tarball 的文件名、SHA256 hash 与完整的 PGP 签名块(scripts/dev/gen_verify_stub)。输出重定向到 php-X.Y.ZRCn.manifest 后,即成为 Gist 与公告邮件的附件内容。

另外,文档在稳定版打包处特别提醒:某些系统的 GNU tar 默认产出带 PAX 头的 POSIX 归档,并非所有应用兼容,打包时应通过环境变量 TAR_OPTIONS='--format=gnu' 强制 GNU 格式。

五、公告非稳定版发布(alpha/beta/RC)

  1. 切换到 web-php 仓库本地克隆,更新 include/release-qa.php$QA_RELEASES 数组(文件内有编辑说明)。pre-GA 阶段先不要提交,因为还要附加公告新闻条目,改完跳到第 2 步;post-GA 的 RC 则直接提交推送:

    git add -p
    git commit --gpg-sign=YOURKEYID -m "Announce PHP X.Y.ZRCn"
    git push upstream master
    
  2. 仅 pre-GA:用 bin/createNewsEntry 工具在 web-php 中创建简短新闻条目,突出主要变化(如安全修复)。pre-GA 非稳定版只使用 "frontpage" 分类(编号 0,PHP.net 首页新闻):

    ./bin/createNewsEntry
    # Please type in the title: PHP X.Y.0 Alpha n available for testing
    # Categories:  0: PHP.net frontpage news [frontpage] ...
    # Will a picture be accompanying this entry? no
    

    提交时把生成的 archive/entries/*.xml 一并纳入。撰写文案时的更新提示:qa.php.net 已由 php.net 的 release-candidates 页面取代;bugs.php.net 已迁至 GitHub issues 表单;自 8.4 起 X.Y.0 只有 4 个 RC。新闻条目必须包含类似 "Please DO NOT use this version in production, it is an early test version." 的警示。post-GA 阶段的非稳定版则再发新闻条目。

  3. 等待官网同步(最长约一小时)后再发公告邮件。

  4. 向以下三个邮件组分别发送独立公告邮件:

    • internals@lists.php.net
    • php-general@lists.php.net
    • php-qa@lists.php.net

    邮件中要说明发布物位置、下一个 RC 或最终版的预计日期,并附上打包时 gen_verify_stub 生成的 manifest。严禁把三个地址放进同一封邮件的 To/Cc/Bcc——否则用户回复时客户端会把回复群发给所有列表。这些列表的订阅者会在发布后验证自己项目在新版本下的表现,并在 GA 前反馈 bug。

  5. alpha、beta 与 pre-GA RC:与社交媒体团队协调,向 Mastodon 上的 PHP 官方账号发布带新闻链接的 toot;也可以自行向 toot-together 仓库提交含 NEWS 摘要的 PR。

六、打包稳定版发布(GA 与补丁版)

  1. 切换到该发布的补丁级版本分支

    git switch PHP-X.Y.Z
    

    该分支应在打包对应 RC 时已创建;若是 PHP-X.Y.0,则分支在最后一个计划内 RC(RC4)时创建。

  2. 安全发布:若即将到来的发布是安全版本,安全发布经理(SRM)会在周二 UTC 12 点前通知。若尚未配置安全仓库远端:

    git remote add security git@github.com:php/php-src-security.git
    

    SRM 会给出一个需要合入补丁级版本分支的安全分支:

    git fetch security
    git merge security/PHP-X.Y.Z-security
    git push upstream PHP-X.Y.Z
    

    无需合并回 PHP-X.Y,SRM 会处理。

  3. 在补丁级版本分支中运行 ./scripts/dev/credits,提交 ext/standard 下 credits 文件改动(很少触发,只为覆盖 cherry-pick 进来的修复)。

  4. 从补丁级版本分支切出仅本地发布分支:

    git checkout -b php-X.Y.Z-local-release-branch upstream/PHP-X.Y.Z
    
  5. 在本地发布分支中把 main/php_version.hZend/zend.hconfigure.ac(可能还有 NEWS)里的版本号从 X.Y.Z-dev 改为 X.Y.Z。例如发布 PHP 8.1.8 时,补丁级分支上全部是 8.1.8-dev,本地发布分支上全部改为 8.1.8

  6. 与 4.5 步相同:ZTS/non-ZTS 两种配置编译并 make test,使用正确版本的 Bison 与 re2c。

  7. 每次构建后核对 ./sapi/cli/php -v 输出。

  8. 提交到本地发布分支:

    git add -p
    git commit --gpg-sign=YOURKEYID -m "Update versions for PHP X.Y.Z"
    
  9. 打签名 tag 并立即推送 tag(稳定版比非稳定版多一步推送):

    git tag -s -u YOURKEYID php-X.Y.Z -m "Tag for php-X.Y.Z"
    git push upstream php-X.Y.Z
    
  10. 打包:

    ./scripts/dev/makedist php-X.Y.Z
    

    顺带确认 PEAR 文件(Phar)已更新;注意前文提到的 TAR_OPTIONS='--format=gnu' 提示。

  11. 签名生成 manifest:

    ./scripts/dev/gen_verify_stub X.Y.Z YOURKEYID > php-X.Y.Z.manifest
    
  12. gh gist create --public php-X.Y.Z.manifest 创建公开 Gist(或手动创建)。

  13. 稳定版 tarball 走 git 仓库分发:切到 web-php-distributions 仓库,把 tarball 与签名文件拷入、提交、推送:

    cd /path/to/repos/php/web-php-distributions
    mv /path/to/repos/php/php-src/php-X.Y.Z.tar.* .
    git add php-X.Y.Z.tar.*
    git commit --gpg-sign=YOURKEYID -m "Add tarballs for php-X.Y.Z"
    git push upstream master
    
  14. 打 tag 后联系 release-managers@php.net 制作 Windows 二进制。此通知只发内部邮件组,不发任何公开列表。示例"ready for builds"邮件(tarball 位置写作 web-php-distributions):

    Subject: PHP 8.1.6 ready for builds
    
    Hi, all!
    
    Tag: php-8.1.6
    Tarballs: web-php-distributions
    Manifest: <gist 链接>
    
    Cheers,
    Ben
    
    << PASTE FULL MANIFEST CONTENTS HERE >>
    

七、公告稳定版发布

  1. (仅适用于 PHP-X.Y.0 之后的版本)在 web-php 中把上一个发布的信息归档进 include/releases.inc。例:准备公告 8.2.2 时,为 8.2.1 归档,通常用 bin/bumpRelease

    ./bin/bumpRelease 8 2
    

    第一个数是主版本、第二个是次版本,不需要补丁号。若工具失败,可手动把 include/version.inc 中上一版本信息拷入 include/releases.inc

  2. include/version.inc 中更新新版本的 $data 段(X.Y.0 需新建段):

    • version 设为完整版本号(如 '8.2.1'
    • date 设为 j M Y 格式的发布日(如 '5 Jan 2021'
    • 安全版本在 tags 数组中加入 'security'
    • sha256 数组填入各 tarball 的哈希
  3. 生成发布页与新闻条目:

    ./bin/createReleaseEntry -v X.Y.Z -r   # 安全发布追加 --security
    

    该工具会生成发布文件(如 releases/X_Y_Z.php)与新闻条目(如 archive/entries/YYYY-MM-DD-n.xml),同时更新 archive/archive.xml。生成的消息是标准模板,可以在此基础上编辑扩充;X.Y.0 的版本公告格式不同,需要参照历史 PHP-8.2 公告提交手工调整。

  4. 更新对应主版本的 ChangeLog(如 ChangeLog-8.php):若发布的是 X.Y.0,先手工修改 ChangeLog-X.php,在 $MINOR_VERSIONS 中补上新版本及其初始锚点(如 PHP 8.4 加 <a id="PHP_8_4"></a>,置于上一版本第一个锚点之前);然后执行:

    ./bin/news2html 'https://github.com/php/php-src/raw/php-X.Y.Z/NEWS' 'X.Y.Z' 'ChangeLog-X.php'
    
  5. 更新 include/release-qa.php$QA_RELEASES:其中通常还挂着两周前发布的 RC。当前版本既已 GA,把该 RC 的 number 属性设为 0 即可让 RC 从 Release Candidate Builds 页面消失(可顺带删掉 RC tarball 的 sha256,非必需)。

  6. 审读 web-php 全部改动,提交并推送:

    git add -p
    git add archive/entries/*.xml releases/*.php
    git commit --gpg-sign=YOURKEYID -m "Announce PHP X.Y.Z"
    git push upstream master
    
  7. 发公告邮件前,先确认网站已同步(最长一小时),逐项核对:

    • tarball 可从 www.php.net/distributions/php-X.Y.Z.tar.gz 下载
    • downloads 页面出现新版本
    • 首页显示新闻条目
    • www.php.net/ChangeLog-8.php 等 ChangeLog 页面出现新条目
    • 存在新版本的发布页(如 www.php.net/releases/X_Y_Z.php
    • 对应 RC 是否已从 Release Candidate Builds 页面撤下
  8. 记录 sha256 与 PGP 签名(.asc)——必须写进发布公告邮件。

  9. 向下列邮件组分别发送独立公告邮件:

    • php-announce@lists.php.net
    • php-general@lists.php.net
    • internals@lists.php.net

    公告必须包含打包时生成的 manifest,以及源码、Windows 二进制、ChangeLog 的链接。普通补丁版本要写明 "This is a bugfix release.";安全版本则必须写 "This is a security release."。同样严禁把三个地址塞进同一封邮件的 To/Cc/Bcc。

  10. 与社交媒体团队协调,为 Mastodon 发布创建待审批的 toot 请求。

八、重发同一版本与 -plN 补丁级发布

极端情况下(如 tarball 损坏)需要重发同一版本:

  • 公告之前发现:可以删除 tag,按前述完整打包流程重来。"提前两天打包"的守则正是为这种补救留出的时间窗口。
  • 公告之后发现:可以打 tag、打包并发布一个 patch-level(pl)版本,如 8.0.1-pl1;若不紧急或影响面极小,也可以等到下一个发布。

pl 发布步骤:提交新二进制到 web-php-distributions;更新 web-php:/include/version.inc$data['X.Y']version'8.0.1-pl1'date、安全版本的 tagssha256);在 web-php 加一条简短新闻,说明重要修复(安全修复)与升级紧迫性(调用 php bin/createReleaseEntry -v <version> [--security]);提交全部改动(include/version.incarchive/archive.xmlarchive/entries/YYYY-MM-DD-N.xml);等一两小时后向 php-announce@lists.php.net、php-general@lists.php.net、internals@lists.php.net 分别发送与新闻条目内容相近的邮件,且 php-announce@ 必须是完全独立的邮件,避免其他列表的回复误入 php-announce@。

九、软冻结与硬冻结

  • 软特性冻结(soft feature freeze):随第一个 beta 发布生效。之所以叫"软",是因为特性仍可在 RM 批准后合入。要在某版本中收录的 RFC,其投票应在第一个 beta 发布前讨论完毕并关票;但实现不必在此前完成——实现可在 RM 批准下于硬冻结前合入。作为对社区的礼貌,RM 应在冻结前 5、4、3、2、1 周向 internals@lists.php.net 发布提醒(间隔可按工作量调整),提醒中附上"最晚可开始投票的 RFC 日期"。
  • 硬特性冻结(hard feature freeze):随第一个 RC 生效,准确地说发生在第一个 RC 被打包之时——即第一个 RC 发布日前两天。此后 php-src 不再接受任何新特性;工作重心转向修 bug、补测试与为已收录特性撰写文档。

十、切分新版本分支(branch cut)

当新版本到达第一个 RC 时,从 master 切出 PHP-X.Y 版本分支,让主干重新自由承载不能进入该版本的新特性开发。步骤:

  1. 在打 X.Y.0RC1 tag 前一周,向 internals@ 预告分支即将创建,明确时间点。

  2. X.Y.0RC1 tag 前,在本地创建 PHP-X.Y

  3. master 的分支点上追加一个提交,内容应包含:

  4. API 版本号约定master 上的 API 号必须大于PHP-X.Y 分支中的。惯例是取发布星期四的 YYYYMMDD 作为版本分支的 API 号,星期五的日期作为 master 的 API 号,从而保证 master 永远被视为更新。

  5. 推送新分支与 master 改动,提交信息形如 "master is now for PHP 8.3.0-dev"。

  6. 立即向 internals@ 通报新分支与新的合并顺序。

  7. 更新 web-phpgit.php 页面与 wiki 上的 git 工作流文档。

    为何在第一个 RC 而非特性冻结时切分支?这样有一段"专注让新版本达到 RC/GA 就绪"的窗口期,期间主干只接受小幅改进与 bug 修复,重大改进与新特性一律等待。

  8. CI 配置维护在最低支持分支上:在该分支更新相关文件反映切分,再把该提交向上合并 5 次到达 master。当前仓库中确认存在的 CI 相关文件包括 .github/matrix.php(加入新分支、更新 master 的版本)与 .github/scripts/windows/find-target-branch.bat(更新 master 版本)。

  9. 更新 push workflow 的触发分支列表:该文件不需要更新最低支持分支,只需更新新切出的分支以加入新分支、再向上合并一次到 master

  10. 更新 php/php-sdk-binary-toolsmasternightlypush 作业所使用的版本以适配新版本;若切分时新版本 SDK 工具尚不可用,应提交 issue 上报。

十一、准备首个稳定版(PHP X.Y.0)

  1. 发布第一个 pre-GA RC 时,提醒文档团队(phpdoc@lists.php.net)撰写该版本的迁移指南(migration guide);X.Y.0 公告中要链接它,因此必须在首发稳定版前就位。

  2. 尽早熟悉稳定版与非稳定版在准备和公告流程上的差异。

  3. 发布 X.Y.0 前,把各预发布版本的 NEWS 条目合并为 X.Y.0 的单一章节,并删除上一版本 NEWS 中已有的条目(即已随上一版本发布的 bug 修复)。可用 grep 对比找出重复项,例如 82/NEWS83/NEWS 分别是 8.2 与 8.3 的 NEWS 时:

    grep -Fxf 82/NEWS 83/NEWS
    
  4. 在 X.Y.0 公告日(或稍早),更新 web-php 仓库 .well-known/ 目录下 security.txtExpires 字段,设为下一个 X.Y.0 的预计日期(通常是一年后的 11 月第四个星期四)。依据 RFC 9116 的建议,PHP 以约一年的周期推进该时间戳,让安全研究人员确信他们看到的是最新报告政策。

十二、发布经理的选拔与上任清单

选拔:在下一主/次版本首个 alpha 计划发布日前约三个月(3 月 1 日前后),当前版本分支的 RM 应在 internals@lists.php.net 发起志愿者招募,目标 4 月初确定人选;志愿者应不少于两人,通常由一位资深 RM 与一两位新手组成,必要时投票决定;随后要手把手带新人起步。

新 RM 上任清单(流程文档末尾的完整清单):

  1. 填写 php.net 的 Git 权限表单获取 PHP 账号(若尚无)。

  2. 申请加入 GitHub 上 php 组织的 release-managers 团队。

  3. 订阅全部将用于公告的邮件组(否则无法向列表投递):internals@、php-announce@、php-general@、php-qa@(均位于 lists.php.net)。

  4. 在 php/infrastructure 项目提交 release manager access 工单,提供 SSH 公钥、@php.net 邮箱、GitHub 账号与首选系统账户名(最好全部一致)。

  5. 按 infrastructure 仓库的 ServerAccess 文档配置经跳板机加 2FA 访问 downloads.php.net;用 Google Authenticator 生成 .google_authenticator 文件,连同上一步工单链接一并发给 systems@php.net。提示:从 @php.net 地址发信需配置自定义 SMTP 服务器(Gmail 可用"其他别名发信")。

  6. 为 @php.net 地址创建 GPG 密钥并发布:

    • 编辑 web-phpinclude/gpg-keys.inc,在 gpg_key_get() 函数中为自己的用户名添加 case,粘贴 gpg --fingerprint 的输出;必要时更新 gpg_key_get_branches()$branches 数组把自己与所负责分支关联;

    • 请一位或多位现有 RM 为自己的密钥签名,并上传公钥到密钥服务器:

      gpg --keyserver keys.openpgp.org --send-keys YOURKEYID
      gpg --keyserver keyserver.ubuntu.com --send-keys YOURKEYID
      
    • 把自己的公钥加入 web-php-distributionsphp-keyring.gpg:先导入现有 keyring 中所有密钥,记录各 RM 的 key ID,再连同自己的 ID 一起导出覆写:

      cd /path/to/repos/php/web-php-distributions
      gpg php-keyring.gpg            # 列出 keyring 内所有密钥
      gpg --import php-keyring.gpg   # 导入到本地 keyring
      gpg --export \
          --export-options export-minimal \
          --armor \
          YOURKEYID <其他 RM 的 KEY IDs>... \
          > php-keyring.gpg
      gpg php-keyring.gpg  # 确认所有密钥(含自己)都在
      git add -p
      git commit --gpg-sign=YOURKEYID -m "Update PHP release manager keyring"
      git push
      
    • web-php-distributionsweb-php 的子模块,还需更新子模块引用:

      cd /path/to/repos/php/web-php
      git submodule update
      cd distributions           # 即 web-php-distributions 子模块
      git pull origin master
      cd ..
      git add distributions
      git commit --gpg-sign=YOURKEYID -m "Update php-keyring.gpg in distributions"
      git push
      
  7. 本地克隆齐三个仓库:php-src、web-php、web-php-distributions。

十三、关键脚本与文件速查

仓库内路径 在发布流程中的角色
scripts/dev/makedist 从 tag/分支导出源码树、生成 configure 与词法语法文件、下载 PEAR、产出 tar.gz/tar.bz2/tar.xz 三种发行包
scripts/dev/gen_verify_stub 对三个 tarball 做 GPG 分离签名,输出 SHA256 与签名构成的 manifest
scripts/dev/credits 由各扩展 CREDITS 文件重新生成 ext/standard 下的 credits 头文件
scripts/dev/genfiles 预生成 bison/re2c 产物,被 makedist 调用,使安装包免装 bison 与 re2c
main/php_version.h PHP 版本号单一事实源之一(当前为 8.6.0-dev
Zend/zend.h ZEND_VERSION(当前为 4.6.0-dev),仅 RC/GA 时随发布更新
configure.ac AC_INIT 中的版本字符串,须与 php_version.h 一致
win32/build/confutils.js Windows 构建的版本号来源,分支切分时一并更新
NEWS 发布变更记录;打包日更新、向上合并时需专用 merge driver
.github/matrix.php CI 分支矩阵,切分版本分支后登记新分支
.github/scripts/windows/find-target-branch.bat Windows CI 的目标分支判定,切分支后更新 master 版本

以上流程均以 docs/release-process.md 为准,其中涉及的 web-php、web-php-distributions、security 仓库与 downloads.php.net 服务器属于 php 组织的基础设施,本文仅按该文档描述其职责与操作步骤。对读者而言,理解这套流程的价值在于:它展示了如何用一个可复现的打包脚本(GNU tar + 时间戳归一化 + 三格式压缩)、一套签名校验链(GPG tag、分离签名、SHA256 manifest、keyring 公钥环)和严格的分支不变式(-dev 版本号、仅 tag 落定),把一个大型解释器项目的版本发布从"手工仪式"变成可审计、可交接的工程流水线。

登录后查看全文
热门项目推荐
相关项目推荐