Gitリポジトリの差分ファイルをGruntを使って抽出する

こんにちは、つみきのフロントエンドエンジニアの佐藤です。

クライアントワーク等では初回納品後に更新した内容を、差分だけで納品するケースは多いかと思います。

差分ファイルの抽出方法は様々かと思いますが、今回は Git で管理しているプロジェクトの更新分の差分ファイルを、 Grunt を使って抽出してみたいと思います。

git archive

Git にはファイルをアーカイブするコマンドが用意されています。

http://git-scm.com/docs/git-archive

git archive --format=zip HEAD -o archive.zip

例えば上記コマンドを叩くと HEAD の内容でリポジトリ配下のファイルが zip アーカイブされます。

また以下のようにすれば指定ファイルやディレクトリのみの抽出も可能です。

git archive --format=zip HEAD filename.txt dirName -o archive.zip

filename.txtdirName ディレクトリ以下のファイルが対象となります。

さらに以下のように git diff --name-only でコミット間の差分ファイル名を返させれば、指定コミット間の差分抽出が可能です。

git archive --format=zip HEAD `git diff --name-only HEAD HEAD^` -o archive.zip

上記は HEAD から 1 つ前のコミットとの差分を抽出してくれます。

Grunt

上記を利用し、Grunt タスクとして定義し、使用してみます。

Gruntfile を用意します。

child_process.exec

Grunt でコマンドを実行するために Node.js のコアモジュールの child_process.exec を利用します。

http://nodejs.org/api/child_process.html

Gruntfile 冒頭で exec 関数を用意します。

exec = require('child_process').exec

これで引数に実行したいコマンドを exec('ls') のように渡して呼び出せば実行できます。

grunt.registerTask

次に実際に実行するタスクを書きます。

module.exports = (grunt) ->
  grunt.registerTask 'diff', ->
    exec 'git archive --format=zip HEAD `git diff --name-only HEAD HEAD^` -o archive.zip'

    return

  return

diff という名前でタスクを登録しました。

これで下記のようにタスクを実行すれば、 1 つ前のコミットとの差分を抽出しアーカイブしてくれます。

grunt diff

オプション

実行するタスクに引数を渡せるようにして、汎用性を持たせてみます。

module.exports = (grunt) ->
  grunt.registerTask 'diff', (format, dir, commitCount, fileName) ->
    commandResult = ->
      result = "git archive --format=" +
               format +
               " --prefix=" +
               dir +
               "/ HEAD `git diff --name-only HEAD HEAD~" +
               commitCount +
               "` -o " +
               fileName;
      result

    command = commandResult()
    exec command

    return

  return

タスク実行時に以下のように : で区切って引数を渡して実行します。

grunt diff:zip:dirName:2:archiveName.zip

これで実際に実行されるコマンドは以下となり、 dirName というディレクトリ名で、 HEAD から 2 つ前のコミットとの差分ファイルを抽出し、 archiveName.zip というファイル名でアーカイブが作成されます。

git archive --format=zip --prefix=dirName/ HEAD `git diff --name-only HEAD HEAD~2` -o archiveName.zip

プラグイン化

一連の処理を Grunt プラグイン化し npm レジストリへ公開しています。

https://www.npmjs.org/package/grunt-diff-archive

通常通りインストールします。

npm install grunt-diff-archive --save-dev

以下のようにタスクを定義し、実行できます。

grunt.initConfig(
  diff:
    target: {}
)

grunt.loadNpmTasks 'grunt-diff-archive'

grunt.registerTask 'default', ['diff']

現時点で指定できるオプションとデフォルト値は以下となっています。

grunt.initConfig(
  diff:
    options:
      # ルートフォルダ名
      pathName: 'root'

      # アーカイブファイル名
      fileName: 'archive'

      # アーカイブフォーマット
      format: 'zip'

      # 基点となるコミットID
      originCommit: 'HEAD'

      # 対象のコミットID
      targetCommit: 1

    target: {}
)

タスクを実行します。

grunt diff

プラグインのライセンスは MIT です。

まとめ

差分ファイルの抽出は小規模の更新でしたらタイムスタンプでの目視確認等でも可能かと思いますが、ある程度規模が大きい更新となるとそれも難しくなってくるかと思います。

git archive はその一つの方法として活用できるかと思います。

スマホアプリ制作、Web制作、UIコンサルなどのご依頼はこちら

お問い合わせ