我已经成功地掌握了jGit文件的基础知识,包括连接到repos以及添加,提交甚至循环文件的提交消息.
File gitDir = new File("/Users/myname/Sites/helloworld/.git");
RepositoryBuilder builder = new RepositoryBuilder();
Repository repository;
repository = builder.setGitDir(gitDir).readEnvironment()
.findGitDir().build();
Git git = new Git(repository);
RevWalk walk = new RevWalk(repository);
RevCommit commit = null;
// Add all files
// AddCommand add = git.add();
// add.addFilepattern(".").call();
// Commit them
// CommitCommand commit = git.commit();
// commit.setMessage("Commiting from java").call();
Iterable<RevCommit> logs = git.log().call();
Iterator<RevCommit> i = logs.iterator();
while (i.hasNext()) {
commit = walk.parseCommit( i.next() );
System.out.println( commit.getFullMessage() );
}
Run Code Online (Sandbox Code Playgroud)
我接下来要做的是能够获取单个文件的所有提交消息,然后能够将单个文件还原回特定的参考/时间点.
tre*_*fer 10
以下是如何根据所有父提交查找提交的更改
var tree = new TreeWalk(repository)
tree.addTree(commit.getTree)
commit.getParents foreach {
parent => tree.addTree(parent.getTree)
}
tree.setFilter(TreeFilter.ANY_DIFF)
Run Code Online (Sandbox Code Playgroud)
(斯卡拉码)
请注意,TreeFilter.ANY_DIFF适用于单个树步行者,并将返回根提交中可用的所有元素.
然后,您必须遍历树以查看您的文件是否在给定的delta中(这非常简单).
while (tree.next)
if (tree.getDepth == cleanPath.size) {
// we are at the right level, do what you want
} else {
if (tree.isSubtree &&
name == cleanPath(tree.getDepth)) {
tree.enterSubtree
}
}
}
Run Code Online (Sandbox Code Playgroud)
(cleanPath是纯粹的repo路径,由'/'分隔)
现在将该代码包装到RevWalk.next循环中,您将获得提交更改的提交和文件.
您可能希望使用与ANY_DIFF不同的过滤器,因为如果一棵树不同,则ANY_DIFF为真.如果合并中blob与所有父树相比没有变化,则这有点违反直觉.所以这里是ALL_DIFF的核心,它只显示与所有父树不同的元素:
override def include(walker: TreeWalk): Boolean = {
val n = walker.getTreeCount();
if (n == 1) {
return true;
}
val m = walker.getRawMode(0)
var i = 1
while (i < n) {
if (walker.getRawMode(i) == m && walker.idEqual(i, 0)) {
return false
}
i += 1
}
true
}
Run Code Online (Sandbox Code Playgroud)
(scala代码,派生自AnyDiffFilter)
所以我试图让charlieboy的解决方案起作用,而且它主要是这样,但在以下情况下我失败了(也许在jgit中发生了一些事情,因为那个帖子?)
添加fileA,提交为"commit 1"add fileB,commit as"commit 2"
getFileVersionDateList("fileA")
Run Code Online (Sandbox Code Playgroud)
双方commit 1并commit 2发现,在这里我只希望commit 1.
我的解决方案如下:
List<Commit> commits = new ArrayList<Commit>();
RevWalk revWalk = new RevWalk(repository);
revWalk.setTreeFilter(
AndTreeFilter.create(
PathFilterGroup.createFromStrings(<relative path in question>),
TreeFilter.ANY_DIFF)
);
RevCommit rootCommit = revWalk.parseCommit(repository.resolve(Constants.HEAD));
revWalk.sort(RevSort.COMMIT_TIME_DESC);
revWalk.markStart(rootCommit);
for (RevCommit revCommit : revWalk) {
commits.add(new GitCommit(getRepository(), revCommit));
}
Run Code Online (Sandbox Code Playgroud)
使用LogCommand更简单,看起来像这样:
List<Commit> commitsList = new ArrayList<Commit>();
Git git = new Git(repository);
LogCommand logCommand = git.log()
.add(git.getRepository().resolve(Constants.HEAD))
.addPath(<relative path in question>);
for (RevCommit revCommit : logCommand.call()) {
commitsList.add(new GitCommit(this, revCommit));
}
Run Code Online (Sandbox Code Playgroud)
显然,您还需要根据需要检查提交日期等.