Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to open a repository creating it if it does not exist in JGit?

Tags:

jgit

Came up with:

/**
 * Create a repo at the specified directory or open one if it already
 * exists. Return a {@link Git} object...
 *
 * @param p
 *            Path to the repo root (the dir that contains the .git folder)
 * @return a "Git" object to run porcelain commands on...
 * @throws GitterException
 *             if the specified path cannot be resolved to a directory, or
 *             the repository failed to be build (...) or created
 */
public static Git open(Path p) throws GitterException {
    if (!Files.isDirectory(p)) // default LinkOption is follow links
        throw new GitterException(p + " can't be resolved to a directory");
    Repository localRepo = null;
    try {
        localRepo = new FileRepository(Paths.get(p.toString(), ".git")
            .toFile()); // do I have to specify the .git folder ?
    } catch (IOException e) {
        throw new GitterException("Failed to build Repository instance", e);
    }
    try {
        localRepo.create();
    } catch (IllegalStateException e) {
        // ISE when the repo exists !
    } catch (IOException e) {
        throw new GitterException("Failed to create Repository instance", e);
    }
    return new Git(localRepo);
}

Am I missing something obvious ? Is it as complicated as this ?

Run across setMustExist(boolean) in the BaseRepositoryBuilder could it be used ?

like image 830
Mr_and_Mrs_D Avatar asked Jul 07 '14 22:07

Mr_and_Mrs_D


People also ask

How do I open a repository in terminal?

Open a Repository in TerminalIn the Repositories view, right-click an item and choose Open in Terminal. If the repository is already open in Tower, you can use Open in Terminal from the File menu.

How do I initialize an empty repository?

The git init command creates a new Git repository. It can be used to convert an existing, unversioned project to a Git repository or initialize a new, empty repository. Most other Git commands are not available outside of an initialized repository, so this is usually the first command you'll run in a new project.


2 Answers

The shortest solution I could find is to always call create() and ignore the already exists exception.

static Git openOrCreate(File gitDirectory) throws IOException {
  Repository repository = new FileRepository(gitDirectory);
  try {
    repository.create();
  } catch(IllegalStateException repositoryExists) {
  }
  return new Git(repository);
}

The code has its caveats though. The IllegalStateException seems to be an implementation detail that might change and break the above code. In addition, FileRepository resides in an internal package and is not part of the public JGit API.

The following is a solution that avoids these problems:

static Git openOrCreate(File gitDirectory) throws IOException, GitAPIException {
  Git git;
  FileRepositoryBuilder repositoryBuilder = new FileRepositoryBuilder();
  repositoryBuilder.addCeilingDirectory(gitDirectory);
  repositoryBuilder.findGitDir(gitDirectory);
  if( repositoryBuilder.getGitDir() == null ) {
    git = Git.init().setDirectory(gitDirectory.getParentFile()).call();
  } else {
    git = new Git(repositoryBuilder.build());
  }
  return git;
}

Note that exception handling was left out in order to focus on the actual purpose of the snippets.

setMustExist doesn't help with creating a repository on demand. It only causes build()to raise a RepositoryNotFoundException if no repository can be found at the specified location.

Repository represents the repository itself whereas Git serves as a factory to create commands which operate on the repository that it wraps. Next to the factory methods there is close(), which simply delegates to Repository.close().

A Repository maintains a use counter that is decremented by close(). You can continue to use a repository after it was closed (through Git or the Repository's own methods) but it will be re-opened if necessary. To avoid leaking file handles you should not use a repository after it was closed.

An in-depth discussion of of how to access and initialize repositories with JGit can be found

here: http://www.codeaffine.com/2014/09/22/access-git-repository-with-jgit/ and

here: http://www.codeaffine.com/2015/05/06/jgit-initialize-repository/

like image 194
Rüdiger Herrmann Avatar answered Sep 16 '22 16:09

Rüdiger Herrmann


After Rüdiger Herrmann's answer

public static Git open(Path p) throws GitterException {
    // default LinkOption is follow links
    try {
        Files.createDirectories(p);
    } catch (IOException e) {
        throw new GitterException("Directory " + p + " can't be created", e);
    }
    RepositoryBuilder repositoryBuilder = new RepositoryBuilder();
    if (!isRepo(p, repositoryBuilder)) {
        LOGGER.debug(p.toAbsolutePath() + " is not a git repository.");
        try {
            return Git.init().setDirectory(p.toFile()).call();
        } catch (GitAPIException e) {
            throw new GitterException("Failed to create Git repository at "
                + p, e);
        }
    }
    try {
        return new Git(repositoryBuilder.build());
    } catch (IOException e) {
        throw new GitterException(
            "Failed to create Repository instance at " + p, e);
    }
}

static boolean isRepo(Path p, RepositoryBuilder rb)
        throws GitterException {
    if (!Files.isDirectory(p))
        throw new GitterException(p + " can't be resolved to a directory");
    final File directory = p.toFile();
    rb.addCeilingDirectory(directory); // for find() below
    // the docs say "Add a ceiling directory to the search limit list" which
    // means in plain english that it will search up to this directory,
    // which happens to be our directory, so it will only search there
    rb.findGitDir(directory); // find **and** add it to the builder
    return rb.getGitDir() != null;
}
like image 21
Mr_and_Mrs_D Avatar answered Sep 19 '22 16:09

Mr_and_Mrs_D