1. Flake = 描述,Lock = 实例#
flake.nix 描述依赖关系(Dependency Specification),flake.lock 锁定依赖实例(Dependency Resolution)。
flake.nix
│
├── nixpkgs = github:NixOS/nixpkgs/nixos-unstable
└── home-manager = github:nix-community/home-manager
│
flake.lock
│
├── nixpkgs -> commit A
├── home-manager -> commit B
└── narHash没有 flake.lock,nixos-unstable 始终指向最新 commit,构建不可复现;可复现性来自 (flake.nix + flake.lock)。
2. 为什么更新的是整个 nixpkgs#
Nix 不管理单个 package,而管理 package set。
nixpkgs(commit A)
├── git
├── gcc
├── firefox
└── neovim
↓
nixpkgs(commit B)
├── git
├── gcc
├── firefox
└── neovim更新 nixpkgs 输入会更换整个 package set 的定义,可能让多个软件及共享依赖一起改变;实际构建只涉及配置需要的闭包。
如果只想追新某个软件,可引入第二个 nixpkgs 并从中选择该包,也可维护 overlay、单独的 Flake 包或固定源码的 derivation。这些方式仍可能引入不同依赖,需检查兼容性,不能把它理解为传统包管理器的原地单包升级。
3. flake update 的本质#
nix flake update更新所有 input。
nix flake update nixpkgs仅更新指定 input。
本质均为:
修改 flake.lock不会修改 flake.nix,不会自动 rebuild。
4. follows#
推荐:
home-manager.inputs.nixpkgs.follows = "nixpkgs";作用:
没有 follows
my flake
├── nixpkgs(A)
└── home-manager
└── nixpkgs(B)
有 follows
my flake
├── nixpkgs(A)
└── home-manager
└── follows -> nixpkgs(A)减少重复的输入来源;不保证消除 Store 中所有重复包,也需检查版本兼容性。
5. Generation 与 Store#
Generation 不是系统副本,而是一组指向 /nix/store 的符号链接。
/run/current-system
│
└── symlink
│
▼
/nix/store因此:
- Generation 很轻量。
- 闭包完整时,相关产物可复用;求值仍需所引用的源和其他输入。
- Store 缺失才需要下载或构建。
6. 为什么更新下载很多#
更新 flake.lock 后,整个 package set 可能变化。
例如:
mesa
linux
linux-firmware
systemd
glibc
llvm即使自己没有显式安装,也可能因依赖链发生变化而更新。
7. Binary Cache 与 fetchFromGitHub#
Binary Cache:
cache.nixos.org
↓
下载已构建好的 narfetchFromGitHub:
GitHub
↓
下载源码(若 Store/缓存中没有)
↓
构建或复用缓存产物二者是不同阶段:源码固定输出 derivation 和最终包都可能被缓存;缓存命中可避免实际下载或构建。
Binary Cache 正常 ≠ GitHub 正常。
8. 源码下载失败的依赖传播示例#
假设首个失败来源是字体源码下载:
example-font
↓
fetchFromGitHub
↓
codeload.github.com
↓
下载失败随后依赖它的构建也可能失败:
example-font
↓
font-package-set
↓
fontconfig
↓
system-path
↓
system均属于依赖传播,不是独立错误。
排查原则:永远定位第一个失败的 .drv。
9. 为什么不能自动改用 jsDelivr#
fetchFromGitHub 固定:
- URL
- hash
- 输出内容
修改来源后应核验内容:规范化输出若完全相同,可以保留 hash;内容不同则需要新的准确 hash。不能仅替换域名就假定归档格式和路径相同。
如果自行维护 derivation,可以使用:
fetchurl并改为 jsDelivr,但必须:
- 固定 commit/tag,不使用
main - 更新 hash
10. 本次理解的核心#
更新 nixpkgs 输入会改变 package set;Nix 也能独立管理 derivation 和包。可复现性的最小单位不是配置,而是 (flake.nix + flake.lock);系统状态不是文件集合,而是 Generation → Store 的引用关系。
多数看似 " 不方便 " 的设计(依赖图更新、严格校验 hash、锁定输入)都服务于同一目标:可复现性(Reproducibility)与一致性(Consistency)。
参考与延伸
根据技术笔记重新整理,示例使用通用名称。