﻿# 如何讓 Git 僅匯出在特定版本中新增或修改過的檔案

上週幫客戶處理一個年久失修的 PHP 專案，修正程式的過程中，我利用 Git 幫我直接在測試機上做好原始碼版控與備份等工作，待修正工作完成後，想要把最近一次 commit 過的變更檔案匯出，卻突然不知道指令怎麼下，研究了一下發現還蠻簡單的，今天這篇文章我打算解釋使用 [TortoiseGit](https://code.google.com/p/tortoisegit/) 、 [Git for Windows](http://msysgit.github.io/) 與在 Linux 底下使用 Git 工具，應該如何順利的匯出特定版本下的變更檔案。

**使用 TortoiseGit 匯出變更檔案**

我在多年前曾經寫過一篇【[如何讓 TortoiseSVN 僅匯出新增或修改過的檔案](/post/2008/09/09/Using-TortoiseSVN-to-Export-Only-Added-Modified-Files.aspx)】文章，在 [TortoiseGit](https://code.google.com/p/tortoisegit/) 上面的操作與 [TortoiseSVN](http://tortoisesvn.net/) 的操作幾乎完全一樣，所以我就不贅述這段，請參考該篇文章解說。  

  
**在 Windows 平台使用 Git for Windows 匯出變更檔案 (透過 Batch 指令)**

要列出最近一個版本的檔案異動清單，可以執行以下指令：

```
git diff-tree -r --no-commit-id --name-only --diff-filter=ACMRT HEAD
```

其中 **\--diff-filter=ACMRT** 所代表的意思份別是：

-   A = Added
-   C = Copied
-   M = Modified
-   R = Renamed
-   T = Changed

※ 完整的 git diff-tree 用法說明，建議可輸入 git help diff-tree 命令，以取得完整的文件說明。

這個指令主要列出該版本 ( HEAD ) 所有變更檔案的路徑與檔名而已，所以如果還要複製出這些檔案，並且依照這些變動的檔案，保留原本檔案的資料夾結構的話，則還須搭配更進階的批次檔語法。

請在你的 Git 工作目錄的最上層資料夾，輸入以下指令：

> **for /f "usebackq tokens=\*" %A in (\`git diff-tree -r --no-commit-id --name-only --diff-filter=ACMRT HEAD\`) do echo FA|xcopy "%~fA" "G:\\git\_changed\_files\\%A"**

上述指令，直接複製貼上到命令提示字元就可以順利執行，並且將目前該版本的所有變更檔案，包含資料夾結構，都複製到 G:\\git\_changed\_files 目錄下。 ( 請依照你自己的需求變更目錄名稱 ) 最後你在利用壓縮軟體自行打包這些檔案即可。

另外，我剛也花點時間寫了一支完整的批次檔，可以更加方便的輸出變更檔案：

檔案名稱：**git-export-changes.cmd  
**檔案路徑：**C:\\Program Files (x86)\\Git\\cmd**

```
@ECHO OFFsetlocal enabledelayedexpansionSET zipfile=update.zipIF "%1"=="" GOTO HelpIF NOT "%2"=="" SET zipfile=%2set output=for /f "delims=" %%a in ('git diff --name-only %1^^') do ( set output=!output! "%%a" )git archive -o %zipfile% HEAD %output%endlocalGOTO Exit:HelpECHO.ECHO 用法: git-export-changes ^<ref^> ^<filename.zip^>ECHO.ECHO 輸入 ^<ref^> 的時候，可用 HEAD，該程式會自動跟前一個版本做比較ECHO 若沒輸入 ^<filename.zip^> 的時候，預設為 updates.zip 並輸出在當前目錄ECHO.PAUSE:Exit
```

  

**使用範例**：在 Git 工作目錄下，輸入 **git-export-changes.cmd HEAD export-updated-files.zip**

  
  
**在 Linux 底下使用 Git 工具匯出變更檔案 (搭配 Shell 指令)**

利用 Git 取得變更的檔案清單，其指令是一樣的：

```
git diff-tree -r --no-commit-id --name-only --diff-filter=ACMRT HEAD
```

然後可以利用 **git archive** 這個 Git 內建命令來產生本次變更的所有檔案：

> **git archive --output=files.tar HEAD $(git diff-tree -r --no-commit-id --name-only --diff-filter=ACMRT HEAD)**

如果你想匯出 Zip 壓縮檔格式，可以改用以下指令：

> **git archive \--format\=zip --output=files.tar HEAD $(git diff-tree -r --no-commit-id --name-only --diff-filter=ACMRT HEAD)**

就這樣，很快地就能打包好這些變更的檔案，方便提供客戶更新與部署新版本。

**請注意**: 如果沒輸入 $(git diff-tree -r --no-commit-id --name-only --diff-filter=ACMRT HEAD) 的話，執行 **git archive** 會把該版本所有的檔案，全部匯出成 tar 檔，也就如同**匯出最新版本的原始碼**的意思，因此若要繪出完整原始碼，比較簡短的寫法如下：（以下指令同時適用於 Windows / Linux / Mac 作業平台）

```
git archive HEAD > export.tar
```

或是 Zip 壓縮檔格式：

```
git archive --format=zip HEAD > export.zip
```

**相關連結**

-   [Export only modified and added files with folder structure in Git](http://stackoverflow.com/questions/4541300/export-only-modified-and-added-files-with-folder-structure-in-git)
-   [How to export all changed/added files from Git?](http://stackoverflow.com/questions/2997612/how-to-export-all-changed-added-files-from-git)
-   Exporting Files From Git (similar to SVN export)
-   [Create archive of modified files in GIT via batch file](http://stackoverflow.com/questions/21639415/create-archive-of-modified-files-in-git-via-batch-file)
-   [Using Git to create an archive of changed files.](http://tosbourn.com/2011/05/git/using-git-to-create-an-archive-of-changed-files/)
-   [git-archive(1) Manual Page](https://www.kernel.org/pub/software/scm/git/docs/git-archive.html)
-   git archive 與 log 小技巧
