JGit:RevWalk 顺序优先的起点

问题描述 投票:0回答:3

我正在将 JGit 用于我的一个需要大量使用 git 的项目。

我的目标是使用

RevWalk
能够按时间顺序迭代存储库中的提交,从特定的提交开始。我已经成功地分别实现了这两个目标:

  • 通过应用
    RevSort.REVERSE
  • 按时间顺序排列
  • 通过调用
    RevWalk.markStart(RevCommit c)
  • 开始点

我的问题是,当我尝试将两者结合起来时,RevSort 似乎会覆盖 markStart,并且 RevWalk 总是从提交的开头开始,而不是我指定的提交。

此片段显示了我所拥有的:

import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.internal.storage.file.FileRepository;
import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevSort;

import java.io.IOException;
import org.eclipse.jgit.errors.AmbiguousObjectException;
import org.eclipse.jgit.errors.MissingObjectException;

public class Main {

    public static void main(String[] args) throws IOException, AmbiguousObjectException, MissingObjectException {
        final String repositoryPath = args[0];
        final String commitID = args[1];
        final Repository repository = new FileRepository(repositoryPath + "/.git");
        final RevWalk walk = new RevWalk(repository);
        walk.sort(RevSort.REVERSE);
        walk.markStart(walk.parseCommit(repository.resolve(commitID)));
        for (final RevCommit revCommit : walk) {
            System.err.println(revCommit.getId());
        }
    }

}

这应该从指定的提交开始以相反的顺序打印存储库的 ID,但它只是忽略第二个设置并从初始提交开始。

更新:

我对这个问题进行了更多调查,结果发现,当一起应用两个选项(以任何顺序)时,

markStart
变成了
markStop
。我认为这是由于 markStart 始终首先执行并限制提交的范围(使用过滤器),然后通过
RevSort
反转这些内容造成的。基本上,
RevWalk
正在迭代我感兴趣的互补提交集。

我是否应该假设我正在尝试做的事情不能以这种方式实现?我想不出另一种方法来获取它,而不需要遍历整个存储库直到我的起点,但这听起来效率很低。

更新2: 在这里举一个适当的例子就是我期望实现的目标。 假设我们有一个包含 4 个提交的存储库:A、B、C 和 D。 我只对 B 到当前修订版的评论感兴趣,不包括 A,按时间顺序排列。我希望能够使用

markStart
sort
通过以下方式实现这一目标:

@Test
public void testReverse2() throws Exception {
    final RevCommit commitA = this.git.commit().setMessage("Commit A").call();
    final RevCommit commitB = this.git.commit().setMessage("Commit B").call();
    final RevCommit commitC = this.git.commit().setMessage("Commit C").call();
    final RevCommit commitD = this.git.commit().setMessage("Commit D").call();

    final RevWalk revWalk = new RevWalk(this.git.getRepository());
    revWalk.markStart(revWalk.parseCommit(commitB));
    revWalk.sort(RevSort.REVERSE);

    assertEquals(commitB, revWalk.next());
    assertEquals(commitC, revWalk.next());
    assertEquals(commitD, revWalk.next());
    assertNull(revWalk.next());
    revWalk.close();
}

现在,据我所知,这不起作用,因为

markStart
始终在
sort
之前执行,因此实际行为满足以下测试:

assertEquals(commitA, revWalk.next());
assertEquals(commitB, revWalk.next());
assertNull(revWalk.next());

这与我想要获得的相反。 这是故意的行为吗?如果是,我可以通过什么其他方式解决这个问题?

java jgit
3个回答
2
投票

在 Git 中,提交仅具有指向其父级的链接。

commitB
不知道其后继者
commitC
commitD

因此,历史只能向后遍历,从给定的提交到其父级、祖父母等。没有信息可以沿相反方向遍历。

在您的示例中,

RevWalk
将从
commitB
走到
commitÀ
REVERSE
排序只会影响迭代器的行为方式,但不能forward行走。

如果您确实想查找

commitB
HEAD
之间的提交,则需要从
HEAD
开始。或者,更一般地说,您需要从所有已知的分支提示开始,找到可能通往
commitB
的多条路径。


0
投票

JGit API 没有给出结合排序和 markStart 的禁忌。 JGit 源代码也没有显示任何表面问题。在我看来,直接修复这个问题需要源代码级调试。您将需要 JGit 源代码并需要在调试器中运行您的示例。

或者,您可以使用 Spliterator 流式传输 RevWalk,而不需要对 RevCommit:getCommitTime() 上的排序输出进行排序,如下所示:

StreamSupport.stream(walk.spliterator())
    .sorted(RevCommit::getCommitTime())
    .toList();

0
投票

我尝试了以下提交:

45ed19d8e226edf5eb4e567f5142f976950b2536 2024-04-02+02:00
7dcd13bc727fefcb137dbc3f0528516957f162ad 2024-04-02+02:00
84f72bbf7b7dd0dcbfb6ba87dde8a94651d326a5 2024-04-02+02:00
6f7733cb1bb79c2ae73785ef0081cec1372ac672 2024-04-02+02:00
6a443e62811f30b9bbd5558a88e7384b182809bc 2024-04-02+02:00
...
61b4291e510fdc19e6b6d03e0f27bad27c6bdd3a 2024-04-25+02:00
a877ff9654c3805e58f4d3bb21903e4042d18bb7 2024-04-25+02:00
c8e3089e47090d91aaf64ea38e7550e268252eb4 2024-04-25+02:00
f3d47d72f5271b89b24f547d2c7fa01ab44ef626 2024-04-26+02:00
3821c60b093577dd994d7542a079b7425e5a6fc0 2024-04-26+02:00

现在,让我们从

84f72bbf7b7dd0dcbfb6ba87dde8a94651d326a5
开始,到
c8e3089e47090d91aaf64ea38e7550e268252eb4

结束

输出:

6f7733cb1bb79c2ae73785ef0081cec1372ac672 2024-04-02+02:00
6a443e62811f30b9bbd5558a88e7384b182809bc 2024-04-02+02:00
...
61b4291e510fdc19e6b6d03e0f27bad27c6bdd3a 2024-04-25+02:00
a877ff9654c3805e58f4d3bb21903e4042d18bb7 2024-04-25+02:00
c8e3089e47090d91aaf64ea38e7550e268252eb4 2024-04-25+02:00

我想,这就是你想看到的吗?

revWalk.markUninteresting(oldCommit);
就是您正在寻找的东西。

完整代码

///usr/bin/env jbang "$0" "$@" ; exit $?

//JAVA 21+

//DEPS org.eclipse.jgit:org.eclipse.jgit:6.9.0.202403050737-r

import java.nio.file.Path;
import java.time.Instant;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Iterator;

import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevSort;
import org.eclipse.jgit.revwalk.RevWalk;

public class tryfromstart {

    public static void main(String... args) throws Exception {
        Path repositoryPath = Path.of(".");
        Git git = Git.open(repositoryPath.toFile());
        Repository repository = git.getRepository();
        RevWalk revWalk = new RevWalk(repository);
        RevCommit oldCommit = revWalk.parseCommit(repository.resolve("84f72bbf7b7dd0dcbfb6ba87dde8a94651d326a5"));
        RevCommit newCommit = revWalk.parseCommit(repository.resolve("c8e3089e47090d91aaf64ea38e7550e268252eb4"));
        revWalk.markUninteresting(oldCommit);
        revWalk.markStart(newCommit);
        revWalk.sort(RevSort.REVERSE);
        Iterator<RevCommit> commitIterator = revWalk.iterator();
        while (commitIterator.hasNext()) {
            RevCommit commit = commitIterator.next();
            Instant instant = commit.getAuthorIdent().getWhen().toInstant();
            System.out.println(commit.getId().name() + " " + DateTimeFormatter.ISO_DATE.withZone(ZoneId.systemDefault()).format(instant));
        }
    }
}

另存为

tryfromstart.java
并使用
jbang
 tryfromstart.java
执行。

提交 ID 来自以下存储库:https://github.com/koppor/github-contributors-list,但代码适用于任意存储库。


根据

git blame
,这个
markUinteresting
已经存在15年了: https://github.com/eclipse-jgit/jgit/blame/master/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevWalk.java

© www.soinside.com 2019 - 2024. All rights reserved.