Using jgit in-memory with local file system repositories


The slight tweak you need to avoid NullPointerException when using jgit InMemoryRepository to fetch from remotes on the local file system. Posted by Thomas Sutton on April 1, 2020

I’ve recently worked on a project that used jgit to access configuration files in repositories hosted on a GitHub. For various reasons we’re using jgit’s in-memory support with code that looks a little bit like CloneRemoteRepositoryIntoMemoryAndReadFile.java from jgit-cookbook:

DfsRepositoryDescription repoDesc = new DfsRepositoryDescription();
InMemoryRepository repo = new InMemoryRepository(repoDesc);
Git git = new Git(repo);
git.fetch()
        .setRemote(REMOTE_URL)
        .setRefSpecs(new RefSpec("+refs/heads/*:refs/heads/*"))
        .call();
repo.getObjectDatabase();
ObjectId lastCommitId = repo.resolve("refs/heads/" + BRANCH);
RevWalk revWalk = new RevWalk(repo);
RevCommit commit = revWalk.parseCommit(lastCommitId);
RevTree tree = commit.getTree();
TreeWalk treeWalk = new TreeWalk(repo);
treeWalk.addTree(tree);
treeWalk.setRecursive(true);
treeWalk.setFilter(PathFilter.create(FILE_TO_READ));
if (!treeWalk.next()) {
    return;
}
ObjectId objectId = treeWalk.getObjectId(0);
ObjectLoader loader = repo.open(objectId);
loader.copyTo(System.out);

This works more or less how you would expect when REMOTE_URL is genuinely remote (e.g. https:// or user@host:path or similar) but results in NullPointerExceptions with a local repository (e.g. file://, /path, etc.) We are using local repositories in our integration tests (so that we don’t need to add yet more fragile, uninteresting network service mocking).

The problem is that Repository subclasses use an instance of FS to access the local file system when required but InMemoryRepository, for superficially understandable reasons, leaves that field null. If you want your InMemoryRepository to be able to operate with on-disk remotes, you need to supply that FS instance during construction:

DfsRepositoryDescription repoDesc = new DfsRepositoryDescription();
InMemoryRepository repo = new InMemoryRepository.Builder()
  .setRepositoryDescription(repoDesc)
  .setFS(FS.detect())
  .build();
Git git = new Git(repo);

Then any subsequent operations on those Repository or Git objects that that need to access the local file system will be able to do so (even though the repository itself is in-memory).

This post was published on April 1, 2020 and last modified on January 26, 2024. It is tagged with: howto, java, git, jgit.