如何让 NixOS 显示一次更新的具体内容

当 NixOS 配置好了 flake、home-manager 等等,后续的更新我们只需要运行:

 1❯ nix flake update
 2
 3❯ sudo nixos-rebuild switch
 4building the system configuration...
 5activating the configuration...
 6setting up /etc...
 7reloading user units for davinci42...
 8restarting sysinit-reactivation.target
 9the following new units were started: NetworkManager-dispatcher.service
10Done. The new configuration is /nix/store/mp17nhbadmffs9ah961ldj0y1l38a73m-nixos-system-azure-25.05.20250424.f771eb4

除了 kernel 的更新需要重启,某些环境变量需要新开 session 之外,其它 pkg 和对应的 systemd-service 应该都是最新的状态了。

但是上面的 log 中,我们是不知道这一次的 switch 具体更新了什么的。
如果 nixpkgs 和 home-manager 的 repo 有新的 commit 我们是可以知道 hash 更新,但是 2 次 commit 之间更新的 pkg 我们是不知道的。
有什么方式,能让我们看到更新前后 2 个 generation 的 diff 吗?

可以使用 nvd1 这个 pkg,它支持对 2 个 generation 做 diff,比如:

1❯ nvd diff /run/booted-system /run/current-system
2<<< /run/booted-system
3>>> /run/current-system
4No version or selection state changes.
5Closure size: 1144 -> 1144 (10 paths added, 10 paths removed, delta +0, disk usage +1.3KiB).

同样的方式,我们就可以对任意 generation 做 diff 了:

1❯ ls -al /nix/var/nix/profiles
2total 52
3drwxr-xr-x 3 root root 4096 Apr 27 20:54 .
4drwxr-xr-x 9 root root 4096 Apr 27 20:15 ..
5lrwxrwxrwx 1 root root   43 Apr  4 00:00 default -> /nix/var/nix/profiles/per-user/root/profile
6drwxr-xr-x 3 root root 4096 Apr  3 17:25 per-user
7lrwxrwxrwx 1 root root   15 Apr 27 20:54 system -> system-166-link
8lrwxrwxrwx 1 root root   85 Apr 27 20:53 system-165-link -> /nix/store/b66ijf8hscs19bz2d8ph6baxgn6p6ff7-nixos-system-azure-25.05.20250424.f771eb4
9lrwxrwxrwx 1 root root   85 Apr 27 20:54 system-166-link -> /nix/store/k57fs0isb02siaaj1vyvjfgsxz882jp1-nixos-system-azure-25.05.20250424.f771eb4

但是这样其实很不方便,我们并不想每次来到这个目录下,找到最后的 2 个 generation 来手动 diff。

正好每次 NixOS 更新也是 2 个单独的命令,写个脚本一起封装了吧:

1alias nfu="treefmt -q . && nix flake update"
2alias nrs="sudo nixos-rebuild switch"
3function ns() {
4    local curVer=$(realpath /run/current-system)
5    nfu && nrs && nvd diff $curVer $(realpath /run/current-system)
6}
  1. 记录 switch 之前的 system 对应的 generation
  2. 对 nixos config 目录下所有 .nix 文件做格式化
  3. 更新 flake
  4. rebuild switch
  5. nvd 做 diff

为什么要做临时变量记录 switch 之前的 path 呢?
因为我们永远可以通过 realpath /run/current-system 找到当前的 path,但是找不到 switch 之前的上一个 path。


我们给 environment.systemPackages 添加 neovim 试试看:

 1❯ ns
 2building the system configuration...
 3activating the configuration...
 4setting up /etc...
 5reloading user units for davinci42...
 6restarting sysinit-reactivation.target
 7reloading the following units: dbus.service
 8the following new units were started: NetworkManager-dispatcher.service
 9Done. The new configuration is /nix/store/dc1j0mljl3dvlcn1qlk0qfjfs46kzs12-nixos-system-azure-25.05.20250424.f771eb4
10<<< /nix/store/abccik16826yrr4jgys1mhmkx3qbwp6a-nixos-system-azure-25.05.20250424.f771eb4
11>>> /nix/store/dc1j0mljl3dvlcn1qlk0qfjfs46kzs12-nixos-system-azure-25.05.20250424.f771eb4
12Version changes:
13[C.]  #1  python3  3.12.9 x2 -> 3.12.9 x2, 3.12.9-env
14Added packages:
15[A.]  #01  c-grammar-neovim                0.11.0
16[A.]  #02  libluv                          1.48.0-2
17[A.]  #03  lua-grammar-neovim              0.11.0
18[A.]  #04  luajit                          2.1.1741730670, 2.1.1741730670-env x2
19[A.]  #05  luajit2.1-lpeg                  1.1.0-2
20[A.]  #06  luajit2.1-luabitop              1.0.2-3
21[A.]  #07  luajit2.1-mpack                 1.0.12-0
22[A.]  #08  markdown-grammar-neovim         0.11.0
23[A.]  #09  markdown_inline-grammar-neovim  0.11.0
24[A+]  #10  neovim                          0.11.0
25[A.]  #11  neovim-unwrapped                0.11.0
26[A.]  #12  python3.12-greenlet             3.1.1
27[A.]  #13  python3.12-msgpack              1.1.0
28[A.]  #14  python3.12-pynvim               0.5.2
29[A.]  #15  query-grammar-neovim            0.11.0
30[A.]  #16  tree-sitter                     0.25.3
31[A.]  #17  unibilium                       2.1.2
32[A.]  #18  utf8proc                        2.10.0
33[A.]  #19  vim-grammar-neovim              0.11.0
34[A.]  #20  vimdoc-grammar-neovim           0.11.0
35Closure size: 1145 -> 1168 (34 paths added, 11 paths removed, delta +23, disk usage +49.0MiB).

很完美!但是这么做具体有什么意义呢?

也没什么,看到 kernel 更新会记得重启一下吧。