Files

249 lines
7.1 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
slug: Windows Git Bash 上使用 ADB 的問題
title: Windows Git Bash 上使用 ADB 的問題
description:
toc: true
authors:
- awin
tags:
- windows
- terminal
categories:
- System
series:
- Windows
date: 2026-08-20T00:00:00
lastmod: 2026-08-20T00:00:00
featuredVideo:
featuredImage:
draft: false
enableComment: true
---
# Windows Git Bash 上使用 ADB 的路徑轉換問題
在 Windows 的 Git Bash 裡使用 ADB 時,可能會遇到一個讓人摸不著頭緒的問題:明明輸入的是正確 Android pathADB 收到的卻像是 Windows path。
<!--more-->
例如,要把目前目錄的 `1.txt` 傳到 Android 裝置:
```zsh
adb push 1.txt /data/local/tmp/
```
這條命令裡其實同時存在兩個檔案系統:
```text
1.txt Windows 本機檔案
/data/local/tmp/ Android 裝置內的目的地
```
對 ADB 來說,兩者的意義很清楚;但 Git Bash 背後的 MSYS2 runtime 只看得到命令列字串。它看到 `/data/local/tmp/` 這種以 `/` 開頭的參數時,可能會以為這是本機 POSIX path,於是在啟動 Windows 原生的 `adb.exe` 前,先把它轉成 Windows path。
結果,一個原本屬於 Android 的 path,就這樣被「好心辦壞事」地改寫了。
## Git Bash 為什麼要自動轉換 path
Git Bash 提供類 Unix 的操作環境,使用的 path 長得像這樣:
```text
/c/Users/<username>/Downloads/1.txt
```
Windows 原生程式通常期待的是:
```text
C:\Users\<username>\Downloads\1.txt
```
為了讓 Git Bash 可以順利呼叫 Windows 程式,Git for Windows 所附的 MSYS2 runtime 會檢查傳給原生 `.exe` 的參數,並嘗試將 POSIX path 自動轉成 Windows path。
```text
Git Bash Windows 原生程式
/c/Users/me/file.txt
|
| MSYS2 path conversion
v
C:\Users\me\file.txt -------> adb.exe、subl.exe、其他 CLI
```
對大部分 Windows CLI 而言,這項功能非常實用。問題是,MSYS2 無法知道某個 `/` 開頭的參數究竟代表:
- Windows 本機檔案的 POSIX 表示法;或
- Android、Docker、遠端主機等另一個系統內的 path。
當兩者長得一樣,自動判斷就可能出錯。
## `MSYS_NO_PATHCONV` 是什麼?
Git for Windows 提供 `MSYS_NO_PATHCONV`,用來停用傳給 Windows 原生程式的 POSIX-to-Windows path conversion。
```zsh
MSYS_NO_PATHCONV=1 adb push 1.txt /data/local/tmp/
```
設定後,`/data/local/tmp/` 會原樣傳給 `adb.exe`,不再被改寫成本機 Windows path。
它的行為可以整理成:
```text
沒有設定 MSYS_NO_PATHCONV
-> 使用預設的自動 path conversion
設定 MSYS_NO_PATHCONV=1
-> 停用自動 path conversion
```
需要特別注意:`MSYS_NO_PATHCONV=1` 不是開啟轉換,而是關閉轉換。若要恢復預設行為,應該移除這個環境變數:
```zsh
unset MSYS_NO_PATHCONV
```
不要把 `MSYS_NO_PATHCONV=0` 當成「重新開啟轉換」;這是一個是否存在的停用開關,不是一般的 `0``1` Boolean 設定。
## 不要全域停用 path conversion
最直接的做法看起來是把下面這行寫進 shell 設定檔:
```zsh
export MSYS_NO_PATHCONV=1
```
但這會影響之後啟動的所有 Windows 原生程式。
例如,原本可以在 Git Bash 使用 POSIX path 呼叫 Sublime Text
```zsh
subl.exe /c/Users/<username>/notes.txt
```
預設情況下,MSYS2 會將參數轉成正確的 Windows path。若全域停用轉換,`subl.exe` 會直接收到 `/c/Users/...`;Windows 原生程式可能將它視為目前磁碟機根目錄下的 `c\Users\...`,最後開啟錯誤的位置。
因此,真正需要的不是「整個 Git Bash 都不要轉換」,而是「只有呼叫 ADB 時不要轉換」。
## 正確做法:只替 ADB 停用轉換
可以為 ADB 建立一個 shell wrapper
```zsh
adb() {
MSYS_NO_PATHCONV=1 command adb.exe "$@"
}
```
如果使用 Zsh,將它加入 `~/.zshrc`,再重新載入:
```zsh
source ~/.zshrc
```
如果使用 Bash,則加入 `~/.bashrc`
```bash
source ~/.bashrc
```
這個 wrapper 做了三件事:
1. 讓輸入的 `adb ...` 先進入 shell function。
2. 只替這次執行設定 `MSYS_NO_PATHCONV=1`
3.`command adb.exe "$@"` 呼叫真正的 ADB,並完整保留所有參數。
如此一來,影響範圍只限於 ADB
```text
一般 Windows CLI
-> 維持預設 path conversion
adb.exe
-> 只在這次呼叫停用 conversion
-> Android path 保持原樣
```
## 停用轉換後,本機絕對路徑怎麼辦?
停用 path conversion 也會帶來另一個問題。以下命令的第一個 path 是 Windows 本機檔案:
```zsh
adb push /c/Users/<username>/Downloads/1.txt /data/local/tmp/
```
wrapper 會讓所有參數都保持原樣,因此 `adb.exe` 收到的本機來源仍是:
```text
/c/Users/<username>/Downloads/1.txt
```
這不是 Windows 原生 path。此時應使用 `cygpath`,主動將本機來源轉換成 Windows 格式:
```zsh
adb push "$(cygpath -w /c/Users/<username>/Downloads/1.txt)" /data/local/tmp/
```
其中:
```text
cygpath 在 POSIX 與 Windows path 格式之間轉換
-w 輸出 Windows 格式
$(...) 執行括號內的命令,並用輸出取代這一段
"..." 確保含有空白的 path 仍被視為單一參數
```
shell 展開後,實際傳給 ADB 的命令概念上會變成:
```zsh
adb.exe push "C:\Users\<username>\Downloads\1.txt" /data/local/tmp/
```
如果來源是目前目錄下的相對路徑,就不需要額外處理:
```zsh
adb push 1.txt /data/local/tmp/
```
相對路徑 `1.txt` 對 Git Bash 與 Windows 原生程式而言,都會以目前工作目錄為基準,因此通常可以直接使用。
## 判斷原則
遇到 path conversion 問題時,可以先問兩個問題:
```text
這個 path 屬於哪一個檔案系統?
|
+-- Windows 本機
| |
| +-- POSIX 絕對路徑:用 cygpath -w 主動轉換
| +-- 相對路徑:通常可直接使用
|
+-- Android/遠端系統
|
+-- 必須保持原樣,不可被 MSYS2 當成本機 path 轉換
```
`MSYS_NO_PATHCONV` 並不是越常設定越好。它適合用在「目標程式有自己的 slash path 語意」的單次命令,例如 ADB;不適合成為整個 shell 的全域預設。
## 結論
這個問題的根源不在 ADB,也不在 Android,而是同一條命令同時跨越了三個世界:
```text
Git Bash 的 POSIX path
|
v
Windows 原生 adb.exe
|
v
Android 裝置內的 path
```
MSYS2 的自動轉換原本是為了打通 Git Bash 與 Windows,卻無法辨認 Android path。正確解法是縮小例外範圍:保留全域預設轉換,只在呼叫 ADB 時設定 `MSYS_NO_PATHCONV=1`;若本機來源使用 POSIX 絕對路徑,再以 `cygpath -w` 明確轉成 Windows path。
簡單來說:**本機 path 主動轉換,Android path 保持原樣,而且例外只套用在真正需要的命令上。**
## 參考資料
- [MSYS2 Filesystem Paths](https://www.msys2.org/docs/filesystem-paths/)
- [Git for Windows release notes`MSYS_NO_PATHCONV`](https://github.com/git-for-windows/build-extra/blob/master/ReleaseNotes.md)