Gitで差分ファイルを抽出+zipファイル化する方法

こんにちは!長屋です。最近は学生時代からのあだ名、めぐたん が社内でも浸透してきました。笑

入社してから本格的に触るようになったGitにもだいぶ慣れてきた…と言いたいところですが、見慣れないコマンドにはやはり躊躇してしまいます。

今回は私にとってその一例であった差分抽出がテーマです。使うシーンは、例えば「更新したファイルだけを集めてzipファイル化したい」というとき。手作業でひとつずつファイルを集めてくることなく、一発でzipファイルが完成します!

基本のコマンド

まずは差分ファイルを抽出+zipファイル化の基本的な使い方をご紹介します。下記のような状況を想定します。

  • 修正前のデータがリモートのmasterブランチにある
  • 作業用にrevisionブランチを作成し、修正を行ってコミット
  • masterとrevisionブランチ間の差分がほしい

変更したファイルのみ抽出・zip化する

こんなときに使うコマンドがこちらです。

$ git archive revision `git diff --name-only origin/master revision --diff-filter=ACMR` -o archive.zip

コマンドの仕組み

上記のコマンドはgit archivegit diffが組み合わさってできています。2つのコマンドを単体で実行してみると挙動がわかりやすくなりますので、それぞれ実行してみましょう!

ファイルをアーカイブする「git archive」

$ git archive revision -o archive.zip

git archiveは、指定したブランチ(上記の例でいうとrevision)の状態を丸々アーカイブしてくれるコマンドです。オプション-o archive.zipによって、データは「archive.zip」というファイル名で作成されます。

また、ブランチ名に続けてファイル名を指定することで指定したファイルだけをarchive.zipの中に含めることができます。

$ git archive revision index.html css/style.css -o archive.zip

差分を確認する「git diff」

$ git diff --name-only origin/master revision
# 実行結果の例
index.html
css/style.css

git diffは差分を確認できるコマンドです。比較の基準になる「origin/master」→作業ブランチ「revision」の順で指定すると、「origin/masterからrevisionまでにどんな変更があったか」という結果を見ることができます。
オプション–name-onlyをつけることで更新されたファイル名だけをシンプルに返してくれます。

2つを組み合わせると…

$ git archive revision `git diff --name-only origin/master revision` -o archive.zip

git archiveとgit diffを組み合わせる

「git diff」でorigin/masterとrevision間を比較して差分を取得→ファイル名を返して「git archive」でアーカイブする という仕組みになっていることがわかると思います!

最後にもう1ステップです。git diffが返してくれる値には削除されたファイルも含まれるのですが、それらはgit archiveしようとした時点で「ファイルが削除されているから見つからない」という状態になりエラーが出てしまいます。

これを防ぐため、git diffの記述の中にはオプション–diff-filter=ACMRを含めておきましょう。「A=追加、C=コピー、M=変更、R=リネームのステータスのファイルだけを返してね」という意味です。

$ git archive revision `git diff --name-only origin/master revision --diff-filter=ACMR` -o archive.zip

これで一番最初に紹介した基本的なコマンドにたどり着きました!

色々な差分の取り方

ここまで、サンプルとして「作業前のmasterブランチから作業後のrevisionブランチまで」という差分のとり方を紹介してきました。しかし差分をとる範囲はブランチ間に限りません。作業ブランチの状況によって使いやすいものを選んでみてください。

HEADを使う

$ git archive HEAD `git diff --name-only HEAD~1 HEAD --diff-filter=ACMR` -o archive.zip

HEAD(=作業しているブランチの最新コミット)からいくつ分前のコミットの差分を取るか?という指定方法です。「HEAD~1」の数字部分を変えれば任意の数だけ前のコミットからの差分を取ることができます。

コミットIDを使う

$ git archive [コミットID2] `git diff --name-only [コミットID1] [コミットID2] --diff-filter=ACMR` -o archive.zip

コミットIDを使った指定方法です。
ちなみにコマンドラインでコミットIDを確認するには、git logにオプション–onelineをつけたものがわかりやすいです。返り値として7桁のコミットIDとコミットメッセージが表示されます。

$ git log --oneline
#実行結果の例
[コミットID2]  cssを修正しました。
[コミットID1]  htmlを修正しました。

タグを使う

$ git archive [タグ2] `git diff --name-only [タグ1] [タグ2] --diff-filter=ACMR` -o archive.zip

タグの名前も指定方法に選ぶことができます。コマンドラインでのタグ設定にはgit tagを使います。

#コミットID指定によるタグ付与
$ git tag [タグ1] [コミットID]

まとめ

一見長くて複雑そうなコマンドですが、2つのコマンドがそれぞれどんな動作をするのかがわかれば安心して使えるのではないかなと思います。 私のようなGit初心者の方でも腑に落ちる解説になっていたら嬉しいです!

また、数クリックで動作を完了できるSourceTreeのカスタムアクションを活用する方法もあります。より簡単に使いたい方は下記の記事を参考にぜひお試しください。
参考サイト: Git管理ツール「SourceTree」で差分ファイルを抜き出す方法