# 5.6 使用源代码更新 FreeBSD

从源代码构建 FreeBSD 可以自定义内核选项和编译参数，适用于 freebsd-update 不支持的架构或需要裁剪系统的场景。

基本思路是获取 FreeBSD 的源代码，然后编译安装。可以使用 Git 直接拉取代码，也可以从 ISO 镜像中下载 txz 压缩文件，或者从 GitHub 下载当前 FreeBSD 项目的 zip 压缩包。

编译流程参见 Handbook 即可。

## SVN 到 Git 的迁移

FreeBSD 项目在 2020 至 2021 年间从 SVN 迁移到了 Git，即 <https://git.freebsd.org>。其中 src 仓库于 2020 年底完成迁移，Ports 仓库于 2021 年初完成迁移。

这一版本控制系统的迁移标志着 FreeBSD 项目开发流程的现代化转型，因此获取源代码的方式也相应发生了变化，不再使用 SVN。

## 从 Git 获取源代码

### 安装 Git

使用 pkg 安装 Git：

```sh
# pkg install git
```

或者使用 Ports 安装 Git：

```sh
# cd /usr/ports/devel/git/
# make install clean
```

### Git 代理设置方法

在网络环境受限制的情况下，可能需要为 Git 设置代理才能正常拉取源代码。下面介绍设置和取消 Git 代理的方法。

* 设置 Git 全局代理：

```sh
# git config --global http.proxy http://192.168.X.X:7890  # 设置 Git 全局 HTTP 代理
# git config --global https.proxy http://192.168.X.X:7890  # 设置 Git 全局 HTTPS 代理
```

* 取消 Git 全局代理：

```sh
# git config --global --unset http.proxy  # 取消 Git 全局 HTTP 代理设置
# git config --global --unset https.proxy  # 取消 Git 全局 HTTPS 代理设置
```

### Git 拉取源代码

#### 拉取 CURRENT

通过 FreeBSD 官方存储库拉取。克隆 FreeBSD 源代码仓库到 **/usr/src**，使用浅克隆减少下载量：

```sh
$ git clone --depth 1 https://git.FreeBSD.org/src.git /usr/src
```

参数 `--depth 1` 说明：浅克隆，仅拉取最新的提交，不拉取全部的日志及历史记录。

或者通过 GitHub 拉取（GitHub 是 FreeBSD.org 上 src 仓库的镜像，每 10 分钟同步一次）。

```sh
$ git clone --depth 1 https://github.com/freebsd/freebsd-src /usr/src
```

#### 拉取某 RELEASE

通过 FreeBSD 官方存储库拉取。克隆 FreeBSD 15.0 发布分支源代码到 **/usr/src**，使用浅克隆并仅包含该分支：

```sh
$ git clone --branch releng/15.0 --single-branch --depth 1 https://git.freebsd.org/src.git /usr/src
```

选项解释：

* `--branch releng/15.0`：指定拉取分支（FreeBSD RELEASE 的版本）
* `--single-branch`：仅克隆一个分支，除所克隆的单一分支外不含任何其他引用（refs）。

或者通过 GitHub 拉取。从 GitHub 克隆 FreeBSD 15.0 发布分支源代码到 **/usr/src**，使用浅克隆并仅包含该分支：

```sh
$ git clone --branch releng/15.0 --single-branch --depth 1 https://github.com/freebsd/freebsd-src /usr/src
```

### 参考文献

* Warner Losh. Submitting GitHub Pull Requests to FreeBSD\[EB/OL]. \[2026-03-25]. <https://freebsdfoundation.org/our-work/journal/browser-based-edition/configuration-management-2/submitting-github-pull-requests-to-freebsd/>. 详解通过 GitHub 向 FreeBSD 提交拉取请求的工作流程与注意事项。

## 从压缩包获取源代码（方便但非最新）

该方法较为简单快捷。

以 FreeBSD 15.0-RELEASE 为例：

```sh
# fetch https://download.freebsd.org/ftp/releases/amd64/15.0-RELEASE/src.txz  # 下载 FreeBSD 15.0-RELEASE 的源代码压缩包
# tar xvf src.txz -C /                                                    # 将源代码解压到根目录
```

> **为何要解压到 `/`？**
>
> 因为解压到 **/** 会将源代码解压到 **/usr/src**。如果将上面的路径改为 **/usr/src**，会将源代码解压到 **/usr/src/usr/src**。因为该压缩包包含路径。

> **技巧**
>
> 如果速度慢可以切换到 <https://mirrors.ustc.edu.cn/freebsd/releases/amd64/15.0-RELEASE/src.txz>

## 开始编译

```sh
# cd /usr/src          # 切换到工作目录
# make -j4 buildworld  # 编译世界
# make -j4 kernel      # 编译并安装内核
# reboot               # 重启以使用新内核
# cd /usr/src          # 切换回工作目录
# etcupdate -p         # 进行必要的配置文件合并
# make installworld    # 安装世界
# etcupdate -B         # 合并更新
# reboot               # 重启以完成更新流程
```

### 附录：解决冲突

* `Conflicts remain from previous update, aborting.`

需要解决冲突。

> **技巧**
>
> 与绝大多数现代 Linux 不同，[FreeBSD](https://github.com/freebsd/freebsd-src/tree/main/contrib/nvi)（OpenBSD）上的 `vi` 是 [*nvi*](https://sites.google.com/a/bostic.com/keithbostic/keith-bostic?authuser=0)（原版 **ex/vi** 的再实现），并非指向任何 *vim* 的符号链接。鲜有人使用，也无学习的必要，因此有必要更换为其他文本编辑器。
>
> ```sh
> export EDITOR=/usr/bin/ee # 切换 vi 为 ee。针对 FreeBSD 14 之前的版本或 csh 使用：setenv EDITOR /usr/bin/ee
> export VISUAL=/usr/bin/ee # 切换 vi 为 ee。针对 FreeBSD 14 之前的版本或 csh 使用：setenv VISUAL /usr/bin/ee
> ```

合并冲突。使用 `etcupdate` 执行备份模式，以便在更新配置文件前备份现有文件：

```sh
# etcupdate -B
Conflicts remain from previous update, aborting.
```

`etcupdate` 在合并后会自动触发若干系统文件的后续处理：

* 若 **/etc/master.passwd** 变更则自动调用 `pwd_mkdb`；
* 若 **/etc/login.conf** 变更则自动调用 `cap_mkdb`；
* 若 **/etc/mail/aliases** 变更则自动调用 `newaliases`；
* 若 **/etc/services** 变更则自动调用 `services_mkdb`；
* 若 **/etc/localtime** 变更且 **/var/db/zoneinfo** 存在则自动调用 `tzsetup`。

解决冲突：

```sh
# etcupdate resolve          # 解决冲突
Resolving conflict in '/etc/group':
Select: (p) postpone, (df) diff-full, (e) edit,
        (h) help for more options: e # 输入 e 解决冲突
# etcupdate -B
```

## 故障排除与未竟事宜

### Git：`fatal: unable to update url base from redirection`

使用 FreeBSD 源仓库地址时未加 `.git` 后缀。

### Git：`fatal: unable to access 'https://git.FreeBSD.org/src.git/': SSL certificate problem: certificate is not yet valid`

可能是系统时间不正确导致的，使用 `pool.ntp.org` 服务器同步系统时间。

```sh
# ntpd -q -g pool.ntp.org # 当时间相差较大时必须使用该命令
```

## 参考文献

* FreeBSD Foundation. 2021 in Review: Software Development\[EB/OL]. \[2026-04-16]. <https://freebsdfoundation.org/blog/2021-in-review-software-development/>
* FreeBSD Project. etcupdate -- manage updates to system files not updated by installworld\[EB/OL]. \[2026-03-25]. <https://man.freebsd.org/cgi/man.cgi?query=etcupdate&sektion=8>. 系统配置文件更新工具的官方技术文档。

## 课后习题

1. 总结从 FreeBSD Git 仓库获取源代码的完整流程，列出所需命令及参数含义。
2. 使用 etcupdate 管理 **/etc** 目录的配置文件更新，记录一次完整的合并冲突处理过程。
3. 修改 **/etc/src.conf**，排除不需要的组件（如某些调试工具），测量 `make buildworld` 编译时间的变化。


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://book.bsdcn.org/di-5-zhang-ruan-jian-guan-li-he-xi-tong-sheng-ji/di-5.6-jie-shi-yong-yuan-dai-ma-geng-xin-freebsd.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
