ShinKouyo の 小栈

用 GNU Stow 管理你的 dotfiles 农场

根据 GNU Free Documentation License, 版本 1.3 或 Free Software Foundation 发布的任何后续版本之条款, 无 Invariant Sections, 无 Front-Cover Texts 及无 Back-Cover Texts, 或根据 Creative Commons Attribution-ShareAlike 4.0 International 之条款, 授予复制, 分发和/或修改本文的许可

StowGNU 项目开发的符号链接农场管理器.

Stow 最初的用途是管理 /usr/local/ 等目录下通过源代码编译的软件. 它将不同软件包的程序文件安装到独立的目录 (如 /usr/local/stow/emacs/), 通过符号链接将这些文件聚合到公共路径 (如 /usr/local/bin/) 中. 这使得软件包的追踪和管理更加简单, 只需要修改其对应的符号链接即可.

这样的理念同样适用于 dotfiles: 用户可以将文件集中存储, 再由 Stow 将它们链接回原位.

Stow 存在于大多数 GNU/Linux 发行版的软件仓库中. 例如, 在 Arch Linux 上, 使用 pacman 安装:

pacman -S extra/stow

1. 基本概念

Stow 基于一个简单的约定工作: 包目录的目录树镜像目标目录的目录树.

例如, 将 ~/.dotfiles/ 作为 Stow 的根目录, 每个子目录代表一个包:

.dotfiles/
└── bash/
    ├── .bashrc
    └── .config/
        └── bash/
            └── bashrc

执行 stow bash 时, Stow 会在 ~ 下创建对应的符号链接:

~/
├── .bashrc -> .dotfiles/bash/.bashrc
└── .config/ -> .dotfiles/bash/.config

stow 的默认目标目录是当前目录的父目录. 因此, 在 ~/.dotfiles/ 内执行 stow bash 会以 ~ 为目标创建链接.

使用 -d 指定 Stow 目录, -t 指定目标目录. 例如:

stow -d ~/my-stow-dir -t ~ bash

2. 使用示例

假设我们在 ~/.dotfiles/bash/ 下准备了上述 .bashrc.config/bash/bashrc.

再次执行 stow 时, 使用 -vv 查看状态:

cd ~/.dotfiles
stow -vv bash

Stow 会报告每个文件的状态:

stow dir is ~/.dotfiles
stow dir path relative to target ~ is .dotfiles
Planning stow of: bash ...
Planning stow of package bash...
    level of .bashrc is 0
--- Skipping .bashrc as it already points to .dotfiles/bash/.bashrc
    level of .config is 0
--- Skipping .config as it already points to .dotfiles/bash/.config
Planning stow of package bash... done
Processing tasks...

-v 接受 0-5 级. -v 仅在创建或删除链接时有输出; -vv 会额外显示已跳过的链接; -vvv 展示完整的处理过程.

在修改 dotfiles 后, 已有的符号链接会自动反映更改. 如果包中添加了新文件, 应重新执行 stow:

-R 会先删除旧的符号链接再重新创建, 相当于 stow -D <package> && stow <package>.

stow -R bash

要移除一个包的所有符号链接, 使用 -D:

stow -D bash

3. 常见选项

-n/--no 模拟执行, 将显示将会进行的操作而不进行实际更改. 在对现有配置进行大规模修改前, 推荐先用 -n 检查:

stow -n -R bash

--adopt 将目标目录已有的文件导入至 Stow 包.

例如, 如果 ~/.bashrc 已经存在, --adopt 会将其移动到 Stow 包目录中, 再在原位创建符号链接:

stow --adopt bash

--adopt覆盖 Stow 包目录中的同名文件.

--no-folding 禁用目录折叠. 上述示例中, Stow 默认将 .config 整个目录链接为单个符号链接. 如果需要在同一目录下混合存放不同包的配置文件, --no-folding 会很有用.

--dotfiles 允许在包目录中使用 dot- 前缀替代 . 前缀.

例如, 将 .bashrc 命名为 dot-bashrc, Stow 链接时会自动将 dot- 转换为 .:

.dotfiles/
└── bash/
    └── dot-bashrc
stow --dotfiles bash

此时 ~/.bashrc 将链接到 .dotfiles/bash/dot-bashrc.


4. 配置文件

Stow 支持通过配置文件设置默认选项. ~/.stowrc (或项目目录下的 .stowrc) 可以包含任意命令行选项:

# .stowrc
--target ~
--dir ~/.dotfiles

此外, 在每个包目录下放置 .stow-local-ignore 文件, 或在 ~ 下放置 .stow-global-ignore, 使用 Perl 正则排除不需要链接的文件:

# .stow-global-ignore
.git
README.*
*.swp

5. 配合 Git

~/.dotfiles/ 初始化为 Git 仓库并推送到远端, 即可同步 dotfiles:

cd ~/.dotfiles
git init
git remote add origin <remote-url>
git add -A
git commit -m "init: add dotfiles"
git push -u origin main

在新机器上, 克隆仓库并执行 stow:

git clone <remote-url> ~/.dotfiles
cd ~/.dotfiles
stow bash

推荐将 .stow-local-ignore.stow-global-ignore 一并纳入版本控制, 确保不同设备上 stow 的行为一致.


要了解更多关于 Stow 的用法, 参阅 GNU Stow 手册stow(8).


参考资料

  1. https://www.gnu.org/software/stow/
  2. https://www.gnu.org/software/stow/manual/stow.html
  3. https://www.bilibili.com/video/BV1ZuBMYpEGe/