LoginSignup
4
4

More than 5 years have passed since last update.

JGitでリポジトリを解析するサンプル3種

Posted at

注意書き

情報を集めたのが数年前なので、より新しい方法が存在する可能性があります。

背景

JGitは少し癖のあるライブラリで、gitの解析をしていた際に困った記憶があります。
そんな当時のコードが一部発掘され、役に立つ人がいるかもしれないので掲載します。
他の解析をしたい場合は、以下のドキュメントが参考になるかと思います。

JGit User Guide
JGit API Documentation

前提

リポジトリを表す変数名は、repositoryとします。
以下のコードで作成しています。

val repository = new FileRepository(new File(repositoryPath + "/.git"))

if( ! repository.getRepositoryState.canResetHead ){
  println("target path is not a valid repository")
  System.exit(0);
}

ここでは、gitリポジトリが存在するかどうか、また、正常な状態かどうかの判定をcanResetHeadで行っています。
チェック方法は様々あるかと思いますが、resetできればおおよそ解析には困らない状態なはずですので、ひとまずこの方法を採用しています。

サンプル

カレントブランチのコミットメッセージ一覧を表示

val revWalk = new PlotWalk(repository)
val rootId = repository.resolve("HEAD")
val root = revWalk.parseCommit(rootId)
revWalk.markStart(root)

val plotCommitList = new PlotCommitList[PlotLane]()
plotCommitList.source(revWalk)
plotCommitList.fillTo(Integer.MAX_VALUE)

for( c <- plotCommitList )
  println( c.getFullMessage )

HEADからInteger.MAX_VALUE個だけコミットを遡る、というシンプルなサンプルです。
もちろんそんなにコミット数は無いので、限界まで遡る、という意味合いになります。

repository.resolve()に文字列を与えると、解析して適切なObjectId(git内部で使ってるハッシュ)を返してくれます。
下の例では"HEAD"を与えていますが、例えば"HEAD^"を与えると1つ前のコミットからたどり始めます。

このサンプルではコミットメッセージのみですが、RevCommitクラスに格納されている情報を出力することができます。

あるコミットにおけるdiffを取得

val df = new DiffFormatter(DisabledOutputStream.INSTANCE)
df.setRepository(repository)
df.setDiffComparator(RawTextComparator.DEFAULT)
df.setDetectRenames(true)

def get(c: RevCommit): mutable.Buffer[DiffEntry] =
  c.getParentCount match {
    case 0 => mutable.Buffer.empty[DiffEntry]
    case _ => df.scan(c.getParent(0), c.getTree).asScala
  }

getにコミットを与えることで、その親との差分を取得できます。

差分情報は、ファイルごとにDiffEntryというクラスに収められます。
DiffEntryには、新しい側の情報と古い側の情報が両方保存されており、リネームや破棄を検出することが可能です。
例えば、AからBにrenameされた場合は、getOldPath="A", getNewPath="B"となります。
また、Aが破棄された場合は、getOldPath="A"、getNewPath="/dev/null"となります。

DiffFormatter
DiffEntry

特定リビジョンのファイルの内容を表示

git cat-file -pです。
該当ファイルのID(blob)を取得した後、以下の通りストリームを使って取得する必要があります。

How to “cat” a file in JGit?

val fileId = ... // 目的ファイルのobject ID
val loader = repository.open(fileId)
loader.copyTo(System.out)   // loader.openStream でInputStreamが取得できる

まとめ

JGitは扱いにくい癖があるので、上記サンプルが参考になれば幸いです。

4
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
4