先说个最扎心的场景:你的C盘已经红了半年,而WSL(Windows Subsystem for Linux)的虚拟磁盘文件就躺在 C:\Users\你的用户名\AppData\Local\Packages 下面,动辄二三十个GB。或者你刚换了台新电脑,想把那套折腾了三个月的Ubuntu开发环境原封不动带过去。这时候你就绕不开“WSL迁移”这个词。
WSL迁移说白了就是两件事:一是把WSL的发行版(比如Ubuntu)从C盘搬到其他盘,释放系统盘空间;二是把整套开发环境迁移到新机器或新位置。这篇博文就是围绕这两件事写的,适合所有把WSL当日常开发环境用的人,不管是Linux小白还是老鸟,看完都能自己动手搬一次。我会把WSL的存储结构、导出导入命令、VHD直搬方案、Python虚拟环境和CUDA环境的迁移修复都拆开讲清楚,最后再放一份我实测踩过的坑列表。
1. WSL迁移之前,先搞懂你到底要搬什么
1.1 WSL的“两个世界”和虚拟磁盘原理
很多人第一次接触WSL迁移时,容易把它想复杂了。实际上WSL分两个版本,WSL 1和WSL 2。WSL 1是翻译层,直接把Linux系统调用翻译成Windows调用,没有独立的文件系统,数据散在Windows目录里,那基本不需要迁移。现在主流用户几乎全是WSL 2,它的本质是一个轻量级虚拟机,整个Linux文件系统被封装在一个VHDX虚拟磁盘文件里,放到Windows的包目录下。
这个VHDX文件就是你整个WSL生命周期的全部家当。你装的apt包、conda环境、写过的代码、数据库数据,全都在这个文件里。Windows侧看WSL迁移,本质就是把一个虚拟磁盘文件从C盘Copy到D盘,然后把注册信息改一下,让WSL知道“这个发行版的根目录现在换地方了”。理解了这一点,后续所有操作就顺了。
顺带说一句WSL 2和传统虚拟机的区别。WSL 2用的是Hyper-V架构,但不是你在VirtualBox里看到的那种完整虚拟机。它没有独立的网络管理界面,会和Windows共享网络,也共享文件系统挂载点。这种设计的好处是轻量、启动快,坏处是——当你想把它搬走时,不能只拖一个文件夹,必须走WSL官方的导出导入机制或者直接操作VHDX文件。
1.2 什么样的人需要迁移,什么样的人建议重装
我见过不少朋友一看到“WSL迁移”四个字,第一反应就是把C盘下的包目录直接剪切到D盘。这是最容易翻车的心态,因为在Windows侧移动文件,WSL全局配置里记录的路径不会自动更新,结果就是wsl命令找不到这个发行版,报一堆莫名其妙错的误。
但也不是所有情况都推荐迁移。我总结下来,适合迁移的是这两种人:
- 你的开发环境里有大量需要保留的东西:conda里装了几十个包、数据库里有历史数据、系统里配好了SSH密钥和全局Git配置。这种人重装一遍成本很高,必须迁移。
- 单纯想把C盘空间释放出来,原环境没那么多东西可保留。这种其实可以走重装路线,把需要的数据拷出来,卸载发行版,重新安装到D盘,耗时未必比导出导入更长。
反过来,如果你刚装完WSL没几天,环境里啥都没有,那别折腾迁移了。直接wsl --unregister删掉发行版,重装到D盘更清爽。迁移方案讲究的是“环境有沉淀价值”,否则纯粹是给自己找事。
2. 迁移准备:备份、瘦身、定方案
2.1 迁移前必须做的检查和备份
我吃过的最大一次亏,就是没备份就开始迁移,结果导出过程到一半磁盘空间不够,tar包损坏。所以不管你用什么方案,迁移前至少要做三件事。
先确认当前WSL发行版列表。命令行里跑一句:
wsl --list --verbose正常情况下你会看到类似“Ubuntu-22.04 Running 2”这样的输出。注意记下发行版的确切名称,后面导出导入都要用这个名字,写错一个字就报错。如果机器上装了多个发行版,每个都要单独处理。
然后检查WSL版本,WSL 2才有VHDX虚拟磁盘,WSL 1走的是另一套机制。运行:
wsl --status如果输出显示内核版本较低,建议先wsl --update把WSL升级到最新版,再考虑迁移。因为新版WSL的导出工具对VHDX格式支持更完善,还多了--vhd参数可以用。
最后确认系统盘有足够的临时空间。导出tar包时,这个包的大小约等于WSL内实际已用空间大小,不一定是压缩后那点体积。比如你的ext4.vhdx有30GB,tar包打包出来大概也是20-30GB。如果你的C盘只剩10GB,那导出很容易失败。解决办法是先把tar包导到D盘去,或者先给WSL内部做一轮瘦身清理。
2.2 清掉环境垃圾,把迁移包体积压到最小
很多人的WSL环境里有大量缓存和无效包,这些东西在你日常使用中没感觉,但迁移时都会变成体积成本。迁移前我建议至少做这几项清理。
清理APT缓存和pip缓存。这两个最占空间,尤其pip经常缓存几百MB的wheel文件。
sudo apt clean sudo apt autoclean pip cache purge清理conda缓存。如果你用conda,那conda的pkgs缓存目录经常会积累一堆下载过的安装包。
conda clean --all清理Docker的悬空镜像和缓存。很多人WSL里跑Docker Desktop on WSL2后端,/var/lib/docker经常膨胀,镜像不知道都是什么年代留下的。迁移前跑一下docker system prune -a,把没在用的镜像全清了,能省出十几个GB。
还有日志文件的处理。journalctl --vacuum-size=50M能把systemd日志收一收,rm -rf ~/.cache/*清掉家目录缓存。
清理完这些之后,建议在WSL里执行一次df -h看一下使用量,再决定要不要继续。如果基础环境只有几GB,导出包会小很多,后续迁移速度也快一大截。
2.3 三种迁移方案的适用场景对比
我在实际迁移中试过三种思路,简单对比一下,大家按情况选。
| 方案 | 操作工具 | 上手难度 | 适用场景 |
|---|---|---|---|
| 方案A:全新重装 | wsl --install | 低 | 环境干净、数据少,迁移成本高于重装 |
| 方案B:导出导入tar | wsl --export / --import | 中 | 主力方案,环境完整、跨机器迁移、换磁盘位置 |
| 方案C:VHDX直搬+挂载 | wsl --import-in-place / 直接移动VHDX | 中高 | 追求极致速度、不想打包解包、熟悉命令行 |
方案A不展开讲,就是wsl --install -d Ubuntu-22.04装到默认位置,手动装环境,适合新人。方案B是这篇的重头戏,见第三章。方案C适合老手,见第四章。
3. 正餐:wsl --export / --import 全流程复盘
3.1 导出:把整个Linux文件系统封进tar
到这一步,准备工作都做完了,开始正式迁移。第一步是导出。打开PowerShell窗口,先确保WSL发行版处于关闭状态,不然导出时文件可能在写入中,容易不一致。用下面的命令关掉:
wsl --shutdown然后执行导出:
wsl --export Ubuntu-22.04 D:\WSL-Backup\ubuntu-backup.tar这里Ubuntu-22.04是你的发行版名,D:\WSL-Backup\ubuntu-backup.tar是导出文件的路径。建议目标路径选一个空间充足的盘,格式用.tar。
导出时间取决于你的WSL内部用掉的空间,空间越大越慢。我的环境大概20GB,导出用了差不多十分钟。期间PowerShell会卡住不动,别手贱去关窗口,我干过一次,tar包直接废了。
如果你的WSL版本较新,还可以把导出格式从tar换成VHD格式:
wsl --export Ubuntu-22.04 D:\WSL-Backup\ubuntu-backup.vhdx --vhdVHD格式的好处是导入时不走“解包tar重新组装”的流程,相当于直接拷贝虚拟磁盘,速度更快,对大环境更友好。不过这是较新的特性,老版本WSL不一定支持,命令行里试试看就知道了。如果不支持会明确报错,那就退回tar方案。
导出完成后,建议顺手看一眼tar或VHDX文件的大小,确认它和你WSL内部使用量大致匹配。如果tar包只有几百MB而WSL内部显示有20GB使用量,说明导出有问题,重新做。
3.2 导入:新位置重建发行版
导出完成后,接下来把tar包恢复到新位置。核心命令是:
wsl --import Ubuntu-22.04 D:\WSL\Ubuntu-22.04 D:\WSL-Backup\ubuntu-backup.tar --version 2这个命令三个参数分别是:发行版名称、安装目录、导出包文件路径。--version 2是强制以WSL 2模式导入,如果是WSL 1的环境就要写1,但现在基本没人用WSL 1了。
注意导入时指定的D:\WSL\Ubuntu-22.04是新的安装目录。导入成功后,这个目录下会出现一个ext4.vhdx或类似名字的虚拟磁盘文件,这就是你新的WSL根目录。导入耗时和解压tar包的时间一样,我的20GB环境大概七八分钟。
导入完成后验证一下:
wsl --list --verbose wsl -d Ubuntu-22.04如果一切正常,你就能进入熟悉的Ubuntu shell,看到之前所有的家目录、conda环境、文件都还在。但别急,迁移还没完,下一章那些“迁移后遗症”才是真正考验。
3.3 迁移后首次进入的“一键修复三件套”
第一次进入迁移后的WSL,大概率会遇到三种情况:默认用户变成root、Windows工具链的PATH对不上、某些服务起不来。我这里直接给出处理顺序。
第一件事,把自己常用的账号设回默认用户。因为导入tar包时,发行版的默认用户信息不会自动带完全,很多时候WSL默认给你用root登录。处理方式是编辑WSL内部的/etc/wsl.conf文件:
sudo vi /etc/wsl.conf在文件里加上:
[user] default=你的用户名然后重启WSL才能生效:
wsl --shutdown第二件事,确认Windows侧的PATH映射正常。有些用户会在WSL里调用Windows的可执行文件,比如/mnt/c/Windows/System32/notepad.exe。如果在导入后发现找不到,多半是WSL的Windows路径互操作设置丢了。检查一下/etc/wsl.conf里[interop]段有没有enabled=true和appendWindowsPath=true,没有就补上。
第三件事,把你原来的启动项和服务拉起来。比如systemd、SSH服务、Docker服务这些,不同发行版检查方式不一样,Ubuntu的一般做法是:
sudo systemctl status ssh docker发现没跑起来就sudo systemctl enable --now补上。这一步容易被忽略,因为它不像用户问题那么表面,但等到你要用SSH进服务器的时候才想起来,就很烦了。
4. 进阶:VHD直搬、离线迁移和“新机迁移”思路
4.1 已经有VHDX文件,怎么直接搬
前文提过,WSL的整个文件系统都在一个VHDX文件里。如果你手头没有tar包的备份,只有原本的ext4.vhdx文件,其实也可以直接迁移。
思路很简单:先在Windows侧找到这个VHDX文件,位置在用户目录的AppData\Local\Packages下。每个发行版对应一个包名,比如CanonicalGroupLimited.UbuntuonWindows_79rhkp1fndgsc,进去后找LocalState文件夹,里面就有ext4.vhdx。把这个文件复制到目标盘的任意目录,然后注册它。
新版WSL提供了一个--import-in-place命令,语义很明确:导入一发行的同时,直接引用现有的VHD/VHDX文件,不做复制也不重新创建虚拟磁盘。用法是:
wsl --import-in-place Ubuntu-22.04 D:\WSL\Ubuntu-22.04\ext4.vhdx这个方式我非常推荐给磁盘空间紧张的朋友,因为--import会把tar解包成新的VHDX,而--import-in-place直接原地挂载原VHDX,少了一层拷贝,速度极快。但注意,这个命令只支持VHD格式,原始的ext4.vhdx文件需要是对应的VHD变种才能行。如果失败,就退回--export --vhd --import的组合拳。
4.2 老版本WSL和不能联网环境的离线迁移
有些时候你的机器上的是老版本WSL,或者目标机器处于比较严格的网络环境,wsl --install和wsl --update都没办法联网完成。这时候要分两步走。
第一步在源机器上导出tar包,第二步到目标机器上安装WSL本身。目标机器如果WSL都还没启用,需要先用管理员身份在PowerShell里启用Windows功能。这一步需要重启机器,但不需要联网:
dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all dism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all然后安装WSL内核。新版本WSL内核是独立MSI安装包,可以提前下载好拷过去。安装完成后,再用wsl --import导入你的tar包,整个环境就恢复了。这套流程本质上是在做双机迁移,很多公司内部换电脑、部门服务器迁移都是这么干的。
如果你既没办法联网装WSL,也没有安装包,那说实话我建议先解决工区网络问题再谈迁移,因为Windows侧的WSL组件实在没办法用离线方式凭空变出来。
4.3 新电脑迁移:不只是备份WSL,还要同步配置
换电脑的场景下,除了WSL本身,Windows侧的很多配套配置也需要一起走,不然迁移完发现“开发环境还是不对”。我每次都要检查这几样:
- Windows Terminal的配置,尤其是WSL profile的启动目录,迁移后启动目录可能指向旧路径。
- 环境变量里如果有指向WSL路径的,全部要更新。
- Windows侧SSH密钥如果之前放在
~/.ssh,那和WSL里的~/.ssh是两套,别只搬一边。 - 如果你用Docker Desktop的WSL2后端,Docker数据盘也要备份,它的位置在
%LOCALAPPDATA%\Docker\wsl,光迁移WSL发行版解决不了Docker数据丢失的问题。
我见过一个朋友换电脑后只导出了WSL发行版,结果发现Docker里的所有容器数据都没了。原因很简单,Docker Desktop后端的虚拟磁盘是独立的Data Disk文件,不跟着发行版走。这个坑值得单独列出来提一次。
5. 迁移后日结:虚拟环境、GPU和开发工具的复燃清单
5.1 Python虚拟环境迁移后为什么失效,怎么抢救
WSL迁移最让人头疼的,就是Python环境。很多人在WSL里用venv或conda搭建了项目环境,结果迁移完成后一启动就报“No module named xxx”或者解释器路径找不到。这不是玄学,是虚拟环境本身的设计逻辑导致的。
先看venv。Python的venv模块在创建虚拟环境时,会把当前Python解释器的绝对路径写进pyvenv.cfg和bin目录下的激活脚本。比如你的旧路径是/home/ubuntu/anaconda3/bin/python,迁移后如果你的conda安装路径变了,那venv里的路径就全部失效。解决方案很简单,不要试图去一个个改路径,直接把虚拟环境删了重建,用requirements.txt重新装一遍依赖:
source /home/你的用户名/项目目录/bin/activate pip freeze > requirements.txt deactivate rm -rf /home/你的用户名/项目目录/bin/ python -m venv /home/你的用户名/项目目录/venv source venv/bin/activate pip install -r requirements.txt再说conda。conda的环境分两种:base环境和创建的其他环境。base环境的路径写在conda的安装目录里,只要你整个conda目录位置不变,通常没问题。而你创建的其他环境,conda会在$CONDA_PREFIX和conda-meta目录里记录绝对路径。如果conda安装的根路径变了,那这些envs全部失效。处理办法有两种。
如果原环境的包名不多,推荐用conda env export把环境导出:
conda env export -n 你的环境名 > environment.yml conda env remove -n 你的环境名 conda env create -f environment.yml如果环境很大,重新建一遍太费时间,就检查conda env list之后,逐个激活测试,发现路径失效的环境再用conda env update修。总之一句话,迁移后别以为环境会自动跟着走,虚拟环境必须手动重新关联。
5.2 CUDA、PyTorch和其他GPU环境的验证流程
如果你是做深度学习开发的,WSL迁移完成后第一件事不是跑迁移学习模型,而是验证GPU状态。因为WSL 2对GPU支持是透传模式,Windows侧装好显卡驱动,WSL内部直接访问GPU设备。迁移后这一层关系可能会松动,需要用命令逐项确认。
第一步看设备是否可见:
nvidia-smi如果你的是NVIDIA的显卡,输出正常就说明GPU透传没丢,驱动在Windows侧、CUDA toolkit在WSL侧,两边的版本匹配关系和你迁移前一样。如果nvidia-smi报错,多半是Windows侧显卡驱动和WSL兼容层需要升级,去Windows这边更新驱动比在WSL里瞎折腾有用。
如果你用的是AMD显卡,比如7900XTX,在WSL里跑PyTorch的场景比较特殊。WSL下AMD GPU走的通常是ROCm的WSL支持或者DirectML后端。迁移后建议先跑一下rocminfo确认ROCm栈是否正常,或者直接跑一小段PyTorch的forward测试:
import torch print(torch.cuda.is_available()) print(torch.cuda.get_device_name(0))能打印出显卡型号,就说明环境没问题。顺便说一句,如果PyTorch的CUDA版本和迁移前不一致,迁移后装好驱动后可能还需要重新装一次匹配的Pytorch wheel包,这属于常规操作。
5.3 VSCode Remote-WSL连不上怎么办
VSCode连接WSL是很多人的日常操作,迁移完成后最常遇到的问题就是Remote-WSL插件重新连不上,或者连接后提示WSL server版本不匹配。原因通常是VSCode Server在迁移前被安装在旧路径下,迁移过程中路径失效了。
处理方法也很暴力:在WSL内部删掉旧的Server目录,让VSCode重新装。目录在:
rm -rf ~/.vscode-server删除之后,重启VSCode,重新打开WSL窗口,它会自动拉取一个和当前VSCode版本匹配的Server组件到新环境。注意这个过程需要WSL内部能访问外网,如果公司网络环境特殊,下载Server组件会卡住很久,这时需要检查你的WSL网络设置和Windows侧的代理配置是不是还是旧机器的。这个我放到最后一章和报错一起讲。
6. 这些坑我替你踩过:常见问题排查速查表
迁移WSL这事,看起来就几条命令,实际操作中会出现一堆细碎问题。我把踩过的坑按场景整理成了速查表,给后来人备用。
| 问题现象 | 可能原因 | 解决办法 |
|---|---|---|
wsl --list没有任何输出或找不到发行版 | 未正确导入,或导入后注册信息丢失 | 重新执行wsl --import,并确认发行版名拼写完全一致 |
| 迁移后 WSL 默认用户是 root | /etc/wsl.conf 中没有 [user] 配置 | 编辑 /etc/wsl.conf 加上default=用户名,然后wsl --shutdown重启 |
| wsl 导入时报错“位置已存在” | 目标安装目录下已存在 VHDX 文件 | 换一个新目录,或先把旧目录里的 VHDX 文件备份删除 |
| 导入时卡在进度条很久不动 | tar包太大,磁盘IO瓶颈 | 耐心等待;迁移前先做目录清理压缩包体积;或者换VHD方式导入 |
| WSL内部能联网,VSCode却连不上 | VSCode Server安装失败 | 删除 ~/.vscode-server,重启VSCode重新安装 |
wsl --shutdown后 WSL 还是占用C盘 | VHDX 文件没释放,Windows侧文件句柄被占用 | 完全退出所有WSL窗口和Windows Terminal,再去查看文件 |
| 迁移后 conda 环境启动失败 | conda env 路径写死了旧目录 | 用conda env export重建,或者手动编辑激活脚本里的路径 |
| 迁移后 Docker 容器数据全没了 | 只导出了WSL发行版,没迁移Docker Desktop的虚拟磁盘 | 备份/迁移%LOCALAPPDATA%\Docker\wsl下的 vhdx 文件 |
整理这一份表的时候,我又回想了自己迁移过的那台机器。我是用--import-in-place方式直接把ext4.vhdx挂到D盘的,当时觉得省时间省空间,结果忘了把Docker Desktop的data盘也搬过去,后来花两个小时重拉了所有容器镜像。说到底,WSL迁移的技术门槛其实不高,难的是把你脑子里那套“环境依赖关系”一并搬过去。
最后分享一个小习惯:现在我每次做完一次大版本WSL配置升级,就会顺手wsl --export一份tar包放到移动硬盘。既不是为了应对硬盘损坏,也不是什么保险洁癖,纯粹是因为我知道,下次换电脑时省下的那半小时,一定会让我觉得这次备份做得太值。