英文:
How to find commit distance using JGit?
问题
我有一个小的 Kotlin 工具类,使用 JGit 查找以下信息:
branch, latestCommit, lastTag, lastTagCommit, lastReleaseTag, lastReleaseTagCommit, commitDistance
其中 lastReleaseTag
通过匹配给定的前缀来找到。
所有这些都在工作,除了 commitDistance
,它表示在 latestCommit
和一个标签之间的提交次数。我正在使用 RevWalkUtils.count,但它总是返回零。
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
返回 33。
JGit 版本为 5.9.0.202009080501-r。
英文:
I've a little Kotlin utility class that uses JGit to find the following information:
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.
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
}
}
}
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
大,可能是因为这个原因:
计算从起始点到达一个从终点可达的提交之间的提交数量。
我最终按以下方式更改了我的实现:
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)
}
}
英文:
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:
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)
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论