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
Tweaks
  • Loading branch information
ben committed Oct 17, 2014
commit f66e5d5768dd75ec1334c41bf03de292db5b7987
26 changes: 14 additions & 12 deletions book/B-embedding-git/sections/jgit.asc
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,7 @@ 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 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`:
Expand Down Expand Up @@ -67,7 +66,7 @@ Ref master = repo.getRef("master");
ObjectId masterTip = master.getObjectId();

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

// Load raw object contents
ObjectLoader loader = r.open(masterTip);
Expand All @@ -91,28 +90,28 @@ 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).
JGit automatically grabs the _actual_ master ref, which lives at `refs/heads/master`, and returns an object that lets you fetch information about the reference.
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 third line is similar, but shows how JGit handles the rev-parse syntax (for more on this, see <<_branch_references>>); you can pass any object 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.
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 a byte array.
For large objects (where `.isLarge()` returns `true`), you can call `.openStream()` to get an InputStream-like object that can read the raw object data without pulling it all into memory at once.

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 work; otherwise the `.delete()` call will return `REJECTED`.
Directly following this is the code to delete that same branch.
Note that `.setForceUpdate(true)` is required for this to work; otherwise the `.delete()` call will return `REJECTED`, and nothing will happen.

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.

This is only a small sampling of the full porcelain API; there are many more methods and classes available.
Also not shown here is the way JGit handles errors: in classic Java fashion, these are specified as exceptions.
This is only a small sampling of the full plumbing API; there are many more methods and classes available.
Also not shown here is the way JGit handles errors, which is through the use of exceptions.
JGit APIs sometimes throw standard Java exceptions (such as `IOException`), but there are a host of JGit-specific exception types that are provided as well (such as `NoRemoteRepositoryException`, `CorruptObjectException`, and `NoMergeBaseException`).

==== Porcelain
Expand All @@ -132,7 +131,9 @@ Let's take a look at an example – doing something like `git ls-remote`:

[source,java]
----
CredentialsProvider cp = new UsernamePasswordCredentialsProvider("username", "p4ssw0rd");
Collection<Ref> remoteRefs = git.lsRemote()
.setCredentialsProvider(cp)
.setRemote("origin")
.setTags(true)
.setHeads(false)
Expand All @@ -144,8 +145,9 @@ for (Ref ref : remoteRefs) {

This is a common pattern with the Git class; the methods return a command object that lets you chain method calls to set parameters, which are executed when you call `.call()`.
In this case, we're asking the `origin` remote for tags, but not heads.
Also notice the use of a `CredentialsProvider` object for authentication.

Many other commands are available through the Git class, including but not limited to `add`, `commit`, `clean`, `push`, `rebase`, `revert`, and `reset`.
Many other commands are available through the Git class, including but not limited to `add`, `blame`, `commit`, `clean`, `push`, `rebase`, `revert`, and `reset`.

==== Further Reading

Expand Down