OFFSET偏移
← 文章目录OFFSET / FIELD NOTESNO. 031

Flake 更新机制

区分输入更新、软件包集合、系统代际与缓存下载。

所在专题Flakes:项目与依赖管理 ↗
约 6 分钟阅读开始阅读

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
        ↓
下载已构建好的 nar

fetchFromGitHub:

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)。

参考与延伸

  1. Nix Flake 手册 ↗
  2. Nix flake update ↗
  3. Nix flake check ↗

根据技术笔记重新整理,示例使用通用名称。

沿专题继续阅读

Flakes:项目与依赖管理

  1. 01Flake 结构:inputs 与 outputs
  2. 02flake.lock 与可复现性
  3. 03Flake Utils 与项目模板
  4. 04外部 Flake 引用与协作
  5. 05将 NixOS 配置迁移到 Flakes
  6. 06Flakes 项目与依赖管理教程
  7. 07Flake 更新机制
  8. 08flake.lock 回退与手动编辑
CONTINUE READING / 下一篇flake.lock 回退与手动编辑

保留已有改动后恢复锁文件,并区分依赖回退与系统代际回退。