How to Access a Git Repository with JGit
A Git repository is represented in JGit through the Repository class that can be viewed as a handle to a repository. With a Repository instance, you can create JGit commands (through the Git factory class), gain access to configuration settings, resolve refs, etc.
There are several ways to obtain a repository reference and because I have seen people having trouble here and there, this article summarizes how to access a Git repository with JGit.
Of Repositories and Builders
The class Repository is abstract to allow for implementations with different storage backends. For example, there is an InMemoryRepository for tests and experiments. But of course, most commonly used is the FileRepository, that represents a repository in the local file system. Because the actual implementations are considered internal, each Repository implementation has a corresponding repository builder that should be used to create instances thereof.
Hence the FileRepositoryBuilder is the recommended way to create a FileRepository. For historical reasons there is also a RepositoryBuilder that does exactly the same but will be removed with the next major-version update.
Once you have configured a repository builder to your needs, call its build() method to have a repository created.
FileRepositoryBuilder repositoryBuilder = new FileRepositoryBuilder(); repositoryBuilder.setMustExist( true ); repositoryBuilder.setGitDir( ... ); Repository repository = repositoryBuilder.build();
For layout reasons, I have put the method calls on a line each, but the FileRepositoryBuilder also implements a fluent interface so that method calls can be chained.
All methods discussed here apply to local repositories only. Git is a distributed version control system and as such is not designed to directly manipulate a remote repository.
In order to manipulate a remote repository, you have to clone it first. Now you can make modifications to the local copy, like commit new or changed files, create branches or tags, etc. To synchronize your changes with the remote repository you will first have to integrate (aka fetch) changes (if any) from the remote and then finally push your local changes.
Prefer setGitDir()
In JGit, a file-based repository is identified through a directory. However, there are two directories that may appear suitable to identify a repository: The work directory wherein the currently checked out revision resides and the git directory which holds the object database and metadata (e.g. branches, tags, etc.).
While FileRepositoryBuilder has a setGitDir() as well as a setWorkTree() method, I recommend to always use setGitDir(), because:
- By default, the git directory is a direct subdirectory of the work directory, but this can be overridden through an environment variable or a configuration setting.
- And then there are bare repositories that don’t have a work directory at all.
Is This a Repository?
The FileRepositoryBuilder’s build() method returns a Repository whether or not a repository exists. Even if the given directory does not exist, an instance is returned.
I found two ways to test if a given directory acually points to an existing repository. By calling setMustExist(true), the FileRepositoryBuilder can be configured to only build existing repositories. Once the must-exist flag is turned on, build() will throw a RepositoryNotFoundException if no repository could be found. As a side note, this behavior is undocumented. It might be just a lapse in the JavaDoc and I doubt that this behavior will change, but still there is no guarantee as if it was part of the API.
Alternatively, you can test if the returned repository’s object database actually exists.
Repository repository = repositoryBuilder.build(); if( repository.getObjectDatabase().exists() ) { ... }
As the name implies, ObjectDatabase.exists() returns true if there is an object database and false otherwise.
A Small Detour: findGitDir()
The repository builder also offers a findGitDir() method that can be used to search for a repository starting from a given directory and going its parent hierarchy upwards.
FileRepositoryBuilder repositoryBuilder = new FileRepositoryBuilder(); repositoryBuilder.addCeilingDirectory( new File( "/home/user" ) ); repositoryBuilder.findGitDir( new File( "/home/user/git/foo/bar" ) );
The search ends if either a repository directory was found or the root of the file system was reached. getGitDir() can be used to obtain the search result and returns the found git directory or null if none was found.
The search can be limited by adding one or more ceiling directories. If one of them is reached while walking up the directory hierarchy, the search ends.
Alternative: Git.open()
If you find the FileRepositoryBuilder inconvenient to use, there is also a shorthand: Git.open().
Git git = Git.open( new File( "/path/to/repo/.git" ) );
The method expects a File parameter that denotes the directory in which the repository is located. The directory can either point to the work directory or the git directory. Again, I recommend to use the git directory here.
If the given directory does not exist or does not contain a repository, a RepositoryNotFoundException will be thrown. On success, an instance of class Git is returned that can be used to access the repository (git.getRepository()) and create git commands.
More than One Way to Access a Git Repository with JGit
While Git.open() is nice and short, the FileRepositoryBuilder gives you more control and a reliable way to determine if the repositry exists. Whether you prefer the first or the latter probably depends on your use case. Just remember to not use the FileRepository constructor directly as is may vanish or changes its behavior without prior notice.
Reference: | How to Access a Git Repository with JGit from our JCG partner Rudiger Herrmann at the Code Affine blog. |