This tutorial contains examples for the usage of the JGit API.

1. JGit

JGit is a pure Java implementation of the Git version control system. It powers many Git related Java projects like the Git support in Eclipse or the Gerrit reviewer server.

JGit is available as Java library and can be integrated into your project with the usual methods.

JGit implements most of the commands that come with the Git CLI. Some of the actions of JGit can be executed on a remote repository but for most methods you have to have a local copy.

1.1. Adding JGit to your project with Maven

The latest release of JGit is available as Maven repository.

You can find the latest release via the following link: https://mvnrepository.com/artifact/org.eclipse.jgit/org.eclipse.jgit

To add JGit as a Maven dependency, add the following to your pom.xml. Since JGit 5.8 you have to add additional dependencies for SSH and GPG support.

<dependency>
    <!-- https://central.sonatype.dev/artifact/org.eclipse.jgit/org.eclipse.jgit/ -->
    <groupId>org.eclipse.jgit</groupId>
    <artifactId>org.eclipse.jgit</artifactId>
    <version>6.4.0.202211300538-r</version>
    <!-- SSH support for JGit based on Apache MINA sshd -->
    <groupId>org.eclipse.jgit</groupId>
    <artifactId>org.eclipse.jgit.ssh.apache</artifactId>
    <version>6.4.0.202211300538-r</version>
    <!-- GPG support for JGit based on BouncyCastle (commit signing) -->
    <groupId>org.eclipse.jgit</groupId>
    <artifactId>org.eclipse.jgit.gpg.bc</artifactId>
    <version>6.4.0.202211300538-r</version>
</dependency>

1.2. Adding JGit to your project with Gradle

dependencies {
    // https://central.sonatype.dev/artifact/org.eclipse.jgit/org.eclipse.jgit/
    implementation 'org.eclipse.jgit:org.eclipse.jgit:6.4.0.202211300538-r'
    // SSH support for JGit based on Apache MINA sshd
    implementation 'org.eclipse.jgit:org.eclipse.jgit.ssh.apache:6.4.0.202211300538-r'
    // GPG support for JGit based on BouncyCastle (commit signing)
    implementation 'org.eclipse.jgit:org.eclipse.jgit.gpg.bc:6.4.0.202211300538-r'
}

2. Example usage of JGit

2.1. Cloning a Git repository with JGit

The Git class has a static method that allows you to clone a remote repository. JGits commands are lazily evaluated to allow for configuration via method chaining. The call of Class#call() starts the execution of the command.

package gittest;

import java.io.File;

import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.api.errors.InvalidRemoteException;
import org.eclipse.jgit.api.errors.TransportException;

public class Snippet {
    public static void main(String[] args) throws InvalidRemoteException, TransportException, GitAPIException {
        Git.cloneRepository()
          .setURI("https://github.com/eclipse/jgit.git")
          .setDirectory(new File("/path/to/targetdirectory")) (1)
          .call();
    }
}
1 Location to which the repo will be cloned

By default, JGit only clones the default branch. It is also possible to tell JGit to clone a specific branch.

Git.cloneRepository()
  .setURI("https://github.com/eclipse/jgit.git")
  .setDirectory(new File("/path/to/targetdirectory"))
  .setBranchesToClone(Arrays.asList("refs/heads/specific-branch"))
  .setBranch("refs/heads/specific-branch")
  .call();

JGit can also be told to clone all branches.

Git git = Git.cloneRepository()
  .setURI("https://github.com/eclipse/jgit.git")
  .setDirectory("/path/to/repo")
  .setCloneAllBranches(true)
  .call();

2.2. Create a local repository with JGit

If you want to directly create a repository object you can use the FileRepositoryBuilder.

FileRepositoryBuilder repositoryBuilder = new FileRepositoryBuilder();
Repository repository = repositoryBuilder.setGitDir(new File("/path/to/repo/.git"))
                .readEnvironment() // scan environment GIT_* variables
                .findGitDir() // scan up the file system tree
                .setMustExist(true)
                .build();

If you also need a Git object you can call a static method on it’s class.

Git.open(new File("/path/to/repo/.git"))
    .checkout();
Repository repository = git.getRepository();

2.3. Checking out a specific commit

The example shows how to check out a specific commit. This leaves you in a detatched HEAD state.

git.checkout()
    .setCreateBranch(true)
    .setName("new-branch")
    .call();

You can also check out a commit and create a new branch with this commit.

git.checkout()
    .setCreateBranch(true)
    .setName("new-branch")
    .setStartPoint("<id-to-commit>")
    .call();

2.4. Searching and accessing a file

This example assumes that your already have opened a repository.

            // find the HEAD
            ObjectId lastCommitId = repository.resolve(Constants.HEAD);

            // a RevWalk allows to walk over commits based on some filtering that is defined
            try (RevWalk revWalk = new RevWalk(repository)) {
                RevCommit commit = revWalk.parseCommit(lastCommitId);
                // and using commit's tree find the path
                RevTree tree = commit.getTree();
                System.out.println("Having tree: " + tree);

                // now try to find a specific file
                try (TreeWalk treeWalk = new TreeWalk(repository)) {
                    treeWalk.addTree(tree);
                    treeWalk.setRecursive(true);
                    treeWalk.setFilter(PathFilter.create("README.md"));
                    if (!treeWalk.next()) {
                        throw new IllegalStateException("Did not find expected file 'README.md'");
                    }

                    ObjectId objectId = treeWalk.getObjectId(0);
                    ObjectLoader loader = repository.open(objectId);

                    // and then one can the loader to read the file
                    loader.copyTo(System.out);
                }

                revWalk.dispose();
        }

2.5. Example for using JGit

The following example, creates a new Git repostory, creates a few files, branches and extracts information for the repo.

This example assume that you have org.eclipse.jgit and ` org.slf4j.api` in your classpath.

package com.vogella.eclipse.jgitexamples;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.util.List;
import java.util.Set;

import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.Status;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.Ref;

public class JGitUsageExample {

    public static void main(String[] args) throws IOException, IllegalStateException, GitAPIException {
        File localPath = File.createTempFile("JGitTestRepository", "");
        // delete repository before running this
        Files.delete(localPath.toPath());

        // This code would allow to access an existing repository
//      try (Git git = Git.open(new File("/home/vogella/git/eclipse.platform.ui"))) {
//          Repository repository = git.getRepository();
//
//      }

        // Create the git repository with init
        try (Git git = Git.init().setDirectory(localPath).call()) {
            System.out.println("Created repository: " + git.getRepository().getDirectory());
            File myFile = new File(git.getRepository().getDirectory().getParent(), "testfile");
            if (!myFile.createNewFile()) {
                throw new IOException("Could not create file " + myFile);
            }

            // run the add-call
            git.add().addFilepattern("testfile").call();

            git.commit().setMessage("Initial commit").call();
            System.out.println("Committed file " + myFile + " to repository at " + git.getRepository().getDirectory());
            // Create a few branches for testing
            for (int i = 0; i < 10; i++) {
                git.checkout().setCreateBranch(true).setName("new-branch" + i).call();
            }
            // List all branches
            List<Ref> call = git.branchList().call();
            for (Ref ref : call) {
                System.out.println("Branch: " + ref + " " + ref.getName() + " " + ref.getObjectId().getName());
            }

            // Create a few new files
            for (int i = 0; i < 10; i++) {
                File f = new File(git.getRepository().getDirectory().getParent(), "testfile" + i);
                f.createNewFile();
                if (i % 2 == 0) {
                    git.add().addFilepattern("testfile" + i).call();
                }
            }

            Status status = git.status().call();

            Set<String> added = status.getAdded();
            for (String add : added) {
                System.out.println("Added: " + add);
            }
            Set<String> uncommittedChanges = status.getUncommittedChanges();
            for (String uncommitted : uncommittedChanges) {
                System.out.println("Uncommitted: " + uncommitted);
            }

            Set<String> untracked = status.getUntracked();
            for (String untrack : untracked) {
                System.out.println("Untracked: " + untrack);
            }

            // Find the head for the repository
            ObjectId lastCommitId = git.getRepository().resolve(Constants.HEAD);
            System.out.println("Head points to the following commit :" + lastCommitId.getName());
        }

    }
}

2.6. Amending a commit / Changing the date of the last commit of a repository

This example shows how to amend a commit with JGit. The code retrieves the HEAD of a repository and changes its commit and author date.

Git git = Git.open(new File("/path/to/repo"));
Repository repository = git.getRepository();
ObjectId lastCommitId = repository.resolve(Constants.HEAD);
RevWalk revWalk = new RevWalk(repository);
RevCommit lastCommit = revWalk.parseCommit(lastCommitId);
PersonIdent authorIdent = lastCommit.getAuthorIdent();
PersonIdent committerIdent = lastCommit.getCommitterIdent();
Date date = new Date(0);
RevCommit revCommit = null;
revCommit = git.commit().setAmend(true).setMessage(lastCommit.getFullMessage())
        .setAuthor(new PersonIdent(authorIdent, date))
        .setAuthor(new PersonIdent(committerIdent, date))
        .call();

3. Plumbing API

3.1. Make inserted objects visible without flushing the ObjectInserter

By getting the reader from the ObjectInserter and initializing the RevWalk with said inserter our RevWalk will be able to find newly inserted ObjectIds without calling inserter.flush() first. This way we can defer flushing the inserter until we actually want to make the inserted objects visible to others.

FileKey fileKey = FileKey.lenient(new File("/path/to/repo"), FS.DETECTED);
try (Repository repository = RepositoryCache.open(fileKey);
       ObjectInserter inserter = repository.newObjectInserter();
       ObjectReader reader = inserter.newReader();
       RevWalk revWalk = new RevWalk(reader)) {
    ObjectId objectId = inserter.insert(commitBuilder);
    RevCommit commit = revWalk.parseCommit(objectId); // this would fail otherwise fail with MissingObjectException
}

4. JGit resources