如何在 jgit 中调用 git show --first-parent?
How to call git show --first-parent in jgit?
我需要从 master 获取非合并类型且不来自其他分支的提交(它们直接放在 master 上)。
git 命令是
git log --no-merges --first-parent
我如何使用 JGit 执行此操作?
我设法使用
获得了非合并类型的提交
RevFilter.NO_MERGES
但是我怎样才能得到直接提交到 master 分支的提交呢?
您可以将 RevWalk
与自定义过滤器结合使用,该过滤器会忽略除第一个 parent 之外的所有提交。
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();
}
}
简单的过滤器假定最多有两个 parent,但可以轻松扩展以处理两个以上的 parent。
结合 NO_MERGES
过滤器和拓扑排序(所有 children 在 parent 之前)它应该做你正在寻找的东西
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
要获得第一个 parent,您可以直接调用 RevCommit.getParent()
并从那里开始工作。
不使用 RevWalk
访问树的基本原理是 RevWalk
遍历 revs 而不遵循层次结构——也就是说,如果你没有阅读提交,它是 parent 将被读取 --,这不是 --first-parent
所做的,也不是我们在这里想要的。
所以 将无法删除在 (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;
}
这是从groovysource
转换过来的
备注
- 需要调用
walk.parseCommit(parents[0])
,因为 .getParents()
返回的提交将不会被完全解析,并且会在调用 .getParents()
时给出 null
。
- 这是为了从 Android 构建脚本 (gradle) 的 git 存储库中查找版本代码而编写的,基于我的另一个 answer。 (参见 source)
我需要从 master 获取非合并类型且不来自其他分支的提交(它们直接放在 master 上)。 git 命令是
git log --no-merges --first-parent
我如何使用 JGit 执行此操作? 我设法使用
获得了非合并类型的提交RevFilter.NO_MERGES
但是我怎样才能得到直接提交到 master 分支的提交呢?
您可以将 RevWalk
与自定义过滤器结合使用,该过滤器会忽略除第一个 parent 之外的所有提交。
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();
}
}
简单的过滤器假定最多有两个 parent,但可以轻松扩展以处理两个以上的 parent。
结合 NO_MERGES
过滤器和拓扑排序(所有 children 在 parent 之前)它应该做你正在寻找的东西
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
要获得第一个 parent,您可以直接调用 RevCommit.getParent()
并从那里开始工作。
不使用 RevWalk
访问树的基本原理是 RevWalk
遍历 revs 而不遵循层次结构——也就是说,如果你没有阅读提交,它是 parent 将被读取 --,这不是 --first-parent
所做的,也不是我们在这里想要的。
所以
代码
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;
}
这是从groovysource
转换过来的备注
- 需要调用
walk.parseCommit(parents[0])
,因为.getParents()
返回的提交将不会被完全解析,并且会在调用.getParents()
时给出null
。 - 这是为了从 Android 构建脚本 (gradle) 的 git 存储库中查找版本代码而编写的,基于我的另一个 answer。 (参见 source)