如何在jgit中调用git show --first-parent?

isr*_*ell 5 java git jgit

我需要从master中获取不属于merge类型的提交,而不是来自其他分支(它们直接放在master上).git命令是

git log --no-merges --first-parent

我怎么能用JGit做到这一点?我设法获得了不使用类型合并的提交

RevFilter.NO_MERGES
Run Code Online (Sandbox Code Playgroud)

但是如何才能获得直接提交到master分支的提交?

Avi*_*h R 6

要获得第一个父母,您只需致电RevCommit.getParent()并从那里开始工作。

不使用 aRevWalk来访问树背后的基本原理是RevWalk遍历 revs 而不遵循层次结构——即,如果你没有阅读提交,它将被读取——这不是什么--first-parent,而是我们想要的这里。

因此,Rüdiger Herrmann 的回答将无法删除在 (n+1,...) th 个分支上所做的提交。它只会删除在这些分支上进行的第一次提交。

代码

Repository repo = git.getRepository();
try (RevWalk walk = new RevWalk(repo)) {
    RevCommit head = walk.parseCommit(repo.getRef(MASTER).getObjectId());
    int count = 0;
    while (head != null) {
        count++;
        RevCommit[] parents = head.getParents();
        if (parents != null && parents.length > 0) {
            head = walk.parseCommit(parents[0]);
        } else {
            head = null;
        }
    }
    return count;
}
Run Code Online (Sandbox Code Playgroud)

这是从groovy转换而来的

笔记

  1. 调用walk.parseCommit(parents[0])是必需的,因为 返回的提交.getParents()不会被完全解析,并且会null在调用.getParents()自己时放弃。
  2. 这是为了根据我的另一个答案从 git repo for Android build script (gradle) 中查找版本代码而编写的。(见来源


Rüd*_*ann 5

您可以将 aRevWalk与自定义过滤器一起使用,该过滤器会忽略除第一个父级之外的所有提交。

class FirstParentFilter extends RevFilter {
  private Set<RevCommit> ignoreCommits = new HashSet<>();

  @Override
  public boolean include( RevWalk revWalk, RevCommit commit ) throws IOException {
    if( commit.getParentCount() > 1 ) {
      ignoreCommits.add( commit.getParent( 1 ) );
    }
    boolean include = true;
    if( ignoreCommits.contains( commit ) ) {
      include = false;
      ignoreCommits.remove( commit );
    }
    return include;    
  }

  @Override
  public RevFilter clone() {
    return new FirstParentFilter();
  }
}
Run Code Online (Sandbox Code Playgroud)

简单化过滤器假设最多有两个父级,但可以轻松扩展以处理两个以上的父级。

结合NO_MERGES过滤器和拓扑排序(所有孩子在父母之前)它应该做你正在寻找的事情

revWalk.sort( RevSort.TOPO );
revWalk.setRevFilter( AndRevFilter.create( new FirstParentFilter(), RevFilter.NO_MERGES ) );
Run Code Online (Sandbox Code Playgroud)

以下是我用来测试过滤器的简单合并场景:

git.commit().setMessage( "base" ).call();
String master = git.getRepository().getFullBranch();
Ref side = git.branchCreate().setName( "side" ).call();
git.commit().setMessage( "master" ).call();
git.checkout().setName( side.getName() ).call();
git.commit().setMessage( "side" ).call();
git.merge().include( git.getRepository().getRef( master ) ).setFastForward( NO_FF ).setMessage( "merge" ).call();

try( RevWalk revWalk = new RevWalk( git.getRepository() ) ) {
  revWalk.setRevFilter( AndRevFilter.create( new FirstParentFilter(), RevFilter.NO_MERGES ) );
  revWalk.sort( RevSort.TOPO );
  Ref headRef = git.getRepository().getRef( Constants.HEAD );
  RevCommit headCommit = revWalk.parseCommit( headRef.getObjectId() );
  revWalk.markStart( headCommit );
  for( RevCommit revCommit : revWalk ) {
    System.out.println( revCommit.getShortMessage() );
  }
}
Run Code Online (Sandbox Code Playgroud)

输出

side
base
Run Code Online (Sandbox Code Playgroud)