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

时间:2015-10-09 12:24:16

标签: java git jgit

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

  

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

如何使用JGit执行此操作?   我设法使用

获取非类型合并的提交
RevFilter.NO_MERGES

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

2 个答案:

答案 0 :(得分:4)

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

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();
  }
}

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

结合NO_MERGES过滤器和拓扑排序(父母之前的所有孩子),它应该做你想要的

revWalk.sort( RevSort.TOPO );
revWalk.setRevFilter( AndRevFilter.create( new FirstParentFilter(), RevFilter.NO_MERGES ) );

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

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() );
  }
}

输出

side
base

答案 1 :(得分:3)

要获得第一位家长,您可以致电RevCommit.getParent()并从那里开始工作。

不使用RevWalk访问树的原因是Stack在没有遵循层次结构的情况下遍历转速 - 即,如果您没有读取提交,那么它就是&#39} ; s的父母将被阅读 - 这不是RevWalk所做的,也不是我们想要的。

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

代码

--first-parent

这是从groovy source

转换而来的

注释

  1. 需要调用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; } ,因为walk.parseCommit(parents[0])返回的提交不会被完全解析,并会在.getParents()上调用null
  2. 这是为了根据我的另一个answer从Android构建脚本(gradle)的git repo中查找版本代码而编写的。 (见source