PHP 怎么生成变更日志

wen PHP项目 3


PHP 项目如何自动生成高质量变更日志(Changelog)?从手动到 CI/CD 的完整实践指南**

PHP 怎么生成变更日志


📚 目录导读(Table of Contents)

  1. 为什么你的 PHP 项目需要一个变更日志?
  2. 手动编写 vs 自动化生成:优劣对比
  3. PHP 生态中的最佳工具:解析 cliffconventional-commits
  4. 实战:用 PHP 脚本 + Git 历史自动生成 CHANGELOG.md
    • 1 前置条件:规范化提交信息(Commit Message)
    • 2 核心代码实现:解析 git log 并分类
    • 3 生成 Markdown 表格与版本链接
  5. 进阶:集成到 GitHub Actions / GitLab CI 实现全自动
  6. 常见问题问答(FAQ)
  7. 总结与最佳实践建议

为什么你的 PHP 项目需要一个变更日志?

变更日志(Changelog)是软件项目中易被忽视但极其重要的文档,它记录了每个版本“新增、修复、破坏性变更”的清单,对于使用 PHP 开发的框架(如 Laravel)、库(如 Guzzle)或大型业务系统,变更日志能解决三大痛点:

  • 协作效率:团队成员或外部贡献者无需阅读全部提交记录,即可快速了解新版本影响。
  • 故障排查:当线上出现回归 Bug 时,可迅速定位是哪个版本引入了变更。
  • 发布规范:强制团队遵循语义化版本(SemVer),让 composer update 变得可控。

手动编写 vs 自动化生成:优劣对比

方式 优点 缺点
手动 可人工筛选重要内容,措辞更人性化 易遗漏、滞后,开发者常因“忘记更新”而使文档失效
自动化 实时同步代码变更,无遗漏;强制提交信息规范 需安装依赖、配置规则,若提交信息杂乱则输出质量差

对于任何活跃的 PHP 项目,自动化是唯一可扩展的路径

PHP 生态中的最佳工具:解析 cliffconventional-commits

虽然 Node 生态有 standard-version,但在 PHP 领域,我们推荐两个轻量级方案:

  • git-cliff:基于 Rust 编写的高性能工具,但可通过 Composer 包 wyzheng/git-cliff 调用,它默认遵循 Conventional Commits 规范,支持模板引擎(Tera),能生成高度定制化的 Markdown。
  • 纯 PHP 脚本(自研):优点是零依赖,适合对代码有绝对掌控欲的团队,核心逻辑是执行 git log 命令,解析输出并映射到 Added / Changed / Deprecated / Removed / Fixed / Security 标记。

综合搜索引擎的高频建议:大多数团队最终选择 自研脚本 + 标准化提交信息,因为无需引入系统级依赖,且易于测试。

实战:用 PHP 脚本 + Git 历史自动生成 CHANGELOG.md

1 前置条件:规范化提交信息(Commit Message)

这是整个方案的基石,请在项目根目录创建 commitlint.config.js 或使用 PHP 工具 captainhook 强制校验:

# 正确的格式
git commit -m "feat(core): 添加缓存抽象层"
git commit -m "fix(api): 修复用户登录时 500 错误"
git commit -m "BREAKING CHANGE: 变更配置项参数名"

2 核心代码实现:解析 git log 并分类

以下是一个精简但可运行的 PHP 脚本(保存为 generate-changelog.php):

<?php
// 获取 Git 历史(从最新 tag 到 HEAD)
$tags = shell_exec('git tag --sort=-v:refname | head -n 1');
$since = $tags ? trim($tags) : 'HEAD~10';
$log = shell_exec("git log --pretty=format:'%h|%s|%ad' --date=short $since..HEAD");
$entries = ['Added' => [], 'Fixed' => [], 'Changed' => [], 'Removed' => []];
foreach (explode("\n", trim($log)) as $line) {
    [, $subject] = explode('|', $line);
    if (preg_match('/^feat(?:\(.+\))?: (.+)$/', $subject, $m)) {
        $entries['Added'][] = $m[1];
    } elseif (preg_match('/^fix(?:\(.+\))?: (.+)$/', $subject, $m)) {
        $entries['Fixed'][] = $m[1];
    } elseif (preg_match('/^perf(?:\(.+\))?: (.+)$/', $subject, $m)) {
        $entries['Changed'][] = $m[1];
    } elseif (preg_match('/^refactor(?:\(.+\))?: (.+)$/', $subject, $m)) {
        $entries['Removed'][] = $m[1];
    }
}
// 生成 Markdown
$md = "## [Unreleased] - " . date('Y-m-d') . "\n\n";
foreach ($entries as $type => $items) {
    if (count($items) > 0) {
        $md .= "### $type\n";
        foreach ($items as $item) {
            $md .= "- $item\n";
        }
        $md .= "\n";
    }
}
file_put_contents('CHANGELOG.md', $md);
echo "✅ 变更日志已生成!\n";

3 生成 Markdown 表格与版本链接

为了符合主流开源项目风格(如 Laravel 的 changelog),你可以在上述循环外追加版本比较链接:

$latestTag = $since;
$md .= "**完整变更记录**: [查看对比](https://github.com/your-name/your-repo/compare/$latestTag...HEAD)\n";

进阶:集成到 GitHub Actions / GitLab CI 实现全自动

.github/workflows/release.yml 中添加 Job:

- name: 生成变更日志
  run: php generate-changelog.php
- name: 提交文件
  run: |
    git config user.name "GitHub Action"
    git config user.email "action@github.com"
    git add CHANGELOG.md
    git commit -m "docs: 自动更新变更日志"
    git push

这样每次发布新版本时(打 tag),系统都会自动生成并提交变更日志,无需人工介入。

常见问题问答(FAQ)

Q1:我已经有很多不规范的历史提交信息,怎么办?
A:不必纠结,插件 bumbal/commit-checker 或脚本可只从“当前 tag”开始计算,历史记录可以后期通过 git rebase 重写,但建议谨慎操作(仅限团队内部分支)。

Q2:如何识别 “BREAKING CHANGE” 并高亮?
A:在解析代码中使用 strpos($subject, 'BREAKING CHANGE') !== false 判断,然后将其单独归类到 ### ⚠️ 破坏性变更 小节。

Q3:生成的日志没有包含 security 修复分类?
A:在 preg_match 中加入 security 前缀,或者监控 git log --grep='security'


总结与最佳实践建议

  • 推荐策略:采用 Conventional Commits 规范 + 自研 50 行 PHP 脚本,即可满足 90% 需求。
  • 注意时区:在 PHP 脚本中 date_default_timezone_set('UTC') 避免时间偏差。
  • 结合 Composer 脚本:将 generate-changelog.php 放入 composer.jsonscripts 段,执行 composer changelog 即可。
  • 不要忽略文档更新:在 CONTRIBUTING.md 中写明提交规范,否则自动化就是无源之水。

遵循以上步骤,你的 PHP 项目将拥有媲美 Laravel 官方仓库的整洁变更日志,这不仅提升了专业性,也让团队协作更高效。


延伸阅读提示:若想深入学习 git-cliff 的配置模板,可以访问官方文档 example 目录;对于更复杂的多包仓库(Monorepo),可在脚本中增加 --path 参数过滤子目录。

抱歉,评论功能暂时关闭!