今天被問到一個關於 Git 版控的問題,同事提到我們有個網站專案的 Repo 裡面有個 *.svg
檔案,之前 git commit 的時候使用 helloWorld.svg
這樣的檔名,但是部署的時候發生錯誤,客戶告知必須用英文小寫的檔名才能正常運作,所以他就來修改一下檔案名稱,結果卻發現 Git 怎樣都無法修改檔名大小寫部分,問我該怎麼辦。這篇文章我就來跟各位說明這個問題的來龍去脈與解決方法。
關於忽略檔名大小寫的預設值
你只要輸入以下命令,就可以查詢 Git 所有設定的說明:
git config --help
其中有個 core.ignoreCase
設定,可以用來告訴 Git 是否要區分檔名路徑的大小寫,其預設值為 false
,但可能有些特殊情況會讓你的預設值並不是 false
!
問題發生的原因
有許多 檔案系統 (Filesystems) 本身就是不區分大小寫的 (case insensitive),像是 APFS (Apple File System), HFS+ (HFS Plus), FAT (File Allocation Table), NTFS (New Technology File System) 等等,都是不區分大小寫的檔案系統。其實並非 "Windows" 就是不區分大小寫,而是「檔案系統」本身決定了檔名是否要區分大小寫,其實 Windows 是可以區分檔名大小寫的。
事實上,當你透過 git clone
或 git init
的時候,Git 會自動判斷你現在所在的檔案系統是否支援區分大小寫,如果你使用 Windows 常見的 NTFS 或 FAT 檔案系統,那麼預設你的 .git\config
會有以下預設值:
[core]
repositoryformatversion = 0
filemode = false
bare = false
logallrefupdates = true
ignorecase = true
這裡有個 core.ignorecase
核心設定預設被寫入了 true
的值,但你若在 Linux 或 macOS 底下執行 git clone
或 git init
的話,預設的 .git/config
並不會有 ignorecase = true
這條設定!
也因此,當你在 Windows 透過 Git 版控時,自然就會忽略所有檔名路徑的大小寫差異,這會讓你永遠無法更新版控中的檔名路徑大小寫。
解決方案 1
如果你去查了設定,很有可能你會這樣設定:
git config --global core.ignorecase false
因為一般來說,我們通常會把 Git 組態設定在 --global
全域等級,不過我們在 Windows 作業系統執行 git config core.ignorecase
的話,你會發現永遠得到 true
的結果,也就是怎麼設定都無效。
其實 Git 組態有三個等級,依照優先權排序分別是 --local
> --global
> --system
等等,而這裡的 --local
就是設定在 本地儲存庫 (Local Repo) 的 .git\config
檔案中,其優先權是最高的。因此,解決這個問題的方法,則是執行以下命令才對:
git config --local core.ignorecase false
如此一來你在執行 git status
的時候,就會判斷檔名大小寫了! 👍
請注意:千萬不要在有區分大小寫的檔案系統中,使用 core.ignorecase=true
設定,這可能會造成許多未知的錯誤! 🔥
除此之外,還有一個冷門的 Git 命令可以用,那就是「一次性」的組態調整,你只要在 git
命令後面立刻接上一個 -c core.ignorecase=false
參數,該命令無論你要執行 status
或 checkout
都可以自動區分檔名大小寫,但這個設定對 git clone
與 git init
是無效的。如下範例:
git -c core.ignorecase=false status
解決方案 2
另一種解決方法,則是使用 git mv
命令,強迫 Git 變更「檔案名稱」,而且此命令會自動忽略 core.ignorecase
組態設定,直接使用你在命令列使用的大小寫來當作檔名。其命令執行的範例如下:
git mv README.md ReadMe.md
上述命令可以強迫將 README.md
修改為 ReadMe.md
檔名,而且儲存在 Git 儲存庫中的檔名也會因此改變!👍
解決方案 3
還有一種可能會發生的問題,那就是你的同事已經更新了檔名大小寫,但是你的 Windows 電腦上的檔名卻一直都沒有變更大小寫。
此時你可以透過以下步驟重置工作目錄:
- 請確認工作目錄是乾淨的 (所有檔案都已經加入版控)
- 刪除工作目錄下所有檔案 (切勿刪除
.git
資料夾)
- 執行
git reset --hard
重置工作目錄
如此一來,所有檔名大小寫都會符合原始碼版控中的所有檔名,這個技巧在 Windows 只對 NTFS
檔案系統才有效喔! 👍
解決方案 4
還有一種可能會發生的問題,那就是你的 Git Repo 中同時有兩個相同檔名但不同大小寫的檔案,這樣的 Repo 在 Windows + NTFS 是無法正確顯示檔案的,只有一個檔案會被取出到工作目錄,另一個則會自動標示為 deleted
狀態。假設我們有兩個檔案在版控中,分別是 README.md
與 ReadMe.md
,假設你想刪除 ReadMe.md
檔案,其解決問題的步驟如下:
- 你無法確認工作目錄是乾淨的,因為永遠會少一個檔案 (因為有兩個同名但檔名大小寫不同的檔案)
- 請直接執行
git rm ReadMe.md
命令,此時你用 git status
會被告知刪除了兩個檔案,一個是 staged
狀態,另一個是 not staged
狀態
- 接著直接執行
git commit -m "移除重複檔案"
,並立刻執行 git reset --hard
重置工作目錄,問題就可以迎刃而解!
後記
其實跨平台開發已經成為常態,一個開發團隊中有成員使用 Windows、有成員使用 macOS 屢見不鮮,不單單後端開發經常都可以跨平台,前端的開發團隊更是如此。如果你有使用 CI/CD 對專案進行自動化建置與部署,也有非常高的機率會遇到各種不同作業系統平台的狀況。因此,我建議大家要開始重視「檔名路徑大小寫」的問題,如果可以,請盡量以「小寫」命名,否則很容易會遇到鬼打牆的狀況。
像是本篇文章提到的問題,在我們公司最近一年就遇到了兩次,我原本以為這個問題應該很簡單,但是第一次遇到此問題的人,還是可能會卡關卡很久,所以才出現撰寫這篇文章的契機,希望大家下次遇到這種狀況可以更快的解決問題! 😊
相關連結