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

How to find commit distance using JGit?

我有一个小的 Kotlin 实用程序 class,它使用 JGit 来查找以下信息:

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

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

commitDistance 之外的所有内容均有效,这是 latestCommit 和标记之间的提交次数。我正在使用 RevWalkUtils.count,但它总是 returns 零。

class GitRepo(dir: File) {
    private val log = LoggerFactory.getLogger(GitRepo::class.java)

    constructor(dir: String) : this(File(dir))

    private val repository = FileRepositoryBuilder()
        .setGitDir(File(dir, ".git"))
        .readEnvironment()
        .findGitDir()
        .setMustExist(true)
        .build()

    @JvmOverloads
    fun info(releaseTagPrefix: String = "release/"): RepoInfo {
        repository.use { repo ->
            RevWalk(repo).use { walk ->
                val latestCommit: RevCommit? = Git(repository).use {
                    try {
                        it.log().setMaxCount(1).call().iterator().next()
                    } catch (ex: NoHeadException) {
                        log.warn("Repository has no HEAD")
                        null
                    }
                }

                val tags = repo.refDatabase.getRefsByPrefix("refs/tags/")
                    .groupBy { it.name.startsWith("refs/tags/$releaseTagPrefix") }
                    .mapValues { entry ->
                        entry.value.maxByOrNull { it.name }
                    }
                val lastReleaseTag = tags[true]
                val lastTag = tags[false]
                val lastTagCommit = lastTag?.toRevCommit(walk)
                val commitDistance = if (latestCommit == null || lastTagCommit == null) 0
                else RevWalkUtils.count(walk, latestCommit, lastTagCommit)

                return RepoInfo(
                    repo.branch,
                    latestCommit?.toObjectId()?.shorten(),
                    lastTag?.tagName(),
                    lastTag?.objectId?.shorten(),
                    lastReleaseTag?.tagName(),
                    lastReleaseTag?.objectId?.shorten(),
                    commitDistance
                )
            }
        }
    }

    private fun ObjectId.shorten(): String {
        return name.take(8)
    }

    private fun Ref.tagName(): String? {
        return "refs\/tags\/(.*)".toRegex().find(this.name)?.groupValues?.get(1)
    }

    private fun Ref.toRevCommit(revWalk: RevWalk): RevCommit? {
        val id = repository.refDatabase.peel(this)?.peeledObjectId ?: objectId
        return try {
            revWalk.parseCommit(id)
        } catch (ex: MissingObjectException) {
            log.warn("Tag: {} points to a non-existing commit", tagName())
            null
        }
    }
}

命令行调用 git rev-list --count start...end returns 33.

JGit 5.9.0.202009080501-r.

感谢@fredrik,这只是在 RevWalkUtils.count 的调用中交换提交的简单问题。然而,事实证明 RevWalkUtils.count 返回的数字大于 git rev-list --count start...end,可能是因为:

count the number of commits that are reachable from start until a commit that is reachable from end is encountered

我最终更改了我的实现如下:

class GitRepo(dir: File) {
    constructor(dir: String) : this(File(dir))

    private val log = LoggerFactory.getLogger(GitRepo::class.java)
    private val repository = FileRepositoryBuilder()
        .setGitDir(File(dir, ".git"))
        .readEnvironment()
        .findGitDir()
        .setMustExist(true)
        .build()

    @JvmOverloads
    fun info(tagPrefix: String = ".*"): RepoInfo {
        repository.use { repo ->
            val lastTag: Ref? = repo.refDatabase.getRefsByPrefix("refs/tags/")
                .filter { it.name.matches("refs/tags/$tagPrefix".toRegex()) }
                .maxByOrNull { it.name }
            var latestCommit: RevCommit? = null
            var lastTagCommit: RevCommit?
            var commitDistance = 0
            Git(repo).use { git ->
                try {
                    latestCommit = git.log().setMaxCount(1).call().firstOrNull()
                    lastTagCommit = lastTag?.let {
                        val id = repo.refDatabase.peel(it)?.peeledObjectId ?: it.objectId
                        git.log().add(id).call().firstOrNull()
                    }
                    if (latestCommit != null && lastTagCommit != null) {
                        commitDistance = git.log().addRange(lastTagCommit, latestCommit).call().count()
                    }
                } catch (ex: NoHeadException) {
                    log.warn("Repository has no HEAD")
                } catch (ex: MissingObjectException) {
                    log.warn("Tag: {} points to a non-existing commit: ", lastTag?.tagName(), ex.objectId.shorten())
                }

                return RepoInfo(
                    repo.branch,
                    latestCommit?.toObjectId()?.shorten(),
                    lastTag?.tagName(),
                    lastTag?.objectId?.shorten(),
                    commitDistance
                )
            }
        }
    }

    private fun ObjectId.shorten(): String {
        return name.take(8)
    }

    private fun Ref.tagName(): String? {
        return "refs\/tags\/(.*)".toRegex().find(name)?.groupValues?.get(1)
    }
}