在 Windows 上通过 MSYS2 使用 rsync 同步
Windows 上没有官方 rsync。本文用 MSYS2 装一个原生 rsync.exe,全程放在非系统盘、不碰 C 盘,再通过 SSH 密钥同步到远端服务器。
文中用 D:\tools\msys64(MSYS2 里写作 /d/tools/msys64)代表 MSYS2 安装目录,用 <本地目录> / <远端目录> 代表同步的源和目标,用 203.0.113.10(RFC 5737 文档专用地址)代表服务器地址。照抄时替换成自己的。
方案选择
| 方案 | 许可证 | 真 rsync | 形态 | 可装到别盘 | 结论 |
|---|---|---|---|---|---|
| MSYS2 + rsync | GPLv3 | ✅ | 原生 exe | ✅ | 本文方案 |
| WSL2 + rsync | GPLv3 | ✅ 本体 | Linux | 需迁 VHDX | 语义最纯,但 /mnt/c 慢 |
| rclone | MIT | ❌ | 单文件 | ✅ | 零依赖,适合多云 |
| cwRsync | 商业打包 | ✅ | exe | ✅ | 发行条款非纯开源 |
| Acrosync / Syncovery | 闭源 | ✅ | GUI | — | 需要 GUI 时才考虑 |
选 MSYS2 的理由:开源、原生 exe、无虚拟机、I/O 接近原生(不像 WSL 的 /mnt/c 走 9p 协议),而且能装到任意盘。
MSYS2 是什么
一个跑在 Windows 用户态的 POSIX 翻译层(msys-2.0.dll),把 open() / fork() / chmod() 翻译成 Win32 调用。它不是虚拟机、不是内核。
你装的 rsync.exe 就是 GNU rsync 源码编译出来的,只是链接了这层运行时。所有”怪”(/c/... 路径、假的权限位)都来自这层翻译。
1. 把 MSYS2 装到非系统盘
1.1 选路径
官方要求:短、纯 ASCII、无空格、无中文、NTFS 本地盘,不能是 subst 或网络驱动器。
D:\tools\msys64 ✅
D:\项目\msys64 ❌ 中文
D:\Program Files\msys64 ❌ 空格
中文路径是硬伤
MSYS2 里大量工具(autotools、cmake、部分 pkg-config 脚本)处理不了非 ASCII 路径,会报出截断的路径错误。这条规则对后面的同步源目录同样适用。
1.2 解压(不要用 GUI 安装器)
从 msys2-installer releases 下载 msys2-base-x86_64-latest.sfx.exe:
cd D:\
.\msys2-base-x86_64-latest.sfx.exe -y -oD:\tools\
为什么不用 GUI 安装器 / winget / scoop / choco:
| 分发形式 | 是否写 C 盘 |
|---|---|
msys2-x86_64-*.exe(GUI 安装器) |
注册表卸载项、开始菜单快捷方式 |
*.sfx.exe 自解压归档 |
无(绿色版,可随时整个删掉) |
winget install MSYS2.MSYS2 |
强制装 C:\msys64,改不了 |
-o 是父目录,不是最终目录
归档里自带一个 msys64 顶层文件夹,所以:
-oD:\tools\→ ✅ 得到D:\tools\msys64-oD:\tools\msys64→ ❌ 得到D:\tools\msys64\msys64
解压完先验证:Test-Path D:\tools\msys64\usr\bin\bash.exe
1.3 首次初始化
D:\tools\msys64\msys2_shell.cmd -defterm -here -no-start -msys
首次登录会看到类似输出,这是一次性的:
'./.bashrc' -> '/home/yourname/.bashrc'
'./.bash_profile' -> '/home/yourname/.bash_profile'
'./.profile' -> '/home/yourname/.profile'
'C:\WINDOWS\system32\drivers\etc\hosts' -> '/etc/hosts'
'C:\WINDOWS\system32\drivers\etc\protocol' -> '/etc/protocols'
'C:\WINDOWS\system32\drivers\etc\services' -> '/etc/services'
'C:\WINDOWS\system32\drivers\etc\networks' -> '/etc/networks'
They will never be overwritten nor automatically updated.
它来自 base-files 包的 postinstall 脚本,干两件事:
- 把
/etc/skel的骨架配置复制进你的$HOME - 把 Windows 的
hosts/protocol/services/networks拷进 MSYS2 的/etc/
那句 never overwritten nor automatically updated 是重点:脚本只在目标文件不存在时才拷贝,所以 /etc/hosts 是一次性快照——以后你在 Windows 改了 hosts,MSYS2 里不会同步。需要时手动覆盖:
cp /c/WINDOWS/system32/drivers/etc/hosts /etc/hosts
1.4 把 HOME 钉在非系统盘
安装目录在 D 盘 ≠ 运行时数据在 D 盘。$HOME 决定 ~/.ssh、~/.config、~/.cache 落哪儿。
echo "$HOME"
cygpath -w "$HOME" # 看物理路径落在哪个盘
| 结果 | 处置 |
|---|---|
/home/yourname |
✅ 已在 MSYS2 安装目录下,无需处理 |
/c/Users/... 或 C:\Users\... |
❌ 要改 |
改法(只影响 MSYS2,不污染全局环境):
echo 'db_home: /home/%U' >> /etc/nsswitch.conf
不要设 Windows 全局 HOME 环境变量
MSYS2 会优先认它。一旦设成 C:\Users\...,整个 ~ 体系(含 .ssh)就被拽回 C 盘了。
1.5 换国内镜像提速
MSYS2 现在只有两个镜像列表文件,注意两者用的变量不同:
| 文件 | 用途 | 占位符 |
|---|---|---|
/etc/pacman.d/mirrorlist.msys |
MSYS 环境的包 | $arch |
/etc/pacman.d/mirrorlist.mingw |
mingw 工具链的包 | $repo |
官方列表里其实已经有清华、中科大、南大、北外,但排在第 8~11 位,轮不到。不用删任何东西,插到第一行即可(pacman 从上往下试,第一个成功的就用,缺包会自动 fallback):
cp /etc/pacman.d/mirrorlist.msys{,.bak}
cp /etc/pacman.d/mirrorlist.mingw{,.bak}
sed -i '1i Server = https://mirrors.tuna.tsinghua.edu.cn/msys2/msys/$arch/' /etc/pacman.d/mirrorlist.msys
sed -i '1i Server = https://mirrors.tuna.tsinghua.edu.cn/msys2/mingw/$repo/' /etc/pacman.d/mirrorlist.mingw
pacman -Syu
其他国内镜像(完整列表见 MSYS2 Mirrors):
| 镜像 | 备注 |
|---|---|
https://mirrors.tuna.tsinghua.edu.cn/msys2/ |
Tier 1,每天至少同步一次,最稳 |
https://mirrors.ustc.edu.cn/msys2/ |
Tier 1 |
https://mirror.nju.edu.cn/msys2/ |
Tier 1 |
https://mirrors.bfsu.edu.cn/msys2/ |
Tier 1 |
https://mirrors.aliyun.com/msys2/ |
Tier 2,同步频率低,更容易 404 |
下载时报 404 是怎么回事
error: failed retrieving file 'xxx.pkg.tar.zst' from mirror.msys2.org : 404
mirror.msys2.org 是地理重定向服务,把你转到就近的 tier-1 镜像。如果那个镜像上某个包还没同步完,就会 404。
pacman 会自动降级去试列表里的下一个镜像,只要后面出现 installing xxx [###] 100% 就是成功了。这不是故障,是镜像同步延迟。
1.6 装 rsync 和 openssh
pacman -S rsync openssh
rsync --version
ssh -V
1.7 「不占 C 盘」核对表
| 位置 | 默认落点 | 状态 |
|---|---|---|
| 安装目录 | D:\tools\msys64 |
✅ |
$HOME(.ssh / .config / .cache) |
见 1.4 | 需确认 |
pacman 缓存 /var/cache/pacman/pkg |
安装目录内 | ✅ 定期 pacman -Scc 清 |
pacman 日志/数据库 /var/log、/var/lib |
安装目录内 | ✅ |
MSYS 工具的临时文件 /tmp |
MSYS2 安装目录下 | ✅ |
原生 Windows 子进程的 %TEMP% |
C:\Users\...\AppData\Local\Temp |
⚠️ 只在调用原生 exe 时触发 |
| 快捷方式 / 卸载项 | 仅 GUI 安装器会产生 | ✅ 用归档方式则无 |
核对命令:
case "$HOME" in /c/*|[Cc]:*) echo "❌ HOME 在 C 盘";; *) echo "✅ HOME: $HOME";; esac
mount | grep -E ' / | /home| /tmp| /var'
du -sh /var/cache/pacman/pkg
Get-ChildItem C:\ -Directory -Filter *msys* -ErrorAction SilentlyContinue
1.8 三个「不要做」
- 不要把
D:\tools\msys64\usr\bin加进系统PATH。 里面有bash.exe/find.exe/sort.exe/link.exe,会和 Windows 自带命令、Git、Cygwin 抢msys-2.0.dll。用msys2_shell.cmd进环境,或需要时写绝对路径。 - 不要用 winget / scoop / choco 装 MSYS2 的 rsync。 它们会落到
C:\Users\...\scoop或C:\ProgramData\chocolatey,正好和目的相反。 - 不要把 MSYS2 目录放进 OneDrive / 坚果云同步,或放在 exFAT 盘上。 MSYS2 大量使用符号链接和 POSIX 权限,同步盘会打架、exFAT 不支持。
2. 配置密钥登录
2.1 私钥就位
mkdir -p ~/.ssh && chmod 700 ~/.ssh
# 从 Windows 侧拷进来(按实际路径改)
cp /d/keys/key.pem ~/.ssh/key.pem
# 必须 chmod:cp 过来默认 644,会被 ssh 直接拒绝
chmod 600 ~/.ssh/key.pem
ls -l ~/.ssh/key.pem # 应为 -rw-------
MSYS2 的 ssh 认 POSIX 权限位,不是 Windows ACL
所以 chmod 600 就够了,不需要 icacls。这也是建议用 MSYS2 自带 ssh 而不是 C:\Windows\System32\OpenSSH\ssh.exe 的原因——两套权限模型混用最容易在私钥上翻车。
2.2 ~/.ssh/config
Host aliyun
HostName 203.0.113.10
User root
Port 2222
IdentityFile ~/.ssh/key.pem
IdentitiesOnly yes
ServerAliveInterval 30
ServerAliveCountMax 6
写好之后,ssh / scp / rsync / git 全部复用,命令里再也不用写 -i 和 -p。
2.3 三条验证
# 密钥能登 + 主机名对 + 对端装了 rsync
ssh aliyun 'echo SSH-OK; hostname; rsync --version | head -1'
第三条很关键:对端没装 rsync 会报 rsync: command not found。
sudo apt install -y rsync # Debian / Ubuntu
sudo yum install -y rsync # RHEL / CentOS / Alibaba Cloud Linux
3. rsync 用法要点
3.1 冒号决定方向
| 方向 | 写法 |
|---|---|
| 上传 | rsync [选项] "<本地目录>/" aliyun:"<远端目录>/" |
| 下载 | rsync [选项] aliyun:"<远端目录>/" "<本地目录>/" |
忘了冒号,就变成两个本地目录互相同步了。
3.2 结尾斜杠(第一大坑)
源是目录时:
| 写法 | 结果 |
|---|---|
"<本地目录>/" |
把目录里面的内容放到目标 → <远端目录>/index.html ✅ |
"<本地目录>" |
把整个目录放进目标 → <远端目录>/<目录名>/index.html ❌ |
记法:源路径结尾加 / = 「要里面的东西」。
3.3 为什么是 -avz --no-owner --no-group 而不是纯 -a
-a 展开是 -rlptgoD。其中 -o(保留属主)和 -g(保留属组)在 MSYS2 → Linux 场景下必须去掉:
- MSYS2 报告的文件属主是数字 UID(不是用户名)、属组是
None - rsync 会老老实实在服务器上执行
chown 1001:None,然后刷一屏chown ... failed: Invalid argument - 非致命,但很吵,还可能把文件属主改坏
去掉后 -a --no-owner --no-group ≡ -rlptD,权限位和时间戳照样保留。
权限位为什么天然是对的
MSYS2 的 / 挂载带 noacl 选项,会把文件统一报告成 644、目录 755、.exe/.dll 类报告成 755。
传过去之后服务器上就是标准的 Web 目录权限,不需要额外 --chmod。
反方向(服务器 → Windows) 则相反,要加 --no-perms:NTFS 存不了 POSIX 权限位,不加的话 MSYS2 会去动只读属性并刷警告。
3.4 常用参数
| 参数 | 作用 |
|---|---|
-a |
归档模式 = -rlptgoD,基本必带 |
-v / -z |
详细输出 / 传输压缩(文本划算,已压缩文件无益) |
-P |
= --partial --progress,断点续传 + 逐文件进度 |
--info=progress2 |
只显示一条总进度条(文件多时比 -P 清爽) |
-n / --dry-run |
干跑,只打印不执行 |
--delete |
目标端删除源端已不存在的文件(镜像同步,危险) |
-i / --itemize-changes |
逐文件打印变更类型 |
--stats |
传输结束打印统计汇总 |
--exclude= / --exclude-from= |
排除 |
--bwlimit=2M |
限速 |
--rsync-path="sudo rsync" |
对端用 sudo 跑 rsync |
--backup --backup-dir=DIR |
被删/被覆盖的文件挪进 DIR 而不是消失 |
3.5 排除规则
--exclude='.git' \
--exclude='node_modules' \
--exclude='*.log' \
--exclude='.env'
多了就写文件,一行一条:
# <本地目录>/.rsyncignore
.git/
node_modules/
*.log
.env
.cache/
--exclude-from="<本地目录>/.rsyncignore"
顺序有意义
--exclude 从上往下匹配,先命中先生效。想只排除根目录的 .git 就写 /.git,写 .git 会连子目录里的一起排掉。
3.6 四种典型配方
| 场景 | 命令 |
|---|---|
| 镜像同步(远端与本地完全一致) | rsync -avz --no-owner --no-group --delete "<本地目录>/" aliyun:"<远端目录>/" |
| 首次全量(大文件可断点续传) | rsync -avzP --no-owner --no-group "<本地目录>/" aliyun:"<远端目录>/" |
| 拉回本地备份 | rsync -avz --no-perms --no-owner --no-group aliyun:"<远端目录>/" "<本地目录>/" |
只增量、不删除(去掉 --delete) |
rsync -avz --no-owner --no-group "<本地目录>/" aliyun:"<远端目录>/" |
3.7 三处可选加固
--info=progress2 # 替代 -P 的逐文件进度条
--chmod=D755,F644 # 把权限钉死,免疫本地挂载选项变化
--compress-choice=zstd # rsync 3.2+,比默认 zlib 快很多
--compress-choice=zstd 需要两端都支持
先查:ssh aliyun 'rsync --version | head -1'。对端低于 3.2 会直接报 unknown compressor,那就保持默认。
4. 执行同步
4.1 整体流程
flowchart LR
A["本地构建产物"] --> B["MSYS2 rsync.exe"]
B -->|"SSH 密钥"| C["远端服务器"]
C --> D["目标目录"]
4.2 最小流程
# 第一步:在本地生成要同步的产物(按你的项目而定)
<构建命令>
# 第二步:镜像同步
rsync -avz --partial --info=progress2 --no-owner --no-group --delete \
"<本地目录>/" aliyun:"<远端目录>/"
发布类场景建议先干跑:
# 插入 --dry-run,确认增删清单无误后再去掉
rsync -avz --no-owner --no-group --delete --dry-run \
"<本地目录>/" aliyun:"<远端目录>/"
4.3 一键脚本
把脚本放进项目目录(例如 <本地目录>\deploy.cmd),用 %~dp0 取自身路径,文件里一个中文都不需要:
@echo off
setlocal
cd /d "%~dp0"
set "NOPAUSE="
set "RC=0"
if /i "%~1"=="/nopause" set "NOPAUSE=1"
echo [1/2] Building...
call <构建命令>
if errorlevel 1 (
set "RC=1"
echo.
echo *** Build failed. Aborted. ***
goto :done
)
echo [2/2] Syncing...
set "CHERE_INVOKING=1"
"D:\tools\msys64\usr\bin\bash.exe" -lc "rsync -avz --partial --info=progress2 --no-owner --no-group --delete ./<产物目录>/ aliyun:<远端目录>/"
if errorlevel 1 (
set "RC=1"
echo.
echo *** Sync failed. ***
goto :done
)
echo.
echo Done.
:done
if not defined NOPAUSE (
echo.
pause
)
endlocal & exit /b %RC%
为什么要这么写:
| 要点 | 原因 |
|---|---|
用 goto :done 而不是 exit /b 1 |
exit /b 会立刻结束批处理,错误路径上的 pause 永远执行不到 |
set "RC=1" 记住返回值 |
goto 之后 errorlevel 会变,最后用 exit /b %RC% 把失败状态还给调用方(任务计划能感知失败) |
if not defined NOPAUSE |
交互式双击时暂停;挂任务计划时加 /nopause,否则会永久挂住等按键 |
endlocal & exit /b %RC% |
写一行是必须的:endlocal 会丢弃 setlocal 内的变量,同一行展开 %RC% 才能取到值 |
set "CHERE_INVOKING=1" |
不加这行,cd /d "%~dp0" 等于白做 —— bash -l 会读 /etc/profile,那里会 cd "$HOME",把工作目录冲掉(详见 4.4) |
批处理文件千万别存成 UTF-8
cmd.exe 按系统 ANSI 代码页(中文 Windows = GBK/936)解析 .cmd 文件,不是 UTF-8。存成 UTF-8 会引发一条连锁故障:
[1/2] 鐢熸垚闈欐€佹枃浠?.. ← 中文 echo 变乱码
系统找不到指定的路径。 ← cd /d "含中文的路径" 解成乱码,目录进不去
Need to install xxx@1.2.3 ← 停在错误目录,找不到本地依赖,包管理器要去联网下载
所以脚本必须满足两条:① 文件内容纯 ASCII;② 用 %~dp0 而不是硬编码路径。%~dp0 由 cmd 在运行时从文件真实路径展开(操作系统给的是 UTF-16 字符串),完全绕过文件编码问题。
注意 rsync 的源路径写的是相对路径 ./<产物目录>/,原因见下一节。
依赖命令别用裸 npx
npx xxx 在本地找不到 xxx 时会联网下载一个新版本,并且阻塞在交互提示上:
Need to install the following packages: xxx@9.9.9
Ok to proceed? (y)
自动化脚本里这是灾难(版本不可控、断网就跑不了)。三种写法按优先级:
| 情况 | 写法 |
|---|---|
| 本地有依赖 | call "%~dp0node_modules\.bin\<命令>.cmd" |
| 全局安装过 | call <命令> |
| 一定要用 npx | call npx --no-install <命令>(找不到就报错,不下载) |
4.4 工作目录与中文路径的三层坑
中文路径会在两个不同的地方出问题,症状相似但根因不同。
第一层:cmd 解析 .cmd 文件本身
cmd.exe 按 GBK(936) 解析批处理文件。文件存成 UTF-8 时,cd /d "D:\项目\..." 里的中文直接变乱码 → 系统找不到指定的路径。。解法就是 4.3 的两条:纯 ASCII + %~dp0。
第二层:cmd 把参数传给 bash
即使目录进对了,bash 的参数仍要经过 cmd → bash 这一层字节传递,而 bash 期望 UTF-8:
:: 路径含中文时,这样传过去大概率报“找不到文件”
bash.exe -lc "rsync -avz /d/项目/输出/ aliyun:/srv/app/"
诡异之处在于:你在 MSYS2 终端里手敲同样的命令却是好的(那里全程 UTF-8),所以极难定位。
规避方式:
| 方式 | 做法 |
|---|---|
| 只传相对路径(推荐,脚本里已用) | cd /d "%~dp0" 之后 rsync 的源写成 ./<产物目录>/。工作目录是 bash 从操作系统继承的(不是字符串),参数里根本不出现中文。⚠️ 必须同时设 CHERE_INVOKING=1,否则工作目录会被冲掉,见下 |
把逻辑写进 .sh |
建一个 UTF-8 无 BOM 的 ~/sync.sh,中文路径写在 .sh 里由 bash 自己读;.cmd 只负责 bash -l /home/yourname/sync.sh |
| 改成 ASCII 路径 | 本地目录改成纯英文,两层坑一起消失,一劳永逸 |
第三层:bash -l 会偷偷改掉工作目录
即使前面两关都过了,还有第三个陷阱:登录 shell 会重置当前目录。Cygwin / MSYS2 的 /etc/profile 里有这么一段:
if [ -z "${CHERE_INVOKING}" ]; then
cd "${HOME}" || echo "WARNING: Failed to cd to ${HOME}"
fi
所以 bash -lc "..." 一启动就跳到了 $HOME,.cmd 里 cd /d "%~dp0" 设好的目录白设了,./<产物目录>/ 被解析到 $HOME 下面:
rsync: [sender] change_dir "/home/yourname/./public" failed: No such file or directory (2)
解法是在调用 bash 之前设置一个环境变量:
set "CHERE_INVOKING=1"
"D:\tools\msys64\usr\bin\bash.exe" -lc "rsync ..."
CHERE_INVOKING 是 Cygwin 系专门为「保留当前目录」提供的开关。它走环境变量而不是命令行参数,所以顺带也不受编码问题影响。
名字必须全大写
shell 环境变量大小写敏感,Chere_Invoking 不生效。
不想被这层 shell 折腾,也可以完全绕开 bash:rsync.exe 本身就是可执行程序,直接调用即可,工作目录原样保留:
set "PATH=D:\tools\msys64\usr\bin;%PATH%"
"D:\tools\msys64\usr\bin\rsync.exe" -avz --partial --info=progress2 --no-owner --no-group --delete ./<产物目录>/ aliyun:<远端目录>/
临时设 PATH 是为了让 rsync.exe 能找到同目录下的 ssh.exe(它靠 PATH 查找远程 shell)。这个 set 只影响当前批处理进程,不会污染系统环境变量。
方式二的脚本:
#!/bin/bash
set -euo pipefail
SRC="<本地目录>/"
DST="aliyun:<远端目录>/"
echo "=== $(date '+%F %T') 同步开始 ==="
rsync -avz --partial --info=progress2 \
--no-owner --no-group --delete \
"$SRC" "$DST"
echo "=== $(date '+%F %T') 同步完成 ==="
"D:\tools\msys64\usr\bin\bash.exe" -l /home/yourname/sync.sh
症状识别
- 批处理输出里中文变乱码、
cd报「系统找不到指定的路径」 → 第一层,文件编码问题 - 报
No such file or directory但你确认文件明明在 → 第二层,参数传递问题 - 报
change_dir "/home/xxx/./..." failed,路径里出现了家目录 → 第三层,bash -l改了工作目录
前两层的根治办法是同一个:让中文既不出现在 .cmd 文件里,也不出现在跨 cmd→bash 的参数里。 第三层则是永远要记得 CHERE_INVOKING=1。
4.5 验证同步结果
# 远端文件数与权限抽样
ssh aliyun 'du -sh "<远端目录>"; find "<远端目录>" -type f | wc -l'
# 找权限异常的文件(应该只剩 644 和 755)
ssh aliyun 'find "<远端目录>" -type f ! -perm 644 | head'
本地对照:
find "<本地目录>" -type f | wc -l
两个数字一致 = 完全镜像。
4.6 回滚保险
把 --delete 换成带备份的版本,被删的文件不会直接消失:
--delete --backup --backup-dir=/srv/.trash-$(date +%F)
远端被”删”的文件会挪进 /srv/.trash-2026-10-10/,定期清旧日期目录即可。
5. 自动化(可选)
5.1 挂 Windows 任务计划
# 路径含空格的话,/tr 里的引号会被再解析一次,很麻烦——这也是尽量别用空格路径的理由
schtasks /create /tn "sync-task" /sc daily /st 09:00 /tr "<本地目录>\deploy.cmd /nopause"
任务计划的三个前提
- 必须加
/nopause—— 否则脚本末尾的pause会一直等按键,任务永久挂住不退出,下次触发还会叠加一个 - 全部用绝对路径,工作目录也要显式设置
- 私钥必须已解锁(无 passphrase)或已加进
ssh-agent,否则会静默失败
5.2 如果项目自带部署插件
不少项目框架自带部署命令(本质是调 rsync),它们要求 rsync 在 Windows 的 PATH 里——这和 1.8 的「不要污染 PATH」冲突。
只在脚本内临时设 PATH(只影响该进程,不动系统环境变量):
set "PATH=D:\tools\msys64\usr\bin;%PATH%"
call <部署命令>
但既然已经有一条验证通过的 rsync 命令,用脚本包起来更可控:参数、日志、失败中止都在你手里。
6. 排错表
| 报错 | 原因 / 处置 |
|---|---|
Permissions 0644 for 'xxx.pem' are too open |
忘了 chmod 600 |
Permission denied (publickey) |
用户名错 / 私钥不对 / 公钥没进 authorized_keys |
rsync: command not found |
对端没装 rsync |
chown ... failed: Invalid Argument 刷屏 |
忘了 --no-owner --no-group |
mkdir "<远端目录>" failed: Permission denied |
加 --rsync-path="sudo rsync",或用有权限的用户 |
批处理输出中文乱码 + 系统找不到指定的路径 |
.cmd 存成了 UTF-8,被 cmd 按 GBK 解析(见 4.3) |
No such file or directory 但文件确实在 |
中文路径跨 cmd→bash 参数编码问题(见 4.4) |
change_dir "/home/xxx/./..." failed: No such file or directory |
bash -l 读 /etc/profile 时 cd "$HOME" 了,加 set "CHERE_INVOKING=1"(见 4.4) |
Need to install xxx@y.z 卡在 Ok to proceed? |
裸 npx 在联网下载,改用本地依赖或 --no-install |
unknown compressor |
对端 rsync < 3.2,去掉 --compress-choice=zstd |
Connection refused / 超时 |
端口错 / 安全组没放行 / sshd 没在听 |
下载时报 404 from mirror |
镜像同步延迟,pacman 会自动 fallback,无害 |
--delete 删多了 |
没干跑。任何带 --delete 的新命令都必须先 --dry-run |
| WSL 里私钥 chmod 无效 | 那是 WSL 的 DrvFs 特性,与本方案无关 |
7. 参考
- MSYS2 Installer 官方文档 —— SFX 归档与
-o参数 - MSYS2 Package Mirrors / 完整镜像列表
- MSYS2 Configuration Locations ——
$HOME与配置落点 man rsync、man ssh_config