# 11.1.使用 Git 制作补丁

当某 Port 不是作者发布的最新版本时，请更新本地工作副本 **/usr/ports**。该 Port 可能已经被更新到新版本。

如果要处理多个 Port，使用 Git 来保持整个 Ports 最新可能会更加方便，正如在 [Using the Ports Collection](https://docs.freebsd.org/en/books/handbook/ports#ports-using) 中所描述的。这还可以跟踪所有 Port 的依赖项。

接下来的步骤是检查是否已经有一个更新待处理。为此，有两种方法。可以通过可搜索的界面访问 [FreeBSD 问题报告（PR）或 bug 数据库](https://bugs.freebsd.org/search/)，在 `Product` 的多选菜单中选择 `Ports & Packages`，然后在 `Summary` 字段中输入 Port 的名称。

如果没有待处理的 PR，接下来的步骤是向 Port 的维护者发送电子邮件，如通过 `make maintainer` 显示的那样。维护者可能已经在进行升级，或者有不升级该 Port 的理由（例如新版本可能存在稳定性问题），这时就没有必要重复他们的工作。注意，未维护的 Ports 会列出 `ports@FreeBSD.org` 作为维护者，这是一个通用的 Ports 邮件列表，因此在这种情况下发送邮件可能没有帮助。

如果维护者要求你进行升级，或者该 Port 没有维护者，那么可以帮助 FreeBSD 准备更新！可以使用基本系统中的 [diff(1)](https://man.freebsd.org/cgi/man.cgi?query=diff\&sektion=1\&format=html) 命令来完成。

要为单个补丁创建合适的 `diff`，将需要修补的文件复制为 **something.orig**，保存更改为 **something**，然后创建补丁：

```sh
% diff -u something.orig something > something.diff
```

否则，可以使用 `git diff` 方法（请参阅 [Using Git to Make Patches](https://docs.freebsd.org/en/books/porters-handbook/upgrading/#git-diff)）或者将 Port 的内容复制到另一个目录，并使用新的和旧的 Port 目录的递归 [diff(1)](https://man.freebsd.org/cgi/man.cgi?query=diff\&sektion=1\&format=html) 输出结果（例如，如果修改过的 Port 目录称为 **superedit**，原目录为 **superedit.bak**，则保存 `diff -ruN superedit.bak superedit` 的结果）。统一或上下文 diff 都可以，但 Port 提交者通常更喜欢统一格式的 diff。注意使用 `-N` 选项——这是处理新文件添加或旧文件删除的标准方法。在提交 diff 之前，请检查输出，确保所有更改都合理。（特别是，确保首先使用 `make clean` 清理工作目录。）

> **注意**
>
> 如果有文件被添加、复制、移动或删除，请将此信息添加到问题报告中，以便提交补丁的提交者知道需要执行哪些 [git(1)](https://man.freebsd.org/cgi/man.cgi?query=git\&sektion=1\&format=html) 命令。

为了简化常见的补丁操作，可以使用 `make makepatch`，如在 [Patching](https://docs.freebsd.org/en/books/porters-handbook/slow-porting/#slow-patch) 中所述。还可以使用其他工具，如 **/usr/ports/Tools/scripts/patchtool.py**。在使用之前，请阅读 **/usr/ports/Tools/scripts/README.patchtool**。

如果该 Port 没有维护者，并且你正在积极使用它，请考虑自愿成为它的维护者。FreeBSD 有超过 4000 个没有维护者的 Ports，这是一个总是需要更多志愿者的领域。（有关维护者职责的详细描述，请参阅 [Developer’s Handbook](https://docs.freebsd.org/en/books/developers-handbook/#POLICIES-MAINTAINER) 章节。）

要提交 diff，请使用 [bug 提交表单](https://bugs.freebsd.org/submit/)（产品 `Ports & Packages`，组件 `Individual Port(s)`）。始终在 Port 名称后附上类别，并简要描述问题。例如：`category/portname:<span> </span>add FOO option`；`category/portname:<span> </span>Update to X.Y`。请在消息中提到任何添加或删除的文件，因为在提交时需要明确指定这些文件给 [git(1)](https://man.freebsd.org/cgi/man.cgi?query=git\&sektion=1\&format=html)。不要压缩或编码 diff。

在提交问题报告之前，请查看 [Writing the problem report](https://docs.freebsd.org/en/articles/problem-reports/#pr-writing) 章节中的问题报告编写指南。它包含了有关如何编写有用问题报告的更多信息。

> **重要**
>
> 如果升级是出于安全考虑或当前提交的 Port 存在严重缺陷，请通知 Ports 管理团队 <<portmgr@FreeBSD.org>>，以请求立即重新构建和重新分发该 Port 的包。否则，使用 `pkg` 的用户将继续通过 `pkg install` 安装旧版本，可能会持续几周。

> **注意**
>
> 请使用 [diff(1)](https://man.freebsd.org/cgi/man.cgi?query=diff\&sektion=1\&format=html) 或 `git diff` 来创建现有 Ports 的更新。其他格式可能包括整个文件，使得无法仅查看更改内容。当没有包含 diff 时，整个更新可能会被忽略。

完成这些工作后，请阅读 [Keeping Up](https://docs.freebsd.org/en/books/porters-handbook/keeping-up/#keeping-up) 中关于如何保持更新的内容。

***

如果可能，请提交 [git(1)](https://man.freebsd.org/cgi/man.cgi?query=git\&sektion=1\&format=html) 补丁或 diff。相比于“新旧”目录之间的 diff，它们更容易处理。这样更容易看到变更内容，并且如果在开始工作后 Ports 集合中有所修改，或者提交者要求修复某些内容，可以更容易地更新 diff。此外，使用 [git-format-patch(1)](https://man.freebsd.org/cgi/man.cgi?query=git-format-patch\&sektion=1\&format=html) 或 [git-diff(1)](https://man.freebsd.org/cgi/man.cgi?query=git-diff\&sektion=1\&format=html) 生成的补丁，可以通过 [git-am(1)](https://man.freebsd.org/cgi/man.cgi?query=git-am\&sektion=1\&format=html) 或 [git-apply(1)](https://man.freebsd.org/cgi/man.cgi?query=git-apply\&sektion=1\&format=html) 轻松应用，并节省提交者的一些时间。最后，通过 [git-format-patch(1)](https://man.freebsd.org/cgi/man.cgi?query=git-format-patch\&sektion=1\&format=html) 生成的 Git 补丁包含你的作者信息和提交消息。这些信息将记录在仓库的日志中，这是提交更改的推荐方式。

```sh
% git clone https://git.FreeBSD.org/ports.git ~/my_wrkdir  ①②
% cd ~/my_wrkdir
```

* ① 当然，这个路径可以是任何位置。构建 Ports 并不限于 **/usr/ports/**。
* ② [git.FreeBSD.org](https://git.freebsd.org/) 是 FreeBSD 的公共 Git 服务器。有关更多信息，请参阅 [FreeBSD Git Repository URL Table](https://docs.freebsd.org/en/books/handbook/mirrors#git-url-table)。

在 Port 目录中，进行必要的更改。如果是添加、移动或删除文件，请使用 `git` 来跟踪这些更改：

```sh
% git add new_file
% git mv old_name new_name
% git rm deleted_file
```

确保使用 [Testing the Port](https://docs.freebsd.org/en/books/porters-handbook/quick-porting/#porting-testing) 和 [Checking the Port with `portlint`](https://docs.freebsd.org/en/books/porters-handbook/quick-porting/#porting-portlint) 中的检查清单来检查该 Port。

同时，使用 `make makesum` 更新 distinfo 中的校验和引用。

在制作补丁之前，获取最新的仓库并将更改 rebase 到其之上。仔细观察并跟踪输出。如果有任何文件 rebase 失败，意味着在你编辑同一个文件时，源文件发生了变化，需要手动解决冲突。

```sh
% git fetch origin main
% git rebase origin/main
```

检查待提交的更改：

```sh
% git status
% git diff --staged
```

最后一步是生成统一的 diff 或补丁：

要使用 [git-format-patch(1)](https://man.freebsd.org/cgi/man.cgi?query=git-format-patch\&sektion=1\&format=html) 生成补丁：

```sh
% git checkout -b my_branch
% git commit
% git format-patch main
```

这将生成一个类似于 `0001-foo.patch` 的补丁文件。这是推荐的方式，因为它包含了作者身份信息，而且当你进行一系列不打算合并在一起的更改时也更方便。

另外，要使用 [git-diff(1)](https://man.freebsd.org/cgi/man.cgi?query=git-diff\&sektion=1\&format=html) 生成统一的 diff，可以执行：

```sh
% git diff --staged > ../`make -VPKGNAME`.diff
```

这将生成一个类似于 `foo-1.2.3.diff` 的 diff 文件，其中 `foo` 替换为提交消息的第一行，即提交消息的主题。

补丁创建完成后，你可以切换回主分支开始其他开发工作。

```sh
% git checkout main
```

补丁被接受并合并后，你可以删除本地开发分支（如果你想的话）：

```sh
% git branch -D my_branch
```

> **注意**
>
> 如果文件已添加、移动或删除，请包含使用的 [git(1)](https://man.freebsd.org/cgi/man.cgi?query=git\&sektion=1\&format=html) `add`、`mv` 和 `rm` 命令。必须在补丁应用之前运行 `git mv`。应用补丁后，必须运行 `git add` 或 `git rm`。

按照 [问题报告提交指南](https://docs.freebsd.org/en/articles/problem-reports/#pr-writing) 提交补丁。
