工作上遇到的需求。從他處取得程式碼在本機用 Git 弄了簡單版控(不需要伺服器就可以切分支比對修改歷程,寫錯能退回原版,超讚的),改了幾支程式想將修改結果打包合併回出處。 檔案分散在多層目錄,修改已放進同一 Commit。我想依其資料夾結構整理檔案,壓縮打包後在原專案解開後覆寫,之後簽入原專案的 TFS 版控,修改清單、程式碼比較都有了,感覺挺完美。 所以我的題目是 - 如何取出最新 Commit 的所有檔案,並依其資料夾結構擺放?

爬文很快找到解答,Git 有個 diff-tree 命令可滿足我的要求。

git diff-tree --no-commit-id --name-only -r <commit id>(取最新版本時可寫 HEAD)

它輸出的結果範例如下,是包含完整路徑的清單:

MyWeb/Views/Home/Index.cshtml
MyWeb/appsettings.json
MyWeb/wwwroot/lib/busy-load/busy-load.min.css
MyWeb/wwwroot/lib/busy-load/busy-load.min.js

將檔案清單導向文字檔方便後續處理:

git diff-tree --no-commit-id --name-only -r HEAD > filelist.txt

下一步是要依據路徑清單將檔案複製到指定資料夾並維持其目錄結構。

做法很多,評估後我想練習 PowerShell,但 XCOPY 支援自動建立目錄結構(延伸閱讀:檔案部署指令實戰技巧整理), 比用 PowerShell Copy-Item 方便,那就摻在一起做瀨尿牛丸吧~

實做過程遇到兩個小問題:

  1. Git 產生的目錄分隔符號是 /,但 DOS 吃 \,我用了 -Replace '/','' 的小技巧把它置換掉
  2. XCOPY 遇到目標資料夾不存在會詢問目標路徑為檔案還是資料夾,若來源是單一檔案,目的路徑需為資料夾並加上""結尾才能避開詢問。 但要從完整檔案路徑擷取資料夾得費點手腳,我用一個小技巧:echo F | xcopy ... 強制傳入 F 回覆 XCOPY 詢問解決問題。

組成的 PowerShell 指令如下

(Get-Content .\filelist.txt) -Replace '/','\' | foreach { cmd /c "echo F | xcopy $_ D:\Update\$_ /i /y" }

組合技示範:

【應用題】

  • 如果不是最新版本,而是某個 Commit 怎麼辦? 先 git checkout &lt;commit id&gt; 取出該 Commit 的檔案版本即可
  • 如何合併匯出多個 Commit 的檔案? 重複跑 git diff-tree --no-commit-id --name-only -r <commit id> >> filelist.txt 可將多個 Commit 檔案清單合併成一個文字檔。或是產生多個 filelist.txt,分別跑 Get-Cotent + XCOPY 複製檔案到同一個資料夾。

Tips of how to export files of specific Git commit and keep their folder structure.


Comments

# by jb

太強大了!如果可以部署到遠端就更棒了! 再請教大大,有沒有辦法讓 main 跟 branch 同時上線運行? 用的是 windows apache server(xampp portable)

# by bl4

如果是 Linux 環境 可試試, GPT 產出的命令: git diff-tree --no-commit-id --name-only -r <commit SHA>| xargs -I {} rsync -R {} </your/destination/directory/>

Post a comment