引言
derivation 的第一步永远是拿到源码。Nix 用 fetcher 把「下载」变成「可校验、可复现」的操作:每个 fetcher 都是固定哈希的 derivation,内容确定才能进缓存。本文讲清 fetcher 的选择(URL vs Git vs GitHub)、哈希格式与 SRI、私有仓库与凭据处理、flake inputs 的 url 写法,以及最常见的坑。
前置:/nix-package-management/(derivation 与 nixpkgs)、/nix-reproducible-hermetic-builds/(固定哈希)、/nix-flakes/(inputs 机制)。
目录
- 1. fetcher:把下载变成可校验的操作
- 2. 按场景选 fetcher
- 3. fetchurl:下载单个文件
- 4. fetchFromGitHub 与 fetchFromGitLab
- 5. fetchgit:任意 Git 仓库与子模块
- 6. 哈希格式与 SRI
- 7. 私有仓库与凭据处理
- 8. fetchpatch:获取补丁
- 9. flake inputs 的 url 获取
- 10. 速查表与一句话记忆
- 延伸阅读
1. fetcher:把下载变成可校验的操作
1.1 为什么需要 fetcher
普通构建脚本里 curl https://... 是不可复现的——下载内容变了构建就变。fetcher 把下载包装成固定哈希 derivation:声明「我要内容=X 的东西」,下载后按哈希校验,不一致直接失败。这让「源码来源」变成可验证的事实。
1.2 fetcher 的通用形态
# 所有 fetcher 返回一个"内容确定"的 derivation
src = pkgs.fetchFromGitHub {
owner = "NixOS";
repo = "nix";
rev = "2.20.0";
hash = "sha256-..."; # 期望内容哈希
};
记忆:fetcher 把下载包装成固定哈希 derivation——声明期望哈希、下载后校验,让「源码来源」可验证、可缓存、可复现。
2. 按场景选 fetcher
| 场景 | fetcher | 说明 |
|---|---|---|
| 单个文件/归档 | fetchurl | 任意 URL 下载 |
| GitHub 仓库快照 | fetchFromGitHub | 按 owner/repo/rev |
| GitLab 仓库 | fetchFromGitLab | 同 GitHub 形态 |
| 任意 Git 仓库 | fetchgit | 通用、含子模块 |
| 补丁 | fetchpatch | 获取统一 diff |
| flake 输入 | url 语法 | flake 专用获取 |
选型原则:GitHub 用 fetchFromGitHub、任意 Git 用 fetchgit、单文件用 fetchurl——专用 fetcher 更稳(自动处理归档格式)。
记忆:选 fetcher 看来源——GitHub 用 fetchFromGitHub、GitLab 用 fetchFromGitLab、任意 Git 用 fetchgit、单文件用 fetchurl、补丁用 fetchpatch;专用 fetcher 处理格式更稳。
3. fetchurl:下载单个文件
3.1 基础用法
src = pkgs.fetchurl {
url = "https://example.com/files/tool-1.2.tar.gz";
hash = "sha256-...";
};
3.2 传参给下载
src = pkgs.fetchurl {
url = "https://example.com/api/1.2.zip";
hash = "sha256-...";
# 下载可选参数
curlOpts = "-H 'Authorization: Bearer xxx'"; # 需要认证时(慎用,别硬编码)
};
3.3 多文件/多 URL
# 多个 URL 自动选可用(镜像)
srcs = map (url: pkgs.fetchurl { inherit url; hash = "sha256-..."; }) urls;
记忆:fetchurl 下载单个文件/归档,指定 url + hash;需要认证用 curlOpts(但别把密钥硬编码进 nix 表达式)。
4. fetchFromGitHub 与 fetchFromGitLab
4.1 fetchFromGitHub
src = pkgs.fetchFromGitHub {
owner = "kubernetes";
repo = "kubernetes";
rev = "v1.30.0";
hash = "sha256-...";
# 可选:只取子目录/稀疏检出
# sparseCheckout = [ "src" "pkg" ];
};
rev 用提交哈希或 tag。生产建议锁定具体提交哈希(比 tag 更防篡改)。
4.2 fetchFromGitLab
src = pkgs.fetchFromGitLab {
domain = "gitlab.com";
owner = "gitlab-org";
repo = "gitlab";
rev = "17.0.0";
hash = "sha256-...";
};
记忆:fetchFromGitHub 按 owner/repo/rev 取仓库快照(rev 用提交哈希最稳)、fetchFromGitLab 同形态指定 domain;归档自动处理、内容哈希校验。
5. fetchgit:任意 Git 仓库与子模块
5.1 基础用法
src = pkgs.fetchgit {
url = "https://example.com/myrepo.git";
rev = "a1b2c3d4...";
sha256 = "sha256-...";
};
5.2 子模块与分支
src = pkgs.fetchgit {
url = "https://example.com/myrepo.git";
rev = "a1b2c3d4...";
sha256 = "sha256-...";
fetchSubmodules = true; # 拉取子模块(内容也进哈希)
# 分支/标签:rev 支持分支名,但生产用哈希
};
5.3 什么时候用 fetchgit 而非 fetchFromGitHub
# 仓库不在 GitHub/GitLab(自建 git、Bitbucket 等)
# 需要子模块/深度控制
# 需要 clone 而非归档(build 依赖 .git 目录)
# 代价:比归档慢、哈希更易受环境扰动
记忆:fetchgit 通用拉任意 Git 仓库(含子模块 fetchSubmodules、.git 保留);非 GitHub/GitLab、需子模块或 clone 时用它,生产 rev 锁提交哈希。
6. 哈希格式与 SRI
6.1 两种格式
传统格式:sha256-<base64>(nix hash 输出的 base32 或 base64)
SRI 格式:sha256-<base64 of raw hash>("sha256-" + base64,自描述算法)
现代 nixpkgs 用 SRI 格式(前缀自带算法名,如 sha256-.../sha512-...)。flake 里补丁/源哈希也统一 SRI。
6.2 生成哈希
nix hash file ./mypkg.tar.gz # 对文件算哈希
nix hash path ./mysource-dir # 对目录算(fetchgit 用)
nix hash to-sri --type sha256 "base32..." # 老格式转 SRI
6.3 哈希不匹配时的处理
# 构建报 "got: sha256-XXX",把 XXX 替换进表达式
# 但要警惕:改了 rev 却"复制 got 哈希"可能掩盖源变化
# 确认 got 的来源符合预期再替换
记忆:哈希用 SRI 格式(sha256-
自描述算法);nix hash file/path 生成、to-sri 转换;报错 got 值先确认来源再替换 。
7. 私有仓库与凭据处理
7.1 私有的原则
# 私有源的最大原则:凭据不进 nix 表达式、不进 git
# 公开仓库永远别放 token;私有仓库也要最小化暴露
7.2 凭据注入方式
# 方式一:用 override 传下载参数(构建时提供)
src = pkgs.fetchgit {
url = "https://user:${token}@git.example.com/repo.git"; # 别直接写 token!
rev = "...";
sha256 = "...";
};
正确的做法是把 token 放环境/机密管理,构建时注入,而不是写死在表达式里:
# 构建前从 secrets 提供
export NIX_CONFIG='extra-http-options = { headers = "Authorization: Bearer $(cat /run/secrets/token)"; }'
7.3 更安全的替代
# 优先考虑:把私有源先同步到一个内网镜像/缓存,公开获取
# 或用 sops-nix/agenix 托管凭据,构建时解密注入
# 无论如何:token 不进 git、不进公开配置
记忆:私有源凭据三原则——不进 nix 表达式、不进 git、最小暴露;用环境注入/NIX_CONFIG 头/agenix 托管,构建时解密,公开源优先走镜像。
8. fetchpatch:获取补丁
8.1 基础用法
patch = pkgs.fetchpatch {
url = "https://github.com/upstream/repo/commit/abc123.patch";
hash = "sha256-...";
# 可选:从补丁中排除某些文件
# excludes = [ "CHANGELOG.md" ];
};
8.2 与 overrideAttrs 配合
myPkg = pkgs.mypkg.overrideAttrs (old: {
patches = (old.patches or []) ++ [
(pkgs.fetchpatch { url = "..."; hash = "sha256-..."; })
];
});
8.3 补丁获取的注意
# fetchpatch 只接受统一 diff(git format-patch 输出)
# 上游把同一 commit 改了 hash → 构建失败,hash 需要更新
# 补丁内容进 derivation 哈希 → 补丁变化会影响整个包重建
记忆:fetchpatch 获取统一 diff 补丁,配 overrideAttrs.patches 打入;上游改 commit 会 hash 失败需更新——补丁变化会触发整包重建。
9. flake inputs 的 url 获取
9.1 在 flake 里获取源码
{
inputs = {
# 直接按 URL 声明输入
myrepo = {
url = "github:owner/repo"; # GitHub
flake = false; # 当作普通源码而非 flake
};
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
other = { url = "git+https://git.example.com/repo"; }; # 任意 git
};
outputs = { self, myrepo, ... }@inputs: {
packages.${system}.default = pkgs.stdenv.mkDerivation {
pname = "from-flake-input";
version = "0.1";
src = inputs.myrepo; # flake=false 时 src 直接可用
};
};
}
9.2 lock 文件的角色
# flake.lock 锁定每个 input 的 rev + 哈希
# 更新 input:nix flake update <name> / nix flake lock
# 锁定保证:别人 clone 后拿到与开发者完全相同的源码
记忆:flake 里源码获取用 inputs url(github:/git+https:),flake=false 让输入成为普通源码直接当 src;flake.lock 锁定 rev+哈希,
nix flake update显式升级。
10. 速查表与一句话记忆
| fetcher | 场景 | 一句话 |
|---|---|---|
| fetchurl | 单文件/归档 | 任意 URL 下载 |
| fetchFromGitHub | GitHub 仓库 | owner/repo/rev |
| fetchFromGitLab | GitLab 仓库 | 同 GitHub 形态 |
| fetchgit | 任意 Git | 含子模块/clone |
| fetchpatch | 补丁 | 统一 diff |
| flake url input | flake 内源码 | github:/git+https: |
一句话记忆:源码获取全看 fetcher——fetchurl 下载单文件/归档、fetchFromGitHub/fetchFromGitLab 按 owner/repo/rev 取平台仓库快照、fetchgit 拉任意 Git(含子模块)、fetchpatch 取补丁配 overrideAttrs.patches、flake 里用 inputs url(github:/git+https:,flake=false 当普通源码);所有 fetcher 都是固定哈希 derivation——SRI 格式哈希自描述算法、nix hash file/path 生成、报错 got 值先确认来源再替换;私有源凭据三原则「不进表达式、不进 git、最小暴露」,用环境注入/agenix 托管、公开源优先走镜像;flake.lock 锁定 rev+哈希保证他人与开发者拿到完全相同的源码——「下载可校验、来源可追溯」是 Nix 供应链的底气。
延伸阅读
- /nix-package-management/ — derivation 与 nixpkgs
- /nix-reproducible-hermetic-builds/ — 固定哈希与确定性
- /nix-package-patching/ — overrideAttrs 与补丁
- /nix-flakes/ — flake inputs 与 lock
- /nix-debugging-error-handling/ — 哈希错误排查
- [[devops]] — 供应链与依赖管理
- Nix fetchers 手册
- Nix 哈希生成指南
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。