4 向组件贡献修改

Yocto 项目和 OpenEmbedded 非常欢迎贡献。 系统具有很高的可配置性和灵活性,我们理解开发者会希望根据具体用途扩展、配置或优化它。

4 通过邮件列表贡献:为什么不使用网页工作流?

Yocto 项目和 OpenEmbedded 的许多关键组件都通过邮件列表提交补丁来维护。 相比 GitHub、GitLab 等基于网页的工作流,这种方式看起来有些传统。 由于经常被问到这个问题,我们在此说明使用邮件列表的原因。

一个重要原因是我们重视同行审阅。针对项目核心部分提出修改时, 让更多人审阅会很有帮助。虽然最终由一位维护者决定是否接受补丁, 但实际审阅来自许多人,维护者事先未必知道谁会参与。 那些意料之外的审阅者,往往能发现最值得关注的问题。

相比之下,“GitHub”式工作流通常由维护者独自审阅,或明确邀请指定人员审阅。 我们认为,开放的同行审阅为代码带来了显著价值,离开邮件列表会损害代码质量。

还应看到,许多开发者已经使用这一工作流多年,并围绕它建立了工具和流程。 改变这种方式可能使项目失去关键参与者,同样不利于项目。

项目也很清楚,潜在的新贡献者可能不喜欢邮件列表,更倾向于网页图形界面。 由于我们认为那种方式不适合本项目,正在确保 patchwork 可用于跟踪补丁状态, 并研究如何通过工具向用户提供更多状态反馈。 我们也在改进 patchtest 等工具,使贡献在进入邮件列表前得到测试, 并完善工作流文档:十年前的常识,对今天的开发者可能已经不那么熟悉。

4 准备提交修改

4 配置 Git

首先安装 Git 软件包。Debian 和 Ubuntu 的示例如下::

sudo apt install git-core git-email

然后设置 Git 用于标识提交的姓名和电子邮件地址::

git config --global user.name "Ada Lovelace"
git config --global user.email "ada.lovelace@gmail.com"

Git 默认在补丁末尾添加包含 Git 版本的签名行。 这并不提供有用信息,建议用以下命令去掉::

git config --global format.signature ""

4 克隆待修改组件的 Git 仓库

按照 确定所属组件 确定待修改组件后, 克隆其 Git 仓库。以下以 OpenEmbedded-Core 为例::

git clone https://git.openembedded.org/openembedded-core
cd openembedded-core

4 创建新分支

从上游仓库的参考分支(通常名为 master)出发, 在本地 Git 仓库创建用于修改的新分支::

$ git checkout <ref-branch>
$ git checkout -b my-changes

如果要提交几组完全无关的修改,应为每一组分别创建分支。

4 实现并提交修改

在每个分支中,应将修改拆分成小而独立、范围可控的单元。 这样便于审阅和合并、变基,也能保持清晰的历史,方便将来查阅。

为此,应当 每项修改对应一个 Git 提交,最终对应一个待提交的补丁。 需要时可参考 Linux 内核文档的 进一步建议。

例如,添加多个新配方时,每个配方应单独提交。 升级已有配方时,通常应在添加新版本的同一提交中删除旧版本。

  1. 暂存修改: 对每个修改过的文件运行 git add。 如果要暂存全部修改,也可以使用 git add -A。

  2. 提交修改: 此时可以创建独立提交。 对每个提交,使用 git commit -s,指定要包含的文件或目录::

    $ git commit -s file1 file2 dir1 dir2 ...
    

    要包含所有已暂存文件::

    $ git commit -sa
    
    1. git commit 的 -s 选项会在提交说明中添加 "Signed-off-by:" 行。 Linux 内核贡献也有相同要求。添加此行表示提交者同意以下 开发者来源证明 1.1:

      Developer's Certificate of Origin 1.1
      
      By making a contribution to this project, I certify that:
      
      (a) The contribution was created in whole or in part by me and I
          have the right to submit it under the open source license
          indicated in the file; or
      
      (b) The contribution is based upon previous work that, to the best
          of my knowledge, is covered under an appropriate open source
          license and I have the right under that license to submit that
          work with modifications, whether created in whole or in part
          by me, under the same open source license (unless I am
          permitted to submit under a different license), as indicated
          in the file; or
      
      (c) The contribution was provided directly to me by some other
          person who certified (a), (b) or (c) and I have not modified
          it.
      
      (d) I understand and agree that this project and the contribution
          are public and that a record of the contribution (including all
          personal information I submit with it, including my sign-off) is
          maintained indefinitely and may be redistributed consistent with
          this project or the open source license(s) involved.
      
    2. 用一行概括修改;如需更多解释,再在提交正文中详细说明。 摘要通常显示在简短提交列表中,因此应简洁、明确,让读者快速理解修改内容。 修改配方时,以配方名称为前缀;否则使用被修改文件路径的简短形式。

      备注

      要寻找合适的摘要前缀,可以查看之前修改相同文件或目录的提交::

      git log --oneline <paths>
      
    3. 提交正文应详细说明改了什么、为什么改,以及采用的方法。 说明如何测试修改也很有帮助。应尽可能提供充分细节。

      备注

      对于简单修改,如果一行摘要已足够说明,提交正文可以为空。

    4. 如果修改解决了具有缺陷跟踪 ID 的特定问题,在提交正文中引用该 ID。 Yocto 项目使用以下约定,必须用实际 Bugzilla ID 替换 bug-id::

      single-line summary of change
      
      Fixes [YOCTO #bug-id]
      
      detailed description of change
      
    5. 如果其他人参与了补丁,可以在正文中加入标签,认可他们的贡献:

      • Reported-by:报告该缺陷的人的姓名和邮箱。 这样可以鼓励继续报告问题,并让报告者知道反馈得到了处理。

      • Suggested-by:提出修改思路的人的姓名和邮箱。

      • Tested-by、Reviewed-by:测试修改或审阅代码的人的姓名和邮箱。 通常由接受补丁的维护者添加;如果你先向他人征求过审阅, 或在新一轮补丁系列中重新提交未修改的补丁,也可自行加入已有标签。

      • Cc:希望收到修改副本的人的姓名和邮箱,供 git send-email 使用。

      更多建议见 Linux 内核文档的 标签使用说明。

      备注

      可以使用 git commit --amend 修改已有提交说明,补充遗漏的贡献者标签。

4 测试修改

每次贡献都应测试相应修改。Yocto 项目提供多种测试,覆盖不同领域; 应根据修改选择适用的测试。例如:

  • 对影响构建环境的修改:

    • bitbake-selftest:测试 BitBake 内部修改。

    • oe-selftest:测试 BitBake 运行的不同组合。

    • oe-build-perf-test:测试常见构建场景的性能。

  • 对配方修改:

    • ptest:运行软件包自身的测试(如果有)。

    • testimage:构建并启动镜像,在其中运行测试用例。

    • 如果适用,还应确保 native 和 nativesdk 变体能够构建。

  • 对 SDK 相关修改:

    • testsdk:构建、安装 SDK,并对其运行测试。

    • testsdk_ext:构建、安装可扩展 SDK,并对其运行测试。

此列表仅供参考,并不完整。详见 Yocto 项目测试类型概览。

4 生成补丁

通过电子邮件提交补丁的一般准备步骤如下:

  1. 描述分支中的修改: 如果分支中有多个提交,建议提供封面信, 介绍即将发送的补丁系列。

    一种合适的做法是将封面信内容保存在分支描述中::

    git branch --edit-description
    

    命令会打开文本编辑器,填写修改说明。可以随时更新描述, Git 会将其与补丁一起用于生成封面信。

    建议第一行写标题,作为封面信的邮件主题。

  2. 为分支生成补丁: git format-patch 为分支中的每个提交生成补丁文件。 需要传入该分支起始的参考分支。

    如果上一步无需分支描述::

    $ git format-patch <ref-branch>
    

    如果填写了分支描述,还应生成封面信::

    $ git format-patch --cover-letter --cover-from-description=auto <ref-branch>
    

    命令执行后,当前目录中会出现带编号的 .patch 文件。 封面信位于 0000-cover-letter.patch。

    备注

    --cover-from-description=auto 让 git format-patch 使用分支描述的第一段作为封面信标题。 也可以只传入更容易记住的 --cover-letter, 但每次生成补丁后都要手动编辑主题。

    详见 git format-patch 手册。

  3. 审阅每个补丁文件: 发送前的最后检查常常能帮助你从不同角度审视修改, 发现拼写、空格等问题,以及本不打算修改的行甚至文件。 封面信也应包含在检查范围内。

    必要时,按照 根据补丁审阅意见修改 修改提交。

4 使用 Patchtest 验证补丁

openembedded-core 提供 patchtest, 检查补丁格式是否正确,以及是否包含维护所需的重要信息,例如 Signed-off-by。 它不执行功能测试,目前仅支持 openembedded-core 分支的补丁。 配置步骤如下::

pip install -r meta/lib/patchtest/requirements.txt
source oe-init-build-env
bitbake-layers add-layer ../meta-selftest

完成配置并生成补丁文件后,可运行::

patchtest --patch <patch_name>

若要遍历并测试某个目录中的多个补丁,使用::

patchtest --directory <directory_name>

默认情况下,patchtest 根据自身模块的文件路径, 确定检查补丁所用的仓库和测试套件。 要针对其他仓库或使用另一组测试,可使用 --repodir 和 --testdir::

patchtest --patch <patch_name> --repodir <path/to/repo> --testdir <path/to/testdir>

注意,patchtest 设计为独立测试每个补丁。 如果补丁依赖同一系列中先前的修改,"merge on head" 测试可能产生误报。

这样使用 patchtest,可以在提交维护者审阅前,对修改的整体质量作最后检查。

4 通过电子邮件发送补丁

4 使用 Git 发送补丁

通过邮件提交补丁时,必须避免自己或邮件客户端引入空白或 HTML 格式变化。 接收补丁的维护者需要能够直接保存邮件,并使用 git am 应用它。

git send-email 是通过邮件发送补丁最可靠的方式, 可以避免普通邮件客户端破坏正文空白。 它还会正确地将补丁作为 内联附件, 普通客户端很难在不破坏换行的情况下做到这一点。 如果使用普通附件,审阅者便无法引用具体修改并发表评论。

4 配置 Git 发送邮件

git send-email 可以使用本地或远程邮件传输代理(MTA), 例如 msmtp、sendmail,也可以通过 ~/.gitconfig 直接配置 SMTP。

以下以 Google Mail 账户为例,设置通过常用 SMTP 服务器发送邮件::

git config --global sendemail.smtpserver smtp.gmail.com
git config --global sendemail.smtpserverport 587
git config --global sendemail.smtpencryption tls
git config --global sendemail.smtpuser ada.lovelace@gmail.com
git config --global sendemail.smtppass = XXXXXXXX

这些设置会写入主目录中的 .gitconfig。

如果既不能使用本地 MTA,也不能使用 SMTP, 请确保邮件客户端不会改动正文,例如把空格变成制表符或自动折行。 Pine(或 Alpine)和 Mutt 是适合的客户端。 更多信息见 Linux 内核文档中的 Linux 邮件客户端说明。

使用这些客户端时,直接将补丁放入邮件正文。

4 查找合适的邮件列表

应将补丁发送到适当的邮件列表,让相关贡献者审阅,并由相应维护者合入。 具体列表取决于修改的代码位置。

如果有人对补丁有疑问,通常会在列表中提出。 如果没有负面审阅意见,受影响层的维护者通常会接收并测试补丁,测试成功后合入。

一般而言,每个组件(例如层)都应有 README,说明修改发往何处及应遵循的流程。

如果新配方既不适合 OpenEmbedded-Core (OE-Core), 也不适合 meta-openembedded, 应在 https://layers.openembedded.org 寻找合适的层。 如果未来还会有类似配方,可以考虑 创建自己的层。

如有疑问,请在 yocto 通用邮件列表, 或 openembedded-devel 列表询问。

4 订阅邮件列表

确定合适的邮件列表后,如果尚未订阅,需要先订阅。

向未订阅的列表发送补丁时,邮件会以无法投递退回。

如果不希望接收列表中的所有消息,可以将订阅方式设为 "no email"。 你仍然是订阅者,可以发信,但不会收到列表邮件。 有人回复你的消息时,其客户端通常仍会默认把你的地址加入对话收件人。

也可以通过浏览器查看列表归档中的新消息; 对于归档在 https://lore.kernel.org 的列表,还可以通过独立新闻组源或 Git 仓库访问。

4 发送补丁邮件

现在可以发送补丁。git send-email 的典型用法如下::

git send-email --to <mailing-list-address> *.patch

仔细检查每封邮件的主题和收件人列表,然后允许命令发送。

git send-email 会自动抄送提交中 Signed-off-by、Reported-by 等标签列出的人。

为 meta-openembedded 或 openembedded-core 之外的其他层发送补丁时, 请添加相应前缀,明确补丁适用的层::

git format-patch --subject-prefix="meta-oe][PATCH" ...

备注

也可以不预先生成补丁文件,直接发送。但必须先仔细检查修改, 因为 git send-email 只会展示各补丁的标题。

分支中只有一个补丁时,可以使用::

git send-email --to <mailing-list-address> -1

如果有多个补丁及封面信,可以发送参考分支到当前分支顶端之间的全部提交::

git send-email --cover-letter --cover-from-description=auto --to <mailing-list-address> -M <ref-branch>

详见 git send-email 手册。

4 排查邮件问题

4 修正 From 身份

一个常见问题是,收到的补丁中 From 字段与 Signed-off-by 不一致。 使用启用了 https://en.wikipedia.org/wiki/DMARC 的域发送邮件时,典型示例如下::

From: "Linus Torvalds via lists.openembedded.org <linus.torvalds=kernel.org@lists.openembedded.org>"

git am 使用 From 字段恢复正确的提交作者姓名。 以下配置会在邮件正文开头增加 From 字段, 使维护者不必手动修正作者信息::

git config --global sendemail.from "linus.torvalds@kernel.org"

sendemail.from 应与 user.email 一致,后者出现在提交的 Signed-off-by 中。

4 简化 git send-email 的使用

可以通过 Git 配置节省时间,避免每次记住全部选项。

  • 为某个仓库设置正确的邮件列表地址::

    git config --local sendemail.to openembedded-devel@lists.openembedded.org
    
  • 如果列表要求主题包含层前缀(仅适用于仓库只有一个层的情况)::

    git config --local format.subjectprefix "meta-something][PATCH"
    

4 使用脚本向上游推送修改并请求拉取

较大的补丁系列更适合发送拉取请求,其中除了补丁,还包含可供拉取的分支地址。 先为修改创建本地分支,推送到可访问的仓库,再使用 openembedded-core 的 create-pull-request 和 send-pull-request 脚本, 生成并发送附带分支链接的补丁系列供审阅。

完成 准备提交修改 中的步骤后,按以下流程向上游 "contrib" Git 仓库推送:

备注

关于向上游推送修改的一般 Git 知识,参见 Git 社区书籍。

  1. 申请上游 contrib 仓库的推送权限: 向 helpdesk@yoctoproject.org 发送邮件:

    • 附上 SSH 公钥,通常名为 id_rsa.pub.。 如果没有,可运行 ssh-keygen -t rsa -b 4096 -C "your_email@example.com" 生成。

    • 列出计划贡献的仓库。

    • 提供希望在 -contrib 仓库中使用的分支前缀。

  2. 向 contrib 上游推送提交: 将修改推送到该仓库::

    $ git push upstream_remote_repo local_branch_name
    

    例如,你有向 meta-intel-contrib 推送的权限, 正在本地 your_name/README 分支工作。 以下命令将本地提交推送到该上游仓库中同名的分支::

    $ git push meta-intel-contrib your_name/README
    
  3. 确定通知对象: 确定需要通知的维护者或邮件列表。

    提交修改前必须明确这一点,可以使用以下方法:

    • 维护信息文件: 查看 OpenEmbedded-Core (OE-Core) 中 meta/conf/distro/include 下的 maintainers.inc,确定代码负责人。

    • 按文件查找: 使用 Git, 运行以下命令,查看某个文件的提交者简表::

      git shortlog -- filename
      

      传入感兴趣的文件名即可。返回结果不按历史顺序排列, 而是按姓名分组列出提交者,由此可以看到谁完成了该文件的大部分修改。

    • 查找邮件列表: 参见前面的 查找合适的邮件列表。

  4. 发起拉取请求: 通过拉取请求通知维护者或邮件列表,修改已推送。

    Yocto 项目提供 create-pull-request 和 send-pull-request 两个脚本, 方便生成并发送拉取请求,位于 OpenEmbedded-Core (OE-Core) 的 scripts。

    这些脚本可以正确格式化请求,不会引入空白或 HTML 格式变化。 维护者无论直接还是通过列表收到补丁,都应能够直接从邮件保存并应用。 因此推荐使用这些脚本发送补丁。

    首先创建拉取请求。以下命令指定已推送修改的 contrib 上游仓库, 并为生成的补丁文件提供主题::

    $ ./scripts/create-pull-request -u meta-intel-contrib -s "Updated Manual Section Reference in README"
    

    脚本会在当前目录的 pull-PID 文件夹中生成 *.patch,其中一个是封面信。

    运行 send-pull-request 前,必须编辑封面信,加入修改信息。 编辑完成后发送请求。以下命令指定补丁目录和邮件地址,此处地址是邮件列表::

    $ ./scripts/send-pull-request -p ~/meta-intel/pull-10565 -t meta-intel@lists.yoctoproject.org
    

    脚本为交互式,需要按提示操作。

    备注

    要查看帮助,传入 -h::

    $ ./scripts/create-pull-request -h
    $ ./scripts/send-pull-request -h
    

4 向稳定发布分支提交修改

向 Yocto 项目稳定分支提议修改,与上述流程有所不同。 稳定分支修改必须解决明确的缺陷或 CVE,并谨慎避免引入新问题或破坏向后兼容性。 通常,修复必须先被 master 接受,才能回移到稳定分支; 除非问题不影响 master,或 master 的修复方式不适合回移。

稳定分支列表、各分支状态和维护者信息见 版本页面。

备注

稳定分支补丁应为独立、便于人工阅读和理解的修改。 复杂度高、提交数量多或修改行数很多的 CVE 及其他修复, 会增加维护和规模化处理的难度,因此不太可能被接受。

通常不接受面向已终止支持(EOL)分支的修改。

具体提交步骤如下:

  1. 明确待修复的缺陷或 CVE: 收集相关信息,以便随提交一起提供。

    CVE 跟踪详见 检查漏洞。

  2. 检查 master 是否已有修复: 已有修复时,进入稳定分支的路径最直接。

    1. master 已有修复:通过邮件申请回移。 向相关稳定分支维护者和邮件列表发送邮件,说明缺陷或 CVE、 master 上的修复提交哈希,以及希望回移到哪些稳定分支。

    2. master 尚无修复:先向 master 提交。 这样可确保修复经过项目正常的补丁审阅与测试流程, 也避免 master 本身仍留有未解决的问题。 master 接受后,再按上述方式申请回移。

    3. 修复不适用于 master:直接提交稳定分支补丁。 这应是最后的选择。通常出现在 master 使用了已包含上游修复的新软件版本, 或 master 的修复引入了不向后兼容的变化时。 此时遵循 准备提交修改 及后续章节的步骤,但在补丁邮件主题中加入目标稳定分支名。 可以通过 git format-patch 的 --subject-prefix 指定。 例如,向 "wrynose" 分支提交::

      git format-patch --subject-prefix='wrynose][PATCH' ...
      

4 根据补丁审阅意见修改

提交后,可能收到社区成员或自动 patchtest 服务的反馈。 发现的问题通常必须解决,补丁才能被项目接受。 应根据反馈修订提交,并向相关列表发送更新版本。

不要通过在分支顶端追加新提交来修复审阅指出的问题。 应始终提供已经解决这些问题的一组新提交。

备注

建议抄送曾为上一版提供反馈的审阅者。 可以在提交正文中添加 CC 标签::

CC: William Shakespeare <bill@yoctoproject.org>

单个补丁可用 git commit --amend 修改; 多个补丁可通过交互式变基重新修改和排序::

git rebase -i <ref-branch>

实际操作可参考 交互式变基教程。

发送修订版本时,还应将邮件主题中的 [PATCH] 改成 [PATCH v2]、[PATCH v3] 等,标明迭代次数。 可以向 git format-patch 传入 -v 和版本号::

git format-patch -v2 <ref-branch>

通过 git format-patch 生成更新补丁后,最好为每个补丁添加版本变更记录, 说明各轮之间的变化。记录放在补丁的 --- 标记之后, 表示它属于本次补丁邮件,但不应进入提交说明及 Git 历史。 这能帮助维护者和审阅者快速理解各版本变化,不必再搜索邮件列表等其他来源。 例如::

<patch title>

<commit message>

<Signed-off-by/other trailers>
---
changes in v4:
- provide a clearer commit message
- fix spelling mistakes

changes in v3:
- replace func() to use other_func() instead

changes in v2:
- this patch was added in v2
---
<diffstat output>

<unified diff>

最后,务必测试修订后的修改,尤其不要仅编辑 git format-patch 生成的补丁文件就重发。

4 跟踪补丁状态

Yocto 项目使用 Patchwork 实例 跟踪提交到各邮件列表的补丁状态,并支持自动化补丁测试。 每个补丁都会检查常见错误及格式偏差;发现问题时,patchtest 会通知提交者, 以减轻维护者的审阅负担。

备注

系统并不完美,修改有时会在处理过程中被遗漏。 如果补丁一段时间没有进展和反馈,询问状态是合理的。

几天没有反馈的补丁也可能已经合入,可以运行 git pull branch 检查。 许多层维护者接受补丁后并不会发送确认邮件。 如果几天后仍没有回复也没有合入,可能是补丁被遗漏,或相关审阅者暂时不在。 此时可以回复自己的邮件,提醒并请求反馈。

备注

功能冻结期间,功能补丁和配方升级补丁的审阅可能推迟, 因为此时不合入这类修改,可能需要等冻结结束。

维护者通常还会用 -next 分支在正式合入前测试提交。 因此,查看补丁是否进入这些分支,也能了解它的状态。 OpenEmbedded-Core 常用测试分支如下:

  • openembedded-core 的 "master-next": 位于 openembedded-core,包含对核心元数据的候选修改。

  • bitbake 的 "master-next": 位于 bitbake,包含对 BitBake 的修改。

  • meta-yocto 的 "master-next": 位于 meta-yocto,包含对 meta-yocto 的候选修改。

类似地,项目维护的稳定分支也可能有对应的 -next 分支,收集候选修改。 例如,"openembedded-core" 和 "meta-yocto" 仓库中的 blacksail-next 和 wrynose-next。

其他层也可能有类似测试分支,但没有统一要求或标准,请查看所贡献层的文档。

4 接受 AI 生成的代码

Yocto 项目和 OpenEmbedded 对生成式 AI 工具的使用遵循 Linux 基金会的指导: https://www.linuxfoundation.org/legal/generative-ai。

本文件现有的全部准则仍须遵守,包括 配方风格指南。 此外,在 实现并提交修改 所述要求之外,还需满足以下条件。

所有 AI 生成的代码都必须在提交说明中明确标注,放在 Signed-off-by 行之前。 同时强烈建议,提交中的补丁或代码也通过注释或其他方式表明其由 AI 生成。

以下是格式正确的提交说明示例::

component: Add the ability to ...

AI-Generated: Uses GitHub Copilot

Signed-off-by: Your Name <your.name@domain>

Signed-off-by 必须由你本人填写,不能由 AI 助手代写。 贡献修改时,这一签署行仍然是必需的, 开发者来源证明 1.1 的规定仍然适用。

此外,你必须确认 AI 贡献符合 Linux 基金会政策,具体包括:

  1. 确保生成式 AI 工具的条款不会对输出的使用施加与项目开源许可证、 知识产权政策或开源定义不一致的合同限制。

  2. 如果 AI 输出包含由第三方创作或拥有版权的既有材料,包括已有开源代码, 贡献之前应确认已获得第三方权利人的许可,允许使用、修改并向项目贡献这些材料。 许可可以是符合项目许可政策的开源许可证或公有领域声明等形式。 同时,应随贡献提供第三方权利的声明和署名,以及适用许可证条款的信息。