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)
}
}
}
実行した感じちゃんと動いてそう.