jgitでファイル変更内容を取得する

前回はjgitを使用して範囲内のCommit一覧を取得しました。今回は指定したCommit間の追加/修正/削除ファイル一覧を取得します。

流れとしては以下になります。

  1. Repositoryインスタンス作成
  2. RevWalkインスタンス作成
  3. DiffFormatterインスタンス生成とRepository設定
  4. 範囲となるRevCommit(始点、終点)インスタンス作成
  5. RevCommitからRevTreeインスタンス取得
  6. DiffFormatterでDiffEntry一覧を取得

ファイルの変更内容はDiffEntryクラスで管理されます。よってDiffEntryの取り方さえわかれば一覧もできますし、その先の追加削除行数の取得にもつながります。

package sample;

import java.io.File;
import java.io.IOException;
import java.util.List;

import org.eclipse.jgit.diff.DiffEntry;
import org.eclipse.jgit.diff.DiffFormatter;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevTree;
import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.storage.file.FileRepositoryBuilder;

public class Sample02 {

    public static void main(String[] args) throws Exception {
        if (args.length == 3) {
            new Sample02(args[0]).execute(args[1], args[2]);
        }
    }

    private Repository repository;

    public Sample02(String path) throws IOException {
        FileRepositoryBuilder builder = new FileRepositoryBuilder();
        repository = builder.setGitDir(new File(path)).readEnvironment()
                .findGitDir().build();
    }

    private void execute(String from, String to) throws Exception {
        DiffFormatter diffFormatter = new DiffFormatter(System.out);
        diffFormatter.setRepository(repository);
        RevWalk walk = new RevWalk(repository);
        RevCommit fromCommit = walk.parseCommit(repository.resolve(from));
        RevCommit toCommit = walk.parseCommit(repository.resolve(to));
        RevTree fromTree = fromCommit.getTree();
        RevTree toTree = toCommit.getTree();
        List<DiffEntry> list = diffFormatter.scan(toTree, fromTree);
        list.forEach1)diffEntry) -> {
            System.out.printf("%s\t%s\n", 
                    diffEntry.getChangeType(),
                    diffEntry.getNewPath(;
        });
        walk.dispose();
    }

}

DiffEntry#getChangeType()でファイルの追加/変更/削除を判別できます。#getNewPath()で変更後のファイルのパスを取得できます。

使用するRepositoryは前回の記事「git logのrange指定」と同じものを使用します。
Release/v0.2.0とRelease/v.0.1.0間に対して実行すると以下を出力します。

ADD	func12.txt
ADD	func21.txt
ADD	release_0.2.0.txt

あまり面白みがありませんね。Release/v0.2.0とfeature/func12の途中である1e68c15で出力するとこうなります。

ADD	func11.txt
MODIFY	func12.txt
ADD	func13.txt
ADD	func21.txt
MODIFY	functions.txt
ADD	release_0.1.0.txt
ADD	release_0.2.0.txt

今回のRepositoryはファイルの削除を行っていないので特に問題にはなりませんが#getChangeType()の戻りがDELETEやRENAMEの場合はパスが取得できなかったり、名前の変更前後がわからない場合があります。そんなときは#getOldPath()を使用しましょう。

追加削除行数はorg.eclipse.jgit.diff.Editクラスで参照できます。これについてはまた後日に。では。

References

References
1 diffEntry) -> { System.out.printf("%s\t%s\n", diffEntry.getChangeType(), diffEntry.getNewPath(