Help us understand the problem. What is going on with this article?

JGitで"git log --follow <path>"を実現

Gitの再実装であるJGitは,JavaのAPIとして利用できることから開発や研究などの幅広い分野で用いられている.
一方非常に癖があることで知られており,良く知られているコマンドを実行するのにも苦労することがある.
今回は,ファイル名の変更を考慮したうえでファイル単位のログを取得するgit log --follow <path>をJGitを用いてJavaプロジェクト内で実行する方法をメモとして書き残しておく.

方法

実は過去に似たような質問がStack Overflowでされていて,それに対する解答もある.
https://stackoverflow.com/questions/11471836/how-to-git-log-follow-path-in-jgit-to-retrieve-the-full-history-includi

一方,この実装はかなりイケてないらしい(https://www.eclipse.org/lists/jgit-dev/msg03286.html ).
JGitの開発者曰く,用意されているFollowFilterを使えば良いらしい.

実装

FollowFilterはインスタンスをRevWalkに食わせて使うらしいので,call()の返り値をダウンキャストして食わせれば良さそう.

class LogCommand(projectPath: Path) {
    private val repository: Repository = FileRepository(projectPath.resolve(".git").toFile())
    private val git: Git = Git(repository)

    fun execute(filePath: Path): List<RevCommit> {
        val followFilter: FollowFilter = FollowFilter.create(filePath.toString(), Config().get(DiffConfig.KEY))
        followFilter.renameCallback = DiffCollector()

        val walk = git.log().addPath(filePath.toString()).call() as RevWalk
        walk.treeFilter = followFilter
        return walk.toList()
    }

    private static class DiffCollector : RenameCallback() {
        val diffs: MutableList<DiffEntry> = mutableListOf()
        override fun renamed(diff: DiffEntry) {
            diffs.add(diff)
        }
    }
}

実行した感じちゃんと動いてそう.

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away