ARTICLE · 1100782
Windows工具分享: #03 软件多版本运行时管理
发布时间:2026-09-30 01:18:09 最近访问:2026-09-30 01:18:10
Windows工具分享: #03 软件多版本运行时管理
多版本运行时:一台电脑装四个 Python 还不打架「Windows 工具分享」系列 · 第 03 期上一篇我们把 Scoop 装到了 D 盘,学会了 scoop install versions/python311 这种装法,也知道 scoop reset 能秒切版本。然后有读者问了一个特别实在的问题:我装了三个 Python,为什么命令行里敲 `python`,出来的还是最老那个?这个问题问到根上了。因为"装得上"和"用得上"是两件事——Scoop 解决了前者,没解决后者。更麻烦的是,你的 PATH 里可能藏着你根本不知道的解释器。我拿自己这台机器跑了一下,结果是这样的:C:\Users\Admin\.workbuddy\...\python.exe 3.13.12D:\Software\Python39\python.exe 3.9C:\Users\Admin\AppData\Local\Microsoft\WindowsApps\python.exe (微软商店存根)D:\Program Files\LibreOffice\program\python.exe (办公软件自带的)
四个 Python,最后一个是 LibreOffice 塞进去的。这一期就解决这件事:让"装了几个版本"和"敲命令跑的是哪个版本"对上号。 | | |
|---|
| 换 Python 版本 | | uv python pin 3.13 |
| 换 Node 版本 | | nvm use 22 |
| 项目 A 用 3.11、项目 B 用 3.13 | | |
| 新项目要 node + python + 环境变量 | | 一个 mise.toml,mise install 一条命令 |
| "我到底装了几个解释器" | | where.exe python |
一句话:版本管理解决的是"确定"——确定你现在跑的是哪个,确定别人拿到你的项目跑的是哪个。Windows 有个命令叫 where.exe,它会按 PATH 的顺序列出所有同名可执行文件。每装一次运行时就跑一次:where.exe pythonwhere.exe nodewhere.exe uv
排在第一行的就是真正会被执行的那个,Windows 按 PATH 顺序找,找到第一个就停。再看两个容易忽略的地方。第一个是 Python 官方的 py 启动器,它有自己的一套注册表,和你 PATH 里的 python不是同一套东西:py --list-paths
我这台机器上的结果是 -V:3.12 * 和 -V:3.9,默认 3.12——但 PATH 里的 python 是 3.13.12。也就是说,敲 `python` 和敲 `py` 跑的是两个不同的解释器。第二个是那些"顺手带进来的"。办公软件、设计软件、输入法、各种国产工具,都可能往 PATH 里塞一个自己的 Python。它们平时不碍事,但一旦解释器数量超过两个,诡异的报错就开始出现了。Windows 上管多版本的工具很多,容易看花眼。判据其实只有三条:只写 Python → uv;只写 Node → nvm-windows;一个项目要同时管好几种语言、还要带环境变量和任务脚本 → mise。 | | |
|---|
| uv | 一个二进制搞定解释器 + 虚拟环境 + 依赖 + 打包,比 pyenv + pip 那一套快一个数量级 |
| nvm-windows v2 | 只管 Node,命令和 .nvmrc 是业界通用格式,换机器、换同事都认 |
| 一个仓库里有 node + python + go | mise | 一个 mise.toml 描述整个项目,还能管环境变量和任务 |
| 都不用装 | Python 用系统自带的 py -3.11 指定版本就行 |
三个工具的定位差异,一句话能说清:uv 是 Python 全家桶,nvm-windows 是 Node 专科医生,mise 是"整个项目的环境描述文件"。还有个特别重要的前提:它们互相不知道对方的存在。 你用 uv 装 Python、用 nvm 装 Node,两边各管各的,不会打架;但要是你用 mise 管 Node、又用 nvm 管 Node,那就一定会打架。一个运行时只归一个工具管,这是铁律。uv 是 Astral 用 Rust 写的一个二进制,把 pip、virtualenv、pyenv、pipx、poetry 的活儿合起来干了,而且是真的快。winget install astral-sh.uv
或者用官方安装脚本(更新最快,装到 ~/.local/bin):powershell -c "irm https://astral.sh/uv/install.ps1 | iex"
uv self updateuv --version
为什么必须先更新? 因为 uv 能装哪些 Python 版本,是按 uv 自己的版本冻结的。你手上这个 uv 是哪天发布的,它就知道那天为止存在哪些 Python。老 uv 装不了新 Python,而且这个报错还特别不好懂。我机器上原先是个 2025 年的 uv 0.7.9,用它装新版本 Python 直接找不到——uv self update 一下就好了。这件事后面坑位还会再说一遍。uv python install 3.11 3.12 3.13 # 一次装多个uv python list # 看装了哪些、还能装哪些uv python pin 3.13 # 当前目录固定用 3.13uv python find # 现在实际会用哪个uv python uninstall 3.11 # 删掉一个
uv python pin 会在当前目录写一个 .python-version 文件,之后在这个目录里跑任何 uv 命令,都会用这个版本。这个文件可以提交到 Git——同事克隆下来跑 `uv run`,版本和你一模一样。Windows 上还有个隐藏福利:uv 装的解释器会按 PEP 514 注册进 Windows 注册表,于是系统自带的 py 启动器也能认出来:py -V:Astral/CPython3.13.1 --version
也就是说,uv 管版本、系统 py 启动器也能调用,两套机制能对上。日常装 CLI 工具(ruff、httpie 这类),别用 pip install -g,用:uv tool install ruff # 装上,全局可用uvx ruff check . # 临时跑一次,不装
uvx 特别适合"这个工具我就用一次"的场景,用完不留痕迹。最后一句要说明白:uv 只管 Python,不管 Node。 网上有些文章说 uv 能管所有运行时,是错的——官方文档里 uv 的 Python 版本管理章节,通篇只有 Python。四、nvm-windows v2:Node 的版本管家nvm-windows 在 2026 年 9 月发布了 v2.0.0,是完全重写的。你现在搜到的大部分中文教程,讲的还是 1.2.2 时代的东西。版本确认一下(winget 源里现在就是 2.0.0):winget install CoreyButler.NVMforWindowsnvm version
v1 时代那些让人头疼的问题,v2 基本都解决了: | |
|---|
| 不需要管理员 |
| 默认 shim 模式,不用符号链接(用 Zig 写的) |
| |
| |
| |
nvm install 22 # 装 22 系列最新nvm install lts # 装最新 LTSnvm use 22 # 切过去nvm list # 已装列表nvm current # 当前是哪个
项目里放一个 .nvmrc 文件,内容就一行版本号(比如 22.16.0),然后 nvm use 不带参数,它会自己读文件里的版本。这是前端圈子的通用约定,CI 和同事的机器都认这个格式。装之前先把已有的 Node.js 卸干净。 这是官方文档明确要求的:C:\Program Files\nodejs 这个真实目录要是还在,nvm 的 shim 就抢不过它,你会遇到"nvm use 显示成功、但 node -v 还是老版本"的鬼打墙。卸完用 where.exe node 复查,确保只剩 nvm 那一条。mise(读作 "meez ahn plahs")的定位比前两个高一层:它不只是版本管理器,而是整个项目的环境说明书。装它。官方文档在 Windows 上推荐的是 Scoop,winget 也行:scoop install mise
⚠️ 这里有个官方文档专门标注的坑:Scoop 装完不会把 mise 的 shims 目录加进 PATH。所以装完要二选一:▸ 方案 A(推荐):把 shims 目录手动加进 PATH —— %LOCALAPPDATA%\mise\shims▸ 方案 B:配置 shell 激活,让 mise 在 cd 进目录时自动切版本方案 B 在 PowerShell 里是一行,写进你的 $PROFILE:(&mise activate pwsh) | Out-String | Invoke-Expression
[tools]node = "22"python = "3.13"[env]NODE_ENV = "development"[tasks.dev]description = "启动开发环境"run = "npm run dev"
mise install # 按文件装好所有工具mise run dev # 跑任务mise ls # 看当前生效的版本
这个文件的价值在于:新人克隆仓库,跑一条 `mise install`,环境就和你完全一致——不光是版本,环境变量和常用命令也一起带过去了。这是 README 里写十行安装说明都做不到的。mise 也能临时用某个版本跑一次命令,不改动项目配置:mise exec node@24 -- node --version
什么时候该上 mise? 如果你的项目只有 Python 或只有 Node,用 uv / nvm 就够了,别为了用 mise 而用 mise。mise 真正划算的场景是"一个仓库里跑着好几种语言",或者"团队里总有人环境配不对"。这一期我给你留了个脚本,放在 03_运行时体检.ps1。它做四件事:1. 列出 PATH 里所有 python / node,标出排在第一位的(就是真正生效的那个)2. 对比 py --list-paths 和 PATH 里的 Python,告诉你两套机制是否对不上3. 检查 uv / mise / nvm 装没装、版本是多少、该不该更新4. 检查当前目录有没有 .python-version / .nvmrc / mise.toml,有就显示它要求的版本pwsh -File .\03_运行时体检.ps1
这份脚本最有价值的输出是第一部分——它会把你机器上的解释器冲突一次性摊开。我第一次跑的时候才知道 LibreOffice 往我 PATH 里塞了个 Python,这件事我在此之前毫无察觉。建议每季度跑一次,尤其是"明明装了新版本但命令还是老的"这类问题出现时,先跑它,别急着重装。uv 能装哪些 Python 版本是按 uv 版本冻结的,不是实时查的。我机器上那个 2025 年的 uv 0.7.9,装新版 Python 直接说找不到。uv self update 一行解决。所以:装完 uv 第一件事就是更新它,往后每隔几个月更新一次。坑 2:`nvm use` 显示成功,但 `node -v` 还是老版本。99% 是 PATH 冲突。跑 where.exe node,如果排第一的不是 nvm 的 shim 而是某个真实的 node.exe,那就说明你还有一份没卸干净的 Node.js。Windows 按 PATH 顺序找,谁在前面谁赢。先卸干净,再 nvm use。Python 同理,where.exe python 是唯一的诊断手段。坑 3:网上 nvm-windows 教程普遍过时。如果你看到的教程在讲"必须用管理员窗口""exit 145 报错""跨盘安装失败",那它讲的是 v1.2.2。v2.0.0 已经完全重写:免管理员、shim 模式、支持按目录自动切换。按老教程操作不会出错,但会白白多走弯路。坑 4:用 Scoop 装完 mise,命令还是找不到。Scoop 的 manifest 不会把 mise 的 shims 目录(默认 %LOCALAPPDATA%\mise\shims)加进 PATH,这是官方文档明确写的。手动把那个目录加进 PATH,或者配置 mise activate pwsh。判断方法很简单:跑 mise --version 有反应、但 mise ls 说没有工具,就是 shims 没进 PATH。用 mise 管了 Node,就别再装 nvm 管 Node;用 uv 管了 Python,Scoop 的 versions/python311 就该卸掉。两个工具同时往 PATH 里塞 shim,谁生效取决于 PATH 顺序,你会陷入"刚才还好好的"这种随机性里。一个运行时,一个管家。版本管理这件事,真正的收益不在"能装多少个版本",而在确定性。确定性有两层:一是你敲下命令,明确知道跑的是哪个版本;二是你把项目交给别人,他能跑出一模一样的结果。前者靠 where.exe 和 pin 住版本,后者靠 .python-version、.nvmrc、mise.toml 这些能进 Git 的小文件。而且这三个工具都是"温和派"——uv 装的解释器在用户目录,mise 的在 %LOCALAPPDATA%\mise,nvm 的也在用户目录。它们都不往系统目录里写东西,想反悔删目录就行,不会把你原来的环境搞脏。1. 跑一次 where.exe python 和 where.exe node,数数你有几个解释器,看看有没有你不认识的2. 装 uv(或用 uv self update 更新),然后 uv python install 3.13,再 uv python pin 3.133. 在一个老项目里放一个 .python-version 或 .nvmrc,体会一下"进目录自动对版"4. 如果你手上有 node + python 混着的项目,写一个 mise.toml 试试下一篇:WSL2——什么时候该进 Linux,什么时候留在 pwsh三个运行时管家都装好之后,会冒出一个新问题:有些东西在 Windows 上就是别扭(Docker、某些 Python 包、shell 脚本),这时候该不该干脆进 Linux?下一篇讲 WSL2 和 Windows 的分工线划在哪,以及怎么让它俩顺畅协作。「Windows 工具分享」系列持续更新,关注不迷路。 系列进度:3 / 17 ✅