31

不久前,我在寻找一个可嵌入的 Java 分布式版本控制系统,我想我在JGit中找到了它,它是 git 的纯 Java 实现。但是,示例代码或教程的方式并不多。

如何使用 JGit 检索某个文件的 HEAD 版本(就像svn cathg cat应该这样做)?

我想这涉及一些 rev-tree-walking 并且正在寻找代码示例。

4

7 回答 7

23

不幸的是,Thilo 的答案不适用于最新的 JGit API。这是我找到的解决方案:

File repoDir = new File("test-git");
// open the repository
Repository repository = new Repository(repoDir);
// find the HEAD
ObjectId lastCommitId = repository.resolve(Constants.HEAD);
// now we have to get the commit
RevWalk revWalk = new RevWalk(repository);
RevCommit commit = revWalk.parseCommit(lastCommitId);
// and using commit's tree find the path
RevTree tree = commit.getTree();
TreeWalk treeWalk = new TreeWalk(repository);
treeWalk.addTree(tree);
treeWalk.setRecursive(true);
treeWalk.setFilter(PathFilter.create(path));
if (!treeWalk.next()) {
  return null;
}
ObjectId objectId = treeWalk.getObjectId(0);
ObjectLoader loader = repository.open(objectId);

// and then one can use either
InputStream in = loader.openStream()
// or
loader.copyTo(out)

我希望它更简单。

于 2011-09-15T08:05:41.903 回答
18

这是@morisil 的答案的一个更简单的版本,使用了来自@directed 笑的一些概念并使用JGit 2.2.0 进行了测试:

private String fetchBlob(String revSpec, String path) throws MissingObjectException, IncorrectObjectTypeException,
        IOException {

    // Resolve the revision specification
    final ObjectId id = this.repo.resolve(revSpec);

    // Makes it simpler to release the allocated resources in one go
    ObjectReader reader = this.repo.newObjectReader();

    try {
        // Get the commit object for that revision
        RevWalk walk = new RevWalk(reader);
        RevCommit commit = walk.parseCommit(id);

        // Get the revision's file tree
        RevTree tree = commit.getTree();
        // .. and narrow it down to the single file's path
        TreeWalk treewalk = TreeWalk.forPath(reader, path, tree);

        if (treewalk != null) {
            // use the blob id to read the file's data
            byte[] data = reader.open(treewalk.getObjectId(0)).getBytes();
            return new String(data, "utf-8");
        } else {
            return "";
        }
    } finally {
        reader.close();
    }
}

repo是在其他答案中创建的 Repository 对象。

于 2013-02-13T14:55:19.503 回答
12

我按照@Thilo 和@morisil 的回答得到了这个,与 JGit 1.2.0 兼容:

File repoDir = new File("test-git/.git");
// open the repository
Repository repo = new Repository(repoDir);
// find the HEAD
Commit head = repo.mapCommit(Constants.HEAD);
// retrieve the tree in HEAD
Tree tree = head.getTree();

// 1.2.0 api version here
// find a file (as a TreeEntry, which contains the blob object id)
TreeWalk treewalk = TreeWalk.forPath(repo, "b/test.txt", tree);
// use the blob id to read the file's data
byte[] data = repo.open(treewalk.getObjectId(0)).getBytes();

我没有测试 Java 版本,但它应该可以工作。它翻译自

(.getBytes (.open repo (.getObjectId (TreeWalk/forPath repo "b/test.txt" tree) 0)))

在 clojure 中(遵循与顶部相同的设置),它确实有效。

于 2012-02-12T19:37:07.377 回答
4

我自己想出来的。API 相当低级,但还不错:

File repoDir = new File("test-git/.git");
// open the repository
Repository repo = new Repository(repoDir);
// find the HEAD
Commit head = repo.mapCommit(Constants.HEAD);
// retrieve the tree in HEAD
Tree tree = head.getTree();
// find a file (as a TreeEntry, which contains the blob object id)
TreeEntry entry = tree.findBlobMember("b/test.txt");
// use the blob id to read the file's data
byte[] data = repo.openBlob(entry.getId()).getBytes();
于 2009-11-08T00:42:34.367 回答
4

我已经开始编写一个名为gitective的库,其中包含许多使用 JGit 处理 blob、提交和树的帮助程序,并且已获得 MIT 许可,可在 GitHub 上获得。

在 HEAD 提交中获取文件内容

Repository repo = new FileRepository("/repos/project/.git");
String content = BlobUtils.getHeadContent(repo, "src/Buffer.java");

获取分支上文件的内容

Repository repo = new FileRepository("/repos/project/.git");
String content = BlobUtils.getContent(repo, "master", "src/Buffer.java");

区分两个文件

Repository repo = new FileRepository("/repos/project/.git");
ObjectId current = BlobUtils.getId(repo, "master", "Main.java");
ObjectId previous = BlobUtils.getId(repo, "master~1", "Main.java");
Collection<Edit> edit = BlobUtils.diff(repo, previous, current);

README中详细介绍了所提供实用程序的更多示例。

于 2011-11-03T14:04:39.043 回答
3

JGit Tutorial有一些信息(但这也不是真的有用,也不是完整的,而且可能已经过时,因为他们切换到没有可用文档的Eclipse )。

于 2009-11-07T02:00:49.710 回答
2

您可以按如下方式读取给定文件路径的内容。请注意,如果在给定的树中找不到路径,则 TreeWalk 可以为空。所以它需要一些特定的处理。

public String readFile(RevCommit commit, String filepath) throws IOException {
    try (TreeWalk walk = TreeWalk.forPath(repo, filepath, commit.getTree())) {
        if (walk != null) {
            byte[] bytes = repo.open(walk.getObjectId(0)).getBytes();
            return new String(bytes, StandardCharsets.UTF_8);
        } else {
            throw new IllegalArgumentException("No path found.");
        }
    }
}

例如:

ObjectId head = repo.resolve(Constants.HEAD);
RevCommit last = repo.parseCommit(head);
readFile(last, "docs/README.md")

这个答案是用 JGit 4.8.0 编写的。

于 2018-04-05T20:16:01.777 回答