Search code examples
javagitrepositoryjgit

Initialize an InMemoryRepository with Jgit from scratch


I am trying to create an InMemoryGitRepository from scratch. Ultimately, I would like to try a custom DFSRepository as git backend, but to begin with I was playing around with the default implementation of InMemoryRepository. I know how to clone an existing repo into InMemoryRepository as mentioned here but I am having a tough time on how to create the repo from scratch and add a file. I am trying the following

    private static void initInMemoryGit() throws IOException, GitAPIException {

        DfsRepositoryDescription repoDesc = new DfsRepositoryDescription("test");

        //InMemoryRepository repo = new InMemoryRepository(repoDesc);
        InMemoryRepository repo = new InMemoryRepository.Builder().setRepositoryDescription(repoDesc)
                                                                  .setInitialBranch("master")
                                                                  .build();
        repo.create();
        Git git = new Git(repo);
        File textFile = new File("/tmp/TestGitRepository", "test.txt");
        Files.write(textFile.toPath(), "hi".getBytes());

        git.add().addFilepattern(textFile.getName()).call();
        git.commit().setMessage("hi").call();

    }

However, I am getting the following error:

Exception in thread "main" org.eclipse.jgit.errors.NoWorkTreeException: Bare Repository has neither a working tree, nor an index
    at org.eclipse.jgit.lib.Repository.getIndexFile(Repository.java:1200)
    at org.eclipse.jgit.dircache.DirCache.lock(DirCache.java:259)
    at org.eclipse.jgit.lib.Repository.lockDirCache(Repository.java:1282)
    at org.eclipse.jgit.api.AddCommand.call(AddCommand.java:122)
    at oracle.bi.versioncontrol.jgit.JGitVersionInMemory.initInMemoryGit(JGitVersionInMemory.java:114)
    at oracle.bi.versioncontrol.jgit.JGitVersionInMemory.main(JGitVersionInMemory.java:51)

Since it is an InMemory Repo, I am not supposed to set the Index File or Working Tree File, but looks like that's what the error message is saying. What am I missing?


Solution

  • By default, the static nested class InMemoryRepository.Builder builds a bare repository. It gave me quite of a headache too, but if you invoke repo.isBare(), you can see that it actually returns true even if setBare() isn't called during the build.

    You could use Git.init() to create a new non-bare repository, and apply your configurations from the InitCommand returned.

    public static void initInMemoryGit() throws IOException, GitAPIException {
        File textFile = new File("./tmp/TestGitRepository/test.txt");
        try (Git git = Git.init().setInitialBranch("master").setDirectory(new File("./tmp/TestGitRepository")).call()) {
            git.add().addFilepattern(textFile.getName()).call();
            git.commit().setMessage("hi").call();
        }
    }
    

    In my previous response I was focused on creating a test repository and forgot about the in memory requirement. An InMemoryRepository can hold a repo read from the file system or pulled from a remote. If your goal is to just test some things, you could write a test class that sets up and tears down the repo on your file system at the beginning and end of the test cycle. A test class based on your code could look like this:

    public class TestGit {
    
        private static Git git;
    
        @BeforeAll
        public static void setup() throws GitAPIException {
            git = Git.init().setInitialBranch("master").setDirectory(new File("./tmp/TestGitRepository")).call();
        }
    
        @Test
        public void testCommit() throws GitAPIException {
            File textFile = new File("./tmp/TestGitRepository/test.txt");
    
            git.add().addFilepattern(textFile.getName()).call();
            git.commit().setMessage("hi").call();
    
            List<RevCommit> commits = StreamSupport.stream(git.log().setMaxCount(1).call().spliterator(), false).toList();
            RevCommit commit = commits.get(0);
    
            Assertions.assertEquals(commit.getFullMessage(), "hi");
        }
    
        @AfterAll
        public static void tearDown() throws IOException {
            git.close();
            deleteDirectory(new File("./tmp/TestGitRepository/.git"));
        }
    
        private static boolean deleteDirectory(File dir) {
            File[] files = dir.listFiles();
            if (files != null) {
                for (File file : files) {
                    deleteDirectory(file);
                }
            }
            return dir.delete();
        }
    }