Skip to content
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
JGit: setup and plumbing
  • Loading branch information
ben committed Oct 13, 2014
commit beccdc4c71ae29c4ef2b68a042663c8e3dfb3d47
115 changes: 114 additions & 1 deletion book/B-embedding-git/sections/jgit.asc
Original file line number Diff line number Diff line change
@@ -1,4 +1,117 @@
=== JGit

(((jgit)))(((java)))
If you want to use Git from within a Java program, there is another fully features Git library called JGit.
If you want to use Git from within a Java program, there is a fully featured Git library called JGit.
JGit is a relatively full-featured implementation of Git written natively in Java, and is widely used in the Java community.
The JGit project is under the Eclipse umbrella, and its home can be found at http://www.eclipse.org/jgit[].

==== Getting Set Up

There are a number of ways to connect your project with JGit and start writing code against it.
Probably the easiest is to use Maven – the integration is accomplished by adding the following snipped to the `<dependencies>` tag in your pom.xml file:

[source,xml]
----
<dependency>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit</artifactId>
<version>3.5.0.201409260305-r</version>
</dependency>
----

The `version` will most likely have advanced by the time you read this; check http://mvnrepository.com/artifact/org.eclipse.jgit/org.eclipse.jgit[] for updated repository information.
Once this step is done, Maven will automatically acquire and use the JGit libraries that you'll need.

If you would rather manage the binary dependencies yourself, pre-built JGit binaries are available from http://www.eclipse.org/jgit/download[].
You can build them into your project by running a command like this:

[source,shell]
----
javac -cp .:org.eclipse.jgit-3.5.0.201409260305-r.jar App.java
java -cp .:org.eclipse.jgit-3.5.0.201409260305-r.jar App
----

==== Plumbing

JGit has two basic levels of API: plumbing and porcelain.
The terminology for these comes from Git itself, and JGit is divided into roughly the same kinds of areas.
Porcelain APIs are a friendly front-end for common user-level actions (the sorts of things a normal user would use the Git command-line tool for), while the plumbing APIs are for interacting with low-level repository objects directly.

The starting point for most JGit sessions is the `Repository` class, and the first thing you'll want to do is create an instance of it.
For a filesystem-based repository (yes, JGit allows for other storage models), this is accomplished using `FileRepositoryBuilder`:

[source,java]
----
// Create a new repository; the path must exist
Repository newlyCreatedRepo = FileRepositoryBuilder.create(
new File("/tmp/new_repo/.git"));

// Open an existing repository
Repository existingRepo = new FileRepositoryBuilder()
.setGitDir(new File("my_repo/.git"))
.build();
----

The builder has a fluent API for providing all the things it needs to find a Git repository, whether or not your program knows exactly where it's located.
It can use environment variables (`.readEnvironment()`), start from a place in the working directory and search (`.setWorkTree(…).findGitDir()`), or just open a known `.git` directory as above.

Once you have a `Repository` instance, you can do all sorts of things with it.
Here's a quick sampling:

[source,java]
----
// Get a reference
Ref master = repo.getRef("master");

// Get the object the reference points to
ObjectId masterTip = master.getObjectId();

// Rev-parse
ObjectId obj = repo.resolve("HEAD~~");

// Load raw object contents
ObjectLoader loader = r.open(masterTip);
loader.copyTo(System.out);

// Create a branch
RefUpdate createBranch1 = r.updateRef("refs/heads/branch1");
createBranch1.setNewObjectId(masterTip);
createBranch1.update();

// Delete a branch
RefUpdate deleteBranch1 = r.updateRef("refs/heads/branch1");
deleteBranch1.setForceUpdate(true);
deleteBranch1.delete();

// Config
Config cfg = r.getConfig();
String name = cfg.getString("user", null, "name");
----

There's quite a bit going on here, so let's go through it one section at a time.

The first line gets a pointer to the `master` reference.
JGit automatically grabs the _actual_ master ref, which lives at `refs/heads/master`, and returns an object that lets you get information about the reference (Ref instances are read-only).
You can get the name (`.getName()`), and either the target object of a direct reference (`.getObjectId()`) or the reference pointed to by a symbolic ref (`.getTarget()`).
Ref objects are also used to represent tag refs and objects, so you can ask if the tag is ``peeled,'' meaning that it points to the final target of a (potentially long) string of tag objects.

The second line gets the target of the `master` reference, which is returned as an ObjectId instance.
ObjectId represents the SHA-1 hash of an object, which might or might not exist in Git's object database.
The third line is similar, but shows how JGit handles the rev-parse syntax (for more on this, see <<_branch_references>>); you can pass any single-point branch specifier that Git understands, and JGit will return either a valid ObjectId for that object, or `null`.

The next two lines show how to load the raw contents of an object.
In this example, we call `ObjectLoader.copyTo()` to stream the contents of the object directly to stdout, but ObjectLoader also has methods to read the type and size of an object, as well as return it as an array of bytes.
For large objects (where `.isLarge()` returns `true`), you can call `.openStream()` to get an InputStream-like object that can read the raw object data.

The next few lines show what it takes to create a new branch.
We create a RefUpdate instance, configure some parameters, and call `.update()` to trigger the change.
Directly following this is how to delete that same branch.
Note that `.setForceUpdate(true)` is required for this to complete.

The last example shows how to fetch the `user.name` value from the Git configuration files.
This Config instance uses the repository we opened earlier for local configuration, but will automatically detect the global and system configuration files and read values from them as well.


==== Porcelain

==== Further Reading