How to “cat” a file in JGit?

后端 未结 7 602
爱一瞬间的悲伤
爱一瞬间的悲伤 2020-12-01 04:25

A while back I was looking for an embeddable distributed version control system in Java, and I think I have found it in JGit, which is a pure Java implementation of git. How

相关标签:
7条回答
  • 2020-12-01 04:54

    Figured it out by myself. The API is quite low-level, but it's not too bad:

    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();
    
    0 讨论(0)
  • 2020-12-01 04:59

    You can read the content of a given filepath as follows. Please be aware that the TreeWalk can be null if no path was found in the given tree. So it requires some specific handling.

    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.");
            }
        }
    }
    

    For example:

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

    This answer is written with JGit 4.8.0.

    0 讨论(0)
  • 2020-12-01 05:00

    I followed @Thilo's and @morisil's answer to get this, compatible with 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();
    

    I didn't test the Java version but it should work. It translates from

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

    in clojure (following the same setup as the top section), which does work.

    0 讨论(0)
  • 2020-12-01 05:01

    There is some info at JGit Tutorial (but that also is neither really helpful nor complete and probably outdated since they switched to eclipse where no documentation is available yet).

    0 讨论(0)
  • 2020-12-01 05:03

    Here's a simpler version of @morisil's answer, using some of the concepts from @directed laugh's and tested with 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 is a Repository object as created in the other answers.

    0 讨论(0)
  • 2020-12-01 05:12

    Unfortunately Thilo's answer does not work with the latest JGit API. Here is the solution I found:

    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)
    

    I wish it was simpler.

    0 讨论(0)
提交回复
热议问题