JGit - manage git workflow programmatically

How to use jgit to programmatically manage git workflow like repository management, pull and push operations etc.

JGit developed by the Eclipse Foundation is a java implementation of the git workflow. When included as a maven or gradle dependency, it allows you to execute most of the git cli commands programmatically, removing the dependency triggering external commands from a java program.

As part of this post, we’ll explore the usage of JGit for some commonly used commands:

init

The init command is used by git to initialize a blank repository on a local system which can then be linked to a remote repository. A hidden .git directory is created inside the working directory which holds all the configuration files corresponding to the remote repository.

When using CLI, following commands are required to be executed:

sumit@jvmaware:~/jgit-demo$ git init
Initialized empty Git repository in /home/gaurs/jgit-demo/.git/

sumit@jvmaware:~/jgit-demo$ git config user.email "sumit@jvmaware.com"
sumit@jvmaware:~/jgit-demo$ git config user.name "jvmaware"

sumit@jvmaware:~/jgit-demo$ git remote add origin https://github.com/jvmaware/jgit-demo.git

Using JGit, we can achieve similar results by executing the following code:

try(Git git = Git.init().setDirectory(Paths.get("D:\\jgit-demo").toFile()).call()){
   git.remoteAdd().setName("origin").setUri(new URIish("https://github.com/jvmaware/jgit-demo.git")).call();
}catch(GitAPIException | URISyntaxException exception){
   log.error("exception occurred while initializing repository", exception);
}

clone

For an existing remote repository, we can clone the same to our local environment and add changes to it afterwards. Following CLI command will create a copy of the remote repository in the same directory from where it is called:

sumit@jvmaware:~/jgit-demo$ git clone https://github.com/jvmaware/jgit-demo.git

Using JGit, the clone process looks something like:

private void cloneRepository(String localPath, String remotePath) {
   try {
       if (Files.notExists(Paths.get(localPath))) {
           Files.createDirectories(Paths.get(localPath));
           CloneCommand gitCommand = prepareCloneCommand(localPath, remotePath);
           gitCommand.call();
       }else{
           log.info("[{}] dir exists; will skip the clone stage", localPath);
       }
   } catch (IOException | GitAPIException exception) {
       log.error("exception occurred while cloning remote repo");
       throw new RuntimeException(exception);
   }
}
private CloneCommand prepareCloneCommand(String localPath, String remotePath) {
   CloneCommand cloneCommand = Git.cloneRepository().setURI(remotePath).setDirectory(Paths.get(localPath).toFile());
   UsernamePasswordCredentialsProvider credentialsProvider = new UsernamePasswordCredentialsProvider("username", "password");
   cloneCommand.setCredentialsProvider(credentialsProvider);
   return cloneCommand;
}

pull

The git pull command is used to fetch changes from a remote repository and immediately update our local repository with those. This includes merging any non-conflicting changes. The general syntax for the pull command is :

sumit@jvmaware:~/jgit-demo$ git pull

Using JGit, we prepare a pull command which is then used to update a local repository - denoted by source (connected to a remote repository) with the changes:

private void pullChanges() {
   try (Git git = Git.open(Paths.get(source).toFile())) {
       PullCommand pull = preparePullCommand(git);
       pull.call();
   } catch (IOException | GitAPIException exception) {
       log.error("exception occurred while pulling changes from remote repo");
       throw new RuntimeException(exception);
   }
}
private PullCommand preparePullCommand(Git git) {
   PullCommand pull = git.pull();
   UsernamePasswordCredentialsProvider credentialsProvider = new UsernamePasswordCredentialsProvider("<useName>", "<passWord>");
   pull.setCredentialsProvider(credentialsProvider);
   return pull;
}

push

Similar to the pull command mentioned above, we can create a push command instance that is used to publish our changes to the remote repository. When preparing a push command, a few additional steps are required:

  1. destination denotes the dir containing changes to be published.
  2. Specify the files to be published using addFilepattern method.
  3. Supply the appropriate credentials having required permissions to publish the changes using UsernamePasswordCredentialsProvider.
  4. In addition to that, we also specify the remote details using remote and RefSpecs:
private void pushChanges() {
   try (Git git = Git.open(Paths.get(destination).toFile())) {
       git.add().addFilepattern(".").call();
       git.commit().setMessage( "updated for changes on: " + LocalDate.now()).call();
       preparePushCommand(git).setRemote("origin").setRefSpecs(new RefSpec("refs/heads/main:refs/heads/main")).call();
   } catch (IOException | GitAPIException exception) {
       log.error("exception occurred while pulling changes from remote repo");
       throw new RuntimeException(exception);
   }
}
private PushCommand preparePushCommand(Git git) {
   PushCommand push = git.push();
   UsernamePasswordCredentialsProvider credentialsProvider = new UsernamePasswordCredentialsProvider("<useName>", "<passWord>");
   push.setCredentialsProvider(credentialsProvider);
   return push;
}

Be notified of new posts. Subscribe to the RSS feed.