[筆記]Copy git commited changed files into new directory

有時候,會需要只取得變更的程式檔案,再做打包

列出 commit 的變更

可在 Git Bash 使用git-diff指令
(列出時,若超過目前 console 高度,按ENTER往下瀏覽,按q結束離開)

使用--name-only列出檔案名稱

  1. 兩個 commit 間差異的變更
    SHA1SHA2分別為你要比對的兩個 commit
1
git diff --name-only SHA1 SHA2
  1. 取得 not staged 的變更 (也就是尚未 git add):
1
git diff --name-only
  1. 比對取得最後一個 commit 之後的變更
1
git diff --name-only HEAD
  1. 比對取得最後一個 commit 之前 與最後一個 commit 之間的變更
1
git diff --name-only HEAD^ HEAD

Q: 如果改成 git diff --name-only HEAD^ 會是甚麼?
A: 就是比對最後一個 commit 之前,與最後一個 commit 之後的變更
就像是
git diff --name-only HEAD^ HEAD
加上
git diff --name-only HEAD
的結果

僅取得狀態為新增與修改的變更

以上的指令,會列出所有的變更,包含已刪除的檔案。
因此,當要進行複製,若列表包含已刪除的檔案,便會出現問題。

則可加上使用--diff-filter參數

  • 新增(Added) : A
  • 修改(Modified) : M
  • 刪除(Deleted) : D
    … 等等

大寫表示 include,小寫表示 exclude

若僅需列出新增(Added)、修改(Modified)

1
git diff --name-only --diff-filter=AM HEAD^ HEAD

相對的,若僅須排除刪除的:

1
git diff --name-only --diff-filter=d HEAD^ HEAD

複製列出的檔案到新的資料夾

複製的指令,可使用 cp
若要讓複製的檔案在新的根目錄中,維持原本的檔案夾結構
須加上參數 --parents

有關$()的說明,可參考這篇unix.stackchange
意思大概是,將$()內的指令,執行的結果,帶入$()所在指令的位置

所以可以利用$()結合如下:
(其中out-dir須為已存在之資料夾)

1
cp --parents $(git diff --name-only --diff-filter=d HEAD^ HEAD) out-dir

建立新資料夾存放複製的檔案

若要一併於指令執行時建立存放的資料夾,可使用mkdir
然而,若資料夾已存在,直接使用mkdir會丟出錯誤
加上-p便不會丟出錯誤(並不會取代)

若要取代,則需先將現有資料夾含所有內容刪除 (使用rm -r)
但是,若刪除時資料夾不存在,仍會丟出錯誤
則須加上-f 忽略不存在的情形,變成

1
rm -rf dirname

因此,可再修改成:
(;表示前方指令的結束,因此,會依序刪除、建立資料夾,再進行複製檔案搬移)

1
rm -rf out-dir; mkdir out-dir; cp --parents $(git diff --name-only --diff-filter=d HEAD^ HEAD) out-dir

References

  1. “What is $() in a command?” - stackexchange
  2. git-diff
  3. “How to list only the file names that changed between two commits?” - stackoverflow
  4. “Git: how to get all the files changed and new files in a folder or zip?” - stackoverflow
  5. “Filter git diff by type of change” - stackoverlfow