asdf 是多语言版本管理器:一个工具统一管理 Node.js、Python、Ruby、Java 等几十种运行时的版本,替代 nvm、pyenv、rbenv 各装一套的局面。核心机制是垫片(shim):安装版本时 asdf 在 ~/.asdf/shims/ 下为每个可执行文件生成包装脚本,该目录置于 PATH 最前。执行 node 时先进入垫片,垫片解析出当前应使用的版本,再 exec 真正的可执行文件。

版本声明写在 .tool-versions 文件中:某目录下的 .tool-versions 对该目录及所有子目录生效。进入不同项目目录,同一命令自动切到不同版本。

每种运行时由对应插件负责下载与安装,先装插件再装版本。以下命令基于 0.16+(Go 重写版)。

插件管理

1
2
3
4
5
asdf plugin add nodejs          # 从官方插件仓库安装
asdf plugin list # 已安装插件
asdf plugin list all # 仓库中全部可用插件
asdf plugin update --all # 更新所有插件(刷新版本列表)
asdf plugin remove nodejs # 移除插件,连带删除其所有版本

安装与卸载版本

1
2
3
4
5
6
7
8
9
10
11
12
asdf install nodejs 22.14.0     # 指定版本
asdf install nodejs latest # 最新稳定版
asdf install nodejs latest:20 # 20 系列最新稳定版
asdf install # 安装当前 .tool-versions 全部工具
asdf install nodejs # 只装 .tool-versions 里声明的 nodejs

asdf list nodejs # 本地已装版本(可加前缀过滤)
asdf list all nodejs # 插件全部可用版本
asdf list all nodejs 20 # 过滤 20 开头的版本
asdf latest --all # 各工具最新稳定版及是否已安装

asdf uninstall nodejs 22.14.0 # 卸载指定版本

asdf install(无参数)是新机器初始化的关键:进入项目目录执行一次,声明的所有工具全部装好。

设置版本

1
2
3
4
5
asdf set nodejs 22.14.0         # 写入当前目录 .tool-versions
asdf set -u nodejs 22.14.0 # 写入 $HOME/.tool-versions(默认值)
asdf set -p nodejs 22.14.0 # 写入最近的父目录 .tool-versions
asdf set nodejs system # 回退使用系统版本
asdf set nodejs latest # 解析为确切版本后写入

.tool-versions 每行 工具 版本,可写多个版本构成 fallback 链,支持注释:

1
2
3
nodejs 22.14.0
python 3.12 3.11 system
ruby 2.5.3 # 行尾注释

版本解析优先级:

  1. 环境变量 ASDF_${TOOL}_VERSION,如 ASDF_NODEJS_VERSION=20.18.0,仅当前 shell 生效,覆盖一切文件
  2. 从当前目录向上查找,最近的 .tool-versions 生效($HOME/.tool-versions 不过是位于家目录的一份普通文件)

临时用某版本跑一次测试,无需改文件:

1
ASDF_ELIXIR_VERSION=1.4.0 mix test

查询与诊断

1
2
3
4
5
6
7
asdf current                    # 各工具当前版本 + 来源文件 + 是否已装
asdf where nodejs # 当前版本的安装目录
asdf which node # 垫片背后真实可执行文件路径
asdf shimversions node # 哪些插件和版本提供了该命令
asdf env node # 垫片执行 node 时的环境变量
asdf exec node -v # 绕过垫片直接执行(脚本中更稳)
asdf info # 环境诊断信息

asdf exec 的价值:cron、CI 等环境的 PATH 顺序不受控,直接 exec 按当前解析规则执行,免去对垫片目录位置的依赖。

垫片维护

asdf 在 install/uninstall 时自动重建垫片。但用运行时自带包管理器(npm install -gpip install)装入新的全局命令后,垫片不会自动出现,需要手动重建:

1
2
3
npm install -g typescript
asdf reshim nodejs
tsc --version # 现在可用了

旧命令迁移(0.15 及以前 -> 0.16+)

0.16 用 Go 完全重写,asdf 从 shell 函数变为独立二进制,一批旧命令被移除:

旧命令新写法
asdf plugin-addasdf plugin add(连字符命令全部移除)
asdf global nodejs 22.14.0asdf set -u nodejs 22.14.0
asdf local nodejs 22.14.0asdf set nodejs 22.14.0
asdf shell nodejs 22.14.0export ASDF_NODEJS_VERSION=22.14.0
asdf update移除,用系统包管理器或手动下载二进制
asdf shim-versions nodeasdf shimversions node

官方同时移除了 global/local 的说法:asdf 本就没有"全局版本"——家目录的 .tool-versions 随时会被项目目录里更近的文件覆盖,set 的三个落点(当前目录/-u 家目录/-p 父目录)更贴近真实的解析机制。

兼容旧版本文件

插件支持时可读取其他版本管理器的文件(如 .nvmrc.ruby-version),需在 ~/.asdfrc 中开启:

1
legacy_version_file = yes

若命令找不到(command not found),按序检查:asdf info 确认 ~/.asdf/shims 是否在 PATH 最前;asdf current 确认版本已安装;仍不行则 asdf reshim