Skip to content

Instantly share code, notes, and snippets.

@wobu
Created February 21, 2018 06:45
Show Gist options
  • Save wobu/ccfaccfc6c04c02b8d1227a0ac151c36 to your computer and use it in GitHub Desktop.
Save wobu/ccfaccfc6c04c02b8d1227a0ac151c36 to your computer and use it in GitHub Desktop.
Get first commit of file with JGit
import java.nio.file.Paths
import org.eclipse.jgit.lib._
import org.eclipse.jgit.api._
import org.eclipse.jgit.revwalk._
import org.eclipse.jgit.treewalk._
import org.eclipse.jgit.diff._
val repo: Repository
val git: Git
def getFirstCommit(file: java.io.File): RevCommit = {
val filePathToAddHeader = Paths
.get(repo.getDirectory.getParent)
.relativize(Paths.get(file.getAbsolutePath))
.toString
.replace("\\", "/")
import scala.collection.JavaConverters._
/**
* get the logs of a file in the git repository and follows andy renames / copies of this file until the source of original creation is found.
* used this example: https://stackoverflow.com/questions/11471836/how-to-git-log-follow-path-in-jgit-to-retrieve-the-full-history-includi
*/
def followCommits(path: String): RevCommit = {
val latestCommit = git
.log()
.add(repo.resolve(Constants.HEAD))
.addPath(path)
.all() // all() is needed to include commits from all refs, otherwise it could happen that ammend commits aren't shown
.call()
.asScala
.toList
.last
val previousCommits = git
.log()
.add(latestCommit)
.setMaxCount(2) // we don't need more, cause we only want the previous commit for diffing
.call()
.asScala
.toList
val commitForDiff = previousCommits match {
case _ :: next :: _ => next // next is the previous commit we want for diffing!
case head :: _ => head // is the same as oldestCommit
case Nil => latestCommit // shouldn't happen because the same commit is always included
}
val tw = new TreeWalk(repo)
// oder is important! old commit has to be added before the new commit...
tw.addTree(commitForDiff.getTree)
tw.addTree(latestCommit.getTree)
tw.setRecursive(true)
val rd = new RenameDetector(repo)
rd.setRenameScore(50) // git client also detects renames with sim of > 50%
rd.addAll(DiffEntry.scan(tw))
val files = rd.compute
val renames = files.asScala.filter { diff =>
List(DiffEntry.ChangeType.RENAME, DiffEntry.ChangeType.COPY)
.contains(diff.getChangeType) && diff.getNewPath.contains(path)
}.toList
renames match {
case Nil =>
latestCommit
case head :: Nil =>
followCommits(head.getOldPath)
case _ :: _ =>
throw new Exception(s"Error in rename detection of file '$filePathToAddHeader'")
}
}
try {
followCommits(filePathToAddHeader)
} catch {
case e: Throwable =>
throw new Exception(
s"Exception while getting first commit of path '$filePathToAddHeader'",
e)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment