如何使用JGit找到提交距离?

huangapple go评论124阅读模式
英文:

How to find commit distance using JGit?

问题

我有一个小的 Kotlin 工具类,使用 JGit 查找以下信息:

  1. branch, latestCommit, lastTag, lastTagCommit, lastReleaseTag, lastReleaseTagCommit, commitDistance

其中 lastReleaseTag 通过匹配给定的前缀来找到。

所有这些都在工作,除了 commitDistance,它表示在 latestCommit 和一个标签之间的提交次数。我正在使用 RevWalkUtils.count,但它总是返回零。

  1. class GitRepo(dir: File) {
  2. private val log = LoggerFactory.getLogger(GitRepo::class.java)
  3. constructor(dir: String) : this(File(dir))
  4. private val repository = FileRepositoryBuilder()
  5. .setGitDir(File(dir, ".git"))
  6. .readEnvironment()
  7. .findGitDir()
  8. .setMustExist(true)
  9. .build()
  10. @JvmOverloads
  11. fun info(releaseTagPrefix: String = "release/"): RepoInfo {
  12. repository.use { repo ->
  13. RevWalk(repo).use { walk ->
  14. val latestCommit: RevCommit? = Git(repository).use {
  15. try {
  16. it.log().setMaxCount(1).call().iterator().next()
  17. } catch (ex: NoHeadException) {
  18. log.warn("Repository has no HEAD")
  19. null
  20. }
  21. }
  22. val tags = repo.refDatabase.getRefsByPrefix("refs/tags/")
  23. .groupBy { it.name.startsWith("refs/tags/$releaseTagPrefix") }
  24. .mapValues { entry ->
  25. entry.value.maxByOrNull { it.name }
  26. }
  27. val lastReleaseTag = tags[true]
  28. val lastTag = tags[false]
  29. val lastTagCommit = lastTag?.toRevCommit(walk)
  30. val commitDistance = if (latestCommit == null || lastTagCommit == null) 0
  31. else RevWalkUtils.count(walk, latestCommit, lastTagCommit)
  32. return RepoInfo(
  33. repo.branch,
  34. latestCommit?.toObjectId()?.shorten(),
  35. lastTag?.tagName(),
  36. lastTag?.objectId?.shorten(),
  37. lastReleaseTag?.tagName(),
  38. lastReleaseTag?.objectId?.shorten(),
  39. commitDistance
  40. )
  41. }
  42. }
  43. }
  44. private fun ObjectId.shorten(): String {
  45. return name.take(8)
  46. }
  47. private fun Ref.tagName(): String? {
  48. return "refs\\/tags\\/(.*)".toRegex().find(this.name)?.groupValues?.get(1)
  49. }
  50. private fun Ref.toRevCommit(revWalk: RevWalk): RevCommit? {
  51. val id = repository.refDatabase.peel(this)?.peeledObjectId ?: objectId
  52. return try {
  53. revWalk.parseCommit(id)
  54. } catch (ex: MissingObjectException) {
  55. log.warn("Tag: {} points to a non-existing commit", tagName())
  56. null
  57. }
  58. }
  59. }

通过命令行调用 git rev-list --count start...end 返回 33。

JGit 版本为 5.9.0.202009080501-r。

英文:

I've a little Kotlin utility class that uses JGit to find the following information:

  1. branch, latestCommit, lastTag, lastTagCommit, lastReleaseTag, lastReleaseTagCommit, commitDistance

where lastReleaseTag is found by matching a given prefix.

All that is working, except for commitDistance, which is the number of commits between the latestCommit and a tag. I'm using RevWalkUtils.count, but it always returns zero.

  1. class GitRepo(dir: File) {
  2. private val log = LoggerFactory.getLogger(GitRepo::class.java)
  3. constructor(dir: String) : this(File(dir))
  4. private val repository = FileRepositoryBuilder()
  5. .setGitDir(File(dir, ".git"))
  6. .readEnvironment()
  7. .findGitDir()
  8. .setMustExist(true)
  9. .build()
  10. @JvmOverloads
  11. fun info(releaseTagPrefix: String = "release/"): RepoInfo {
  12. repository.use { repo ->
  13. RevWalk(repo).use { walk ->
  14. val latestCommit: RevCommit? = Git(repository).use {
  15. try {
  16. it.log().setMaxCount(1).call().iterator().next()
  17. } catch (ex: NoHeadException) {
  18. log.warn("Repository has no HEAD")
  19. null
  20. }
  21. }
  22. val tags = repo.refDatabase.getRefsByPrefix("refs/tags/")
  23. .groupBy { it.name.startsWith("refs/tags/$releaseTagPrefix") }
  24. .mapValues { entry ->
  25. entry.value.maxByOrNull { it.name }
  26. }
  27. val lastReleaseTag = tags[true]
  28. val lastTag = tags[false]
  29. val lastTagCommit = lastTag?.toRevCommit(walk)
  30. val commitDistance = if (latestCommit == null || lastTagCommit == null) 0
  31. else RevWalkUtils.count(walk, latestCommit, lastTagCommit)
  32. return RepoInfo(
  33. repo.branch,
  34. latestCommit?.toObjectId()?.shorten(),
  35. lastTag?.tagName(),
  36. lastTag?.objectId?.shorten(),
  37. lastReleaseTag?.tagName(),
  38. lastReleaseTag?.objectId?.shorten(),
  39. commitDistance
  40. )
  41. }
  42. }
  43. }
  44. private fun ObjectId.shorten(): String {
  45. return name.take(8)
  46. }
  47. private fun Ref.tagName(): String? {
  48. return "refs\\/tags\\/(.*)".toRegex().find(this.name)?.groupValues?.get(1)
  49. }
  50. private fun Ref.toRevCommit(revWalk: RevWalk): RevCommit? {
  51. val id = repository.refDatabase.peel(this)?.peeledObjectId ?: objectId
  52. return try {
  53. revWalk.parseCommit(id)
  54. } catch (ex: MissingObjectException) {
  55. log.warn("Tag: {} points to a non-existing commit", tagName())
  56. null
  57. }
  58. }
  59. }

A command line invocation of git rev-list --count start...end returns 33.

JGit 5.9.0.202009080501-r.

答案1

得分: 2

感谢 @fredrik,只需简单地在对 RevWalkUtils.count 的调用中交换提交即可。然而,事实证明 RevWalkUtils.count 返回的数量比 git rev-list --count start...end 大,可能是因为这个原因:

计算从起始点到达一个从终点可达的提交之间的提交数量。

我最终按以下方式更改了我的实现:

  1. class GitRepo(dir: File) {
  2. constructor(dir: String) : this(File(dir))
  3. private val log = LoggerFactory.getLogger(GitRepo::class.java)
  4. private val repository = FileRepositoryBuilder()
  5. .setGitDir(File(dir, ".git"))
  6. .readEnvironment()
  7. .findGitDir()
  8. .setMustExist(true)
  9. .build()
  10. @JvmOverloads
  11. fun info(tagPrefix: String = ".*"): RepoInfo {
  12. repository.use { repo ->
  13. val lastTag: Ref? = repo.refDatabase.getRefsByPrefix("refs/tags/")
  14. .filter { it.name.matches("refs/tags/$tagPrefix".toRegex()) }
  15. .maxByOrNull { it.name }
  16. var latestCommit: RevCommit? = null
  17. var lastTagCommit: RevCommit?
  18. var commitDistance = 0
  19. Git(repo).use { git ->
  20. try {
  21. latestCommit = git.log().setMaxCount(1).call().firstOrNull()
  22. lastTagCommit = lastTag?.let {
  23. val id = repo.refDatabase.peel(it)?.peeledObjectId ?: it.objectId
  24. git.log().add(id).call().firstOrNull()
  25. }
  26. if (latestCommit != null && lastTagCommit != null) {
  27. commitDistance = git.log().addRange(lastTagCommit, latestCommit).call().count()
  28. }
  29. } catch (ex: NoHeadException) {
  30. log.warn("Repository has no HEAD")
  31. } catch (ex: MissingObjectException) {
  32. log.warn("Tag: {} points to a non-existing commit: ", lastTag?.tagName(), ex.objectId.shorten())
  33. }
  34. return RepoInfo(
  35. repo.branch,
  36. latestCommit?.toObjectId()?.shorten(),
  37. lastTag?.tagName(),
  38. lastTag?.objectId?.shorten(),
  39. commitDistance
  40. )
  41. }
  42. }
  43. }
  44. private fun ObjectId.shorten(): String {
  45. return name.take(8)
  46. }
  47. private fun Ref.tagName(): String? {
  48. return "refs\\/tags\\/(.*)".toRegex().find(name)?.groupValues?.get(1)
  49. }
  50. }
英文:

Thanks to @fredrik, it's just a simple matter of swapping the commits in the call to RevWalkUtils.count. However, it turns out that RevWalkUtils.count is returning a greater number than git rev-list --count start...end, perhaps because of this:
> count the number of commits that are reachable from start until a commit that is reachable from end is encountered

I ended up changing my implementation as follows:

  1. class GitRepo(dir: File) {
  2. constructor(dir: String) : this(File(dir))
  3. private val log = LoggerFactory.getLogger(GitRepo::class.java)
  4. private val repository = FileRepositoryBuilder()
  5. .setGitDir(File(dir, ".git"))
  6. .readEnvironment()
  7. .findGitDir()
  8. .setMustExist(true)
  9. .build()
  10. @JvmOverloads
  11. fun info(tagPrefix: String = ".*"): RepoInfo {
  12. repository.use { repo ->
  13. val lastTag: Ref? = repo.refDatabase.getRefsByPrefix("refs/tags/")
  14. .filter { it.name.matches("refs/tags/$tagPrefix".toRegex()) }
  15. .maxByOrNull { it.name }
  16. var latestCommit: RevCommit? = null
  17. var lastTagCommit: RevCommit?
  18. var commitDistance = 0
  19. Git(repo).use { git ->
  20. try {
  21. latestCommit = git.log().setMaxCount(1).call().firstOrNull()
  22. lastTagCommit = lastTag?.let {
  23. val id = repo.refDatabase.peel(it)?.peeledObjectId ?: it.objectId
  24. git.log().add(id).call().firstOrNull()
  25. }
  26. if (latestCommit != null && lastTagCommit != null) {
  27. commitDistance = git.log().addRange(lastTagCommit, latestCommit).call().count()
  28. }
  29. } catch (ex: NoHeadException) {
  30. log.warn("Repository has no HEAD")
  31. } catch (ex: MissingObjectException) {
  32. log.warn("Tag: {} points to a non-existing commit: ", lastTag?.tagName(), ex.objectId.shorten())
  33. }
  34. return RepoInfo(
  35. repo.branch,
  36. latestCommit?.toObjectId()?.shorten(),
  37. lastTag?.tagName(),
  38. lastTag?.objectId?.shorten(),
  39. commitDistance
  40. )
  41. }
  42. }
  43. }
  44. private fun ObjectId.shorten(): String {
  45. return name.take(8)
  46. }
  47. private fun Ref.tagName(): String? {
  48. return "refs\\/tags\\/(.*)".toRegex().find(name)?.groupValues?.get(1)
  49. }
  50. }

huangapple
  • 本文由 发表于 2020年10月22日 16:53:09
  • 转载请务必保留本文链接:https://go.coder-hub.com/64478667.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定