TFS でバージョン管理されているファイルを一式取得する方法
立て続けにご質問をいただいたので、書いてみました。
Team Foundation Server でバージョン管理されているファイルは、実際には SQL Server 内にデータとして格納されています。
ソースコードを成果物として納品する等の理由で、
「ファイルとして一式取得したい」
しかも
「最新バージョンのファイルだけでなく、変更管理されている、開発途中のバージョンもすべてファイルとして取得したい」
といったニーズを聞きます。
この場合、最新/旧バージョンのソースコードを “ファイル” として TFS から抽出する必要が出てきます。
Visual Studio でひとつひとつ手動で取得する、TFS API を利用しツールを開発するなど、実際には様々な方法があるのですが、個人的には、Team Foundation Server のコマンド ライン ツールを活用する方法が最も労力が少ないかなと思っています。
もちろん、これが唯一の正解ではないですが、ここでは、コマンド ライン ツールを活用した例をご紹介します。
(注) 以下の手順を実施すると、チェックインされていない編集途中のファイルは無くなってしまうので、ご注意ください。
準備
この方法を実行するには、以下の点が必要です。
- 該当のチーム コレクションに適切なアクセス権限があること
- 操作するコンピュータに対して適切なアクセス権限があること
- 取得したい最上位フォルダにワークスペース マッピングが行われていること
特に “ワークスペース マッピング” の確認は重要で、該当のソリューション フォルダのみマッピングが行われているものの、下記のようにチーム プロジェクトの最上位、またはチーム コレクションの最上位では、マッピングされていないケースがあります。
もし「ワークスペースが見つからない」といったエラーが発生した際には、そのフォルダのマッピングが適切に行われているかご確認ください。
最新バージョンの取得
まず最新バージョンを取得する方法を紹介します。
[開発者コマンド プロンプト] を起動します。
[開発者コマンド プロンプト] は、Visual Studio 2013 の場合、\Program Files (x86)\Microsoft Visual Studio 12.0\Common7\Tools\Shortcuts にショートカットがあります。
もちろん、各種ツールへのパスが通っていれば、通常のコマンド プロンプトでも問題ありません。
コマンド プロンプトで、取得したい最上位フォルダのマップ先 (ローカル パス) に移動してください。
ローカル パスは、以下のようにソース管理エクスプローラーから確認できます。
以下のコマンドを実行します。(実行する前に、いったんこのフォルダ内のファイルをクリアすると結果がわかりやすいです)
tf get /force /overwrite
マップ先のフォルダを確認すると最新ファイルが一式ダウンロードされているかと思います。
特定バージョンの取得 その 1
次に、特定の変更セットのファイルを取得する方法です。(実行する前に、いったんこのフォルダ内のファイルをクリアすると結果がわかりやすいです)
tf get /force /overwrite /version:n
*n = 変更セットの番号
マップ先のフォルダが、変更セットの時の状態となっているのがご覧いだだけます。
(たとえば、この変更セット以降で追加されたファイルやフォルダが無いなど)
ただし、この方法では、ワークスペース全体を特定の変更セットの時の状態に戻せるものの、その変更セットで変更されていないファイルも含まれています。
特定バージョンの取得 その 2
もし、特定の変更セットで変更されたファイル “のみ” を取得したい場合には、tf.exe ではなく、Team Foundation Server Power Tools に付属の tfpt.exe を使用します。
この Power Tools は、それぞれ以下の URL より入手できます。
2013 版: https://visualstudiogallery.msdn.microsoft.com/f017b10c-02b4-4d6d-9845-58a06545627f
2012 版: https://visualstudiogallery.msdn.microsoft.com/b1ef7eb2-e084-4cb8-9bc7-06c3bad9148f
2010 版: https://visualstudiogallery.msdn.microsoft.com/c255a1e4-04ba-4f68-8f4e-cd473d6b971f
Power Tools がインストールされた環境で、以下のコマンドで、特定の変更セットで変更されたファイルのみ取得することができます。
(実行する前に、いったんこのフォルダ内のファイルをクリアすると結果がわかりやすいです)
tfpt getcs /force /overwrite /changeset:n
*n = 変更セットの番号
応用編 ~ 納品用に一式取得
例えば、以下のようなバッチ ファイルを作成すると、納品用に最新のファイル一式と、各変更セットにおける旧バージョンのファイル、およびその履歴情報のログを作成することができます。
もっとスマートな方法がきっとあると思うのですが、あくまでも例として捉えていただければ。
ここでは WineOnlineShop というチーム プロジェクトのファイル一式を取得しています。
なお、絶対パスでそれぞれ書かれていますが、皆様の環境にあわせて適宜修正ください。
作業用に一時的なワークスペースを作成します。
マッピングの定義において、"ソース管理フォルダ" は、処理対象フォルダの 1 つ上のフォルダを指定してください。(move コマンドの都合上...)
以下の画面例では、WineOnlineShop チームプロジェクトのデータを取りたいので、一つ上のフォルダ ($/) を指定してます。
ローカル フォルダは、以降で作成するバッチ ファイルの定義に合わせてください。(例では C:\temp\TempWorkspace となります)[開発者コマンド プロンプト] を起動し、上記で作成したローカル フォルダに移動します。
以下で作成した 2 つのバッチファイルを順に起動します。tf.exe / tfpt.exe は、現在のフォルダ配下に対して再帰的に処理を行いますので、2. の位置にいることは重要です。
- GetHistory.bat
- GetAllVersion.bat 最終変更セット番号
一時的なワークスペースを削除し、元のワークスペース定義に戻します。
それでは、2 つのバッチファイルの中身を解説します。
GetHistory.bat
tf history WineOnlineShop /r /noprompt /stopafter:1 /version:T
tf history WineOnlineShop /r /noprompt /version:T /format:detailed > c:\temp\delivery\ChangesetHistory.txt
1 行目: 変更セットの最終番号を取得しています。GetAllVersion.bat の入力パラメータでこの数値を指定します。
2 行目: 変更セットの詳細情報を c:\temp\deliverty\ChangesetHistory.txt に書き込んでいます。
GetAllVersion.bat
if "%1" == "" goto ERROR
setlocal enabledelayedexpansion
start /wait tf get /force /overwrite
move "C:\temp\TempWorkspace\WineOnlineShop" "c:\temp\delivery\_latest"
for /l %%X in (1, 1, %1) do (
start /wait tfpt getcs /force /overwrite /changeset:%%X
move "C:\temp\TempWorkspace\WineOnlineShop" "c:\temp\delivery\%%~X"
)
:ERROR
echo " GetAllVersion.bat 最終変更セット番号"
1 行目: 変更セットの最終番号をパラメーターで取得しています。もしパラメーターが指定されていなければ、9 行目にジャンプして、エラーメッセージが表示されます。
2 行目: 遅延環境変数の宣言。ループカウンタ用にこの定義が必要なのです。
3 行目: まずは最新バージョンを取得します。tf.exe の処理は非同期で行われるため、次の move コマンドのために start /wait で処理を待ち合わせるようにしています。
4 行目: move コマンドで取得した最新バージョンを含むフォルダを _latest というフォルダ名に変更して移動しています。
5 行目: for 文を使い、パラメーターで指定した最終変更セット番号 (%1) の数になるまで、以下の処理を繰り返し実行します。
6 行目: tfpt getcs で変更セット内の変更されたファイルのみを抽出しています。変更セット番号は、ループカウンタ (%%X) で指定しています。5 行目と同様、start /wait で処理を待ち合わせるようにしています。
7 行目: move コマンドで取得したバージョンを含むフォルダを、変更セットの番号に変更して移動しています。
んー。もっと良い方法あるような気がしてきました。もう少し考えたいと思います。