Merge branch 'stable-4.9' into stable-5.0

* stable-4.9:
  Ensure DirectoryStream is closed promptly

Change-Id: I447a01e1170db85fcf5978206ed35ad1956a2d82
Signed-off-by: Matthias Sohn <matthias.sohn@sap.com>
diff --git a/.mailmap b/.mailmap
index 560baaa..96a4f257 100644
--- a/.mailmap
+++ b/.mailmap
@@ -1,3 +1,4 @@
+Han-Wen Nienhuys <hanwen@google.com>         Han-Wen NIenhuys <hanwen@google.com>
 Mark Ingram <markdingram@gmail.com>          markdingram <markdingram@gmail.com>
 Roberto Tyley <roberto.tyley@guardian.co.uk> roberto <roberto.tyley@guardian.co.uk>
 Saša Živkov <sasa.zivkov@sap.com>            Sasa Zivkov <sasa.zivkov@sap.com>
diff --git a/BUILD b/BUILD
index be6dd76..5fea669 100644
--- a/BUILD
+++ b/BUILD
@@ -1,5 +1,12 @@
 package(default_visibility = ["//visibility:public"])
 
+config_setting(
+    name = "jdk9",
+    values = {
+        "java_toolchain": "@bazel_tools//tools/jdk:toolchain_jdk9",
+    },
+)
+
 genrule(
     name = "all",
     testonly = 1,
diff --git a/WORKSPACE b/WORKSPACE
index e47a7df..0fff5f9 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -16,6 +16,12 @@
 )
 
 maven_jar(
+    name = "jzlib",
+    artifact = "com.jcraft:jzlib:1.1.1",
+    sha1 = "a1551373315ffc2f96130a0e5704f74e151777ba",
+)
+
+maven_jar(
     name = "javaewah",
     artifact = "com.googlecode.javaewah:JavaEWAH:1.1.6",
     sha1 = "94ad16d728b374d65bd897625f3fbb3da223a2b6",
@@ -23,14 +29,14 @@
 
 maven_jar(
     name = "httpclient",
-    artifact = "org.apache.httpcomponents:httpclient:4.3.6",
-    sha1 = "4c47155e3e6c9a41a28db36680b828ced53b8af4",
+    artifact = "org.apache.httpcomponents:httpclient:4.5.2",
+    sha1 = "733db77aa8d9b2d68015189df76ab06304406e50",
 )
 
 maven_jar(
     name = "httpcore",
-    artifact = "org.apache.httpcomponents:httpcore:4.3.3",
-    sha1 = "f91b7a4aadc5cf486df6e4634748d7dd7a73f06d",
+    artifact = "org.apache.httpcomponents:httpcore:4.4.6",
+    sha1 = "e3fd8ced1f52c7574af952e2e6da0df8df08eb82",
 )
 
 maven_jar(
@@ -65,14 +71,14 @@
 
 maven_jar(
     name = "commons_compress",
-    artifact = "org.apache.commons:commons-compress:1.6",
-    sha1 = "c7d9b580aff9e9f1998361f16578e63e5c064699",
+    artifact = "org.apache.commons:commons-compress:1.15",
+    sha1 = "b686cd04abaef1ea7bc5e143c080563668eec17e",
 )
 
 maven_jar(
     name = "tukaani_xz",
-    artifact = "org.tukaani:xz:1.3",
-    sha1 = "66db21c8484120cb6a51b5b3ea47b6f383942bec",
+    artifact = "org.tukaani:xz:1.6",
+    sha1 = "05b6f921f1810bdf90e25471968f741f87168b64",
 )
 
 maven_jar(
@@ -101,50 +107,50 @@
 
 maven_jar(
     name = "gson",
-    artifact = "com.google.code.gson:gson:2.2.4",
-    sha1 = "a60a5e993c98c864010053cb901b7eab25306568",
+    artifact = "com.google.code.gson:gson:2.8.2",
+    sha1 = "3edcfe49d2c6053a70a2a47e4e1c2f94998a49cf",
 )
 
-JETTY_VER = "9.4.5.v20170502"
+JETTY_VER = "9.4.8.v20171121"
 
 maven_jar(
     name = "jetty_servlet",
     artifact = "org.eclipse.jetty:jetty-servlet:" + JETTY_VER,
-    sha1 = "394a535b76ca7399b25be3266f06f614e020517e",
-    src_sha1 = "4e85803c8d539aa0a8389e113095ef86032ac425",
+    sha1 = "bbbb9b5de08f468c7b9b3de6aea0b098d2c679b6",
+    src_sha1 = "6ef1e65a5af7ab2d79ba6043923affdaeaafb1e5",
 )
 
 maven_jar(
     name = "jetty_security",
     artifact = "org.eclipse.jetty:jetty-security:" + JETTY_VER,
-    sha1 = "4f4fc4cbe3504b6c91143ee37b38a1f3de2dcc72",
-    src_sha1 = "2124a757c87eacea7ad6507be6a415b5b51139b5",
+    sha1 = "e8350eec683b55494287f06740543e4be6f75425",
+    src_sha1 = "e3a879d8675fa10bc305e7a59006f1d09db04a68",
 )
 
 maven_jar(
     name = "jetty_server",
     artifact = "org.eclipse.jetty:jetty-server:" + JETTY_VER,
-    sha1 = "b4d30340213c3d2a5f908860ba170c5a697829be",
-    src_sha1 = "295d873f609a0e2863f33b5dbc8906ca348f1107",
+    sha1 = "34614bd9a29de57ef28ca31f1f2b49a412af196d",
+    src_sha1 = "fef49ac6b2bbc6d142dc0be34f68f0fb0792d52b",
 )
 
 maven_jar(
     name = "jetty_http",
     artifact = "org.eclipse.jetty:jetty-http:" + JETTY_VER,
-    sha1 = "c51b8a6a67d64672889249dd958edd77bff8fc0c",
-    src_sha1 = "c1bee39aeb565a4f26852b1851192d98ab611dbc",
+    sha1 = "9879d6c4e37400bf43f0cd4b3c6e34a3ba409864",
+    src_sha1 = "5e746cd0ccb732eef0427c8c4b9dcb034e26c61b",
 )
 
 maven_jar(
     name = "jetty_io",
     artifact = "org.eclipse.jetty:jetty-io:" + JETTY_VER,
-    sha1 = "76086f955d4e943396b8f340fd5bae3ce4da19d9",
-    src_sha1 = "8d41e410b2f0dd284a6e199ed08f45ef7ab2acf1",
+    sha1 = "d3fe2dfa62f52ee91ff07cb359f63387e0e30b40",
+    src_sha1 = "41f25e1e1bba14ab0d3415488fa189f09c27a1cf",
 )
 
 maven_jar(
     name = "jetty_util",
     artifact = "org.eclipse.jetty:jetty-util:" + JETTY_VER,
-    sha1 = "5fd36dfcf39110b809bd9b20cec62706ab694711",
-    src_sha1 = "629fcda1e4eecfd795e24cc07715ab9797970980",
+    sha1 = "d6ec1a1613c7fa72aa6bf5d8c204750afbc3df3b",
+    src_sha1 = "a74ecb43f96b2e21852f6908604316d7348a16ad",
 )
diff --git a/lib/BUILD b/lib/BUILD
index 703e7be..10496a7 100644
--- a/lib/BUILD
+++ b/lib/BUILD
@@ -30,7 +30,10 @@
 
 java_library(
     name = "gson",
-    visibility = ["//org.eclipse.jgit.lfs.server:__pkg__"],
+    visibility = [
+        "//org.eclipse.jgit.lfs:__pkg__",
+        "//org.eclipse.jgit.lfs.server:__pkg__",
+    ],
     exports = ["@gson//jar"],
 )
 
@@ -114,6 +117,15 @@
 )
 
 java_library(
+    name = "jzlib",
+    visibility = [
+        "//org.eclipse.jgit:__pkg__",
+        "//org.eclipse.jgit.test:__pkg__",
+    ],
+    exports = ["@jzlib//jar"],
+)
+
+java_library(
     name = "junit",
     testonly = 1,
     visibility = ["//visibility:public"],
diff --git a/org.eclipse.jgit.ant.test/.settings/org.eclipse.jdt.core.prefs b/org.eclipse.jgit.ant.test/.settings/org.eclipse.jdt.core.prefs
index 64f7498..794592d 100644
--- a/org.eclipse.jgit.ant.test/.settings/org.eclipse.jdt.core.prefs
+++ b/org.eclipse.jgit.ant.test/.settings/org.eclipse.jdt.core.prefs
@@ -25,7 +25,7 @@
 org.eclipse.jdt.core.compiler.problem.discouragedReference=warning
 org.eclipse.jdt.core.compiler.problem.emptyStatement=warning
 org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
-org.eclipse.jdt.core.compiler.problem.explicitlyClosedAutoCloseable=ignore
+org.eclipse.jdt.core.compiler.problem.explicitlyClosedAutoCloseable=warning
 org.eclipse.jdt.core.compiler.problem.fallthroughCase=warning
 org.eclipse.jdt.core.compiler.problem.fatalOptionalError=disabled
 org.eclipse.jdt.core.compiler.problem.fieldHiding=warning
diff --git a/org.eclipse.jgit.ant.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.ant.test/META-INF/MANIFEST.MF
index 3d89977..ae9496c 100644
--- a/org.eclipse.jgit.ant.test/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.ant.test/META-INF/MANIFEST.MF
@@ -2,14 +2,15 @@
 Manifest-Version: 1.0
 Bundle-ManifestVersion: 2
 Bundle-Name: %plugin_name
+Automatic-Module-Name: org.eclipse.jgit.ant.test
 Bundle-SymbolicName: org.eclipse.jgit.ant.test
-Bundle-Version: 4.9.3.qualifier
+Bundle-Version: 5.0.0.qualifier
 Bundle-ActivationPolicy: lazy
 Bundle-RequiredExecutionEnvironment: JavaSE-1.8
 Import-Package: org.apache.tools.ant,
- org.eclipse.jgit.ant.tasks;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.junit;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.lib;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.util;version="[4.9.3,4.10.0)",
+ org.eclipse.jgit.ant.tasks;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.junit;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.lib;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.util;version="[5.0.0,5.1.0)",
  org.hamcrest.core;version="[1.1.0,2.0.0)",
- org.junit;version="[4.0.0,5.0.0)"
+ org.junit;version="[4.12,5.0.0)"
diff --git a/org.eclipse.jgit.ant.test/pom.xml b/org.eclipse.jgit.ant.test/pom.xml
index 9d7f136..f8b83c2 100644
--- a/org.eclipse.jgit.ant.test/pom.xml
+++ b/org.eclipse.jgit.ant.test/pom.xml
@@ -50,7 +50,7 @@
   <parent>
     <groupId>org.eclipse.jgit</groupId>
     <artifactId>org.eclipse.jgit-parent</artifactId>
-    <version>4.9.3-SNAPSHOT</version>
+    <version>5.0.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>org.eclipse.jgit.ant.test</artifactId>
diff --git a/org.eclipse.jgit.ant/.settings/org.eclipse.jdt.core.prefs b/org.eclipse.jgit.ant/.settings/org.eclipse.jdt.core.prefs
index 4d260cf..565b75c 100644
--- a/org.eclipse.jgit.ant/.settings/org.eclipse.jdt.core.prefs
+++ b/org.eclipse.jgit.ant/.settings/org.eclipse.jdt.core.prefs
@@ -25,7 +25,7 @@
 org.eclipse.jdt.core.compiler.problem.discouragedReference=warning
 org.eclipse.jdt.core.compiler.problem.emptyStatement=warning
 org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
-org.eclipse.jdt.core.compiler.problem.explicitlyClosedAutoCloseable=ignore
+org.eclipse.jdt.core.compiler.problem.explicitlyClosedAutoCloseable=warning
 org.eclipse.jdt.core.compiler.problem.fallthroughCase=warning
 org.eclipse.jdt.core.compiler.problem.fatalOptionalError=disabled
 org.eclipse.jdt.core.compiler.problem.fieldHiding=warning
diff --git a/org.eclipse.jgit.ant/META-INF/MANIFEST.MF b/org.eclipse.jgit.ant/META-INF/MANIFEST.MF
index fdd9787..f917ba3 100644
--- a/org.eclipse.jgit.ant/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.ant/META-INF/MANIFEST.MF
@@ -1,12 +1,13 @@
 Manifest-Version: 1.0
 Bundle-ManifestVersion: 2
 Bundle-Name: %Bundle-Name
+Automatic-Module-Name: org.eclipse.jgit.ant
 Bundle-SymbolicName: org.eclipse.jgit.ant
-Bundle-Version: 4.9.3.qualifier
+Bundle-Version: 5.0.0.qualifier
 Bundle-RequiredExecutionEnvironment: JavaSE-1.8
 Import-Package: org.apache.tools.ant,
-  org.eclipse.jgit.storage.file;version="[4.9.3,4.10.0)"
+  org.eclipse.jgit.storage.file;version="[5.0.0,5.1.0)"
 Bundle-Localization: plugin
 Bundle-Vendor: %Provider-Name
-Export-Package: org.eclipse.jgit.ant.tasks;version="4.9.3";
+Export-Package: org.eclipse.jgit.ant.tasks;version="5.0.0";
  uses:="org.apache.tools.ant.types,org.apache.tools.ant"
diff --git a/org.eclipse.jgit.ant/pom.xml b/org.eclipse.jgit.ant/pom.xml
index 20c349e..7767c69 100644
--- a/org.eclipse.jgit.ant/pom.xml
+++ b/org.eclipse.jgit.ant/pom.xml
@@ -48,7 +48,7 @@
 	<parent>
 		<groupId>org.eclipse.jgit</groupId>
 		<artifactId>org.eclipse.jgit-parent</artifactId>
-		<version>4.9.3-SNAPSHOT</version>
+		<version>5.0.0-SNAPSHOT</version>
 	</parent>
 
 	<artifactId>org.eclipse.jgit.ant</artifactId>
diff --git a/org.eclipse.jgit.ant/src/org/eclipse/jgit/ant/tasks/GitAddTask.java b/org.eclipse.jgit.ant/src/org/eclipse/jgit/ant/tasks/GitAddTask.java
index db6f008..479dd86 100644
--- a/org.eclipse.jgit.ant/src/org/eclipse/jgit/ant/tasks/GitAddTask.java
+++ b/org.eclipse.jgit.ant/src/org/eclipse/jgit/ant/tasks/GitAddTask.java
@@ -71,6 +71,8 @@ public class GitAddTask extends Task {
 	private Union path;
 
 	/**
+	 * <p>Set the field <code>src</code>.</p>
+	 *
 	 * @param src
 	 *            the src to set
 	 */
@@ -106,6 +108,7 @@ private synchronized Union getPath() {
 		return path;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void execute() throws BuildException {
 		if (src == null) {
diff --git a/org.eclipse.jgit.ant/src/org/eclipse/jgit/ant/tasks/GitCheckoutTask.java b/org.eclipse.jgit.ant/src/org/eclipse/jgit/ant/tasks/GitCheckoutTask.java
index 9962472..0b27cc2 100644
--- a/org.eclipse.jgit.ant/src/org/eclipse/jgit/ant/tasks/GitCheckoutTask.java
+++ b/org.eclipse.jgit.ant/src/org/eclipse/jgit/ant/tasks/GitCheckoutTask.java
@@ -67,6 +67,8 @@ public class GitCheckoutTask extends Task {
 	private boolean force;
 
 	/**
+	 * Set the <code>src</code>
+	 *
 	 * @param src
 	 *            the src to set
 	 */
@@ -75,6 +77,8 @@ public void setSrc(File src) {
 	}
 
 	/**
+	 * Set <code>branch</code>
+	 *
 	 * @param branch
 	 *            the initial branch to check out
 	 */
@@ -83,6 +87,8 @@ public void setBranch(String branch) {
 	}
 
 	/**
+	 * Set if branch should be created if not yet existing
+	 *
 	 * @param createBranch
 	 *            whether the branch should be created if it does not already
 	 *            exist
@@ -92,6 +98,8 @@ public void setCreateBranch(boolean createBranch) {
 	}
 
 	/**
+	 * Set <code>force</code>
+	 *
 	 * @param force
 	 *            if <code>true</code> and the branch with the given name
 	 *            already exists, the start-point of an existing branch will be
@@ -102,6 +110,7 @@ public void setForce(boolean force) {
 		this.force = force;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void execute() throws BuildException {
 		CheckoutCommand checkout;
diff --git a/org.eclipse.jgit.ant/src/org/eclipse/jgit/ant/tasks/GitCloneTask.java b/org.eclipse.jgit.ant/src/org/eclipse/jgit/ant/tasks/GitCloneTask.java
index b2cb35c..18a6db8 100644
--- a/org.eclipse.jgit.ant/src/org/eclipse/jgit/ant/tasks/GitCloneTask.java
+++ b/org.eclipse.jgit.ant/src/org/eclipse/jgit/ant/tasks/GitCloneTask.java
@@ -68,6 +68,8 @@ public class GitCloneTask extends Task {
 	private String branch = Constants.HEAD;
 
 	/**
+	 * Set the <code>uri</code>.
+	 *
 	 * @param uri
 	 *            the uri to clone from
 	 */
@@ -80,7 +82,6 @@ public void setUri(String uri) {
 	 * directory isn't set, a name associated with the source uri will be used.
 	 *
 	 * @see URIish#getHumanishName()
-	 *
 	 * @param destination
 	 *            the directory to clone to
 	 */
@@ -89,6 +90,8 @@ public void setDest(File destination) {
 	}
 
 	/**
+	 * Set <code>bare</code>
+	 *
 	 * @param bare
 	 *            whether the cloned repository is bare or not
 	 */
@@ -97,6 +100,8 @@ public void setBare(boolean bare) {
 	}
 
 	/**
+	 * Set the <code>branch</code>
+	 *
 	 * @param branch
 	 *            the initial branch to check out when cloning the repository
 	 */
@@ -104,6 +109,7 @@ public void setBranch(String branch) {
 		this.branch = branch;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void execute() throws BuildException {
 		log("Cloning repository " + uri);
diff --git a/org.eclipse.jgit.ant/src/org/eclipse/jgit/ant/tasks/GitInitTask.java b/org.eclipse.jgit.ant/src/org/eclipse/jgit/ant/tasks/GitInitTask.java
index 91e57c0..70fd80e 100644
--- a/org.eclipse.jgit.ant/src/org/eclipse/jgit/ant/tasks/GitInitTask.java
+++ b/org.eclipse.jgit.ant/src/org/eclipse/jgit/ant/tasks/GitInitTask.java
@@ -71,6 +71,8 @@ public void setDest(File dest) {
 	}
 
 	/**
+	 * Configure if the repository should be <code>bare</code>
+	 *
 	 * @param bare
 	 *            whether the repository should be initialized to a bare
 	 *            repository or not.
@@ -79,6 +81,7 @@ public void setBare(boolean bare) {
 		this.bare = bare;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void execute() throws BuildException {
 		if (bare) {
diff --git a/org.eclipse.jgit.archive/.settings/org.eclipse.jdt.core.prefs b/org.eclipse.jgit.archive/.settings/org.eclipse.jdt.core.prefs
index 06ddbab..13c32a6 100644
--- a/org.eclipse.jgit.archive/.settings/org.eclipse.jdt.core.prefs
+++ b/org.eclipse.jgit.archive/.settings/org.eclipse.jdt.core.prefs
@@ -25,7 +25,7 @@
 org.eclipse.jdt.core.compiler.problem.discouragedReference=warning
 org.eclipse.jdt.core.compiler.problem.emptyStatement=warning
 org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
-org.eclipse.jdt.core.compiler.problem.explicitlyClosedAutoCloseable=ignore
+org.eclipse.jdt.core.compiler.problem.explicitlyClosedAutoCloseable=warning
 org.eclipse.jdt.core.compiler.problem.fallthroughCase=warning
 org.eclipse.jdt.core.compiler.problem.fatalOptionalError=disabled
 org.eclipse.jdt.core.compiler.problem.fieldHiding=warning
diff --git a/org.eclipse.jgit.archive/META-INF/MANIFEST.MF b/org.eclipse.jgit.archive/META-INF/MANIFEST.MF
index a0aeb04..7fa8576 100644
--- a/org.eclipse.jgit.archive/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.archive/META-INF/MANIFEST.MF
@@ -1,8 +1,9 @@
 Manifest-Version: 1.0
 Bundle-ManifestVersion: 2
 Bundle-Name: %plugin_name
+Automatic-Module-Name: org.eclipse.jgit.archive
 Bundle-SymbolicName: org.eclipse.jgit.archive
-Bundle-Version: 4.9.3.qualifier
+Bundle-Version: 5.0.0.qualifier
 Bundle-Vendor: %provider_name
 Bundle-Localization: plugin
 Bundle-RequiredExecutionEnvironment: JavaSE-1.8
@@ -12,15 +13,15 @@
  org.apache.commons.compress.compressors.bzip2;version="[1.4,2.0)",
  org.apache.commons.compress.compressors.gzip;version="[1.4,2.0)",
  org.apache.commons.compress.compressors.xz;version="[1.4,2.0)",
- org.eclipse.jgit.api;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.lib;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.nls;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.revwalk;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.util;version="[4.9.3,4.10.0)",
+ org.eclipse.jgit.api;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.lib;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.nls;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.revwalk;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.util;version="[5.0.0,5.1.0)",
  org.osgi.framework;version="[1.3.0,2.0.0)"
 Bundle-ActivationPolicy: lazy
 Bundle-Activator: org.eclipse.jgit.archive.FormatActivator
-Export-Package: org.eclipse.jgit.archive;version="4.9.3";
+Export-Package: org.eclipse.jgit.archive;version="5.0.0";
   uses:="org.eclipse.jgit.lib,
    org.eclipse.jgit.api,
    org.apache.commons.compress.archivers,
diff --git a/org.eclipse.jgit.archive/META-INF/SOURCE-MANIFEST.MF b/org.eclipse.jgit.archive/META-INF/SOURCE-MANIFEST.MF
index 66aa665..ef53d07 100644
--- a/org.eclipse.jgit.archive/META-INF/SOURCE-MANIFEST.MF
+++ b/org.eclipse.jgit.archive/META-INF/SOURCE-MANIFEST.MF
@@ -3,5 +3,5 @@
 Bundle-Name: org.eclipse.jgit.archive - Sources
 Bundle-SymbolicName: org.eclipse.jgit.archive.source
 Bundle-Vendor: Eclipse.org - JGit
-Bundle-Version: 4.9.3.qualifier
-Eclipse-SourceBundle: org.eclipse.jgit.archive;version="4.9.3.qualifier";roots="."
+Bundle-Version: 5.0.0.qualifier
+Eclipse-SourceBundle: org.eclipse.jgit.archive;version="5.0.0.qualifier";roots="."
diff --git a/org.eclipse.jgit.archive/pom.xml b/org.eclipse.jgit.archive/pom.xml
index 8508cdc..2a3500c 100644
--- a/org.eclipse.jgit.archive/pom.xml
+++ b/org.eclipse.jgit.archive/pom.xml
@@ -50,7 +50,7 @@
   <parent>
     <groupId>org.eclipse.jgit</groupId>
     <artifactId>org.eclipse.jgit-parent</artifactId>
-    <version>4.9.3-SNAPSHOT</version>
+    <version>5.0.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>org.eclipse.jgit.archive</artifactId>
diff --git a/org.eclipse.jgit.archive/src/org/eclipse/jgit/archive/ArchiveFormats.java b/org.eclipse.jgit.archive/src/org/eclipse/jgit/archive/ArchiveFormats.java
index 9d3decd..bf0d88e 100644
--- a/org.eclipse.jgit.archive/src/org/eclipse/jgit/archive/ArchiveFormats.java
+++ b/org.eclipse.jgit.archive/src/org/eclipse/jgit/archive/ArchiveFormats.java
@@ -48,11 +48,11 @@
 import org.eclipse.jgit.api.ArchiveCommand;
 
 /**
- * Registers all format types from the org.eclipse.jgit.archive
- * package for use via the ArchiveCommand API.
+ * Registers all format types from the org.eclipse.jgit.archive package for use
+ * via the ArchiveCommand API.
  *
- * See {@link FormatActivator} for an OSGi bundle activator
- * that performs the same registration automatically.
+ * See {@link org.eclipse.jgit.archive.FormatActivator} for an OSGi bundle
+ * activator that performs the same registration automatically.
  */
 public class ArchiveFormats {
 	private static final List<String> myFormats = new ArrayList<>();
diff --git a/org.eclipse.jgit.archive/src/org/eclipse/jgit/archive/FormatActivator.java b/org.eclipse.jgit.archive/src/org/eclipse/jgit/archive/FormatActivator.java
index aa4e4f5..0bb595a 100644
--- a/org.eclipse.jgit.archive/src/org/eclipse/jgit/archive/FormatActivator.java
+++ b/org.eclipse.jgit.archive/src/org/eclipse/jgit/archive/FormatActivator.java
@@ -57,12 +57,11 @@
  */
 public class FormatActivator implements BundleActivator {
 	/**
+	 * {@inheritDoc}
+	 *
 	 * Registers all included archive formats by calling
 	 * {@link ArchiveFormats#registerAll()}. This method is called by the OSGi
 	 * framework when the bundle is started.
-	 *
-	 * @param context
-	 *            unused
 	 */
 	@Override
 	public void start(BundleContext context) {
@@ -70,11 +69,10 @@ public void start(BundleContext context) {
 	}
 
 	/**
+	 * {@inheritDoc}
+	 *
 	 * Cleans up after {@link #start(BundleContext)} by calling
 	 * {@link ArchiveFormats#unregisterAll}.
-	 *
-	 * @param context
-	 *            unused
 	 */
 	@Override
 	public void stop(BundleContext context) {
diff --git a/org.eclipse.jgit.archive/src/org/eclipse/jgit/archive/TarFormat.java b/org.eclipse.jgit.archive/src/org/eclipse/jgit/archive/TarFormat.java
index 7b7fbcd..9ed60d9 100644
--- a/org.eclipse.jgit.archive/src/org/eclipse/jgit/archive/TarFormat.java
+++ b/org.eclipse.jgit.archive/src/org/eclipse/jgit/archive/TarFormat.java
@@ -42,6 +42,8 @@
  */
 package org.eclipse.jgit.archive;
 
+import static org.eclipse.jgit.lib.Constants.CHARACTER_ENCODING;
+
 import java.io.IOException;
 import java.io.OutputStream;
 import java.text.MessageFormat;
@@ -70,6 +72,7 @@ public final class TarFormat extends BaseFormat implements
 	private static final List<String> SUFFIXES = Collections
 			.unmodifiableList(Arrays.asList(".tar")); //$NON-NLS-1$
 
+	/** {@inheritDoc} */
 	@Override
 	public ArchiveOutputStream createArchiveOutputStream(OutputStream s)
 			throws IOException {
@@ -77,29 +80,18 @@ public ArchiveOutputStream createArchiveOutputStream(OutputStream s)
 				Collections.<String, Object> emptyMap());
 	}
 
-	/**
-	 * @since 4.0
-	 */
+	/** {@inheritDoc} */
 	@Override
 	public ArchiveOutputStream createArchiveOutputStream(OutputStream s,
 			Map<String, Object> o) throws IOException {
-		TarArchiveOutputStream out = new TarArchiveOutputStream(s, "UTF-8"); //$NON-NLS-1$
+		TarArchiveOutputStream out = new TarArchiveOutputStream(s,
+				CHARACTER_ENCODING);
 		out.setLongFileMode(TarArchiveOutputStream.LONGFILE_POSIX);
 		out.setBigNumberMode(TarArchiveOutputStream.BIGNUMBER_POSIX);
 		return applyFormatOptions(out, o);
 	}
 
-	@Deprecated
-	@Override
-	public void putEntry(ArchiveOutputStream out,
-			String path, FileMode mode, ObjectLoader loader)
-			throws IOException {
-		putEntry(out, null, path, mode,loader);
-	}
-
-	/**
-	 * @since 4.7
-	 */
+	/** {@inheritDoc} */
 	@Override
 	public void putEntry(ArchiveOutputStream out,
 			ObjectId tree, String path, FileMode mode, ObjectLoader loader)
@@ -108,7 +100,7 @@ public void putEntry(ArchiveOutputStream out,
 			final TarArchiveEntry entry = new TarArchiveEntry(
 					path, TarConstants.LF_SYMLINK);
 			entry.setLinkName(new String(
-					loader.getCachedBytes(100), "UTF-8")); //$NON-NLS-1$
+					loader.getCachedBytes(100), CHARACTER_ENCODING));
 			out.putArchiveEntry(entry);
 			out.closeArchiveEntry();
 			return;
@@ -150,16 +142,19 @@ public void putEntry(ArchiveOutputStream out,
 		out.closeArchiveEntry();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public Iterable<String> suffixes() {
 		return SUFFIXES;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public boolean equals(Object other) {
 		return (other instanceof TarFormat);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public int hashCode() {
 		return getClass().hashCode();
diff --git a/org.eclipse.jgit.archive/src/org/eclipse/jgit/archive/Tbz2Format.java b/org.eclipse.jgit.archive/src/org/eclipse/jgit/archive/Tbz2Format.java
index 5f194ec..fa6a7b0 100644
--- a/org.eclipse.jgit.archive/src/org/eclipse/jgit/archive/Tbz2Format.java
+++ b/org.eclipse.jgit.archive/src/org/eclipse/jgit/archive/Tbz2Format.java
@@ -66,6 +66,7 @@ public final class Tbz2Format extends BaseFormat implements
 
 	private final ArchiveCommand.Format<ArchiveOutputStream> tarFormat = new TarFormat();
 
+	/** {@inheritDoc} */
 	@Override
 	public ArchiveOutputStream createArchiveOutputStream(OutputStream s)
 			throws IOException {
@@ -73,9 +74,7 @@ public ArchiveOutputStream createArchiveOutputStream(OutputStream s)
 				Collections.<String, Object> emptyMap());
 	}
 
-	/**
-	 * @since 4.0
-	 */
+	/** {@inheritDoc} */
 	@Override
 	public ArchiveOutputStream createArchiveOutputStream(OutputStream s,
 			Map<String, Object> o) throws IOException {
@@ -83,17 +82,7 @@ public ArchiveOutputStream createArchiveOutputStream(OutputStream s,
 		return tarFormat.createArchiveOutputStream(out, o);
 	}
 
-	@Deprecated
-	@Override
-	public void putEntry(ArchiveOutputStream out,
-			String path, FileMode mode, ObjectLoader loader)
-			throws IOException {
-		putEntry(out, null, path, mode,loader);
-	}
-
-	/**
-	 * @since 4.7
-	 */
+	/** {@inheritDoc} */
 	@Override
 	public void putEntry(ArchiveOutputStream out,
 			ObjectId tree, String path, FileMode mode, ObjectLoader loader)
@@ -101,16 +90,19 @@ public void putEntry(ArchiveOutputStream out,
 		tarFormat.putEntry(out, tree, path, mode, loader);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public Iterable<String> suffixes() {
 		return SUFFIXES;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public boolean equals(Object other) {
 		return (other instanceof Tbz2Format);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public int hashCode() {
 		return getClass().hashCode();
diff --git a/org.eclipse.jgit.archive/src/org/eclipse/jgit/archive/TgzFormat.java b/org.eclipse.jgit.archive/src/org/eclipse/jgit/archive/TgzFormat.java
index a6d053e..368b4f2 100644
--- a/org.eclipse.jgit.archive/src/org/eclipse/jgit/archive/TgzFormat.java
+++ b/org.eclipse.jgit.archive/src/org/eclipse/jgit/archive/TgzFormat.java
@@ -66,6 +66,7 @@ public final class TgzFormat extends BaseFormat implements
 
 	private final ArchiveCommand.Format<ArchiveOutputStream> tarFormat = new TarFormat();
 
+	/** {@inheritDoc} */
 	@Override
 	public ArchiveOutputStream createArchiveOutputStream(OutputStream s)
 			throws IOException {
@@ -73,9 +74,7 @@ public ArchiveOutputStream createArchiveOutputStream(OutputStream s)
 				Collections.<String, Object> emptyMap());
 	}
 
-	/**
-	 * @since 4.0
-	 */
+	/** {@inheritDoc} */
 	@Override
 	public ArchiveOutputStream createArchiveOutputStream(OutputStream s,
 			Map<String, Object> o) throws IOException {
@@ -83,17 +82,7 @@ public ArchiveOutputStream createArchiveOutputStream(OutputStream s,
 		return tarFormat.createArchiveOutputStream(out, o);
 	}
 
-	@Deprecated
-	@Override
-	public void putEntry(ArchiveOutputStream out,
-			String path, FileMode mode, ObjectLoader loader)
-			throws IOException {
-		putEntry(out, null, path, mode,loader);
-	}
-
-	/**
-	 * @since 4.7
-	 */
+	/** {@inheritDoc} */
 	@Override
 	public void putEntry(ArchiveOutputStream out,
 			ObjectId tree, String path, FileMode mode, ObjectLoader loader)
@@ -101,16 +90,19 @@ public void putEntry(ArchiveOutputStream out,
 		tarFormat.putEntry(out, tree, path, mode, loader);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public Iterable<String> suffixes() {
 		return SUFFIXES;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public boolean equals(Object other) {
 		return (other instanceof TgzFormat);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public int hashCode() {
 		return getClass().hashCode();
diff --git a/org.eclipse.jgit.archive/src/org/eclipse/jgit/archive/TxzFormat.java b/org.eclipse.jgit.archive/src/org/eclipse/jgit/archive/TxzFormat.java
index b6742ac..36616ed 100644
--- a/org.eclipse.jgit.archive/src/org/eclipse/jgit/archive/TxzFormat.java
+++ b/org.eclipse.jgit.archive/src/org/eclipse/jgit/archive/TxzFormat.java
@@ -66,6 +66,7 @@ public final class TxzFormat extends BaseFormat implements
 
 	private final ArchiveCommand.Format<ArchiveOutputStream> tarFormat = new TarFormat();
 
+	/** {@inheritDoc} */
 	@Override
 	public ArchiveOutputStream createArchiveOutputStream(OutputStream s)
 			throws IOException {
@@ -73,9 +74,7 @@ public ArchiveOutputStream createArchiveOutputStream(OutputStream s)
 				Collections.<String, Object> emptyMap());
 	}
 
-	/**
-	 * @since 4.0
-	 */
+	/** {@inheritDoc} */
 	@Override
 	public ArchiveOutputStream createArchiveOutputStream(OutputStream s,
 			Map<String, Object> o) throws IOException {
@@ -83,17 +82,7 @@ public ArchiveOutputStream createArchiveOutputStream(OutputStream s,
 		return tarFormat.createArchiveOutputStream(out, o);
 	}
 
-	@Deprecated
-	@Override
-	public void putEntry(ArchiveOutputStream out,
-			String path, FileMode mode, ObjectLoader loader)
-			throws IOException {
-		putEntry(out, null, path, mode,loader);
-	}
-
-	/**
-	 * @since 4.7
-	 */
+	/** {@inheritDoc} */
 	@Override
 	public void putEntry(ArchiveOutputStream out,
 			ObjectId tree, String path, FileMode mode, ObjectLoader loader)
@@ -101,16 +90,19 @@ public void putEntry(ArchiveOutputStream out,
 		tarFormat.putEntry(out, tree, path, mode, loader);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public Iterable<String> suffixes() {
 		return SUFFIXES;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public boolean equals(Object other) {
 		return (other instanceof TxzFormat);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public int hashCode() {
 		return getClass().hashCode();
diff --git a/org.eclipse.jgit.archive/src/org/eclipse/jgit/archive/ZipFormat.java b/org.eclipse.jgit.archive/src/org/eclipse/jgit/archive/ZipFormat.java
index 46d918e..8483801 100644
--- a/org.eclipse.jgit.archive/src/org/eclipse/jgit/archive/ZipFormat.java
+++ b/org.eclipse.jgit.archive/src/org/eclipse/jgit/archive/ZipFormat.java
@@ -68,6 +68,7 @@ public final class ZipFormat extends BaseFormat implements
 	private static final List<String> SUFFIXES = Collections
 			.unmodifiableList(Arrays.asList(".zip")); //$NON-NLS-1$
 
+	/** {@inheritDoc} */
 	@Override
 	public ArchiveOutputStream createArchiveOutputStream(OutputStream s)
 			throws IOException {
@@ -75,26 +76,14 @@ public ArchiveOutputStream createArchiveOutputStream(OutputStream s)
 				Collections.<String, Object> emptyMap());
 	}
 
-	/**
-	 * @since 4.0
-	 */
+	/** {@inheritDoc} */
 	@Override
 	public ArchiveOutputStream createArchiveOutputStream(OutputStream s,
 			Map<String, Object> o) throws IOException {
 		return applyFormatOptions(new ZipArchiveOutputStream(s), o);
 	}
 
-	@Deprecated
-	@Override
-	public void putEntry(ArchiveOutputStream out,
-			String path, FileMode mode, ObjectLoader loader)
-			throws IOException {
-		putEntry(out, null, path, mode,loader);
-	}
-
-	/**
-	 * @since 4.7
-	 */
+	/** {@inheritDoc} */
 	@Override
 	public void putEntry(ArchiveOutputStream out,
 			ObjectId tree, String path, FileMode mode, ObjectLoader loader)
@@ -136,16 +125,19 @@ public void putEntry(ArchiveOutputStream out,
 		out.closeArchiveEntry();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public Iterable<String> suffixes() {
 		return SUFFIXES;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public boolean equals(Object other) {
 		return (other instanceof ZipFormat);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public int hashCode() {
 		return getClass().hashCode();
diff --git a/org.eclipse.jgit.archive/src/org/eclipse/jgit/archive/internal/ArchiveText.java b/org.eclipse.jgit.archive/src/org/eclipse/jgit/archive/internal/ArchiveText.java
index f631cf8..cac491a 100644
--- a/org.eclipse.jgit.archive/src/org/eclipse/jgit/archive/internal/ArchiveText.java
+++ b/org.eclipse.jgit.archive/src/org/eclipse/jgit/archive/internal/ArchiveText.java
@@ -51,6 +51,8 @@
  */
 public class ArchiveText extends TranslationBundle {
 	/**
+	 * Get an instance of this translation bundle.
+	 *
 	 * @return an instance of this translation bundle
 	 */
 	public static ArchiveText get() {
diff --git a/org.eclipse.jgit.http.apache/.settings/.api_filters b/org.eclipse.jgit.http.apache/.settings/.api_filters
new file mode 100644
index 0000000..d1a0664
--- /dev/null
+++ b/org.eclipse.jgit.http.apache/.settings/.api_filters
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<component id="org.eclipse.jgit.http.apache" version="2">
+    <resource path="META-INF/MANIFEST.MF">
+        <filter id="925892614">
+            <message_arguments>
+                <message_argument value="5.0.0"/>
+                <message_argument value="4.11.0"/>
+            </message_arguments>
+        </filter>
+    </resource>
+</component>
diff --git a/org.eclipse.jgit.http.apache/.settings/org.eclipse.jdt.core.prefs b/org.eclipse.jgit.http.apache/.settings/org.eclipse.jdt.core.prefs
index 4d260cf..565b75c 100644
--- a/org.eclipse.jgit.http.apache/.settings/org.eclipse.jdt.core.prefs
+++ b/org.eclipse.jgit.http.apache/.settings/org.eclipse.jdt.core.prefs
@@ -25,7 +25,7 @@
 org.eclipse.jdt.core.compiler.problem.discouragedReference=warning
 org.eclipse.jdt.core.compiler.problem.emptyStatement=warning
 org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
-org.eclipse.jdt.core.compiler.problem.explicitlyClosedAutoCloseable=ignore
+org.eclipse.jdt.core.compiler.problem.explicitlyClosedAutoCloseable=warning
 org.eclipse.jdt.core.compiler.problem.fallthroughCase=warning
 org.eclipse.jdt.core.compiler.problem.fatalOptionalError=disabled
 org.eclipse.jdt.core.compiler.problem.fieldHiding=warning
diff --git a/org.eclipse.jgit.http.apache/META-INF/MANIFEST.MF b/org.eclipse.jgit.http.apache/META-INF/MANIFEST.MF
index 709b8a7..ced2532 100644
--- a/org.eclipse.jgit.http.apache/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.http.apache/META-INF/MANIFEST.MF
@@ -1,8 +1,9 @@
 Manifest-Version: 1.0
 Bundle-ManifestVersion: 2
 Bundle-Name: %Bundle-Name
+Automatic-Module-Name: org.eclipse.jgit.http.apache
 Bundle-SymbolicName: org.eclipse.jgit.http.apache
-Bundle-Version: 4.9.3.qualifier
+Bundle-Version: 5.0.0.qualifier
 Bundle-RequiredExecutionEnvironment: JavaSE-1.8
 Bundle-Localization: plugin
 Bundle-Vendor: %Provider-Name
@@ -22,10 +23,10 @@
  org.apache.http.impl.client;version="[4.3.0,5.0.0)",
  org.apache.http.impl.conn;version="[4.3.0,5.0.0)",
  org.apache.http.params;version="[4.3.0,5.0.0)",
- org.eclipse.jgit.nls;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.transport.http;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.util;version="[4.9.3,4.10.0)"
-Export-Package: org.eclipse.jgit.transport.http.apache;version="4.9.3";
+ org.eclipse.jgit.nls;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.transport.http;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.util;version="[5.0.0,5.1.0)"
+Export-Package: org.eclipse.jgit.transport.http.apache;version="5.0.0";
   uses:="org.apache.http.client,
    org.eclipse.jgit.transport.http,
    org.apache.http.entity,
diff --git a/org.eclipse.jgit.http.apache/pom.xml b/org.eclipse.jgit.http.apache/pom.xml
index 017d403..8d3e365 100644
--- a/org.eclipse.jgit.http.apache/pom.xml
+++ b/org.eclipse.jgit.http.apache/pom.xml
@@ -48,7 +48,7 @@
 	<parent>
 		<groupId>org.eclipse.jgit</groupId>
 		<artifactId>org.eclipse.jgit-parent</artifactId>
-		<version>4.9.3-SNAPSHOT</version>
+		<version>5.0.0-SNAPSHOT</version>
 	</parent>
 
 	<artifactId>org.eclipse.jgit.http.apache</artifactId>
@@ -68,6 +68,14 @@
 			<artifactId>org.eclipse.jgit</artifactId>
 			<version>${project.version}</version>
 		</dependency>
+        <dependency>
+          <groupId>org.apache.httpcomponents</groupId>
+          <artifactId>httpclient</artifactId>
+        </dependency>
+        <dependency>
+          <groupId>org.apache.httpcomponents</groupId>
+          <artifactId>httpcore</artifactId>
+        </dependency>
 	</dependencies>
 
 	<build>
diff --git a/org.eclipse.jgit.http.apache/src/org/eclipse/jgit/transport/http/apache/HttpClientConnection.java b/org.eclipse.jgit.http.apache/src/org/eclipse/jgit/transport/http/apache/HttpClientConnection.java
index 945ecd5..7f1fecb 100644
--- a/org.eclipse.jgit.http.apache/src/org/eclipse/jgit/transport/http/apache/HttpClientConnection.java
+++ b/org.eclipse.jgit.http.apache/src/org/eclipse/jgit/transport/http/apache/HttpClientConnection.java
@@ -58,7 +58,6 @@
 import java.security.KeyManagementException;
 import java.security.NoSuchAlgorithmException;
 import java.security.SecureRandom;
-import java.security.cert.X509Certificate;
 import java.util.HashMap;
 import java.util.LinkedList;
 import java.util.List;
@@ -67,9 +66,6 @@
 import javax.net.ssl.HostnameVerifier;
 import javax.net.ssl.KeyManager;
 import javax.net.ssl.SSLContext;
-import javax.net.ssl.SSLException;
-import javax.net.ssl.SSLSession;
-import javax.net.ssl.SSLSocket;
 import javax.net.ssl.TrustManager;
 
 import org.apache.http.Header;
@@ -91,7 +87,6 @@
 import org.apache.http.conn.socket.ConnectionSocketFactory;
 import org.apache.http.conn.socket.PlainConnectionSocketFactory;
 import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
-import org.apache.http.conn.ssl.X509HostnameVerifier;
 import org.apache.http.impl.client.HttpClientBuilder;
 import org.apache.http.impl.client.HttpClients;
 import org.apache.http.impl.conn.BasicHttpClientConnectionManager;
@@ -101,7 +96,8 @@
 import org.eclipse.jgit.util.TemporaryBuffer.LocalFile;
 
 /**
- * A {@link HttpConnection} which uses {@link HttpClient}
+ * A {@link org.eclipse.jgit.transport.http.HttpConnection} which uses
+ * {@link org.apache.http.client.HttpClient}
  *
  * @since 3.3
  */
@@ -128,7 +124,7 @@ public class HttpClientConnection implements HttpConnection {
 
 	private Boolean followRedirects;
 
-	private X509HostnameVerifier hostnameverifier;
+	private HostnameVerifier hostnameverifier;
 
 	SSLContext ctx;
 
@@ -193,6 +189,8 @@ public void setBuffer(TemporaryBuffer buffer) {
 	}
 
 	/**
+	 * Constructor for HttpClientConnection.
+	 *
 	 * @param urlStr
 	 * @throws MalformedURLException
 	 */
@@ -201,6 +199,8 @@ public HttpClientConnection(String urlStr) throws MalformedURLException {
 	}
 
 	/**
+	 * Constructor for HttpClientConnection.
+	 *
 	 * @param urlStr
 	 * @param proxy
 	 * @throws MalformedURLException
@@ -211,6 +211,8 @@ public HttpClientConnection(String urlStr, Proxy proxy)
 	}
 
 	/**
+	 * Constructor for HttpClientConnection.
+	 *
 	 * @param urlStr
 	 * @param proxy
 	 * @param cl
@@ -223,17 +225,20 @@ public HttpClientConnection(String urlStr, Proxy proxy, HttpClient cl)
 		this.proxy = proxy;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public int getResponseCode() throws IOException {
 		execute();
 		return resp.getStatusLine().getStatusCode();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public URL getURL() {
 		return url;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public String getResponseMessage() throws IOException {
 		execute();
@@ -262,6 +267,7 @@ private void execute() throws IOException, ClientProtocolException {
 		}
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public Map<String, List<String>> getHeaderFields() {
 		Map<String, List<String>> ret = new HashMap<>();
@@ -274,11 +280,13 @@ public Map<String, List<String>> getHeaderFields() {
 		return ret;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void setRequestProperty(String name, String value) {
 		req.addHeader(name, value);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void setRequestMethod(String method) throws ProtocolException {
 		this.method = method;
@@ -296,21 +304,25 @@ public void setRequestMethod(String method) throws ProtocolException {
 		}
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void setUseCaches(boolean usecaches) {
 		// not needed
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void setConnectTimeout(int timeout) {
 		this.timeout = Integer.valueOf(timeout);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void setReadTimeout(int readTimeout) {
 		this.readTimeout = Integer.valueOf(readTimeout);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public String getContentType() {
 		HttpEntity responseEntity = resp.getEntity();
@@ -322,18 +334,21 @@ public String getContentType() {
 		return null;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public InputStream getInputStream() throws IOException {
 		return resp.getEntity().getContent();
 	}
 
 	// will return only the first field
+	/** {@inheritDoc} */
 	@Override
 	public String getHeaderField(String name) {
 		Header header = resp.getFirstHeader(name);
 		return (header == null) ? null : header.getValue();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public int getContentLength() {
 		Header contentLength = resp.getFirstHeader("content-length"); //$NON-NLS-1$
@@ -349,16 +364,19 @@ public int getContentLength() {
 		}
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void setInstanceFollowRedirects(boolean followRedirects) {
 		this.followRedirects = Boolean.valueOf(followRedirects);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void setDoOutput(boolean dooutput) {
 		// TODO: check whether we can really ignore this.
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void setFixedLengthStreamingMode(int contentLength) {
 		if (entity != null)
@@ -367,6 +385,7 @@ public void setFixedLengthStreamingMode(int contentLength) {
 		entity.setContentLength(contentLength);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public OutputStream getOutputStream() throws IOException {
 		if (entity == null)
@@ -374,6 +393,7 @@ public OutputStream getOutputStream() throws IOException {
 		return entity.getBuffer();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void setChunkedStreamingMode(int chunklen) {
 		if (entity == null)
@@ -381,48 +401,31 @@ public void setChunkedStreamingMode(int chunklen) {
 		entity.setChunked(true);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public String getRequestMethod() {
 		return method;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public boolean usingProxy() {
 		return isUsingProxy;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void connect() throws IOException {
 		execute();
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	public void setHostnameVerifier(final HostnameVerifier hostnameverifier) {
-		this.hostnameverifier = new X509HostnameVerifier() {
-			@Override
-			public boolean verify(String hostname, SSLSession session) {
-				return hostnameverifier.verify(hostname, session);
-			}
-
-			@Override
-			public void verify(String host, String[] cns, String[] subjectAlts)
-					throws SSLException {
-				throw new UnsupportedOperationException(); // TODO message
-			}
-
-			@Override
-			public void verify(String host, X509Certificate cert)
-					throws SSLException {
-				throw new UnsupportedOperationException(); // TODO message
-			}
-
-			@Override
-			public void verify(String host, SSLSocket ssl) throws IOException {
-				hostnameverifier.verify(host, ssl.getSession());
-			}
-		};
+	public void setHostnameVerifier(HostnameVerifier hostnameverifier) {
+		this.hostnameverifier = hostnameverifier;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void configure(KeyManager[] km, TrustManager[] tm,
 			SecureRandom random) throws KeyManagementException {
diff --git a/org.eclipse.jgit.http.apache/src/org/eclipse/jgit/transport/http/apache/HttpClientConnectionFactory.java b/org.eclipse.jgit.http.apache/src/org/eclipse/jgit/transport/http/apache/HttpClientConnectionFactory.java
index f97d284..4556a34 100644
--- a/org.eclipse.jgit.http.apache/src/org/eclipse/jgit/transport/http/apache/HttpClientConnectionFactory.java
+++ b/org.eclipse.jgit.http.apache/src/org/eclipse/jgit/transport/http/apache/HttpClientConnectionFactory.java
@@ -50,16 +50,19 @@
 import org.eclipse.jgit.transport.http.HttpConnectionFactory;
 
 /**
- * A factory returning instances of {@link HttpClientConnection}
+ * A factory returning instances of
+ * {@link org.eclipse.jgit.transport.http.apache.HttpClientConnection}
  *
  * @since 3.3
  */
 public class HttpClientConnectionFactory implements HttpConnectionFactory {
+	/** {@inheritDoc} */
 	@Override
 	public HttpConnection create(URL url) throws IOException {
 		return new HttpClientConnection(url.toString());
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public HttpConnection create(URL url, Proxy proxy)
 			throws IOException {
diff --git a/org.eclipse.jgit.http.apache/src/org/eclipse/jgit/transport/http/apache/TemporaryBufferEntity.java b/org.eclipse.jgit.http.apache/src/org/eclipse/jgit/transport/http/apache/TemporaryBufferEntity.java
index 3efff49..b81e31c 100644
--- a/org.eclipse.jgit.http.apache/src/org/eclipse/jgit/transport/http/apache/TemporaryBufferEntity.java
+++ b/org.eclipse.jgit.http.apache/src/org/eclipse/jgit/transport/http/apache/TemporaryBufferEntity.java
@@ -46,12 +46,12 @@
 import java.io.InputStream;
 import java.io.OutputStream;
 
-import org.apache.http.HttpEntity;
 import org.apache.http.entity.AbstractHttpEntity;
 import org.eclipse.jgit.util.TemporaryBuffer;
 
 /**
- * A {@link HttpEntity} which takes it's content from a {@link TemporaryBuffer}
+ * A {@link org.apache.http.HttpEntity} which takes its content from a
+ * {@link org.eclipse.jgit.util.TemporaryBuffer}
  *
  * @since 3.3
  */
@@ -62,8 +62,8 @@ public class TemporaryBufferEntity extends AbstractHttpEntity
 	private Integer contentLength;
 
 	/**
-	 * Construct a new {@link HttpEntity} which will contain the content stored
-	 * in the specified buffer
+	 * Construct a new {@link org.apache.http.HttpEntity} which will contain the
+	 * content stored in the specified buffer
 	 *
 	 * @param buffer
 	 */
@@ -72,17 +72,21 @@ public TemporaryBufferEntity(TemporaryBuffer buffer) {
 	}
 
 	/**
+	 * Get the <code>buffer</code> containing the content
+	 *
 	 * @return buffer containing the content
 	 */
 	public TemporaryBuffer getBuffer() {
 		return buffer;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public boolean isRepeatable() {
 		return true;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public long getContentLength() {
 		if (contentLength != null)
@@ -90,23 +94,28 @@ public long getContentLength() {
 		return buffer.length();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public InputStream getContent() throws IOException, IllegalStateException {
 		return buffer.openInputStream();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void writeTo(OutputStream outstream) throws IOException {
 		// TODO: dont we need a progressmonitor
 		buffer.writeTo(outstream, null);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public boolean isStreaming() {
 		return false;
 	}
 
 	/**
+	 * Set the <code>contentLength</code>
+	 *
 	 * @param contentLength
 	 */
 	public void setContentLength(int contentLength) {
@@ -114,8 +123,9 @@ public void setContentLength(int contentLength) {
 	}
 
 	/**
-	 * Close destroys the associated buffer used to buffer the entity
+	 * {@inheritDoc}
 	 *
+	 * Close destroys the associated buffer used to buffer the entity
 	 * @since 4.5
 	 */
 	@Override
diff --git a/org.eclipse.jgit.http.apache/src/org/eclipse/jgit/transport/http/apache/internal/HttpApacheText.java b/org.eclipse.jgit.http.apache/src/org/eclipse/jgit/transport/http/apache/internal/HttpApacheText.java
index 38f1578..1c65230 100644
--- a/org.eclipse.jgit.http.apache/src/org/eclipse/jgit/transport/http/apache/internal/HttpApacheText.java
+++ b/org.eclipse.jgit.http.apache/src/org/eclipse/jgit/transport/http/apache/internal/HttpApacheText.java
@@ -51,6 +51,8 @@
  */
 public class HttpApacheText extends TranslationBundle {
 	/**
+	 * Get an instance of this translation bundle.
+	 *
 	 * @return an instance of this translation bundle
 	 */
 	public static HttpApacheText get() {
diff --git a/org.eclipse.jgit.http.server/.settings/org.eclipse.jdt.core.prefs b/org.eclipse.jgit.http.server/.settings/org.eclipse.jdt.core.prefs
index 4d260cf..565b75c 100644
--- a/org.eclipse.jgit.http.server/.settings/org.eclipse.jdt.core.prefs
+++ b/org.eclipse.jgit.http.server/.settings/org.eclipse.jdt.core.prefs
@@ -25,7 +25,7 @@
 org.eclipse.jdt.core.compiler.problem.discouragedReference=warning
 org.eclipse.jdt.core.compiler.problem.emptyStatement=warning
 org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
-org.eclipse.jdt.core.compiler.problem.explicitlyClosedAutoCloseable=ignore
+org.eclipse.jdt.core.compiler.problem.explicitlyClosedAutoCloseable=warning
 org.eclipse.jdt.core.compiler.problem.fallthroughCase=warning
 org.eclipse.jdt.core.compiler.problem.fatalOptionalError=disabled
 org.eclipse.jdt.core.compiler.problem.fieldHiding=warning
diff --git a/org.eclipse.jgit.http.server/META-INF/MANIFEST.MF b/org.eclipse.jgit.http.server/META-INF/MANIFEST.MF
index a723ab3..d7ed5f0 100644
--- a/org.eclipse.jgit.http.server/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.http.server/META-INF/MANIFEST.MF
@@ -1,14 +1,15 @@
 Manifest-Version: 1.0
 Bundle-ManifestVersion: 2
 Bundle-Name: %plugin_name
+Automatic-Module-Name: org.eclipse.jgit.http.server
 Bundle-SymbolicName: org.eclipse.jgit.http.server
-Bundle-Version: 4.9.3.qualifier
+Bundle-Version: 5.0.0.qualifier
 Bundle-Localization: plugin
 Bundle-Vendor: %provider_name
-Export-Package: org.eclipse.jgit.http.server;version="4.9.3",
- org.eclipse.jgit.http.server.glue;version="4.9.3";
+Export-Package: org.eclipse.jgit.http.server;version="5.0.0",
+ org.eclipse.jgit.http.server.glue;version="5.0.0";
   uses:="javax.servlet,javax.servlet.http",
- org.eclipse.jgit.http.server.resolver;version="4.9.3";
+ org.eclipse.jgit.http.server.resolver;version="5.0.0";
   uses:="org.eclipse.jgit.transport.resolver,
    org.eclipse.jgit.lib,
    org.eclipse.jgit.transport,
@@ -17,12 +18,12 @@
 Bundle-RequiredExecutionEnvironment: JavaSE-1.8
 Import-Package: javax.servlet;version="[2.5.0,3.2.0)",
  javax.servlet.http;version="[2.5.0,3.2.0)",
- org.eclipse.jgit.errors;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.internal.storage.dfs;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.internal.storage.file;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.lib;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.nls;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.revwalk;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.transport;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.transport.resolver;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.util;version="[4.9.3,4.10.0)"
+ org.eclipse.jgit.errors;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.internal.storage.dfs;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.internal.storage.file;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.lib;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.nls;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.revwalk;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.transport;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.transport.resolver;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.util;version="[5.0.0,5.1.0)"
diff --git a/org.eclipse.jgit.http.server/pom.xml b/org.eclipse.jgit.http.server/pom.xml
index cb92f4c..6aaffcf 100644
--- a/org.eclipse.jgit.http.server/pom.xml
+++ b/org.eclipse.jgit.http.server/pom.xml
@@ -52,7 +52,7 @@
   <parent>
     <groupId>org.eclipse.jgit</groupId>
     <artifactId>org.eclipse.jgit-parent</artifactId>
-    <version>4.9.3-SNAPSHOT</version>
+    <version>5.0.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>org.eclipse.jgit.http.server</artifactId>
diff --git a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/AsIsFileFilter.java b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/AsIsFileFilter.java
index 05391eb..9e9f25e 100644
--- a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/AsIsFileFilter.java
+++ b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/AsIsFileFilter.java
@@ -66,20 +66,23 @@
 class AsIsFileFilter implements Filter {
 	private final AsIsFileService asIs;
 
-	AsIsFileFilter(final AsIsFileService getAnyFile) {
+	AsIsFileFilter(AsIsFileService getAnyFile) {
 		this.asIs = getAnyFile;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void init(FilterConfig config) throws ServletException {
 		// Do nothing.
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void destroy() {
 		// Do nothing.
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void doFilter(ServletRequest request, ServletResponse response,
 			FilterChain chain) throws IOException, ServletException {
diff --git a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/ClientVersionUtil.java b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/ClientVersionUtil.java
index c0d4b5e..38a9ea7 100644
--- a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/ClientVersionUtil.java
+++ b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/ClientVersionUtil.java
@@ -47,13 +47,19 @@
 
 import javax.servlet.http.HttpServletRequest;
 
-/** Parses Git client User-Agent strings. */
+/**
+ * Parses Git client User-Agent strings.
+ */
 public class ClientVersionUtil {
 	private static final int[] v1_7_5 = { 1, 7, 5 };
 	private static final int[] v1_7_8_6 = { 1, 7, 8, 6 };
 	private static final int[] v1_7_9 = { 1, 7, 9 };
 
-	/** @return maximum version array, indicating an invalid version of Git. */
+	/**
+	 * An invalid version of Git
+	 *
+	 * @return maximum version array, indicating an invalid version of Git.
+	 */
 	public static int[] invalidVersion() {
 		return new int[] { Integer.MAX_VALUE };
 	}
diff --git a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/FileSender.java b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/FileSender.java
index 91e749e..05510a0 100644
--- a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/FileSender.java
+++ b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/FileSender.java
@@ -84,7 +84,7 @@ final class FileSender {
 
 	private long end;
 
-	FileSender(final File path) throws FileNotFoundException {
+	FileSender(File path) throws FileNotFoundException {
 		this.path = path;
 		this.source = new RandomAccessFile(path, "r");
 
@@ -137,8 +137,7 @@ void serve(final HttpServletRequest req, final HttpServletResponse rsp,
 		rsp.setHeader(HDR_CONTENT_LENGTH, Long.toString(end - pos));
 
 		if (sendBody) {
-			final OutputStream out = rsp.getOutputStream();
-			try {
+			try (OutputStream out = rsp.getOutputStream()) {
 				final byte[] buf = new byte[4096];
 				source.seek(pos);
 				while (pos < end) {
@@ -151,8 +150,6 @@ void serve(final HttpServletRequest req, final HttpServletResponse rsp,
 					pos += n;
 				}
 				out.flush();
-			} finally {
-				out.close();
 			}
 		}
 	}
@@ -220,7 +217,7 @@ private boolean initRangeRequest(final HttpServletRequest req,
 		return true;
 	}
 
-	private static Enumeration<String> getRange(final HttpServletRequest req) {
+	private static Enumeration<String> getRange(HttpServletRequest req) {
 		return req.getHeaders(HDR_RANGE);
 	}
 }
diff --git a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/GitFilter.java b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/GitFilter.java
index 8070371..2ebe1b7 100644
--- a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/GitFilter.java
+++ b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/GitFilter.java
@@ -62,8 +62,6 @@
 import org.eclipse.jgit.http.server.resolver.DefaultReceivePackFactory;
 import org.eclipse.jgit.http.server.resolver.DefaultUploadPackFactory;
 import org.eclipse.jgit.lib.Constants;
-import org.eclipse.jgit.transport.ReceivePack;
-import org.eclipse.jgit.transport.UploadPack;
 import org.eclipse.jgit.transport.resolver.FileResolver;
 import org.eclipse.jgit.transport.resolver.ReceivePackFactory;
 import org.eclipse.jgit.transport.resolver.RepositoryResolver;
@@ -74,15 +72,16 @@
  * Handles Git repository access over HTTP.
  * <p>
  * Applications embedding this filter should map a directory path within the
- * application to this filter. For a servlet version, see {@link GitServlet}.
+ * application to this filter. For a servlet version, see
+ * {@link org.eclipse.jgit.http.server.GitServlet}.
  * <p>
  * Applications may wish to add additional repository action URLs to this
- * servlet by taking advantage of its extension from {@link MetaFilter}.
- * Callers may register their own URL suffix translations through
- * {@link #serve(String)}, or their regex translations through
- * {@link #serveRegex(String)}. Each translation should contain a complete
- * filter pipeline which ends with the HttpServlet that should handle the
- * requested action.
+ * servlet by taking advantage of its extension from
+ * {@link org.eclipse.jgit.http.server.glue.MetaFilter}. Callers may register
+ * their own URL suffix translations through {@link #serve(String)}, or their
+ * regex translations through {@link #serveRegex(String)}. Each translation
+ * should contain a complete filter pipeline which ends with the HttpServlet
+ * that should handle the requested action.
  */
 public class GitFilter extends MetaFilter {
 	private volatile boolean initialized;
@@ -124,6 +123,8 @@ public void setRepositoryResolver(RepositoryResolver<HttpServletRequest> resolve
 	}
 
 	/**
+	 * Set AsIsFileService
+	 *
 	 * @param f
 	 *            the filter to validate direct access to repository files
 	 *            through a dumb client. If {@code null} then dumb client
@@ -135,9 +136,12 @@ public void setAsIsFileService(AsIsFileService f) {
 	}
 
 	/**
+	 * Set upload-pack factory
+	 *
 	 * @param f
-	 *            the factory to construct and configure an {@link UploadPack}
-	 *            session when a fetch or clone is requested by a client.
+	 *            the factory to construct and configure an
+	 *            {@link org.eclipse.jgit.transport.UploadPack} session when a
+	 *            fetch or clone is requested by a client.
 	 */
 	@SuppressWarnings("unchecked")
 	public void setUploadPackFactory(UploadPackFactory<HttpServletRequest> f) {
@@ -146,10 +150,12 @@ public void setUploadPackFactory(UploadPackFactory<HttpServletRequest> f) {
 	}
 
 	/**
+	 * Add upload-pack filter
+	 *
 	 * @param filter
 	 *            filter to apply before any of the UploadPack operations. The
 	 *            UploadPack instance is available in the request attribute
-	 *            {@link ServletUtils#ATTRIBUTE_HANDLER}.
+	 *            {@link org.eclipse.jgit.http.server.ServletUtils#ATTRIBUTE_HANDLER}.
 	 */
 	public void addUploadPackFilter(Filter filter) {
 		assertNotInitialized();
@@ -157,9 +163,12 @@ public void addUploadPackFilter(Filter filter) {
 	}
 
 	/**
+	 * Set the receive-pack factory
+	 *
 	 * @param f
-	 *            the factory to construct and configure a {@link ReceivePack}
-	 *            session when a push is requested by a client.
+	 *            the factory to construct and configure a
+	 *            {@link org.eclipse.jgit.transport.ReceivePack} session when a
+	 *            push is requested by a client.
 	 */
 	@SuppressWarnings("unchecked")
 	public void setReceivePackFactory(ReceivePackFactory<HttpServletRequest> f) {
@@ -168,10 +177,12 @@ public void setReceivePackFactory(ReceivePackFactory<HttpServletRequest> f) {
 	}
 
 	/**
+	 * Add receive-pack filter
+	 *
 	 * @param filter
 	 *            filter to apply before any of the ReceivePack operations. The
 	 *            ReceivePack instance is available in the request attribute
-	 *            {@link ServletUtils#ATTRIBUTE_HANDLER}.
+	 *            {@link org.eclipse.jgit.http.server.ServletUtils#ATTRIBUTE_HANDLER}.
 	 */
 	public void addReceivePackFilter(Filter filter) {
 		assertNotInitialized();
@@ -183,6 +194,7 @@ private void assertNotInitialized() {
 			throw new IllegalStateException(HttpServerText.get().alreadyInitializedByContainer);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void init(FilterConfig filterConfig) throws ServletException {
 		super.init(filterConfig);
@@ -297,6 +309,7 @@ private static boolean getBoolean(FilterConfig cfg, String param)
 		}
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected ServletBinder register(ServletBinder binder) {
 		if (resolver == null)
diff --git a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/GitServlet.java b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/GitServlet.java
index 3a5edee..d0ea7b6 100644
--- a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/GitServlet.java
+++ b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/GitServlet.java
@@ -54,8 +54,6 @@
 
 import org.eclipse.jgit.http.server.glue.MetaServlet;
 import org.eclipse.jgit.http.server.resolver.AsIsFileService;
-import org.eclipse.jgit.transport.ReceivePack;
-import org.eclipse.jgit.transport.UploadPack;
 import org.eclipse.jgit.transport.resolver.ReceivePackFactory;
 import org.eclipse.jgit.transport.resolver.RepositoryResolver;
 import org.eclipse.jgit.transport.resolver.UploadPackFactory;
@@ -87,12 +85,12 @@
  *
  * <p>
  * Applications may wish to add additional repository action URLs to this
- * servlet by taking advantage of its extension from {@link MetaServlet}.
- * Callers may register their own URL suffix translations through
- * {@link #serve(String)}, or their regex translations through
- * {@link #serveRegex(String)}. Each translation should contain a complete
- * filter pipeline which ends with the HttpServlet that should handle the
- * requested action.
+ * servlet by taking advantage of its extension from
+ * {@link org.eclipse.jgit.http.server.glue.MetaServlet}. Callers may register
+ * their own URL suffix translations through {@link #serve(String)}, or their
+ * regex translations through {@link #serveRegex(String)}. Each translation
+ * should contain a complete filter pipeline which ends with the HttpServlet
+ * that should handle the requested action.
  */
 public class GitServlet extends MetaServlet {
 	private static final long serialVersionUID = 1L;
@@ -124,6 +122,8 @@ public void setRepositoryResolver(RepositoryResolver<HttpServletRequest> resolve
 	}
 
 	/**
+	 * Set AsIsFileService
+	 *
 	 * @param f
 	 *            the filter to validate direct access to repository files
 	 *            through a dumb client. If {@code null} then dumb client
@@ -134,45 +134,56 @@ public void setAsIsFileService(AsIsFileService f) {
 	}
 
 	/**
+	 * Set upload-pack factory
+	 *
 	 * @param f
-	 *            the factory to construct and configure an {@link UploadPack}
-	 *            session when a fetch or clone is requested by a client.
+	 *            the factory to construct and configure an
+	 *            {@link org.eclipse.jgit.transport.UploadPack} session when a
+	 *            fetch or clone is requested by a client.
 	 */
 	public void setUploadPackFactory(UploadPackFactory<HttpServletRequest> f) {
 		gitFilter.setUploadPackFactory(f);
 	}
 
 	/**
+	 * Add upload-pack filter
+	 *
 	 * @param filter
 	 *            filter to apply before any of the UploadPack operations. The
 	 *            UploadPack instance is available in the request attribute
-	 *            {@link ServletUtils#ATTRIBUTE_HANDLER}.
+	 *            {@link org.eclipse.jgit.http.server.ServletUtils#ATTRIBUTE_HANDLER}.
 	 */
 	public void addUploadPackFilter(Filter filter) {
 		gitFilter.addUploadPackFilter(filter);
 	}
 
 	/**
+	 * Set receive-pack factory
+	 *
 	 * @param f
-	 *            the factory to construct and configure a {@link ReceivePack}
-	 *            session when a push is requested by a client.
+	 *            the factory to construct and configure a
+	 *            {@link org.eclipse.jgit.transport.ReceivePack} session when a
+	 *            push is requested by a client.
 	 */
 	public void setReceivePackFactory(ReceivePackFactory<HttpServletRequest> f) {
 		gitFilter.setReceivePackFactory(f);
 	}
 
 	/**
+	 * Add receive-pack filter
+	 *
 	 * @param filter
 	 *            filter to apply before any of the ReceivePack operations. The
 	 *            ReceivePack instance is available in the request attribute
-	 *            {@link ServletUtils#ATTRIBUTE_HANDLER}.
+	 *            {@link org.eclipse.jgit.http.server.ServletUtils#ATTRIBUTE_HANDLER}.
 	 */
 	public void addReceivePackFilter(Filter filter) {
 		gitFilter.addReceivePackFilter(filter);
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	public void init(final ServletConfig config) throws ServletException {
+	public void init(ServletConfig config) throws ServletException {
 		gitFilter.init(new FilterConfig() {
 			@Override
 			public String getFilterName() {
diff --git a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/GitSmartHttpTools.java b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/GitSmartHttpTools.java
index cfe4822..b9ca12b 100644
--- a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/GitSmartHttpTools.java
+++ b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/GitSmartHttpTools.java
@@ -154,9 +154,9 @@ public static void sendError(HttpServletRequest req,
 	 * an HTTP response code is returned instead.
 	 * <p>
 	 * This method may only be called before handing off the request to
-	 * {@link UploadPack#upload(java.io.InputStream, OutputStream, OutputStream)}
+	 * {@link org.eclipse.jgit.transport.UploadPack#upload(java.io.InputStream, OutputStream, OutputStream)}
 	 * or
-	 * {@link ReceivePack#receive(java.io.InputStream, OutputStream, OutputStream)}.
+	 * {@link org.eclipse.jgit.transport.ReceivePack#receive(java.io.InputStream, OutputStream, OutputStream)}.
 	 *
 	 * @param req
 	 *            current request.
@@ -314,11 +314,8 @@ private static void send(HttpServletRequest req, HttpServletResponse res,
 		res.setStatus(HttpServletResponse.SC_OK);
 		res.setContentType(type);
 		res.setContentLength(buf.length);
-		OutputStream os = res.getOutputStream();
-		try {
+		try (OutputStream os = res.getOutputStream()) {
 			os.write(buf);
-		} finally {
-			os.close();
 		}
 	}
 
diff --git a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/HttpServerText.java b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/HttpServerText.java
index dff90a6..fbb2061 100644
--- a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/HttpServerText.java
+++ b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/HttpServerText.java
@@ -52,6 +52,8 @@
 public class HttpServerText extends TranslationBundle {
 
 	/**
+	 * Get an instance of this translation bundle
+	 *
 	 * @return an instance of this translation bundle
 	 */
 	public static HttpServerText get() {
diff --git a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/InfoPacksServlet.java b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/InfoPacksServlet.java
index 91c2f9f..52aaf51 100644
--- a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/InfoPacksServlet.java
+++ b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/InfoPacksServlet.java
@@ -60,13 +60,14 @@
 class InfoPacksServlet extends HttpServlet {
 	private static final long serialVersionUID = 1L;
 
+	/** {@inheritDoc} */
 	@Override
 	public void doGet(final HttpServletRequest req,
 			final HttpServletResponse rsp) throws IOException {
 		sendPlainText(packList(req), req, rsp);
 	}
 
-	private static String packList(final HttpServletRequest req) {
+	private static String packList(HttpServletRequest req) {
 		final StringBuilder out = new StringBuilder();
 		final ObjectDatabase db = getRepository(req).getObjectDatabase();
 		if (db instanceof ObjectDirectory) {
diff --git a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/InfoRefsServlet.java b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/InfoRefsServlet.java
index 72c7136..0f4633b 100644
--- a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/InfoRefsServlet.java
+++ b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/InfoRefsServlet.java
@@ -44,18 +44,15 @@
 package org.eclipse.jgit.http.server;
 
 import static org.eclipse.jgit.http.server.ServletUtils.getRepository;
-import static org.eclipse.jgit.lib.RefDatabase.ALL;
 
 import java.io.IOException;
 import java.io.OutputStreamWriter;
-import java.util.Map;
 
 import javax.servlet.http.HttpServlet;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
 import org.eclipse.jgit.lib.Constants;
-import org.eclipse.jgit.lib.Ref;
 import org.eclipse.jgit.lib.Repository;
 import org.eclipse.jgit.transport.RefAdvertiser;
 import org.eclipse.jgit.util.HttpSupport;
@@ -64,6 +61,7 @@
 class InfoRefsServlet extends HttpServlet {
 	private static final long serialVersionUID = 1L;
 
+	/** {@inheritDoc} */
 	@Override
 	public void doGet(final HttpServletRequest req,
 			final HttpServletResponse rsp) throws IOException {
@@ -73,29 +71,27 @@ public void doGet(final HttpServletRequest req,
 		rsp.setCharacterEncoding(Constants.CHARACTER_ENCODING);
 
 		final Repository db = getRepository(req);
-		final OutputStreamWriter out = new OutputStreamWriter(
+		try (OutputStreamWriter out = new OutputStreamWriter(
 				new SmartOutputStream(req, rsp, true),
-				Constants.CHARSET);
-		final RefAdvertiser adv = new RefAdvertiser() {
-			@Override
-			protected void writeOne(final CharSequence line) throws IOException {
-				// Whoever decided that info/refs should use a different
-				// delimiter than the native git:// protocol shouldn't
-				// be allowed to design this sort of stuff. :-(
-				out.append(line.toString().replace(' ', '\t'));
-			}
+				Constants.CHARSET)) {
+			final RefAdvertiser adv = new RefAdvertiser() {
+				@Override
+				protected void writeOne(CharSequence line)
+						throws IOException {
+					// Whoever decided that info/refs should use a different
+					// delimiter than the native git:// protocol shouldn't
+					// be allowed to design this sort of stuff. :-(
+					out.append(line.toString().replace(' ', '\t'));
+				}
 
-			@Override
-			protected void end() {
-				// No end marker required for info/refs format.
-			}
-		};
-		adv.init(db);
-		adv.setDerefTags(true);
-
-		Map<String, Ref> refs = db.getRefDatabase().getRefs(ALL);
-		refs.remove(Constants.HEAD);
-		adv.send(refs);
-		out.close();
+				@Override
+				protected void end() {
+					// No end marker required for info/refs format.
+				}
+			};
+			adv.init(db);
+			adv.setDerefTags(true);
+			adv.send(db.getRefDatabase().getRefsByPrefix(Constants.R_REFS));
+		}
 	}
 }
diff --git a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/IsLocalFilter.java b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/IsLocalFilter.java
index 223813f..b379983 100644
--- a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/IsLocalFilter.java
+++ b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/IsLocalFilter.java
@@ -66,16 +66,19 @@
  * downstream servlet can directly access its contents on disk.
  */
 class IsLocalFilter implements Filter {
+	/** {@inheritDoc} */
 	@Override
 	public void init(FilterConfig config) throws ServletException {
 		// Do nothing.
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void destroy() {
 		// Do nothing.
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void doFilter(ServletRequest request, ServletResponse response,
 			FilterChain chain) throws IOException, ServletException {
@@ -85,7 +88,7 @@ public void doFilter(ServletRequest request, ServletResponse response,
 			((HttpServletResponse) response).sendError(SC_FORBIDDEN);
 	}
 
-	private static boolean isLocal(final Repository db) {
+	private static boolean isLocal(Repository db) {
 		return db.getObjectDatabase() instanceof ObjectDirectory;
 	}
 }
diff --git a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/NoCacheFilter.java b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/NoCacheFilter.java
index bdc3420..5177858 100644
--- a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/NoCacheFilter.java
+++ b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/NoCacheFilter.java
@@ -57,18 +57,21 @@
 import javax.servlet.ServletResponse;
 import javax.servlet.http.HttpServletResponse;
 
-/** Adds HTTP response headers to prevent caching by proxies/browsers. */
+/** Add HTTP response headers to prevent caching by proxies/browsers. */
 class NoCacheFilter implements Filter {
+	/** {@inheritDoc} */
 	@Override
 	public void init(FilterConfig config) throws ServletException {
 		// Do nothing.
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void destroy() {
 		// Do nothing.
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void doFilter(ServletRequest request, ServletResponse response,
 			FilterChain chain) throws IOException, ServletException {
diff --git a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/ObjectFileServlet.java b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/ObjectFileServlet.java
index babc036..62f075c 100644
--- a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/ObjectFileServlet.java
+++ b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/ObjectFileServlet.java
@@ -75,7 +75,7 @@ static class Loose extends ObjectFileServlet {
 		}
 
 		@Override
-		String etag(final FileSender sender) throws IOException {
+		String etag(FileSender sender) throws IOException {
 			return Long.toHexString(sender.getLastModified());
 		}
 	}
@@ -88,7 +88,7 @@ private static abstract class PackData extends ObjectFileServlet {
 		}
 
 		@Override
-		String etag(final FileSender sender) throws IOException {
+		String etag(FileSender sender) throws IOException {
 			return sender.getTailChecksum();
 		}
 	}
@@ -111,18 +111,20 @@ static class PackIdx extends PackData {
 
 	private final String contentType;
 
-	ObjectFileServlet(final String contentType) {
+	ObjectFileServlet(String contentType) {
 		this.contentType = contentType;
 	}
 
 	abstract String etag(FileSender sender) throws IOException;
 
+	/** {@inheritDoc} */
 	@Override
 	public void doGet(final HttpServletRequest req,
 			final HttpServletResponse rsp) throws IOException {
 		serve(req, rsp, true);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected void doHead(final HttpServletRequest req,
 			final HttpServletResponse rsp) throws ServletException, IOException {
@@ -168,7 +170,7 @@ private void serve(final HttpServletRequest req,
 		}
 	}
 
-	private static File objects(final HttpServletRequest req) {
+	private static File objects(HttpServletRequest req) {
 		final Repository db = getRepository(req);
 		return ((ObjectDirectory) db.getObjectDatabase()).getDirectory();
 	}
diff --git a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/ReceivePackServlet.java b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/ReceivePackServlet.java
index 9d24bf7..a46652e 100644
--- a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/ReceivePackServlet.java
+++ b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/ReceivePackServlet.java
@@ -165,6 +165,7 @@ public void destroy() {
 		}
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void doPost(final HttpServletRequest req,
 			final HttpServletResponse rsp) throws IOException {
diff --git a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/RepositoryFilter.java b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/RepositoryFilter.java
index de09c54..020be4f 100644
--- a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/RepositoryFilter.java
+++ b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/RepositoryFilter.java
@@ -71,16 +71,19 @@
 import org.eclipse.jgit.transport.resolver.ServiceNotEnabledException;
 
 /**
- * Opens a repository named by the path info through {@link RepositoryResolver}.
+ * Open a repository named by the path info through
+ * {@link org.eclipse.jgit.transport.resolver.RepositoryResolver}.
  * <p>
- * This filter assumes it is invoked by {@link GitServlet} and is likely to not
- * work as expected if called from any other class. This filter assumes the path
- * info of the current request is a repository name which can be used by the
- * configured {@link RepositoryResolver} to open a {@link Repository} and attach
- * it to the current request.
+ * This filter assumes it is invoked by
+ * {@link org.eclipse.jgit.http.server.GitServlet} and is likely to not work as
+ * expected if called from any other class. This filter assumes the path info of
+ * the current request is a repository name which can be used by the configured
+ * {@link org.eclipse.jgit.transport.resolver.RepositoryResolver} to open a
+ * {@link org.eclipse.jgit.lib.Repository} and attach it to the current request.
  * <p>
- * This filter sets request attribute {@link ServletUtils#ATTRIBUTE_REPOSITORY}
- * when it discovers the repository, and automatically closes and removes the
+ * This filter sets request attribute
+ * {@link org.eclipse.jgit.http.server.ServletUtils#ATTRIBUTE_REPOSITORY} when
+ * it discovers the repository, and automatically closes and removes the
  * attribute when the request is complete.
  */
 public class RepositoryFilter implements Filter {
@@ -93,23 +96,27 @@ public class RepositoryFilter implements Filter {
 	 *
 	 * @param resolver
 	 *            the resolver which will be used to translate the URL name
-	 *            component to the actual {@link Repository} instance for the
+	 *            component to the actual
+	 *            {@link org.eclipse.jgit.lib.Repository} instance for the
 	 *            current web request.
 	 */
-	public RepositoryFilter(final RepositoryResolver<HttpServletRequest> resolver) {
+	public RepositoryFilter(RepositoryResolver<HttpServletRequest> resolver) {
 		this.resolver = resolver;
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	public void init(final FilterConfig config) throws ServletException {
+	public void init(FilterConfig config) throws ServletException {
 		context = config.getServletContext();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void destroy() {
 		context = null;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void doFilter(final ServletRequest request,
 			final ServletResponse response, final FilterChain chain)
@@ -133,9 +140,9 @@ public void doFilter(final ServletRequest request,
 			return;
 		}
 
-		final Repository db;
-		try {
-			db = resolver.open(req, name);
+		try (Repository db = resolver.open(req, name)) {
+			request.setAttribute(ATTRIBUTE_REPOSITORY, db);
+			chain.doFilter(request, response);
 		} catch (RepositoryNotFoundException e) {
 			sendError(req, res, SC_NOT_FOUND);
 			return;
@@ -148,13 +155,8 @@ public void doFilter(final ServletRequest request,
 		} catch (ServiceMayNotContinueException e) {
 			sendError(req, res, e.getStatusCode(), e.getMessage());
 			return;
-		}
-		try {
-			request.setAttribute(ATTRIBUTE_REPOSITORY, db);
-			chain.doFilter(request, response);
 		} finally {
 			request.removeAttribute(ATTRIBUTE_REPOSITORY);
-			db.close();
 		}
 	}
 }
diff --git a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/ServletUtils.java b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/ServletUtils.java
index c7fbaf6..9601c8c 100644
--- a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/ServletUtils.java
+++ b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/ServletUtils.java
@@ -68,7 +68,9 @@
 import org.eclipse.jgit.lib.ObjectId;
 import org.eclipse.jgit.lib.Repository;
 
-/** Common utility functions for servlets. */
+/**
+ * Common utility functions for servlets.
+ */
 public final class ServletUtils {
 	/** Request attribute which stores the {@link Repository} instance. */
 	public static final String ATTRIBUTE_REPOSITORY = "org.eclipse.jgit.Repository";
@@ -88,7 +90,7 @@ public final class ServletUtils {
 	 *             the filter runs before the servlet.
 	 * @see #ATTRIBUTE_REPOSITORY
 	 */
-	public static Repository getRepository(final ServletRequest req) {
+	public static Repository getRepository(ServletRequest req) {
 		Repository db = (Repository) req.getAttribute(ATTRIBUTE_REPOSITORY);
 		if (db == null)
 			throw new IllegalStateException(HttpServerText.get().expectedRepositoryAttribute);
@@ -108,7 +110,7 @@ public static Repository getRepository(final ServletRequest req) {
 	 * @throws IOException
 	 *             if an input or output exception occurred.
 	 */
-	public static InputStream getInputStream(final HttpServletRequest req)
+	public static InputStream getInputStream(HttpServletRequest req)
 			throws IOException {
 		InputStream in = req.getInputStream();
 		final String enc = req.getHeader(HDR_CONTENT_ENCODING);
@@ -218,12 +220,9 @@ public static void sendPlainText(final String content,
 	public static void send(byte[] content, final HttpServletRequest req,
 			final HttpServletResponse rsp) throws IOException {
 		content = sendInit(content, req, rsp);
-		final OutputStream out = rsp.getOutputStream();
-		try {
+		try (OutputStream out = rsp.getOutputStream()) {
 			out.write(content);
 			out.flush();
-		} finally {
-			out.close();
 		}
 	}
 
@@ -239,7 +238,7 @@ public static void send(byte[] content, final HttpServletRequest req,
 		return content;
 	}
 
-	static boolean acceptsGzipEncoding(final HttpServletRequest req) {
+	static boolean acceptsGzipEncoding(HttpServletRequest req) {
 		return acceptsGzipEncoding(req.getHeader(HDR_ACCEPT_ENCODING));
 	}
 
@@ -259,7 +258,7 @@ static boolean acceptsGzipEncoding(String accepts) {
 		return false;
 	}
 
-	private static byte[] compress(final byte[] raw) throws IOException {
+	private static byte[] compress(byte[] raw) throws IOException {
 		final int maxLen = raw.length + 32;
 		final ByteArrayOutputStream out = new ByteArrayOutputStream(maxLen);
 		final GZIPOutputStream gz = new GZIPOutputStream(out);
@@ -269,7 +268,7 @@ static boolean acceptsGzipEncoding(String accepts) {
 		return out.toByteArray();
 	}
 
-	private static String etag(final byte[] content) {
+	private static String etag(byte[] content) {
 		final MessageDigest md = Constants.newMessageDigest();
 		md.update(content);
 		return ObjectId.fromRaw(md.digest()).getName();
diff --git a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/SmartOutputStream.java b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/SmartOutputStream.java
index 08a5eba..ad5e8d4 100644
--- a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/SmartOutputStream.java
+++ b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/SmartOutputStream.java
@@ -83,6 +83,7 @@ class SmartOutputStream extends TemporaryBuffer {
 		this.compressStream = compressStream;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected OutputStream overflow() throws IOException {
 		startedOutput = true;
@@ -95,6 +96,7 @@ protected OutputStream overflow() throws IOException {
 		return out;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void close() throws IOException {
 		super.close();
@@ -108,11 +110,8 @@ public void close() throws IOException {
 			if (256 < out.length() && acceptsGzipEncoding(req)) {
 				TemporaryBuffer gzbuf = new TemporaryBuffer.Heap(LIMIT);
 				try {
-					GZIPOutputStream gzip = new GZIPOutputStream(gzbuf);
-					try {
+					try (GZIPOutputStream gzip = new GZIPOutputStream(gzbuf)) {
 						out.writeTo(gzip, null);
-					} finally {
-						gzip.close();
 					}
 					if (gzbuf.length() < out.length()) {
 						out = gzbuf;
@@ -129,12 +128,9 @@ public void close() throws IOException {
 			// hardcoded LIMIT constant above assures us we wouldn't store
 			// more than 2 GiB of content in memory.
 			rsp.setContentLength((int) out.length());
-			final OutputStream os = rsp.getOutputStream();
-			try {
+			try (OutputStream os = rsp.getOutputStream()) {
 				out.writeTo(os, null);
 				os.flush();
-			} finally {
-				os.close();
 			}
 		}
 	}
diff --git a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/SmartServiceInfoRefs.java b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/SmartServiceInfoRefs.java
index fe34f66..195dff9 100644
--- a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/SmartServiceInfoRefs.java
+++ b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/SmartServiceInfoRefs.java
@@ -75,21 +75,24 @@ abstract class SmartServiceInfoRefs implements Filter {
 
 	private final Filter[] filters;
 
-	SmartServiceInfoRefs(final String service, final List<Filter> filters) {
+	SmartServiceInfoRefs(String service, List<Filter> filters) {
 		this.svc = service;
 		this.filters = filters.toArray(new Filter[filters.size()]);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void init(FilterConfig config) throws ServletException {
 		// Do nothing.
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void destroy() {
 		// Do nothing.
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void doFilter(ServletRequest request, ServletResponse response,
 			FilterChain chain) throws IOException, ServletException {
@@ -130,9 +133,7 @@ private void service(ServletRequest request, ServletResponse response)
 			res.setContentType(infoRefsResultType(svc));
 
 			final PacketLineOut out = new PacketLineOut(buf);
-			out.writeString("# service=" + svc + "\n");
-			out.end();
-			advertise(req, new PacketLineOutRefAdvertiser(out));
+			respond(req, out, svc);
 			buf.close();
 		} catch (ServiceNotAuthorizedException e) {
 			res.sendError(SC_UNAUTHORIZED, e.getMessage());
@@ -146,14 +147,66 @@ private void service(ServletRequest request, ServletResponse response)
 		}
 	}
 
+	/**
+	 * Begin service.
+	 *
+	 * @param req
+	 *            request
+	 * @param db
+	 *            repository
+	 * @throws IOException
+	 * @throws ServiceNotEnabledException
+	 * @throws ServiceNotAuthorizedException
+	 */
 	protected abstract void begin(HttpServletRequest req, Repository db)
 			throws IOException, ServiceNotEnabledException,
 			ServiceNotAuthorizedException;
 
+	/**
+	 * Advertise.
+	 *
+	 * @param req
+	 *            request
+	 * @param pck
+	 * @throws IOException
+	 * @throws ServiceNotEnabledException
+	 * @throws ServiceNotAuthorizedException
+	 */
 	protected abstract void advertise(HttpServletRequest req,
 			PacketLineOutRefAdvertiser pck) throws IOException,
 			ServiceNotEnabledException, ServiceNotAuthorizedException;
 
+	/**
+	 * Writes the appropriate response to an info/refs request received by
+	 * a smart service. In protocol v0, this starts with "#
+	 * service=serviceName" followed by a flush packet, but this is not
+	 * necessarily the case in other protocol versions.
+	 * <p>
+	 * The default implementation writes "# service=serviceName" and a
+	 * flush packet, then calls {@link #advertise}. Subclasses should
+	 * override this method if they support protocol versions other than
+	 * protocol v0.
+	 *
+	 * @param req
+	 *            request
+	 * @param pckOut
+	 *            destination of response
+	 * @param serviceName
+	 *            service name to be written out in protocol v0; may or may
+	 *            not be used in other versions
+	 * @throws IOException
+	 * @throws ServiceNotEnabledException
+	 * @throws ServiceNotAuthorizedException
+	 */
+	protected void respond(HttpServletRequest req,
+			PacketLineOut pckOut, String serviceName)
+			throws IOException, ServiceNotEnabledException,
+			ServiceNotAuthorizedException {
+		pckOut.writeString("# service=" + svc + '\n'); //$NON-NLS-1$
+		pckOut.end();
+		advertise(req, new PacketLineOutRefAdvertiser(pckOut));
+	}
+
 	private class Chain implements FilterChain {
 		private int filterIdx;
 
diff --git a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/TextFileServlet.java b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/TextFileServlet.java
index 28ee17d..b2466d0 100644
--- a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/TextFileServlet.java
+++ b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/TextFileServlet.java
@@ -64,10 +64,11 @@ class TextFileServlet extends HttpServlet {
 
 	private final String fileName;
 
-	TextFileServlet(final String name) {
+	TextFileServlet(String name) {
 		this.fileName = name;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void doGet(final HttpServletRequest req,
 			final HttpServletResponse rsp) throws IOException {
@@ -79,7 +80,7 @@ public void doGet(final HttpServletRequest req,
 		}
 	}
 
-	private byte[] read(final HttpServletRequest req) throws IOException {
+	private byte[] read(HttpServletRequest req) throws IOException {
 		final File gitdir = getRepository(req).getDirectory();
 		if (gitdir == null)
 			throw new FileNotFoundException(fileName);
diff --git a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/UploadPackServlet.java b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/UploadPackServlet.java
index 97d00c1..ca6b749 100644
--- a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/UploadPackServlet.java
+++ b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/UploadPackServlet.java
@@ -76,6 +76,7 @@
 
 import org.eclipse.jgit.lib.Repository;
 import org.eclipse.jgit.transport.InternalHttpServerGlue;
+import org.eclipse.jgit.transport.PacketLineOut;
 import org.eclipse.jgit.transport.RefAdvertiser.PacketLineOutRefAdvertiser;
 import org.eclipse.jgit.transport.ServiceMayNotContinueException;
 import org.eclipse.jgit.transport.UploadPack;
@@ -117,6 +118,25 @@ protected void advertise(HttpServletRequest req,
 				up.setBiDirectionalPipe(false);
 				up.sendAdvertisedRefs(pck);
 			} finally {
+				// TODO(jonathantanmy): Move responsibility for closing the
+				// RevWalk to UploadPack, either by making it AutoCloseable
+				// or by making sendAdvertisedRefs clean up after itself.
+				up.getRevWalk().close();
+			}
+		}
+
+		@Override
+		protected void respond(HttpServletRequest req,
+				PacketLineOut pckOut, String serviceName) throws IOException,
+				ServiceNotEnabledException, ServiceNotAuthorizedException {
+			UploadPack up = (UploadPack) req.getAttribute(ATTRIBUTE_HANDLER);
+			try {
+				up.setBiDirectionalPipe(false);
+				up.sendAdvertisedRefs(new PacketLineOutRefAdvertiser(pckOut), serviceName);
+			} finally {
+				// TODO(jonathantanmy): Move responsibility for closing the
+				// RevWalk to UploadPack, either by making it AutoCloseable
+				// or by making sendAdvertisedRefs clean up after itself.
 				up.getRevWalk().close();
 			}
 		}
@@ -164,6 +184,7 @@ public void destroy() {
 		}
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void doPost(final HttpServletRequest req,
 			final HttpServletResponse rsp) throws IOException {
diff --git a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/glue/ErrorServlet.java b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/glue/ErrorServlet.java
index c0a9e0e..6f27b28 100644
--- a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/glue/ErrorServlet.java
+++ b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/glue/ErrorServlet.java
@@ -50,7 +50,9 @@
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
-/** Sends a fixed status code to the client. */
+/**
+ * Send a fixed status code to the client.
+ */
 public class ErrorServlet extends HttpServlet {
 	private static final long serialVersionUID = 1L;
 
@@ -62,10 +64,11 @@ public class ErrorServlet extends HttpServlet {
 	 * @param status
 	 *            the HTTP status code to always send.
 	 */
-	public ErrorServlet(final int status) {
+	public ErrorServlet(int status) {
 		this.status = status;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected void doGet(HttpServletRequest req, HttpServletResponse rsp)
 			throws ServletException, IOException {
diff --git a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/glue/MetaFilter.java b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/glue/MetaFilter.java
index adb6c42..43e22b3 100644
--- a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/glue/MetaFilter.java
+++ b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/glue/MetaFilter.java
@@ -87,7 +87,9 @@ public class MetaFilter implements Filter {
 
 	private volatile UrlPipeline[] pipelines;
 
-	/** Empty filter with no bindings. */
+	/**
+	 * Empty filter with no bindings.
+	 */
 	public MetaFilter() {
 		this.bindings = new ArrayList<>();
 	}
@@ -128,11 +130,13 @@ public ServletBinder serveRegex(Pattern pattern) {
 		return register(new RegexPipeline.Binder(pattern));
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void init(FilterConfig filterConfig) throws ServletException {
 		servletContext = filterConfig.getServletContext();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void destroy() {
 		if (pipelines != null) {
@@ -168,6 +172,7 @@ public int size() {
 		};
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void doFilter(ServletRequest request, ServletResponse response,
 			FilterChain chain) throws IOException, ServletException {
diff --git a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/glue/MetaServlet.java b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/glue/MetaServlet.java
index 71365c8..d8fa712 100644
--- a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/glue/MetaServlet.java
+++ b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/glue/MetaServlet.java
@@ -74,7 +74,9 @@ public class MetaServlet extends HttpServlet {
 
 	private final MetaFilter filter;
 
-	/** Empty servlet with no bindings. */
+	/**
+	 * Empty servlet with no bindings.
+	 */
 	public MetaServlet() {
 		this(new MetaFilter());
 	}
@@ -89,7 +91,11 @@ protected MetaServlet(MetaFilter delegateFilter) {
 		filter = delegateFilter;
 	}
 
-	/** @return filter this servlet delegates all routing logic to. */
+	/**
+	 * Get delegate filter
+	 *
+	 * @return filter this servlet delegates all routing logic to.
+	 */
 	protected MetaFilter getDelegateFilter() {
 		return filter;
 	}
@@ -116,6 +122,7 @@ public ServletBinder serveRegex(String expression) {
 		return filter.serveRegex(expression);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void init(ServletConfig config) throws ServletException {
 		String name = filter.getClass().getName();
@@ -123,11 +130,13 @@ public void init(ServletConfig config) throws ServletException {
 		filter.init(new NoParameterFilterConfig(name, ctx));
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void destroy() {
 		filter.destroy();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected void service(HttpServletRequest req, HttpServletResponse res)
 			throws ServletException, IOException {
diff --git a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/glue/NoParameterFilterConfig.java b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/glue/NoParameterFilterConfig.java
index 961f88e..b4b7455 100644
--- a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/glue/NoParameterFilterConfig.java
+++ b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/glue/NoParameterFilterConfig.java
@@ -59,11 +59,13 @@ final class NoParameterFilterConfig implements FilterConfig {
 		this.context = context;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public String getInitParameter(String name) {
 		return null;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public Enumeration<String> getInitParameterNames() {
 		return new Enumeration<String>() {
@@ -79,11 +81,13 @@ public String nextElement() {
 		};
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public ServletContext getServletContext() {
 		return context;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public String getFilterName() {
 		return filterName;
diff --git a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/glue/RegexGroupFilter.java b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/glue/RegexGroupFilter.java
index a402977..f26ebc3 100644
--- a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/glue/RegexGroupFilter.java
+++ b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/glue/RegexGroupFilter.java
@@ -61,34 +61,40 @@
  * Switch servlet path and path info to use another regex match group.
  * <p>
  * This filter is meant to be installed in the middle of a pipeline created by
- * {@link MetaServlet#serveRegex(String)}. The passed request's servlet path is
- * updated to be all text up to the start of the designated capture group, and
- * the path info is changed to the contents of the capture group.
- **/
+ * {@link org.eclipse.jgit.http.server.glue.MetaServlet#serveRegex(String)}. The
+ * passed request's servlet path is updated to be all text up to the start of
+ * the designated capture group, and the path info is changed to the contents of
+ * the capture group.
+ */
 public class RegexGroupFilter implements Filter {
 	private final int groupIdx;
 
 	/**
+	 * Constructor for RegexGroupFilter
+	 *
 	 * @param groupIdx
 	 *            capture group number, 1 through the number of groups.
 	 */
-	public RegexGroupFilter(final int groupIdx) {
+	public RegexGroupFilter(int groupIdx) {
 		if (groupIdx < 1)
 			throw new IllegalArgumentException(MessageFormat.format(
 					HttpServerText.get().invalidIndex, valueOf(groupIdx)));
 		this.groupIdx = groupIdx - 1;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void init(FilterConfig config) throws ServletException {
 		// Do nothing.
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void destroy() {
 		// Do nothing.
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void doFilter(final ServletRequest request,
 			final ServletResponse rsp, final FilterChain chain)
@@ -102,7 +108,7 @@ public void doFilter(final ServletRequest request,
 					valueOf(groupIdx + 1)));
 	}
 
-	private static WrappedRequest[] groupsFor(final ServletRequest r) {
+	private static WrappedRequest[] groupsFor(ServletRequest r) {
 		return (WrappedRequest[]) r.getAttribute(MetaFilter.REGEX_GROUPS);
 	}
 }
diff --git a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/glue/RegexPipeline.java b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/glue/RegexPipeline.java
index f33243b..0108105 100644
--- a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/glue/RegexPipeline.java
+++ b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/glue/RegexPipeline.java
@@ -87,11 +87,11 @@ class RegexPipeline extends UrlPipeline {
 	static class Binder extends ServletBinderImpl {
 		private final Pattern pattern;
 
-		Binder(final String p) {
+		Binder(String p) {
 			pattern = Pattern.compile(p);
 		}
 
-		Binder(final Pattern p) {
+		Binder(Pattern p) {
 			pattern = p;
 		}
 
@@ -110,7 +110,7 @@ UrlPipeline create() {
 	}
 
 	@Override
-	boolean match(final HttpServletRequest req) {
+	boolean match(HttpServletRequest req) {
 		final String pathInfo = req.getPathInfo();
 		return pathInfo != null && pattern.matcher(pathInfo).matches();
 	}
@@ -164,6 +164,7 @@ void service(HttpServletRequest req, HttpServletResponse rsp)
 		}
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public String toString() {
 		return "Pipeline[regex: " + pattern + " ]";
diff --git a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/glue/ServletBinder.java b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/glue/ServletBinder.java
index 47443f5..b2b4748 100644
--- a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/glue/ServletBinder.java
+++ b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/glue/ServletBinder.java
@@ -46,9 +46,13 @@
 import javax.servlet.Filter;
 import javax.servlet.http.HttpServlet;
 
-/** Binds a servlet to a URL. */
+/**
+ * Binds a servlet to a URL.
+ */
 public interface ServletBinder {
 	/**
+	 * Set the filter to trigger while processing the path.
+	 *
 	 * @param filter
 	 *            the filter to trigger while processing the path.
 	 * @return {@code this}.
@@ -56,6 +60,8 @@ public interface ServletBinder {
 	public ServletBinder through(Filter filter);
 
 	/**
+	 * Set the servlet to execute on this path
+	 *
 	 * @param servlet
 	 *            the servlet to execute on this path.
 	 */
diff --git a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/glue/ServletBinderImpl.java b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/glue/ServletBinderImpl.java
index 4e879a9..18650eb 100644
--- a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/glue/ServletBinderImpl.java
+++ b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/glue/ServletBinderImpl.java
@@ -61,6 +61,7 @@ abstract class ServletBinderImpl implements ServletBinder {
 		this.filters = new ArrayList<>();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public ServletBinder through(Filter filter) {
 		if (filter == null)
@@ -69,6 +70,7 @@ public ServletBinder through(Filter filter) {
 		return this;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void with(HttpServlet servlet) {
 		if (servlet == null)
@@ -78,7 +80,11 @@ public void with(HttpServlet servlet) {
 		httpServlet = servlet;
 	}
 
-	/** @return the configured servlet, or singleton returning 404 if none. */
+	/**
+	 * Get the servlet
+	 *
+	 * @return the configured servlet, or singleton returning 404 if none.
+	 */
 	protected HttpServlet getServlet() {
 		if (httpServlet != null)
 			return httpServlet;
@@ -86,7 +92,11 @@ protected HttpServlet getServlet() {
 			return new ErrorServlet(HttpServletResponse.SC_NOT_FOUND);
 	}
 
-	/** @return the configured filters; zero-length array if none. */
+	/**
+	 * Get filters
+	 *
+	 * @return the configured filters; zero-length array if none.
+	 */
 	protected Filter[] getFilters() {
 		return filters.toArray(new Filter[filters.size()]);
 	}
diff --git a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/glue/SuffixPipeline.java b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/glue/SuffixPipeline.java
index 903de63..4fd99c6 100644
--- a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/glue/SuffixPipeline.java
+++ b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/glue/SuffixPipeline.java
@@ -67,7 +67,7 @@ class SuffixPipeline extends UrlPipeline {
 	static class Binder extends ServletBinderImpl {
 		private final String suffix;
 
-		Binder(final String suffix) {
+		Binder(String suffix) {
 			this.suffix = suffix;
 		}
 
@@ -89,7 +89,7 @@ UrlPipeline create() {
 	}
 
 	@Override
-	boolean match(final HttpServletRequest req) {
+	boolean match(HttpServletRequest req) {
 		final String pathInfo = req.getPathInfo();
 		return pathInfo != null && pathInfo.endsWith(suffix);
 	}
@@ -103,6 +103,7 @@ void service(HttpServletRequest req, HttpServletResponse rsp)
 		super.service(new WrappedRequest(req, newPath, newInfo), rsp);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public String toString() {
 		return "Pipeline[ *" + suffix + " ]";
diff --git a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/glue/UrlPipeline.java b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/glue/UrlPipeline.java
index 56e4e22..c02399a 100644
--- a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/glue/UrlPipeline.java
+++ b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/glue/UrlPipeline.java
@@ -79,7 +79,7 @@ abstract class UrlPipeline {
 	/** Instance that must generate the response; never null. */
 	private final HttpServlet servlet;
 
-	UrlPipeline(final Filter[] filters, final HttpServlet servlet) {
+	UrlPipeline(Filter[] filters, HttpServlet servlet) {
 		this.filters = filters;
 		this.servlet = servlet;
 	}
@@ -99,7 +99,7 @@ abstract class UrlPipeline {
 	 * @throws ServletException
 	 *             a filter or servlet is unable to initialize.
 	 */
-	void init(final ServletContext context, final Set<Object> inited)
+	void init(ServletContext context, Set<Object> inited)
 			throws ServletException {
 		for (Filter ref : filters)
 			initFilter(ref, context, inited);
@@ -165,7 +165,7 @@ public String getServletName() {
 	 *            destroyed a second time. Filters and servlets that are first
 	 *            destroyed by this pipeline will be added to this set.
 	 */
-	void destroy(final Set<Object> destroyed) {
+	void destroy(Set<Object> destroyed) {
 		for (Filter ref : filters)
 			destroyFilter(ref, destroyed);
 		destroyServlet(servlet, destroyed);
@@ -230,7 +230,7 @@ private static class Chain implements FilterChain {
 
 		private int filterIdx;
 
-		Chain(final Filter[] filters, final HttpServlet servlet) {
+		Chain(Filter[] filters, HttpServlet servlet) {
 			this.filters = filters;
 			this.servlet = servlet;
 		}
diff --git a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/glue/WrappedRequest.java b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/glue/WrappedRequest.java
index b702c07..0964568 100644
--- a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/glue/WrappedRequest.java
+++ b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/glue/WrappedRequest.java
@@ -46,7 +46,9 @@
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletRequestWrapper;
 
-/** Overrides the path and path info. */
+/**
+ * Overrides the path and path info.
+ */
 public class WrappedRequest extends HttpServletRequestWrapper {
 	private final String path;
 
@@ -69,17 +71,20 @@ public WrappedRequest(final HttpServletRequest originalRequest,
 		this.pathInfo = pathInfo;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public String getPathTranslated() {
 		final String p = getPathInfo();
 		return p != null ? getSession().getServletContext().getRealPath(p) : null;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public String getPathInfo() {
 		return pathInfo;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public String getServletPath() {
 		return path;
diff --git a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/resolver/AsIsFileService.java b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/resolver/AsIsFileService.java
index d20fe9f..9a928b1 100644
--- a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/resolver/AsIsFileService.java
+++ b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/resolver/AsIsFileService.java
@@ -45,7 +45,6 @@
 
 import javax.servlet.http.HttpServletRequest;
 
-import org.eclipse.jgit.http.server.GitServlet;
 import org.eclipse.jgit.lib.Config;
 import org.eclipse.jgit.lib.Repository;
 import org.eclipse.jgit.transport.resolver.ServiceNotAuthorizedException;
@@ -57,8 +56,9 @@
  * Older HTTP clients which do not speak the smart HTTP variant of the Git
  * protocol fetch from a repository by directly getting its objects and pack
  * files. This class, along with the {@code http.getanyfile} per-repository
- * configuration setting, can be used by {@link GitServlet} to control whether
- * or not these older clients are permitted to read these direct files.
+ * configuration setting, can be used by
+ * {@link org.eclipse.jgit.http.server.GitServlet} to control whether or not
+ * these older clients are permitted to read these direct files.
  */
 public class AsIsFileService {
 	/** Always throws {@link ServiceNotEnabledException}. */
@@ -73,7 +73,7 @@ public void access(HttpServletRequest req, Repository db)
 	private static class ServiceConfig {
 		final boolean enabled;
 
-		ServiceConfig(final Config cfg) {
+		ServiceConfig(Config cfg) {
 			enabled = cfg.getBoolean("http", "getanyfile", true);
 		}
 	}
@@ -98,8 +98,10 @@ protected static boolean isEnabled(Repository db) {
 	 * throwing a checked exception if access should be denied.
 	 * <p>
 	 * The default implementation of this method checks {@code http.getanyfile},
-	 * throwing {@link ServiceNotEnabledException} if it was explicitly set to
-	 * {@code false}, and otherwise succeeding silently.
+	 * throwing
+	 * {@link org.eclipse.jgit.transport.resolver.ServiceNotEnabledException} if
+	 * it was explicitly set to {@code false}, and otherwise succeeding
+	 * silently.
 	 *
 	 * @param req
 	 *            current HTTP request, in case information from the request may
diff --git a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/resolver/DefaultReceivePackFactory.java b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/resolver/DefaultReceivePackFactory.java
index c0ffbb6..06a8f5e 100644
--- a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/resolver/DefaultReceivePackFactory.java
+++ b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/resolver/DefaultReceivePackFactory.java
@@ -54,12 +54,14 @@
 import org.eclipse.jgit.transport.resolver.ServiceNotEnabledException;
 
 /**
- * Create and configure {@link ReceivePack} service instance.
+ * Create and configure {@link org.eclipse.jgit.transport.ReceivePack} service
+ * instance.
  * <p>
  * Writing by receive-pack is permitted if any of the following is true:
  * <ul>
  * <li>The container has authenticated the user and set
- * {@link HttpServletRequest#getRemoteUser()} to the authenticated name.
+ * {@link javax.servlet.http.HttpServletRequest#getRemoteUser()} to the
+ * authenticated name.
  * <li>The repository configuration file has {@code http.receivepack} explicitly
  * set to true.
  * </ul>
@@ -72,14 +74,15 @@ private static class ServiceConfig {
 
 		final boolean enabled;
 
-		ServiceConfig(final Config cfg) {
+		ServiceConfig(Config cfg) {
 			set = cfg.getString("http", null, "receivepack") != null;
 			enabled = cfg.getBoolean("http", "receivepack", false);
 		}
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	public ReceivePack create(final HttpServletRequest req, final Repository db)
+	public ReceivePack create(HttpServletRequest req, Repository db)
 			throws ServiceNotEnabledException, ServiceNotAuthorizedException {
 		final ServiceConfig cfg = db.getConfig().get(ServiceConfig::new);
 		String user = req.getRemoteUser();
diff --git a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/resolver/DefaultUploadPackFactory.java b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/resolver/DefaultUploadPackFactory.java
index 642623b..a69fab0 100644
--- a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/resolver/DefaultUploadPackFactory.java
+++ b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/resolver/DefaultUploadPackFactory.java
@@ -43,6 +43,8 @@
 
 package org.eclipse.jgit.http.server.resolver;
 
+import java.util.Arrays;
+
 import javax.servlet.http.HttpServletRequest;
 
 import org.eclipse.jgit.lib.Config;
@@ -53,7 +55,8 @@
 import org.eclipse.jgit.transport.resolver.UploadPackFactory;
 
 /**
- * Create and configure {@link UploadPack} service instance.
+ * Create and configure {@link org.eclipse.jgit.transport.UploadPack} service
+ * instance.
  * <p>
  * Reading by upload-pack is permitted unless {@code http.uploadpack} is
  * explicitly set to false.
@@ -63,17 +66,25 @@ public class DefaultUploadPackFactory implements
 	private static class ServiceConfig {
 		final boolean enabled;
 
-		ServiceConfig(final Config cfg) {
+		ServiceConfig(Config cfg) {
 			enabled = cfg.getBoolean("http", "uploadpack", true);
 		}
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	public UploadPack create(final HttpServletRequest req, final Repository db)
+	public UploadPack create(HttpServletRequest req, Repository db)
 			throws ServiceNotEnabledException, ServiceNotAuthorizedException {
-		if (db.getConfig().get(ServiceConfig::new).enabled)
-			return new UploadPack(db);
-		else
+		if (db.getConfig().get(ServiceConfig::new).enabled) {
+			UploadPack up = new UploadPack(db);
+			String header = req.getHeader("Git-Protocol"); //$NON-NLS-1$
+			if (header != null) {
+				String[] params = header.split(":"); //$NON-NLS-1$
+				up.setExtraParameters(Arrays.asList(params));
+			}
+			return up;
+		} else {
 			throw new ServiceNotEnabledException();
+		}
 	}
 }
diff --git a/org.eclipse.jgit.http.test/.settings/org.eclipse.jdt.core.prefs b/org.eclipse.jgit.http.test/.settings/org.eclipse.jdt.core.prefs
index 64f7498..794592d 100644
--- a/org.eclipse.jgit.http.test/.settings/org.eclipse.jdt.core.prefs
+++ b/org.eclipse.jgit.http.test/.settings/org.eclipse.jdt.core.prefs
@@ -25,7 +25,7 @@
 org.eclipse.jdt.core.compiler.problem.discouragedReference=warning
 org.eclipse.jdt.core.compiler.problem.emptyStatement=warning
 org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
-org.eclipse.jdt.core.compiler.problem.explicitlyClosedAutoCloseable=ignore
+org.eclipse.jdt.core.compiler.problem.explicitlyClosedAutoCloseable=warning
 org.eclipse.jdt.core.compiler.problem.fallthroughCase=warning
 org.eclipse.jdt.core.compiler.problem.fatalOptionalError=disabled
 org.eclipse.jdt.core.compiler.problem.fieldHiding=warning
diff --git a/org.eclipse.jgit.http.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.http.test/META-INF/MANIFEST.MF
index 58f21b5..e7795eb 100644
--- a/org.eclipse.jgit.http.test/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.http.test/META-INF/MANIFEST.MF
@@ -1,15 +1,16 @@
 Manifest-Version: 1.0
 Bundle-ManifestVersion: 2
 Bundle-Name: %plugin_name
+Automatic-Module-Name: org.eclipse.jgit.http.test
 Bundle-SymbolicName: org.eclipse.jgit.http.test
-Bundle-Version: 4.9.3.qualifier
+Bundle-Version: 5.0.0.qualifier
 Bundle-Vendor: %provider_name
 Bundle-Localization: plugin
 Bundle-RequiredExecutionEnvironment: JavaSE-1.8
 Import-Package: javax.servlet;version="[2.5.0,3.2.0)",
  javax.servlet.http;version="[2.5.0,3.2.0)",
- org.apache.commons.codec;version="[1.6.0, 2.0.0)",
- org.apache.commons.codec.binary;version="[1.6.0, 2.0.0)",
+ org.apache.commons.codec;version="[1.6.0,2.0.0)",
+ org.apache.commons.codec.binary;version="[1.6.0,2.0.0)",
  org.eclipse.jetty.continuation;version="[9.4.5,10.0.0)",
  org.eclipse.jetty.http;version="[9.4.5,10.0.0)",
  org.eclipse.jetty.io;version="[9.4.5,10.0.0)",
@@ -24,25 +25,27 @@
  org.eclipse.jetty.util.log;version="[9.4.5,10.0.0)",
  org.eclipse.jetty.util.security;version="[9.4.5,10.0.0)",
  org.eclipse.jetty.util.thread;version="[9.4.5,10.0.0)",
- org.eclipse.jgit.errors;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.http.server;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.http.server.glue;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.http.server.resolver;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.internal;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.internal.storage.dfs;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.internal.storage.file;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.junit;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.junit.http;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.lib;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.nls;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.revwalk;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.storage.file;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.transport;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.transport.http;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.transport.http.apache;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.transport.resolver;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.util;version="[4.9.3,4.10.0)",
+ org.eclipse.jgit.errors;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.http.server;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.http.server.glue;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.http.server.resolver;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.internal;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.internal.storage.dfs;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.internal.storage.file;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.internal.storage.reftable;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.junit;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.junit.http;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.lib;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.nls;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.revwalk;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.storage.file;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.transport;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.transport.http;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.transport.http.apache;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.transport.resolver;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.util;version="[5.0.0,5.1.0)",
+ org.hamcrest;version="[1.1.0,2.0.0)",
  org.hamcrest.core;version="[1.1.0,2.0.0)",
- org.junit;version="[4.0.0,5.0.0)",
- org.junit.runner;version="[4.0.0,5.0.0)",
- org.junit.runners;version="[4.0.0,5.0.0)"
+ org.junit;version="[4.12,5.0.0)",
+ org.junit.runner;version="[4.12,5.0.0)",
+ org.junit.runners;version="[4.12,5.0.0)"
diff --git a/org.eclipse.jgit.http.test/pom.xml b/org.eclipse.jgit.http.test/pom.xml
index 72cfacd..06eb0e8 100644
--- a/org.eclipse.jgit.http.test/pom.xml
+++ b/org.eclipse.jgit.http.test/pom.xml
@@ -51,7 +51,7 @@
   <parent>
     <groupId>org.eclipse.jgit</groupId>
     <artifactId>org.eclipse.jgit-parent</artifactId>
-    <version>4.9.3-SNAPSHOT</version>
+    <version>5.0.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>org.eclipse.jgit.http.test</artifactId>
@@ -84,6 +84,13 @@
     </dependency>
 
     <dependency>
+      <groupId>org.hamcrest</groupId>
+      <artifactId>hamcrest-library</artifactId>
+      <scope>test</scope>
+      <version>[1.1.0,2.0.0)</version>
+    </dependency>
+
+    <dependency>
       <groupId>org.eclipse.jgit</groupId>
       <artifactId>org.eclipse.jgit.junit.http</artifactId>
       <version>${project.version}</version>
diff --git a/org.eclipse.jgit.http.test/src/org/eclipse/jgit/http/test/RefsUnreadableInMemoryRepository.java b/org.eclipse.jgit.http.test/src/org/eclipse/jgit/http/test/RefsUnreadableInMemoryRepository.java
index a1e41d1..78f909e 100644
--- a/org.eclipse.jgit.http.test/src/org/eclipse/jgit/http/test/RefsUnreadableInMemoryRepository.java
+++ b/org.eclipse.jgit.http.test/src/org/eclipse/jgit/http/test/RefsUnreadableInMemoryRepository.java
@@ -46,6 +46,7 @@
 
 import org.eclipse.jgit.internal.storage.dfs.DfsRepositoryDescription;
 import org.eclipse.jgit.internal.storage.dfs.InMemoryRepository;
+import org.eclipse.jgit.internal.storage.reftable.Reftable;
 import org.eclipse.jgit.lib.RefDatabase;
 
 /**
@@ -64,6 +65,7 @@ class RefsUnreadableInMemoryRepository extends InMemoryRepository {
 		failing = false;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public RefDatabase getRefDatabase() {
 		return refs;
@@ -80,14 +82,12 @@ void startFailing() {
 	}
 
 	private class RefsUnreadableRefDatabase extends MemRefDatabase {
-
 		@Override
-		protected RefCache scanAllRefs() throws IOException {
+		protected Reftable reader() throws IOException {
 			if (failing) {
 				throw new IOException("disk failed, no refs found");
-			} else {
-				return super.scanAllRefs();
 			}
+			return super.reader();
 		}
 	}
 }
diff --git a/org.eclipse.jgit.http.test/src/org/eclipse/jgit/http/test/TestRepositoryResolver.java b/org.eclipse.jgit.http.test/src/org/eclipse/jgit/http/test/TestRepositoryResolver.java
index 334e57c..c6a3e3b 100644
--- a/org.eclipse.jgit.http.test/src/org/eclipse/jgit/http/test/TestRepositoryResolver.java
+++ b/org.eclipse.jgit.http.test/src/org/eclipse/jgit/http/test/TestRepositoryResolver.java
@@ -50,7 +50,9 @@
 import org.eclipse.jgit.transport.resolver.RepositoryResolver;
 import org.eclipse.jgit.transport.resolver.ServiceNotEnabledException;
 
-/** A simple repository resolver for tests. */
+/**
+ * A simple repository resolver for tests.
+ */
 public final class TestRepositoryResolver
 		implements RepositoryResolver<HttpServletRequest> {
 
@@ -59,8 +61,8 @@ public final class TestRepositoryResolver
 	private final String repoName;
 
 	/**
-	 * Creates a new {@link TestRepositoryResolver} that resolves the given name to
-	 * the given repository.
+	 * Create a new {@link org.eclipse.jgit.http.test.TestRepositoryResolver}
+	 * that resolves the given name to the given repository.
 	 *
 	 * @param repo
 	 *            to resolve to
@@ -72,6 +74,7 @@ public TestRepositoryResolver(TestRepository<Repository> repo, String repoName)
 		this.repoName = repoName;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public Repository open(HttpServletRequest req, String name)
 			throws RepositoryNotFoundException, ServiceNotEnabledException {
diff --git a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/AdvertiseErrorTest.java b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/AdvertiseErrorTest.java
index 0e92b14..5a46967 100644
--- a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/AdvertiseErrorTest.java
+++ b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/AdvertiseErrorTest.java
@@ -135,8 +135,7 @@ public void testPush_CreateBranch() throws Exception {
 		final RevCommit Q = src.commit().add("Q", Q_txt).create();
 		final Repository db = src.getRepository();
 		final String dstName = Constants.R_HEADS + "new.branch";
-		final Transport t = Transport.open(db, remoteURI);
-		try {
+		try (Transport t = Transport.open(db, remoteURI)) {
 			final String srcExpr = Q.name();
 			final boolean forceUpdate = false;
 			final String localName = null;
@@ -154,8 +153,6 @@ public void testPush_CreateBranch() throws Exception {
 						+ "come back next year!", //
 						error.getMessage());
 			}
-		} finally {
-			t.close();
 		}
 	}
 }
diff --git a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/AsIsServiceTest.java b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/AsIsServiceTest.java
index e94a792..298bf21 100644
--- a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/AsIsServiceTest.java
+++ b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/AsIsServiceTest.java
@@ -133,7 +133,7 @@ private static final class R extends HttpServletRequestWrapper {
 
 		private final String host;
 
-		R(final String user, final String host) {
+		R(String user, String host) {
 			super(new Request(null, null) /* can't pass null, sigh */);
 			this.user = user;
 			this.host = host;
diff --git a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/DefaultReceivePackFactoryTest.java b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/DefaultReceivePackFactoryTest.java
index b24e2df..ade1e1d 100644
--- a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/DefaultReceivePackFactoryTest.java
+++ b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/DefaultReceivePackFactoryTest.java
@@ -205,7 +205,7 @@ private static final class R extends HttpServletRequestWrapper {
 
 		private final String host;
 
-		R(final String user, final String host) {
+		R(String user, String host) {
 			super(new Request(null, null) /* can't pass null, sigh */);
 			this.user = user;
 			this.host = host;
diff --git a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/DefaultUploadPackFactoryTest.java b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/DefaultUploadPackFactoryTest.java
index ce24d64..268c281 100644
--- a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/DefaultUploadPackFactoryTest.java
+++ b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/DefaultUploadPackFactoryTest.java
@@ -161,7 +161,7 @@ private static final class R extends HttpServletRequestWrapper {
 
 		private final String host;
 
-		R(final String user, final String host) {
+		R(String user, String host) {
 			super(new Request(null, null) /* can't pass null, sigh */);
 			this.user = user;
 			this.host = host;
diff --git a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/DumbClientSmartServerTest.java b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/DumbClientSmartServerTest.java
index 727f9ba..4ff81c5 100644
--- a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/DumbClientSmartServerTest.java
+++ b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/DumbClientSmartServerTest.java
@@ -140,9 +140,8 @@ public void testListRemote() throws IOException {
 		assertEquals("http", remoteURI.getScheme());
 
 		Map<String, Ref> map;
-		Transport t = Transport.open(dst, remoteURI);
+		try (Transport t = Transport.open(dst, remoteURI)) {
 		((TransportHttp) t).setUseSmartHttp(false);
-		try {
 			// I didn't make up these public interface names, I just
 			// approved them for inclusion into the code base. Sorry.
 			// --spearce
@@ -150,14 +149,9 @@ public void testListRemote() throws IOException {
 			assertTrue("isa TransportHttp", t instanceof TransportHttp);
 			assertTrue("isa HttpTransport", t instanceof HttpTransport);
 
-			FetchConnection c = t.openFetch();
-			try {
+			try (FetchConnection c = t.openFetch()) {
 				map = c.getRefsMap();
-			} finally {
-				c.close();
 			}
-		} finally {
-			t.close();
 		}
 
 		assertNotNull("have map of refs", map);
@@ -201,12 +195,9 @@ public void testInitialClone_Small() throws Exception {
 		Repository dst = createBareRepository();
 		assertFalse(dst.hasObject(A_txt));
 
-		Transport t = Transport.open(dst, remoteURI);
+		try (Transport t = Transport.open(dst, remoteURI)) {
 		((TransportHttp) t).setUseSmartHttp(false);
-		try {
 			t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
-		} finally {
-			t.close();
 		}
 
 		assertTrue(dst.hasObject(A_txt));
@@ -229,12 +220,9 @@ public void testInitialClone_Packed() throws Exception {
 		Repository dst = createBareRepository();
 		assertFalse(dst.hasObject(A_txt));
 
-		Transport t = Transport.open(dst, remoteURI);
-		((TransportHttp) t).setUseSmartHttp(false);
-		try {
+		try (Transport t = Transport.open(dst, remoteURI)) {
+			((TransportHttp) t).setUseSmartHttp(false);
 			t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
-		} finally {
-			t.close();
 		}
 
 		assertTrue(dst.hasObject(A_txt));
@@ -265,9 +253,8 @@ public void testPushNotSupported() throws Exception {
 		final RevCommit Q = src.commit().create();
 		final Repository db = src.getRepository();
 
-		Transport t = Transport.open(db, remoteURI);
-		((TransportHttp) t).setUseSmartHttp(false);
-		try {
+		try (Transport t = Transport.open(db, remoteURI)) {
+			((TransportHttp) t).setUseSmartHttp(false);
 			try {
 				t.push(NullProgressMonitor.INSTANCE, push(src, Q));
 				fail("push incorrectly completed against a smart server");
@@ -275,8 +262,6 @@ public void testPushNotSupported() throws Exception {
 				String exp = "smart HTTP push disabled";
 				assertEquals(exp, nse.getMessage());
 			}
-		} finally {
-			t.close();
 		}
 	}
 }
diff --git a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/GitServletResponseTests.java b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/GitServletResponseTests.java
index de7891c..8dce98b 100644
--- a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/GitServletResponseTests.java
+++ b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/GitServletResponseTests.java
@@ -176,7 +176,6 @@ public void testRuntimeExceptionInPreReceiveHook() throws Exception {
 		final RevCommit Q = client.commit().add("Q", Q_txt).create();
 		final Repository clientRepo = client.getRepository();
 		final String srvBranchName = Constants.R_HEADS + "new.branch";
-		Transport t;
 
 		maxPackSize = 0;
 		postHook = null;
@@ -188,8 +187,7 @@ public void onPreReceive(ReceivePack rp,
 			}
 		};
 
-		t = Transport.open(clientRepo, srvURI);
-		try {
+		try (Transport t = Transport.open(clientRepo, srvURI)) {
 			RemoteRefUpdate update = new RemoteRefUpdate(clientRepo, Q.name(),
 					srvBranchName, false, null, null);
 			try {
@@ -199,8 +197,6 @@ public void onPreReceive(ReceivePack rp,
 			} catch (Exception e) {
 				assertTrue(e instanceof TransportException);
 			}
-		} finally {
-			t.close();
 		}
 	}
 
@@ -218,7 +214,6 @@ public void testObjectCheckerException() throws Exception {
 		final RevCommit Q = client.commit().add("Q", Q_txt).create();
 		final Repository clientRepo = client.getRepository();
 		final String srvBranchName = Constants.R_HEADS + "new.branch";
-		Transport t;
 
 		maxPackSize = 0;
 		postHook = null;
@@ -231,8 +226,7 @@ public void checkCommit(AnyObjectId id, byte[] raw)
 			}
 		};
 
-		t = Transport.open(clientRepo, srvURI);
-		try {
+		try (Transport t = Transport.open(clientRepo, srvURI)) {
 			RemoteRefUpdate update = new RemoteRefUpdate(clientRepo, Q.name(),
 					srvBranchName, false, null, null);
 			try {
@@ -242,8 +236,6 @@ public void checkCommit(AnyObjectId id, byte[] raw)
 			} catch (Exception e) {
 				assertTrue(e instanceof TransportException);
 			}
-		} finally {
-			t.close();
 		}
 	}
 
@@ -266,7 +258,6 @@ public void testUnpackErrorWithSubsequentExceptionInPostReceiveHook()
 		final RevCommit Q = client.commit().add("Q", Q_txt).create();
 		final Repository clientRepo = client.getRepository();
 		final String srvBranchName = Constants.R_HEADS + "new.branch";
-		Transport t;
 
 		// this maxPackSize leads to an unPackError
 		maxPackSize = 100;
@@ -283,8 +274,7 @@ public void onPostReceive(ReceivePack rp,
 			}
 		};
 
-		t = Transport.open(clientRepo, srvURI);
-		try {
+		try (Transport t = Transport.open(clientRepo, srvURI)) {
 			RemoteRefUpdate update = new RemoteRefUpdate(clientRepo, Q.name(),
 					srvBranchName, false, null, null);
 			try {
@@ -294,8 +284,6 @@ public void onPostReceive(ReceivePack rp,
 			} catch (Exception e) {
 				assertTrue(e instanceof TooLargePackException);
 			}
-		} finally {
-			t.close();
 		}
 	}
 }
diff --git a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/HookMessageTest.java b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/HookMessageTest.java
index adb69ec..7795658 100644
--- a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/HookMessageTest.java
+++ b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/HookMessageTest.java
@@ -149,11 +149,9 @@ public void testPush_CreateBranch() throws Exception {
 		final RevCommit Q = src.commit().add("Q", Q_txt).create();
 		final Repository db = src.getRepository();
 		final String dstName = Constants.R_HEADS + "new.branch";
-		Transport t;
 		PushResult result;
 
-		t = Transport.open(db, remoteURI);
-		try {
+		try (Transport t = Transport.open(db, remoteURI)) {
 			final String srcExpr = Q.name();
 			final boolean forceUpdate = false;
 			final String localName = null;
@@ -163,8 +161,6 @@ public void testPush_CreateBranch() throws Exception {
 					srcExpr, dstName, forceUpdate, localName, oldId);
 			result = t.push(NullProgressMonitor.INSTANCE, Collections
 					.singleton(update));
-		} finally {
-			t.close();
 		}
 
 		assertTrue(remoteRepository.hasObject(Q_txt));
@@ -193,12 +189,10 @@ public void testPush_HookMessagesToOutputStream() throws Exception {
 		final RevCommit Q = src.commit().add("Q", Q_txt).create();
 		final Repository db = src.getRepository();
 		final String dstName = Constants.R_HEADS + "new.branch";
-		Transport t;
 		PushResult result;
 
-		t = Transport.open(db, remoteURI);
 		OutputStream out = new ByteArrayOutputStream();
-		try {
+		try (Transport t = Transport.open(db, remoteURI)) {
 			final String srcExpr = Q.name();
 			final boolean forceUpdate = false;
 			final String localName = null;
@@ -208,8 +202,6 @@ public void testPush_HookMessagesToOutputStream() throws Exception {
 					srcExpr, dstName, forceUpdate, localName, oldId);
 			result = t.push(NullProgressMonitor.INSTANCE,
 					Collections.singleton(update), out);
-		} finally {
-			t.close();
 		}
 
 		String expectedMessage = "message line 1\n" //
diff --git a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/HttpClientTests.java b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/HttpClientTests.java
index 6dbe0e3..ef059bf 100644
--- a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/HttpClientTests.java
+++ b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/HttpClientTests.java
@@ -43,15 +43,20 @@
 
 package org.eclipse.jgit.http.test;
 
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.theInstance;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertThat;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
 import java.io.File;
+import java.io.OutputStream;
 import java.net.URI;
+import java.net.URL;
 import java.util.List;
 
 import javax.servlet.http.HttpServletRequest;
@@ -75,9 +80,13 @@
 import org.eclipse.jgit.lib.StoredConfig;
 import org.eclipse.jgit.revwalk.RevCommit;
 import org.eclipse.jgit.transport.FetchConnection;
+import org.eclipse.jgit.transport.PacketLineIn;
+import org.eclipse.jgit.transport.PacketLineOut;
 import org.eclipse.jgit.transport.Transport;
 import org.eclipse.jgit.transport.URIish;
 import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider;
+import org.eclipse.jgit.transport.http.HttpConnection;
+import org.eclipse.jgit.transport.http.JDKHttpConnectionFactory;
 import org.eclipse.jgit.transport.resolver.RepositoryResolver;
 import org.eclipse.jgit.transport.resolver.ServiceNotEnabledException;
 import org.junit.Before;
@@ -118,7 +127,7 @@ public void setUp() throws Exception {
 		smartAuthBasicURI = toURIish(sBasic, srcName);
 	}
 
-	private ServletContextHandler dumb(final String path) {
+	private ServletContextHandler dumb(String path) {
 		final File srcGit = remoteRepository.getRepository().getDirectory();
 		final URI base = srcGit.getParentFile().toURI();
 
@@ -130,7 +139,7 @@ private ServletContextHandler dumb(final String path) {
 		return ctx;
 	}
 
-	private ServletContextHandler smart(final String path) {
+	private ServletContextHandler smart(String path) {
 		GitServlet gs = new GitServlet();
 		gs.setRepositoryResolver(new RepositoryResolver<HttpServletRequest>() {
 			@Override
@@ -151,7 +160,7 @@ public Repository open(HttpServletRequest req, String name)
 		return ctx;
 	}
 
-	private static String nameOf(final Repository db) {
+	private static String nameOf(Repository db) {
 		return db.getDirectory().getName();
 	}
 
@@ -345,4 +354,82 @@ public void testListRemoteWithoutLocalRepository() throws Exception {
 			assertNotNull(head);
 		}
 	}
+
+	@Test
+	public void testHttpClientWantsV2ButServerNotConfigured() throws Exception {
+		JDKHttpConnectionFactory f = new JDKHttpConnectionFactory();
+		String url = smartAuthNoneURI.toString() + "/info/refs?service=git-upload-pack";
+		HttpConnection c = f.create(new URL(url));
+		c.setRequestMethod("GET");
+		c.setRequestProperty("Git-Protocol", "version=2");
+		c.connect();
+		assertThat(c.getResponseCode(), is(200));
+
+		PacketLineIn pckIn = new PacketLineIn(c.getInputStream());
+
+		// Check that we get a v0 response.
+		assertThat(pckIn.readString(), is("# service=git-upload-pack"));
+		assertThat(pckIn.readString(), theInstance(PacketLineIn.END));
+		assertTrue(pckIn.readString().matches("[0-9a-f]{40} HEAD.*"));
+	}
+
+	@Test
+	public void testV2HttpFirstResponse() throws Exception {
+		remoteRepository.getRepository().getConfig().setInt(
+				"protocol", null, "version", 2);
+
+		JDKHttpConnectionFactory f = new JDKHttpConnectionFactory();
+		String url = smartAuthNoneURI.toString() + "/info/refs?service=git-upload-pack";
+		HttpConnection c = f.create(new URL(url));
+		c.setRequestMethod("GET");
+		c.setRequestProperty("Git-Protocol", "version=2");
+		c.connect();
+		assertThat(c.getResponseCode(), is(200));
+
+		PacketLineIn pckIn = new PacketLineIn(c.getInputStream());
+		assertThat(pckIn.readString(), is("version 2"));
+
+		// What remains are capabilities - ensure that all of them are
+		// non-empty strings, and that we see END at the end.
+		String s;
+		while ((s = pckIn.readString()) != PacketLineIn.END) {
+			assertTrue(!s.isEmpty());
+		}
+	}
+
+	@Test
+	public void testV2HttpSubsequentResponse() throws Exception {
+		remoteRepository.getRepository().getConfig().setInt(
+				"protocol", null, "version", 2);
+
+		JDKHttpConnectionFactory f = new JDKHttpConnectionFactory();
+		String url = smartAuthNoneURI.toString() + "/git-upload-pack";
+		HttpConnection c = f.create(new URL(url));
+		c.setRequestMethod("POST");
+		c.setRequestProperty("Content-Type", "application/x-git-upload-pack-request");
+		c.setRequestProperty("Git-Protocol", "version=2");
+		c.setDoOutput(true);
+		c.connect();
+
+		// Test ls-refs to verify that everything is connected
+		// properly. Tests for other commands go in
+		// UploadPackTest.java.
+
+		OutputStream os = c.getOutputStream();
+		PacketLineOut pckOut = new PacketLineOut(os);
+		pckOut.writeString("command=ls-refs");
+		pckOut.writeDelim();
+		pckOut.end();
+		os.close();
+
+		PacketLineIn pckIn = new PacketLineIn(c.getInputStream());
+
+		// Just check that we get what looks like a ref advertisement.
+		String s;
+		while ((s = pckIn.readString()) != PacketLineIn.END) {
+			assertTrue(s.matches("[0-9a-f]{40} [A-Za-z/]*"));
+		}
+
+		assertThat(c.getResponseCode(), is(200));
+	}
 }
diff --git a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/MeasurePackSizeTest.java b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/MeasurePackSizeTest.java
index 4c08ec2..0415bcb 100644
--- a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/MeasurePackSizeTest.java
+++ b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/MeasurePackSizeTest.java
@@ -144,11 +144,9 @@ public void testPush_packSize() throws Exception {
 		final RevCommit Q = src.commit().add("Q", Q_txt).create();
 		final Repository db = src.getRepository();
 		final String dstName = Constants.R_HEADS + "new.branch";
-		Transport t;
 		PushResult result;
 
-		t = Transport.open(db, remoteURI);
-		try {
+		try (Transport t = Transport.open(db, remoteURI)) {
 			final String srcExpr = Q.name();
 			final boolean forceUpdate = false;
 			final String localName = null;
@@ -158,8 +156,6 @@ public void testPush_packSize() throws Exception {
 					srcExpr, dstName, forceUpdate, localName, oldId);
 			result = t.push(NullProgressMonitor.INSTANCE,
 					Collections.singleton(update));
-		} finally {
-			t.close();
 		}
 		assertEquals("expected 1 RemoteUpdate", 1, result.getRemoteUpdates()
 				.size());
diff --git a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/ProtocolErrorTest.java b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/ProtocolErrorTest.java
index 87d0bad..a1baae3 100644
--- a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/ProtocolErrorTest.java
+++ b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/ProtocolErrorTest.java
@@ -149,19 +149,15 @@ public void testPush_UnpackError_TruncatedPack() throws Exception {
 			c.setRequestProperty("Content-Type",
 					GitSmartHttpTools.RECEIVE_PACK_REQUEST_TYPE);
 			c.setFixedLengthStreamingMode(reqbin.length);
-			OutputStream out = c.getOutputStream();
-			try {
+			try (OutputStream out = c.getOutputStream()) {
 				out.write(reqbin);
-			} finally {
-				out.close();
 			}
 
 			assertEquals(200, c.getResponseCode());
 			assertEquals(GitSmartHttpTools.RECEIVE_PACK_RESULT_TYPE,
 					c.getContentType());
 
-			InputStream rawin = c.getInputStream();
-			try {
+			try (InputStream rawin = c.getInputStream()) {
 				PacketLineIn pckin = new PacketLineIn(rawin);
 				assertEquals("unpack error "
 						+ JGitText.get().packfileIsTruncatedNoParam,
@@ -169,8 +165,6 @@ public void testPush_UnpackError_TruncatedPack() throws Exception {
 				assertEquals("ng refs/objects/A n/a (unpacker error)",
 						pckin.readString());
 				assertSame(PacketLineIn.END, pckin.readString());
-			} finally {
-				rawin.close();
 			}
 		} finally {
 			c.disconnect();
diff --git a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/SetAdditionalHeadersTest.java b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/SetAdditionalHeadersTest.java
index ef8daec..fbc54f3 100644
--- a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/SetAdditionalHeadersTest.java
+++ b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/SetAdditionalHeadersTest.java
@@ -107,8 +107,7 @@ public void testSetHeaders() throws IOException {
 
 		assertEquals("http", remoteURI.getScheme());
 
-		Transport t = Transport.open(dst, remoteURI);
-		try {
+		try (Transport t = Transport.open(dst, remoteURI)) {
 			assertTrue("isa TransportHttp", t instanceof TransportHttp);
 			assertTrue("isa HttpTransport", t instanceof HttpTransport);
 
@@ -117,8 +116,6 @@ public void testSetHeaders() throws IOException {
 			headers.put("AnotherKey", "someValue");
 			((TransportHttp) t).setAdditionalHeaders(headers);
 			t.openFetch();
-		} finally {
-			t.close();
 		}
 
 		List<AccessEvent> requests = getRequests();
diff --git a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/SmartClientSmartServerTest.java b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/SmartClientSmartServerTest.java
index 51b7990..42db0fe 100644
--- a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/SmartClientSmartServerTest.java
+++ b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/SmartClientSmartServerTest.java
@@ -43,6 +43,7 @@
 
 package org.eclipse.jgit.http.test;
 
+import static org.eclipse.jgit.lib.Constants.CHARSET;
 import static org.eclipse.jgit.util.HttpSupport.HDR_CONTENT_ENCODING;
 import static org.eclipse.jgit.util.HttpSupport.HDR_CONTENT_LENGTH;
 import static org.eclipse.jgit.util.HttpSupport.HDR_CONTENT_TYPE;
@@ -56,7 +57,6 @@
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.net.URISyntaxException;
-import java.nio.charset.StandardCharsets;
 import java.text.MessageFormat;
 import java.util.Arrays;
 import java.util.Collection;
@@ -266,10 +266,10 @@ public void doFilter(ServletRequest request,
 					throws IOException, ServletException {
 				final HttpServletResponse r = (HttpServletResponse) response;
 				r.setContentType("text/plain");
-				r.setCharacterEncoding("UTF-8");
-				PrintWriter w = r.getWriter();
-				w.print("OK");
-				w.close();
+				r.setCharacterEncoding(Constants.CHARACTER_ENCODING);
+				try (PrintWriter w = r.getWriter()) {
+					w.print("OK");
+				}
 			}
 
 			@Override
@@ -397,11 +397,8 @@ public void testListRemote() throws IOException {
 			assertTrue("isa TransportHttp", t instanceof TransportHttp);
 			assertTrue("isa HttpTransport", t instanceof HttpTransport);
 
-			FetchConnection c = t.openFetch();
-			try {
+			try (FetchConnection c = t.openFetch()) {
 				map = c.getRefsMap();
-			} finally {
-				c.close();
 			}
 		}
 
@@ -1084,7 +1081,7 @@ public void testInitialClone_BrokenServer() throws Exception {
 	public void testInvalidWant() throws Exception {
 		@SuppressWarnings("resource")
 		ObjectId id = new ObjectInserter.Formatter().idFor(Constants.OBJ_BLOB,
-				"testInvalidWant".getBytes(StandardCharsets.UTF_8));
+				"testInvalidWant".getBytes(CHARSET));
 
 		Repository dst = createBareRepository();
 		try (Transport t = Transport.open(dst, remoteURI);
diff --git a/org.eclipse.jgit.junit.http/.settings/org.eclipse.jdt.core.prefs b/org.eclipse.jgit.junit.http/.settings/org.eclipse.jdt.core.prefs
index 64f7498..794592d 100644
--- a/org.eclipse.jgit.junit.http/.settings/org.eclipse.jdt.core.prefs
+++ b/org.eclipse.jgit.junit.http/.settings/org.eclipse.jdt.core.prefs
@@ -25,7 +25,7 @@
 org.eclipse.jdt.core.compiler.problem.discouragedReference=warning
 org.eclipse.jdt.core.compiler.problem.emptyStatement=warning
 org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
-org.eclipse.jdt.core.compiler.problem.explicitlyClosedAutoCloseable=ignore
+org.eclipse.jdt.core.compiler.problem.explicitlyClosedAutoCloseable=warning
 org.eclipse.jdt.core.compiler.problem.fallthroughCase=warning
 org.eclipse.jdt.core.compiler.problem.fatalOptionalError=disabled
 org.eclipse.jdt.core.compiler.problem.fieldHiding=warning
diff --git a/org.eclipse.jgit.junit.http/META-INF/MANIFEST.MF b/org.eclipse.jgit.junit.http/META-INF/MANIFEST.MF
index bea731f..f3d587a 100644
--- a/org.eclipse.jgit.junit.http/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.junit.http/META-INF/MANIFEST.MF
@@ -1,8 +1,9 @@
 Manifest-Version: 1.0
 Bundle-ManifestVersion: 2
 Bundle-Name: %plugin_name
+Automatic-Module-Name: org.eclipse.jgit.junit.http
 Bundle-SymbolicName: org.eclipse.jgit.junit.http
-Bundle-Version: 4.9.3.qualifier
+Bundle-Version: 5.0.0.qualifier
 Bundle-Localization: plugin
 Bundle-Vendor: %provider_name
 Bundle-ActivationPolicy: lazy
@@ -21,16 +22,16 @@
  org.eclipse.jetty.util.log;version="[9.4.5,10.0.0)",
  org.eclipse.jetty.util.security;version="[9.4.5,10.0.0)",
  org.eclipse.jetty.util.ssl;version="[9.4.5,10.0.0)",
- org.eclipse.jgit.errors;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.http.server;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.internal.storage.file;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.junit;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.lib;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.revwalk;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.transport;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.transport.resolver;version="[4.9.3,4.10.0)",
- org.junit;version="[4.0.0,5.0.0)"
-Export-Package: org.eclipse.jgit.junit.http;version="4.9.3";
+ org.eclipse.jgit.errors;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.http.server;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.internal.storage.file;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.junit;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.lib;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.revwalk;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.transport;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.transport.resolver;version="[5.0.0,5.1.0)",
+ org.junit;version="[4.12,5.0.0)"
+Export-Package: org.eclipse.jgit.junit.http;version="5.0.0";
   uses:="org.eclipse.jgit.transport,
    org.eclipse.jgit.junit,
    javax.servlet.http,
diff --git a/org.eclipse.jgit.junit.http/pom.xml b/org.eclipse.jgit.junit.http/pom.xml
index 8e67f6e..59b2c25 100644
--- a/org.eclipse.jgit.junit.http/pom.xml
+++ b/org.eclipse.jgit.junit.http/pom.xml
@@ -50,7 +50,7 @@
   <parent>
     <groupId>org.eclipse.jgit</groupId>
     <artifactId>org.eclipse.jgit-parent</artifactId>
-    <version>4.9.3-SNAPSHOT</version>
+    <version>5.0.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>org.eclipse.jgit.junit.http</artifactId>
diff --git a/org.eclipse.jgit.junit.http/src/org/eclipse/jgit/junit/http/AccessEvent.java b/org.eclipse.jgit.junit.http/src/org/eclipse/jgit/junit/http/AccessEvent.java
index 0154a7f..82476de 100644
--- a/org.eclipse.jgit.junit.http/src/org/eclipse/jgit/junit/http/AccessEvent.java
+++ b/org.eclipse.jgit.junit.http/src/org/eclipse/jgit/junit/http/AccessEvent.java
@@ -51,7 +51,9 @@
 import org.eclipse.jetty.server.Request;
 import org.eclipse.jetty.server.Response;
 
-/** A single request made through {@link AppServer}. */
+/**
+ * A single request made through {@link org.eclipse.jgit.junit.http.AppServer}.
+ */
 public class AccessEvent {
 	private final String method;
 
@@ -65,7 +67,7 @@ public class AccessEvent {
 
 	private final Map<String, String> responseHeaders;
 
-	AccessEvent(final Request req, final Response rsp) {
+	AccessEvent(Request req, Response rsp) {
 		method = req.getMethod();
 		uri = req.getRequestURI();
 		requestHeaders = cloneHeaders(req);
@@ -75,7 +77,7 @@ public class AccessEvent {
 		responseHeaders = cloneHeaders(rsp);
 	}
 
-	private static Map<String, String> cloneHeaders(final Request req) {
+	private static Map<String, String> cloneHeaders(Request req) {
 		Map<String, String> r = new TreeMap<>();
 		Enumeration hn = req.getHeaderNames();
 		while (hn.hasMoreElements()) {
@@ -87,7 +89,7 @@ private static Map<String, String> cloneHeaders(final Request req) {
 		return Collections.unmodifiableMap(r);
 	}
 
-	private static Map<String, String> cloneHeaders(final Response rsp) {
+	private static Map<String, String> cloneHeaders(Response rsp) {
 		Map<String, String> r = new TreeMap<>();
 		Enumeration<String> hn = rsp.getHttpFields().getFieldNames();
 		while (hn.hasMoreElements()) {
@@ -105,17 +107,27 @@ private static Map<String, String> cloneHeaders(final Response rsp) {
 		return new TreeMap<>(parameterMap);
 	}
 
-	/** @return {@code "GET"} or {@code "POST"} */
+	/**
+	 * Get the <code>method</code>.
+	 *
+	 * @return {@code "GET"} or {@code "POST"}
+	 */
 	public String getMethod() {
 		return method;
 	}
 
-	/** @return path of the file on the server, e.g. {@code /git/HEAD}. */
+	/**
+	 * Get <code>path</code>.
+	 *
+	 * @return path of the file on the server, e.g. {@code /git/HEAD}.
+	 */
 	public String getPath() {
 		return uri;
 	}
 
 	/**
+	 * Get request header
+	 *
 	 * @param name
 	 *            name of the request header to read.
 	 * @return first value of the request header; null if not sent.
@@ -125,6 +137,8 @@ public String getRequestHeader(String name) {
 	}
 
 	/**
+	 * Get parameter
+	 *
 	 * @param name
 	 *            name of the request parameter to read.
 	 * @return first value of the request parameter; null if not sent.
@@ -134,17 +148,27 @@ public String getParameter(String name) {
 		return r != null && 1 <= r.length ? r[0] : null;
 	}
 
-	/** @return all parameters in the request. */
+	/**
+	 * Get <code>parameters</code>
+	 *
+	 * @return all parameters in the request.
+	 */
 	public Map<String, String[]> getParameters() {
 		return parameters;
 	}
 
-	/** @return HTTP status code of the response, e.g. 200, 403, 500. */
+	/**
+	 * Get the <code>status</code>.
+	 *
+	 * @return HTTP status code of the response, e.g. 200, 403, 500.
+	 */
 	public int getStatus() {
 		return status;
 	}
 
 	/**
+	 * Get response header.
+	 *
 	 * @param name
 	 *            name of the response header to read.
 	 * @return first value of the response header; null if not sent.
@@ -153,6 +177,7 @@ public String getResponseHeader(String name) {
 		return responseHeaders.get(name);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public String toString() {
 		StringBuilder b = new StringBuilder();
diff --git a/org.eclipse.jgit.junit.http/src/org/eclipse/jgit/junit/http/AppServer.java b/org.eclipse.jgit.junit.http/src/org/eclipse/jgit/junit/http/AppServer.java
index e257cf6..9309fe7 100644
--- a/org.eclipse.jgit.junit.http/src/org/eclipse/jgit/junit/http/AppServer.java
+++ b/org.eclipse.jgit.junit.http/src/org/eclipse/jgit/junit/http/AppServer.java
@@ -124,11 +124,16 @@ public class AppServer {
 
 	private List<File> filesToDelete = new ArrayList<>();
 
+	/**
+	 * Constructor for <code>AppServer</code>.
+	 */
 	public AppServer() {
 		this(0, -1);
 	}
 
 	/**
+	 * Constructor for <code>AppServer</code>.
+	 *
 	 * @param port
 	 *            the http port number; may be zero to allocate a port
 	 *            dynamically
@@ -139,6 +144,8 @@ public AppServer(int port) {
 	}
 
 	/**
+	 * Constructor for <code>AppServer</code>.
+	 *
 	 * @param port
 	 *            for http, may be zero to allocate a port dynamically
 	 * @param sslPort
@@ -268,6 +275,13 @@ public ServletContextHandler addContext(String path) {
 		return ctx;
 	}
 
+	/**
+	 * Configure basic authentication.
+	 *
+	 * @param ctx
+	 * @param methods
+	 * @return servlet context handler
+	 */
 	public ServletContextHandler authBasic(ServletContextHandler ctx,
 			String... methods) {
 		assertNotYetSetUp();
@@ -395,24 +409,38 @@ public URI getURI() {
 		}
 	}
 
-	/** @return the local port number the server is listening on. */
+	/**
+	 * Get port.
+	 *
+	 * @return the local port number the server is listening on.
+	 */
 	public int getPort() {
 		assertAlreadySetUp();
 		return connector.getLocalPort();
 	}
 
-	/** @return the HTTPS port or -1 if not configured. */
+	/**
+	 * Get secure port.
+	 *
+	 * @return the HTTPS port or -1 if not configured.
+	 */
 	public int getSecurePort() {
 		assertAlreadySetUp();
 		return secureConnector != null ? secureConnector.getLocalPort() : -1;
 	}
 
-	/** @return all requests since the server was started. */
+	/**
+	 * Get requests.
+	 *
+	 * @return all requests since the server was started.
+	 */
 	public List<AccessEvent> getRequests() {
 		return new ArrayList<>(log.getEvents());
 	}
 
 	/**
+	 * Get requests.
+	 *
 	 * @param base
 	 *            base URI used to access the server.
 	 * @param path
@@ -424,6 +452,8 @@ public List<AccessEvent> getRequests(URIish base, String path) {
 	}
 
 	/**
+	 * Get requests.
+	 *
 	 * @param path
 	 *            the path to locate requests for.
 	 * @return all requests which match the given path.
diff --git a/org.eclipse.jgit.junit.http/src/org/eclipse/jgit/junit/http/HttpTestCase.java b/org.eclipse.jgit.junit.http/src/org/eclipse/jgit/junit/http/HttpTestCase.java
index eabb0f2..a133ca6 100644
--- a/org.eclipse.jgit.junit.http/src/org/eclipse/jgit/junit/http/HttpTestCase.java
+++ b/org.eclipse.jgit.junit.http/src/org/eclipse/jgit/junit/http/HttpTestCase.java
@@ -67,19 +67,24 @@
 import org.eclipse.jgit.transport.RemoteRefUpdate;
 import org.eclipse.jgit.transport.URIish;
 
-/** Base class for HTTP related transport testing. */
+/**
+ * Base class for HTTP related transport testing.
+ */
 public abstract class HttpTestCase extends LocalDiskRepositoryTestCase {
+	/** Constant <code>master="Constants.R_HEADS + Constants.MASTER"</code> */
 	protected static final String master = Constants.R_HEADS + Constants.MASTER;
 
 	/** In-memory application server; subclass must start. */
 	protected AppServer server;
 
+	/** {@inheritDoc} */
 	@Override
 	public void setUp() throws Exception {
 		super.setUp();
 		server = createServer();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void tearDown() throws Exception {
 		server.tearDown();
@@ -87,29 +92,50 @@ public void tearDown() throws Exception {
 	}
 
 	/**
-	 * Creates the {@linkAppServer}.This default implementation creates a server
+	 * Create the {@link AppServer}.This default implementation creates a server
 	 * without SSLsupport listening for HTTP connections on a dynamically chosen
 	 * port, which can be gotten once the server has been started via its
-	 * {@link AppServer#getPort()} method. Subclasses may override if they need
-	 * a more specialized server.
+	 * {@link org.eclipse.jgit.junit.http.AppServer#getPort()} method.
+	 * Subclasses may override if they need a more specialized server.
 	 *
-	 * @return the {@link AppServer}.
+	 * @return the {@link org.eclipse.jgit.junit.http.AppServer}.
 	 * @since 4.9
 	 */
 	protected AppServer createServer() {
 		return new AppServer();
 	}
 
+	/**
+	 * Create TestRepository
+	 *
+	 * @return the TestRepository
+	 * @throws IOException
+	 */
 	protected TestRepository<Repository> createTestRepository()
 			throws IOException {
 		return new TestRepository<>(createBareRepository());
 	}
 
+	/**
+	 * Convert path to URIish
+	 *
+	 * @param path
+	 * @return the URIish
+	 * @throws URISyntaxException
+	 */
 	protected URIish toURIish(String path) throws URISyntaxException {
 		URI u = server.getURI().resolve(path);
 		return new URIish(u.toString());
 	}
 
+	/**
+	 * Convert a path relative to the app's context path to a URIish
+	 *
+	 * @param app
+	 * @param name
+	 * @return the warnings (if any) from the last execution
+	 * @throws URISyntaxException
+	 */
 	protected URIish toURIish(ServletContextHandler app, String name)
 			throws URISyntaxException {
 		String p = app.getContextPath();
@@ -119,18 +145,45 @@ protected URIish toURIish(ServletContextHandler app, String name)
 		return toURIish(p);
 	}
 
+	/**
+	 * Get requests.
+	 *
+	 * @return list of events
+	 */
 	protected List<AccessEvent> getRequests() {
 		return server.getRequests();
 	}
 
+	/**
+	 * Get requests.
+	 *
+	 * @param base
+	 * @param path
+	 *
+	 * @return list of events
+	 */
 	protected List<AccessEvent> getRequests(URIish base, String path) {
 		return server.getRequests(base, path);
 	}
 
+	/**
+	 * Get requests.
+	 *
+	 * @param path
+	 *
+	 * @return list of events
+	 */
 	protected List<AccessEvent> getRequests(String path) {
 		return server.getRequests(path);
 	}
 
+	/**
+	 * Run fsck
+	 *
+	 * @param db
+	 * @param tips
+	 * @throws Exception
+	 */
 	protected static void fsck(Repository db, RevObject... tips)
 			throws Exception {
 		TestRepository<? extends Repository> tr =
@@ -138,6 +191,12 @@ protected static void fsck(Repository db, RevObject... tips)
 		tr.fsck(tips);
 	}
 
+	/**
+	 * Mirror refs
+	 *
+	 * @param refs
+	 * @return set of RefSpecs
+	 */
 	protected static Set<RefSpec> mirror(String... refs) {
 		HashSet<RefSpec> r = new HashSet<>();
 		for (String name : refs) {
@@ -149,6 +208,14 @@ protected static Set<RefSpec> mirror(String... refs) {
 		return r;
 	}
 
+	/**
+	 * Push a commit
+	 *
+	 * @param from
+	 * @param q
+	 * @return collection of RefUpdates
+	 * @throws IOException
+	 */
 	protected static Collection<RemoteRefUpdate> push(TestRepository from,
 			RevCommit q) throws IOException {
 		final Repository db = from.getRepository();
@@ -163,6 +230,13 @@ protected static Collection<RemoteRefUpdate> push(TestRepository from,
 		return Collections.singleton(u);
 	}
 
+	/**
+	 * Create loose object path
+	 *
+	 * @param base
+	 * @param id
+	 * @return path of the loose object
+	 */
 	public static String loose(URIish base, AnyObjectId id) {
 		final String objectName = id.name();
 		final String d = objectName.substring(0, 2);
@@ -170,6 +244,14 @@ public static String loose(URIish base, AnyObjectId id) {
 		return join(base, "objects/" + d + "/" + f);
 	}
 
+	/**
+	 * Join a base URIish and a path
+	 *
+	 * @param base
+	 * @param path
+	 *            a relative path
+	 * @return the joined path
+	 */
 	public static String join(URIish base, String path) {
 		if (path.startsWith("/"))
 			fail("Cannot join absolute path " + path + " to URIish " + base);
@@ -180,6 +262,14 @@ public static String join(URIish base, String path) {
 		return dir + path;
 	}
 
+	/**
+	 * Rewrite a url
+	 *
+	 * @param url
+	 * @param newProtocol
+	 * @param newPort
+	 * @return the rewritten url
+	 */
 	protected static String rewriteUrl(String url, String newProtocol,
 			int newPort) {
 		String newUrl = url;
@@ -198,6 +288,14 @@ protected static String rewriteUrl(String url, String newProtocol,
 		return newUrl;
 	}
 
+	/**
+	 * Extend a path
+	 *
+	 * @param uri
+	 * @param pathComponents
+	 * @return the extended URIish
+	 * @throws URISyntaxException
+	 */
 	protected static URIish extendPath(URIish uri, String pathComponents)
 			throws URISyntaxException {
 		String raw = uri.toString();
diff --git a/org.eclipse.jgit.junit.http/src/org/eclipse/jgit/junit/http/MockServletConfig.java b/org.eclipse.jgit.junit.http/src/org/eclipse/jgit/junit/http/MockServletConfig.java
index 03c0816..895070f 100644
--- a/org.eclipse.jgit.junit.http/src/org/eclipse/jgit/junit/http/MockServletConfig.java
+++ b/org.eclipse.jgit.junit.http/src/org/eclipse/jgit/junit/http/MockServletConfig.java
@@ -51,18 +51,29 @@
 import javax.servlet.ServletConfig;
 import javax.servlet.ServletContext;
 
+/**
+ * Mock ServletConfig
+ */
 public class MockServletConfig implements ServletConfig {
 	private final Map<String, String> parameters = new HashMap<>();
 
+	/**
+	 * Set init parameter.
+	 *
+	 * @param name
+	 * @param value
+	 */
 	public void setInitParameter(String name, String value) {
 		parameters.put(name, value);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public String getInitParameter(String name) {
 		return parameters.get(name);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public Enumeration<String> getInitParameterNames() {
 		final Iterator<String> i = parameters.keySet().iterator();
@@ -79,11 +90,13 @@ public String nextElement() {
 		};
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public String getServletName() {
 		return "MOCK_SERVLET";
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public ServletContext getServletContext() {
 		return null;
diff --git a/org.eclipse.jgit.junit.http/src/org/eclipse/jgit/junit/http/RecordingLogger.java b/org.eclipse.jgit.junit.http/src/org/eclipse/jgit/junit/http/RecordingLogger.java
index 4e35ff6..a714eb0 100644
--- a/org.eclipse.jgit.junit.http/src/org/eclipse/jgit/junit/http/RecordingLogger.java
+++ b/org.eclipse.jgit.junit.http/src/org/eclipse/jgit/junit/http/RecordingLogger.java
@@ -50,18 +50,27 @@
 
 import org.eclipse.jetty.util.log.Logger;
 
-/** Logs warnings into an array for later inspection. */
+/**
+ * Log warnings into an array for later inspection.
+ */
 public class RecordingLogger implements Logger {
 	private static List<Warning> warnings = new ArrayList<>();
 
-	/** Clear the warnings, automatically done by {@link AppServer#setUp()} */
+	/**
+	 * Clear the warnings, automatically done by
+	 * {@link org.eclipse.jgit.junit.http.AppServer#setUp()}
+	 */
 	public static void clear() {
 		synchronized (warnings) {
 			warnings.clear();
 		}
 	}
 
-	/** @return the warnings (if any) from the last execution */
+	/**
+	 * Get the <code>warnings</code>.
+	 *
+	 * @return the warnings (if any) from the last execution
+	 */
 	public static List<Warning> getWarnings() {
 		synchronized (warnings) {
 			ArrayList<Warning> copy = new ArrayList<>(warnings);
@@ -86,30 +95,48 @@ public Warning(Throwable thrown) {
 
 	private final String name;
 
+	/**
+	 * Constructor for <code>RecordingLogger</code>.
+	 */
 	public RecordingLogger() {
 		this("");
 	}
 
-	public RecordingLogger(final String name) {
+	/**
+	 * Constructor for <code>RecordingLogger</code>.
+	 *
+	 * @param name
+	 */
+	public RecordingLogger(String name) {
 		this.name = name;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public Logger getLogger(@SuppressWarnings("hiding") String name) {
 		return new RecordingLogger(name);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public String getName() {
 		return name;
 	}
 
+	/**
+	 * Warning
+	 *
+	 * @param msg
+	 * @param arg0
+	 * @param arg1
+	 */
 	public void warn(String msg, Object arg0, Object arg1) {
 		synchronized (warnings) {
 			warnings.add(new Warning(MessageFormat.format(msg, arg0, arg1)));
 		}
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void warn(String msg, Throwable th) {
 		synchronized (warnings) {
@@ -117,47 +144,78 @@ public void warn(String msg, Throwable th) {
 		}
 	}
 
+	/**
+	 * Warning
+	 *
+	 * @param msg
+	 *            warning message
+	 */
 	public void warn(String msg) {
 		synchronized (warnings) {
 			warnings.add(new Warning(msg));
 		}
 	}
 
-	public void debug(@SuppressWarnings("unused") String msg,
-			          @SuppressWarnings("unused") Object arg0,
-			          @SuppressWarnings("unused") Object arg1) {
+	/**
+	 * Debug log
+	 *
+	 * @param msg
+	 * @param arg0
+	 * @param arg1
+	 */
+	public void debug(String msg, Object arg0, Object arg1) {
 		// Ignore (not relevant to test failures)
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void debug(String msg, Throwable th) {
 		// Ignore (not relevant to test failures)
 	}
 
-	public void debug(@SuppressWarnings("unused") String msg) {
+	/**
+	 * Debug log
+	 *
+	 * @param msg
+	 *            debug message
+	 */
+	public void debug(String msg) {
 		// Ignore (not relevant to test failures)
 	}
 
-	public void info(@SuppressWarnings("unused") String msg,
-			         @SuppressWarnings("unused") Object arg0,
-			         @SuppressWarnings("unused") Object arg1) {
+	/**
+	 * Info
+	 *
+	 * @param msg
+	 * @param arg0
+	 * @param arg1
+	 */
+	public void info(String msg, Object arg0, Object arg1) {
 		// Ignore (not relevant to test failures)
 	}
 
-	public void info(@SuppressWarnings("unused") String msg) {
+	/**
+	 * Info
+	 *
+	 * @param msg
+	 */
+	public void info(String msg) {
 		// Ignore (not relevant to test failures)
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public boolean isDebugEnabled() {
 		return false;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void setDebugEnabled(boolean enabled) {
 		// Ignore (not relevant to test failures)
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void warn(String msg, Object... args) {
 		synchronized (warnings) {
@@ -171,6 +229,7 @@ public void warn(String msg, Object... args) {
 		}
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void warn(Throwable thrown) {
 		synchronized (warnings) {
@@ -178,36 +237,43 @@ public void warn(Throwable thrown) {
 		}
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void info(String msg, Object... args) {
 		// Ignore (not relevant to test failures)
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void info(Throwable thrown) {
 		// Ignore (not relevant to test failures)
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void info(String msg, Throwable thrown) {
 		// Ignore (not relevant to test failures)
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void debug(String msg, Object... args) {
 		// Ignore (not relevant to test failures)
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void debug(Throwable thrown) {
 		// Ignore (not relevant to test failures)
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void ignore(Throwable arg0) {
 		// Ignore (not relevant to test failures)
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void debug(String msg, long value) {
 		// Ignore (not relevant to test failures)
diff --git a/org.eclipse.jgit.junit.http/src/org/eclipse/jgit/junit/http/SimpleHttpServer.java b/org.eclipse.jgit.junit.http/src/org/eclipse/jgit/junit/http/SimpleHttpServer.java
index 0ea0721..245b510 100644
--- a/org.eclipse.jgit.junit.http/src/org/eclipse/jgit/junit/http/SimpleHttpServer.java
+++ b/org.eclipse.jgit.junit.http/src/org/eclipse/jgit/junit/http/SimpleHttpServer.java
@@ -71,15 +71,31 @@ public class SimpleHttpServer {
 
 	private URIish secureUri;
 
+	/**
+	 * Constructor for <code>SimpleHttpServer</code>.
+	 *
+	 * @param repository
+	 */
 	public SimpleHttpServer(Repository repository) {
 		this(repository, false);
 	}
 
+	/**
+	 * Constructor for <code>SimpleHttpServer</code>.
+	 *
+	 * @param repository
+	 * @param withSsl
+	 */
 	public SimpleHttpServer(Repository repository, boolean withSsl) {
 		this.db = repository;
 		server = new AppServer(0, withSsl ? 0 : -1);
 	}
 
+	/**
+	 * Start the server
+	 *
+	 * @throws Exception
+	 */
 	public void start() throws Exception {
 		ServletContextHandler sBasic = server.authBasic(smart("/sbasic"));
 		server.setUp();
@@ -91,19 +107,34 @@ public void start() throws Exception {
 		}
 	}
 
+	/**
+	 * Stop the server.
+	 *
+	 * @throws Exception
+	 */
 	public void stop() throws Exception {
 		server.tearDown();
 	}
 
+	/**
+	 * Get the <code>uri</code>.
+	 *
+	 * @return the uri
+	 */
 	public URIish getUri() {
 		return uri;
 	}
 
+	/**
+	 * Get the <code>secureUri</code>.
+	 *
+	 * @return the secure uri
+	 */
 	public URIish getSecureUri() {
 		return secureUri;
 	}
 
-	private ServletContextHandler smart(final String path) {
+	private ServletContextHandler smart(String path) {
 		GitServlet gs = new GitServlet();
 		gs.setRepositoryResolver(new RepositoryResolver<HttpServletRequest>() {
 			@Override
@@ -123,7 +154,7 @@ public Repository open(HttpServletRequest req, String name)
 		return ctx;
 	}
 
-	private static String nameOf(final Repository db) {
+	private static String nameOf(Repository db) {
 		return db.getDirectory().getName();
 	}
 
diff --git a/org.eclipse.jgit.junit.http/src/org/eclipse/jgit/junit/http/TestRequestLog.java b/org.eclipse.jgit.junit.http/src/org/eclipse/jgit/junit/http/TestRequestLog.java
index c218c07..c1abe37 100644
--- a/org.eclipse.jgit.junit.http/src/org/eclipse/jgit/junit/http/TestRequestLog.java
+++ b/org.eclipse.jgit.junit.http/src/org/eclipse/jgit/junit/http/TestRequestLog.java
@@ -59,78 +59,80 @@
 
 /** Logs request made through {@link AppServer}. */
 class TestRequestLog extends HandlerWrapper {
-  private static final int MAX = 16;
+	private static final int MAX = 16;
 
-  private final List<AccessEvent> events = new ArrayList<>();
+	private final List<AccessEvent> events = new ArrayList<>();
 
-  private final Semaphore active = new Semaphore(MAX);
+	private final Semaphore active = new Semaphore(MAX, true);
 
-  /** Reset the log back to its original empty state. */
-  void clear() {
-    try {
-      for (;;) {
-        try {
-          active.acquire(MAX);
-          break;
-        } catch (InterruptedException e) {
-          continue;
-        }
-      }
+	/** Reset the log back to its original empty state. */
+	void clear() {
+		try {
+			for (;;) {
+				try {
+					active.acquire(MAX);
+					break;
+				} catch (InterruptedException e) {
+					continue;
+				}
+			}
 
-      synchronized (events) {
-        events.clear();
-      }
-    } finally {
-      active.release(MAX);
-    }
-  }
+			synchronized (events) {
+				events.clear();
+			}
+		} finally {
+			active.release(MAX);
+		}
+	}
 
-  /** @return all of the events made since the last clear. */
-  List<AccessEvent> getEvents() {
-    try {
-      for (;;) {
-        try {
-          active.acquire(MAX);
-          break;
-        } catch (InterruptedException e) {
-          continue;
-        }
-      }
+	/** @return all of the events made since the last clear. */
+	List<AccessEvent> getEvents() {
+		try {
+			for (;;) {
+				try {
+					active.acquire(MAX);
+					break;
+				} catch (InterruptedException e) {
+					continue;
+				}
+			}
 
-      synchronized (events) {
-        return events;
-      }
-    } finally {
-      active.release(MAX);
-    }
-  }
+			synchronized (events) {
+				return events;
+			}
+		} finally {
+			active.release(MAX);
+		}
+	}
 
-  @Override
-  public void handle(String target, Request baseRequest, HttpServletRequest request,
-      HttpServletResponse response) throws IOException, ServletException {
-    try {
-      for (;;) {
-        try {
-          active.acquire();
-          break;
-        } catch (InterruptedException e) {
-          continue;
-        }
-      }
+	/** {@inheritDoc} */
+	@Override
+	public void handle(String target, Request baseRequest,
+			HttpServletRequest request, HttpServletResponse response)
+			throws IOException, ServletException {
+		try {
+			for (;;) {
+				try {
+					active.acquire();
+					break;
+				} catch (InterruptedException e) {
+					continue;
+				}
+			}
 
-      super.handle(target, baseRequest, request, response);
+			super.handle(target, baseRequest, request, response);
 
-      if (DispatcherType.REQUEST.equals(baseRequest.getDispatcherType()))
-        log((Request) request, (Response) response);
+			if (DispatcherType.REQUEST.equals(baseRequest.getDispatcherType()))
+				log((Request) request, (Response) response);
 
-    } finally {
-      active.release();
-    }
-  }
+		} finally {
+			active.release();
+		}
+	}
 
-  private void log(Request request, Response response) {
-    synchronized (events) {
-      events.add(new AccessEvent(request, response));
-    }
-  }
+	private void log(Request request, Response response) {
+		synchronized (events) {
+			events.add(new AccessEvent(request, response));
+		}
+	}
 }
diff --git a/org.eclipse.jgit.junit/.settings/.api_filters b/org.eclipse.jgit.junit/.settings/.api_filters
new file mode 100644
index 0000000..e5de787
--- /dev/null
+++ b/org.eclipse.jgit.junit/.settings/.api_filters
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<component id="org.eclipse.jgit.junit" version="2">
+    <resource path="src/org/eclipse/jgit/junit/LocalDiskRepositoryTestCase.java" type="org.eclipse.jgit.junit.LocalDiskRepositoryTestCase">
+        <filter comment="Don't care about non-API in tests." id="643842064">
+            <message_arguments>
+                <message_argument value="FileRepository"/>
+                <message_argument value="LocalDiskRepositoryTestCase"/>
+                <message_argument value="createBareRepository()"/>
+            </message_arguments>
+        </filter>
+        <filter comment="Don't care about non-API in tests." id="643842064">
+            <message_arguments>
+                <message_argument value="FileRepository"/>
+                <message_argument value="LocalDiskRepositoryTestCase"/>
+                <message_argument value="createRepository(boolean, boolean)"/>
+            </message_arguments>
+        </filter>
+        <filter comment="Don't care about non-API in tests." id="643842064">
+            <message_arguments>
+                <message_argument value="FileRepository"/>
+                <message_argument value="LocalDiskRepositoryTestCase"/>
+                <message_argument value="createWorkRepository()"/>
+            </message_arguments>
+        </filter>
+    </resource>
+    <resource path="src/org/eclipse/jgit/junit/RepositoryTestCase.java" type="org.eclipse.jgit.junit.RepositoryTestCase">
+        <filter comment="Don't care about non-API in tests." id="627060751">
+            <message_arguments>
+                <message_argument value="FileRepository"/>
+                <message_argument value="RepositoryTestCase"/>
+                <message_argument value="db"/>
+            </message_arguments>
+        </filter>
+    </resource>
+</component>
diff --git a/org.eclipse.jgit.junit/.settings/org.eclipse.jdt.core.prefs b/org.eclipse.jgit.junit/.settings/org.eclipse.jdt.core.prefs
index 64f7498..794592d 100644
--- a/org.eclipse.jgit.junit/.settings/org.eclipse.jdt.core.prefs
+++ b/org.eclipse.jgit.junit/.settings/org.eclipse.jdt.core.prefs
@@ -25,7 +25,7 @@
 org.eclipse.jdt.core.compiler.problem.discouragedReference=warning
 org.eclipse.jdt.core.compiler.problem.emptyStatement=warning
 org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
-org.eclipse.jdt.core.compiler.problem.explicitlyClosedAutoCloseable=ignore
+org.eclipse.jdt.core.compiler.problem.explicitlyClosedAutoCloseable=warning
 org.eclipse.jdt.core.compiler.problem.fallthroughCase=warning
 org.eclipse.jdt.core.compiler.problem.fatalOptionalError=disabled
 org.eclipse.jdt.core.compiler.problem.fieldHiding=warning
diff --git a/org.eclipse.jgit.junit/META-INF/MANIFEST.MF b/org.eclipse.jgit.junit/META-INF/MANIFEST.MF
index ecfe7ac..81e90e0 100644
--- a/org.eclipse.jgit.junit/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.junit/META-INF/MANIFEST.MF
@@ -1,32 +1,33 @@
 Manifest-Version: 1.0
 Bundle-ManifestVersion: 2
 Bundle-Name: %plugin_name
+Automatic-Module-Name: org.eclipse.jgit.junit
 Bundle-SymbolicName: org.eclipse.jgit.junit
-Bundle-Version: 4.9.3.qualifier
+Bundle-Version: 5.0.0.qualifier
 Bundle-Localization: plugin
 Bundle-Vendor: %provider_name
 Bundle-ActivationPolicy: lazy
 Bundle-RequiredExecutionEnvironment: JavaSE-1.8
-Import-Package: org.eclipse.jgit.api;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.api.errors;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.dircache;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.errors;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.internal.storage.file;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.internal.storage.pack;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.lib;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.merge;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.revwalk;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.storage.file;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.treewalk;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.treewalk.filter;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.util;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.util.io;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.util.time;version="[4.9.3,4.10.0)",
- org.junit;version="[4.0.0,5.0.0)",
- org.junit.rules;version="[4.9.0,5.0.0)",
- org.junit.runner;version="[4.0.0,5.0.0)",
- org.junit.runners.model;version="[4.5.0,5.0.0)"
-Export-Package: org.eclipse.jgit.junit;version="4.9.3";
+Import-Package: org.eclipse.jgit.api;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.api.errors;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.dircache;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.errors;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.internal.storage.file;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.internal.storage.pack;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.lib;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.merge;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.revwalk;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.storage.file;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.treewalk;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.treewalk.filter;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.util;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.util.io;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.util.time;version="[5.0.0,5.1.0)",
+ org.junit;version="[4.12,5.0.0)",
+ org.junit.rules;version="[4.12,5.0.0)",
+ org.junit.runner;version="[4.12,5.0.0)",
+ org.junit.runners.model;version="[4.12,5.0.0)"
+Export-Package: org.eclipse.jgit.junit;version="5.0.0";
   uses:="org.eclipse.jgit.dircache,
    org.eclipse.jgit.lib,
    org.eclipse.jgit.revwalk,
@@ -35,4 +36,4 @@
    org.eclipse.jgit.util,
    org.eclipse.jgit.storage.file,
    org.eclipse.jgit.api",
- org.eclipse.jgit.junit.time;version="4.9.3"
+ org.eclipse.jgit.junit.time;version="5.0.0"
diff --git a/org.eclipse.jgit.junit/pom.xml b/org.eclipse.jgit.junit/pom.xml
index ba36d9b..1c1fa04 100644
--- a/org.eclipse.jgit.junit/pom.xml
+++ b/org.eclipse.jgit.junit/pom.xml
@@ -52,7 +52,7 @@
   <parent>
     <groupId>org.eclipse.jgit</groupId>
     <artifactId>org.eclipse.jgit-parent</artifactId>
-    <version>4.9.3-SNAPSHOT</version>
+    <version>5.0.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>org.eclipse.jgit.junit</artifactId>
diff --git a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/Assert.java b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/Assert.java
index 40a05b4..57b33e1 100644
--- a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/Assert.java
+++ b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/Assert.java
@@ -44,12 +44,33 @@
 
 import static java.lang.Boolean.valueOf;
 
+/**
+ * Assertion class
+ */
 public class Assert {
 
+	/**
+	 * Assert booleans are equal
+	 *
+	 * @param expect
+	 *            expected value
+	 * @param actual
+	 *            actual value
+	 */
 	public static void assertEquals(boolean expect, boolean actual) {
 		org.junit.Assert.assertEquals(valueOf(expect), valueOf(actual));
 	}
 
+	/**
+	 * Assert booleans are equal
+	 *
+	 * @param message
+	 *            message
+	 * @param expect
+	 *            expected value
+	 * @param actual
+	 *            actual value
+	 */
 	public static void assertEquals(String message, boolean expect,
 			boolean actual) {
 		org.junit.Assert
diff --git a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/JGitTestUtil.java b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/JGitTestUtil.java
index 5bf61f0..a102da1 100644
--- a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/JGitTestUtil.java
+++ b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/JGitTestUtil.java
@@ -45,6 +45,8 @@
 
 package org.eclipse.jgit.junit;
 
+import static org.eclipse.jgit.lib.Constants.CHARSET;
+
 import java.io.File;
 import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
@@ -64,13 +66,22 @@
 import org.junit.Assert;
 import org.junit.Test;
 
+/**
+ * Abstract test util class
+ */
 public abstract class JGitTestUtil {
+	/** Constant <code>CLASSPATH_TO_RESOURCES="org/eclipse/jgit/test/resources/"</code> */
 	public static final String CLASSPATH_TO_RESOURCES = "org/eclipse/jgit/test/resources/";
 
 	private JGitTestUtil() {
 		throw new UnsupportedOperationException();
 	}
 
+	/**
+	 * Get name of current test by inspecting stack trace
+	 *
+	 * @return the name
+	 */
 	public static String getName() {
 		GatherStackTrace stack;
 		try {
@@ -109,6 +120,14 @@ private static class GatherStackTrace extends Exception {
 		// Thrown above to collect the stack frame.
 	}
 
+	/**
+	 * Assert byte arrays are equal
+	 *
+	 * @param exp
+	 *            expected value
+	 * @param act
+	 *            actual value
+	 */
 	public static void assertEquals(byte[] exp, byte[] act) {
 		Assert.assertEquals(s(exp), s(act));
 	}
@@ -117,7 +136,13 @@ private static String s(byte[] raw) {
 		return RawParseUtils.decode(raw);
 	}
 
-	public static File getTestResourceFile(final String fileName) {
+	/**
+	 * Get test resource file.
+	 *
+	 * @param fileName
+	 * @return the test resource file
+	 */
+	public static File getTestResourceFile(String fileName) {
 		if (fileName == null || fileName.length() <= 0) {
 			return null;
 		}
@@ -145,23 +170,23 @@ public static File getTestResourceFile(final String fileName) {
 		}
 	}
 
+	/**
+	 * Copy test resource.
+	 *
+	 * @param name
+	 * @param dest
+	 * @throws IOException
+	 */
 	public static void copyTestResource(String name, File dest)
 			throws IOException {
 		URL url = cl().getResource(CLASSPATH_TO_RESOURCES + name);
 		if (url == null)
 			throw new FileNotFoundException(name);
-		InputStream in = url.openStream();
-		try {
-			FileOutputStream out = new FileOutputStream(dest);
-			try {
-				byte[] buf = new byte[4096];
-				for (int n; (n = in.read(buf)) > 0;)
-					out.write(buf, 0, n);
-			} finally {
-				out.close();
-			}
-		} finally {
-			in.close();
+		try (InputStream in = url.openStream();
+				FileOutputStream out = new FileOutputStream(dest)) {
+			byte[] buf = new byte[4096];
+			for (int n; (n = in.read(buf)) > 0;)
+				out.write(buf, 0, n);
 		}
 	}
 
@@ -169,6 +194,15 @@ private static ClassLoader cl() {
 		return JGitTestUtil.class.getClassLoader();
 	}
 
+	/**
+	 * Write a trash file.
+	 *
+	 * @param db
+	 * @param name
+	 * @param data
+	 * @return the trash file
+	 * @throws IOException
+	 */
 	public static File writeTrashFile(final Repository db,
 			final String name, final String data) throws IOException {
 		File path = new File(db.getWorkTree(), name);
@@ -176,6 +210,16 @@ public static File writeTrashFile(final Repository db,
 		return path;
 	}
 
+	/**
+	 * Write a trash file.
+	 *
+	 * @param db
+	 * @param subdir
+	 * @param name
+	 * @param data
+	 * @return the trash file
+	 * @throws IOException
+	 */
 	public static File writeTrashFile(final Repository db,
 			final String subdir,
 			final String name, final String data) throws IOException {
@@ -198,14 +242,12 @@ public static File writeTrashFile(final Repository db,
 	 * @throws IOException
 	 *             the file could not be written.
 	 */
-	public static void write(final File f, final String body)
+	public static void write(File f, String body)
 			throws IOException {
 		FileUtils.mkdirs(f.getParentFile(), true);
-		Writer w = new OutputStreamWriter(new FileOutputStream(f), "UTF-8");
-		try {
+		try (Writer w = new OutputStreamWriter(new FileOutputStream(f),
+				CHARSET)) {
 			w.write(body);
-		} finally {
-			w.close();
 		}
 	}
 
@@ -219,22 +261,45 @@ public static void write(final File f, final String body)
 	 * @throws IOException
 	 *             the file does not exist, or could not be read.
 	 */
-	public static String read(final File file) throws IOException {
+	public static String read(File file) throws IOException {
 		final byte[] body = IO.readFully(file);
-		return new String(body, 0, body.length, "UTF-8");
+		return new String(body, 0, body.length, CHARSET);
 	}
 
-	public static String read(final Repository db, final String name)
+	/**
+	 * Read a file's content
+	 *
+	 * @param db
+	 * @param name
+	 * @return the content of the file
+	 * @throws IOException
+	 */
+	public static String read(Repository db, String name)
 			throws IOException {
 		File file = new File(db.getWorkTree(), name);
 		return read(file);
 	}
 
-	public static boolean check(final Repository db, final String name) {
+	/**
+	 * Check if file exists
+	 *
+	 * @param db
+	 * @param name
+	 *            name of the file
+	 * @return {@code true} if the file exists
+	 */
+	public static boolean check(Repository db, String name) {
 		File file = new File(db.getWorkTree(), name);
 		return file.exists();
 	}
 
+	/**
+	 * Delete a trash file.
+	 *
+	 * @param db
+	 * @param name
+	 * @throws IOException
+	 */
 	public static void deleteTrashFile(final Repository db,
 			final String name) throws IOException {
 		File path = new File(db.getWorkTree(), name);
@@ -242,6 +307,8 @@ public static void deleteTrashFile(final Repository db,
 	}
 
 	/**
+	 * Write a symbolic link
+	 *
 	 * @param db
 	 *            the repository
 	 * @param link
diff --git a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/LocalDiskRepositoryTestCase.java b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/LocalDiskRepositoryTestCase.java
index 6ace9fc..6cdd0eb 100644
--- a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/LocalDiskRepositoryTestCase.java
+++ b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/LocalDiskRepositoryTestCase.java
@@ -45,6 +45,7 @@
 
 package org.eclipse.jgit.junit;
 
+import static org.eclipse.jgit.lib.Constants.CHARSET;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.fail;
 
@@ -82,8 +83,9 @@
  * A temporary directory is created for each test, allowing each test to use a
  * fresh environment. The temporary directory is cleaned up after the test ends.
  * <p>
- * Callers should not use {@link RepositoryCache} from within these tests as it
- * may wedge file descriptors open past the end of the test.
+ * Callers should not use {@link org.eclipse.jgit.lib.RepositoryCache} from
+ * within these tests as it may wedge file descriptors open past the end of the
+ * test.
  * <p>
  * A system property {@code jgit.junit.usemmap} defines whether memory mapping
  * is used. Memory mapping has an effect on the file system, in that memory
@@ -112,6 +114,11 @@ public abstract class LocalDiskRepositoryTestCase {
 	private final Set<Repository> toClose = new HashSet<>();
 	private File tmp;
 
+	/**
+	 * Setup test
+	 *
+	 * @throws Exception
+	 */
 	@Before
 	public void setUp() throws Exception {
 		tmp = File.createTempFile("jgit_test_", "_tmp");
@@ -142,10 +149,20 @@ public void setUp() throws Exception {
 		c.install();
 	}
 
+	/**
+	 * Get temporary directory.
+	 *
+	 * @return the temporary directory
+	 */
 	protected File getTemporaryDirectory() {
 		return tmp.getAbsoluteFile();
 	}
 
+	/**
+	 * Get list of ceiling directories
+	 *
+	 * @return list of ceiling directories
+	 */
 	protected List<File> getCeilings() {
 		return Collections.singletonList(getTemporaryDirectory());
 	}
@@ -164,6 +181,11 @@ private static String makePath(List<?> objects) {
 		return stringBuilder.toString();
 	}
 
+	/**
+	 * Tear down the test
+	 *
+	 * @throws Exception
+	 */
 	@After
 	public void tearDown() throws Exception {
 		RepositoryCache.clear();
@@ -185,7 +207,9 @@ public void tearDown() throws Exception {
 		SystemReader.setInstance(null);
 	}
 
-	/** Increment the {@link #author} and {@link #committer} times. */
+	/**
+	 * Increment the {@link #author} and {@link #committer} times.
+	 */
 	protected void tick() {
 		mockSystemReader.tick(5 * 60);
 		final long now = mockSystemReader.getCurrentTime();
@@ -201,7 +225,7 @@ protected void tick() {
 	 * @param dir
 	 *            the recursively directory to delete, if present.
 	 */
-	protected void recursiveDelete(final File dir) {
+	protected void recursiveDelete(File dir) {
 		recursiveDelete(dir, false, true);
 	}
 
@@ -239,16 +263,22 @@ private static void reportDeleteFailure(boolean failOnError, File e) {
 			System.err.println(msg);
 	}
 
+	/** Constant <code>MOD_TIME=1</code> */
 	public static final int MOD_TIME = 1;
 
+	/** Constant <code>SMUDGE=2</code> */
 	public static final int SMUDGE = 2;
 
+	/** Constant <code>LENGTH=4</code> */
 	public static final int LENGTH = 4;
 
+	/** Constant <code>CONTENT_ID=8</code> */
 	public static final int CONTENT_ID = 8;
 
+	/** Constant <code>CONTENT=16</code> */
 	public static final int CONTENT = 16;
 
+	/** Constant <code>ASSUME_UNCHANGED=32</code> */
 	public static final int ASSUME_UNCHANGED = 32;
 
 	/**
@@ -279,7 +309,6 @@ private static void reportDeleteFailure(boolean failOnError, File e) {
 	 *
 	 * @param repo
 	 *            the repository the index state should be determined for
-	 *
 	 * @param includedOptions
 	 *            a bitmask constructed out of the constants {@link #MOD_TIME},
 	 *            {@link #SMUDGE}, {@link #LENGTH}, {@link #CONTENT_ID} and
@@ -323,7 +352,7 @@ public static String indexState(Repository repo, int includedOptions)
 			if (0 != (includedOptions & CONTENT)) {
 				sb.append(", content:"
 						+ new String(repo.open(entry.getObjectId(),
-						Constants.OBJ_BLOB).getCachedBytes(), "UTF-8"));
+						Constants.OBJ_BLOB).getCachedBytes(), CHARSET));
 			}
 			if (0 != (includedOptions & ASSUME_UNCHANGED))
 				sb.append(", assume-unchanged:"
@@ -511,7 +540,7 @@ private static void putPersonIdent(final Map<String, String> env,
 	 * @throws IOException
 	 *             the file could not be written.
 	 */
-	protected File write(final String body) throws IOException {
+	protected File write(String body) throws IOException {
 		final File f = File.createTempFile("temp", "txt", tmp);
 		try {
 			write(f, body);
@@ -542,15 +571,23 @@ protected File write(final String body) throws IOException {
 	 * @throws IOException
 	 *             the file could not be written.
 	 */
-	protected void write(final File f, final String body) throws IOException {
+	protected void write(File f, String body) throws IOException {
 		JGitTestUtil.write(f, body);
 	}
 
-	protected String read(final File f) throws IOException {
+	/**
+	 * Read a file's content
+	 *
+	 * @param f
+	 *            the file
+	 * @return the content of the file
+	 * @throws IOException
+	 */
+	protected String read(File f) throws IOException {
 		return JGitTestUtil.read(f);
 	}
 
-	private static String[] toEnvArray(final Map<String, String> env) {
+	private static String[] toEnvArray(Map<String, String> env) {
 		final String[] envp = new String[env.size()];
 		int i = 0;
 		for (Map.Entry<String, String> e : env.entrySet())
diff --git a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/MockSystemReader.java b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/MockSystemReader.java
index 68482c6..d3d7d68 100644
--- a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/MockSystemReader.java
+++ b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/MockSystemReader.java
@@ -67,7 +67,7 @@
 import org.eclipse.jgit.util.time.ProposedTimestamp;
 
 /**
- * Mock {@link SystemReader} for tests.
+ * Mock {@link org.eclipse.jgit.util.SystemReader} for tests.
  */
 public class MockSystemReader extends SystemReader {
 	private final class MockConfig extends FileBasedConfig {
@@ -94,6 +94,9 @@ public boolean isOutdated() {
 
 	FileBasedConfig systemGitConfig;
 
+	/**
+	 * Constructor for <code>MockSystemReader</code>
+	 */
 	public MockSystemReader() {
 		init(Constants.OS_USER_NAME_KEY);
 		init(Constants.GIT_AUTHOR_NAME_KEY);
@@ -106,50 +109,66 @@ public MockSystemReader() {
 		setCurrentPlatform();
 	}
 
-	private void init(final String n) {
+	private void init(String n) {
 		setProperty(n, n);
 	}
 
+	/**
+	 * Clear properties
+	 */
 	public void clearProperties() {
 		values.clear();
 	}
 
+	/**
+	 * Set a property
+	 *
+	 * @param key
+	 * @param value
+	 */
 	public void setProperty(String key, String value) {
 		values.put(key, value);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public String getenv(String variable) {
 		return values.get(variable);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public String getProperty(String key) {
 		return values.get(key);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public FileBasedConfig openUserConfig(Config parent, FS fs) {
 		assert parent == null || parent == systemGitConfig;
 		return userGitConfig;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public FileBasedConfig openSystemConfig(Config parent, FS fs) {
 		assert parent == null;
 		return systemGitConfig;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public String getHostname() {
 		return "fake.host.example.com";
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public long getCurrentTime() {
 		return now;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public MonotonicClock getClock() {
 		return new MonotonicClock() {
@@ -178,30 +197,35 @@ public void blockUntil(Duration maxWait) {
 	 *            number of seconds to add to the current time.
 	 * @since 4.2
 	 */
-	public void tick(final int secDelta) {
+	public void tick(int secDelta) {
 		now += secDelta * 1000L;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public int getTimezone(long when) {
 		return getTimeZone().getOffset(when) / (60 * 1000);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public TimeZone getTimeZone() {
 		return TimeZone.getTimeZone("GMT-03:30");
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public Locale getLocale() {
 		return Locale.US;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public SimpleDateFormat getSimpleDateFormat(String pattern) {
 		return new SimpleDateFormat(pattern, getLocale());
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public DateFormat getDateTimeInstance(int dateStyle, int timeStyle) {
 		return DateFormat
diff --git a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/Repeat.java b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/Repeat.java
index a3c869f..08220ce 100644
--- a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/Repeat.java
+++ b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/Repeat.java
@@ -46,8 +46,14 @@
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
 
+/**
+ * Annotation enabling to run tests repeatedly
+ */
 @Retention(RetentionPolicy.RUNTIME)
 @Target({ java.lang.annotation.ElementType.METHOD })
 public @interface Repeat {
+	/**
+	 * Number of repetitions
+	 */
 	public abstract int n();
 }
diff --git a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/RepeatRule.java b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/RepeatRule.java
index 4230073..8165738 100644
--- a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/RepeatRule.java
+++ b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/RepeatRule.java
@@ -51,8 +51,8 @@
 import org.junit.runners.model.Statement;
 
 /**
- * {@link TestRule} which enables to run the same JUnit test repeatedly. Add
- * this rule to the test class
+ * {@link org.junit.rules.TestRule} which enables to run the same JUnit test
+ * repeatedly. Add this rule to the test class
  *
  * <pre>
  * public class MyTest {
@@ -118,6 +118,7 @@ public void evaluate() throws Throwable {
 		}
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public Statement apply(Statement statement, Description description) {
 		Statement result = statement;
diff --git a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/RepositoryTestCase.java b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/RepositoryTestCase.java
index c282df0..e983e5d 100644
--- a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/RepositoryTestCase.java
+++ b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/RepositoryTestCase.java
@@ -46,6 +46,7 @@
 
 package org.eclipse.jgit.junit;
 
+import static org.eclipse.jgit.lib.Constants.CHARSET;
 import static org.junit.Assert.assertEquals;
 
 import java.io.File;
@@ -84,26 +85,34 @@
  * repositories and destroying them when the tests are finished.
  */
 public abstract class RepositoryTestCase extends LocalDiskRepositoryTestCase {
-	protected static void copyFile(final File src, final File dst)
+	/**
+	 * Copy a file
+	 *
+	 * @param src
+	 * @param dst
+	 * @throws IOException
+	 */
+	protected static void copyFile(File src, File dst)
 			throws IOException {
-		final FileInputStream fis = new FileInputStream(src);
-		try {
-			final FileOutputStream fos = new FileOutputStream(dst);
-			try {
-				final byte[] buf = new byte[4096];
-				int r;
-				while ((r = fis.read(buf)) > 0) {
-					fos.write(buf, 0, r);
-				}
-			} finally {
-				fos.close();
+		try (FileInputStream fis = new FileInputStream(src);
+				FileOutputStream fos = new FileOutputStream(dst)) {
+			final byte[] buf = new byte[4096];
+			int r;
+			while ((r = fis.read(buf)) > 0) {
+				fos.write(buf, 0, r);
 			}
-		} finally {
-			fis.close();
 		}
 	}
 
-	protected File writeTrashFile(final String name, final String data)
+	/**
+	 * Write a trash file
+	 *
+	 * @param name
+	 * @param data
+	 * @return the trash file
+	 * @throws IOException
+	 */
+	protected File writeTrashFile(String name, String data)
 			throws IOException {
 		return JGitTestUtil.writeTrashFile(db, name, data);
 	}
@@ -119,39 +128,77 @@ protected File writeTrashFile(final String name, final String data)
 	 * @throws Exception
 	 * @since 4.2
 	 */
-	protected Path writeLink(final String link, final String target)
+	protected Path writeLink(String link, String target)
 			throws Exception {
 		return JGitTestUtil.writeLink(db, link, target);
 	}
 
+	/**
+	 * Write a trash file
+	 *
+	 * @param subdir
+	 * @param name
+	 * @param data
+	 * @return the trash file
+	 * @throws IOException
+	 */
 	protected File writeTrashFile(final String subdir, final String name,
 			final String data)
 			throws IOException {
 		return JGitTestUtil.writeTrashFile(db, subdir, name, data);
 	}
 
-	protected String read(final String name) throws IOException {
+	/**
+	 * Read content of a file
+	 *
+	 * @param name
+	 * @return the file's content
+	 * @throws IOException
+	 */
+	protected String read(String name) throws IOException {
 		return JGitTestUtil.read(db, name);
 	}
 
-	protected boolean check(final String name) {
+	/**
+	 * Check if file exists
+	 *
+	 * @param name
+	 *            file name
+	 * @return if the file exists
+	 */
+	protected boolean check(String name) {
 		return JGitTestUtil.check(db, name);
 	}
 
-	protected void deleteTrashFile(final String name) throws IOException {
+	/**
+	 * Delete a trash file
+	 *
+	 * @param name
+	 *            file name
+	 * @throws IOException
+	 */
+	protected void deleteTrashFile(String name) throws IOException {
 		JGitTestUtil.deleteTrashFile(db, name);
 	}
 
-	protected static void checkFile(File f, final String checkData)
+	/**
+	 * Check content of a file.
+	 *
+	 * @param f
+	 * @param checkData
+	 *            expected content
+	 * @throws IOException
+	 */
+	protected static void checkFile(File f, String checkData)
 			throws IOException {
-		Reader r = new InputStreamReader(new FileInputStream(f), "UTF-8");
-		try {
-			char[] data = new char[checkData.length()];
-			if (checkData.length() != r.read(data))
-				throw new IOException("Internal error reading file data from "+f);
-			assertEquals(checkData, new String(data));
-		} finally {
-			r.close();
+		try (Reader r = new InputStreamReader(new FileInputStream(f),
+				CHARSET)) {
+			if (checkData.length() > 0) {
+				char[] data = new char[checkData.length()];
+				assertEquals(data.length, r.read(data));
+				assertEquals(checkData, new String(data));
+			}
+			assertEquals(-1, r.read());
 		}
 	}
 
@@ -161,6 +208,7 @@ protected static void checkFile(File f, final String checkData)
 	/** Working directory of {@link #db}. */
 	protected File trash;
 
+	/** {@inheritDoc} */
 	@Override
 	@Before
 	public void setUp() throws Exception {
@@ -220,8 +268,8 @@ public String indexState(int includedOptions)
 	 * have an index which matches their prepared content.
 	 *
 	 * @param treeItr
-	 *            a {@link FileTreeIterator} which determines which files should
-	 *            go into the new index
+	 *            a {@link org.eclipse.jgit.treewalk.FileTreeIterator} which
+	 *            determines which files should go into the new index
 	 * @throws FileNotFoundException
 	 * @throws IOException
 	 */
@@ -238,10 +286,11 @@ protected void resetIndex(FileTreeIterator treeItr)
 				dce.setFileMode(treeItr.getEntryFileMode());
 				dce.setLastModified(treeItr.getEntryLastModified());
 				dce.setLength((int) len);
-				FileInputStream in = new FileInputStream(
-						treeItr.getEntryFile());
-				dce.setObjectId(inserter.insert(Constants.OBJ_BLOB, len, in));
-				in.close();
+				try (FileInputStream in = new FileInputStream(
+						treeItr.getEntryFile())) {
+					dce.setObjectId(
+							inserter.insert(Constants.OBJ_BLOB, len, in));
+				}
 				builder.add(dce);
 				treeItr.next(1);
 			}
@@ -261,13 +310,13 @@ protected void resetIndex(FileTreeIterator treeItr)
 	 *
 	 * @param l
 	 *            the object to lookup
+	 * @param lookupTable
+	 *            a table storing object-name mappings.
 	 * @param nameTemplate
 	 *            the name for that object. Can contain "%n" which will be
 	 *            replaced by a running number before used as a name. If the
 	 *            lookup table already contains the object this parameter will
 	 *            be ignored
-	 * @param lookupTable
-	 *            a table storing object-name mappings.
 	 * @return a name of that object. Is not guaranteed to be unique. Use
 	 *         nameTemplates containing "%n" to always have unique names
 	 */
@@ -288,7 +337,7 @@ public static String lookup(Object l, String nameTemplate,
 	 * @param str
 	 *            the string in which backslashes should be replaced
 	 * @return the resulting string with slashes
-         * @since 4.2
+	 * @since 4.2
 	 */
 	public static String slashify(String str) {
 		str = str.replace('\\', '/');
@@ -325,8 +374,9 @@ public static long fsTick(File lastFile) throws InterruptedException,
 			while (actTime <= startTime) {
 				Thread.sleep(sleepTime);
 				sleepTime *= 2;
-				FileOutputStream fos = new FileOutputStream(tmp);
-				fos.close();
+				try (FileOutputStream fos = new FileOutputStream(tmp)) {
+					// Do nothing
+				}
 				actTime = fs.lastModified(tmp);
 			}
 			return actTime;
@@ -335,6 +385,13 @@ public static long fsTick(File lastFile) throws InterruptedException,
 		}
 	}
 
+	/**
+	 * Create a branch
+	 *
+	 * @param objectId
+	 * @param branchName
+	 * @throws IOException
+	 */
 	protected void createBranch(ObjectId objectId, String branchName)
 			throws IOException {
 		RefUpdate updateRef = db.updateRef(branchName);
@@ -342,6 +399,13 @@ protected void createBranch(ObjectId objectId, String branchName)
 		updateRef.update();
 	}
 
+	/**
+	 * Checkout a branch
+	 *
+	 * @param branchName
+	 * @throws IllegalStateException
+	 * @throws IOException
+	 */
 	protected void checkoutBranch(String branchName)
 			throws IllegalStateException, IOException {
 		try (RevWalk walk = new RevWalk(db)) {
@@ -429,15 +493,39 @@ else if (empty)
 		}
 	}
 
-	protected DirCacheEntry createEntry(final String path, final FileMode mode) {
+	/**
+	 * Create <code>DirCacheEntry</code>
+	 *
+	 * @param path
+	 * @param mode
+	 * @return the DirCacheEntry
+	 */
+	protected DirCacheEntry createEntry(String path, FileMode mode) {
 		return createEntry(path, mode, DirCacheEntry.STAGE_0, path);
 	}
 
+	/**
+	 * Create <code>DirCacheEntry</code>
+	 *
+	 * @param path
+	 * @param mode
+	 * @param content
+	 * @return the DirCacheEntry
+	 */
 	protected DirCacheEntry createEntry(final String path, final FileMode mode,
 			final String content) {
 		return createEntry(path, mode, DirCacheEntry.STAGE_0, content);
 	}
 
+	/**
+	 * Create <code>DirCacheEntry</code>
+	 *
+	 * @param path
+	 * @param mode
+	 * @param stage
+	 * @param content
+	 * @return the DirCacheEntry
+	 */
 	protected DirCacheEntry createEntry(final String path, final FileMode mode,
 			final int stage, final String content) {
 		final DirCacheEntry entry = new DirCacheEntry(path, stage);
@@ -449,6 +537,13 @@ protected DirCacheEntry createEntry(final String path, final FileMode mode,
 		return entry;
 	}
 
+	/**
+	 * Assert files are equal
+	 *
+	 * @param expected
+	 * @param actual
+	 * @throws IOException
+	 */
 	public static void assertEqualsFile(File expected, File actual)
 			throws IOException {
 		assertEquals(expected.getCanonicalFile(), actual.getCanonicalFile());
diff --git a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/StrictWorkMonitor.java b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/StrictWorkMonitor.java
index 22b69a3..fcedfb0 100644
--- a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/StrictWorkMonitor.java
+++ b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/StrictWorkMonitor.java
@@ -47,30 +47,38 @@
 
 import org.eclipse.jgit.lib.ProgressMonitor;
 
+/**
+ * Strict work monitor
+ */
 public final class StrictWorkMonitor implements ProgressMonitor {
 	private int lastWork, totalWork;
 
+	/** {@inheritDoc} */
 	@Override
 	public void start(int totalTasks) {
 		// empty
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void beginTask(String title, int total) {
 		this.totalWork = total;
 		lastWork = 0;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void update(int completed) {
 		lastWork += completed;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void endTask() {
 		assertEquals("Units of work recorded", totalWork, lastWork);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public boolean isCancelled() {
 		return false;
diff --git a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/TestRepository.java b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/TestRepository.java
index d1358ee..d23c0d3 100644
--- a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/TestRepository.java
+++ b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/TestRepository.java
@@ -43,6 +43,7 @@
 
 package org.eclipse.jgit.junit;
 
+import static org.eclipse.jgit.lib.Constants.CHARSET;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.fail;
 
@@ -113,12 +114,16 @@
  */
 public class TestRepository<R extends Repository> {
 
+	/** Constant <code>AUTHOR="J. Author"</code> */
 	public static final String AUTHOR = "J. Author";
 
+	/** Constant <code>AUTHOR_EMAIL="jauthor@example.com"</code> */
 	public static final String AUTHOR_EMAIL = "jauthor@example.com";
 
+	/** Constant <code>COMMITTER="J. Committer"</code> */
 	public static final String COMMITTER = "J. Committer";
 
+	/** Constant <code>COMMITTER_EMAIL="jcommitter@example.com"</code> */
 	public static final String COMMITTER_EMAIL = "jcommitter@example.com";
 
 	private final PersonIdent defaultAuthor;
@@ -185,25 +190,38 @@ public TestRepository(R db, RevWalk rw, MockSystemReader reader)
 		defaultCommitter = new PersonIdent(COMMITTER, COMMITTER_EMAIL, now, tz);
 	}
 
-	/** @return the repository this helper class operates against. */
+	/**
+	 * Get repository
+	 *
+	 * @return the repository this helper class operates against.
+	 */
 	public R getRepository() {
 		return db;
 	}
 
-	/** @return get the RevWalk pool all objects are allocated through. */
+	/**
+	 * Get RevWalk
+	 *
+	 * @return get the RevWalk pool all objects are allocated through.
+	 */
 	public RevWalk getRevWalk() {
 		return pool;
 	}
 
 	/**
+	 * Return Git API wrapper
+	 *
 	 * @return an API wrapper for the underlying repository. This wrapper does
-	 *         not allocate any new resources and need not be closed (but closing
-	 *         it is harmless). */
+	 *         not allocate any new resources and need not be closed (but
+	 *         closing it is harmless).
+	 */
 	public Git git() {
 		return git;
 	}
 
 	/**
+	 * Get date
+	 *
 	 * @return current date.
 	 * @since 4.2
 	 */
@@ -211,7 +229,11 @@ public Date getDate() {
 		return new Date(mockSystemReader.getCurrentTime());
 	}
 
-	/** @return timezone used for default identities. */
+	/**
+	 * Get timezone
+	 *
+	 * @return timezone used for default identities.
+	 */
 	public TimeZone getTimeZone() {
 		return mockSystemReader.getTimeZone();
 	}
@@ -222,7 +244,7 @@ public TimeZone getTimeZone() {
 	 * @param secDelta
 	 *            number of seconds to add to the current time.
 	 */
-	public void tick(final int secDelta) {
+	public void tick(int secDelta) {
 		mockSystemReader.tick(secDelta);
 	}
 
@@ -245,8 +267,8 @@ public void setAuthorAndCommitter(org.eclipse.jgit.lib.CommitBuilder c) {
 	 * @return reference to the blob.
 	 * @throws Exception
 	 */
-	public RevBlob blob(final String content) throws Exception {
-		return blob(content.getBytes("UTF-8"));
+	public RevBlob blob(String content) throws Exception {
+		return blob(content.getBytes(CHARSET));
 	}
 
 	/**
@@ -257,7 +279,7 @@ public RevBlob blob(final String content) throws Exception {
 	 * @return reference to the blob.
 	 * @throws Exception
 	 */
-	public RevBlob blob(final byte[] content) throws Exception {
+	public RevBlob blob(byte[] content) throws Exception {
 		ObjectId id;
 		try (ObjectInserter ins = inserter) {
 			id = ins.insert(Constants.OBJ_BLOB, content);
@@ -276,7 +298,7 @@ public RevBlob blob(final byte[] content) throws Exception {
 	 * @return the entry.
 	 * @throws Exception
 	 */
-	public DirCacheEntry file(final String path, final RevBlob blob)
+	public DirCacheEntry file(String path, RevBlob blob)
 			throws Exception {
 		final DirCacheEntry e = new DirCacheEntry(path);
 		e.setFileMode(FileMode.REGULAR_FILE);
@@ -293,10 +315,10 @@ public DirCacheEntry file(final String path, final RevBlob blob)
 	 * @return reference to the tree specified by the entry list.
 	 * @throws Exception
 	 */
-	public RevTree tree(final DirCacheEntry... entries) throws Exception {
+	public RevTree tree(DirCacheEntry... entries) throws Exception {
 		final DirCache dc = DirCache.newInCore();
 		final DirCacheBuilder b = dc.builder();
-		for (final DirCacheEntry e : entries)
+		for (DirCacheEntry e : entries)
 			b.add(e);
 		b.finish();
 		ObjectId root;
@@ -317,7 +339,7 @@ public RevTree tree(final DirCacheEntry... entries) throws Exception {
 	 * @return the parsed object entry at this path, never null.
 	 * @throws Exception
 	 */
-	public RevObject get(final RevTree tree, final String path)
+	public RevObject get(RevTree tree, String path)
 			throws Exception {
 		try (TreeWalk tw = new TreeWalk(pool.getObjectReader())) {
 			tw.setFilter(PathFilterGroup.createFromStrings(Collections
@@ -348,7 +370,7 @@ public RevObject get(final RevTree tree, final String path)
 	 * @return the new commit.
 	 * @throws Exception
 	 */
-	public RevCommit commit(final RevCommit... parents) throws Exception {
+	public RevCommit commit(RevCommit... parents) throws Exception {
 		return commit(1, tree(), parents);
 	}
 
@@ -364,7 +386,7 @@ public RevCommit commit(final RevCommit... parents) throws Exception {
 	 * @return the new commit.
 	 * @throws Exception
 	 */
-	public RevCommit commit(final RevTree tree, final RevCommit... parents)
+	public RevCommit commit(RevTree tree, RevCommit... parents)
 			throws Exception {
 		return commit(1, tree, parents);
 	}
@@ -382,7 +404,7 @@ public RevCommit commit(final RevTree tree, final RevCommit... parents)
 	 * @return the new commit.
 	 * @throws Exception
 	 */
-	public RevCommit commit(final int secDelta, final RevCommit... parents)
+	public RevCommit commit(int secDelta, RevCommit... parents)
 			throws Exception {
 		return commit(secDelta, tree(), parents);
 	}
@@ -423,7 +445,11 @@ public RevCommit commit(final int secDelta, final RevTree tree,
 		return pool.lookupCommit(id);
 	}
 
-	/** @return a new commit builder. */
+	/**
+	 * Create commit builder
+	 *
+	 * @return a new commit builder.
+	 */
 	public CommitBuilder commit() {
 		return new CommitBuilder();
 	}
@@ -444,7 +470,7 @@ public CommitBuilder commit() {
 	 * @return the annotated tag object.
 	 * @throws Exception
 	 */
-	public RevTag tag(final String name, final RevObject dst) throws Exception {
+	public RevTag tag(String name, RevObject dst) throws Exception {
 		final TagBuilder t = new TagBuilder();
 		t.setObjectId(dst);
 		t.setTag(name);
@@ -587,6 +613,7 @@ public <T extends AnyObjectId> T update(String ref, T obj) throws Exception {
 	public void delete(String ref) throws Exception {
 		ref = normalizeRef(ref);
 		RefUpdate u = db.updateRef(ref);
+		u.setForceUpdate(true);
 		switch (u.delete()) {
 		case FAST_FORWARD:
 		case FORCED:
@@ -616,7 +643,7 @@ private static String normalizeRef(String ref) {
 
 	/**
 	 * Soft-reset HEAD to a detached state.
-	 * <p>
+	 *
 	 * @param id
 	 *            ID of detached head.
 	 * @throws Exception
@@ -732,7 +759,7 @@ public void updateServerInfo() throws Exception {
 			final FileRepository fr = (FileRepository) db;
 			RefWriter rw = new RefWriter(fr.getAllRefs().values()) {
 				@Override
-				protected void writeFile(final String name, final byte[] bin)
+				protected void writeFile(String name, byte[] bin)
 						throws IOException {
 					File path = new File(fr.getDirectory(), name);
 					TestRepository.this.writeFile(path, bin);
@@ -756,14 +783,15 @@ protected void writeFile(final String name, final byte[] bin)
 	 * Ensure the body of the given object has been parsed.
 	 *
 	 * @param <T>
-	 *            type of object, e.g. {@link RevTag} or {@link RevCommit}.
+	 *            type of object, e.g. {@link org.eclipse.jgit.revwalk.RevTag}
+	 *            or {@link org.eclipse.jgit.revwalk.RevCommit}.
 	 * @param object
 	 *            reference to the (possibly unparsed) object to force body
 	 *            parsing of.
 	 * @return {@code object}
 	 * @throws Exception
 	 */
-	public <T extends RevObject> T parseBody(final T object) throws Exception {
+	public <T extends RevObject> T parseBody(T object) throws Exception {
 		pool.parseBody(object);
 		return object;
 	}
@@ -912,11 +940,11 @@ private static void prunePacked(ObjectDirectory odb) throws IOException {
 	}
 
 	private static File nameFor(ObjectDirectory odb, ObjectId name, String t) {
-		File packdir = new File(odb.getDirectory(), "pack");
+		File packdir = odb.getPackDirectory();
 		return new File(packdir, "pack-" + name.name() + t);
 	}
 
-	private void writeFile(final File p, final byte[] bin) throws IOException,
+	private void writeFile(File p, byte[] bin) throws IOException,
 			ObjectWritingException {
 		final LockFile lck = new LockFile(p);
 		if (!lck.lock())
@@ -934,7 +962,7 @@ private void writeFile(final File p, final byte[] bin) throws IOException,
 	public class BranchBuilder {
 		private final String ref;
 
-		BranchBuilder(final String ref) {
+		BranchBuilder(String ref) {
 			this.ref = ref;
 		}
 
@@ -1065,7 +1093,7 @@ public CommitBuilder add(String path, String content) throws Exception {
 			return add(path, blob(content));
 		}
 
-		public CommitBuilder add(String path, final RevBlob id)
+		public CommitBuilder add(String path, RevBlob id)
 				throws Exception {
 			return edit(new PathEdit(path) {
 				@Override
diff --git a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/TestRng.java b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/TestRng.java
index 93facc3..f7af36a 100644
--- a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/TestRng.java
+++ b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/TestRng.java
@@ -43,7 +43,9 @@
 
 package org.eclipse.jgit.junit;
 
-/** Toy RNG to ensure we get predictable numbers during unit tests. */
+/**
+ * Toy RNG to ensure we get predictable numbers during unit tests.
+ */
 public class TestRng {
 	private int next;
 
@@ -53,7 +55,7 @@ public class TestRng {
 	 * @param seed
 	 *            seed to bootstrap, usually this is the test method name.
 	 */
-	public TestRng(final String seed) {
+	public TestRng(String seed) {
 		next = 0;
 		for (int i = 0; i < seed.length(); i++)
 			next = next * 11 + seed.charAt(i);
@@ -66,7 +68,7 @@ public TestRng(final String seed) {
 	 *            number of random bytes to produce.
 	 * @return array of {@code cnt} randomly generated bytes.
 	 */
-	public byte[] nextBytes(final int cnt) {
+	public byte[] nextBytes(int cnt) {
 		final byte[] r = new byte[cnt];
 		for (int i = 0; i < cnt; i++)
 			r[i] = (byte) nextInt();
@@ -74,6 +76,8 @@ public TestRng(final String seed) {
 	}
 
 	/**
+	 * Next int
+	 *
 	 * @return the next random integer.
 	 */
 	public int nextInt() {
diff --git a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/time/MonotonicFakeClock.java b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/time/MonotonicFakeClock.java
index f09d303..1f5cac6 100644
--- a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/time/MonotonicFakeClock.java
+++ b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/time/MonotonicFakeClock.java
@@ -50,7 +50,8 @@
 import org.eclipse.jgit.util.time.ProposedTimestamp;
 
 /**
- * Fake {@link MonotonicClock} for testing code that uses Clock.
+ * Fake {@link org.eclipse.jgit.util.time.MonotonicClock} for testing code that
+ * uses Clock.
  *
  * @since 4.6
  */
@@ -72,6 +73,7 @@ public void tick(long add, TimeUnit unit) {
 		now += unit.toMillis(add);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public ProposedTimestamp propose() {
 		long t = now++;
diff --git a/org.eclipse.jgit.lfs.server.test/.settings/org.eclipse.jdt.core.prefs b/org.eclipse.jgit.lfs.server.test/.settings/org.eclipse.jdt.core.prefs
index 64f7498..794592d 100644
--- a/org.eclipse.jgit.lfs.server.test/.settings/org.eclipse.jdt.core.prefs
+++ b/org.eclipse.jgit.lfs.server.test/.settings/org.eclipse.jdt.core.prefs
@@ -25,7 +25,7 @@
 org.eclipse.jdt.core.compiler.problem.discouragedReference=warning
 org.eclipse.jdt.core.compiler.problem.emptyStatement=warning
 org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
-org.eclipse.jdt.core.compiler.problem.explicitlyClosedAutoCloseable=ignore
+org.eclipse.jdt.core.compiler.problem.explicitlyClosedAutoCloseable=warning
 org.eclipse.jdt.core.compiler.problem.fallthroughCase=warning
 org.eclipse.jdt.core.compiler.problem.fatalOptionalError=disabled
 org.eclipse.jdt.core.compiler.problem.fieldHiding=warning
diff --git a/org.eclipse.jgit.lfs.server.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.lfs.server.test/META-INF/MANIFEST.MF
index 6a23e7a..e272e3d 100644
--- a/org.eclipse.jgit.lfs.server.test/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.lfs.server.test/META-INF/MANIFEST.MF
@@ -1,8 +1,9 @@
 Manifest-Version: 1.0
 Bundle-ManifestVersion: 2
 Bundle-Name: %plugin_name
+Automatic-Module-Name: org.eclipse.jgit.lfs.server.test
 Bundle-SymbolicName: org.eclipse.jgit.lfs.server.test
-Bundle-Version: 4.9.3.qualifier
+Bundle-Version: 5.0.0.qualifier
 Bundle-Vendor: %provider_name
 Bundle-Localization: plugin
 Bundle-RequiredExecutionEnvironment: JavaSE-1.8
@@ -27,12 +28,26 @@
  org.eclipse.jetty.util.log;version="[9.4.5,10.0.0)",
  org.eclipse.jetty.util.security;version="[9.4.5,10.0.0)",
  org.eclipse.jetty.util.thread;version="[9.4.5,10.0.0)",
- org.eclipse.jgit.junit.http;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.lfs.lib;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.lfs.server.fs;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.lfs.test;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.util;version="[4.9.3,4.10.0)",
+ org.eclipse.jgit.api;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.api.errors;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.internal.storage.file;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.junit;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.junit.http;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.lfs;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.lfs.errors;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.lfs.lib;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.lfs.server;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.lfs.server.fs;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.lfs.test;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.lib;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.revwalk;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.storage.file;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.transport;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.treewalk;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.treewalk.filter;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.util;version="[5.0.0,5.1.0)",
  org.hamcrest.core;version="[1.1.0,2.0.0)",
- org.junit;version="[4.0.0,5.0.0)",
- org.junit.runner;version="[4.0.0,5.0.0)",
- org.junit.runners;version="[4.0.0,5.0.0)"
+ org.junit;version="[4.12,5.0.0)",
+ org.junit.rules;version="[4.12,5.0.0)",
+ org.junit.runner;version="[4.12,5.0.0)",
+ org.junit.runners;version="[4.12,5.0.0)"
diff --git a/org.eclipse.jgit.lfs.server.test/pom.xml b/org.eclipse.jgit.lfs.server.test/pom.xml
index 2a3360d..fbf4d4b 100644
--- a/org.eclipse.jgit.lfs.server.test/pom.xml
+++ b/org.eclipse.jgit.lfs.server.test/pom.xml
@@ -50,7 +50,7 @@
   <parent>
     <groupId>org.eclipse.jgit</groupId>
     <artifactId>org.eclipse.jgit-parent</artifactId>
-    <version>4.9.3-SNAPSHOT</version>
+    <version>5.0.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>org.eclipse.jgit.lfs.server.test</artifactId>
diff --git a/org.eclipse.jgit.lfs.server.test/tst/org/eclipse/jgit/lfs/server/fs/CheckoutTest.java b/org.eclipse.jgit.lfs.server.test/tst/org/eclipse/jgit/lfs/server/fs/CheckoutTest.java
new file mode 100644
index 0000000..fb6225b
--- /dev/null
+++ b/org.eclipse.jgit.lfs.server.test/tst/org/eclipse/jgit/lfs/server/fs/CheckoutTest.java
@@ -0,0 +1,161 @@
+/*
+ * Copyright (C) 2016, Christian Halstrick <christian.halstrick@sap.com>
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ *   copyright notice, this list of conditions and the following
+ *   disclaimer in the documentation and/or other materials provided
+ *   with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ *   names of its contributors may be used to endorse or promote
+ *   products derived from this software without specific prior
+ *   written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.eclipse.jgit.lfs.server.fs;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+
+import java.nio.file.Files;
+import java.nio.file.Path;
+
+import org.eclipse.jgit.api.Git;
+import org.eclipse.jgit.api.errors.JGitInternalException;
+import org.eclipse.jgit.junit.JGitTestUtil;
+import org.eclipse.jgit.junit.TestRepository;
+import org.eclipse.jgit.lfs.BuiltinLFS;
+import org.eclipse.jgit.lfs.lib.LongObjectId;
+import org.eclipse.jgit.lib.ConfigConstants;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.lib.StoredConfig;
+import org.eclipse.jgit.storage.file.FileRepositoryBuilder;
+import org.eclipse.jgit.util.FileUtils;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+public class CheckoutTest extends LfsServerTest {
+
+	Git git;
+	private TestRepository tdb;
+
+	@Override
+	@Before
+	public void setup() throws Exception {
+		super.setup();
+
+		BuiltinLFS.register();
+
+		Path tmp = Files.createTempDirectory("jgit_test_");
+		Repository db = FileRepositoryBuilder
+				.create(tmp.resolve(".git").toFile());
+		db.create();
+		StoredConfig cfg = db.getConfig();
+		cfg.setBoolean(ConfigConstants.CONFIG_FILTER_SECTION,
+				ConfigConstants.CONFIG_SECTION_LFS,
+				ConfigConstants.CONFIG_KEY_USEJGITBUILTIN, true);
+		cfg.setBoolean(ConfigConstants.CONFIG_FILTER_SECTION,
+				ConfigConstants.CONFIG_SECTION_LFS,
+				ConfigConstants.CONFIG_KEY_REQUIRED, false);
+		cfg.setString(ConfigConstants.CONFIG_SECTION_LFS, null, "url",
+				server.getURI().toString() + "/lfs");
+		cfg.save();
+
+		tdb = new TestRepository<>(db);
+		tdb.branch("test").commit()
+				.add(".gitattributes",
+						"*.bin filter=lfs diff=lfs merge=lfs -text ")
+				.add("a.bin",
+						"version https://git-lfs.github.com/spec/v1\noid sha256:8bb0cf6eb9b17d0f7d22b456f121257dc1254e1f01665370476383ea776df414\nsize 7\n")
+				.create();
+		git = Git.wrap(db);
+		tdb.branch("test2").commit().add(".gitattributes",
+				"*.bin filter=lfs diff=lfs merge=lfs -text ").create();
+	}
+
+	@After
+	public void cleanup() throws Exception {
+		tdb.getRepository().close();
+		FileUtils.delete(tdb.getRepository().getWorkTree(),
+				FileUtils.RECURSIVE);
+	}
+
+	@Test
+	public void testUnknownContent() throws Exception {
+		git.checkout().setName("test").call();
+		// unknown content. We will see the pointer file
+		assertEquals(
+				"version https://git-lfs.github.com/spec/v1\noid sha256:8bb0cf6eb9b17d0f7d22b456f121257dc1254e1f01665370476383ea776df414\nsize 7\n",
+				JGitTestUtil.read(git.getRepository(), "a.bin"));
+		assertEquals("[POST /lfs/objects/batch 200]",
+				server.getRequests().toString());
+	}
+
+	@Test(expected = JGitInternalException.class)
+	public void testUnknownContentRequired() throws Exception {
+		StoredConfig cfg = tdb.getRepository().getConfig();
+		cfg.setBoolean(ConfigConstants.CONFIG_FILTER_SECTION,
+				ConfigConstants.CONFIG_SECTION_LFS,
+				ConfigConstants.CONFIG_KEY_REQUIRED, true);
+		cfg.save();
+
+		// must throw
+		git.checkout().setName("test").call();
+	}
+
+	@Test
+	public void testKnownContent() throws Exception {
+		putContent(
+				LongObjectId.fromString(
+						"8bb0cf6eb9b17d0f7d22b456f121257dc1254e1f01665370476383ea776df414"),
+				"1234567");
+		git.checkout().setName("test").call();
+		// known content. we will see the actual content of the LFS blob.
+		assertEquals(
+				"1234567",
+				JGitTestUtil.read(git.getRepository(), "a.bin"));
+		assertEquals(
+				"[PUT /lfs/objects/8bb0cf6eb9b17d0f7d22b456f121257dc1254e1f01665370476383ea776df414 200"
+						+ ", POST /lfs/objects/batch 200"
+						+ ", GET /lfs/objects/8bb0cf6eb9b17d0f7d22b456f121257dc1254e1f01665370476383ea776df414 200]",
+				server.getRequests().toString());
+
+		git.checkout().setName("test2").call();
+		assertFalse(JGitTestUtil.check(git.getRepository(), "a.bin"));
+		git.checkout().setName("test").call();
+		// unknown content. We will see the pointer file
+		assertEquals("1234567",
+				JGitTestUtil.read(git.getRepository(), "a.bin"));
+		assertEquals(3, server.getRequests().size());
+	}
+
+}
diff --git a/org.eclipse.jgit.lfs.server.test/tst/org/eclipse/jgit/lfs/server/fs/DownloadTest.java b/org.eclipse.jgit.lfs.server.test/tst/org/eclipse/jgit/lfs/server/fs/DownloadTest.java
index 303d8056..a38bf6a 100644
--- a/org.eclipse.jgit.lfs.server.test/tst/org/eclipse/jgit/lfs/server/fs/DownloadTest.java
+++ b/org.eclipse.jgit.lfs.server.test/tst/org/eclipse/jgit/lfs/server/fs/DownloadTest.java
@@ -45,7 +45,6 @@
 import static org.apache.http.HttpStatus.SC_NOT_FOUND;
 import static org.apache.http.HttpStatus.SC_UNPROCESSABLE_ENTITY;
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.fail;
 
 import java.io.IOException;
 import java.nio.file.Path;
@@ -56,10 +55,15 @@
 import org.eclipse.jgit.lfs.lib.AnyLongObjectId;
 import org.eclipse.jgit.lfs.test.LongObjectIdTestUtils;
 import org.eclipse.jgit.util.FileUtils;
+import org.junit.Rule;
 import org.junit.Test;
+import org.junit.rules.ExpectedException;
 
 public class DownloadTest extends LfsServerTest {
 
+	@Rule
+	public ExpectedException exception = ExpectedException.none();
+
 	@Test
 	public void testDownload() throws Exception {
 		String TEXT = "test";
@@ -76,15 +80,12 @@ public void testDownloadInvalidPathInfo()
 		String TEXT = "test";
 		String id = putContent(TEXT).name().substring(0, 60);
 		Path f = Paths.get(getTempDirectory().toString(), "download");
-		try {
-			getContent(id, f);
-			fail("expected RuntimeException");
-		} catch (RuntimeException e) {
-			String error = String.format(
-					"Invalid pathInfo: '/%s' does not match '/{SHA-256}'", id);
-			assertEquals(formatErrorMessage(SC_UNPROCESSABLE_ENTITY, error),
-					e.getMessage());
-		}
+		String error = String.format(
+				"Invalid pathInfo: '/%s' does not match '/{SHA-256}'", id);
+		exception.expect(RuntimeException.class);
+		exception.expectMessage(
+				formatErrorMessage(SC_UNPROCESSABLE_ENTITY, error));
+		getContent(id, f);
 	}
 
 	@Test
@@ -93,14 +94,11 @@ public void testDownloadInvalidId()
 		String TEXT = "test";
 		String id = putContent(TEXT).name().replace('f', 'z');
 		Path f = Paths.get(getTempDirectory().toString(), "download");
-		try {
-			getContent(id, f);
-			fail("expected RuntimeException");
-		} catch (RuntimeException e) {
-			String error = String.format("Invalid id: %s", id);
-			assertEquals(formatErrorMessage(SC_UNPROCESSABLE_ENTITY, error),
-					e.getMessage());
-		}
+		String error = String.format("Invalid id: %s", id);
+		exception.expect(RuntimeException.class);
+		exception.expectMessage(
+				formatErrorMessage(SC_UNPROCESSABLE_ENTITY, error));
+		getContent(id, f);
 	}
 
 	@Test
@@ -109,14 +107,10 @@ public void testDownloadNotFound()
 		String TEXT = "test";
 		AnyLongObjectId id = LongObjectIdTestUtils.hash(TEXT);
 		Path f = Paths.get(getTempDirectory().toString(), "download");
-		try {
-			getContent(id, f);
-			fail("expected RuntimeException");
-		} catch (RuntimeException e) {
-			String error = String.format("Object '%s' not found", id.getName());
-			assertEquals(formatErrorMessage(SC_NOT_FOUND, error),
-					e.getMessage());
-		}
+		String error = String.format("Object '%s' not found", id.getName());
+		exception.expect(RuntimeException.class);
+		exception.expectMessage(formatErrorMessage(SC_NOT_FOUND, error));
+		getContent(id, f);
 	}
 
 	@SuppressWarnings("boxing")
diff --git a/org.eclipse.jgit.lfs.server.test/tst/org/eclipse/jgit/lfs/server/fs/LfsServerTest.java b/org.eclipse.jgit.lfs.server.test/tst/org/eclipse/jgit/lfs/server/fs/LfsServerTest.java
index 5da502e..50a06f9 100644
--- a/org.eclipse.jgit.lfs.server.test/tst/org/eclipse/jgit/lfs/server/fs/LfsServerTest.java
+++ b/org.eclipse.jgit.lfs.server.test/tst/org/eclipse/jgit/lfs/server/fs/LfsServerTest.java
@@ -42,7 +42,7 @@
  */
 package org.eclipse.jgit.lfs.server.fs;
 
-import static java.nio.charset.StandardCharsets.UTF_8;
+import static org.eclipse.jgit.lib.Constants.CHARSET;
 import static org.junit.Assert.assertEquals;
 
 import java.io.BufferedInputStream;
@@ -75,9 +75,12 @@
 import org.eclipse.jetty.servlet.ServletContextHandler;
 import org.eclipse.jetty.servlet.ServletHolder;
 import org.eclipse.jgit.junit.http.AppServer;
+import org.eclipse.jgit.lfs.errors.LfsException;
 import org.eclipse.jgit.lfs.lib.AnyLongObjectId;
 import org.eclipse.jgit.lfs.lib.Constants;
 import org.eclipse.jgit.lfs.lib.LongObjectId;
+import org.eclipse.jgit.lfs.server.LargeFileRepository;
+import org.eclipse.jgit.lfs.server.LfsProtocolServlet;
 import org.eclipse.jgit.lfs.test.LongObjectIdTestUtils;
 import org.eclipse.jgit.util.FileUtils;
 import org.eclipse.jgit.util.IO;
@@ -122,7 +125,21 @@ public void setup() throws Exception {
 		this.repository = new FileLfsRepository(null, dir);
 		servlet = new FileLfsServlet(repository, timeout);
 		app.addServlet(new ServletHolder(servlet), "/objects/*");
+
+		LfsProtocolServlet protocol = new LfsProtocolServlet() {
+			private static final long serialVersionUID = 1L;
+
+			@Override
+			protected LargeFileRepository getLargeFileRepository(
+					LfsRequest request, String path, String auth)
+					throws LfsException {
+				return repository;
+			}
+		};
+		app.addServlet(new ServletHolder(protocol), "/objects/batch");
+
 		server.setUp();
+		this.repository.setUrl(server.getURI() + "/lfs/objects/");
 	}
 
 	@After
@@ -194,11 +211,11 @@ private void checkResponseStatus(HttpResponse response) {
 				if (buf.hasArray()) {
 					error = new String(buf.array(),
 							buf.arrayOffset() + buf.position(), buf.remaining(),
-							UTF_8);
+							CHARSET);
 				} else {
 					final byte[] b = new byte[buf.remaining()];
 					buf.duplicate().get(b);
-					error = new String(b, UTF_8);
+					error = new String(b, CHARSET);
 				}
 			} catch (IOException e) {
 				error = statusLine.getReasonPhrase();
diff --git a/org.eclipse.jgit.lfs.server.test/tst/org/eclipse/jgit/lfs/server/fs/PushTest.java b/org.eclipse.jgit.lfs.server.test/tst/org/eclipse/jgit/lfs/server/fs/PushTest.java
new file mode 100644
index 0000000..b081a8e
--- /dev/null
+++ b/org.eclipse.jgit.lfs.server.test/tst/org/eclipse/jgit/lfs/server/fs/PushTest.java
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2018, Markus Duft <markus.duft@ssi-schaefer.com>
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ *   copyright notice, this list of conditions and the following
+ *   disclaimer in the documentation and/or other materials provided
+ *   with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ *   names of its contributors may be used to endorse or promote
+ *   products derived from this software without specific prior
+ *   written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.eclipse.jgit.lfs.server.fs;
+
+import static org.junit.Assert.assertEquals;
+
+import java.io.InputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+
+import org.eclipse.jgit.api.Git;
+import org.eclipse.jgit.api.RemoteAddCommand;
+import org.eclipse.jgit.junit.JGitTestUtil;
+import org.eclipse.jgit.junit.TestRepository;
+import org.eclipse.jgit.lfs.BuiltinLFS;
+import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.ObjectLoader;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.lib.StoredConfig;
+import org.eclipse.jgit.revwalk.RevCommit;
+import org.eclipse.jgit.revwalk.RevWalk;
+import org.eclipse.jgit.storage.file.FileRepositoryBuilder;
+import org.eclipse.jgit.transport.URIish;
+import org.eclipse.jgit.treewalk.TreeWalk;
+import org.eclipse.jgit.treewalk.filter.PathFilter;
+import org.eclipse.jgit.util.FileUtils;
+import org.eclipse.jgit.util.IO;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+public class PushTest extends LfsServerTest {
+
+	Git git;
+
+	private TestRepository localDb;
+
+	private Repository remoteDb;
+
+	@Override
+	@Before
+	public void setup() throws Exception {
+		super.setup();
+
+		BuiltinLFS.register();
+
+		Path rtmp = Files.createTempDirectory("jgit_test_");
+		remoteDb = FileRepositoryBuilder.create(rtmp.toFile());
+		remoteDb.create(true);
+
+		Path tmp = Files.createTempDirectory("jgit_test_");
+		Repository db = FileRepositoryBuilder
+				.create(tmp.resolve(".git").toFile());
+		db.create(false);
+		StoredConfig cfg = db.getConfig();
+		cfg.setString("filter", "lfs", "usejgitbuiltin", "true");
+		cfg.setString("lfs", null, "url", server.getURI().toString() + "/lfs");
+		cfg.save();
+
+		localDb = new TestRepository<>(db);
+		localDb.branch("master").commit().add(".gitattributes",
+				"*.bin filter=lfs diff=lfs merge=lfs -text ").create();
+		git = Git.wrap(db);
+
+		URIish uri = new URIish(
+				"file://" + remoteDb.getDirectory());
+		RemoteAddCommand radd = git.remoteAdd();
+		radd.setUri(uri);
+		radd.setName(Constants.DEFAULT_REMOTE_NAME);
+		radd.call();
+
+		git.checkout().setName("master").call();
+		git.push().call();
+	}
+
+	@After
+	public void cleanup() throws Exception {
+		remoteDb.close();
+		localDb.getRepository().close();
+		FileUtils.delete(localDb.getRepository().getWorkTree(),
+				FileUtils.RECURSIVE);
+		FileUtils.delete(remoteDb.getDirectory(), FileUtils.RECURSIVE);
+	}
+
+	@Test
+	public void testPushSimple() throws Exception {
+		JGitTestUtil.writeTrashFile(localDb.getRepository(), "a.bin",
+				"1234567");
+		git.add().addFilepattern("a.bin").call();
+		RevCommit commit = git.commit().setMessage("add lfs blob").call();
+		git.push().call();
+
+		// check object in remote db, should be LFS pointer
+		ObjectId id = commit.getId();
+		try (RevWalk walk = new RevWalk(remoteDb)) {
+			RevCommit rc = walk.parseCommit(id);
+			try (TreeWalk tw = new TreeWalk(walk.getObjectReader())) {
+				tw.addTree(rc.getTree());
+				tw.setFilter(PathFilter.create("a.bin"));
+				tw.next();
+
+				assertEquals(tw.getPathString(), "a.bin");
+				ObjectLoader ldr = walk.getObjectReader()
+						.open(tw.getObjectId(0), Constants.OBJ_BLOB);
+				try(InputStream is = ldr.openStream()) {
+					assertEquals(
+							"version https://git-lfs.github.com/spec/v1\noid sha256:8bb0cf6eb9b17d0f7d22b456f121257dc1254e1f01665370476383ea776df414\nsize 7\n",
+							new String(IO
+									.readWholeStream(is,
+											(int) ldr.getSize())
+									.array()));
+				}
+			}
+
+		}
+
+		assertEquals(
+				"[POST /lfs/objects/batch 200, PUT /lfs/objects/8bb0cf6eb9b17d0f7d22b456f121257dc1254e1f01665370476383ea776df414 200]",
+				server.getRequests().toString());
+	}
+
+}
diff --git a/org.eclipse.jgit.lfs.server.test/tst/org/eclipse/jgit/lfs/server/fs/UploadTest.java b/org.eclipse.jgit.lfs.server.test/tst/org/eclipse/jgit/lfs/server/fs/UploadTest.java
index 8a8f49c..09f8d0a 100644
--- a/org.eclipse.jgit.lfs.server.test/tst/org/eclipse/jgit/lfs/server/fs/UploadTest.java
+++ b/org.eclipse.jgit.lfs.server.test/tst/org/eclipse/jgit/lfs/server/fs/UploadTest.java
@@ -122,7 +122,7 @@ public void testParallelUploads() throws Exception {
 
 		ExecutorService e = Executors.newFixedThreadPool(count);
 		try {
-			for (final Path p : paths) {
+			for (Path p : paths) {
 				e.submit(new Callable<Void>() {
 					@Override
 					public Void call() throws Exception {
diff --git a/org.eclipse.jgit.lfs.server/.settings/org.eclipse.jdt.core.prefs b/org.eclipse.jgit.lfs.server/.settings/org.eclipse.jdt.core.prefs
index ede0f7d..89394ec 100644
--- a/org.eclipse.jgit.lfs.server/.settings/org.eclipse.jdt.core.prefs
+++ b/org.eclipse.jgit.lfs.server/.settings/org.eclipse.jdt.core.prefs
@@ -25,7 +25,7 @@
 org.eclipse.jdt.core.compiler.problem.discouragedReference=warning
 org.eclipse.jdt.core.compiler.problem.emptyStatement=warning
 org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
-org.eclipse.jdt.core.compiler.problem.explicitlyClosedAutoCloseable=ignore
+org.eclipse.jdt.core.compiler.problem.explicitlyClosedAutoCloseable=warning
 org.eclipse.jdt.core.compiler.problem.fallthroughCase=warning
 org.eclipse.jdt.core.compiler.problem.fatalOptionalError=disabled
 org.eclipse.jdt.core.compiler.problem.fieldHiding=warning
diff --git a/org.eclipse.jgit.lfs.server/META-INF/MANIFEST.MF b/org.eclipse.jgit.lfs.server/META-INF/MANIFEST.MF
index 8c7fb96..28b1231 100644
--- a/org.eclipse.jgit.lfs.server/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.lfs.server/META-INF/MANIFEST.MF
@@ -1,37 +1,39 @@
 Manifest-Version: 1.0
 Bundle-ManifestVersion: 2
 Bundle-Name: %plugin_name
+Automatic-Module-Name: org.eclipse.jgit.lfs.server
 Bundle-SymbolicName: org.eclipse.jgit.lfs.server
-Bundle-Version: 4.9.3.qualifier
+Bundle-Version: 5.0.0.qualifier
 Bundle-Localization: plugin
 Bundle-Vendor: %provider_name
-Export-Package: org.eclipse.jgit.lfs.server;version="4.9.3";
+Export-Package: org.eclipse.jgit.lfs.server;version="5.0.0";
   uses:="javax.servlet.http,
    org.eclipse.jgit.lfs.lib",
- org.eclipse.jgit.lfs.server.fs;version="4.9.3";
+ org.eclipse.jgit.lfs.server.fs;version="5.0.0";
   uses:="javax.servlet,
    javax.servlet.http,
    org.eclipse.jgit.lfs.server,
    org.eclipse.jgit.lfs.lib",
- org.eclipse.jgit.lfs.server.internal;version="4.9.3";x-internal:=true,
- org.eclipse.jgit.lfs.server.s3;version="4.9.3";
+ org.eclipse.jgit.lfs.server.internal;version="5.0.0";x-internal:=true,
+ org.eclipse.jgit.lfs.server.s3;version="5.0.0";
   uses:="org.eclipse.jgit.lfs.server,
    org.eclipse.jgit.lfs.lib"
 Bundle-RequiredExecutionEnvironment: JavaSE-1.8
-Import-Package: com.google.gson;version="[2.2.4,3.0.0)",
+Import-Package: com.google.gson;version="[2.8.0,3.0.0)",
  javax.servlet;version="[3.1.0,4.0.0)",
  javax.servlet.annotation;version="[3.1.0,4.0.0)",
  javax.servlet.http;version="[3.1.0,4.0.0)",
  org.apache.http;version="[4.3.0,5.0.0)",
  org.apache.http.client;version="[4.3.0,5.0.0)",
- org.eclipse.jgit.annotations;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.internal;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.internal.storage.file;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.lfs.errors;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.lfs.internal;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.lfs.lib;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.nls;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.transport.http;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.transport.http.apache;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.util;version="[4.9.3,4.10.0)",
+ org.eclipse.jgit.annotations;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.internal;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.internal.storage.file;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.lfs.errors;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.lfs.internal;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.lfs.lib;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.lib;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.nls;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.transport.http;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.transport.http.apache;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.util;version="[5.0.0,5.1.0)",
  org.slf4j;version="[1.7.0,2.0.0)"
diff --git a/org.eclipse.jgit.lfs.server/pom.xml b/org.eclipse.jgit.lfs.server/pom.xml
index 37e70c2..3bb09ba 100644
--- a/org.eclipse.jgit.lfs.server/pom.xml
+++ b/org.eclipse.jgit.lfs.server/pom.xml
@@ -50,7 +50,7 @@
   <parent>
     <groupId>org.eclipse.jgit</groupId>
     <artifactId>org.eclipse.jgit-parent</artifactId>
-    <version>4.9.3-SNAPSHOT</version>
+    <version>5.0.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>org.eclipse.jgit.lfs.server</artifactId>
diff --git a/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/LargeFileRepository.java b/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/LargeFileRepository.java
index 3bdf8d0..cfa53af 100644
--- a/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/LargeFileRepository.java
+++ b/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/LargeFileRepository.java
@@ -55,6 +55,8 @@
 public interface LargeFileRepository {
 
 	/**
+	 * Get download action
+	 *
 	 * @param id
 	 *            id of the object to download
 	 * @return Action for downloading the object
@@ -62,6 +64,8 @@ public interface LargeFileRepository {
 	public Response.Action getDownloadAction(AnyLongObjectId id);
 
 	/**
+	 * Get upload action
+	 *
 	 * @param id
 	 *            id of the object to upload
 	 * @param size
@@ -71,6 +75,8 @@ public interface LargeFileRepository {
 	public Response.Action getUploadAction(AnyLongObjectId id, long size);
 
 	/**
+	 * Get verify action
+	 *
 	 * @param id
 	 *            id of the object to be verified
 	 * @return Action for verifying the object, or {@code null} if the server
@@ -79,11 +85,13 @@ public interface LargeFileRepository {
 	public @Nullable Response.Action getVerifyAction(AnyLongObjectId id);
 
 	/**
+	 * Get size of an object
+	 *
 	 * @param id
 	 *            id of the object
 	 * @return length of the object content in bytes, -1 if the object doesn't
 	 *         exist
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 */
 	public long getSize(AnyLongObjectId id) throws IOException;
 }
diff --git a/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/LfsObject.java b/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/LfsObject.java
index 4d97502..907e156 100644
--- a/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/LfsObject.java
+++ b/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/LfsObject.java
@@ -52,6 +52,8 @@ public class LfsObject {
 	long size;
 
 	/**
+	 * Get the <code>oid</code> of this object.
+	 *
 	 * @return the object ID.
 	 */
 	public String getOid() {
@@ -59,6 +61,8 @@ public String getOid() {
 	}
 
 	/**
+	 * Get the <code>size</code> of this object.
+	 *
 	 * @return the object size.
 	 */
 	public long getSize() {
diff --git a/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/LfsProtocolServlet.java b/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/LfsProtocolServlet.java
index 2473dcd..d22d459 100644
--- a/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/LfsProtocolServlet.java
+++ b/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/LfsProtocolServlet.java
@@ -42,7 +42,7 @@
  */
 package org.eclipse.jgit.lfs.server;
 
-import static java.nio.charset.StandardCharsets.UTF_8;
+import static org.eclipse.jgit.lib.Constants.CHARSET;
 import static org.apache.http.HttpStatus.SC_FORBIDDEN;
 import static org.apache.http.HttpStatus.SC_INSUFFICIENT_STORAGE;
 import static org.apache.http.HttpStatus.SC_INTERNAL_SERVER_ERROR;
@@ -81,13 +81,10 @@
 import org.eclipse.jgit.lfs.errors.LfsUnavailable;
 import org.eclipse.jgit.lfs.errors.LfsValidationError;
 import org.eclipse.jgit.lfs.internal.LfsText;
+import org.eclipse.jgit.lfs.server.internal.LfsGson;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.google.gson.FieldNamingPolicy;
-import com.google.gson.Gson;
-import com.google.gson.GsonBuilder;
-
 /**
  * LFS protocol handler implementing the LFS batch API [1]
  *
@@ -108,51 +105,6 @@ public abstract class LfsProtocolServlet extends HttpServlet {
 
 	private static final int SC_BANDWIDTH_LIMIT_EXCEEDED = 509;
 
-	private Gson gson = createGson();
-
-	/**
-	 * Get the large file repository for the given request and path.
-	 *
-	 * @param request
-	 *            the request
-	 * @param path
-	 *            the path
-	 *
-	 * @return the large file repository storing large files.
-	 * @throws LfsException
-	 *             implementations should throw more specific exceptions to
-	 *             signal which type of error occurred:
-	 *             <dl>
-	 *             <dt>{@link LfsValidationError}</dt>
-	 *             <dd>when there is a validation error with one or more of the
-	 *             objects in the request</dd>
-	 *             <dt>{@link LfsRepositoryNotFound}</dt>
-	 *             <dd>when the repository does not exist for the user</dd>
-	 *             <dt>{@link LfsRepositoryReadOnly}</dt>
-	 *             <dd>when the user has read, but not write access. Only
-	 *             applicable when the operation in the request is "upload"</dd>
-	 *             <dt>{@link LfsRateLimitExceeded}</dt>
-	 *             <dd>when the user has hit a rate limit with the server</dd>
-	 *             <dt>{@link LfsBandwidthLimitExceeded}</dt>
-	 *             <dd>when the bandwidth limit for the user or repository has
-	 *             been exceeded</dd>
-	 *             <dt>{@link LfsInsufficientStorage}</dt>
-	 *             <dd>when there is insufficient storage on the server</dd>
-	 *             <dt>{@link LfsUnavailable}</dt>
-	 *             <dd>when LFS is not available</dd>
-	 *             <dt>{@link LfsException}</dt>
-	 *             <dd>when an unexpected internal server error occurred</dd>
-	 *             </dl>
-	 * @since 4.5
-	 * @deprecated use
-	 *             {@link #getLargeFileRepository(LfsRequest, String, String)}
-	 */
-	@Deprecated
-	protected LargeFileRepository getLargeFileRepository(LfsRequest request,
-			String path) throws LfsException {
-		return getLargeFileRepository(request, path, null);
-	}
-
 	/**
 	 * Get the large file repository for the given request and path.
 	 *
@@ -162,30 +114,29 @@ protected LargeFileRepository getLargeFileRepository(LfsRequest request,
 	 *            the path
 	 * @param auth
 	 *            the Authorization HTTP header
-	 *
 	 * @return the large file repository storing large files.
-	 * @throws LfsException
+	 * @throws org.eclipse.jgit.lfs.errors.LfsException
 	 *             implementations should throw more specific exceptions to
 	 *             signal which type of error occurred:
 	 *             <dl>
-	 *             <dt>{@link LfsValidationError}</dt>
+	 *             <dt>{@link org.eclipse.jgit.lfs.errors.LfsValidationError}</dt>
 	 *             <dd>when there is a validation error with one or more of the
 	 *             objects in the request</dd>
-	 *             <dt>{@link LfsRepositoryNotFound}</dt>
+	 *             <dt>{@link org.eclipse.jgit.lfs.errors.LfsRepositoryNotFound}</dt>
 	 *             <dd>when the repository does not exist for the user</dd>
-	 *             <dt>{@link LfsRepositoryReadOnly}</dt>
+	 *             <dt>{@link org.eclipse.jgit.lfs.errors.LfsRepositoryReadOnly}</dt>
 	 *             <dd>when the user has read, but not write access. Only
 	 *             applicable when the operation in the request is "upload"</dd>
-	 *             <dt>{@link LfsRateLimitExceeded}</dt>
+	 *             <dt>{@link org.eclipse.jgit.lfs.errors.LfsRateLimitExceeded}</dt>
 	 *             <dd>when the user has hit a rate limit with the server</dd>
-	 *             <dt>{@link LfsBandwidthLimitExceeded}</dt>
+	 *             <dt>{@link org.eclipse.jgit.lfs.errors.LfsBandwidthLimitExceeded}</dt>
 	 *             <dd>when the bandwidth limit for the user or repository has
 	 *             been exceeded</dd>
-	 *             <dt>{@link LfsInsufficientStorage}</dt>
+	 *             <dt>{@link org.eclipse.jgit.lfs.errors.LfsInsufficientStorage}</dt>
 	 *             <dd>when there is insufficient storage on the server</dd>
-	 *             <dt>{@link LfsUnavailable}</dt>
+	 *             <dt>{@link org.eclipse.jgit.lfs.errors.LfsUnavailable}</dt>
 	 *             <dd>when LFS is not available</dd>
-	 *             <dt>{@link LfsException}</dt>
+	 *             <dt>{@link org.eclipse.jgit.lfs.errors.LfsException}</dt>
 	 *             <dd>when an unexpected internal server error occurred</dd>
 	 *             </dl>
 	 * @since 4.7
@@ -246,15 +197,16 @@ public boolean isVerify() {
 		}
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected void doPost(HttpServletRequest req, HttpServletResponse res)
 			throws ServletException, IOException {
 		Writer w = new BufferedWriter(
-				new OutputStreamWriter(res.getOutputStream(), UTF_8));
+				new OutputStreamWriter(res.getOutputStream(), CHARSET));
 
 		Reader r = new BufferedReader(
-				new InputStreamReader(req.getInputStream(), UTF_8));
-		LfsRequest request = gson.fromJson(r, LfsRequest.class);
+				new InputStreamReader(req.getInputStream(), CHARSET));
+		LfsRequest request = LfsGson.fromJson(r, LfsRequest.class);
 		String path = req.getPathInfo();
 
 		res.setContentType(CONTENTTYPE_VND_GIT_LFS_JSON);
@@ -271,7 +223,7 @@ protected void doPost(HttpServletRequest req, HttpServletResponse res)
 			res.setStatus(SC_OK);
 			TransferHandler handler = TransferHandler
 					.forOperation(request.operation, repo, request.objects);
-			gson.toJson(handler.process(), w);
+			LfsGson.toJson(handler.process(), w);
 		} catch (LfsValidationError e) {
 			sendError(res, w, SC_UNPROCESSABLE_ENTITY, e.getMessage());
 		} catch (LfsRepositoryNotFound e) {
@@ -295,24 +247,9 @@ protected void doPost(HttpServletRequest req, HttpServletResponse res)
 		}
 	}
 
-	static class Error {
-		String message;
-
-		Error(String m) {
-			this.message = m;
-		}
-	}
-
 	private void sendError(HttpServletResponse rsp, Writer writer, int status,
 			String message) {
 		rsp.setStatus(status);
-		gson.toJson(new Error(message), writer);
-	}
-
-	private Gson createGson() {
-		return new GsonBuilder()
-				.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
-				.disableHtmlEscaping()
-				.create();
+		LfsGson.toJson(message, writer);
 	}
 }
diff --git a/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/Response.java b/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/Response.java
index dc972e0..a80e5b9 100644
--- a/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/Response.java
+++ b/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/Response.java
@@ -46,11 +46,10 @@
 import java.util.Map;
 
 /**
- * POJOs for Gson serialization/deserialization
+ * POJOs for Gson serialization/de-serialization.
  *
- * See
- * {@link <a href="https://github.com/github/git-lfs/tree/master/docs/api">LFS
- * API specification</a>}
+ * See the <a href="https://github.com/github/git-lfs/tree/master/docs/api">LFS
+ * API specification</a>
  *
  * @since 4.3
  */
diff --git a/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/fs/FileLfsRepository.java b/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/fs/FileLfsRepository.java
index a05fa01..55d9093 100644
--- a/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/fs/FileLfsRepository.java
+++ b/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/fs/FileLfsRepository.java
@@ -67,15 +67,17 @@
  */
 public class FileLfsRepository implements LargeFileRepository {
 
-	private final String url;
+	private String url;
 	private final Path dir;
 
 	/**
+	 * <p>Constructor for FileLfsRepository.</p>
+	 *
 	 * @param url
 	 *            external URL of this repository
 	 * @param dir
 	 *            storage directory
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 */
 	public FileLfsRepository(String url, Path dir) throws IOException {
 		this.url = url;
@@ -83,21 +85,25 @@ public FileLfsRepository(String url, Path dir) throws IOException {
 		Files.createDirectories(dir);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public Response.Action getDownloadAction(AnyLongObjectId id) {
 		return getAction(id);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public Action getUploadAction(AnyLongObjectId id, long size) {
 		return getAction(id);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public @Nullable Action getVerifyAction(AnyLongObjectId id) {
 		return null;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public long getSize(AnyLongObjectId id) throws IOException {
 		Path p = getPath(id);
@@ -164,7 +170,7 @@ AtomicObjectOutputStream getOutputStream(AnyLongObjectId id)
 	private static final char[] hexchar = { '0', '1', '2', '3', '4', '5', '6',
 			'7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
 
-	private static void formatHexChar(final char[] dst, final int p, int b) {
+	private static void formatHexChar(char[] dst, int p, int b) {
 		int o = p + 1;
 		while (o >= p && b != 0) {
 			dst[o--] = hexchar[b & 0xf];
@@ -173,4 +179,21 @@ private static void formatHexChar(final char[] dst, final int p, int b) {
 		while (o >= p)
 			dst[o--] = '0';
 	}
+
+	/**
+	 * @return the url of the content server
+	 * @since 4.11
+	 */
+	public String getUrl() {
+		return url;
+	}
+
+	/**
+	 * @param url
+	 *            the url of the content server
+	 * @since 4.11
+	 */
+	public void setUrl(String url) {
+		this.url = url;
+	}
 }
diff --git a/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/fs/FileLfsServlet.java b/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/fs/FileLfsServlet.java
index b13beb5..36dc760 100644
--- a/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/fs/FileLfsServlet.java
+++ b/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/fs/FileLfsServlet.java
@@ -58,12 +58,9 @@
 import org.eclipse.jgit.lfs.lib.AnyLongObjectId;
 import org.eclipse.jgit.lfs.lib.Constants;
 import org.eclipse.jgit.lfs.lib.LongObjectId;
+import org.eclipse.jgit.lfs.server.internal.LfsGson;
 import org.eclipse.jgit.lfs.server.internal.LfsServerText;
 
-import com.google.gson.FieldNamingPolicy;
-import com.google.gson.Gson;
-import com.google.gson.GsonBuilder;
-
 /**
  * Servlet supporting upload and download of large objects as defined by the
  * GitHub Large File Storage extension API extending git to allow separate
@@ -81,9 +78,9 @@ public class FileLfsServlet extends HttpServlet {
 
 	private final long timeout;
 
-	private static Gson gson = createGson();
-
 	/**
+	 * <p>Constructor for FileLfsServlet.</p>
+	 *
 	 * @param repository
 	 *            the repository storing the large objects
 	 * @param timeout
@@ -95,16 +92,9 @@ public FileLfsServlet(FileLfsRepository repository, long timeout) {
 	}
 
 	/**
-	 * Handles object downloads
+	 * {@inheritDoc}
 	 *
-	 * @param req
-	 *            servlet request
-	 * @param rsp
-	 *            servlet response
-	 * @throws ServletException
-	 *             if a servlet-specific error occurs
-	 * @throws IOException
-	 *             if an I/O error occurs
+	 * Handle object downloads
 	 */
 	@Override
 	protected void doGet(HttpServletRequest req,
@@ -134,9 +124,9 @@ protected void doGet(HttpServletRequest req,
 	 *            servlet response
 	 * @return object id, or <code>null</code> if the object id could not be
 	 *         retrieved
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             if an I/O error occurs
-         * @since 4.6
+	 * @since 4.6
 	 */
 	protected AnyLongObjectId getObjectToTransfer(HttpServletRequest req,
 			HttpServletResponse rsp) throws IOException {
@@ -156,16 +146,9 @@ protected AnyLongObjectId getObjectToTransfer(HttpServletRequest req,
 	}
 
 	/**
-	 * Handle object uploads
+	 * {@inheritDoc}
 	 *
-	 * @param req
-	 *            servlet request
-	 * @param rsp
-	 *            servlet response
-	 * @throws ServletException
-	 *             if a servlet-specific error occurs
-	 * @throws IOException
-	 *             if an I/O error occurs
+	 * Handle object uploads
 	 */
 	@Override
 	protected void doPut(HttpServletRequest req,
@@ -179,14 +162,6 @@ protected void doPut(HttpServletRequest req,
 		}
 	}
 
-	static class Error {
-		String message;
-
-		Error(String m) {
-			this.message = m;
-		}
-	}
-
 	/**
 	 * Send an error response.
 	 *
@@ -196,24 +171,17 @@ static class Error {
 	 *            HTTP status code
 	 * @param message
 	 *            error message
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             on failure to send the response
 	 * @since 4.6
 	 */
 	protected static void sendError(HttpServletResponse rsp, int status, String message)
 			throws IOException {
 		rsp.setStatus(status);
-		PrintWriter writer = rsp.getWriter();
-		gson.toJson(new Error(message), writer);
-		writer.flush();
-		writer.close();
+		try (PrintWriter writer = rsp.getWriter()) {
+			LfsGson.toJson(message, writer);
+			writer.flush();
+		}
 		rsp.flushBuffer();
 	}
-
-	private static Gson createGson() {
-		return new GsonBuilder()
-				.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
-				.disableHtmlEscaping()
-				.create();
-	}
 }
diff --git a/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/fs/ObjectDownloadListener.java b/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/fs/ObjectDownloadListener.java
index cc43500..ec1d3cd 100644
--- a/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/fs/ObjectDownloadListener.java
+++ b/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/fs/ObjectDownloadListener.java
@@ -83,6 +83,8 @@ public class ObjectDownloadListener implements WriteListener {
 	private final ByteBuffer buffer = ByteBuffer.allocateDirect(8192);
 
 	/**
+	 * <p>Constructor for ObjectDownloadListener.</p>
+	 *
 	 * @param repository
 	 *            the repository storing large objects
 	 * @param context
@@ -91,7 +93,7 @@ public class ObjectDownloadListener implements WriteListener {
 	 *            the servlet response
 	 * @param id
 	 *            id of the object to be downloaded
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 */
 	public ObjectDownloadListener(FileLfsRepository repository,
 			AsyncContext context, HttpServletResponse response,
@@ -108,9 +110,9 @@ public ObjectDownloadListener(FileLfsRepository repository,
 	}
 
 	/**
-	 * Write file content
+	 * {@inheritDoc}
 	 *
-	 * @throws IOException
+	 * Write file content
 	 */
 	@Override
 	public void onWritePossible() throws IOException {
@@ -134,10 +136,9 @@ public void onWritePossible() throws IOException {
 	}
 
 	/**
-	 * Handle errors
+	 * {@inheritDoc}
 	 *
-	 * @param e
-	 *            the cause
+	 * Handle errors
 	 */
 	@Override
 	public void onError(Throwable e) {
diff --git a/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/fs/ObjectUploadListener.java b/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/fs/ObjectUploadListener.java
index 84e4e6f..e4c04c1 100644
--- a/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/fs/ObjectUploadListener.java
+++ b/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/fs/ObjectUploadListener.java
@@ -88,14 +88,20 @@ public class ObjectUploadListener implements ReadListener {
 	private final ByteBuffer buffer = ByteBuffer.allocateDirect(8192);
 
 	/**
+	 * Constructor for ObjectUploadListener.
+	 *
 	 * @param repository
 	 *            the repository storing large objects
 	 * @param context
+	 *            a {@link javax.servlet.AsyncContext} object.
 	 * @param request
+	 *            a {@link javax.servlet.http.HttpServletRequest} object.
 	 * @param response
+	 *            a {@link javax.servlet.http.HttpServletResponse} object.
 	 * @param id
-	 * @throws FileNotFoundException
-	 * @throws IOException
+	 *            a {@link org.eclipse.jgit.lfs.lib.AnyLongObjectId} object.
+	 * @throws java.io.FileNotFoundException
+	 * @throws java.io.IOException
 	 */
 	public ObjectUploadListener(FileLfsRepository repository,
 			AsyncContext context, HttpServletRequest request,
@@ -111,9 +117,9 @@ public ObjectUploadListener(FileLfsRepository repository,
 	}
 
 	/**
-	 * Writes all the received data to the output channel
+	 * {@inheritDoc}
 	 *
-	 * @throws IOException
+	 * Writes all the received data to the output channel
 	 */
 	@Override
 	public void onDataAvailable() throws IOException {
@@ -133,16 +139,16 @@ public void onDataAvailable() throws IOException {
 		}
 	}
 
-	/**
-	 * @throws IOException
-	 */
+	/** {@inheritDoc} */
 	@Override
 	public void onAllDataRead() throws IOException {
 		close();
 	}
 
 	/**
-	 * @throws IOException
+	 * Close resources held by this listener
+	 *
+	 * @throws java.io.IOException
 	 */
 	protected void close() throws IOException {
 		try {
@@ -156,10 +162,7 @@ protected void close() throws IOException {
 		}
 	}
 
-	/**
-	 * @param e
-	 *            the exception that caused the problem
-	 */
+	/** {@inheritDoc} */
 	@Override
 	public void onError(Throwable e) {
 		try {
diff --git a/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/internal/LfsGson.java b/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/internal/LfsGson.java
new file mode 100644
index 0000000..7974b24
--- /dev/null
+++ b/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/internal/LfsGson.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2017, David Pursehouse <david.pursehouse@gmail.com>
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ *   copyright notice, this list of conditions and the following
+ *   disclaimer in the documentation and/or other materials provided
+ *   with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ *   names of its contributors may be used to endorse or promote
+ *   products derived from this software without specific prior
+ *   written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.lfs.server.internal;
+
+import java.io.Reader;
+
+import com.google.gson.FieldNamingPolicy;
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.google.gson.JsonIOException;
+import com.google.gson.JsonSyntaxException;
+
+/**
+ * Wrapper for {@link com.google.gson.Gson} used by LFS servlets.
+ *
+ * @since 4.10.0
+ */
+public class LfsGson {
+	private static final Gson gson = new GsonBuilder()
+			.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
+			.disableHtmlEscaping()
+			.create();
+
+	/**
+	 * Wrapper class only used for serialization of error messages.
+	 */
+	static class Error {
+		String message;
+
+		Error(String m) {
+			this.message = m;
+		}
+	}
+
+	/**
+	 * Serializes the specified object into its equivalent Json representation.
+	 *
+	 * @param src
+	 *            the object for which Json representation is to be created. If
+	 *            this is a String, it is wrapped in an instance of
+	 *            {@link org.eclipse.jgit.lfs.server.internal.LfsGson.Error}.
+	 * @param writer
+	 *            Writer to which the Json representation needs to be written
+	 * @throws com.google.gson.JsonIOException
+	 *             if there was a problem writing to the writer
+	 * @see Gson#toJson(Object, Appendable)
+	 */
+	public static void toJson(Object src, Appendable writer)
+			throws JsonIOException {
+		if (src instanceof String) {
+			gson.toJson(new Error((String) src), writer);
+		} else {
+			gson.toJson(src, writer);
+		}
+	}
+
+	/**
+	 * Deserializes the Json read from the specified reader into an object of
+	 * the specified type.
+	 *
+	 * @param json
+	 *            reader producing json from which the object is to be
+	 *            deserialized
+	 * @param classOfT
+	 *            specified type to deserialize
+	 * @return an Object of type T
+	 * @throws com.google.gson.JsonIOException
+	 *             if there was a problem reading from the Reader
+	 * @throws com.google.gson.JsonSyntaxException
+	 *             if json is not a valid representation for an object of type
+	 * @see Gson#fromJson(Reader, java.lang.reflect.Type)
+	 * @param <T>
+	 *            a T object.
+	 */
+	public static <T> T fromJson(Reader json, Class<T> classOfT)
+			throws JsonSyntaxException, JsonIOException {
+		return gson.fromJson(json, classOfT);
+	}
+}
diff --git a/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/internal/LfsServerText.java b/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/internal/LfsServerText.java
index 2e088fd..5d6bbfa 100644
--- a/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/internal/LfsServerText.java
+++ b/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/internal/LfsServerText.java
@@ -51,6 +51,8 @@
 public class LfsServerText extends TranslationBundle {
 
 	/**
+	 * Get an instance of this translation bundle
+	 *
 	 * @return an instance of this translation bundle
 	 */
 	public static LfsServerText get() {
diff --git a/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/s3/S3Config.java b/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/s3/S3Config.java
index 4876fb8..4c21421 100644
--- a/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/s3/S3Config.java
+++ b/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/s3/S3Config.java
@@ -58,6 +58,8 @@ public class S3Config {
 	private final boolean disableSslVerify;
 
 	/**
+	 * <p>Constructor for S3Config.</p>
+	 *
 	 * @param region
 	 *            AWS region
 	 * @param bucket
@@ -88,6 +90,8 @@ public S3Config(String region, String bucket, String storageClass,
 	}
 
 	/**
+	 * Get the <code>region</code>.
+	 *
 	 * @return Get name of AWS region this bucket resides in
 	 */
 	public String getRegion() {
@@ -95,6 +99,8 @@ public String getRegion() {
 	}
 
 	/**
+	 * Get the <code>bucket</code>.
+	 *
 	 * @return Get S3 storage bucket name
 	 */
 	public String getBucket() {
@@ -102,6 +108,8 @@ public String getBucket() {
 	}
 
 	/**
+	 * Get the <code>storageClass</code>.
+	 *
 	 * @return S3 storage class to use for objects stored in this bucket
 	 */
 	public String getStorageClass() {
@@ -109,6 +117,8 @@ public String getStorageClass() {
 	}
 
 	/**
+	 * Get the <code>accessKey</code>.
+	 *
 	 * @return access key for authenticating to AWS
 	 */
 	public String getAccessKey() {
@@ -116,6 +126,8 @@ public String getAccessKey() {
 	}
 
 	/**
+	 * Get the <code>secretKey</code>.
+	 *
 	 * @return secret key for authenticating to AWS
 	 */
 	public String getSecretKey() {
@@ -123,6 +135,8 @@ public String getSecretKey() {
 	}
 
 	/**
+	 * Get the <code>expirationSeconds</code>.
+	 *
 	 * @return period in seconds after which requests signed for this bucket
 	 *         will expire
 	 */
diff --git a/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/s3/S3Repository.java b/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/s3/S3Repository.java
index ed896ad..043d3d0 100644
--- a/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/s3/S3Repository.java
+++ b/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/s3/S3Repository.java
@@ -91,6 +91,7 @@ public S3Repository(S3Config config) {
 		this.s3Config = config;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public Response.Action getDownloadAction(AnyLongObjectId oid) {
 		URL endpointUrl = getObjectUrl(oid);
@@ -107,6 +108,7 @@ public Response.Action getDownloadAction(AnyLongObjectId oid) {
 		return a;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public Response.Action getUploadAction(AnyLongObjectId oid, long size) {
 		cacheObjectMetaData(oid, size);
@@ -126,11 +128,13 @@ public Response.Action getUploadAction(AnyLongObjectId oid, long size) {
 		return a;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public Action getVerifyAction(AnyLongObjectId id) {
 		return null; // TODO(ms) implement this
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public long getSize(AnyLongObjectId oid) throws IOException {
 		URL endpointUrl = getObjectUrl(oid);
diff --git a/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/s3/SignerV4.java b/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/s3/SignerV4.java
index a9b0ec4..374a560 100644
--- a/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/s3/SignerV4.java
+++ b/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/s3/SignerV4.java
@@ -43,12 +43,12 @@
  */
 package org.eclipse.jgit.lfs.server.s3;
 
+import static org.eclipse.jgit.lib.Constants.CHARSET;
 import static org.eclipse.jgit.util.HttpSupport.HDR_AUTHORIZATION;
 
 import java.io.UnsupportedEncodingException;
 import java.net.URL;
 import java.net.URLEncoder;
-import java.nio.charset.StandardCharsets;
 import java.security.MessageDigest;
 import java.text.MessageFormat;
 import java.text.SimpleDateFormat;
@@ -359,13 +359,13 @@ private static String canonicalizeResourcePath(URL endpoint) {
 
 	private static byte[] hash(String s) {
 		MessageDigest md = Constants.newMessageDigest();
-		md.update(s.getBytes(StandardCharsets.UTF_8));
+		md.update(s.getBytes(CHARSET));
 		return md.digest();
 	}
 
 	private static byte[] sign(String stringData, byte[] key) {
 		try {
-			byte[] data = stringData.getBytes("UTF-8"); //$NON-NLS-1$
+			byte[] data = stringData.getBytes(CHARSET);
 			Mac mac = Mac.getInstance(HMACSHA256);
 			mac.init(new SecretKeySpec(key, HMACSHA256));
 			return mac.doFinal(data);
@@ -395,7 +395,7 @@ private static String toHex(byte[] bytes) {
 	private static String urlEncode(String url, boolean keepPathSlash) {
 		String encoded;
 		try {
-			encoded = URLEncoder.encode(url, StandardCharsets.UTF_8.name());
+			encoded = URLEncoder.encode(url, CHARSET.name());
 		} catch (UnsupportedEncodingException e) {
 			throw new RuntimeException(LfsServerText.get().unsupportedUtf8, e);
 		}
diff --git a/org.eclipse.jgit.lfs.test/.settings/org.eclipse.jdt.core.prefs b/org.eclipse.jgit.lfs.test/.settings/org.eclipse.jdt.core.prefs
index 64f7498..794592d 100644
--- a/org.eclipse.jgit.lfs.test/.settings/org.eclipse.jdt.core.prefs
+++ b/org.eclipse.jgit.lfs.test/.settings/org.eclipse.jdt.core.prefs
@@ -25,7 +25,7 @@
 org.eclipse.jdt.core.compiler.problem.discouragedReference=warning
 org.eclipse.jdt.core.compiler.problem.emptyStatement=warning
 org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
-org.eclipse.jdt.core.compiler.problem.explicitlyClosedAutoCloseable=ignore
+org.eclipse.jdt.core.compiler.problem.explicitlyClosedAutoCloseable=warning
 org.eclipse.jdt.core.compiler.problem.fallthroughCase=warning
 org.eclipse.jdt.core.compiler.problem.fatalOptionalError=disabled
 org.eclipse.jdt.core.compiler.problem.fieldHiding=warning
diff --git a/org.eclipse.jgit.lfs.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.lfs.test/META-INF/MANIFEST.MF
index 5576d7f..eda0867 100644
--- a/org.eclipse.jgit.lfs.test/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.lfs.test/META-INF/MANIFEST.MF
@@ -1,24 +1,25 @@
 Manifest-Version: 1.0
 Bundle-ManifestVersion: 2
 Bundle-Name: %plugin_name
+Automatic-Module-Name: org.eclipse.jgit.lfs.test
 Bundle-SymbolicName: org.eclipse.jgit.lfs.test
-Bundle-Version: 4.9.3.qualifier
+Bundle-Version: 5.0.0.qualifier
 Bundle-Vendor: %provider_name
 Bundle-Localization: plugin
 Bundle-RequiredExecutionEnvironment: JavaSE-1.8
-Import-Package: org.eclipse.jgit.internal.storage.dfs;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.junit;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.lfs;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.lfs.errors;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.lfs.lib;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.lib;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.revwalk;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.treewalk;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.treewalk.filter;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.util;version="[4.9.3,4.10.0)",
+Import-Package: org.eclipse.jgit.internal.storage.dfs;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.junit;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.lfs;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.lfs.errors;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.lfs.lib;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.lib;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.revwalk;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.treewalk;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.treewalk.filter;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.util;version="[5.0.0,5.1.0)",
  org.hamcrest.core;version="[1.1.0,2.0.0)",
- org.junit;version="[4.0.0,5.0.0)",
- org.junit.runner;version="[4.0.0,5.0.0)",
- org.junit.runners;version="[4.0.0,5.0.0)"
-Export-Package: org.eclipse.jgit.lfs.test;version="4.9.3";x-friends:="org.eclipse.jgit.lfs.server.test"
+ org.junit;version="[4.12,5.0.0)",
+ org.junit.runner;version="[4.12,5.0.0)",
+ org.junit.runners;version="[4.12,5.0.0)"
+Export-Package: org.eclipse.jgit.lfs.test;version="5.0.0";x-friends:="org.eclipse.jgit.lfs.server.test"
 
diff --git a/org.eclipse.jgit.lfs.test/pom.xml b/org.eclipse.jgit.lfs.test/pom.xml
index d810898..7c6aa72 100644
--- a/org.eclipse.jgit.lfs.test/pom.xml
+++ b/org.eclipse.jgit.lfs.test/pom.xml
@@ -50,7 +50,7 @@
   <parent>
     <groupId>org.eclipse.jgit</groupId>
     <artifactId>org.eclipse.jgit-parent</artifactId>
-    <version>4.9.3-SNAPSHOT</version>
+    <version>5.0.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>org.eclipse.jgit.lfs.test</artifactId>
diff --git a/org.eclipse.jgit.lfs.test/src/org/eclipse/jgit/lfs/test/LongObjectIdTestUtils.java b/org.eclipse.jgit.lfs.test/src/org/eclipse/jgit/lfs/test/LongObjectIdTestUtils.java
index 6c6400f..e3c6ef8 100644
--- a/org.eclipse.jgit.lfs.test/src/org/eclipse/jgit/lfs/test/LongObjectIdTestUtils.java
+++ b/org.eclipse.jgit.lfs.test/src/org/eclipse/jgit/lfs/test/LongObjectIdTestUtils.java
@@ -42,11 +42,12 @@
  */
 package org.eclipse.jgit.lfs.test;
 
+import static org.eclipse.jgit.lib.Constants.CHARSET;
+
 import java.io.BufferedInputStream;
 import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.InputStream;
-import java.nio.charset.StandardCharsets;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.security.MessageDigest;
@@ -65,7 +66,7 @@ public class LongObjectIdTestUtils {
 	 */
 	public static LongObjectId hash(String s) {
 		MessageDigest md = Constants.newMessageDigest();
-		md.update(s.getBytes(StandardCharsets.UTF_8));
+		md.update(s.getBytes(CHARSET));
 		return LongObjectId.fromRaw(md.digest());
 	}
 
diff --git a/org.eclipse.jgit.lfs.test/tst/org/eclipse/jgit/lfs/lib/AbbreviatedLongObjectIdTest.java b/org.eclipse.jgit.lfs.test/tst/org/eclipse/jgit/lfs/lib/AbbreviatedLongObjectIdTest.java
index 8938a78..2a8f66e 100644
--- a/org.eclipse.jgit.lfs.test/tst/org/eclipse/jgit/lfs/lib/AbbreviatedLongObjectIdTest.java
+++ b/org.eclipse.jgit.lfs.test/tst/org/eclipse/jgit/lfs/lib/AbbreviatedLongObjectIdTest.java
@@ -587,6 +587,7 @@ public void testGetFirstByte() {
 		assertEquals(id.getFirstByte(), a.getFirstByte());
 	}
 
+	@SuppressWarnings("unlikely-arg-type")
 	@Test
 	public void testNotEquals() {
 		AbbreviatedLongObjectId a = new LongObjectId(1L, 2L, 3L, 4L)
diff --git a/org.eclipse.jgit.lfs.test/tst/org/eclipse/jgit/lfs/lib/LFSPointerTest.java b/org.eclipse.jgit.lfs.test/tst/org/eclipse/jgit/lfs/lib/LFSPointerTest.java
index 4827d3d..a1283dd 100644
--- a/org.eclipse.jgit.lfs.test/tst/org/eclipse/jgit/lfs/lib/LFSPointerTest.java
+++ b/org.eclipse.jgit.lfs.test/tst/org/eclipse/jgit/lfs/lib/LFSPointerTest.java
@@ -43,11 +43,11 @@
 
 package org.eclipse.jgit.lfs.lib;
 
+import static org.eclipse.jgit.lib.Constants.CHARACTER_ENCODING;
 import static org.junit.Assert.assertEquals;
 
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
-import java.nio.charset.StandardCharsets;
 
 import org.eclipse.jgit.lfs.LfsPointer;
 import org.junit.Test;
@@ -61,11 +61,12 @@ public void testEncoding() throws IOException {
 		final String s = "27e15b72937fc8f558da24ac3d50ec20302a4cf21e33b87ae8e4ce90e89c4b10";
 		AnyLongObjectId id = LongObjectId.fromString(s);
 		LfsPointer ptr = new LfsPointer(id, 4);
-		ByteArrayOutputStream baos = new ByteArrayOutputStream();
-		ptr.encode(baos);
-		baos.close();
-		assertEquals("version https://git-lfs.github.com/spec/v1\noid sha256:"
-				+ s + "\nsize 4\n",
-				baos.toString(StandardCharsets.UTF_8.name()));
+		try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
+			ptr.encode(baos);
+			assertEquals(
+					"version https://git-lfs.github.com/spec/v1\noid sha256:"
+							+ s + "\nsize 4\n",
+					baos.toString(CHARACTER_ENCODING));
+		}
 	}
 }
diff --git a/org.eclipse.jgit.lfs.test/tst/org/eclipse/jgit/lfs/lib/LongObjectIdTest.java b/org.eclipse.jgit.lfs.test/tst/org/eclipse/jgit/lfs/lib/LongObjectIdTest.java
index 31ab783..8642e7e 100644
--- a/org.eclipse.jgit.lfs.test/tst/org/eclipse/jgit/lfs/lib/LongObjectIdTest.java
+++ b/org.eclipse.jgit.lfs.test/tst/org/eclipse/jgit/lfs/lib/LongObjectIdTest.java
@@ -43,6 +43,7 @@
 
 package org.eclipse.jgit.lfs.lib;
 
+import static java.nio.charset.StandardCharsets.US_ASCII;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotEquals;
@@ -54,7 +55,6 @@
 import java.io.OutputStreamWriter;
 import java.nio.ByteBuffer;
 import java.nio.charset.Charset;
-import java.nio.charset.StandardCharsets;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.util.Locale;
@@ -270,7 +270,7 @@ public void testCopyFromStringInvalid() {
 	public void testCopyFromStringByte() {
 		AnyLongObjectId id1 = LongObjectIdTestUtils.hash("test");
 		byte[] buf = new byte[64];
-		Charset cs = StandardCharsets.US_ASCII;
+		Charset cs = US_ASCII;
 		cs.encode(id1.name()).get(buf);
 		AnyLongObjectId id2 = LongObjectId.fromString(buf, 0);
 		assertEquals("objects should be equals", id1, id2);
@@ -392,9 +392,10 @@ public void testCopyToOutputStream() throws IOException {
 	public void testCopyToWriter() throws IOException {
 		AnyLongObjectId id1 = LongObjectIdTestUtils.hash("test");
 		ByteArrayOutputStream os = new ByteArrayOutputStream(64);
-		OutputStreamWriter w = new OutputStreamWriter(os, Constants.CHARSET);
-		id1.copyTo(w);
-		w.close();
+		try (OutputStreamWriter w = new OutputStreamWriter(os,
+				Constants.CHARSET)) {
+			id1.copyTo(w);
+		}
 		assertEquals(id1, LongObjectId.fromString(os.toByteArray(), 0));
 	}
 
@@ -402,10 +403,11 @@ public void testCopyToWriter() throws IOException {
 	public void testCopyToWriterWithBuf() throws IOException {
 		AnyLongObjectId id1 = LongObjectIdTestUtils.hash("test");
 		ByteArrayOutputStream os = new ByteArrayOutputStream(64);
-		OutputStreamWriter w = new OutputStreamWriter(os, Constants.CHARSET);
-		char[] buf = new char[64];
-		id1.copyTo(buf, w);
-		w.close();
+		try (OutputStreamWriter w = new OutputStreamWriter(os,
+				Constants.CHARSET)) {
+			char[] buf = new char[64];
+			id1.copyTo(buf, w);
+		}
 		assertEquals(id1, LongObjectId.fromString(os.toByteArray(), 0));
 	}
 
diff --git a/org.eclipse.jgit.lfs/.settings/org.eclipse.jdt.core.prefs b/org.eclipse.jgit.lfs/.settings/org.eclipse.jdt.core.prefs
index ede0f7d..89394ec 100644
--- a/org.eclipse.jgit.lfs/.settings/org.eclipse.jdt.core.prefs
+++ b/org.eclipse.jgit.lfs/.settings/org.eclipse.jdt.core.prefs
@@ -25,7 +25,7 @@
 org.eclipse.jdt.core.compiler.problem.discouragedReference=warning
 org.eclipse.jdt.core.compiler.problem.emptyStatement=warning
 org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
-org.eclipse.jdt.core.compiler.problem.explicitlyClosedAutoCloseable=ignore
+org.eclipse.jdt.core.compiler.problem.explicitlyClosedAutoCloseable=warning
 org.eclipse.jdt.core.compiler.problem.fallthroughCase=warning
 org.eclipse.jdt.core.compiler.problem.fatalOptionalError=disabled
 org.eclipse.jdt.core.compiler.problem.fieldHiding=warning
diff --git a/org.eclipse.jgit.lfs/BUILD b/org.eclipse.jgit.lfs/BUILD
index 0c7b1b2..cd291da 100644
--- a/org.eclipse.jgit.lfs/BUILD
+++ b/org.eclipse.jgit.lfs/BUILD
@@ -6,6 +6,7 @@
     resource_strip_prefix = "org.eclipse.jgit.lfs/resources",
     resources = glob(["resources/**"]),
     deps = [
+        "//lib:gson",
         "//org.eclipse.jgit:jgit",
     ],
 )
diff --git a/org.eclipse.jgit.lfs/META-INF/MANIFEST.MF b/org.eclipse.jgit.lfs/META-INF/MANIFEST.MF
index cbd4278..acc3532 100644
--- a/org.eclipse.jgit.lfs/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.lfs/META-INF/MANIFEST.MF
@@ -1,21 +1,35 @@
 Manifest-Version: 1.0
 Bundle-ManifestVersion: 2
 Bundle-Name: %plugin_name
+Automatic-Module-Name: org.eclipse.jgit.lfs
 Bundle-SymbolicName: org.eclipse.jgit.lfs
-Bundle-Version: 4.9.3.qualifier
+Bundle-Version: 5.0.0.qualifier
 Bundle-Localization: plugin
 Bundle-Vendor: %provider_name
-Export-Package: org.eclipse.jgit.lfs;version="4.9.3",
- org.eclipse.jgit.lfs.errors;version="4.9.3",
- org.eclipse.jgit.lfs.internal;version="4.9.3";x-friends:="org.eclipse.jgit.lfs.test,org.eclipse.jgit.lfs.server.fs,org.eclipse.jgit.lfs.server",
- org.eclipse.jgit.lfs.lib;version="4.9.3"
+Export-Package: org.eclipse.jgit.lfs;version="5.0.0",
+ org.eclipse.jgit.lfs.errors;version="5.0.0",
+ org.eclipse.jgit.lfs.internal;version="5.0.0";x-friends:="org.eclipse.jgit.lfs.test,org.eclipse.jgit.lfs.server.fs,org.eclipse.jgit.lfs.server",
+ org.eclipse.jgit.lfs.lib;version="5.0.0"
 Bundle-RequiredExecutionEnvironment: JavaSE-1.8
-Import-Package: org.eclipse.jgit.annotations;version="[4.9.3,4.10.0)";resolution:=optional,
- org.eclipse.jgit.attributes;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.errors;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.internal.storage.file;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.lib;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.nls;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.treewalk;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.treewalk.filter;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.util;version="[4.9.3,4.10.0)"
+Import-Package: com.google.gson;version="[2.8.2,3.0.0)",
+ com.google.gson.stream;version="[2.8.2,3.0.0)",
+ org.apache.http.impl.client;version="[4.2.6,5.0.0)",
+ org.apache.http.impl.conn;version="[4.2.6,5.0.0)",
+ org.eclipse.jgit.annotations;version="[5.0.0,5.1.0)";resolution:=optional,
+ org.eclipse.jgit.api.errors;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.attributes;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.diff;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.errors;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.hooks;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.internal.storage.file;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.lib;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.nls;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.revwalk;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.storage.file;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.storage.pack;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.transport;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.transport.http;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.treewalk;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.treewalk.filter;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.util;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.util.io;version="[5.0.0,5.1.0)"
diff --git a/org.eclipse.jgit.lfs/pom.xml b/org.eclipse.jgit.lfs/pom.xml
index 9fbf776..b1539e5 100644
--- a/org.eclipse.jgit.lfs/pom.xml
+++ b/org.eclipse.jgit.lfs/pom.xml
@@ -50,7 +50,7 @@
   <parent>
     <groupId>org.eclipse.jgit</groupId>
     <artifactId>org.eclipse.jgit-parent</artifactId>
-    <version>4.9.3-SNAPSHOT</version>
+    <version>5.0.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>org.eclipse.jgit.lfs</artifactId>
@@ -70,6 +70,10 @@
       <artifactId>org.eclipse.jgit</artifactId>
       <version>${project.version}</version>
     </dependency>
+    <dependency>
+      <groupId>com.google.code.gson</groupId>
+      <artifactId>gson</artifactId>
+    </dependency>
   </dependencies>
   <build>
     <sourceDirectory>src/</sourceDirectory>
diff --git a/org.eclipse.jgit.lfs/resources/org/eclipse/jgit/lfs/internal/LfsText.properties b/org.eclipse.jgit.lfs/resources/org/eclipse/jgit/lfs/internal/LfsText.properties
index e08e28c..0e00f14 100644
--- a/org.eclipse.jgit.lfs/resources/org/eclipse/jgit/lfs/internal/LfsText.properties
+++ b/org.eclipse.jgit.lfs/resources/org/eclipse/jgit/lfs/internal/LfsText.properties
@@ -1,11 +1,19 @@
 corruptLongObject=The content hash ''{0}'' of the long object ''{1}'' doesn''t match its id, the corrupt object will be deleted.
 incorrectLONG_OBJECT_ID_LENGTH=Incorrect LONG_OBJECT_ID_LENGTH.
-inconsistentMediafileLength=mediafile {0} has unexpected length; expected {1} but found {2}.
+inconsistentMediafileLength=Mediafile {0} has unexpected length; expected {1} but found {2}.
+inconsistentContentLength=Unexpected content length reported by LFS server ({0}), expected {1} but reported was {2}
 invalidLongId=Invalid id: {0}
 invalidLongIdLength=Invalid id length {0}; should be {1}
+lfsUnavailable=LFS is not available for repository {0}
+protocolError=LFS Protocol Error {0}: {1}
 requiredHashFunctionNotAvailable=Required hash function {0} not available.
 repositoryNotFound=Repository {0} not found
 repositoryReadOnly=Repository {0} is read-only
 lfsUnavailable=LFS is not available for repository {0}
 lfsUnathorized=Not authorized to perform operation {0} on repository {1}
 lfsFailedToGetRepository=failed to get repository {0}
+lfsNoDownloadUrl="Need to download object from LFS server but couldn't determine LFS server URL"
+serverFailure=When trying to open a connection to {0} the server responded with an error code. rc={1}
+wrongAmoutOfDataReceived=While downloading data from the content server {0} {1} bytes have been received while {2} have been expected
+userConfigInvalid="User config file {0} invalid {1}"
+missingLocalObject="Local Object {0} is missing"
\ No newline at end of file
diff --git a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/BuiltinLFS.java b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/BuiltinLFS.java
new file mode 100644
index 0000000..415caa9
--- /dev/null
+++ b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/BuiltinLFS.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2017, Markus Duft <markus.duft@ssi-schaefer.com>
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ *   copyright notice, this list of conditions and the following
+ *   disclaimer in the documentation and/or other materials provided
+ *   with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ *   names of its contributors may be used to endorse or promote
+ *   products derived from this software without specific prior
+ *   written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.eclipse.jgit.lfs;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PrintStream;
+
+import org.eclipse.jgit.annotations.Nullable;
+import org.eclipse.jgit.attributes.Attribute;
+import org.eclipse.jgit.hooks.PrePushHook;
+import org.eclipse.jgit.lib.ConfigConstants;
+import org.eclipse.jgit.lib.ObjectLoader;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.util.LfsFactory;
+
+/**
+ * Implementation of {@link LfsFactory}, using built-in (optional) LFS support.
+ *
+ * @since 4.11
+ */
+public class BuiltinLFS extends LfsFactory {
+
+	private BuiltinLFS() {
+		SmudgeFilter.register();
+		CleanFilter.register();
+	}
+
+	/**
+	 * Activates the built-in LFS support.
+	 */
+	public static void register() {
+		setInstance(new BuiltinLFS());
+	}
+
+	@Override
+	public boolean isAvailable() {
+		return true;
+	}
+
+	@Override
+	public ObjectLoader applySmudgeFilter(Repository db, ObjectLoader loader,
+			Attribute attribute) throws IOException {
+		if (isEnabled(db) && (attribute == null || isEnabled(db, attribute))) {
+			return LfsBlobFilter.smudgeLfsBlob(db, loader);
+		} else {
+			return loader;
+		}
+	}
+
+	@Override
+	public LfsInputStream applyCleanFilter(Repository db, InputStream input,
+			long length, Attribute attribute) throws IOException {
+		if (isEnabled(db, attribute)) {
+			return new LfsInputStream(LfsBlobFilter.cleanLfsBlob(db, input));
+		} else {
+			return new LfsInputStream(input, length);
+		}
+	}
+
+	@Override
+	public @Nullable PrePushHook getPrePushHook(Repository repo,
+			PrintStream outputStream) {
+		if (isEnabled(repo)) {
+			return new LfsPrePushHook(repo, outputStream);
+		}
+		return null;
+	}
+
+	/**
+	 * @param db
+	 *            the repository
+	 * @return whether LFS is requested for the given repo.
+	 */
+	@Override
+	public boolean isEnabled(Repository db) {
+		if (db == null) {
+			return false;
+		}
+		return db.getConfig().getBoolean(ConfigConstants.CONFIG_FILTER_SECTION,
+				ConfigConstants.CONFIG_SECTION_LFS,
+				ConfigConstants.CONFIG_KEY_USEJGITBUILTIN,
+				false);
+	}
+
+	/**
+	 * @param db
+	 *            the repository
+	 * @param attribute
+	 *            the attribute to check
+	 * @return whether LFS filter is enabled for the given .gitattribute
+	 *         attribute.
+	 */
+	private boolean isEnabled(Repository db, Attribute attribute) {
+		if (attribute == null) {
+			return false;
+		}
+		return isEnabled(db) && ConfigConstants.CONFIG_SECTION_LFS
+				.equals(attribute.getValue());
+	}
+
+	@Override
+	public LfsInstallCommand getInstallCommand() {
+		return new InstallBuiltinLfsCommand();
+	}
+
+}
diff --git a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/CleanFilter.java b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/CleanFilter.java
index b78ee04..217e46f 100644
--- a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/CleanFilter.java
+++ b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/CleanFilter.java
@@ -55,6 +55,7 @@
 import org.eclipse.jgit.lfs.errors.CorruptMediaFile;
 import org.eclipse.jgit.lfs.internal.AtomicObjectOutputStream;
 import org.eclipse.jgit.lfs.lib.AnyLongObjectId;
+import org.eclipse.jgit.lfs.lib.Constants;
 import org.eclipse.jgit.lib.Repository;
 import org.eclipse.jgit.util.FileUtils;
 
@@ -66,7 +67,7 @@
  * content with content of a so-called LFS pointer file. The pointer file
  * content will then be added to the git repository. Additionally this filter
  * writes the original content in a so-called 'media file' to '.git/lfs/objects/
- * <first-two-characters-of-contentid>/<rest-of-contentid>'
+ * &lt;first-two-characters-of-contentid&gt;/&lt;rest-of-contentid&gt;'
  *
  * @see <a href="https://github.com/github/git-lfs/blob/master/docs/spec.md">Git
  *      LFS Specification</a>
@@ -74,7 +75,8 @@
  */
 public class CleanFilter extends FilterCommand {
 	/**
-	 * The factory is responsible for creating instances of {@link CleanFilter}
+	 * The factory is responsible for creating instances of
+	 * {@link org.eclipse.jgit.lfs.CleanFilter}
 	 */
 	public final static FilterCommandFactory FACTORY = new FilterCommandFactory() {
 
@@ -89,11 +91,12 @@ public FilterCommand create(Repository db, InputStream in,
 	 * Registers this filter by calling
 	 * {@link FilterCommandRegistry#register(String, FilterCommandFactory)}
 	 */
-	public final static void register() {
-		FilterCommandRegistry.register(
-				org.eclipse.jgit.lib.Constants.BUILTIN_FILTER_PREFIX
-						+ "lfs/clean", //$NON-NLS-1$
-				FACTORY);
+	static void register() {
+		FilterCommandRegistry
+				.register(org.eclipse.jgit.lib.Constants.BUILTIN_FILTER_PREFIX
+						+ Constants.ATTR_FILTER_DRIVER_PREFIX
+						+ org.eclipse.jgit.lib.Constants.ATTR_FILTER_TYPE_CLEAN,
+						FACTORY);
 	}
 
 	// Used to compute the hash for the original content
@@ -109,27 +112,30 @@ public final static void register() {
 	private Path tmpFile;
 
 	/**
+	 * Constructor for CleanFilter.
+	 *
 	 * @param db
 	 *            the repository
 	 * @param in
-	 *            an {@link InputStream} providing the original content
+	 *            an {@link java.io.InputStream} providing the original content
 	 * @param out
-	 *            the {@link OutputStream} into which the content of the pointer
-	 *            file should be written. That's the content which will be added
-	 *            to the git repository
-	 * @throws IOException
+	 *            the {@link java.io.OutputStream} into which the content of the
+	 *            pointer file should be written. That's the content which will
+	 *            be added to the git repository
+	 * @throws java.io.IOException
 	 *             when the creation of the temporary file fails or when no
-	 *             {@link OutputStream} for this file can be created
+	 *             {@link java.io.OutputStream} for this file can be created
 	 */
 	public CleanFilter(Repository db, InputStream in, OutputStream out)
 			throws IOException {
 		super(in, out);
-		lfsUtil = new Lfs(db.getDirectory().toPath().resolve("lfs")); //$NON-NLS-1$
+		lfsUtil = new Lfs(db);
 		Files.createDirectories(lfsUtil.getLfsTmpDir());
 		tmpFile = lfsUtil.createTmpFile();
 		this.aOut = new AtomicObjectOutputStream(tmpFile.toAbsolutePath());
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public int run() throws IOException {
 		try {
@@ -161,6 +167,7 @@ public int run() throws IOException {
 				}
 				LfsPointer lfsPointer = new LfsPointer(loid, size);
 				lfsPointer.encode(out);
+				in.close();
 				out.close();
 				return -1;
 			}
@@ -168,6 +175,7 @@ public int run() throws IOException {
 			if (aOut != null) {
 				aOut.abort();
 			}
+			in.close();
 			out.close();
 			throw e;
 		}
diff --git a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/InstallBuiltinLfsCommand.java b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/InstallBuiltinLfsCommand.java
new file mode 100644
index 0000000..028b19b
--- /dev/null
+++ b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/InstallBuiltinLfsCommand.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2018, Markus Duft <markus.duft@ssi-schaefer.com>
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ *   copyright notice, this list of conditions and the following
+ *   disclaimer in the documentation and/or other materials provided
+ *   with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ *   names of its contributors may be used to endorse or promote
+ *   products derived from this software without specific prior
+ *   written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.eclipse.jgit.lfs;
+
+import java.io.IOException;
+import java.text.MessageFormat;
+
+import org.eclipse.jgit.errors.ConfigInvalidException;
+import org.eclipse.jgit.lfs.internal.LfsText;
+import org.eclipse.jgit.lib.ConfigConstants;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.lib.StoredConfig;
+import org.eclipse.jgit.storage.file.FileBasedConfig;
+import org.eclipse.jgit.util.FS;
+import org.eclipse.jgit.util.LfsFactory.LfsInstallCommand;
+import org.eclipse.jgit.util.SystemReader;
+
+/**
+ * Installs all required LFS properties for the current user, analogous to 'git
+ * lfs install', but defaulting to using JGit builtin hooks.
+ *
+ * @since 4.11
+ */
+public class InstallBuiltinLfsCommand implements LfsInstallCommand {
+
+	private static final String[] ARGS_USER = new String[] { "lfs", "install" }; //$NON-NLS-1$//$NON-NLS-2$
+
+	private static final String[] ARGS_LOCAL = new String[] { "lfs", "install", //$NON-NLS-1$//$NON-NLS-2$
+			"--local" }; //$NON-NLS-1$
+
+	private Repository repository;
+
+	/** {@inheritDoc} */
+	@Override
+	public Void call() throws Exception {
+		StoredConfig cfg = null;
+		if (repository == null) {
+			cfg = loadUserConfig();
+		} else {
+			cfg = repository.getConfig();
+		}
+
+		cfg.setBoolean(ConfigConstants.CONFIG_FILTER_SECTION,
+				ConfigConstants.CONFIG_SECTION_LFS,
+				ConfigConstants.CONFIG_KEY_USEJGITBUILTIN, true);
+		cfg.setBoolean(ConfigConstants.CONFIG_FILTER_SECTION,
+				ConfigConstants.CONFIG_SECTION_LFS,
+				ConfigConstants.CONFIG_KEY_REQUIRED, true);
+
+		cfg.save();
+
+		// try to run git lfs install, we really don't care if it is present
+		// and/or works here (yet).
+		ProcessBuilder builder = FS.DETECTED.runInShell("git", //$NON-NLS-1$
+				repository == null ? ARGS_USER : ARGS_LOCAL);
+		if (repository != null) {
+			builder.directory(repository.isBare() ? repository.getDirectory()
+					: repository.getWorkTree());
+		}
+		FS.DETECTED.runProcess(builder, null, null, (String) null);
+
+		return null;
+	}
+
+	/**
+	 * Set the repository to install LFS for
+	 *
+	 * @param repo
+	 *            the repository to install LFS into locally instead of the user
+	 *            configuration
+	 * @return this command
+	 */
+	@Override
+	public LfsInstallCommand setRepository(Repository repo) {
+		this.repository = repo;
+		return this;
+	}
+
+	private StoredConfig loadUserConfig() throws IOException {
+		FileBasedConfig c = SystemReader.getInstance().openUserConfig(null,
+				FS.DETECTED);
+		try {
+			c.load();
+		} catch (ConfigInvalidException e1) {
+			throw new IOException(MessageFormat
+					.format(LfsText.get().userConfigInvalid, c.getFile()
+							.getAbsolutePath(), e1),
+					e1);
+		}
+
+		return c;
+	}
+
+}
diff --git a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/Lfs.java b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/Lfs.java
index 75e34e0..4c46bbd 100644
--- a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/Lfs.java
+++ b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/Lfs.java
@@ -47,9 +47,11 @@
 import java.nio.file.Path;
 
 import org.eclipse.jgit.lfs.lib.AnyLongObjectId;
+import org.eclipse.jgit.lfs.lib.Constants;
+import org.eclipse.jgit.lib.Repository;
 
 /**
- * Class which represents the lfs folder hierarchy inside a .git folder
+ * Class which represents the lfs folder hierarchy inside a {@code .git} folder
  *
  * @since 4.6
  */
@@ -61,14 +63,20 @@ public class Lfs {
 	private Path tmpDir;
 
 	/**
-	 * @param root
-	 *            the path to the LFS media directory. Will be "<repo>/.git/lfs"
+	 * Constructor for Lfs.
+	 *
+	 * @param db
+	 *            the associated repo
+	 *
+	 * @since 4.11
 	 */
-	public Lfs(Path root) {
-		this.root = root;
+	public Lfs(Repository db) {
+		this.root = db.getDirectory().toPath().resolve(Constants.LFS);
 	}
 
 	/**
+	 * Get the LFS root directory
+	 *
 	 * @return the path to the LFS directory
 	 */
 	public Path getLfsRoot() {
@@ -76,8 +84,10 @@ public Path getLfsRoot() {
 	}
 
 	/**
-	 * @return the path to the temp directory used by LFS. Will be
-	 *         "<repo>/.git/lfs/tmp"
+	 * Get the path to the temporary directory used by LFS.
+	 *
+	 * @return the path to the temporary directory used by LFS. Will be
+	 *         {@code <repo>/.git/lfs/tmp}
 	 */
 	public Path getLfsTmpDir() {
 		if (tmpDir == null) {
@@ -87,8 +97,10 @@ public Path getLfsTmpDir() {
 	}
 
 	/**
+	 * Get the object directory used by LFS
+	 *
 	 * @return the path to the object directory used by LFS. Will be
-	 *         "<repo>/.git/lfs/objects"
+	 *         {@code <repo>/.git/lfs/objects}
 	 */
 	public Path getLfsObjDir() {
 		if (objDir == null) {
@@ -98,23 +110,25 @@ public Path getLfsObjDir() {
 	}
 
 	/**
+	 * Get the media file which stores the original content
+	 *
 	 * @param id
 	 *            the id of the mediafile
-	 * @return the file which stores the original content. This will be files
-	 *         underneath
-	 *         "<repo>/.git/lfs/objects/<firstTwoLettersOfID>/<remainingLettersOfID>"
+	 * @return the file which stores the original content. Its path will look
+	 *         like
+	 *         {@code "<repo>/.git/lfs/objects/<firstTwoLettersOfID>/<remainingLettersOfID>"}
 	 */
 	public Path getMediaFile(AnyLongObjectId id) {
 		String idStr = id.name();
 		return getLfsObjDir().resolve(idStr.substring(0, 2))
-				.resolve(idStr.substring(2));
+				.resolve(idStr.substring(2, 4)).resolve(idStr);
 	}
 
 	/**
 	 * Create a new temp file in the LFS directory
 	 *
 	 * @return a new temporary file in the LFS directory
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             when the temp file could not be created
 	 */
 	public Path createTmpFile() throws IOException {
diff --git a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/LfsBlobFilter.java b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/LfsBlobFilter.java
new file mode 100644
index 0000000..a7d218f
--- /dev/null
+++ b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/LfsBlobFilter.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2017, Markus Duft <markus.duft@ssi-schaefer.com>
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ *   copyright notice, this list of conditions and the following
+ *   disclaimer in the documentation and/or other materials provided
+ *   with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ *   names of its contributors may be used to endorse or promote
+ *   products derived from this software without specific prior
+ *   written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.eclipse.jgit.lfs;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+
+import org.eclipse.jgit.lfs.lib.AnyLongObjectId;
+import org.eclipse.jgit.lib.ObjectLoader;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.util.TemporaryBuffer;
+import org.eclipse.jgit.util.TemporaryBuffer.LocalFile;
+
+/**
+ * Provides transparently either a stream to the blob or a LFS media file if
+ * managed by LFS.
+ *
+ * @since 4.11
+ */
+public class LfsBlobFilter {
+
+	/**
+	 * In case the given {@link ObjectLoader} points to a LFS pointer file
+	 * replace the loader with one pointing to the LFS media file contents.
+	 * Missing LFS files are downloaded on the fly - same logic as the smudge
+	 * filter.
+	 *
+	 * @param db
+	 *            the repo
+	 * @param loader
+	 *            the loader for the blob
+	 * @return either the original loader, or a loader for the LFS media file if
+	 *         managed by LFS. Files are downloaded on demand if required.
+	 * @throws IOException
+	 *             in case of an error
+	 */
+	public static ObjectLoader smudgeLfsBlob(Repository db, ObjectLoader loader)
+			throws IOException {
+		if (loader.getSize() > LfsPointer.SIZE_THRESHOLD) {
+			return loader;
+		}
+
+		try (InputStream is = loader.openStream()) {
+			LfsPointer ptr = LfsPointer.parseLfsPointer(is);
+			if (ptr != null) {
+				Lfs lfs = new Lfs(db);
+				AnyLongObjectId oid = ptr.getOid();
+				Path mediaFile = lfs.getMediaFile(oid);
+				if (!Files.exists(mediaFile)) {
+					SmudgeFilter.downloadLfsResource(lfs, db, ptr);
+				}
+
+				return new LfsBlobLoader(mediaFile);
+			}
+		}
+
+		return loader;
+	}
+
+	/**
+	 * Run the LFS clean filter on the given stream and return a stream to the
+	 * LFS pointer file buffer. Used when inserting objects.
+	 *
+	 * @param db
+	 *            the {@link Repository}
+	 * @param originalContent
+	 *            the {@link InputStream} to the original content
+	 * @return a {@link TemporaryBuffer} representing the LFS pointer. The
+	 *         caller is responsible to destroy the buffer.
+	 * @throws IOException
+	 *             in case of any error.
+	 */
+	public static TemporaryBuffer cleanLfsBlob(Repository db,
+			InputStream originalContent) throws IOException {
+		LocalFile buffer = new TemporaryBuffer.LocalFile(null);
+		CleanFilter f = new CleanFilter(db, originalContent, buffer);
+		try {
+			while (f.run() != -1) {
+				// loop as long as f.run() tells there is work to do
+			}
+		} catch (IOException e) {
+			buffer.destroy();
+			throw e;
+		}
+		return buffer;
+	}
+
+}
diff --git a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/LfsBlobLoader.java b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/LfsBlobLoader.java
new file mode 100644
index 0000000..697ae47
--- /dev/null
+++ b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/LfsBlobLoader.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2017, Markus Duft <markus.duft@ssi-schaefer.com>
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ *   copyright notice, this list of conditions and the following
+ *   disclaimer in the documentation and/or other materials provided
+ *   with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ *   names of its contributors may be used to endorse or promote
+ *   products derived from this software without specific prior
+ *   written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.eclipse.jgit.lfs;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.attribute.BasicFileAttributes;
+
+import org.eclipse.jgit.errors.LargeObjectException;
+import org.eclipse.jgit.errors.MissingObjectException;
+import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.ObjectLoader;
+import org.eclipse.jgit.lib.ObjectStream;
+import org.eclipse.jgit.storage.pack.PackConfig;
+import org.eclipse.jgit.util.IO;
+
+/**
+ * An {@link ObjectLoader} implementation that reads a media file from the LFS
+ * storage.
+ *
+ * @since 4.11
+ */
+public class LfsBlobLoader extends ObjectLoader {
+
+	private Path mediaFile;
+
+	private BasicFileAttributes attributes;
+
+	private byte[] cached;
+
+	/**
+	 * Create a loader for the LFS media file at the given path.
+	 *
+	 * @param mediaFile
+	 *            path to the file
+	 * @throws IOException
+	 *             in case of an error reading attributes
+	 */
+	public LfsBlobLoader(Path mediaFile) throws IOException {
+		this.mediaFile = mediaFile;
+		this.attributes = Files.readAttributes(mediaFile,
+				BasicFileAttributes.class);
+	}
+
+	@Override
+	public int getType() {
+		return Constants.OBJ_BLOB;
+	}
+
+	@Override
+	public long getSize() {
+		return attributes.size();
+	}
+
+	@Override
+	public byte[] getCachedBytes() throws LargeObjectException {
+		if (getSize() > PackConfig.DEFAULT_BIG_FILE_THRESHOLD) {
+			throw new LargeObjectException();
+		}
+
+		if (cached == null) {
+			try {
+				cached = IO.readFully(mediaFile.toFile());
+			} catch (IOException ioe) {
+				throw new LargeObjectException(ioe);
+			}
+		}
+		return cached;
+	}
+
+	@Override
+	public ObjectStream openStream()
+			throws MissingObjectException, IOException {
+		return new ObjectStream.Filter(getType(), getSize(),
+				Files.newInputStream(mediaFile));
+	}
+
+}
diff --git a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/LfsPointer.java b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/LfsPointer.java
index 0f62025..4f95940 100644
--- a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/LfsPointer.java
+++ b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/LfsPointer.java
@@ -42,6 +42,8 @@
  */
 package org.eclipse.jgit.lfs;
 
+import static org.eclipse.jgit.lib.Constants.CHARSET;
+
 import java.io.BufferedReader;
 import java.io.IOException;
 import java.io.InputStream;
@@ -49,7 +51,6 @@
 import java.io.OutputStream;
 import java.io.PrintStream;
 import java.io.UnsupportedEncodingException;
-import java.nio.charset.StandardCharsets;
 import java.nio.charset.UnsupportedCharsetException;
 import java.util.Locale;
 
@@ -63,7 +64,7 @@
  *
  * @since 4.6
  */
-public class LfsPointer {
+public class LfsPointer implements Comparable<LfsPointer> {
 	/**
 	 * The version of the LfsPointer file format
 	 */
@@ -76,6 +77,13 @@ public class LfsPointer {
 	public static final String VERSION_LEGACY = "https://hawser.github.com/spec/v1"; //$NON-NLS-1$
 
 	/**
+	 * Don't inspect files that are larger than this threshold to avoid
+	 * excessive reading. No pointer file should be larger than this.
+	 * @since 4.11
+	 */
+	public static final int SIZE_THRESHOLD = 200;
+
+	/**
 	 * The name of the hash function as used in the pointer files. This will
 	 * evaluate to "sha256"
 	 */
@@ -87,6 +95,8 @@ public class LfsPointer {
 	private long size;
 
 	/**
+	 * <p>Constructor for LfsPointer.</p>
+	 *
 	 * @param oid
 	 *            the id of the content
 	 * @param size
@@ -98,6 +108,8 @@ public LfsPointer(AnyLongObjectId oid, long size) {
 	}
 
 	/**
+	 * <p>Getter for the field <code>oid</code>.</p>
+	 *
 	 * @return the id of the content
 	 */
 	public AnyLongObjectId getOid() {
@@ -105,6 +117,8 @@ public AnyLongObjectId getOid() {
 	}
 
 	/**
+	 * <p>Getter for the field <code>size</code>.</p>
+	 *
 	 * @return the size of the content
 	 */
 	public long getSize() {
@@ -115,12 +129,12 @@ public long getSize() {
 	 * Encode this object into the LFS format defined by {@link #VERSION}
 	 *
 	 * @param out
-	 *            the {@link OutputStream} into which the encoded data should be
+	 *            the {@link java.io.OutputStream} into which the encoded data should be
 	 *            written
 	 */
 	public void encode(OutputStream out) {
 		try (PrintStream ps = new PrintStream(out, false,
-				StandardCharsets.UTF_8.name())) {
+				CHARSET.name())) {
 			ps.print("version "); //$NON-NLS-1$
 			ps.print(VERSION + "\n"); //$NON-NLS-1$
 			ps.print("oid " + HASH_FUNCTION_NAME + ":"); //$NON-NLS-1$ //$NON-NLS-2$
@@ -129,8 +143,7 @@ public void encode(OutputStream out) {
 			ps.print(size + "\n"); //$NON-NLS-1$
 		} catch (UnsupportedEncodingException e) {
 			// should not happen, we are using a standard charset
-			throw new UnsupportedCharsetException(
-					StandardCharsets.UTF_8.name());
+			throw new UnsupportedCharsetException(CHARSET.name());
 		}
 	}
 
@@ -139,10 +152,10 @@ public void encode(OutputStream out) {
 	 * {@link #VERSION}
 	 *
 	 * @param in
-	 *            the {@link InputStream} from where to read the data
-	 * @return an {@link LfsPointer} or <code>null</code> if the stream was not
-	 *         parseable as LfsPointer
-	 * @throws IOException
+	 *            the {@link java.io.InputStream} from where to read the data
+	 * @return an {@link org.eclipse.jgit.lfs.LfsPointer} or <code>null</code>
+	 *         if the stream was not parseable as LfsPointer
+	 * @throws java.io.IOException
 	 */
 	@Nullable
 	public static LfsPointer parseLfsPointer(InputStream in)
@@ -152,7 +165,7 @@ public static LfsPointer parseLfsPointer(InputStream in)
 		long sz = -1;
 
 		try (BufferedReader br = new BufferedReader(
-				new InputStreamReader(in, StandardCharsets.UTF_8.name()))) {
+				new InputStreamReader(in, CHARSET))) {
 			for (String s = br.readLine(); s != null; s = br.readLine()) {
 				if (s.startsWith("#") || s.length() == 0) { //$NON-NLS-1$
 					continue;
@@ -173,10 +186,24 @@ public static LfsPointer parseLfsPointer(InputStream in)
 		return null;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public String toString() {
 		return "LfsPointer: oid=" + oid.name() + ", size=" //$NON-NLS-1$ //$NON-NLS-2$
 				+ size;
 	}
+
+	/**
+	 * @since 4.11
+	 */
+	@Override
+	public int compareTo(LfsPointer o) {
+		int x = getOid().compareTo(o.getOid());
+		if (x != 0) {
+			return x;
+		}
+
+		return (int) (getSize() - o.getSize());
+	}
 }
 
diff --git a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/LfsPrePushHook.java b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/LfsPrePushHook.java
new file mode 100644
index 0000000..de4449f
--- /dev/null
+++ b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/LfsPrePushHook.java
@@ -0,0 +1,277 @@
+/*
+ * Copyright (C) 2017, Markus Duft <markus.duft@ssi-schaefer.com>
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ *   copyright notice, this list of conditions and the following
+ *   disclaimer in the documentation and/or other materials provided
+ *   with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ *   names of its contributors may be used to endorse or promote
+ *   products derived from this software without specific prior
+ *   written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.eclipse.jgit.lfs;
+
+import static org.eclipse.jgit.lib.Constants.CHARSET;
+import static org.eclipse.jgit.lfs.Protocol.OPERATION_UPLOAD;
+import static org.eclipse.jgit.lfs.internal.LfsConnectionFactory.toRequest;
+import static org.eclipse.jgit.transport.http.HttpConnection.HTTP_OK;
+import static org.eclipse.jgit.util.HttpSupport.METHOD_POST;
+import static org.eclipse.jgit.util.HttpSupport.METHOD_PUT;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.text.MessageFormat;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+
+import org.eclipse.jgit.api.errors.AbortedByHookException;
+import org.eclipse.jgit.errors.IncorrectObjectTypeException;
+import org.eclipse.jgit.errors.MissingObjectException;
+import org.eclipse.jgit.hooks.PrePushHook;
+import org.eclipse.jgit.lfs.Protocol.ObjectInfo;
+import org.eclipse.jgit.lfs.errors.CorruptMediaFile;
+import org.eclipse.jgit.lfs.internal.LfsConnectionFactory;
+import org.eclipse.jgit.lfs.internal.LfsText;
+import org.eclipse.jgit.lib.AnyObjectId;
+import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.ObjectReader;
+import org.eclipse.jgit.lib.Ref;
+import org.eclipse.jgit.lib.RefDatabase;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.revwalk.ObjectWalk;
+import org.eclipse.jgit.revwalk.RevObject;
+import org.eclipse.jgit.transport.RemoteRefUpdate;
+import org.eclipse.jgit.transport.http.HttpConnection;
+
+import com.google.gson.Gson;
+import com.google.gson.stream.JsonReader;
+
+/**
+ * Pre-push hook that handles uploading LFS artefacts.
+ *
+ * @since 4.11
+ */
+public class LfsPrePushHook extends PrePushHook {
+
+	private static final String EMPTY = ""; //$NON-NLS-1$
+	private Collection<RemoteRefUpdate> refs;
+
+	/**
+	 * @param repo
+	 *            the repository
+	 * @param outputStream
+	 *            not used by this implementation
+	 */
+	public LfsPrePushHook(Repository repo, PrintStream outputStream) {
+		super(repo, outputStream);
+	}
+
+	@Override
+	public void setRefs(Collection<RemoteRefUpdate> toRefs) {
+		this.refs = toRefs;
+	}
+
+	@Override
+	public String call() throws IOException, AbortedByHookException {
+		Set<LfsPointer> toPush = findObjectsToPush();
+		if (toPush.isEmpty()) {
+			return EMPTY;
+		}
+		HttpConnection api = LfsConnectionFactory.getLfsConnection(
+				getRepository(), METHOD_POST, OPERATION_UPLOAD);
+		Map<String, LfsPointer> oid2ptr = requestBatchUpload(api, toPush);
+		uploadContents(api, oid2ptr);
+		return EMPTY;
+
+	}
+
+	private Set<LfsPointer> findObjectsToPush() throws IOException,
+			MissingObjectException, IncorrectObjectTypeException {
+		Set<LfsPointer> toPush = new TreeSet<>();
+
+		try (ObjectWalk walk = new ObjectWalk(getRepository())) {
+			for (RemoteRefUpdate up : refs) {
+				walk.setRewriteParents(false);
+				excludeRemoteRefs(walk);
+				walk.markStart(walk.parseCommit(up.getNewObjectId()));
+				while (walk.next() != null) {
+					// walk all commits to populate objects
+				}
+				findLfsPointers(toPush, walk);
+			}
+		}
+		return toPush;
+	}
+
+	private static void findLfsPointers(Set<LfsPointer> toPush, ObjectWalk walk)
+			throws MissingObjectException, IncorrectObjectTypeException,
+			IOException {
+		RevObject obj;
+		ObjectReader r = walk.getObjectReader();
+		while ((obj = walk.nextObject()) != null) {
+			if (obj.getType() == Constants.OBJ_BLOB
+					&& getObjectSize(r, obj) < LfsPointer.SIZE_THRESHOLD) {
+				LfsPointer ptr = loadLfsPointer(r, obj);
+				if (ptr != null) {
+					toPush.add(ptr);
+				}
+			}
+		}
+	}
+
+	private static long getObjectSize(ObjectReader r, RevObject obj)
+			throws IOException {
+		return r.getObjectSize(obj.getId(), Constants.OBJ_BLOB);
+	}
+
+	private static LfsPointer loadLfsPointer(ObjectReader r, AnyObjectId obj)
+			throws IOException {
+		try (InputStream is = r.open(obj, Constants.OBJ_BLOB).openStream()) {
+			return LfsPointer.parseLfsPointer(is);
+		}
+	}
+
+	private void excludeRemoteRefs(ObjectWalk walk) throws IOException {
+		RefDatabase refDatabase = getRepository().getRefDatabase();
+		List<Ref> remoteRefs = refDatabase.getRefsByPrefix(remote());
+		for (Ref r : remoteRefs) {
+			ObjectId oid = r.getPeeledObjectId();
+			if (oid == null) {
+				oid = r.getObjectId();
+			}
+			if (oid == null) {
+				// ignore (e.g. symbolic, ...)
+				continue;
+			}
+			RevObject o = walk.parseAny(oid);
+			if (o.getType() == Constants.OBJ_COMMIT
+					|| o.getType() == Constants.OBJ_TAG) {
+				walk.markUninteresting(o);
+			}
+		}
+	}
+
+	private String remote() {
+		String remoteName = getRemoteName() == null
+				? Constants.DEFAULT_REMOTE_NAME
+				: getRemoteName();
+		return Constants.R_REMOTES + remoteName;
+	}
+
+	private Map<String, LfsPointer> requestBatchUpload(HttpConnection api,
+			Set<LfsPointer> toPush) throws IOException {
+		LfsPointer[] res = toPush.toArray(new LfsPointer[toPush.size()]);
+		Map<String, LfsPointer> oidStr2ptr = new HashMap<>();
+		for (LfsPointer p : res) {
+			oidStr2ptr.put(p.getOid().name(), p);
+		}
+		Gson gson = Protocol.gson();
+		api.getOutputStream().write(
+				gson.toJson(toRequest(OPERATION_UPLOAD, res)).getBytes(CHARSET));
+		int responseCode = api.getResponseCode();
+		if (responseCode != HTTP_OK) {
+			throw new IOException(
+					MessageFormat.format(LfsText.get().serverFailure,
+							api.getURL(), Integer.valueOf(responseCode)));
+		}
+		return oidStr2ptr;
+	}
+
+	private void uploadContents(HttpConnection api,
+			Map<String, LfsPointer> oid2ptr) throws IOException {
+		try (JsonReader reader = new JsonReader(
+				new InputStreamReader(api.getInputStream()))) {
+			for (Protocol.ObjectInfo o : parseObjects(reader)) {
+				if (o.actions == null) {
+					continue;
+				}
+				LfsPointer ptr = oid2ptr.get(o.oid);
+				if (ptr == null) {
+					// received an object we didn't request
+					continue;
+				}
+				Protocol.Action uploadAction = o.actions.get(OPERATION_UPLOAD);
+				if (uploadAction == null || uploadAction.href == null) {
+					continue;
+				}
+
+				Lfs lfs = new Lfs(getRepository());
+				Path path = lfs.getMediaFile(ptr.getOid());
+				if (!Files.exists(path)) {
+					throw new IOException(MessageFormat
+							.format(LfsText.get().missingLocalObject, path));
+				}
+				uploadFile(o, uploadAction, path);
+			}
+		}
+	}
+
+	private List<ObjectInfo> parseObjects(JsonReader reader) {
+		Gson gson = new Gson();
+		Protocol.Response resp = gson.fromJson(reader, Protocol.Response.class);
+		return resp.objects;
+	}
+
+	private void uploadFile(Protocol.ObjectInfo o,
+			Protocol.Action uploadAction, Path path)
+			throws IOException, CorruptMediaFile {
+		HttpConnection contentServer = LfsConnectionFactory
+				.getLfsContentConnection(getRepository(), uploadAction,
+						METHOD_PUT);
+		contentServer.setDoOutput(true);
+		try (OutputStream out = contentServer
+				.getOutputStream()) {
+			long size = Files.copy(path, out);
+			if (size != o.size) {
+				throw new CorruptMediaFile(path, o.size, size);
+			}
+		}
+		int responseCode = contentServer.getResponseCode();
+		if (responseCode != HTTP_OK) {
+			throw new IOException(MessageFormat.format(
+					LfsText.get().serverFailure, contentServer.getURL(),
+					Integer.valueOf(responseCode)));
+		}
+	}
+}
diff --git a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/Protocol.java b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/Protocol.java
new file mode 100644
index 0000000..d88742e
--- /dev/null
+++ b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/Protocol.java
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2016, Christian Halstrick <christian.halstrick@sap.com>
+ * Copyright (C) 2015, Sasa Zivkov <sasa.zivkov@sap.com>
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ *   copyright notice, this list of conditions and the following
+ *   disclaimer in the documentation and/or other materials provided
+ *   with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ *   names of its contributors may be used to endorse or promote
+ *   products derived from this software without specific prior
+ *   written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.eclipse.jgit.lfs;
+
+import java.util.List;
+import java.util.Map;
+
+import com.google.gson.FieldNamingPolicy;
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+
+/**
+ * This interface describes the network protocol used between lfs client and lfs
+ * server
+ *
+ * @since 4.11
+ */
+public interface Protocol {
+	/** A request sent to an LFS server */
+	class Request {
+		/** The operation of this request */
+		public String operation;
+
+		/** The objects of this request */
+		public List<ObjectSpec> objects;
+	}
+
+	/** A response received from an LFS server */
+	class Response {
+		public List<ObjectInfo> objects;
+	}
+
+	/**
+	 * MetaData of an LFS object. Needs to be specified when requesting objects
+	 * from the LFS server and is also returned in the response
+	 */
+	class ObjectSpec {
+		public String oid; // the objectid
+
+		public long size; // the size of the object
+	}
+
+	/**
+	 * Describes in a response all actions the LFS server offers for a single
+	 * object
+	 */
+	class ObjectInfo extends ObjectSpec {
+		public Map<String, Action> actions; // Maps operation to action
+
+		public Error error;
+	}
+
+	/**
+	 * Describes in a Response a single action the client can execute on a
+	 * single object
+	 */
+	class Action {
+		public String href;
+
+		public Map<String, String> header;
+	}
+
+	/**
+	 * An action with an additional expiration timestamp
+	 *
+	 * @since 4.11
+	 */
+	class ExpiringAction extends Action {
+		/**
+		 * Absolute date/time in format "yyyy-MM-dd'T'HH:mm:ss.SSSX"
+		 */
+		public String expiresAt;
+
+		/**
+		 * Validity time in milliseconds (preferred over expiresAt as specified:
+		 * https://github.com/git-lfs/git-lfs/blob/master/docs/api/authentication.md)
+		 */
+		public String expiresIn;
+	}
+
+	/** Describes an error to be returned by the LFS batch API */
+	class Error {
+		public int code;
+
+		public String message;
+	}
+
+	/**
+	 * The "download" operation
+	 */
+	String OPERATION_DOWNLOAD = "download"; //$NON-NLS-1$
+
+	/**
+	 * The "upload" operation
+	 */
+	String OPERATION_UPLOAD = "upload"; //$NON-NLS-1$
+
+	/**
+	 * The contenttype used in LFS requests
+	 */
+	String CONTENTTYPE_VND_GIT_LFS_JSON = "application/vnd.git-lfs+json; charset=utf-8"; //$NON-NLS-1$
+
+	/**
+	 * Authorization header when auto-discovering via SSH.
+	 */
+	String HDR_AUTH = "Authorization"; //$NON-NLS-1$
+
+	/**
+	 * Prefix of authentication token obtained through SSH.
+	 */
+	String HDR_AUTH_SSH_PREFIX = "Ssh: "; //$NON-NLS-1$
+
+	/**
+	 * Path to the LFS info servlet.
+	 */
+	String INFO_LFS_ENDPOINT = "/info/lfs"; //$NON-NLS-1$
+
+	/**
+	 * Path to the LFS objects servlet.
+	 */
+	String OBJECTS_LFS_ENDPOINT = "/objects/batch"; //$NON-NLS-1$
+
+	/**
+	 * @return a {@link Gson} instance suitable for handling this
+	 *         {@link Protocol}
+	 *
+	 * @since 4.11
+	 */
+	public static Gson gson() {
+		return new GsonBuilder()
+				.setFieldNamingPolicy(
+						FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
+				.disableHtmlEscaping().create();
+	}
+}
diff --git a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/SmudgeFilter.java b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/SmudgeFilter.java
index 2332477..6bff12f 100644
--- a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/SmudgeFilter.java
+++ b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/SmudgeFilter.java
@@ -42,17 +42,33 @@
  */
 package org.eclipse.jgit.lfs;
 
+import static org.eclipse.jgit.lib.Constants.CHARSET;
+
 import java.io.IOException;
 import java.io.InputStream;
+import java.io.InputStreamReader;
 import java.io.OutputStream;
 import java.nio.file.Files;
 import java.nio.file.Path;
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
 
 import org.eclipse.jgit.attributes.FilterCommand;
 import org.eclipse.jgit.attributes.FilterCommandFactory;
 import org.eclipse.jgit.attributes.FilterCommandRegistry;
+import org.eclipse.jgit.lfs.internal.LfsConnectionFactory;
+import org.eclipse.jgit.lfs.internal.LfsText;
+import org.eclipse.jgit.lfs.lib.AnyLongObjectId;
 import org.eclipse.jgit.lfs.lib.Constants;
 import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.transport.http.HttpConnection;
+import org.eclipse.jgit.util.HttpSupport;
+
+import com.google.gson.Gson;
+import com.google.gson.stream.JsonReader;
 
 /**
  * Built-in LFS smudge filter
@@ -61,15 +77,20 @@
  * and this filter is configured for that content, then this filter will replace
  * the content of LFS pointer files with the original content. This happens e.g.
  * when a checkout needs to update a working tree file which is under LFS
- * control. This implementation expects that the origin content is already
- * available in the .git/lfs/objects folder. This implementation will not
- * contact any LFS servers in order to get the missing content.
+ * control.
  *
  * @since 4.6
  */
 public class SmudgeFilter extends FilterCommand {
+
 	/**
-	 * The factory is responsible for creating instances of {@link SmudgeFilter}
+	 * Max number of bytes to copy in a single {@link #run()} call.
+	 */
+	private static final int MAX_COPY_BYTES = 1024 * 1024 * 256;
+
+	/**
+	 * The factory is responsible for creating instances of
+	 * {@link org.eclipse.jgit.lfs.SmudgeFilter}
 	 */
 	public final static FilterCommandFactory FACTORY = new FilterCommandFactory() {
 		@Override
@@ -80,46 +101,180 @@ public FilterCommand create(Repository db, InputStream in,
 	};
 
 	/**
-	 * Registers this filter in JGit by calling
+	 * Register this filter in JGit
 	 */
-	public final static void register() {
-		FilterCommandRegistry.register(
-				org.eclipse.jgit.lib.Constants.BUILTIN_FILTER_PREFIX
-						+ "lfs/smudge", //$NON-NLS-1$
-				FACTORY);
+	static void register() {
+		FilterCommandRegistry
+				.register(org.eclipse.jgit.lib.Constants.BUILTIN_FILTER_PREFIX
+						+ Constants.ATTR_FILTER_DRIVER_PREFIX
+						+ org.eclipse.jgit.lib.Constants.ATTR_FILTER_TYPE_SMUDGE,
+						FACTORY);
 	}
 
-	private Lfs lfs;
-
 	/**
+	 * Constructor for SmudgeFilter.
+	 *
 	 * @param db
+	 *            a {@link org.eclipse.jgit.lib.Repository} object.
 	 * @param in
+	 *            a {@link java.io.InputStream} object. The stream is closed in
+	 *            any case.
 	 * @param out
-	 * @throws IOException
+	 *            a {@link java.io.OutputStream} object.
+	 * @throws java.io.IOException
+	 *             in case of an error
 	 */
 	public SmudgeFilter(Repository db, InputStream in, OutputStream out)
 			throws IOException {
 		super(in, out);
-		lfs = new Lfs(db.getDirectory().toPath().resolve(Constants.LFS));
-		LfsPointer res = LfsPointer.parseLfsPointer(in);
-		if (res != null) {
-			Path mediaFile = lfs.getMediaFile(res.getOid());
-			if (Files.exists(mediaFile)) {
+		try {
+			Lfs lfs = new Lfs(db);
+			LfsPointer res = LfsPointer.parseLfsPointer(in);
+			if (res != null) {
+				AnyLongObjectId oid = res.getOid();
+				Path mediaFile = lfs.getMediaFile(oid);
+				if (!Files.exists(mediaFile)) {
+					downloadLfsResource(lfs, db, res);
+				}
 				this.in = Files.newInputStream(mediaFile);
 			}
+		} finally {
+			in.close(); // make sure the swapped stream is closed properly.
 		}
 	}
 
+	/**
+	 * Download content which is hosted on a LFS server
+	 *
+	 * @param lfs
+	 *            local {@link Lfs} storage.
+	 * @param db
+	 *            the repository to work with
+	 * @param res
+	 *            the objects to download
+	 * @return the paths of all mediafiles which have been downloaded
+	 * @throws IOException
+	 * @since 4.11
+	 */
+	public static Collection<Path> downloadLfsResource(Lfs lfs, Repository db,
+			LfsPointer... res) throws IOException {
+		Collection<Path> downloadedPaths = new ArrayList<>();
+		Map<String, LfsPointer> oidStr2ptr = new HashMap<>();
+		for (LfsPointer p : res) {
+			oidStr2ptr.put(p.getOid().name(), p);
+		}
+		HttpConnection lfsServerConn = LfsConnectionFactory.getLfsConnection(db,
+				HttpSupport.METHOD_POST, Protocol.OPERATION_DOWNLOAD);
+		Gson gson = Protocol.gson();
+		lfsServerConn.getOutputStream()
+				.write(gson
+						.toJson(LfsConnectionFactory
+								.toRequest(Protocol.OPERATION_DOWNLOAD, res))
+						.getBytes(CHARSET));
+		int responseCode = lfsServerConn.getResponseCode();
+		if (responseCode != HttpConnection.HTTP_OK) {
+			throw new IOException(
+					MessageFormat.format(LfsText.get().serverFailure,
+							lfsServerConn.getURL(),
+							Integer.valueOf(responseCode)));
+		}
+		try (JsonReader reader = new JsonReader(
+				new InputStreamReader(lfsServerConn.getInputStream()))) {
+			Protocol.Response resp = gson.fromJson(reader,
+					Protocol.Response.class);
+			for (Protocol.ObjectInfo o : resp.objects) {
+				if (o.error != null) {
+					throw new IOException(
+							MessageFormat.format(LfsText.get().protocolError,
+									Integer.valueOf(o.error.code),
+									o.error.message));
+				}
+				if (o.actions == null) {
+					continue;
+				}
+				LfsPointer ptr = oidStr2ptr.get(o.oid);
+				if (ptr == null) {
+					// received an object we didn't request
+					continue;
+				}
+				if (ptr.getSize() != o.size) {
+					throw new IOException(MessageFormat.format(
+							LfsText.get().inconsistentContentLength,
+							lfsServerConn.getURL(), Long.valueOf(ptr.getSize()),
+							Long.valueOf(o.size)));
+				}
+				Protocol.Action downloadAction = o.actions
+						.get(Protocol.OPERATION_DOWNLOAD);
+				if (downloadAction == null || downloadAction.href == null) {
+					continue;
+				}
+
+				HttpConnection contentServerConn = LfsConnectionFactory
+						.getLfsContentConnection(db, downloadAction,
+								HttpSupport.METHOD_GET);
+
+				responseCode = contentServerConn.getResponseCode();
+				if (responseCode != HttpConnection.HTTP_OK) {
+					throw new IOException(
+							MessageFormat.format(LfsText.get().serverFailure,
+									contentServerConn.getURL(),
+									Integer.valueOf(responseCode)));
+				}
+				Path path = lfs.getMediaFile(ptr.getOid());
+				path.getParent().toFile().mkdirs();
+				try (InputStream contentIn = contentServerConn
+						.getInputStream()) {
+					long bytesCopied = Files.copy(contentIn, path);
+					if (bytesCopied != o.size) {
+						throw new IOException(MessageFormat.format(
+								LfsText.get().wrongAmoutOfDataReceived,
+								contentServerConn.getURL(),
+								Long.valueOf(bytesCopied),
+								Long.valueOf(o.size)));
+					}
+					downloadedPaths.add(path);
+				}
+			}
+		}
+		return downloadedPaths;
+	}
+
+	/** {@inheritDoc} */
 	@Override
 	public int run() throws IOException {
-		int b;
-		if (in != null) {
-			while ((b = in.read()) != -1) {
-				out.write(b);
+		try {
+			int totalRead = 0;
+			int length = 0;
+			if (in != null) {
+				byte[] buf = new byte[8192];
+				while ((length = in.read(buf)) != -1) {
+					out.write(buf, 0, length);
+					totalRead += length;
+
+					// when threshold reached, loop back to the caller.
+					// otherwise we could only support files up to 2GB (int
+					// return type) properly. we will be called again as long as
+					// we don't return -1 here.
+					if (totalRead >= MAX_COPY_BYTES) {
+						// leave streams open - we need them in the next call.
+						return totalRead;
+					}
+				}
 			}
-			in.close();
+
+			if (totalRead == 0 && length == -1) {
+				// we're totally done :) cleanup all streams
+				in.close();
+				out.close();
+				return length;
+			}
+
+			return totalRead;
+		} catch (IOException e) {
+			in.close(); // clean up - we swapped this stream.
+			out.close();
+			throw e;
 		}
-		out.close();
-		return -1;
 	}
+
 }
diff --git a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/errors/CorruptLongObjectException.java b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/errors/CorruptLongObjectException.java
index fea148b..d45a0ee 100644
--- a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/errors/CorruptLongObjectException.java
+++ b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/errors/CorruptLongObjectException.java
@@ -66,8 +66,7 @@ public class CorruptLongObjectException extends IllegalArgumentException {
 	 *            id of the long object
 	 * @param contentHash
 	 *            hash of the long object's content
-	 *
-	 * @param message
+	 * @param message a {@link java.lang.String} object.
 	 */
 	public CorruptLongObjectException(AnyLongObjectId id,
 			AnyLongObjectId contentHash,
@@ -78,6 +77,8 @@ public CorruptLongObjectException(AnyLongObjectId id,
 	}
 
 	/**
+	 * Get the <code>id</code> of the object.
+	 *
 	 * @return the id of the object, i.e. the expected hash of the object's
 	 *         content
 	 */
@@ -86,6 +87,8 @@ public AnyLongObjectId getId() {
 	}
 
 	/**
+	 * Get the <code>contentHash</code>.
+	 *
 	 * @return the actual hash of the object's content which doesn't match the
 	 *         object's id when this exception is thrown which signals that the
 	 *         object has been corrupted
diff --git a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/errors/CorruptMediaFile.java b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/errors/CorruptMediaFile.java
index f2b51c0..08ef807 100644
--- a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/errors/CorruptMediaFile.java
+++ b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/errors/CorruptMediaFile.java
@@ -63,9 +63,11 @@ public class CorruptMediaFile extends IOException {
 	private long size;
 
 	/**
-	 * @param mediaFile
-	 * @param expectedSize
-	 * @param size
+	 * <p>Constructor for CorruptMediaFile.</p>
+	 *
+	 * @param mediaFile a {@link java.nio.file.Path} object.
+	 * @param expectedSize a long.
+	 * @param size a long.
 	 */
 	@SuppressWarnings("boxing")
 	public CorruptMediaFile(Path mediaFile, long expectedSize,
@@ -78,6 +80,8 @@ public CorruptMediaFile(Path mediaFile, long expectedSize,
 	}
 
 	/**
+	 * Get the <code>mediaFile</code>.
+	 *
 	 * @return the media file which seems to be corrupt
 	 */
 	public Path getMediaFile() {
@@ -85,6 +89,8 @@ public Path getMediaFile() {
 	}
 
 	/**
+	 * Get the <code>expectedSize</code>.
+	 *
 	 * @return the expected size of the media file
 	 */
 	public long getExpectedSize() {
@@ -92,6 +98,8 @@ public long getExpectedSize() {
 	}
 
 	/**
+	 * Get the <code>size</code>.
+	 *
 	 * @return the actual size of the media file in the file system
 	 */
 	public long getSize() {
diff --git a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/errors/InvalidLongObjectIdException.java b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/errors/InvalidLongObjectIdException.java
index 44ac317..f7bba85 100644
--- a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/errors/InvalidLongObjectIdException.java
+++ b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/errors/InvalidLongObjectIdException.java
@@ -45,7 +45,8 @@
 
 package org.eclipse.jgit.lfs.errors;
 
-import java.io.UnsupportedEncodingException;
+import static java.nio.charset.StandardCharsets.US_ASCII;
+
 import java.text.MessageFormat;
 
 import org.eclipse.jgit.lfs.internal.LfsText;
@@ -71,6 +72,8 @@ public InvalidLongObjectIdException(byte[] bytes, int offset, int length) {
 	}
 
 	/**
+	 * <p>Constructor for InvalidLongObjectIdException.</p>
+	 *
 	 * @param idString
 	 *            String containing the invalid id
 	 */
@@ -80,10 +83,8 @@ public InvalidLongObjectIdException(String idString) {
 
 	private static String asAscii(byte[] bytes, int offset, int length) {
 		try {
-			return new String(bytes, offset, length, "US-ASCII"); //$NON-NLS-1$
-		} catch (UnsupportedEncodingException e2) {
-			return ""; //$NON-NLS-1$
-		} catch (StringIndexOutOfBoundsException e2) {
+			return new String(bytes, offset, length, US_ASCII);
+		} catch (StringIndexOutOfBoundsException e) {
 			return ""; //$NON-NLS-1$
 		}
 	}
diff --git a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/errors/LfsBandwidthLimitExceeded.java b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/errors/LfsBandwidthLimitExceeded.java
index 1b1baec..949981f 100644
--- a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/errors/LfsBandwidthLimitExceeded.java
+++ b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/errors/LfsBandwidthLimitExceeded.java
@@ -47,12 +47,13 @@
  * Thrown when the bandwidth limit for the user or repository has been exceeded.
  *
  * @since 4.5
- *
  */
 public class LfsBandwidthLimitExceeded extends LfsException {
 	private static final long serialVersionUID = 1L;
 
 	/**
+	 * <p>Constructor for LfsBandwidthLimitExceeded.</p>
+	 *
 	 * @param message
 	 *            error message, which may be shown to an end-user.
 	 */
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/SafeBufferedOutputStream.java b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/errors/LfsConfigInvalidException.java
similarity index 71%
copy from org.eclipse.jgit/src/org/eclipse/jgit/util/io/SafeBufferedOutputStream.java
copy to org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/errors/LfsConfigInvalidException.java
index 84c3398..5320af0 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/SafeBufferedOutputStream.java
+++ b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/errors/LfsConfigInvalidException.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011, Robin Rosenberg
+ * Copyright (C) 2016, Christian Halstrick <christian.halstrick@sap.com>
  * and other copyright owners as documented in the project's IP log.
  *
  * This program and the accompanying materials are made available
@@ -40,33 +40,27 @@
  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
-package org.eclipse.jgit.util.io;
+package org.eclipse.jgit.lfs.errors;
 
-import java.io.BufferedOutputStream;
-import java.io.OutputStream;
+import java.io.IOException;
 
 /**
- * @deprecated use BufferedOutputStream in Java 8 and later.
+ * Thrown when a LFS configuration problem has been detected (i.e. unable to
+ * find the remote LFS repository URL).
+ *
+ * @since 4.11
  */
-@Deprecated
-public class SafeBufferedOutputStream extends BufferedOutputStream {
-	/**
-	 * @see BufferedOutputStream#BufferedOutputStream(OutputStream)
-	 * @param out
-	 *            underlying output stream
-	 */
-	public SafeBufferedOutputStream(OutputStream out) {
-		super(out);
-	}
+public class LfsConfigInvalidException extends IOException {
+	private static final long serialVersionUID = 1L;
 
 	/**
-	 * @see BufferedOutputStream#BufferedOutputStream(OutputStream, int)
-	 * @param out
-	 *            underlying output stream
-	 * @param size
-	 *            buffer size
+	 * Constructor for LfsConfigInvalidException.
+	 *
+	 * @param msg
+	 *            the error description
 	 */
-	public SafeBufferedOutputStream(OutputStream out, int size) {
-		super(out, size);
+	public LfsConfigInvalidException(String msg) {
+		super(msg);
 	}
+
 }
diff --git a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/errors/LfsException.java b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/errors/LfsException.java
index 3b83639..778a819 100644
--- a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/errors/LfsException.java
+++ b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/errors/LfsException.java
@@ -52,6 +52,8 @@ public class LfsException extends Exception {
 	private static final long serialVersionUID = 1L;
 
 	/**
+	 * <p>Constructor for LfsException.</p>
+	 *
 	 * @param message
 	 *            error message, which may be shown to an end-user.
 	 */
diff --git a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/errors/LfsInsufficientStorage.java b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/errors/LfsInsufficientStorage.java
index 4faace9..f8bb89c 100644
--- a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/errors/LfsInsufficientStorage.java
+++ b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/errors/LfsInsufficientStorage.java
@@ -47,12 +47,13 @@
  * Thrown when there is insufficient storage on the server.
  *
  * @since 4.5
- *
  */
 public class LfsInsufficientStorage extends LfsException {
 	private static final long serialVersionUID = 1L;
 
 	/**
+	 * <p>Constructor for LfsInsufficientStorage.</p>
+	 *
 	 * @param message
 	 *            error message, which may be shown to an end-user.
 	 */
diff --git a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/errors/LfsRateLimitExceeded.java b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/errors/LfsRateLimitExceeded.java
index 606783041..7f7ed9b 100644
--- a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/errors/LfsRateLimitExceeded.java
+++ b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/errors/LfsRateLimitExceeded.java
@@ -47,12 +47,13 @@
  * Thrown when the user has hit a rate limit with the server.
  *
  * @since 4.5
- *
  */
 public class LfsRateLimitExceeded extends LfsException {
 	private static final long serialVersionUID = 1L;
 
 	/**
+	 * <p>Constructor for LfsRateLimitExceeded.</p>
+	 *
 	 * @param message
 	 *            error message, which may be shown to an end-user.
 	 */
diff --git a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/errors/LfsRepositoryNotFound.java b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/errors/LfsRepositoryNotFound.java
index 52c932a..9fa1105 100644
--- a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/errors/LfsRepositoryNotFound.java
+++ b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/errors/LfsRepositoryNotFound.java
@@ -56,9 +56,10 @@ public class LfsRepositoryNotFound extends LfsException {
 	private static final long serialVersionUID = 1L;
 
 	/**
+	 * <p>Constructor for LfsRepositoryNotFound.</p>
+	 *
 	 * @param name
 	 *            the repository name.
-	 *
 	 */
 	public LfsRepositoryNotFound(String name) {
 		super(MessageFormat.format(LfsText.get().repositoryNotFound, name));
diff --git a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/errors/LfsRepositoryReadOnly.java b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/errors/LfsRepositoryReadOnly.java
index 3610377..c3821fc 100644
--- a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/errors/LfsRepositoryReadOnly.java
+++ b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/errors/LfsRepositoryReadOnly.java
@@ -57,6 +57,8 @@ public class LfsRepositoryReadOnly extends LfsException {
 	private static final long serialVersionUID = 1L;
 
 	/**
+	 * <p>Constructor for LfsRepositoryReadOnly.</p>
+	 *
 	 * @param name
 	 *            the repository name.
 	 */
diff --git a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/errors/LfsUnauthorized.java b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/errors/LfsUnauthorized.java
index 62b0cde..45e29ec 100644
--- a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/errors/LfsUnauthorized.java
+++ b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/errors/LfsUnauthorized.java
@@ -56,6 +56,8 @@ public class LfsUnauthorized extends LfsException {
 	private static final long serialVersionUID = 1L;
 
 	/**
+	 * <p>Constructor for LfsUnauthorized.</p>
+	 *
 	 * @param operation
 	 *            the operation that was attempted.
 	 * @param name
diff --git a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/errors/LfsUnavailable.java b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/errors/LfsUnavailable.java
index ecb5e9e..285a172 100644
--- a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/errors/LfsUnavailable.java
+++ b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/errors/LfsUnavailable.java
@@ -56,6 +56,8 @@ public class LfsUnavailable extends LfsException {
 	private static final long serialVersionUID = 1L;
 
 	/**
+	 * Constructor for LfsUnavailable.
+	 *
 	 * @param name
 	 *            the repository name.
 	 */
diff --git a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/errors/LfsValidationError.java b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/errors/LfsValidationError.java
index 5e445ec..0492d3f 100644
--- a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/errors/LfsValidationError.java
+++ b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/errors/LfsValidationError.java
@@ -53,6 +53,8 @@ public class LfsValidationError extends LfsException {
 	private static final long serialVersionUID = 1L;
 
 	/**
+	 * Constructor for LfsValidationError.
+	 *
 	 * @param message
 	 *            error message, which may be shown to an end-user.
 	 */
diff --git a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/internal/AtomicObjectOutputStream.java b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/internal/AtomicObjectOutputStream.java
index 1598b9e..0762ac5 100644
--- a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/internal/AtomicObjectOutputStream.java
+++ b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/internal/AtomicObjectOutputStream.java
@@ -56,9 +56,9 @@
 import org.eclipse.jgit.lfs.lib.LongObjectId;
 
 /**
- * Output stream writing content to a {@link LockFile} which is committed on
- * close(). The stream checks if the hash of the stream content matches the
- * id.
+ * Output stream writing content to a
+ * {@link org.eclipse.jgit.internal.storage.file.LockFile} which is committed on
+ * close(). The stream checks if the hash of the stream content matches the id.
  */
 public class AtomicObjectOutputStream extends OutputStream {
 
@@ -71,9 +71,13 @@ public class AtomicObjectOutputStream extends OutputStream {
 	private AnyLongObjectId id;
 
 	/**
+	 * Constructor for AtomicObjectOutputStream.
+	 *
 	 * @param path
+	 *            a {@link java.nio.file.Path} object.
 	 * @param id
-	 * @throws IOException
+	 *            a {@link org.eclipse.jgit.lfs.lib.AnyLongObjectId} object.
+	 * @throws java.io.IOException
 	 */
 	public AtomicObjectOutputStream(Path path, AnyLongObjectId id)
 			throws IOException {
@@ -85,36 +89,46 @@ public AtomicObjectOutputStream(Path path, AnyLongObjectId id)
 	}
 
 	/**
+	 * Constructor for AtomicObjectOutputStream.
+	 *
 	 * @param path
-	 * @throws IOException
+	 *            a {@link java.nio.file.Path} object.
+	 * @throws java.io.IOException
 	 */
 	public AtomicObjectOutputStream(Path path) throws IOException {
 		this(path, null);
 	}
 
 	/**
+	 * Get the <code>id</code>.
+	 *
 	 * @return content hash of the object which was streamed through this
-	 *         stream. May return {@code null} if called before closing this stream.
+	 *         stream. May return {@code null} if called before closing this
+	 *         stream.
 	 */
 	public @Nullable AnyLongObjectId getId() {
 		return id;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void write(int b) throws IOException {
 		out.write(b);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void write(byte[] b) throws IOException {
 		out.write(b);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void write(byte[] b, int off, int len) throws IOException {
 		out.write(b, off, len);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void close() throws IOException {
 		out.close();
diff --git a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/internal/LfsConnectionFactory.java b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/internal/LfsConnectionFactory.java
new file mode 100644
index 0000000..3ac6992
--- /dev/null
+++ b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/internal/LfsConnectionFactory.java
@@ -0,0 +1,313 @@
+/*
+ * Copyright (C) 2017, Markus Duft <markus.duft@ssi-schaefer.com>
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ *   copyright notice, this list of conditions and the following
+ *   disclaimer in the documentation and/or other materials provided
+ *   with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ *   names of its contributors may be used to endorse or promote
+ *   products derived from this software without specific prior
+ *   written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.eclipse.jgit.lfs.internal;
+
+import static org.eclipse.jgit.util.HttpSupport.ENCODING_GZIP;
+import static org.eclipse.jgit.util.HttpSupport.HDR_ACCEPT;
+import static org.eclipse.jgit.util.HttpSupport.HDR_ACCEPT_ENCODING;
+import static org.eclipse.jgit.util.HttpSupport.HDR_CONTENT_TYPE;
+
+import java.io.IOException;
+import java.net.ProxySelector;
+import java.net.URL;
+import java.text.SimpleDateFormat;
+import java.util.LinkedList;
+import java.util.Map;
+import java.util.TreeMap;
+
+import org.eclipse.jgit.annotations.NonNull;
+import org.eclipse.jgit.lfs.LfsPointer;
+import org.eclipse.jgit.lfs.Protocol;
+import org.eclipse.jgit.lfs.errors.LfsConfigInvalidException;
+import org.eclipse.jgit.lib.ConfigConstants;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.lib.StoredConfig;
+import org.eclipse.jgit.transport.HttpConfig;
+import org.eclipse.jgit.transport.HttpTransport;
+import org.eclipse.jgit.transport.URIish;
+import org.eclipse.jgit.transport.http.HttpConnection;
+import org.eclipse.jgit.util.HttpSupport;
+import org.eclipse.jgit.util.SshSupport;
+
+/**
+ * Provides means to get a valid LFS connection for a given repository.
+ */
+public class LfsConnectionFactory {
+
+	private static final int SSH_AUTH_TIMEOUT_SECONDS = 5;
+	private static final String SCHEME_HTTPS = "https"; //$NON-NLS-1$
+	private static final String SCHEME_SSH = "ssh"; //$NON-NLS-1$
+	private static final Map<String, AuthCache> sshAuthCache = new TreeMap<>();
+
+	/**
+	 * Determine URL of LFS server by looking into config parameters lfs.url,
+	 * lfs.[remote].url or remote.[remote].url. The LFS server URL is computed
+	 * from remote.[remote].url by appending "/info/lfs". In case there is no
+	 * URL configured, a SSH remote URI can be used to auto-detect the LFS URI
+	 * by using the remote "git-lfs-authenticate" command.
+	 *
+	 * @param db
+	 *            the repository to work with
+	 * @param method
+	 *            the method (GET,PUT,...) of the request this connection will
+	 *            be used for
+	 * @param purpose
+	 *            the action, e.g. Protocol.OPERATION_DOWNLOAD
+	 * @return the url for the lfs server. e.g.
+	 *         "https://github.com/github/git-lfs.git/info/lfs"
+	 * @throws IOException
+	 */
+	public static HttpConnection getLfsConnection(Repository db, String method,
+			String purpose) throws IOException {
+		StoredConfig config = db.getConfig();
+		Map<String, String> additionalHeaders = new TreeMap<>();
+		String lfsUrl = getLfsUrl(db, purpose, additionalHeaders);
+		URL url = new URL(lfsUrl + Protocol.OBJECTS_LFS_ENDPOINT);
+		HttpConnection connection = HttpTransport.getConnectionFactory().create(
+				url, HttpSupport.proxyFor(ProxySelector.getDefault(), url));
+		connection.setDoOutput(true);
+		if (url.getProtocol().equals(SCHEME_HTTPS)
+				&& !config.getBoolean(HttpConfig.HTTP,
+						HttpConfig.SSL_VERIFY_KEY, true)) {
+			HttpSupport.disableSslVerify(connection);
+		}
+		connection.setRequestMethod(method);
+		connection.setRequestProperty(HDR_ACCEPT,
+				Protocol.CONTENTTYPE_VND_GIT_LFS_JSON);
+		connection.setRequestProperty(HDR_CONTENT_TYPE,
+				Protocol.CONTENTTYPE_VND_GIT_LFS_JSON);
+		additionalHeaders
+				.forEach((k, v) -> connection.setRequestProperty(k, v));
+		return connection;
+	}
+
+	private static String getLfsUrl(Repository db, String purpose,
+			Map<String, String> additionalHeaders)
+			throws LfsConfigInvalidException {
+		StoredConfig config = db.getConfig();
+		String lfsUrl = config.getString(ConfigConstants.CONFIG_SECTION_LFS,
+				null,
+				ConfigConstants.CONFIG_KEY_URL);
+		if (lfsUrl == null) {
+			String remoteUrl = null;
+			for (String remote : db.getRemoteNames()) {
+				lfsUrl = config.getString(ConfigConstants.CONFIG_SECTION_LFS,
+						remote,
+						ConfigConstants.CONFIG_KEY_URL);
+				// This could be done better (more precise logic), but according
+				// to https://github.com/git-lfs/git-lfs/issues/1759 git-lfs
+				// generally only supports 'origin' in an integrated workflow.
+				if (lfsUrl == null && (remote.equals(
+						org.eclipse.jgit.lib.Constants.DEFAULT_REMOTE_NAME))) {
+					remoteUrl = config.getString(
+							ConfigConstants.CONFIG_KEY_REMOTE, remote,
+							ConfigConstants.CONFIG_KEY_URL);
+				}
+				break;
+			}
+			if (lfsUrl == null && remoteUrl != null) {
+				lfsUrl = discoverLfsUrl(db, purpose, additionalHeaders,
+						remoteUrl);
+			} else {
+				lfsUrl = lfsUrl + Protocol.INFO_LFS_ENDPOINT;
+			}
+		}
+		if (lfsUrl == null) {
+			throw new LfsConfigInvalidException(LfsText.get().lfsNoDownloadUrl);
+		}
+		return lfsUrl;
+	}
+
+	private static String discoverLfsUrl(Repository db, String purpose,
+			Map<String, String> additionalHeaders, String remoteUrl) {
+		try {
+			URIish u = new URIish(remoteUrl);
+			if (SCHEME_SSH.equals(u.getScheme())) {
+				Protocol.ExpiringAction action = getSshAuthentication(
+						db, purpose, remoteUrl, u);
+				additionalHeaders.putAll(action.header);
+				return action.href;
+			} else {
+				return remoteUrl + Protocol.INFO_LFS_ENDPOINT;
+			}
+		} catch (Exception e) {
+			return null; // could not discover
+		}
+	}
+
+	private static Protocol.ExpiringAction getSshAuthentication(
+			Repository db, String purpose, String remoteUrl, URIish u)
+			throws IOException {
+		AuthCache cached = sshAuthCache.get(remoteUrl);
+		Protocol.ExpiringAction action = null;
+		if (cached != null && cached.validUntil > System.currentTimeMillis()) {
+			action = cached.cachedAction;
+		}
+
+		if (action == null) {
+			// discover and authenticate; git-lfs does "ssh
+			// -p <port> -- <host> git-lfs-authenticate
+			// <project> <upload/download>"
+			String json = SshSupport.runSshCommand(u.setPath(""), //$NON-NLS-1$
+					null, db.getFS(),
+					"git-lfs-authenticate " + extractProjectName(u) + " " //$NON-NLS-1$//$NON-NLS-2$
+							+ purpose,
+					SSH_AUTH_TIMEOUT_SECONDS);
+
+			action = Protocol.gson().fromJson(json,
+					Protocol.ExpiringAction.class);
+
+			// cache the result as long as possible.
+			AuthCache c = new AuthCache(action);
+			sshAuthCache.put(remoteUrl, c);
+		}
+		return action;
+	}
+
+	/**
+	 * Create a connection for the specified
+	 * {@link org.eclipse.jgit.lfs.Protocol.Action}.
+	 *
+	 * @param repo
+	 *            the repo to fetch required configuration from
+	 * @param action
+	 *            the action for which to create a connection
+	 * @param method
+	 *            the target method (GET or PUT)
+	 * @return a connection. output mode is not set.
+	 * @throws IOException
+	 *             in case of any error.
+	 */
+	public static @NonNull HttpConnection getLfsContentConnection(
+			Repository repo, Protocol.Action action, String method)
+			throws IOException {
+		URL contentUrl = new URL(action.href);
+		HttpConnection contentServerConn = HttpTransport.getConnectionFactory()
+				.create(contentUrl, HttpSupport
+						.proxyFor(ProxySelector.getDefault(), contentUrl));
+		contentServerConn.setRequestMethod(method);
+		action.header
+				.forEach((k, v) -> contentServerConn.setRequestProperty(k, v));
+		if (contentUrl.getProtocol().equals(SCHEME_HTTPS)
+				&& !repo.getConfig().getBoolean(HttpConfig.HTTP,
+						HttpConfig.SSL_VERIFY_KEY, true)) {
+			HttpSupport.disableSslVerify(contentServerConn);
+		}
+
+		contentServerConn.setRequestProperty(HDR_ACCEPT_ENCODING,
+				ENCODING_GZIP);
+
+		return contentServerConn;
+	}
+
+	private static String extractProjectName(URIish u) {
+		String path = u.getPath().substring(1);
+		if (path.endsWith(org.eclipse.jgit.lib.Constants.DOT_GIT)) {
+			return path.substring(0, path.length() - 4);
+		} else {
+			return path;
+		}
+	}
+
+	/**
+	 * @param operation
+	 *            the operation to perform, e.g. Protocol.OPERATION_DOWNLOAD
+	 * @param resources
+	 *            the LFS resources affected
+	 * @return a request that can be serialized to JSON
+	 */
+	public static Protocol.Request toRequest(String operation,
+			LfsPointer... resources) {
+		Protocol.Request req = new Protocol.Request();
+		req.operation = operation;
+		if (resources != null) {
+			req.objects = new LinkedList<>();
+			for (LfsPointer res : resources) {
+				Protocol.ObjectSpec o = new Protocol.ObjectSpec();
+				o.oid = res.getOid().getName();
+				o.size = res.getSize();
+				req.objects.add(o);
+			}
+		}
+		return req;
+	}
+
+	private static final class AuthCache {
+		private static final long AUTH_CACHE_EAGER_TIMEOUT = 500;
+
+		private static final SimpleDateFormat ISO_FORMAT = new SimpleDateFormat(
+				"yyyy-MM-dd'T'HH:mm:ss.SSSX"); //$NON-NLS-1$
+
+		/**
+		 * Creates a cache entry for an authentication response.
+		 * <p>
+		 * The timeout of the cache token is extracted from the given action. If
+		 * no timeout can be determined, the token will be used only once.
+		 *
+		 * @param action
+		 */
+		public AuthCache(Protocol.ExpiringAction action) {
+			this.cachedAction = action;
+			try {
+				if (action.expiresIn != null && !action.expiresIn.isEmpty()) {
+					this.validUntil = (System.currentTimeMillis()
+							+ Long.parseLong(action.expiresIn))
+							- AUTH_CACHE_EAGER_TIMEOUT;
+				} else if (action.expiresAt != null
+						&& !action.expiresAt.isEmpty()) {
+					this.validUntil = ISO_FORMAT.parse(action.expiresAt)
+							.getTime() - AUTH_CACHE_EAGER_TIMEOUT;
+				} else {
+					this.validUntil = System.currentTimeMillis();
+				}
+			} catch (Exception e) {
+				this.validUntil = System.currentTimeMillis();
+			}
+		}
+
+		long validUntil;
+
+		Protocol.ExpiringAction cachedAction;
+	}
+
+}
diff --git a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/internal/LfsText.java b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/internal/LfsText.java
index 4459588..d7d0fe1 100644
--- a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/internal/LfsText.java
+++ b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/internal/LfsText.java
@@ -51,6 +51,8 @@
 public class LfsText extends TranslationBundle {
 
 	/**
+	 * Get an instance of this translation bundle.
+	 *
 	 * @return an instance of this translation bundle
 	 */
 	public static LfsText get() {
@@ -60,13 +62,20 @@ public static LfsText get() {
 	// @formatter:off
 	/***/ public String corruptLongObject;
 	/***/ public String inconsistentMediafileLength;
+	/***/ public String inconsistentContentLength;
 	/***/ public String incorrectLONG_OBJECT_ID_LENGTH;
 	/***/ public String invalidLongId;
 	/***/ public String invalidLongIdLength;
+	/***/ public String lfsUnavailable;
+	/***/ public String protocolError;
 	/***/ public String requiredHashFunctionNotAvailable;
 	/***/ public String repositoryNotFound;
 	/***/ public String repositoryReadOnly;
-	/***/ public String lfsUnavailable;
 	/***/ public String lfsUnathorized;
 	/***/ public String lfsFailedToGetRepository;
+	/***/ public String lfsNoDownloadUrl;
+	/***/ public String serverFailure;
+	/***/ public String wrongAmoutOfDataReceived;
+	/***/ public String userConfigInvalid;
+	/***/ public String missingLocalObject;
 }
diff --git a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/lib/AbbreviatedLongObjectId.java b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/lib/AbbreviatedLongObjectId.java
index e9eb0e3..bdd1b39 100644
--- a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/lib/AbbreviatedLongObjectId.java
+++ b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/lib/AbbreviatedLongObjectId.java
@@ -48,14 +48,11 @@
 
 import org.eclipse.jgit.lfs.errors.InvalidLongObjectIdException;
 import org.eclipse.jgit.lfs.internal.LfsText;
-import org.eclipse.jgit.lib.AbbreviatedObjectId;
-import org.eclipse.jgit.lib.AnyObjectId;
-import org.eclipse.jgit.lib.ObjectId;
 import org.eclipse.jgit.util.NB;
 import org.eclipse.jgit.util.RawParseUtils;
 
 /**
- * A prefix abbreviation of an {@link LongObjectId}.
+ * A prefix abbreviation of an {@link org.eclipse.jgit.lfs.lib.LongObjectId}.
  * <p>
  * Enable abbreviating SHA-256 strings used by Git LFS, using sufficient leading
  * digits from the LongObjectId name to still be unique within the repository
@@ -65,7 +62,7 @@
  * This class converts the hex string into a binary form, to make it more
  * efficient for matching against an object.
  *
- * Ported to SHA-256 from {@link AbbreviatedObjectId}
+ * Ported to SHA-256 from {@link org.eclipse.jgit.lib.AbbreviatedObjectId}
  *
  * @since 4.3
  */
@@ -81,7 +78,7 @@ public final class AbbreviatedLongObjectId implements Serializable {
 	 *            the string to test.
 	 * @return true if the string can converted into an AbbreviatedObjectId.
 	 */
-	public static final boolean isId(final String id) {
+	public static final boolean isId(String id) {
 		if (id.length() < 2
 				|| Constants.LONG_OBJECT_ID_STRING_LENGTH < id.length())
 			return false;
@@ -117,13 +114,14 @@ public static final AbbreviatedLongObjectId fromString(final byte[] buf,
 	}
 
 	/**
-	 * Convert an AbbreviatedObjectId from an {@link AnyObjectId}.
+	 * Convert an AbbreviatedObjectId from an
+	 * {@link org.eclipse.jgit.lib.AnyObjectId}.
 	 * <p>
 	 * This method copies over all bits of the Id, and is therefore complete
 	 * (see {@link #isComplete()}).
 	 *
 	 * @param id
-	 *            the {@link ObjectId} to convert from.
+	 *            the {@link org.eclipse.jgit.lib.ObjectId} to convert from.
 	 * @return the converted object id.
 	 */
 	public static final AbbreviatedLongObjectId fromLongObjectId(
@@ -140,7 +138,7 @@ public static final AbbreviatedLongObjectId fromLongObjectId(
 	 *            the string to read from. Must be &lt;= 64 characters.
 	 * @return the converted object id.
 	 */
-	public static final AbbreviatedLongObjectId fromString(final String str) {
+	public static final AbbreviatedLongObjectId fromString(String str) {
 		if (str.length() > Constants.LONG_OBJECT_ID_STRING_LENGTH)
 			throw new IllegalArgumentException(
 					MessageFormat.format(LfsText.get().invalidLongId, str));
@@ -175,7 +173,7 @@ private static final long hexUInt64(final byte[] bs, int p, final int end) {
 		return r << (16 - n) * 4;
 	}
 
-	static long mask(final int nibbles, final long word, final long v) {
+	static long mask(int nibbles, long word, long v) {
 		final long b = (word - 1) * 16;
 		if (b + 16 <= nibbles) {
 			// We have all of the bits required for this word.
@@ -213,17 +211,29 @@ static long mask(final int nibbles, final long word, final long v) {
 		w4 = new_4;
 	}
 
-	/** @return number of hex digits appearing in this id */
+	/**
+	 * Get length
+	 *
+	 * @return number of hex digits appearing in this id.
+	 */
 	public int length() {
 		return nibbles;
 	}
 
-	/** @return true if this ObjectId is actually a complete id. */
+	/**
+	 * Check if this id is complete
+	 *
+	 * @return true if this ObjectId is actually a complete id.
+	 */
 	public boolean isComplete() {
 		return length() == Constants.LONG_OBJECT_ID_STRING_LENGTH;
 	}
 
-	/** @return a complete ObjectId; null if {@link #isComplete()} is false */
+	/**
+	 * Convert to LongObjectId
+	 *
+	 * @return a complete ObjectId; null if {@link #isComplete()} is false.
+	 */
 	public LongObjectId toLongObjectId() {
 		return isComplete() ? new LongObjectId(w1, w2, w3, w4) : null;
 	}
@@ -239,7 +249,7 @@ public LongObjectId toLongObjectId() {
 	 *         &gt;0 if this abbreviation names an object that is after
 	 *         <code>other</code>.
 	 */
-	public final int prefixCompare(final AnyLongObjectId other) {
+	public final int prefixCompare(AnyLongObjectId other) {
 		int cmp;
 
 		cmp = NB.compareUInt64(w1, mask(1, other.w1));
@@ -271,7 +281,7 @@ public final int prefixCompare(final AnyLongObjectId other) {
 	 *         &gt;0 if this abbreviation names an object that is after
 	 *         <code>other</code>.
 	 */
-	public final int prefixCompare(final byte[] bs, final int p) {
+	public final int prefixCompare(byte[] bs, int p) {
 		int cmp;
 
 		cmp = NB.compareUInt64(w1, mask(1, NB.decodeInt64(bs, p)));
@@ -303,7 +313,7 @@ public final int prefixCompare(final byte[] bs, final int p) {
 	 *         &gt;0 if this abbreviation names an object that is after
 	 *         <code>other</code>.
 	 */
-	public final int prefixCompare(final long[] bs, final int p) {
+	public final int prefixCompare(long[] bs, int p) {
 		int cmp;
 
 		cmp = NB.compareUInt64(w1, mask(1, bs[p]));
@@ -321,22 +331,28 @@ public final int prefixCompare(final long[] bs, final int p) {
 		return NB.compareUInt64(w4, mask(4, bs[p + 3]));
 	}
 
-	/** @return value for a fan-out style map, only valid of length &gt;= 2. */
+	/**
+	 * Get the first byte of this id
+	 *
+	 * @return value for a fan-out style map, only valid of length &gt;= 2.
+	 */
 	public final int getFirstByte() {
 		return (int) (w1 >>> 56);
 	}
 
-	private long mask(final long word, final long v) {
+	private long mask(long word, long v) {
 		return mask(nibbles, word, v);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public int hashCode() {
 		return (int) (w1 >> 32);
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	public boolean equals(final Object o) {
+	public boolean equals(Object o) {
 		if (o instanceof AbbreviatedLongObjectId) {
 			final AbbreviatedLongObjectId b = (AbbreviatedLongObjectId) o;
 			return nibbles == b.nibbles && w1 == b.w1 && w2 == b.w2
@@ -346,6 +362,8 @@ public boolean equals(final Object o) {
 	}
 
 	/**
+	 * <p>name.</p>
+	 *
 	 * @return string form of the abbreviation, in lower case hexadecimal.
 	 */
 	public final String name() {
@@ -367,6 +385,7 @@ public final String name() {
 		return new String(b, 0, nibbles);
 	}
 
+	/** {@inheritDoc} */
 	@SuppressWarnings("nls")
 	@Override
 	public String toString() {
diff --git a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/lib/AnyLongObjectId.java b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/lib/AnyLongObjectId.java
index caf034d..0788922 100644
--- a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/lib/AnyLongObjectId.java
+++ b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/lib/AnyLongObjectId.java
@@ -49,17 +49,17 @@
 import java.nio.ByteBuffer;
 
 import org.eclipse.jgit.lib.AnyObjectId;
-import org.eclipse.jgit.lib.ObjectReader;
 import org.eclipse.jgit.util.NB;
 
 /**
  * A (possibly mutable) SHA-256 abstraction.
  * <p>
- * If this is an instance of {@link MutableLongObjectId} the concept of equality
+ * If this is an instance of
+ * {@link org.eclipse.jgit.lfs.lib.MutableLongObjectId} the concept of equality
  * with this instance can alter at any time, if this instance is modified to
  * represent a different object name.
  *
- * Ported to SHA-256 from {@link AnyObjectId}
+ * Ported to SHA-256 from {@link org.eclipse.jgit.lib.AnyObjectId}
  *
  * @since 4.3
  */
@@ -132,14 +132,15 @@ public final int getSecondByte() {
 	 * @param index
 	 *            index of the byte to obtain from the raw form of the
 	 *            LongObjectId. Must be in range [0,
-	 *            {@link Constants#LONG_OBJECT_ID_LENGTH}).
+	 *            {@link org.eclipse.jgit.lfs.lib.Constants#LONG_OBJECT_ID_LENGTH}).
 	 * @return the value of the requested byte at {@code index}. Returned values
 	 *         are unsigned and thus are in the range [0,255] rather than the
 	 *         signed byte range of [-128, 127].
-	 * @throws ArrayIndexOutOfBoundsException
+	 * @throws java.lang.ArrayIndexOutOfBoundsException
 	 *             {@code index} is less than 0, equal to
-	 *             {@link Constants#LONG_OBJECT_ID_LENGTH}, or greater than
-	 *             {@link Constants#LONG_OBJECT_ID_LENGTH}.
+	 *             {@link org.eclipse.jgit.lfs.lib.Constants#LONG_OBJECT_ID_LENGTH},
+	 *             or greater than
+	 *             {@link org.eclipse.jgit.lfs.lib.Constants#LONG_OBJECT_ID_LENGTH}.
 	 */
 	public final int getByte(int index) {
 		long w;
@@ -164,15 +165,12 @@ public final int getByte(int index) {
 	}
 
 	/**
-	 * Compare this LongObjectId to another and obtain a sort ordering.
+	 * {@inheritDoc}
 	 *
-	 * @param other
-	 *            the other id to compare to. Must not be null.
-	 * @return &lt; 0 if this id comes before other; 0 if this id is equal to
-	 *         other; &gt; 0 if this id comes after other.
+	 * Compare this LongObjectId to another and obtain a sort ordering.
 	 */
 	@Override
-	public final int compareTo(final AnyLongObjectId other) {
+	public final int compareTo(AnyLongObjectId other) {
 		if (this == other)
 			return 0;
 
@@ -204,7 +202,7 @@ public final int compareTo(final AnyLongObjectId other) {
 	 * @return a negative integer, zero, or a positive integer as this object is
 	 *         less than, equal to, or greater than the specified object.
 	 */
-	public final int compareTo(final byte[] bs, final int p) {
+	public final int compareTo(byte[] bs, int p) {
 		int cmp;
 
 		cmp = NB.compareUInt64(w1, NB.decodeInt64(bs, p));
@@ -233,7 +231,7 @@ public final int compareTo(final byte[] bs, final int p) {
 	 * @return a negative integer, zero, or a positive integer as this object is
 	 *         less than, equal to, or greater than the specified object.
 	 */
-	public final int compareTo(final long[] bs, final int p) {
+	public final int compareTo(long[] bs, int p) {
 		int cmp;
 
 		cmp = NB.compareUInt64(w1, bs[p]);
@@ -259,10 +257,11 @@ public final int compareTo(final long[] bs, final int p) {
 	 * @return true if this LongObjectId begins with the abbreviation; else
 	 *         false.
 	 */
-	public boolean startsWith(final AbbreviatedLongObjectId abbr) {
+	public boolean startsWith(AbbreviatedLongObjectId abbr) {
 		return abbr.prefixCompare(this) == 0;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public final int hashCode() {
 		return (int) (w1 >> 32);
@@ -275,12 +274,13 @@ public final int hashCode() {
 	 *            the other id to compare to. May be null.
 	 * @return true only if both LongObjectIds have identical bits.
 	 */
-	public final boolean equals(final AnyLongObjectId other) {
+	public final boolean equals(AnyLongObjectId other) {
 		return other != null ? equals(this, other) : false;
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	public final boolean equals(final Object o) {
+	public final boolean equals(Object o) {
 		if (o instanceof AnyLongObjectId)
 			return equals((AnyLongObjectId) o);
 		else
@@ -293,7 +293,7 @@ public final boolean equals(final Object o) {
 	 * @param w
 	 *            the buffer to copy to. Must be in big endian order.
 	 */
-	public void copyRawTo(final ByteBuffer w) {
+	public void copyRawTo(ByteBuffer w) {
 		w.putLong(w1);
 		w.putLong(w2);
 		w.putLong(w3);
@@ -308,7 +308,7 @@ public void copyRawTo(final ByteBuffer w) {
 	 * @param o
 	 *            the offset within b to write at.
 	 */
-	public void copyRawTo(final byte[] b, final int o) {
+	public void copyRawTo(byte[] b, int o) {
 		NB.encodeInt64(b, o, w1);
 		NB.encodeInt64(b, o + 8, w2);
 		NB.encodeInt64(b, o + 16, w3);
@@ -323,7 +323,7 @@ public void copyRawTo(final byte[] b, final int o) {
 	 * @param o
 	 *            the offset within b to write at.
 	 */
-	public void copyRawTo(final long[] b, final int o) {
+	public void copyRawTo(long[] b, int o) {
 		b[o] = w1;
 		b[o + 1] = w2;
 		b[o + 2] = w3;
@@ -335,17 +335,17 @@ public void copyRawTo(final long[] b, final int o) {
 	 *
 	 * @param w
 	 *            the stream to write to.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the stream writing failed.
 	 */
-	public void copyRawTo(final OutputStream w) throws IOException {
+	public void copyRawTo(OutputStream w) throws IOException {
 		writeRawLong(w, w1);
 		writeRawLong(w, w2);
 		writeRawLong(w, w3);
 		writeRawLong(w, w4);
 	}
 
-	private static void writeRawLong(final OutputStream w, long v)
+	private static void writeRawLong(OutputStream w, long v)
 			throws IOException {
 		w.write((int) (v >>> 56));
 		w.write((int) (v >>> 48));
@@ -362,10 +362,10 @@ private static void writeRawLong(final OutputStream w, long v)
 	 *
 	 * @param w
 	 *            the stream to copy to.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the stream writing failed.
 	 */
-	public void copyTo(final OutputStream w) throws IOException {
+	public void copyTo(OutputStream w) throws IOException {
 		w.write(toHexByteArray());
 	}
 
@@ -406,7 +406,7 @@ public void copyTo(ByteBuffer b) {
 	private static final byte[] hexbyte = { '0', '1', '2', '3', '4', '5', '6',
 			'7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
 
-	private static void formatHexByte(final byte[] dst, final int p, long w) {
+	private static void formatHexByte(byte[] dst, int p, long w) {
 		int o = p + 15;
 		while (o >= p && w != 0) {
 			dst[o--] = hexbyte[(int) (w & 0xf)];
@@ -421,10 +421,10 @@ private static void formatHexByte(final byte[] dst, final int p, long w) {
 	 *
 	 * @param w
 	 *            the stream to copy to.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the stream writing failed.
 	 */
-	public void copyTo(final Writer w) throws IOException {
+	public void copyTo(Writer w) throws IOException {
 		w.write(toHexCharArray());
 	}
 
@@ -437,10 +437,10 @@ public void copyTo(final Writer w) throws IOException {
 	 *            of object id (64 characters or larger).
 	 * @param w
 	 *            the stream to copy to.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the stream writing failed.
 	 */
-	public void copyTo(final char[] tmp, final Writer w) throws IOException {
+	public void copyTo(char[] tmp, Writer w) throws IOException {
 		toHexCharArray(tmp);
 		w.write(tmp, 0, Constants.LONG_OBJECT_ID_STRING_LENGTH);
 	}
@@ -455,7 +455,7 @@ public void copyTo(final char[] tmp, final Writer w) throws IOException {
 	 * @param w
 	 *            the string to append onto.
 	 */
-	public void copyTo(final char[] tmp, final StringBuilder w) {
+	public void copyTo(char[] tmp, StringBuilder w) {
 		toHexCharArray(tmp);
 		w.append(tmp, 0, Constants.LONG_OBJECT_ID_STRING_LENGTH);
 	}
@@ -466,7 +466,7 @@ public void copyTo(final char[] tmp, final StringBuilder w) {
 		return dst;
 	}
 
-	private void toHexCharArray(final char[] dst) {
+	private void toHexCharArray(char[] dst) {
 		formatHexChar(dst, 0, w1);
 		formatHexChar(dst, 16, w2);
 		formatHexChar(dst, 32, w3);
@@ -476,7 +476,7 @@ private void toHexCharArray(final char[] dst) {
 	private static final char[] hexchar = { '0', '1', '2', '3', '4', '5', '6',
 			'7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
 
-	static void formatHexChar(final char[] dst, final int p, long w) {
+	static void formatHexChar(char[] dst, int p, long w) {
 		int o = p + 15;
 		while (o >= p && w != 0) {
 			dst[o--] = hexchar[(int) (w & 0xf)];
@@ -486,6 +486,7 @@ static void formatHexChar(final char[] dst, final int p, long w) {
 			dst[o--] = '0';
 	}
 
+	/** {@inheritDoc} */
 	@SuppressWarnings("nls")
 	@Override
 	public String toString() {
@@ -493,6 +494,8 @@ public String toString() {
 	}
 
 	/**
+	 * Get string form of the SHA-256
+	 *
 	 * @return string form of the SHA-256, in lower case hexadecimal.
 	 */
 	public final String name() {
@@ -500,6 +503,8 @@ public final String name() {
 	}
 
 	/**
+	 * Get string form of the SHA-256
+	 *
 	 * @return string form of the SHA-256, in lower case hexadecimal.
 	 */
 	public final String getName() {
@@ -510,14 +515,16 @@ public final String getName() {
 	 * Return an abbreviation (prefix) of this object SHA-256.
 	 * <p>
 	 * This implementation does not guarantee uniqueness. Callers should instead
-	 * use {@link ObjectReader#abbreviate(AnyObjectId, int)} to obtain a unique
-	 * abbreviation within the scope of a particular object database.
+	 * use
+	 * {@link org.eclipse.jgit.lib.ObjectReader#abbreviate(AnyObjectId, int)} to
+	 * obtain a unique abbreviation within the scope of a particular object
+	 * database.
 	 *
 	 * @param len
 	 *            length of the abbreviated string.
 	 * @return SHA-256 abbreviation.
 	 */
-	public AbbreviatedLongObjectId abbreviate(final int len) {
+	public AbbreviatedLongObjectId abbreviate(int len) {
 		final long a = AbbreviatedLongObjectId.mask(len, 1, w1);
 		final long b = AbbreviatedLongObjectId.mask(len, 2, w2);
 		final long c = AbbreviatedLongObjectId.mask(len, 3, w3);
@@ -529,8 +536,8 @@ public AbbreviatedLongObjectId abbreviate(final int len) {
 	 * Obtain an immutable copy of this current object.
 	 * <p>
 	 * Only returns <code>this</code> if this instance is an unsubclassed
-	 * instance of {@link LongObjectId}; otherwise a new instance is returned
-	 * holding the same value.
+	 * instance of {@link org.eclipse.jgit.lfs.lib.LongObjectId}; otherwise a
+	 * new instance is returned holding the same value.
 	 * <p>
 	 * This method is useful to shed any additional memory that may be tied to
 	 * the subclass, yet retain the unique identity of the object id for future
diff --git a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/lib/Constants.java b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/lib/Constants.java
index 0220743..835d7be 100644
--- a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/lib/Constants.java
+++ b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/lib/Constants.java
@@ -52,11 +52,11 @@
  * Misc. constants used throughout JGit LFS extension.
  *
  * @since 4.3
- **/
+ */
 @SuppressWarnings("nls")
 public final class Constants {
 	/**
-	 * lfs folder
+	 * lfs folder/section/filter name
 	 *
 	 * @since 4.6
 	 */
@@ -108,10 +108,17 @@ public final class Constants {
 	public static final String VERIFY = "verify";
 
 	/**
+	 * Prefix for all LFS related filters.
+	 *
+	 * @since 4.11
+	 */
+	public static final String ATTR_FILTER_DRIVER_PREFIX = "lfs/";
+
+	/**
 	 * Create a new digest function for objects.
 	 *
 	 * @return a new digest object.
-	 * @throws RuntimeException
+	 * @throws java.lang.RuntimeException
 	 *             this Java virtual machine does not support the required hash
 	 *             function. Very unlikely given that JGit uses a hash function
 	 *             that is in the Java reference specification.
@@ -133,14 +140,15 @@ public static MessageDigest newMessageDigest() {
 	}
 
 	/**
-	 * Content type used by LFS REST API as defined in
-	 * {@link "https://github.com/github/git-lfs/blob/master/docs/api/v1/http-v1-batch.md"}
+	 * Content type used by LFS REST API as defined in <a href=
+	 * "https://github.com/github/git-lfs/blob/master/docs/api/v1/http-v1-batch.md">
+	 * https://github.com/github/git-lfs/blob/master/docs/api/v1/http-v1-batch.md</a>
 	 */
 	public static final String CONTENT_TYPE_GIT_LFS_JSON = "application/vnd.git-lfs+json";
 
 	/**
-	 * "arbitrary binary data" as defined in RFC 2046
-	 * {@link "https://www.ietf.org/rfc/rfc2046.txt"}
+	 * "Arbitrary binary data" as defined in
+	 * <a href="https://www.ietf.org/rfc/rfc2046.txt">RFC 2046</a>
 	 */
 	public static final String HDR_APPLICATION_OCTET_STREAM = "application/octet-stream";
 }
diff --git a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/lib/LfsPointerFilter.java b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/lib/LfsPointerFilter.java
index 6f672b8..dcc915d 100644
--- a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/lib/LfsPointerFilter.java
+++ b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/lib/LfsPointerFilter.java
@@ -66,12 +66,15 @@ public class LfsPointerFilter extends TreeFilter {
 	private LfsPointer pointer;
 
 	/**
-	 * @return {@link LfsPointer} or {@code null}
+	 * Get the field <code>pointer</code>.
+	 *
+	 * @return {@link org.eclipse.jgit.lfs.LfsPointer} or {@code null}
 	 */
 	public LfsPointer getPointer() {
 		return pointer;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public boolean include(TreeWalk walk) throws MissingObjectException,
 			IncorrectObjectTypeException, IOException {
@@ -91,11 +94,13 @@ public boolean include(TreeWalk walk) throws MissingObjectException,
 		}
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public boolean shouldBeRecursive() {
 		return false;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public TreeFilter clone() {
 		return new LfsPointerFilter();
diff --git a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/lib/LongObjectId.java b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/lib/LongObjectId.java
index c4a4e43..8159576 100644
--- a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/lib/LongObjectId.java
+++ b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/lib/LongObjectId.java
@@ -49,14 +49,13 @@
 import java.io.Serializable;
 
 import org.eclipse.jgit.lfs.errors.InvalidLongObjectIdException;
-import org.eclipse.jgit.lib.ObjectId;
 import org.eclipse.jgit.util.NB;
 import org.eclipse.jgit.util.RawParseUtils;
 
 /**
  * A SHA-256 abstraction.
  *
- * Ported to SHA-256 from {@link ObjectId}
+ * Ported to SHA-256 from {@link org.eclipse.jgit.lib.ObjectId}
  *
  * @since 4.3
  */
@@ -91,7 +90,7 @@ public static final LongObjectId zeroId() {
 	 *            the string to test.
 	 * @return true if the string can converted into an LongObjectId.
 	 */
-	public static final boolean isId(final String id) {
+	public static final boolean isId(String id) {
 		if (id.length() != Constants.LONG_OBJECT_ID_STRING_LENGTH)
 			return false;
 		try {
@@ -111,7 +110,7 @@ public static final boolean isId(final String id) {
 	 *            the id to convert. May be null.
 	 * @return the hex string conversion of this id's content.
 	 */
-	public static final String toString(final LongObjectId i) {
+	public static final String toString(LongObjectId i) {
 		return i != null ? i.name() : ZEROID_STR;
 	}
 
@@ -174,7 +173,7 @@ public static boolean equals(final byte[] firstBuffer, final int fi,
 	 *            available within this byte array.
 	 * @return the converted object id.
 	 */
-	public static final LongObjectId fromRaw(final byte[] bs) {
+	public static final LongObjectId fromRaw(byte[] bs) {
 		return fromRaw(bs, 0);
 	}
 
@@ -188,7 +187,7 @@ public static final LongObjectId fromRaw(final byte[] bs) {
 	 *            position to read the first byte of data from.
 	 * @return the converted object id.
 	 */
-	public static final LongObjectId fromRaw(final byte[] bs, final int p) {
+	public static final LongObjectId fromRaw(byte[] bs, int p) {
 		final long a = NB.decodeInt64(bs, p);
 		final long b = NB.decodeInt64(bs, p + 8);
 		final long c = NB.decodeInt64(bs, p + 16);
@@ -204,7 +203,7 @@ public static final LongObjectId fromRaw(final byte[] bs, final int p) {
 	 *            available within this long array.
 	 * @return the converted object id.
 	 */
-	public static final LongObjectId fromRaw(final long[] is) {
+	public static final LongObjectId fromRaw(long[] is) {
 		return fromRaw(is, 0);
 	}
 
@@ -218,7 +217,7 @@ public static final LongObjectId fromRaw(final long[] is) {
 	 *            position to read the first long of data from.
 	 * @return the converted object id.
 	 */
-	public static final LongObjectId fromRaw(final long[] is, final int p) {
+	public static final LongObjectId fromRaw(long[] is, int p) {
 		return new LongObjectId(is[p], is[p + 1], is[p + 2], is[p + 3]);
 	}
 
@@ -232,7 +231,7 @@ public static final LongObjectId fromRaw(final long[] is, final int p) {
 	 *            position to read the first character from.
 	 * @return the converted object id.
 	 */
-	public static final LongObjectId fromString(final byte[] buf, final int offset) {
+	public static final LongObjectId fromString(byte[] buf, int offset) {
 		return fromHexString(buf, offset);
 	}
 
@@ -243,14 +242,14 @@ public static final LongObjectId fromString(final byte[] buf, final int offset)
 	 *            the string to read from. Must be 64 characters long.
 	 * @return the converted object id.
 	 */
-	public static LongObjectId fromString(final String str) {
+	public static LongObjectId fromString(String str) {
 		if (str.length() != Constants.LONG_OBJECT_ID_STRING_LENGTH)
 			throw new InvalidLongObjectIdException(str);
 		return fromHexString(org.eclipse.jgit.lib.Constants.encodeASCII(str),
 				0);
 	}
 
-	private static final LongObjectId fromHexString(final byte[] bs, int p) {
+	private static final LongObjectId fromHexString(byte[] bs, int p) {
 		try {
 			final long a = RawParseUtils.parseHexInt64(bs, p);
 			final long b = RawParseUtils.parseHexInt64(bs, p + 16);
@@ -281,13 +280,14 @@ private static final LongObjectId fromHexString(final byte[] bs, int p) {
 	 * @param src
 	 *            another already parsed LongObjectId to copy the value out of.
 	 */
-	protected LongObjectId(final AnyLongObjectId src) {
+	protected LongObjectId(AnyLongObjectId src) {
 		w1 = src.w1;
 		w2 = src.w2;
 		w3 = src.w3;
 		w4 = src.w4;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public LongObjectId toObjectId() {
 		return this;
diff --git a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/lib/MutableLongObjectId.java b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/lib/MutableLongObjectId.java
index 130e94e..3d62490 100644
--- a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/lib/MutableLongObjectId.java
+++ b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/lib/MutableLongObjectId.java
@@ -47,14 +47,13 @@
 
 import org.eclipse.jgit.lfs.errors.InvalidLongObjectIdException;
 import org.eclipse.jgit.lfs.internal.LfsText;
-import org.eclipse.jgit.lib.MutableObjectId;
 import org.eclipse.jgit.util.NB;
 import org.eclipse.jgit.util.RawParseUtils;
 
 /**
  * A mutable SHA-256 abstraction.
  *
- * Ported to SHA-256 from {@link MutableObjectId}
+ * Ported to SHA-256 from {@link org.eclipse.jgit.lib.MutableObjectId}
  *
  * @since 4.3
  */
@@ -81,15 +80,17 @@ public MutableLongObjectId() {
 	 *
 	 * @param index
 	 *            index of the byte to set in the raw form of the ObjectId. Must
-	 *            be in range [0, {@link Constants#LONG_OBJECT_ID_LENGTH}).
+	 *            be in range [0,
+	 *            {@link org.eclipse.jgit.lfs.lib.Constants#LONG_OBJECT_ID_LENGTH}).
 	 * @param value
 	 *            the value of the specified byte at {@code index}. Values are
 	 *            unsigned and thus are in the range [0,255] rather than the
 	 *            signed byte range of [-128, 127].
-	 * @throws ArrayIndexOutOfBoundsException
+	 * @throws java.lang.ArrayIndexOutOfBoundsException
 	 *             {@code index} is less than 0, equal to
-	 *             {@link Constants#LONG_OBJECT_ID_LENGTH}, or greater than
-	 *             {@link Constants#LONG_OBJECT_ID_LENGTH}.
+	 *             {@link org.eclipse.jgit.lfs.lib.Constants#LONG_OBJECT_ID_LENGTH},
+	 *             or greater than
+	 *             {@link org.eclipse.jgit.lfs.lib.Constants#LONG_OBJECT_ID_LENGTH}.
 	 */
 	public void setByte(int index, int value) {
 		switch (index >> 3) {
@@ -135,7 +136,10 @@ private static long set(long w, int index, long value) {
 		}
 	}
 
-	/** Make this id match {@link LongObjectId#zeroId()}. */
+	/**
+	 * Make this id match
+	 * {@link org.eclipse.jgit.lfs.lib.LongObjectId#zeroId()}.
+	 */
 	public void clear() {
 		w1 = 0;
 		w2 = 0;
@@ -144,7 +148,7 @@ public void clear() {
 	}
 
 	/**
-	 * Copy an LongObjectId into this mutable buffer.
+	 * Copy a LongObjectId into this mutable buffer.
 	 *
 	 * @param src
 	 *            the source id to copy from.
@@ -157,18 +161,18 @@ public void fromObjectId(AnyLongObjectId src) {
 	}
 
 	/**
-	 * Convert an LongObjectId from raw binary representation.
+	 * Convert a LongObjectId from raw binary representation.
 	 *
 	 * @param bs
 	 *            the raw byte buffer to read from. At least 32 bytes must be
 	 *            available within this byte array.
 	 */
-	public void fromRaw(final byte[] bs) {
+	public void fromRaw(byte[] bs) {
 		fromRaw(bs, 0);
 	}
 
 	/**
-	 * Convert an LongObjectId from raw binary representation.
+	 * Convert a LongObjectId from raw binary representation.
 	 *
 	 * @param bs
 	 *            the raw byte buffer to read from. At least 32 bytes after p
@@ -176,7 +180,7 @@ public void fromRaw(final byte[] bs) {
 	 * @param p
 	 *            position to read the first byte of data from.
 	 */
-	public void fromRaw(final byte[] bs, final int p) {
+	public void fromRaw(byte[] bs, int p) {
 		w1 = NB.decodeInt64(bs, p);
 		w2 = NB.decodeInt64(bs, p + 8);
 		w3 = NB.decodeInt64(bs, p + 16);
@@ -184,27 +188,26 @@ public void fromRaw(final byte[] bs, final int p) {
 	}
 
 	/**
-	 * Convert an LongObjectId from binary representation expressed in integers.
+	 * Convert a LongObjectId from binary representation expressed in integers.
 	 *
 	 * @param longs
 	 *            the raw long buffer to read from. At least 4 longs must be
 	 *            available within this longs array.
 	 */
-	public void fromRaw(final long[] longs) {
+	public void fromRaw(long[] longs) {
 		fromRaw(longs, 0);
 	}
 
 	/**
-	 * Convert an LongObjectId from binary representation expressed in longs.
+	 * Convert a LongObjectId from binary representation expressed in longs.
 	 *
 	 * @param longs
 	 *            the raw int buffer to read from. At least 4 longs after p must
 	 *            be available within this longs array.
 	 * @param p
 	 *            position to read the first integer of data from.
-	 *
 	 */
-	public void fromRaw(final long[] longs, final int p) {
+	public void fromRaw(long[] longs, int p) {
 		w1 = longs[p];
 		w2 = longs[p + 1];
 		w3 = longs[p + 2];
@@ -212,7 +215,7 @@ public void fromRaw(final long[] longs, final int p) {
 	}
 
 	/**
-	 * Convert an LongObjectId from hex characters (US-ASCII).
+	 * Convert a LongObjectId from hex characters (US-ASCII).
 	 *
 	 * @param buf
 	 *            the US-ASCII buffer to read from. At least 32 bytes after
@@ -220,24 +223,24 @@ public void fromRaw(final long[] longs, final int p) {
 	 * @param offset
 	 *            position to read the first character from.
 	 */
-	public void fromString(final byte[] buf, final int offset) {
+	public void fromString(byte[] buf, int offset) {
 		fromHexString(buf, offset);
 	}
 
 	/**
-	 * Convert an LongObjectId from hex characters.
+	 * Convert a LongObjectId from hex characters.
 	 *
 	 * @param str
 	 *            the string to read from. Must be 64 characters long.
 	 */
-	public void fromString(final String str) {
+	public void fromString(String str) {
 		if (str.length() != Constants.LONG_OBJECT_ID_STRING_LENGTH)
 			throw new IllegalArgumentException(
 					MessageFormat.format(LfsText.get().invalidLongId, str));
 		fromHexString(org.eclipse.jgit.lib.Constants.encodeASCII(str), 0);
 	}
 
-	private void fromHexString(final byte[] bs, int p) {
+	private void fromHexString(byte[] bs, int p) {
 		try {
 			w1 = RawParseUtils.parseHexInt64(bs, p);
 			w2 = RawParseUtils.parseHexInt64(bs, p + 16);
@@ -249,6 +252,7 @@ private void fromHexString(final byte[] bs, int p) {
 		}
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public LongObjectId toObjectId() {
 		return new LongObjectId(this);
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.feature/feature.properties b/org.eclipse.jgit.packaging/org.eclipse.jgit.feature/feature.properties
index 369e307..169ef7e 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.feature/feature.properties
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.feature/feature.properties
@@ -35,125 +35,143 @@
 # should be plain text version of license agreement pointed to be "licenseURL"
 license=\
 Eclipse Foundation Software User Agreement\n\
-April 9, 2014\n\
+\n\
+November 22, 2017\n\
 \n\
 Usage Of Content\n\
 \n\
-THE ECLIPSE FOUNDATION MAKES AVAILABLE SOFTWARE, DOCUMENTATION, INFORMATION AND/OR\n\
-OTHER MATERIALS FOR OPEN SOURCE PROJECTS (COLLECTIVELY "CONTENT").\n\
-USE OF THE CONTENT IS GOVERNED BY THE TERMS AND CONDITIONS OF THIS\n\
-AGREEMENT AND/OR THE TERMS AND CONDITIONS OF LICENSE AGREEMENTS OR\n\
-NOTICES INDICATED OR REFERENCED BELOW.  BY USING THE CONTENT, YOU\n\
-AGREE THAT YOUR USE OF THE CONTENT IS GOVERNED BY THIS AGREEMENT\n\
-AND/OR THE TERMS AND CONDITIONS OF ANY APPLICABLE LICENSE AGREEMENTS\n\
-OR NOTICES INDICATED OR REFERENCED BELOW.  IF YOU DO NOT AGREE TO THE\n\
-TERMS AND CONDITIONS OF THIS AGREEMENT AND THE TERMS AND CONDITIONS\n\
-OF ANY APPLICABLE LICENSE AGREEMENTS OR NOTICES INDICATED OR REFERENCED\n\
-BELOW, THEN YOU MAY NOT USE THE CONTENT.\n\
+THE ECLIPSE FOUNDATION MAKES AVAILABLE SOFTWARE, DOCUMENTATION, INFORMATION\n\
+AND/OR OTHER MATERIALS FOR OPEN SOURCE PROJECTS (COLLECTIVELY "CONTENT"). USE OF\n\
+THE CONTENT IS GOVERNED BY THE TERMS AND CONDITIONS OF THIS AGREEMENT AND/OR THE\n\
+TERMS AND CONDITIONS OF LICENSE AGREEMENTS OR NOTICES INDICATED OR REFERENCED\n\
+BELOW. BY USING THE CONTENT, YOU AGREE THAT YOUR USE OF THE CONTENT IS GOVERNED\n\
+BY THIS AGREEMENT AND/OR THE TERMS AND CONDITIONS OF ANY APPLICABLE LICENSE\n\
+AGREEMENTS OR NOTICES INDICATED OR REFERENCED BELOW. IF YOU DO NOT AGREE TO THE\n\
+TERMS AND CONDITIONS OF THIS AGREEMENT AND THE TERMS AND CONDITIONS OF ANY\n\
+APPLICABLE LICENSE AGREEMENTS OR NOTICES INDICATED OR REFERENCED BELOW, THEN YOU\n\
+MAY NOT USE THE CONTENT.\n\
 \n\
 Applicable Licenses\n\
 \n\
-Unless otherwise indicated, all Content made available by the\n\
-Eclipse Foundation is provided to you under the terms and conditions of\n\
-the Eclipse Public License Version 1.0 ("EPL"). A copy of the EPL is\n\
-provided with this Content and is also available at http://www.eclipse.org/legal/epl-v10.html.\n\
-For purposes of the EPL, "Program" will mean the Content.\n\
+Unless otherwise indicated, all Content made available by the Eclipse Foundation\n\
+is provided to you under the terms and conditions of the Eclipse Public License\n\
+Version 2.0 ("EPL"). A copy of the EPL is provided with this Content and is also\n\
+available at http://www.eclipse.org/legal/epl-2.0. For purposes of the EPL,\n\
+"Program" will mean the Content.\n\
 \n\
-Content includes, but is not limited to, source code, object code,\n\
-documentation and other files maintained in the Eclipse Foundation source code\n\
-repository ("Repository") in software modules ("Modules") and made available\n\
-as downloadable archives ("Downloads").\n\
+Content includes, but is not limited to, source code, object code, documentation\n\
+and other files maintained in the Eclipse Foundation source code repository\n\
+("Repository") in software modules ("Modules") and made available as\n\
+downloadable archives ("Downloads").\n\
 \n\
-       - Content may be structured and packaged into modules to facilitate delivering,\n\
-         extending, and upgrading the Content. Typical modules may include plug-ins ("Plug-ins"),\n\
-         plug-in fragments ("Fragments"), and features ("Features").\n\
-       - Each Plug-in or Fragment may be packaged as a sub-directory or JAR (Java(TM) ARchive)\n\
-         in a directory named "plugins".\n\
-       - A Feature is a bundle of one or more Plug-ins and/or Fragments and associated material.\n\
-         Each Feature may be packaged as a sub-directory in a directory named "features".\n\
-         Within a Feature, files named "feature.xml" may contain a list of the names and version\n\
-         numbers of the Plug-ins and/or Fragments associated with that Feature.\n\
-       - Features may also include other Features ("Included Features"). Within a Feature, files\n\
-         named "feature.xml" may contain a list of the names and version numbers of Included Features.\n\
+-   Content may be structured and packaged into modules to facilitate\n\
+    delivering, extending, and upgrading the Content. Typical modules may\n\
+    include plug-ins ("Plug-ins"), plug-in fragments ("Fragments"), and\n\
+    features ("Features").\n\
+-   Each Plug-in or Fragment may be packaged as a sub-directory or JAR\n\
+    (Java™ ARchive) in a directory named "plugins".\n\
+-   A Feature is a bundle of one or more Plug-ins and/or Fragments and\n\
+    associated material. Each Feature may be packaged as a sub-directory in a\n\
+    directory named "features". Within a Feature, files named "feature.xml" may\n\
+    contain a list of the names and version numbers of the Plug-ins and/or\n\
+    Fragments associated with that Feature.\n\
+-   Features may also include other Features ("Included Features"). Within a\n\
+    Feature, files named "feature.xml" may contain a list of the names and\n\
+    version numbers of Included Features.\n\
 \n\
-The terms and conditions governing Plug-ins and Fragments should be\n\
-contained in files named "about.html" ("Abouts"). The terms and\n\
-conditions governing Features and Included Features should be contained\n\
-in files named "license.html" ("Feature Licenses"). Abouts and Feature\n\
-Licenses may be located in any directory of a Download or Module\n\
-including, but not limited to the following locations:\n\
+The terms and conditions governing Plug-ins and Fragments should be contained in\n\
+files named "about.html" ("Abouts"). The terms and conditions governing Features\n\
+and Included Features should be contained in files named "license.html"\n\
+("Feature Licenses"). Abouts and Feature Licenses may be located in any\n\
+directory of a Download or Module including, but not limited to the following\n\
+locations:\n\
 \n\
-       - The top-level (root) directory\n\
-       - Plug-in and Fragment directories\n\
-       - Inside Plug-ins and Fragments packaged as JARs\n\
-       - Sub-directories of the directory named "src" of certain Plug-ins\n\
-       - Feature directories\n\
+-   The top-level (root) directory\n\
+-   Plug-in and Fragment directories\n\
+-   Inside Plug-ins and Fragments packaged as JARs\n\
+-   Sub-directories of the directory named "src" of certain Plug-ins\n\
+-   Feature directories\n\
 \n\
-Note: if a Feature made available by the Eclipse Foundation is installed using the\n\
-Provisioning Technology (as defined below), you must agree to a license ("Feature \n\
-Update License") during the installation process. If the Feature contains\n\
-Included Features, the Feature Update License should either provide you\n\
-with the terms and conditions governing the Included Features or inform\n\
-you where you can locate them. Feature Update Licenses may be found in\n\
-the "license" property of files named "feature.properties" found within a Feature.\n\
-Such Abouts, Feature Licenses, and Feature Update Licenses contain the\n\
-terms and conditions (or references to such terms and conditions) that\n\
-govern your use of the associated Content in that directory.\n\
+Note: if a Feature made available by the Eclipse Foundation is installed using\n\
+the Provisioning Technology (as defined below), you must agree to a license\n\
+("Feature Update License") during the installation process. If the Feature\n\
+contains Included Features, the Feature Update License should either provide you\n\
+with the terms and conditions governing the Included Features or inform you\n\
+where you can locate them. Feature Update Licenses may be found in the "license"\n\
+property of files named "feature.properties" found within a Feature. Such\n\
+Abouts, Feature Licenses, and Feature Update Licenses contain the terms and\n\
+conditions (or references to such terms and conditions) that govern your use of\n\
+the associated Content in that directory.\n\
 \n\
-THE ABOUTS, FEATURE LICENSES, AND FEATURE UPDATE LICENSES MAY REFER\n\
-TO THE EPL OR OTHER LICENSE AGREEMENTS, NOTICES OR TERMS AND CONDITIONS.\n\
-SOME OF THESE OTHER LICENSE AGREEMENTS MAY INCLUDE (BUT ARE NOT LIMITED TO):\n\
+THE ABOUTS, FEATURE LICENSES, AND FEATURE UPDATE LICENSES MAY REFER TO THE EPL\n\
+OR OTHER LICENSE AGREEMENTS, NOTICES OR TERMS AND CONDITIONS. SOME OF THESE\n\
+OTHER LICENSE AGREEMENTS MAY INCLUDE (BUT ARE NOT LIMITED TO):\n\
 \n\
-       - Eclipse Distribution License Version 1.0 (available at http://www.eclipse.org/licenses/edl-v1.0.html)\n\
-       - Common Public License Version 1.0 (available at http://www.eclipse.org/legal/cpl-v10.html)\n\
-       - Apache Software License 1.1 (available at http://www.apache.org/licenses/LICENSE)\n\
-       - Apache Software License 2.0 (available at http://www.apache.org/licenses/LICENSE-2.0)\n\
-       - Mozilla Public License Version 1.1 (available at http://www.mozilla.org/MPL/MPL-1.1.html)\n\
+-   Eclipse Public License Version 1.0 (available at\n\
+    http://www.eclipse.org/legal/epl-v10.html)\n\
+-   Eclipse Distribution License Version 1.0 (available at\n\
+    http://www.eclipse.org/licenses/edl-v1.0.html)\n\
+-   Common Public License Version 1.0 (available at\n\
+    http://www.eclipse.org/legal/cpl-v10.html)\n\
+-   Apache Software License 1.1 (available at\n\
+    http://www.apache.org/licenses/LICENSE)\n\
+-   Apache Software License 2.0 (available at\n\
+    http://www.apache.org/licenses/LICENSE-2.0)\n\
+-   Mozilla Public License Version 1.1 (available at\n\
+    http://www.mozilla.org/MPL/MPL-1.1.html)\n\
 \n\
-IT IS YOUR OBLIGATION TO READ AND ACCEPT ALL SUCH TERMS AND CONDITIONS PRIOR\n\
-TO USE OF THE CONTENT. If no About, Feature License, or Feature Update License\n\
-is provided, please contact the Eclipse Foundation to determine what terms and conditions\n\
-govern that particular Content.\n\
+IT IS YOUR OBLIGATION TO READ AND ACCEPT ALL SUCH TERMS AND CONDITIONS PRIOR TO\n\
+USE OF THE CONTENT. If no About, Feature License, or Feature Update License is\n\
+provided, please contact the Eclipse Foundation to determine what terms and\n\
+conditions govern that particular Content.\n\
 \n\
-\n\Use of Provisioning Technology\n\
+Use of Provisioning Technology\n\
 \n\
-The Eclipse Foundation makes available provisioning software, examples of which include,\n\
-but are not limited to, p2 and the Eclipse Update Manager ("Provisioning Technology") for\n\
-the purpose of allowing users to install software, documentation, information and/or\n\
-other materials (collectively "Installable Software"). This capability is provided with\n\
-the intent of allowing such users to install, extend and update Eclipse-based products.\n\
-Information about packaging Installable Software is available at\n\
+The Eclipse Foundation makes available provisioning software, examples of which\n\
+include, but are not limited to, p2 and the Eclipse Update Manager\n\
+("Provisioning Technology") for the purpose of allowing users to install\n\
+software, documentation, information and/or other materials (collectively\n\
+"Installable Software"). This capability is provided with the intent of allowing\n\
+such users to install, extend and update Eclipse-based products. Information\n\
+about packaging Installable Software is available at\n\
 http://eclipse.org/equinox/p2/repository_packaging.html ("Specification").\n\
 \n\
-You may use Provisioning Technology to allow other parties to install Installable Software.\n\
-You shall be responsible for enabling the applicable license agreements relating to the\n\
-Installable Software to be presented to, and accepted by, the users of the Provisioning Technology\n\
-in accordance with the Specification. By using Provisioning Technology in such a manner and\n\
-making it available in accordance with the Specification, you further acknowledge your\n\
-agreement to, and the acquisition of all necessary rights to permit the following:\n\
+You may use Provisioning Technology to allow other parties to install\n\
+Installable Software. You shall be responsible for enabling the applicable\n\
+license agreements relating to the Installable Software to be presented to, and\n\
+accepted by, the users of the Provisioning Technology in accordance with the\n\
+Specification. By using Provisioning Technology in such a manner and making it\n\
+available in accordance with the Specification, you further acknowledge your\n\
+agreement to, and the acquisition of all necessary rights to permit the\n\
+following:\n\
 \n\
-       1. A series of actions may occur ("Provisioning Process") in which a user may execute\n\
-          the Provisioning Technology on a machine ("Target Machine") with the intent of installing,\n\
-          extending or updating the functionality of an Eclipse-based product.\n\
-       2. During the Provisioning Process, the Provisioning Technology may cause third party\n\
-          Installable Software or a portion thereof to be accessed and copied to the Target Machine.\n\
-       3. Pursuant to the Specification, you will provide to the user the terms and conditions that\n\
-          govern the use of the Installable Software ("Installable Software Agreement") and such\n\
-          Installable Software Agreement shall be accessed from the Target Machine in accordance\n\
-          with the Specification. Such Installable Software Agreement must inform the user of the\n\
-          terms and conditions that govern the Installable Software and must solicit acceptance by\n\
-          the end user in the manner prescribed in such Installable Software Agreement. Upon such\n\
-          indication of agreement by the user, the provisioning Technology will complete installation\n\
-          of the Installable Software.\n\
+1.  A series of actions may occur ("Provisioning Process") in which a user may\n\
+    execute the Provisioning Technology on a machine ("Target Machine") with the\n\
+    intent of installing, extending or updating the functionality of an\n\
+    Eclipse-based product.\n\
+2.  During the Provisioning Process, the Provisioning Technology may cause third\n\
+    party Installable Software or a portion thereof to be accessed and copied to\n\
+    the Target Machine.\n\
+3.  Pursuant to the Specification, you will provide to the user the terms and\n\
+    conditions that govern the use of the Installable Software ("Installable\n\
+    Software Agreement") and such Installable Software Agreement shall be\n\
+    accessed from the Target Machine in accordance with the Specification. Such\n\
+    Installable Software Agreement must inform the user of the terms and\n\
+    conditions that govern the Installable Software and must solicit acceptance\n\
+    by the end user in the manner prescribed in such Installable\n\
+    Software Agreement. Upon such indication of agreement by the user, the\n\
+    provisioning Technology will complete installation of the\n\
+    Installable Software.\n\
 \n\
 Cryptography\n\
 \n\
-Content may contain encryption software. The country in which you are\n\
-currently may have restrictions on the import, possession, and use,\n\
-and/or re-export to another country, of encryption software. BEFORE\n\
-using any encryption software, please check the country's laws,\n\
-regulations and policies concerning the import, possession, or use, and\n\
-re-export of encryption software, to see if this is permitted.\n\
+Content may contain encryption software. The country in which you are currently\n\
+may have restrictions on the import, possession, and use, and/or re-export to\n\
+another country, of encryption software. BEFORE using any encryption software,\n\
+please check the country's laws, regulations and policies concerning the import,\n\
+possession, or use, and re-export of encryption software, to see if this is\n\
+permitted.\n\
 \n\
-Java and all Java-based trademarks are trademarks of Oracle Corporation in the United States, other countries, or both.\n
-########### end of license property ##########################################
\ No newline at end of file
+Java and all Java-based trademarks are trademarks of Oracle Corporation in the\n\
+United States, other countries, or both.\n
+########### end of license property ##########################################
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.feature/feature.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.feature/feature.xml
index 7585296..ab047c9 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.feature/feature.xml
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.feature/feature.xml
@@ -2,7 +2,7 @@
 <feature
       id="org.eclipse.jgit"
       label="%featureName"
-      version="4.9.3.qualifier"
+      version="5.0.0.qualifier"
       provider-name="%providerName">
 
    <description url="http://www.eclipse.org/jgit/">
@@ -79,4 +79,11 @@
          version="0.0.0"
          unpack="false"/>
 
+   <plugin
+         id="com.jcraft.jzlib"
+         download-size="0"
+         install-size="0"
+         version="0.0.0"
+         unpack="false"/>
+
 </feature>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.feature/license.html b/org.eclipse.jgit.packaging/org.eclipse.jgit.feature/license.html
index 95ad95e..008b801 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.feature/license.html
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.feature/license.html
@@ -1,106 +1,189 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-<!-- saved from url=(0044)http://www.eclipse.org/legal/epl/notice.html -->
-<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
-
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
 <title>Eclipse Foundation Software User Agreement</title>
 </head>
 
 <body lang="EN-US">
-<h2>Eclipse Foundation Software User Agreement</h2>
-<p>April 9, 2014</p>
+	<h2>Eclipse Foundation Software User Agreement</h2>
+	<p>November 22, 2017</p>
 
-<h3>Usage Of Content</h3>
+	<h3>Usage Of Content</h3>
 
-<p>THE ECLIPSE FOUNDATION MAKES AVAILABLE SOFTWARE, DOCUMENTATION, INFORMATION AND/OR OTHER MATERIALS FOR OPEN SOURCE PROJECTS
-   (COLLECTIVELY "CONTENT").  USE OF THE CONTENT IS GOVERNED BY THE TERMS AND CONDITIONS OF THIS AGREEMENT AND/OR THE TERMS AND
-   CONDITIONS OF LICENSE AGREEMENTS OR NOTICES INDICATED OR REFERENCED BELOW.  BY USING THE CONTENT, YOU AGREE THAT YOUR USE
-   OF THE CONTENT IS GOVERNED BY THIS AGREEMENT AND/OR THE TERMS AND CONDITIONS OF ANY APPLICABLE LICENSE AGREEMENTS OR
-   NOTICES INDICATED OR REFERENCED BELOW.  IF YOU DO NOT AGREE TO THE TERMS AND CONDITIONS OF THIS AGREEMENT AND THE TERMS AND
-   CONDITIONS OF ANY APPLICABLE LICENSE AGREEMENTS OR NOTICES INDICATED OR REFERENCED BELOW, THEN YOU MAY NOT USE THE CONTENT.</p>
+	<p>THE ECLIPSE FOUNDATION MAKES AVAILABLE SOFTWARE, DOCUMENTATION,
+		INFORMATION AND/OR OTHER MATERIALS FOR OPEN SOURCE PROJECTS
+		(COLLECTIVELY &quot;CONTENT&quot;). USE OF THE CONTENT IS GOVERNED BY
+		THE TERMS AND CONDITIONS OF THIS AGREEMENT AND/OR THE TERMS AND
+		CONDITIONS OF LICENSE AGREEMENTS OR NOTICES INDICATED OR REFERENCED
+		BELOW. BY USING THE CONTENT, YOU AGREE THAT YOUR USE OF THE CONTENT IS
+		GOVERNED BY THIS AGREEMENT AND/OR THE TERMS AND CONDITIONS OF ANY
+		APPLICABLE LICENSE AGREEMENTS OR NOTICES INDICATED OR REFERENCED
+		BELOW. IF YOU DO NOT AGREE TO THE TERMS AND CONDITIONS OF THIS
+		AGREEMENT AND THE TERMS AND CONDITIONS OF ANY APPLICABLE LICENSE
+		AGREEMENTS OR NOTICES INDICATED OR REFERENCED BELOW, THEN YOU MAY NOT
+		USE THE CONTENT.</p>
 
-<h3>Applicable Licenses</h3>
+	<h3>Applicable Licenses</h3>
 
-<p>Unless otherwise indicated, all Content made available by the Eclipse Foundation is provided to you under the terms and conditions of the Eclipse Public License Version 1.0
-   ("EPL").  A copy of the EPL is provided with this Content and is also available at <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a>.
-   For purposes of the EPL, "Program" will mean the Content.</p>
+	<p>
+		Unless otherwise indicated, all Content made available by the Eclipse
+		Foundation is provided to you under the terms and conditions of the
+		Eclipse Public License Version 2.0 (&quot;EPL&quot;). A copy of the
+		EPL is provided with this Content and is also available at <a
+			href="http://www.eclipse.org/legal/epl-2.0">http://www.eclipse.org/legal/epl-2.0</a>.
+		For purposes of the EPL, &quot;Program&quot; will mean the Content.
+	</p>
 
-<p>Content includes, but is not limited to, source code, object code, documentation and other files maintained in the Eclipse Foundation source code
-   repository ("Repository") in software modules ("Modules") and made available as downloadable archives ("Downloads").</p>
+	<p>Content includes, but is not limited to, source code, object
+		code, documentation and other files maintained in the Eclipse
+		Foundation source code repository (&quot;Repository&quot;) in software
+		modules (&quot;Modules&quot;) and made available as downloadable
+		archives (&quot;Downloads&quot;).</p>
 
-<ul>
-       <li>Content may be structured and packaged into modules to facilitate delivering, extending, and upgrading the Content.  Typical modules may include plug-ins ("Plug-ins"), plug-in fragments ("Fragments"), and features ("Features").</li>
-       <li>Each Plug-in or Fragment may be packaged as a sub-directory or JAR (Java™ ARchive) in a directory named "plugins".</li>
-       <li>A Feature is a bundle of one or more Plug-ins and/or Fragments and associated material.  Each Feature may be packaged as a sub-directory in a directory named "features".  Within a Feature, files named "feature.xml" may contain a list of the names and version numbers of the Plug-ins
-      and/or Fragments associated with that Feature.</li>
-       <li>Features may also include other Features ("Included Features"). Within a Feature, files named "feature.xml" may contain a list of the names and version numbers of Included Features.</li>
-</ul>
+	<ul>
+		<li>Content may be structured and packaged into modules to
+			facilitate delivering, extending, and upgrading the Content. Typical
+			modules may include plug-ins (&quot;Plug-ins&quot;), plug-in
+			fragments (&quot;Fragments&quot;), and features
+			(&quot;Features&quot;).</li>
+		<li>Each Plug-in or Fragment may be packaged as a sub-directory
+			or JAR (Java&trade; ARchive) in a directory named
+			&quot;plugins&quot;.</li>
+		<li>A Feature is a bundle of one or more Plug-ins and/or
+			Fragments and associated material. Each Feature may be packaged as a
+			sub-directory in a directory named &quot;features&quot;. Within a
+			Feature, files named &quot;feature.xml&quot; may contain a list of
+			the names and version numbers of the Plug-ins and/or Fragments
+			associated with that Feature.</li>
+		<li>Features may also include other Features (&quot;Included
+			Features&quot;). Within a Feature, files named
+			&quot;feature.xml&quot; may contain a list of the names and version
+			numbers of Included Features.</li>
+	</ul>
 
-<p>The terms and conditions governing Plug-ins and Fragments should be contained in files named "about.html" ("Abouts"). The terms and conditions governing Features and
-Included Features should be contained in files named "license.html" ("Feature Licenses").  Abouts and Feature Licenses may be located in any directory of a Download or Module
-including, but not limited to the following locations:</p>
+	<p>The terms and conditions governing Plug-ins and Fragments should
+		be contained in files named &quot;about.html&quot;
+		(&quot;Abouts&quot;). The terms and conditions governing Features and
+		Included Features should be contained in files named
+		&quot;license.html&quot; (&quot;Feature Licenses&quot;). Abouts and
+		Feature Licenses may be located in any directory of a Download or
+		Module including, but not limited to the following locations:</p>
 
-<ul>
-       <li>The top-level (root) directory</li>
-       <li>Plug-in and Fragment directories</li>
-       <li>Inside Plug-ins and Fragments packaged as JARs</li>
-       <li>Sub-directories of the directory named "src" of certain Plug-ins</li>
-       <li>Feature directories</li>
-</ul>
+	<ul>
+		<li>The top-level (root) directory</li>
+		<li>Plug-in and Fragment directories</li>
+		<li>Inside Plug-ins and Fragments packaged as JARs</li>
+		<li>Sub-directories of the directory named &quot;src&quot; of
+			certain Plug-ins</li>
+		<li>Feature directories</li>
+	</ul>
 
-<p>Note: if a Feature made available by the Eclipse Foundation is installed using the Provisioning Technology (as defined below), you must agree to a license ("Feature Update License") during the
-installation process.  If the Feature contains Included Features, the Feature Update License should either provide you with the terms and conditions governing the Included Features or
-inform you where you can locate them.  Feature Update Licenses may be found in the "license" property of files named "feature.properties" found within a Feature.
-Such Abouts, Feature Licenses, and Feature Update Licenses contain the terms and conditions (or references to such terms and conditions) that govern your use of the associated Content in
-that directory.</p>
+	<p>Note: if a Feature made available by the Eclipse Foundation is
+		installed using the Provisioning Technology (as defined below), you
+		must agree to a license (&quot;Feature Update License&quot;) during
+		the installation process. If the Feature contains Included Features,
+		the Feature Update License should either provide you with the terms
+		and conditions governing the Included Features or inform you where you
+		can locate them. Feature Update Licenses may be found in the
+		&quot;license&quot; property of files named
+		&quot;feature.properties&quot; found within a Feature. Such Abouts,
+		Feature Licenses, and Feature Update Licenses contain the terms and
+		conditions (or references to such terms and conditions) that govern
+		your use of the associated Content in that directory.</p>
 
-<p>THE ABOUTS, FEATURE LICENSES, AND FEATURE UPDATE LICENSES MAY REFER TO THE EPL OR OTHER LICENSE AGREEMENTS, NOTICES OR TERMS AND CONDITIONS.  SOME OF THESE
-OTHER LICENSE AGREEMENTS MAY INCLUDE (BUT ARE NOT LIMITED TO):</p>
+	<p>THE ABOUTS, FEATURE LICENSES, AND FEATURE UPDATE LICENSES MAY
+		REFER TO THE EPL OR OTHER LICENSE AGREEMENTS, NOTICES OR TERMS AND
+		CONDITIONS. SOME OF THESE OTHER LICENSE AGREEMENTS MAY INCLUDE (BUT
+		ARE NOT LIMITED TO):</p>
 
-<ul>
-       <li>Eclipse Distribution License Version 1.0 (available at <a href="http://www.eclipse.org/licenses/edl-v10.html">http://www.eclipse.org/licenses/edl-v1.0.html</a>)</li>
-       <li>Common Public License Version 1.0 (available at <a href="http://www.eclipse.org/legal/cpl-v10.html">http://www.eclipse.org/legal/cpl-v10.html</a>)</li>
-       <li>Apache Software License 1.1 (available at <a href="http://www.apache.org/licenses/LICENSE">http://www.apache.org/licenses/LICENSE</a>)</li>
-       <li>Apache Software License 2.0 (available at <a href="http://www.apache.org/licenses/LICENSE-2.0">http://www.apache.org/licenses/LICENSE-2.0</a>)</li>
-       <li>Mozilla Public License Version 1.1 (available at <a href="http://www.mozilla.org/MPL/MPL-1.1.html">http://www.mozilla.org/MPL/MPL-1.1.html</a>)</li>
-</ul>
+	<ul>
+		<li>Eclipse Public License Version 1.0 (available at <a
+			href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a>)
+		</li>
+		<li>Eclipse Distribution License Version 1.0 (available at <a
+			href="http://www.eclipse.org/licenses/edl-v10.html">http://www.eclipse.org/licenses/edl-v1.0.html</a>)
+		</li>
+		<li>Common Public License Version 1.0 (available at <a
+			href="http://www.eclipse.org/legal/cpl-v10.html">http://www.eclipse.org/legal/cpl-v10.html</a>)
+		</li>
+		<li>Apache Software License 1.1 (available at <a
+			href="http://www.apache.org/licenses/LICENSE">http://www.apache.org/licenses/LICENSE</a>)
+		</li>
+		<li>Apache Software License 2.0 (available at <a
+			href="http://www.apache.org/licenses/LICENSE-2.0">http://www.apache.org/licenses/LICENSE-2.0</a>)
+		</li>
+		<li>Mozilla Public License Version 1.1 (available at <a
+			href="http://www.mozilla.org/MPL/MPL-1.1.html">http://www.mozilla.org/MPL/MPL-1.1.html</a>)
+		</li>
+	</ul>
 
-<p>IT IS YOUR OBLIGATION TO READ AND ACCEPT ALL SUCH TERMS AND CONDITIONS PRIOR TO USE OF THE CONTENT.  If no About, Feature License, or Feature Update License is provided, please
-contact the Eclipse Foundation to determine what terms and conditions govern that particular Content.</p>
+	<p>IT IS YOUR OBLIGATION TO READ AND ACCEPT ALL SUCH TERMS AND
+		CONDITIONS PRIOR TO USE OF THE CONTENT. If no About, Feature License,
+		or Feature Update License is provided, please contact the Eclipse
+		Foundation to determine what terms and conditions govern that
+		particular Content.</p>
 
 
-<h3>Use of Provisioning Technology</h3>
+	<h3>Use of Provisioning Technology</h3>
 
-<p>The Eclipse Foundation makes available provisioning software, examples of which include, but are not limited to, p2 and the Eclipse
-   Update Manager ("Provisioning Technology") for the purpose of allowing users to install software, documentation, information and/or
-   other materials (collectively "Installable Software"). This capability is provided with the intent of allowing such users to
-   install, extend and update Eclipse-based products. Information about packaging Installable Software is available at <a href="http://eclipse.org/equinox/p2/repository_packaging.html">http://eclipse.org/equinox/p2/repository_packaging.html</a>
-   ("Specification").</p>
+	<p>
+		The Eclipse Foundation makes available provisioning software, examples
+		of which include, but are not limited to, p2 and the Eclipse Update
+		Manager (&quot;Provisioning Technology&quot;) for the purpose of
+		allowing users to install software, documentation, information and/or
+		other materials (collectively &quot;Installable Software&quot;). This
+		capability is provided with the intent of allowing such users to
+		install, extend and update Eclipse-based products. Information about
+		packaging Installable Software is available at <a
+			href="http://eclipse.org/equinox/p2/repository_packaging.html">http://eclipse.org/equinox/p2/repository_packaging.html</a>
+		(&quot;Specification&quot;).
+	</p>
 
-<p>You may use Provisioning Technology to allow other parties to install Installable Software. You shall be responsible for enabling the
-   applicable license agreements relating to the Installable Software to be presented to, and accepted by, the users of the Provisioning Technology
-   in accordance with the Specification. By using Provisioning Technology in such a manner and making it available in accordance with the
-   Specification, you further acknowledge your agreement to, and the acquisition of all necessary rights to permit the following:</p>
+	<p>You may use Provisioning Technology to allow other parties to
+		install Installable Software. You shall be responsible for enabling
+		the applicable license agreements relating to the Installable Software
+		to be presented to, and accepted by, the users of the Provisioning
+		Technology in accordance with the Specification. By using Provisioning
+		Technology in such a manner and making it available in accordance with
+		the Specification, you further acknowledge your agreement to, and the
+		acquisition of all necessary rights to permit the following:</p>
 
-<ol>
-       <li>A series of actions may occur ("Provisioning Process") in which a user may execute the Provisioning Technology
-       on a machine ("Target Machine") with the intent of installing, extending or updating the functionality of an Eclipse-based
-       product.</li>
-       <li>During the Provisioning Process, the Provisioning Technology may cause third party Installable Software or a portion thereof to be
-       accessed and copied to the Target Machine.</li>
-       <li>Pursuant to the Specification, you will provide to the user the terms and conditions that govern the use of the Installable
-       Software ("Installable Software Agreement") and such Installable Software Agreement shall be accessed from the Target
-       Machine in accordance with the Specification. Such Installable Software Agreement must inform the user of the terms and conditions that govern
-       the Installable Software and must solicit acceptance by the end user in the manner prescribed in such Installable Software Agreement. Upon such
-       indication of agreement by the user, the provisioning Technology will complete installation of the Installable Software.</li>
-</ol>
+	<ol>
+		<li>A series of actions may occur (&quot;Provisioning
+			Process&quot;) in which a user may execute the Provisioning
+			Technology on a machine (&quot;Target Machine&quot;) with the intent
+			of installing, extending or updating the functionality of an
+			Eclipse-based product.</li>
+		<li>During the Provisioning Process, the Provisioning Technology
+			may cause third party Installable Software or a portion thereof to be
+			accessed and copied to the Target Machine.</li>
+		<li>Pursuant to the Specification, you will provide to the user
+			the terms and conditions that govern the use of the Installable
+			Software (&quot;Installable Software Agreement&quot;) and such
+			Installable Software Agreement shall be accessed from the Target
+			Machine in accordance with the Specification. Such Installable
+			Software Agreement must inform the user of the terms and conditions
+			that govern the Installable Software and must solicit acceptance by
+			the end user in the manner prescribed in such Installable Software
+			Agreement. Upon such indication of agreement by the user, the
+			provisioning Technology will complete installation of the Installable
+			Software.</li>
+	</ol>
 
-<h3>Cryptography</h3>
+	<h3>Cryptography</h3>
 
-<p>Content may contain encryption software. The country in which you are currently may have restrictions on the import, possession, and use, and/or re-export to
-   another country, of encryption software. BEFORE using any encryption software, please check the country's laws, regulations and policies concerning the import,
-   possession, or use, and re-export of encryption software, to see if this is permitted.</p>
+	<p>Content may contain encryption software. The country in which
+		you are currently may have restrictions on the import, possession, and
+		use, and/or re-export to another country, of encryption software.
+		BEFORE using any encryption software, please check the country's laws,
+		regulations and policies concerning the import, possession, or use,
+		and re-export of encryption software, to see if this is permitted.</p>
 
-<p><small>Java and all Java-based trademarks are trademarks of Oracle Corporation in the United States, other countries, or both.</small></p>
-
-
-</body></html>
\ No newline at end of file
+	<p>
+		<small>Java and all Java-based trademarks are trademarks of
+			Oracle Corporation in the United States, other countries, or both.</small>
+	</p>
+</body>
+</html>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.feature/pom.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.feature/pom.xml
index 7997b59..d6f38ac 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.feature/pom.xml
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.feature/pom.xml
@@ -50,7 +50,7 @@
   <parent>
     <groupId>org.eclipse.jgit</groupId>
     <artifactId>jgit.tycho.parent</artifactId>
-    <version>4.9.3-SNAPSHOT</version>
+    <version>5.0.0-SNAPSHOT</version>
   </parent>
 
   <groupId>org.eclipse.jgit.feature</groupId>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.http.apache.feature/feature.properties b/org.eclipse.jgit.packaging/org.eclipse.jgit.http.apache.feature/feature.properties
index b9b5cce..480e9c3 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.http.apache.feature/feature.properties
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.http.apache.feature/feature.properties
@@ -35,125 +35,143 @@
 # should be plain text version of license agreement pointed to be "licenseURL"
 license=\
 Eclipse Foundation Software User Agreement\n\
-April 9, 2014\n\
+\n\
+November 22, 2017\n\
 \n\
 Usage Of Content\n\
 \n\
-THE ECLIPSE FOUNDATION MAKES AVAILABLE SOFTWARE, DOCUMENTATION, INFORMATION AND/OR\n\
-OTHER MATERIALS FOR OPEN SOURCE PROJECTS (COLLECTIVELY "CONTENT").\n\
-USE OF THE CONTENT IS GOVERNED BY THE TERMS AND CONDITIONS OF THIS\n\
-AGREEMENT AND/OR THE TERMS AND CONDITIONS OF LICENSE AGREEMENTS OR\n\
-NOTICES INDICATED OR REFERENCED BELOW.  BY USING THE CONTENT, YOU\n\
-AGREE THAT YOUR USE OF THE CONTENT IS GOVERNED BY THIS AGREEMENT\n\
-AND/OR THE TERMS AND CONDITIONS OF ANY APPLICABLE LICENSE AGREEMENTS\n\
-OR NOTICES INDICATED OR REFERENCED BELOW.  IF YOU DO NOT AGREE TO THE\n\
-TERMS AND CONDITIONS OF THIS AGREEMENT AND THE TERMS AND CONDITIONS\n\
-OF ANY APPLICABLE LICENSE AGREEMENTS OR NOTICES INDICATED OR REFERENCED\n\
-BELOW, THEN YOU MAY NOT USE THE CONTENT.\n\
+THE ECLIPSE FOUNDATION MAKES AVAILABLE SOFTWARE, DOCUMENTATION, INFORMATION\n\
+AND/OR OTHER MATERIALS FOR OPEN SOURCE PROJECTS (COLLECTIVELY "CONTENT"). USE OF\n\
+THE CONTENT IS GOVERNED BY THE TERMS AND CONDITIONS OF THIS AGREEMENT AND/OR THE\n\
+TERMS AND CONDITIONS OF LICENSE AGREEMENTS OR NOTICES INDICATED OR REFERENCED\n\
+BELOW. BY USING THE CONTENT, YOU AGREE THAT YOUR USE OF THE CONTENT IS GOVERNED\n\
+BY THIS AGREEMENT AND/OR THE TERMS AND CONDITIONS OF ANY APPLICABLE LICENSE\n\
+AGREEMENTS OR NOTICES INDICATED OR REFERENCED BELOW. IF YOU DO NOT AGREE TO THE\n\
+TERMS AND CONDITIONS OF THIS AGREEMENT AND THE TERMS AND CONDITIONS OF ANY\n\
+APPLICABLE LICENSE AGREEMENTS OR NOTICES INDICATED OR REFERENCED BELOW, THEN YOU\n\
+MAY NOT USE THE CONTENT.\n\
 \n\
 Applicable Licenses\n\
 \n\
-Unless otherwise indicated, all Content made available by the\n\
-Eclipse Foundation is provided to you under the terms and conditions of\n\
-the Eclipse Public License Version 1.0 ("EPL"). A copy of the EPL is\n\
-provided with this Content and is also available at http://www.eclipse.org/legal/epl-v10.html.\n\
-For purposes of the EPL, "Program" will mean the Content.\n\
+Unless otherwise indicated, all Content made available by the Eclipse Foundation\n\
+is provided to you under the terms and conditions of the Eclipse Public License\n\
+Version 2.0 ("EPL"). A copy of the EPL is provided with this Content and is also\n\
+available at http://www.eclipse.org/legal/epl-2.0. For purposes of the EPL,\n\
+"Program" will mean the Content.\n\
 \n\
-Content includes, but is not limited to, source code, object code,\n\
-documentation and other files maintained in the Eclipse Foundation source code\n\
-repository ("Repository") in software modules ("Modules") and made available\n\
-as downloadable archives ("Downloads").\n\
+Content includes, but is not limited to, source code, object code, documentation\n\
+and other files maintained in the Eclipse Foundation source code repository\n\
+("Repository") in software modules ("Modules") and made available as\n\
+downloadable archives ("Downloads").\n\
 \n\
-       - Content may be structured and packaged into modules to facilitate delivering,\n\
-         extending, and upgrading the Content. Typical modules may include plug-ins ("Plug-ins"),\n\
-         plug-in fragments ("Fragments"), and features ("Features").\n\
-       - Each Plug-in or Fragment may be packaged as a sub-directory or JAR (Java(TM) ARchive)\n\
-         in a directory named "plugins".\n\
-       - A Feature is a bundle of one or more Plug-ins and/or Fragments and associated material.\n\
-         Each Feature may be packaged as a sub-directory in a directory named "features".\n\
-         Within a Feature, files named "feature.xml" may contain a list of the names and version\n\
-         numbers of the Plug-ins and/or Fragments associated with that Feature.\n\
-       - Features may also include other Features ("Included Features"). Within a Feature, files\n\
-         named "feature.xml" may contain a list of the names and version numbers of Included Features.\n\
+-   Content may be structured and packaged into modules to facilitate\n\
+    delivering, extending, and upgrading the Content. Typical modules may\n\
+    include plug-ins ("Plug-ins"), plug-in fragments ("Fragments"), and\n\
+    features ("Features").\n\
+-   Each Plug-in or Fragment may be packaged as a sub-directory or JAR\n\
+    (Java™ ARchive) in a directory named "plugins".\n\
+-   A Feature is a bundle of one or more Plug-ins and/or Fragments and\n\
+    associated material. Each Feature may be packaged as a sub-directory in a\n\
+    directory named "features". Within a Feature, files named "feature.xml" may\n\
+    contain a list of the names and version numbers of the Plug-ins and/or\n\
+    Fragments associated with that Feature.\n\
+-   Features may also include other Features ("Included Features"). Within a\n\
+    Feature, files named "feature.xml" may contain a list of the names and\n\
+    version numbers of Included Features.\n\
 \n\
-The terms and conditions governing Plug-ins and Fragments should be\n\
-contained in files named "about.html" ("Abouts"). The terms and\n\
-conditions governing Features and Included Features should be contained\n\
-in files named "license.html" ("Feature Licenses"). Abouts and Feature\n\
-Licenses may be located in any directory of a Download or Module\n\
-including, but not limited to the following locations:\n\
+The terms and conditions governing Plug-ins and Fragments should be contained in\n\
+files named "about.html" ("Abouts"). The terms and conditions governing Features\n\
+and Included Features should be contained in files named "license.html"\n\
+("Feature Licenses"). Abouts and Feature Licenses may be located in any\n\
+directory of a Download or Module including, but not limited to the following\n\
+locations:\n\
 \n\
-       - The top-level (root) directory\n\
-       - Plug-in and Fragment directories\n\
-       - Inside Plug-ins and Fragments packaged as JARs\n\
-       - Sub-directories of the directory named "src" of certain Plug-ins\n\
-       - Feature directories\n\
+-   The top-level (root) directory\n\
+-   Plug-in and Fragment directories\n\
+-   Inside Plug-ins and Fragments packaged as JARs\n\
+-   Sub-directories of the directory named "src" of certain Plug-ins\n\
+-   Feature directories\n\
 \n\
-Note: if a Feature made available by the Eclipse Foundation is installed using the\n\
-Provisioning Technology (as defined below), you must agree to a license ("Feature \n\
-Update License") during the installation process. If the Feature contains\n\
-Included Features, the Feature Update License should either provide you\n\
-with the terms and conditions governing the Included Features or inform\n\
-you where you can locate them. Feature Update Licenses may be found in\n\
-the "license" property of files named "feature.properties" found within a Feature.\n\
-Such Abouts, Feature Licenses, and Feature Update Licenses contain the\n\
-terms and conditions (or references to such terms and conditions) that\n\
-govern your use of the associated Content in that directory.\n\
+Note: if a Feature made available by the Eclipse Foundation is installed using\n\
+the Provisioning Technology (as defined below), you must agree to a license\n\
+("Feature Update License") during the installation process. If the Feature\n\
+contains Included Features, the Feature Update License should either provide you\n\
+with the terms and conditions governing the Included Features or inform you\n\
+where you can locate them. Feature Update Licenses may be found in the "license"\n\
+property of files named "feature.properties" found within a Feature. Such\n\
+Abouts, Feature Licenses, and Feature Update Licenses contain the terms and\n\
+conditions (or references to such terms and conditions) that govern your use of\n\
+the associated Content in that directory.\n\
 \n\
-THE ABOUTS, FEATURE LICENSES, AND FEATURE UPDATE LICENSES MAY REFER\n\
-TO THE EPL OR OTHER LICENSE AGREEMENTS, NOTICES OR TERMS AND CONDITIONS.\n\
-SOME OF THESE OTHER LICENSE AGREEMENTS MAY INCLUDE (BUT ARE NOT LIMITED TO):\n\
+THE ABOUTS, FEATURE LICENSES, AND FEATURE UPDATE LICENSES MAY REFER TO THE EPL\n\
+OR OTHER LICENSE AGREEMENTS, NOTICES OR TERMS AND CONDITIONS. SOME OF THESE\n\
+OTHER LICENSE AGREEMENTS MAY INCLUDE (BUT ARE NOT LIMITED TO):\n\
 \n\
-       - Eclipse Distribution License Version 1.0 (available at http://www.eclipse.org/licenses/edl-v1.0.html)\n\
-       - Common Public License Version 1.0 (available at http://www.eclipse.org/legal/cpl-v10.html)\n\
-       - Apache Software License 1.1 (available at http://www.apache.org/licenses/LICENSE)\n\
-       - Apache Software License 2.0 (available at http://www.apache.org/licenses/LICENSE-2.0)\n\
-       - Mozilla Public License Version 1.1 (available at http://www.mozilla.org/MPL/MPL-1.1.html)\n\
+-   Eclipse Public License Version 1.0 (available at\n\
+    http://www.eclipse.org/legal/epl-v10.html)\n\
+-   Eclipse Distribution License Version 1.0 (available at\n\
+    http://www.eclipse.org/licenses/edl-v1.0.html)\n\
+-   Common Public License Version 1.0 (available at\n\
+    http://www.eclipse.org/legal/cpl-v10.html)\n\
+-   Apache Software License 1.1 (available at\n\
+    http://www.apache.org/licenses/LICENSE)\n\
+-   Apache Software License 2.0 (available at\n\
+    http://www.apache.org/licenses/LICENSE-2.0)\n\
+-   Mozilla Public License Version 1.1 (available at\n\
+    http://www.mozilla.org/MPL/MPL-1.1.html)\n\
 \n\
-IT IS YOUR OBLIGATION TO READ AND ACCEPT ALL SUCH TERMS AND CONDITIONS PRIOR\n\
-TO USE OF THE CONTENT. If no About, Feature License, or Feature Update License\n\
-is provided, please contact the Eclipse Foundation to determine what terms and conditions\n\
-govern that particular Content.\n\
+IT IS YOUR OBLIGATION TO READ AND ACCEPT ALL SUCH TERMS AND CONDITIONS PRIOR TO\n\
+USE OF THE CONTENT. If no About, Feature License, or Feature Update License is\n\
+provided, please contact the Eclipse Foundation to determine what terms and\n\
+conditions govern that particular Content.\n\
 \n\
-\n\Use of Provisioning Technology\n\
+Use of Provisioning Technology\n\
 \n\
-The Eclipse Foundation makes available provisioning software, examples of which include,\n\
-but are not limited to, p2 and the Eclipse Update Manager ("Provisioning Technology") for\n\
-the purpose of allowing users to install software, documentation, information and/or\n\
-other materials (collectively "Installable Software"). This capability is provided with\n\
-the intent of allowing such users to install, extend and update Eclipse-based products.\n\
-Information about packaging Installable Software is available at\n\
+The Eclipse Foundation makes available provisioning software, examples of which\n\
+include, but are not limited to, p2 and the Eclipse Update Manager\n\
+("Provisioning Technology") for the purpose of allowing users to install\n\
+software, documentation, information and/or other materials (collectively\n\
+"Installable Software"). This capability is provided with the intent of allowing\n\
+such users to install, extend and update Eclipse-based products. Information\n\
+about packaging Installable Software is available at\n\
 http://eclipse.org/equinox/p2/repository_packaging.html ("Specification").\n\
 \n\
-You may use Provisioning Technology to allow other parties to install Installable Software.\n\
-You shall be responsible for enabling the applicable license agreements relating to the\n\
-Installable Software to be presented to, and accepted by, the users of the Provisioning Technology\n\
-in accordance with the Specification. By using Provisioning Technology in such a manner and\n\
-making it available in accordance with the Specification, you further acknowledge your\n\
-agreement to, and the acquisition of all necessary rights to permit the following:\n\
+You may use Provisioning Technology to allow other parties to install\n\
+Installable Software. You shall be responsible for enabling the applicable\n\
+license agreements relating to the Installable Software to be presented to, and\n\
+accepted by, the users of the Provisioning Technology in accordance with the\n\
+Specification. By using Provisioning Technology in such a manner and making it\n\
+available in accordance with the Specification, you further acknowledge your\n\
+agreement to, and the acquisition of all necessary rights to permit the\n\
+following:\n\
 \n\
-       1. A series of actions may occur ("Provisioning Process") in which a user may execute\n\
-          the Provisioning Technology on a machine ("Target Machine") with the intent of installing,\n\
-          extending or updating the functionality of an Eclipse-based product.\n\
-       2. During the Provisioning Process, the Provisioning Technology may cause third party\n\
-          Installable Software or a portion thereof to be accessed and copied to the Target Machine.\n\
-       3. Pursuant to the Specification, you will provide to the user the terms and conditions that\n\
-          govern the use of the Installable Software ("Installable Software Agreement") and such\n\
-          Installable Software Agreement shall be accessed from the Target Machine in accordance\n\
-          with the Specification. Such Installable Software Agreement must inform the user of the\n\
-          terms and conditions that govern the Installable Software and must solicit acceptance by\n\
-          the end user in the manner prescribed in such Installable Software Agreement. Upon such\n\
-          indication of agreement by the user, the provisioning Technology will complete installation\n\
-          of the Installable Software.\n\
+1.  A series of actions may occur ("Provisioning Process") in which a user may\n\
+    execute the Provisioning Technology on a machine ("Target Machine") with the\n\
+    intent of installing, extending or updating the functionality of an\n\
+    Eclipse-based product.\n\
+2.  During the Provisioning Process, the Provisioning Technology may cause third\n\
+    party Installable Software or a portion thereof to be accessed and copied to\n\
+    the Target Machine.\n\
+3.  Pursuant to the Specification, you will provide to the user the terms and\n\
+    conditions that govern the use of the Installable Software ("Installable\n\
+    Software Agreement") and such Installable Software Agreement shall be\n\
+    accessed from the Target Machine in accordance with the Specification. Such\n\
+    Installable Software Agreement must inform the user of the terms and\n\
+    conditions that govern the Installable Software and must solicit acceptance\n\
+    by the end user in the manner prescribed in such Installable\n\
+    Software Agreement. Upon such indication of agreement by the user, the\n\
+    provisioning Technology will complete installation of the\n\
+    Installable Software.\n\
 \n\
 Cryptography\n\
 \n\
-Content may contain encryption software. The country in which you are\n\
-currently may have restrictions on the import, possession, and use,\n\
-and/or re-export to another country, of encryption software. BEFORE\n\
-using any encryption software, please check the country's laws,\n\
-regulations and policies concerning the import, possession, or use, and\n\
-re-export of encryption software, to see if this is permitted.\n\
+Content may contain encryption software. The country in which you are currently\n\
+may have restrictions on the import, possession, and use, and/or re-export to\n\
+another country, of encryption software. BEFORE using any encryption software,\n\
+please check the country's laws, regulations and policies concerning the import,\n\
+possession, or use, and re-export of encryption software, to see if this is\n\
+permitted.\n\
 \n\
-Java and all Java-based trademarks are trademarks of Oracle Corporation in the United States, other countries, or both.\n
-########### end of license property ##########################################
\ No newline at end of file
+Java and all Java-based trademarks are trademarks of Oracle Corporation in the\n\
+United States, other countries, or both.\n
+########### end of license property ##########################################
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.http.apache.feature/feature.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.http.apache.feature/feature.xml
index 322bd4c..6c046b4 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.http.apache.feature/feature.xml
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.http.apache.feature/feature.xml
@@ -2,7 +2,7 @@
 <feature
       id="org.eclipse.jgit.http.apache"
       label="%featureName"
-      version="4.9.3.qualifier"
+      version="5.0.0.qualifier"
       provider-name="%providerName">
 
    <description url="http://www.eclipse.org/jgit/">
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.http.apache.feature/license.html b/org.eclipse.jgit.packaging/org.eclipse.jgit.http.apache.feature/license.html
index 95ad95e..008b801 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.http.apache.feature/license.html
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.http.apache.feature/license.html
@@ -1,106 +1,189 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-<!-- saved from url=(0044)http://www.eclipse.org/legal/epl/notice.html -->
-<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
-
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
 <title>Eclipse Foundation Software User Agreement</title>
 </head>
 
 <body lang="EN-US">
-<h2>Eclipse Foundation Software User Agreement</h2>
-<p>April 9, 2014</p>
+	<h2>Eclipse Foundation Software User Agreement</h2>
+	<p>November 22, 2017</p>
 
-<h3>Usage Of Content</h3>
+	<h3>Usage Of Content</h3>
 
-<p>THE ECLIPSE FOUNDATION MAKES AVAILABLE SOFTWARE, DOCUMENTATION, INFORMATION AND/OR OTHER MATERIALS FOR OPEN SOURCE PROJECTS
-   (COLLECTIVELY "CONTENT").  USE OF THE CONTENT IS GOVERNED BY THE TERMS AND CONDITIONS OF THIS AGREEMENT AND/OR THE TERMS AND
-   CONDITIONS OF LICENSE AGREEMENTS OR NOTICES INDICATED OR REFERENCED BELOW.  BY USING THE CONTENT, YOU AGREE THAT YOUR USE
-   OF THE CONTENT IS GOVERNED BY THIS AGREEMENT AND/OR THE TERMS AND CONDITIONS OF ANY APPLICABLE LICENSE AGREEMENTS OR
-   NOTICES INDICATED OR REFERENCED BELOW.  IF YOU DO NOT AGREE TO THE TERMS AND CONDITIONS OF THIS AGREEMENT AND THE TERMS AND
-   CONDITIONS OF ANY APPLICABLE LICENSE AGREEMENTS OR NOTICES INDICATED OR REFERENCED BELOW, THEN YOU MAY NOT USE THE CONTENT.</p>
+	<p>THE ECLIPSE FOUNDATION MAKES AVAILABLE SOFTWARE, DOCUMENTATION,
+		INFORMATION AND/OR OTHER MATERIALS FOR OPEN SOURCE PROJECTS
+		(COLLECTIVELY &quot;CONTENT&quot;). USE OF THE CONTENT IS GOVERNED BY
+		THE TERMS AND CONDITIONS OF THIS AGREEMENT AND/OR THE TERMS AND
+		CONDITIONS OF LICENSE AGREEMENTS OR NOTICES INDICATED OR REFERENCED
+		BELOW. BY USING THE CONTENT, YOU AGREE THAT YOUR USE OF THE CONTENT IS
+		GOVERNED BY THIS AGREEMENT AND/OR THE TERMS AND CONDITIONS OF ANY
+		APPLICABLE LICENSE AGREEMENTS OR NOTICES INDICATED OR REFERENCED
+		BELOW. IF YOU DO NOT AGREE TO THE TERMS AND CONDITIONS OF THIS
+		AGREEMENT AND THE TERMS AND CONDITIONS OF ANY APPLICABLE LICENSE
+		AGREEMENTS OR NOTICES INDICATED OR REFERENCED BELOW, THEN YOU MAY NOT
+		USE THE CONTENT.</p>
 
-<h3>Applicable Licenses</h3>
+	<h3>Applicable Licenses</h3>
 
-<p>Unless otherwise indicated, all Content made available by the Eclipse Foundation is provided to you under the terms and conditions of the Eclipse Public License Version 1.0
-   ("EPL").  A copy of the EPL is provided with this Content and is also available at <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a>.
-   For purposes of the EPL, "Program" will mean the Content.</p>
+	<p>
+		Unless otherwise indicated, all Content made available by the Eclipse
+		Foundation is provided to you under the terms and conditions of the
+		Eclipse Public License Version 2.0 (&quot;EPL&quot;). A copy of the
+		EPL is provided with this Content and is also available at <a
+			href="http://www.eclipse.org/legal/epl-2.0">http://www.eclipse.org/legal/epl-2.0</a>.
+		For purposes of the EPL, &quot;Program&quot; will mean the Content.
+	</p>
 
-<p>Content includes, but is not limited to, source code, object code, documentation and other files maintained in the Eclipse Foundation source code
-   repository ("Repository") in software modules ("Modules") and made available as downloadable archives ("Downloads").</p>
+	<p>Content includes, but is not limited to, source code, object
+		code, documentation and other files maintained in the Eclipse
+		Foundation source code repository (&quot;Repository&quot;) in software
+		modules (&quot;Modules&quot;) and made available as downloadable
+		archives (&quot;Downloads&quot;).</p>
 
-<ul>
-       <li>Content may be structured and packaged into modules to facilitate delivering, extending, and upgrading the Content.  Typical modules may include plug-ins ("Plug-ins"), plug-in fragments ("Fragments"), and features ("Features").</li>
-       <li>Each Plug-in or Fragment may be packaged as a sub-directory or JAR (Java™ ARchive) in a directory named "plugins".</li>
-       <li>A Feature is a bundle of one or more Plug-ins and/or Fragments and associated material.  Each Feature may be packaged as a sub-directory in a directory named "features".  Within a Feature, files named "feature.xml" may contain a list of the names and version numbers of the Plug-ins
-      and/or Fragments associated with that Feature.</li>
-       <li>Features may also include other Features ("Included Features"). Within a Feature, files named "feature.xml" may contain a list of the names and version numbers of Included Features.</li>
-</ul>
+	<ul>
+		<li>Content may be structured and packaged into modules to
+			facilitate delivering, extending, and upgrading the Content. Typical
+			modules may include plug-ins (&quot;Plug-ins&quot;), plug-in
+			fragments (&quot;Fragments&quot;), and features
+			(&quot;Features&quot;).</li>
+		<li>Each Plug-in or Fragment may be packaged as a sub-directory
+			or JAR (Java&trade; ARchive) in a directory named
+			&quot;plugins&quot;.</li>
+		<li>A Feature is a bundle of one or more Plug-ins and/or
+			Fragments and associated material. Each Feature may be packaged as a
+			sub-directory in a directory named &quot;features&quot;. Within a
+			Feature, files named &quot;feature.xml&quot; may contain a list of
+			the names and version numbers of the Plug-ins and/or Fragments
+			associated with that Feature.</li>
+		<li>Features may also include other Features (&quot;Included
+			Features&quot;). Within a Feature, files named
+			&quot;feature.xml&quot; may contain a list of the names and version
+			numbers of Included Features.</li>
+	</ul>
 
-<p>The terms and conditions governing Plug-ins and Fragments should be contained in files named "about.html" ("Abouts"). The terms and conditions governing Features and
-Included Features should be contained in files named "license.html" ("Feature Licenses").  Abouts and Feature Licenses may be located in any directory of a Download or Module
-including, but not limited to the following locations:</p>
+	<p>The terms and conditions governing Plug-ins and Fragments should
+		be contained in files named &quot;about.html&quot;
+		(&quot;Abouts&quot;). The terms and conditions governing Features and
+		Included Features should be contained in files named
+		&quot;license.html&quot; (&quot;Feature Licenses&quot;). Abouts and
+		Feature Licenses may be located in any directory of a Download or
+		Module including, but not limited to the following locations:</p>
 
-<ul>
-       <li>The top-level (root) directory</li>
-       <li>Plug-in and Fragment directories</li>
-       <li>Inside Plug-ins and Fragments packaged as JARs</li>
-       <li>Sub-directories of the directory named "src" of certain Plug-ins</li>
-       <li>Feature directories</li>
-</ul>
+	<ul>
+		<li>The top-level (root) directory</li>
+		<li>Plug-in and Fragment directories</li>
+		<li>Inside Plug-ins and Fragments packaged as JARs</li>
+		<li>Sub-directories of the directory named &quot;src&quot; of
+			certain Plug-ins</li>
+		<li>Feature directories</li>
+	</ul>
 
-<p>Note: if a Feature made available by the Eclipse Foundation is installed using the Provisioning Technology (as defined below), you must agree to a license ("Feature Update License") during the
-installation process.  If the Feature contains Included Features, the Feature Update License should either provide you with the terms and conditions governing the Included Features or
-inform you where you can locate them.  Feature Update Licenses may be found in the "license" property of files named "feature.properties" found within a Feature.
-Such Abouts, Feature Licenses, and Feature Update Licenses contain the terms and conditions (or references to such terms and conditions) that govern your use of the associated Content in
-that directory.</p>
+	<p>Note: if a Feature made available by the Eclipse Foundation is
+		installed using the Provisioning Technology (as defined below), you
+		must agree to a license (&quot;Feature Update License&quot;) during
+		the installation process. If the Feature contains Included Features,
+		the Feature Update License should either provide you with the terms
+		and conditions governing the Included Features or inform you where you
+		can locate them. Feature Update Licenses may be found in the
+		&quot;license&quot; property of files named
+		&quot;feature.properties&quot; found within a Feature. Such Abouts,
+		Feature Licenses, and Feature Update Licenses contain the terms and
+		conditions (or references to such terms and conditions) that govern
+		your use of the associated Content in that directory.</p>
 
-<p>THE ABOUTS, FEATURE LICENSES, AND FEATURE UPDATE LICENSES MAY REFER TO THE EPL OR OTHER LICENSE AGREEMENTS, NOTICES OR TERMS AND CONDITIONS.  SOME OF THESE
-OTHER LICENSE AGREEMENTS MAY INCLUDE (BUT ARE NOT LIMITED TO):</p>
+	<p>THE ABOUTS, FEATURE LICENSES, AND FEATURE UPDATE LICENSES MAY
+		REFER TO THE EPL OR OTHER LICENSE AGREEMENTS, NOTICES OR TERMS AND
+		CONDITIONS. SOME OF THESE OTHER LICENSE AGREEMENTS MAY INCLUDE (BUT
+		ARE NOT LIMITED TO):</p>
 
-<ul>
-       <li>Eclipse Distribution License Version 1.0 (available at <a href="http://www.eclipse.org/licenses/edl-v10.html">http://www.eclipse.org/licenses/edl-v1.0.html</a>)</li>
-       <li>Common Public License Version 1.0 (available at <a href="http://www.eclipse.org/legal/cpl-v10.html">http://www.eclipse.org/legal/cpl-v10.html</a>)</li>
-       <li>Apache Software License 1.1 (available at <a href="http://www.apache.org/licenses/LICENSE">http://www.apache.org/licenses/LICENSE</a>)</li>
-       <li>Apache Software License 2.0 (available at <a href="http://www.apache.org/licenses/LICENSE-2.0">http://www.apache.org/licenses/LICENSE-2.0</a>)</li>
-       <li>Mozilla Public License Version 1.1 (available at <a href="http://www.mozilla.org/MPL/MPL-1.1.html">http://www.mozilla.org/MPL/MPL-1.1.html</a>)</li>
-</ul>
+	<ul>
+		<li>Eclipse Public License Version 1.0 (available at <a
+			href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a>)
+		</li>
+		<li>Eclipse Distribution License Version 1.0 (available at <a
+			href="http://www.eclipse.org/licenses/edl-v10.html">http://www.eclipse.org/licenses/edl-v1.0.html</a>)
+		</li>
+		<li>Common Public License Version 1.0 (available at <a
+			href="http://www.eclipse.org/legal/cpl-v10.html">http://www.eclipse.org/legal/cpl-v10.html</a>)
+		</li>
+		<li>Apache Software License 1.1 (available at <a
+			href="http://www.apache.org/licenses/LICENSE">http://www.apache.org/licenses/LICENSE</a>)
+		</li>
+		<li>Apache Software License 2.0 (available at <a
+			href="http://www.apache.org/licenses/LICENSE-2.0">http://www.apache.org/licenses/LICENSE-2.0</a>)
+		</li>
+		<li>Mozilla Public License Version 1.1 (available at <a
+			href="http://www.mozilla.org/MPL/MPL-1.1.html">http://www.mozilla.org/MPL/MPL-1.1.html</a>)
+		</li>
+	</ul>
 
-<p>IT IS YOUR OBLIGATION TO READ AND ACCEPT ALL SUCH TERMS AND CONDITIONS PRIOR TO USE OF THE CONTENT.  If no About, Feature License, or Feature Update License is provided, please
-contact the Eclipse Foundation to determine what terms and conditions govern that particular Content.</p>
+	<p>IT IS YOUR OBLIGATION TO READ AND ACCEPT ALL SUCH TERMS AND
+		CONDITIONS PRIOR TO USE OF THE CONTENT. If no About, Feature License,
+		or Feature Update License is provided, please contact the Eclipse
+		Foundation to determine what terms and conditions govern that
+		particular Content.</p>
 
 
-<h3>Use of Provisioning Technology</h3>
+	<h3>Use of Provisioning Technology</h3>
 
-<p>The Eclipse Foundation makes available provisioning software, examples of which include, but are not limited to, p2 and the Eclipse
-   Update Manager ("Provisioning Technology") for the purpose of allowing users to install software, documentation, information and/or
-   other materials (collectively "Installable Software"). This capability is provided with the intent of allowing such users to
-   install, extend and update Eclipse-based products. Information about packaging Installable Software is available at <a href="http://eclipse.org/equinox/p2/repository_packaging.html">http://eclipse.org/equinox/p2/repository_packaging.html</a>
-   ("Specification").</p>
+	<p>
+		The Eclipse Foundation makes available provisioning software, examples
+		of which include, but are not limited to, p2 and the Eclipse Update
+		Manager (&quot;Provisioning Technology&quot;) for the purpose of
+		allowing users to install software, documentation, information and/or
+		other materials (collectively &quot;Installable Software&quot;). This
+		capability is provided with the intent of allowing such users to
+		install, extend and update Eclipse-based products. Information about
+		packaging Installable Software is available at <a
+			href="http://eclipse.org/equinox/p2/repository_packaging.html">http://eclipse.org/equinox/p2/repository_packaging.html</a>
+		(&quot;Specification&quot;).
+	</p>
 
-<p>You may use Provisioning Technology to allow other parties to install Installable Software. You shall be responsible for enabling the
-   applicable license agreements relating to the Installable Software to be presented to, and accepted by, the users of the Provisioning Technology
-   in accordance with the Specification. By using Provisioning Technology in such a manner and making it available in accordance with the
-   Specification, you further acknowledge your agreement to, and the acquisition of all necessary rights to permit the following:</p>
+	<p>You may use Provisioning Technology to allow other parties to
+		install Installable Software. You shall be responsible for enabling
+		the applicable license agreements relating to the Installable Software
+		to be presented to, and accepted by, the users of the Provisioning
+		Technology in accordance with the Specification. By using Provisioning
+		Technology in such a manner and making it available in accordance with
+		the Specification, you further acknowledge your agreement to, and the
+		acquisition of all necessary rights to permit the following:</p>
 
-<ol>
-       <li>A series of actions may occur ("Provisioning Process") in which a user may execute the Provisioning Technology
-       on a machine ("Target Machine") with the intent of installing, extending or updating the functionality of an Eclipse-based
-       product.</li>
-       <li>During the Provisioning Process, the Provisioning Technology may cause third party Installable Software or a portion thereof to be
-       accessed and copied to the Target Machine.</li>
-       <li>Pursuant to the Specification, you will provide to the user the terms and conditions that govern the use of the Installable
-       Software ("Installable Software Agreement") and such Installable Software Agreement shall be accessed from the Target
-       Machine in accordance with the Specification. Such Installable Software Agreement must inform the user of the terms and conditions that govern
-       the Installable Software and must solicit acceptance by the end user in the manner prescribed in such Installable Software Agreement. Upon such
-       indication of agreement by the user, the provisioning Technology will complete installation of the Installable Software.</li>
-</ol>
+	<ol>
+		<li>A series of actions may occur (&quot;Provisioning
+			Process&quot;) in which a user may execute the Provisioning
+			Technology on a machine (&quot;Target Machine&quot;) with the intent
+			of installing, extending or updating the functionality of an
+			Eclipse-based product.</li>
+		<li>During the Provisioning Process, the Provisioning Technology
+			may cause third party Installable Software or a portion thereof to be
+			accessed and copied to the Target Machine.</li>
+		<li>Pursuant to the Specification, you will provide to the user
+			the terms and conditions that govern the use of the Installable
+			Software (&quot;Installable Software Agreement&quot;) and such
+			Installable Software Agreement shall be accessed from the Target
+			Machine in accordance with the Specification. Such Installable
+			Software Agreement must inform the user of the terms and conditions
+			that govern the Installable Software and must solicit acceptance by
+			the end user in the manner prescribed in such Installable Software
+			Agreement. Upon such indication of agreement by the user, the
+			provisioning Technology will complete installation of the Installable
+			Software.</li>
+	</ol>
 
-<h3>Cryptography</h3>
+	<h3>Cryptography</h3>
 
-<p>Content may contain encryption software. The country in which you are currently may have restrictions on the import, possession, and use, and/or re-export to
-   another country, of encryption software. BEFORE using any encryption software, please check the country's laws, regulations and policies concerning the import,
-   possession, or use, and re-export of encryption software, to see if this is permitted.</p>
+	<p>Content may contain encryption software. The country in which
+		you are currently may have restrictions on the import, possession, and
+		use, and/or re-export to another country, of encryption software.
+		BEFORE using any encryption software, please check the country's laws,
+		regulations and policies concerning the import, possession, or use,
+		and re-export of encryption software, to see if this is permitted.</p>
 
-<p><small>Java and all Java-based trademarks are trademarks of Oracle Corporation in the United States, other countries, or both.</small></p>
-
-
-</body></html>
\ No newline at end of file
+	<p>
+		<small>Java and all Java-based trademarks are trademarks of
+			Oracle Corporation in the United States, other countries, or both.</small>
+	</p>
+</body>
+</html>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.http.apache.feature/pom.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.http.apache.feature/pom.xml
index 6099222..7dcc484 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.http.apache.feature/pom.xml
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.http.apache.feature/pom.xml
@@ -50,7 +50,7 @@
   <parent>
     <groupId>org.eclipse.jgit</groupId>
     <artifactId>jgit.tycho.parent</artifactId>
-    <version>4.9.3-SNAPSHOT</version>
+    <version>5.0.0-SNAPSHOT</version>
   </parent>
 
   <groupId>org.eclipse.jgit.feature</groupId>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.junit.feature/feature.properties b/org.eclipse.jgit.packaging/org.eclipse.jgit.junit.feature/feature.properties
index 4450bbb..291b29e 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.junit.feature/feature.properties
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.junit.feature/feature.properties
@@ -36,125 +36,143 @@
 # should be plain text version of license agreement pointed to be "licenseURL"
 license=\
 Eclipse Foundation Software User Agreement\n\
-April 9, 2014\n\
+\n\
+November 22, 2017\n\
 \n\
 Usage Of Content\n\
 \n\
-THE ECLIPSE FOUNDATION MAKES AVAILABLE SOFTWARE, DOCUMENTATION, INFORMATION AND/OR\n\
-OTHER MATERIALS FOR OPEN SOURCE PROJECTS (COLLECTIVELY "CONTENT").\n\
-USE OF THE CONTENT IS GOVERNED BY THE TERMS AND CONDITIONS OF THIS\n\
-AGREEMENT AND/OR THE TERMS AND CONDITIONS OF LICENSE AGREEMENTS OR\n\
-NOTICES INDICATED OR REFERENCED BELOW.  BY USING THE CONTENT, YOU\n\
-AGREE THAT YOUR USE OF THE CONTENT IS GOVERNED BY THIS AGREEMENT\n\
-AND/OR THE TERMS AND CONDITIONS OF ANY APPLICABLE LICENSE AGREEMENTS\n\
-OR NOTICES INDICATED OR REFERENCED BELOW.  IF YOU DO NOT AGREE TO THE\n\
-TERMS AND CONDITIONS OF THIS AGREEMENT AND THE TERMS AND CONDITIONS\n\
-OF ANY APPLICABLE LICENSE AGREEMENTS OR NOTICES INDICATED OR REFERENCED\n\
-BELOW, THEN YOU MAY NOT USE THE CONTENT.\n\
+THE ECLIPSE FOUNDATION MAKES AVAILABLE SOFTWARE, DOCUMENTATION, INFORMATION\n\
+AND/OR OTHER MATERIALS FOR OPEN SOURCE PROJECTS (COLLECTIVELY "CONTENT"). USE OF\n\
+THE CONTENT IS GOVERNED BY THE TERMS AND CONDITIONS OF THIS AGREEMENT AND/OR THE\n\
+TERMS AND CONDITIONS OF LICENSE AGREEMENTS OR NOTICES INDICATED OR REFERENCED\n\
+BELOW. BY USING THE CONTENT, YOU AGREE THAT YOUR USE OF THE CONTENT IS GOVERNED\n\
+BY THIS AGREEMENT AND/OR THE TERMS AND CONDITIONS OF ANY APPLICABLE LICENSE\n\
+AGREEMENTS OR NOTICES INDICATED OR REFERENCED BELOW. IF YOU DO NOT AGREE TO THE\n\
+TERMS AND CONDITIONS OF THIS AGREEMENT AND THE TERMS AND CONDITIONS OF ANY\n\
+APPLICABLE LICENSE AGREEMENTS OR NOTICES INDICATED OR REFERENCED BELOW, THEN YOU\n\
+MAY NOT USE THE CONTENT.\n\
 \n\
 Applicable Licenses\n\
 \n\
-Unless otherwise indicated, all Content made available by the\n\
-Eclipse Foundation is provided to you under the terms and conditions of\n\
-the Eclipse Public License Version 1.0 ("EPL"). A copy of the EPL is\n\
-provided with this Content and is also available at http://www.eclipse.org/legal/epl-v10.html.\n\
-For purposes of the EPL, "Program" will mean the Content.\n\
+Unless otherwise indicated, all Content made available by the Eclipse Foundation\n\
+is provided to you under the terms and conditions of the Eclipse Public License\n\
+Version 2.0 ("EPL"). A copy of the EPL is provided with this Content and is also\n\
+available at http://www.eclipse.org/legal/epl-2.0. For purposes of the EPL,\n\
+"Program" will mean the Content.\n\
 \n\
-Content includes, but is not limited to, source code, object code,\n\
-documentation and other files maintained in the Eclipse Foundation source code\n\
-repository ("Repository") in software modules ("Modules") and made available\n\
-as downloadable archives ("Downloads").\n\
+Content includes, but is not limited to, source code, object code, documentation\n\
+and other files maintained in the Eclipse Foundation source code repository\n\
+("Repository") in software modules ("Modules") and made available as\n\
+downloadable archives ("Downloads").\n\
 \n\
-       - Content may be structured and packaged into modules to facilitate delivering,\n\
-         extending, and upgrading the Content. Typical modules may include plug-ins ("Plug-ins"),\n\
-         plug-in fragments ("Fragments"), and features ("Features").\n\
-       - Each Plug-in or Fragment may be packaged as a sub-directory or JAR (Java(TM) ARchive)\n\
-         in a directory named "plugins".\n\
-       - A Feature is a bundle of one or more Plug-ins and/or Fragments and associated material.\n\
-         Each Feature may be packaged as a sub-directory in a directory named "features".\n\
-         Within a Feature, files named "feature.xml" may contain a list of the names and version\n\
-         numbers of the Plug-ins and/or Fragments associated with that Feature.\n\
-       - Features may also include other Features ("Included Features"). Within a Feature, files\n\
-         named "feature.xml" may contain a list of the names and version numbers of Included Features.\n\
+-   Content may be structured and packaged into modules to facilitate\n\
+    delivering, extending, and upgrading the Content. Typical modules may\n\
+    include plug-ins ("Plug-ins"), plug-in fragments ("Fragments"), and\n\
+    features ("Features").\n\
+-   Each Plug-in or Fragment may be packaged as a sub-directory or JAR\n\
+    (Java™ ARchive) in a directory named "plugins".\n\
+-   A Feature is a bundle of one or more Plug-ins and/or Fragments and\n\
+    associated material. Each Feature may be packaged as a sub-directory in a\n\
+    directory named "features". Within a Feature, files named "feature.xml" may\n\
+    contain a list of the names and version numbers of the Plug-ins and/or\n\
+    Fragments associated with that Feature.\n\
+-   Features may also include other Features ("Included Features"). Within a\n\
+    Feature, files named "feature.xml" may contain a list of the names and\n\
+    version numbers of Included Features.\n\
 \n\
-The terms and conditions governing Plug-ins and Fragments should be\n\
-contained in files named "about.html" ("Abouts"). The terms and\n\
-conditions governing Features and Included Features should be contained\n\
-in files named "license.html" ("Feature Licenses"). Abouts and Feature\n\
-Licenses may be located in any directory of a Download or Module\n\
-including, but not limited to the following locations:\n\
+The terms and conditions governing Plug-ins and Fragments should be contained in\n\
+files named "about.html" ("Abouts"). The terms and conditions governing Features\n\
+and Included Features should be contained in files named "license.html"\n\
+("Feature Licenses"). Abouts and Feature Licenses may be located in any\n\
+directory of a Download or Module including, but not limited to the following\n\
+locations:\n\
 \n\
-       - The top-level (root) directory\n\
-       - Plug-in and Fragment directories\n\
-       - Inside Plug-ins and Fragments packaged as JARs\n\
-       - Sub-directories of the directory named "src" of certain Plug-ins\n\
-       - Feature directories\n\
+-   The top-level (root) directory\n\
+-   Plug-in and Fragment directories\n\
+-   Inside Plug-ins and Fragments packaged as JARs\n\
+-   Sub-directories of the directory named "src" of certain Plug-ins\n\
+-   Feature directories\n\
 \n\
-Note: if a Feature made available by the Eclipse Foundation is installed using the\n\
-Provisioning Technology (as defined below), you must agree to a license ("Feature \n\
-Update License") during the installation process. If the Feature contains\n\
-Included Features, the Feature Update License should either provide you\n\
-with the terms and conditions governing the Included Features or inform\n\
-you where you can locate them. Feature Update Licenses may be found in\n\
-the "license" property of files named "feature.properties" found within a Feature.\n\
-Such Abouts, Feature Licenses, and Feature Update Licenses contain the\n\
-terms and conditions (or references to such terms and conditions) that\n\
-govern your use of the associated Content in that directory.\n\
+Note: if a Feature made available by the Eclipse Foundation is installed using\n\
+the Provisioning Technology (as defined below), you must agree to a license\n\
+("Feature Update License") during the installation process. If the Feature\n\
+contains Included Features, the Feature Update License should either provide you\n\
+with the terms and conditions governing the Included Features or inform you\n\
+where you can locate them. Feature Update Licenses may be found in the "license"\n\
+property of files named "feature.properties" found within a Feature. Such\n\
+Abouts, Feature Licenses, and Feature Update Licenses contain the terms and\n\
+conditions (or references to such terms and conditions) that govern your use of\n\
+the associated Content in that directory.\n\
 \n\
-THE ABOUTS, FEATURE LICENSES, AND FEATURE UPDATE LICENSES MAY REFER\n\
-TO THE EPL OR OTHER LICENSE AGREEMENTS, NOTICES OR TERMS AND CONDITIONS.\n\
-SOME OF THESE OTHER LICENSE AGREEMENTS MAY INCLUDE (BUT ARE NOT LIMITED TO):\n\
+THE ABOUTS, FEATURE LICENSES, AND FEATURE UPDATE LICENSES MAY REFER TO THE EPL\n\
+OR OTHER LICENSE AGREEMENTS, NOTICES OR TERMS AND CONDITIONS. SOME OF THESE\n\
+OTHER LICENSE AGREEMENTS MAY INCLUDE (BUT ARE NOT LIMITED TO):\n\
 \n\
-       - Eclipse Distribution License Version 1.0 (available at http://www.eclipse.org/licenses/edl-v1.0.html)\n\
-       - Common Public License Version 1.0 (available at http://www.eclipse.org/legal/cpl-v10.html)\n\
-       - Apache Software License 1.1 (available at http://www.apache.org/licenses/LICENSE)\n\
-       - Apache Software License 2.0 (available at http://www.apache.org/licenses/LICENSE-2.0)\n\
-       - Mozilla Public License Version 1.1 (available at http://www.mozilla.org/MPL/MPL-1.1.html)\n\
+-   Eclipse Public License Version 1.0 (available at\n\
+    http://www.eclipse.org/legal/epl-v10.html)\n\
+-   Eclipse Distribution License Version 1.0 (available at\n\
+    http://www.eclipse.org/licenses/edl-v1.0.html)\n\
+-   Common Public License Version 1.0 (available at\n\
+    http://www.eclipse.org/legal/cpl-v10.html)\n\
+-   Apache Software License 1.1 (available at\n\
+    http://www.apache.org/licenses/LICENSE)\n\
+-   Apache Software License 2.0 (available at\n\
+    http://www.apache.org/licenses/LICENSE-2.0)\n\
+-   Mozilla Public License Version 1.1 (available at\n\
+    http://www.mozilla.org/MPL/MPL-1.1.html)\n\
 \n\
-IT IS YOUR OBLIGATION TO READ AND ACCEPT ALL SUCH TERMS AND CONDITIONS PRIOR\n\
-TO USE OF THE CONTENT. If no About, Feature License, or Feature Update License\n\
-is provided, please contact the Eclipse Foundation to determine what terms and conditions\n\
-govern that particular Content.\n\
+IT IS YOUR OBLIGATION TO READ AND ACCEPT ALL SUCH TERMS AND CONDITIONS PRIOR TO\n\
+USE OF THE CONTENT. If no About, Feature License, or Feature Update License is\n\
+provided, please contact the Eclipse Foundation to determine what terms and\n\
+conditions govern that particular Content.\n\
 \n\
-\n\Use of Provisioning Technology\n\
+Use of Provisioning Technology\n\
 \n\
-The Eclipse Foundation makes available provisioning software, examples of which include,\n\
-but are not limited to, p2 and the Eclipse Update Manager ("Provisioning Technology") for\n\
-the purpose of allowing users to install software, documentation, information and/or\n\
-other materials (collectively "Installable Software"). This capability is provided with\n\
-the intent of allowing such users to install, extend and update Eclipse-based products.\n\
-Information about packaging Installable Software is available at\n\
+The Eclipse Foundation makes available provisioning software, examples of which\n\
+include, but are not limited to, p2 and the Eclipse Update Manager\n\
+("Provisioning Technology") for the purpose of allowing users to install\n\
+software, documentation, information and/or other materials (collectively\n\
+"Installable Software"). This capability is provided with the intent of allowing\n\
+such users to install, extend and update Eclipse-based products. Information\n\
+about packaging Installable Software is available at\n\
 http://eclipse.org/equinox/p2/repository_packaging.html ("Specification").\n\
 \n\
-You may use Provisioning Technology to allow other parties to install Installable Software.\n\
-You shall be responsible for enabling the applicable license agreements relating to the\n\
-Installable Software to be presented to, and accepted by, the users of the Provisioning Technology\n\
-in accordance with the Specification. By using Provisioning Technology in such a manner and\n\
-making it available in accordance with the Specification, you further acknowledge your\n\
-agreement to, and the acquisition of all necessary rights to permit the following:\n\
+You may use Provisioning Technology to allow other parties to install\n\
+Installable Software. You shall be responsible for enabling the applicable\n\
+license agreements relating to the Installable Software to be presented to, and\n\
+accepted by, the users of the Provisioning Technology in accordance with the\n\
+Specification. By using Provisioning Technology in such a manner and making it\n\
+available in accordance with the Specification, you further acknowledge your\n\
+agreement to, and the acquisition of all necessary rights to permit the\n\
+following:\n\
 \n\
-       1. A series of actions may occur ("Provisioning Process") in which a user may execute\n\
-          the Provisioning Technology on a machine ("Target Machine") with the intent of installing,\n\
-          extending or updating the functionality of an Eclipse-based product.\n\
-       2. During the Provisioning Process, the Provisioning Technology may cause third party\n\
-          Installable Software or a portion thereof to be accessed and copied to the Target Machine.\n\
-       3. Pursuant to the Specification, you will provide to the user the terms and conditions that\n\
-          govern the use of the Installable Software ("Installable Software Agreement") and such\n\
-          Installable Software Agreement shall be accessed from the Target Machine in accordance\n\
-          with the Specification. Such Installable Software Agreement must inform the user of the\n\
-          terms and conditions that govern the Installable Software and must solicit acceptance by\n\
-          the end user in the manner prescribed in such Installable Software Agreement. Upon such\n\
-          indication of agreement by the user, the provisioning Technology will complete installation\n\
-          of the Installable Software.\n\
+1.  A series of actions may occur ("Provisioning Process") in which a user may\n\
+    execute the Provisioning Technology on a machine ("Target Machine") with the\n\
+    intent of installing, extending or updating the functionality of an\n\
+    Eclipse-based product.\n\
+2.  During the Provisioning Process, the Provisioning Technology may cause third\n\
+    party Installable Software or a portion thereof to be accessed and copied to\n\
+    the Target Machine.\n\
+3.  Pursuant to the Specification, you will provide to the user the terms and\n\
+    conditions that govern the use of the Installable Software ("Installable\n\
+    Software Agreement") and such Installable Software Agreement shall be\n\
+    accessed from the Target Machine in accordance with the Specification. Such\n\
+    Installable Software Agreement must inform the user of the terms and\n\
+    conditions that govern the Installable Software and must solicit acceptance\n\
+    by the end user in the manner prescribed in such Installable\n\
+    Software Agreement. Upon such indication of agreement by the user, the\n\
+    provisioning Technology will complete installation of the\n\
+    Installable Software.\n\
 \n\
 Cryptography\n\
 \n\
-Content may contain encryption software. The country in which you are\n\
-currently may have restrictions on the import, possession, and use,\n\
-and/or re-export to another country, of encryption software. BEFORE\n\
-using any encryption software, please check the country's laws,\n\
-regulations and policies concerning the import, possession, or use, and\n\
-re-export of encryption software, to see if this is permitted.\n\
+Content may contain encryption software. The country in which you are currently\n\
+may have restrictions on the import, possession, and use, and/or re-export to\n\
+another country, of encryption software. BEFORE using any encryption software,\n\
+please check the country's laws, regulations and policies concerning the import,\n\
+possession, or use, and re-export of encryption software, to see if this is\n\
+permitted.\n\
 \n\
-Java and all Java-based trademarks are trademarks of Oracle Corporation in the United States, other countries, or both.\n
-########### end of license property ##########################################
\ No newline at end of file
+Java and all Java-based trademarks are trademarks of Oracle Corporation in the\n\
+United States, other countries, or both.\n
+########### end of license property ##########################################
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.junit.feature/feature.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.junit.feature/feature.xml
index 29b57ff..7ad4b1a 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.junit.feature/feature.xml
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.junit.feature/feature.xml
@@ -2,7 +2,7 @@
 <feature
       id="org.eclipse.jgit.junit"
       label="%featureName"
-      version="4.9.3.qualifier"
+      version="5.0.0.qualifier"
       provider-name="%providerName">
 
    <description url="http://www.eclipse.org/jgit/">
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.junit.feature/license.html b/org.eclipse.jgit.packaging/org.eclipse.jgit.junit.feature/license.html
index 95ad95e..008b801 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.junit.feature/license.html
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.junit.feature/license.html
@@ -1,106 +1,189 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-<!-- saved from url=(0044)http://www.eclipse.org/legal/epl/notice.html -->
-<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
-
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
 <title>Eclipse Foundation Software User Agreement</title>
 </head>
 
 <body lang="EN-US">
-<h2>Eclipse Foundation Software User Agreement</h2>
-<p>April 9, 2014</p>
+	<h2>Eclipse Foundation Software User Agreement</h2>
+	<p>November 22, 2017</p>
 
-<h3>Usage Of Content</h3>
+	<h3>Usage Of Content</h3>
 
-<p>THE ECLIPSE FOUNDATION MAKES AVAILABLE SOFTWARE, DOCUMENTATION, INFORMATION AND/OR OTHER MATERIALS FOR OPEN SOURCE PROJECTS
-   (COLLECTIVELY "CONTENT").  USE OF THE CONTENT IS GOVERNED BY THE TERMS AND CONDITIONS OF THIS AGREEMENT AND/OR THE TERMS AND
-   CONDITIONS OF LICENSE AGREEMENTS OR NOTICES INDICATED OR REFERENCED BELOW.  BY USING THE CONTENT, YOU AGREE THAT YOUR USE
-   OF THE CONTENT IS GOVERNED BY THIS AGREEMENT AND/OR THE TERMS AND CONDITIONS OF ANY APPLICABLE LICENSE AGREEMENTS OR
-   NOTICES INDICATED OR REFERENCED BELOW.  IF YOU DO NOT AGREE TO THE TERMS AND CONDITIONS OF THIS AGREEMENT AND THE TERMS AND
-   CONDITIONS OF ANY APPLICABLE LICENSE AGREEMENTS OR NOTICES INDICATED OR REFERENCED BELOW, THEN YOU MAY NOT USE THE CONTENT.</p>
+	<p>THE ECLIPSE FOUNDATION MAKES AVAILABLE SOFTWARE, DOCUMENTATION,
+		INFORMATION AND/OR OTHER MATERIALS FOR OPEN SOURCE PROJECTS
+		(COLLECTIVELY &quot;CONTENT&quot;). USE OF THE CONTENT IS GOVERNED BY
+		THE TERMS AND CONDITIONS OF THIS AGREEMENT AND/OR THE TERMS AND
+		CONDITIONS OF LICENSE AGREEMENTS OR NOTICES INDICATED OR REFERENCED
+		BELOW. BY USING THE CONTENT, YOU AGREE THAT YOUR USE OF THE CONTENT IS
+		GOVERNED BY THIS AGREEMENT AND/OR THE TERMS AND CONDITIONS OF ANY
+		APPLICABLE LICENSE AGREEMENTS OR NOTICES INDICATED OR REFERENCED
+		BELOW. IF YOU DO NOT AGREE TO THE TERMS AND CONDITIONS OF THIS
+		AGREEMENT AND THE TERMS AND CONDITIONS OF ANY APPLICABLE LICENSE
+		AGREEMENTS OR NOTICES INDICATED OR REFERENCED BELOW, THEN YOU MAY NOT
+		USE THE CONTENT.</p>
 
-<h3>Applicable Licenses</h3>
+	<h3>Applicable Licenses</h3>
 
-<p>Unless otherwise indicated, all Content made available by the Eclipse Foundation is provided to you under the terms and conditions of the Eclipse Public License Version 1.0
-   ("EPL").  A copy of the EPL is provided with this Content and is also available at <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a>.
-   For purposes of the EPL, "Program" will mean the Content.</p>
+	<p>
+		Unless otherwise indicated, all Content made available by the Eclipse
+		Foundation is provided to you under the terms and conditions of the
+		Eclipse Public License Version 2.0 (&quot;EPL&quot;). A copy of the
+		EPL is provided with this Content and is also available at <a
+			href="http://www.eclipse.org/legal/epl-2.0">http://www.eclipse.org/legal/epl-2.0</a>.
+		For purposes of the EPL, &quot;Program&quot; will mean the Content.
+	</p>
 
-<p>Content includes, but is not limited to, source code, object code, documentation and other files maintained in the Eclipse Foundation source code
-   repository ("Repository") in software modules ("Modules") and made available as downloadable archives ("Downloads").</p>
+	<p>Content includes, but is not limited to, source code, object
+		code, documentation and other files maintained in the Eclipse
+		Foundation source code repository (&quot;Repository&quot;) in software
+		modules (&quot;Modules&quot;) and made available as downloadable
+		archives (&quot;Downloads&quot;).</p>
 
-<ul>
-       <li>Content may be structured and packaged into modules to facilitate delivering, extending, and upgrading the Content.  Typical modules may include plug-ins ("Plug-ins"), plug-in fragments ("Fragments"), and features ("Features").</li>
-       <li>Each Plug-in or Fragment may be packaged as a sub-directory or JAR (Java™ ARchive) in a directory named "plugins".</li>
-       <li>A Feature is a bundle of one or more Plug-ins and/or Fragments and associated material.  Each Feature may be packaged as a sub-directory in a directory named "features".  Within a Feature, files named "feature.xml" may contain a list of the names and version numbers of the Plug-ins
-      and/or Fragments associated with that Feature.</li>
-       <li>Features may also include other Features ("Included Features"). Within a Feature, files named "feature.xml" may contain a list of the names and version numbers of Included Features.</li>
-</ul>
+	<ul>
+		<li>Content may be structured and packaged into modules to
+			facilitate delivering, extending, and upgrading the Content. Typical
+			modules may include plug-ins (&quot;Plug-ins&quot;), plug-in
+			fragments (&quot;Fragments&quot;), and features
+			(&quot;Features&quot;).</li>
+		<li>Each Plug-in or Fragment may be packaged as a sub-directory
+			or JAR (Java&trade; ARchive) in a directory named
+			&quot;plugins&quot;.</li>
+		<li>A Feature is a bundle of one or more Plug-ins and/or
+			Fragments and associated material. Each Feature may be packaged as a
+			sub-directory in a directory named &quot;features&quot;. Within a
+			Feature, files named &quot;feature.xml&quot; may contain a list of
+			the names and version numbers of the Plug-ins and/or Fragments
+			associated with that Feature.</li>
+		<li>Features may also include other Features (&quot;Included
+			Features&quot;). Within a Feature, files named
+			&quot;feature.xml&quot; may contain a list of the names and version
+			numbers of Included Features.</li>
+	</ul>
 
-<p>The terms and conditions governing Plug-ins and Fragments should be contained in files named "about.html" ("Abouts"). The terms and conditions governing Features and
-Included Features should be contained in files named "license.html" ("Feature Licenses").  Abouts and Feature Licenses may be located in any directory of a Download or Module
-including, but not limited to the following locations:</p>
+	<p>The terms and conditions governing Plug-ins and Fragments should
+		be contained in files named &quot;about.html&quot;
+		(&quot;Abouts&quot;). The terms and conditions governing Features and
+		Included Features should be contained in files named
+		&quot;license.html&quot; (&quot;Feature Licenses&quot;). Abouts and
+		Feature Licenses may be located in any directory of a Download or
+		Module including, but not limited to the following locations:</p>
 
-<ul>
-       <li>The top-level (root) directory</li>
-       <li>Plug-in and Fragment directories</li>
-       <li>Inside Plug-ins and Fragments packaged as JARs</li>
-       <li>Sub-directories of the directory named "src" of certain Plug-ins</li>
-       <li>Feature directories</li>
-</ul>
+	<ul>
+		<li>The top-level (root) directory</li>
+		<li>Plug-in and Fragment directories</li>
+		<li>Inside Plug-ins and Fragments packaged as JARs</li>
+		<li>Sub-directories of the directory named &quot;src&quot; of
+			certain Plug-ins</li>
+		<li>Feature directories</li>
+	</ul>
 
-<p>Note: if a Feature made available by the Eclipse Foundation is installed using the Provisioning Technology (as defined below), you must agree to a license ("Feature Update License") during the
-installation process.  If the Feature contains Included Features, the Feature Update License should either provide you with the terms and conditions governing the Included Features or
-inform you where you can locate them.  Feature Update Licenses may be found in the "license" property of files named "feature.properties" found within a Feature.
-Such Abouts, Feature Licenses, and Feature Update Licenses contain the terms and conditions (or references to such terms and conditions) that govern your use of the associated Content in
-that directory.</p>
+	<p>Note: if a Feature made available by the Eclipse Foundation is
+		installed using the Provisioning Technology (as defined below), you
+		must agree to a license (&quot;Feature Update License&quot;) during
+		the installation process. If the Feature contains Included Features,
+		the Feature Update License should either provide you with the terms
+		and conditions governing the Included Features or inform you where you
+		can locate them. Feature Update Licenses may be found in the
+		&quot;license&quot; property of files named
+		&quot;feature.properties&quot; found within a Feature. Such Abouts,
+		Feature Licenses, and Feature Update Licenses contain the terms and
+		conditions (or references to such terms and conditions) that govern
+		your use of the associated Content in that directory.</p>
 
-<p>THE ABOUTS, FEATURE LICENSES, AND FEATURE UPDATE LICENSES MAY REFER TO THE EPL OR OTHER LICENSE AGREEMENTS, NOTICES OR TERMS AND CONDITIONS.  SOME OF THESE
-OTHER LICENSE AGREEMENTS MAY INCLUDE (BUT ARE NOT LIMITED TO):</p>
+	<p>THE ABOUTS, FEATURE LICENSES, AND FEATURE UPDATE LICENSES MAY
+		REFER TO THE EPL OR OTHER LICENSE AGREEMENTS, NOTICES OR TERMS AND
+		CONDITIONS. SOME OF THESE OTHER LICENSE AGREEMENTS MAY INCLUDE (BUT
+		ARE NOT LIMITED TO):</p>
 
-<ul>
-       <li>Eclipse Distribution License Version 1.0 (available at <a href="http://www.eclipse.org/licenses/edl-v10.html">http://www.eclipse.org/licenses/edl-v1.0.html</a>)</li>
-       <li>Common Public License Version 1.0 (available at <a href="http://www.eclipse.org/legal/cpl-v10.html">http://www.eclipse.org/legal/cpl-v10.html</a>)</li>
-       <li>Apache Software License 1.1 (available at <a href="http://www.apache.org/licenses/LICENSE">http://www.apache.org/licenses/LICENSE</a>)</li>
-       <li>Apache Software License 2.0 (available at <a href="http://www.apache.org/licenses/LICENSE-2.0">http://www.apache.org/licenses/LICENSE-2.0</a>)</li>
-       <li>Mozilla Public License Version 1.1 (available at <a href="http://www.mozilla.org/MPL/MPL-1.1.html">http://www.mozilla.org/MPL/MPL-1.1.html</a>)</li>
-</ul>
+	<ul>
+		<li>Eclipse Public License Version 1.0 (available at <a
+			href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a>)
+		</li>
+		<li>Eclipse Distribution License Version 1.0 (available at <a
+			href="http://www.eclipse.org/licenses/edl-v10.html">http://www.eclipse.org/licenses/edl-v1.0.html</a>)
+		</li>
+		<li>Common Public License Version 1.0 (available at <a
+			href="http://www.eclipse.org/legal/cpl-v10.html">http://www.eclipse.org/legal/cpl-v10.html</a>)
+		</li>
+		<li>Apache Software License 1.1 (available at <a
+			href="http://www.apache.org/licenses/LICENSE">http://www.apache.org/licenses/LICENSE</a>)
+		</li>
+		<li>Apache Software License 2.0 (available at <a
+			href="http://www.apache.org/licenses/LICENSE-2.0">http://www.apache.org/licenses/LICENSE-2.0</a>)
+		</li>
+		<li>Mozilla Public License Version 1.1 (available at <a
+			href="http://www.mozilla.org/MPL/MPL-1.1.html">http://www.mozilla.org/MPL/MPL-1.1.html</a>)
+		</li>
+	</ul>
 
-<p>IT IS YOUR OBLIGATION TO READ AND ACCEPT ALL SUCH TERMS AND CONDITIONS PRIOR TO USE OF THE CONTENT.  If no About, Feature License, or Feature Update License is provided, please
-contact the Eclipse Foundation to determine what terms and conditions govern that particular Content.</p>
+	<p>IT IS YOUR OBLIGATION TO READ AND ACCEPT ALL SUCH TERMS AND
+		CONDITIONS PRIOR TO USE OF THE CONTENT. If no About, Feature License,
+		or Feature Update License is provided, please contact the Eclipse
+		Foundation to determine what terms and conditions govern that
+		particular Content.</p>
 
 
-<h3>Use of Provisioning Technology</h3>
+	<h3>Use of Provisioning Technology</h3>
 
-<p>The Eclipse Foundation makes available provisioning software, examples of which include, but are not limited to, p2 and the Eclipse
-   Update Manager ("Provisioning Technology") for the purpose of allowing users to install software, documentation, information and/or
-   other materials (collectively "Installable Software"). This capability is provided with the intent of allowing such users to
-   install, extend and update Eclipse-based products. Information about packaging Installable Software is available at <a href="http://eclipse.org/equinox/p2/repository_packaging.html">http://eclipse.org/equinox/p2/repository_packaging.html</a>
-   ("Specification").</p>
+	<p>
+		The Eclipse Foundation makes available provisioning software, examples
+		of which include, but are not limited to, p2 and the Eclipse Update
+		Manager (&quot;Provisioning Technology&quot;) for the purpose of
+		allowing users to install software, documentation, information and/or
+		other materials (collectively &quot;Installable Software&quot;). This
+		capability is provided with the intent of allowing such users to
+		install, extend and update Eclipse-based products. Information about
+		packaging Installable Software is available at <a
+			href="http://eclipse.org/equinox/p2/repository_packaging.html">http://eclipse.org/equinox/p2/repository_packaging.html</a>
+		(&quot;Specification&quot;).
+	</p>
 
-<p>You may use Provisioning Technology to allow other parties to install Installable Software. You shall be responsible for enabling the
-   applicable license agreements relating to the Installable Software to be presented to, and accepted by, the users of the Provisioning Technology
-   in accordance with the Specification. By using Provisioning Technology in such a manner and making it available in accordance with the
-   Specification, you further acknowledge your agreement to, and the acquisition of all necessary rights to permit the following:</p>
+	<p>You may use Provisioning Technology to allow other parties to
+		install Installable Software. You shall be responsible for enabling
+		the applicable license agreements relating to the Installable Software
+		to be presented to, and accepted by, the users of the Provisioning
+		Technology in accordance with the Specification. By using Provisioning
+		Technology in such a manner and making it available in accordance with
+		the Specification, you further acknowledge your agreement to, and the
+		acquisition of all necessary rights to permit the following:</p>
 
-<ol>
-       <li>A series of actions may occur ("Provisioning Process") in which a user may execute the Provisioning Technology
-       on a machine ("Target Machine") with the intent of installing, extending or updating the functionality of an Eclipse-based
-       product.</li>
-       <li>During the Provisioning Process, the Provisioning Technology may cause third party Installable Software or a portion thereof to be
-       accessed and copied to the Target Machine.</li>
-       <li>Pursuant to the Specification, you will provide to the user the terms and conditions that govern the use of the Installable
-       Software ("Installable Software Agreement") and such Installable Software Agreement shall be accessed from the Target
-       Machine in accordance with the Specification. Such Installable Software Agreement must inform the user of the terms and conditions that govern
-       the Installable Software and must solicit acceptance by the end user in the manner prescribed in such Installable Software Agreement. Upon such
-       indication of agreement by the user, the provisioning Technology will complete installation of the Installable Software.</li>
-</ol>
+	<ol>
+		<li>A series of actions may occur (&quot;Provisioning
+			Process&quot;) in which a user may execute the Provisioning
+			Technology on a machine (&quot;Target Machine&quot;) with the intent
+			of installing, extending or updating the functionality of an
+			Eclipse-based product.</li>
+		<li>During the Provisioning Process, the Provisioning Technology
+			may cause third party Installable Software or a portion thereof to be
+			accessed and copied to the Target Machine.</li>
+		<li>Pursuant to the Specification, you will provide to the user
+			the terms and conditions that govern the use of the Installable
+			Software (&quot;Installable Software Agreement&quot;) and such
+			Installable Software Agreement shall be accessed from the Target
+			Machine in accordance with the Specification. Such Installable
+			Software Agreement must inform the user of the terms and conditions
+			that govern the Installable Software and must solicit acceptance by
+			the end user in the manner prescribed in such Installable Software
+			Agreement. Upon such indication of agreement by the user, the
+			provisioning Technology will complete installation of the Installable
+			Software.</li>
+	</ol>
 
-<h3>Cryptography</h3>
+	<h3>Cryptography</h3>
 
-<p>Content may contain encryption software. The country in which you are currently may have restrictions on the import, possession, and use, and/or re-export to
-   another country, of encryption software. BEFORE using any encryption software, please check the country's laws, regulations and policies concerning the import,
-   possession, or use, and re-export of encryption software, to see if this is permitted.</p>
+	<p>Content may contain encryption software. The country in which
+		you are currently may have restrictions on the import, possession, and
+		use, and/or re-export to another country, of encryption software.
+		BEFORE using any encryption software, please check the country's laws,
+		regulations and policies concerning the import, possession, or use,
+		and re-export of encryption software, to see if this is permitted.</p>
 
-<p><small>Java and all Java-based trademarks are trademarks of Oracle Corporation in the United States, other countries, or both.</small></p>
-
-
-</body></html>
\ No newline at end of file
+	<p>
+		<small>Java and all Java-based trademarks are trademarks of
+			Oracle Corporation in the United States, other countries, or both.</small>
+	</p>
+</body>
+</html>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.junit.feature/pom.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.junit.feature/pom.xml
index 73cc7ea..8b0b3ee 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.junit.feature/pom.xml
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.junit.feature/pom.xml
@@ -50,7 +50,7 @@
   <parent>
     <groupId>org.eclipse.jgit</groupId>
     <artifactId>jgit.tycho.parent</artifactId>
-    <version>4.9.3-SNAPSHOT</version>
+    <version>5.0.0-SNAPSHOT</version>
   </parent>
 
   <groupId>org.eclipse.jgit.feature</groupId>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.lfs.feature/feature.properties b/org.eclipse.jgit.packaging/org.eclipse.jgit.lfs.feature/feature.properties
index c5bffa8..8387585 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.lfs.feature/feature.properties
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.lfs.feature/feature.properties
@@ -35,125 +35,143 @@
 # should be plain text version of license agreement pointed to be "licenseURL"
 license=\
 Eclipse Foundation Software User Agreement\n\
-April 9, 2014\n\
+\n\
+November 22, 2017\n\
 \n\
 Usage Of Content\n\
 \n\
-THE ECLIPSE FOUNDATION MAKES AVAILABLE SOFTWARE, DOCUMENTATION, INFORMATION AND/OR\n\
-OTHER MATERIALS FOR OPEN SOURCE PROJECTS (COLLECTIVELY "CONTENT").\n\
-USE OF THE CONTENT IS GOVERNED BY THE TERMS AND CONDITIONS OF THIS\n\
-AGREEMENT AND/OR THE TERMS AND CONDITIONS OF LICENSE AGREEMENTS OR\n\
-NOTICES INDICATED OR REFERENCED BELOW.  BY USING THE CONTENT, YOU\n\
-AGREE THAT YOUR USE OF THE CONTENT IS GOVERNED BY THIS AGREEMENT\n\
-AND/OR THE TERMS AND CONDITIONS OF ANY APPLICABLE LICENSE AGREEMENTS\n\
-OR NOTICES INDICATED OR REFERENCED BELOW.  IF YOU DO NOT AGREE TO THE\n\
-TERMS AND CONDITIONS OF THIS AGREEMENT AND THE TERMS AND CONDITIONS\n\
-OF ANY APPLICABLE LICENSE AGREEMENTS OR NOTICES INDICATED OR REFERENCED\n\
-BELOW, THEN YOU MAY NOT USE THE CONTENT.\n\
+THE ECLIPSE FOUNDATION MAKES AVAILABLE SOFTWARE, DOCUMENTATION, INFORMATION\n\
+AND/OR OTHER MATERIALS FOR OPEN SOURCE PROJECTS (COLLECTIVELY "CONTENT"). USE OF\n\
+THE CONTENT IS GOVERNED BY THE TERMS AND CONDITIONS OF THIS AGREEMENT AND/OR THE\n\
+TERMS AND CONDITIONS OF LICENSE AGREEMENTS OR NOTICES INDICATED OR REFERENCED\n\
+BELOW. BY USING THE CONTENT, YOU AGREE THAT YOUR USE OF THE CONTENT IS GOVERNED\n\
+BY THIS AGREEMENT AND/OR THE TERMS AND CONDITIONS OF ANY APPLICABLE LICENSE\n\
+AGREEMENTS OR NOTICES INDICATED OR REFERENCED BELOW. IF YOU DO NOT AGREE TO THE\n\
+TERMS AND CONDITIONS OF THIS AGREEMENT AND THE TERMS AND CONDITIONS OF ANY\n\
+APPLICABLE LICENSE AGREEMENTS OR NOTICES INDICATED OR REFERENCED BELOW, THEN YOU\n\
+MAY NOT USE THE CONTENT.\n\
 \n\
 Applicable Licenses\n\
 \n\
-Unless otherwise indicated, all Content made available by the\n\
-Eclipse Foundation is provided to you under the terms and conditions of\n\
-the Eclipse Public License Version 1.0 ("EPL"). A copy of the EPL is\n\
-provided with this Content and is also available at http://www.eclipse.org/legal/epl-v10.html.\n\
-For purposes of the EPL, "Program" will mean the Content.\n\
+Unless otherwise indicated, all Content made available by the Eclipse Foundation\n\
+is provided to you under the terms and conditions of the Eclipse Public License\n\
+Version 2.0 ("EPL"). A copy of the EPL is provided with this Content and is also\n\
+available at http://www.eclipse.org/legal/epl-2.0. For purposes of the EPL,\n\
+"Program" will mean the Content.\n\
 \n\
-Content includes, but is not limited to, source code, object code,\n\
-documentation and other files maintained in the Eclipse Foundation source code\n\
-repository ("Repository") in software modules ("Modules") and made available\n\
-as downloadable archives ("Downloads").\n\
+Content includes, but is not limited to, source code, object code, documentation\n\
+and other files maintained in the Eclipse Foundation source code repository\n\
+("Repository") in software modules ("Modules") and made available as\n\
+downloadable archives ("Downloads").\n\
 \n\
-       - Content may be structured and packaged into modules to facilitate delivering,\n\
-         extending, and upgrading the Content. Typical modules may include plug-ins ("Plug-ins"),\n\
-         plug-in fragments ("Fragments"), and features ("Features").\n\
-       - Each Plug-in or Fragment may be packaged as a sub-directory or JAR (Java(TM) ARchive)\n\
-         in a directory named "plugins".\n\
-       - A Feature is a bundle of one or more Plug-ins and/or Fragments and associated material.\n\
-         Each Feature may be packaged as a sub-directory in a directory named "features".\n\
-         Within a Feature, files named "feature.xml" may contain a list of the names and version\n\
-         numbers of the Plug-ins and/or Fragments associated with that Feature.\n\
-       - Features may also include other Features ("Included Features"). Within a Feature, files\n\
-         named "feature.xml" may contain a list of the names and version numbers of Included Features.\n\
+-   Content may be structured and packaged into modules to facilitate\n\
+    delivering, extending, and upgrading the Content. Typical modules may\n\
+    include plug-ins ("Plug-ins"), plug-in fragments ("Fragments"), and\n\
+    features ("Features").\n\
+-   Each Plug-in or Fragment may be packaged as a sub-directory or JAR\n\
+    (Java™ ARchive) in a directory named "plugins".\n\
+-   A Feature is a bundle of one or more Plug-ins and/or Fragments and\n\
+    associated material. Each Feature may be packaged as a sub-directory in a\n\
+    directory named "features". Within a Feature, files named "feature.xml" may\n\
+    contain a list of the names and version numbers of the Plug-ins and/or\n\
+    Fragments associated with that Feature.\n\
+-   Features may also include other Features ("Included Features"). Within a\n\
+    Feature, files named "feature.xml" may contain a list of the names and\n\
+    version numbers of Included Features.\n\
 \n\
-The terms and conditions governing Plug-ins and Fragments should be\n\
-contained in files named "about.html" ("Abouts"). The terms and\n\
-conditions governing Features and Included Features should be contained\n\
-in files named "license.html" ("Feature Licenses"). Abouts and Feature\n\
-Licenses may be located in any directory of a Download or Module\n\
-including, but not limited to the following locations:\n\
+The terms and conditions governing Plug-ins and Fragments should be contained in\n\
+files named "about.html" ("Abouts"). The terms and conditions governing Features\n\
+and Included Features should be contained in files named "license.html"\n\
+("Feature Licenses"). Abouts and Feature Licenses may be located in any\n\
+directory of a Download or Module including, but not limited to the following\n\
+locations:\n\
 \n\
-       - The top-level (root) directory\n\
-       - Plug-in and Fragment directories\n\
-       - Inside Plug-ins and Fragments packaged as JARs\n\
-       - Sub-directories of the directory named "src" of certain Plug-ins\n\
-       - Feature directories\n\
+-   The top-level (root) directory\n\
+-   Plug-in and Fragment directories\n\
+-   Inside Plug-ins and Fragments packaged as JARs\n\
+-   Sub-directories of the directory named "src" of certain Plug-ins\n\
+-   Feature directories\n\
 \n\
-Note: if a Feature made available by the Eclipse Foundation is installed using the\n\
-Provisioning Technology (as defined below), you must agree to a license ("Feature \n\
-Update License") during the installation process. If the Feature contains\n\
-Included Features, the Feature Update License should either provide you\n\
-with the terms and conditions governing the Included Features or inform\n\
-you where you can locate them. Feature Update Licenses may be found in\n\
-the "license" property of files named "feature.properties" found within a Feature.\n\
-Such Abouts, Feature Licenses, and Feature Update Licenses contain the\n\
-terms and conditions (or references to such terms and conditions) that\n\
-govern your use of the associated Content in that directory.\n\
+Note: if a Feature made available by the Eclipse Foundation is installed using\n\
+the Provisioning Technology (as defined below), you must agree to a license\n\
+("Feature Update License") during the installation process. If the Feature\n\
+contains Included Features, the Feature Update License should either provide you\n\
+with the terms and conditions governing the Included Features or inform you\n\
+where you can locate them. Feature Update Licenses may be found in the "license"\n\
+property of files named "feature.properties" found within a Feature. Such\n\
+Abouts, Feature Licenses, and Feature Update Licenses contain the terms and\n\
+conditions (or references to such terms and conditions) that govern your use of\n\
+the associated Content in that directory.\n\
 \n\
-THE ABOUTS, FEATURE LICENSES, AND FEATURE UPDATE LICENSES MAY REFER\n\
-TO THE EPL OR OTHER LICENSE AGREEMENTS, NOTICES OR TERMS AND CONDITIONS.\n\
-SOME OF THESE OTHER LICENSE AGREEMENTS MAY INCLUDE (BUT ARE NOT LIMITED TO):\n\
+THE ABOUTS, FEATURE LICENSES, AND FEATURE UPDATE LICENSES MAY REFER TO THE EPL\n\
+OR OTHER LICENSE AGREEMENTS, NOTICES OR TERMS AND CONDITIONS. SOME OF THESE\n\
+OTHER LICENSE AGREEMENTS MAY INCLUDE (BUT ARE NOT LIMITED TO):\n\
 \n\
-       - Eclipse Distribution License Version 1.0 (available at http://www.eclipse.org/licenses/edl-v1.0.html)\n\
-       - Common Public License Version 1.0 (available at http://www.eclipse.org/legal/cpl-v10.html)\n\
-       - Apache Software License 1.1 (available at http://www.apache.org/licenses/LICENSE)\n\
-       - Apache Software License 2.0 (available at http://www.apache.org/licenses/LICENSE-2.0)\n\
-       - Mozilla Public License Version 1.1 (available at http://www.mozilla.org/MPL/MPL-1.1.html)\n\
+-   Eclipse Public License Version 1.0 (available at\n\
+    http://www.eclipse.org/legal/epl-v10.html)\n\
+-   Eclipse Distribution License Version 1.0 (available at\n\
+    http://www.eclipse.org/licenses/edl-v1.0.html)\n\
+-   Common Public License Version 1.0 (available at\n\
+    http://www.eclipse.org/legal/cpl-v10.html)\n\
+-   Apache Software License 1.1 (available at\n\
+    http://www.apache.org/licenses/LICENSE)\n\
+-   Apache Software License 2.0 (available at\n\
+    http://www.apache.org/licenses/LICENSE-2.0)\n\
+-   Mozilla Public License Version 1.1 (available at\n\
+    http://www.mozilla.org/MPL/MPL-1.1.html)\n\
 \n\
-IT IS YOUR OBLIGATION TO READ AND ACCEPT ALL SUCH TERMS AND CONDITIONS PRIOR\n\
-TO USE OF THE CONTENT. If no About, Feature License, or Feature Update License\n\
-is provided, please contact the Eclipse Foundation to determine what terms and conditions\n\
-govern that particular Content.\n\
+IT IS YOUR OBLIGATION TO READ AND ACCEPT ALL SUCH TERMS AND CONDITIONS PRIOR TO\n\
+USE OF THE CONTENT. If no About, Feature License, or Feature Update License is\n\
+provided, please contact the Eclipse Foundation to determine what terms and\n\
+conditions govern that particular Content.\n\
 \n\
-\n\Use of Provisioning Technology\n\
+Use of Provisioning Technology\n\
 \n\
-The Eclipse Foundation makes available provisioning software, examples of which include,\n\
-but are not limited to, p2 and the Eclipse Update Manager ("Provisioning Technology") for\n\
-the purpose of allowing users to install software, documentation, information and/or\n\
-other materials (collectively "Installable Software"). This capability is provided with\n\
-the intent of allowing such users to install, extend and update Eclipse-based products.\n\
-Information about packaging Installable Software is available at\n\
+The Eclipse Foundation makes available provisioning software, examples of which\n\
+include, but are not limited to, p2 and the Eclipse Update Manager\n\
+("Provisioning Technology") for the purpose of allowing users to install\n\
+software, documentation, information and/or other materials (collectively\n\
+"Installable Software"). This capability is provided with the intent of allowing\n\
+such users to install, extend and update Eclipse-based products. Information\n\
+about packaging Installable Software is available at\n\
 http://eclipse.org/equinox/p2/repository_packaging.html ("Specification").\n\
 \n\
-You may use Provisioning Technology to allow other parties to install Installable Software.\n\
-You shall be responsible for enabling the applicable license agreements relating to the\n\
-Installable Software to be presented to, and accepted by, the users of the Provisioning Technology\n\
-in accordance with the Specification. By using Provisioning Technology in such a manner and\n\
-making it available in accordance with the Specification, you further acknowledge your\n\
-agreement to, and the acquisition of all necessary rights to permit the following:\n\
+You may use Provisioning Technology to allow other parties to install\n\
+Installable Software. You shall be responsible for enabling the applicable\n\
+license agreements relating to the Installable Software to be presented to, and\n\
+accepted by, the users of the Provisioning Technology in accordance with the\n\
+Specification. By using Provisioning Technology in such a manner and making it\n\
+available in accordance with the Specification, you further acknowledge your\n\
+agreement to, and the acquisition of all necessary rights to permit the\n\
+following:\n\
 \n\
-       1. A series of actions may occur ("Provisioning Process") in which a user may execute\n\
-          the Provisioning Technology on a machine ("Target Machine") with the intent of installing,\n\
-          extending or updating the functionality of an Eclipse-based product.\n\
-       2. During the Provisioning Process, the Provisioning Technology may cause third party\n\
-          Installable Software or a portion thereof to be accessed and copied to the Target Machine.\n\
-       3. Pursuant to the Specification, you will provide to the user the terms and conditions that\n\
-          govern the use of the Installable Software ("Installable Software Agreement") and such\n\
-          Installable Software Agreement shall be accessed from the Target Machine in accordance\n\
-          with the Specification. Such Installable Software Agreement must inform the user of the\n\
-          terms and conditions that govern the Installable Software and must solicit acceptance by\n\
-          the end user in the manner prescribed in such Installable Software Agreement. Upon such\n\
-          indication of agreement by the user, the provisioning Technology will complete installation\n\
-          of the Installable Software.\n\
+1.  A series of actions may occur ("Provisioning Process") in which a user may\n\
+    execute the Provisioning Technology on a machine ("Target Machine") with the\n\
+    intent of installing, extending or updating the functionality of an\n\
+    Eclipse-based product.\n\
+2.  During the Provisioning Process, the Provisioning Technology may cause third\n\
+    party Installable Software or a portion thereof to be accessed and copied to\n\
+    the Target Machine.\n\
+3.  Pursuant to the Specification, you will provide to the user the terms and\n\
+    conditions that govern the use of the Installable Software ("Installable\n\
+    Software Agreement") and such Installable Software Agreement shall be\n\
+    accessed from the Target Machine in accordance with the Specification. Such\n\
+    Installable Software Agreement must inform the user of the terms and\n\
+    conditions that govern the Installable Software and must solicit acceptance\n\
+    by the end user in the manner prescribed in such Installable\n\
+    Software Agreement. Upon such indication of agreement by the user, the\n\
+    provisioning Technology will complete installation of the\n\
+    Installable Software.\n\
 \n\
 Cryptography\n\
 \n\
-Content may contain encryption software. The country in which you are\n\
-currently may have restrictions on the import, possession, and use,\n\
-and/or re-export to another country, of encryption software. BEFORE\n\
-using any encryption software, please check the country's laws,\n\
-regulations and policies concerning the import, possession, or use, and\n\
-re-export of encryption software, to see if this is permitted.\n\
+Content may contain encryption software. The country in which you are currently\n\
+may have restrictions on the import, possession, and use, and/or re-export to\n\
+another country, of encryption software. BEFORE using any encryption software,\n\
+please check the country's laws, regulations and policies concerning the import,\n\
+possession, or use, and re-export of encryption software, to see if this is\n\
+permitted.\n\
 \n\
-Java and all Java-based trademarks are trademarks of Oracle Corporation in the United States, other countries, or both.\n
+Java and all Java-based trademarks are trademarks of Oracle Corporation in the\n\
+United States, other countries, or both.\n
 ########### end of license property ##########################################
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.lfs.feature/feature.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.lfs.feature/feature.xml
index 63224be..b3770f5 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.lfs.feature/feature.xml
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.lfs.feature/feature.xml
@@ -2,7 +2,7 @@
 <feature
       id="org.eclipse.jgit.lfs"
       label="%featureName"
-      version="4.9.3.qualifier"
+      version="5.0.0.qualifier"
       provider-name="%providerName">
 
    <description url="http://www.eclipse.org/jgit/">
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.lfs.feature/license.html b/org.eclipse.jgit.packaging/org.eclipse.jgit.lfs.feature/license.html
index 95ad95e..008b801 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.lfs.feature/license.html
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.lfs.feature/license.html
@@ -1,106 +1,189 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-<!-- saved from url=(0044)http://www.eclipse.org/legal/epl/notice.html -->
-<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
-
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
 <title>Eclipse Foundation Software User Agreement</title>
 </head>
 
 <body lang="EN-US">
-<h2>Eclipse Foundation Software User Agreement</h2>
-<p>April 9, 2014</p>
+	<h2>Eclipse Foundation Software User Agreement</h2>
+	<p>November 22, 2017</p>
 
-<h3>Usage Of Content</h3>
+	<h3>Usage Of Content</h3>
 
-<p>THE ECLIPSE FOUNDATION MAKES AVAILABLE SOFTWARE, DOCUMENTATION, INFORMATION AND/OR OTHER MATERIALS FOR OPEN SOURCE PROJECTS
-   (COLLECTIVELY "CONTENT").  USE OF THE CONTENT IS GOVERNED BY THE TERMS AND CONDITIONS OF THIS AGREEMENT AND/OR THE TERMS AND
-   CONDITIONS OF LICENSE AGREEMENTS OR NOTICES INDICATED OR REFERENCED BELOW.  BY USING THE CONTENT, YOU AGREE THAT YOUR USE
-   OF THE CONTENT IS GOVERNED BY THIS AGREEMENT AND/OR THE TERMS AND CONDITIONS OF ANY APPLICABLE LICENSE AGREEMENTS OR
-   NOTICES INDICATED OR REFERENCED BELOW.  IF YOU DO NOT AGREE TO THE TERMS AND CONDITIONS OF THIS AGREEMENT AND THE TERMS AND
-   CONDITIONS OF ANY APPLICABLE LICENSE AGREEMENTS OR NOTICES INDICATED OR REFERENCED BELOW, THEN YOU MAY NOT USE THE CONTENT.</p>
+	<p>THE ECLIPSE FOUNDATION MAKES AVAILABLE SOFTWARE, DOCUMENTATION,
+		INFORMATION AND/OR OTHER MATERIALS FOR OPEN SOURCE PROJECTS
+		(COLLECTIVELY &quot;CONTENT&quot;). USE OF THE CONTENT IS GOVERNED BY
+		THE TERMS AND CONDITIONS OF THIS AGREEMENT AND/OR THE TERMS AND
+		CONDITIONS OF LICENSE AGREEMENTS OR NOTICES INDICATED OR REFERENCED
+		BELOW. BY USING THE CONTENT, YOU AGREE THAT YOUR USE OF THE CONTENT IS
+		GOVERNED BY THIS AGREEMENT AND/OR THE TERMS AND CONDITIONS OF ANY
+		APPLICABLE LICENSE AGREEMENTS OR NOTICES INDICATED OR REFERENCED
+		BELOW. IF YOU DO NOT AGREE TO THE TERMS AND CONDITIONS OF THIS
+		AGREEMENT AND THE TERMS AND CONDITIONS OF ANY APPLICABLE LICENSE
+		AGREEMENTS OR NOTICES INDICATED OR REFERENCED BELOW, THEN YOU MAY NOT
+		USE THE CONTENT.</p>
 
-<h3>Applicable Licenses</h3>
+	<h3>Applicable Licenses</h3>
 
-<p>Unless otherwise indicated, all Content made available by the Eclipse Foundation is provided to you under the terms and conditions of the Eclipse Public License Version 1.0
-   ("EPL").  A copy of the EPL is provided with this Content and is also available at <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a>.
-   For purposes of the EPL, "Program" will mean the Content.</p>
+	<p>
+		Unless otherwise indicated, all Content made available by the Eclipse
+		Foundation is provided to you under the terms and conditions of the
+		Eclipse Public License Version 2.0 (&quot;EPL&quot;). A copy of the
+		EPL is provided with this Content and is also available at <a
+			href="http://www.eclipse.org/legal/epl-2.0">http://www.eclipse.org/legal/epl-2.0</a>.
+		For purposes of the EPL, &quot;Program&quot; will mean the Content.
+	</p>
 
-<p>Content includes, but is not limited to, source code, object code, documentation and other files maintained in the Eclipse Foundation source code
-   repository ("Repository") in software modules ("Modules") and made available as downloadable archives ("Downloads").</p>
+	<p>Content includes, but is not limited to, source code, object
+		code, documentation and other files maintained in the Eclipse
+		Foundation source code repository (&quot;Repository&quot;) in software
+		modules (&quot;Modules&quot;) and made available as downloadable
+		archives (&quot;Downloads&quot;).</p>
 
-<ul>
-       <li>Content may be structured and packaged into modules to facilitate delivering, extending, and upgrading the Content.  Typical modules may include plug-ins ("Plug-ins"), plug-in fragments ("Fragments"), and features ("Features").</li>
-       <li>Each Plug-in or Fragment may be packaged as a sub-directory or JAR (Java™ ARchive) in a directory named "plugins".</li>
-       <li>A Feature is a bundle of one or more Plug-ins and/or Fragments and associated material.  Each Feature may be packaged as a sub-directory in a directory named "features".  Within a Feature, files named "feature.xml" may contain a list of the names and version numbers of the Plug-ins
-      and/or Fragments associated with that Feature.</li>
-       <li>Features may also include other Features ("Included Features"). Within a Feature, files named "feature.xml" may contain a list of the names and version numbers of Included Features.</li>
-</ul>
+	<ul>
+		<li>Content may be structured and packaged into modules to
+			facilitate delivering, extending, and upgrading the Content. Typical
+			modules may include plug-ins (&quot;Plug-ins&quot;), plug-in
+			fragments (&quot;Fragments&quot;), and features
+			(&quot;Features&quot;).</li>
+		<li>Each Plug-in or Fragment may be packaged as a sub-directory
+			or JAR (Java&trade; ARchive) in a directory named
+			&quot;plugins&quot;.</li>
+		<li>A Feature is a bundle of one or more Plug-ins and/or
+			Fragments and associated material. Each Feature may be packaged as a
+			sub-directory in a directory named &quot;features&quot;. Within a
+			Feature, files named &quot;feature.xml&quot; may contain a list of
+			the names and version numbers of the Plug-ins and/or Fragments
+			associated with that Feature.</li>
+		<li>Features may also include other Features (&quot;Included
+			Features&quot;). Within a Feature, files named
+			&quot;feature.xml&quot; may contain a list of the names and version
+			numbers of Included Features.</li>
+	</ul>
 
-<p>The terms and conditions governing Plug-ins and Fragments should be contained in files named "about.html" ("Abouts"). The terms and conditions governing Features and
-Included Features should be contained in files named "license.html" ("Feature Licenses").  Abouts and Feature Licenses may be located in any directory of a Download or Module
-including, but not limited to the following locations:</p>
+	<p>The terms and conditions governing Plug-ins and Fragments should
+		be contained in files named &quot;about.html&quot;
+		(&quot;Abouts&quot;). The terms and conditions governing Features and
+		Included Features should be contained in files named
+		&quot;license.html&quot; (&quot;Feature Licenses&quot;). Abouts and
+		Feature Licenses may be located in any directory of a Download or
+		Module including, but not limited to the following locations:</p>
 
-<ul>
-       <li>The top-level (root) directory</li>
-       <li>Plug-in and Fragment directories</li>
-       <li>Inside Plug-ins and Fragments packaged as JARs</li>
-       <li>Sub-directories of the directory named "src" of certain Plug-ins</li>
-       <li>Feature directories</li>
-</ul>
+	<ul>
+		<li>The top-level (root) directory</li>
+		<li>Plug-in and Fragment directories</li>
+		<li>Inside Plug-ins and Fragments packaged as JARs</li>
+		<li>Sub-directories of the directory named &quot;src&quot; of
+			certain Plug-ins</li>
+		<li>Feature directories</li>
+	</ul>
 
-<p>Note: if a Feature made available by the Eclipse Foundation is installed using the Provisioning Technology (as defined below), you must agree to a license ("Feature Update License") during the
-installation process.  If the Feature contains Included Features, the Feature Update License should either provide you with the terms and conditions governing the Included Features or
-inform you where you can locate them.  Feature Update Licenses may be found in the "license" property of files named "feature.properties" found within a Feature.
-Such Abouts, Feature Licenses, and Feature Update Licenses contain the terms and conditions (or references to such terms and conditions) that govern your use of the associated Content in
-that directory.</p>
+	<p>Note: if a Feature made available by the Eclipse Foundation is
+		installed using the Provisioning Technology (as defined below), you
+		must agree to a license (&quot;Feature Update License&quot;) during
+		the installation process. If the Feature contains Included Features,
+		the Feature Update License should either provide you with the terms
+		and conditions governing the Included Features or inform you where you
+		can locate them. Feature Update Licenses may be found in the
+		&quot;license&quot; property of files named
+		&quot;feature.properties&quot; found within a Feature. Such Abouts,
+		Feature Licenses, and Feature Update Licenses contain the terms and
+		conditions (or references to such terms and conditions) that govern
+		your use of the associated Content in that directory.</p>
 
-<p>THE ABOUTS, FEATURE LICENSES, AND FEATURE UPDATE LICENSES MAY REFER TO THE EPL OR OTHER LICENSE AGREEMENTS, NOTICES OR TERMS AND CONDITIONS.  SOME OF THESE
-OTHER LICENSE AGREEMENTS MAY INCLUDE (BUT ARE NOT LIMITED TO):</p>
+	<p>THE ABOUTS, FEATURE LICENSES, AND FEATURE UPDATE LICENSES MAY
+		REFER TO THE EPL OR OTHER LICENSE AGREEMENTS, NOTICES OR TERMS AND
+		CONDITIONS. SOME OF THESE OTHER LICENSE AGREEMENTS MAY INCLUDE (BUT
+		ARE NOT LIMITED TO):</p>
 
-<ul>
-       <li>Eclipse Distribution License Version 1.0 (available at <a href="http://www.eclipse.org/licenses/edl-v10.html">http://www.eclipse.org/licenses/edl-v1.0.html</a>)</li>
-       <li>Common Public License Version 1.0 (available at <a href="http://www.eclipse.org/legal/cpl-v10.html">http://www.eclipse.org/legal/cpl-v10.html</a>)</li>
-       <li>Apache Software License 1.1 (available at <a href="http://www.apache.org/licenses/LICENSE">http://www.apache.org/licenses/LICENSE</a>)</li>
-       <li>Apache Software License 2.0 (available at <a href="http://www.apache.org/licenses/LICENSE-2.0">http://www.apache.org/licenses/LICENSE-2.0</a>)</li>
-       <li>Mozilla Public License Version 1.1 (available at <a href="http://www.mozilla.org/MPL/MPL-1.1.html">http://www.mozilla.org/MPL/MPL-1.1.html</a>)</li>
-</ul>
+	<ul>
+		<li>Eclipse Public License Version 1.0 (available at <a
+			href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a>)
+		</li>
+		<li>Eclipse Distribution License Version 1.0 (available at <a
+			href="http://www.eclipse.org/licenses/edl-v10.html">http://www.eclipse.org/licenses/edl-v1.0.html</a>)
+		</li>
+		<li>Common Public License Version 1.0 (available at <a
+			href="http://www.eclipse.org/legal/cpl-v10.html">http://www.eclipse.org/legal/cpl-v10.html</a>)
+		</li>
+		<li>Apache Software License 1.1 (available at <a
+			href="http://www.apache.org/licenses/LICENSE">http://www.apache.org/licenses/LICENSE</a>)
+		</li>
+		<li>Apache Software License 2.0 (available at <a
+			href="http://www.apache.org/licenses/LICENSE-2.0">http://www.apache.org/licenses/LICENSE-2.0</a>)
+		</li>
+		<li>Mozilla Public License Version 1.1 (available at <a
+			href="http://www.mozilla.org/MPL/MPL-1.1.html">http://www.mozilla.org/MPL/MPL-1.1.html</a>)
+		</li>
+	</ul>
 
-<p>IT IS YOUR OBLIGATION TO READ AND ACCEPT ALL SUCH TERMS AND CONDITIONS PRIOR TO USE OF THE CONTENT.  If no About, Feature License, or Feature Update License is provided, please
-contact the Eclipse Foundation to determine what terms and conditions govern that particular Content.</p>
+	<p>IT IS YOUR OBLIGATION TO READ AND ACCEPT ALL SUCH TERMS AND
+		CONDITIONS PRIOR TO USE OF THE CONTENT. If no About, Feature License,
+		or Feature Update License is provided, please contact the Eclipse
+		Foundation to determine what terms and conditions govern that
+		particular Content.</p>
 
 
-<h3>Use of Provisioning Technology</h3>
+	<h3>Use of Provisioning Technology</h3>
 
-<p>The Eclipse Foundation makes available provisioning software, examples of which include, but are not limited to, p2 and the Eclipse
-   Update Manager ("Provisioning Technology") for the purpose of allowing users to install software, documentation, information and/or
-   other materials (collectively "Installable Software"). This capability is provided with the intent of allowing such users to
-   install, extend and update Eclipse-based products. Information about packaging Installable Software is available at <a href="http://eclipse.org/equinox/p2/repository_packaging.html">http://eclipse.org/equinox/p2/repository_packaging.html</a>
-   ("Specification").</p>
+	<p>
+		The Eclipse Foundation makes available provisioning software, examples
+		of which include, but are not limited to, p2 and the Eclipse Update
+		Manager (&quot;Provisioning Technology&quot;) for the purpose of
+		allowing users to install software, documentation, information and/or
+		other materials (collectively &quot;Installable Software&quot;). This
+		capability is provided with the intent of allowing such users to
+		install, extend and update Eclipse-based products. Information about
+		packaging Installable Software is available at <a
+			href="http://eclipse.org/equinox/p2/repository_packaging.html">http://eclipse.org/equinox/p2/repository_packaging.html</a>
+		(&quot;Specification&quot;).
+	</p>
 
-<p>You may use Provisioning Technology to allow other parties to install Installable Software. You shall be responsible for enabling the
-   applicable license agreements relating to the Installable Software to be presented to, and accepted by, the users of the Provisioning Technology
-   in accordance with the Specification. By using Provisioning Technology in such a manner and making it available in accordance with the
-   Specification, you further acknowledge your agreement to, and the acquisition of all necessary rights to permit the following:</p>
+	<p>You may use Provisioning Technology to allow other parties to
+		install Installable Software. You shall be responsible for enabling
+		the applicable license agreements relating to the Installable Software
+		to be presented to, and accepted by, the users of the Provisioning
+		Technology in accordance with the Specification. By using Provisioning
+		Technology in such a manner and making it available in accordance with
+		the Specification, you further acknowledge your agreement to, and the
+		acquisition of all necessary rights to permit the following:</p>
 
-<ol>
-       <li>A series of actions may occur ("Provisioning Process") in which a user may execute the Provisioning Technology
-       on a machine ("Target Machine") with the intent of installing, extending or updating the functionality of an Eclipse-based
-       product.</li>
-       <li>During the Provisioning Process, the Provisioning Technology may cause third party Installable Software or a portion thereof to be
-       accessed and copied to the Target Machine.</li>
-       <li>Pursuant to the Specification, you will provide to the user the terms and conditions that govern the use of the Installable
-       Software ("Installable Software Agreement") and such Installable Software Agreement shall be accessed from the Target
-       Machine in accordance with the Specification. Such Installable Software Agreement must inform the user of the terms and conditions that govern
-       the Installable Software and must solicit acceptance by the end user in the manner prescribed in such Installable Software Agreement. Upon such
-       indication of agreement by the user, the provisioning Technology will complete installation of the Installable Software.</li>
-</ol>
+	<ol>
+		<li>A series of actions may occur (&quot;Provisioning
+			Process&quot;) in which a user may execute the Provisioning
+			Technology on a machine (&quot;Target Machine&quot;) with the intent
+			of installing, extending or updating the functionality of an
+			Eclipse-based product.</li>
+		<li>During the Provisioning Process, the Provisioning Technology
+			may cause third party Installable Software or a portion thereof to be
+			accessed and copied to the Target Machine.</li>
+		<li>Pursuant to the Specification, you will provide to the user
+			the terms and conditions that govern the use of the Installable
+			Software (&quot;Installable Software Agreement&quot;) and such
+			Installable Software Agreement shall be accessed from the Target
+			Machine in accordance with the Specification. Such Installable
+			Software Agreement must inform the user of the terms and conditions
+			that govern the Installable Software and must solicit acceptance by
+			the end user in the manner prescribed in such Installable Software
+			Agreement. Upon such indication of agreement by the user, the
+			provisioning Technology will complete installation of the Installable
+			Software.</li>
+	</ol>
 
-<h3>Cryptography</h3>
+	<h3>Cryptography</h3>
 
-<p>Content may contain encryption software. The country in which you are currently may have restrictions on the import, possession, and use, and/or re-export to
-   another country, of encryption software. BEFORE using any encryption software, please check the country's laws, regulations and policies concerning the import,
-   possession, or use, and re-export of encryption software, to see if this is permitted.</p>
+	<p>Content may contain encryption software. The country in which
+		you are currently may have restrictions on the import, possession, and
+		use, and/or re-export to another country, of encryption software.
+		BEFORE using any encryption software, please check the country's laws,
+		regulations and policies concerning the import, possession, or use,
+		and re-export of encryption software, to see if this is permitted.</p>
 
-<p><small>Java and all Java-based trademarks are trademarks of Oracle Corporation in the United States, other countries, or both.</small></p>
-
-
-</body></html>
\ No newline at end of file
+	<p>
+		<small>Java and all Java-based trademarks are trademarks of
+			Oracle Corporation in the United States, other countries, or both.</small>
+	</p>
+</body>
+</html>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.lfs.feature/pom.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.lfs.feature/pom.xml
index 7f0c7f5..8c49ebf 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.lfs.feature/pom.xml
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.lfs.feature/pom.xml
@@ -50,7 +50,7 @@
   <parent>
     <groupId>org.eclipse.jgit</groupId>
     <artifactId>jgit.tycho.parent</artifactId>
-    <version>4.9.3-SNAPSHOT</version>
+    <version>5.0.0-SNAPSHOT</version>
   </parent>
 
   <groupId>org.eclipse.jgit.feature</groupId>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.feature/feature.properties b/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.feature/feature.properties
index 8992ad3..ef9031e 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.feature/feature.properties
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.feature/feature.properties
@@ -35,125 +35,143 @@
 # should be plain text version of license agreement pointed to be "licenseURL"
 license=\
 Eclipse Foundation Software User Agreement\n\
-April 9, 2014\n\
+\n\
+November 22, 2017\n\
 \n\
 Usage Of Content\n\
 \n\
-THE ECLIPSE FOUNDATION MAKES AVAILABLE SOFTWARE, DOCUMENTATION, INFORMATION AND/OR\n\
-OTHER MATERIALS FOR OPEN SOURCE PROJECTS (COLLECTIVELY "CONTENT").\n\
-USE OF THE CONTENT IS GOVERNED BY THE TERMS AND CONDITIONS OF THIS\n\
-AGREEMENT AND/OR THE TERMS AND CONDITIONS OF LICENSE AGREEMENTS OR\n\
-NOTICES INDICATED OR REFERENCED BELOW.  BY USING THE CONTENT, YOU\n\
-AGREE THAT YOUR USE OF THE CONTENT IS GOVERNED BY THIS AGREEMENT\n\
-AND/OR THE TERMS AND CONDITIONS OF ANY APPLICABLE LICENSE AGREEMENTS\n\
-OR NOTICES INDICATED OR REFERENCED BELOW.  IF YOU DO NOT AGREE TO THE\n\
-TERMS AND CONDITIONS OF THIS AGREEMENT AND THE TERMS AND CONDITIONS\n\
-OF ANY APPLICABLE LICENSE AGREEMENTS OR NOTICES INDICATED OR REFERENCED\n\
-BELOW, THEN YOU MAY NOT USE THE CONTENT.\n\
+THE ECLIPSE FOUNDATION MAKES AVAILABLE SOFTWARE, DOCUMENTATION, INFORMATION\n\
+AND/OR OTHER MATERIALS FOR OPEN SOURCE PROJECTS (COLLECTIVELY "CONTENT"). USE OF\n\
+THE CONTENT IS GOVERNED BY THE TERMS AND CONDITIONS OF THIS AGREEMENT AND/OR THE\n\
+TERMS AND CONDITIONS OF LICENSE AGREEMENTS OR NOTICES INDICATED OR REFERENCED\n\
+BELOW. BY USING THE CONTENT, YOU AGREE THAT YOUR USE OF THE CONTENT IS GOVERNED\n\
+BY THIS AGREEMENT AND/OR THE TERMS AND CONDITIONS OF ANY APPLICABLE LICENSE\n\
+AGREEMENTS OR NOTICES INDICATED OR REFERENCED BELOW. IF YOU DO NOT AGREE TO THE\n\
+TERMS AND CONDITIONS OF THIS AGREEMENT AND THE TERMS AND CONDITIONS OF ANY\n\
+APPLICABLE LICENSE AGREEMENTS OR NOTICES INDICATED OR REFERENCED BELOW, THEN YOU\n\
+MAY NOT USE THE CONTENT.\n\
 \n\
 Applicable Licenses\n\
 \n\
-Unless otherwise indicated, all Content made available by the\n\
-Eclipse Foundation is provided to you under the terms and conditions of\n\
-the Eclipse Public License Version 1.0 ("EPL"). A copy of the EPL is\n\
-provided with this Content and is also available at http://www.eclipse.org/legal/epl-v10.html.\n\
-For purposes of the EPL, "Program" will mean the Content.\n\
+Unless otherwise indicated, all Content made available by the Eclipse Foundation\n\
+is provided to you under the terms and conditions of the Eclipse Public License\n\
+Version 2.0 ("EPL"). A copy of the EPL is provided with this Content and is also\n\
+available at http://www.eclipse.org/legal/epl-2.0. For purposes of the EPL,\n\
+"Program" will mean the Content.\n\
 \n\
-Content includes, but is not limited to, source code, object code,\n\
-documentation and other files maintained in the Eclipse Foundation source code\n\
-repository ("Repository") in software modules ("Modules") and made available\n\
-as downloadable archives ("Downloads").\n\
+Content includes, but is not limited to, source code, object code, documentation\n\
+and other files maintained in the Eclipse Foundation source code repository\n\
+("Repository") in software modules ("Modules") and made available as\n\
+downloadable archives ("Downloads").\n\
 \n\
-       - Content may be structured and packaged into modules to facilitate delivering,\n\
-         extending, and upgrading the Content. Typical modules may include plug-ins ("Plug-ins"),\n\
-         plug-in fragments ("Fragments"), and features ("Features").\n\
-       - Each Plug-in or Fragment may be packaged as a sub-directory or JAR (Java(TM) ARchive)\n\
-         in a directory named "plugins".\n\
-       - A Feature is a bundle of one or more Plug-ins and/or Fragments and associated material.\n\
-         Each Feature may be packaged as a sub-directory in a directory named "features".\n\
-         Within a Feature, files named "feature.xml" may contain a list of the names and version\n\
-         numbers of the Plug-ins and/or Fragments associated with that Feature.\n\
-       - Features may also include other Features ("Included Features"). Within a Feature, files\n\
-         named "feature.xml" may contain a list of the names and version numbers of Included Features.\n\
+-   Content may be structured and packaged into modules to facilitate\n\
+    delivering, extending, and upgrading the Content. Typical modules may\n\
+    include plug-ins ("Plug-ins"), plug-in fragments ("Fragments"), and\n\
+    features ("Features").\n\
+-   Each Plug-in or Fragment may be packaged as a sub-directory or JAR\n\
+    (Java™ ARchive) in a directory named "plugins".\n\
+-   A Feature is a bundle of one or more Plug-ins and/or Fragments and\n\
+    associated material. Each Feature may be packaged as a sub-directory in a\n\
+    directory named "features". Within a Feature, files named "feature.xml" may\n\
+    contain a list of the names and version numbers of the Plug-ins and/or\n\
+    Fragments associated with that Feature.\n\
+-   Features may also include other Features ("Included Features"). Within a\n\
+    Feature, files named "feature.xml" may contain a list of the names and\n\
+    version numbers of Included Features.\n\
 \n\
-The terms and conditions governing Plug-ins and Fragments should be\n\
-contained in files named "about.html" ("Abouts"). The terms and\n\
-conditions governing Features and Included Features should be contained\n\
-in files named "license.html" ("Feature Licenses"). Abouts and Feature\n\
-Licenses may be located in any directory of a Download or Module\n\
-including, but not limited to the following locations:\n\
+The terms and conditions governing Plug-ins and Fragments should be contained in\n\
+files named "about.html" ("Abouts"). The terms and conditions governing Features\n\
+and Included Features should be contained in files named "license.html"\n\
+("Feature Licenses"). Abouts and Feature Licenses may be located in any\n\
+directory of a Download or Module including, but not limited to the following\n\
+locations:\n\
 \n\
-       - The top-level (root) directory\n\
-       - Plug-in and Fragment directories\n\
-       - Inside Plug-ins and Fragments packaged as JARs\n\
-       - Sub-directories of the directory named "src" of certain Plug-ins\n\
-       - Feature directories\n\
+-   The top-level (root) directory\n\
+-   Plug-in and Fragment directories\n\
+-   Inside Plug-ins and Fragments packaged as JARs\n\
+-   Sub-directories of the directory named "src" of certain Plug-ins\n\
+-   Feature directories\n\
 \n\
-Note: if a Feature made available by the Eclipse Foundation is installed using the\n\
-Provisioning Technology (as defined below), you must agree to a license ("Feature \n\
-Update License") during the installation process. If the Feature contains\n\
-Included Features, the Feature Update License should either provide you\n\
-with the terms and conditions governing the Included Features or inform\n\
-you where you can locate them. Feature Update Licenses may be found in\n\
-the "license" property of files named "feature.properties" found within a Feature.\n\
-Such Abouts, Feature Licenses, and Feature Update Licenses contain the\n\
-terms and conditions (or references to such terms and conditions) that\n\
-govern your use of the associated Content in that directory.\n\
+Note: if a Feature made available by the Eclipse Foundation is installed using\n\
+the Provisioning Technology (as defined below), you must agree to a license\n\
+("Feature Update License") during the installation process. If the Feature\n\
+contains Included Features, the Feature Update License should either provide you\n\
+with the terms and conditions governing the Included Features or inform you\n\
+where you can locate them. Feature Update Licenses may be found in the "license"\n\
+property of files named "feature.properties" found within a Feature. Such\n\
+Abouts, Feature Licenses, and Feature Update Licenses contain the terms and\n\
+conditions (or references to such terms and conditions) that govern your use of\n\
+the associated Content in that directory.\n\
 \n\
-THE ABOUTS, FEATURE LICENSES, AND FEATURE UPDATE LICENSES MAY REFER\n\
-TO THE EPL OR OTHER LICENSE AGREEMENTS, NOTICES OR TERMS AND CONDITIONS.\n\
-SOME OF THESE OTHER LICENSE AGREEMENTS MAY INCLUDE (BUT ARE NOT LIMITED TO):\n\
+THE ABOUTS, FEATURE LICENSES, AND FEATURE UPDATE LICENSES MAY REFER TO THE EPL\n\
+OR OTHER LICENSE AGREEMENTS, NOTICES OR TERMS AND CONDITIONS. SOME OF THESE\n\
+OTHER LICENSE AGREEMENTS MAY INCLUDE (BUT ARE NOT LIMITED TO):\n\
 \n\
-       - Eclipse Distribution License Version 1.0 (available at http://www.eclipse.org/licenses/edl-v1.0.html)\n\
-       - Common Public License Version 1.0 (available at http://www.eclipse.org/legal/cpl-v10.html)\n\
-       - Apache Software License 1.1 (available at http://www.apache.org/licenses/LICENSE)\n\
-       - Apache Software License 2.0 (available at http://www.apache.org/licenses/LICENSE-2.0)\n\
-       - Mozilla Public License Version 1.1 (available at http://www.mozilla.org/MPL/MPL-1.1.html)\n\
+-   Eclipse Public License Version 1.0 (available at\n\
+    http://www.eclipse.org/legal/epl-v10.html)\n\
+-   Eclipse Distribution License Version 1.0 (available at\n\
+    http://www.eclipse.org/licenses/edl-v1.0.html)\n\
+-   Common Public License Version 1.0 (available at\n\
+    http://www.eclipse.org/legal/cpl-v10.html)\n\
+-   Apache Software License 1.1 (available at\n\
+    http://www.apache.org/licenses/LICENSE)\n\
+-   Apache Software License 2.0 (available at\n\
+    http://www.apache.org/licenses/LICENSE-2.0)\n\
+-   Mozilla Public License Version 1.1 (available at\n\
+    http://www.mozilla.org/MPL/MPL-1.1.html)\n\
 \n\
-IT IS YOUR OBLIGATION TO READ AND ACCEPT ALL SUCH TERMS AND CONDITIONS PRIOR\n\
-TO USE OF THE CONTENT. If no About, Feature License, or Feature Update License\n\
-is provided, please contact the Eclipse Foundation to determine what terms and conditions\n\
-govern that particular Content.\n\
+IT IS YOUR OBLIGATION TO READ AND ACCEPT ALL SUCH TERMS AND CONDITIONS PRIOR TO\n\
+USE OF THE CONTENT. If no About, Feature License, or Feature Update License is\n\
+provided, please contact the Eclipse Foundation to determine what terms and\n\
+conditions govern that particular Content.\n\
 \n\
-\n\Use of Provisioning Technology\n\
+Use of Provisioning Technology\n\
 \n\
-The Eclipse Foundation makes available provisioning software, examples of which include,\n\
-but are not limited to, p2 and the Eclipse Update Manager ("Provisioning Technology") for\n\
-the purpose of allowing users to install software, documentation, information and/or\n\
-other materials (collectively "Installable Software"). This capability is provided with\n\
-the intent of allowing such users to install, extend and update Eclipse-based products.\n\
-Information about packaging Installable Software is available at\n\
+The Eclipse Foundation makes available provisioning software, examples of which\n\
+include, but are not limited to, p2 and the Eclipse Update Manager\n\
+("Provisioning Technology") for the purpose of allowing users to install\n\
+software, documentation, information and/or other materials (collectively\n\
+"Installable Software"). This capability is provided with the intent of allowing\n\
+such users to install, extend and update Eclipse-based products. Information\n\
+about packaging Installable Software is available at\n\
 http://eclipse.org/equinox/p2/repository_packaging.html ("Specification").\n\
 \n\
-You may use Provisioning Technology to allow other parties to install Installable Software.\n\
-You shall be responsible for enabling the applicable license agreements relating to the\n\
-Installable Software to be presented to, and accepted by, the users of the Provisioning Technology\n\
-in accordance with the Specification. By using Provisioning Technology in such a manner and\n\
-making it available in accordance with the Specification, you further acknowledge your\n\
-agreement to, and the acquisition of all necessary rights to permit the following:\n\
+You may use Provisioning Technology to allow other parties to install\n\
+Installable Software. You shall be responsible for enabling the applicable\n\
+license agreements relating to the Installable Software to be presented to, and\n\
+accepted by, the users of the Provisioning Technology in accordance with the\n\
+Specification. By using Provisioning Technology in such a manner and making it\n\
+available in accordance with the Specification, you further acknowledge your\n\
+agreement to, and the acquisition of all necessary rights to permit the\n\
+following:\n\
 \n\
-       1. A series of actions may occur ("Provisioning Process") in which a user may execute\n\
-          the Provisioning Technology on a machine ("Target Machine") with the intent of installing,\n\
-          extending or updating the functionality of an Eclipse-based product.\n\
-       2. During the Provisioning Process, the Provisioning Technology may cause third party\n\
-          Installable Software or a portion thereof to be accessed and copied to the Target Machine.\n\
-       3. Pursuant to the Specification, you will provide to the user the terms and conditions that\n\
-          govern the use of the Installable Software ("Installable Software Agreement") and such\n\
-          Installable Software Agreement shall be accessed from the Target Machine in accordance\n\
-          with the Specification. Such Installable Software Agreement must inform the user of the\n\
-          terms and conditions that govern the Installable Software and must solicit acceptance by\n\
-          the end user in the manner prescribed in such Installable Software Agreement. Upon such\n\
-          indication of agreement by the user, the provisioning Technology will complete installation\n\
-          of the Installable Software.\n\
+1.  A series of actions may occur ("Provisioning Process") in which a user may\n\
+    execute the Provisioning Technology on a machine ("Target Machine") with the\n\
+    intent of installing, extending or updating the functionality of an\n\
+    Eclipse-based product.\n\
+2.  During the Provisioning Process, the Provisioning Technology may cause third\n\
+    party Installable Software or a portion thereof to be accessed and copied to\n\
+    the Target Machine.\n\
+3.  Pursuant to the Specification, you will provide to the user the terms and\n\
+    conditions that govern the use of the Installable Software ("Installable\n\
+    Software Agreement") and such Installable Software Agreement shall be\n\
+    accessed from the Target Machine in accordance with the Specification. Such\n\
+    Installable Software Agreement must inform the user of the terms and\n\
+    conditions that govern the Installable Software and must solicit acceptance\n\
+    by the end user in the manner prescribed in such Installable\n\
+    Software Agreement. Upon such indication of agreement by the user, the\n\
+    provisioning Technology will complete installation of the\n\
+    Installable Software.\n\
 \n\
 Cryptography\n\
 \n\
-Content may contain encryption software. The country in which you are\n\
-currently may have restrictions on the import, possession, and use,\n\
-and/or re-export to another country, of encryption software. BEFORE\n\
-using any encryption software, please check the country's laws,\n\
-regulations and policies concerning the import, possession, or use, and\n\
-re-export of encryption software, to see if this is permitted.\n\
+Content may contain encryption software. The country in which you are currently\n\
+may have restrictions on the import, possession, and use, and/or re-export to\n\
+another country, of encryption software. BEFORE using any encryption software,\n\
+please check the country's laws, regulations and policies concerning the import,\n\
+possession, or use, and re-export of encryption software, to see if this is\n\
+permitted.\n\
 \n\
-Java and all Java-based trademarks are trademarks of Oracle Corporation in the United States, other countries, or both.\n
-########### end of license property ##########################################
\ No newline at end of file
+Java and all Java-based trademarks are trademarks of Oracle Corporation in the\n\
+United States, other countries, or both.\n
+########### end of license property ##########################################
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.feature/feature.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.feature/feature.xml
index ecfe96a..f1a8101 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.feature/feature.xml
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.feature/feature.xml
@@ -2,7 +2,7 @@
 <feature
       id="org.eclipse.jgit.pgm"
       label="%featureName"
-      version="4.9.3.qualifier"
+      version="5.0.0.qualifier"
       provider-name="%providerName">
 
    <description url="http://www.eclipse.org/jgit/">
@@ -31,8 +31,8 @@
          version="0.0.0"/>
 
    <requires>
-      <import feature="org.eclipse.jgit" version="4.9.3" match="equivalent"/>
-      <import feature="org.eclipse.jgit.lfs" version="4.9.3" match="equivalent"/>
+      <import feature="org.eclipse.jgit" version="5.0.0" match="equivalent"/>
+      <import feature="org.eclipse.jgit.lfs" version="5.0.0" match="equivalent"/>
    </requires>
 
    <plugin
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.feature/license.html b/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.feature/license.html
index 95ad95e..008b801 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.feature/license.html
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.feature/license.html
@@ -1,106 +1,189 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-<!-- saved from url=(0044)http://www.eclipse.org/legal/epl/notice.html -->
-<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
-
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
 <title>Eclipse Foundation Software User Agreement</title>
 </head>
 
 <body lang="EN-US">
-<h2>Eclipse Foundation Software User Agreement</h2>
-<p>April 9, 2014</p>
+	<h2>Eclipse Foundation Software User Agreement</h2>
+	<p>November 22, 2017</p>
 
-<h3>Usage Of Content</h3>
+	<h3>Usage Of Content</h3>
 
-<p>THE ECLIPSE FOUNDATION MAKES AVAILABLE SOFTWARE, DOCUMENTATION, INFORMATION AND/OR OTHER MATERIALS FOR OPEN SOURCE PROJECTS
-   (COLLECTIVELY "CONTENT").  USE OF THE CONTENT IS GOVERNED BY THE TERMS AND CONDITIONS OF THIS AGREEMENT AND/OR THE TERMS AND
-   CONDITIONS OF LICENSE AGREEMENTS OR NOTICES INDICATED OR REFERENCED BELOW.  BY USING THE CONTENT, YOU AGREE THAT YOUR USE
-   OF THE CONTENT IS GOVERNED BY THIS AGREEMENT AND/OR THE TERMS AND CONDITIONS OF ANY APPLICABLE LICENSE AGREEMENTS OR
-   NOTICES INDICATED OR REFERENCED BELOW.  IF YOU DO NOT AGREE TO THE TERMS AND CONDITIONS OF THIS AGREEMENT AND THE TERMS AND
-   CONDITIONS OF ANY APPLICABLE LICENSE AGREEMENTS OR NOTICES INDICATED OR REFERENCED BELOW, THEN YOU MAY NOT USE THE CONTENT.</p>
+	<p>THE ECLIPSE FOUNDATION MAKES AVAILABLE SOFTWARE, DOCUMENTATION,
+		INFORMATION AND/OR OTHER MATERIALS FOR OPEN SOURCE PROJECTS
+		(COLLECTIVELY &quot;CONTENT&quot;). USE OF THE CONTENT IS GOVERNED BY
+		THE TERMS AND CONDITIONS OF THIS AGREEMENT AND/OR THE TERMS AND
+		CONDITIONS OF LICENSE AGREEMENTS OR NOTICES INDICATED OR REFERENCED
+		BELOW. BY USING THE CONTENT, YOU AGREE THAT YOUR USE OF THE CONTENT IS
+		GOVERNED BY THIS AGREEMENT AND/OR THE TERMS AND CONDITIONS OF ANY
+		APPLICABLE LICENSE AGREEMENTS OR NOTICES INDICATED OR REFERENCED
+		BELOW. IF YOU DO NOT AGREE TO THE TERMS AND CONDITIONS OF THIS
+		AGREEMENT AND THE TERMS AND CONDITIONS OF ANY APPLICABLE LICENSE
+		AGREEMENTS OR NOTICES INDICATED OR REFERENCED BELOW, THEN YOU MAY NOT
+		USE THE CONTENT.</p>
 
-<h3>Applicable Licenses</h3>
+	<h3>Applicable Licenses</h3>
 
-<p>Unless otherwise indicated, all Content made available by the Eclipse Foundation is provided to you under the terms and conditions of the Eclipse Public License Version 1.0
-   ("EPL").  A copy of the EPL is provided with this Content and is also available at <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a>.
-   For purposes of the EPL, "Program" will mean the Content.</p>
+	<p>
+		Unless otherwise indicated, all Content made available by the Eclipse
+		Foundation is provided to you under the terms and conditions of the
+		Eclipse Public License Version 2.0 (&quot;EPL&quot;). A copy of the
+		EPL is provided with this Content and is also available at <a
+			href="http://www.eclipse.org/legal/epl-2.0">http://www.eclipse.org/legal/epl-2.0</a>.
+		For purposes of the EPL, &quot;Program&quot; will mean the Content.
+	</p>
 
-<p>Content includes, but is not limited to, source code, object code, documentation and other files maintained in the Eclipse Foundation source code
-   repository ("Repository") in software modules ("Modules") and made available as downloadable archives ("Downloads").</p>
+	<p>Content includes, but is not limited to, source code, object
+		code, documentation and other files maintained in the Eclipse
+		Foundation source code repository (&quot;Repository&quot;) in software
+		modules (&quot;Modules&quot;) and made available as downloadable
+		archives (&quot;Downloads&quot;).</p>
 
-<ul>
-       <li>Content may be structured and packaged into modules to facilitate delivering, extending, and upgrading the Content.  Typical modules may include plug-ins ("Plug-ins"), plug-in fragments ("Fragments"), and features ("Features").</li>
-       <li>Each Plug-in or Fragment may be packaged as a sub-directory or JAR (Java™ ARchive) in a directory named "plugins".</li>
-       <li>A Feature is a bundle of one or more Plug-ins and/or Fragments and associated material.  Each Feature may be packaged as a sub-directory in a directory named "features".  Within a Feature, files named "feature.xml" may contain a list of the names and version numbers of the Plug-ins
-      and/or Fragments associated with that Feature.</li>
-       <li>Features may also include other Features ("Included Features"). Within a Feature, files named "feature.xml" may contain a list of the names and version numbers of Included Features.</li>
-</ul>
+	<ul>
+		<li>Content may be structured and packaged into modules to
+			facilitate delivering, extending, and upgrading the Content. Typical
+			modules may include plug-ins (&quot;Plug-ins&quot;), plug-in
+			fragments (&quot;Fragments&quot;), and features
+			(&quot;Features&quot;).</li>
+		<li>Each Plug-in or Fragment may be packaged as a sub-directory
+			or JAR (Java&trade; ARchive) in a directory named
+			&quot;plugins&quot;.</li>
+		<li>A Feature is a bundle of one or more Plug-ins and/or
+			Fragments and associated material. Each Feature may be packaged as a
+			sub-directory in a directory named &quot;features&quot;. Within a
+			Feature, files named &quot;feature.xml&quot; may contain a list of
+			the names and version numbers of the Plug-ins and/or Fragments
+			associated with that Feature.</li>
+		<li>Features may also include other Features (&quot;Included
+			Features&quot;). Within a Feature, files named
+			&quot;feature.xml&quot; may contain a list of the names and version
+			numbers of Included Features.</li>
+	</ul>
 
-<p>The terms and conditions governing Plug-ins and Fragments should be contained in files named "about.html" ("Abouts"). The terms and conditions governing Features and
-Included Features should be contained in files named "license.html" ("Feature Licenses").  Abouts and Feature Licenses may be located in any directory of a Download or Module
-including, but not limited to the following locations:</p>
+	<p>The terms and conditions governing Plug-ins and Fragments should
+		be contained in files named &quot;about.html&quot;
+		(&quot;Abouts&quot;). The terms and conditions governing Features and
+		Included Features should be contained in files named
+		&quot;license.html&quot; (&quot;Feature Licenses&quot;). Abouts and
+		Feature Licenses may be located in any directory of a Download or
+		Module including, but not limited to the following locations:</p>
 
-<ul>
-       <li>The top-level (root) directory</li>
-       <li>Plug-in and Fragment directories</li>
-       <li>Inside Plug-ins and Fragments packaged as JARs</li>
-       <li>Sub-directories of the directory named "src" of certain Plug-ins</li>
-       <li>Feature directories</li>
-</ul>
+	<ul>
+		<li>The top-level (root) directory</li>
+		<li>Plug-in and Fragment directories</li>
+		<li>Inside Plug-ins and Fragments packaged as JARs</li>
+		<li>Sub-directories of the directory named &quot;src&quot; of
+			certain Plug-ins</li>
+		<li>Feature directories</li>
+	</ul>
 
-<p>Note: if a Feature made available by the Eclipse Foundation is installed using the Provisioning Technology (as defined below), you must agree to a license ("Feature Update License") during the
-installation process.  If the Feature contains Included Features, the Feature Update License should either provide you with the terms and conditions governing the Included Features or
-inform you where you can locate them.  Feature Update Licenses may be found in the "license" property of files named "feature.properties" found within a Feature.
-Such Abouts, Feature Licenses, and Feature Update Licenses contain the terms and conditions (or references to such terms and conditions) that govern your use of the associated Content in
-that directory.</p>
+	<p>Note: if a Feature made available by the Eclipse Foundation is
+		installed using the Provisioning Technology (as defined below), you
+		must agree to a license (&quot;Feature Update License&quot;) during
+		the installation process. If the Feature contains Included Features,
+		the Feature Update License should either provide you with the terms
+		and conditions governing the Included Features or inform you where you
+		can locate them. Feature Update Licenses may be found in the
+		&quot;license&quot; property of files named
+		&quot;feature.properties&quot; found within a Feature. Such Abouts,
+		Feature Licenses, and Feature Update Licenses contain the terms and
+		conditions (or references to such terms and conditions) that govern
+		your use of the associated Content in that directory.</p>
 
-<p>THE ABOUTS, FEATURE LICENSES, AND FEATURE UPDATE LICENSES MAY REFER TO THE EPL OR OTHER LICENSE AGREEMENTS, NOTICES OR TERMS AND CONDITIONS.  SOME OF THESE
-OTHER LICENSE AGREEMENTS MAY INCLUDE (BUT ARE NOT LIMITED TO):</p>
+	<p>THE ABOUTS, FEATURE LICENSES, AND FEATURE UPDATE LICENSES MAY
+		REFER TO THE EPL OR OTHER LICENSE AGREEMENTS, NOTICES OR TERMS AND
+		CONDITIONS. SOME OF THESE OTHER LICENSE AGREEMENTS MAY INCLUDE (BUT
+		ARE NOT LIMITED TO):</p>
 
-<ul>
-       <li>Eclipse Distribution License Version 1.0 (available at <a href="http://www.eclipse.org/licenses/edl-v10.html">http://www.eclipse.org/licenses/edl-v1.0.html</a>)</li>
-       <li>Common Public License Version 1.0 (available at <a href="http://www.eclipse.org/legal/cpl-v10.html">http://www.eclipse.org/legal/cpl-v10.html</a>)</li>
-       <li>Apache Software License 1.1 (available at <a href="http://www.apache.org/licenses/LICENSE">http://www.apache.org/licenses/LICENSE</a>)</li>
-       <li>Apache Software License 2.0 (available at <a href="http://www.apache.org/licenses/LICENSE-2.0">http://www.apache.org/licenses/LICENSE-2.0</a>)</li>
-       <li>Mozilla Public License Version 1.1 (available at <a href="http://www.mozilla.org/MPL/MPL-1.1.html">http://www.mozilla.org/MPL/MPL-1.1.html</a>)</li>
-</ul>
+	<ul>
+		<li>Eclipse Public License Version 1.0 (available at <a
+			href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a>)
+		</li>
+		<li>Eclipse Distribution License Version 1.0 (available at <a
+			href="http://www.eclipse.org/licenses/edl-v10.html">http://www.eclipse.org/licenses/edl-v1.0.html</a>)
+		</li>
+		<li>Common Public License Version 1.0 (available at <a
+			href="http://www.eclipse.org/legal/cpl-v10.html">http://www.eclipse.org/legal/cpl-v10.html</a>)
+		</li>
+		<li>Apache Software License 1.1 (available at <a
+			href="http://www.apache.org/licenses/LICENSE">http://www.apache.org/licenses/LICENSE</a>)
+		</li>
+		<li>Apache Software License 2.0 (available at <a
+			href="http://www.apache.org/licenses/LICENSE-2.0">http://www.apache.org/licenses/LICENSE-2.0</a>)
+		</li>
+		<li>Mozilla Public License Version 1.1 (available at <a
+			href="http://www.mozilla.org/MPL/MPL-1.1.html">http://www.mozilla.org/MPL/MPL-1.1.html</a>)
+		</li>
+	</ul>
 
-<p>IT IS YOUR OBLIGATION TO READ AND ACCEPT ALL SUCH TERMS AND CONDITIONS PRIOR TO USE OF THE CONTENT.  If no About, Feature License, or Feature Update License is provided, please
-contact the Eclipse Foundation to determine what terms and conditions govern that particular Content.</p>
+	<p>IT IS YOUR OBLIGATION TO READ AND ACCEPT ALL SUCH TERMS AND
+		CONDITIONS PRIOR TO USE OF THE CONTENT. If no About, Feature License,
+		or Feature Update License is provided, please contact the Eclipse
+		Foundation to determine what terms and conditions govern that
+		particular Content.</p>
 
 
-<h3>Use of Provisioning Technology</h3>
+	<h3>Use of Provisioning Technology</h3>
 
-<p>The Eclipse Foundation makes available provisioning software, examples of which include, but are not limited to, p2 and the Eclipse
-   Update Manager ("Provisioning Technology") for the purpose of allowing users to install software, documentation, information and/or
-   other materials (collectively "Installable Software"). This capability is provided with the intent of allowing such users to
-   install, extend and update Eclipse-based products. Information about packaging Installable Software is available at <a href="http://eclipse.org/equinox/p2/repository_packaging.html">http://eclipse.org/equinox/p2/repository_packaging.html</a>
-   ("Specification").</p>
+	<p>
+		The Eclipse Foundation makes available provisioning software, examples
+		of which include, but are not limited to, p2 and the Eclipse Update
+		Manager (&quot;Provisioning Technology&quot;) for the purpose of
+		allowing users to install software, documentation, information and/or
+		other materials (collectively &quot;Installable Software&quot;). This
+		capability is provided with the intent of allowing such users to
+		install, extend and update Eclipse-based products. Information about
+		packaging Installable Software is available at <a
+			href="http://eclipse.org/equinox/p2/repository_packaging.html">http://eclipse.org/equinox/p2/repository_packaging.html</a>
+		(&quot;Specification&quot;).
+	</p>
 
-<p>You may use Provisioning Technology to allow other parties to install Installable Software. You shall be responsible for enabling the
-   applicable license agreements relating to the Installable Software to be presented to, and accepted by, the users of the Provisioning Technology
-   in accordance with the Specification. By using Provisioning Technology in such a manner and making it available in accordance with the
-   Specification, you further acknowledge your agreement to, and the acquisition of all necessary rights to permit the following:</p>
+	<p>You may use Provisioning Technology to allow other parties to
+		install Installable Software. You shall be responsible for enabling
+		the applicable license agreements relating to the Installable Software
+		to be presented to, and accepted by, the users of the Provisioning
+		Technology in accordance with the Specification. By using Provisioning
+		Technology in such a manner and making it available in accordance with
+		the Specification, you further acknowledge your agreement to, and the
+		acquisition of all necessary rights to permit the following:</p>
 
-<ol>
-       <li>A series of actions may occur ("Provisioning Process") in which a user may execute the Provisioning Technology
-       on a machine ("Target Machine") with the intent of installing, extending or updating the functionality of an Eclipse-based
-       product.</li>
-       <li>During the Provisioning Process, the Provisioning Technology may cause third party Installable Software or a portion thereof to be
-       accessed and copied to the Target Machine.</li>
-       <li>Pursuant to the Specification, you will provide to the user the terms and conditions that govern the use of the Installable
-       Software ("Installable Software Agreement") and such Installable Software Agreement shall be accessed from the Target
-       Machine in accordance with the Specification. Such Installable Software Agreement must inform the user of the terms and conditions that govern
-       the Installable Software and must solicit acceptance by the end user in the manner prescribed in such Installable Software Agreement. Upon such
-       indication of agreement by the user, the provisioning Technology will complete installation of the Installable Software.</li>
-</ol>
+	<ol>
+		<li>A series of actions may occur (&quot;Provisioning
+			Process&quot;) in which a user may execute the Provisioning
+			Technology on a machine (&quot;Target Machine&quot;) with the intent
+			of installing, extending or updating the functionality of an
+			Eclipse-based product.</li>
+		<li>During the Provisioning Process, the Provisioning Technology
+			may cause third party Installable Software or a portion thereof to be
+			accessed and copied to the Target Machine.</li>
+		<li>Pursuant to the Specification, you will provide to the user
+			the terms and conditions that govern the use of the Installable
+			Software (&quot;Installable Software Agreement&quot;) and such
+			Installable Software Agreement shall be accessed from the Target
+			Machine in accordance with the Specification. Such Installable
+			Software Agreement must inform the user of the terms and conditions
+			that govern the Installable Software and must solicit acceptance by
+			the end user in the manner prescribed in such Installable Software
+			Agreement. Upon such indication of agreement by the user, the
+			provisioning Technology will complete installation of the Installable
+			Software.</li>
+	</ol>
 
-<h3>Cryptography</h3>
+	<h3>Cryptography</h3>
 
-<p>Content may contain encryption software. The country in which you are currently may have restrictions on the import, possession, and use, and/or re-export to
-   another country, of encryption software. BEFORE using any encryption software, please check the country's laws, regulations and policies concerning the import,
-   possession, or use, and re-export of encryption software, to see if this is permitted.</p>
+	<p>Content may contain encryption software. The country in which
+		you are currently may have restrictions on the import, possession, and
+		use, and/or re-export to another country, of encryption software.
+		BEFORE using any encryption software, please check the country's laws,
+		regulations and policies concerning the import, possession, or use,
+		and re-export of encryption software, to see if this is permitted.</p>
 
-<p><small>Java and all Java-based trademarks are trademarks of Oracle Corporation in the United States, other countries, or both.</small></p>
-
-
-</body></html>
\ No newline at end of file
+	<p>
+		<small>Java and all Java-based trademarks are trademarks of
+			Oracle Corporation in the United States, other countries, or both.</small>
+	</p>
+</body>
+</html>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.feature/pom.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.feature/pom.xml
index 89b5f01..c81ed79 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.feature/pom.xml
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.feature/pom.xml
@@ -50,7 +50,7 @@
   <parent>
     <groupId>org.eclipse.jgit</groupId>
     <artifactId>jgit.tycho.parent</artifactId>
-    <version>4.9.3-SNAPSHOT</version>
+    <version>5.0.0-SNAPSHOT</version>
   </parent>
 
   <groupId>org.eclipse.jgit.feature</groupId>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.source.feature/feature.properties b/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.source.feature/feature.properties
index 012c217..73701b2 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.source.feature/feature.properties
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.source.feature/feature.properties
@@ -16,7 +16,7 @@
 # description property - text of the "Feature Description"
 description=\
 Do not install in your IDE: this feature is meant to provision Target Platforms.\n\
-Source code for the support for PDE's JUnit runner for a Target Platform\n\
+Source code for the support for PDE's JUnit runner for a Target Platform\n
 ################ end of description property ##################################
 
 # "copyright" property - text of the "Feature Update Copyright"
@@ -36,125 +36,143 @@
 # should be plain text version of license agreement pointed to be "licenseURL"
 license=\
 Eclipse Foundation Software User Agreement\n\
-April 9, 2014\n\
+\n\
+November 22, 2017\n\
 \n\
 Usage Of Content\n\
 \n\
-THE ECLIPSE FOUNDATION MAKES AVAILABLE SOFTWARE, DOCUMENTATION, INFORMATION AND/OR\n\
-OTHER MATERIALS FOR OPEN SOURCE PROJECTS (COLLECTIVELY "CONTENT").\n\
-USE OF THE CONTENT IS GOVERNED BY THE TERMS AND CONDITIONS OF THIS\n\
-AGREEMENT AND/OR THE TERMS AND CONDITIONS OF LICENSE AGREEMENTS OR\n\
-NOTICES INDICATED OR REFERENCED BELOW.  BY USING THE CONTENT, YOU\n\
-AGREE THAT YOUR USE OF THE CONTENT IS GOVERNED BY THIS AGREEMENT\n\
-AND/OR THE TERMS AND CONDITIONS OF ANY APPLICABLE LICENSE AGREEMENTS\n\
-OR NOTICES INDICATED OR REFERENCED BELOW.  IF YOU DO NOT AGREE TO THE\n\
-TERMS AND CONDITIONS OF THIS AGREEMENT AND THE TERMS AND CONDITIONS\n\
-OF ANY APPLICABLE LICENSE AGREEMENTS OR NOTICES INDICATED OR REFERENCED\n\
-BELOW, THEN YOU MAY NOT USE THE CONTENT.\n\
+THE ECLIPSE FOUNDATION MAKES AVAILABLE SOFTWARE, DOCUMENTATION, INFORMATION\n\
+AND/OR OTHER MATERIALS FOR OPEN SOURCE PROJECTS (COLLECTIVELY "CONTENT"). USE OF\n\
+THE CONTENT IS GOVERNED BY THE TERMS AND CONDITIONS OF THIS AGREEMENT AND/OR THE\n\
+TERMS AND CONDITIONS OF LICENSE AGREEMENTS OR NOTICES INDICATED OR REFERENCED\n\
+BELOW. BY USING THE CONTENT, YOU AGREE THAT YOUR USE OF THE CONTENT IS GOVERNED\n\
+BY THIS AGREEMENT AND/OR THE TERMS AND CONDITIONS OF ANY APPLICABLE LICENSE\n\
+AGREEMENTS OR NOTICES INDICATED OR REFERENCED BELOW. IF YOU DO NOT AGREE TO THE\n\
+TERMS AND CONDITIONS OF THIS AGREEMENT AND THE TERMS AND CONDITIONS OF ANY\n\
+APPLICABLE LICENSE AGREEMENTS OR NOTICES INDICATED OR REFERENCED BELOW, THEN YOU\n\
+MAY NOT USE THE CONTENT.\n\
 \n\
 Applicable Licenses\n\
 \n\
-Unless otherwise indicated, all Content made available by the\n\
-Eclipse Foundation is provided to you under the terms and conditions of\n\
-the Eclipse Public License Version 1.0 ("EPL"). A copy of the EPL is\n\
-provided with this Content and is also available at http://www.eclipse.org/legal/epl-v10.html.\n\
-For purposes of the EPL, "Program" will mean the Content.\n\
+Unless otherwise indicated, all Content made available by the Eclipse Foundation\n\
+is provided to you under the terms and conditions of the Eclipse Public License\n\
+Version 2.0 ("EPL"). A copy of the EPL is provided with this Content and is also\n\
+available at http://www.eclipse.org/legal/epl-2.0. For purposes of the EPL,\n\
+"Program" will mean the Content.\n\
 \n\
-Content includes, but is not limited to, source code, object code,\n\
-documentation and other files maintained in the Eclipse Foundation source code\n\
-repository ("Repository") in software modules ("Modules") and made available\n\
-as downloadable archives ("Downloads").\n\
+Content includes, but is not limited to, source code, object code, documentation\n\
+and other files maintained in the Eclipse Foundation source code repository\n\
+("Repository") in software modules ("Modules") and made available as\n\
+downloadable archives ("Downloads").\n\
 \n\
-       - Content may be structured and packaged into modules to facilitate delivering,\n\
-         extending, and upgrading the Content. Typical modules may include plug-ins ("Plug-ins"),\n\
-         plug-in fragments ("Fragments"), and features ("Features").\n\
-       - Each Plug-in or Fragment may be packaged as a sub-directory or JAR (Java(TM) ARchive)\n\
-         in a directory named "plugins".\n\
-       - A Feature is a bundle of one or more Plug-ins and/or Fragments and associated material.\n\
-         Each Feature may be packaged as a sub-directory in a directory named "features".\n\
-         Within a Feature, files named "feature.xml" may contain a list of the names and version\n\
-         numbers of the Plug-ins and/or Fragments associated with that Feature.\n\
-       - Features may also include other Features ("Included Features"). Within a Feature, files\n\
-         named "feature.xml" may contain a list of the names and version numbers of Included Features.\n\
+-   Content may be structured and packaged into modules to facilitate\n\
+    delivering, extending, and upgrading the Content. Typical modules may\n\
+    include plug-ins ("Plug-ins"), plug-in fragments ("Fragments"), and\n\
+    features ("Features").\n\
+-   Each Plug-in or Fragment may be packaged as a sub-directory or JAR\n\
+    (Java™ ARchive) in a directory named "plugins".\n\
+-   A Feature is a bundle of one or more Plug-ins and/or Fragments and\n\
+    associated material. Each Feature may be packaged as a sub-directory in a\n\
+    directory named "features". Within a Feature, files named "feature.xml" may\n\
+    contain a list of the names and version numbers of the Plug-ins and/or\n\
+    Fragments associated with that Feature.\n\
+-   Features may also include other Features ("Included Features"). Within a\n\
+    Feature, files named "feature.xml" may contain a list of the names and\n\
+    version numbers of Included Features.\n\
 \n\
-The terms and conditions governing Plug-ins and Fragments should be\n\
-contained in files named "about.html" ("Abouts"). The terms and\n\
-conditions governing Features and Included Features should be contained\n\
-in files named "license.html" ("Feature Licenses"). Abouts and Feature\n\
-Licenses may be located in any directory of a Download or Module\n\
-including, but not limited to the following locations:\n\
+The terms and conditions governing Plug-ins and Fragments should be contained in\n\
+files named "about.html" ("Abouts"). The terms and conditions governing Features\n\
+and Included Features should be contained in files named "license.html"\n\
+("Feature Licenses"). Abouts and Feature Licenses may be located in any\n\
+directory of a Download or Module including, but not limited to the following\n\
+locations:\n\
 \n\
-       - The top-level (root) directory\n\
-       - Plug-in and Fragment directories\n\
-       - Inside Plug-ins and Fragments packaged as JARs\n\
-       - Sub-directories of the directory named "src" of certain Plug-ins\n\
-       - Feature directories\n\
+-   The top-level (root) directory\n\
+-   Plug-in and Fragment directories\n\
+-   Inside Plug-ins and Fragments packaged as JARs\n\
+-   Sub-directories of the directory named "src" of certain Plug-ins\n\
+-   Feature directories\n\
 \n\
-Note: if a Feature made available by the Eclipse Foundation is installed using the\n\
-Provisioning Technology (as defined below), you must agree to a license ("Feature \n\
-Update License") during the installation process. If the Feature contains\n\
-Included Features, the Feature Update License should either provide you\n\
-with the terms and conditions governing the Included Features or inform\n\
-you where you can locate them. Feature Update Licenses may be found in\n\
-the "license" property of files named "feature.properties" found within a Feature.\n\
-Such Abouts, Feature Licenses, and Feature Update Licenses contain the\n\
-terms and conditions (or references to such terms and conditions) that\n\
-govern your use of the associated Content in that directory.\n\
+Note: if a Feature made available by the Eclipse Foundation is installed using\n\
+the Provisioning Technology (as defined below), you must agree to a license\n\
+("Feature Update License") during the installation process. If the Feature\n\
+contains Included Features, the Feature Update License should either provide you\n\
+with the terms and conditions governing the Included Features or inform you\n\
+where you can locate them. Feature Update Licenses may be found in the "license"\n\
+property of files named "feature.properties" found within a Feature. Such\n\
+Abouts, Feature Licenses, and Feature Update Licenses contain the terms and\n\
+conditions (or references to such terms and conditions) that govern your use of\n\
+the associated Content in that directory.\n\
 \n\
-THE ABOUTS, FEATURE LICENSES, AND FEATURE UPDATE LICENSES MAY REFER\n\
-TO THE EPL OR OTHER LICENSE AGREEMENTS, NOTICES OR TERMS AND CONDITIONS.\n\
-SOME OF THESE OTHER LICENSE AGREEMENTS MAY INCLUDE (BUT ARE NOT LIMITED TO):\n\
+THE ABOUTS, FEATURE LICENSES, AND FEATURE UPDATE LICENSES MAY REFER TO THE EPL\n\
+OR OTHER LICENSE AGREEMENTS, NOTICES OR TERMS AND CONDITIONS. SOME OF THESE\n\
+OTHER LICENSE AGREEMENTS MAY INCLUDE (BUT ARE NOT LIMITED TO):\n\
 \n\
-       - Eclipse Distribution License Version 1.0 (available at http://www.eclipse.org/licenses/edl-v1.0.html)\n\
-       - Common Public License Version 1.0 (available at http://www.eclipse.org/legal/cpl-v10.html)\n\
-       - Apache Software License 1.1 (available at http://www.apache.org/licenses/LICENSE)\n\
-       - Apache Software License 2.0 (available at http://www.apache.org/licenses/LICENSE-2.0)\n\
-       - Mozilla Public License Version 1.1 (available at http://www.mozilla.org/MPL/MPL-1.1.html)\n\
+-   Eclipse Public License Version 1.0 (available at\n\
+    http://www.eclipse.org/legal/epl-v10.html)\n\
+-   Eclipse Distribution License Version 1.0 (available at\n\
+    http://www.eclipse.org/licenses/edl-v1.0.html)\n\
+-   Common Public License Version 1.0 (available at\n\
+    http://www.eclipse.org/legal/cpl-v10.html)\n\
+-   Apache Software License 1.1 (available at\n\
+    http://www.apache.org/licenses/LICENSE)\n\
+-   Apache Software License 2.0 (available at\n\
+    http://www.apache.org/licenses/LICENSE-2.0)\n\
+-   Mozilla Public License Version 1.1 (available at\n\
+    http://www.mozilla.org/MPL/MPL-1.1.html)\n\
 \n\
-IT IS YOUR OBLIGATION TO READ AND ACCEPT ALL SUCH TERMS AND CONDITIONS PRIOR\n\
-TO USE OF THE CONTENT. If no About, Feature License, or Feature Update License\n\
-is provided, please contact the Eclipse Foundation to determine what terms and conditions\n\
-govern that particular Content.\n\
+IT IS YOUR OBLIGATION TO READ AND ACCEPT ALL SUCH TERMS AND CONDITIONS PRIOR TO\n\
+USE OF THE CONTENT. If no About, Feature License, or Feature Update License is\n\
+provided, please contact the Eclipse Foundation to determine what terms and\n\
+conditions govern that particular Content.\n\
 \n\
-\n\Use of Provisioning Technology\n\
+Use of Provisioning Technology\n\
 \n\
-The Eclipse Foundation makes available provisioning software, examples of which include,\n\
-but are not limited to, p2 and the Eclipse Update Manager ("Provisioning Technology") for\n\
-the purpose of allowing users to install software, documentation, information and/or\n\
-other materials (collectively "Installable Software"). This capability is provided with\n\
-the intent of allowing such users to install, extend and update Eclipse-based products.\n\
-Information about packaging Installable Software is available at\n\
+The Eclipse Foundation makes available provisioning software, examples of which\n\
+include, but are not limited to, p2 and the Eclipse Update Manager\n\
+("Provisioning Technology") for the purpose of allowing users to install\n\
+software, documentation, information and/or other materials (collectively\n\
+"Installable Software"). This capability is provided with the intent of allowing\n\
+such users to install, extend and update Eclipse-based products. Information\n\
+about packaging Installable Software is available at\n\
 http://eclipse.org/equinox/p2/repository_packaging.html ("Specification").\n\
 \n\
-You may use Provisioning Technology to allow other parties to install Installable Software.\n\
-You shall be responsible for enabling the applicable license agreements relating to the\n\
-Installable Software to be presented to, and accepted by, the users of the Provisioning Technology\n\
-in accordance with the Specification. By using Provisioning Technology in such a manner and\n\
-making it available in accordance with the Specification, you further acknowledge your\n\
-agreement to, and the acquisition of all necessary rights to permit the following:\n\
+You may use Provisioning Technology to allow other parties to install\n\
+Installable Software. You shall be responsible for enabling the applicable\n\
+license agreements relating to the Installable Software to be presented to, and\n\
+accepted by, the users of the Provisioning Technology in accordance with the\n\
+Specification. By using Provisioning Technology in such a manner and making it\n\
+available in accordance with the Specification, you further acknowledge your\n\
+agreement to, and the acquisition of all necessary rights to permit the\n\
+following:\n\
 \n\
-       1. A series of actions may occur ("Provisioning Process") in which a user may execute\n\
-          the Provisioning Technology on a machine ("Target Machine") with the intent of installing,\n\
-          extending or updating the functionality of an Eclipse-based product.\n\
-       2. During the Provisioning Process, the Provisioning Technology may cause third party\n\
-          Installable Software or a portion thereof to be accessed and copied to the Target Machine.\n\
-       3. Pursuant to the Specification, you will provide to the user the terms and conditions that\n\
-          govern the use of the Installable Software ("Installable Software Agreement") and such\n\
-          Installable Software Agreement shall be accessed from the Target Machine in accordance\n\
-          with the Specification. Such Installable Software Agreement must inform the user of the\n\
-          terms and conditions that govern the Installable Software and must solicit acceptance by\n\
-          the end user in the manner prescribed in such Installable Software Agreement. Upon such\n\
-          indication of agreement by the user, the provisioning Technology will complete installation\n\
-          of the Installable Software.\n\
+1.  A series of actions may occur ("Provisioning Process") in which a user may\n\
+    execute the Provisioning Technology on a machine ("Target Machine") with the\n\
+    intent of installing, extending or updating the functionality of an\n\
+    Eclipse-based product.\n\
+2.  During the Provisioning Process, the Provisioning Technology may cause third\n\
+    party Installable Software or a portion thereof to be accessed and copied to\n\
+    the Target Machine.\n\
+3.  Pursuant to the Specification, you will provide to the user the terms and\n\
+    conditions that govern the use of the Installable Software ("Installable\n\
+    Software Agreement") and such Installable Software Agreement shall be\n\
+    accessed from the Target Machine in accordance with the Specification. Such\n\
+    Installable Software Agreement must inform the user of the terms and\n\
+    conditions that govern the Installable Software and must solicit acceptance\n\
+    by the end user in the manner prescribed in such Installable\n\
+    Software Agreement. Upon such indication of agreement by the user, the\n\
+    provisioning Technology will complete installation of the\n\
+    Installable Software.\n\
 \n\
 Cryptography\n\
 \n\
-Content may contain encryption software. The country in which you are\n\
-currently may have restrictions on the import, possession, and use,\n\
-and/or re-export to another country, of encryption software. BEFORE\n\
-using any encryption software, please check the country's laws,\n\
-regulations and policies concerning the import, possession, or use, and\n\
-re-export of encryption software, to see if this is permitted.\n\
+Content may contain encryption software. The country in which you are currently\n\
+may have restrictions on the import, possession, and use, and/or re-export to\n\
+another country, of encryption software. BEFORE using any encryption software,\n\
+please check the country's laws, regulations and policies concerning the import,\n\
+possession, or use, and re-export of encryption software, to see if this is\n\
+permitted.\n\
 \n\
-Java and all Java-based trademarks are trademarks of Oracle Corporation in the United States, other countries, or both.\n
-########### end of license property ##########################################
\ No newline at end of file
+Java and all Java-based trademarks are trademarks of Oracle Corporation in the\n\
+United States, other countries, or both.\n
+########### end of license property ##########################################
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.source.feature/feature.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.source.feature/feature.xml
index 972e433..a93d865 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.source.feature/feature.xml
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.source.feature/feature.xml
@@ -2,7 +2,7 @@
 <feature
       id="org.eclipse.jgit.pgm.source"
       label="%featureName"
-      version="4.9.3.qualifier"
+      version="5.0.0.qualifier"
       provider-name="%providerName">
 
    <description url="http://www.eclipse.org/jgit/">
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.source.feature/license.html b/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.source.feature/license.html
index 95ad95e..008b801 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.source.feature/license.html
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.source.feature/license.html
@@ -1,106 +1,189 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-<!-- saved from url=(0044)http://www.eclipse.org/legal/epl/notice.html -->
-<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
-
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
 <title>Eclipse Foundation Software User Agreement</title>
 </head>
 
 <body lang="EN-US">
-<h2>Eclipse Foundation Software User Agreement</h2>
-<p>April 9, 2014</p>
+	<h2>Eclipse Foundation Software User Agreement</h2>
+	<p>November 22, 2017</p>
 
-<h3>Usage Of Content</h3>
+	<h3>Usage Of Content</h3>
 
-<p>THE ECLIPSE FOUNDATION MAKES AVAILABLE SOFTWARE, DOCUMENTATION, INFORMATION AND/OR OTHER MATERIALS FOR OPEN SOURCE PROJECTS
-   (COLLECTIVELY "CONTENT").  USE OF THE CONTENT IS GOVERNED BY THE TERMS AND CONDITIONS OF THIS AGREEMENT AND/OR THE TERMS AND
-   CONDITIONS OF LICENSE AGREEMENTS OR NOTICES INDICATED OR REFERENCED BELOW.  BY USING THE CONTENT, YOU AGREE THAT YOUR USE
-   OF THE CONTENT IS GOVERNED BY THIS AGREEMENT AND/OR THE TERMS AND CONDITIONS OF ANY APPLICABLE LICENSE AGREEMENTS OR
-   NOTICES INDICATED OR REFERENCED BELOW.  IF YOU DO NOT AGREE TO THE TERMS AND CONDITIONS OF THIS AGREEMENT AND THE TERMS AND
-   CONDITIONS OF ANY APPLICABLE LICENSE AGREEMENTS OR NOTICES INDICATED OR REFERENCED BELOW, THEN YOU MAY NOT USE THE CONTENT.</p>
+	<p>THE ECLIPSE FOUNDATION MAKES AVAILABLE SOFTWARE, DOCUMENTATION,
+		INFORMATION AND/OR OTHER MATERIALS FOR OPEN SOURCE PROJECTS
+		(COLLECTIVELY &quot;CONTENT&quot;). USE OF THE CONTENT IS GOVERNED BY
+		THE TERMS AND CONDITIONS OF THIS AGREEMENT AND/OR THE TERMS AND
+		CONDITIONS OF LICENSE AGREEMENTS OR NOTICES INDICATED OR REFERENCED
+		BELOW. BY USING THE CONTENT, YOU AGREE THAT YOUR USE OF THE CONTENT IS
+		GOVERNED BY THIS AGREEMENT AND/OR THE TERMS AND CONDITIONS OF ANY
+		APPLICABLE LICENSE AGREEMENTS OR NOTICES INDICATED OR REFERENCED
+		BELOW. IF YOU DO NOT AGREE TO THE TERMS AND CONDITIONS OF THIS
+		AGREEMENT AND THE TERMS AND CONDITIONS OF ANY APPLICABLE LICENSE
+		AGREEMENTS OR NOTICES INDICATED OR REFERENCED BELOW, THEN YOU MAY NOT
+		USE THE CONTENT.</p>
 
-<h3>Applicable Licenses</h3>
+	<h3>Applicable Licenses</h3>
 
-<p>Unless otherwise indicated, all Content made available by the Eclipse Foundation is provided to you under the terms and conditions of the Eclipse Public License Version 1.0
-   ("EPL").  A copy of the EPL is provided with this Content and is also available at <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a>.
-   For purposes of the EPL, "Program" will mean the Content.</p>
+	<p>
+		Unless otherwise indicated, all Content made available by the Eclipse
+		Foundation is provided to you under the terms and conditions of the
+		Eclipse Public License Version 2.0 (&quot;EPL&quot;). A copy of the
+		EPL is provided with this Content and is also available at <a
+			href="http://www.eclipse.org/legal/epl-2.0">http://www.eclipse.org/legal/epl-2.0</a>.
+		For purposes of the EPL, &quot;Program&quot; will mean the Content.
+	</p>
 
-<p>Content includes, but is not limited to, source code, object code, documentation and other files maintained in the Eclipse Foundation source code
-   repository ("Repository") in software modules ("Modules") and made available as downloadable archives ("Downloads").</p>
+	<p>Content includes, but is not limited to, source code, object
+		code, documentation and other files maintained in the Eclipse
+		Foundation source code repository (&quot;Repository&quot;) in software
+		modules (&quot;Modules&quot;) and made available as downloadable
+		archives (&quot;Downloads&quot;).</p>
 
-<ul>
-       <li>Content may be structured and packaged into modules to facilitate delivering, extending, and upgrading the Content.  Typical modules may include plug-ins ("Plug-ins"), plug-in fragments ("Fragments"), and features ("Features").</li>
-       <li>Each Plug-in or Fragment may be packaged as a sub-directory or JAR (Java™ ARchive) in a directory named "plugins".</li>
-       <li>A Feature is a bundle of one or more Plug-ins and/or Fragments and associated material.  Each Feature may be packaged as a sub-directory in a directory named "features".  Within a Feature, files named "feature.xml" may contain a list of the names and version numbers of the Plug-ins
-      and/or Fragments associated with that Feature.</li>
-       <li>Features may also include other Features ("Included Features"). Within a Feature, files named "feature.xml" may contain a list of the names and version numbers of Included Features.</li>
-</ul>
+	<ul>
+		<li>Content may be structured and packaged into modules to
+			facilitate delivering, extending, and upgrading the Content. Typical
+			modules may include plug-ins (&quot;Plug-ins&quot;), plug-in
+			fragments (&quot;Fragments&quot;), and features
+			(&quot;Features&quot;).</li>
+		<li>Each Plug-in or Fragment may be packaged as a sub-directory
+			or JAR (Java&trade; ARchive) in a directory named
+			&quot;plugins&quot;.</li>
+		<li>A Feature is a bundle of one or more Plug-ins and/or
+			Fragments and associated material. Each Feature may be packaged as a
+			sub-directory in a directory named &quot;features&quot;. Within a
+			Feature, files named &quot;feature.xml&quot; may contain a list of
+			the names and version numbers of the Plug-ins and/or Fragments
+			associated with that Feature.</li>
+		<li>Features may also include other Features (&quot;Included
+			Features&quot;). Within a Feature, files named
+			&quot;feature.xml&quot; may contain a list of the names and version
+			numbers of Included Features.</li>
+	</ul>
 
-<p>The terms and conditions governing Plug-ins and Fragments should be contained in files named "about.html" ("Abouts"). The terms and conditions governing Features and
-Included Features should be contained in files named "license.html" ("Feature Licenses").  Abouts and Feature Licenses may be located in any directory of a Download or Module
-including, but not limited to the following locations:</p>
+	<p>The terms and conditions governing Plug-ins and Fragments should
+		be contained in files named &quot;about.html&quot;
+		(&quot;Abouts&quot;). The terms and conditions governing Features and
+		Included Features should be contained in files named
+		&quot;license.html&quot; (&quot;Feature Licenses&quot;). Abouts and
+		Feature Licenses may be located in any directory of a Download or
+		Module including, but not limited to the following locations:</p>
 
-<ul>
-       <li>The top-level (root) directory</li>
-       <li>Plug-in and Fragment directories</li>
-       <li>Inside Plug-ins and Fragments packaged as JARs</li>
-       <li>Sub-directories of the directory named "src" of certain Plug-ins</li>
-       <li>Feature directories</li>
-</ul>
+	<ul>
+		<li>The top-level (root) directory</li>
+		<li>Plug-in and Fragment directories</li>
+		<li>Inside Plug-ins and Fragments packaged as JARs</li>
+		<li>Sub-directories of the directory named &quot;src&quot; of
+			certain Plug-ins</li>
+		<li>Feature directories</li>
+	</ul>
 
-<p>Note: if a Feature made available by the Eclipse Foundation is installed using the Provisioning Technology (as defined below), you must agree to a license ("Feature Update License") during the
-installation process.  If the Feature contains Included Features, the Feature Update License should either provide you with the terms and conditions governing the Included Features or
-inform you where you can locate them.  Feature Update Licenses may be found in the "license" property of files named "feature.properties" found within a Feature.
-Such Abouts, Feature Licenses, and Feature Update Licenses contain the terms and conditions (or references to such terms and conditions) that govern your use of the associated Content in
-that directory.</p>
+	<p>Note: if a Feature made available by the Eclipse Foundation is
+		installed using the Provisioning Technology (as defined below), you
+		must agree to a license (&quot;Feature Update License&quot;) during
+		the installation process. If the Feature contains Included Features,
+		the Feature Update License should either provide you with the terms
+		and conditions governing the Included Features or inform you where you
+		can locate them. Feature Update Licenses may be found in the
+		&quot;license&quot; property of files named
+		&quot;feature.properties&quot; found within a Feature. Such Abouts,
+		Feature Licenses, and Feature Update Licenses contain the terms and
+		conditions (or references to such terms and conditions) that govern
+		your use of the associated Content in that directory.</p>
 
-<p>THE ABOUTS, FEATURE LICENSES, AND FEATURE UPDATE LICENSES MAY REFER TO THE EPL OR OTHER LICENSE AGREEMENTS, NOTICES OR TERMS AND CONDITIONS.  SOME OF THESE
-OTHER LICENSE AGREEMENTS MAY INCLUDE (BUT ARE NOT LIMITED TO):</p>
+	<p>THE ABOUTS, FEATURE LICENSES, AND FEATURE UPDATE LICENSES MAY
+		REFER TO THE EPL OR OTHER LICENSE AGREEMENTS, NOTICES OR TERMS AND
+		CONDITIONS. SOME OF THESE OTHER LICENSE AGREEMENTS MAY INCLUDE (BUT
+		ARE NOT LIMITED TO):</p>
 
-<ul>
-       <li>Eclipse Distribution License Version 1.0 (available at <a href="http://www.eclipse.org/licenses/edl-v10.html">http://www.eclipse.org/licenses/edl-v1.0.html</a>)</li>
-       <li>Common Public License Version 1.0 (available at <a href="http://www.eclipse.org/legal/cpl-v10.html">http://www.eclipse.org/legal/cpl-v10.html</a>)</li>
-       <li>Apache Software License 1.1 (available at <a href="http://www.apache.org/licenses/LICENSE">http://www.apache.org/licenses/LICENSE</a>)</li>
-       <li>Apache Software License 2.0 (available at <a href="http://www.apache.org/licenses/LICENSE-2.0">http://www.apache.org/licenses/LICENSE-2.0</a>)</li>
-       <li>Mozilla Public License Version 1.1 (available at <a href="http://www.mozilla.org/MPL/MPL-1.1.html">http://www.mozilla.org/MPL/MPL-1.1.html</a>)</li>
-</ul>
+	<ul>
+		<li>Eclipse Public License Version 1.0 (available at <a
+			href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a>)
+		</li>
+		<li>Eclipse Distribution License Version 1.0 (available at <a
+			href="http://www.eclipse.org/licenses/edl-v10.html">http://www.eclipse.org/licenses/edl-v1.0.html</a>)
+		</li>
+		<li>Common Public License Version 1.0 (available at <a
+			href="http://www.eclipse.org/legal/cpl-v10.html">http://www.eclipse.org/legal/cpl-v10.html</a>)
+		</li>
+		<li>Apache Software License 1.1 (available at <a
+			href="http://www.apache.org/licenses/LICENSE">http://www.apache.org/licenses/LICENSE</a>)
+		</li>
+		<li>Apache Software License 2.0 (available at <a
+			href="http://www.apache.org/licenses/LICENSE-2.0">http://www.apache.org/licenses/LICENSE-2.0</a>)
+		</li>
+		<li>Mozilla Public License Version 1.1 (available at <a
+			href="http://www.mozilla.org/MPL/MPL-1.1.html">http://www.mozilla.org/MPL/MPL-1.1.html</a>)
+		</li>
+	</ul>
 
-<p>IT IS YOUR OBLIGATION TO READ AND ACCEPT ALL SUCH TERMS AND CONDITIONS PRIOR TO USE OF THE CONTENT.  If no About, Feature License, or Feature Update License is provided, please
-contact the Eclipse Foundation to determine what terms and conditions govern that particular Content.</p>
+	<p>IT IS YOUR OBLIGATION TO READ AND ACCEPT ALL SUCH TERMS AND
+		CONDITIONS PRIOR TO USE OF THE CONTENT. If no About, Feature License,
+		or Feature Update License is provided, please contact the Eclipse
+		Foundation to determine what terms and conditions govern that
+		particular Content.</p>
 
 
-<h3>Use of Provisioning Technology</h3>
+	<h3>Use of Provisioning Technology</h3>
 
-<p>The Eclipse Foundation makes available provisioning software, examples of which include, but are not limited to, p2 and the Eclipse
-   Update Manager ("Provisioning Technology") for the purpose of allowing users to install software, documentation, information and/or
-   other materials (collectively "Installable Software"). This capability is provided with the intent of allowing such users to
-   install, extend and update Eclipse-based products. Information about packaging Installable Software is available at <a href="http://eclipse.org/equinox/p2/repository_packaging.html">http://eclipse.org/equinox/p2/repository_packaging.html</a>
-   ("Specification").</p>
+	<p>
+		The Eclipse Foundation makes available provisioning software, examples
+		of which include, but are not limited to, p2 and the Eclipse Update
+		Manager (&quot;Provisioning Technology&quot;) for the purpose of
+		allowing users to install software, documentation, information and/or
+		other materials (collectively &quot;Installable Software&quot;). This
+		capability is provided with the intent of allowing such users to
+		install, extend and update Eclipse-based products. Information about
+		packaging Installable Software is available at <a
+			href="http://eclipse.org/equinox/p2/repository_packaging.html">http://eclipse.org/equinox/p2/repository_packaging.html</a>
+		(&quot;Specification&quot;).
+	</p>
 
-<p>You may use Provisioning Technology to allow other parties to install Installable Software. You shall be responsible for enabling the
-   applicable license agreements relating to the Installable Software to be presented to, and accepted by, the users of the Provisioning Technology
-   in accordance with the Specification. By using Provisioning Technology in such a manner and making it available in accordance with the
-   Specification, you further acknowledge your agreement to, and the acquisition of all necessary rights to permit the following:</p>
+	<p>You may use Provisioning Technology to allow other parties to
+		install Installable Software. You shall be responsible for enabling
+		the applicable license agreements relating to the Installable Software
+		to be presented to, and accepted by, the users of the Provisioning
+		Technology in accordance with the Specification. By using Provisioning
+		Technology in such a manner and making it available in accordance with
+		the Specification, you further acknowledge your agreement to, and the
+		acquisition of all necessary rights to permit the following:</p>
 
-<ol>
-       <li>A series of actions may occur ("Provisioning Process") in which a user may execute the Provisioning Technology
-       on a machine ("Target Machine") with the intent of installing, extending or updating the functionality of an Eclipse-based
-       product.</li>
-       <li>During the Provisioning Process, the Provisioning Technology may cause third party Installable Software or a portion thereof to be
-       accessed and copied to the Target Machine.</li>
-       <li>Pursuant to the Specification, you will provide to the user the terms and conditions that govern the use of the Installable
-       Software ("Installable Software Agreement") and such Installable Software Agreement shall be accessed from the Target
-       Machine in accordance with the Specification. Such Installable Software Agreement must inform the user of the terms and conditions that govern
-       the Installable Software and must solicit acceptance by the end user in the manner prescribed in such Installable Software Agreement. Upon such
-       indication of agreement by the user, the provisioning Technology will complete installation of the Installable Software.</li>
-</ol>
+	<ol>
+		<li>A series of actions may occur (&quot;Provisioning
+			Process&quot;) in which a user may execute the Provisioning
+			Technology on a machine (&quot;Target Machine&quot;) with the intent
+			of installing, extending or updating the functionality of an
+			Eclipse-based product.</li>
+		<li>During the Provisioning Process, the Provisioning Technology
+			may cause third party Installable Software or a portion thereof to be
+			accessed and copied to the Target Machine.</li>
+		<li>Pursuant to the Specification, you will provide to the user
+			the terms and conditions that govern the use of the Installable
+			Software (&quot;Installable Software Agreement&quot;) and such
+			Installable Software Agreement shall be accessed from the Target
+			Machine in accordance with the Specification. Such Installable
+			Software Agreement must inform the user of the terms and conditions
+			that govern the Installable Software and must solicit acceptance by
+			the end user in the manner prescribed in such Installable Software
+			Agreement. Upon such indication of agreement by the user, the
+			provisioning Technology will complete installation of the Installable
+			Software.</li>
+	</ol>
 
-<h3>Cryptography</h3>
+	<h3>Cryptography</h3>
 
-<p>Content may contain encryption software. The country in which you are currently may have restrictions on the import, possession, and use, and/or re-export to
-   another country, of encryption software. BEFORE using any encryption software, please check the country's laws, regulations and policies concerning the import,
-   possession, or use, and re-export of encryption software, to see if this is permitted.</p>
+	<p>Content may contain encryption software. The country in which
+		you are currently may have restrictions on the import, possession, and
+		use, and/or re-export to another country, of encryption software.
+		BEFORE using any encryption software, please check the country's laws,
+		regulations and policies concerning the import, possession, or use,
+		and re-export of encryption software, to see if this is permitted.</p>
 
-<p><small>Java and all Java-based trademarks are trademarks of Oracle Corporation in the United States, other countries, or both.</small></p>
-
-
-</body></html>
\ No newline at end of file
+	<p>
+		<small>Java and all Java-based trademarks are trademarks of
+			Oracle Corporation in the United States, other countries, or both.</small>
+	</p>
+</body>
+</html>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.source.feature/pom.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.source.feature/pom.xml
index f70f7d0..13d58fb 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.source.feature/pom.xml
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.source.feature/pom.xml
@@ -50,7 +50,7 @@
   <parent>
     <groupId>org.eclipse.jgit</groupId>
     <artifactId>jgit.tycho.parent</artifactId>
-    <version>4.9.3-SNAPSHOT</version>
+    <version>5.0.0-SNAPSHOT</version>
   </parent>
 
   <groupId>org.eclipse.jgit.feature</groupId>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.repository/pom.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.repository/pom.xml
index 42fe127..92d6692 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.repository/pom.xml
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.repository/pom.xml
@@ -50,7 +50,7 @@
   <parent>
     <groupId>org.eclipse.jgit</groupId>
     <artifactId>jgit.tycho.parent</artifactId>
-    <version>4.9.3-SNAPSHOT</version>
+    <version>5.0.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>org.eclipse.jgit.repository</artifactId>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.source.feature/feature.properties b/org.eclipse.jgit.packaging/org.eclipse.jgit.source.feature/feature.properties
index 9843e23..c04dc63 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.source.feature/feature.properties
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.source.feature/feature.properties
@@ -36,125 +36,143 @@
 # should be plain text version of license agreement pointed to be "licenseURL"
 license=\
 Eclipse Foundation Software User Agreement\n\
-April 9, 2014\n\
+\n\
+November 22, 2017\n\
 \n\
 Usage Of Content\n\
 \n\
-THE ECLIPSE FOUNDATION MAKES AVAILABLE SOFTWARE, DOCUMENTATION, INFORMATION AND/OR\n\
-OTHER MATERIALS FOR OPEN SOURCE PROJECTS (COLLECTIVELY "CONTENT").\n\
-USE OF THE CONTENT IS GOVERNED BY THE TERMS AND CONDITIONS OF THIS\n\
-AGREEMENT AND/OR THE TERMS AND CONDITIONS OF LICENSE AGREEMENTS OR\n\
-NOTICES INDICATED OR REFERENCED BELOW.  BY USING THE CONTENT, YOU\n\
-AGREE THAT YOUR USE OF THE CONTENT IS GOVERNED BY THIS AGREEMENT\n\
-AND/OR THE TERMS AND CONDITIONS OF ANY APPLICABLE LICENSE AGREEMENTS\n\
-OR NOTICES INDICATED OR REFERENCED BELOW.  IF YOU DO NOT AGREE TO THE\n\
-TERMS AND CONDITIONS OF THIS AGREEMENT AND THE TERMS AND CONDITIONS\n\
-OF ANY APPLICABLE LICENSE AGREEMENTS OR NOTICES INDICATED OR REFERENCED\n\
-BELOW, THEN YOU MAY NOT USE THE CONTENT.\n\
+THE ECLIPSE FOUNDATION MAKES AVAILABLE SOFTWARE, DOCUMENTATION, INFORMATION\n\
+AND/OR OTHER MATERIALS FOR OPEN SOURCE PROJECTS (COLLECTIVELY "CONTENT"). USE OF\n\
+THE CONTENT IS GOVERNED BY THE TERMS AND CONDITIONS OF THIS AGREEMENT AND/OR THE\n\
+TERMS AND CONDITIONS OF LICENSE AGREEMENTS OR NOTICES INDICATED OR REFERENCED\n\
+BELOW. BY USING THE CONTENT, YOU AGREE THAT YOUR USE OF THE CONTENT IS GOVERNED\n\
+BY THIS AGREEMENT AND/OR THE TERMS AND CONDITIONS OF ANY APPLICABLE LICENSE\n\
+AGREEMENTS OR NOTICES INDICATED OR REFERENCED BELOW. IF YOU DO NOT AGREE TO THE\n\
+TERMS AND CONDITIONS OF THIS AGREEMENT AND THE TERMS AND CONDITIONS OF ANY\n\
+APPLICABLE LICENSE AGREEMENTS OR NOTICES INDICATED OR REFERENCED BELOW, THEN YOU\n\
+MAY NOT USE THE CONTENT.\n\
 \n\
 Applicable Licenses\n\
 \n\
-Unless otherwise indicated, all Content made available by the\n\
-Eclipse Foundation is provided to you under the terms and conditions of\n\
-the Eclipse Public License Version 1.0 ("EPL"). A copy of the EPL is\n\
-provided with this Content and is also available at http://www.eclipse.org/legal/epl-v10.html.\n\
-For purposes of the EPL, "Program" will mean the Content.\n\
+Unless otherwise indicated, all Content made available by the Eclipse Foundation\n\
+is provided to you under the terms and conditions of the Eclipse Public License\n\
+Version 2.0 ("EPL"). A copy of the EPL is provided with this Content and is also\n\
+available at http://www.eclipse.org/legal/epl-2.0. For purposes of the EPL,\n\
+"Program" will mean the Content.\n\
 \n\
-Content includes, but is not limited to, source code, object code,\n\
-documentation and other files maintained in the Eclipse Foundation source code\n\
-repository ("Repository") in software modules ("Modules") and made available\n\
-as downloadable archives ("Downloads").\n\
+Content includes, but is not limited to, source code, object code, documentation\n\
+and other files maintained in the Eclipse Foundation source code repository\n\
+("Repository") in software modules ("Modules") and made available as\n\
+downloadable archives ("Downloads").\n\
 \n\
-       - Content may be structured and packaged into modules to facilitate delivering,\n\
-         extending, and upgrading the Content. Typical modules may include plug-ins ("Plug-ins"),\n\
-         plug-in fragments ("Fragments"), and features ("Features").\n\
-       - Each Plug-in or Fragment may be packaged as a sub-directory or JAR (Java(TM) ARchive)\n\
-         in a directory named "plugins".\n\
-       - A Feature is a bundle of one or more Plug-ins and/or Fragments and associated material.\n\
-         Each Feature may be packaged as a sub-directory in a directory named "features".\n\
-         Within a Feature, files named "feature.xml" may contain a list of the names and version\n\
-         numbers of the Plug-ins and/or Fragments associated with that Feature.\n\
-       - Features may also include other Features ("Included Features"). Within a Feature, files\n\
-         named "feature.xml" may contain a list of the names and version numbers of Included Features.\n\
+-   Content may be structured and packaged into modules to facilitate\n\
+    delivering, extending, and upgrading the Content. Typical modules may\n\
+    include plug-ins ("Plug-ins"), plug-in fragments ("Fragments"), and\n\
+    features ("Features").\n\
+-   Each Plug-in or Fragment may be packaged as a sub-directory or JAR\n\
+    (Java™ ARchive) in a directory named "plugins".\n\
+-   A Feature is a bundle of one or more Plug-ins and/or Fragments and\n\
+    associated material. Each Feature may be packaged as a sub-directory in a\n\
+    directory named "features". Within a Feature, files named "feature.xml" may\n\
+    contain a list of the names and version numbers of the Plug-ins and/or\n\
+    Fragments associated with that Feature.\n\
+-   Features may also include other Features ("Included Features"). Within a\n\
+    Feature, files named "feature.xml" may contain a list of the names and\n\
+    version numbers of Included Features.\n\
 \n\
-The terms and conditions governing Plug-ins and Fragments should be\n\
-contained in files named "about.html" ("Abouts"). The terms and\n\
-conditions governing Features and Included Features should be contained\n\
-in files named "license.html" ("Feature Licenses"). Abouts and Feature\n\
-Licenses may be located in any directory of a Download or Module\n\
-including, but not limited to the following locations:\n\
+The terms and conditions governing Plug-ins and Fragments should be contained in\n\
+files named "about.html" ("Abouts"). The terms and conditions governing Features\n\
+and Included Features should be contained in files named "license.html"\n\
+("Feature Licenses"). Abouts and Feature Licenses may be located in any\n\
+directory of a Download or Module including, but not limited to the following\n\
+locations:\n\
 \n\
-       - The top-level (root) directory\n\
-       - Plug-in and Fragment directories\n\
-       - Inside Plug-ins and Fragments packaged as JARs\n\
-       - Sub-directories of the directory named "src" of certain Plug-ins\n\
-       - Feature directories\n\
+-   The top-level (root) directory\n\
+-   Plug-in and Fragment directories\n\
+-   Inside Plug-ins and Fragments packaged as JARs\n\
+-   Sub-directories of the directory named "src" of certain Plug-ins\n\
+-   Feature directories\n\
 \n\
-Note: if a Feature made available by the Eclipse Foundation is installed using the\n\
-Provisioning Technology (as defined below), you must agree to a license ("Feature \n\
-Update License") during the installation process. If the Feature contains\n\
-Included Features, the Feature Update License should either provide you\n\
-with the terms and conditions governing the Included Features or inform\n\
-you where you can locate them. Feature Update Licenses may be found in\n\
-the "license" property of files named "feature.properties" found within a Feature.\n\
-Such Abouts, Feature Licenses, and Feature Update Licenses contain the\n\
-terms and conditions (or references to such terms and conditions) that\n\
-govern your use of the associated Content in that directory.\n\
+Note: if a Feature made available by the Eclipse Foundation is installed using\n\
+the Provisioning Technology (as defined below), you must agree to a license\n\
+("Feature Update License") during the installation process. If the Feature\n\
+contains Included Features, the Feature Update License should either provide you\n\
+with the terms and conditions governing the Included Features or inform you\n\
+where you can locate them. Feature Update Licenses may be found in the "license"\n\
+property of files named "feature.properties" found within a Feature. Such\n\
+Abouts, Feature Licenses, and Feature Update Licenses contain the terms and\n\
+conditions (or references to such terms and conditions) that govern your use of\n\
+the associated Content in that directory.\n\
 \n\
-THE ABOUTS, FEATURE LICENSES, AND FEATURE UPDATE LICENSES MAY REFER\n\
-TO THE EPL OR OTHER LICENSE AGREEMENTS, NOTICES OR TERMS AND CONDITIONS.\n\
-SOME OF THESE OTHER LICENSE AGREEMENTS MAY INCLUDE (BUT ARE NOT LIMITED TO):\n\
+THE ABOUTS, FEATURE LICENSES, AND FEATURE UPDATE LICENSES MAY REFER TO THE EPL\n\
+OR OTHER LICENSE AGREEMENTS, NOTICES OR TERMS AND CONDITIONS. SOME OF THESE\n\
+OTHER LICENSE AGREEMENTS MAY INCLUDE (BUT ARE NOT LIMITED TO):\n\
 \n\
-       - Eclipse Distribution License Version 1.0 (available at http://www.eclipse.org/licenses/edl-v1.0.html)\n\
-       - Common Public License Version 1.0 (available at http://www.eclipse.org/legal/cpl-v10.html)\n\
-       - Apache Software License 1.1 (available at http://www.apache.org/licenses/LICENSE)\n\
-       - Apache Software License 2.0 (available at http://www.apache.org/licenses/LICENSE-2.0)\n\
-       - Mozilla Public License Version 1.1 (available at http://www.mozilla.org/MPL/MPL-1.1.html)\n\
+-   Eclipse Public License Version 1.0 (available at\n\
+    http://www.eclipse.org/legal/epl-v10.html)\n\
+-   Eclipse Distribution License Version 1.0 (available at\n\
+    http://www.eclipse.org/licenses/edl-v1.0.html)\n\
+-   Common Public License Version 1.0 (available at\n\
+    http://www.eclipse.org/legal/cpl-v10.html)\n\
+-   Apache Software License 1.1 (available at\n\
+    http://www.apache.org/licenses/LICENSE)\n\
+-   Apache Software License 2.0 (available at\n\
+    http://www.apache.org/licenses/LICENSE-2.0)\n\
+-   Mozilla Public License Version 1.1 (available at\n\
+    http://www.mozilla.org/MPL/MPL-1.1.html)\n\
 \n\
-IT IS YOUR OBLIGATION TO READ AND ACCEPT ALL SUCH TERMS AND CONDITIONS PRIOR\n\
-TO USE OF THE CONTENT. If no About, Feature License, or Feature Update License\n\
-is provided, please contact the Eclipse Foundation to determine what terms and conditions\n\
-govern that particular Content.\n\
+IT IS YOUR OBLIGATION TO READ AND ACCEPT ALL SUCH TERMS AND CONDITIONS PRIOR TO\n\
+USE OF THE CONTENT. If no About, Feature License, or Feature Update License is\n\
+provided, please contact the Eclipse Foundation to determine what terms and\n\
+conditions govern that particular Content.\n\
 \n\
-\n\Use of Provisioning Technology\n\
+Use of Provisioning Technology\n\
 \n\
-The Eclipse Foundation makes available provisioning software, examples of which include,\n\
-but are not limited to, p2 and the Eclipse Update Manager ("Provisioning Technology") for\n\
-the purpose of allowing users to install software, documentation, information and/or\n\
-other materials (collectively "Installable Software"). This capability is provided with\n\
-the intent of allowing such users to install, extend and update Eclipse-based products.\n\
-Information about packaging Installable Software is available at\n\
+The Eclipse Foundation makes available provisioning software, examples of which\n\
+include, but are not limited to, p2 and the Eclipse Update Manager\n\
+("Provisioning Technology") for the purpose of allowing users to install\n\
+software, documentation, information and/or other materials (collectively\n\
+"Installable Software"). This capability is provided with the intent of allowing\n\
+such users to install, extend and update Eclipse-based products. Information\n\
+about packaging Installable Software is available at\n\
 http://eclipse.org/equinox/p2/repository_packaging.html ("Specification").\n\
 \n\
-You may use Provisioning Technology to allow other parties to install Installable Software.\n\
-You shall be responsible for enabling the applicable license agreements relating to the\n\
-Installable Software to be presented to, and accepted by, the users of the Provisioning Technology\n\
-in accordance with the Specification. By using Provisioning Technology in such a manner and\n\
-making it available in accordance with the Specification, you further acknowledge your\n\
-agreement to, and the acquisition of all necessary rights to permit the following:\n\
+You may use Provisioning Technology to allow other parties to install\n\
+Installable Software. You shall be responsible for enabling the applicable\n\
+license agreements relating to the Installable Software to be presented to, and\n\
+accepted by, the users of the Provisioning Technology in accordance with the\n\
+Specification. By using Provisioning Technology in such a manner and making it\n\
+available in accordance with the Specification, you further acknowledge your\n\
+agreement to, and the acquisition of all necessary rights to permit the\n\
+following:\n\
 \n\
-       1. A series of actions may occur ("Provisioning Process") in which a user may execute\n\
-          the Provisioning Technology on a machine ("Target Machine") with the intent of installing,\n\
-          extending or updating the functionality of an Eclipse-based product.\n\
-       2. During the Provisioning Process, the Provisioning Technology may cause third party\n\
-          Installable Software or a portion thereof to be accessed and copied to the Target Machine.\n\
-       3. Pursuant to the Specification, you will provide to the user the terms and conditions that\n\
-          govern the use of the Installable Software ("Installable Software Agreement") and such\n\
-          Installable Software Agreement shall be accessed from the Target Machine in accordance\n\
-          with the Specification. Such Installable Software Agreement must inform the user of the\n\
-          terms and conditions that govern the Installable Software and must solicit acceptance by\n\
-          the end user in the manner prescribed in such Installable Software Agreement. Upon such\n\
-          indication of agreement by the user, the provisioning Technology will complete installation\n\
-          of the Installable Software.\n\
+1.  A series of actions may occur ("Provisioning Process") in which a user may\n\
+    execute the Provisioning Technology on a machine ("Target Machine") with the\n\
+    intent of installing, extending or updating the functionality of an\n\
+    Eclipse-based product.\n\
+2.  During the Provisioning Process, the Provisioning Technology may cause third\n\
+    party Installable Software or a portion thereof to be accessed and copied to\n\
+    the Target Machine.\n\
+3.  Pursuant to the Specification, you will provide to the user the terms and\n\
+    conditions that govern the use of the Installable Software ("Installable\n\
+    Software Agreement") and such Installable Software Agreement shall be\n\
+    accessed from the Target Machine in accordance with the Specification. Such\n\
+    Installable Software Agreement must inform the user of the terms and\n\
+    conditions that govern the Installable Software and must solicit acceptance\n\
+    by the end user in the manner prescribed in such Installable\n\
+    Software Agreement. Upon such indication of agreement by the user, the\n\
+    provisioning Technology will complete installation of the\n\
+    Installable Software.\n\
 \n\
 Cryptography\n\
 \n\
-Content may contain encryption software. The country in which you are\n\
-currently may have restrictions on the import, possession, and use,\n\
-and/or re-export to another country, of encryption software. BEFORE\n\
-using any encryption software, please check the country's laws,\n\
-regulations and policies concerning the import, possession, or use, and\n\
-re-export of encryption software, to see if this is permitted.\n\
+Content may contain encryption software. The country in which you are currently\n\
+may have restrictions on the import, possession, and use, and/or re-export to\n\
+another country, of encryption software. BEFORE using any encryption software,\n\
+please check the country's laws, regulations and policies concerning the import,\n\
+possession, or use, and re-export of encryption software, to see if this is\n\
+permitted.\n\
 \n\
-Java and all Java-based trademarks are trademarks of Oracle Corporation in the United States, other countries, or both.\n
-########### end of license property ##########################################
\ No newline at end of file
+Java and all Java-based trademarks are trademarks of Oracle Corporation in the\n\
+United States, other countries, or both.\n
+########### end of license property ##########################################
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.source.feature/feature.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.source.feature/feature.xml
index 999d289..b8244a8 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.source.feature/feature.xml
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.source.feature/feature.xml
@@ -2,7 +2,7 @@
 <feature
       id="org.eclipse.jgit.source"
       label="%featureName"
-      version="4.9.3.qualifier"
+      version="5.0.0.qualifier"
       provider-name="%providerName">
 
    <description url="http://www.eclipse.org/jgit/">
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.source.feature/license.html b/org.eclipse.jgit.packaging/org.eclipse.jgit.source.feature/license.html
index 95ad95e..008b801 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.source.feature/license.html
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.source.feature/license.html
@@ -1,106 +1,189 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-<!-- saved from url=(0044)http://www.eclipse.org/legal/epl/notice.html -->
-<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
-
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
 <title>Eclipse Foundation Software User Agreement</title>
 </head>
 
 <body lang="EN-US">
-<h2>Eclipse Foundation Software User Agreement</h2>
-<p>April 9, 2014</p>
+	<h2>Eclipse Foundation Software User Agreement</h2>
+	<p>November 22, 2017</p>
 
-<h3>Usage Of Content</h3>
+	<h3>Usage Of Content</h3>
 
-<p>THE ECLIPSE FOUNDATION MAKES AVAILABLE SOFTWARE, DOCUMENTATION, INFORMATION AND/OR OTHER MATERIALS FOR OPEN SOURCE PROJECTS
-   (COLLECTIVELY "CONTENT").  USE OF THE CONTENT IS GOVERNED BY THE TERMS AND CONDITIONS OF THIS AGREEMENT AND/OR THE TERMS AND
-   CONDITIONS OF LICENSE AGREEMENTS OR NOTICES INDICATED OR REFERENCED BELOW.  BY USING THE CONTENT, YOU AGREE THAT YOUR USE
-   OF THE CONTENT IS GOVERNED BY THIS AGREEMENT AND/OR THE TERMS AND CONDITIONS OF ANY APPLICABLE LICENSE AGREEMENTS OR
-   NOTICES INDICATED OR REFERENCED BELOW.  IF YOU DO NOT AGREE TO THE TERMS AND CONDITIONS OF THIS AGREEMENT AND THE TERMS AND
-   CONDITIONS OF ANY APPLICABLE LICENSE AGREEMENTS OR NOTICES INDICATED OR REFERENCED BELOW, THEN YOU MAY NOT USE THE CONTENT.</p>
+	<p>THE ECLIPSE FOUNDATION MAKES AVAILABLE SOFTWARE, DOCUMENTATION,
+		INFORMATION AND/OR OTHER MATERIALS FOR OPEN SOURCE PROJECTS
+		(COLLECTIVELY &quot;CONTENT&quot;). USE OF THE CONTENT IS GOVERNED BY
+		THE TERMS AND CONDITIONS OF THIS AGREEMENT AND/OR THE TERMS AND
+		CONDITIONS OF LICENSE AGREEMENTS OR NOTICES INDICATED OR REFERENCED
+		BELOW. BY USING THE CONTENT, YOU AGREE THAT YOUR USE OF THE CONTENT IS
+		GOVERNED BY THIS AGREEMENT AND/OR THE TERMS AND CONDITIONS OF ANY
+		APPLICABLE LICENSE AGREEMENTS OR NOTICES INDICATED OR REFERENCED
+		BELOW. IF YOU DO NOT AGREE TO THE TERMS AND CONDITIONS OF THIS
+		AGREEMENT AND THE TERMS AND CONDITIONS OF ANY APPLICABLE LICENSE
+		AGREEMENTS OR NOTICES INDICATED OR REFERENCED BELOW, THEN YOU MAY NOT
+		USE THE CONTENT.</p>
 
-<h3>Applicable Licenses</h3>
+	<h3>Applicable Licenses</h3>
 
-<p>Unless otherwise indicated, all Content made available by the Eclipse Foundation is provided to you under the terms and conditions of the Eclipse Public License Version 1.0
-   ("EPL").  A copy of the EPL is provided with this Content and is also available at <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a>.
-   For purposes of the EPL, "Program" will mean the Content.</p>
+	<p>
+		Unless otherwise indicated, all Content made available by the Eclipse
+		Foundation is provided to you under the terms and conditions of the
+		Eclipse Public License Version 2.0 (&quot;EPL&quot;). A copy of the
+		EPL is provided with this Content and is also available at <a
+			href="http://www.eclipse.org/legal/epl-2.0">http://www.eclipse.org/legal/epl-2.0</a>.
+		For purposes of the EPL, &quot;Program&quot; will mean the Content.
+	</p>
 
-<p>Content includes, but is not limited to, source code, object code, documentation and other files maintained in the Eclipse Foundation source code
-   repository ("Repository") in software modules ("Modules") and made available as downloadable archives ("Downloads").</p>
+	<p>Content includes, but is not limited to, source code, object
+		code, documentation and other files maintained in the Eclipse
+		Foundation source code repository (&quot;Repository&quot;) in software
+		modules (&quot;Modules&quot;) and made available as downloadable
+		archives (&quot;Downloads&quot;).</p>
 
-<ul>
-       <li>Content may be structured and packaged into modules to facilitate delivering, extending, and upgrading the Content.  Typical modules may include plug-ins ("Plug-ins"), plug-in fragments ("Fragments"), and features ("Features").</li>
-       <li>Each Plug-in or Fragment may be packaged as a sub-directory or JAR (Java™ ARchive) in a directory named "plugins".</li>
-       <li>A Feature is a bundle of one or more Plug-ins and/or Fragments and associated material.  Each Feature may be packaged as a sub-directory in a directory named "features".  Within a Feature, files named "feature.xml" may contain a list of the names and version numbers of the Plug-ins
-      and/or Fragments associated with that Feature.</li>
-       <li>Features may also include other Features ("Included Features"). Within a Feature, files named "feature.xml" may contain a list of the names and version numbers of Included Features.</li>
-</ul>
+	<ul>
+		<li>Content may be structured and packaged into modules to
+			facilitate delivering, extending, and upgrading the Content. Typical
+			modules may include plug-ins (&quot;Plug-ins&quot;), plug-in
+			fragments (&quot;Fragments&quot;), and features
+			(&quot;Features&quot;).</li>
+		<li>Each Plug-in or Fragment may be packaged as a sub-directory
+			or JAR (Java&trade; ARchive) in a directory named
+			&quot;plugins&quot;.</li>
+		<li>A Feature is a bundle of one or more Plug-ins and/or
+			Fragments and associated material. Each Feature may be packaged as a
+			sub-directory in a directory named &quot;features&quot;. Within a
+			Feature, files named &quot;feature.xml&quot; may contain a list of
+			the names and version numbers of the Plug-ins and/or Fragments
+			associated with that Feature.</li>
+		<li>Features may also include other Features (&quot;Included
+			Features&quot;). Within a Feature, files named
+			&quot;feature.xml&quot; may contain a list of the names and version
+			numbers of Included Features.</li>
+	</ul>
 
-<p>The terms and conditions governing Plug-ins and Fragments should be contained in files named "about.html" ("Abouts"). The terms and conditions governing Features and
-Included Features should be contained in files named "license.html" ("Feature Licenses").  Abouts and Feature Licenses may be located in any directory of a Download or Module
-including, but not limited to the following locations:</p>
+	<p>The terms and conditions governing Plug-ins and Fragments should
+		be contained in files named &quot;about.html&quot;
+		(&quot;Abouts&quot;). The terms and conditions governing Features and
+		Included Features should be contained in files named
+		&quot;license.html&quot; (&quot;Feature Licenses&quot;). Abouts and
+		Feature Licenses may be located in any directory of a Download or
+		Module including, but not limited to the following locations:</p>
 
-<ul>
-       <li>The top-level (root) directory</li>
-       <li>Plug-in and Fragment directories</li>
-       <li>Inside Plug-ins and Fragments packaged as JARs</li>
-       <li>Sub-directories of the directory named "src" of certain Plug-ins</li>
-       <li>Feature directories</li>
-</ul>
+	<ul>
+		<li>The top-level (root) directory</li>
+		<li>Plug-in and Fragment directories</li>
+		<li>Inside Plug-ins and Fragments packaged as JARs</li>
+		<li>Sub-directories of the directory named &quot;src&quot; of
+			certain Plug-ins</li>
+		<li>Feature directories</li>
+	</ul>
 
-<p>Note: if a Feature made available by the Eclipse Foundation is installed using the Provisioning Technology (as defined below), you must agree to a license ("Feature Update License") during the
-installation process.  If the Feature contains Included Features, the Feature Update License should either provide you with the terms and conditions governing the Included Features or
-inform you where you can locate them.  Feature Update Licenses may be found in the "license" property of files named "feature.properties" found within a Feature.
-Such Abouts, Feature Licenses, and Feature Update Licenses contain the terms and conditions (or references to such terms and conditions) that govern your use of the associated Content in
-that directory.</p>
+	<p>Note: if a Feature made available by the Eclipse Foundation is
+		installed using the Provisioning Technology (as defined below), you
+		must agree to a license (&quot;Feature Update License&quot;) during
+		the installation process. If the Feature contains Included Features,
+		the Feature Update License should either provide you with the terms
+		and conditions governing the Included Features or inform you where you
+		can locate them. Feature Update Licenses may be found in the
+		&quot;license&quot; property of files named
+		&quot;feature.properties&quot; found within a Feature. Such Abouts,
+		Feature Licenses, and Feature Update Licenses contain the terms and
+		conditions (or references to such terms and conditions) that govern
+		your use of the associated Content in that directory.</p>
 
-<p>THE ABOUTS, FEATURE LICENSES, AND FEATURE UPDATE LICENSES MAY REFER TO THE EPL OR OTHER LICENSE AGREEMENTS, NOTICES OR TERMS AND CONDITIONS.  SOME OF THESE
-OTHER LICENSE AGREEMENTS MAY INCLUDE (BUT ARE NOT LIMITED TO):</p>
+	<p>THE ABOUTS, FEATURE LICENSES, AND FEATURE UPDATE LICENSES MAY
+		REFER TO THE EPL OR OTHER LICENSE AGREEMENTS, NOTICES OR TERMS AND
+		CONDITIONS. SOME OF THESE OTHER LICENSE AGREEMENTS MAY INCLUDE (BUT
+		ARE NOT LIMITED TO):</p>
 
-<ul>
-       <li>Eclipse Distribution License Version 1.0 (available at <a href="http://www.eclipse.org/licenses/edl-v10.html">http://www.eclipse.org/licenses/edl-v1.0.html</a>)</li>
-       <li>Common Public License Version 1.0 (available at <a href="http://www.eclipse.org/legal/cpl-v10.html">http://www.eclipse.org/legal/cpl-v10.html</a>)</li>
-       <li>Apache Software License 1.1 (available at <a href="http://www.apache.org/licenses/LICENSE">http://www.apache.org/licenses/LICENSE</a>)</li>
-       <li>Apache Software License 2.0 (available at <a href="http://www.apache.org/licenses/LICENSE-2.0">http://www.apache.org/licenses/LICENSE-2.0</a>)</li>
-       <li>Mozilla Public License Version 1.1 (available at <a href="http://www.mozilla.org/MPL/MPL-1.1.html">http://www.mozilla.org/MPL/MPL-1.1.html</a>)</li>
-</ul>
+	<ul>
+		<li>Eclipse Public License Version 1.0 (available at <a
+			href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a>)
+		</li>
+		<li>Eclipse Distribution License Version 1.0 (available at <a
+			href="http://www.eclipse.org/licenses/edl-v10.html">http://www.eclipse.org/licenses/edl-v1.0.html</a>)
+		</li>
+		<li>Common Public License Version 1.0 (available at <a
+			href="http://www.eclipse.org/legal/cpl-v10.html">http://www.eclipse.org/legal/cpl-v10.html</a>)
+		</li>
+		<li>Apache Software License 1.1 (available at <a
+			href="http://www.apache.org/licenses/LICENSE">http://www.apache.org/licenses/LICENSE</a>)
+		</li>
+		<li>Apache Software License 2.0 (available at <a
+			href="http://www.apache.org/licenses/LICENSE-2.0">http://www.apache.org/licenses/LICENSE-2.0</a>)
+		</li>
+		<li>Mozilla Public License Version 1.1 (available at <a
+			href="http://www.mozilla.org/MPL/MPL-1.1.html">http://www.mozilla.org/MPL/MPL-1.1.html</a>)
+		</li>
+	</ul>
 
-<p>IT IS YOUR OBLIGATION TO READ AND ACCEPT ALL SUCH TERMS AND CONDITIONS PRIOR TO USE OF THE CONTENT.  If no About, Feature License, or Feature Update License is provided, please
-contact the Eclipse Foundation to determine what terms and conditions govern that particular Content.</p>
+	<p>IT IS YOUR OBLIGATION TO READ AND ACCEPT ALL SUCH TERMS AND
+		CONDITIONS PRIOR TO USE OF THE CONTENT. If no About, Feature License,
+		or Feature Update License is provided, please contact the Eclipse
+		Foundation to determine what terms and conditions govern that
+		particular Content.</p>
 
 
-<h3>Use of Provisioning Technology</h3>
+	<h3>Use of Provisioning Technology</h3>
 
-<p>The Eclipse Foundation makes available provisioning software, examples of which include, but are not limited to, p2 and the Eclipse
-   Update Manager ("Provisioning Technology") for the purpose of allowing users to install software, documentation, information and/or
-   other materials (collectively "Installable Software"). This capability is provided with the intent of allowing such users to
-   install, extend and update Eclipse-based products. Information about packaging Installable Software is available at <a href="http://eclipse.org/equinox/p2/repository_packaging.html">http://eclipse.org/equinox/p2/repository_packaging.html</a>
-   ("Specification").</p>
+	<p>
+		The Eclipse Foundation makes available provisioning software, examples
+		of which include, but are not limited to, p2 and the Eclipse Update
+		Manager (&quot;Provisioning Technology&quot;) for the purpose of
+		allowing users to install software, documentation, information and/or
+		other materials (collectively &quot;Installable Software&quot;). This
+		capability is provided with the intent of allowing such users to
+		install, extend and update Eclipse-based products. Information about
+		packaging Installable Software is available at <a
+			href="http://eclipse.org/equinox/p2/repository_packaging.html">http://eclipse.org/equinox/p2/repository_packaging.html</a>
+		(&quot;Specification&quot;).
+	</p>
 
-<p>You may use Provisioning Technology to allow other parties to install Installable Software. You shall be responsible for enabling the
-   applicable license agreements relating to the Installable Software to be presented to, and accepted by, the users of the Provisioning Technology
-   in accordance with the Specification. By using Provisioning Technology in such a manner and making it available in accordance with the
-   Specification, you further acknowledge your agreement to, and the acquisition of all necessary rights to permit the following:</p>
+	<p>You may use Provisioning Technology to allow other parties to
+		install Installable Software. You shall be responsible for enabling
+		the applicable license agreements relating to the Installable Software
+		to be presented to, and accepted by, the users of the Provisioning
+		Technology in accordance with the Specification. By using Provisioning
+		Technology in such a manner and making it available in accordance with
+		the Specification, you further acknowledge your agreement to, and the
+		acquisition of all necessary rights to permit the following:</p>
 
-<ol>
-       <li>A series of actions may occur ("Provisioning Process") in which a user may execute the Provisioning Technology
-       on a machine ("Target Machine") with the intent of installing, extending or updating the functionality of an Eclipse-based
-       product.</li>
-       <li>During the Provisioning Process, the Provisioning Technology may cause third party Installable Software or a portion thereof to be
-       accessed and copied to the Target Machine.</li>
-       <li>Pursuant to the Specification, you will provide to the user the terms and conditions that govern the use of the Installable
-       Software ("Installable Software Agreement") and such Installable Software Agreement shall be accessed from the Target
-       Machine in accordance with the Specification. Such Installable Software Agreement must inform the user of the terms and conditions that govern
-       the Installable Software and must solicit acceptance by the end user in the manner prescribed in such Installable Software Agreement. Upon such
-       indication of agreement by the user, the provisioning Technology will complete installation of the Installable Software.</li>
-</ol>
+	<ol>
+		<li>A series of actions may occur (&quot;Provisioning
+			Process&quot;) in which a user may execute the Provisioning
+			Technology on a machine (&quot;Target Machine&quot;) with the intent
+			of installing, extending or updating the functionality of an
+			Eclipse-based product.</li>
+		<li>During the Provisioning Process, the Provisioning Technology
+			may cause third party Installable Software or a portion thereof to be
+			accessed and copied to the Target Machine.</li>
+		<li>Pursuant to the Specification, you will provide to the user
+			the terms and conditions that govern the use of the Installable
+			Software (&quot;Installable Software Agreement&quot;) and such
+			Installable Software Agreement shall be accessed from the Target
+			Machine in accordance with the Specification. Such Installable
+			Software Agreement must inform the user of the terms and conditions
+			that govern the Installable Software and must solicit acceptance by
+			the end user in the manner prescribed in such Installable Software
+			Agreement. Upon such indication of agreement by the user, the
+			provisioning Technology will complete installation of the Installable
+			Software.</li>
+	</ol>
 
-<h3>Cryptography</h3>
+	<h3>Cryptography</h3>
 
-<p>Content may contain encryption software. The country in which you are currently may have restrictions on the import, possession, and use, and/or re-export to
-   another country, of encryption software. BEFORE using any encryption software, please check the country's laws, regulations and policies concerning the import,
-   possession, or use, and re-export of encryption software, to see if this is permitted.</p>
+	<p>Content may contain encryption software. The country in which
+		you are currently may have restrictions on the import, possession, and
+		use, and/or re-export to another country, of encryption software.
+		BEFORE using any encryption software, please check the country's laws,
+		regulations and policies concerning the import, possession, or use,
+		and re-export of encryption software, to see if this is permitted.</p>
 
-<p><small>Java and all Java-based trademarks are trademarks of Oracle Corporation in the United States, other countries, or both.</small></p>
-
-
-</body></html>
\ No newline at end of file
+	<p>
+		<small>Java and all Java-based trademarks are trademarks of
+			Oracle Corporation in the United States, other countries, or both.</small>
+	</p>
+</body>
+</html>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.source.feature/pom.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.source.feature/pom.xml
index 52a83e1..aba2cb6 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.source.feature/pom.xml
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.source.feature/pom.xml
@@ -50,7 +50,7 @@
   <parent>
     <groupId>org.eclipse.jgit</groupId>
     <artifactId>jgit.tycho.parent</artifactId>
-    <version>4.9.3-SNAPSHOT</version>
+    <version>5.0.0-SNAPSHOT</version>
   </parent>
 
   <groupId>org.eclipse.jgit.feature</groupId>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/META-INF/MANIFEST.MF b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/META-INF/MANIFEST.MF
index 1ef54c8..3fb306b 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/META-INF/MANIFEST.MF
@@ -2,4 +2,4 @@
 Bundle-ManifestVersion: 2
 Bundle-Name: JGit Target Platform Bundle
 Bundle-SymbolicName: org.eclipse.jgit.target
-Bundle-Version: 4.9.3.qualifier
+Bundle-Version: 5.0.0.qualifier
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.5.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.5.target
index b4b3908..9fab245 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.5.target
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.5.target
@@ -1,106 +1,72 @@
 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
 <?pde?>
 <!-- generated with https://github.com/mbarbero/fr.obeo.releng.targetplatform -->
-<target name="jgit-4.5" sequenceNumber="1504052010">
+<target name="jgit-4.5" sequenceNumber="1528375371">
   <locations>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
-      <unit id="org.eclipse.jetty.client" version="9.4.5.v20170502"/>
-      <unit id="org.eclipse.jetty.client.source" version="9.4.5.v20170502"/>
-      <unit id="org.eclipse.jetty.continuation" version="9.4.5.v20170502"/>
-      <unit id="org.eclipse.jetty.continuation.source" version="9.4.5.v20170502"/>
-      <unit id="org.eclipse.jetty.http" version="9.4.5.v20170502"/>
-      <unit id="org.eclipse.jetty.http.source" version="9.4.5.v20170502"/>
-      <unit id="org.eclipse.jetty.io" version="9.4.5.v20170502"/>
-      <unit id="org.eclipse.jetty.io.source" version="9.4.5.v20170502"/>
-      <unit id="org.eclipse.jetty.security" version="9.4.5.v20170502"/>
-      <unit id="org.eclipse.jetty.security.source" version="9.4.5.v20170502"/>
-      <unit id="org.eclipse.jetty.server" version="9.4.5.v20170502"/>
-      <unit id="org.eclipse.jetty.server.source" version="9.4.5.v20170502"/>
-      <unit id="org.eclipse.jetty.servlet" version="9.4.5.v20170502"/>
-      <unit id="org.eclipse.jetty.servlet.source" version="9.4.5.v20170502"/>
-      <unit id="org.eclipse.jetty.util" version="9.4.5.v20170502"/>
-      <unit id="org.eclipse.jetty.util.source" version="9.4.5.v20170502"/>
-      <repository id="jetty-9.4.5" location="http://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.4.5.v20170502/"/>
-    </location>
-    <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
-      <unit id="org.apache.ant" version="1.9.4.v201504302020"/>
-      <unit id="org.apache.ant.source" version="1.9.4.v201504302020"/>
-      <unit id="org.apache.commons.compress" version="1.6.0.v201310281400"/>
-      <unit id="org.apache.commons.compress.source" version="1.6.0.v201310281400"/>
-      <unit id="org.apache.commons.logging" version="1.1.1.v201101211721"/>
-      <unit id="org.apache.commons.logging.source" version="1.1.1.v201101211721"/>
-      <unit id="org.apache.httpcomponents.httpcore" version="4.3.3.v201411290715"/>
-      <unit id="org.apache.httpcomponents.httpcore.source" version="4.3.3.v201411290715"/>
-      <unit id="org.apache.httpcomponents.httpclient" version="4.3.6.v201411290715B"/>
-      <unit id="org.apache.httpcomponents.httpclient.source" version="4.3.6.v201411290715B"/>
-      <unit id="org.apache.log4j" version="1.2.15.v201012070815"/>
-      <unit id="org.apache.log4j.source" version="1.2.15.v201012070815"/>
-      <unit id="org.kohsuke.args4j" version="2.0.21.v201301150030"/>
-      <unit id="org.kohsuke.args4j.source" version="2.0.21.v201301150030"/>
-      <unit id="org.hamcrest.core" version="1.3.0.v201303031735"/>
-      <unit id="org.hamcrest.core.source" version="1.3.0.v201303031735"/>
-      <unit id="javaewah" version="0.7.9.v201401101600"/>
-      <unit id="javaewah.source" version="0.7.9.v201401101600"/>
-      <unit id="org.objenesis" version="1.0.0.v201505121915"/>
-      <unit id="org.objenesis.source" version="1.0.0.v201505121915"/>
-      <unit id="org.mockito" version="1.8.4.v201303031500"/>
-      <unit id="org.mockito.source" version="1.8.4.v201303031500"/>
-      <unit id="com.google.gson" version="2.2.4.v201311231704"/>
-      <unit id="com.jcraft.jsch" version="0.1.53.v201508180515"/>
-      <unit id="com.jcraft.jsch.source" version="0.1.53.v201508180515"/>
-      <unit id="org.junit" version="4.11.0.v201303080030"/>
-      <unit id="org.junit.source" version="4.11.0.v201303080030"/>
-      <unit id="javax.servlet" version="3.1.0.v201410161800"/>
-      <unit id="javax.servlet.source" version="3.1.0.v201410161800"/>
-      <unit id="org.tukaani.xz" version="1.3.0.v201308270617"/>
-      <unit id="org.tukaani.xz.source" version="1.3.0.v201308270617"/>
-      <unit id="org.slf4j.api" version="1.7.2.v20121108-1250"/>
-      <unit id="org.slf4j.api.source" version="1.7.2.v20121108-1250"/>
-      <unit id="org.slf4j.impl.log4j12" version="1.7.2.v20131105-2200"/>
-      <unit id="org.slf4j.impl.log4j12.source" version="1.7.2.v20131105-2200"/>
-      <repository location="http://download.eclipse.org/tools/orbit/downloads/drops/R20160221192158/repository/"/>
+      <unit id="org.eclipse.jetty.client" version="9.4.8.v20171121"/>
+      <unit id="org.eclipse.jetty.client.source" version="9.4.8.v20171121"/>
+      <unit id="org.eclipse.jetty.continuation" version="9.4.8.v20171121"/>
+      <unit id="org.eclipse.jetty.continuation.source" version="9.4.8.v20171121"/>
+      <unit id="org.eclipse.jetty.http" version="9.4.8.v20171121"/>
+      <unit id="org.eclipse.jetty.http.source" version="9.4.8.v20171121"/>
+      <unit id="org.eclipse.jetty.io" version="9.4.8.v20171121"/>
+      <unit id="org.eclipse.jetty.io.source" version="9.4.8.v20171121"/>
+      <unit id="org.eclipse.jetty.security" version="9.4.8.v20171121"/>
+      <unit id="org.eclipse.jetty.security.source" version="9.4.8.v20171121"/>
+      <unit id="org.eclipse.jetty.server" version="9.4.8.v20171121"/>
+      <unit id="org.eclipse.jetty.server.source" version="9.4.8.v20171121"/>
+      <unit id="org.eclipse.jetty.servlet" version="9.4.8.v20171121"/>
+      <unit id="org.eclipse.jetty.servlet.source" version="9.4.8.v20171121"/>
+      <unit id="org.eclipse.jetty.util" version="9.4.8.v20171121"/>
+      <unit id="org.eclipse.jetty.util.source" version="9.4.8.v20171121"/>
+      <repository id="jetty-9.4.8" location="http://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.4.8.v20171121"/>
     </location>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
       <unit id="org.apache.ant" version="1.9.6.v201510161327"/>
       <unit id="org.apache.ant.source" version="1.9.6.v201510161327"/>
       <unit id="org.apache.commons.codec" version="1.9.0.v20170208-1614"/>
       <unit id="org.apache.commons.codec.source" version="1.9.0.v20170208-1614"/>
-      <unit id="org.apache.commons.compress" version="1.6.0.v201310281400"/>
-      <unit id="org.apache.commons.compress.source" version="1.6.0.v201310281400"/>
+      <unit id="org.apache.commons.compress" version="1.15.0.v20180119-1613"/>
+      <unit id="org.apache.commons.compress.source" version="1.15.0.v20180119-1613"/>
       <unit id="org.apache.commons.logging" version="1.1.1.v201101211721"/>
       <unit id="org.apache.commons.logging.source" version="1.1.1.v201101211721"/>
-      <unit id="org.apache.httpcomponents.httpcore" version="4.3.3.v201411290715"/>
-      <unit id="org.apache.httpcomponents.httpcore.source" version="4.3.3.v201411290715"/>
-      <unit id="org.apache.httpcomponents.httpclient" version="4.3.6.v201511171540"/>
-      <unit id="org.apache.httpcomponents.httpclient.source" version="4.3.6.v201511171540"/>
+      <unit id="org.apache.httpcomponents.httpcore" version="4.4.6.v20170210-0925"/>
+      <unit id="org.apache.httpcomponents.httpcore.source" version="4.4.6.v20170210-0925"/>
+      <unit id="org.apache.httpcomponents.httpclient" version="4.5.2.v20180410-1551"/>
+      <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.2.v20180410-1551"/>
       <unit id="org.apache.log4j" version="1.2.15.v201012070815"/>
       <unit id="org.apache.log4j.source" version="1.2.15.v201012070815"/>
       <unit id="org.kohsuke.args4j" version="2.33.0.v20160323-2218"/>
       <unit id="org.kohsuke.args4j.source" version="2.33.0.v20160323-2218"/>
-      <unit id="org.hamcrest.core" version="1.3.0.v201303031735"/>
-      <unit id="org.hamcrest.core.source" version="1.3.0.v201303031735"/>
-      <unit id="org.hamcrest.library" version="1.3.0.v201505072020"/>
-      <unit id="org.hamcrest.library.source" version="1.3.0.v201505072020"/>
+      <unit id="org.hamcrest" version="1.1.0.v20090501071000"/>
+      <unit id="org.hamcrest.core" version="1.3.0.v20180420-1519"/>
+      <unit id="org.hamcrest.core.source" version="1.3.0.v20180420-1519"/>
+      <unit id="org.hamcrest.library" version="1.3.0.v20180524-2246"/>
+      <unit id="org.hamcrest.library.source" version="1.3.0.v20180524-2246"/>
       <unit id="javaewah" version="1.1.6.v20160919-1400"/>
       <unit id="javaewah.source" version="1.1.6.v20160919-1400"/>
       <unit id="org.objenesis" version="1.0.0.v201505121915"/>
       <unit id="org.objenesis.source" version="1.0.0.v201505121915"/>
       <unit id="org.mockito" version="1.8.4.v201303031500"/>
       <unit id="org.mockito.source" version="1.8.4.v201303031500"/>
-      <unit id="com.google.gson" version="2.2.4.v201311231704"/>
+      <unit id="com.google.gson" version="2.8.2.v20180104-1110"/>
+      <unit id="com.google.gson.source" version="2.8.2.v20180104-1110"/>
       <unit id="com.jcraft.jsch" version="0.1.54.v20170116-1932"/>
       <unit id="com.jcraft.jsch.source" version="0.1.54.v20170116-1932"/>
       <unit id="org.junit" version="4.12.0.v201504281640"/>
       <unit id="org.junit.source" version="4.12.0.v201504281640"/>
       <unit id="javax.servlet" version="3.1.0.v201410161800"/>
       <unit id="javax.servlet.source" version="3.1.0.v201410161800"/>
-      <unit id="org.tukaani.xz" version="1.3.0.v201308270617"/>
-      <unit id="org.tukaani.xz.source" version="1.3.0.v201308270617"/>
+      <unit id="org.tukaani.xz" version="1.6.0.v20170629-1752"/>
+      <unit id="org.tukaani.xz.source" version="1.6.0.v20170629-1752"/>
       <unit id="org.slf4j.api" version="1.7.2.v20121108-1250"/>
       <unit id="org.slf4j.api.source" version="1.7.2.v20121108-1250"/>
       <unit id="org.slf4j.impl.log4j12" version="1.7.2.v20131105-2200"/>
       <unit id="org.slf4j.impl.log4j12.source" version="1.7.2.v20131105-2200"/>
-      <repository location="http://download.eclipse.org/tools/orbit/downloads/drops/R20170516192513/repository"/>
+      <unit id="com.jcraft.jzlib" version="1.1.1.v201205102305"/>
+      <unit id="com.jcraft.jzlib.source" version="1.1.1.v201205102305"/>
+      <repository location="http://download.eclipse.org/tools/orbit/downloads/drops/R20180606145124/repository"/>
     </location>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
       <unit id="org.eclipse.osgi" version="0.0.0"/>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.5.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.5.tpd
index f9653b2..c85343c 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.5.tpd
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.5.tpd
@@ -1,8 +1,7 @@
 target "jgit-4.5" with source configurePhase
 
-include "projects/jetty-9.4.5.tpd"
-include "orbit/R20160221192158-Mars.tpd"
-include "orbit/R20170516192513-Oxygen.tpd"
+include "projects/jetty-9.4.8.tpd"
+include "orbit/R20180606145124-Photon.tpd"
 
 location "http://download.eclipse.org/releases/mars/" {
 	org.eclipse.osgi lazy
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.6.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.6.target
index 48cd300..909b330 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.6.target
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.6.target
@@ -1,68 +1,72 @@
 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
 <?pde?>
 <!-- generated with https://github.com/mbarbero/fr.obeo.releng.targetplatform -->
-<target name="jgit-4.6" sequenceNumber="1504051999">
+<target name="jgit-4.6" sequenceNumber="1528375359">
   <locations>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
-      <unit id="org.eclipse.jetty.client" version="9.4.5.v20170502"/>
-      <unit id="org.eclipse.jetty.client.source" version="9.4.5.v20170502"/>
-      <unit id="org.eclipse.jetty.continuation" version="9.4.5.v20170502"/>
-      <unit id="org.eclipse.jetty.continuation.source" version="9.4.5.v20170502"/>
-      <unit id="org.eclipse.jetty.http" version="9.4.5.v20170502"/>
-      <unit id="org.eclipse.jetty.http.source" version="9.4.5.v20170502"/>
-      <unit id="org.eclipse.jetty.io" version="9.4.5.v20170502"/>
-      <unit id="org.eclipse.jetty.io.source" version="9.4.5.v20170502"/>
-      <unit id="org.eclipse.jetty.security" version="9.4.5.v20170502"/>
-      <unit id="org.eclipse.jetty.security.source" version="9.4.5.v20170502"/>
-      <unit id="org.eclipse.jetty.server" version="9.4.5.v20170502"/>
-      <unit id="org.eclipse.jetty.server.source" version="9.4.5.v20170502"/>
-      <unit id="org.eclipse.jetty.servlet" version="9.4.5.v20170502"/>
-      <unit id="org.eclipse.jetty.servlet.source" version="9.4.5.v20170502"/>
-      <unit id="org.eclipse.jetty.util" version="9.4.5.v20170502"/>
-      <unit id="org.eclipse.jetty.util.source" version="9.4.5.v20170502"/>
-      <repository id="jetty-9.4.5" location="http://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.4.5.v20170502/"/>
+      <unit id="org.eclipse.jetty.client" version="9.4.8.v20171121"/>
+      <unit id="org.eclipse.jetty.client.source" version="9.4.8.v20171121"/>
+      <unit id="org.eclipse.jetty.continuation" version="9.4.8.v20171121"/>
+      <unit id="org.eclipse.jetty.continuation.source" version="9.4.8.v20171121"/>
+      <unit id="org.eclipse.jetty.http" version="9.4.8.v20171121"/>
+      <unit id="org.eclipse.jetty.http.source" version="9.4.8.v20171121"/>
+      <unit id="org.eclipse.jetty.io" version="9.4.8.v20171121"/>
+      <unit id="org.eclipse.jetty.io.source" version="9.4.8.v20171121"/>
+      <unit id="org.eclipse.jetty.security" version="9.4.8.v20171121"/>
+      <unit id="org.eclipse.jetty.security.source" version="9.4.8.v20171121"/>
+      <unit id="org.eclipse.jetty.server" version="9.4.8.v20171121"/>
+      <unit id="org.eclipse.jetty.server.source" version="9.4.8.v20171121"/>
+      <unit id="org.eclipse.jetty.servlet" version="9.4.8.v20171121"/>
+      <unit id="org.eclipse.jetty.servlet.source" version="9.4.8.v20171121"/>
+      <unit id="org.eclipse.jetty.util" version="9.4.8.v20171121"/>
+      <unit id="org.eclipse.jetty.util.source" version="9.4.8.v20171121"/>
+      <repository id="jetty-9.4.8" location="http://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.4.8.v20171121"/>
     </location>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
       <unit id="org.apache.ant" version="1.9.6.v201510161327"/>
       <unit id="org.apache.ant.source" version="1.9.6.v201510161327"/>
       <unit id="org.apache.commons.codec" version="1.9.0.v20170208-1614"/>
       <unit id="org.apache.commons.codec.source" version="1.9.0.v20170208-1614"/>
-      <unit id="org.apache.commons.compress" version="1.6.0.v201310281400"/>
-      <unit id="org.apache.commons.compress.source" version="1.6.0.v201310281400"/>
+      <unit id="org.apache.commons.compress" version="1.15.0.v20180119-1613"/>
+      <unit id="org.apache.commons.compress.source" version="1.15.0.v20180119-1613"/>
       <unit id="org.apache.commons.logging" version="1.1.1.v201101211721"/>
       <unit id="org.apache.commons.logging.source" version="1.1.1.v201101211721"/>
-      <unit id="org.apache.httpcomponents.httpcore" version="4.3.3.v201411290715"/>
-      <unit id="org.apache.httpcomponents.httpcore.source" version="4.3.3.v201411290715"/>
-      <unit id="org.apache.httpcomponents.httpclient" version="4.3.6.v201511171540"/>
-      <unit id="org.apache.httpcomponents.httpclient.source" version="4.3.6.v201511171540"/>
+      <unit id="org.apache.httpcomponents.httpcore" version="4.4.6.v20170210-0925"/>
+      <unit id="org.apache.httpcomponents.httpcore.source" version="4.4.6.v20170210-0925"/>
+      <unit id="org.apache.httpcomponents.httpclient" version="4.5.2.v20180410-1551"/>
+      <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.2.v20180410-1551"/>
       <unit id="org.apache.log4j" version="1.2.15.v201012070815"/>
       <unit id="org.apache.log4j.source" version="1.2.15.v201012070815"/>
       <unit id="org.kohsuke.args4j" version="2.33.0.v20160323-2218"/>
       <unit id="org.kohsuke.args4j.source" version="2.33.0.v20160323-2218"/>
-      <unit id="org.hamcrest.core" version="1.3.0.v201303031735"/>
-      <unit id="org.hamcrest.core.source" version="1.3.0.v201303031735"/>
-      <unit id="org.hamcrest.library" version="1.3.0.v201505072020"/>
-      <unit id="org.hamcrest.library.source" version="1.3.0.v201505072020"/>
+      <unit id="org.hamcrest" version="1.1.0.v20090501071000"/>
+      <unit id="org.hamcrest.core" version="1.3.0.v20180420-1519"/>
+      <unit id="org.hamcrest.core.source" version="1.3.0.v20180420-1519"/>
+      <unit id="org.hamcrest.library" version="1.3.0.v20180524-2246"/>
+      <unit id="org.hamcrest.library.source" version="1.3.0.v20180524-2246"/>
       <unit id="javaewah" version="1.1.6.v20160919-1400"/>
       <unit id="javaewah.source" version="1.1.6.v20160919-1400"/>
       <unit id="org.objenesis" version="1.0.0.v201505121915"/>
       <unit id="org.objenesis.source" version="1.0.0.v201505121915"/>
       <unit id="org.mockito" version="1.8.4.v201303031500"/>
       <unit id="org.mockito.source" version="1.8.4.v201303031500"/>
-      <unit id="com.google.gson" version="2.2.4.v201311231704"/>
+      <unit id="com.google.gson" version="2.8.2.v20180104-1110"/>
+      <unit id="com.google.gson.source" version="2.8.2.v20180104-1110"/>
       <unit id="com.jcraft.jsch" version="0.1.54.v20170116-1932"/>
       <unit id="com.jcraft.jsch.source" version="0.1.54.v20170116-1932"/>
       <unit id="org.junit" version="4.12.0.v201504281640"/>
       <unit id="org.junit.source" version="4.12.0.v201504281640"/>
       <unit id="javax.servlet" version="3.1.0.v201410161800"/>
       <unit id="javax.servlet.source" version="3.1.0.v201410161800"/>
-      <unit id="org.tukaani.xz" version="1.3.0.v201308270617"/>
-      <unit id="org.tukaani.xz.source" version="1.3.0.v201308270617"/>
+      <unit id="org.tukaani.xz" version="1.6.0.v20170629-1752"/>
+      <unit id="org.tukaani.xz.source" version="1.6.0.v20170629-1752"/>
       <unit id="org.slf4j.api" version="1.7.2.v20121108-1250"/>
       <unit id="org.slf4j.api.source" version="1.7.2.v20121108-1250"/>
       <unit id="org.slf4j.impl.log4j12" version="1.7.2.v20131105-2200"/>
       <unit id="org.slf4j.impl.log4j12.source" version="1.7.2.v20131105-2200"/>
-      <repository location="http://download.eclipse.org/tools/orbit/downloads/drops/R20170516192513/repository"/>
+      <unit id="com.jcraft.jzlib" version="1.1.1.v201205102305"/>
+      <unit id="com.jcraft.jzlib.source" version="1.1.1.v201205102305"/>
+      <repository location="http://download.eclipse.org/tools/orbit/downloads/drops/R20180606145124/repository"/>
     </location>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
       <unit id="org.eclipse.osgi" version="0.0.0"/>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.6.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.6.tpd
index 9ddba2d..3c2a910 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.6.tpd
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.6.tpd
@@ -1,7 +1,7 @@
 target "jgit-4.6" with source configurePhase
 
-include "projects/jetty-9.4.5.tpd"
-include "orbit/R20170516192513-Oxygen.tpd"
+include "projects/jetty-9.4.8.tpd"
+include "orbit/R20180606145124-Photon.tpd"
 
 location "http://download.eclipse.org/releases/neon/" {
 	org.eclipse.osgi lazy
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.7.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.7.target
index 4ac65dd..8b064bc 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.7.target
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.7.target
@@ -1,68 +1,72 @@
 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
 <?pde?>
 <!-- generated with https://github.com/mbarbero/fr.obeo.releng.targetplatform -->
-<target name="jgit-4.7" sequenceNumber="1504051975">
+<target name="jgit-4.7" sequenceNumber="1528375339">
   <locations>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
-      <unit id="org.eclipse.jetty.client" version="9.4.5.v20170502"/>
-      <unit id="org.eclipse.jetty.client.source" version="9.4.5.v20170502"/>
-      <unit id="org.eclipse.jetty.continuation" version="9.4.5.v20170502"/>
-      <unit id="org.eclipse.jetty.continuation.source" version="9.4.5.v20170502"/>
-      <unit id="org.eclipse.jetty.http" version="9.4.5.v20170502"/>
-      <unit id="org.eclipse.jetty.http.source" version="9.4.5.v20170502"/>
-      <unit id="org.eclipse.jetty.io" version="9.4.5.v20170502"/>
-      <unit id="org.eclipse.jetty.io.source" version="9.4.5.v20170502"/>
-      <unit id="org.eclipse.jetty.security" version="9.4.5.v20170502"/>
-      <unit id="org.eclipse.jetty.security.source" version="9.4.5.v20170502"/>
-      <unit id="org.eclipse.jetty.server" version="9.4.5.v20170502"/>
-      <unit id="org.eclipse.jetty.server.source" version="9.4.5.v20170502"/>
-      <unit id="org.eclipse.jetty.servlet" version="9.4.5.v20170502"/>
-      <unit id="org.eclipse.jetty.servlet.source" version="9.4.5.v20170502"/>
-      <unit id="org.eclipse.jetty.util" version="9.4.5.v20170502"/>
-      <unit id="org.eclipse.jetty.util.source" version="9.4.5.v20170502"/>
-      <repository id="jetty-9.4.5" location="http://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.4.5.v20170502/"/>
+      <unit id="org.eclipse.jetty.client" version="9.4.8.v20171121"/>
+      <unit id="org.eclipse.jetty.client.source" version="9.4.8.v20171121"/>
+      <unit id="org.eclipse.jetty.continuation" version="9.4.8.v20171121"/>
+      <unit id="org.eclipse.jetty.continuation.source" version="9.4.8.v20171121"/>
+      <unit id="org.eclipse.jetty.http" version="9.4.8.v20171121"/>
+      <unit id="org.eclipse.jetty.http.source" version="9.4.8.v20171121"/>
+      <unit id="org.eclipse.jetty.io" version="9.4.8.v20171121"/>
+      <unit id="org.eclipse.jetty.io.source" version="9.4.8.v20171121"/>
+      <unit id="org.eclipse.jetty.security" version="9.4.8.v20171121"/>
+      <unit id="org.eclipse.jetty.security.source" version="9.4.8.v20171121"/>
+      <unit id="org.eclipse.jetty.server" version="9.4.8.v20171121"/>
+      <unit id="org.eclipse.jetty.server.source" version="9.4.8.v20171121"/>
+      <unit id="org.eclipse.jetty.servlet" version="9.4.8.v20171121"/>
+      <unit id="org.eclipse.jetty.servlet.source" version="9.4.8.v20171121"/>
+      <unit id="org.eclipse.jetty.util" version="9.4.8.v20171121"/>
+      <unit id="org.eclipse.jetty.util.source" version="9.4.8.v20171121"/>
+      <repository id="jetty-9.4.8" location="http://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.4.8.v20171121"/>
     </location>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
       <unit id="org.apache.ant" version="1.9.6.v201510161327"/>
       <unit id="org.apache.ant.source" version="1.9.6.v201510161327"/>
       <unit id="org.apache.commons.codec" version="1.9.0.v20170208-1614"/>
       <unit id="org.apache.commons.codec.source" version="1.9.0.v20170208-1614"/>
-      <unit id="org.apache.commons.compress" version="1.6.0.v201310281400"/>
-      <unit id="org.apache.commons.compress.source" version="1.6.0.v201310281400"/>
+      <unit id="org.apache.commons.compress" version="1.15.0.v20180119-1613"/>
+      <unit id="org.apache.commons.compress.source" version="1.15.0.v20180119-1613"/>
       <unit id="org.apache.commons.logging" version="1.1.1.v201101211721"/>
       <unit id="org.apache.commons.logging.source" version="1.1.1.v201101211721"/>
-      <unit id="org.apache.httpcomponents.httpcore" version="4.3.3.v201411290715"/>
-      <unit id="org.apache.httpcomponents.httpcore.source" version="4.3.3.v201411290715"/>
-      <unit id="org.apache.httpcomponents.httpclient" version="4.3.6.v201511171540"/>
-      <unit id="org.apache.httpcomponents.httpclient.source" version="4.3.6.v201511171540"/>
+      <unit id="org.apache.httpcomponents.httpcore" version="4.4.6.v20170210-0925"/>
+      <unit id="org.apache.httpcomponents.httpcore.source" version="4.4.6.v20170210-0925"/>
+      <unit id="org.apache.httpcomponents.httpclient" version="4.5.2.v20180410-1551"/>
+      <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.2.v20180410-1551"/>
       <unit id="org.apache.log4j" version="1.2.15.v201012070815"/>
       <unit id="org.apache.log4j.source" version="1.2.15.v201012070815"/>
       <unit id="org.kohsuke.args4j" version="2.33.0.v20160323-2218"/>
       <unit id="org.kohsuke.args4j.source" version="2.33.0.v20160323-2218"/>
-      <unit id="org.hamcrest.core" version="1.3.0.v201303031735"/>
-      <unit id="org.hamcrest.core.source" version="1.3.0.v201303031735"/>
-      <unit id="org.hamcrest.library" version="1.3.0.v201505072020"/>
-      <unit id="org.hamcrest.library.source" version="1.3.0.v201505072020"/>
+      <unit id="org.hamcrest" version="1.1.0.v20090501071000"/>
+      <unit id="org.hamcrest.core" version="1.3.0.v20180420-1519"/>
+      <unit id="org.hamcrest.core.source" version="1.3.0.v20180420-1519"/>
+      <unit id="org.hamcrest.library" version="1.3.0.v20180524-2246"/>
+      <unit id="org.hamcrest.library.source" version="1.3.0.v20180524-2246"/>
       <unit id="javaewah" version="1.1.6.v20160919-1400"/>
       <unit id="javaewah.source" version="1.1.6.v20160919-1400"/>
       <unit id="org.objenesis" version="1.0.0.v201505121915"/>
       <unit id="org.objenesis.source" version="1.0.0.v201505121915"/>
       <unit id="org.mockito" version="1.8.4.v201303031500"/>
       <unit id="org.mockito.source" version="1.8.4.v201303031500"/>
-      <unit id="com.google.gson" version="2.2.4.v201311231704"/>
+      <unit id="com.google.gson" version="2.8.2.v20180104-1110"/>
+      <unit id="com.google.gson.source" version="2.8.2.v20180104-1110"/>
       <unit id="com.jcraft.jsch" version="0.1.54.v20170116-1932"/>
       <unit id="com.jcraft.jsch.source" version="0.1.54.v20170116-1932"/>
       <unit id="org.junit" version="4.12.0.v201504281640"/>
       <unit id="org.junit.source" version="4.12.0.v201504281640"/>
       <unit id="javax.servlet" version="3.1.0.v201410161800"/>
       <unit id="javax.servlet.source" version="3.1.0.v201410161800"/>
-      <unit id="org.tukaani.xz" version="1.3.0.v201308270617"/>
-      <unit id="org.tukaani.xz.source" version="1.3.0.v201308270617"/>
+      <unit id="org.tukaani.xz" version="1.6.0.v20170629-1752"/>
+      <unit id="org.tukaani.xz.source" version="1.6.0.v20170629-1752"/>
       <unit id="org.slf4j.api" version="1.7.2.v20121108-1250"/>
       <unit id="org.slf4j.api.source" version="1.7.2.v20121108-1250"/>
       <unit id="org.slf4j.impl.log4j12" version="1.7.2.v20131105-2200"/>
       <unit id="org.slf4j.impl.log4j12.source" version="1.7.2.v20131105-2200"/>
-      <repository location="http://download.eclipse.org/tools/orbit/downloads/drops/R20170516192513/repository"/>
+      <unit id="com.jcraft.jzlib" version="1.1.1.v201205102305"/>
+      <unit id="com.jcraft.jzlib.source" version="1.1.1.v201205102305"/>
+      <repository location="http://download.eclipse.org/tools/orbit/downloads/drops/R20180606145124/repository"/>
     </location>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
       <unit id="org.eclipse.osgi" version="0.0.0"/>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.7.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.7.tpd
index 4185079..4e543ff 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.7.tpd
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.7.tpd
@@ -1,7 +1,7 @@
 target "jgit-4.7" with source configurePhase
 
-include "projects/jetty-9.4.5.tpd"
-include "orbit/R20170516192513-Oxygen.tpd"
+include "projects/jetty-9.4.8.tpd"
+include "orbit/R20180606145124-Photon.tpd"
 
 location "http://download.eclipse.org/releases/oxygen/" {
 	org.eclipse.osgi lazy
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.8.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.8.target
index 390d72d..564b493 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.8.target
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.8.target
@@ -1,68 +1,72 @@
 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
 <?pde?>
 <!-- generated with https://github.com/mbarbero/fr.obeo.releng.targetplatform -->
-<target name="jgit-4.8" sequenceNumber="1506813373">
+<target name="jgit-4.8" sequenceNumber="1528373976">
   <locations>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
-      <unit id="org.eclipse.jetty.client" version="9.4.5.v20170502"/>
-      <unit id="org.eclipse.jetty.client.source" version="9.4.5.v20170502"/>
-      <unit id="org.eclipse.jetty.continuation" version="9.4.5.v20170502"/>
-      <unit id="org.eclipse.jetty.continuation.source" version="9.4.5.v20170502"/>
-      <unit id="org.eclipse.jetty.http" version="9.4.5.v20170502"/>
-      <unit id="org.eclipse.jetty.http.source" version="9.4.5.v20170502"/>
-      <unit id="org.eclipse.jetty.io" version="9.4.5.v20170502"/>
-      <unit id="org.eclipse.jetty.io.source" version="9.4.5.v20170502"/>
-      <unit id="org.eclipse.jetty.security" version="9.4.5.v20170502"/>
-      <unit id="org.eclipse.jetty.security.source" version="9.4.5.v20170502"/>
-      <unit id="org.eclipse.jetty.server" version="9.4.5.v20170502"/>
-      <unit id="org.eclipse.jetty.server.source" version="9.4.5.v20170502"/>
-      <unit id="org.eclipse.jetty.servlet" version="9.4.5.v20170502"/>
-      <unit id="org.eclipse.jetty.servlet.source" version="9.4.5.v20170502"/>
-      <unit id="org.eclipse.jetty.util" version="9.4.5.v20170502"/>
-      <unit id="org.eclipse.jetty.util.source" version="9.4.5.v20170502"/>
-      <repository id="jetty-9.4.5" location="http://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.4.5.v20170502/"/>
+      <unit id="org.eclipse.jetty.client" version="9.4.8.v20171121"/>
+      <unit id="org.eclipse.jetty.client.source" version="9.4.8.v20171121"/>
+      <unit id="org.eclipse.jetty.continuation" version="9.4.8.v20171121"/>
+      <unit id="org.eclipse.jetty.continuation.source" version="9.4.8.v20171121"/>
+      <unit id="org.eclipse.jetty.http" version="9.4.8.v20171121"/>
+      <unit id="org.eclipse.jetty.http.source" version="9.4.8.v20171121"/>
+      <unit id="org.eclipse.jetty.io" version="9.4.8.v20171121"/>
+      <unit id="org.eclipse.jetty.io.source" version="9.4.8.v20171121"/>
+      <unit id="org.eclipse.jetty.security" version="9.4.8.v20171121"/>
+      <unit id="org.eclipse.jetty.security.source" version="9.4.8.v20171121"/>
+      <unit id="org.eclipse.jetty.server" version="9.4.8.v20171121"/>
+      <unit id="org.eclipse.jetty.server.source" version="9.4.8.v20171121"/>
+      <unit id="org.eclipse.jetty.servlet" version="9.4.8.v20171121"/>
+      <unit id="org.eclipse.jetty.servlet.source" version="9.4.8.v20171121"/>
+      <unit id="org.eclipse.jetty.util" version="9.4.8.v20171121"/>
+      <unit id="org.eclipse.jetty.util.source" version="9.4.8.v20171121"/>
+      <repository id="jetty-9.4.8" location="http://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.4.8.v20171121"/>
     </location>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
       <unit id="org.apache.ant" version="1.9.6.v201510161327"/>
       <unit id="org.apache.ant.source" version="1.9.6.v201510161327"/>
       <unit id="org.apache.commons.codec" version="1.9.0.v20170208-1614"/>
       <unit id="org.apache.commons.codec.source" version="1.9.0.v20170208-1614"/>
-      <unit id="org.apache.commons.compress" version="1.6.0.v201310281400"/>
-      <unit id="org.apache.commons.compress.source" version="1.6.0.v201310281400"/>
+      <unit id="org.apache.commons.compress" version="1.15.0.v20180119-1613"/>
+      <unit id="org.apache.commons.compress.source" version="1.15.0.v20180119-1613"/>
       <unit id="org.apache.commons.logging" version="1.1.1.v201101211721"/>
       <unit id="org.apache.commons.logging.source" version="1.1.1.v201101211721"/>
-      <unit id="org.apache.httpcomponents.httpcore" version="4.3.3.v201411290715"/>
-      <unit id="org.apache.httpcomponents.httpcore.source" version="4.3.3.v201411290715"/>
-      <unit id="org.apache.httpcomponents.httpclient" version="4.3.6.v201511171540"/>
-      <unit id="org.apache.httpcomponents.httpclient.source" version="4.3.6.v201511171540"/>
+      <unit id="org.apache.httpcomponents.httpcore" version="4.4.6.v20170210-0925"/>
+      <unit id="org.apache.httpcomponents.httpcore.source" version="4.4.6.v20170210-0925"/>
+      <unit id="org.apache.httpcomponents.httpclient" version="4.5.2.v20180410-1551"/>
+      <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.2.v20180410-1551"/>
       <unit id="org.apache.log4j" version="1.2.15.v201012070815"/>
       <unit id="org.apache.log4j.source" version="1.2.15.v201012070815"/>
       <unit id="org.kohsuke.args4j" version="2.33.0.v20160323-2218"/>
       <unit id="org.kohsuke.args4j.source" version="2.33.0.v20160323-2218"/>
-      <unit id="org.hamcrest.core" version="1.3.0.v201303031735"/>
-      <unit id="org.hamcrest.core.source" version="1.3.0.v201303031735"/>
-      <unit id="org.hamcrest.library" version="1.3.0.v201505072020"/>
-      <unit id="org.hamcrest.library.source" version="1.3.0.v201505072020"/>
+      <unit id="org.hamcrest" version="1.1.0.v20090501071000"/>
+      <unit id="org.hamcrest.core" version="1.3.0.v20180420-1519"/>
+      <unit id="org.hamcrest.core.source" version="1.3.0.v20180420-1519"/>
+      <unit id="org.hamcrest.library" version="1.3.0.v20180524-2246"/>
+      <unit id="org.hamcrest.library.source" version="1.3.0.v20180524-2246"/>
       <unit id="javaewah" version="1.1.6.v20160919-1400"/>
       <unit id="javaewah.source" version="1.1.6.v20160919-1400"/>
       <unit id="org.objenesis" version="1.0.0.v201505121915"/>
       <unit id="org.objenesis.source" version="1.0.0.v201505121915"/>
       <unit id="org.mockito" version="1.8.4.v201303031500"/>
       <unit id="org.mockito.source" version="1.8.4.v201303031500"/>
-      <unit id="com.google.gson" version="2.2.4.v201311231704"/>
+      <unit id="com.google.gson" version="2.8.2.v20180104-1110"/>
+      <unit id="com.google.gson.source" version="2.8.2.v20180104-1110"/>
       <unit id="com.jcraft.jsch" version="0.1.54.v20170116-1932"/>
       <unit id="com.jcraft.jsch.source" version="0.1.54.v20170116-1932"/>
       <unit id="org.junit" version="4.12.0.v201504281640"/>
       <unit id="org.junit.source" version="4.12.0.v201504281640"/>
       <unit id="javax.servlet" version="3.1.0.v201410161800"/>
       <unit id="javax.servlet.source" version="3.1.0.v201410161800"/>
-      <unit id="org.tukaani.xz" version="1.3.0.v201308270617"/>
-      <unit id="org.tukaani.xz.source" version="1.3.0.v201308270617"/>
+      <unit id="org.tukaani.xz" version="1.6.0.v20170629-1752"/>
+      <unit id="org.tukaani.xz.source" version="1.6.0.v20170629-1752"/>
       <unit id="org.slf4j.api" version="1.7.2.v20121108-1250"/>
       <unit id="org.slf4j.api.source" version="1.7.2.v20121108-1250"/>
       <unit id="org.slf4j.impl.log4j12" version="1.7.2.v20131105-2200"/>
       <unit id="org.slf4j.impl.log4j12.source" version="1.7.2.v20131105-2200"/>
-      <repository location="http://download.eclipse.org/tools/orbit/downloads/drops/S20170912163609/repository"/>
+      <unit id="com.jcraft.jzlib" version="1.1.1.v201205102305"/>
+      <unit id="com.jcraft.jzlib.source" version="1.1.1.v201205102305"/>
+      <repository location="http://download.eclipse.org/tools/orbit/downloads/drops/R20180606145124/repository"/>
     </location>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
       <unit id="org.eclipse.osgi" version="0.0.0"/>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.8.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.8.tpd
index 39d7553..efcba7c 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.8.tpd
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.8.tpd
@@ -1,7 +1,7 @@
 target "jgit-4.8" with source configurePhase
 
-include "projects/jetty-9.4.5.tpd"
-include "orbit/S20170912163609-Photon.tpd"
+include "projects/jetty-9.4.8.tpd"
+include "orbit/R20180606145124-Photon.tpd"
 
 location "http://download.eclipse.org/releases/oxygen/" {
 	org.eclipse.osgi lazy
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/R20150124073747-Luna-SR2.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/R20150124073747-Luna-SR2.tpd
deleted file mode 100644
index d9e072f..0000000
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/R20150124073747-Luna-SR2.tpd
+++ /dev/null
@@ -1,40 +0,0 @@
-target "R20150124073747" with source configurePhase
-// see http://download.eclipse.org/tools/orbit/downloads/
-
-location "http://download.eclipse.org/tools/orbit/downloads/drops/R20150124073747/repository/" {
-	org.apache.ant [1.9.2.v201404171502,1.9.2.v201404171502]
-	org.apache.ant.source [1.9.2.v201404171502,1.9.2.v201404171502]
-	org.apache.commons.compress [1.6.0.v201310281400,1.6.0.v201310281400]
-	org.apache.commons.compress.source [1.6.0.v201310281400,1.6.0.v201310281400]
-	org.apache.commons.logging [1.1.1.v201101211721,1.1.1.v201101211721]
-	org.apache.commons.logging.source [1.1.1.v201101211721,1.1.1.v201101211721]
-	org.apache.httpcomponents.httpcore [4.3.3.v201411290715,4.3.3.v201411290715]
-	org.apache.httpcomponents.httpcore.source [4.3.3.v201411290715,4.3.3.v201411290715]
-	org.apache.httpcomponents.httpclient [4.3.6.v201411290715,4.3.6.v201411290715]
-	org.apache.httpcomponents.httpclient.source [4.3.6.v201411290715,4.3.6.v201411290715]
-	org.apache.log4j [1.2.15.v201012070815,1.2.15.v201012070815]
-	org.apache.log4j.source [1.2.15.v201012070815,1.2.15.v201012070815]
-	org.kohsuke.args4j [2.0.21.v201301150030,2.0.21.v201301150030]
-	org.kohsuke.args4j.source [2.0.21.v201301150030,2.0.21.v201301150030]
-	org.hamcrest.core [1.3.0.v201303031735,1.3.0.v201303031735]
-	org.hamcrest.core.source [1.3.0.v201303031735,1.3.0.v201303031735]
-	javaewah [0.7.9.v201401101600,0.7.9.v201401101600]
-	javaewah.source [0.7.9.v201401101600,0.7.9.v201401101600]
-	org.objenesis [1.0.0.v201105211943,1.0.0.v201105211943]
-	org.objenesis.source [1.0.0.v201105211943,1.0.0.v201105211943]
-	org.mockito [1.8.4.v201303031500,1.8.4.v201303031500]
-	org.mockito.source [1.8.4.v201303031500,1.8.4.v201303031500]
-	com.google.gson [2.2.4.v201311231704,2.2.4.v201311231704]
-	com.jcraft.jsch [0.1.51.v201410302000,0.1.51.v201410302000]
-	com.jcraft.jsch.source [0.1.51.v201410302000,0.1.51.v201410302000]
-	org.junit [4.11.0.v201303080030,4.11.0.v201303080030]
-	org.junit.source [4.11.0.v201303080030,4.11.0.v201303080030]
-	javax.servlet [3.1.0.v20140303-1611,3.1.0.v20140303-1611]
-	javax.servlet.source [3.1.0.v20140303-1611,3.1.0.v20140303-1611]
-	org.tukaani.xz [1.3.0.v201308270617,1.3.0.v201308270617]
-	org.tukaani.xz.source [1.3.0.v201308270617,1.3.0.v201308270617]
-	org.slf4j.api [1.7.2.v20121108-1250,1.7.2.v20121108-1250]
-	org.slf4j.api.source [1.7.2.v20121108-1250,1.7.2.v20121108-1250]
-	org.slf4j.impl.log4j12 [1.7.2.v20131105-2200,1.7.2.v20131105-2200]
-	org.slf4j.impl.log4j12.source [1.7.2.v20131105-2200,1.7.2.v20131105-2200]
-}
\ No newline at end of file
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/R20160221192158-Mars.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/R20160221192158-Mars.tpd
deleted file mode 100644
index 5e47f68..0000000
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/R20160221192158-Mars.tpd
+++ /dev/null
@@ -1,40 +0,0 @@
-target "R20160221192158-Mars" with source configurePhase
-// see http://download.eclipse.org/tools/orbit/downloads/
-
-location "http://download.eclipse.org/tools/orbit/downloads/drops/R20160221192158/repository/" {
-	org.apache.ant [1.9.4.v201504302020,1.9.4.v201504302020]
-	org.apache.ant.source [1.9.4.v201504302020,1.9.4.v201504302020]
-	org.apache.commons.compress [1.6.0.v201310281400,1.6.0.v201310281400]
-	org.apache.commons.compress.source [1.6.0.v201310281400,1.6.0.v201310281400]
-	org.apache.commons.logging [1.1.1.v201101211721,1.1.1.v201101211721]
-	org.apache.commons.logging.source [1.1.1.v201101211721,1.1.1.v201101211721]
-	org.apache.httpcomponents.httpcore [4.3.3.v201411290715,4.3.3.v201411290715]
-	org.apache.httpcomponents.httpcore.source [4.3.3.v201411290715,4.3.3.v201411290715]
-	org.apache.httpcomponents.httpclient [4.3.6.v201411290715B,4.3.6.v201411290715B]
-	org.apache.httpcomponents.httpclient.source [4.3.6.v201411290715B,4.3.6.v201411290715B]
-	org.apache.log4j [1.2.15.v201012070815,1.2.15.v201012070815]
-	org.apache.log4j.source [1.2.15.v201012070815,1.2.15.v201012070815]
-	org.kohsuke.args4j [2.0.21.v201301150030,2.0.21.v201301150030]
-	org.kohsuke.args4j.source [2.0.21.v201301150030,2.0.21.v201301150030]
-	org.hamcrest.core [1.3.0.v201303031735,1.3.0.v201303031735]
-	org.hamcrest.core.source [1.3.0.v201303031735,1.3.0.v201303031735]
-	javaewah [0.7.9.v201401101600,0.7.9.v201401101600]
-	javaewah.source [0.7.9.v201401101600,0.7.9.v201401101600]
-	org.objenesis [1.0.0.v201505121915,1.0.0.v201505121915]
-	org.objenesis.source [1.0.0.v201505121915,1.0.0.v201505121915]
-	org.mockito [1.8.4.v201303031500,1.8.4.v201303031500]
-	org.mockito.source [1.8.4.v201303031500,1.8.4.v201303031500]
-	com.google.gson [2.2.4.v201311231704,2.2.4.v201311231704]
-	com.jcraft.jsch [0.1.53.v201508180515,0.1.53.v201508180515]
-	com.jcraft.jsch.source [0.1.53.v201508180515,0.1.53.v201508180515]
-	org.junit [4.11.0.v201303080030,4.11.0.v201303080030]
-	org.junit.source [4.11.0.v201303080030,4.11.0.v201303080030]
-	javax.servlet [3.1.0.v201410161800,3.1.0.v201410161800]
-	javax.servlet.source [3.1.0.v201410161800,3.1.0.v201410161800]
-	org.tukaani.xz [1.3.0.v201308270617,1.3.0.v201308270617]
-	org.tukaani.xz.source [1.3.0.v201308270617,1.3.0.v201308270617]
-	org.slf4j.api [1.7.2.v20121108-1250,1.7.2.v20121108-1250]
-	org.slf4j.api.source [1.7.2.v20121108-1250,1.7.2.v20121108-1250]
-	org.slf4j.impl.log4j12 [1.7.2.v20131105-2200,1.7.2.v20131105-2200]
-	org.slf4j.impl.log4j12.source [1.7.2.v20131105-2200,1.7.2.v20131105-2200]
-}
\ No newline at end of file
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/R20160520211859-Neon.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/R20160520211859-Neon.tpd
deleted file mode 100644
index 5aca0b7..0000000
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/R20160520211859-Neon.tpd
+++ /dev/null
@@ -1,40 +0,0 @@
-target "R20160520211859-Neon" with source configurePhase
-// see http://download.eclipse.org/tools/orbit/downloads/
-
-location "http://download.eclipse.org/tools/orbit/downloads/drops/R20160520211859/repository/" {
-	org.apache.ant [1.9.6.v201510161327,1.9.6.v201510161327]
-	org.apache.ant.source [1.9.6.v201510161327,1.9.6.v201510161327]
-	org.apache.commons.compress [1.6.0.v201310281400,1.6.0.v201310281400]
-	org.apache.commons.compress.source [1.6.0.v201310281400,1.6.0.v201310281400]
-	org.apache.commons.logging [1.1.1.v201101211721,1.1.1.v201101211721]
-	org.apache.commons.logging.source [1.1.1.v201101211721,1.1.1.v201101211721]
-	org.apache.httpcomponents.httpcore [4.3.3.v201411290715,4.3.3.v201411290715]
-	org.apache.httpcomponents.httpcore.source [4.3.3.v201411290715,4.3.3.v201411290715]
-	org.apache.httpcomponents.httpclient [4.3.6.v201511171540,4.3.6.v201511171540]
-	org.apache.httpcomponents.httpclient.source [4.3.6.v201511171540,4.3.6.v201511171540]
-	org.apache.log4j [1.2.15.v201012070815,1.2.15.v201012070815]
-	org.apache.log4j.source [1.2.15.v201012070815,1.2.15.v201012070815]
-	org.kohsuke.args4j [2.0.21.v201301150030,2.0.21.v201301150030]
-	org.kohsuke.args4j.source [2.0.21.v201301150030,2.0.21.v201301150030]
-	org.hamcrest.core [1.3.0.v201303031735,1.3.0.v201303031735]
-	org.hamcrest.core.source [1.3.0.v201303031735,1.3.0.v201303031735]
-	javaewah [0.7.9.v201605172130,0.7.9.v201605172130]
-	javaewah.source [0.7.9.v201605172130,0.7.9.v201605172130]
-	org.objenesis [1.0.0.v201505121915,1.0.0.v201505121915]
-	org.objenesis.source [1.0.0.v201505121915,1.0.0.v201505121915]
-	org.mockito [1.8.4.v201303031500,1.8.4.v201303031500]
-	org.mockito.source [1.8.4.v201303031500,1.8.4.v201303031500]
-	com.google.gson [2.2.4.v201311231704,2.2.4.v201311231704]
-	com.jcraft.jsch [0.1.53.v201508180515,0.1.53.v201508180515]
-	com.jcraft.jsch.source [0.1.53.v201508180515,0.1.53.v201508180515]
-	org.junit [4.12.0.v201504281640,4.12.0.v201504281640]
-	org.junit.source [4.12.0.v201504281640,4.12.0.v201504281640]
-	javax.servlet [3.1.0.v201410161800,3.1.0.v201410161800]
-	javax.servlet.source [3.1.0.v201410161800,3.1.0.v201410161800]
-	org.tukaani.xz [1.3.0.v201308270617,1.3.0.v201308270617]
-	org.tukaani.xz.source [1.3.0.v201308270617,1.3.0.v201308270617]
-	org.slf4j.api [1.7.2.v20121108-1250,1.7.2.v20121108-1250]
-	org.slf4j.api.source [1.7.2.v20121108-1250,1.7.2.v20121108-1250]
-	org.slf4j.impl.log4j12 [1.7.2.v20131105-2200,1.7.2.v20131105-2200]
-	org.slf4j.impl.log4j12.source [1.7.2.v20131105-2200,1.7.2.v20131105-2200]
-}
\ No newline at end of file
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/R20170516192513-Oxygen.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/R20180206163158-Oxygen.tpd
similarity index 81%
rename from org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/R20170516192513-Oxygen.tpd
rename to org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/R20180206163158-Oxygen.tpd
index f4cb572..91c66db 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/R20170516192513-Oxygen.tpd
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/R20180206163158-Oxygen.tpd
@@ -1,7 +1,7 @@
-target "R20170516192513-Oxygen" with source configurePhase
+target "R20180206163158-Oxygen" with source configurePhase
 // see http://download.eclipse.org/tools/orbit/downloads/
 
-location "http://download.eclipse.org/tools/orbit/downloads/drops/R20170516192513/repository" {
+location "http://download.eclipse.org/tools/orbit/downloads/drops/R20180206163158/repository" {
 	org.apache.ant [1.9.6.v201510161327,1.9.6.v201510161327]
 	org.apache.ant.source [1.9.6.v201510161327,1.9.6.v201510161327]
 	org.apache.commons.codec [1.9.0.v20170208-1614,1.9.0.v20170208-1614]
@@ -10,10 +10,10 @@
 	org.apache.commons.compress.source [1.6.0.v201310281400,1.6.0.v201310281400]
 	org.apache.commons.logging [1.1.1.v201101211721,1.1.1.v201101211721]
 	org.apache.commons.logging.source [1.1.1.v201101211721,1.1.1.v201101211721]
-	org.apache.httpcomponents.httpcore [4.3.3.v201411290715,4.3.3.v201411290715]
-	org.apache.httpcomponents.httpcore.source [4.3.3.v201411290715,4.3.3.v201411290715]
-	org.apache.httpcomponents.httpclient [4.3.6.v201511171540,4.3.6.v201511171540]
-	org.apache.httpcomponents.httpclient.source [4.3.6.v201511171540,4.3.6.v201511171540]
+	org.apache.httpcomponents.httpcore [4.4.6.v20170210-0925,4.4.6.v20170210-0925]
+	org.apache.httpcomponents.httpcore.source [4.4.6.v20170210-0925,4.4.6.v20170210-0925]
+	org.apache.httpcomponents.httpclient [4.5.2.v20170210-0925,4.5.2.v20170210-0925]
+	org.apache.httpcomponents.httpclient.source [4.5.2.v20170210-0925,4.5.2.v20170210-0925]
 	org.apache.log4j [1.2.15.v201012070815,1.2.15.v201012070815]
 	org.apache.log4j.source [1.2.15.v201012070815,1.2.15.v201012070815]
 	org.kohsuke.args4j [2.33.0.v20160323-2218,2.33.0.v20160323-2218]
@@ -41,4 +41,6 @@
 	org.slf4j.api.source [1.7.2.v20121108-1250,1.7.2.v20121108-1250]
 	org.slf4j.impl.log4j12 [1.7.2.v20131105-2200,1.7.2.v20131105-2200]
 	org.slf4j.impl.log4j12.source [1.7.2.v20131105-2200,1.7.2.v20131105-2200]
+	com.jcraft.jzlib [1.1.1.v201205102305,1.1.1.v201205102305]
+	com.jcraft.jzlib.source [1.1.1.v201205102305,1.1.1.v201205102305]
 }
\ No newline at end of file
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/R20180606145124-Photon.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/R20180606145124-Photon.tpd
new file mode 100644
index 0000000..8497c2c
--- /dev/null
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/R20180606145124-Photon.tpd
@@ -0,0 +1,48 @@
+target "R20180606145124-Photon" with source configurePhase
+// see http://download.eclipse.org/tools/orbit/downloads/
+
+location "http://download.eclipse.org/tools/orbit/downloads/drops/R20180606145124/repository" {
+	org.apache.ant [1.9.6.v201510161327,1.9.6.v201510161327]
+	org.apache.ant.source [1.9.6.v201510161327,1.9.6.v201510161327]
+	org.apache.commons.codec [1.9.0.v20170208-1614,1.9.0.v20170208-1614]
+	org.apache.commons.codec.source [1.9.0.v20170208-1614,1.9.0.v20170208-1614]
+	org.apache.commons.compress [1.15.0.v20180119-1613,1.15.0.v20180119-1613]
+	org.apache.commons.compress.source [1.15.0.v20180119-1613,1.15.0.v20180119-1613s]
+	org.apache.commons.logging [1.1.1.v201101211721,1.1.1.v201101211721]
+	org.apache.commons.logging.source [1.1.1.v201101211721,1.1.1.v201101211721]
+	org.apache.httpcomponents.httpcore [4.4.6.v20170210-0925,4.4.6.v20170210-0925]
+	org.apache.httpcomponents.httpcore.source [4.4.6.v20170210-0925,4.4.6.v20170210-0925]
+	org.apache.httpcomponents.httpclient [4.5.2.v20180410-1551,4.5.2.v20180410-1551]
+	org.apache.httpcomponents.httpclient.source [4.5.2.v20180410-1551,4.5.2.v20180410-1551]
+	org.apache.log4j [1.2.15.v201012070815,1.2.15.v201012070815]
+	org.apache.log4j.source [1.2.15.v201012070815,1.2.15.v201012070815]
+	org.kohsuke.args4j [2.33.0.v20160323-2218,2.33.0.v20160323-2218]
+	org.kohsuke.args4j.source [2.33.0.v20160323-2218,2.33.0.v20160323-2218]
+	org.hamcrest [1.1.0.v20090501071000,1.1.0.v20090501071000]
+	org.hamcrest.core [1.3.0.v20180420-1519,1.3.0.v20180420-1519]
+	org.hamcrest.core.source [1.3.0.v20180420-1519,1.3.0.v20180420-1519]
+	org.hamcrest.library [1.3.0.v20180524-2246,1.3.0.v20180524-2246]
+	org.hamcrest.library.source [1.3.0.v20180524-2246,1.3.0.v20180524-2246]
+	javaewah [1.1.6.v20160919-1400,1.1.6.v20160919-1400]
+	javaewah.source [1.1.6.v20160919-1400,1.1.6.v20160919-1400]
+	org.objenesis [1.0.0.v201505121915,1.0.0.v201505121915]
+	org.objenesis.source [1.0.0.v201505121915,1.0.0.v201505121915]
+	org.mockito [1.8.4.v201303031500,1.8.4.v201303031500]
+	org.mockito.source [1.8.4.v201303031500,1.8.4.v201303031500]
+	com.google.gson [2.8.2.v20180104-1110,2.8.2.v20180104-1110]
+	com.google.gson.source [2.8.2.v20180104-1110,2.8.2.v20180104-1110]
+	com.jcraft.jsch [0.1.54.v20170116-1932,0.1.54.v20170116-1932]
+	com.jcraft.jsch.source [0.1.54.v20170116-1932,0.1.54.v20170116-1932]
+	org.junit [4.12.0.v201504281640,4.12.0.v201504281640]
+	org.junit.source [4.12.0.v201504281640,4.12.0.v201504281640]
+	javax.servlet [3.1.0.v201410161800,3.1.0.v201410161800]
+	javax.servlet.source [3.1.0.v201410161800,3.1.0.v201410161800]
+	org.tukaani.xz [1.6.0.v20170629-1752,1.6.0.v20170629-1752]
+	org.tukaani.xz.source [1.6.0.v20170629-1752,1.6.0.v20170629-1752]
+	org.slf4j.api [1.7.2.v20121108-1250,1.7.2.v20121108-1250]
+	org.slf4j.api.source [1.7.2.v20121108-1250,1.7.2.v20121108-1250]
+	org.slf4j.impl.log4j12 [1.7.2.v20131105-2200,1.7.2.v20131105-2200]
+	org.slf4j.impl.log4j12.source [1.7.2.v20131105-2200,1.7.2.v20131105-2200]
+	com.jcraft.jzlib [1.1.1.v201205102305,1.1.1.v201205102305]
+	com.jcraft.jzlib.source [1.1.1.v201205102305,1.1.1.v201205102305]
+}
\ No newline at end of file
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/S20170912163609-Photon.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/S20170912163609-Photon.tpd
deleted file mode 100644
index c2524d3..0000000
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/S20170912163609-Photon.tpd
+++ /dev/null
@@ -1,44 +0,0 @@
-target "S20170912163609-Photon" with source configurePhase
-// see http://download.eclipse.org/tools/orbit/downloads/
-
-location "http://download.eclipse.org/tools/orbit/downloads/drops/S20170912163609/repository" {
-	org.apache.ant [1.9.6.v201510161327,1.9.6.v201510161327]
-	org.apache.ant.source [1.9.6.v201510161327,1.9.6.v201510161327]
-	org.apache.commons.codec [1.9.0.v20170208-1614,1.9.0.v20170208-1614]
-	org.apache.commons.codec.source [1.9.0.v20170208-1614,1.9.0.v20170208-1614]
-	org.apache.commons.compress [1.6.0.v201310281400,1.6.0.v201310281400]
-	org.apache.commons.compress.source [1.6.0.v201310281400,1.6.0.v201310281400]
-	org.apache.commons.logging [1.1.1.v201101211721,1.1.1.v201101211721]
-	org.apache.commons.logging.source [1.1.1.v201101211721,1.1.1.v201101211721]
-	org.apache.httpcomponents.httpcore [4.3.3.v201411290715,4.3.3.v201411290715]
-	org.apache.httpcomponents.httpcore.source [4.3.3.v201411290715,4.3.3.v201411290715]
-	org.apache.httpcomponents.httpclient [4.3.6.v201511171540,4.3.6.v201511171540]
-	org.apache.httpcomponents.httpclient.source [4.3.6.v201511171540,4.3.6.v201511171540]
-	org.apache.log4j [1.2.15.v201012070815,1.2.15.v201012070815]
-	org.apache.log4j.source [1.2.15.v201012070815,1.2.15.v201012070815]
-	org.kohsuke.args4j [2.33.0.v20160323-2218,2.33.0.v20160323-2218]
-	org.kohsuke.args4j.source [2.33.0.v20160323-2218,2.33.0.v20160323-2218]
-	org.hamcrest.core [1.3.0.v201303031735,1.3.0.v201303031735]
-	org.hamcrest.core.source [1.3.0.v201303031735,1.3.0.v201303031735]
-	org.hamcrest.library [1.3.0.v201505072020,1.3.0.v201505072020]
-	org.hamcrest.library.source [1.3.0.v201505072020,1.3.0.v201505072020]
-	javaewah [1.1.6.v20160919-1400,1.1.6.v20160919-1400]
-	javaewah.source [1.1.6.v20160919-1400,1.1.6.v20160919-1400]
-	org.objenesis [1.0.0.v201505121915,1.0.0.v201505121915]
-	org.objenesis.source [1.0.0.v201505121915,1.0.0.v201505121915]
-	org.mockito [1.8.4.v201303031500,1.8.4.v201303031500]
-	org.mockito.source [1.8.4.v201303031500,1.8.4.v201303031500]
-	com.google.gson [2.2.4.v201311231704,2.2.4.v201311231704]
-	com.jcraft.jsch [0.1.54.v20170116-1932,0.1.54.v20170116-1932]
-	com.jcraft.jsch.source [0.1.54.v20170116-1932,0.1.54.v20170116-1932]
-	org.junit [4.12.0.v201504281640,4.12.0.v201504281640]
-	org.junit.source [4.12.0.v201504281640,4.12.0.v201504281640]
-	javax.servlet [3.1.0.v201410161800,3.1.0.v201410161800]
-	javax.servlet.source [3.1.0.v201410161800,3.1.0.v201410161800]
-	org.tukaani.xz [1.3.0.v201308270617,1.3.0.v201308270617]
-	org.tukaani.xz.source [1.3.0.v201308270617,1.3.0.v201308270617]
-	org.slf4j.api [1.7.2.v20121108-1250,1.7.2.v20121108-1250]
-	org.slf4j.api.source [1.7.2.v20121108-1250,1.7.2.v20121108-1250]
-	org.slf4j.impl.log4j12 [1.7.2.v20131105-2200,1.7.2.v20131105-2200]
-	org.slf4j.impl.log4j12.source [1.7.2.v20131105-2200,1.7.2.v20131105-2200]
-}
\ No newline at end of file
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/pom.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/pom.xml
index 290b3e2..63b87af 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/pom.xml
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/pom.xml
@@ -49,7 +49,7 @@
   <parent>
     <groupId>org.eclipse.jgit</groupId>
     <artifactId>jgit.tycho.parent</artifactId>
-    <version>4.9.3-SNAPSHOT</version>
+    <version>5.0.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>org.eclipse.jgit.target</artifactId>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/projects/jetty-9.4.5.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/projects/jetty-9.4.5.tpd
deleted file mode 100644
index 363c600..0000000
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/projects/jetty-9.4.5.tpd
+++ /dev/null
@@ -1,20 +0,0 @@
-target "jetty-9.4.5" with source configurePhase
-
-location jetty-9.4.5 "http://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.4.5.v20170502/" {
-	org.eclipse.jetty.client [9.4.5.v20170502,9.4.5.v20170502]
-	org.eclipse.jetty.client.source [9.4.5.v20170502,9.4.5.v20170502]
-	org.eclipse.jetty.continuation [9.4.5.v20170502,9.4.5.v20170502]
-	org.eclipse.jetty.continuation.source [9.4.5.v20170502,9.4.5.v20170502]
-	org.eclipse.jetty.http [9.4.5.v20170502,9.4.5.v20170502]
-	org.eclipse.jetty.http.source [9.4.5.v20170502,9.4.5.v20170502]
-	org.eclipse.jetty.io [9.4.5.v20170502,9.4.5.v20170502]
-	org.eclipse.jetty.io.source [9.4.5.v20170502,9.4.5.v20170502]
-	org.eclipse.jetty.security [9.4.5.v20170502,9.4.5.v20170502]
-	org.eclipse.jetty.security.source [9.4.5.v20170502,9.4.5.v20170502]
-	org.eclipse.jetty.server [9.4.5.v20170502,9.4.5.v20170502]
-	org.eclipse.jetty.server.source [9.4.5.v20170502,9.4.5.v20170502]
-	org.eclipse.jetty.servlet [9.4.5.v20170502,9.4.5.v20170502]
-	org.eclipse.jetty.servlet.source [9.4.5.v20170502,9.4.5.v20170502]
-	org.eclipse.jetty.util [9.4.5.v20170502,9.4.5.v20170502]
-	org.eclipse.jetty.util.source [9.4.5.v20170502,9.4.5.v20170502]
-}
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/projects/jetty-9.4.8.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/projects/jetty-9.4.8.tpd
new file mode 100644
index 0000000..e37a062
--- /dev/null
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/projects/jetty-9.4.8.tpd
@@ -0,0 +1,20 @@
+target "jetty-9.4.8" with source configurePhase
+
+location jetty-9.4.8 "http://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.4.8.v20171121" {
+	org.eclipse.jetty.client [9.4.8.v20171121,9.4.8.v20171121]
+	org.eclipse.jetty.client.source [9.4.8.v20171121,9.4.8.v20171121]
+	org.eclipse.jetty.continuation [9.4.8.v20171121,9.4.8.v20171121]
+	org.eclipse.jetty.continuation.source [9.4.8.v20171121,9.4.8.v20171121]
+	org.eclipse.jetty.http [9.4.8.v20171121,9.4.8.v20171121]
+	org.eclipse.jetty.http.source [9.4.8.v20171121,9.4.8.v20171121]
+	org.eclipse.jetty.io [9.4.8.v20171121,9.4.8.v20171121]
+	org.eclipse.jetty.io.source [9.4.8.v20171121,9.4.8.v20171121]
+	org.eclipse.jetty.security [9.4.8.v20171121,9.4.8.v20171121]
+	org.eclipse.jetty.security.source [9.4.8.v20171121,9.4.8.v20171121]
+	org.eclipse.jetty.server [9.4.8.v20171121,9.4.8.v20171121]
+	org.eclipse.jetty.server.source [9.4.8.v20171121,9.4.8.v20171121]
+	org.eclipse.jetty.servlet [9.4.8.v20171121,9.4.8.v20171121]
+	org.eclipse.jetty.servlet.source [9.4.8.v20171121,9.4.8.v20171121]
+	org.eclipse.jetty.util [9.4.8.v20171121,9.4.8.v20171121]
+	org.eclipse.jetty.util.source [9.4.8.v20171121,9.4.8.v20171121]
+}
diff --git a/org.eclipse.jgit.packaging/pom.xml b/org.eclipse.jgit.packaging/pom.xml
index c1a7d99..5afdae5 100644
--- a/org.eclipse.jgit.packaging/pom.xml
+++ b/org.eclipse.jgit.packaging/pom.xml
@@ -53,13 +53,13 @@
 
   <groupId>org.eclipse.jgit</groupId>
   <artifactId>jgit.tycho.parent</artifactId>
-  <version>4.9.3-SNAPSHOT</version>
+  <version>5.0.0-SNAPSHOT</version>
   <packaging>pom</packaging>
 
   <name>JGit Tycho Parent</name>
 
   <properties>
-    <tycho-version>1.0.0</tycho-version>
+    <tycho-version>1.1.0</tycho-version>
     <tycho-extras-version>${tycho-version}</tycho-extras-version>
     <target-platform>jgit-4.6</target-platform>
   </properties>
@@ -120,6 +120,26 @@
   <build>
     <plugins>
       <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-enforcer-plugin</artifactId>
+        <version>3.0.0-M1</version>
+        <executions>
+          <execution>
+            <id>enforce-maven</id>
+            <goals>
+              <goal>enforce</goal>
+            </goals>
+            <configuration>
+              <rules>
+                <requireMavenVersion>
+                  <version>3.5.2</version>
+                </requireMavenVersion>
+              </rules>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+      <plugin>
         <groupId>org.eclipse.tycho</groupId>
         <artifactId>tycho-maven-plugin</artifactId>
         <version>${tycho-version}</version>
diff --git a/org.eclipse.jgit.pgm.test/.settings/org.eclipse.jdt.core.prefs b/org.eclipse.jgit.pgm.test/.settings/org.eclipse.jdt.core.prefs
index 64f7498..794592d 100644
--- a/org.eclipse.jgit.pgm.test/.settings/org.eclipse.jdt.core.prefs
+++ b/org.eclipse.jgit.pgm.test/.settings/org.eclipse.jdt.core.prefs
@@ -25,7 +25,7 @@
 org.eclipse.jdt.core.compiler.problem.discouragedReference=warning
 org.eclipse.jdt.core.compiler.problem.emptyStatement=warning
 org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
-org.eclipse.jdt.core.compiler.problem.explicitlyClosedAutoCloseable=ignore
+org.eclipse.jdt.core.compiler.problem.explicitlyClosedAutoCloseable=warning
 org.eclipse.jdt.core.compiler.problem.fallthroughCase=warning
 org.eclipse.jdt.core.compiler.problem.fatalOptionalError=disabled
 org.eclipse.jdt.core.compiler.problem.fieldHiding=warning
diff --git a/org.eclipse.jgit.pgm.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.pgm.test/META-INF/MANIFEST.MF
index 9dfe655..bee6c49 100644
--- a/org.eclipse.jgit.pgm.test/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.pgm.test/META-INF/MANIFEST.MF
@@ -1,31 +1,32 @@
 Manifest-Version: 1.0
 Bundle-ManifestVersion: 2
 Bundle-Name: %plugin_name
+Automatic-Module-Name: org.eclipse.jgit.pgm.test
 Bundle-SymbolicName: org.eclipse.jgit.pgm.test
-Bundle-Version: 4.9.3.qualifier
+Bundle-Version: 5.0.0.qualifier
 Bundle-Vendor: %provider_name
 Bundle-Localization: plugin
 Bundle-ActivationPolicy: lazy
 Bundle-RequiredExecutionEnvironment: JavaSE-1.8
-Import-Package: org.eclipse.jgit.api;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.api.errors;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.diff;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.dircache;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.internal.storage.file;version="4.9.3",
- org.eclipse.jgit.junit;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.lib;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.merge;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.pgm;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.pgm.internal;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.pgm.opt;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.revwalk;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.storage.file;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.transport;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.treewalk;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.util;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.util.io;version="[4.9.3,4.10.0)",
+Import-Package: org.eclipse.jgit.api;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.api.errors;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.diff;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.dircache;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.internal.storage.file;version="5.0.0",
+ org.eclipse.jgit.junit;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.lib;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.merge;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.pgm;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.pgm.internal;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.pgm.opt;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.revwalk;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.storage.file;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.transport;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.treewalk;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.util;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.util.io;version="[5.0.0,5.1.0)",
  org.hamcrest.core;bundle-version="[1.1.0,2.0.0)",
- org.junit;version="[4.11.0,5.0.0)",
- org.junit.rules;version="[4.11.0,5.0.0)",
+ org.junit;version="[4.12,5.0.0)",
+ org.junit.rules;version="[4.12,5.0.0)",
  org.kohsuke.args4j;version="[2.33.0,3.0.0)"
 Require-Bundle: org.tukaani.xz;bundle-version="[1.3.0,2.0.0)"
diff --git a/org.eclipse.jgit.pgm.test/pom.xml b/org.eclipse.jgit.pgm.test/pom.xml
index 26a001c..2c36e46 100644
--- a/org.eclipse.jgit.pgm.test/pom.xml
+++ b/org.eclipse.jgit.pgm.test/pom.xml
@@ -50,7 +50,7 @@
   <parent>
     <groupId>org.eclipse.jgit</groupId>
     <artifactId>org.eclipse.jgit-parent</artifactId>
-    <version>4.9.3-SNAPSHOT</version>
+    <version>5.0.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>org.eclipse.jgit.pgm.test</artifactId>
@@ -84,6 +84,11 @@
       <version>${project.version}</version>
     </dependency>
 
+    <dependency>
+      <groupId>org.tukaani</groupId>
+      <artifactId>xz</artifactId>
+      <optional>true</optional>
+    </dependency>
   </dependencies>
 
   <build>
diff --git a/org.eclipse.jgit.pgm.test/src/org/eclipse/jgit/lib/CLIRepositoryTestCase.java b/org.eclipse.jgit.pgm.test/src/org/eclipse/jgit/lib/CLIRepositoryTestCase.java
index 0eeabab..0d1894b 100644
--- a/org.eclipse.jgit.pgm.test/src/org/eclipse/jgit/lib/CLIRepositoryTestCase.java
+++ b/org.eclipse.jgit.pgm.test/src/org/eclipse/jgit/lib/CLIRepositoryTestCase.java
@@ -122,17 +122,17 @@ protected Path writeLink(String link, String target) throws Exception {
 		return JGitTestUtil.writeLink(db, link, target);
 	}
 
-	protected File writeTrashFile(final String name, final String data)
+	protected File writeTrashFile(String name, String data)
 			throws IOException {
 		return JGitTestUtil.writeTrashFile(db, name, data);
 	}
 
 	@Override
-	protected String read(final File file) throws IOException {
+	protected String read(File file) throws IOException {
 		return JGitTestUtil.read(file);
 	}
 
-	protected void deleteTrashFile(final String name) throws IOException {
+	protected void deleteTrashFile(String name) throws IOException {
 		JGitTestUtil.deleteTrashFile(db, name);
 	}
 
diff --git a/org.eclipse.jgit.pgm.test/src/org/eclipse/jgit/pgm/CLIGitCommand.java b/org.eclipse.jgit.pgm.test/src/org/eclipse/jgit/pgm/CLIGitCommand.java
index 69eb198..44ad79d 100644
--- a/org.eclipse.jgit.pgm.test/src/org/eclipse/jgit/pgm/CLIGitCommand.java
+++ b/org.eclipse.jgit.pgm.test/src/org/eclipse/jgit/pgm/CLIGitCommand.java
@@ -157,7 +157,7 @@ PrintWriter createErrorWriter() {
 	}
 
 	@Override
-	void init(final TextBuiltin cmd) throws IOException {
+	void init(TextBuiltin cmd) throws IOException {
 		cmd.outs = result.out;
 		cmd.errs = result.err;
 		super.init(cmd);
diff --git a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/ArchiveTest.java b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/ArchiveTest.java
index 6f32bfa..afeb5ef 100644
--- a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/ArchiveTest.java
+++ b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/ArchiveTest.java
@@ -42,7 +42,9 @@
  */
 package org.eclipse.jgit.pgm;
 
+import static org.eclipse.jgit.lib.Constants.CHARSET;
 import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.fail;
 import static org.junit.Assume.assumeNoException;
 
@@ -610,7 +612,7 @@ private Process spawnAssumingCommandPresent(String... cmdline) {
 
 	private BufferedReader readFromProcess(Process proc) throws Exception {
 		return new BufferedReader(
-				new InputStreamReader(proc.getInputStream(), "UTF-8"));
+				new InputStreamReader(proc.getInputStream(), CHARSET));
 	}
 
 	private void grepForEntry(String name, String mode, String... cmdline)
@@ -632,16 +634,16 @@ private void grepForEntry(String name, String mode, String... cmdline)
 	}
 
 	private void assertMagic(long offset, byte[] magicBytes, File file) throws Exception {
-		BufferedInputStream in = new BufferedInputStream(
-				new FileInputStream(file));
-		try {
-			in.skip(offset);
+		try (BufferedInputStream in = new BufferedInputStream(
+				new FileInputStream(file))) {
+			if (offset > 0) {
+				long skipped = in.skip(offset);
+				assertEquals(offset, skipped);
+			}
 
 			byte[] actual = new byte[magicBytes.length];
 			in.read(actual);
 			assertArrayEquals(magicBytes, actual);
-		} finally {
-			in.close();
 		}
 	}
 
@@ -682,27 +684,23 @@ private void assertTarContainsEntry(String tarfile, String mode, String name)
 	private void writeRaw(String filename, byte[] data)
 			throws IOException {
 		File path = new File(db.getWorkTree(), filename);
-		OutputStream out = new FileOutputStream(path);
-		try {
+		try (OutputStream out = new FileOutputStream(path)) {
 			out.write(data);
-		} finally {
-			out.close();
 		}
 	}
 
 	private static String[] listZipEntries(byte[] zipData) throws IOException {
 		List<String> l = new ArrayList<>();
-		ZipInputStream in = new ZipInputStream(
-				new ByteArrayInputStream(zipData));
-
-		ZipEntry e;
-		while ((e = in.getNextEntry()) != null)
-			l.add(e.getName());
-		in.close();
+		try (ZipInputStream in = new ZipInputStream(
+				new ByteArrayInputStream(zipData))) {
+			ZipEntry e;
+			while ((e = in.getNextEntry()) != null)
+				l.add(e.getName());
+		}
 		return l.toArray(new String[l.size()]);
 	}
 
-	private static Future<Object> writeAsync(final OutputStream stream, final byte[] data) {
+	private static Future<Object> writeAsync(OutputStream stream, byte[] data) {
 		ExecutorService executor = Executors.newSingleThreadExecutor();
 
 		return executor.submit(new Callable<Object>() {
@@ -721,22 +719,22 @@ public Object call() throws IOException {
 	private String[] listTarEntries(byte[] tarData) throws Exception {
 		List<String> l = new ArrayList<>();
 		Process proc = spawnAssumingCommandPresent("tar", "tf", "-");
-		BufferedReader reader = readFromProcess(proc);
-		OutputStream out = proc.getOutputStream();
+		try (BufferedReader reader = readFromProcess(proc)) {
+			OutputStream out = proc.getOutputStream();
 
-		// Dump tarball to tar stdin in background
-		Future<?> writing = writeAsync(out, tarData);
+			// Dump tarball to tar stdin in background
+			Future<?> writing = writeAsync(out, tarData);
 
-		try {
-			String line;
-			while ((line = reader.readLine()) != null)
-				l.add(line);
+			try {
+				String line;
+				while ((line = reader.readLine()) != null)
+					l.add(line);
 
-			return l.toArray(new String[l.size()]);
-		} finally {
-			writing.get();
-			reader.close();
-			proc.destroy();
+				return l.toArray(new String[l.size()]);
+			} finally {
+				writing.get();
+				proc.destroy();
+			}
 		}
 	}
 
@@ -752,7 +750,7 @@ public Object call() throws IOException {
 			// found!
 			List<String> l = new ArrayList<>();
 			BufferedReader reader = new BufferedReader(
-					new InputStreamReader(in, "UTF-8"));
+					new InputStreamReader(in, CHARSET));
 			String line;
 			while ((line = reader.readLine()) != null)
 				l.add(line);
@@ -767,20 +765,20 @@ public Object call() throws IOException {
 			throws Exception {
 		List<String> l = new ArrayList<>();
 		Process proc = spawnAssumingCommandPresent("tar", "Oxf", "-", path);
-		BufferedReader reader = readFromProcess(proc);
-		OutputStream out = proc.getOutputStream();
-		Future<?> writing = writeAsync(out, tarData);
+		try (BufferedReader reader = readFromProcess(proc)) {
+			OutputStream out = proc.getOutputStream();
+			Future<?> writing = writeAsync(out, tarData);
 
-		try {
-			String line;
-			while ((line = reader.readLine()) != null)
-				l.add(line);
+			try {
+				String line;
+				while ((line = reader.readLine()) != null)
+					l.add(line);
 
-			return l.toArray(new String[l.size()]);
-		} finally {
-			writing.get();
-			reader.close();
-			proc.destroy();
+				return l.toArray(new String[l.size()]);
+			} finally {
+				writing.get();
+				proc.destroy();
+			}
 		}
 	}
 }
diff --git a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/CheckoutTest.java b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/CheckoutTest.java
index a98dd1c..b2115a4 100644
--- a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/CheckoutTest.java
+++ b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/CheckoutTest.java
@@ -502,7 +502,8 @@ public void fileModeTestFolderThenFileWithMissingInWorkingTree()
 	 * <li>Create branch '1'
 	 * <li>Modify file 'a'
 	 * <li>Commit
-	 * <li>Delete file 'a' & replace by folder 'a' in the working tree & index
+	 * <li>Delete file 'a' and replace by folder 'a' in the working tree and
+	 * index
 	 * <li>Checkout branch '1'
 	 * </ol>
 	 * <p>
@@ -555,7 +556,8 @@ public void fileModeTestFileThenFileWithFolderInIndex() throws Exception {
 	 * <li>Create branch '1'
 	 * <li>Modify file 'a'
 	 * <li>Commit
-	 * <li>Delete file 'a' & replace by folder 'a' in the working tree & index
+	 * <li>Delete file 'a' and replace by folder 'a' in the working tree and
+	 * index
 	 * <li>Checkout branch '1'
 	 * </ol>
 	 * <p>
diff --git a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/FetchTest.java b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/FetchTest.java
index 9685d45..dde1a33 100644
--- a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/FetchTest.java
+++ b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/FetchTest.java
@@ -92,6 +92,19 @@ public void testFetchDefault() throws Exception {
 	}
 
 	@Test
+	public void testFetchForceUpdate() throws Exception {
+		String[] result = execute(
+				"git fetch test refs/heads/master:refs/remotes/origin/master");
+		assertEquals(" * [new branch]      master     -> origin/master",
+				result[1]);
+		assertEquals(" * [new tag]         tag        -> tag", result[2]);
+		remoteGit.commit().setAmend(true).setMessage("amended").call();
+		result = execute(
+				"git fetch -f test refs/heads/master:refs/remotes/origin/master");
+		assertEquals("", result[0]);
+	}
+
+	@Test
 	public void testFetchNoTags() throws Exception {
 		String[] result = execute("git fetch --no-tags test refs/heads/master:refs/remotes/origin/master");
 		assertEquals(" * [new branch]      master     -> origin/master",
diff --git a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/ProxyConfigTest.java b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/ProxyConfigTest.java
index 06e7a1d..40a223d 100644
--- a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/ProxyConfigTest.java
+++ b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/ProxyConfigTest.java
@@ -47,6 +47,7 @@
 import java.util.List;
 import java.util.Map;
 
+import org.eclipse.jgit.lib.Constants;
 import org.junit.Before;
 import org.junit.Test;
 
@@ -203,7 +204,7 @@ private static String getOutput(Process p)
 			while ((length = inputStream.read(buffer)) != -1) {
 				result.write(buffer, 0, length);
 			}
-			return result.toString("UTF-8");
+			return result.toString(Constants.CHARACTER_ENCODING);
 		}
 	}
 }
diff --git a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/TagTest.java b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/TagTest.java
index 03391a0..d38a41d 100644
--- a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/TagTest.java
+++ b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/TagTest.java
@@ -43,10 +43,11 @@
 package org.eclipse.jgit.pgm;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
 
 import org.eclipse.jgit.api.Git;
 import org.eclipse.jgit.lib.CLIRepositoryTestCase;
-import org.eclipse.jgit.lib.Ref;
 import org.junit.Before;
 import org.junit.Test;
 
@@ -75,13 +76,9 @@ public void testTagTwice() throws Exception {
 	@Test
 	public void testTagDelete() throws Exception {
 		git.tag().setName("test").call();
-
-		Ref ref = git.getRepository().getTags().get("test");
-		assertEquals("refs/tags/test", ref.getName());
-
+		assertNotNull(git.getRepository().exactRef("refs/tags/test"));
 		assertEquals("", executeUnchecked("git tag -d test")[0]);
-		Ref deletedRef = git.getRepository().getTags().get("test");
-		assertEquals(null, deletedRef);
+		assertNull(git.getRepository().exactRef("refs/tags/test"));
 	}
 
 	@Test
diff --git a/org.eclipse.jgit.pgm/.settings/.api_filters b/org.eclipse.jgit.pgm/.settings/.api_filters
new file mode 100644
index 0000000..facef2d
--- /dev/null
+++ b/org.eclipse.jgit.pgm/.settings/.api_filters
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<component id="org.eclipse.jgit.pgm" version="2">
+    <resource path="META-INF/MANIFEST.MF">
+        <filter id="925892614">
+            <message_arguments>
+                <message_argument value="5.0.0"/>
+                <message_argument value="4.11.0"/>
+            </message_arguments>
+        </filter>
+    </resource>
+</component>
diff --git a/org.eclipse.jgit.pgm/.settings/org.eclipse.jdt.core.prefs b/org.eclipse.jgit.pgm/.settings/org.eclipse.jdt.core.prefs
index 06ddbab..13c32a6 100644
--- a/org.eclipse.jgit.pgm/.settings/org.eclipse.jdt.core.prefs
+++ b/org.eclipse.jgit.pgm/.settings/org.eclipse.jdt.core.prefs
@@ -25,7 +25,7 @@
 org.eclipse.jdt.core.compiler.problem.discouragedReference=warning
 org.eclipse.jdt.core.compiler.problem.emptyStatement=warning
 org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
-org.eclipse.jdt.core.compiler.problem.explicitlyClosedAutoCloseable=ignore
+org.eclipse.jdt.core.compiler.problem.explicitlyClosedAutoCloseable=warning
 org.eclipse.jdt.core.compiler.problem.fallthroughCase=warning
 org.eclipse.jdt.core.compiler.problem.fatalOptionalError=disabled
 org.eclipse.jdt.core.compiler.problem.fieldHiding=warning
diff --git a/org.eclipse.jgit.pgm/BUILD b/org.eclipse.jgit.pgm/BUILD
index 0792268..bbf4b1c 100644
--- a/org.eclipse.jgit.pgm/BUILD
+++ b/org.eclipse.jgit.pgm/BUILD
@@ -25,6 +25,12 @@
     ],
 )
 
+java_binary(
+    name = "jgit",
+    runtime_deps = [":pgm"],
+    main_class = "org.eclipse.jgit.pgm.Main",
+)
+
 java_import(
     name = "services",
     jars = [":services_jar"],
diff --git a/org.eclipse.jgit.pgm/META-INF/MANIFEST.MF b/org.eclipse.jgit.pgm/META-INF/MANIFEST.MF
index c2e4c32..0e47968 100644
--- a/org.eclipse.jgit.pgm/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.pgm/META-INF/MANIFEST.MF
@@ -1,8 +1,9 @@
 Manifest-Version: 1.0
 Bundle-ManifestVersion: 2
 Bundle-Name: %plugin_name
+Automatic-Module-Name: org.eclipse.jgit.pgm
 Bundle-SymbolicName: org.eclipse.jgit.pgm
-Bundle-Version: 4.9.3.qualifier
+Bundle-Version: 5.0.0.qualifier
 Bundle-Vendor: %provider_name
 Bundle-ActivationPolicy: lazy
 Bundle-Localization: plugin
@@ -27,49 +28,49 @@
  org.eclipse.jetty.util.log;version="[9.4.5,10.0.0)",
  org.eclipse.jetty.util.security;version="[9.4.5,10.0.0)",
  org.eclipse.jetty.util.thread;version="[9.4.5,10.0.0)",
- org.eclipse.jgit.api;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.api.errors;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.archive;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.awtui;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.blame;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.diff;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.dircache;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.errors;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.gitrepo;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.internal.ketch;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.internal.storage.dfs;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.internal.storage.file;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.internal.storage.io;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.internal.storage.pack;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.internal.storage.reftable;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.internal.storage.reftree;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.lfs;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.lfs.lib;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.lfs.server;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.lfs.server.fs;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.lfs.server.s3;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.lib;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.merge;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.nls;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.notes;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.revplot;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.revwalk;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.revwalk.filter;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.storage.file;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.storage.pack;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.transport;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.transport.http.apache;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.transport.resolver;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.treewalk;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.treewalk.filter;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.util;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.util.io;version="[4.9.3,4.10.0)",
+ org.eclipse.jgit.api;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.api.errors;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.archive;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.awtui;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.blame;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.diff;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.dircache;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.errors;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.gitrepo;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.internal.ketch;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.internal.storage.dfs;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.internal.storage.file;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.internal.storage.io;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.internal.storage.pack;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.internal.storage.reftable;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.internal.storage.reftree;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.lfs;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.lfs.lib;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.lfs.server;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.lfs.server.fs;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.lfs.server.s3;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.lib;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.merge;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.nls;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.notes;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.revplot;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.revwalk;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.revwalk.filter;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.storage.file;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.storage.pack;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.transport;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.transport.http.apache;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.transport.resolver;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.treewalk;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.treewalk.filter;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.util;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.util.io;version="[5.0.0,5.1.0)",
  org.kohsuke.args4j;version="[2.33.0,3.0.0)",
  org.kohsuke.args4j.spi;version="[2.33.0,3.0.0)"
-Export-Package: org.eclipse.jgit.console;version="4.9.3";
+Export-Package: org.eclipse.jgit.console;version="5.0.0";
   uses:="org.eclipse.jgit.transport,
    org.eclipse.jgit.util",
- org.eclipse.jgit.pgm;version="4.9.3";
+ org.eclipse.jgit.pgm;version="5.0.0";
   uses:="org.eclipse.jgit.revwalk,
    org.eclipse.jgit.treewalk.filter,
    org.eclipse.jgit.pgm.opt,
@@ -80,11 +81,11 @@
    org.eclipse.jgit.treewalk,
    javax.swing,
    org.eclipse.jgit.transport",
- org.eclipse.jgit.pgm.debug;version="4.9.3";
+ org.eclipse.jgit.pgm.debug;version="5.0.0";
   uses:="org.eclipse.jgit.util.io,
    org.eclipse.jgit.pgm",
- org.eclipse.jgit.pgm.internal;version="4.9.3";x-friends:="org.eclipse.jgit.pgm.test,org.eclipse.jgit.test",
- org.eclipse.jgit.pgm.opt;version="4.9.3";
+ org.eclipse.jgit.pgm.internal;version="5.0.0";x-friends:="org.eclipse.jgit.pgm.test,org.eclipse.jgit.test",
+ org.eclipse.jgit.pgm.opt;version="5.0.0";
   uses:="org.eclipse.jgit.lib,
    org.eclipse.jgit.revwalk,
    org.kohsuke.args4j.spi,
diff --git a/org.eclipse.jgit.pgm/META-INF/SOURCE-MANIFEST.MF b/org.eclipse.jgit.pgm/META-INF/SOURCE-MANIFEST.MF
index cf142ff..e14f1c7 100644
--- a/org.eclipse.jgit.pgm/META-INF/SOURCE-MANIFEST.MF
+++ b/org.eclipse.jgit.pgm/META-INF/SOURCE-MANIFEST.MF
@@ -3,5 +3,5 @@
 Bundle-Name: org.eclipse.jgit.pgm - Sources
 Bundle-SymbolicName: org.eclipse.jgit.pgm.source
 Bundle-Vendor: Eclipse.org - JGit
-Bundle-Version: 4.9.3.qualifier
-Eclipse-SourceBundle: org.eclipse.jgit.pgm;version="4.9.3.qualifier";roots="."
+Bundle-Version: 5.0.0.qualifier
+Eclipse-SourceBundle: org.eclipse.jgit.pgm;version="5.0.0.qualifier";roots="."
diff --git a/org.eclipse.jgit.pgm/pom.xml b/org.eclipse.jgit.pgm/pom.xml
index 184bb53..b4a3b11 100644
--- a/org.eclipse.jgit.pgm/pom.xml
+++ b/org.eclipse.jgit.pgm/pom.xml
@@ -50,7 +50,7 @@
   <parent>
     <groupId>org.eclipse.jgit</groupId>
     <artifactId>org.eclipse.jgit-parent</artifactId>
-    <version>4.9.3-SNAPSHOT</version>
+    <version>5.0.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>org.eclipse.jgit.pgm</artifactId>
diff --git a/org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/internal/CLIText.properties b/org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/internal/CLIText.properties
index cb0ea1b..e937093 100644
--- a/org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/internal/CLIText.properties
+++ b/org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/internal/CLIText.properties
@@ -343,6 +343,7 @@
 usage_forceCheckout=when switching branches, proceed even if the index or the working tree differs from HEAD
 usage_forceClean=required to delete files or directories
 usage_forceCreateBranchEvenExists=force create branch even exists
+usage_forcedFetch=force ref update fetch option
 usage_forceReplacingAnExistingTag=force replacing an existing tag
 usage_getAndSetOptions=Get and set repository or global options
 usage_groups=Restrict manifest projects to ones with specified group(s), use "-" for excluding [default|all|G1,G2,G3|G4,-G5,-G6]
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/console/ConsoleAuthenticator.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/console/ConsoleAuthenticator.java
index 8bf451c..06c95d8 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/console/ConsoleAuthenticator.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/console/ConsoleAuthenticator.java
@@ -58,7 +58,9 @@
  * @since 4.0
  */
 public class ConsoleAuthenticator extends CachedAuthenticator {
-	/** Install this authenticator implementation into the JVM. */
+	/**
+	 * Install this authenticator implementation into the JVM.
+	 */
 	public static void install() {
 		final ConsoleAuthenticator c = new ConsoleAuthenticator();
 		if (c.cons == null)
@@ -69,6 +71,7 @@ public static void install() {
 
 	private final Console cons = System.console();
 
+	/** {@inheritDoc} */
 	@Override
 	protected PasswordAuthentication promptPasswordAuthentication() {
 		final String realm = formatRealm();
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/console/ConsoleCredentialsProvider.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/console/ConsoleCredentialsProvider.java
index 0aa0cf4..f8442fa 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/console/ConsoleCredentialsProvider.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/console/ConsoleCredentialsProvider.java
@@ -61,7 +61,9 @@
  * @since 4.0
  */
 public class ConsoleCredentialsProvider extends CredentialsProvider {
-	/** Install this implementation as the default. */
+	/**
+	 * Install this implementation as the default.
+	 */
 	public static void install() {
 		final ConsoleCredentialsProvider c = new ConsoleCredentialsProvider();
 		if (c.cons == null)
@@ -74,11 +76,13 @@ public static void install() {
 
 	private final Console cons = System.console();
 
+	/** {@inheritDoc} */
 	@Override
 	public boolean isInteractive() {
 		return true;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public boolean supports(CredentialItem... items) {
 		for (CredentialItem i : items) {
@@ -100,6 +104,7 @@ else if (i instanceof CredentialItem.InformationalMessage)
 		return true;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public boolean get(URIish uri, CredentialItem... items)
 			throws UnsupportedCredentialItem {
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/AbstractFetchCommand.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/AbstractFetchCommand.java
index 08ec096..9223e0f 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/AbstractFetchCommand.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/AbstractFetchCommand.java
@@ -66,10 +66,18 @@ abstract class AbstractFetchCommand extends TextBuiltin {
 	@Option(name = "--verbose", aliases = { "-v" }, usage = "usage_beMoreVerbose")
 	private boolean verbose;
 
-	protected void showFetchResult(final FetchResult r) throws IOException {
+	/**
+	 * Show fetch result.
+	 *
+	 * @param r
+	 *            a {@link org.eclipse.jgit.transport.FetchResult} object.
+	 * @throws java.io.IOException
+	 *             if any.
+	 */
+	protected void showFetchResult(FetchResult r) throws IOException {
 		try (ObjectReader reader = db.newObjectReader()) {
 			boolean shownURI = false;
-			for (final TrackingRefUpdate u : r.getTrackingRefUpdates()) {
+			for (TrackingRefUpdate u : r.getTrackingRefUpdates()) {
 				if (!verbose && u.getResult() == RefUpdate.Result.NO_CHANGE)
 					continue;
 
@@ -173,7 +181,7 @@ private static String safeAbbreviate(ObjectReader reader, ObjectId id) {
 		}
 	}
 
-	private static char shortTypeOf(final RefUpdate.Result r) {
+	private static char shortTypeOf(RefUpdate.Result r) {
 		if (r == RefUpdate.Result.LOCK_FAILURE)
 			return '!';
 		if (r == RefUpdate.Result.IO_FAILURE)
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Add.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Add.java
index 3c13590..08a9f48 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Add.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Add.java
@@ -60,6 +60,7 @@ class Add extends TextBuiltin {
 	@Argument(required = true, metaVar = "metaVar_filepattern", usage = "usage_filesToAddContentFrom")
 	private List<String> filepatterns = new ArrayList<>();
 
+	/** {@inheritDoc} */
 	@Override
 	protected void run() throws Exception {
 		try (Git git = new Git(db)) {
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/AmazonS3Client.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/AmazonS3Client.java
index e0a9244..f4f8d8f 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/AmazonS3Client.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/AmazonS3Client.java
@@ -75,11 +75,13 @@ class AmazonS3Client extends TextBuiltin {
 	@Argument(index = 3, metaVar = "metaVar_KEY", required = true)
 	private String key;
 
+	/** {@inheritDoc} */
 	@Override
 	protected final boolean requiresRepository() {
 		return false;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected void run() throws Exception {
 		final AmazonS3 s3 = new AmazonS3(properties());
@@ -87,8 +89,7 @@ protected void run() throws Exception {
 		if ("get".equals(op)) { //$NON-NLS-1$
 			final URLConnection c = s3.get(bucket, key);
 			int len = c.getContentLength();
-			final InputStream in = c.getInputStream();
-			try {
+			try (InputStream in = c.getInputStream()) {
 				outw.flush();
 				final byte[] tmp = new byte[2048];
 				while (len > 0) {
@@ -101,25 +102,22 @@ protected void run() throws Exception {
 					len -= n;
 				}
 				outs.flush();
-			} finally {
-				in.close();
 			}
 
 		} else if ("ls".equals(op) || "list".equals(op)) { //$NON-NLS-1$//$NON-NLS-2$
-			for (final String k : s3.list(bucket, key))
+			for (String k : s3.list(bucket, key))
 				outw.println(k);
 
 		} else if ("rm".equals(op) || "delete".equals(op)) { //$NON-NLS-1$ //$NON-NLS-2$
 			s3.delete(bucket, key);
 
 		} else if ("put".equals(op)) { //$NON-NLS-1$
-			final OutputStream os = s3.beginPut(bucket, key, null, null);
-			final byte[] tmp = new byte[2048];
-			int n;
-			while ((n = ins.read(tmp)) > 0)
-				os.write(tmp, 0, n);
-			os.close();
-
+			try (OutputStream os = s3.beginPut(bucket, key, null, null)) {
+				final byte[] tmp = new byte[2048];
+				int n;
+				while ((n = ins.read(tmp)) > 0)
+					os.write(tmp, 0, n);
+			}
 		} else {
 			throw die(MessageFormat.format(CLIText.get().unsupportedOperation, op));
 		}
@@ -127,13 +125,10 @@ protected void run() throws Exception {
 
 	private Properties properties() {
 		try {
-			final InputStream in = new FileInputStream(propertyFile);
-			try {
+			try (InputStream in = new FileInputStream(propertyFile)) {
 				final Properties p = new Properties();
 				p.load(in);
 				return p;
-			} finally {
-				in.close();
 			}
 		} catch (FileNotFoundException e) {
 			throw die(MessageFormat.format(CLIText.get().noSuchFile, propertyFile), e);
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Archive.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Archive.java
index cff0bf6..4721b3a 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Archive.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Archive.java
@@ -74,6 +74,7 @@ class Archive extends TextBuiltin {
 	@Option(name = "--output", aliases = { "-o" }, metaVar = "metaVar_file", usage = "usage_archiveOutput")
 	private String output;
 
+	/** {@inheritDoc} */
 	@Override
 	protected void run() throws Exception {
 		if (tree == null)
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Blame.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Blame.java
index 4193254..13a38dd 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Blame.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Blame.java
@@ -134,6 +134,7 @@ void ignoreAllSpace(@SuppressWarnings("unused") boolean on) {
 
 	private BlameResult blame;
 
+	/** {@inheritDoc} */
 	@Override
 	protected void run() throws Exception {
 		if (file == null) {
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Branch.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Branch.java
index f6e3810..a88354d 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Branch.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Branch.java
@@ -87,6 +87,12 @@ class Branch extends TextBuiltin {
 
 	private List<String> delete;
 
+	/**
+	 * Delete branches
+	 *
+	 * @param names
+	 *            a {@link java.util.List} of branch names.
+	 */
 	@Option(name = "--delete", aliases = {
 			"-d" }, metaVar = "metaVar_branchNames", usage = "usage_deleteFullyMergedBranch", handler = OptionWithValuesListHandler.class)
 	public void delete(List<String> names) {
@@ -98,6 +104,12 @@ public void delete(List<String> names) {
 
 	private List<String> deleteForce;
 
+	/**
+	 * Forcefully delete branches
+	 *
+	 * @param names
+	 *            a {@link java.util.List} of branch names.
+	 */
 	@Option(name = "--delete-force", aliases = {
 			"-D" }, metaVar = "metaVar_branchNames", usage = "usage_deleteBranchEvenIfNotMerged", handler = OptionWithValuesListHandler.class)
 	public void deleteForce(List<String> names) {
@@ -107,6 +119,12 @@ public void deleteForce(List<String> names) {
 		deleteForce = names;
 	}
 
+	/**
+	 * Forcefully create a list of branches
+	 *
+	 * @param branchAndStartPoint
+	 *            a branch name and a start point
+	 */
 	@Option(name = "--create-force", aliases = {
 			"-f" }, metaVar = "metaVar_branchAndStartPoint", usage = "usage_forceCreateBranchEvenExists", handler = OptionWithValuesListHandler.class)
 	public void createForce(List<String> branchAndStartPoint) {
@@ -125,6 +143,12 @@ public void createForce(List<String> branchAndStartPoint) {
 		}
 	}
 
+	/**
+	 * Move or rename a branch
+	 *
+	 * @param currentAndNew
+	 *            the current and the new branch name
+	 */
 	@Option(name = "--move", aliases = {
 			"-m" }, metaVar = "metaVar_oldNewBranchNames", usage = "usage_moveRenameABranch", handler = OptionWithValuesListHandler.class)
 	public void moveRename(List<String> currentAndNew) {
@@ -156,6 +180,7 @@ public void moveRename(List<String> currentAndNew) {
 
 	private int maxNameLength;
 
+	/** {@inheritDoc} */
 	@Override
 	protected void run() throws Exception {
 		if (delete != null || deleteForce != null) {
@@ -267,7 +292,7 @@ else if (remote)
 				addRefs(refs, Constants.R_REMOTES);
 
 				try (ObjectReader reader = db.newObjectReader()) {
-					for (final Entry<String, Ref> e : printRefs.entrySet()) {
+					for (Entry<String, Ref> e : printRefs.entrySet()) {
 						final Ref ref = e.getValue();
 						printHead(reader, e.getKey(),
 								current.equals(ref.getName()), ref);
@@ -277,15 +302,15 @@ else if (remote)
 		}
 	}
 
-	private void addRefs(final Collection<Ref> refs, final String prefix) {
-		for (final Ref ref : RefComparator.sort(refs)) {
+	private void addRefs(Collection<Ref> refs, String prefix) {
+		for (Ref ref : RefComparator.sort(refs)) {
 			final String name = ref.getName();
 			if (name.startsWith(prefix))
 				addRef(name.substring(name.indexOf('/', 5) + 1), ref);
 		}
 	}
 
-	private void addRef(final String name, final Ref ref) {
+	private void addRef(String name, Ref ref) {
 		printRefs.put(name, ref);
 		maxNameLength = Math.max(maxNameLength, name.length());
 	}
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Checkout.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Checkout.java
index 2af1eca..6ff39fa 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Checkout.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Checkout.java
@@ -57,6 +57,7 @@
 import org.eclipse.jgit.lib.ObjectId;
 import org.eclipse.jgit.lib.Ref;
 import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.lib.TextProgressMonitor;
 import org.eclipse.jgit.pgm.internal.CLIText;
 import org.kohsuke.args4j.Argument;
 import org.kohsuke.args4j.Option;
@@ -80,6 +81,7 @@ class Checkout extends TextBuiltin {
 	@Option(name = "--", metaVar = "metaVar_paths", handler = RestOfArgumentsHandler.class)
 	private List<String> paths = new ArrayList<>();
 
+	/** {@inheritDoc} */
 	@Override
 	protected void run() throws Exception {
 		if (createBranch) {
@@ -89,7 +91,8 @@ protected void run() throws Exception {
 		}
 
 		try (Git git = new Git(db)) {
-			CheckoutCommand command = git.checkout();
+			CheckoutCommand command = git.checkout()
+					.setProgressMonitor(new TextProgressMonitor(errw));
 			if (paths.size() > 0) {
 				command.setStartPoint(name);
 				if (paths.size() == 1 && paths.get(0).equals(".")) { //$NON-NLS-1$
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Clean.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Clean.java
index ce4faf8..6ae078c 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Clean.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Clean.java
@@ -62,6 +62,7 @@ class Clean extends TextBuiltin {
 	@Option(name = "--dryRun", aliases = { "-n" })
 	private boolean dryRun = false;
 
+	/** {@inheritDoc} */
 	@Override
 	protected void run() throws Exception {
 		try (Git git = new Git(db)) {
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Clone.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Clone.java
index a8eb474..393c607 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Clone.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Clone.java
@@ -86,11 +86,13 @@ class Clone extends AbstractFetchCommand implements CloneCommand.Callback {
 	@Argument(index = 1, metaVar = "metaVar_directory")
 	private String localName;
 
+	/** {@inheritDoc} */
 	@Override
 	protected final boolean requiresRepository() {
 		return false;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected void run() throws Exception {
 		if (localName != null && gitdir != null)
@@ -148,6 +150,7 @@ protected void run() throws Exception {
 		}
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void initializedSubmodules(Collection<String> submodules) {
 		try {
@@ -161,6 +164,7 @@ public void initializedSubmodules(Collection<String> submodules) {
 		}
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void cloningSubmodule(String path) {
 		try {
@@ -172,6 +176,7 @@ public void cloningSubmodule(String path) {
 		}
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void checkingOut(AnyObjectId commit, String path) {
 		try {
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Command.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Command.java
index 0562416..d7adaf8 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Command.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Command.java
@@ -50,7 +50,7 @@
 import java.lang.annotation.Target;
 
 /**
- * Annotation to document a {@link TextBuiltin}.
+ * Annotation to document a {@link org.eclipse.jgit.pgm.TextBuiltin}.
  * <p>
  * This is an optional annotation for TextBuiltin subclasses and it carries
  * documentation forward into the runtime system describing what the command is
@@ -60,6 +60,8 @@
 @Target( { TYPE })
 public @interface Command {
 	/**
+	 * Get the command name
+	 *
 	 * @return name the command is invoked as from the command line. If the
 	 *         (default) empty string is supplied the name will be generated
 	 *         from the class name.
@@ -67,11 +69,15 @@
 	public String name() default "";
 
 	/**
+	 * Get command description
+	 *
 	 * @return one line description of the command's feature set.
 	 */
 	public String usage() default "";
 
 	/**
+	 * If this command is considered to be commonly used
+	 *
 	 * @return true if this command is considered to be commonly used.
 	 */
 	public boolean common() default false;
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/CommandCatalog.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/CommandCatalog.java
index cf4c6e3..5754d7c 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/CommandCatalog.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/CommandCatalog.java
@@ -43,9 +43,10 @@
 
 package org.eclipse.jgit.pgm;
 
+import static org.eclipse.jgit.lib.Constants.CHARSET;
+
 import java.io.BufferedReader;
 import java.io.IOException;
-import java.io.InputStream;
 import java.io.InputStreamReader;
 import java.net.URL;
 import java.util.ArrayList;
@@ -60,9 +61,10 @@
 /**
  * List of all commands known by jgit's command line tools.
  * <p>
- * Commands are implementations of {@link TextBuiltin}, with an optional
- * {@link Command} class annotation to insert additional documentation or
- * override the default command name (which is guessed from the class name).
+ * Commands are implementations of {@link org.eclipse.jgit.pgm.TextBuiltin},
+ * with an optional {@link org.eclipse.jgit.pgm.Command} class annotation to
+ * insert additional documentation or override the default command name (which
+ * is guessed from the class name).
  * <p>
  * Commands may be registered by adding them to a services file in the same JAR
  * (or classes directory) as the command implementation. The service file name
@@ -85,11 +87,13 @@ public class CommandCatalog {
 	 *            was derived from the DashLowerCaseForm class name.
 	 * @return the command instance; null if no command exists by that name.
 	 */
-	public static CommandRef get(final String name) {
+	public static CommandRef get(String name) {
 		return INSTANCE.commands.get(name);
 	}
 
 	/**
+	 * Get all commands sorted by their name
+	 *
 	 * @return all known commands, sorted by command name.
 	 */
 	public static CommandRef[] all() {
@@ -97,21 +101,23 @@ public static CommandRef get(final String name) {
 	}
 
 	/**
+	 * Get all common commands sorted by their name
+	 *
 	 * @return all common commands, sorted by command name.
 	 */
 	public static CommandRef[] common() {
 		final ArrayList<CommandRef> common = new ArrayList<>();
-		for (final CommandRef c : INSTANCE.commands.values())
+		for (CommandRef c : INSTANCE.commands.values())
 			if (c.isCommon())
 				common.add(c);
 		return toSortedArray(common);
 	}
 
-	private static CommandRef[] toSortedArray(final Collection<CommandRef> c) {
+	private static CommandRef[] toSortedArray(Collection<CommandRef> c) {
 		final CommandRef[] r = c.toArray(new CommandRef[c.size()]);
 		Arrays.sort(r, new Comparator<CommandRef>() {
 			@Override
-			public int compare(final CommandRef o1, final CommandRef o2) {
+			public int compare(CommandRef o1, CommandRef o2) {
 				return o1.getName().compareTo(o2.getName());
 			}
 		});
@@ -140,36 +146,20 @@ private Enumeration<URL> catalogs() {
 		}
 	}
 
-	private void scan(final URL cUrl) {
-		final BufferedReader cIn;
-		try {
-			final InputStream in = cUrl.openStream();
-			cIn = new BufferedReader(new InputStreamReader(in, "UTF-8")); //$NON-NLS-1$
-		} catch (IOException err) {
-			// If we cannot read from the service list, go to the next.
-			//
-			return;
-		}
-
-		try {
+	private void scan(URL cUrl) {
+		try (BufferedReader cIn = new BufferedReader(
+				new InputStreamReader(cUrl.openStream(), CHARSET))) {
 			String line;
 			while ((line = cIn.readLine()) != null) {
 				if (line.length() > 0 && !line.startsWith("#")) //$NON-NLS-1$
 					load(line);
 			}
-		} catch (IOException err) {
-			// If we failed during a read, ignore the error.
-			//
-		} finally {
-			try {
-				cIn.close();
-			} catch (IOException e) {
-				// Ignore the close error; we are only reading.
-			}
+		} catch (IOException e) {
+			// Ignore errors
 		}
 	}
 
-	private void load(final String cn) {
+	private void load(String cn) {
 		final Class<? extends TextBuiltin> clazz;
 		try {
 			clazz = Class.forName(cn, false, ldr).asSubclass(TextBuiltin.class);
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/CommandRef.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/CommandRef.java
index e5f8532..1773de5 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/CommandRef.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/CommandRef.java
@@ -50,7 +50,8 @@
 import org.eclipse.jgit.pgm.internal.CLIText;
 
 /**
- * Description of a command (a {@link TextBuiltin} subclass.
+ * Description of a command (a {@link org.eclipse.jgit.pgm.TextBuiltin}
+ * subclass).
  * <p>
  * These descriptions are lightweight compared to creating a command instance
  * and are therefore suitable for catalogs of "known" commands without linking
@@ -65,29 +66,29 @@ public class CommandRef {
 
 	boolean common;
 
-	CommandRef(final Class<? extends TextBuiltin> clazz) {
+	CommandRef(Class<? extends TextBuiltin> clazz) {
 		this(clazz, guessName(clazz));
 	}
 
-	CommandRef(final Class<? extends TextBuiltin> clazz, final Command cmd) {
+	CommandRef(Class<? extends TextBuiltin> clazz, Command cmd) {
 		this(clazz, cmd.name().length() > 0 ? cmd.name() : guessName(clazz));
 		usage = cmd.usage();
 		common = cmd.common();
 	}
 
-	private CommandRef(final Class<? extends TextBuiltin> clazz, final String cn) {
+	private CommandRef(Class<? extends TextBuiltin> clazz, String cn) {
 		impl = clazz;
 		name = cn;
 		usage = ""; //$NON-NLS-1$
 	}
 
-	private static String guessName(final Class<? extends TextBuiltin> clazz) {
+	private static String guessName(Class<? extends TextBuiltin> clazz) {
 		final StringBuilder s = new StringBuilder();
 		if (clazz.getName().startsWith("org.eclipse.jgit.pgm.debug.")) //$NON-NLS-1$
 			s.append("debug-"); //$NON-NLS-1$
 
 		boolean lastWasDash = true;
-		for (final char c : clazz.getSimpleName().toCharArray()) {
+		for (char c : clazz.getSimpleName().toCharArray()) {
 			if (Character.isUpperCase(c)) {
 				if (!lastWasDash)
 					s.append('-');
@@ -102,6 +103,8 @@ private static String guessName(final Class<? extends TextBuiltin> clazz) {
 	}
 
 	/**
+	 * Get the <code>name</code>.
+	 *
 	 * @return name the command is invoked as from the command line.
 	 */
 	public String getName() {
@@ -109,6 +112,8 @@ public String getName() {
 	}
 
 	/**
+	 * Get <code>usage</code>.
+	 *
 	 * @return one line description of the command's feature set.
 	 */
 	public String getUsage() {
@@ -116,6 +121,8 @@ public String getUsage() {
 	}
 
 	/**
+	 * Is this command commonly used
+	 *
 	 * @return true if this command is considered to be commonly used.
 	 */
 	public boolean isCommon() {
@@ -123,6 +130,8 @@ public boolean isCommon() {
 	}
 
 	/**
+	 * Get implementation class name
+	 *
 	 * @return name of the Java class which implements this command.
 	 */
 	public String getImplementationClassName() {
@@ -130,6 +139,8 @@ public String getImplementationClassName() {
 	}
 
 	/**
+	 * Get implementation class loader
+	 *
 	 * @return loader for {@link #getImplementationClassName()}.
 	 */
 	public ClassLoader getImplementationClassLoader() {
@@ -137,6 +148,8 @@ public ClassLoader getImplementationClassLoader() {
 	}
 
 	/**
+	 * Create an instance of the command implementation
+	 *
 	 * @return a new instance of the command implementation.
 	 */
 	public TextBuiltin create() {
@@ -166,6 +179,7 @@ public TextBuiltin create() {
 		return r;
 	}
 
+	/** {@inheritDoc} */
 	@SuppressWarnings("nls")
 	@Override
 	public String toString() {
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Commit.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Commit.java
index befc4ec..2e67c02 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Commit.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Commit.java
@@ -77,6 +77,7 @@ class Commit extends TextBuiltin {
 	@Argument(metaVar = "metaVar_commitPaths", usage = "usage_CommitPaths")
 	private List<String> paths = new ArrayList<>();
 
+	/** {@inheritDoc} */
 	@Override
 	protected void run() throws NoHeadException, NoMessageException,
 			ConcurrentRefUpdateException, JGitInternalException, Exception {
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Config.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Config.java
index f5c3f9a..f762c0d 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Config.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Config.java
@@ -68,6 +68,7 @@ class Config extends TextBuiltin {
 	@Option(name = "--file", aliases = { "-f" }, metaVar = "metaVar_file", usage = "usage_configFile")
 	private File configFile;
 
+	/** {@inheritDoc} */
 	@Override
 	protected void run() throws Exception {
 		if (list)
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Daemon.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Daemon.java
index 51bb979..319b5e3 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Daemon.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Daemon.java
@@ -111,11 +111,13 @@ enum KetchServerType {
 	@Argument(required = true, metaVar = "metaVar_directory", usage = "usage_directoriesToExport")
 	List<File> directory = new ArrayList<>();
 
+	/** {@inheritDoc} */
 	@Override
 	protected boolean requiresRepository() {
 		return false;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected void run() throws Exception {
 		PackConfig packConfig = new PackConfig();
@@ -140,7 +142,7 @@ protected void run() throws Exception {
 			packConfig.setExecutor(Executors.newFixedThreadPool(threads));
 
 		final FileResolver<DaemonClient> resolver = new FileResolver<>();
-		for (final File f : directory) {
+		for (File f : directory) {
 			outw.println(MessageFormat.format(CLIText.get().exporting, f.getAbsolutePath()));
 			resolver.exportDirectory(f);
 		}
@@ -155,14 +157,14 @@ protected void run() throws Exception {
 		if (0 <= timeout)
 			d.setTimeout(timeout);
 
-		for (final String n : enable)
+		for (String n : enable)
 			service(d, n).setEnabled(true);
-		for (final String n : disable)
+		for (String n : disable)
 			service(d, n).setEnabled(false);
 
-		for (final String n : canOverride)
+		for (String n : canOverride)
 			service(d, n).setOverridable(true);
-		for (final String n : forbidOverride)
+		for (String n : forbidOverride)
 			service(d, n).setOverridable(false);
 		if (ketchServerType == KetchServerType.LEADER) {
 			startKetchLeader(d);
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Describe.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Describe.java
index 03e2711..f9c1cf5 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Describe.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Describe.java
@@ -65,6 +65,7 @@ class Describe extends TextBuiltin {
 	@Option(name = "--match", usage = "usage_Match", metaVar = "metaVar_pattern")
 	private List<String> patterns = new ArrayList<>();
 
+	/** {@inheritDoc} */
 	@Override
 	protected void run() throws Exception {
 		try (Git git = new Git(db)) {
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Die.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Die.java
index a25f1e9..4ec5f04 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Die.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Die.java
@@ -45,7 +45,8 @@
 package org.eclipse.jgit.pgm;
 
 /**
- * Indicates a {@link TextBuiltin} implementation has failed during execution.
+ * Indicates a {@link org.eclipse.jgit.pgm.TextBuiltin} implementation has
+ * failed during execution.
  * <p>
  * Typically the stack trace for a Die exception is not shown to the user as it
  * may indicate a simple error condition that the end-user can fix on their own,
@@ -62,7 +63,7 @@ public class Die extends RuntimeException {
 	 * @param why
 	 *            the message to show to the end-user.
 	 */
-	public Die(final String why) {
+	public Die(String why) {
 		super(why);
 	}
 
@@ -74,7 +75,7 @@ public Die(final String why) {
 	 * @param cause
 	 *            why the command has failed.
 	 */
-	public Die(final String why, final Throwable cause) {
+	public Die(String why, Throwable cause) {
 		super(why, cause);
 	}
 
@@ -99,7 +100,7 @@ public Die(boolean aborted) {
 	 *            can be null
 	 * @since 4.2
 	 */
-	public Die(boolean aborted, final Throwable cause) {
+	public Die(boolean aborted, Throwable cause) {
 		super(cause != null ? cause.getMessage() : null, cause);
 		this.aborted = aborted;
 	}
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Diff.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Diff.java
index 16284d5..97e3df3 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Diff.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Diff.java
@@ -168,12 +168,14 @@ void noPrefix(@SuppressWarnings("unused") boolean on) {
 
 	// END -- Options shared with Log
 
+	/** {@inheritDoc} */
 	@Override
-	protected void init(final Repository repository, final String gitDir) {
+	protected void init(Repository repository, String gitDir) {
 		super.init(repository, gitDir);
 		diffFmt = new DiffFormatter(new BufferedOutputStream(outs));
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected void run() throws Exception {
 		diffFmt.setRepository(db);
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/DiffTree.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/DiffTree.java
index 4432405..42aabc2 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/DiffTree.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/DiffTree.java
@@ -72,11 +72,12 @@ void tree_0(final AbstractTreeIterator c) {
 	@Option(name = "--", metaVar = "metaVar_path", handler = PathTreeFilterHandler.class)
 	private TreeFilter pathFilter = TreeFilter.ALL;
 
+	/** {@inheritDoc} */
 	@Override
 	protected void run() throws Exception {
-		try (final TreeWalk walk = new TreeWalk(db)) {
+		try (TreeWalk walk = new TreeWalk(db)) {
 			walk.setRecursive(recursive);
-			for (final AbstractTreeIterator i : trees)
+			for (AbstractTreeIterator i : trees)
 				walk.addTree(i);
 			walk.setFilter(AndTreeFilter.create(TreeFilter.ANY_DIFF, pathFilter));
 
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Fetch.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Fetch.java
index f4b7708..61fd521 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Fetch.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Fetch.java
@@ -100,6 +100,9 @@ void notags(@SuppressWarnings("unused")
 		tags = Boolean.FALSE;
 	}
 
+	@Option(name = "--force", usage = "usage_forcedFetch", aliases = { "-f" })
+	private Boolean force;
+
 	private FetchRecurseSubmodulesMode recurseSubmodules;
 
 	@Option(name = "--recurse-submodules", usage = "usage_recurseSubmodules")
@@ -131,6 +134,7 @@ void noRecurseSubmodules(@SuppressWarnings("unused")
 	@Argument(index = 1, metaVar = "metaVar_refspec")
 	private List<RefSpec> toget;
 
+	/** {@inheritDoc} */
 	@Override
 	protected void run() throws Exception {
 		try (Git git = new Git(db)) {
@@ -154,6 +158,9 @@ protected void run() throws Exception {
 			if (quiet == null || !quiet.booleanValue())
 				fetch.setProgressMonitor(new TextProgressMonitor(errw));
 			fetch.setRecurseSubmodules(recurseSubmodules).setCallback(this);
+			if (force != null) {
+				fetch.setForceUpdate(force.booleanValue());
+			}
 
 			FetchResult result = fetch.call();
 			if (result.getTrackingRefUpdates().isEmpty()
@@ -164,6 +171,7 @@ protected void run() throws Exception {
 		}
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void fetchingSubmodule(String name) {
 		try {
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Gc.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Gc.java
index 7289abb..56172f5 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Gc.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Gc.java
@@ -58,6 +58,7 @@ class Gc extends TextBuiltin {
 	@Option(name = "--prune-preserved", usage = "usage_PrunePreserved")
 	private boolean prunePreserved;
 
+	/** {@inheritDoc} */
 	@Override
 	protected void run() throws Exception {
 		Git git = Git.wrap(db);
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Glog.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Glog.java
index 7b71575..2b5af5d 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Glog.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Glog.java
@@ -75,7 +75,7 @@ class Glog extends RevWalkTextBuiltin {
 		frame = new JFrame();
 		frame.addWindowListener(new WindowAdapter() {
 			@Override
-			public void windowClosing(final WindowEvent e) {
+			public void windowClosing(WindowEvent e) {
 				frame.dispose();
 			}
 		});
@@ -102,6 +102,7 @@ public void actionPerformed(ActionEvent e) {
 		frame.getContentPane().add(world);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected int walkLoop() throws Exception {
 		graphPane.getCommitList().source(walk);
@@ -113,11 +114,13 @@ protected int walkLoop() throws Exception {
 		return graphPane.getCommitList().size();
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	protected void show(final RevCommit c) throws Exception {
+	protected void show(RevCommit c) throws Exception {
 		throw new UnsupportedOperationException();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected RevWalk createWalk() {
 		if (objects)
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/IndexPack.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/IndexPack.java
index 22f3be9..2627671 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/IndexPack.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/IndexPack.java
@@ -60,6 +60,7 @@ class IndexPack extends TextBuiltin {
 	@Option(name = "--index-version", usage = "usage_indexFileFormatToCreate")
 	private int indexVersion = -1;
 
+	/** {@inheritDoc} */
 	@Override
 	protected void run() throws Exception {
 		BufferedInputStream in = new BufferedInputStream(ins);
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Init.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Init.java
index a7bee7f..f880fc2 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Init.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Init.java
@@ -66,11 +66,13 @@ class Init extends TextBuiltin {
 	@Argument(index = 0, metaVar = "metaVar_directory")
 	private String directory;
 
+	/** {@inheritDoc} */
 	@Override
 	protected final boolean requiresRepository() {
 		return false;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected void run() throws Exception {
 		InitCommand command = Git.init();
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Log.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Log.java
index 1108ddd..ad92a78 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Log.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Log.java
@@ -184,12 +184,14 @@ void noPrefix(@SuppressWarnings("unused") boolean on) {
 		dateFormatter = new GitDateFormatter(Format.DEFAULT);
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	protected void init(final Repository repository, final String gitDir) {
+	protected void init(Repository repository, String gitDir) {
 		super.init(repository, gitDir);
 		diffFmt = new DiffFormatter(new BufferedOutputStream(outs));
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected void run() throws Exception {
 		diffFmt.setRepository(db);
@@ -237,8 +239,9 @@ private void addNoteMap(String notesRef) throws IOException {
 				NoteMap.read(argWalk.getObjectReader(), notesCommit));
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	protected void show(final RevCommit c) throws Exception {
+	protected void show(RevCommit c) throws Exception {
 		outw.print(CLIText.get().commitLabel);
 		outw.print(" "); //$NON-NLS-1$
 		c.getId().copyTo(outbuffer, outw);
@@ -263,7 +266,7 @@ protected void show(final RevCommit c) throws Exception {
 
 		outw.println();
 		final String[] lines = c.getFullMessage().split("\n"); //$NON-NLS-1$
-		for (final String s : lines) {
+		for (String s : lines) {
 			outw.print("    "); //$NON-NLS-1$
 			outw.print(s);
 			outw.println();
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/LsRemote.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/LsRemote.java
index 7a5f3d8..2711c15 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/LsRemote.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/LsRemote.java
@@ -70,6 +70,7 @@ class LsRemote extends TextBuiltin {
 	@Argument(index = 0, metaVar = "metaVar_uriish", required = true)
 	private String remote;
 
+	/** {@inheritDoc} */
 	@Override
 	protected void run() throws Exception {
 		LsRemoteCommand command = Git.lsRemoteRepository().setRemote(remote)
@@ -82,19 +83,20 @@ public int compare(Ref r1, Ref r2) {
 			}
 		});
 		refs.addAll(command.call());
-		for (final Ref r : refs) {
+		for (Ref r : refs) {
 			show(r.getObjectId(), r.getName());
 			if (r.getPeeledObjectId() != null)
 				show(r.getPeeledObjectId(), r.getName() + "^{}"); //$NON-NLS-1$
 		}
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected boolean requiresRepository() {
 		return false;
 	}
 
-	private void show(final AnyObjectId id, final String name)
+	private void show(AnyObjectId id, String name)
 			throws IOException {
 		outw.print(id.name());
 		outw.print('\t');
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/LsTree.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/LsTree.java
index 398d305..01fa7ee 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/LsTree.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/LsTree.java
@@ -70,9 +70,10 @@ class LsTree extends TextBuiltin {
 	@Option(name = "--", metaVar = "metaVar_paths", handler = StopOptionHandler.class)
 	private List<String> paths = new ArrayList<>();
 
+	/** {@inheritDoc} */
 	@Override
 	protected void run() throws Exception {
-		try (final TreeWalk walk = new TreeWalk(db)) {
+		try (TreeWalk walk = new TreeWalk(db)) {
 			walk.reset(); // drop the first empty tree, which we do not need here
 			if (paths.size() > 0)
 				walk.setFilter(PathFilterGroup.createFromStrings(paths));
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Main.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Main.java
index 9d44dc0..ac53de9 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Main.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Main.java
@@ -44,7 +44,7 @@
 
 package org.eclipse.jgit.pgm;
 
-import static java.nio.charset.StandardCharsets.UTF_8;
+import static org.eclipse.jgit.lib.Constants.CHARSET;
 
 import java.io.File;
 import java.io.IOException;
@@ -65,13 +65,13 @@
 import org.eclipse.jgit.awtui.AwtAuthenticator;
 import org.eclipse.jgit.awtui.AwtCredentialsProvider;
 import org.eclipse.jgit.errors.TransportException;
-import org.eclipse.jgit.lfs.CleanFilter;
-import org.eclipse.jgit.lfs.SmudgeFilter;
+import org.eclipse.jgit.lfs.BuiltinLFS;
 import org.eclipse.jgit.lib.Repository;
 import org.eclipse.jgit.lib.RepositoryBuilder;
 import org.eclipse.jgit.pgm.internal.CLIText;
 import org.eclipse.jgit.pgm.opt.CmdLineParser;
 import org.eclipse.jgit.pgm.opt.SubcommandHandler;
+import org.eclipse.jgit.storage.file.WindowCacheConfig;
 import org.eclipse.jgit.transport.HttpTransport;
 import org.eclipse.jgit.transport.http.apache.HttpClientConnectionFactory;
 import org.eclipse.jgit.util.CachedAuthenticator;
@@ -80,7 +80,9 @@
 import org.kohsuke.args4j.Option;
 import org.kohsuke.args4j.OptionHandlerFilter;
 
-/** Command line entry point. */
+/**
+ * Command line entry point.
+ */
 public class Main {
 	@Option(name = "--help", usage = "usage_displayThisHelpText", aliases = { "-h" })
 	private boolean help;
@@ -104,13 +106,21 @@ public class Main {
 
 	private ExecutorService gcExecutor;
 
+	private static final int MB = 1024 * 1024;
+
 	/**
-	 *
+	 * <p>Constructor for Main.</p>
 	 */
 	public Main() {
+		final WindowCacheConfig c = new WindowCacheConfig();
+		c.setPackedGitMMAP(true);
+		c.setPackedGitWindowSize(8 * 1024);
+		c.setPackedGitLimit(10 * MB);
+		c.setDeltaBaseCacheLimit(10 * MB);
+		c.setStreamFileThreshold(50 * MB);
+		c.install();
 		HttpTransport.setConnectionFactory(new HttpClientConnectionFactory());
-		CleanFilter.register();
-		SmudgeFilter.register();
+		BuiltinLFS.register();
 		gcExecutor = Executors.newSingleThreadExecutor(new ThreadFactory() {
 			private final ThreadFactory baseFactory = Executors
 					.defaultThreadFactory();
@@ -129,9 +139,12 @@ public Thread newThread(Runnable taskBody) {
 	 *
 	 * @param argv
 	 *            arguments.
-	 * @throws Exception
+	 * @throws java.lang.Exception
 	 */
-	public static void main(final String[] argv) throws Exception {
+	public static void main(String[] argv) throws Exception {
+		// make sure built-in filters are registered
+		BuiltinLFS.register();
+
 		new Main().run(argv);
 	}
 
@@ -150,9 +163,9 @@ public static void main(final String[] argv) throws Exception {
 	 *
 	 * @param argv
 	 *            arguments.
-	 * @throws Exception
+	 * @throws java.lang.Exception
 	 */
-	protected void run(final String[] argv) throws Exception {
+	protected void run(String[] argv) throws Exception {
 		writer = createErrorWriter();
 		try {
 			if (!installConsole()) {
@@ -214,10 +227,10 @@ protected void run(final String[] argv) throws Exception {
 	}
 
 	PrintWriter createErrorWriter() {
-		return new PrintWriter(new OutputStreamWriter(System.err, UTF_8));
+		return new PrintWriter(new OutputStreamWriter(System.err, CHARSET));
 	}
 
-	private void execute(final String[] argv) throws Exception {
+	private void execute(String[] argv) throws Exception {
 		final CmdLineParser clp = new SubcommandLineParser(this);
 
 		try {
@@ -243,12 +256,12 @@ private void execute(final String[] argv) throws Exception {
 				writer.println(CLIText.get().mostCommonlyUsedCommandsAre);
 				final CommandRef[] common = CommandCatalog.common();
 				int width = 0;
-				for (final CommandRef c : common) {
+				for (CommandRef c : common) {
 					width = Math.max(width, c.getName().length());
 				}
 				width += 2;
 
-				for (final CommandRef c : common) {
+				for (CommandRef c : common) {
 					writer.print(' ');
 					writer.print(c.getName());
 					for (int i = c.getName().length(); i < width; i++) {
@@ -283,7 +296,7 @@ private void execute(final String[] argv) throws Exception {
 		}
 	}
 
-	void init(final TextBuiltin cmd) throws IOException {
+	void init(TextBuiltin cmd) throws IOException {
 		if (cmd.requiresRepository()) {
 			cmd.init(openGitDir(gitdir), null);
 		} else {
@@ -309,7 +322,7 @@ void exit(int status, Exception t) throws Exception {
 	 *            the {@code --git-dir} option given on the command line. May be
 	 *            null if it was not supplied.
 	 * @return the repository to operate on.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the repository cannot be opened.
 	 */
 	protected Repository openGitDir(String aGitdir) throws IOException {
@@ -347,7 +360,7 @@ private static boolean installConsole() {
 		}
 	}
 
-	private static void install(final String name)
+	private static void install(String name)
 			throws IllegalAccessException, InvocationTargetException,
 			NoSuchMethodException, ClassNotFoundException {
 		try {
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Merge.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Merge.java
index 1aab748..de059e9 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Merge.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Merge.java
@@ -101,6 +101,7 @@ void ffonly(@SuppressWarnings("unused") final boolean ignored) {
 	@Option(name = "-m", usage = "usage_message")
 	private String message;
 
+	/** {@inheritDoc} */
 	@Override
 	protected void run() throws Exception {
 		if (squash && ff == FastForwardMode.NO_FF)
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/MergeBase.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/MergeBase.java
index 975d5de..6842d8d 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/MergeBase.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/MergeBase.java
@@ -65,9 +65,10 @@ void commit_0(final RevCommit c) {
 	@Argument(index = 1, metaVar = "metaVar_commitish", required = true)
 	private List<RevCommit> commits = new ArrayList<>();
 
+	/** {@inheritDoc} */
 	@Override
 	protected void run() throws Exception {
-		for (final RevCommit c : commits)
+		for (RevCommit c : commits)
 			argWalk.markStart(c);
 		argWalk.setRevFilter(RevFilter.MERGE_BASE);
 		int max = all ? Integer.MAX_VALUE : 1;
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Push.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Push.java
index 389708e..be8ad37 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Push.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Push.java
@@ -113,6 +113,7 @@ void nothin(@SuppressWarnings("unused") final boolean ignored) {
 
 	private boolean shownURI;
 
+	/** {@inheritDoc} */
 	@Override
 	protected void run() throws Exception {
 		try (Git git = new Git(db)) {
@@ -148,7 +149,7 @@ private void printPushResult(final ObjectReader reader, final URIish uri,
 		boolean everythingUpToDate = true;
 
 		// at first, print up-to-date ones...
-		for (final RemoteRefUpdate rru : result.getRemoteUpdates()) {
+		for (RemoteRefUpdate rru : result.getRemoteUpdates()) {
 			if (rru.getStatus() == Status.UP_TO_DATE) {
 				if (verbose)
 					printRefUpdateResult(reader, uri, result, rru);
@@ -156,13 +157,13 @@ private void printPushResult(final ObjectReader reader, final URIish uri,
 				everythingUpToDate = false;
 		}
 
-		for (final RemoteRefUpdate rru : result.getRemoteUpdates()) {
+		for (RemoteRefUpdate rru : result.getRemoteUpdates()) {
 			// ...then successful updates...
 			if (rru.getStatus() == Status.OK)
 				printRefUpdateResult(reader, uri, result, rru);
 		}
 
-		for (final RemoteRefUpdate rru : result.getRemoteUpdates()) {
+		for (RemoteRefUpdate rru : result.getRemoteUpdates()) {
 			// ...finally, others (problematic)
 			if (rru.getStatus() != Status.OK
 					&& rru.getStatus() != Status.UP_TO_DATE)
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/ReceivePack.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/ReceivePack.java
index d7f895a..f3baafb 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/ReceivePack.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/ReceivePack.java
@@ -58,11 +58,13 @@ class ReceivePack extends TextBuiltin {
 	@Argument(index = 0, required = true, metaVar = "metaVar_directory", usage = "usage_RepositoryToReceiveInto")
 	File dstGitdir;
 
+	/** {@inheritDoc} */
 	@Override
 	protected final boolean requiresRepository() {
 		return false;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected void run() throws Exception {
 		final org.eclipse.jgit.transport.ReceivePack rp;
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Reflog.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Reflog.java
index 86a021d..6f4fcc2 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Reflog.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Reflog.java
@@ -57,6 +57,7 @@ class Reflog extends TextBuiltin {
 	@Argument(metaVar = "metaVar_ref")
 	private String ref;
 
+	/** {@inheritDoc} */
 	@Override
 	protected void run() throws Exception {
 		try (Git git = new Git(db)) {
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Remote.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Remote.java
index 24916bd..3308e18 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Remote.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Remote.java
@@ -84,6 +84,7 @@ class Remote extends TextBuiltin {
 	@Argument(index = 2, metaVar = "metaVar_uriish")
 	private String uri;
 
+	/** {@inheritDoc} */
 	@Override
 	protected void run() throws Exception {
 		try (Git git = new Git(db)) {
@@ -143,8 +144,9 @@ protected void run() throws Exception {
 		}
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	public void printUsage(final String message, final CmdLineParser clp)
+	public void printUsage(String message, CmdLineParser clp)
 			throws IOException {
 		errw.println(message);
 		errw.println("jgit remote [--verbose (-v)] [--help (-h)]"); //$NON-NLS-1$
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Repo.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Repo.java
index bec5003..f557211 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Repo.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Repo.java
@@ -58,6 +58,7 @@ class Repo extends TextBuiltin {
 	@Argument(required = true, metaVar = "metaVar_path", usage = "usage_pathToXml")
 	private String path;
 
+	/** {@inheritDoc} */
 	@Override
 	protected void run() throws Exception {
 		new RepoCommand(db)
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Reset.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Reset.java
index 4c19883..f84c848 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Reset.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Reset.java
@@ -72,6 +72,7 @@ class Reset extends TextBuiltin {
 	@Option(name = "--", metaVar = "metaVar_paths", handler = RestOfArgumentsHandler.class)
 	private List<String> paths = new ArrayList<>();
 
+	/** {@inheritDoc} */
 	@Override
 	protected void run() throws Exception {
 		try (Git git = new Git(db)) {
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/RevList.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/RevList.java
index 4420abe..101fbb2 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/RevList.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/RevList.java
@@ -51,8 +51,9 @@
 
 @Command(usage = "usage_RevList")
 class RevList extends RevWalkTextBuiltin {
+	/** {@inheritDoc} */
 	@Override
-	protected void show(final RevCommit c) throws Exception {
+	protected void show(RevCommit c) throws Exception {
 		if (c.has(RevFlag.UNINTERESTING))
 			outw.print('-');
 		c.getId().copyTo(outbuffer, outw);
@@ -64,8 +65,9 @@ protected void show(final RevCommit c) throws Exception {
 		outw.println();
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	protected void show(final ObjectWalk ow, final RevObject obj)
+	protected void show(ObjectWalk ow, RevObject obj)
 			throws Exception {
 		if (obj.has(RevFlag.UNINTERESTING))
 			outw.print('-');
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/RevParse.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/RevParse.java
index 2157034..ac08cd6 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/RevParse.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/RevParse.java
@@ -45,11 +45,8 @@
 
 package org.eclipse.jgit.pgm;
 
-import static org.eclipse.jgit.lib.RefDatabase.ALL;
-
 import java.util.ArrayList;
 import java.util.List;
-import java.util.Map;
 
 import org.eclipse.jgit.lib.ObjectId;
 import org.eclipse.jgit.lib.Ref;
@@ -70,11 +67,11 @@ class RevParse extends TextBuiltin {
 	@Argument(index = 0, metaVar = "metaVar_commitish")
 	private List<ObjectId> commits = new ArrayList<>();
 
+	/** {@inheritDoc} */
 	@Override
 	protected void run() throws Exception {
 		if (all) {
-			Map<String, Ref> allRefs = db.getRefDatabase().getRefs(ALL);
-			for (final Ref r : allRefs.values()) {
+			for (Ref r : db.getRefDatabase().getRefs()) {
 				ObjectId objectId = r.getObjectId();
 				// getRefs skips dangling symrefs, so objectId should never be
 				// null.
@@ -90,7 +87,7 @@ protected void run() throws Exception {
 						CLIText.format(CLIText.get().needSingleRevision));
 			}
 
-			for (final ObjectId o : commits) {
+			for (ObjectId o : commits) {
 				outw.println(o.name());
 			}
 		}
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/RevWalkTextBuiltin.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/RevWalkTextBuiltin.java
index 6b0744d..15abeac 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/RevWalkTextBuiltin.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/RevWalkTextBuiltin.java
@@ -47,14 +47,12 @@
 import java.util.ArrayList;
 import java.util.EnumSet;
 import java.util.List;
-import java.util.Map;
 
 import org.eclipse.jgit.diff.DiffConfig;
 import org.eclipse.jgit.errors.IncorrectObjectTypeException;
 import org.eclipse.jgit.lib.Constants;
 import org.eclipse.jgit.lib.ObjectId;
 import org.eclipse.jgit.lib.Ref;
-import org.eclipse.jgit.lib.RefDatabase;
 import org.eclipse.jgit.pgm.internal.CLIText;
 import org.eclipse.jgit.pgm.opt.PathTreeFilterHandler;
 import org.eclipse.jgit.revwalk.FollowFilter;
@@ -93,7 +91,7 @@ abstract class RevWalkTextBuiltin extends TextBuiltin {
 
 	private final EnumSet<RevSort> sorting = EnumSet.noneOf(RevSort.class);
 
-	private void enableRevSort(final RevSort type, final boolean on) {
+	private void enableRevSort(RevSort type, boolean on) {
 		if (on)
 			sorting.add(type);
 		else
@@ -101,22 +99,22 @@ private void enableRevSort(final RevSort type, final boolean on) {
 	}
 
 	@Option(name = "--date-order")
-	void enableDateOrder(final boolean on) {
+	void enableDateOrder(boolean on) {
 		enableRevSort(RevSort.COMMIT_TIME_DESC, on);
 	}
 
 	@Option(name = "--topo-order")
-	void enableTopoOrder(final boolean on) {
+	void enableTopoOrder(boolean on) {
 		enableRevSort(RevSort.TOPO, on);
 	}
 
 	@Option(name = "--reverse")
-	void enableReverse(final boolean on) {
+	void enableReverse(boolean on) {
 		enableRevSort(RevSort.REVERSE, on);
 	}
 
 	@Option(name = "--boundary")
-	void enableBoundary(final boolean on) {
+	void enableBoundary(boolean on) {
 		enableRevSort(RevSort.BOUNDARY, on);
 	}
 
@@ -132,27 +130,28 @@ void enableBoundary(final boolean on) {
 	private final List<RevFilter> revLimiter = new ArrayList<>();
 
 	@Option(name = "--author")
-	void addAuthorRevFilter(final String who) {
+	void addAuthorRevFilter(String who) {
 		revLimiter.add(AuthorRevFilter.create(who));
 	}
 
 	@Option(name = "--committer")
-	void addCommitterRevFilter(final String who) {
+	void addCommitterRevFilter(String who) {
 		revLimiter.add(CommitterRevFilter.create(who));
 	}
 
 	@Option(name = "--grep")
-	void addCMessageRevFilter(final String msg) {
+	void addCMessageRevFilter(String msg) {
 		revLimiter.add(MessageRevFilter.create(msg));
 	}
 
 	@Option(name = "--max-count", aliases = "-n", metaVar = "metaVar_n")
 	private int maxCount = -1;
 
+	/** {@inheritDoc} */
 	@Override
 	protected void run() throws Exception {
 		walk = createWalk();
-		for (final RevSort s : sorting)
+		for (RevSort s : sorting)
 			walk.sort(s, true);
 
 		if (pathFilter == TreeFilter.ALL) {
@@ -170,9 +169,7 @@ else if (revLimiter.size() > 1)
 			walk.setRevFilter(AndRevFilter.create(revLimiter));
 
 		if (all) {
-			Map<String, Ref> refs =
-				db.getRefDatabase().getRefs(RefDatabase.ALL);
-			for (Ref a : refs.values()) {
+			for (Ref a : db.getRefDatabase().getRefs()) {
 				ObjectId oid = a.getPeeledObjectId();
 				if (oid == null)
 					oid = a.getObjectId();
@@ -190,7 +187,7 @@ else if (revLimiter.size() > 1)
 				throw die(MessageFormat.format(CLIText.get().cannotResolve, Constants.HEAD));
 			commits.add(walk.parseCommit(head));
 		}
-		for (final RevCommit c : commits) {
+		for (RevCommit c : commits) {
 			final RevCommit real = argWalk == walk ? c : walk.parseCommit(c);
 			if (c.has(RevFlag.UNINTERESTING))
 				walk.markUninteresting(real);
@@ -210,6 +207,11 @@ else if (revLimiter.size() > 1)
 		}
 	}
 
+	/**
+	 * Create RevWalk
+	 *
+	 * @return a {@link org.eclipse.jgit.revwalk.RevWalk} object.
+	 */
 	protected RevWalk createWalk() {
 		RevWalk result;
 		if (objects)
@@ -222,9 +224,16 @@ else if (argWalk != null)
 		return result;
 	}
 
+	/**
+	 * Loop the walk
+	 *
+	 * @return number of RevCommits walked
+	 * @throws java.lang.Exception
+	 *             if any.
+	 */
 	protected int walkLoop() throws Exception {
 		int n = 0;
-		for (final RevCommit c : walk) {
+		for (RevCommit c : walk) {
 			if (++n > maxCount && maxCount >= 0)
 				break;
 			show(c);
@@ -248,10 +257,10 @@ protected int walkLoop() throws Exception {
 	 * RevWalkTextBuiltin.
 	 *
 	 * @param c
-	 *            The current {@link RevCommit}
-	 * @throws Exception
+	 *            The current {@link org.eclipse.jgit.revwalk.RevCommit}
+	 * @throws java.lang.Exception
 	 */
-	protected abstract void show(final RevCommit c) throws Exception;
+	protected abstract void show(RevCommit c) throws Exception;
 
 	/**
 	 * "Show" the current RevCommit when called from the main processing loop.
@@ -260,10 +269,11 @@ protected int walkLoop() throws Exception {
 	 * process RevCommits.
 	 *
 	 * @param objectWalk
-	 *            the {@link ObjectWalk} used by {@link #walkLoop()}
+	 *            the {@link org.eclipse.jgit.revwalk.ObjectWalk} used by
+	 *            {@link #walkLoop()}
 	 * @param currentObject
-	 *            The current {@link RevObject}
-	 * @throws Exception
+	 *            The current {@link org.eclipse.jgit.revwalk.RevObject}
+	 * @throws java.lang.Exception
 	 */
 	protected void show(final ObjectWalk objectWalk,
 			final RevObject currentObject) throws Exception {
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Rm.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Rm.java
index 32a5631..f591610 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Rm.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Rm.java
@@ -59,6 +59,7 @@ class Rm extends TextBuiltin {
 	@Option(name = "--", handler = StopOptionHandler.class)
 	private List<String> paths = new ArrayList<>();
 
+	/** {@inheritDoc} */
 	@Override
 	protected void run() throws Exception {
 		try (Git git = new Git(db)) {
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Show.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Show.java
index 5eda36f..89a15fe 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Show.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Show.java
@@ -165,12 +165,14 @@ void noPrefix(@SuppressWarnings("unused") boolean on) {
 		fmt = new SimpleDateFormat("EEE MMM dd HH:mm:ss yyyy ZZZZZ", Locale.US); //$NON-NLS-1$
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	protected void init(final Repository repository, final String gitDir) {
+	protected void init(Repository repository, String gitDir) {
 		super.init(repository, gitDir);
 		diffFmt = new DiffFormatter(new BufferedOutputStream(outs));
 	}
 
+	/** {@inheritDoc} */
 	@SuppressWarnings("boxing")
 	@Override
 	protected void run() throws Exception {
@@ -246,7 +248,7 @@ private void show(RevTag tag) throws IOException {
 
 		outw.println();
 		final String[] lines = tag.getFullMessage().split("\n"); //$NON-NLS-1$
-		for (final String s : lines) {
+		for (String s : lines) {
 			outw.print("    "); //$NON-NLS-1$
 			outw.print(s);
 			outw.println();
@@ -257,7 +259,7 @@ private void show(RevTag tag) throws IOException {
 
 	private void show(RevTree obj) throws MissingObjectException,
 			IncorrectObjectTypeException, CorruptObjectException, IOException {
-		try (final TreeWalk walk = new TreeWalk(db)) {
+		try (TreeWalk walk = new TreeWalk(db)) {
 			walk.reset();
 			walk.addTree(obj);
 
@@ -271,7 +273,7 @@ private void show(RevTree obj) throws MissingObjectException,
 		}
 	}
 
-	private void show(RevWalk rw, final RevCommit c) throws Exception {
+	private void show(RevWalk rw, RevCommit c) throws Exception {
 		char[] outbuffer = new char[Constants.OBJECT_ID_LENGTH * 2];
 
 		outw.print(CLIText.get().commitLabel);
@@ -290,7 +292,7 @@ private void show(RevWalk rw, final RevCommit c) throws Exception {
 
 		outw.println();
 		final String[] lines = c.getFullMessage().split("\n"); //$NON-NLS-1$
-		for (final String s : lines) {
+		for (String s : lines) {
 			outw.print("    "); //$NON-NLS-1$
 			outw.print(s);
 			outw.println();
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/ShowRef.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/ShowRef.java
index e9d9df6..6318a63 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/ShowRef.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/ShowRef.java
@@ -45,22 +45,19 @@
 
 package org.eclipse.jgit.pgm;
 
-import static org.eclipse.jgit.lib.RefDatabase.ALL;
-
 import java.io.IOException;
-import java.util.Map;
-import java.util.SortedMap;
+import java.util.List;
 
 import org.eclipse.jgit.lib.AnyObjectId;
 import org.eclipse.jgit.lib.Ref;
 import org.eclipse.jgit.lib.RefComparator;
-import org.eclipse.jgit.util.RefMap;
 
 @Command(usage = "usage_ShowRef")
 class ShowRef extends TextBuiltin {
+	/** {@inheritDoc} */
 	@Override
 	protected void run() throws Exception {
-		for (final Ref r : getSortedRefs()) {
+		for (Ref r : getSortedRefs()) {
 			show(r.getObjectId(), r.getName());
 			if (r.getPeeledObjectId() != null)
 				show(r.getPeeledObjectId(), r.getName() + "^{}"); //$NON-NLS-1$
@@ -68,14 +65,13 @@ protected void run() throws Exception {
 	}
 
 	private Iterable<Ref> getSortedRefs() throws Exception {
-		Map<String, Ref> all = db.getRefDatabase().getRefs(ALL);
-		if (all instanceof RefMap
-				|| (all instanceof SortedMap && ((SortedMap) all).comparator() == null))
-			return all.values();
-		return RefComparator.sort(all.values());
+		List<Ref> all = db.getRefDatabase().getRefs();
+		// TODO(jrn) check if we can reintroduce fast-path by e.g. implementing
+		// SortedList
+		return RefComparator.sort(all);
 	}
 
-	private void show(final AnyObjectId id, final String name)
+	private void show(AnyObjectId id, String name)
 			throws IOException {
 		outw.print(id.name());
 		outw.print('\t');
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Status.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Status.java
index adcfea4..fb2fd7e 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Status.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Status.java
@@ -86,6 +86,7 @@ class Status extends TextBuiltin {
 	@Option(name = "--", metaVar = "metaVar_paths", handler = RestOfArgumentsHandler.class)
 	protected List<String> filterPaths;
 
+	/** {@inheritDoc} */
 	@Override
 	protected void run() throws Exception {
 		try (Git git = new Git(db)) {
@@ -261,6 +262,15 @@ private void printLongStatus(org.eclipse.jgit.api.Status status)
 		}
 	}
 
+	/**
+	 * Print section header
+	 *
+	 * @param pattern
+	 *            a {@link java.lang.String} object.
+	 * @param arguments
+	 *            a {@link java.lang.Object} object.
+	 * @throws java.io.IOException
+	 */
 	protected void printSectionHeader(String pattern, Object... arguments)
 			throws IOException {
 		if (!porcelain) {
@@ -272,6 +282,14 @@ protected void printSectionHeader(String pattern, Object... arguments)
 		}
 	}
 
+	/**
+	 * Print String list
+	 *
+	 * @param list
+	 *            a {@link java.util.Collection} object.
+	 * @return a int.
+	 * @throws java.io.IOException
+	 */
 	protected int printList(Collection<String> list) throws IOException {
 		if (!list.isEmpty()) {
 			List<String> sortedList = new ArrayList<>(list);
@@ -286,10 +304,30 @@ protected int printList(Collection<String> list) throws IOException {
 			return 0;
 	}
 
+	/**
+	 * Print String list
+	 *
+	 * @param status1
+	 *            a {@link java.lang.String} object.
+	 * @param status2
+	 *            a {@link java.lang.String} object.
+	 * @param status3
+	 *            a {@link java.lang.String} object.
+	 * @param list
+	 *            a {@link java.util.Collection} object.
+	 * @param set1
+	 *            a {@link java.util.Collection} object.
+	 * @param set2
+	 *            a {@link java.util.Collection} object.
+	 * @param set3
+	 *            a {@link java.util.Collection} object.
+	 * @return a int.
+	 * @throws java.io.IOException
+	 */
 	protected int printList(String status1, String status2, String status3,
 			Collection<String> list, Collection<String> set1,
 			Collection<String> set2,
-			@SuppressWarnings("unused") Collection<String> set3)
+			Collection<String> set3)
 			throws IOException {
 		List<String> sortedList = new ArrayList<>(list);
 		java.util.Collections.sort(sortedList);
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Tag.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Tag.java
index dc4b037..43c1f54 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Tag.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Tag.java
@@ -80,6 +80,7 @@ class Tag extends TextBuiltin {
 	@Argument(index = 1, metaVar = "metaVar_object")
 	private ObjectId object;
 
+	/** {@inheritDoc} */
 	@Override
 	protected void run() throws Exception {
 		try (Git git = new Git(db)) {
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/TextBuiltin.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/TextBuiltin.java
index c3b45e8..7e5b545 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/TextBuiltin.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/TextBuiltin.java
@@ -129,11 +129,15 @@ public abstract class TextBuiltin {
 	/** RevWalk used during command line parsing, if it was required. */
 	protected RevWalk argWalk;
 
-	final void setCommandName(final String name) {
+	final void setCommandName(String name) {
 		commandName = name;
 	}
 
-	/** @return true if {@link #db}/{@link #getRepository()} is required. */
+	/**
+	 * If this command requires a repository.
+	 *
+	 * @return true if {@link #db}/{@link #getRepository()} is required
+	 */
 	protected boolean requiresRepository() {
 		return true;
 	}
@@ -172,7 +176,7 @@ public void initRaw(final Repository repository, final String gitDir,
 	 *            value of the {@code --git-dir} command line option, if
 	 *            {@code repository} is null.
 	 */
-	protected void init(final Repository repository, final String gitDir) {
+	protected void init(Repository repository, String gitDir) {
 		try {
 			final String outputEncoding = repository != null ? repository
 					.getConfig().getString("i18n", null, "logOutputEncoding") : null; //$NON-NLS-1$ //$NON-NLS-2$
@@ -214,7 +218,7 @@ protected void init(final Repository repository, final String gitDir) {
 	 *
 	 * @param args
 	 *            command line arguments passed after the command name.
-	 * @throws Exception
+	 * @throws java.lang.Exception
 	 *             an error occurred while processing the command. The main
 	 *             framework will catch the exception and print a message on
 	 *             standard error.
@@ -233,9 +237,9 @@ public final void execute(String[] args) throws Exception {
 	 *
 	 * @param args
 	 *            the arguments supplied on the command line, if any.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 */
-	protected void parseArguments(final String[] args) throws IOException {
+	protected void parseArguments(String[] args) throws IOException {
 		final CmdLineParser clp = new CmdLineParser(this);
 		help = containsHelp(args);
 		try {
@@ -260,9 +264,10 @@ protected void parseArguments(final String[] args) throws IOException {
 	 * Print the usage line
 	 *
 	 * @param clp
-	 * @throws IOException
+	 *            a {@link org.eclipse.jgit.pgm.opt.CmdLineParser} object.
+	 * @throws java.io.IOException
 	 */
-	public void printUsageAndExit(final CmdLineParser clp) throws IOException {
+	public void printUsageAndExit(CmdLineParser clp) throws IOException {
 		printUsageAndExit("", clp); //$NON-NLS-1$
 	}
 
@@ -270,23 +275,27 @@ public void printUsageAndExit(final CmdLineParser clp) throws IOException {
 	 * Print an error message and the usage line
 	 *
 	 * @param message
+	 *            a {@link java.lang.String} object.
 	 * @param clp
-	 * @throws IOException
+	 *            a {@link org.eclipse.jgit.pgm.opt.CmdLineParser} object.
+	 * @throws java.io.IOException
 	 */
-	public void printUsageAndExit(final String message, final CmdLineParser clp) throws IOException {
+	public void printUsageAndExit(String message, CmdLineParser clp) throws IOException {
 		printUsage(message, clp);
 		throw die(true);
 	}
 
 	/**
+	 * Print usage help text.
+	 *
 	 * @param message
 	 *            non null
 	 * @param clp
 	 *            parser used to print options
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 * @since 4.2
 	 */
-	protected void printUsage(final String message, final CmdLineParser clp)
+	protected void printUsage(String message, CmdLineParser clp)
 			throws IOException {
 		errw.println(message);
 		errw.print("jgit "); //$NON-NLS-1$
@@ -302,6 +311,8 @@ protected void printUsage(final String message, final CmdLineParser clp)
 	}
 
 	/**
+	 * Get error writer
+	 *
 	 * @return error writer, typically this is standard error.
 	 * @since 4.2
 	 */
@@ -310,6 +321,8 @@ public ThrowingPrintWriter getErrorWriter() {
 	}
 
 	/**
+	 * Get output writer
+	 *
 	 * @return output writer, typically this is standard output.
 	 * @since 4.9
 	 */
@@ -318,6 +331,8 @@ public ThrowingPrintWriter getOutputWriter() {
 	}
 
 	/**
+	 * Get resource bundle with localized texts
+	 *
 	 * @return the resource bundle that will be passed to args4j for purpose of
 	 *         string localization
 	 */
@@ -330,7 +345,7 @@ protected ResourceBundle getResourceBundle() {
 	 * <p>
 	 * This method should only be invoked by {@link #execute(String[])}.
 	 *
-	 * @throws Exception
+	 * @throws java.lang.Exception
 	 *             an error occurred while processing the command. The main
 	 *             framework will catch the exception and print a message on
 	 *             standard error.
@@ -338,13 +353,15 @@ protected ResourceBundle getResourceBundle() {
 	protected abstract void run() throws Exception;
 
 	/**
+	 * Get the repository
+	 *
 	 * @return the repository this command accesses.
 	 */
 	public Repository getRepository() {
 		return db;
 	}
 
-	ObjectId resolve(final String s) throws IOException {
+	ObjectId resolve(String s) throws IOException {
 		final ObjectId r = db.resolve(s);
 		if (r == null)
 			throw die(MessageFormat.format(CLIText.get().notARevision, s));
@@ -352,28 +369,35 @@ ObjectId resolve(final String s) throws IOException {
 	}
 
 	/**
+	 * Exit the command with an error message
+	 *
 	 * @param why
 	 *            textual explanation
 	 * @return a runtime exception the caller is expected to throw
 	 */
-	protected static Die die(final String why) {
+	protected static Die die(String why) {
 		return new Die(why);
 	}
 
 	/**
+	 * Exit the command with an error message and an exception
+	 *
 	 * @param why
 	 *            textual explanation
 	 * @param cause
 	 *            why the command has failed.
 	 * @return a runtime exception the caller is expected to throw
 	 */
-	protected static Die die(final String why, final Throwable cause) {
+	protected static Die die(String why, Throwable cause) {
 		return new Die(why, cause);
 	}
 
 	/**
+	 * Exit the command
+	 *
 	 * @param aborted
-	 *            boolean indicating that the execution has been aborted before running
+	 *            boolean indicating that the execution has been aborted before
+	 *            running
 	 * @return a runtime exception the caller is expected to throw
 	 * @since 3.4
 	 */
@@ -382,6 +406,8 @@ protected static Die die(boolean aborted) {
 	}
 
 	/**
+	 * Exit the command
+	 *
 	 * @param aborted
 	 *            boolean indicating that the execution has been aborted before
 	 *            running
@@ -390,7 +416,7 @@ protected static Die die(boolean aborted) {
 	 * @return a runtime exception the caller is expected to throw
 	 * @since 4.2
 	 */
-	protected static Die die(boolean aborted, final Throwable cause) {
+	protected static Die die(boolean aborted, Throwable cause) {
 		return new Die(aborted, cause);
 	}
 
@@ -405,6 +431,8 @@ else if (abbreviateRemote && dst.startsWith(R_REMOTES))
 	}
 
 	/**
+	 * Check if the arguments contain a help option
+	 *
 	 * @param args
 	 *            non null
 	 * @return true if the given array contains help option
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/UploadPack.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/UploadPack.java
index 447374d..5d032d2 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/UploadPack.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/UploadPack.java
@@ -62,11 +62,13 @@ class UploadPack extends TextBuiltin {
 	@Argument(index = 0, required = true, metaVar = "metaVar_directory", usage = "usage_RepositoryToReadFrom")
 	File srcGitdir;
 
+	/** {@inheritDoc} */
 	@Override
 	protected final boolean requiresRepository() {
 		return false;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected void run() throws Exception {
 		final org.eclipse.jgit.transport.UploadPack up;
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Version.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Version.java
index 6bed9c6..58acc5c 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Version.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Version.java
@@ -55,6 +55,7 @@
 
 @Command(common = true, usage = "usage_DisplayTheVersionOfJgit")
 class Version extends TextBuiltin {
+	/** {@inheritDoc} */
 	@Override
 	protected void run() throws Exception {
 		// read the Implementation-Version from Manifest
@@ -73,6 +74,7 @@ protected void run() throws Exception {
 		outw.println(MessageFormat.format(CLIText.get().jgitVersion, version));
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected final boolean requiresRepository() {
 		return false;
@@ -94,14 +96,9 @@ private String getBundleVersion() {
 	}
 
 	private static String getBundleVersion(URL url) {
-		try {
-			InputStream is = url.openStream();
-			try {
-				Manifest manifest = new Manifest(is);
-				return manifest.getMainAttributes().getValue("Bundle-Version"); //$NON-NLS-1$
-			} finally {
-				is.close();
-			}
+		try (InputStream is = url.openStream()) {
+			Manifest manifest = new Manifest(is);
+			return manifest.getMainAttributes().getValue("Bundle-Version"); //$NON-NLS-1$
 		} catch (IOException e) {
 			// do nothing - will return null
 		}
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/BenchmarkReftable.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/BenchmarkReftable.java
index 71c8db8..575a122 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/BenchmarkReftable.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/BenchmarkReftable.java
@@ -43,7 +43,7 @@
 
 package org.eclipse.jgit.pgm.debug;
 
-import static java.nio.charset.StandardCharsets.UTF_8;
+import static org.eclipse.jgit.lib.Constants.CHARSET;
 import static org.eclipse.jgit.lib.Constants.HEAD;
 import static org.eclipse.jgit.lib.Constants.MASTER;
 import static org.eclipse.jgit.lib.Constants.R_HEADS;
@@ -95,6 +95,7 @@ enum Test {
 	@Argument(index = 1)
 	private String reftablePath;
 
+	/** {@inheritDoc} */
 	@Override
 	protected void run() throws Exception {
 		switch (test) {
@@ -153,7 +154,7 @@ private RefList<Ref> readLsRemote()
 			throws IOException, FileNotFoundException {
 		RefList.Builder<Ref> list = new RefList.Builder<>();
 		try (BufferedReader br = new BufferedReader(new InputStreamReader(
-				new FileInputStream(lsRemotePath), UTF_8))) {
+				new FileInputStream(lsRemotePath), CHARSET))) {
 			Ref last = null;
 			String line;
 			while ((line = br.readLine()) != null) {
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/DiffAlgorithms.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/DiffAlgorithms.java
index 8de57e3..0e1b398 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/DiffAlgorithms.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/DiffAlgorithms.java
@@ -130,11 +130,13 @@ DiffAlgorithm create() {
 
 	private ThreadMXBean mxBean;
 
+	/** {@inheritDoc} */
 	@Override
 	protected boolean requiresRepository() {
 		return false;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected void run() throws Exception {
 		mxBean = ManagementFactory.getThreadMXBean();
@@ -158,11 +160,8 @@ protected void run() throws Exception {
 			else
 				rb.findGitDir(dir);
 
-			Repository repo = rb.build();
-			try {
+			try (Repository repo = rb.build()) {
 				run(repo);
-			} finally {
-				repo.close();
 			}
 		}
 	}
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/LfsStore.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/LfsStore.java
index 9dc4721..973b0d7 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/LfsStore.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/LfsStore.java
@@ -214,11 +214,13 @@ private static enum StorageClass {
 
 	String secretKey;
 
+	/** {@inheritDoc} */
 	@Override
 	protected boolean requiresRepository() {
 		return false;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected void run() throws Exception {
 		AppServer server = new AppServer(port);
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/MakeCacheTree.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/MakeCacheTree.java
index d3a0a3e..2a1326d 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/MakeCacheTree.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/MakeCacheTree.java
@@ -57,6 +57,7 @@
 
 @Command(usage = "usage_MakeCacheTree")
 class MakeCacheTree extends TextBuiltin {
+	/** {@inheritDoc} */
 	@Override
 	protected void run() throws Exception {
 		final DirCache cache = db.readDirCache();
@@ -64,7 +65,7 @@ protected void run() throws Exception {
 		show(tree);
 	}
 
-	private void show(final DirCacheTree tree) throws IOException {
+	private void show(DirCacheTree tree) throws IOException {
 		outw.println(MessageFormat.format(CLIText.get().cacheTreePathInfo,
 				tree.getPathString(), valueOf(tree.getEntrySpan()),
 				valueOf(tree.getChildCount())));
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/ReadDirCache.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/ReadDirCache.java
index 07bfc4b..0194cca 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/ReadDirCache.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/ReadDirCache.java
@@ -54,6 +54,7 @@
 
 @Command(usage = "usage_ReadDirCache")
 class ReadDirCache extends TextBuiltin {
+	/** {@inheritDoc} */
 	@Override
 	protected void run() throws Exception {
 		final int cnt = 100;
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/ReadReftable.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/ReadReftable.java
index 9b8db3e..fda1901 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/ReadReftable.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/ReadReftable.java
@@ -63,6 +63,7 @@ class ReadReftable extends TextBuiltin {
 	@Argument(index = 1, required = false)
 	private String ref;
 
+	/** {@inheritDoc} */
 	@Override
 	protected void run() throws Exception {
 		try (FileInputStream in = new FileInputStream(input);
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/RebuildCommitGraph.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/RebuildCommitGraph.java
index da602d0..2d16fef 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/RebuildCommitGraph.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/RebuildCommitGraph.java
@@ -43,8 +43,6 @@
 
 package org.eclipse.jgit.pgm.debug;
 
-import static org.eclipse.jgit.lib.RefDatabase.ALL;
-
 import java.io.BufferedReader;
 import java.io.File;
 import java.io.FileInputStream;
@@ -114,9 +112,10 @@ class RebuildCommitGraph extends TextBuiltin {
 
 	private Map<ObjectId, ObjectId> rewrites = new HashMap<>();
 
+	/** {@inheritDoc} */
 	@Override
 	protected void run() throws Exception {
-		if (!really && !db.getRefDatabase().getRefs(ALL).isEmpty()) {
+		if (!really && db.getRefDatabase().hasRefs()) {
 			File directory = db.getDirectory();
 			String absolutePath = directory == null ? "null" //$NON-NLS-1$
 					: directory.getAbsolutePath();
@@ -223,7 +222,7 @@ private static class ToRewrite {
 
 		ObjectId newId;
 
-		ToRewrite(final ObjectId o, final long t, final ObjectId[] p) {
+		ToRewrite(ObjectId o, long t, ObjectId[] p) {
 			oldId = o;
 			commitTime = t;
 			oldParents = p;
@@ -246,8 +245,7 @@ private void detachHead() throws IOException {
 
 	private void deleteAllRefs() throws Exception {
 		final RevWalk rw = new RevWalk(db);
-		Map<String, Ref> refs = db.getRefDatabase().getRefs(ALL);
-		for (final Ref r : refs.values()) {
+		for (Ref r : db.getRefDatabase().getRefs()) {
 			if (Constants.HEAD.equals(r.getName()))
 				continue;
 			final RefUpdate u = db.updateRef(r.getName());
@@ -260,7 +258,7 @@ private void recreateRefs() throws Exception {
 		final Map<String, Ref> refs = computeNewRefs();
 		new RefWriter(refs.values()) {
 			@Override
-			protected void writeFile(final String name, final byte[] content)
+			protected void writeFile(String name, byte[] content)
 					throws IOException {
 				final File file = new File(db.getDirectory(), name);
 				final LockFile lck = new LockFile(file);
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/RebuildRefTree.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/RebuildRefTree.java
index 8cde513..063600f 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/RebuildRefTree.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/RebuildRefTree.java
@@ -73,6 +73,7 @@ class RebuildRefTree extends TextBuiltin {
 	private String txnNamespace;
 	private String txnCommitted;
 
+	/** {@inheritDoc} */
 	@Override
 	protected void run() throws Exception {
 		try (ObjectReader reader = db.newObjectReader();
@@ -153,14 +154,14 @@ private RefTree rebuild(RefDatabase refdb) throws IOException {
 					head));
 		}
 
-		for (Ref r : refdb.getRefs(RefDatabase.ALL).values()) {
+		for (Ref r : refdb.getRefs()) {
 			if (r.getName().equals(txnCommitted) || r.getName().equals(HEAD)
 					|| r.getName().startsWith(txnNamespace)) {
 				continue;
 			}
 			cmds.add(new org.eclipse.jgit.internal.storage.reftree.Command(
 					null,
-					db.peel(r)));
+					db.getRefDatabase().peel(r)));
 		}
 		tree.apply(cmds);
 		return tree;
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/ShowCacheTree.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/ShowCacheTree.java
index e287425..6b97e08 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/ShowCacheTree.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/ShowCacheTree.java
@@ -57,6 +57,7 @@
 
 @Command(usage = "usage_ShowCacheTree")
 class ShowCacheTree extends TextBuiltin {
+	/** {@inheritDoc} */
 	@Override
 	protected void run() throws Exception {
 		final DirCache cache = db.readDirCache();
@@ -66,7 +67,7 @@ protected void run() throws Exception {
 		show(tree);
 	}
 
-	private void show(final DirCacheTree tree) throws IOException {
+	private void show(DirCacheTree tree) throws IOException {
 		outw.println(MessageFormat.format(CLIText.get().cacheTreePathInfo,
 				tree.getPathString(), valueOf(tree.getEntrySpan()),
 				valueOf(tree.getChildCount())));
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/ShowCommands.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/ShowCommands.java
index 415c7d3..af56d65 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/ShowCommands.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/ShowCommands.java
@@ -59,16 +59,17 @@ class ShowCommands extends TextBuiltin {
 	@Option(name = "--pretty", metaVar = "metaVar_commandDetail", usage = "usage_alterTheDetailShown")
 	private Format pretty = Format.USAGE;
 
+	/** {@inheritDoc} */
 	@Override
 	protected void run() throws Exception {
 		final CommandRef[] list = CommandCatalog.all();
 
 		int width = 0;
-		for (final CommandRef c : list)
+		for (CommandRef c : list)
 			width = Math.max(width, c.getName().length());
 		width += 2;
 
-		for (final CommandRef c : list) {
+		for (CommandRef c : list) {
 			errw.print(c.isCommon() ? '*' : ' ');
 			errw.print(' ');
 
@@ -86,7 +87,7 @@ static enum Format {
 		/** */
 		USAGE {
 			@Override
-			void print(ThrowingPrintWriter err, final CommandRef c) throws IOException {
+			void print(ThrowingPrintWriter err, CommandRef c) throws IOException {
 				String usage = c.getUsage();
 				if (usage != null && usage.length() > 0)
 					err.print(CLIText.get().resourceBundle().getString(usage));
@@ -96,7 +97,7 @@ void print(ThrowingPrintWriter err, final CommandRef c) throws IOException {
 		/** */
 		CLASSES {
 			@Override
-			void print(ThrowingPrintWriter err, final CommandRef c) throws IOException {
+			void print(ThrowingPrintWriter err, CommandRef c) throws IOException {
 				err.print(c.getImplementationClassName());
 			}
 		},
@@ -104,7 +105,7 @@ void print(ThrowingPrintWriter err, final CommandRef c) throws IOException {
 		/** */
 		URLS {
 			@Override
-			void print(ThrowingPrintWriter err, final CommandRef c) throws IOException {
+			void print(ThrowingPrintWriter err, CommandRef c) throws IOException {
 				final ClassLoader ldr = c.getImplementationClassLoader();
 
 				String cn = c.getImplementationClassName();
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/ShowDirCache.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/ShowDirCache.java
index bb4f73d..7f99d76 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/ShowDirCache.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/ShowDirCache.java
@@ -64,6 +64,7 @@ class ShowDirCache extends TextBuiltin {
 	@Option(name = "--millis", aliases = { "-m" }, usage = "usage_showTimeInMilliseconds")
 	private boolean millis = false;
 
+	/** {@inheritDoc} */
 	@Override
 	protected void run() throws Exception {
 		final SimpleDateFormat fmt;
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/ShowPackDelta.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/ShowPackDelta.java
index 150fe6e..f39ecbe 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/ShowPackDelta.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/ShowPackDelta.java
@@ -72,6 +72,7 @@ class ShowPackDelta extends TextBuiltin {
 	@Argument(index = 0)
 	private ObjectId objectId;
 
+	/** {@inheritDoc} */
 	@Override
 	protected void run() throws Exception {
 		ObjectReader reader = db.newObjectReader();
@@ -124,12 +125,13 @@ public void select(ObjectToPack otp, StoredObjectRepresentation next) {
 			ptr++;
 		ptr++;
 
-		@SuppressWarnings("resource" /* java 7 */)
-		TemporaryBuffer.Heap raw = new TemporaryBuffer.Heap(bufArray.length);
-		InflaterInputStream inf = new InflaterInputStream(
-				new ByteArrayInputStream(bufArray, ptr, bufArray.length));
-		raw.copy(inf);
-		inf.close();
-		return raw.toByteArray();
+		try (TemporaryBuffer.Heap raw = new TemporaryBuffer.Heap(
+				bufArray.length);
+				InflaterInputStream inf = new InflaterInputStream(
+						new ByteArrayInputStream(bufArray, ptr,
+								bufArray.length))) {
+			raw.copy(inf);
+			return raw.toByteArray();
+		}
 	}
 }
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/TextHashFunctions.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/TextHashFunctions.java
index ce58201..bb51b50 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/TextHashFunctions.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/TextHashFunctions.java
@@ -262,11 +262,13 @@ public int fold(int hash, int bits) {
 	@Option(name = "--repository", aliases = { "-r" }, metaVar = "GIT_DIR", usage = "Repository to scan")
 	List<File> gitDirs = new ArrayList<>();
 
+	/** {@inheritDoc} */
 	@Override
 	protected boolean requiresRepository() {
 		return false;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected void run() throws Exception {
 		if (gitDirs.isEmpty()) {
@@ -286,11 +288,8 @@ protected void run() throws Exception {
 			else
 				rb.findGitDir(dir);
 
-			Repository repo = rb.build();
-			try {
+			try (Repository repo = rb.build()) {
 				run(repo);
-			} finally {
-				repo.close();
 			}
 		}
 	}
@@ -500,7 +499,7 @@ public boolean equals(Object obj) {
 		}
 	}
 
-	private static int tableBits(final int sz) {
+	private static int tableBits(int sz) {
 		int bits = 31 - Integer.numberOfLeadingZeros(sz);
 		if (bits == 0)
 			bits = 1;
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/VerifyReftable.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/VerifyReftable.java
index dffb579..b38de14 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/VerifyReftable.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/VerifyReftable.java
@@ -75,6 +75,7 @@ class VerifyReftable extends TextBuiltin {
 	@Argument(index = 1)
 	private String reftablePath;
 
+	/** {@inheritDoc} */
 	@Override
 	protected void run() throws Exception {
 		List<Ref> refs = WriteReftable.readRefs(lsRemotePath);
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/WriteDirCache.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/WriteDirCache.java
index 42428c7..d3b0005 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/WriteDirCache.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/WriteDirCache.java
@@ -51,6 +51,7 @@
 
 @Command(usage = "usage_WriteDirCache")
 class WriteDirCache extends TextBuiltin {
+	/** {@inheritDoc} */
 	@Override
 	protected void run() throws Exception {
 		final DirCache cache = db.readDirCache();
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/WriteReftable.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/WriteReftable.java
index 76ffa19..c5ea028 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/WriteReftable.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/WriteReftable.java
@@ -43,7 +43,7 @@
 
 package org.eclipse.jgit.pgm.debug;
 
-import static java.nio.charset.StandardCharsets.UTF_8;
+import static org.eclipse.jgit.lib.Constants.CHARSET;
 import static org.eclipse.jgit.lib.Constants.HEAD;
 import static org.eclipse.jgit.lib.Constants.MASTER;
 import static org.eclipse.jgit.lib.Constants.R_HEADS;
@@ -104,6 +104,7 @@ class WriteReftable extends TextBuiltin {
 	@Argument(index = 1)
 	private String out;
 
+	/** {@inheritDoc} */
 	@SuppressWarnings({ "nls", "boxing" })
 	@Override
 	protected void run() throws Exception {
@@ -191,7 +192,7 @@ private void printf(String fmt, Object... args) throws IOException {
 	static List<Ref> readRefs(String inputFile) throws IOException {
 		List<Ref> refs = new ArrayList<>();
 		try (BufferedReader br = new BufferedReader(
-				new InputStreamReader(new FileInputStream(inputFile), UTF_8))) {
+				new InputStreamReader(new FileInputStream(inputFile), CHARSET))) {
 			String line;
 			while ((line = br.readLine()) != null) {
 				ObjectId id = ObjectId.fromString(line.substring(0, 40));
@@ -226,7 +227,7 @@ private static List<LogEntry> readLog(String logPath)
 
 		List<LogEntry> log = new ArrayList<>();
 		try (BufferedReader br = new BufferedReader(
-				new InputStreamReader(new FileInputStream(logPath), UTF_8))) {
+				new InputStreamReader(new FileInputStream(logPath), CHARSET))) {
 			@SuppressWarnings("nls")
 			Pattern pattern = Pattern.compile("([^,]+)" // 1: ref
 					+ ",([0-9]+(?:[.][0-9]+)?)" // 2: time
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/internal/CLIText.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/internal/CLIText.java
index dfb489d..b3ad8bf 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/internal/CLIText.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/internal/CLIText.java
@@ -79,6 +79,8 @@ public String format(Object... args) {
 	}
 
 	/**
+	 * Format text
+	 *
 	 * @param text
 	 *            the text to format.
 	 * @return a new Format instance.
@@ -88,6 +90,8 @@ public static Format format(String text) {
 	}
 
 	/**
+	 * Get an instance of this translation bundle
+	 *
 	 * @return an instance of this translation bundle
 	 */
 	public static CLIText get() {
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/AbstractTreeIteratorHandler.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/AbstractTreeIteratorHandler.java
index 587f98c..a14f651 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/AbstractTreeIteratorHandler.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/AbstractTreeIteratorHandler.java
@@ -68,7 +68,8 @@
 import org.kohsuke.args4j.spi.Setter;
 
 /**
- * Custom argument handler {@link AbstractTreeIterator} from string values.
+ * Custom argument handler
+ * {@link org.eclipse.jgit.treewalk.AbstractTreeIterator} from string values.
  * <p>
  * Assumes the parser has been initialized with a Repository.
  */
@@ -82,8 +83,11 @@ public class AbstractTreeIteratorHandler extends
 	 * This constructor is used only by args4j.
 	 *
 	 * @param parser
+	 *            a {@link org.kohsuke.args4j.CmdLineParser} object.
 	 * @param option
+	 *            a {@link org.kohsuke.args4j.OptionDef} object.
 	 * @param setter
+	 *            a {@link org.kohsuke.args4j.spi.Setter} object.
 	 */
 	public AbstractTreeIteratorHandler(final CmdLineParser parser,
 			final OptionDef option,
@@ -92,8 +96,9 @@ public AbstractTreeIteratorHandler(final CmdLineParser parser,
 		clp = (org.eclipse.jgit.pgm.opt.CmdLineParser) parser;
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	public int parseArguments(final Parameters params) throws CmdLineException {
+	public int parseArguments(Parameters params) throws CmdLineException {
 		final String name = params.getParameter(0);
 
 		if (new File(name).isDirectory()) {
@@ -144,6 +149,7 @@ public int parseArguments(final Parameters params) throws CmdLineException {
 		return 1;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public String getDefaultMetaVariable() {
 		return CLIText.get().metaVar_treeish;
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/CmdLineParser.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/CmdLineParser.java
index 3dcb2a3..5cc98ca 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/CmdLineParser.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/CmdLineParser.java
@@ -61,11 +61,9 @@
 import org.eclipse.jgit.revwalk.RevWalk;
 import org.eclipse.jgit.transport.RefSpec;
 import org.eclipse.jgit.treewalk.AbstractTreeIterator;
-import org.kohsuke.args4j.Argument;
 import org.kohsuke.args4j.CmdLineException;
 import org.kohsuke.args4j.IllegalAnnotationError;
 import org.kohsuke.args4j.NamedOptionDef;
-import org.kohsuke.args4j.Option;
 import org.kohsuke.args4j.OptionDef;
 import org.kohsuke.args4j.OptionHandlerRegistry;
 import org.kohsuke.args4j.spi.OptionHandler;
@@ -105,14 +103,15 @@ public class CmdLineParser extends org.kohsuke.args4j.CmdLineParser {
 	 * them into the given object.
 	 *
 	 * @param bean
-	 *            instance of a class annotated by {@link Option} and
-	 *            {@link Argument}. this object will receive values.
-	 *
+	 *            instance of a class annotated by
+	 *            {@link org.kohsuke.args4j.Option} and
+	 *            {@link org.kohsuke.args4j.Argument}. this object will receive
+	 *            values.
 	 * @throws IllegalAnnotationError
 	 *             if the option bean class is using args4j annotations
 	 *             incorrectly.
 	 */
-	public CmdLineParser(final Object bean) {
+	public CmdLineParser(Object bean) {
 		this(bean, null);
 	}
 
@@ -121,15 +120,17 @@ public CmdLineParser(final Object bean) {
 	 * them into the given object.
 	 *
 	 * @param bean
-	 *            instance of a class annotated by {@link Option} and
-	 *            {@link Argument}. this object will receive values.
+	 *            instance of a class annotated by
+	 *            {@link org.kohsuke.args4j.Option} and
+	 *            {@link org.kohsuke.args4j.Argument}. this object will receive
+	 *            values.
 	 * @param repo
 	 *            repository this parser can translate options through.
 	 * @throws IllegalAnnotationError
 	 *             if the option bean class is using args4j annotations
 	 *             incorrectly.
 	 */
-	public CmdLineParser(final Object bean, Repository repo) {
+	public CmdLineParser(Object bean, Repository repo) {
 		super(bean);
 		if (bean instanceof TextBuiltin) {
 			cmd = (TextBuiltin) bean;
@@ -140,8 +141,9 @@ public CmdLineParser(final Object bean, Repository repo) {
 		this.db = repo;
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	public void parseArgument(final String... args) throws CmdLineException {
+	public void parseArgument(String... args) throws CmdLineException {
 		final ArrayList<String> tmp = new ArrayList<>(args.length);
 		for (int argi = 0; argi < args.length; argi++) {
 			final String str = args[argi];
@@ -223,12 +225,14 @@ private void restoreRequiredOptions(List<OptionHandler> backup) {
 	}
 
 	/**
+	 * Check if array contains help option
+	 *
 	 * @param args
 	 *            non null
 	 * @return true if the given array contains help option
 	 * @since 4.2
 	 */
-	protected boolean containsHelp(final String... args) {
+	protected boolean containsHelp(String... args) {
 		return TextBuiltin.containsHelp(args);
 	}
 
@@ -292,6 +296,7 @@ public boolean required() {
 		}
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected OptionHandler createOptionHandler(OptionDef o, Setter setter) {
 		if (o instanceof NamedOptionDef)
@@ -301,6 +306,7 @@ protected OptionHandler createOptionHandler(OptionDef o, Setter setter) {
 
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void printSingleLineUsage(Writer w, ResourceBundle rb) {
 		List<OptionHandler> options = getOptions();
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/ObjectIdHandler.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/ObjectIdHandler.java
index 74bab2d..5f7e81e 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/ObjectIdHandler.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/ObjectIdHandler.java
@@ -56,7 +56,8 @@
 import org.kohsuke.args4j.spi.Setter;
 
 /**
- * Custom argument handler {@link ObjectId} from string values.
+ * Custom argument handler {@link org.eclipse.jgit.lib.ObjectId} from string
+ * values.
  * <p>
  * Assumes the parser has been initialized with a Repository.
  */
@@ -69,8 +70,11 @@ public class ObjectIdHandler extends OptionHandler<ObjectId> {
 	 * This constructor is used only by args4j.
 	 *
 	 * @param parser
+	 *            a {@link org.kohsuke.args4j.CmdLineParser} object.
 	 * @param option
+	 *            a {@link org.kohsuke.args4j.OptionDef} object.
 	 * @param setter
+	 *            a {@link org.kohsuke.args4j.spi.Setter} object.
 	 */
 	public ObjectIdHandler(final CmdLineParser parser, final OptionDef option,
 			final Setter<? super ObjectId> setter) {
@@ -78,8 +82,9 @@ public ObjectIdHandler(final CmdLineParser parser, final OptionDef option,
 		clp = (org.eclipse.jgit.pgm.opt.CmdLineParser) parser;
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	public int parseArguments(final Parameters params) throws CmdLineException {
+	public int parseArguments(Parameters params) throws CmdLineException {
 		final String name = params.getParameter(0);
 		final ObjectId id;
 		try {
@@ -96,6 +101,7 @@ public int parseArguments(final Parameters params) throws CmdLineException {
 				CLIText.format(CLIText.get().notAnObject), name);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public String getDefaultMetaVariable() {
 		return CLIText.get().metaVar_object;
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/OptionWithValuesListHandler.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/OptionWithValuesListHandler.java
index 3de7a81..7d7c806 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/OptionWithValuesListHandler.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/OptionWithValuesListHandler.java
@@ -19,15 +19,21 @@
 public class OptionWithValuesListHandler extends OptionHandler<List<?>> {
 
 	/**
+	 * Constructor for OptionWithValuesListHandler.
+	 *
 	 * @param parser
+	 *            a {@link org.kohsuke.args4j.CmdLineParser} object.
 	 * @param option
+	 *            a {@link org.kohsuke.args4j.OptionDef} object.
 	 * @param setter
+	 *            a {@link org.kohsuke.args4j.spi.Setter} object.
 	 */
 	public OptionWithValuesListHandler(CmdLineParser parser,
 			OptionDef option, Setter<List<?>> setter) {
 		super(parser, option, setter);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public int parseArguments(Parameters params) throws CmdLineException {
 		final List<String> list = new ArrayList<>();
@@ -44,6 +50,7 @@ public int parseArguments(Parameters params) throws CmdLineException {
 		return list.size();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public String getDefaultMetaVariable() {
 		return CLIText.get().metaVar_values;
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/PathTreeFilterHandler.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/PathTreeFilterHandler.java
index b873c3d..d99f88e 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/PathTreeFilterHandler.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/PathTreeFilterHandler.java
@@ -52,17 +52,17 @@
 import org.eclipse.jgit.treewalk.filter.TreeFilter;
 import org.kohsuke.args4j.CmdLineException;
 import org.kohsuke.args4j.CmdLineParser;
-import org.kohsuke.args4j.Option;
 import org.kohsuke.args4j.OptionDef;
 import org.kohsuke.args4j.spi.OptionHandler;
 import org.kohsuke.args4j.spi.Parameters;
 import org.kohsuke.args4j.spi.Setter;
 
 /**
- * Create a {@link TreeFilter} to patch math names.
+ * Create a {@link org.eclipse.jgit.treewalk.filter.TreeFilter} to patch math
+ * names.
  * <p>
  * This handler consumes all arguments to the end of the command line, and is
- * meant to be used on an {@link Option} of name "--".
+ * meant to be used on an {@link org.kohsuke.args4j.Option} of name "--".
  */
 public class PathTreeFilterHandler extends OptionHandler<TreeFilter> {
 	/**
@@ -71,16 +71,20 @@ public class PathTreeFilterHandler extends OptionHandler<TreeFilter> {
 	 * This constructor is used only by args4j.
 	 *
 	 * @param parser
+	 *            a {@link org.kohsuke.args4j.CmdLineParser} object.
 	 * @param option
+	 *            a {@link org.kohsuke.args4j.OptionDef} object.
 	 * @param setter
+	 *            a {@link org.kohsuke.args4j.spi.Setter} object.
 	 */
 	public PathTreeFilterHandler(final CmdLineParser parser,
 			final OptionDef option, final Setter<? super TreeFilter> setter) {
 		super(parser, option, setter);
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	public int parseArguments(final Parameters params) throws CmdLineException {
+	public int parseArguments(Parameters params) throws CmdLineException {
 		final List<PathFilter> filters = new ArrayList<>();
 		for (int idx = 0;; idx++) {
 			final String path;
@@ -102,6 +106,7 @@ public int parseArguments(final Parameters params) throws CmdLineException {
 		return filters.size();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public String getDefaultMetaVariable() {
 		return CLIText.get().metaVar_paths;
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/RefSpecHandler.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/RefSpecHandler.java
index f50c7ad..29577ed 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/RefSpecHandler.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/RefSpecHandler.java
@@ -53,7 +53,8 @@
 import org.kohsuke.args4j.spi.Setter;
 
 /**
- * Custom argument handler {@link RefSpec} from string values.
+ * Custom argument handler {@link org.eclipse.jgit.transport.RefSpec} from
+ * string values.
  * <p>
  * Assumes the parser has been initialized with a Repository.
  */
@@ -64,20 +65,25 @@ public class RefSpecHandler extends OptionHandler<RefSpec> {
 	 * This constructor is used only by args4j.
 	 *
 	 * @param parser
+	 *            a {@link org.kohsuke.args4j.CmdLineParser} object.
 	 * @param option
+	 *            a {@link org.kohsuke.args4j.OptionDef} object.
 	 * @param setter
+	 *            a {@link org.kohsuke.args4j.spi.Setter} object.
 	 */
 	public RefSpecHandler(final CmdLineParser parser, final OptionDef option,
 			final Setter<? super RefSpec> setter) {
 		super(parser, option, setter);
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	public int parseArguments(final Parameters params) throws CmdLineException {
+	public int parseArguments(Parameters params) throws CmdLineException {
 		setter.addValue(new RefSpec(params.getParameter(0)));
 		return 1;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public String getDefaultMetaVariable() {
 		return CLIText.get().metaVar_refspec;
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/RevCommitHandler.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/RevCommitHandler.java
index 27555e3..b925e31 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/RevCommitHandler.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/RevCommitHandler.java
@@ -60,7 +60,8 @@
 import org.kohsuke.args4j.spi.Setter;
 
 /**
- * Custom argument handler {@link RevCommit} from string values.
+ * Custom argument handler {@link org.eclipse.jgit.revwalk.RevCommit} from
+ * string values.
  * <p>
  * Assumes the parser has been initialized with a Repository.
  */
@@ -73,8 +74,11 @@ public class RevCommitHandler extends OptionHandler<RevCommit> {
 	 * This constructor is used only by args4j.
 	 *
 	 * @param parser
+	 *            a {@link org.kohsuke.args4j.CmdLineParser} object.
 	 * @param option
+	 *            a {@link org.kohsuke.args4j.OptionDef} object.
 	 * @param setter
+	 *            a {@link org.kohsuke.args4j.spi.Setter} object.
 	 */
 	public RevCommitHandler(final CmdLineParser parser, final OptionDef option,
 			final Setter<? super RevCommit> setter) {
@@ -82,8 +86,9 @@ public RevCommitHandler(final CmdLineParser parser, final OptionDef option,
 		clp = (org.eclipse.jgit.pgm.opt.CmdLineParser) parser;
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	public int parseArguments(final Parameters params) throws CmdLineException {
+	public int parseArguments(Parameters params) throws CmdLineException {
 		String name = params.getParameter(0);
 
 		boolean interesting = true;
@@ -110,7 +115,7 @@ public int parseArguments(final Parameters params) throws CmdLineException {
 		return 1;
 	}
 
-	private void addOne(final String name, final boolean interesting)
+	private void addOne(String name, boolean interesting)
 			throws CmdLineException {
 		final ObjectId id;
 		try {
@@ -145,6 +150,7 @@ private void addOne(final String name, final boolean interesting)
 		setter.addValue(c);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public String getDefaultMetaVariable() {
 		return CLIText.get().metaVar_commitish;
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/RevTreeHandler.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/RevTreeHandler.java
index 15ed589..85922a2 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/RevTreeHandler.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/RevTreeHandler.java
@@ -59,7 +59,8 @@
 import org.kohsuke.args4j.spi.Setter;
 
 /**
- * Custom argument handler {@link RevTree} from string values.
+ * Custom argument handler {@link org.eclipse.jgit.revwalk.RevTree} from string
+ * values.
  * <p>
  * Assumes the parser has been initialized with a Repository.
  */
@@ -72,8 +73,11 @@ public class RevTreeHandler extends OptionHandler<RevTree> {
 	 * This constructor is used only by args4j.
 	 *
 	 * @param parser
+	 *            a {@link org.kohsuke.args4j.CmdLineParser} object.
 	 * @param option
+	 *            a {@link org.kohsuke.args4j.OptionDef} object.
 	 * @param setter
+	 *            a {@link org.kohsuke.args4j.spi.Setter} object.
 	 */
 	public RevTreeHandler(final CmdLineParser parser, final OptionDef option,
 			final Setter<? super RevTree> setter) {
@@ -81,8 +85,9 @@ public RevTreeHandler(final CmdLineParser parser, final OptionDef option,
 		clp = (org.eclipse.jgit.pgm.opt.CmdLineParser) parser;
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	public int parseArguments(final Parameters params) throws CmdLineException {
+	public int parseArguments(Parameters params) throws CmdLineException {
 		final String name = params.getParameter(0);
 		final ObjectId id;
 		try {
@@ -112,6 +117,7 @@ public int parseArguments(final Parameters params) throws CmdLineException {
 		return 1;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public String getDefaultMetaVariable() {
 		return CLIText.get().metaVar_treeish;
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/SubcommandHandler.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/SubcommandHandler.java
index ae5263f..92eebf4 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/SubcommandHandler.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/SubcommandHandler.java
@@ -57,8 +57,9 @@
 /**
  * Custom Argument handler for jgit command selection.
  * <p>
- * Translates a single argument string to a {@link TextBuiltin} instance which
- * we can execute at runtime with the remaining arguments of the parser.
+ * Translates a single argument string to a
+ * {@link org.eclipse.jgit.pgm.TextBuiltin} instance which we can execute at
+ * runtime with the remaining arguments of the parser.
  */
 public class SubcommandHandler extends OptionHandler<TextBuiltin> {
 	private final org.eclipse.jgit.pgm.opt.CmdLineParser clp;
@@ -69,8 +70,11 @@ public class SubcommandHandler extends OptionHandler<TextBuiltin> {
 	 * This constructor is used only by args4j.
 	 *
 	 * @param parser
+	 *            a {@link org.kohsuke.args4j.CmdLineParser} object.
 	 * @param option
+	 *            a {@link org.kohsuke.args4j.OptionDef} object.
 	 * @param setter
+	 *            a {@link org.kohsuke.args4j.spi.Setter} object.
 	 */
 	public SubcommandHandler(final CmdLineParser parser,
 			final OptionDef option, final Setter<? super TextBuiltin> setter) {
@@ -78,8 +82,9 @@ public SubcommandHandler(final CmdLineParser parser,
 		clp = (org.eclipse.jgit.pgm.opt.CmdLineParser) parser;
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	public int parseArguments(final Parameters params) throws CmdLineException {
+	public int parseArguments(Parameters params) throws CmdLineException {
 		final String name = params.getParameter(0);
 		final CommandRef cr = CommandCatalog.get(name);
 		if (cr == null)
@@ -95,6 +100,7 @@ public int parseArguments(final Parameters params) throws CmdLineException {
 		return 1;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public String getDefaultMetaVariable() {
 		return CLIText.get().metaVar_command;
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/UntrackedFilesHandler.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/UntrackedFilesHandler.java
index e22b2e4..2487a92 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/UntrackedFilesHandler.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/UntrackedFilesHandler.java
@@ -71,6 +71,8 @@
 public class UntrackedFilesHandler extends StringOptionHandler {
 
 	/**
+	 * <p>Constructor for UntrackedFilesHandler.</p>
+	 *
 	 * @param parser
 	 *            The parser to which this handler belongs to.
 	 * @param option
@@ -83,6 +85,7 @@ public UntrackedFilesHandler(CmdLineParser parser, OptionDef option,
 		super(parser, option, setter);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public int parseArguments(Parameters params) throws CmdLineException {
 		String alias = params.getParameter(-1);
diff --git a/org.eclipse.jgit.test/.settings/org.eclipse.jdt.core.prefs b/org.eclipse.jgit.test/.settings/org.eclipse.jdt.core.prefs
index 64f7498..794592d 100644
--- a/org.eclipse.jgit.test/.settings/org.eclipse.jdt.core.prefs
+++ b/org.eclipse.jgit.test/.settings/org.eclipse.jdt.core.prefs
@@ -25,7 +25,7 @@
 org.eclipse.jdt.core.compiler.problem.discouragedReference=warning
 org.eclipse.jdt.core.compiler.problem.emptyStatement=warning
 org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
-org.eclipse.jdt.core.compiler.problem.explicitlyClosedAutoCloseable=ignore
+org.eclipse.jdt.core.compiler.problem.explicitlyClosedAutoCloseable=warning
 org.eclipse.jdt.core.compiler.problem.fallthroughCase=warning
 org.eclipse.jdt.core.compiler.problem.fatalOptionalError=disabled
 org.eclipse.jdt.core.compiler.problem.fieldHiding=warning
diff --git a/org.eclipse.jgit.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.test/META-INF/MANIFEST.MF
index f36df07..06bac92 100644
--- a/org.eclipse.jgit.test/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.test/META-INF/MANIFEST.MF
@@ -1,64 +1,65 @@
 Manifest-Version: 1.0
 Bundle-ManifestVersion: 2
 Bundle-Name: %plugin_name
+Automatic-Module-Name: org.eclipse.jgit.test
 Bundle-SymbolicName: org.eclipse.jgit.test
-Bundle-Version: 4.9.3.qualifier
+Bundle-Version: 5.0.0.qualifier
 Bundle-Localization: plugin
 Bundle-Vendor: %provider_name
 Bundle-ActivationPolicy: lazy
 Bundle-RequiredExecutionEnvironment: JavaSE-1.8
 Import-Package: com.googlecode.javaewah;version="[1.1.6,2.0.0)",
  com.jcraft.jsch;version="[0.1.54,0.2.0)",
- org.eclipse.jgit.api;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.api.errors;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.attributes;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.awtui;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.blame;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.diff;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.dircache;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.errors;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.events;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.fnmatch;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.gitrepo;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.hooks;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.ignore;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.ignore.internal;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.internal;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.internal.fsck;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.internal.storage.dfs;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.internal.storage.file;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.internal.storage.io;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.internal.storage.pack;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.internal.storage.reftable;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.internal.storage.reftree;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.junit;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.lfs;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.lib;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.merge;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.nls;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.notes;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.patch;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.pgm;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.pgm.internal;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.revplot;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.revwalk;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.revwalk.filter;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.storage.file;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.storage.pack;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.submodule;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.transport;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.transport.http;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.transport.resolver;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.treewalk;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.treewalk.filter;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.util;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.util.io;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.util.sha1;version="[4.9.3,4.10.0)",
- org.junit;version="[4.4.0,5.0.0)",
- org.junit.experimental.theories;version="[4.4.0,5.0.0)",
- org.junit.rules;version="[4.11.0,5.0.0)",
- org.junit.runner;version="[4.4.0,5.0.0)",
- org.junit.runners;version="[4.11.0,5.0.0)",
- org.slf4j;version="[1.7.2,2.0.0)"
+ org.eclipse.jgit.api;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.api.errors;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.attributes;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.awtui;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.blame;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.diff;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.dircache;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.errors;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.events;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.fnmatch;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.gitrepo;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.hooks;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.ignore;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.ignore.internal;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.internal;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.internal.fsck;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.internal.storage.dfs;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.internal.storage.file;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.internal.storage.io;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.internal.storage.pack;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.internal.storage.reftable;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.internal.storage.reftree;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.junit;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.lfs;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.lib;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.merge;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.nls;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.notes;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.patch;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.pgm;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.pgm.internal;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.revplot;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.revwalk;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.revwalk.filter;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.storage.file;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.storage.pack;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.submodule;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.transport;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.transport.http;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.transport.resolver;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.treewalk;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.treewalk.filter;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.util;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.util.io;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.util.sha1;version="[5.0.0,5.1.0)",
+ org.junit;version="[4.12,5.0.0)",
+ org.junit.experimental.theories;version="[4.12,5.0.0)",
+ org.junit.rules;version="[4.12,5.0.0)",
+ org.junit.runner;version="[4.12,5.0.0)",
+ org.junit.runners;version="[4.12,5.0.0)",
+ org.slf4j;version="[1.7.0,2.0.0)"
 Require-Bundle: org.hamcrest.core;bundle-version="[1.1.0,2.0.0)",
  org.hamcrest.library;bundle-version="[1.1.0,2.0.0)"
diff --git a/org.eclipse.jgit.test/exttst/org/eclipse/jgit/ignore/CGitVsJGitRandomIgnorePatternTest.java b/org.eclipse.jgit.test/exttst/org/eclipse/jgit/ignore/CGitVsJGitRandomIgnorePatternTest.java
index db5f1b2..4d9e864 100644
--- a/org.eclipse.jgit.test/exttst/org/eclipse/jgit/ignore/CGitVsJGitRandomIgnorePatternTest.java
+++ b/org.eclipse.jgit.test/exttst/org/eclipse/jgit/ignore/CGitVsJGitRandomIgnorePatternTest.java
@@ -42,13 +42,14 @@
  */
 package org.eclipse.jgit.ignore;
 
+import static org.eclipse.jgit.lib.Constants.CHARSET;
+
 import java.io.BufferedReader;
 import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
 import java.io.OutputStream;
-import java.io.UnsupportedEncodingException;
 import java.nio.file.Files;
 import java.nio.file.StandardOpenOption;
 import java.util.Arrays;
@@ -56,6 +57,7 @@
 import java.util.Random;
 
 import org.eclipse.jgit.api.Git;
+import org.eclipse.jgit.util.FileUtils;
 import org.junit.Assert;
 import org.junit.Test;
 
@@ -152,13 +154,11 @@ public static class CGitIgnoreRule {
 
 		private String pattern;
 
-		public CGitIgnoreRule(File gitDir, String pattern)
-				throws UnsupportedEncodingException, IOException {
+		public CGitIgnoreRule(File gitDir, String pattern) throws IOException {
 			this.gitDir = gitDir;
 			this.pattern = pattern;
-			Files.write(new File(gitDir, ".gitignore").toPath(),
-					(pattern + "\n").getBytes("UTF-8"),
-					StandardOpenOption.CREATE,
+			Files.write(FileUtils.toPath(new File(gitDir, ".gitignore")),
+					(pattern + "\n").getBytes(CHARSET), StandardOpenOption.CREATE,
 					StandardOpenOption.TRUNCATE_EXISTING,
 					StandardOpenOption.WRITE);
 		}
@@ -187,10 +187,10 @@ private Process startCgitCheckIgnore(String path) throws IOException {
 					"--no-index", "-v", "-n", "--stdin" };
 			Process proc = Runtime.getRuntime().exec(command, new String[0],
 					gitDir);
-			OutputStream out = proc.getOutputStream();
-			out.write((path + "\n").getBytes("UTF-8"));
-			out.flush();
-			out.close();
+			try (OutputStream out = proc.getOutputStream()) {
+				out.write((path + "\n").getBytes(CHARSET));
+				out.flush();
+			}
 			return proc;
 		}
 
diff --git a/org.eclipse.jgit.test/exttst/org/eclipse/jgit/patch/EGitPatchHistoryTest.java b/org.eclipse.jgit.test/exttst/org/eclipse/jgit/patch/EGitPatchHistoryTest.java
index 7c0ea44..79d8d0e 100644
--- a/org.eclipse.jgit.test/exttst/org/eclipse/jgit/patch/EGitPatchHistoryTest.java
+++ b/org.eclipse.jgit.test/exttst/org/eclipse/jgit/patch/EGitPatchHistoryTest.java
@@ -43,6 +43,7 @@
 
 package org.eclipse.jgit.patch;
 
+import static java.nio.charset.StandardCharsets.ISO_8859_1;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
@@ -84,7 +85,7 @@ static class PatchReader extends CommitReader {
 
 		int errors;
 
-		PatchReader(final HashMap<String, HashMap<String, StatInfo>> s)
+		PatchReader(HashMap<String, HashMap<String, StatInfo>> s)
 				throws IOException {
 			super(new String[] { "-p" });
 			stats = s;
@@ -102,7 +103,7 @@ void onCommit(String cid, byte[] buf) {
 			p.parse(buf, 0, buf.length - 1);
 			assertEquals("File count " + cid, files.size(), p.getFiles().size());
 			if (!p.getErrors().isEmpty()) {
-				for (final FormatError e : p.getErrors()) {
+				for (FormatError e : p.getErrors()) {
 					System.out.println("error " + e.getMessage());
 					System.out.println("  at " + e.getLineText());
 				}
@@ -110,7 +111,7 @@ void onCommit(String cid, byte[] buf) {
 				fail("Unexpected error in " + cid);
 			}
 
-			for (final FileHeader fh : p.getFiles()) {
+			for (FileHeader fh : p.getFiles()) {
 				final String fileName;
 				if (fh.getChangeType() != FileHeader.ChangeType.DELETE)
 					fileName = fh.getNewPath();
@@ -120,7 +121,7 @@ void onCommit(String cid, byte[] buf) {
 				final String nid = fileName + " in " + cid;
 				assertNotNull("No " + nid, s);
 				int added = 0, deleted = 0;
-				for (final HunkHeader h : fh.getHunks()) {
+				for (HunkHeader h : fh.getHunks()) {
 					added += h.getOldImage().getLinesAdded();
 					deleted += h.getOldImage().getLinesDeleted();
 				}
@@ -146,7 +147,7 @@ void onCommit(String cid, byte[] buf) {
 			assertTrue("Missed files in " + cid, files.isEmpty());
 		}
 
-		private static void dump(final byte[] buf) {
+		private static void dump(byte[] buf) {
 			String str;
 			try {
 				str = new String(buf, 0, buf.length - 1, "ISO-8859-1");
@@ -187,7 +188,7 @@ void onCommit(String commitId, byte[] buf) {
 	static abstract class CommitReader {
 		private Process proc;
 
-		CommitReader(final String[] args) throws IOException {
+		CommitReader(String[] args) throws IOException {
 			final String[] realArgs = new String[3 + args.length + 1];
 			realArgs[0] = "git";
 			realArgs[1] = "log";
@@ -201,28 +202,28 @@ static abstract class CommitReader {
 		}
 
 		void read() throws IOException, InterruptedException {
-			final BufferedReader in = new BufferedReader(new InputStreamReader(
-					proc.getInputStream(), "ISO-8859-1"));
-			String commitId = null;
-			TemporaryBuffer buf = null;
-			for (;;) {
-				String line = in.readLine();
-				if (line == null)
-					break;
-				if (line.startsWith("commit ")) {
-					if (buf != null) {
-						buf.close();
-						onCommit(commitId, buf.toByteArray());
-						buf.destroy();
+			try (BufferedReader in = new BufferedReader(
+					new InputStreamReader(proc.getInputStream(), ISO_8859_1))) {
+				String commitId = null;
+				TemporaryBuffer buf = null;
+				for (;;) {
+					String line = in.readLine();
+					if (line == null)
+						break;
+					if (line.startsWith("commit ")) {
+						if (buf != null) {
+							buf.close();
+							onCommit(commitId, buf.toByteArray());
+							buf.destroy();
+						}
+						commitId = line.substring("commit ".length());
+						buf = new TemporaryBuffer.LocalFile(null);
+					} else if (buf != null) {
+						buf.write(line.getBytes(ISO_8859_1));
+						buf.write('\n');
 					}
-					commitId = line.substring("commit ".length());
-					buf = new TemporaryBuffer.LocalFile(null);
-				} else if (buf != null) {
-					buf.write(line.getBytes("ISO-8859-1"));
-					buf.write('\n');
 				}
 			}
-			in.close();
 			assertEquals(0, proc.waitFor());
 			proc = null;
 		}
diff --git a/org.eclipse.jgit.test/exttst/org/eclipse/jgit/treewalk/FileTreeIteratorPerformanceTest.java b/org.eclipse.jgit.test/exttst/org/eclipse/jgit/treewalk/FileTreeIteratorPerformanceTest.java
new file mode 100644
index 0000000..b238389
--- /dev/null
+++ b/org.eclipse.jgit.test/exttst/org/eclipse/jgit/treewalk/FileTreeIteratorPerformanceTest.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2018, Thomas Wolf <thomas.wolf@paranor.ch>
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ *   copyright notice, this list of conditions and the following
+ *   disclaimer in the documentation and/or other materials provided
+ *   with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ *   names of its contributors may be used to endorse or promote
+ *   products derived from this software without specific prior
+ *   written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.eclipse.jgit.treewalk;
+
+import static org.junit.Assert.fail;
+
+import org.eclipse.jgit.api.Git;
+import org.eclipse.jgit.junit.RepositoryTestCase;
+import org.eclipse.jgit.treewalk.filter.PathFilter;
+import org.junit.Test;
+
+/**
+ * Simple performance test for git add / FileTreeIterator.
+ */
+public class FileTreeIteratorPerformanceTest extends RepositoryTestCase {
+
+	private static int N_OF_FILES = 501;
+
+	@Test
+	public void testPerformance() throws Exception {
+		try (Git git = new Git(db)) {
+			long times[] = new long[N_OF_FILES];
+			long sum = 0;
+			String lastName = null;
+			for (int i = 0; i < N_OF_FILES; i++) {
+				lastName = "a" + (i + 100000) + ".txt";
+				writeTrashFile(lastName, "");
+				long start = System.nanoTime();
+				git.add().addFilepattern(lastName).call();
+				long elapsed = System.nanoTime() - start;
+				times[i] = elapsed;
+				sum += elapsed;
+			}
+			System.out.println("Total (µs) " + sum / 1000.0);
+			for (int i = 0; i < times.length; i++) {
+				System.out
+						.println("Time " + i + " (µs) = " + times[i] / 1000.0);
+			}
+			FileTreeIterator iter = new FileTreeIterator(db);
+			try (TreeWalk walk = new TreeWalk(db)) {
+				walk.setFilter(PathFilter.create(lastName));
+				walk.addTree(iter);
+				long start = System.nanoTime();
+				if (walk.next()) {
+					System.out.println("Walk time (µs) = "
+							+ (System.nanoTime() - start) / 1000.0);
+				} else {
+					fail("File not found");
+				}
+			}
+		}
+	}
+}
diff --git a/org.eclipse.jgit.test/pom.xml b/org.eclipse.jgit.test/pom.xml
index faa1ba1..e53aaab 100644
--- a/org.eclipse.jgit.test/pom.xml
+++ b/org.eclipse.jgit.test/pom.xml
@@ -52,7 +52,7 @@
   <parent>
     <groupId>org.eclipse.jgit</groupId>
     <artifactId>org.eclipse.jgit-parent</artifactId>
-    <version>4.9.3-SNAPSHOT</version>
+    <version>5.0.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>org.eclipse.jgit.test</artifactId>
diff --git a/org.eclipse.jgit.test/tests.bzl b/org.eclipse.jgit.test/tests.bzl
index 637fe0c..b1b7b7a 100644
--- a/org.eclipse.jgit.test/tests.bzl
+++ b/org.eclipse.jgit.test/tests.bzl
@@ -19,6 +19,10 @@
     if 'lib' not in labels:
       labels.append('lib')
 
+    # TODO(http://eclip.se/534285): Make this test pass reliably
+    # and remove the flaky attribute.
+    flaky = src.endswith("CrissCrossMergeTest.java")
+
     additional_deps = []
     if src.endswith("RootLocaleTest.java"):
       additional_deps = [
@@ -52,5 +56,6 @@
         '//org.eclipse.jgit.junit:junit',
         '//org.eclipse.jgit.lfs:jgit-lfs',
       ],
+      flaky = flaky,
       jvm_flags = ["-Xmx256m", "-Dfile.encoding=UTF-8"],
     )
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/AddCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/AddCommandTest.java
index aafda01..911f659 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/AddCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/AddCommandTest.java
@@ -63,8 +63,7 @@
 import org.eclipse.jgit.dircache.DirCacheEntry;
 import org.eclipse.jgit.junit.JGitTestUtil;
 import org.eclipse.jgit.junit.RepositoryTestCase;
-import org.eclipse.jgit.lfs.CleanFilter;
-import org.eclipse.jgit.lfs.SmudgeFilter;
+import org.eclipse.jgit.lfs.BuiltinLFS;
 import org.eclipse.jgit.lib.ConfigConstants;
 import org.eclipse.jgit.lib.Constants;
 import org.eclipse.jgit.lib.FileMode;
@@ -92,8 +91,7 @@ public class AddCommandTest extends RepositoryTestCase {
 
 	@Override
 	public void setUp() throws Exception {
-		CleanFilter.register();
-		SmudgeFilter.register();
+		BuiltinLFS.register();
 		super.setUp();
 	}
 
@@ -120,9 +118,9 @@ public void testAddNonExistingSingleFile() throws GitAPIException {
 	public void testAddExistingSingleFile() throws IOException, GitAPIException {
 		File file = new File(db.getWorkTree(), "a.txt");
 		FileUtils.createNewFile(file);
-		PrintWriter writer = new PrintWriter(file);
-		writer.print("content");
-		writer.close();
+		try (PrintWriter writer = new PrintWriter(file)) {
+			writer.print("content");
+		}
 
 		try (Git git = new Git(db)) {
 			git.add().addFilepattern("a.txt").call();
@@ -491,9 +489,9 @@ public void testAddExistingSingleSmallFileWithNewLine() throws IOException,
 			GitAPIException {
 		File file = new File(db.getWorkTree(), "a.txt");
 		FileUtils.createNewFile(file);
-		PrintWriter writer = new PrintWriter(file);
-		writer.print("row1\r\nrow2");
-		writer.close();
+		try (PrintWriter writer = new PrintWriter(file)) {
+			writer.print("row1\r\nrow2");
+		}
 
 		try (Git git = new Git(db)) {
 			db.getConfig().setString("core", null, "autocrlf", "false");
@@ -521,9 +519,9 @@ public void testAddExistingSingleMediumSizeFileWithNewLine()
 			data.append("row1\r\nrow2");
 		}
 		String crData = data.toString();
-		PrintWriter writer = new PrintWriter(file);
-		writer.print(crData);
-		writer.close();
+		try (PrintWriter writer = new PrintWriter(file)) {
+			writer.print(crData);
+		}
 		String lfData = data.toString().replaceAll("\r", "");
 		try (Git git = new Git(db)) {
 			db.getConfig().setString("core", null, "autocrlf", "false");
@@ -546,9 +544,9 @@ public void testAddExistingSingleBinaryFile() throws IOException,
 			GitAPIException {
 		File file = new File(db.getWorkTree(), "a.txt");
 		FileUtils.createNewFile(file);
-		PrintWriter writer = new PrintWriter(file);
-		writer.print("row1\r\nrow2\u0000");
-		writer.close();
+		try (PrintWriter writer = new PrintWriter(file)) {
+			writer.print("row1\r\nrow2\u0000");
+		}
 
 		try (Git git = new Git(db)) {
 			db.getConfig().setString("core", null, "autocrlf", "false");
@@ -572,9 +570,9 @@ public void testAddExistingSingleFileInSubDir() throws IOException,
 		FileUtils.mkdir(new File(db.getWorkTree(), "sub"));
 		File file = new File(db.getWorkTree(), "sub/a.txt");
 		FileUtils.createNewFile(file);
-		PrintWriter writer = new PrintWriter(file);
-		writer.print("content");
-		writer.close();
+		try (PrintWriter writer = new PrintWriter(file)) {
+			writer.print("content");
+		}
 
 		try (Git git = new Git(db)) {
 			git.add().addFilepattern("sub/a.txt").call();
@@ -590,18 +588,18 @@ public void testAddExistingSingleFileTwice() throws IOException,
 			GitAPIException {
 		File file = new File(db.getWorkTree(), "a.txt");
 		FileUtils.createNewFile(file);
-		PrintWriter writer = new PrintWriter(file);
-		writer.print("content");
-		writer.close();
+		try (PrintWriter writer = new PrintWriter(file)) {
+			writer.print("content");
+		}
 
 		try (Git git = new Git(db)) {
 			DirCache dc = git.add().addFilepattern("a.txt").call();
 
 			dc.getEntry(0).getObjectId();
 
-			writer = new PrintWriter(file);
-			writer.print("other content");
-			writer.close();
+			try (PrintWriter writer = new PrintWriter(file)) {
+				writer.print("other content");
+			}
 
 			dc = git.add().addFilepattern("a.txt").call();
 
@@ -615,9 +613,9 @@ public void testAddExistingSingleFileTwice() throws IOException,
 	public void testAddExistingSingleFileTwiceWithCommit() throws Exception {
 		File file = new File(db.getWorkTree(), "a.txt");
 		FileUtils.createNewFile(file);
-		PrintWriter writer = new PrintWriter(file);
-		writer.print("content");
-		writer.close();
+		try (PrintWriter writer = new PrintWriter(file)) {
+			writer.print("content");
+		}
 
 		try (Git git = new Git(db)) {
 			DirCache dc = git.add().addFilepattern("a.txt").call();
@@ -626,9 +624,9 @@ public void testAddExistingSingleFileTwiceWithCommit() throws Exception {
 
 			git.commit().setMessage("commit a.txt").call();
 
-			writer = new PrintWriter(file);
-			writer.print("other content");
-			writer.close();
+			try (PrintWriter writer = new PrintWriter(file)) {
+				writer.print("other content");
+			}
 
 			dc = git.add().addFilepattern("a.txt").call();
 
@@ -642,9 +640,9 @@ public void testAddExistingSingleFileTwiceWithCommit() throws Exception {
 	public void testAddRemovedFile() throws Exception {
 		File file = new File(db.getWorkTree(), "a.txt");
 		FileUtils.createNewFile(file);
-		PrintWriter writer = new PrintWriter(file);
-		writer.print("content");
-		writer.close();
+		try (PrintWriter writer = new PrintWriter(file)) {
+			writer.print("content");
+		}
 
 		try (Git git = new Git(db)) {
 			DirCache dc = git.add().addFilepattern("a.txt").call();
@@ -665,9 +663,9 @@ public void testAddRemovedFile() throws Exception {
 	public void testAddRemovedCommittedFile() throws Exception {
 		File file = new File(db.getWorkTree(), "a.txt");
 		FileUtils.createNewFile(file);
-		PrintWriter writer = new PrintWriter(file);
-		writer.print("content");
-		writer.close();
+		try (PrintWriter writer = new PrintWriter(file)) {
+			writer.print("content");
+		}
 
 		try (Git git = new Git(db)) {
 			DirCache dc = git.add().addFilepattern("a.txt").call();
@@ -692,15 +690,15 @@ public void testAddWithConflicts() throws Exception {
 
 		File file = new File(db.getWorkTree(), "a.txt");
 		FileUtils.createNewFile(file);
-		PrintWriter writer = new PrintWriter(file);
-		writer.print("content");
-		writer.close();
+		try (PrintWriter writer = new PrintWriter(file)) {
+			writer.print("content");
+		}
 
 		File file2 = new File(db.getWorkTree(), "b.txt");
 		FileUtils.createNewFile(file2);
-		writer = new PrintWriter(file2);
-		writer.print("content b");
-		writer.close();
+		try (PrintWriter writer = new PrintWriter(file2)) {
+			writer.print("content b");
+		}
 
 		ObjectInserter newObjectInserter = db.newObjectInserter();
 		DirCache dc = db.lockDirCache();
@@ -709,14 +707,14 @@ public void testAddWithConflicts() throws Exception {
 		addEntryToBuilder("b.txt", file2, newObjectInserter, builder, 0);
 		addEntryToBuilder("a.txt", file, newObjectInserter, builder, 1);
 
-		writer = new PrintWriter(file);
-		writer.print("other content");
-		writer.close();
+		try (PrintWriter writer = new PrintWriter(file)) {
+			writer.print("other content");
+		}
 		addEntryToBuilder("a.txt", file, newObjectInserter, builder, 3);
 
-		writer = new PrintWriter(file);
-		writer.print("our content");
-		writer.close();
+		try (PrintWriter writer = new PrintWriter(file)) {
+			writer.print("our content");
+		}
 		addEntryToBuilder("a.txt", file, newObjectInserter, builder, 2)
 				.getObjectId();
 
@@ -745,15 +743,15 @@ public void testAddWithConflicts() throws Exception {
 	public void testAddTwoFiles() throws Exception  {
 		File file = new File(db.getWorkTree(), "a.txt");
 		FileUtils.createNewFile(file);
-		PrintWriter writer = new PrintWriter(file);
-		writer.print("content");
-		writer.close();
+		try (PrintWriter writer = new PrintWriter(file)) {
+			writer.print("content");
+		}
 
 		File file2 = new File(db.getWorkTree(), "b.txt");
 		FileUtils.createNewFile(file2);
-		writer = new PrintWriter(file2);
-		writer.print("content b");
-		writer.close();
+		try (PrintWriter writer = new PrintWriter(file2)) {
+			writer.print("content b");
+		}
 
 		try (Git git = new Git(db)) {
 			git.add().addFilepattern("a.txt").addFilepattern("b.txt").call();
@@ -769,15 +767,15 @@ public void testAddFolder() throws Exception  {
 		FileUtils.mkdir(new File(db.getWorkTree(), "sub"));
 		File file = new File(db.getWorkTree(), "sub/a.txt");
 		FileUtils.createNewFile(file);
-		PrintWriter writer = new PrintWriter(file);
-		writer.print("content");
-		writer.close();
+		try (PrintWriter writer = new PrintWriter(file)) {
+			writer.print("content");
+		}
 
 		File file2 = new File(db.getWorkTree(), "sub/b.txt");
 		FileUtils.createNewFile(file2);
-		writer = new PrintWriter(file2);
-		writer.print("content b");
-		writer.close();
+		try (PrintWriter writer = new PrintWriter(file2)) {
+			writer.print("content b");
+		}
 
 		try (Git git = new Git(db)) {
 			git.add().addFilepattern("sub").call();
@@ -793,21 +791,21 @@ public void testAddIgnoredFile() throws Exception  {
 		FileUtils.mkdir(new File(db.getWorkTree(), "sub"));
 		File file = new File(db.getWorkTree(), "sub/a.txt");
 		FileUtils.createNewFile(file);
-		PrintWriter writer = new PrintWriter(file);
-		writer.print("content");
-		writer.close();
+		try (PrintWriter writer = new PrintWriter(file)) {
+			writer.print("content");
+		}
 
 		File ignoreFile = new File(db.getWorkTree(), ".gitignore");
 		FileUtils.createNewFile(ignoreFile);
-		writer = new PrintWriter(ignoreFile);
-		writer.print("sub/b.txt");
-		writer.close();
+		try (PrintWriter writer = new PrintWriter(ignoreFile)) {
+			writer.print("sub/b.txt");
+		}
 
 		File file2 = new File(db.getWorkTree(), "sub/b.txt");
 		FileUtils.createNewFile(file2);
-		writer = new PrintWriter(file2);
-		writer.print("content b");
-		writer.close();
+		try (PrintWriter writer = new PrintWriter(file2)) {
+			writer.print("content b");
+		}
 
 		try (Git git = new Git(db)) {
 			git.add().addFilepattern("sub").call();
@@ -823,15 +821,15 @@ public void testAddWholeRepo() throws Exception  {
 		FileUtils.mkdir(new File(db.getWorkTree(), "sub"));
 		File file = new File(db.getWorkTree(), "sub/a.txt");
 		FileUtils.createNewFile(file);
-		PrintWriter writer = new PrintWriter(file);
-		writer.print("content");
-		writer.close();
+		try (PrintWriter writer = new PrintWriter(file)) {
+			writer.print("content");
+		}
 
 		File file2 = new File(db.getWorkTree(), "sub/b.txt");
 		FileUtils.createNewFile(file2);
-		writer = new PrintWriter(file2);
-		writer.print("content b");
-		writer.close();
+		try (PrintWriter writer = new PrintWriter(file2)) {
+			writer.print("content b");
+		}
 
 		try (Git git = new Git(db)) {
 			git.add().addFilepattern(".").call();
@@ -851,15 +849,15 @@ public void testAddWithoutParameterUpdate() throws Exception {
 		FileUtils.mkdir(new File(db.getWorkTree(), "sub"));
 		File file = new File(db.getWorkTree(), "sub/a.txt");
 		FileUtils.createNewFile(file);
-		PrintWriter writer = new PrintWriter(file);
-		writer.print("content");
-		writer.close();
+		try (PrintWriter writer = new PrintWriter(file)) {
+			writer.print("content");
+		}
 
 		File file2 = new File(db.getWorkTree(), "sub/b.txt");
 		FileUtils.createNewFile(file2);
-		writer = new PrintWriter(file2);
-		writer.print("content b");
-		writer.close();
+		try (PrintWriter writer = new PrintWriter(file2)) {
+			writer.print("content b");
+		}
 
 		try (Git git = new Git(db)) {
 			git.add().addFilepattern("sub").call();
@@ -874,14 +872,14 @@ public void testAddWithoutParameterUpdate() throws Exception {
 			// new unstaged file sub/c.txt
 			File file3 = new File(db.getWorkTree(), "sub/c.txt");
 			FileUtils.createNewFile(file3);
-			writer = new PrintWriter(file3);
-			writer.print("content c");
-			writer.close();
+			try (PrintWriter writer = new PrintWriter(file3)) {
+				writer.print("content c");
+			}
 
 			// file sub/a.txt is modified
-			writer = new PrintWriter(file);
-			writer.print("modified content");
-			writer.close();
+			try (PrintWriter writer = new PrintWriter(file)) {
+				writer.print("modified content");
+			}
 
 			// file sub/b.txt is deleted
 			FileUtils.delete(file2);
@@ -906,15 +904,15 @@ public void testAddWithParameterUpdate() throws Exception {
 		FileUtils.mkdir(new File(db.getWorkTree(), "sub"));
 		File file = new File(db.getWorkTree(), "sub/a.txt");
 		FileUtils.createNewFile(file);
-		PrintWriter writer = new PrintWriter(file);
-		writer.print("content");
-		writer.close();
+		try (PrintWriter writer = new PrintWriter(file)) {
+			writer.print("content");
+		}
 
 		File file2 = new File(db.getWorkTree(), "sub/b.txt");
 		FileUtils.createNewFile(file2);
-		writer = new PrintWriter(file2);
-		writer.print("content b");
-		writer.close();
+		try (PrintWriter writer = new PrintWriter(file2)) {
+			writer.print("content b");
+		}
 
 		try (Git git = new Git(db)) {
 			git.add().addFilepattern("sub").call();
@@ -929,14 +927,14 @@ public void testAddWithParameterUpdate() throws Exception {
 			// new unstaged file sub/c.txt
 			File file3 = new File(db.getWorkTree(), "sub/c.txt");
 			FileUtils.createNewFile(file3);
-			writer = new PrintWriter(file3);
-			writer.print("content c");
-			writer.close();
+			try (PrintWriter writer = new PrintWriter(file3)) {
+				writer.print("content c");
+			}
 
 			// file sub/a.txt is modified
-			writer = new PrintWriter(file);
-			writer.print("modified content");
-			writer.close();
+			try (PrintWriter writer = new PrintWriter(file)) {
+				writer.print("modified content");
+			}
 
 			FileUtils.delete(file2);
 
@@ -1250,9 +1248,9 @@ public void testAddGitlinkDoesNotChange() throws Exception {
 
 		try (Git git = new Git(db)) {
 			git.add().addFilepattern("nested-repo").call();
-
+			// with gitlinks ignored, we treat this as a normal directory
 			assertEquals(
-					"[nested-repo, mode:160000]",
+					"[nested-repo/README1.md, mode:100644][nested-repo/README2.md, mode:100644]",
 					indexState(0));
 		}
 	}
@@ -1260,10 +1258,11 @@ public void testAddGitlinkDoesNotChange() throws Exception {
 	private static DirCacheEntry addEntryToBuilder(String path, File file,
 			ObjectInserter newObjectInserter, DirCacheBuilder builder, int stage)
 			throws IOException {
-		FileInputStream inputStream = new FileInputStream(file);
-		ObjectId id = newObjectInserter.insert(
+		ObjectId id;
+		try (FileInputStream inputStream = new FileInputStream(file)) {
+			id = newObjectInserter.insert(
 				Constants.OBJ_BLOB, file.length(), inputStream);
-		inputStream.close();
+		}
 		DirCacheEntry entry = new DirCacheEntry(path, stage);
 		entry.setObjectId(id);
 		entry.setFileMode(FileMode.REGULAR_FILE);
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/ApplyCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/ApplyCommandTest.java
index 172807c..1dd329a 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/ApplyCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/ApplyCommandTest.java
@@ -64,7 +64,7 @@ public class ApplyCommandTest extends RepositoryTestCase {
 
 	private RawText b;
 
-	private ApplyResult init(final String name) throws Exception {
+	private ApplyResult init(String name) throws Exception {
 		return init(name, true, true);
 	}
 
@@ -273,7 +273,7 @@ public void testNonASCIIDel() throws Exception {
 		assertFalse(new File(db.getWorkTree(), "NonASCIIDel").exists());
 	}
 
-	private static byte[] readFile(final String patchFile) throws IOException {
+	private static byte[] readFile(String patchFile) throws IOException {
 		final InputStream in = getTestResource(patchFile);
 		if (in == null) {
 			fail("No " + patchFile + " test vector");
@@ -291,7 +291,7 @@ public void testNonASCIIDel() throws Exception {
 		}
 	}
 
-	private static InputStream getTestResource(final String patchFile) {
+	private static InputStream getTestResource(String patchFile) {
 		return ApplyCommandTest.class.getClassLoader()
 				.getResourceAsStream("org/eclipse/jgit/diff/" + patchFile);
 	}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/ArchiveCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/ArchiveCommandTest.java
index edab96b..1300f98 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/ArchiveCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/ArchiveCommandTest.java
@@ -229,11 +229,6 @@ public MockOutputStream createArchiveOutputStream(OutputStream s,
 		}
 
 		@Override
-		public void putEntry(MockOutputStream out, String path, FileMode mode, ObjectLoader loader) {
-			putEntry(out, null, path, mode, loader);
-		}
-
-		@Override
 		public void putEntry(MockOutputStream out, ObjectId tree, String path, FileMode mode, ObjectLoader loader) {
 			String content = mode != FileMode.TREE ? new String(loader.getBytes()) : null;
 			entries.put(path, content);
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/BlameCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/BlameCommandTest.java
index f37aa13..7a1d222 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/BlameCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/BlameCommandTest.java
@@ -136,7 +136,7 @@ public void testMoveToOtherDir() throws Exception {
 		testRename("subdir/file1.txt", "otherdir/file1.txt");
 	}
 
-	private void testRename(final String sourcePath, final String destPath)
+	private void testRename(String sourcePath, String destPath)
 			throws Exception {
 		try (Git git = new Git(db)) {
 			String[] content1 = new String[] { "a", "b", "c" };
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/BranchCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/BranchCommandTest.java
index 2fe40b9..08f1fdf 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/BranchCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/BranchCommandTest.java
@@ -191,6 +191,18 @@ public void testCreateAndList() throws Exception {
 				- allBefore);
 	}
 
+	@Test(expected = InvalidRefNameException.class)
+	public void testInvalidBranchHEAD() throws Exception {
+		git.branchCreate().setName("HEAD").call();
+		fail("Create branch with invalid ref name should fail");
+	}
+
+	@Test(expected = InvalidRefNameException.class)
+	public void testInvalidBranchDash() throws Exception {
+		git.branchCreate().setName("-x").call();
+		fail("Create branch with invalid ref name should fail");
+	}
+
 	@Test
 	public void testListAllBranchesShouldNotDie() throws Exception {
 		setUpRepoWithRemote().branchList().setListMode(ListMode.ALL).call();
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CheckoutCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CheckoutCommandTest.java
index 1201d9f..71df59e 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CheckoutCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CheckoutCommandTest.java
@@ -74,8 +74,7 @@
 import org.eclipse.jgit.dircache.DirCacheEntry;
 import org.eclipse.jgit.junit.JGitTestUtil;
 import org.eclipse.jgit.junit.RepositoryTestCase;
-import org.eclipse.jgit.lfs.CleanFilter;
-import org.eclipse.jgit.lfs.SmudgeFilter;
+import org.eclipse.jgit.lfs.BuiltinLFS;
 import org.eclipse.jgit.lib.ConfigConstants;
 import org.eclipse.jgit.lib.Constants;
 import org.eclipse.jgit.lib.Ref;
@@ -102,8 +101,7 @@ public class CheckoutCommandTest extends RepositoryTestCase {
 	@Override
 	@Before
 	public void setUp() throws Exception {
-		CleanFilter.register();
-		SmudgeFilter.register();
+		BuiltinLFS.register();
 		super.setUp();
 		git = new Git(db);
 		// commit something
@@ -172,15 +170,12 @@ public void testCheckoutWithConflict() {
 	@Test
 	public void testCheckoutWithNonDeletedFiles() throws Exception {
 		File testFile = writeTrashFile("temp", "");
-		FileInputStream fis = new FileInputStream(testFile);
-		try {
+		try (FileInputStream fis = new FileInputStream(testFile)) {
 			FileUtils.delete(testFile);
 			return;
 		} catch (IOException e) {
 			// the test makes only sense if deletion of
 			// a file with open stream fails
-		} finally {
-			fis.close();
 		}
 		FileUtils.delete(testFile);
 		CheckoutCommand co = git.checkout();
@@ -194,15 +189,12 @@ public void testCheckoutWithNonDeletedFiles() throws Exception {
 		git.checkout().setName("master").call();
 		assertTrue(testFile.exists());
 		// lock the file so it can't be deleted (in Windows, that is)
-		fis = new FileInputStream(testFile);
-		try {
+		try (FileInputStream fis = new FileInputStream(testFile)) {
 			assertEquals(Status.NOT_TRIED, co.getResult().getStatus());
 			co.setName("test").call();
 			assertTrue(testFile.exists());
 			assertEquals(Status.NONDELETED, co.getResult().getStatus());
 			assertTrue(co.getResult().getUndeletedList().contains("Test.txt"));
-		} finally {
-			fis.close();
 		}
 	}
 
@@ -824,7 +816,7 @@ public void testNonDeletableFilesOnWindows()
 	}
 
 	private File writeTempFile(String body) throws IOException {
-		File f = File.createTempFile("AddCommandTest_", "");
+		File f = File.createTempFile("CheckoutCommandTest_", "");
 		JGitTestUtil.write(f, body);
 		return f;
 	}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CherryPickCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CherryPickCommandTest.java
index 354b9c6..fbc2cf6 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CherryPickCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CherryPickCommandTest.java
@@ -338,7 +338,7 @@ public void testCherryPickOurCommitName() throws Exception {
 		}
 	}
 
-	private RevCommit prepareCherryPick(final Git git) throws Exception {
+	private RevCommit prepareCherryPick(Git git) throws Exception {
 		// create, add and commit file a
 		writeTrashFile("a", "a");
 		git.add().addFilepattern("a").call();
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CleanCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CleanCommandTest.java
index 85436db..065b5b4 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CleanCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CleanCommandTest.java
@@ -48,10 +48,12 @@
 import static org.junit.Assert.assertTrue;
 
 import java.io.File;
+import java.io.IOException;
 import java.util.Set;
 import java.util.TreeSet;
 
 import org.eclipse.jgit.api.errors.GitAPIException;
+import org.eclipse.jgit.api.errors.NoFilepatternException;
 import org.eclipse.jgit.errors.NoWorkTreeException;
 import org.eclipse.jgit.junit.RepositoryTestCase;
 import org.eclipse.jgit.lib.Repository;
@@ -238,8 +240,9 @@ public void testCleanDirsWithSubmodule() throws Exception {
 		command.setPath(path);
 		String uri = db.getDirectory().toURI().toString();
 		command.setURI(uri);
-		Repository repo = command.call();
-		repo.close();
+		try (Repository repo = command.call()) {
+			// Unused
+		}
 
 		Status beforeCleanStatus = git.status().call();
 		assertTrue(beforeCleanStatus.getAdded().contains(DOT_GIT_MODULES));
@@ -296,4 +299,18 @@ public void testCleanDirsWithRepository() throws Exception {
 		// The inner repository should be cleaned this time
 		assertTrue(forceCleanedFiles.contains(innerRepoName + "/"));
 	}
+
+	@Test
+	// To proof Bug 514434. No assertions, but before the bugfix
+	// this test was throwing Exceptions
+	public void testFilesShouldBeCleanedInSubSubFolders()
+			throws IOException, NoFilepatternException, GitAPIException {
+		writeTrashFile(".gitignore",
+				"/ignored-dir\n/sub-noclean/Ignored.txt\n/this_is_ok\n/this_is/not_ok\n");
+		git.add().addFilepattern(".gitignore").call();
+		git.commit().setMessage("adding .gitignore").call();
+		writeTrashFile("this_is_ok/more/subdirs/file.txt", "1");
+		writeTrashFile("this_is/not_ok/more/subdirs/file.txt", "2");
+		git.clean().setCleanDirectories(true).setIgnore(false).call();
+	}
 }
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CloneCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CloneCommandTest.java
index e687a6c..0d7009d 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CloneCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CloneCommandTest.java
@@ -601,17 +601,17 @@ public void testCloneRepositoryWithNestedSubmodules() throws Exception {
 
 		SubmoduleWalk walk = SubmoduleWalk.forIndex(git2.getRepository());
 		assertTrue(walk.next());
-		Repository clonedSub1 = walk.getRepository();
-		assertNotNull(clonedSub1);
-		assertEquals(
-				new File(git2.getRepository().getWorkTree(), walk.getPath()),
-				clonedSub1.getWorkTree());
-		assertEquals(new File(new File(git2.getRepository().getDirectory(),
-				"modules"), walk.getPath()),
-				clonedSub1.getDirectory());
-		status = new SubmoduleStatusCommand(clonedSub1);
-		statuses = status.call();
-		clonedSub1.close();
+		try (Repository clonedSub1 = walk.getRepository()) {
+			assertNotNull(clonedSub1);
+			assertEquals(new File(git2.getRepository().getWorkTree(),
+					walk.getPath()), clonedSub1.getWorkTree());
+			assertEquals(
+					new File(new File(git2.getRepository().getDirectory(),
+							"modules"), walk.getPath()),
+					clonedSub1.getDirectory());
+			status = new SubmoduleStatusCommand(clonedSub1);
+			statuses = status.call();
+		}
 		pathStatus = statuses.get(path);
 		assertNotNull(pathStatus);
 		assertEquals(SubmoduleStatusType.INITIALIZED, pathStatus.getType());
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitAndLogCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitAndLogCommandTest.java
index 1d5c674..ca0630e 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitAndLogCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitAndLogCommandTest.java
@@ -120,9 +120,9 @@ public void testLogWithFilter() throws IOException, JGitInternalException,
 			// create first file
 			File file = new File(db.getWorkTree(), "a.txt");
 			FileUtils.createNewFile(file);
-			PrintWriter writer = new PrintWriter(file);
-			writer.print("content1");
-			writer.close();
+			try (PrintWriter writer = new PrintWriter(file)) {
+				writer.print("content1");
+			}
 
 			// First commit - a.txt file
 			git.add().addFilepattern("a.txt").call();
@@ -131,9 +131,9 @@ public void testLogWithFilter() throws IOException, JGitInternalException,
 			// create second file
 			file = new File(db.getWorkTree(), "b.txt");
 			FileUtils.createNewFile(file);
-			writer = new PrintWriter(file);
-			writer.print("content2");
-			writer.close();
+			try (PrintWriter writer = new PrintWriter(file)) {
+				writer.print("content2");
+			}
 
 			// Second commit - b.txt file
 			git.add().addFilepattern("b.txt").call();
@@ -231,9 +231,9 @@ public void testAddUnstagedChanges() throws IOException,
 			JGitInternalException, GitAPIException {
 		File file = new File(db.getWorkTree(), "a.txt");
 		FileUtils.createNewFile(file);
-		PrintWriter writer = new PrintWriter(file);
-		writer.print("content");
-		writer.close();
+		try (PrintWriter writer = new PrintWriter(file)) {
+			writer.print("content");
+		}
 
 		try (Git git = new Git(db)) {
 			git.add().addFilepattern("a.txt").call();
@@ -242,9 +242,9 @@ public void testAddUnstagedChanges() throws IOException,
 			assertEquals("6b584e8ece562ebffc15d38808cd6b98fc3d97ea",
 					tw.getObjectId(0).getName());
 
-			writer = new PrintWriter(file);
-			writer.print("content2");
-			writer.close();
+			try (PrintWriter writer = new PrintWriter(file)) {
+				writer.print("content2");
+			}
 			commit = git.commit().setMessage("second commit").call();
 			tw = TreeWalk.forPath(db, "a.txt", commit.getTree());
 			assertEquals("6b584e8ece562ebffc15d38808cd6b98fc3d97ea",
@@ -265,9 +265,9 @@ public void testModeChange() throws IOException, GitAPIException {
 			// create file
 			File file = new File(db.getWorkTree(), "a.txt");
 			FileUtils.createNewFile(file);
-			PrintWriter writer = new PrintWriter(file);
-			writer.print("content1");
-			writer.close();
+			try (PrintWriter writer = new PrintWriter(file)) {
+				writer.print("content1");
+			}
 
 			// First commit - a.txt file
 			git.add().addFilepattern("a.txt").call();
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitCommandTest.java
index a0834e7..3a13aa5 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitCommandTest.java
@@ -54,7 +54,7 @@
 import java.util.List;
 import java.util.TimeZone;
 
-import org.eclipse.jgit.api.errors.EmtpyCommitException;
+import org.eclipse.jgit.api.errors.EmptyCommitException;
 import org.eclipse.jgit.api.errors.WrongRepositoryStateException;
 import org.eclipse.jgit.diff.DiffEntry;
 import org.eclipse.jgit.dircache.DirCache;
@@ -223,9 +223,9 @@ public void commitNewSubmodule() throws Exception {
 			assertEquals(uri, generator.getModulesUrl());
 			assertEquals(path, generator.getModulesPath());
 			assertEquals(uri, generator.getConfigUrl());
-			Repository subModRepo = generator.getRepository();
-			assertNotNull(subModRepo);
-			subModRepo.close();
+			try (Repository subModRepo = generator.getRepository()) {
+				assertNotNull(subModRepo);
+			}
 			assertEquals(commit, repo.resolve(Constants.HEAD));
 
 			RevCommit submoduleCommit = git.commit().setMessage("submodule add")
@@ -273,9 +273,9 @@ public void commitSubmoduleUpdate() throws Exception {
 			assertEquals(uri, generator.getModulesUrl());
 			assertEquals(path, generator.getModulesPath());
 			assertEquals(uri, generator.getConfigUrl());
-			Repository subModRepo = generator.getRepository();
-			assertNotNull(subModRepo);
-			subModRepo.close();
+			try (Repository subModRepo = generator.getRepository()) {
+				assertNotNull(subModRepo);
+			}
 			assertEquals(commit2, repo.resolve(Constants.HEAD));
 
 			RevCommit submoduleAddCommit = git.commit().setMessage("submodule add")
@@ -553,8 +553,8 @@ public void commitEmptyCommits() throws Exception {
 				git.commit().setAuthor("New Author", "newauthor@example.org")
 						.setMessage("again no change").setAllowEmpty(false)
 						.call();
-				fail("Didn't get the expected EmtpyCommitException");
-			} catch (EmtpyCommitException e) {
+				fail("Didn't get the expected EmptyCommitException");
+			} catch (EmptyCommitException e) {
 				// expect this exception
 			}
 
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitOnlyTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitOnlyTest.java
index 5f7434b..bbd6ec0 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitOnlyTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitOnlyTest.java
@@ -70,19 +70,19 @@
  * ---------------------------------------------------------------------
  *        | HEAD  DirCache  Worktree | HEAD  DirCache
  * ---------------------------------------------------------------------
- *  f1_1  |  -       -       c       |                => e: path unknown
- *  f1_2  |  -       c       -       |                => no changes
+ *  f1_1  |  -       -       c       |                =&gt; e: path unknown
+ *  f1_2  |  -       c       -       |                =&gt; no changes
  *  f1_3  |  c       -       -       |  -       -
  *  f1_4  |  -       c       c       |  c       c
  *  f1_5  |  c       c       -       |  -       -
- *  f1_6  |  c       -       c       |                => no changes
- *  f1_7  |  c       c       c       |                => no changes
+ *  f1_6  |  c       -       c       |                =&gt; no changes
+ *  f1_7  |  c       c       c       |                =&gt; no changes
  * ---------------------------------------------------------------------
  *  f1_8  |  -       c       c'      |  c'      c'
  *  f1_9  |  c       -       c'      |  c'      c'
  * f1_10  |  c       c'      -       |  -       -
  * f1_11  |  c       c       c'      |  c'      c'
- * f1_12  |  c       c'      c       |                => no changes
+ * f1_12  |  c       c'      c       |                =&gt; no changes
  * f1_13  |  c       c'      c'      |  c'      c'
  * ---------------------------------------------------------------------
  * f1_14  |  c       c'      c''     |  c''     c''
@@ -97,7 +97,7 @@
  * ---------------------------------------------------------------------------
  *              | HEAD  DirCache  Worktree | HEAD  DirCache
  * ---------------------------------------------------------------------------
- *  f1_1_f2_14  |  -       -       c       |                => e: path unknown
+ *  f1_1_f2_14  |  -       -       c       |                =&gt; e: path unknown
  *  f1_2_f2_14  |  -       c       -       |  -       -
  *  f1_6_f2_14  |  c       -       c       |  c       c
  *  f1_7_f2_14  |  c       c       c       |  c       c
@@ -1289,7 +1289,7 @@ private static String expected_f3_idx(final int state) {
 		return null;
 	}
 
-	static private String getHead(final Git git, final String path)
+	static private String getHead(Git git, String path)
 			throws Exception {
 		try {
 			final Repository repo = git.getRepository();
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/DescribeCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/DescribeCommandTest.java
index 6a66783..79da2da 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/DescribeCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/DescribeCommandTest.java
@@ -158,9 +158,9 @@ public void testDescribeMultiMatch() throws Exception {
 	 * Make sure it finds a tag when not all ancestries include a tag.
 	 *
 	 * <pre>
-	 * c1 -+-> T  -
+	 * c1 -+-&gt; T  -
 	 *     |       |
-	 *     +-> c3 -+-> c4
+	 *     +-&gt; c3 -+-&gt; c4
 	 * </pre>
 	 *
 	 * @throws Exception
@@ -193,9 +193,9 @@ private void branch(String name, ObjectId base) throws GitAPIException {
 	 * When t2 dominates t1, it's clearly preferable to describe by using t2.
 	 *
 	 * <pre>
-	 * t1 -+-> t2  -
+	 * t1 -+-&gt; t2  -
 	 *     |       |
-	 *     +-> c3 -+-> c4
+	 *     +-&gt; c3 -+-&gt; c4
 	 * </pre>
 	 *
 	 * @throws Exception
@@ -225,9 +225,9 @@ public void t1DominatesT2() throws Exception {
 	 * When t1 is nearer than t2, t2 should be found
 	 *
 	 * <pre>
-	 * c1 -+-> c2 -> t1 -+
+	 * c1 -+-&gt; c2 -&gt; t1 -+
 	 *     |             |
-	 *     +-> t2 -> c3 -+-> c4
+	 *     +-&gt; t2 -&gt; c3 -+-&gt; c4
 	 * </pre>
 	 *
 	 * @throws Exception
@@ -254,9 +254,9 @@ public void t1nearerT2() throws Exception {
 	 * paths
 	 *
 	 * <pre>
-	 * c1 -+-> t1 -> c2 -+
+	 * c1 -+-&gt; t1 -&gt; c2 -+
 	 *     |             |
-	 *     +-> t2 -> c3 -+-> c4
+	 *     +-&gt; t2 -&gt; c3 -+-&gt; c4
 	 * </pre>
 	 *
 	 * @throws Exception
@@ -297,9 +297,9 @@ private void tag(String tag) throws GitAPIException {
 	}
 
 	private static void touch(File f, String contents) throws Exception {
-		FileWriter w = new FileWriter(f);
-		w.write(contents);
-		w.close();
+		try (FileWriter w = new FileWriter(f)) {
+			w.write(contents);
+		}
 	}
 
 	private String describe(ObjectId c1, boolean longDesc)
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/EolStreamTypeUtilTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/EolStreamTypeUtilTest.java
index 2ee77a0..bb303cc 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/EolStreamTypeUtilTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/EolStreamTypeUtilTest.java
@@ -42,6 +42,7 @@
 
 package org.eclipse.jgit.api;
 
+import static org.eclipse.jgit.lib.Constants.CHARSET;
 import static org.eclipse.jgit.lib.CoreConfig.EolStreamType.AUTO_CRLF;
 import static org.eclipse.jgit.lib.CoreConfig.EolStreamType.AUTO_LF;
 import static org.eclipse.jgit.lib.CoreConfig.EolStreamType.DIRECT;
@@ -53,7 +54,6 @@
 import java.io.ByteArrayOutputStream;
 import java.io.InputStream;
 import java.io.OutputStream;
-import java.nio.charset.StandardCharsets;
 import java.util.Arrays;
 
 import org.eclipse.jgit.lib.CoreConfig.EolStreamType;
@@ -150,9 +150,8 @@ private void testCheckout(EolStreamType streamTypeText,
 			EolStreamType streamTypeWithBinaryCheck, String output,
 			String expectedConversion) throws Exception {
 		ByteArrayOutputStream b;
-		byte[] outputBytes = output.getBytes(StandardCharsets.UTF_8);
-		byte[] expectedConversionBytes = expectedConversion
-				.getBytes(StandardCharsets.UTF_8);
+		byte[] outputBytes = output.getBytes(CHARSET);
+		byte[] expectedConversionBytes = expectedConversion.getBytes(CHARSET);
 
 		// test using output text and assuming it was declared TEXT
 		b = new ByteArrayOutputStream();
@@ -278,9 +277,8 @@ public void testCheckinCRLF() throws Exception {
 	private void testCheckin(EolStreamType streamTypeText,
 			EolStreamType streamTypeWithBinaryCheck, String input,
 			String expectedConversion) throws Exception {
-		byte[] inputBytes = input.getBytes(StandardCharsets.UTF_8);
-		byte[] expectedConversionBytes = expectedConversion
-				.getBytes(StandardCharsets.UTF_8);
+		byte[] inputBytes = input.getBytes(CHARSET);
+		byte[] expectedConversionBytes = expectedConversion.getBytes(CHARSET);
 
 		// test using input text and assuming it was declared TEXT
 		try (InputStream in = EolStreamTypeUtil.wrapInputStream(
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/FetchCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/FetchCommandTest.java
index 83a0564..4c2c0e8 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/FetchCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/FetchCommandTest.java
@@ -43,10 +43,15 @@
 package org.eclipse.jgit.api;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
 
+import java.io.File;
 import java.util.Collection;
 
+import org.eclipse.jgit.junit.JGitTestUtil;
 import org.eclipse.jgit.junit.RepositoryTestCase;
 import org.eclipse.jgit.lib.Constants;
 import org.eclipse.jgit.lib.ObjectId;
@@ -102,6 +107,25 @@ public void testFetch() throws Exception {
 	}
 
 	@Test
+	public void testForcedFetch() throws Exception {
+		remoteGit.commit().setMessage("commit").call();
+		remoteGit.commit().setMessage("commit2").call();
+		git.fetch().setRemote("test")
+				.setRefSpecs("refs/heads/master:refs/heads/master").call();
+
+		remoteGit.commit().setAmend(true).setMessage("amended").call();
+		FetchResult res = git.fetch().setRemote("test")
+				.setRefSpecs("refs/heads/master:refs/heads/master").call();
+		assertEquals(RefUpdate.Result.REJECTED,
+				res.getTrackingRefUpdate("refs/heads/master").getResult());
+		res = git.fetch().setRemote("test")
+				.setRefSpecs("refs/heads/master:refs/heads/master")
+				.setForceUpdate(true).call();
+		assertEquals(RefUpdate.Result.FORCED,
+				res.getTrackingRefUpdate("refs/heads/master").getResult());
+	}
+
+	@Test
 	public void fetchShouldAutoFollowTag() throws Exception {
 		remoteGit.commit().setMessage("commit").call();
 		Ref tagRef = remoteGit.tag().setName("foo").call();
@@ -185,4 +209,43 @@ public void fetchWithExplicitTagsShouldUpdateLocal() throws Exception {
 		assertEquals(RefUpdate.Result.FORCED, update.getResult());
 		assertEquals(tagRef2.getObjectId(), db.resolve(tagName));
 	}
+
+	@Test
+	public void testFetchWithPruneShouldKeepOriginHead() throws Exception {
+		// Create a commit in the test repo.
+		commitFile("foo", "foo", "master");
+		// Produce a real clone of the git repo
+		Git cloned = Git.cloneRepository()
+				.setDirectory(createTempDirectory("testCloneRepository"))
+				.setURI("file://"
+						+ git.getRepository().getWorkTree().getAbsolutePath())
+				.call();
+		assertNotNull(cloned);
+		Repository clonedRepo = cloned.getRepository();
+		addRepoToClose(clonedRepo);
+		ObjectId originMasterId = clonedRepo
+				.resolve("refs/remotes/origin/master");
+		assertNotNull("Should have origin/master", originMasterId);
+		assertNotEquals("origin/master should not be zero ID",
+				ObjectId.zeroId(), originMasterId);
+		// Canonical git creates origin/HEAD; JGit (for now) doesn't. Let's
+		// pretend we did the clone via command-line git.
+		ObjectId originHeadId = clonedRepo.resolve("refs/remotes/origin/HEAD");
+		if (originHeadId == null) {
+			JGitTestUtil.write(
+					new File(clonedRepo.getDirectory(),
+							"refs/remotes/origin/HEAD"),
+					"ref: refs/remotes/origin/master\n");
+			originHeadId = clonedRepo.resolve("refs/remotes/origin/HEAD");
+		}
+		assertEquals("Should have origin/HEAD", originMasterId, originHeadId);
+		FetchResult result = cloned.fetch().setRemote("origin")
+				.setRemoveDeletedRefs(true).call();
+		assertTrue("Fetch after clone should be up-to-date",
+				result.getTrackingRefUpdates().isEmpty());
+		assertEquals("origin/master should still exist", originMasterId,
+				clonedRepo.resolve("refs/remotes/origin/master"));
+		assertEquals("origin/HEAD should be unchanged", originHeadId,
+				clonedRepo.resolve("refs/remotes/origin/HEAD"));
+	}
 }
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/HugeFileTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/HugeFileTest.java
index 4208f4d..6c3504a 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/HugeFileTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/HugeFileTest.java
@@ -87,9 +87,9 @@ public void after() {
 	public void testAddHugeFile() throws Exception {
 		measure("Commencing test");
 		File file = new File(db.getWorkTree(), "a.txt");
-		RandomAccessFile rf = new RandomAccessFile(file, "rw");
-		rf.setLength(4429185024L);
-		rf.close();
+		try (RandomAccessFile rf = new RandomAccessFile(file, "rw")) {
+			rf.setLength(4429185024L);
+		}
 		measure("Created file");
 
 		git.add().addFilepattern("a.txt").call();
@@ -109,9 +109,9 @@ public void testAddHugeFile() throws Exception {
 		assertEquals(0, status.getUntracked().size());
 
 		// Does not change anything, but modified timestamp
-		rf = new RandomAccessFile(file, "rw");
-		rf.write(0);
-		rf.close();
+		try (RandomAccessFile rf = new RandomAccessFile(file, "rw")) {
+			rf.write(0);
+		}
 
 		status = git.status().call();
 		measure("Status after non-modifying update");
@@ -125,9 +125,9 @@ public void testAddHugeFile() throws Exception {
 		assertEquals(0, status.getUntracked().size());
 
 		// Change something
-		rf = new RandomAccessFile(file, "rw");
-		rf.write('a');
-		rf.close();
+		try (RandomAccessFile rf = new RandomAccessFile(file, "rw")) {
+			rf.write('a');
+		}
 
 		status = git.status().call();
 		measure("Status after modifying update");
@@ -141,10 +141,10 @@ public void testAddHugeFile() throws Exception {
 		assertEquals(0, status.getUntracked().size());
 
 		// Truncate mod 4G and re-establish equality
-		rf = new RandomAccessFile(file, "rw");
-		rf.setLength(134217728L);
-		rf.write(0);
-		rf.close();
+		try (RandomAccessFile rf = new RandomAccessFile(file, "rw")) {
+			rf.setLength(134217728L);
+			rf.write(0);
+		}
 
 		status = git.status().call();
 		measure("Status after truncating update");
@@ -158,9 +158,9 @@ public void testAddHugeFile() throws Exception {
 		assertEquals(0, status.getUntracked().size());
 
 		// Change something
-		rf = new RandomAccessFile(file, "rw");
-		rf.write('a');
-		rf.close();
+		try (RandomAccessFile rf = new RandomAccessFile(file, "rw")) {
+			rf.write('a');
+		}
 
 		status = git.status().call();
 		measure("Status after modifying and truncating update");
@@ -174,10 +174,10 @@ public void testAddHugeFile() throws Exception {
 		assertEquals(0, status.getUntracked().size());
 
 		// Truncate to entry length becomes negative int
-		rf = new RandomAccessFile(file, "rw");
-		rf.setLength(3429185024L);
-		rf.write(0);
-		rf.close();
+		try (RandomAccessFile rf = new RandomAccessFile(file, "rw")) {
+			rf.setLength(3429185024L);
+			rf.write(0);
+		}
 
 		git.add().addFilepattern("a.txt").call();
 		measure("Added truncated file");
@@ -197,9 +197,9 @@ public void testAddHugeFile() throws Exception {
 		assertEquals(0, status.getUntracked().size());
 
 		// Change something
-		rf = new RandomAccessFile(file, "rw");
-		rf.write('a');
-		rf.close();
+		try (RandomAccessFile rf = new RandomAccessFile(file, "rw")) {
+			rf.write('a');
+		}
 
 		status = git.status().call();
 		measure("Status after modifying and truncating update");
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/InitCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/InitCommandTest.java
index e850223..9e3ee2c 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/InitCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/InitCommandTest.java
@@ -69,14 +69,14 @@ public void setUp() throws Exception {
 	}
 
 	@Test
-	public void testInitRepository() throws IOException, JGitInternalException,
-			GitAPIException {
+	public void testInitRepository()
+			throws IOException, JGitInternalException, GitAPIException {
 		File directory = createTempDirectory("testInitRepository");
 		InitCommand command = new InitCommand();
 		command.setDirectory(directory);
-		Repository repository = command.call().getRepository();
-		addRepoToClose(repository);
-		assertNotNull(repository);
+		try (Git git = command.call()) {
+			assertNotNull(git.getRepository());
+		}
 	}
 
 	@Test
@@ -89,9 +89,9 @@ public void testInitNonEmptyRepository() throws IOException,
 		assertTrue(directory.listFiles().length > 0);
 		InitCommand command = new InitCommand();
 		command.setDirectory(directory);
-		Repository repository = command.call().getRepository();
-		addRepoToClose(repository);
-		assertNotNull(repository);
+		try (Git git = command.call()) {
+			assertNotNull(git.getRepository());
+		}
 	}
 
 	@Test
@@ -101,10 +101,11 @@ public void testInitBareRepository() throws IOException,
 		InitCommand command = new InitCommand();
 		command.setDirectory(directory);
 		command.setBare(true);
-		Repository repository = command.call().getRepository();
-		addRepoToClose(repository);
-		assertNotNull(repository);
-		assertTrue(repository.isBare());
+		try (Git git = command.call()) {
+			Repository repository = git.getRepository();
+			assertNotNull(repository);
+			assertTrue(repository.isBare());
+		}
 	}
 
 	// non-bare repos where gitDir and directory is set. Same as
@@ -117,11 +118,12 @@ public void testInitWithExplicitGitDir() throws IOException,
 		InitCommand command = new InitCommand();
 		command.setDirectory(wt);
 		command.setGitDir(gitDir);
-		Repository repository = command.call().getRepository();
-		addRepoToClose(repository);
-		assertNotNull(repository);
-		assertEqualsFile(wt, repository.getWorkTree());
-		assertEqualsFile(gitDir, repository.getDirectory());
+		try (Git git = command.call()) {
+			Repository repository = git.getRepository();
+			assertNotNull(repository);
+			assertEqualsFile(wt, repository.getWorkTree());
+			assertEqualsFile(gitDir, repository.getDirectory());
+		}
 	}
 
 	// non-bare repos where only gitDir is set. Same as
@@ -135,12 +137,13 @@ public void testInitWithOnlyExplicitGitDir() throws IOException,
 		File gitDir = createTempDirectory("testInitRepository/.git");
 		InitCommand command = new InitCommand();
 		command.setGitDir(gitDir);
-		Repository repository = command.call().getRepository();
-		addRepoToClose(repository);
-		assertNotNull(repository);
-		assertEqualsFile(gitDir, repository.getDirectory());
-		assertEqualsFile(new File(reader.getProperty("user.dir")),
-				repository.getWorkTree());
+		try (Git git = command.call()) {
+			Repository repository = git.getRepository();
+			assertNotNull(repository);
+			assertEqualsFile(gitDir, repository.getDirectory());
+			assertEqualsFile(new File(reader.getProperty("user.dir")),
+					repository.getWorkTree());
+		}
 	}
 
 	// Bare repos where gitDir and directory is set will only work if gitDir and
@@ -169,13 +172,14 @@ public void testInitWithDefaultsNonBare() throws JGitInternalException,
 				.getAbsolutePath());
 		InitCommand command = new InitCommand();
 		command.setBare(false);
-		Repository repository = command.call().getRepository();
-		addRepoToClose(repository);
-		assertNotNull(repository);
-		assertEqualsFile(new File(reader.getProperty("user.dir"), ".git"),
-				repository.getDirectory());
-		assertEqualsFile(new File(reader.getProperty("user.dir")),
-				repository.getWorkTree());
+		try (Git git = command.call()) {
+			Repository repository = git.getRepository();
+			assertNotNull(repository);
+			assertEqualsFile(new File(reader.getProperty("user.dir"), ".git"),
+					repository.getDirectory());
+			assertEqualsFile(new File(reader.getProperty("user.dir")),
+					repository.getWorkTree());
+		}
 	}
 
 	// If neither directory nor gitDir is set in a bare repo make sure
@@ -189,12 +193,13 @@ public void testInitWithDefaultsBare() throws JGitInternalException,
 				.getAbsolutePath());
 		InitCommand command = new InitCommand();
 		command.setBare(true);
-		Repository repository = command.call().getRepository();
-		addRepoToClose(repository);
-		assertNotNull(repository);
-		assertEqualsFile(new File(reader.getProperty("user.dir")),
-				repository.getDirectory());
-		assertNull(repository.getWorkTree());
+		try (Git git = command.call()) {
+			Repository repository = git.getRepository();
+			assertNotNull(repository);
+			assertEqualsFile(new File(reader.getProperty("user.dir")),
+					repository.getDirectory());
+			assertNull(repository.getWorkTree());
+		}
 	}
 
 	// In a non-bare repo when directory and gitDir is set then they shouldn't
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/LogCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/LogCommandTest.java
index bd0efad..4ef511e 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/LogCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/LogCommandTest.java
@@ -116,7 +116,7 @@ public void logAllCommitsWithTag() throws Exception {
 		Iterator<RevCommit> log = git.log().all().call().iterator();
 		assertTrue(log.hasNext());
 		RevCommit commit = log.next();
-		tag = db.peel(tag);
+		tag = db.getRefDatabase().peel(tag);
 
 		assertEquals(commit.getName(), tag.getPeeledObjectId().getName());
 		assertTrue(commits.contains(commit));
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/MergeCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/MergeCommandTest.java
index 4b23349..9af003d 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/MergeCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/MergeCommandTest.java
@@ -54,6 +54,7 @@
 
 import java.io.File;
 import java.util.Iterator;
+import java.util.regex.Pattern;
 
 import org.eclipse.jgit.api.MergeCommand.FastForwardMode;
 import org.eclipse.jgit.api.MergeResult.MergeStatus;
@@ -1584,27 +1585,31 @@ public void testRecursiveMergeWithConflict() throws Exception {
 		assertEquals(MergeStatus.CONFLICTING, result.getMergeStatus());
 	}
 
+	private Ref prepareSuccessfulMerge(Git git) throws Exception {
+		writeTrashFile("a", "1\na\n3\n");
+		git.add().addFilepattern("a").call();
+		RevCommit initialCommit = git.commit().setMessage("initial").call();
+
+		createBranch(initialCommit, "refs/heads/side");
+		checkoutBranch("refs/heads/side");
+
+		writeTrashFile("b", "1\nb\n3\n");
+		git.add().addFilepattern("b").call();
+		git.commit().setMessage("side").call();
+
+		checkoutBranch("refs/heads/master");
+
+		writeTrashFile("c", "1\nc\n3\n");
+		git.add().addFilepattern("c").call();
+		git.commit().setMessage("main").call();
+
+		return db.exactRef("refs/heads/side");
+	}
+
 	@Test
 	public void testMergeWithMessageOption() throws Exception {
 		try (Git git = new Git(db)) {
-			writeTrashFile("a", "1\na\n3\n");
-			git.add().addFilepattern("a").call();
-			RevCommit initialCommit = git.commit().setMessage("initial").call();
-
-			createBranch(initialCommit, "refs/heads/side");
-			checkoutBranch("refs/heads/side");
-
-			writeTrashFile("b", "1\nb\n3\n");
-			git.add().addFilepattern("b").call();
-			git.commit().setMessage("side").call();
-
-			checkoutBranch("refs/heads/master");
-
-			writeTrashFile("c", "1\nc\n3\n");
-			git.add().addFilepattern("c").call();
-			git.commit().setMessage("main").call();
-
-			Ref sideBranch = db.exactRef("refs/heads/side");
+			Ref sideBranch = prepareSuccessfulMerge(git);
 
 			git.merge().include(sideBranch).setStrategy(MergeStrategy.RESOLVE)
 					.setMessage("user message").call();
@@ -1618,6 +1623,43 @@ public void testMergeWithMessageOption() throws Exception {
 	}
 
 	@Test
+	public void testMergeWithChangeId() throws Exception {
+		try (Git git = new Git(db)) {
+			Ref sideBranch = prepareSuccessfulMerge(git);
+
+			git.merge().include(sideBranch).setStrategy(MergeStrategy.RESOLVE)
+					.setInsertChangeId(true).call();
+
+			assertNull(db.readMergeCommitMsg());
+
+			Iterator<RevCommit> it = git.log().call().iterator();
+			RevCommit newHead = it.next();
+			String commitMessage = newHead.getFullMessage();
+			assertTrue(Pattern.compile("\nChange-Id: I[0-9a-fA-F]{40}\n")
+					.matcher(commitMessage).find());
+		}
+	}
+
+	@Test
+	public void testMergeWithMessageAndChangeId() throws Exception {
+		try (Git git = new Git(db)) {
+			Ref sideBranch = prepareSuccessfulMerge(git);
+
+			git.merge().include(sideBranch).setStrategy(MergeStrategy.RESOLVE)
+					.setMessage("user message").setInsertChangeId(true).call();
+
+			assertNull(db.readMergeCommitMsg());
+
+			Iterator<RevCommit> it = git.log().call().iterator();
+			RevCommit newHead = it.next();
+			String commitMessage = newHead.getFullMessage();
+			assertTrue(commitMessage.startsWith("user message\n\n"));
+			assertTrue(Pattern.compile("\nChange-Id: I[0-9a-fA-F]{40}\n")
+					.matcher(commitMessage).find());
+		}
+	}
+
+	@Test
 	public void testMergeConflictWithMessageOption() throws Exception {
 		try (Git git = new Git(db)) {
 			writeTrashFile("a", "1\na\n3\n");
@@ -1657,7 +1699,7 @@ private static boolean canExecute(Git git, String path) {
 				.getWorkTree(), path));
 	}
 
-	private static RevCommit addAllAndCommit(final Git git) throws Exception {
+	private static RevCommit addAllAndCommit(Git git) throws Exception {
 		git.add().addFilepattern(".").call();
 		return git.commit().setMessage("message").call();
 	}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/NotesCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/NotesCommandTest.java
index 9d15699..e234aa3 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/NotesCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/NotesCommandTest.java
@@ -42,6 +42,7 @@
  */
 package org.eclipse.jgit.api;
 
+import static org.eclipse.jgit.lib.Constants.CHARSET;
 import static org.junit.Assert.assertEquals;
 
 import java.util.List;
@@ -87,7 +88,7 @@ public void testAddAndRemoveNote() throws Exception {
 		git.notesAdd().setObjectId(commit2).setMessage("data").call();
 		Note note = git.notesShow().setObjectId(commit2).call();
 		String content = new String(db.open(note.getData()).getCachedBytes(),
-				"UTF-8");
+				CHARSET);
 		assertEquals(content, "data");
 
 		git.notesRemove().setObjectId(commit2).call();
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/PullCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/PullCommandTest.java
index a341284..0b0e3bf 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/PullCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/PullCommandTest.java
@@ -42,6 +42,7 @@
  */
 package org.eclipse.jgit.api;
 
+import static org.eclipse.jgit.lib.Constants.CHARSET;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
@@ -590,34 +591,23 @@ public void setUp() throws Exception {
 
 	private static void writeToFile(File actFile, String string)
 			throws IOException {
-		FileOutputStream fos = null;
-		try {
-			fos = new FileOutputStream(actFile);
-			fos.write(string.getBytes("UTF-8"));
-			fos.close();
-		} finally {
-			if (fos != null)
-				fos.close();
+		try (FileOutputStream fos = new FileOutputStream(actFile)) {
+			fos.write(string.getBytes(CHARSET));
 		}
 	}
 
 	private static void assertFileContentsEqual(File actFile, String string)
 			throws IOException {
 		ByteArrayOutputStream bos = new ByteArrayOutputStream();
-		FileInputStream fis = null;
 		byte[] buffer = new byte[100];
-		try {
-			fis = new FileInputStream(actFile);
+		try (FileInputStream fis = new FileInputStream(actFile)) {
 			int read = fis.read(buffer);
 			while (read > 0) {
 				bos.write(buffer, 0, read);
 				read = fis.read(buffer);
 			}
-			String content = new String(bos.toByteArray(), "UTF-8");
+			String content = new String(bos.toByteArray(), CHARSET);
 			assertEquals(string, content);
-		} finally {
-			if (fis != null)
-				fis.close();
 		}
 	}
 }
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/PullCommandWithRebaseTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/PullCommandWithRebaseTest.java
index 6f6b115..b349c66 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/PullCommandWithRebaseTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/PullCommandWithRebaseTest.java
@@ -42,6 +42,7 @@
  */
 package org.eclipse.jgit.api;
 
+import static org.eclipse.jgit.lib.Constants.CHARSET;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
@@ -394,34 +395,23 @@ public void setUp() throws Exception {
 
 	private static void writeToFile(File actFile, String string)
 			throws IOException {
-		FileOutputStream fos = null;
-		try {
-			fos = new FileOutputStream(actFile);
-			fos.write(string.getBytes("UTF-8"));
-			fos.close();
-		} finally {
-			if (fos != null)
-				fos.close();
+		try (FileOutputStream fos = new FileOutputStream(actFile)) {
+			fos.write(string.getBytes(CHARSET));
 		}
 	}
 
 	private static void assertFileContentsEqual(File actFile, String string)
 			throws IOException {
 		ByteArrayOutputStream bos = new ByteArrayOutputStream();
-		FileInputStream fis = null;
 		byte[] buffer = new byte[100];
-		try {
-			fis = new FileInputStream(actFile);
+		try (FileInputStream fis = new FileInputStream(actFile)) {
 			int read = fis.read(buffer);
 			while (read > 0) {
 				bos.write(buffer, 0, read);
 				read = fis.read(buffer);
 			}
-			String content = new String(bos.toByteArray(), "UTF-8");
+			String content = new String(bos.toByteArray(), CHARSET);
 			assertEquals(string, content);
-		} finally {
-			if (fis != null)
-				fis.close();
 		}
 	}
 }
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/PushCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/PushCommandTest.java
index e0c1499..1af37e2 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/PushCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/PushCommandTest.java
@@ -152,7 +152,7 @@ public void testPrePushHook() throws JGitInternalException, IOException,
 		}
 	}
 
-	private File writeHookFile(final String name, final String data)
+	private File writeHookFile(String name, String data)
 			throws IOException {
 		File path = new File(db.getWorkTree() + "/.git/hooks/", name);
 		JGitTestUtil.write(path, data);
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RebaseCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RebaseCommandTest.java
index 0cc0816..96e7091 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RebaseCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RebaseCommandTest.java
@@ -42,6 +42,7 @@
  */
 package org.eclipse.jgit.api;
 
+import static org.eclipse.jgit.lib.Constants.CHARSET;
 import static org.hamcrest.CoreMatchers.equalTo;
 import static org.hamcrest.CoreMatchers.not;
 import static org.hamcrest.MatcherAssert.assertThat;
@@ -1463,7 +1464,7 @@ public void testAuthorScriptConverter() throws Exception {
 		assertEquals("GIT_AUTHOR_DATE='@123456789 -0100'", lines[2]);
 
 		PersonIdent parsedIdent = git.rebase().parseAuthor(
-				convertedAuthor.getBytes("UTF-8"));
+				convertedAuthor.getBytes(CHARSET));
 		assertEquals(ident.getName(), parsedIdent.getName());
 		assertEquals(ident.getEmailAddress(), parsedIdent.getEmailAddress());
 		// this is rounded to the last second
@@ -1480,7 +1481,7 @@ public void testAuthorScriptConverter() throws Exception {
 		assertEquals("GIT_AUTHOR_DATE='@123456789 +0930'", lines[2]);
 
 		parsedIdent = git.rebase().parseAuthor(
-				convertedAuthor.getBytes("UTF-8"));
+				convertedAuthor.getBytes(CHARSET));
 		assertEquals(ident.getName(), parsedIdent.getName());
 		assertEquals(ident.getEmailAddress(), parsedIdent.getEmailAddress());
 		assertEquals(123456789000L, parsedIdent.getWhen().getTime());
@@ -2102,9 +2103,8 @@ private List<DiffEntry> diffWorkingAgainstHead(final RevCommit commit,
 	private int countPicks() throws IOException {
 		int count = 0;
 		File todoFile = getTodoFile();
-		BufferedReader br = new BufferedReader(new InputStreamReader(
-				new FileInputStream(todoFile), "UTF-8"));
-		try {
+		try (BufferedReader br = new BufferedReader(new InputStreamReader(
+				new FileInputStream(todoFile), CHARSET))) {
 			String line = br.readLine();
 			while (line != null) {
 				int firstBlank = line.indexOf(' ');
@@ -2122,8 +2122,6 @@ private int countPicks() throws IOException {
 				line = br.readLine();
 			}
 			return count;
-		} finally {
-			br.close();
 		}
 	}
 
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/ResetCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/ResetCommandTest.java
index ba51881..8f56a92 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/ResetCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/ResetCommandTest.java
@@ -100,39 +100,39 @@ public void setupRepository() throws IOException, JGitInternalException,
 		File nestedFile = new File(dir, "b.txt");
 		FileUtils.createNewFile(nestedFile);
 
-		PrintWriter nesterFileWriter = new PrintWriter(nestedFile);
-		nesterFileWriter.print("content");
-		nesterFileWriter.flush();
+		try (PrintWriter nestedFileWriter = new PrintWriter(nestedFile)) {
+			nestedFileWriter.print("content");
+			nestedFileWriter.flush();
 
-		// create file
-		indexFile = new File(db.getWorkTree(), "a.txt");
-		FileUtils.createNewFile(indexFile);
-		PrintWriter writer = new PrintWriter(indexFile);
-		writer.print("content");
-		writer.flush();
+			// create file
+			indexFile = new File(db.getWorkTree(), "a.txt");
+			FileUtils.createNewFile(indexFile);
+			try (PrintWriter writer = new PrintWriter(indexFile)) {
+				writer.print("content");
+				writer.flush();
 
-		// add file and commit it
-		git.add().addFilepattern("dir").addFilepattern("a.txt").call();
-		secondCommit = git.commit().setMessage("adding a.txt and dir/b.txt")
-				.call();
+				// add file and commit it
+				git.add().addFilepattern("dir").addFilepattern("a.txt").call();
+				secondCommit = git.commit()
+						.setMessage("adding a.txt and dir/b.txt").call();
 
-		prestage = DirCache.read(db.getIndexFile(), db.getFS()).getEntry(
-				indexFile.getName());
+				prestage = DirCache.read(db.getIndexFile(), db.getFS())
+						.getEntry(indexFile.getName());
 
-		// modify file and add to index
-		writer.print("new content");
-		writer.close();
-		nesterFileWriter.print("new content");
-		nesterFileWriter.close();
+				// modify file and add to index
+				writer.print("new content");
+			}
+			nestedFileWriter.print("new content");
+		}
 		git.add().addFilepattern("a.txt").addFilepattern("dir").call();
 
 		// create a file not added to the index
 		untrackedFile = new File(db.getWorkTree(),
 				"notAddedToIndex.txt");
 		FileUtils.createNewFile(untrackedFile);
-		PrintWriter writer2 = new PrintWriter(untrackedFile);
-		writer2.print("content");
-		writer2.close();
+		try (PrintWriter writer2 = new PrintWriter(untrackedFile)) {
+			writer2.print("content");
+		}
 	}
 
 	@Test
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RevertCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RevertCommandTest.java
index ea63104..d77c4e1 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RevertCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RevertCommandTest.java
@@ -379,7 +379,7 @@ public void testRevertOurCommitName() throws Exception {
 		}
 	}
 
-	private RevCommit prepareRevert(final Git git) throws Exception {
+	private RevCommit prepareRevert(Git git) throws Exception {
 		// create, add and commit file a
 		writeTrashFile("a", "a");
 		git.add().addFilepattern("a").call();
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/StashCreateCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/StashCreateCommandTest.java
index b9f9f5b..3b582d7 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/StashCreateCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/StashCreateCommandTest.java
@@ -94,7 +94,7 @@ public void setUp() throws Exception {
 		untrackedFile = writeTrashFile("untracked.txt", "content");
 	}
 
-	private void validateStashedCommit(final RevCommit commit)
+	private void validateStashedCommit(RevCommit commit)
 			throws IOException {
 		validateStashedCommit(commit, 2);
 	}
@@ -140,7 +140,7 @@ private TreeWalk createTreeWalk() {
 		return walk;
 	}
 
-	private List<DiffEntry> diffWorkingAgainstHead(final RevCommit commit)
+	private List<DiffEntry> diffWorkingAgainstHead(RevCommit commit)
 			throws IOException {
 		try (TreeWalk walk = createTreeWalk()) {
 			walk.addTree(commit.getParent(0).getTree());
@@ -149,7 +149,7 @@ private List<DiffEntry> diffWorkingAgainstHead(final RevCommit commit)
 		}
 	}
 
-	private List<DiffEntry> diffIndexAgainstHead(final RevCommit commit)
+	private List<DiffEntry> diffIndexAgainstHead(RevCommit commit)
 			throws IOException {
 		try (TreeWalk walk = createTreeWalk()) {
 			walk.addTree(commit.getParent(0).getTree());
@@ -158,7 +158,7 @@ private List<DiffEntry> diffIndexAgainstHead(final RevCommit commit)
 		}
 	}
 
-	private List<DiffEntry> diffIndexAgainstWorking(final RevCommit commit)
+	private List<DiffEntry> diffIndexAgainstWorking(RevCommit commit)
 			throws IOException {
 		try (TreeWalk walk = createTreeWalk()) {
 			walk.addTree(commit.getParent(1).getTree());
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/TagCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/TagCommandTest.java
index 87098b6..a220e77 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/TagCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/TagCommandTest.java
@@ -42,6 +42,7 @@
  */
 package org.eclipse.jgit.api;
 
+import static org.eclipse.jgit.lib.Constants.R_TAGS;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.fail;
 
@@ -66,19 +67,22 @@ public void testTaggingOnHead() throws GitAPIException, IOException {
 				RevWalk walk = new RevWalk(db)) {
 			RevCommit commit = git.commit().setMessage("initial commit").call();
 			Ref tagRef = git.tag().setName("tag").call();
-			assertEquals(commit.getId(), db.peel(tagRef).getPeeledObjectId());
+			assertEquals(commit.getId(),
+					db.getRefDatabase().peel(tagRef).getPeeledObjectId());
 			assertEquals("tag", walk.parseTag(tagRef.getObjectId()).getTagName());
 		}
 	}
 
 	@Test
-	public void testTagging() throws GitAPIException, JGitInternalException {
+	public void testTagging()
+			throws GitAPIException, JGitInternalException, IOException {
 		try (Git git = new Git(db)) {
 			git.commit().setMessage("initial commit").call();
 			RevCommit commit = git.commit().setMessage("second commit").call();
 			git.commit().setMessage("third commit").call();
 			Ref tagRef = git.tag().setObjectId(commit).setName("tag").call();
-			assertEquals(commit.getId(), db.peel(tagRef).getPeeledObjectId());
+			assertEquals(commit.getId(),
+					db.getRefDatabase().peel(tagRef).getPeeledObjectId());
 		}
 	}
 
@@ -135,26 +139,30 @@ public void testFailureOnSignedTags() throws GitAPIException {
 		}
 	}
 
+	private List<Ref> getTags() throws Exception {
+		return db.getRefDatabase().getRefsByPrefix(R_TAGS);
+	}
+
 	@Test
 	public void testDelete() throws Exception {
 		try (Git git = new Git(db)) {
 			git.commit().setMessage("initial commit").call();
 			Ref tagRef = git.tag().setName("tag").call();
-			assertEquals(1, db.getTags().size());
+			assertEquals(1, getTags().size());
 
 			List<String> deleted = git.tagDelete().setTags(tagRef.getName())
 					.call();
 			assertEquals(1, deleted.size());
 			assertEquals(tagRef.getName(), deleted.get(0));
-			assertEquals(0, db.getTags().size());
+			assertEquals(0, getTags().size());
 
 			Ref tagRef1 = git.tag().setName("tag1").call();
 			Ref tagRef2 = git.tag().setName("tag2").call();
-			assertEquals(2, db.getTags().size());
+			assertEquals(2, getTags().size());
 			deleted = git.tagDelete().setTags(tagRef1.getName(), tagRef2.getName())
 					.call();
 			assertEquals(2, deleted.size());
-			assertEquals(0, db.getTags().size());
+			assertEquals(0, getTags().size());
 		}
 	}
 
@@ -163,13 +171,13 @@ public void testDeleteFullName() throws Exception {
 		try (Git git = new Git(db)) {
 			git.commit().setMessage("initial commit").call();
 			Ref tagRef = git.tag().setName("tag").call();
-			assertEquals(1, db.getTags().size());
+			assertEquals(1, getTags().size());
 
 			List<String> deleted = git.tagDelete()
 					.setTags(Repository.shortenRefName(tagRef.getName())).call();
 			assertEquals(1, deleted.size());
 			assertEquals(tagRef.getName(), deleted.get(0));
-			assertEquals(0, db.getTags().size());
+			assertEquals(0, getTags().size());
 		}
 	}
 
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributesMatcherTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributesMatcherTest.java
index 72cc1d1..196c4f7 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributesMatcherTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributesMatcherTest.java
@@ -424,7 +424,7 @@ public void testBracketsInGroup() {
 	 * @param target
 	 *            Target file path relative to repository's GIT_DIR
 	 */
-	public void assertMatched(String pattern, String target) {
+	private void assertMatched(String pattern, String target) {
 		boolean value = match(pattern, target);
 		assertTrue("Expected a match for: " + pattern + " with: " + target,
 				value);
@@ -439,7 +439,7 @@ public void assertMatched(String pattern, String target) {
 	 * @param target
 	 *            Target file path relative to repository's GIT_DIR
 	 */
-	public void assertNotMatched(String pattern, String target) {
+	private void assertNotMatched(String pattern, String target) {
 		boolean value = match(pattern, target);
 		assertFalse("Expected no match for: " + pattern + " with: " + target,
 				value);
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/CGitAttributesTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/CGitAttributesTest.java
index 3483813..344d1af 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/CGitAttributesTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/CGitAttributesTest.java
@@ -366,6 +366,34 @@ public void testDirectoryMatchSubRecursiveBacktrack6() throws Exception {
 	}
 
 	@Test
+	public void testDirectoryWildmatchDoesNotMatchFiles1() throws Exception {
+		createFiles("a", "dir/b", "dir/sub/c");
+		writeTrashFile(".gitattributes", "**/ bar\n");
+		assertSameAsCGit();
+	}
+
+	@Test
+	public void testDirectoryWildmatchDoesNotMatchFiles2() throws Exception {
+		createFiles("a", "dir/b", "dir/sub/c");
+		writeTrashFile(".gitattributes", "**/**/ bar\n");
+		assertSameAsCGit();
+	}
+
+	@Test
+	public void testDirectoryWildmatchDoesNotMatchFiles3() throws Exception {
+		createFiles("a", "x/b", "sub/x/c", "sub/x/d/e");
+		writeTrashFile(".gitattributes", "x/**/ bar\n");
+		assertSameAsCGit();
+	}
+
+	@Test
+	public void testDirectoryWildmatchDoesNotMatchFiles4() throws Exception {
+		createFiles("a", "dir/x", "dir/sub1/x", "dir/sub2/x/y");
+		writeTrashFile(".gitattributes", "x/**/ bar\n");
+		assertSameAsCGit();
+	}
+
+	@Test
 	public void testDirectoryMatchSubComplex() throws Exception {
 		createFiles("src/new/foo.txt", "foo/src/new/foo.txt", "sub/src/new");
 		writeTrashFile(".gitattributes", "s[rs]c/n*/ bar\n");
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/merge/MergeGitAttributeTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/merge/MergeGitAttributeTest.java
index a4f3d18..01ca888 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/merge/MergeGitAttributeTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/merge/MergeGitAttributeTest.java
@@ -313,7 +313,6 @@ public void mergeBinaryFile_NoAttr_Conflict() throws IllegalStateException,
 			WrongRepositoryStateException, NoMessageException, GitAPIException {
 
 		RevCommit disableCheckedCommit;
-		FileInputStream mergeResultFile = null;
 		// Set up a git with conflict commits on images
 		try (Git git = new Git(db)) {
 			// First commit
@@ -352,15 +351,12 @@ public void mergeBinaryFile_NoAttr_Conflict() throws IllegalStateException,
 			assertEquals(MergeStatus.CONFLICTING, mergeResult.getMergeStatus());
 
 			// Check that the image was not modified (no conflict marker added)
-			mergeResultFile = new FileInputStream(
+			try (FileInputStream mergeResultFile = new FileInputStream(
 					db.getWorkTree().toPath().resolve(ENABLED_CHECKED_GIF)
-							.toFile());
-			assertTrue(contentEquals(
-					getClass().getResourceAsStream(ENABLED_CHECKED_GIF),
-					mergeResultFile));
-		} finally {
-			if (mergeResultFile != null) {
-				mergeResultFile.close();
+							.toFile())) {
+				assertTrue(contentEquals(
+						getClass().getResourceAsStream(ENABLED_CHECKED_GIF),
+						mergeResultFile));
 			}
 		}
 	}
@@ -373,7 +369,6 @@ public void mergeBinaryFile_UnsetMerge_Conflict()
 			WrongRepositoryStateException, NoMessageException, GitAPIException {
 
 		RevCommit disableCheckedCommit;
-		FileInputStream mergeResultFile = null;
 		// Set up a git whith conflict commits on images
 		try (Git git = new Git(db)) {
 			// First commit
@@ -412,14 +407,12 @@ public void mergeBinaryFile_UnsetMerge_Conflict()
 			assertEquals(MergeStatus.CONFLICTING, mergeResult.getMergeStatus());
 
 			// Check that the image was not modified (not conflict marker added)
-			mergeResultFile = new FileInputStream(db.getWorkTree().toPath()
-					.resolve(ENABLED_CHECKED_GIF).toFile());
-			assertTrue(contentEquals(
-					getClass().getResourceAsStream(ENABLED_CHECKED_GIF),
-					mergeResultFile));
-		} finally {
-			if (mergeResultFile != null) {
-				mergeResultFile.close();
+			try (FileInputStream mergeResultFile = new FileInputStream(
+					db.getWorkTree().toPath().resolve(ENABLED_CHECKED_GIF)
+							.toFile())) {
+				assertTrue(contentEquals(
+						getClass().getResourceAsStream(ENABLED_CHECKED_GIF),
+						mergeResultFile));
 			}
 		}
 	}
@@ -432,7 +425,6 @@ public void mergeBinaryFile_SetMerge_Conflict()
 			NoMessageException, GitAPIException {
 
 		RevCommit disableCheckedCommit;
-		FileInputStream mergeResultFile = null;
 		// Set up a git whith conflict commits on images
 		try (Git git = new Git(db)) {
 			// First commit
@@ -471,14 +463,12 @@ public void mergeBinaryFile_SetMerge_Conflict()
 			assertEquals(MergeStatus.CONFLICTING, mergeResult.getMergeStatus());
 
 			// Check that the image was not modified (not conflict marker added)
-			mergeResultFile = new FileInputStream(db.getWorkTree().toPath()
-					.resolve(ENABLED_CHECKED_GIF).toFile());
-			assertFalse(contentEquals(
-					getClass().getResourceAsStream(ENABLED_CHECKED_GIF),
-					mergeResultFile));
-		} finally {
-			if (mergeResultFile != null) {
-				mergeResultFile.close();
+			try (FileInputStream mergeResultFile = new FileInputStream(
+					db.getWorkTree().toPath().resolve(ENABLED_CHECKED_GIF)
+							.toFile())) {
+				assertFalse(contentEquals(
+						getClass().getResourceAsStream(ENABLED_CHECKED_GIF),
+						mergeResultFile));
 			}
 		}
 	}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/AbstractDiffTestCase.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/AbstractDiffTestCase.java
index 4130b7e..32f3421 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/AbstractDiffTestCase.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/AbstractDiffTestCase.java
@@ -43,11 +43,10 @@
 
 package org.eclipse.jgit.diff;
 
+import static org.eclipse.jgit.lib.Constants.CHARSET;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 
-import java.io.UnsupportedEncodingException;
-
 import org.junit.Test;
 
 public abstract class AbstractDiffTestCase {
@@ -241,10 +240,6 @@ public static RawText t(String text) {
 			r.append(text.charAt(i));
 			r.append('\n');
 		}
-		try {
-			return new RawText(r.toString().getBytes("UTF-8"));
-		} catch (UnsupportedEncodingException e) {
-			throw new RuntimeException(e);
-		}
+		return new RawText(r.toString().getBytes(CHARSET));
 	}
 }
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/DiffFormatterReflowTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/DiffFormatterReflowTest.java
index 31f70cf..0e344f5 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/DiffFormatterReflowTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/DiffFormatterReflowTest.java
@@ -146,7 +146,7 @@ public void testNoNewLine2() throws IOException {
 		assertFormatted("Z.patch");
 	}
 
-	private void init(final String name) throws IOException {
+	private void init(String name) throws IOException {
 		a = new RawText(readFile(name + "_PreImage"));
 		b = new RawText(readFile(name + "_PostImage"));
 		file = parseTestPatchFile(name + ".patch").getFiles().get(0);
@@ -156,13 +156,13 @@ private void assertFormatted() throws IOException {
 		assertFormatted(JGitTestUtil.getName() + ".out");
 	}
 
-	private void assertFormatted(final String name) throws IOException {
+	private void assertFormatted(String name) throws IOException {
 		fmt.format(file, a, b);
 		final String exp = RawParseUtils.decode(readFile(name));
 		assertEquals(exp, RawParseUtils.decode(out.toByteArray()));
 	}
 
-	private byte[] readFile(final String patchFile) throws IOException {
+	private byte[] readFile(String patchFile) throws IOException {
 		final InputStream in = getClass().getResourceAsStream(patchFile);
 		if (in == null) {
 			fail("No " + patchFile + " test vector");
@@ -180,18 +180,15 @@ private void assertFormatted(final String name) throws IOException {
 		}
 	}
 
-	private Patch parseTestPatchFile(final String patchFile) throws IOException {
-		final InputStream in = getClass().getResourceAsStream(patchFile);
-		if (in == null) {
-			fail("No " + patchFile + " test vector");
-			return null; // Never happens
-		}
-		try {
+	private Patch parseTestPatchFile(String patchFile) throws IOException {
+		try (InputStream in = getClass().getResourceAsStream(patchFile)) {
+			if (in == null) {
+				fail("No " + patchFile + " test vector");
+				return null; // Never happens
+			}
 			final Patch p = new Patch();
 			p.parse(in);
 			return p;
-		} finally {
-			in.close();
 		}
 	}
 }
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/DiffFormatterTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/DiffFormatterTest.java
index fabf034..45832f4 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/DiffFormatterTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/DiffFormatterTest.java
@@ -55,12 +55,14 @@
 import org.eclipse.jgit.junit.RepositoryTestCase;
 import org.eclipse.jgit.junit.TestRepository;
 import org.eclipse.jgit.lib.AnyObjectId;
+import org.eclipse.jgit.lib.ConfigConstants;
 import org.eclipse.jgit.lib.FileMode;
 import org.eclipse.jgit.lib.ObjectId;
 import org.eclipse.jgit.lib.Repository;
 import org.eclipse.jgit.patch.FileHeader;
 import org.eclipse.jgit.patch.HunkHeader;
 import org.eclipse.jgit.revwalk.RevCommit;
+import org.eclipse.jgit.storage.file.FileBasedConfig;
 import org.eclipse.jgit.treewalk.FileTreeIterator;
 import org.eclipse.jgit.treewalk.filter.PathFilter;
 import org.eclipse.jgit.util.FileUtils;
@@ -485,6 +487,102 @@ public void testDiffNullToNull() throws Exception {
 		}
 	}
 
+	@Test
+	public void testDiffAutoCrlfSmallFile() throws Exception {
+		String content = "01234\r\n01234\r\n01234\r\n";
+		String expectedDiff = "diff --git a/test.txt b/test.txt\n"
+				+ "index fe25983..a44a032 100644\n" //
+				+ "--- a/test.txt\n" //
+				+ "+++ b/test.txt\n" //
+				+ "@@ -1,3 +1,4 @@\n" //
+				+ " 01234\n" //
+				+ "+ABCD\n" //
+				+ " 01234\n" //
+				+ " 01234\n";
+		doAutoCrLfTest(content, expectedDiff);
+	}
+
+	@Test
+	public void testDiffAutoCrlfMediumFile() throws Exception {
+		String content = mediumCrLfString();
+		String expectedDiff = "diff --git a/test.txt b/test.txt\n"
+				+ "index 215c502..c10f08c 100644\n" //
+				+ "--- a/test.txt\n" //
+				+ "+++ b/test.txt\n" //
+				+ "@@ -1,4 +1,5 @@\n" //
+				+ " 01234567\n" //
+				+ "+ABCD\n" //
+				+ " 01234567\n" //
+				+ " 01234567\n" //
+				+ " 01234567\n";
+		doAutoCrLfTest(content, expectedDiff);
+	}
+
+	@Test
+	public void testDiffAutoCrlfLargeFile() throws Exception {
+		String content = largeCrLfString();
+		String expectedDiff = "diff --git a/test.txt b/test.txt\n"
+				+ "index 7014942..c0487a7 100644\n" //
+				+ "--- a/test.txt\n" //
+				+ "+++ b/test.txt\n" //
+				+ "@@ -1,4 +1,5 @@\n"
+				+ " 012345678901234567890123456789012345678901234567\n"
+				+ "+ABCD\n"
+				+ " 012345678901234567890123456789012345678901234567\n"
+				+ " 012345678901234567890123456789012345678901234567\n"
+				+ " 012345678901234567890123456789012345678901234567\n";
+		doAutoCrLfTest(content, expectedDiff);
+	}
+
+	private void doAutoCrLfTest(String content, String expectedDiff)
+			throws Exception {
+		FileBasedConfig config = db.getConfig();
+		config.setString(ConfigConstants.CONFIG_CORE_SECTION, null,
+				ConfigConstants.CONFIG_KEY_AUTOCRLF, "true");
+		config.save();
+		commitFile("test.txt", content, "master");
+		// Insert a line into content
+		int i = content.indexOf('\n');
+		content = content.substring(0, i + 1) + "ABCD\r\n"
+				+ content.substring(i + 1);
+		writeTrashFile("test.txt", content);
+		// Create the patch
+		try (ByteArrayOutputStream os = new ByteArrayOutputStream();
+				DiffFormatter dfmt = new DiffFormatter(
+						new BufferedOutputStream(os))) {
+			dfmt.setRepository(db);
+			dfmt.format(new DirCacheIterator(db.readDirCache()),
+					new FileTreeIterator(db));
+			dfmt.flush();
+
+			String actual = os.toString("UTF-8");
+
+			assertEquals(expectedDiff, actual);
+		}
+	}
+
+	private static String largeCrLfString() {
+		String line = "012345678901234567890123456789012345678901234567\r\n";
+		StringBuilder builder = new StringBuilder(
+				2 * RawText.FIRST_FEW_BYTES);
+		while (builder.length() < 2 * RawText.FIRST_FEW_BYTES) {
+			builder.append(line);
+		}
+		return builder.toString();
+	}
+
+	private static String mediumCrLfString() {
+		// Create a CR-LF string longer than RawText.FIRST_FEW_BYTES whose
+		// canonical representation is shorter than RawText.FIRST_FEW_BYTES.
+		String line = "01234567\r\n"; // 10 characters
+		StringBuilder builder = new StringBuilder(
+				RawText.FIRST_FEW_BYTES + line.length());
+		while (builder.length() <= RawText.FIRST_FEW_BYTES) {
+			builder.append(line);
+		}
+		return builder.toString();
+	}
+
 	private static String makeDiffHeader(String pathA, String pathB,
 			ObjectId aId,
 			ObjectId bId) {
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/EditListTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/EditListTest.java
index d6a5dcd..70447c7 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/EditListTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/EditListTest.java
@@ -53,6 +53,7 @@
 import org.junit.Test;
 
 public class EditListTest {
+	@SuppressWarnings("unlikely-arg-type")
 	@Test
 	public void testEmpty() {
 		final EditList l = new EditList();
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/EditTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/EditTest.java
index 1a0c39e..c621a7f 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/EditTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/EditTest.java
@@ -125,6 +125,7 @@ public void testToString() {
 		assertEquals("REPLACE(1-2,1-4)", e.toString());
 	}
 
+	@SuppressWarnings("unlikely-arg-type")
 	@Test
 	public void testEquals1() {
 		final Edit e1 = new Edit(1, 2, 3, 4);
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/RawTextLoadTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/RawTextLoadTest.java
new file mode 100644
index 0000000..a11402f
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/RawTextLoadTest.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2017, Google Inc.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ *   copyright notice, this list of conditions and the following
+ *   disclaimer in the documentation and/or other materials provided
+ *   with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ *   names of its contributors may be used to endorse or promote
+ *   products derived from this software without specific prior
+ *   written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.eclipse.jgit.diff;
+
+import org.eclipse.jgit.errors.BinaryBlobException;
+import org.eclipse.jgit.internal.storage.file.FileRepository;
+import org.eclipse.jgit.junit.RepositoryTestCase;
+import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.ObjectInserter;
+import org.eclipse.jgit.lib.ObjectLoader;
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.io.IOException;
+
+public class RawTextLoadTest extends RepositoryTestCase {
+	private static byte[] generate(int size, int nullAt) {
+		byte[] data = new byte[size];
+		for (int i = 0; i < data.length; i++) {
+			data[i] = (byte) ((i % 72 == 0) ? '\n' : (i%10) + '0');
+		}
+		if (nullAt >= 0) {
+			data[nullAt] = '\0';
+		}
+		return data;
+	}
+
+	private RawText textFor(byte[] data, int limit) throws IOException, BinaryBlobException {
+		FileRepository repo = createBareRepository();
+		ObjectId id;
+		try (ObjectInserter ins = repo.getObjectDatabase().newInserter()) {
+			id = ins.insert(Constants.OBJ_BLOB, data);
+		}
+		ObjectLoader ldr = repo.open(id);
+		return RawText.load(ldr, limit);
+	}
+
+	@Test
+	public void testSmallOK() throws Exception {
+		byte[] data = generate(1000, -1);
+		RawText result = textFor(data, 1 << 20);
+		Assert.assertArrayEquals(result.content, data);
+	}
+
+	@Test(expected = BinaryBlobException.class)
+	public void testSmallNull() throws Exception {
+		byte[] data = generate(1000, 22);
+		textFor(data, 1 << 20);
+	}
+
+	@Test
+	public void testBigOK() throws Exception {
+		byte[] data = generate(10000, -1);
+		RawText result = textFor(data, 1 << 20);
+		Assert.assertArrayEquals(result.content, data);
+	}
+
+	@Test(expected = BinaryBlobException.class)
+	public void testBigWithNullAtStart() throws Exception {
+		byte[] data = generate(10000, 22);
+		textFor(data, 1 << 20);
+	}
+
+	@Test(expected = BinaryBlobException.class)
+	public void testBinaryThreshold() throws Exception {
+		byte[] data = generate(2 << 20, -1);
+		textFor(data, 1 << 20);
+	}
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/RawTextTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/RawTextTest.java
index 93ea9a7..58a8b2d 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/RawTextTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/RawTextTest.java
@@ -44,6 +44,8 @@
 
 package org.eclipse.jgit.diff;
 
+import static org.eclipse.jgit.lib.Constants.CHARSET;
+import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNull;
@@ -51,7 +53,6 @@
 
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
-import java.io.UnsupportedEncodingException;
 
 import org.eclipse.jgit.lib.Constants;
 import org.eclipse.jgit.util.RawParseUtils;
@@ -65,6 +66,16 @@ public void testEmpty() {
 	}
 
 	@Test
+	public void testBinary() {
+		String input = "foo-a\nf\0o-b\n";
+		byte[] data = Constants.encodeASCII(input);
+		final RawText a = new RawText(data);
+		assertArrayEquals(a.content, data);
+		assertEquals(a.size(), 1);
+		assertEquals(a.getString(0, 1, false), input);
+	}
+
+	@Test
 	public void testEquals() {
 		final RawText a = new RawText(Constants.encodeASCII("foo-a\nfoo-b\n"));
 		final RawText b = new RawText(Constants.encodeASCII("foo-b\nfoo-c\n"));
@@ -110,8 +121,7 @@ public void testWriteLine3() throws IOException {
 	}
 
 	@Test
-	public void testComparatorReduceCommonStartEnd()
-			throws UnsupportedEncodingException {
+	public void testComparatorReduceCommonStartEnd() {
 		final RawTextComparator c = RawTextComparator.DEFAULT;
 		Edit e;
 
@@ -137,54 +147,51 @@ public void testComparatorReduceCommonStartEnd()
 		e = c.reduceCommonStartEnd(t("abQxy"), t("abRxy"), e);
 		assertEquals(new Edit(2, 3, 2, 3), e);
 
-		RawText a = new RawText("p\na b\nQ\nc d\n".getBytes("UTF-8"));
-		RawText b = new RawText("p\na  b \nR\n c  d \n".getBytes("UTF-8"));
+		RawText a = new RawText("p\na b\nQ\nc d\n".getBytes(CHARSET));
+		RawText b = new RawText("p\na  b \nR\n c  d \n".getBytes(CHARSET));
 		e = new Edit(0, 4, 0, 4);
 		e = RawTextComparator.WS_IGNORE_ALL.reduceCommonStartEnd(a, b, e);
 		assertEquals(new Edit(2, 3, 2, 3), e);
 	}
 
 	@Test
-	public void testComparatorReduceCommonStartEnd_EmptyLine()
-			throws UnsupportedEncodingException {
+	public void testComparatorReduceCommonStartEnd_EmptyLine() {
 		RawText a;
 		RawText b;
 		Edit e;
 
-		a = new RawText("R\n y\n".getBytes("UTF-8"));
-		b = new RawText("S\n\n y\n".getBytes("UTF-8"));
+		a = new RawText("R\n y\n".getBytes(CHARSET));
+		b = new RawText("S\n\n y\n".getBytes(CHARSET));
 		e = new Edit(0, 2, 0, 3);
 		e = RawTextComparator.DEFAULT.reduceCommonStartEnd(a, b, e);
 		assertEquals(new Edit(0, 1, 0, 2), e);
 
-		a = new RawText("S\n\n y\n".getBytes("UTF-8"));
-		b = new RawText("R\n y\n".getBytes("UTF-8"));
+		a = new RawText("S\n\n y\n".getBytes(CHARSET));
+		b = new RawText("R\n y\n".getBytes(CHARSET));
 		e = new Edit(0, 3, 0, 2);
 		e = RawTextComparator.DEFAULT.reduceCommonStartEnd(a, b, e);
 		assertEquals(new Edit(0, 2, 0, 1), e);
 	}
 
 	@Test
-	public void testComparatorReduceCommonStartButLastLineNoEol()
-			throws UnsupportedEncodingException {
+	public void testComparatorReduceCommonStartButLastLineNoEol() {
 		RawText a;
 		RawText b;
 		Edit e;
-		a = new RawText("start".getBytes("UTF-8"));
-		b = new RawText("start of line".getBytes("UTF-8"));
+		a = new RawText("start".getBytes(CHARSET));
+		b = new RawText("start of line".getBytes(CHARSET));
 		e = new Edit(0, 1, 0, 1);
 		e = RawTextComparator.DEFAULT.reduceCommonStartEnd(a, b, e);
 		assertEquals(new Edit(0, 1, 0, 1), e);
 	}
 
 	@Test
-	public void testComparatorReduceCommonStartButLastLineNoEol_2()
-			throws UnsupportedEncodingException {
+	public void testComparatorReduceCommonStartButLastLineNoEol_2() {
 		RawText a;
 		RawText b;
 		Edit e;
-		a = new RawText("start".getBytes("UTF-8"));
-		b = new RawText("start of\nlastline".getBytes("UTF-8"));
+		a = new RawText("start".getBytes(CHARSET));
+		b = new RawText("start of\nlastline".getBytes(CHARSET));
 		e = new Edit(0, 1, 0, 2);
 		e = RawTextComparator.DEFAULT.reduceCommonStartEnd(a, b, e);
 		assertEquals(new Edit(0, 1, 0, 2), e);
@@ -243,10 +250,6 @@ private static RawText t(String text) {
 			r.append(text.charAt(i));
 			r.append('\n');
 		}
-		try {
-			return new RawText(r.toString().getBytes("UTF-8"));
-		} catch (UnsupportedEncodingException e) {
-			throw new RuntimeException(e);
-		}
+		return new RawText(r.toString().getBytes(CHARSET));
 	}
 }
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/SimilarityIndexTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/SimilarityIndexTest.java
index 4724677..51a6f81 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/SimilarityIndexTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/SimilarityIndexTest.java
@@ -43,6 +43,7 @@
 
 package org.eclipse.jgit.diff;
 
+import static org.eclipse.jgit.lib.Constants.CHARSET;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 
@@ -81,7 +82,7 @@ public void testIndexingLargeObject() throws IOException,
 				+ "A\n" //
 				+ "B\n" //
 				+ "B\n" //
-				+ "B\n").getBytes("UTF-8");
+				+ "B\n").getBytes(CHARSET);
 		SimilarityIndex si = new SimilarityIndex();
 		si.hash(new ByteArrayInputStream(in), in.length, false);
 		assertEquals(2, si.size());
@@ -129,12 +130,12 @@ public void testCommonScoreLargeObject_SameFiles_CR_canonicalization()
 				+ "D\r\n" //
 				+ "B\r\n";
 		SimilarityIndex src = new SimilarityIndex();
-		byte[] bytes1 = text.getBytes("UTF-8");
+		byte[] bytes1 = text.getBytes(CHARSET);
 		src.hash(new ByteArrayInputStream(bytes1), bytes1.length, true);
 		src.sort();
 
 		SimilarityIndex dst = new SimilarityIndex();
-		byte[] bytes2 = text.replace("\r", "").getBytes("UTF-8");
+		byte[] bytes2 = text.replace("\r", "").getBytes(CHARSET);
 		dst.hash(new ByteArrayInputStream(bytes2), bytes2.length, true);
 		dst.sort();
 
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheBuilderIteratorTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheBuilderIteratorTest.java
index 2b10887..3598f3a 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheBuilderIteratorTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheBuilderIteratorTest.java
@@ -78,7 +78,7 @@ public void testPathFilterGroup_DoesNotSkipTail() throws Exception {
 
 		final int expIdx = 2;
 		final DirCacheBuilder b = dc.builder();
-		try (final TreeWalk tw = new TreeWalk(db)) {
+		try (TreeWalk tw = new TreeWalk(db)) {
 			tw.addTree(new DirCacheBuildIterator(b));
 			tw.setRecursive(true);
 			tw.setFilter(PathFilterGroup.createFromStrings(Collections
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheCGitCompatabilityTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheCGitCompatabilityTest.java
index 92ce4e1..c362e74 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheCGitCompatabilityTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheCGitCompatabilityTest.java
@@ -43,6 +43,7 @@
 
 package org.eclipse.jgit.dircache;
 
+import static org.eclipse.jgit.lib.Constants.CHARSET;
 import static org.eclipse.jgit.junit.Assert.assertEquals;
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
@@ -98,7 +99,7 @@ public void testTreeWalk_LsFiles() throws Exception {
 		assertEquals(ls.size(), dc.getEntryCount());
 		{
 			final Iterator<CGitIndexRecord> rItr = ls.values().iterator();
-			try (final TreeWalk tw = new TreeWalk(db)) {
+			try (TreeWalk tw = new TreeWalk(db)) {
 				tw.setRecursive(true);
 				tw.addTree(new DirCacheIterator(dc));
 				while (rItr.hasNext()) {
@@ -179,7 +180,7 @@ public void testReadIndex_DirCacheTree() throws Exception {
 		assertEquals(cList.size(), jTree.getEntrySpan());
 
 		final ArrayList<CGitLsTreeRecord> subtrees = new ArrayList<>();
-		for (final CGitLsTreeRecord r : cTree.values()) {
+		for (CGitLsTreeRecord r : cTree.values()) {
 			if (FileMode.TREE.equals(r.mode))
 				subtrees.add(r);
 		}
@@ -228,38 +229,32 @@ private static void assertV3TreeEntry(int indexPosition, String path,
 		assertEquals(intentToAdd, entry.isIntentToAdd());
 	}
 
-	private static File pathOf(final String name) {
+	private static File pathOf(String name) {
 		return JGitTestUtil.getTestResourceFile(name);
 	}
 
 	private static Map<String, CGitIndexRecord> readLsFiles() throws Exception {
 		final LinkedHashMap<String, CGitIndexRecord> r = new LinkedHashMap<>();
-		final BufferedReader br = new BufferedReader(new InputStreamReader(
-				new FileInputStream(pathOf("gitgit.lsfiles")), "UTF-8"));
-		try {
+		try (BufferedReader br = new BufferedReader(new InputStreamReader(
+				new FileInputStream(pathOf("gitgit.lsfiles")), CHARSET))) {
 			String line;
 			while ((line = br.readLine()) != null) {
 				final CGitIndexRecord cr = new CGitIndexRecord(line);
 				r.put(cr.path, cr);
 			}
-		} finally {
-			br.close();
 		}
 		return r;
 	}
 
 	private static Map<String, CGitLsTreeRecord> readLsTree() throws Exception {
 		final LinkedHashMap<String, CGitLsTreeRecord> r = new LinkedHashMap<>();
-		final BufferedReader br = new BufferedReader(new InputStreamReader(
-				new FileInputStream(pathOf("gitgit.lstree")), "UTF-8"));
-		try {
+		try (BufferedReader br = new BufferedReader(new InputStreamReader(
+				new FileInputStream(pathOf("gitgit.lstree")), CHARSET))) {
 			String line;
 			while ((line = br.readLine()) != null) {
 				final CGitLsTreeRecord cr = new CGitLsTreeRecord(line);
 				r.put(cr.path, cr);
 			}
-		} finally {
-			br.close();
 		}
 		return r;
 	}
@@ -273,7 +268,7 @@ private static class CGitIndexRecord {
 
 		final String path;
 
-		CGitIndexRecord(final String line) {
+		CGitIndexRecord(String line) {
 			final int tab = line.indexOf('\t');
 			final int sp1 = line.indexOf(' ');
 			final int sp2 = line.indexOf(' ', sp1 + 1);
@@ -291,7 +286,7 @@ private static class CGitLsTreeRecord {
 
 		final String path;
 
-		CGitLsTreeRecord(final String line) {
+		CGitLsTreeRecord(String line) {
 			final int tab = line.indexOf('\t');
 			final int sp1 = line.indexOf(' ');
 			final int sp2 = line.indexOf(' ', sp1 + 1);
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheEntryTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheEntryTest.java
index 05fa007..86e2852 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheEntryTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheEntryTest.java
@@ -183,7 +183,7 @@ public void testCopyMetaDataWithoutStage() {
 		copyMetaDataHelper(true);
 	}
 
-	private static void copyMetaDataHelper(final boolean keepStage) {
+	private static void copyMetaDataHelper(boolean keepStage) {
 		DirCacheEntry e = new DirCacheEntry("some/path", DirCacheEntry.STAGE_2);
 		e.setAssumeValid(false);
 		e.setCreationTime(2L);
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheIteratorTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheIteratorTest.java
index dd242e5..82565fc 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheIteratorTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheIteratorTest.java
@@ -76,7 +76,7 @@ public void testEmptyTree_WithTreeWalk() throws Exception {
 		final DirCache dc = DirCache.newInCore();
 		assertEquals(0, dc.getEntryCount());
 
-		try (final TreeWalk tw = new TreeWalk(db)) {
+		try (TreeWalk tw = new TreeWalk(db)) {
 			tw.addTree(new DirCacheIterator(dc));
 			assertFalse(tw.next());
 		}
@@ -126,7 +126,7 @@ public void testNoSubtree_WithTreeWalk() throws Exception {
 		b.finish();
 
 		final DirCacheIterator i = new DirCacheIterator(dc);
-		try (final TreeWalk tw = new TreeWalk(db)) {
+		try (TreeWalk tw = new TreeWalk(db)) {
 			tw.addTree(i);
 			int pathIdx = 0;
 			while (tw.next()) {
@@ -164,7 +164,7 @@ public void testSingleSubtree_NoRecursion() throws Exception {
 		final int expPos[] = { 0, -1, 4 };
 
 		final DirCacheIterator i = new DirCacheIterator(dc);
-		try (final TreeWalk tw = new TreeWalk(db)) {
+		try (TreeWalk tw = new TreeWalk(db)) {
 			tw.addTree(i);
 			tw.setRecursive(false);
 			int pathIdx = 0;
@@ -205,7 +205,7 @@ public void testSingleSubtree_Recursive() throws Exception {
 		b.finish();
 
 		final DirCacheIterator i = new DirCacheIterator(dc);
-		try (final TreeWalk tw = new TreeWalk(db)) {
+		try (TreeWalk tw = new TreeWalk(db)) {
 			tw.addTree(i);
 			tw.setRecursive(true);
 			int pathIdx = 0;
@@ -240,7 +240,7 @@ public void testTwoLevelSubtree_Recursive() throws Exception {
 			b.add(ents[i]);
 		b.finish();
 
-		try (final TreeWalk tw = new TreeWalk(db)) {
+		try (TreeWalk tw = new TreeWalk(db)) {
 			tw.addTree(new DirCacheIterator(dc));
 			tw.setRecursive(true);
 			int pathIdx = 0;
@@ -402,7 +402,7 @@ public void testTwoLevelSubtree_FilterPath() throws Exception {
 			b.add(ents[i]);
 		b.finish();
 
-		try (final TreeWalk tw = new TreeWalk(db)) {
+		try (TreeWalk tw = new TreeWalk(db)) {
 			for (int victimIdx = 0; victimIdx < paths.length; victimIdx++) {
 				tw.reset();
 				tw.addTree(new DirCacheIterator(dc));
@@ -430,7 +430,7 @@ public void testRemovedSubtree() throws Exception {
 		final DirCache dc = DirCache.read(path, FS.DETECTED);
 		assertEquals(2, dc.getEntryCount());
 
-		try (final TreeWalk tw = new TreeWalk(db)) {
+		try (TreeWalk tw = new TreeWalk(db)) {
 			tw.setRecursive(true);
 			tw.addTree(new DirCacheIterator(dc));
 
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheLargePathTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheLargePathTest.java
index ef3e611..dfc136c 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheLargePathTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheLargePathTest.java
@@ -81,7 +81,7 @@ public void testPath_16384() throws Exception {
 		testLongPath(16384);
 	}
 
-	private void testLongPath(final int len) throws CorruptObjectException,
+	private void testLongPath(int len) throws CorruptObjectException,
 			IOException {
 		final String longPath = makeLongPath(len);
 		final String shortPath = "~~~ shorter-path";
@@ -119,7 +119,7 @@ private void testLongPath(final int len) throws CorruptObjectException,
 		}
 	}
 
-	private static String makeLongPath(final int len) {
+	private static String makeLongPath(int len) {
 		final StringBuilder r = new StringBuilder(len);
 		for (int i = 0; i < len; i++)
 			r.append('a' + (i % 26));
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/gitrepo/ManifestParserTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/gitrepo/ManifestParserTest.java
index c9673a6..69a48cc 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/gitrepo/ManifestParserTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/gitrepo/ManifestParserTest.java
@@ -42,7 +42,7 @@
  */
 package org.eclipse.jgit.gitrepo;
 
-import static java.nio.charset.StandardCharsets.UTF_8;
+import static org.eclipse.jgit.lib.Constants.CHARSET;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
@@ -82,7 +82,7 @@ public void testManifestParser() throws Exception {
 
 		ManifestParser parser = new ManifestParser(
 				null, null, "master", baseUrl, null, null);
-		parser.read(new ByteArrayInputStream(xmlContent.toString().getBytes(UTF_8)));
+		parser.read(new ByteArrayInputStream(xmlContent.toString().getBytes(CHARSET)));
 		// Unfiltered projects should have them all.
 		results.clear();
 		results.add("foo");
@@ -136,7 +136,7 @@ public void testManifestParserWithMissingFetchOnRemote() throws Exception {
 				baseUrl, null, null);
 		try {
 			parser.read(new ByteArrayInputStream(
-					xmlContent.toString().getBytes(UTF_8)));
+					xmlContent.toString().getBytes(CHARSET)));
 			fail("ManifestParser did not throw exception for missing fetch");
 		} catch (IOException e) {
 			assertTrue(e.getCause() instanceof SAXException);
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/gitrepo/RepoCommandSymlinkTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/gitrepo/RepoCommandSymlinkTest.java
index 341cc4f..548b903 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/gitrepo/RepoCommandSymlinkTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/gitrepo/RepoCommandSymlinkTest.java
@@ -119,45 +119,47 @@ public void testLinkFileBare() throws Exception {
 					.setURI(rootUri).call();
 			// Clone it
 			File directory = createTempDirectory("testCopyFileBare");
-			Repository localDb = Git.cloneRepository().setDirectory(directory)
+			try (Repository localDb = Git.cloneRepository()
+					.setDirectory(directory)
 					.setURI(remoteDb.getDirectory().toURI().toString()).call()
-					.getRepository();
+					.getRepository()) {
 
-			// The LinkedHello symlink should exist.
-			File linkedhello = new File(localDb.getWorkTree(), "LinkedHello");
-			assertTrue("The LinkedHello file should exist",
-					localDb.getFS().exists(linkedhello));
-			assertTrue("The LinkedHello file should be a symlink",
-					localDb.getFS().isSymLink(linkedhello));
-			assertEquals("foo/hello.txt",
-					localDb.getFS().readSymLink(linkedhello));
+				// The LinkedHello symlink should exist.
+				File linkedhello = new File(localDb.getWorkTree(),
+						"LinkedHello");
+				assertTrue("The LinkedHello file should exist",
+						localDb.getFS().exists(linkedhello));
+				assertTrue("The LinkedHello file should be a symlink",
+						localDb.getFS().isSymLink(linkedhello));
+				assertEquals("foo/hello.txt",
+						localDb.getFS().readSymLink(linkedhello));
 
-			// The foo/LinkedHello file should be skipped.
-			File linkedfoohello = new File(localDb.getWorkTree(), "foo/LinkedHello");
-			assertFalse("The foo/LinkedHello file should be skipped",
-					localDb.getFS().exists(linkedfoohello));
+				// The foo/LinkedHello file should be skipped.
+				File linkedfoohello = new File(localDb.getWorkTree(),
+						"foo/LinkedHello");
+				assertFalse("The foo/LinkedHello file should be skipped",
+						localDb.getFS().exists(linkedfoohello));
 
-			// The subdir/LinkedHello file should use a relative ../
-			File linkedsubdirhello = new File(localDb.getWorkTree(),
-					"subdir/LinkedHello");
-			assertTrue("The subdir/LinkedHello file should exist",
-					localDb.getFS().exists(linkedsubdirhello));
-			assertTrue("The subdir/LinkedHello file should be a symlink",
-					localDb.getFS().isSymLink(linkedsubdirhello));
-			assertEquals("../foo/hello.txt",
-					localDb.getFS().readSymLink(linkedsubdirhello));
+				// The subdir/LinkedHello file should use a relative ../
+				File linkedsubdirhello = new File(localDb.getWorkTree(),
+						"subdir/LinkedHello");
+				assertTrue("The subdir/LinkedHello file should exist",
+						localDb.getFS().exists(linkedsubdirhello));
+				assertTrue("The subdir/LinkedHello file should be a symlink",
+						localDb.getFS().isSymLink(linkedsubdirhello));
+				assertEquals("../foo/hello.txt",
+						localDb.getFS().readSymLink(linkedsubdirhello));
 
-			// The bar/foo/LinkedHello file should use a single relative ../
-			File linkedbarfoohello = new File(localDb.getWorkTree(),
-					"bar/foo/LinkedHello");
-			assertTrue("The bar/foo/LinkedHello file should exist",
-					localDb.getFS().exists(linkedbarfoohello));
-			assertTrue("The bar/foo/LinkedHello file should be a symlink",
-					localDb.getFS().isSymLink(linkedbarfoohello));
-			assertEquals("../baz/hello.txt",
-					localDb.getFS().readSymLink(linkedbarfoohello));
-
-			localDb.close();
+				// The bar/foo/LinkedHello file should use a single relative ../
+				File linkedbarfoohello = new File(localDb.getWorkTree(),
+						"bar/foo/LinkedHello");
+				assertTrue("The bar/foo/LinkedHello file should exist",
+						localDb.getFS().exists(linkedbarfoohello));
+				assertTrue("The bar/foo/LinkedHello file should be a symlink",
+						localDb.getFS().isSymLink(linkedbarfoohello));
+				assertEquals("../baz/hello.txt",
+						localDb.getFS().readSymLink(linkedbarfoohello));
+			}
 		}
 	}
 }
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/gitrepo/RepoCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/gitrepo/RepoCommandTest.java
index 6ed2c21..df31ab0 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/gitrepo/RepoCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/gitrepo/RepoCommandTest.java
@@ -42,6 +42,7 @@
  */
 package org.eclipse.jgit.gitrepo;
 
+import static org.eclipse.jgit.lib.Constants.CHARSET;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNull;
@@ -54,7 +55,6 @@
 import java.io.FileReader;
 import java.io.IOException;
 import java.net.URI;
-import java.nio.charset.StandardCharsets;
 import java.util.HashMap;
 import java.util.Map;
 
@@ -160,7 +160,7 @@ public ObjectId sha1(String uri, String refname) throws GitAPIException {
 				Ref ref = r.findRef(refname);
 				if (ref == null) return null;
 
-				ref = r.peel(ref);
+				ref = r.getRefDatabase().peel(ref);
 				ObjectId id = ref.getObjectId();
 				return id;
 			} catch (IOException e) {
@@ -185,162 +185,273 @@ public ObjectId sha1(String uri, String refname) throws GitAPIException {
 		}
 	}
 
+	private Repository cloneRepository(Repository repo, boolean bare)
+			throws Exception {
+		Repository r = Git.cloneRepository()
+				.setURI(repo.getDirectory().toURI().toString())
+				.setDirectory(createUniqueTestGitDir(true)).setBare(bare).call()
+				.getRepository();
+		if (bare) {
+			assertTrue(r.isBare());
+		} else {
+			assertFalse(r.isBare());
+		}
+		return r;
+	}
+
+	@Test
+	public void runTwiceIsNOP() throws Exception {
+		try (Repository child = cloneRepository(groupADb, true);
+				Repository dest = cloneRepository(db, true)) {
+			StringBuilder xmlContent = new StringBuilder();
+			xmlContent.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
+					.append("<manifest>")
+					.append("<remote name=\"remote1\" fetch=\"..\" />")
+					.append("<default revision=\"master\" remote=\"remote1\" />")
+					.append("<project path=\"base\" name=\"platform/base\" />")
+					.append("</manifest>");
+			RepoCommand cmd = new RepoCommand(dest);
+
+			IndexedRepos repos = new IndexedRepos();
+			repos.put("platform/base", child);
+
+			RevCommit commit = cmd
+					.setInputStream(new ByteArrayInputStream(
+							xmlContent.toString().getBytes(CHARSET)))
+					.setRemoteReader(repos).setURI("platform/")
+					.setTargetURI("platform/superproject")
+					.setRecordRemoteBranch(true).setRecordSubmoduleLabels(true)
+					.call();
+
+			String firstIdStr = commit.getId().name() + ":" + ".gitmodules";
+			commit = new RepoCommand(dest)
+					.setInputStream(new ByteArrayInputStream(
+							xmlContent.toString().getBytes(CHARSET)))
+					.setRemoteReader(repos).setURI("platform/")
+					.setTargetURI("platform/superproject")
+					.setRecordRemoteBranch(true).setRecordSubmoduleLabels(true)
+					.call();
+			String idStr = commit.getId().name() + ":" + ".gitmodules";
+			assertEquals(firstIdStr, idStr);
+		}
+	}
+
 	@Test
 	public void androidSetup() throws Exception {
-		Repository child = Git.cloneRepository()
-				.setURI(groupADb.getDirectory().toURI().toString())
-				.setDirectory(createUniqueTestGitDir(true)).setBare(true).call()
-				.getRepository();
+		try (Repository child = cloneRepository(groupADb, true);
+				Repository dest = cloneRepository(db, true)) {
+			StringBuilder xmlContent = new StringBuilder();
+			xmlContent.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
+					.append("<manifest>")
+					.append("<remote name=\"remote1\" fetch=\"..\" />")
+					.append("<default revision=\"master\" remote=\"remote1\" />")
+					.append("<project path=\"base\" name=\"platform/base\" />")
+					.append("</manifest>");
+			RepoCommand cmd = new RepoCommand(dest);
 
-		Repository dest = Git.cloneRepository()
-				.setURI(db.getDirectory().toURI().toString())
-				.setDirectory(createUniqueTestGitDir(true)).setBare(true).call()
-				.getRepository();
+			IndexedRepos repos = new IndexedRepos();
+			repos.put("platform/base", child);
 
-		assertTrue(dest.isBare());
-		assertTrue(child.isBare());
+			RevCommit commit = cmd
+					.setInputStream(new ByteArrayInputStream(
+							xmlContent.toString().getBytes(CHARSET)))
+					.setRemoteReader(repos).setURI("platform/")
+					.setTargetURI("platform/superproject")
+					.setRecordRemoteBranch(true).setRecordSubmoduleLabels(true)
+					.call();
 
+			String idStr = commit.getId().name() + ":" + ".gitmodules";
+			ObjectId modId = dest.resolve(idStr);
+
+			try (ObjectReader reader = dest.newObjectReader()) {
+				byte[] bytes = reader.open(modId)
+						.getCachedBytes(Integer.MAX_VALUE);
+				Config base = new Config();
+				BlobBasedConfig cfg = new BlobBasedConfig(base, bytes);
+				String subUrl = cfg.getString("submodule", "base", "url");
+				assertEquals(subUrl, "../base");
+			}
+		}
+	}
+
+	@Test
+	public void recordUnreachableRemotes() throws Exception {
 		StringBuilder xmlContent = new StringBuilder();
 		xmlContent.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
 			.append("<manifest>")
-			.append("<remote name=\"remote1\" fetch=\"..\" />")
+			.append("<remote name=\"remote1\" fetch=\"https://host.com/\" />")
 			.append("<default revision=\"master\" remote=\"remote1\" />")
 			.append("<project path=\"base\" name=\"platform/base\" />")
 			.append("</manifest>");
-		RepoCommand cmd = new RepoCommand(dest);
 
-		IndexedRepos repos = new IndexedRepos();
-		repos.put("platform/base", child);
+		try (Repository dest = cloneRepository(db, true)) {
+			RevCommit commit = new RepoCommand(dest)
+					.setInputStream(new ByteArrayInputStream(
+							xmlContent.toString().getBytes(CHARSET)))
+					.setRemoteReader(new IndexedRepos()).setURI("platform/")
+					.setTargetURI("platform/superproject")
+					.setRecordRemoteBranch(true).setIgnoreRemoteFailures(true)
+					.setRecordSubmoduleLabels(true).call();
 
-		RevCommit commit = cmd
-			.setInputStream(new ByteArrayInputStream(xmlContent.toString().getBytes(StandardCharsets.UTF_8)))
-			.setRemoteReader(repos)
-			.setURI("platform/")
-			.setTargetURI("platform/superproject")
-			.setRecordRemoteBranch(true)
-			.setRecordSubmoduleLabels(true)
-			.call();
+			String idStr = commit.getId().name() + ":" + ".gitmodules";
+			ObjectId modId = dest.resolve(idStr);
 
-		String idStr = commit.getId().name() + ":" + ".gitmodules";
-		ObjectId modId = dest.resolve(idStr);
-
-		try (ObjectReader reader = dest.newObjectReader()) {
-			byte[] bytes = reader.open(modId).getCachedBytes(Integer.MAX_VALUE);
-			Config base = new Config();
-			BlobBasedConfig cfg = new BlobBasedConfig(base, bytes);
-			String subUrl = cfg.getString("submodule", "base", "url");
-			assertEquals(subUrl, "../base");
+			try (ObjectReader reader = dest.newObjectReader()) {
+				byte[] bytes = reader.open(modId)
+						.getCachedBytes(Integer.MAX_VALUE);
+				Config base = new Config();
+				BlobBasedConfig cfg = new BlobBasedConfig(base, bytes);
+				String subUrl = cfg.getString("submodule", "base", "url");
+				assertEquals(subUrl, "https://host.com/platform/base");
+			}
 		}
-
-		child.close();
-		dest.close();
 	}
 
 	@Test
 	public void gerritSetup() throws Exception {
-		Repository child =
-			Git.cloneRepository().setURI(groupADb.getDirectory().toURI().toString())
-				.setDirectory(createUniqueTestGitDir(true))
-				.setBare(true).call().getRepository();
+		try (Repository child = cloneRepository(groupADb, true);
+				Repository dest = cloneRepository(db, true)) {
+			StringBuilder xmlContent = new StringBuilder();
+			xmlContent.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
+					.append("<manifest>")
+					.append("<remote name=\"remote1\" fetch=\".\" />")
+					.append("<default revision=\"master\" remote=\"remote1\" />")
+					.append("<project path=\"plugins/cookbook\" name=\"plugins/cookbook\" />")
+					.append("</manifest>");
+			RepoCommand cmd = new RepoCommand(dest);
 
-		Repository dest = Git.cloneRepository()
-			.setURI(db.getDirectory().toURI().toString()).setDirectory(createUniqueTestGitDir(true))
-			.setBare(true).call().getRepository();
+			IndexedRepos repos = new IndexedRepos();
+			repos.put("plugins/cookbook", child);
 
-		assertTrue(dest.isBare());
-		assertTrue(child.isBare());
+			RevCommit commit = cmd
+					.setInputStream(new ByteArrayInputStream(
+							xmlContent.toString().getBytes(CHARSET)))
+					.setRemoteReader(repos).setURI("").setTargetURI("gerrit")
+					.setRecordRemoteBranch(true).setRecordSubmoduleLabels(true)
+					.call();
 
-		StringBuilder xmlContent = new StringBuilder();
-		xmlContent.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
-			.append("<manifest>")
-			.append("<remote name=\"remote1\" fetch=\".\" />")
-			.append("<default revision=\"master\" remote=\"remote1\" />")
-			.append("<project path=\"plugins/cookbook\" name=\"plugins/cookbook\" />")
-			.append("</manifest>");
-		RepoCommand cmd = new RepoCommand(dest);
+			String idStr = commit.getId().name() + ":" + ".gitmodules";
+			ObjectId modId = dest.resolve(idStr);
 
-		IndexedRepos repos = new IndexedRepos();
-		repos.put("plugins/cookbook", child);
-
-		RevCommit commit = cmd
-			.setInputStream(new ByteArrayInputStream(xmlContent.toString().getBytes(StandardCharsets.UTF_8)))
-			.setRemoteReader(repos)
-			.setURI("")
-			.setTargetURI("gerrit")
-			.setRecordRemoteBranch(true)
-			.setRecordSubmoduleLabels(true)
-			.call();
-
-		String idStr = commit.getId().name() + ":" + ".gitmodules";
-		ObjectId modId = dest.resolve(idStr);
-
-		try (ObjectReader reader = dest.newObjectReader()) {
-			byte[] bytes = reader.open(modId).getCachedBytes(Integer.MAX_VALUE);
-			Config base = new Config();
-			BlobBasedConfig cfg = new BlobBasedConfig(base, bytes);
-			String subUrl = cfg.getString("submodule", "plugins/cookbook", "url");
-			assertEquals(subUrl, "../plugins/cookbook");
+			try (ObjectReader reader = dest.newObjectReader()) {
+				byte[] bytes = reader.open(modId)
+						.getCachedBytes(Integer.MAX_VALUE);
+				Config base = new Config();
+				BlobBasedConfig cfg = new BlobBasedConfig(base, bytes);
+				String subUrl = cfg.getString("submodule", "plugins/cookbook",
+						"url");
+				assertEquals(subUrl, "../plugins/cookbook");
+			}
 		}
-
-		child.close();
-		dest.close();
 	}
 
 	@Test
 	public void absoluteRemoteURL() throws Exception {
-		Repository child =
-			Git.cloneRepository().setURI(groupADb.getDirectory().toURI().toString())
-				.setDirectory(createUniqueTestGitDir(true))
-				.setBare(true).call().getRepository();
-		Repository dest = Git.cloneRepository()
-			.setURI(db.getDirectory().toURI().toString()).setDirectory(createUniqueTestGitDir(true))
-			.setBare(true).call().getRepository();
-		String abs = "https://chromium.googlesource.com";
-		String repoUrl = "https://chromium.googlesource.com/chromium/src";
-		boolean fetchSlash = false;
-		boolean baseSlash = false;
-		do {
+		try (Repository child = cloneRepository(groupADb, true);
+				Repository dest = cloneRepository(db, true)) {
+			String abs = "https://chromium.googlesource.com";
+			String repoUrl = "https://chromium.googlesource.com/chromium/src";
+			boolean fetchSlash = false;
+			boolean baseSlash = false;
 			do {
-				String fetchUrl = fetchSlash ? abs + "/" : abs;
-				String baseUrl = baseSlash ? abs + "/" : abs;
+				do {
+					String fetchUrl = fetchSlash ? abs + "/" : abs;
+					String baseUrl = baseSlash ? abs + "/" : abs;
 
-				StringBuilder xmlContent = new StringBuilder();
-				xmlContent.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
-					.append("<manifest>")
-					.append("<remote name=\"origin\" fetch=\"" + fetchUrl + "\" />")
-					.append("<default revision=\"master\" remote=\"origin\" />")
-					.append("<project path=\"src\" name=\"chromium/src\" />")
-					.append("</manifest>");
-				RepoCommand cmd = new RepoCommand(dest);
+					StringBuilder xmlContent = new StringBuilder();
+					xmlContent.append(
+							"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
+							.append("<manifest>")
+							.append("<remote name=\"origin\" fetch=\""
+									+ fetchUrl + "\" />")
+							.append("<default revision=\"master\" remote=\"origin\" />")
+							.append("<project path=\"src\" name=\"chromium/src\" />")
+							.append("</manifest>");
+					RepoCommand cmd = new RepoCommand(dest);
 
-				IndexedRepos repos = new IndexedRepos();
-				repos.put(repoUrl, child);
+					IndexedRepos repos = new IndexedRepos();
+					repos.put(repoUrl, child);
 
-				RevCommit commit = cmd
-					.setInputStream(new ByteArrayInputStream(xmlContent.toString().getBytes(StandardCharsets.UTF_8)))
-					.setRemoteReader(repos)
-					.setURI(baseUrl)
-					.setTargetURI("gerrit")
-					.setRecordRemoteBranch(true)
-					.setRecordSubmoduleLabels(true)
-					.call();
+					RevCommit commit = cmd
+							.setInputStream(new ByteArrayInputStream(
+									xmlContent.toString().getBytes(CHARSET)))
+							.setRemoteReader(repos).setURI(baseUrl)
+							.setTargetURI("gerrit").setRecordRemoteBranch(true)
+							.setRecordSubmoduleLabels(true).call();
 
-				String idStr = commit.getId().name() + ":" + ".gitmodules";
-				ObjectId modId = dest.resolve(idStr);
+					String idStr = commit.getId().name() + ":" + ".gitmodules";
+					ObjectId modId = dest.resolve(idStr);
 
-				try (ObjectReader reader = dest.newObjectReader()) {
-					byte[] bytes = reader.open(modId).getCachedBytes(Integer.MAX_VALUE);
-					Config base = new Config();
-					BlobBasedConfig cfg = new BlobBasedConfig(base, bytes);
-					String subUrl = cfg.getString("submodule", "src", "url");
-					assertEquals("https://chromium.googlesource.com/chromium/src", subUrl);
-				}
-				fetchSlash = !fetchSlash;
-			} while (fetchSlash);
-			baseSlash = !baseSlash;
-		} while (baseSlash);
-		child.close();
-		dest.close();
+					try (ObjectReader reader = dest.newObjectReader()) {
+						byte[] bytes = reader.open(modId)
+								.getCachedBytes(Integer.MAX_VALUE);
+						Config base = new Config();
+						BlobBasedConfig cfg = new BlobBasedConfig(base, bytes);
+						String subUrl = cfg.getString("submodule", "src",
+								"url");
+						assertEquals(
+								"https://chromium.googlesource.com/chromium/src",
+								subUrl);
+					}
+					fetchSlash = !fetchSlash;
+				} while (fetchSlash);
+				baseSlash = !baseSlash;
+			} while (baseSlash);
+		}
+	}
+
+	@Test
+	public void absoluteRemoteURLAbsoluteTargetURL() throws Exception {
+		try (Repository child = cloneRepository(groupADb, true);
+				Repository dest = cloneRepository(db, true)) {
+			String abs = "https://chromium.googlesource.com";
+			String repoUrl = "https://chromium.googlesource.com/chromium/src";
+			boolean fetchSlash = false;
+			boolean baseSlash = false;
+			do {
+				do {
+					String fetchUrl = fetchSlash ? abs + "/" : abs;
+					String baseUrl = baseSlash ? abs + "/" : abs;
+
+					StringBuilder xmlContent = new StringBuilder();
+					xmlContent.append(
+							"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
+							.append("<manifest>")
+							.append("<remote name=\"origin\" fetch=\""
+									+ fetchUrl + "\" />")
+							.append("<default revision=\"master\" remote=\"origin\" />")
+							.append("<project path=\"src\" name=\"chromium/src\" />")
+							.append("</manifest>");
+					RepoCommand cmd = new RepoCommand(dest);
+
+					IndexedRepos repos = new IndexedRepos();
+					repos.put(repoUrl, child);
+
+					RevCommit commit = cmd
+							.setInputStream(new ByteArrayInputStream(
+									xmlContent.toString().getBytes(CHARSET)))
+							.setRemoteReader(repos).setURI(baseUrl)
+							.setTargetURI(abs + "/superproject")
+							.setRecordRemoteBranch(true)
+							.setRecordSubmoduleLabels(true).call();
+
+					String idStr = commit.getId().name() + ":" + ".gitmodules";
+					ObjectId modId = dest.resolve(idStr);
+
+					try (ObjectReader reader = dest.newObjectReader()) {
+						byte[] bytes = reader.open(modId)
+								.getCachedBytes(Integer.MAX_VALUE);
+						Config base = new Config();
+						BlobBasedConfig cfg = new BlobBasedConfig(base, bytes);
+						String subUrl = cfg.getString("submodule", "src",
+								"url");
+						assertEquals("../chromium/src", subUrl);
+					}
+					fetchSlash = !fetchSlash;
+				} while (fetchSlash);
+				baseSlash = !baseSlash;
+			} while (baseSlash);
+		}
 	}
 
 	@Test
@@ -361,11 +472,12 @@ public void testAddRepoManifest() throws Exception {
 			.call();
 		File hello = new File(db.getWorkTree(), "foo/hello.txt");
 		assertTrue("submodule should be checked out", hello.exists());
-		BufferedReader reader = new BufferedReader(new FileReader(hello));
-		String content = reader.readLine();
-		reader.close();
-		assertEquals("submodule content should be as expected",
-				"master world", content);
+		try (BufferedReader reader = new BufferedReader(
+				new FileReader(hello))) {
+			String content = reader.readLine();
+			assertEquals("submodule content should be as expected",
+					"master world", content);
+		}
 	}
 
 	@Test
@@ -451,19 +563,21 @@ public void testRepoManifestCopyFile() throws Exception {
 		// The original file should exist
 		File hello = new File(localDb.getWorkTree(), "foo/hello.txt");
 		assertTrue("The original file should exist", hello.exists());
-		BufferedReader reader = new BufferedReader(new FileReader(hello));
-		String content = reader.readLine();
-		reader.close();
-		assertEquals("The original file should have expected content",
-				"master world", content);
+		try (BufferedReader reader = new BufferedReader(
+				new FileReader(hello))) {
+			String content = reader.readLine();
+			assertEquals("The original file should have expected content",
+					"master world", content);
+		}
 		// The dest file should also exist
 		hello = new File(localDb.getWorkTree(), "Hello");
 		assertTrue("The destination file should exist", hello.exists());
-		reader = new BufferedReader(new FileReader(hello));
-		content = reader.readLine();
-		reader.close();
-		assertEquals("The destination file should have expected content",
-				"master world", content);
+		try (BufferedReader reader = new BufferedReader(
+				new FileReader(hello))) {
+			String content = reader.readLine();
+			assertEquals("The destination file should have expected content",
+					"master world", content);
+		}
 	}
 
 	@Test
@@ -486,24 +600,27 @@ public void testBareRepo() throws Exception {
 				.setURI(rootUri).call();
 		// Clone it
 		File directory = createTempDirectory("testBareRepo");
-		Repository localDb = Git.cloneRepository().setDirectory(directory)
+		try (Repository localDb = Git.cloneRepository().setDirectory(directory)
 				.setURI(remoteDb.getDirectory().toURI().toString()).call()
-				.getRepository();
-		// The .gitmodules file should exist
-		File gitmodules = new File(localDb.getWorkTree(), ".gitmodules");
-		assertTrue("The .gitmodules file should exist", gitmodules.exists());
-		// The first line of .gitmodules file should be expected
-		BufferedReader reader = new BufferedReader(new FileReader(gitmodules));
-		String content = reader.readLine();
-		reader.close();
-		assertEquals("The first line of .gitmodules file should be as expected",
-				"[submodule \"foo\"]", content);
-		// The gitlink should be the same as remote head sha1
-		String gitlink = localDb.resolve(Constants.HEAD + ":foo").name();
-		localDb.close();
-		String remote = defaultDb.resolve(Constants.HEAD).name();
-		assertEquals("The gitlink should be the same as remote head", remote,
-				gitlink);
+				.getRepository()) {
+			// The .gitmodules file should exist
+			File gitmodules = new File(localDb.getWorkTree(), ".gitmodules");
+			assertTrue("The .gitmodules file should exist",
+					gitmodules.exists());
+			// The first line of .gitmodules file should be expected
+			try (BufferedReader reader = new BufferedReader(
+					new FileReader(gitmodules))) {
+				String content = reader.readLine();
+				assertEquals(
+						"The first line of .gitmodules file should be as expected",
+						"[submodule \"foo\"]", content);
+			}
+			// The gitlink should be the same as remote head sha1
+			String gitlink = localDb.resolve(Constants.HEAD + ":foo").name();
+			String remote = defaultDb.resolve(Constants.HEAD).name();
+			assertEquals("The gitlink should be the same as remote head",
+					remote, gitlink);
+		}
 	}
 
 	@Test
@@ -525,11 +642,12 @@ public void testRevision() throws Exception {
 			.setURI(rootUri)
 			.call();
 		File hello = new File(db.getWorkTree(), "foo/hello.txt");
-		BufferedReader reader = new BufferedReader(new FileReader(hello));
-		String content = reader.readLine();
-		reader.close();
-		assertEquals("submodule content should be as expected",
-				"branch world", content);
+		try (BufferedReader reader = new BufferedReader(
+				new FileReader(hello))) {
+			String content = reader.readLine();
+			assertEquals("submodule content should be as expected",
+					"branch world", content);
+		}
 	}
 
 	@Test
@@ -551,11 +669,12 @@ public void testRevisionBranch() throws Exception {
 			.setURI(rootUri)
 			.call();
 		File hello = new File(db.getWorkTree(), "foo/hello.txt");
-		BufferedReader reader = new BufferedReader(new FileReader(hello));
-		String content = reader.readLine();
-		reader.close();
-		assertEquals("submodule content should be as expected",
-				"branch world", content);
+		try (BufferedReader reader = new BufferedReader(
+				new FileReader(hello))) {
+			String content = reader.readLine();
+			assertEquals("submodule content should be as expected",
+					"branch world", content);
+		}
 	}
 
 	@Test
@@ -577,11 +696,12 @@ public void testRevisionTag() throws Exception {
 			.setURI(rootUri)
 			.call();
 		File hello = new File(db.getWorkTree(), "foo/hello.txt");
-		BufferedReader reader = new BufferedReader(new FileReader(hello));
-		String content = reader.readLine();
-		reader.close();
-		assertEquals("submodule content should be as expected",
-				"branch world", content);
+		try (BufferedReader reader = new BufferedReader(
+				new FileReader(hello))) {
+			String content = reader.readLine();
+			assertEquals("submodule content should be as expected",
+					"branch world", content);
+		}
 	}
 
 	@Test
@@ -605,14 +725,14 @@ public void testRevisionBare() throws Exception {
 				.setURI(rootUri).call();
 		// Clone it
 		File directory = createTempDirectory("testRevisionBare");
-		Repository localDb = Git.cloneRepository().setDirectory(directory)
+		try (Repository localDb = Git.cloneRepository().setDirectory(directory)
 				.setURI(remoteDb.getDirectory().toURI().toString()).call()
-				.getRepository();
-		// The gitlink should be the same as oldCommitId
-		String gitlink = localDb.resolve(Constants.HEAD + ":foo").name();
-		localDb.close();
-		assertEquals("The gitlink is same as remote head", oldCommitId.name(),
-				gitlink);
+				.getRepository()) {
+			// The gitlink should be the same as oldCommitId
+			String gitlink = localDb.resolve(Constants.HEAD + ":foo").name();
+			assertEquals("The gitlink is same as remote head",
+					oldCommitId.name(), gitlink);
+		}
 	}
 
 	@Test
@@ -638,22 +758,24 @@ public void testCopyFileBare() throws Exception {
 				.setURI(rootUri).call();
 		// Clone it
 		File directory = createTempDirectory("testCopyFileBare");
-		Repository localDb = Git.cloneRepository().setDirectory(directory)
+		try (Repository localDb = Git.cloneRepository().setDirectory(directory)
 				.setURI(remoteDb.getDirectory().toURI().toString()).call()
-				.getRepository();
-		// The Hello file should exist
-		File hello = new File(localDb.getWorkTree(), "Hello");
-		assertTrue("The Hello file should exist", hello.exists());
-		// The foo/Hello file should be skipped.
-		File foohello = new File(localDb.getWorkTree(), "foo/Hello");
-		assertFalse("The foo/Hello file should be skipped", foohello.exists());
-		localDb.close();
-		// The content of Hello file should be expected
-		BufferedReader reader = new BufferedReader(new FileReader(hello));
-		String content = reader.readLine();
-		reader.close();
-		assertEquals("The Hello file should have expected content",
-				"branch world", content);
+				.getRepository()) {
+			// The Hello file should exist
+			File hello = new File(localDb.getWorkTree(), "Hello");
+			assertTrue("The Hello file should exist", hello.exists());
+			// The foo/Hello file should be skipped.
+			File foohello = new File(localDb.getWorkTree(), "foo/Hello");
+			assertFalse("The foo/Hello file should be skipped",
+					foohello.exists());
+			// The content of Hello file should be expected
+			try (BufferedReader reader = new BufferedReader(
+					new FileReader(hello))) {
+				String content = reader.readLine();
+				assertEquals("The Hello file should have expected content",
+						"branch world", content);
+			}
+		}
 	}
 
 	@Test
@@ -689,36 +811,38 @@ public void testReplaceManifestBare() throws Exception {
 				.setURI(rootUri).call();
 		// Clone it
 		File directory = createTempDirectory("testReplaceManifestBare");
-		Repository localDb = Git.cloneRepository().setDirectory(directory)
+		File dotmodules;
+		try (Repository localDb = Git.cloneRepository().setDirectory(directory)
 				.setURI(remoteDb.getDirectory().toURI().toString()).call()
-				.getRepository();
-		// The Hello file should not exist
-		File hello = new File(localDb.getWorkTree(), "Hello");
-		assertFalse("The Hello file shouldn't exist", hello.exists());
-		// The Hello.txt file should exist
-		File hellotxt = new File(localDb.getWorkTree(), "Hello.txt");
-		assertTrue("The Hello.txt file should exist", hellotxt.exists());
+				.getRepository()) {
+			// The Hello file should not exist
+			File hello = new File(localDb.getWorkTree(), "Hello");
+			assertFalse("The Hello file shouldn't exist", hello.exists());
+			// The Hello.txt file should exist
+			File hellotxt = new File(localDb.getWorkTree(), "Hello.txt");
+			assertTrue("The Hello.txt file should exist", hellotxt.exists());
+			dotmodules = new File(localDb.getWorkTree(),
+					Constants.DOT_GIT_MODULES);
+		}
 		// The .gitmodules file should have 'submodule "bar"' and shouldn't
 		// have
 		// 'submodule "foo"' lines.
-		File dotmodules = new File(localDb.getWorkTree(),
-				Constants.DOT_GIT_MODULES);
-		localDb.close();
-		BufferedReader reader = new BufferedReader(new FileReader(dotmodules));
-		boolean foo = false;
-		boolean bar = false;
-		while (true) {
-			String line = reader.readLine();
-			if (line == null)
-				break;
-			if (line.contains("submodule \"foo\""))
-				foo = true;
-			if (line.contains("submodule \"bar\""))
-				bar = true;
+		try (BufferedReader reader = new BufferedReader(
+				new FileReader(dotmodules))) {
+			boolean foo = false;
+			boolean bar = false;
+			while (true) {
+				String line = reader.readLine();
+				if (line == null)
+					break;
+				if (line.contains("submodule \"foo\""))
+					foo = true;
+				if (line.contains("submodule \"bar\""))
+					bar = true;
+			}
+			assertTrue("The bar submodule should exist", bar);
+			assertFalse("The foo submodule shouldn't exist", foo);
 		}
-		reader.close();
-		assertTrue("The bar submodule should exist", bar);
-		assertFalse("The foo submodule shouldn't exist", foo);
 	}
 
 	@Test
@@ -744,34 +868,37 @@ public void testRemoveOverlappingBare() throws Exception {
 				.setURI(rootUri).call();
 		// Clone it
 		File directory = createTempDirectory("testRemoveOverlappingBare");
-		Repository localDb = Git.cloneRepository().setDirectory(directory)
+		File dotmodules;
+		try (Repository localDb = Git.cloneRepository().setDirectory(directory)
 				.setURI(remoteDb.getDirectory().toURI().toString()).call()
-				.getRepository();
+				.getRepository()) {
+			dotmodules = new File(localDb.getWorkTree(),
+				Constants.DOT_GIT_MODULES);
+		}
+
 		// The .gitmodules file should have 'submodule "foo"' and shouldn't
 		// have
 		// 'submodule "foo/bar"' lines.
-		File dotmodules = new File(localDb.getWorkTree(),
-				Constants.DOT_GIT_MODULES);
-		localDb.close();
-		BufferedReader reader = new BufferedReader(new FileReader(dotmodules));
-		boolean foo = false;
-		boolean foobar = false;
-		boolean a = false;
-		while (true) {
-			String line = reader.readLine();
-			if (line == null)
-				break;
-			if (line.contains("submodule \"foo\""))
-				foo = true;
-			if (line.contains("submodule \"foo/bar\""))
-				foobar = true;
-			if (line.contains("submodule \"a\""))
-				a = true;
+		try (BufferedReader reader = new BufferedReader(
+				new FileReader(dotmodules))) {
+			boolean foo = false;
+			boolean foobar = false;
+			boolean a = false;
+			while (true) {
+				String line = reader.readLine();
+				if (line == null)
+					break;
+				if (line.contains("submodule \"foo\""))
+					foo = true;
+				if (line.contains("submodule \"foo/bar\""))
+					foobar = true;
+				if (line.contains("submodule \"a\""))
+					a = true;
+			}
+			assertTrue("The foo submodule should exist", foo);
+			assertFalse("The foo/bar submodule shouldn't exist", foobar);
+			assertTrue("The a submodule should exist", a);
 		}
-		reader.close();
-		assertTrue("The foo submodule should exist", foo);
-		assertFalse("The foo/bar submodule shouldn't exist", foobar);
-		assertTrue("The a submodule should exist", a);
 	}
 
 	@Test
@@ -807,43 +934,13 @@ public void testIncludeTag() throws Exception {
 			.call();
 		File hello = new File(localDb.getWorkTree(), "foo/hello.txt");
 		assertTrue("submodule should be checked out", hello.exists());
-		BufferedReader reader = new BufferedReader(new FileReader(hello));
-		String content = reader.readLine();
-		reader.close();
-		assertEquals("submodule content should be as expected",
-				"master world", content);
+		try (BufferedReader reader = new BufferedReader(
+				new FileReader(hello))) {
+			String content = reader.readLine();
+			assertEquals("submodule content should be as expected",
+					"master world", content);
+		}
 	}
-
-	@Test
-	public void testNonDefaultRemotes() throws Exception {
-		StringBuilder xmlContent = new StringBuilder();
-		xmlContent.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
-			.append("<manifest>")
-			.append("<remote name=\"remote1\" fetch=\".\" />")
-			.append("<remote name=\"remote2\" fetch=\"")
-			.append(notDefaultUri)
-			.append("\" />")
-			.append("<default revision=\"master\" remote=\"remote1\" />")
-			.append("<project path=\"foo\" name=\"")
-			.append(defaultUri)
-			.append("\" />")
-			.append("<project path=\"bar\" name=\".\" remote=\"remote2\" />")
-			.append("</manifest>");
-
-		Repository localDb = createWorkRepository();
-		JGitTestUtil.writeTrashFile(
-				localDb, "manifest.xml", xmlContent.toString());
-		RepoCommand command = new RepoCommand(localDb);
-		command
-			.setPath(localDb.getWorkTree().getAbsolutePath() + "/manifest.xml")
-			.setURI(rootUri)
-			.call();
-		File file = new File(localDb.getWorkTree(), "foo/hello.txt");
-		assertTrue("We should have foo", file.exists());
-		file = new File(localDb.getWorkTree(), "bar/world.txt");
-		assertTrue("We should have bar", file.exists());
-	}
-
 	@Test
 	public void testRemoteAlias() throws Exception {
 		StringBuilder xmlContent = new StringBuilder();
@@ -1044,11 +1141,12 @@ public void testRemoteRevision() throws Exception {
 			.setURI(rootUri)
 			.call();
 		File hello = new File(db.getWorkTree(), "foo/hello.txt");
-		BufferedReader reader = new BufferedReader(new FileReader(hello));
-		String content = reader.readLine();
-		reader.close();
-		assertEquals("submodule content should be as expected",
-				"branch world", content);
+		try (BufferedReader reader = new BufferedReader(
+				new FileReader(hello))) {
+			String content = reader.readLine();
+			assertEquals("submodule content should be as expected",
+					"branch world", content);
+		}
 	}
 
 	@Test
@@ -1070,11 +1168,12 @@ public void testDefaultRemoteRevision() throws Exception {
 			.setURI(rootUri)
 			.call();
 		File hello = new File(db.getWorkTree(), "foo/hello.txt");
-		BufferedReader reader = new BufferedReader(new FileReader(hello));
-		String content = reader.readLine();
-		reader.close();
-		assertEquals("submodule content should be as expected",
-				"branch world", content);
+		try (BufferedReader reader = new BufferedReader(
+				new FileReader(hello))) {
+			String content = reader.readLine();
+			assertEquals("submodule content should be as expected",
+					"branch world", content);
+		}
 	}
 
 	private void resolveRelativeUris() {
@@ -1124,5 +1223,6 @@ public void relative() {
 		testRelative("abc", "/bcd", "/bcd");
 		testRelative("http://a", "a/b", "a/b");
 		testRelative("http://base.com/a/", "http://child.com/a/b", "http://child.com/a/b");
+		testRelative("http://base.com/a/", "http://base.com/a/b", "b");
 	}
 }
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/ignore/CGitIgnoreTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/ignore/CGitIgnoreTest.java
index ee8191f..0c6ed0c 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/ignore/CGitIgnoreTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/ignore/CGitIgnoreTest.java
@@ -118,20 +118,43 @@ private String toString(TemporaryBuffer b) throws IOException {
 		}
 	}
 
-	private LinkedHashSet<String> jgitIgnored() throws IOException {
+	private String[] cgitUntracked() throws Exception {
+		FS fs = db.getFS();
+		ProcessBuilder builder = fs.runInShell("git",
+				new String[] { "ls-files", "--exclude-standard", "-o" });
+		builder.directory(db.getWorkTree());
+		builder.environment().put("HOME", fs.userHome().getAbsolutePath());
+		ExecutionResult result = fs.execute(builder,
+				new ByteArrayInputStream(new byte[0]));
+		String errorOut = toString(result.getStderr());
+		assertEquals("External git failed", "exit 0\n",
+				"exit " + result.getRc() + '\n' + errorOut);
+		try (BufferedReader r = new BufferedReader(new InputStreamReader(
+				new BufferedInputStream(result.getStdout().openInputStream()),
+				Constants.CHARSET))) {
+			return r.lines().toArray(String[]::new);
+		}
+	}
+
+	private void jgitIgnoredAndUntracked(LinkedHashSet<String> ignored,
+			LinkedHashSet<String> untracked) throws IOException {
 		// Do a tree walk that does descend into ignored directories and return
 		// a list of all ignored files
-		LinkedHashSet<String> result = new LinkedHashSet<>();
 		try (TreeWalk walk = new TreeWalk(db)) {
-			walk.addTree(new FileTreeIterator(db));
+			FileTreeIterator iter = new FileTreeIterator(db);
+			iter.setWalkIgnoredDirectories(true);
+			walk.addTree(iter);
 			walk.setRecursive(true);
 			while (walk.next()) {
 				if (walk.getTree(WorkingTreeIterator.class).isEntryIgnored()) {
-					result.add(walk.getPathString());
+					ignored.add(walk.getPathString());
+				} else {
+					// tests of this class won't add any files to the index,
+					// hence everything what is not ignored is untracked
+					untracked.add(walk.getPathString());
 				}
 			}
 		}
-		return result;
 	}
 
 	private void assertNoIgnoredVisited(Set<String> ignored) throws Exception {
@@ -150,9 +173,13 @@ private void assertNoIgnoredVisited(Set<String> ignored) throws Exception {
 	}
 
 	private void assertSameAsCGit(String... notIgnored) throws Exception {
-		LinkedHashSet<String> ignored = jgitIgnored();
+		LinkedHashSet<String> ignored = new LinkedHashSet<>();
+		LinkedHashSet<String> untracked = new LinkedHashSet<>();
+		jgitIgnoredAndUntracked(ignored, untracked);
 		String[] cgit = cgitIgnored();
+		String[] cgitUntracked = cgitUntracked();
 		assertArrayEquals(cgit, ignored.toArray());
+		assertArrayEquals(cgitUntracked, untracked.toArray());
 		for (String notExcluded : notIgnored) {
 			assertFalse("File " + notExcluded + " should not be ignored",
 					ignored.contains(notExcluded));
@@ -242,6 +269,34 @@ public void testDirectoryMatchSubRecursiveBacktrack5() throws Exception {
 	}
 
 	@Test
+	public void testDirectoryWildmatchDoesNotMatchFiles1() throws Exception {
+		createFiles("a", "dir/b", "dir/sub/c");
+		writeTrashFile(".gitignore", "**/\n");
+		assertSameAsCGit();
+	}
+
+	@Test
+	public void testDirectoryWildmatchDoesNotMatchFiles2() throws Exception {
+		createFiles("a", "dir/b", "dir/sub/c");
+		writeTrashFile(".gitignore", "**/**/\n");
+		assertSameAsCGit();
+	}
+
+	@Test
+	public void testDirectoryWildmatchDoesNotMatchFiles3() throws Exception {
+		createFiles("a", "x/b", "sub/x/c", "sub/x/d/e");
+		writeTrashFile(".gitignore", "x/**/\n");
+		assertSameAsCGit();
+	}
+
+	@Test
+	public void testDirectoryWildmatchDoesNotMatchFiles4() throws Exception {
+		createFiles("a", "dir/x", "dir/sub1/x", "dir/sub2/x/y");
+		writeTrashFile(".gitignore", "**/x/\n");
+		assertSameAsCGit();
+	}
+
+	@Test
 	public void testUnescapedBracketsInGroup() throws Exception {
 		createFiles("[", "]", "[]", "][", "[[]", "[]]", "[[]]");
 		writeTrashFile(".gitignore", "[[]]\n");
@@ -268,4 +323,68 @@ public void testEscapedBothBracketsInGroup() throws Exception {
 		writeTrashFile(".gitignore", "[\\[\\]]\n");
 		assertSameAsCGit();
 	}
+
+	@Test
+	public void testSimpleRootGitIgnoreGlobalNegation1() throws Exception {
+		// see IgnoreNodeTest.testSimpleRootGitIgnoreGlobalNegation1
+		createFiles("x1", "a/x2", "x3/y");
+		writeTrashFile(".gitignore", "*\n!x*");
+		assertSameAsCGit();
+	}
+
+	@Test
+	public void testRepeatedNegationInDifferentFiles5() throws Exception {
+		// see IgnoreNodeTest.testRepeatedNegationInDifferentFiles5
+		createFiles("a/b/e/nothere.o");
+		writeTrashFile(".gitignore", "e");
+		writeTrashFile("a/.gitignore", "e");
+		writeTrashFile("a/b/.gitignore", "!e");
+		assertSameAsCGit();
+	}
+
+	@Test
+	public void testRepeatedNegationInDifferentFilesWithWildmatcher1()
+			throws Exception {
+		createFiles("e", "x/e/f", "a/e/x1", "a/e/x2", "a/e/y", "a/e/sub/y");
+		writeTrashFile(".gitignore", "a/e/**");
+		writeTrashFile("a/.gitignore", "!e/x*");
+		assertSameAsCGit();
+	}
+
+	@Test
+	public void testRepeatedNegationInDifferentFilesWithWildmatcher2()
+			throws Exception {
+		createFiles("e", "dir/f", "dir/g/h", "a/dir/i", "a/dir/j/k",
+				"a/b/dir/l", "a/b/dir/m/n", "a/b/dir/m/o/p", "a/q/dir/r",
+				"a/q/dir/dir/s", "c/d/dir/x", "c/d/dir/y");
+		writeTrashFile(".gitignore", "**/dir/*");
+		writeTrashFile("a/.gitignore", "!dir/*");
+		writeTrashFile("a/b/.gitignore", "!**/dir/*");
+		writeTrashFile("c/.gitignore", "!d/dir/x");
+		assertSameAsCGit();
+	}
+
+	@Test
+	public void testNegationForSubDirectoryWithinIgnoredDirectoryHasNoEffect1()
+			throws Exception {
+		createFiles("e", "a/f", "a/b/g", "a/b/h/i");
+		writeTrashFile(".gitignore", "a/b");
+		writeTrashFile("a/.gitignore", "!b/*");
+		assertSameAsCGit();
+	}
+
+	/*
+	 * See https://bugs.eclipse.org/bugs/show_bug.cgi?id=407475
+	 */
+	@Test
+	public void testNegationAllExceptJavaInSrcAndExceptChildDirInSrc()
+			throws Exception {
+		// see
+		// IgnoreNodeTest.testNegationAllExceptJavaInSrcAndExceptChildDirInSrc
+		createFiles("nothere.o", "src/keep.java", "src/nothere.o",
+				"src/a/keep.java", "src/a/keep.o");
+		writeTrashFile(".gitignore", "/*\n!/src/");
+		writeTrashFile("src/.gitignore", "*\n!*.java\n!*/");
+		assertSameAsCGit();
+	}
 }
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/ignore/FastIgnoreRuleTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/ignore/FastIgnoreRuleTest.java
index bcc8f7e..2a1721e 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/ignore/FastIgnoreRuleTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/ignore/FastIgnoreRuleTest.java
@@ -48,10 +48,18 @@
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
+import org.junit.Before;
 import org.junit.Test;
 
 public class FastIgnoreRuleTest {
 
+	private boolean pathMatch;
+
+	@Before
+	public void setup() {
+		pathMatch = false;
+	}
+
 	@Test
 	public void testSimpleCharClass() {
 		assertMatched("][a]", "]a");
@@ -410,6 +418,19 @@ public void testWildmatch() {
 
 		assertMatched("a/**/b/**/c", "a/c/b/d/c");
 		assertMatched("a/**/**/b/**/**/c", "a/c/b/d/c");
+
+		assertMatched("**/", "a/");
+		assertMatched("**/", "a/b");
+		assertMatched("**/", "a/b/c");
+		assertMatched("**/**/", "a/");
+		assertMatched("**/**/", "a/b");
+		assertMatched("**/**/", "a/b/");
+		assertMatched("**/**/", "a/b/c");
+		assertMatched("x/**/", "x/a/");
+		assertMatched("x/**/", "x/a/b");
+		assertMatched("x/**/", "x/a/b/");
+		assertMatched("**/x/", "a/x/");
+		assertMatched("**/x/", "a/b/x/");
 	}
 
 	@Test
@@ -424,6 +445,10 @@ public void testWildmatchDoNotMatch() {
 		assertNotMatched("!/**/*.zip", "c/a/b.zip");
 		assertNotMatched("!**/*.zip", "c/a/b.zip");
 		assertNotMatched("a/**/b", "a/c/bb");
+
+		assertNotMatched("**/", "a");
+		assertNotMatched("**/**/", "a");
+		assertNotMatched("**/x/", "a/b/x");
 	}
 
 	@SuppressWarnings("unused")
@@ -465,7 +490,29 @@ public void testSplit() {
 				split("/a/b/c/", '/').toArray());
 	}
 
-	public void assertMatched(String pattern, String path) {
+	@Test
+	public void testPathMatch() {
+		pathMatch = true;
+		assertMatched("a", "a");
+		assertMatched("a/", "a/");
+		assertNotMatched("a/", "a/b");
+
+		assertMatched("**", "a");
+		assertMatched("**", "a/");
+		assertMatched("**", "a/b");
+
+		assertNotMatched("**/", "a");
+		assertNotMatched("**/", "a/b");
+		assertMatched("**/", "a/");
+		assertMatched("**/", "a/b/");
+
+		assertNotMatched("x/**/", "x/a");
+		assertNotMatched("x/**/", "x/a/b");
+		assertMatched("x/**/", "x/a/");
+		assertMatched("x/**/", "x/y/a/");
+	}
+
+	private void assertMatched(String pattern, String path) {
 		boolean match = match(pattern, path);
 		String result = path + " is " + (match ? "ignored" : "not ignored")
 				+ " via '" + pattern + "' rule";
@@ -485,7 +532,7 @@ public void assertMatched(String pattern, String path) {
 				match);
 	}
 
-	public void assertNotMatched(String pattern, String path) {
+	private void assertNotMatched(String pattern, String path) {
 		boolean match = match(pattern, path);
 		String result = path + " is " + (match ? "ignored" : "not ignored")
 				+ " via '" + pattern + "' rule";
@@ -520,7 +567,7 @@ private boolean match(String pattern, String target) {
 		FastIgnoreRule r = new FastIgnoreRule(pattern);
 		// If speed of this test is ever an issue, we can use a presetRule field
 		// to avoid recompiling a pattern each time.
-		boolean match = r.isMatch(target, isDirectory);
+		boolean match = r.isMatch(target, isDirectory, pathMatch);
 		if (r.getNegation())
 			match = !match;
 		return match;
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/ignore/IgnoreMatcherParametrizedTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/ignore/IgnoreMatcherParametrizedTest.java
index 529c75f..137230d 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/ignore/IgnoreMatcherParametrizedTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/ignore/IgnoreMatcherParametrizedTest.java
@@ -346,7 +346,7 @@ public void testNegation() {
 	 *            Target file path relative to repository's GIT_DIR
 	 * @param assume
 	 */
-	public void assertMatched(String pattern, String target, Boolean... assume) {
+	private void assertMatched(String pattern, String target, Boolean... assume) {
 		boolean value = match(pattern, target);
 		if (assume.length == 0 || !assume[0].booleanValue())
 			assertTrue("Expected a match for: " + pattern + " with: " + target,
@@ -366,7 +366,7 @@ public void assertMatched(String pattern, String target, Boolean... assume) {
 	 *            Target file path relative to repository's GIT_DIR
 	 * @param assume
 	 */
-	public void assertNotMatched(String pattern, String target,
+	private void assertNotMatched(String pattern, String target,
 			Boolean... assume) {
 		boolean value = match(pattern, target);
 		if (assume.length == 0 || !assume[0].booleanValue())
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/ignore/IgnoreNodeTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/ignore/IgnoreNodeTest.java
index 4a7dcd5..78d9a82 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/ignore/IgnoreNodeTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/ignore/IgnoreNodeTest.java
@@ -42,6 +42,7 @@
  */
 package org.eclipse.jgit.ignore;
 
+import static org.eclipse.jgit.lib.Constants.CHARSET;
 import static org.eclipse.jgit.junit.Assert.assertEquals;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
@@ -55,7 +56,6 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 
-import org.eclipse.jgit.ignore.IgnoreNode.MatchResult;
 import org.eclipse.jgit.junit.RepositoryTestCase;
 import org.eclipse.jgit.lib.FileMode;
 import org.eclipse.jgit.treewalk.FileTreeIterator;
@@ -80,6 +80,141 @@ public class IgnoreNodeTest extends RepositoryTestCase {
 	private TreeWalk walk;
 
 	@Test
+	public void testSimpleRootGitIgnoreGlobalIgnore() throws IOException {
+		writeIgnoreFile(".gitignore", "x");
+
+		writeTrashFile("a/x/file", "");
+		writeTrashFile("b/x", "");
+		writeTrashFile("x/file", "");
+
+		beginWalk();
+		assertEntry(F, tracked, ".gitignore");
+		assertEntry(D, tracked, "a");
+		assertEntry(D, ignored, "a/x");
+		assertEntry(F, ignored, "a/x/file");
+		assertEntry(D, tracked, "b");
+		assertEntry(F, ignored, "b/x");
+		assertEntry(D, ignored, "x");
+		assertEntry(F, ignored, "x/file");
+		endWalk();
+	}
+
+	@Test
+	public void testSimpleRootGitIgnoreGlobalDirIgnore() throws IOException {
+		writeIgnoreFile(".gitignore", "x/");
+
+		writeTrashFile("a/x/file", "");
+		writeTrashFile("x/file", "");
+
+		beginWalk();
+		assertEntry(F, tracked, ".gitignore");
+		assertEntry(D, tracked, "a");
+		assertEntry(D, ignored, "a/x");
+		assertEntry(F, ignored, "a/x/file");
+		assertEntry(D, ignored, "x");
+		assertEntry(F, ignored, "x/file");
+		endWalk();
+	}
+
+	@Test
+	public void testSimpleRootGitIgnoreWildMatcher() throws IOException {
+		writeIgnoreFile(".gitignore", "**");
+
+		writeTrashFile("a/x", "");
+		writeTrashFile("y", "");
+
+		beginWalk();
+		assertEntry(F, ignored, ".gitignore");
+		assertEntry(D, ignored, "a");
+		assertEntry(F, ignored, "a/x");
+		assertEntry(F, ignored, "y");
+		endWalk();
+	}
+
+	@Test
+	public void testSimpleRootGitIgnoreWildMatcherDirOnly() throws IOException {
+		writeIgnoreFile(".gitignore", "**/");
+
+		writeTrashFile("a/x", "");
+		writeTrashFile("y", "");
+
+		beginWalk();
+		assertEntry(F, tracked, ".gitignore");
+		assertEntry(D, ignored, "a");
+		assertEntry(F, ignored, "a/x");
+		assertEntry(F, tracked, "y");
+		endWalk();
+	}
+
+	@Test
+	public void testSimpleRootGitIgnoreGlobalNegation1() throws IOException {
+		writeIgnoreFile(".gitignore", "*", "!x*");
+		writeTrashFile("x1", "");
+		writeTrashFile("a/x2", "");
+		writeTrashFile("x3/y", "");
+
+		beginWalk();
+		assertEntry(F, ignored, ".gitignore");
+		assertEntry(D, ignored, "a");
+		assertEntry(F, ignored, "a/x2");
+		assertEntry(F, tracked, "x1");
+		assertEntry(D, tracked, "x3");
+		assertEntry(F, ignored, "x3/y");
+		endWalk();
+	}
+
+	@Test
+	public void testSimpleRootGitIgnoreGlobalNegation2() throws IOException {
+		writeIgnoreFile(".gitignore", "*", "!x*", "!/a");
+		writeTrashFile("x1", "");
+		writeTrashFile("a/x2", "");
+		writeTrashFile("x3/y", "");
+
+		beginWalk();
+		assertEntry(F, ignored, ".gitignore");
+		assertEntry(D, tracked, "a");
+		assertEntry(F, tracked, "a/x2");
+		assertEntry(F, tracked, "x1");
+		assertEntry(D, tracked, "x3");
+		assertEntry(F, ignored, "x3/y");
+		endWalk();
+	}
+
+	@Test
+	public void testSimpleRootGitIgnoreGlobalNegation3() throws IOException {
+		writeIgnoreFile(".gitignore", "*", "!x*", "!x*/**");
+		writeTrashFile("x1", "");
+		writeTrashFile("a/x2", "");
+		writeTrashFile("x3/y", "");
+
+		beginWalk();
+		assertEntry(F, ignored, ".gitignore");
+		assertEntry(D, ignored, "a");
+		assertEntry(F, ignored, "a/x2");
+		assertEntry(F, tracked, "x1");
+		assertEntry(D, tracked, "x3");
+		assertEntry(F, tracked, "x3/y");
+		endWalk();
+	}
+
+	@Test
+	public void testSimpleRootGitIgnoreGlobalNegation4() throws IOException {
+		writeIgnoreFile(".gitignore", "*", "!**/");
+		writeTrashFile("x1", "");
+		writeTrashFile("a/x2", "");
+		writeTrashFile("x3/y", "");
+
+		beginWalk();
+		assertEntry(F, ignored, ".gitignore");
+		assertEntry(D, tracked, "a");
+		assertEntry(F, ignored, "a/x2");
+		assertEntry(F, ignored, "x1");
+		assertEntry(D, tracked, "x3");
+		assertEntry(F, ignored, "x3/y");
+		endWalk();
+	}
+
+	@Test
 	public void testRules() throws IOException {
 		writeIgnoreFile(".git/info/exclude", "*~", "/out");
 
@@ -209,7 +344,7 @@ public void testNegationAllExceptJavaInSrcAndExceptChildDirInSrc()
 		assertEntry(F, ignored, "src/.gitignore");
 		assertEntry(D, tracked, "src/a");
 		assertEntry(F, tracked, "src/a/keep.java");
-		assertEntry(F, tracked, "src/a/keep.o");
+		assertEntry(F, ignored, "src/a/keep.o");
 		assertEntry(F, tracked, "src/keep.java");
 		assertEntry(F, ignored, "src/nothere.o");
 		endWalk();
@@ -315,15 +450,99 @@ public void testRepeatedNegationInDifferentFiles4() throws IOException {
 	}
 
 	@Test
-	public void testEmptyIgnoreNode() {
-		// Rules are never empty: WorkingTreeIterator optimizes empty files away
-		// So we have to test it manually in case third party clients use
-		// IgnoreNode directly.
-		IgnoreNode node = new IgnoreNode();
-		assertEquals(MatchResult.CHECK_PARENT, node.isIgnored("", false));
-		assertEquals(MatchResult.CHECK_PARENT, node.isIgnored("", false, false));
-		assertEquals(MatchResult.CHECK_PARENT_NEGATE_FIRST_MATCH,
-				node.isIgnored("", false, true));
+	public void testRepeatedNegationInDifferentFiles5() throws IOException {
+		writeIgnoreFile(".gitignore", "e");
+		writeIgnoreFile("a/.gitignore", "e");
+		writeIgnoreFile("a/b/.gitignore", "!e");
+		writeTrashFile("a/b/e/nothere.o", "");
+
+		beginWalk();
+		assertEntry(F, tracked, ".gitignore");
+		assertEntry(D, tracked, "a");
+		assertEntry(F, tracked, "a/.gitignore");
+		assertEntry(D, tracked, "a/b");
+		assertEntry(F, tracked, "a/b/.gitignore");
+		assertEntry(D, tracked, "a/b/e");
+		assertEntry(F, tracked, "a/b/e/nothere.o");
+		endWalk();
+	}
+
+	@Test
+	public void testIneffectiveNegationDifferentLevels1() throws IOException {
+		writeIgnoreFile(".gitignore", "a/b/e/", "!a/b/e/*");
+		writeTrashFile("a/b/e/nothere.o", "");
+
+		beginWalk();
+		assertEntry(F, tracked, ".gitignore");
+		assertEntry(D, tracked, "a");
+		assertEntry(D, tracked, "a/b");
+		assertEntry(D, ignored, "a/b/e");
+		assertEntry(F, ignored, "a/b/e/nothere.o");
+		endWalk();
+	}
+
+	@Test
+	public void testIneffectiveNegationDifferentLevels2() throws IOException {
+		writeIgnoreFile(".gitignore", "a/b/e/");
+		writeIgnoreFile("a/.gitignore", "!b/e/*");
+		writeTrashFile("a/b/e/nothere.o", "");
+
+		beginWalk();
+		assertEntry(F, tracked, ".gitignore");
+		assertEntry(D, tracked, "a");
+		assertEntry(F, tracked, "a/.gitignore");
+		assertEntry(D, tracked, "a/b");
+		assertEntry(D, ignored, "a/b/e");
+		assertEntry(F, ignored, "a/b/e/nothere.o");
+		endWalk();
+	}
+
+	@Test
+	public void testIneffectiveNegationDifferentLevels3() throws IOException {
+		writeIgnoreFile(".gitignore", "a/b/e/");
+		writeIgnoreFile("a/b/.gitignore", "!e/*");
+		writeTrashFile("a/b/e/nothere.o", "");
+
+		beginWalk();
+		assertEntry(F, tracked, ".gitignore");
+		assertEntry(D, tracked, "a");
+		assertEntry(D, tracked, "a/b");
+		assertEntry(F, tracked, "a/b/.gitignore");
+		assertEntry(D, ignored, "a/b/e");
+		assertEntry(F, ignored, "a/b/e/nothere.o");
+		endWalk();
+	}
+
+	@Test
+	public void testIneffectiveNegationDifferentLevels4() throws IOException {
+		writeIgnoreFile(".gitignore", "a/b/e/");
+		writeIgnoreFile("a/b/e/.gitignore", "!*");
+		writeTrashFile("a/b/e/nothere.o", "");
+
+		beginWalk();
+		assertEntry(F, tracked, ".gitignore");
+		assertEntry(D, tracked, "a");
+		assertEntry(D, tracked, "a/b");
+		assertEntry(D, ignored, "a/b/e");
+		assertEntry(F, ignored, "a/b/e/.gitignore");
+		assertEntry(F, ignored, "a/b/e/nothere.o");
+		endWalk();
+	}
+
+	@Test
+	public void testIneffectiveNegationDifferentLevels5() throws IOException {
+		writeIgnoreFile("a/.gitignore", "b/e/");
+		writeIgnoreFile("a/b/.gitignore", "!e/*");
+		writeTrashFile("a/b/e/nothere.o", "");
+
+		beginWalk();
+		assertEntry(D, tracked, "a");
+		assertEntry(F, tracked, "a/.gitignore");
+		assertEntry(D, tracked, "a/b");
+		assertEntry(F, tracked, "a/b/.gitignore");
+		assertEntry(D, ignored, "a/b/e");
+		assertEntry(F, ignored, "a/b/e/nothere.o");
+		endWalk();
 	}
 
 	@Test
@@ -513,7 +732,9 @@ public void testToString() throws Exception {
 
 	private void beginWalk() {
 		walk = new TreeWalk(db);
-		walk.addTree(new FileTreeIterator(db));
+		FileTreeIterator iter = new FileTreeIterator(db);
+		iter.setWalkIgnoredDirectories(true);
+		walk.addTree(iter);
 	}
 
 	private void endWalk() throws IOException {
@@ -541,11 +762,11 @@ private void writeIgnoreFile(String name, String... rules)
 		writeTrashFile(name, data.toString());
 	}
 
-	private InputStream writeToString(String... rules) throws IOException {
+	private InputStream writeToString(String... rules) {
 		StringBuilder data = new StringBuilder();
 		for (String line : rules) {
 			data.append(line + "\n");
 		}
-		return new ByteArrayInputStream(data.toString().getBytes("UTF-8"));
+		return new ByteArrayInputStream(data.toString().getBytes(CHARSET));
 	}
 }
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/indexdiff/IndexDiffWithSymlinkTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/indexdiff/IndexDiffWithSymlinkTest.java
index 4228c9d..26c11c7 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/indexdiff/IndexDiffWithSymlinkTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/indexdiff/IndexDiffWithSymlinkTest.java
@@ -41,6 +41,7 @@
  */
 package org.eclipse.jgit.indexdiff;
 
+import static org.eclipse.jgit.lib.Constants.CHARSET;
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
@@ -60,7 +61,6 @@
 import java.io.Writer;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
-import java.nio.charset.StandardCharsets;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
@@ -111,14 +111,12 @@ public void setUp() throws Exception {
 				&& FS.DETECTED.supportsSymlinks());
 		super.setUp();
 		File testDir = createTempDirectory(this.getClass().getSimpleName());
-		InputStream in = this.getClass().getClassLoader().getResourceAsStream(
+		try (InputStream in = this.getClass().getClassLoader()
+				.getResourceAsStream(
 				this.getClass().getPackage().getName().replace('.', '/') + '/'
-						+ FILEREPO + ".txt");
-		assertNotNull("Test repo file not found", in);
-		try {
+								+ FILEREPO + ".txt")) {
+			assertNotNull("Test repo file not found", in);
 			testRepoDir = restoreGitRepo(in, testDir, FILEREPO);
-		} finally {
-			in.close();
 		}
 	}
 
@@ -130,8 +128,7 @@ private File restoreGitRepo(InputStream in, File testDir, String name)
 		File restoreScript = new File(testDir, name + ".sh");
 		try (OutputStream out = new BufferedOutputStream(
 				new FileOutputStream(restoreScript));
-				Writer writer = new OutputStreamWriter(out,
-						StandardCharsets.UTF_8)) {
+				Writer writer = new OutputStreamWriter(out, CHARSET)) {
 			writer.write("echo `which git` 1>&2\n");
 			writer.write("echo `git --version` 1>&2\n");
 			writer.write("git init " + name + " && \\\n");
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DeltaBaseCacheTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DeltaBaseCacheTest.java
index 32d711f..6a5d3c2 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DeltaBaseCacheTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DeltaBaseCacheTest.java
@@ -64,7 +64,7 @@ public class DeltaBaseCacheTest {
 	@Before
 	public void setUp() {
 		DfsRepositoryDescription repo = new DfsRepositoryDescription("test");
-		key = DfsStreamKey.of(repo, "test.key");
+		key = DfsStreamKey.of(repo, "test.key", null);
 		cache = new DeltaBaseCache(SZ);
 		rng = new TestRng(getClass().getSimpleName());
 	}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsBlockCacheTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsBlockCacheTest.java
index 2e3ee45..d29744d 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsBlockCacheTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsBlockCacheTest.java
@@ -50,6 +50,7 @@
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
+import java.util.stream.LongStream;
 
 import org.eclipse.jgit.junit.TestRng;
 import org.eclipse.jgit.lib.ObjectId;
@@ -84,9 +85,9 @@ public void streamKeyReusesBlocks() throws Exception {
 			ins.flush();
 		}
 
-		long oldSize = cache.getCurrentSize();
+		long oldSize = LongStream.of(cache.getCurrentSize()).sum();
 		assertTrue(oldSize > 2000);
-		assertEquals(0, cache.getHitCount());
+		assertEquals(0, LongStream.of(cache.getHitCount()).sum());
 
 		List<DfsPackDescription> packs = r1.getObjectDatabase().listPacks();
 		InMemoryRepository r2 = new InMemoryRepository(repo);
@@ -95,8 +96,8 @@ public void streamKeyReusesBlocks() throws Exception {
 			byte[] actual = rdr.open(id, OBJ_BLOB).getBytes();
 			assertTrue(Arrays.equals(content, actual));
 		}
-		assertEquals(0, cache.getMissCount());
-		assertEquals(oldSize, cache.getCurrentSize());
+		assertEquals(0, LongStream.of(cache.getMissCount()).sum());
+		assertEquals(oldSize, LongStream.of(cache.getCurrentSize()).sum());
 	}
 
 	@SuppressWarnings("resource")
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsGarbageCollectorTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsGarbageCollectorTest.java
index 55a5f72..5b567d0 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsGarbageCollectorTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsGarbageCollectorTest.java
@@ -9,16 +9,17 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertSame;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
 import java.io.IOException;
-import java.nio.charset.StandardCharsets;
 import java.util.Collections;
 import java.util.concurrent.TimeUnit;
 
 import org.eclipse.jgit.internal.storage.dfs.DfsObjDatabase.PackSource;
+import org.eclipse.jgit.internal.storage.dfs.DfsRefDatabase;
 import org.eclipse.jgit.internal.storage.reftable.RefCursor;
 import org.eclipse.jgit.internal.storage.reftable.ReftableConfig;
 import org.eclipse.jgit.internal.storage.reftable.ReftableReader;
@@ -722,7 +723,7 @@ public void leavesNonGcReftablesIfNotConfigured() throws Exception {
 
 		DfsPackDescription t1 = odb.newPack(INSERT);
 		try (DfsOutputStream out = odb.writeFile(t1, REFTABLE)) {
-			out.write("ignored".getBytes(StandardCharsets.UTF_8));
+			new ReftableWriter().begin(out).finish();
 			t1.addFileExt(REFTABLE);
 		}
 		odb.commitPack(Collections.singleton(t1), null);
@@ -739,9 +740,9 @@ public void leavesNonGcReftablesIfNotConfigured() throws Exception {
 		assertTrue("commit0 in pack", isObjectInPack(commit0, pack));
 		assertTrue("commit1 in pack", isObjectInPack(commit1, pack));
 
-		// Only INSERT REFTABLE above is present.
+		// A GC and the older INSERT REFTABLE above is present.
 		DfsReftable[] tables = odb.getReftables();
-		assertEquals(1, tables.length);
+		assertEquals(2, tables.length);
 		assertEquals(t1, tables[0].getPackDescription());
 	}
 
@@ -754,7 +755,7 @@ public void prunesNonGcReftables() throws Exception {
 
 		DfsPackDescription t1 = odb.newPack(INSERT);
 		try (DfsOutputStream out = odb.writeFile(t1, REFTABLE)) {
-			out.write("ignored".getBytes(StandardCharsets.UTF_8));
+			new ReftableWriter().begin(out).finish();
 			t1.addFileExt(REFTABLE);
 		}
 		odb.commitPack(Collections.singleton(t1), null);
@@ -843,6 +844,106 @@ public void compactsReftables() throws Exception {
 		}
 	}
 
+	@Test
+	public void reftableWithoutTombstoneResurrected() throws Exception {
+		RevCommit commit0 = commit().message("0").create();
+		String NEXT = "refs/heads/next";
+		DfsRefDatabase refdb = (DfsRefDatabase)repo.getRefDatabase();
+		git.update(NEXT, commit0);
+		Ref next = refdb.exactRef(NEXT);
+		assertNotNull(next);
+		assertEquals(commit0, next.getObjectId());
+
+		git.delete(NEXT);
+		refdb.clearCache();
+		assertNull(refdb.exactRef(NEXT));
+
+		DfsGarbageCollector gc = new DfsGarbageCollector(repo);
+		gc.setReftableConfig(new ReftableConfig());
+		gc.setIncludeDeletes(false);
+		gc.setConvertToReftable(false);
+		run(gc);
+		assertEquals(1, odb.getReftables().length);
+		try (DfsReader ctx = odb.newReader();
+			 ReftableReader rr = odb.getReftables()[0].open(ctx)) {
+			rr.setIncludeDeletes(true);
+			assertEquals(1, rr.minUpdateIndex());
+			assertEquals(2, rr.maxUpdateIndex());
+			assertNull(rr.exactRef(NEXT));
+		}
+
+		RevCommit commit1 = commit().message("1").create();
+		DfsPackDescription t1 = odb.newPack(INSERT);
+		Ref newNext = new ObjectIdRef.PeeledNonTag(Ref.Storage.LOOSE, NEXT,
+				commit1);
+		try (DfsOutputStream out = odb.writeFile(t1, REFTABLE)) {
+			ReftableWriter w = new ReftableWriter();
+			w.setMinUpdateIndex(1);
+			w.setMaxUpdateIndex(1);
+			w.begin(out);
+			w.writeRef(newNext, 1);
+			w.finish();
+			t1.addFileExt(REFTABLE);
+			t1.setReftableStats(w.getStats());
+		}
+		odb.commitPack(Collections.singleton(t1), null);
+		assertEquals(2, odb.getReftables().length);
+		refdb.clearCache();
+		newNext = refdb.exactRef(NEXT);
+		assertNotNull(newNext);
+		assertEquals(commit1, newNext.getObjectId());
+	}
+
+	@Test
+	public void reftableWithTombstoneNotResurrected() throws Exception {
+		RevCommit commit0 = commit().message("0").create();
+		String NEXT = "refs/heads/next";
+		DfsRefDatabase refdb = (DfsRefDatabase)repo.getRefDatabase();
+		git.update(NEXT, commit0);
+		Ref next = refdb.exactRef(NEXT);
+		assertNotNull(next);
+		assertEquals(commit0, next.getObjectId());
+
+		git.delete(NEXT);
+		refdb.clearCache();
+		assertNull(refdb.exactRef(NEXT));
+
+		DfsGarbageCollector gc = new DfsGarbageCollector(repo);
+		gc.setReftableConfig(new ReftableConfig());
+		gc.setIncludeDeletes(true);
+		gc.setConvertToReftable(false);
+		run(gc);
+		assertEquals(1, odb.getReftables().length);
+		try (DfsReader ctx = odb.newReader();
+			 ReftableReader rr = odb.getReftables()[0].open(ctx)) {
+			rr.setIncludeDeletes(true);
+			assertEquals(1, rr.minUpdateIndex());
+			assertEquals(2, rr.maxUpdateIndex());
+			next = rr.exactRef(NEXT);
+			assertNotNull(next);
+			assertNull(next.getObjectId());
+		}
+
+		RevCommit commit1 = commit().message("1").create();
+		DfsPackDescription t1 = odb.newPack(INSERT);
+		Ref newNext = new ObjectIdRef.PeeledNonTag(Ref.Storage.LOOSE, NEXT,
+				commit1);
+		try (DfsOutputStream out = odb.writeFile(t1, REFTABLE)) {
+			ReftableWriter w = new ReftableWriter();
+			w.setMinUpdateIndex(1);
+			w.setMaxUpdateIndex(1);
+			w.begin(out);
+			w.writeRef(newNext, 1);
+			w.finish();
+			t1.addFileExt(REFTABLE);
+			t1.setReftableStats(w.getStats());
+		}
+		odb.commitPack(Collections.singleton(t1), null);
+		assertEquals(2, odb.getReftables().length);
+		refdb.clearCache();
+		assertNull(refdb.exactRef(NEXT));
+	}
+
 	private TestRepository<InMemoryRepository>.CommitBuilder commit() {
 		return git.commit();
 	}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/AbbreviationTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/AbbreviationTest.java
index 343120e..1486348 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/AbbreviationTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/AbbreviationTest.java
@@ -178,7 +178,7 @@ public void testAbbreviateIsActuallyUnique() throws Exception {
 		}
 
 		String packName = "pack-" + id.name();
-		File packDir = new File(db.getObjectDatabase().getDirectory(), "pack");
+		File packDir = db.getObjectDatabase().getPackDirectory();
 		File idxFile = new File(packDir, packName + ".idx");
 		File packFile = new File(packDir, packName + ".pack");
 		FileUtils.mkdir(packDir, true);
@@ -187,7 +187,10 @@ public void testAbbreviateIsActuallyUnique() throws Exception {
 			PackIndexWriter writer = new PackIndexWriterV2(dst);
 			writer.write(objects, new byte[OBJECT_ID_LENGTH]);
 		}
-		new FileOutputStream(packFile).close();
+
+		try (FileOutputStream unused = new FileOutputStream(packFile)) {
+			// unused
+		}
 
 		assertEquals(id.abbreviate(20), reader.abbreviate(id, 2));
 
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/ConcurrentRepackTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/ConcurrentRepackTest.java
index 09438e96..643daa5 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/ConcurrentRepackTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/ConcurrentRepackTest.java
@@ -210,17 +210,17 @@ private static void whackCache() {
 		config.install();
 	}
 
-	private RevObject parse(final AnyObjectId id)
+	private RevObject parse(AnyObjectId id)
 			throws MissingObjectException, IOException {
 		try (RevWalk rw = new RevWalk(db)) {
 			return rw.parseAny(id);
 		}
 	}
 
-	private File[] pack(final Repository src, final RevObject... list)
+	private File[] pack(Repository src, RevObject... list)
 			throws IOException {
 		try (PackWriter pw = new PackWriter(src)) {
-			for (final RevObject o : list) {
+			for (RevObject o : list) {
 				pw.addObject(o);
 			}
 
@@ -233,7 +233,7 @@ private RevObject parse(final AnyObjectId id)
 		}
 	}
 
-	private static void write(final File[] files, final PackWriter pw)
+	private static void write(File[] files, PackWriter pw)
 			throws IOException {
 		final long begin = files[0].getParentFile().lastModified();
 		NullProgressMonitor m = NullProgressMonitor.INSTANCE;
@@ -251,16 +251,16 @@ private static void write(final File[] files, final PackWriter pw)
 		touch(begin, files[0].getParentFile());
 	}
 
-	private static void delete(final File[] list) throws IOException {
+	private static void delete(File[] list) throws IOException {
 		final long begin = list[0].getParentFile().lastModified();
-		for (final File f : list) {
+		for (File f : list) {
 			FileUtils.delete(f);
 			assertFalse(f + " was removed", f.exists());
 		}
 		touch(begin, list[0].getParentFile());
 	}
 
-	private static void touch(final long begin, final File dir) {
+	private static void touch(long begin, File dir) {
 		while (begin >= dir.lastModified()) {
 			try {
 				Thread.sleep(25);
@@ -271,12 +271,12 @@ private static void touch(final long begin, final File dir) {
 		}
 	}
 
-	private File fullPackFileName(final ObjectId name, final String suffix) {
-		final File packdir = new File(db.getObjectDatabase().getDirectory(), "pack");
+	private File fullPackFileName(ObjectId name, String suffix) {
+		final File packdir = db.getObjectDatabase().getPackDirectory();
 		return new File(packdir, "pack-" + name.name() + suffix);
 	}
 
-	private RevObject writeBlob(final Repository repo, final String data)
+	private RevObject writeBlob(Repository repo, String data)
 			throws IOException {
 		final byte[] bytes = Constants.encode(data);
 		final ObjectId id;
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/FileSnapshotTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/FileSnapshotTest.java
index 9998666..9ceaa34 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/FileSnapshotTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/FileSnapshotTest.java
@@ -135,11 +135,8 @@ private File createFile(String string) throws IOException {
 	}
 
 	private static void append(File f, byte b) throws IOException {
-		FileOutputStream os = new FileOutputStream(f, true);
-		try {
+		try (FileOutputStream os = new FileOutputStream(f, true)) {
 			os.write(b);
-		} finally {
-			os.close();
 		}
 	}
 
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcDeleteEmptyRefsFoldersTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcDeleteEmptyRefsFoldersTest.java
new file mode 100644
index 0000000..76e1534
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcDeleteEmptyRefsFoldersTest.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2018 Ericsson
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ *   copyright notice, this list of conditions and the following
+ *   disclaimer in the documentation and/or other materials provided
+ *   with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ *   names of its contributors may be used to endorse or promote
+ *   products derived from this software without specific prior
+ *   written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.internal.storage.file;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.attribute.FileTime;
+import java.time.Instant;
+
+import org.junit.Before;
+import org.junit.Test;
+
+public class GcDeleteEmptyRefsFoldersTest extends GcTestCase {
+	private static final String REF_FOLDER_01 = "01";
+	private static final String REF_FOLDER_02 = "02";
+
+	private Path refsDir;
+	private Path heads;
+
+	@Override
+	@Before
+	public void setUp() throws Exception {
+		super.setUp();
+		refsDir = Paths.get(repo.getDirectory().getAbsolutePath())
+				.resolve("refs");
+		heads = refsDir.resolve("heads");
+	}
+
+	@Test
+	public void emptyRefFoldersAreDeleted() throws Exception {
+		FileTime fileTime = FileTime.from(Instant.now().minusSeconds(31));
+		Path refDir01 = Files.createDirectory(heads.resolve(REF_FOLDER_01));
+		Path refDir02 = Files.createDirectory(heads.resolve(REF_FOLDER_02));
+		Files.setLastModifiedTime(refDir01, fileTime);
+		Files.setLastModifiedTime(refDir02, fileTime);
+		assertTrue(refDir01.toFile().exists());
+		assertTrue(refDir02.toFile().exists());
+		gc.gc();
+
+		assertFalse(refDir01.toFile().exists());
+		assertFalse(refDir02.toFile().exists());
+	}
+
+	@Test
+	public void emptyRefFoldersAreKeptIfTheyAreTooRecent()
+			throws Exception {
+		Path refDir01 = Files.createDirectory(heads.resolve(REF_FOLDER_01));
+		Path refDir02 = Files.createDirectory(heads.resolve(REF_FOLDER_02));
+		assertTrue(refDir01.toFile().exists());
+		assertTrue(refDir02.toFile().exists());
+		gc.gc();
+
+		assertTrue(refDir01.toFile().exists());
+		assertTrue(refDir02.toFile().exists());
+	}
+
+	@Test
+	public void nonEmptyRefsFoldersAreKept() throws Exception {
+		Path refDir01 = Files.createDirectory(heads.resolve(REF_FOLDER_01));
+		Path refDir02 = Files.createDirectory(heads.resolve(REF_FOLDER_02));
+		Path ref01 = Files.createFile(refDir01.resolve("ref01"));
+		Path ref02 = Files.createFile(refDir01.resolve("ref02"));
+		assertTrue(refDir01.toFile().exists());
+		assertTrue(refDir02.toFile().exists());
+		assertTrue(ref01.toFile().exists());
+		assertTrue(ref02.toFile().exists());
+		gc.gc();
+		assertTrue(refDir01.toFile().exists());
+		assertTrue(refDir02.toFile().exists());
+		assertTrue(ref01.toFile().exists());
+		assertTrue(ref02.toFile().exists());
+	}
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcOrphanFilesTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcOrphanFilesTest.java
index 5393987..79d72c5 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcOrphanFilesTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcOrphanFilesTest.java
@@ -71,7 +71,7 @@ public class GcOrphanFilesTest extends GcTestCase {
 	@Before
 	public void setUp() throws Exception {
 		super.setUp();
-		packDir = new File(repo.getObjectsDirectory(), PACK);
+		packDir = repo.getObjectDatabase().getPackDirectory();
 	}
 
 	@Test
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/ObjectDirectoryTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/ObjectDirectoryTest.java
index f1cbb99..cbb73bb 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/ObjectDirectoryTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/ObjectDirectoryTest.java
@@ -129,8 +129,8 @@ public void testScanningForPackfiles() throws Exception {
 			assertTrue(receivingDB.getObjectDatabase().hasPackedObject(id));
 
 			// preparations
-			File packsFolder = new File(receivingDB.getObjectsDirectory(),
-					"pack");
+			File packsFolder = receivingDB.getObjectDatabase()
+					.getPackDirectory();
 			// prepare creation of a temporary file in the pack folder. This
 			// simulates that a native git gc is happening starting to write
 			// temporary files but has not yet finished
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackFileTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackFileTest.java
index 91bd523..04fccf3 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackFileTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackFileTest.java
@@ -146,15 +146,15 @@ public void testWhole_SmallObject() throws Exception {
 		assertFalse("is not large", ol.isLarge());
 		assertTrue("same content", Arrays.equals(data, ol.getCachedBytes()));
 
-		ObjectStream in = ol.openStream();
-		assertNotNull("have stream", in);
-		assertEquals(type, in.getType());
-		assertEquals(data.length, in.getSize());
-		byte[] data2 = new byte[data.length];
-		IO.readFully(in, data2, 0, data.length);
-		assertTrue("same content", Arrays.equals(data2, data));
-		assertEquals("stream at EOF", -1, in.read());
-		in.close();
+		try (ObjectStream in = ol.openStream()) {
+			assertNotNull("have stream", in);
+			assertEquals(type, in.getType());
+			assertEquals(data.length, in.getSize());
+			byte[] data2 = new byte[data.length];
+			IO.readFully(in, data2, 0, data.length);
+			assertTrue("same content", Arrays.equals(data2, data));
+			assertEquals("stream at EOF", -1, in.read());
+		}
 	}
 
 	@Test
@@ -180,15 +180,15 @@ public void testWhole_LargeObject() throws Exception {
 					.getMessage());
 		}
 
-		ObjectStream in = ol.openStream();
-		assertNotNull("have stream", in);
-		assertEquals(type, in.getType());
-		assertEquals(data.length, in.getSize());
-		byte[] data2 = new byte[data.length];
-		IO.readFully(in, data2, 0, data.length);
-		assertTrue("same content", Arrays.equals(data2, data));
-		assertEquals("stream at EOF", -1, in.read());
-		in.close();
+		try (ObjectStream in = ol.openStream()) {
+			assertNotNull("have stream", in);
+			assertEquals(type, in.getType());
+			assertEquals(data.length, in.getSize());
+			byte[] data2 = new byte[data.length];
+			IO.readFully(in, data2, 0, data.length);
+			assertTrue("same content", Arrays.equals(data2, data));
+			assertEquals("stream at EOF", -1, in.read());
+		}
 	}
 
 	@Test
@@ -239,15 +239,15 @@ public void testDelta_SmallObjectChain() throws Exception {
 			assertNotNull(ol.getCachedBytes());
 			assertArrayEquals(data3, ol.getCachedBytes());
 
-			ObjectStream in = ol.openStream();
-			assertNotNull("have stream", in);
-			assertEquals(Constants.OBJ_BLOB, in.getType());
-			assertEquals(data3.length, in.getSize());
-			byte[] act = new byte[data3.length];
-			IO.readFully(in, act, 0, data3.length);
-			assertTrue("same content", Arrays.equals(act, data3));
-			assertEquals("stream at EOF", -1, in.read());
-			in.close();
+			try (ObjectStream in = ol.openStream()) {
+				assertNotNull("have stream", in);
+				assertEquals(Constants.OBJ_BLOB, in.getType());
+				assertEquals(data3.length, in.getSize());
+				byte[] act = new byte[data3.length];
+				IO.readFully(in, act, 0, data3.length);
+				assertTrue("same content", Arrays.equals(act, data3));
+				assertEquals("stream at EOF", -1, in.read());
+			}
 		}
 	}
 
@@ -282,22 +282,16 @@ public void testDelta_FailsOver2GiB() throws Exception {
 			File packName = new File(dir, idA.name() + ".pack");
 			File idxName = new File(dir, idA.name() + ".idx");
 
-			FileOutputStream f = new FileOutputStream(packName);
-			try {
+			try (FileOutputStream f = new FileOutputStream(packName)) {
 				f.write(pack.toByteArray());
-			} finally {
-				f.close();
 			}
 
-			f = new FileOutputStream(idxName);
-			try {
+			try (FileOutputStream f = new FileOutputStream(idxName)) {
 				List<PackedObjectInfo> list = new ArrayList<>();
 				list.add(a);
 				list.add(b);
 				Collections.sort(list);
 				new PackIndexWriterV1(f).write(list, footer);
-			} finally {
-				f.close();
 			}
 
 			PackFile packFile = new PackFile(packName, PackExt.INDEX.getBit());
@@ -321,16 +315,17 @@ public void testConfigurableStreamFileThreshold() throws Exception {
 		assertTrue("has blob", wc.has(id));
 
 		ObjectLoader ol = wc.open(id);
-		ObjectStream in = ol.openStream();
-		assertTrue(in instanceof ObjectStream.SmallStream);
-		assertEquals(300, in.available());
-		in.close();
+		try (ObjectStream in = ol.openStream()) {
+			assertTrue(in instanceof ObjectStream.SmallStream);
+			assertEquals(300, in.available());
+		}
 
 		wc.setStreamFileThreshold(299);
 		ol = wc.open(id);
-		in = ol.openStream();
-		assertTrue(in instanceof ObjectStream.Filter);
-		assertEquals(1, in.available());
+		try (ObjectStream in = ol.openStream()) {
+			assertTrue(in instanceof ObjectStream.Filter);
+			assertEquals(1, in.available());
+		}
 	}
 
 	private static byte[] clone(int first, byte[] base) {
@@ -372,7 +367,7 @@ private static void objectHeader(TemporaryBuffer.Heap pack, int type, int sz)
 		pack.write(buf, 0, n);
 	}
 
-	private static void deflate(TemporaryBuffer.Heap pack, final byte[] content)
+	private static void deflate(TemporaryBuffer.Heap pack, byte[] content)
 			throws IOException {
 		final Deflater deflater = new Deflater();
 		final byte[] buf = new byte[128];
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackInserterTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackInserterTest.java
index 8596f74..8e438bc 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackInserterTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackInserterTest.java
@@ -95,6 +95,8 @@
 public class PackInserterTest extends RepositoryTestCase {
 	private WindowCacheConfig origWindowCacheConfig;
 
+	private static final Random random = new Random(0);
+
 	@Before
 	public void setWindowCacheConfig() {
 		origWindowCacheConfig = new WindowCacheConfig();
@@ -518,7 +520,7 @@ private PackInserter newInserter() {
 
 	private static byte[] newLargeBlob() {
 		byte[] blob = new byte[10240];
-		new Random(0).nextBytes(blob);
+		random.nextBytes(blob);
 		return blob;
 	}
 
@@ -575,9 +577,12 @@ void assertNoBadFiles(File f) throws IOException {
 
 		@Override
 		public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
-			String name = file.getFileName().toString();
-			if (!attrs.isDirectory() && badName.test(name)) {
-				bad.add(name);
+			Path fileName = file.getFileName();
+			if (fileName != null) {
+				String name = fileName.toString();
+				if (!attrs.isDirectory() && badName.test(name)) {
+					bad.add(name);
+				}
 			}
 			return FileVisitResult.CONTINUE;
 		}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackWriterTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackWriterTest.java
index 9b97eb4..04bed09 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackWriterTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackWriterTest.java
@@ -337,7 +337,7 @@ public void testWritePack2DeltasReuseOffsets() throws IOException {
 	 */
 	@Test
 	public void testWritePack2DeltasCRC32Copy() throws IOException {
-		final File packDir = new File(db.getObjectDatabase().getDirectory(), "pack");
+		final File packDir = db.getObjectDatabase().getPackDirectory();
 		final File crc32Pack = new File(packDir,
 				"pack-34be9032ac282b11fa9babdc2b2a93ca996c9c2f.pack");
 		final File crc32Idx = new File(packDir,
@@ -368,7 +368,7 @@ public void testWritePack3() throws MissingObjectException, IOException {
 				ObjectId.fromString("902d5476fa249b7abc9d84c611577a81381f0327"),
 				ObjectId.fromString("6ff87c4664981e4397625791c8ea3bbb5f2279a3") ,
 				ObjectId.fromString("5b6e7c66c276e7610d4a73c70ec1a1f7c1003259") };
-		try (final RevWalk parser = new RevWalk(db)) {
+		try (RevWalk parser = new RevWalk(db)) {
 			final RevObject forcedOrderRevs[] = new RevObject[forcedOrder.length];
 			for (int i = 0; i < forcedOrder.length; i++)
 				forcedOrderRevs[i] = parser.parseAny(forcedOrder[i]);
@@ -515,11 +515,8 @@ public void testWriteIndex() throws Exception {
 
 		// Validate that an index written by PackWriter is the same.
 		final File idx2File = new File(indexFile.getAbsolutePath() + ".2");
-		final FileOutputStream is = new FileOutputStream(idx2File);
-		try {
+		try (FileOutputStream is = new FileOutputStream(idx2File)) {
 			writer.writeIndex(is);
-		} finally {
-			is.close();
 		}
 		final PackIndex idx2 = PackIndex.open(idx2File);
 		assertTrue(idx2 instanceof PackIndexV2);
@@ -713,16 +710,16 @@ private static PackIndex writePack(FileRepository repo, RevWalk walk,
 
 			pw.preparePack(NullProgressMonitor.INSTANCE, ow, want, have, NONE);
 			String id = pw.computeName().getName();
-			File packdir = new File(repo.getObjectsDirectory(), "pack");
+			File packdir = repo.getObjectDatabase().getPackDirectory();
 			File packFile = new File(packdir, "pack-" + id + ".pack");
-			FileOutputStream packOS = new FileOutputStream(packFile);
-			pw.writePack(NullProgressMonitor.INSTANCE,
-					NullProgressMonitor.INSTANCE, packOS);
-			packOS.close();
+			try (FileOutputStream packOS = new FileOutputStream(packFile)) {
+				pw.writePack(NullProgressMonitor.INSTANCE,
+						NullProgressMonitor.INSTANCE, packOS);
+			}
 			File idxFile = new File(packdir, "pack-" + id + ".idx");
-			FileOutputStream idxOS = new FileOutputStream(idxFile);
-			pw.writeIndex(idxOS);
-			idxOS.close();
+			try (FileOutputStream idxOS = new FileOutputStream(idxFile)) {
+				pw.writeIndex(idxOS);
+			}
 			return PackIndex.open(idxFile);
 		}
 	}
@@ -838,7 +835,7 @@ private void createVerifyOpenPack(final Set<ObjectId> interestings,
 		verifyOpenPack(thin);
 	}
 
-	private void createVerifyOpenPack(final List<RevObject> objectSource)
+	private void createVerifyOpenPack(List<RevObject> objectSource)
 			throws MissingObjectException, IOException {
 		NullProgressMonitor m = NullProgressMonitor.INSTANCE;
 		writer = new PackWriter(config, db.newObjectReader());
@@ -849,7 +846,7 @@ private void createVerifyOpenPack(final List<RevObject> objectSource)
 		verifyOpenPack(false);
 	}
 
-	private void verifyOpenPack(final boolean thin) throws IOException {
+	private void verifyOpenPack(boolean thin) throws IOException {
 		final byte[] packData = os.toByteArray();
 
 		if (thin) {
@@ -871,13 +868,13 @@ private void verifyOpenPack(final boolean thin) throws IOException {
 		assertNotNull("have PackFile after parsing", pack);
 	}
 
-	private PackParser index(final byte[] packData) throws IOException {
+	private PackParser index(byte[] packData) throws IOException {
 		if (inserter == null)
 			inserter = dst.newObjectInserter();
 		return inserter.newPackParser(new ByteArrayInputStream(packData));
 	}
 
-	private void verifyObjectsOrder(final ObjectId objectsOrder[]) {
+	private void verifyObjectsOrder(ObjectId objectsOrder[]) {
 		final List<PackIndex.MutableEntry> entries = new ArrayList<>();
 
 		for (MutableEntry me : pack) {
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/RefDirectoryTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/RefDirectoryTest.java
index fefccf3..5a2bd9c 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/RefDirectoryTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/RefDirectoryTest.java
@@ -1271,7 +1271,7 @@ public void testRefsChangedStackOverflow() throws Exception {
 					@Override
 					public void onRefsChanged(RefsChangedEvent event) {
 						try {
-							refDb.getRefs("ref");
+							refDb.getRefsByPrefix("ref");
 							changeCount.incrementAndGet();
 						} catch (StackOverflowError soe) {
 							error.set(soe);
@@ -1280,8 +1280,8 @@ public void onRefsChanged(RefsChangedEvent event) {
 						}
 					}
 				});
-		refDb.getRefs("ref");
-		refDb.getRefs("ref");
+		refDb.getRefsByPrefix("ref");
+		refDb.getRefsByPrefix("ref");
 		assertNull(error.get());
 		assertNull(exception.get());
 		assertEquals(1, changeCount.get());
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/RefUpdateTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/RefUpdateTest.java
index 52861ec..b2fae31 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/RefUpdateTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/RefUpdateTest.java
@@ -45,8 +45,9 @@
 
 package org.eclipse.jgit.internal.storage.file;
 
-import static java.nio.charset.StandardCharsets.UTF_8;
 import static org.eclipse.jgit.junit.Assert.assertEquals;
+import static org.eclipse.jgit.lib.Constants.CHARSET;
+import static org.eclipse.jgit.lib.Constants.LOCK_SUFFIX;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
@@ -93,13 +94,13 @@ private void writeSymref(String src, String dst) throws IOException {
 		}
 	}
 
-	private RefUpdate updateRef(final String name) throws IOException {
+	private RefUpdate updateRef(String name) throws IOException {
 		final RefUpdate ref = db.updateRef(name);
 		ref.setNewObjectId(db.resolve(Constants.HEAD));
 		return ref;
 	}
 
-	private void delete(final RefUpdate ref, final Result expected)
+	private void delete(RefUpdate ref, Result expected)
 			throws IOException {
 		delete(ref, expected, true, true);
 	}
@@ -252,7 +253,7 @@ public void testDeleteHeadInBareRepo() throws IOException {
 
 		ObjectId blobId;
 		try (ObjectInserter ins = bareRepo.newObjectInserter()) {
-			blobId = ins.insert(Constants.OBJ_BLOB, "contents".getBytes(UTF_8));
+			blobId = ins.insert(Constants.OBJ_BLOB, "contents".getBytes(CHARSET));
 			ins.flush();
 		}
 
@@ -819,11 +820,11 @@ public void tryRenameWhenLocked(String toLock, String fromName,
 			// Check that the involved refs are the same despite the failure
 			assertExists(false, toName);
 			if (!toLock.equals(toName))
-				assertExists(false, toName + ".lock");
-			assertExists(true, toLock + ".lock");
+				assertExists(false, toName + LOCK_SUFFIX);
+			assertExists(true, toLock + LOCK_SUFFIX);
 			if (!toLock.equals(fromName))
-				assertExists(false, "logs/" + fromName + ".lock");
-			assertExists(false, "logs/" + toName + ".lock");
+				assertExists(false, "logs/" + fromName + LOCK_SUFFIX);
+			assertExists(false, "logs/" + toName + LOCK_SUFFIX);
 			assertEquals(oldHeadId, db.resolve(Constants.HEAD));
 			assertEquals(oldfromId, db.resolve(fromName));
 			assertNull(db.resolve(toName));
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/ReflogReaderTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/ReflogReaderTest.java
index 63bd7f4..dc05eea 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/ReflogReaderTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/ReflogReaderTest.java
@@ -270,19 +270,16 @@ public void testSpecificEntryNumber() throws Exception {
 
 	private void setupReflog(String logName, byte[] data)
 			throws FileNotFoundException, IOException {
-				File logfile = new File(db.getDirectory(), logName);
-				if (!logfile.getParentFile().mkdirs()
-						&& !logfile.getParentFile().isDirectory()) {
-					throw new IOException(
-							"oops, cannot create the directory for the test reflog file"
-									+ logfile);
-				}
-				FileOutputStream fileOutputStream = new FileOutputStream(logfile);
-				try {
-					fileOutputStream.write(data);
-				} finally {
-					fileOutputStream.close();
-				}
-			}
+		File logfile = new File(db.getDirectory(), logName);
+		if (!logfile.getParentFile().mkdirs()
+				&& !logfile.getParentFile().isDirectory()) {
+			throw new IOException(
+					"oops, cannot create the directory for the test reflog file"
+							+ logfile);
+		}
+		try (FileOutputStream fileOutputStream = new FileOutputStream(logfile)) {
+			fileOutputStream.write(data);
+		}
+	}
 
 }
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/ReflogWriterTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/ReflogWriterTest.java
index 7f40bae..1d188c3 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/ReflogWriterTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/ReflogWriterTest.java
@@ -87,11 +87,8 @@ private void readReflog(byte[] buffer)
 					"oops, cannot create the directory for the test reflog file"
 							+ logfile);
 		}
-		FileInputStream fileInputStream = new FileInputStream(logfile);
-		try {
+		try (FileInputStream fileInputStream = new FileInputStream(logfile)) {
 			fileInputStream.read(buffer);
-		} finally {
-			fileInputStream.close();
 		}
 	}
 }
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/T0003_BasicTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/T0003_BasicTest.java
index 9d23d83..e113db1 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/T0003_BasicTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/T0003_BasicTest.java
@@ -46,6 +46,8 @@
 
 package org.eclipse.jgit.internal.storage.file;
 
+import static java.nio.charset.StandardCharsets.ISO_8859_1;
+import static org.eclipse.jgit.lib.Constants.CHARSET;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
@@ -55,7 +57,6 @@
 
 import java.io.File;
 import java.io.FileInputStream;
-import java.io.FileReader;
 import java.io.IOException;
 import java.io.UnsupportedEncodingException;
 
@@ -82,6 +83,7 @@
 import org.eclipse.jgit.storage.file.FileRepositoryBuilder;
 import org.eclipse.jgit.test.resources.SampleDataRepositoryTestCase;
 import org.eclipse.jgit.util.FileUtils;
+import org.eclipse.jgit.util.IO;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.ExpectedException;
@@ -135,10 +137,10 @@ public void test000_openRepoBadArgs() throws IOException {
 	@Test
 	public void test000_openrepo_default_gitDirSet() throws IOException {
 		File repo1Parent = new File(trash.getParentFile(), "r1");
-		Repository repo1initial = new FileRepository(new File(repo1Parent,
-				Constants.DOT_GIT));
-		repo1initial.create();
-		repo1initial.close();
+		try (Repository repo1initial = new FileRepository(
+				new File(repo1Parent, Constants.DOT_GIT))) {
+			repo1initial.create();
+		}
 
 		File theDir = new File(repo1Parent, Constants.DOT_GIT);
 		FileRepository r = (FileRepository) new FileRepositoryBuilder()
@@ -160,10 +162,10 @@ public void test000_openrepo_default_gitDirSet() throws IOException {
 	public void test000_openrepo_default_gitDirAndWorkTreeSet()
 			throws IOException {
 		File repo1Parent = new File(trash.getParentFile(), "r1");
-		Repository repo1initial = new FileRepository(new File(repo1Parent,
-				Constants.DOT_GIT));
-		repo1initial.create();
-		repo1initial.close();
+		try (Repository repo1initial = new FileRepository(
+				new File(repo1Parent, Constants.DOT_GIT))) {
+			repo1initial.create();
+		}
 
 		File theDir = new File(repo1Parent, Constants.DOT_GIT);
 		FileRepository r = (FileRepository) new FileRepositoryBuilder()
@@ -185,10 +187,10 @@ public void test000_openrepo_default_gitDirAndWorkTreeSet()
 	@Test
 	public void test000_openrepo_default_workDirSet() throws IOException {
 		File repo1Parent = new File(trash.getParentFile(), "r1");
-		Repository repo1initial = new FileRepository(new File(repo1Parent,
-				Constants.DOT_GIT));
-		repo1initial.create();
-		repo1initial.close();
+		try (Repository repo1initial = new FileRepository(
+				new File(repo1Parent, Constants.DOT_GIT))) {
+			repo1initial.create();
+		}
 
 		File theDir = new File(repo1Parent, Constants.DOT_GIT);
 		FileRepository r = (FileRepository) new FileRepositoryBuilder()
@@ -211,13 +213,13 @@ public void test000_openrepo_default_absolute_workdirconfig()
 		File repo1Parent = new File(trash.getParentFile(), "r1");
 		File workdir = new File(trash.getParentFile(), "rw");
 		FileUtils.mkdir(workdir);
-		FileRepository repo1initial = new FileRepository(new File(repo1Parent,
-				Constants.DOT_GIT));
-		repo1initial.create();
-		final FileBasedConfig cfg = repo1initial.getConfig();
-		cfg.setString("core", null, "worktree", workdir.getAbsolutePath());
-		cfg.save();
-		repo1initial.close();
+		try (FileRepository repo1initial = new FileRepository(
+				new File(repo1Parent, Constants.DOT_GIT))) {
+			repo1initial.create();
+			final FileBasedConfig cfg = repo1initial.getConfig();
+			cfg.setString("core", null, "worktree", workdir.getAbsolutePath());
+			cfg.save();
+		}
 
 		File theDir = new File(repo1Parent, Constants.DOT_GIT);
 		FileRepository r = (FileRepository) new FileRepositoryBuilder()
@@ -240,13 +242,13 @@ public void test000_openrepo_default_relative_workdirconfig()
 		File repo1Parent = new File(trash.getParentFile(), "r1");
 		File workdir = new File(trash.getParentFile(), "rw");
 		FileUtils.mkdir(workdir);
-		FileRepository repo1initial = new FileRepository(new File(repo1Parent,
-				Constants.DOT_GIT));
-		repo1initial.create();
-		final FileBasedConfig cfg = repo1initial.getConfig();
-		cfg.setString("core", null, "worktree", "../../rw");
-		cfg.save();
-		repo1initial.close();
+		try (FileRepository repo1initial = new FileRepository(
+				new File(repo1Parent, Constants.DOT_GIT))) {
+			repo1initial.create();
+			final FileBasedConfig cfg = repo1initial.getConfig();
+			cfg.setString("core", null, "worktree", "../../rw");
+			cfg.save();
+		}
 
 		File theDir = new File(repo1Parent, Constants.DOT_GIT);
 		FileRepository r = (FileRepository) new FileRepositoryBuilder()
@@ -271,26 +273,24 @@ public void test000_openrepo_alternate_index_file_and_objdirs()
 		File indexFile = new File(trash, "idx");
 		File objDir = new File(trash, "../obj");
 		File altObjDir = db.getObjectDatabase().getDirectory();
-		Repository repo1initial = new FileRepository(new File(repo1Parent,
-				Constants.DOT_GIT));
-		repo1initial.create();
-		repo1initial.close();
+		try (Repository repo1initial = new FileRepository(
+				new File(repo1Parent, Constants.DOT_GIT))) {
+			repo1initial.create();
+		}
 
 		File theDir = new File(repo1Parent, Constants.DOT_GIT);
-		FileRepository r = (FileRepository) new FileRepositoryBuilder() //
+		try (FileRepository r = (FileRepository) new FileRepositoryBuilder() //
 				.setGitDir(theDir).setObjectDirectory(objDir) //
 				.addAlternateObjectDirectory(altObjDir) //
 				.setIndexFile(indexFile) //
-				.build();
-		assertEqualsPath(theDir, r.getDirectory());
-		assertEqualsPath(theDir.getParentFile(), r.getWorkTree());
-		assertEqualsPath(indexFile, r.getIndexFile());
-		assertEqualsPath(objDir, r.getObjectDatabase().getDirectory());
-		assertNotNull(r.open(ObjectId
-				.fromString("6db9c2ebf75590eef973081736730a9ea169a0c4")));
-		// Must close or the default repo pack files created by this test gets
-		// locked via the alternate object directories on Windows.
-		r.close();
+				.build()) {
+			assertEqualsPath(theDir, r.getDirectory());
+			assertEqualsPath(theDir.getParentFile(), r.getWorkTree());
+			assertEqualsPath(indexFile, r.getIndexFile());
+			assertEqualsPath(objDir, r.getObjectDatabase().getDirectory());
+			assertNotNull(r.open(ObjectId
+					.fromString("6db9c2ebf75590eef973081736730a9ea169a0c4")));
+		}
 	}
 
 	protected void assertEqualsPath(File expected, File actual)
@@ -305,7 +305,7 @@ public void test002_WriteEmptyTree() throws IOException {
 		// object (as it already exists in the pack).
 		//
 		final Repository newdb = createBareRepository();
-		try (final ObjectInserter oi = newdb.newObjectInserter()) {
+		try (ObjectInserter oi = newdb.newObjectInserter()) {
 			final ObjectId treeId = oi.insert(new TreeFormatter());
 			assertEquals("4b825dc642cb6eb9a060e54bf8d69288fbee4904",
 					treeId.name());
@@ -360,16 +360,20 @@ public void test006_ReadUglyConfig() throws IOException,
 		assertEquals("a many line\ncomment\n to test", c.getString("user",
 				null, "defaultCheckInComment"));
 		c.save();
-		final FileReader fr = new FileReader(cfg);
-		final char[] cbuf = new char[configStr.length()];
-		fr.read(cbuf);
-		fr.close();
-		assertEquals(configStr, new String(cbuf));
+
+		// Saving normalizes out the weird "\\n\\\n" to a single escaped newline,
+		// and quotes the whole string.
+		final String expectedStr = "  [core];comment\n\tfilemode = yes\n"
+				+ "[user]\n"
+				+ "  email = A U Thor <thor@example.com> # Just an example...\n"
+				+ " name = \"A  Thor \\\\ \\\"\\t \"\n"
+				+ "    defaultCheckInComment = a many line\\ncomment\\n to test\n";
+		assertEquals(expectedStr, new String(IO.readFully(cfg), Constants.CHARSET));
 	}
 
 	@Test
 	public void test007_Open() throws IOException {
-		try (final FileRepository db2 = new FileRepository(db.getDirectory())) {
+		try (FileRepository db2 = new FileRepository(db.getDirectory())) {
 			assertEquals(db.getDirectory(), db2.getDirectory());
 			assertEquals(db.getObjectDatabase().getDirectory(), db2
 					.getObjectDatabase().getDirectory());
@@ -411,14 +415,11 @@ public void test009_CreateCommitOldFormat() throws IOException {
 		// Verify the commit we just wrote is in the correct format.
 		ObjectDatabase odb = db.getObjectDatabase();
 		assertTrue("is ObjectDirectory", odb instanceof ObjectDirectory);
-		final XInputStream xis = new XInputStream(new FileInputStream(
-				((ObjectDirectory) odb).fileFor(cmtid)));
-		try {
+		try (XInputStream xis = new XInputStream(
+				new FileInputStream(((ObjectDirectory) odb).fileFor(cmtid)))) {
 			assertEquals(0x78, xis.readUInt8());
 			assertEquals(0x9c, xis.readUInt8());
 			assertEquals(0, 0x789c % 31);
-		} finally {
-			xis.close();
 		}
 
 		// Verify we can read it.
@@ -516,7 +517,7 @@ public void test023_createCommitNonAnullii() throws IOException {
 				4294967295000L, 60));
 		commit.setCommitter(new PersonIdent("Joe Hacker", "joe2@example.com",
 				4294967295000L, 60));
-		commit.setEncoding("UTF-8");
+		commit.setEncoding(CHARSET);
 		commit.setMessage("\u00dcbergeeks");
 		ObjectId cid = insertCommit(commit);
 		assertEquals("4680908112778718f37e686cbebcc912730b3154", cid.name());
@@ -544,9 +545,9 @@ public void test024_createCommitNonAscii() throws IOException {
 	}
 
 	@Test
-	public void test025_computeSha1NoStore() throws IOException {
+	public void test025_computeSha1NoStore() {
 		byte[] data = "test025 some data, more than 16 bytes to get good coverage"
-				.getBytes("ISO-8859-1");
+				.getBytes(ISO_8859_1);
 		try (ObjectInserter.Formatter formatter = new ObjectInserter.Formatter()) {
 			final ObjectId id = formatter.idFor(Constants.OBJ_BLOB, data);
 			assertEquals("4f561df5ecf0dfbd53a0dc0f37262fef075d9dde", id.name());
@@ -556,7 +557,7 @@ public void test025_computeSha1NoStore() throws IOException {
 	@Test
 	public void test026_CreateCommitMultipleparents() throws IOException {
 		final ObjectId treeId;
-		try (final ObjectInserter oi = db.newObjectInserter()) {
+		try (ObjectInserter oi = db.newObjectInserter()) {
 			final ObjectId blobId = oi.insert(Constants.OBJ_BLOB,
 					"and this is the data in me\n".getBytes(Constants.CHARSET
 							.name()));
@@ -746,7 +747,7 @@ private ObjectId insertTree(TreeFormatter tree) throws IOException {
 		}
 	}
 
-	private ObjectId insertCommit(final CommitBuilder builder)
+	private ObjectId insertCommit(CommitBuilder builder)
 			throws IOException, UnsupportedEncodingException {
 		try (ObjectInserter oi = db.newObjectInserter()) {
 			ObjectId id = oi.insert(builder);
@@ -763,7 +764,7 @@ private RevCommit parseCommit(AnyObjectId id)
 		}
 	}
 
-	private ObjectId insertTag(final TagBuilder tag) throws IOException,
+	private ObjectId insertTag(TagBuilder tag) throws IOException,
 			UnsupportedEncodingException {
 		try (ObjectInserter oi = db.newObjectInserter()) {
 			ObjectId id = oi.insert(tag);
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/UnpackedObjectTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/UnpackedObjectTest.java
index c5ab766..98ff04e 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/UnpackedObjectTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/UnpackedObjectTest.java
@@ -130,15 +130,15 @@ public void testStandardFormat_SmallObject() throws Exception {
 		assertFalse("is not large", ol.isLarge());
 		assertTrue("same content", Arrays.equals(data, ol.getCachedBytes()));
 
-		ObjectStream in = ol.openStream();
-		assertNotNull("have stream", in);
-		assertEquals(type, in.getType());
-		assertEquals(data.length, in.getSize());
-		byte[] data2 = new byte[data.length];
-		IO.readFully(in, data2, 0, data.length);
-		assertTrue("same content", Arrays.equals(data2, data));
-		assertEquals("stream at EOF", -1, in.read());
-		in.close();
+		try (ObjectStream in = ol.openStream()) {
+			assertNotNull("have stream", in);
+			assertEquals(type, in.getType());
+			assertEquals(data.length, in.getSize());
+			byte[] data2 = new byte[data.length];
+			IO.readFully(in, data2, 0, data.length);
+			assertTrue("same content", Arrays.equals(data2, data));
+			assertEquals("stream at EOF", -1, in.read());
+		}
 	}
 
 	@Test
@@ -150,11 +150,8 @@ public void testStandardFormat_LargeObject() throws Exception {
 
 		ObjectLoader ol;
 		{
-			FileInputStream fs = new FileInputStream(path(id));
-			try {
+			try (FileInputStream fs = new FileInputStream(path(id))) {
 				ol = UnpackedObject.open(fs, path(id), id, wc);
-			} finally {
-				fs.close();
 			}
 		}
 
@@ -171,15 +168,15 @@ public void testStandardFormat_LargeObject() throws Exception {
 					.getMessage());
 		}
 
-		ObjectStream in = ol.openStream();
-		assertNotNull("have stream", in);
-		assertEquals(type, in.getType());
-		assertEquals(data.length, in.getSize());
-		byte[] data2 = new byte[data.length];
-		IO.readFully(in, data2, 0, data.length);
-		assertTrue("same content", Arrays.equals(data2, data));
-		assertEquals("stream at EOF", -1, in.read());
-		in.close();
+		try (ObjectStream in = ol.openStream()) {
+			assertNotNull("have stream", in);
+			assertEquals(type, in.getType());
+			assertEquals(data.length, in.getSize());
+			byte[] data2 = new byte[data.length];
+			IO.readFully(in, data2, 0, data.length);
+			assertTrue("same content", Arrays.equals(data2, data));
+			assertEquals("stream at EOF", -1, in.read());
+		}
 	}
 
 	@Test
@@ -316,23 +313,13 @@ public void testStandardFormat_LargeObject_CorruptZLibStream()
 		write(id, gz);
 
 		ObjectLoader ol;
-		{
-			FileInputStream fs = new FileInputStream(path(id));
-			try {
-				ol = UnpackedObject.open(fs, path(id), id, wc);
-			} finally {
-				fs.close();
-			}
+		try (FileInputStream fs = new FileInputStream(path(id))) {
+			ol = UnpackedObject.open(fs, path(id), id, wc);
 		}
 
-		try {
-			byte[] tmp = new byte[data.length];
-			InputStream in = ol.openStream();
-			try {
-				IO.readFully(in, tmp, 0, tmp.length);
-			} finally {
-				in.close();
-			}
+		byte[] tmp = new byte[data.length];
+		try (InputStream in = ol.openStream()) {
+			IO.readFully(in, tmp, 0, tmp.length);
 			fail("Did not throw CorruptObjectException");
 		} catch (CorruptObjectException coe) {
 			assertEquals(MessageFormat.format(JGitText.get().objectIsCorrupt,
@@ -354,16 +341,12 @@ public void testStandardFormat_LargeObject_TruncatedZLibStream()
 		write(id, tr);
 
 		ObjectLoader ol;
-		{
-			FileInputStream fs = new FileInputStream(path(id));
-			try {
-				ol = UnpackedObject.open(fs, path(id), id, wc);
-			} finally {
-				fs.close();
-			}
+		try (FileInputStream fs = new FileInputStream(path(id))) {
+			ol = UnpackedObject.open(fs, path(id), id, wc);
 		}
 
 		byte[] tmp = new byte[data.length];
+		@SuppressWarnings("resource") // We are testing that the close() method throws
 		InputStream in = ol.openStream();
 		IO.readFully(in, tmp, 0, tmp.length);
 		try {
@@ -389,16 +372,12 @@ public void testStandardFormat_LargeObject_TrailingGarbage()
 		write(id, tr);
 
 		ObjectLoader ol;
-		{
-			FileInputStream fs = new FileInputStream(path(id));
-			try {
-				ol = UnpackedObject.open(fs, path(id), id, wc);
-			} finally {
-				fs.close();
-			}
+		try (FileInputStream fs = new FileInputStream(path(id))) {
+			ol = UnpackedObject.open(fs, path(id), id, wc);
 		}
 
 		byte[] tmp = new byte[data.length];
+		@SuppressWarnings("resource") // We are testing that the close() method throws
 		InputStream in = ol.openStream();
 		IO.readFully(in, tmp, 0, tmp.length);
 		try {
@@ -426,14 +405,15 @@ public void testPackFormat_SmallObject() throws Exception {
 		assertFalse("is not large", ol.isLarge());
 		assertTrue("same content", Arrays.equals(data, ol.getCachedBytes()));
 
-		ObjectStream in = ol.openStream();
-		assertNotNull("have stream", in);
-		assertEquals(type, in.getType());
-		assertEquals(data.length, in.getSize());
-		byte[] data2 = new byte[data.length];
-		IO.readFully(in, data2, 0, data.length);
-		assertTrue("same content", Arrays.equals(data, ol.getCachedBytes()));
-		in.close();
+		try (ObjectStream in = ol.openStream()) {
+			assertNotNull("have stream", in);
+			assertEquals(type, in.getType());
+			assertEquals(data.length, in.getSize());
+			byte[] data2 = new byte[data.length];
+			IO.readFully(in, data2, 0, data.length);
+			assertTrue("same content",
+					Arrays.equals(data, ol.getCachedBytes()));
+		}
 	}
 
 	@Test
@@ -444,13 +424,8 @@ public void testPackFormat_LargeObject() throws Exception {
 		write(id, compressPackFormat(type, data));
 
 		ObjectLoader ol;
-		{
-			FileInputStream fs = new FileInputStream(path(id));
-			try {
-				ol = UnpackedObject.open(fs, path(id), id, wc);
-			} finally {
-				fs.close();
-			}
+		try (FileInputStream fs = new FileInputStream(path(id))) {
+			ol = UnpackedObject.open(fs, path(id), id, wc);
 		}
 
 		assertNotNull("created loader", ol);
@@ -466,15 +441,15 @@ public void testPackFormat_LargeObject() throws Exception {
 					.getMessage());
 		}
 
-		ObjectStream in = ol.openStream();
-		assertNotNull("have stream", in);
-		assertEquals(type, in.getType());
-		assertEquals(data.length, in.getSize());
-		byte[] data2 = new byte[data.length];
-		IO.readFully(in, data2, 0, data.length);
-		assertTrue("same content", Arrays.equals(data2, data));
-		assertEquals("stream at EOF", -1, in.read());
-		in.close();
+		try (ObjectStream in = ol.openStream()) {
+			assertNotNull("have stream", in);
+			assertEquals(type, in.getType());
+			assertEquals(data.length, in.getSize());
+			byte[] data2 = new byte[data.length];
+			IO.readFully(in, data2, 0, data.length);
+			assertTrue("same content", Arrays.equals(data2, data));
+			assertEquals("stream at EOF", -1, in.read());
+		}
 	}
 
 	@Test
@@ -573,11 +548,8 @@ private File path(ObjectId id) {
 	private void write(ObjectId id, byte[] data) throws IOException {
 		File path = path(id);
 		FileUtils.mkdirs(path.getParentFile());
-		FileOutputStream out = new FileOutputStream(path);
-		try {
+		try (FileOutputStream out = new FileOutputStream(path)) {
 			out.write(data);
-		} finally {
-			out.close();
 		}
 	}
 
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/WindowCacheGetTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/WindowCacheGetTest.java
index cc34838..82ad28e 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/WindowCacheGetTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/WindowCacheGetTest.java
@@ -74,11 +74,10 @@ public void setUp() throws Exception {
 		super.setUp();
 
 		toLoad = new ArrayList<>();
-		final BufferedReader br = new BufferedReader(new InputStreamReader(
+		try (BufferedReader br = new BufferedReader(new InputStreamReader(
 				new FileInputStream(JGitTestUtil
 						.getTestResourceFile("all_packed_objects.txt")),
-				Constants.CHARSET));
-		try {
+				Constants.CHARSET))) {
 			String line;
 			while ((line = br.readLine()) != null) {
 				final String[] parts = line.split(" {1,}");
@@ -90,8 +89,6 @@ public void setUp() throws Exception {
 				// parts[4] is the offset in the pack
 				toLoad.add(o);
 			}
-		} finally {
-			br.close();
 		}
 		assertEquals(96, toLoad.size());
 	}
@@ -127,7 +124,7 @@ public void testCache_TooSmallLimit() throws IOException {
 		checkLimits(cfg);
 	}
 
-	private static void checkLimits(final WindowCacheConfig cfg) {
+	private static void checkLimits(WindowCacheConfig cfg) {
 		final WindowCache cache = WindowCache.getInstance();
 		assertTrue(cache.getOpenFiles() <= cfg.getPackedGitOpenFiles());
 		assertTrue(cache.getOpenBytes() <= cfg.getPackedGitLimit());
@@ -136,7 +133,7 @@ private static void checkLimits(final WindowCacheConfig cfg) {
 	}
 
 	private void doCacheTests() throws IOException {
-		for (final TestObject o : toLoad) {
+		for (TestObject o : toLoad) {
 			final ObjectLoader or = db.open(o.id, o.type);
 			assertNotNull(or);
 			assertEquals(o.type, or.getType());
@@ -148,7 +145,7 @@ private class TestObject {
 
 		int type;
 
-		void setType(final String typeStr) throws CorruptObjectException {
+		void setType(String typeStr) throws CorruptObjectException {
 			final byte[] typeRaw = Constants.encode(typeStr + " ");
 			final MutableInteger ptr = new MutableInteger();
 			type = Constants.decodeTypeString(id, typeRaw, (byte) ' ', ptr);
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/XInputStream.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/XInputStream.java
index 46f9ee3..910999c 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/XInputStream.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/XInputStream.java
@@ -53,7 +53,7 @@
 class XInputStream extends BufferedInputStream {
 	private final byte[] intbuf = new byte[8];
 
-	XInputStream(final InputStream s) {
+	XInputStream(InputStream s) {
 		super(s);
 	}
 
@@ -63,7 +63,7 @@ class XInputStream extends BufferedInputStream {
 		return b;
 	}
 
-	synchronized void readFully(final byte[] b, int o, int len)
+	synchronized void readFully(byte[] b, int o, int len)
 			throws IOException {
 		int r;
 		while (len > 0 && (r = read(b, o, len)) > 0) {
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/reftable/MergedReftableTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/reftable/MergedReftableTest.java
index adba048..ec60bd9 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/reftable/MergedReftableTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/reftable/MergedReftableTest.java
@@ -218,6 +218,27 @@ public void fourTableScan() throws IOException {
 	}
 
 	@Test
+	public void scanDuplicates() throws IOException {
+		List<Ref> delta1 = Arrays.asList(
+				ref("refs/heads/apple", 1),
+				ref("refs/heads/banana", 2));
+		List<Ref> delta2 = Arrays.asList(
+				ref("refs/heads/apple", 3),
+				ref("refs/heads/apple", 4));
+
+		MergedReftable mr = merge(write(delta1, 1000), write(delta2, 2000));
+		try (RefCursor rc = mr.allRefs()) {
+			assertTrue(rc.next());
+			assertEquals("refs/heads/apple", rc.getRef().getName());
+			assertEquals(id(3), rc.getRef().getObjectId());
+			assertTrue(rc.next());
+			assertEquals("refs/heads/banana", rc.getRef().getName());
+			assertEquals(id(2), rc.getRef().getObjectId());
+			assertFalse(rc.next());
+		}
+	}
+
+	@Test
 	public void scanIncludeDeletes() throws IOException {
 		List<Ref> delta1 = Arrays.asList(ref("refs/heads/next", 4));
 		List<Ref> delta2 = Arrays.asList(delete("refs/heads/next"));
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/reftable/ReftableCompactorTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/reftable/ReftableCompactorTest.java
new file mode 100644
index 0000000..46a37ff
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/reftable/ReftableCompactorTest.java
@@ -0,0 +1,325 @@
+/*
+ * Copyright (C) 2017, Google Inc.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ *   copyright notice, this list of conditions and the following
+ *   disclaimer in the documentation and/or other materials provided
+ *   with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ *   names of its contributors may be used to endorse or promote
+ *   products derived from this software without specific prior
+ *   written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.internal.storage.reftable;
+
+import static org.eclipse.jgit.lib.Constants.OBJECT_ID_LENGTH;
+import static org.eclipse.jgit.lib.Ref.Storage.NEW;
+import static org.eclipse.jgit.lib.Ref.Storage.PACKED;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.Arrays;
+
+import org.eclipse.jgit.internal.storage.io.BlockSource;
+import org.eclipse.jgit.internal.storage.reftable.ReftableWriter.Stats;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.ObjectIdRef;
+import org.eclipse.jgit.lib.Ref;
+import org.junit.Test;
+
+public class ReftableCompactorTest {
+	private static final String MASTER = "refs/heads/master";
+	private static final String NEXT = "refs/heads/next";
+
+	@Test
+	public void noTables() throws IOException {
+		ReftableCompactor compactor = new ReftableCompactor();
+		try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
+			compactor.compact(out);
+		}
+		Stats stats = compactor.getStats();
+		assertEquals(0, stats.minUpdateIndex());
+		assertEquals(0, stats.maxUpdateIndex());
+		assertEquals(0, stats.refCount());
+	}
+
+	@Test
+	public void oneTable() throws IOException {
+		byte[] inTab;
+		try (ByteArrayOutputStream inBuf = new ByteArrayOutputStream()) {
+			ReftableWriter writer = new ReftableWriter()
+				.setMinUpdateIndex(0)
+				.setMaxUpdateIndex(0)
+				.begin(inBuf);
+
+			writer.writeRef(ref(MASTER, 1));
+			writer.finish();
+			inTab = inBuf.toByteArray();
+		}
+
+		byte[] outTab;
+		ReftableCompactor compactor = new ReftableCompactor();
+		try (ByteArrayOutputStream outBuf = new ByteArrayOutputStream()) {
+			compactor.tryAddFirst(read(inTab));
+			compactor.compact(outBuf);
+			outTab = outBuf.toByteArray();
+		}
+		Stats stats = compactor.getStats();
+		assertEquals(0, stats.minUpdateIndex());
+		assertEquals(0, stats.maxUpdateIndex());
+		assertEquals(1, stats.refCount());
+
+		ReftableReader rr = read(outTab);
+		try (RefCursor rc = rr.allRefs()) {
+			assertTrue(rc.next());
+			assertEquals(MASTER, rc.getRef().getName());
+			assertEquals(id(1), rc.getRef().getObjectId());
+			assertEquals(0, rc.getUpdateIndex());
+		}
+	}
+
+	@Test
+	public void twoTablesOneRef() throws IOException {
+		byte[] inTab1;
+		try (ByteArrayOutputStream inBuf = new ByteArrayOutputStream()) {
+			ReftableWriter writer = new ReftableWriter()
+				.setMinUpdateIndex(0)
+				.setMaxUpdateIndex(0)
+				.begin(inBuf);
+
+			writer.writeRef(ref(MASTER, 1));
+			writer.finish();
+			inTab1 = inBuf.toByteArray();
+		}
+
+		byte[] inTab2;
+		try (ByteArrayOutputStream inBuf = new ByteArrayOutputStream()) {
+			ReftableWriter writer = new ReftableWriter()
+				.setMinUpdateIndex(1)
+				.setMaxUpdateIndex(1)
+				.begin(inBuf);
+
+			writer.writeRef(ref(MASTER, 2));
+			writer.finish();
+			inTab2 = inBuf.toByteArray();
+		}
+
+		byte[] outTab;
+		ReftableCompactor compactor = new ReftableCompactor();
+		try (ByteArrayOutputStream outBuf = new ByteArrayOutputStream()) {
+			compactor.addAll(Arrays.asList(read(inTab1), read(inTab2)));
+			compactor.compact(outBuf);
+			outTab = outBuf.toByteArray();
+		}
+		Stats stats = compactor.getStats();
+		assertEquals(0, stats.minUpdateIndex());
+		assertEquals(1, stats.maxUpdateIndex());
+		assertEquals(1, stats.refCount());
+
+		ReftableReader rr = read(outTab);
+		try (RefCursor rc = rr.allRefs()) {
+			assertTrue(rc.next());
+			assertEquals(MASTER, rc.getRef().getName());
+			assertEquals(id(2), rc.getRef().getObjectId());
+			assertEquals(1, rc.getUpdateIndex());
+		}
+	}
+
+	@Test
+	public void twoTablesTwoRefs() throws IOException {
+		byte[] inTab1;
+		try (ByteArrayOutputStream inBuf = new ByteArrayOutputStream()) {
+			ReftableWriter writer = new ReftableWriter()
+				.setMinUpdateIndex(0)
+				.setMaxUpdateIndex(0)
+				.begin(inBuf);
+
+			writer.writeRef(ref(MASTER, 1));
+			writer.writeRef(ref(NEXT, 2));
+			writer.finish();
+			inTab1 = inBuf.toByteArray();
+		}
+
+		byte[] inTab2;
+		try (ByteArrayOutputStream inBuf = new ByteArrayOutputStream()) {
+			ReftableWriter writer = new ReftableWriter()
+				.setMinUpdateIndex(1)
+				.setMaxUpdateIndex(1)
+				.begin(inBuf);
+
+			writer.writeRef(ref(MASTER, 3));
+			writer.finish();
+			inTab2 = inBuf.toByteArray();
+		}
+
+		byte[] outTab;
+		ReftableCompactor compactor = new ReftableCompactor();
+		try (ByteArrayOutputStream outBuf = new ByteArrayOutputStream()) {
+			compactor.addAll(Arrays.asList(read(inTab1), read(inTab2)));
+			compactor.compact(outBuf);
+			outTab = outBuf.toByteArray();
+		}
+		Stats stats = compactor.getStats();
+		assertEquals(0, stats.minUpdateIndex());
+		assertEquals(1, stats.maxUpdateIndex());
+		assertEquals(2, stats.refCount());
+
+		ReftableReader rr = read(outTab);
+		try (RefCursor rc = rr.allRefs()) {
+			assertTrue(rc.next());
+			assertEquals(MASTER, rc.getRef().getName());
+			assertEquals(id(3), rc.getRef().getObjectId());
+			assertEquals(1, rc.getUpdateIndex());
+
+			assertTrue(rc.next());
+			assertEquals(NEXT, rc.getRef().getName());
+			assertEquals(id(2), rc.getRef().getObjectId());
+			assertEquals(0, rc.getUpdateIndex());
+		}
+	}
+
+	@Test
+	public void twoTablesIncludeOneDelete() throws IOException {
+		byte[] inTab1;
+		try (ByteArrayOutputStream inBuf = new ByteArrayOutputStream()) {
+			ReftableWriter writer = new ReftableWriter()
+				.setMinUpdateIndex(0)
+				.setMaxUpdateIndex(0)
+				.begin(inBuf);
+
+			writer.writeRef(ref(MASTER, 1));
+			writer.finish();
+			inTab1 = inBuf.toByteArray();
+		}
+
+		byte[] inTab2;
+		try (ByteArrayOutputStream inBuf = new ByteArrayOutputStream()) {
+			ReftableWriter writer = new ReftableWriter()
+				.setMinUpdateIndex(1)
+				.setMaxUpdateIndex(1)
+				.begin(inBuf);
+
+			writer.writeRef(tombstone(MASTER));
+			writer.finish();
+			inTab2 = inBuf.toByteArray();
+		}
+
+		byte[] outTab;
+		ReftableCompactor compactor = new ReftableCompactor();
+		try (ByteArrayOutputStream outBuf = new ByteArrayOutputStream()) {
+			compactor.setIncludeDeletes(true);
+			compactor.addAll(Arrays.asList(read(inTab1), read(inTab2)));
+			compactor.compact(outBuf);
+			outTab = outBuf.toByteArray();
+		}
+		Stats stats = compactor.getStats();
+		assertEquals(0, stats.minUpdateIndex());
+		assertEquals(1, stats.maxUpdateIndex());
+		assertEquals(1, stats.refCount());
+
+		ReftableReader rr = read(outTab);
+		try (RefCursor rc = rr.allRefs()) {
+			assertFalse(rc.next());
+		}
+	}
+
+	@Test
+	public void twoTablesNotIncludeOneDelete() throws IOException {
+		byte[] inTab1;
+		try (ByteArrayOutputStream inBuf = new ByteArrayOutputStream()) {
+			ReftableWriter writer = new ReftableWriter()
+				.setMinUpdateIndex(0)
+				.setMaxUpdateIndex(0)
+				.begin(inBuf);
+
+			writer.writeRef(ref(MASTER, 1));
+			writer.finish();
+			inTab1 = inBuf.toByteArray();
+		}
+
+		byte[] inTab2;
+		try (ByteArrayOutputStream inBuf = new ByteArrayOutputStream()) {
+			ReftableWriter writer = new ReftableWriter()
+				.setMinUpdateIndex(1)
+				.setMaxUpdateIndex(1)
+				.begin(inBuf);
+
+			writer.writeRef(tombstone(MASTER));
+			writer.finish();
+			inTab2 = inBuf.toByteArray();
+		}
+
+		byte[] outTab;
+		ReftableCompactor compactor = new ReftableCompactor();
+		try (ByteArrayOutputStream outBuf = new ByteArrayOutputStream()) {
+			compactor.setIncludeDeletes(false);
+			compactor.addAll(Arrays.asList(read(inTab1), read(inTab2)));
+			compactor.compact(outBuf);
+			outTab = outBuf.toByteArray();
+		}
+		Stats stats = compactor.getStats();
+		assertEquals(0, stats.minUpdateIndex());
+		assertEquals(1, stats.maxUpdateIndex());
+		assertEquals(0, stats.refCount());
+
+		ReftableReader rr = read(outTab);
+		try (RefCursor rc = rr.allRefs()) {
+			assertFalse(rc.next());
+		}
+	}
+
+	private static Ref ref(String name, int id) {
+		return new ObjectIdRef.PeeledNonTag(PACKED, name, id(id));
+	}
+
+	private static Ref tombstone(String name) {
+		return new ObjectIdRef.Unpeeled(NEW, name, null);
+	}
+
+	private static ObjectId id(int i) {
+		byte[] buf = new byte[OBJECT_ID_LENGTH];
+		buf[0] = (byte) (i & 0xff);
+		buf[1] = (byte) ((i >>> 8) & 0xff);
+		buf[2] = (byte) ((i >>> 16) & 0xff);
+		buf[3] = (byte) (i >>> 24);
+		return ObjectId.fromRaw(buf);
+	}
+
+	private static ReftableReader read(byte[] table) {
+		return new ReftableReader(BlockSource.from(table));
+	}
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/reftree/RefTreeDatabaseTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/reftree/RefTreeDatabaseTest.java
index 9aef943..ae52ad5 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/reftree/RefTreeDatabaseTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/reftree/RefTreeDatabaseTest.java
@@ -631,7 +631,7 @@ private static ReceiveCommand command(AnyObjectId a, AnyObjectId b,
 				name);
 	}
 
-	private void symref(final String name, final String dst)
+	private void symref(String name, String dst)
 			throws IOException {
 		commit(new Function() {
 			@Override
@@ -648,7 +648,7 @@ public boolean apply(ObjectReader reader, RefTree tree)
 		});
 	}
 
-	private void update(final String name, final ObjectId id)
+	private void update(String name, ObjectId id)
 			throws IOException {
 		commit(new Function() {
 			@Override
@@ -657,7 +657,8 @@ public boolean apply(ObjectReader reader, RefTree tree)
 				Ref old = tree.exactRef(reader, name);
 				Command n;
 				try (RevWalk rw = new RevWalk(repo)) {
-					n = new Command(old, Command.toRef(rw, id, name, true));
+					n = new Command(old,
+							Command.toRef(rw, id, null, name, true));
 				}
 				return tree.apply(Collections.singleton(n));
 			}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/junit/TestRepositoryTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/junit/TestRepositoryTest.java
index b7027f3..965899e 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/junit/TestRepositoryTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/junit/TestRepositoryTest.java
@@ -43,7 +43,7 @@
 
 package org.eclipse.jgit.junit;
 
-import static java.nio.charset.StandardCharsets.UTF_8;
+import static org.eclipse.jgit.lib.Constants.CHARSET;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotEquals;
@@ -418,6 +418,6 @@ private String blobAsString(AnyObjectId treeish, String path)
 		RevObject obj = tr.get(rw.parseTree(treeish), path);
 		assertSame(RevBlob.class, obj.getClass());
 		ObjectLoader loader = rw.getObjectReader().open(obj);
-		return new String(loader.getCachedBytes(), UTF_8);
+		return new String(loader.getCachedBytes(), CHARSET);
 	}
 }
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/BranchConfigTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/BranchConfigTest.java
index 87bb082..1ecdf21 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/BranchConfigTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/BranchConfigTest.java
@@ -160,7 +160,7 @@ public void isRebase() {
 		assertTrue(new BranchConfig(c, "true").isRebase());
 	}
 
-	private static Config parse(final String content) {
+	private static Config parse(String content) {
 		final Config c = new Config(null);
 		try {
 			c.fromText(content);
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ConfigTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ConfigTest.java
index a12831a..c4c4da8 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ConfigTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ConfigTest.java
@@ -53,6 +53,7 @@
 import static java.util.concurrent.TimeUnit.MILLISECONDS;
 import static java.util.concurrent.TimeUnit.MINUTES;
 import static java.util.concurrent.TimeUnit.SECONDS;
+import static org.eclipse.jgit.util.FileUtils.pathToString;
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
@@ -80,7 +81,6 @@
 import org.eclipse.jgit.util.FS;
 import org.eclipse.jgit.util.SystemReader;
 import org.junit.After;
-import org.junit.Ignore;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.ExpectedException;
@@ -89,7 +89,10 @@
 /**
  * Test reading of git config
  */
+@SuppressWarnings("boxing")
 public class ConfigTest {
+	// A non-ASCII whitespace character: U+2002 EN QUAD.
+	private static final char WS = '\u2002';
 
 	@Rule
 	public ExpectedException expectedEx = ExpectedException.none();
@@ -666,28 +669,6 @@ public void readNamesInSubSectionRecursive() throws ConfigInvalidException {
 		assertTrue("Subsection should contain \"B\"", names.contains("B"));
 	}
 
-	@Test
-	public void testQuotingForSubSectionNames() {
-		String resultPattern = "[testsection \"{0}\"]\n\ttestname = testvalue\n";
-		String result;
-
-		Config config = new Config();
-		config.setString("testsection", "testsubsection", "testname",
-				"testvalue");
-
-		result = MessageFormat.format(resultPattern, "testsubsection");
-		assertEquals(result, config.toText());
-		config.clear();
-
-		config.setString("testsection", "#quotable", "testname", "testvalue");
-		result = MessageFormat.format(resultPattern, "#quotable");
-		assertEquals(result, config.toText());
-		config.clear();
-
-		config.setString("testsection", "with\"quote", "testname", "testvalue");
-		result = MessageFormat.format(resultPattern, "with\\\"quote");
-		assertEquals(result, config.toText());
-	}
 
 	@Test
 	public void testNoFinalNewline() throws ConfigInvalidException {
@@ -767,7 +748,6 @@ public void testReadMultipleValuesForName() throws ConfigInvalidException {
 	}
 
 	@Test
-	@Ignore
 	public void testIncludeInvalidName() throws ConfigInvalidException {
 		expectedEx.expect(ConfigInvalidException.class);
 		expectedEx.expectMessage(JGitText.get().invalidLineInConfigFile);
@@ -775,7 +755,6 @@ public void testIncludeInvalidName() throws ConfigInvalidException {
 	}
 
 	@Test
-	@Ignore
 	public void testIncludeNoValue() throws ConfigInvalidException {
 		expectedEx.expect(ConfigInvalidException.class);
 		expectedEx.expectMessage(JGitText.get().invalidLineInConfigFile);
@@ -783,7 +762,6 @@ public void testIncludeNoValue() throws ConfigInvalidException {
 	}
 
 	@Test
-	@Ignore
 	public void testIncludeEmptyValue() throws ConfigInvalidException {
 		expectedEx.expect(ConfigInvalidException.class);
 		expectedEx.expectMessage(JGitText.get().invalidLineInConfigFile);
@@ -820,10 +798,9 @@ public void testIncludeValuePathRelative() throws ConfigInvalidException {
 	}
 
 	@Test
-	@Ignore
 	public void testIncludeTooManyRecursions() throws IOException {
 		File config = tmp.newFile("config");
-		String include = "[include]\npath=" + config.toPath() + "\n";
+		String include = "[include]\npath=" + pathToString(config) + "\n";
 		Files.write(config.toPath(), include.getBytes());
 		FileBasedConfig fbConfig = new FileBasedConfig(null, config,
 				FS.DETECTED);
@@ -831,8 +808,14 @@ public void testIncludeTooManyRecursions() throws IOException {
 			fbConfig.load();
 			fail();
 		} catch (ConfigInvalidException cie) {
-			assertEquals(JGitText.get().tooManyIncludeRecursions,
-					cie.getCause().getMessage());
+			for (Throwable t = cie; t != null; t = t.getCause()) {
+				if (t.getMessage()
+						.equals(JGitText.get().tooManyIncludeRecursions)) {
+					return;
+				}
+			}
+			fail("Expected to find expected exception message: "
+					+ JGitText.get().tooManyIncludeRecursions);
 		}
 	}
 
@@ -843,10 +826,84 @@ public void testIncludeIsNoop() throws IOException, ConfigInvalidException {
 		String fooBar = "[foo]\nbar=true\n";
 		Files.write(config.toPath(), fooBar.getBytes());
 
-		Config parsed = parse("[include]\npath=" + config.toPath() + "\n");
+		Config parsed = parse("[include]\npath=" + pathToString(config) + "\n");
 		assertFalse(parsed.getBoolean("foo", "bar", false));
 	}
 
+	@Test
+	public void testIncludeCaseInsensitiveSection()
+			throws IOException, ConfigInvalidException {
+		File included = tmp.newFile("included");
+		String content = "[foo]\nbar=true\n";
+		Files.write(included.toPath(), content.getBytes());
+
+		File config = tmp.newFile("config");
+		content = "[Include]\npath=" + pathToString(included) + "\n";
+		Files.write(config.toPath(), content.getBytes());
+
+		FileBasedConfig fbConfig = new FileBasedConfig(null, config,
+				FS.DETECTED);
+		fbConfig.load();
+		assertTrue(fbConfig.getBoolean("foo", "bar", false));
+	}
+
+	@Test
+	public void testIncludeCaseInsensitiveKey()
+			throws IOException, ConfigInvalidException {
+		File included = tmp.newFile("included");
+		String content = "[foo]\nbar=true\n";
+		Files.write(included.toPath(), content.getBytes());
+
+		File config = tmp.newFile("config");
+		content = "[include]\nPath=" + pathToString(included) + "\n";
+		Files.write(config.toPath(), content.getBytes());
+
+		FileBasedConfig fbConfig = new FileBasedConfig(null, config,
+				FS.DETECTED);
+		fbConfig.load();
+		assertTrue(fbConfig.getBoolean("foo", "bar", false));
+	}
+
+	@Test
+	public void testIncludeExceptionContainsLine() {
+		try {
+			parse("[include]\npath=\n");
+			fail("Expected ConfigInvalidException");
+		} catch (ConfigInvalidException e) {
+			assertTrue(
+					"Expected to find the problem line in the exception message",
+					e.getMessage().contains("include.path"));
+		}
+	}
+
+	@Test
+	public void testIncludeExceptionContainsFile() throws IOException {
+		File included = tmp.newFile("included");
+		String includedPath = pathToString(included);
+		String content = "[include]\npath=\n";
+		Files.write(included.toPath(), content.getBytes());
+
+		File config = tmp.newFile("config");
+		String include = "[include]\npath=" + includedPath + "\n";
+		Files.write(config.toPath(), include.getBytes());
+		FileBasedConfig fbConfig = new FileBasedConfig(null, config,
+				FS.DETECTED);
+		try {
+			fbConfig.load();
+			fail("Expected ConfigInvalidException");
+		} catch (ConfigInvalidException e) {
+			// Check that there is some exception in the chain that contains
+			// includedPath
+			for (Throwable t = e; t != null; t = t.getCause()) {
+				if (t.getMessage().contains(includedPath)) {
+					return;
+				}
+			}
+			fail("Expected to find the path in the exception message: "
+					+ includedPath);
+		}
+	}
+
 	private static void assertReadLong(long exp) throws ConfigInvalidException {
 		assertReadLong(exp, String.valueOf(exp));
 	}
@@ -857,12 +914,12 @@ private static void assertReadLong(long exp, String act)
 		assertEquals(exp, c.getLong("s", null, "a", 0L));
 	}
 
-	private static Config parse(final String content)
+	private static Config parse(String content)
 			throws ConfigInvalidException {
 		return parse(content, null);
 	}
 
-	private static Config parse(final String content, Config baseConfig)
+	private static Config parse(String content, Config baseConfig)
 			throws ConfigInvalidException {
 		final Config c = new Config(baseConfig);
 		c.fromText(content);
@@ -957,4 +1014,207 @@ public void testTimeUnitNegative() throws ConfigInvalidException {
 		expectedEx.expect(IllegalArgumentException.class);
 		parseTime("-1", MILLISECONDS);
 	}
+
+	@Test
+	public void testEscapeSpacesOnly() throws ConfigInvalidException {
+		// Empty string is read back as null, so this doesn't round-trip.
+		assertEquals("", Config.escapeValue(""));
+
+		assertValueRoundTrip(" ", "\" \"");
+		assertValueRoundTrip("  ", "\"  \"");
+	}
+
+	@Test
+	public void testEscapeLeadingSpace() throws ConfigInvalidException {
+		assertValueRoundTrip("x", "x");
+		assertValueRoundTrip(" x", "\" x\"");
+		assertValueRoundTrip("  x", "\"  x\"");
+	}
+
+	@Test
+	public void testEscapeTrailingSpace() throws ConfigInvalidException {
+		assertValueRoundTrip("x", "x");
+		assertValueRoundTrip("x  ","\"x  \"");
+		assertValueRoundTrip("x ","\"x \"");
+	}
+
+	@Test
+	public void testEscapeLeadingAndTrailingSpace()
+			throws ConfigInvalidException {
+		assertValueRoundTrip(" x ", "\" x \"");
+		assertValueRoundTrip("  x ", "\"  x \"");
+		assertValueRoundTrip(" x  ", "\" x  \"");
+		assertValueRoundTrip("  x  ", "\"  x  \"");
+	}
+
+	@Test
+	public void testNoEscapeInternalSpaces() throws ConfigInvalidException {
+		assertValueRoundTrip("x y");
+		assertValueRoundTrip("x  y");
+		assertValueRoundTrip("x  y");
+		assertValueRoundTrip("x  y   z");
+		assertValueRoundTrip("x " + WS + " y");
+	}
+
+	@Test
+	public void testNoEscapeSpecialCharacters() throws ConfigInvalidException {
+		assertValueRoundTrip("x\\y", "x\\\\y");
+		assertValueRoundTrip("x\"y", "x\\\"y");
+		assertValueRoundTrip("x\ny", "x\\ny");
+		assertValueRoundTrip("x\ty", "x\\ty");
+		assertValueRoundTrip("x\by", "x\\by");
+	}
+
+	@Test
+	public void testParseLiteralBackspace() throws ConfigInvalidException {
+		// This is round-tripped with an escape sequence by JGit, but C git writes
+		// it out as a literal backslash.
+		assertEquals("x\by", parseEscapedValue("x\by"));
+	}
+
+	@Test
+	public void testEscapeCommentCharacters() throws ConfigInvalidException {
+		assertValueRoundTrip("x#y", "\"x#y\"");
+		assertValueRoundTrip("x;y", "\"x;y\"");
+	}
+
+	@Test
+	public void testEscapeValueInvalidCharacters() {
+		assertIllegalArgumentException(() -> Config.escapeSubsection("x\0y"));
+	}
+
+	@Test
+	public void testEscapeSubsectionInvalidCharacters() {
+		assertIllegalArgumentException(() -> Config.escapeSubsection("x\ny"));
+		assertIllegalArgumentException(() -> Config.escapeSubsection("x\0y"));
+	}
+
+	@Test
+	public void testParseMultipleQuotedRegions() throws ConfigInvalidException {
+		assertEquals("b a z; \n", parseEscapedValue("b\" a\"\" z; \\n\""));
+	}
+
+	@Test
+	public void testParseComments() throws ConfigInvalidException {
+		assertEquals("baz", parseEscapedValue("baz; comment"));
+		assertEquals("baz", parseEscapedValue("baz# comment"));
+		assertEquals("baz", parseEscapedValue("baz ; comment"));
+		assertEquals("baz", parseEscapedValue("baz # comment"));
+
+		assertEquals("baz", parseEscapedValue("baz ; comment"));
+		assertEquals("baz", parseEscapedValue("baz # comment"));
+		assertEquals("baz", parseEscapedValue("baz " + WS + " ; comment"));
+		assertEquals("baz", parseEscapedValue("baz " + WS + " # comment"));
+
+		assertEquals("baz ", parseEscapedValue("\"baz \"; comment"));
+		assertEquals("baz ", parseEscapedValue("\"baz \"# comment"));
+		assertEquals("baz ", parseEscapedValue("\"baz \" ; comment"));
+		assertEquals("baz ", parseEscapedValue("\"baz \" # comment"));
+	}
+
+	@Test
+	public void testEscapeSubsection() throws ConfigInvalidException {
+		assertSubsectionRoundTrip("", "\"\"");
+		assertSubsectionRoundTrip("x", "\"x\"");
+		assertSubsectionRoundTrip(" x", "\" x\"");
+		assertSubsectionRoundTrip("x ", "\"x \"");
+		assertSubsectionRoundTrip(" x ", "\" x \"");
+		assertSubsectionRoundTrip("x y", "\"x y\"");
+		assertSubsectionRoundTrip("x  y", "\"x  y\"");
+		assertSubsectionRoundTrip("x\\y", "\"x\\\\y\"");
+		assertSubsectionRoundTrip("x\"y", "\"x\\\"y\"");
+
+		// Unlike for values, \b and \t are not escaped.
+		assertSubsectionRoundTrip("x\by", "\"x\by\"");
+		assertSubsectionRoundTrip("x\ty", "\"x\ty\"");
+	}
+
+	@Test
+	public void testParseInvalidValues() {
+		assertInvalidValue(JGitText.get().newlineInQuotesNotAllowed, "x\"\n\"y");
+		assertInvalidValue(JGitText.get().endOfFileInEscape, "x\\");
+		assertInvalidValue(
+				MessageFormat.format(JGitText.get().badEscape, 'q'), "x\\q");
+	}
+
+	@Test
+	public void testParseInvalidSubsections() {
+		assertInvalidSubsection(
+				JGitText.get().newlineInQuotesNotAllowed, "\"x\ny\"");
+	}
+
+	@Test
+	public void testDropBackslashFromInvalidEscapeSequenceInSubsectionName()
+			throws ConfigInvalidException {
+		assertEquals("x0", parseEscapedSubsection("\"x\\0\""));
+		assertEquals("xq", parseEscapedSubsection("\"x\\q\""));
+		// Unlike for values, \b, \n, and \t are not valid escape sequences.
+		assertEquals("xb", parseEscapedSubsection("\"x\\b\""));
+		assertEquals("xn", parseEscapedSubsection("\"x\\n\""));
+		assertEquals("xt", parseEscapedSubsection("\"x\\t\""));
+	}
+
+	private static void assertValueRoundTrip(String value)
+			throws ConfigInvalidException {
+		assertValueRoundTrip(value, value);
+	}
+
+	private static void assertValueRoundTrip(String value, String expectedEscaped)
+			throws ConfigInvalidException {
+		String escaped = Config.escapeValue(value);
+		assertEquals("escape failed;", expectedEscaped, escaped);
+		assertEquals("parse failed;", value, parseEscapedValue(escaped));
+	}
+
+	private static String parseEscapedValue(String escapedValue)
+			throws ConfigInvalidException {
+		String text = "[foo]\nbar=" + escapedValue;
+		Config c = parse(text);
+		return c.getString("foo", null, "bar");
+	}
+
+	private static void assertInvalidValue(String expectedMessage,
+			String escapedValue) {
+		try {
+			parseEscapedValue(escapedValue);
+			fail("expected ConfigInvalidException");
+		} catch (ConfigInvalidException e) {
+			assertEquals(expectedMessage, e.getMessage());
+		}
+	}
+
+	private static void assertSubsectionRoundTrip(String subsection,
+			String expectedEscaped) throws ConfigInvalidException {
+		String escaped = Config.escapeSubsection(subsection);
+		assertEquals("escape failed;", expectedEscaped, escaped);
+		assertEquals("parse failed;", subsection, parseEscapedSubsection(escaped));
+	}
+
+	private static String parseEscapedSubsection(String escapedSubsection)
+			throws ConfigInvalidException {
+		String text = "[foo " + escapedSubsection + "]\nbar = value";
+		Config c = parse(text);
+		Set<String> subsections = c.getSubsections("foo");
+		assertEquals("only one section", 1, subsections.size());
+		return subsections.iterator().next();
+	}
+
+	private static void assertIllegalArgumentException(Runnable r) {
+		try {
+			r.run();
+			fail("expected IllegalArgumentException");
+		} catch (IllegalArgumentException e) {
+			// Expected.
+		}
+	}
+
+	private static void assertInvalidSubsection(String expectedMessage,
+			String escapedSubsection) {
+		try {
+			parseEscapedSubsection(escapedSubsection);
+			fail("expected ConfigInvalidException");
+		} catch (ConfigInvalidException e) {
+			assertEquals(expectedMessage, e.getMessage());
+		}
+	}
 }
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/DirCacheCheckoutTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/DirCacheCheckoutTest.java
index 05573b9..eb87827 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/DirCacheCheckoutTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/DirCacheCheckoutTest.java
@@ -78,8 +78,10 @@
 import org.eclipse.jgit.junit.TestRepository;
 import org.eclipse.jgit.junit.TestRepository.BranchBuilder;
 import org.eclipse.jgit.revwalk.RevCommit;
+import org.eclipse.jgit.treewalk.AbstractTreeIterator;
 import org.eclipse.jgit.treewalk.FileTreeIterator;
 import org.eclipse.jgit.treewalk.TreeWalk;
+import org.eclipse.jgit.treewalk.WorkingTreeIterator;
 import org.eclipse.jgit.util.FS;
 import org.eclipse.jgit.util.FileUtils;
 import org.junit.Assume;
@@ -218,8 +220,8 @@ public void testResetHard() throws IOException, NoFilepatternException,
 	/**
 	 * Reset hard from unclean condition.
 	 * <p>
-	 * WorkDir: Empty <br/>
-	 * Index: f/g <br/>
+	 * WorkDir: Empty <br>
+	 * Index: f/g <br>
 	 * Merge: x
 	 *
 	 * @throws Exception
@@ -1904,6 +1906,117 @@ public void testLongFilename() throws Exception {
 		assertUpdated(longFileName);
 	}
 
+	@Test
+	public void testIgnoredDirectory() throws Exception {
+		writeTrashFile(".gitignore", "src/ignored");
+		writeTrashFile("src/ignored/sub/foo.txt", "1");
+		try (Git git = new Git(db)) {
+			git.add().addFilepattern(".").call();
+			RevCommit commit = git.commit().setMessage("adding .gitignore")
+					.call();
+			writeTrashFile("foo.txt", "2");
+			writeTrashFile("zzz.txt", "3");
+			git.add().addFilepattern("foo.txt").call();
+			git.commit().setMessage("add file").call();
+			assertEquals("Should not have entered ignored directory", 1,
+					resetHardAndCount(commit));
+		}
+	}
+
+	@Test
+	public void testIgnoredDirectoryWithTrackedContent() throws Exception {
+		writeTrashFile("src/ignored/sub/foo.txt", "1");
+		try (Git git = new Git(db)) {
+			git.add().addFilepattern(".").call();
+			git.commit().setMessage("adding foo.txt").call();
+			writeTrashFile(".gitignore", "src/ignored");
+			writeTrashFile("src/ignored/sub/foo.txt", "2");
+			writeTrashFile("src/ignored/other/bar.txt", "3");
+			git.add().addFilepattern(".").call();
+			RevCommit commit = git.commit().setMessage("adding .gitignore")
+					.call();
+			writeTrashFile("foo.txt", "2");
+			writeTrashFile("zzz.txt", "3");
+			git.add().addFilepattern("foo.txt").call();
+			git.commit().setMessage("add file").call();
+			File file = writeTrashFile("src/ignored/sub/foo.txt", "3");
+			assertEquals("Should have entered ignored directory", 3,
+					resetHardAndCount(commit));
+			checkFile(file, "2");
+		}
+	}
+
+	@Test
+	public void testResetWithChangeInGitignore() throws Exception {
+		writeTrashFile(".gitignore", "src/ignored");
+		writeTrashFile("src/ignored/sub/foo.txt", "1");
+		try (Git git = new Git(db)) {
+			git.add().addFilepattern(".").call();
+			RevCommit initial = git.commit().setMessage("initial").call();
+			writeTrashFile("src/newignored/foo.txt", "2");
+			writeTrashFile("src/.gitignore", "newignored");
+			git.add().addFilepattern(".").call();
+			RevCommit commit = git.commit().setMessage("newignored").call();
+			assertEquals("Should not have entered src/newignored directory", 1,
+					resetHardAndCount(initial));
+			assertEquals("Should have entered src/newignored directory", 2,
+					resetHardAndCount(commit));
+			deleteTrashFile("src/.gitignore");
+			git.rm().addFilepattern("src/.gitignore").call();
+			RevCommit top = git.commit().setMessage("Unignore newignore")
+					.call();
+			assertEquals("Should have entered src/newignored directory", 2,
+					resetHardAndCount(initial));
+			assertEquals("Should have entered src/newignored directory", 2,
+					resetHardAndCount(commit));
+			assertEquals("Should not have entered src/newignored directory", 1,
+					resetHardAndCount(top));
+
+		}
+	}
+
+	private static class TestFileTreeIterator extends FileTreeIterator {
+
+		// For assertions only
+		private final int[] count;
+
+		public TestFileTreeIterator(Repository repo, int[] count) {
+			super(repo);
+			this.count = count;
+		}
+
+		protected TestFileTreeIterator(final WorkingTreeIterator p,
+				final File root, FS fs, FileModeStrategy fileModeStrategy,
+				int[] count) {
+			super(p, root, fs, fileModeStrategy);
+			this.count = count;
+		}
+
+		@Override
+		protected AbstractTreeIterator enterSubtree() {
+			count[0] += 1;
+			return new TestFileTreeIterator(this,
+					((FileEntry) current()).getFile(), fs, fileModeStrategy,
+					count);
+		}
+	}
+
+	private int resetHardAndCount(RevCommit commit) throws Exception {
+		int[] callCount = { 0 };
+		DirCache cache = db.lockDirCache();
+		FileTreeIterator workingTreeIterator = new TestFileTreeIterator(db,
+				callCount);
+		try {
+			DirCacheCheckout checkout = new DirCacheCheckout(db, null, cache,
+					commit.getTree().getId(), workingTreeIterator);
+			checkout.setFailOnConflict(false);
+			checkout.checkout();
+		} finally {
+			cache.unlock();
+		}
+		return callCount[0];
+	}
+
 	public void assertWorkDir(Map<String, String> i)
 			throws CorruptObjectException,
 			IOException {
@@ -1923,18 +2036,20 @@ public void assertWorkDir(Map<String, String> i)
 				if (file.isFile()) {
 					assertNotNull("found unexpected file for path " + path
 							+ " in workdir", expectedValue);
-					FileInputStream is = new FileInputStream(file);
-					byte[] buffer = new byte[(int) file.length()];
-					int offset = 0;
-					int numRead = 0;
-					while (offset < buffer.length
-							&& (numRead = is.read(buffer, offset, buffer.length
-									- offset)) >= 0) {
-						offset += numRead;
+					try (FileInputStream is = new FileInputStream(file)) {
+						byte[] buffer = new byte[(int) file.length()];
+						int offset = 0;
+						int numRead = 0;
+						while (offset < buffer.length
+								&& (numRead = is.read(buffer, offset,
+										buffer.length - offset)) >= 0) {
+							offset += numRead;
+						}
+						assertArrayEquals(
+								"unexpected content for path " + path
+										+ " in workDir. ",
+								buffer, i.get(path).getBytes());
 					}
-					is.close();
-					assertArrayEquals("unexpected content for path " + path
-							+ " in workDir. ", buffer, i.get(path).getBytes());
 					nrFiles++;
 				} else if (file.isDirectory()) {
 					String[] files = file.list();
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/IndexDiffTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/IndexDiffTest.java
index 2cb8f86..580b08b 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/IndexDiffTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/IndexDiffTest.java
@@ -470,7 +470,8 @@ public void testUntrackedFolders() throws Exception {
 	}
 
 	/**
-	 * Test that ignored folders aren't listed as untracked
+	 * Test that ignored folders aren't listed as untracked, but are listed as
+	 * ignored.
 	 *
 	 * @throws Exception
 	 */
@@ -499,6 +500,8 @@ public void testUntrackedNotIgnoredFolders() throws Exception {
 			diff.diff();
 			assertEquals(new HashSet<>(Arrays.asList("src")),
 					diff.getUntrackedFolders());
+			assertEquals(new HashSet<>(Arrays.asList("sr", "target")),
+					diff.getIgnoredNotInIndex());
 
 			git.add().addFilepattern("src").call();
 			writeTrashFile("sr/com/X1.java", "");
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/MergeHeadMsgTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/MergeHeadMsgTest.java
index 4f26a27..347883f 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/MergeHeadMsgTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/MergeHeadMsgTest.java
@@ -68,13 +68,11 @@ public void testReadWriteMergeHeads() throws IOException {
 		assertEquals(db.readMergeHeads().size(), 2);
 		assertEquals(db.readMergeHeads().get(0), ObjectId.zeroId());
 		assertEquals(db.readMergeHeads().get(1), ObjectId.fromString(sampleId));
+
 		// same test again, this time with lower-level io
-		FileOutputStream fos = new FileOutputStream(new File(db.getDirectory(),
-		"MERGE_HEAD"));
-		try {
+		try (FileOutputStream fos = new FileOutputStream(
+				new File(db.getDirectory(), "MERGE_HEAD"));) {
 			fos.write("0000000000000000000000000000000000000000\n1c6db447abdbb291b25f07be38ea0b1bf94947c5\n".getBytes(Constants.CHARACTER_ENCODING));
-		} finally {
-			fos.close();
 		}
 		assertEquals(db.readMergeHeads().size(), 2);
 		assertEquals(db.readMergeHeads().get(0), ObjectId.zeroId());
@@ -82,12 +80,9 @@ public void testReadWriteMergeHeads() throws IOException {
 		db.writeMergeHeads(Collections.<ObjectId> emptyList());
 		assertEquals(read(new File(db.getDirectory(), "MERGE_HEAD")), "");
 		assertEquals(db.readMergeHeads(), null);
-		fos = new FileOutputStream(new File(db.getDirectory(),
-				"MERGE_HEAD"));
-		try {
+		try (FileOutputStream fos = new FileOutputStream(
+				new File(db.getDirectory(), "MERGE_HEAD"))) {
 			fos.write(sampleId.getBytes(Constants.CHARACTER_ENCODING));
-		} finally {
-			fos.close();
 		}
 		assertEquals(db.readMergeHeads().size(), 1);
 		assertEquals(db.readMergeHeads().get(0), ObjectId.fromString(sampleId));
@@ -103,12 +98,9 @@ public void testReadWriteMergeMsg() throws IOException {
 		db.writeMergeCommitMsg(null);
 		assertEquals(db.readMergeCommitMsg(), null);
 		assertFalse(new File(db.getDirectory(), "MERGE_MSG").exists());
-		FileOutputStream fos = new FileOutputStream(new File(db.getDirectory(),
-				Constants.MERGE_MSG));
-		try {
+		try (FileOutputStream fos = new FileOutputStream(
+				new File(db.getDirectory(), Constants.MERGE_MSG))) {
 			fos.write(mergeMsg.getBytes(Constants.CHARACTER_ENCODING));
-		} finally {
-			fos.close();
 		}
 		assertEquals(db.readMergeCommitMsg(), mergeMsg);
 	}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ObjectCheckerTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ObjectCheckerTest.java
index 7475d69..b8e8a12 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ObjectCheckerTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ObjectCheckerTest.java
@@ -45,6 +45,7 @@
 package org.eclipse.jgit.lib;
 
 import static java.lang.Integer.valueOf;
+import static org.eclipse.jgit.lib.Constants.CHARSET;
 import static org.eclipse.jgit.junit.JGitTestUtil.concat;
 import static org.eclipse.jgit.lib.Constants.OBJECT_ID_LENGTH;
 import static org.eclipse.jgit.lib.Constants.OBJ_BAD;
@@ -68,7 +69,6 @@
 import static org.junit.Assert.assertSame;
 import static org.junit.Assert.fail;
 
-import java.io.UnsupportedEncodingException;
 import java.text.MessageFormat;
 
 import org.eclipse.jgit.errors.CorruptObjectException;
@@ -1450,11 +1450,11 @@ public void testInvalidTreeDuplicateNames4() throws CorruptObjectException {
 
 	@Test
 	public void testInvalidTreeDuplicateNames5()
-			throws UnsupportedEncodingException, CorruptObjectException {
+			throws CorruptObjectException {
 		StringBuilder b = new StringBuilder();
 		entry(b, "100644 A");
 		entry(b, "100644 a");
-		byte[] data = b.toString().getBytes("UTF-8");
+		byte[] data = b.toString().getBytes(CHARSET);
 		checker.setSafeForWindows(true);
 		assertCorrupt("duplicate entry names", OBJ_TREE, data);
 		assertSkipListAccepts(OBJ_TREE, data);
@@ -1464,11 +1464,11 @@ public void testInvalidTreeDuplicateNames5()
 
 	@Test
 	public void testInvalidTreeDuplicateNames6()
-			throws UnsupportedEncodingException, CorruptObjectException {
+			throws CorruptObjectException {
 		StringBuilder b = new StringBuilder();
 		entry(b, "100644 A");
 		entry(b, "100644 a");
-		byte[] data = b.toString().getBytes("UTF-8");
+		byte[] data = b.toString().getBytes(CHARSET);
 		checker.setSafeForMacOS(true);
 		assertCorrupt("duplicate entry names", OBJ_TREE, data);
 		assertSkipListAccepts(OBJ_TREE, data);
@@ -1478,11 +1478,11 @@ public void testInvalidTreeDuplicateNames6()
 
 	@Test
 	public void testInvalidTreeDuplicateNames7()
-			throws UnsupportedEncodingException, CorruptObjectException {
+			throws CorruptObjectException {
 		StringBuilder b = new StringBuilder();
 		entry(b, "100644 \u0065\u0301");
 		entry(b, "100644 \u00e9");
-		byte[] data = b.toString().getBytes("UTF-8");
+		byte[] data = b.toString().getBytes(CHARSET);
 		checker.setSafeForMacOS(true);
 		assertCorrupt("duplicate entry names", OBJ_TREE, data);
 		assertSkipListAccepts(OBJ_TREE, data);
@@ -1492,11 +1492,11 @@ public void testInvalidTreeDuplicateNames7()
 
 	@Test
 	public void testInvalidTreeDuplicateNames8()
-			throws UnsupportedEncodingException, CorruptObjectException {
+			throws CorruptObjectException {
 		StringBuilder b = new StringBuilder();
 		entry(b, "100644 A");
 		checker.setSafeForMacOS(true);
-		checker.checkTree(b.toString().getBytes("UTF-8"));
+		checker.checkTree(b.toString().getBytes(CHARSET));
 	}
 
 	@Test
@@ -1607,7 +1607,7 @@ private void checkOneName(String name) throws CorruptObjectException {
 		checker.checkTree(encodeASCII(b.toString()));
 	}
 
-	private static void entry(StringBuilder b, final String modeName) {
+	private static void entry(StringBuilder b, String modeName) {
 		b.append(modeName);
 		b.append('\0');
 		for (int i = 0; i < OBJECT_ID_LENGTH; i++)
@@ -1647,7 +1647,7 @@ private void assertSkipListRejects(String msg, int type, byte[] data) {
 		checker.setSkipList(null);
 	}
 
-	private static ObjectIdSet set(final ObjectId... ids) {
+	private static ObjectIdSet set(ObjectId... ids) {
 		return new ObjectIdSet() {
 			@Override
 			public boolean contains(AnyObjectId objectId) {
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ObjectIdSerializerTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ObjectIdSerializerTest.java
new file mode 100644
index 0000000..d98b792
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ObjectIdSerializerTest.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2018, David Pursehouse <david.pursehouse@gmail.com>
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ *   copyright notice, this list of conditions and the following
+ *   disclaimer in the documentation and/or other materials provided
+ *   with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ *   names of its contributors may be used to endorse or promote
+ *   products derived from this software without specific prior
+ *   written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.lib;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import org.junit.Test;
+
+public class ObjectIdSerializerTest {
+	@Test
+	public void serialize() throws Exception {
+		ObjectId original = new ObjectId(1, 2, 3, 4, 5);
+		ObjectId deserialized = writeAndReadBackFromTempFile(original);
+		assertEquals(original, deserialized);
+	}
+
+	@Test
+	public void serializeZeroId() throws Exception {
+		ObjectId original = ObjectId.zeroId();
+		ObjectId deserialized = writeAndReadBackFromTempFile(original);
+		assertEquals(original, deserialized);
+	}
+
+	@Test
+	public void serializeNull() throws Exception {
+		ObjectId deserialized = writeAndReadBackFromTempFile(null);
+		assertNull(deserialized);
+	}
+
+	private ObjectId writeAndReadBackFromTempFile(ObjectId objectId)
+			throws Exception {
+		File file = File.createTempFile("ObjectIdSerializerTest_", "");
+		try (OutputStream out = new FileOutputStream(file)) {
+			if (objectId == null) {
+				ObjectIdSerializer.write(out, objectId);
+			} else {
+				ObjectIdSerializer.writeWithoutMarker(out, objectId);
+			}
+		}
+		try (InputStream in = new FileInputStream(file)) {
+			if (objectId == null) {
+				return ObjectIdSerializer.read(in);
+			} else {
+				return ObjectIdSerializer.readWithoutMarker(in);
+			}
+		}
+	}
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RacyGitTests.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RacyGitTests.java
index 9236b4e..8d9ccab 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RacyGitTests.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RacyGitTests.java
@@ -176,12 +176,9 @@ public void testRacyGitDetection() throws Exception {
 
 	private File addToWorkDir(String path, String content) throws IOException {
 		File f = new File(db.getWorkTree(), path);
-		FileOutputStream fos = new FileOutputStream(f);
-		try {
+		try (FileOutputStream fos = new FileOutputStream(f)) {
 			fos.write(content.getBytes(Constants.CHARACTER_ENCODING));
 			return f;
-		} finally {
-			fos.close();
 		}
 	}
 }
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RefTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RefTest.java
index 7fb3309..2481e64 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RefTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RefTest.java
@@ -57,6 +57,7 @@
 import java.io.File;
 import java.io.FileOutputStream;
 import java.io.IOException;
+import java.util.List;
 import java.util.Map;
 import java.util.TreeSet;
 
@@ -253,11 +254,11 @@ public void testReadLoosePackedRef() throws IOException,
 			InterruptedException {
 		Ref ref = db.exactRef("refs/heads/master");
 		assertEquals(Storage.PACKED, ref.getStorage());
-		FileOutputStream os = new FileOutputStream(new File(db.getDirectory(),
-				"refs/heads/master"));
-		os.write(ref.getObjectId().name().getBytes());
-		os.write('\n');
-		os.close();
+		try (FileOutputStream os = new FileOutputStream(
+				new File(db.getDirectory(), "refs/heads/master"))) {
+			os.write(ref.getObjectId().name().getBytes());
+			os.write('\n');
+		}
 
 		ref = db.exactRef("refs/heads/master");
 		assertEquals(Storage.LOOSE, ref.getStorage());
@@ -305,4 +306,26 @@ public void testResolvedSymRef() throws IOException {
 		assertSame(dst.getPeeledObjectId(), ref.getPeeledObjectId());
 		assertEquals(dst.isPeeled(), ref.isPeeled());
 	}
+
+	private static void checkContainsRef(List<Ref> haystack, Ref needle) {
+		for (Ref ref : haystack) {
+			if (ref.getName().equals(needle.getName()) &&
+					ref.getObjectId().equals(needle.getObjectId())) {
+				return;
+			}
+		}
+		fail("list " + haystack + " does not contain ref " + needle);
+	}
+
+	@Test
+	public void testGetRefsByPrefix() throws IOException {
+		List<Ref> refs = db.getRefDatabase().getRefsByPrefix("refs/heads/g");
+		assertEquals(2, refs.size());
+		checkContainsRef(refs, db.exactRef("refs/heads/g"));
+		checkContainsRef(refs, db.exactRef("refs/heads/gitlink"));
+
+		refs = db.getRefDatabase().getRefsByPrefix("refs/heads/prefix/");
+		assertEquals(1, refs.size());
+		checkContainsRef(refs, db.exactRef("refs/heads/prefix/a"));
+	}
 }
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RepositoryCacheTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RepositoryCacheTest.java
index 1107c2c..58b005c 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RepositoryCacheTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RepositoryCacheTest.java
@@ -94,24 +94,25 @@ public void testBareFileKey() throws IOException {
 
 	@Test
 	public void testFileKeyOpenExisting() throws IOException {
-		Repository r;
+		try (Repository r = new FileKey(db.getDirectory(), db.getFS())
+				.open(true)) {
+			assertNotNull(r);
+			assertEqualsFile(db.getDirectory(), r.getDirectory());
+		}
 
-		r = new FileKey(db.getDirectory(), db.getFS()).open(true);
-		assertNotNull(r);
-		assertEqualsFile(db.getDirectory(), r.getDirectory());
-		r.close();
-
-		r = new FileKey(db.getDirectory(), db.getFS()).open(false);
-		assertNotNull(r);
-		assertEqualsFile(db.getDirectory(), r.getDirectory());
-		r.close();
+		try (Repository r = new FileKey(db.getDirectory(), db.getFS())
+				.open(false)) {
+			assertNotNull(r);
+			assertEqualsFile(db.getDirectory(), r.getDirectory());
+		}
 	}
 
 	@Test
 	public void testFileKeyOpenNew() throws IOException {
-		final Repository n = createRepository(true, false);
-		final File gitdir = n.getDirectory();
-		n.close();
+		File gitdir;
+		try (Repository n = createRepository(true, false)) {
+			gitdir = n.getDirectory();
+		}
 		recursiveDelete(gitdir);
 		assertFalse(gitdir.exists());
 
@@ -143,6 +144,7 @@ public void testCacheRegisterOpen() throws Exception {
 	@Test
 	public void testCacheOpen() throws Exception {
 		final FileKey loc = FileKey.exact(db.getDirectory(), db.getFS());
+		@SuppressWarnings("resource") // We are testing the close() method
 		final Repository d2 = RepositoryCache.open(loc);
 		assertNotSame(db, d2);
 		assertSame(d2, RepositoryCache.open(FileKey.exact(loc.getFile(), db.getFS())));
@@ -176,6 +178,7 @@ public void testUnregister() {
 	@Test
 	public void testRepositoryUsageCount() throws Exception {
 		FileKey loc = FileKey.exact(db.getDirectory(), db.getFS());
+		@SuppressWarnings("resource") // We are testing the close() method
 		Repository d2 = RepositoryCache.open(loc);
 		assertEquals(1, d2.useCnt.get());
 		RepositoryCache.open(FileKey.exact(loc.getFile(), db.getFS()));
@@ -189,6 +192,7 @@ public void testRepositoryUsageCount() throws Exception {
 	@Test
 	public void testRepositoryUsageCountWithRegisteredRepository()
 			throws IOException {
+		@SuppressWarnings("resource") // We are testing the close() method
 		Repository repo = createRepository(false, false);
 		assertEquals(1, repo.useCnt.get());
 		RepositoryCache.register(repo);
@@ -200,6 +204,7 @@ public void testRepositoryUsageCountWithRegisteredRepository()
 	@Test
 	public void testRepositoryNotUnregisteringWhenClosing() throws Exception {
 		FileKey loc = FileKey.exact(db.getDirectory(), db.getFS());
+		@SuppressWarnings("resource") // We are testing the close() method
 		Repository d2 = RepositoryCache.open(loc);
 		assertEquals(1, d2.useCnt.get());
 		assertThat(RepositoryCache.getRegisteredKeys(),
@@ -214,6 +219,7 @@ public void testRepositoryNotUnregisteringWhenClosing() throws Exception {
 	@Test
 	public void testRepositoryUnregisteringWhenExpiredAndUsageCountNegative()
 			throws Exception {
+		@SuppressWarnings("resource") // We are testing the close() method
 		Repository repoA = createBareRepository();
 		RepositoryCache.register(repoA);
 
@@ -234,7 +240,9 @@ public void testRepositoryUnregisteringWhenExpiredAndUsageCountNegative()
 
 	@Test
 	public void testRepositoryUnregisteringWhenExpired() throws Exception {
+		@SuppressWarnings("resource") // We are testing the close() method
 		Repository repoA = createRepository(true, false);
+		@SuppressWarnings("resource") // We are testing the close() method
 		Repository repoB = createRepository(true, false);
 		Repository repoC = createBareRepository();
 		RepositoryCache.register(repoA);
@@ -268,6 +276,7 @@ public void testRepositoryUnregisteringWhenExpired() throws Exception {
 
 	@Test
 	public void testReconfigure() throws InterruptedException, IOException {
+		@SuppressWarnings("resource") // We are testing the close() method
 		Repository repo = createRepository(false, false);
 		RepositoryCache.register(repo);
 		assertTrue(RepositoryCache.isCached(repo));
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RepositoryResolveTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RepositoryResolveTest.java
index 1d2a4e9..05b78ea 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RepositoryResolveTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RepositoryResolveTest.java
@@ -324,6 +324,8 @@ public void invalidNames() throws AmbiguousObjectException, IOException {
 		assertFalse(Repository.isValidRefName("x/a\\b"));
 		assertFalse(Repository.isValidRefName("x/a\u0000"));
 
+		db.resolve("x/a@");
+
 		assertUnparseable(".");
 		assertUnparseable("x@{3");
 		assertUnparseable("x[b");
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/SquashCommitMsgTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/SquashCommitMsgTest.java
index 3bcd787..203c00e 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/SquashCommitMsgTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/SquashCommitMsgTest.java
@@ -66,12 +66,9 @@ public void testReadWriteMergeMsg() throws IOException {
 		db.writeSquashCommitMsg(null);
 		assertEquals(db.readSquashCommitMsg(), null);
 		assertFalse(new File(db.getDirectory(), Constants.SQUASH_MSG).exists());
-		FileOutputStream fos = new FileOutputStream(new File(db.getDirectory(),
-				Constants.SQUASH_MSG));
-		try {
+		try (FileOutputStream fos = new FileOutputStream(
+				new File(db.getDirectory(), Constants.SQUASH_MSG))) {
 			fos.write(squashMsg.getBytes(Constants.CHARACTER_ENCODING));
-		} finally {
-			fos.close();
 		}
 		assertEquals(db.readSquashCommitMsg(), squashMsg);
 	}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ValidRefNameTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ValidRefNameTest.java
index d431a89..87e901f 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ValidRefNameTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ValidRefNameTest.java
@@ -51,7 +51,7 @@
 import org.junit.Test;
 
 public class ValidRefNameTest {
-	private static void assertValid(final boolean exp, final String name) {
+	private static void assertValid(boolean exp, String name) {
 		SystemReader instance = SystemReader.getInstance();
 		try {
 			setUnixSystemReader();
@@ -81,7 +81,7 @@ private static void setUnixSystemReader() {
 		});
 	}
 
-	private static void assertInvalidOnWindows(final String name) {
+	private static void assertInvalidOnWindows(String name) {
 		SystemReader instance = SystemReader.getInstance();
 		try {
 			setUnixSystemReader();
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/CherryPickTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/CherryPickTest.java
index 4948b37..19f6dcb 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/CherryPickTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/CherryPickTest.java
@@ -183,7 +183,7 @@ public void testRevert() throws Exception {
 		assertFalse(tw.next());
 	}
 
-	private static void assertCorrectId(final DirCache treeT, final TreeWalk tw) {
+	private static void assertCorrectId(DirCache treeT, TreeWalk tw) {
 		assertEquals(treeT.getEntry(tw.getPathString()).getObjectId(), tw
 				.getObjectId(0));
 	}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/RecursiveMergerTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/CrissCrossMergeTest.java
similarity index 96%
rename from org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/RecursiveMergerTest.java
rename to org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/CrissCrossMergeTest.java
index 039a6e8..aaa08a9 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/RecursiveMergerTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/CrissCrossMergeTest.java
@@ -83,7 +83,7 @@
 import org.junit.runner.RunWith;
 
 @RunWith(Theories.class)
-public class RecursiveMergerTest extends RepositoryTestCase {
+public class CrissCrossMergeTest extends RepositoryTestCase {
 	static int counter = 0;
 
 	@DataPoints
@@ -783,7 +783,7 @@ void modifyIndex(IndexState indexState, String path, String other)
 		}
 	}
 
-	private void setIndex(final ObjectId id, String path)
+	private void setIndex(ObjectId id, String path)
 			throws MissingObjectException, IOException {
 		DirCache lockedDircache;
 		DirCacheEditor dcedit;
@@ -817,40 +817,35 @@ private ObjectId contentId(String revName, String path) throws Exception {
 
 	void modifyWorktree(WorktreeState worktreeState, String path, String other)
 			throws Exception {
-		FileOutputStream fos = null;
-		ObjectId bloblId;
-
-		try {
-			switch (worktreeState) {
-			case Missing:
-				new File(db.getWorkTree(), path).delete();
-				break;
-			case DifferentFromHeadAndOther:
-				write(new File(db.getWorkTree(), path),
-						Integer.toString(counter++));
-				break;
-			case SameAsHead:
-				bloblId = contentId(Constants.HEAD, path);
-				fos = new FileOutputStream(new File(db.getWorkTree(), path));
-				db.newObjectReader().open(bloblId).copyTo(fos);
-				break;
-			case SameAsOther:
-				bloblId = contentId(other, path);
-				fos = new FileOutputStream(new File(db.getWorkTree(), path));
-				db.newObjectReader().open(bloblId).copyTo(fos);
-				break;
-			case Bare:
-				if (db.isBare())
-					return;
-				File workTreeFile = db.getWorkTree();
-				db.getConfig().setBoolean("core", null, "bare", true);
-				db.getDirectory().renameTo(new File(workTreeFile, "test.git"));
-				db = new FileRepository(new File(workTreeFile, "test.git"));
-				db_t = new TestRepository<>(db);
+		switch (worktreeState) {
+		case Missing:
+			new File(db.getWorkTree(), path).delete();
+			break;
+		case DifferentFromHeadAndOther:
+			write(new File(db.getWorkTree(), path),
+					Integer.toString(counter++));
+			break;
+		case SameAsHead:
+			try (FileOutputStream fos = new FileOutputStream(
+					new File(db.getWorkTree(), path))) {
+				db.newObjectReader().open(contentId(Constants.HEAD, path))
+						.copyTo(fos);
 			}
-		} finally {
-			if (fos != null)
-				fos.close();
+			break;
+		case SameAsOther:
+			try (FileOutputStream fos = new FileOutputStream(
+					new File(db.getWorkTree(), path))) {
+				db.newObjectReader().open(contentId(other, path)).copyTo(fos);
+			}
+			break;
+		case Bare:
+			if (db.isBare())
+				return;
+			File workTreeFile = db.getWorkTree();
+			db.getConfig().setBoolean("core", null, "bare", true);
+			db.getDirectory().renameTo(new File(workTreeFile, "test.git"));
+			db = new FileRepository(new File(workTreeFile, "test.git"));
+			db_t = new TestRepository<>(db);
 		}
 	}
 
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/ResolveMergerTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/MergerTest.java
similarity index 75%
rename from org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/ResolveMergerTest.java
rename to org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/MergerTest.java
index d8b8750..58093a3 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/ResolveMergerTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/MergerTest.java
@@ -42,10 +42,12 @@
  */
 package org.eclipse.jgit.merge;
 
-import static java.nio.charset.StandardCharsets.UTF_8;
+import static org.eclipse.jgit.lib.Constants.CHARSET;
 import static org.eclipse.jgit.lib.Constants.OBJ_BLOB;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 
 import java.io.ByteArrayOutputStream;
@@ -53,6 +55,7 @@
 import java.io.FileInputStream;
 import java.io.IOException;
 import java.util.Arrays;
+import java.util.Map;
 
 import org.eclipse.jgit.api.Git;
 import org.eclipse.jgit.api.MergeResult;
@@ -61,34 +64,44 @@
 import org.eclipse.jgit.api.errors.GitAPIException;
 import org.eclipse.jgit.api.errors.JGitInternalException;
 import org.eclipse.jgit.dircache.DirCache;
+import org.eclipse.jgit.dircache.DirCacheEditor;
+import org.eclipse.jgit.dircache.DirCacheEntry;
+import org.eclipse.jgit.errors.ConfigInvalidException;
 import org.eclipse.jgit.errors.NoMergeBaseException;
 import org.eclipse.jgit.errors.NoMergeBaseException.MergeBaseFailureReason;
 import org.eclipse.jgit.junit.RepositoryTestCase;
 import org.eclipse.jgit.junit.TestRepository;
+import org.eclipse.jgit.lib.AnyObjectId;
+import org.eclipse.jgit.lib.ConfigConstants;
+import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.FileMode;
 import org.eclipse.jgit.lib.ObjectId;
 import org.eclipse.jgit.lib.ObjectInserter;
+import org.eclipse.jgit.lib.ObjectLoader;
+import org.eclipse.jgit.lib.ObjectReader;
+import org.eclipse.jgit.lib.ObjectStream;
+import org.eclipse.jgit.lib.StoredConfig;
 import org.eclipse.jgit.merge.ResolveMerger.MergeFailureReason;
 import org.eclipse.jgit.revwalk.RevCommit;
 import org.eclipse.jgit.revwalk.RevObject;
 import org.eclipse.jgit.revwalk.RevTree;
 import org.eclipse.jgit.revwalk.RevWalk;
+import org.eclipse.jgit.storage.file.FileBasedConfig;
 import org.eclipse.jgit.treewalk.FileTreeIterator;
 import org.eclipse.jgit.util.FS;
 import org.eclipse.jgit.util.FileUtils;
 import org.junit.Assert;
-import org.junit.experimental.theories.DataPoint;
+import org.junit.experimental.theories.DataPoints;
 import org.junit.experimental.theories.Theories;
 import org.junit.experimental.theories.Theory;
 import org.junit.runner.RunWith;
 
 @RunWith(Theories.class)
-public class ResolveMergerTest extends RepositoryTestCase {
+public class MergerTest extends RepositoryTestCase {
 
-	@DataPoint
-	public static MergeStrategy resolve = MergeStrategy.RESOLVE;
-
-	@DataPoint
-	public static MergeStrategy recursive = MergeStrategy.RECURSIVE;
+	@DataPoints
+	public static MergeStrategy[] strategiesUnderTest = new MergeStrategy[] {
+			MergeStrategy.RECURSIVE, MergeStrategy.RESOLVE };
 
 	@Theory
 	public void failingDeleteOfDirectoryWithUntrackedContent(
@@ -383,6 +396,38 @@ public void mergeWithCrlfInWT(MergeStrategy strategy) throws IOException,
 				mergeResult.getMergeStatus());
 	}
 
+	@Theory
+	public void mergeWithCrlfAutoCrlfTrue(MergeStrategy strategy)
+			throws IOException, GitAPIException {
+		Git git = Git.wrap(db);
+		db.getConfig().setString("core", null, "autocrlf", "true");
+		db.getConfig().save();
+		writeTrashFile("crlf.txt", "a crlf file\r\n");
+		git.add().addFilepattern("crlf.txt").call();
+		git.commit().setMessage("base").call();
+
+		git.branchCreate().setName("brancha").call();
+
+		writeTrashFile("crlf.txt", "a crlf file\r\na second line\r\n");
+		git.add().addFilepattern("crlf.txt").call();
+		git.commit().setMessage("on master").call();
+
+		git.checkout().setName("brancha").call();
+		File testFile = writeTrashFile("crlf.txt",
+				"a first line\r\na crlf file\r\n");
+		git.add().addFilepattern("crlf.txt").call();
+		git.commit().setMessage("on brancha").call();
+
+		MergeResult mergeResult = git.merge().setStrategy(strategy)
+				.include(db.resolve("master")).call();
+		assertEquals(MergeResult.MergeStatus.MERGED,
+				mergeResult.getMergeStatus());
+		checkFile(testFile, "a first line\r\na crlf file\r\na second line\r\n");
+		assertEquals(
+				"[crlf.txt, mode:100644, content:a first line\na crlf file\na second line\n]",
+				indexState(CONTENT));
+	}
+
 	/**
 	 * Merging two equal subtrees when the index does not contain any file in
 	 * that subtree should lead to a merged state.
@@ -689,6 +734,143 @@ public void checkContentMergeNoConflict_noRepo(MergeStrategy strategy)
 		}
 	}
 
+
+	/**
+	 * Merging a change involving large binary files should short-circuit reads.
+	 *
+	 * @param strategy
+	 * @throws Exception
+	 */
+	@Theory
+	public void checkContentMergeLargeBinaries(MergeStrategy strategy) throws Exception {
+		Git git = Git.wrap(db);
+		final int LINELEN = 72;
+
+		// setup a merge that would work correctly if we disconsider the stray '\0'
+		// that the file contains near the start.
+		byte[] binary = new byte[LINELEN * 2000];
+		for (int i = 0; i < binary.length; i++) {
+			binary[i] = (byte)((i % LINELEN) == 0 ? '\n' : 'x');
+		}
+		binary[50] = '\0';
+
+		writeTrashFile("file", new String(binary, CHARSET));
+		git.add().addFilepattern("file").call();
+		RevCommit first = git.commit().setMessage("added file").call();
+
+		// Generate an edit in a single line.
+		int idx = LINELEN * 1200 + 1;
+		byte save = binary[idx];
+		binary[idx] = '@';
+		writeTrashFile("file", new String(binary, CHARSET));
+
+		binary[idx] = save;
+		git.add().addFilepattern("file").call();
+		RevCommit masterCommit = git.commit().setAll(true)
+			.setMessage("modified file l 1200").call();
+
+		git.checkout().setCreateBranch(true).setStartPoint(first).setName("side").call();
+		binary[LINELEN * 1500 + 1] = '!';
+		writeTrashFile("file", new String(binary, CHARSET));
+		git.add().addFilepattern("file").call();
+		RevCommit sideCommit = git.commit().setAll(true)
+			.setMessage("modified file l 1500").call();
+
+		try (ObjectInserter ins = db.newObjectInserter()) {
+			// Check that we don't read the large blobs.
+			ObjectInserter forbidInserter = new ObjectInserter.Filter() {
+				@Override
+				protected ObjectInserter delegate() {
+					return ins;
+				}
+
+				@Override
+				public ObjectReader newReader() {
+					return new BigReadForbiddenReader(super.newReader(), 8000);
+				}
+			};
+
+			ResolveMerger merger =
+				(ResolveMerger) strategy.newMerger(forbidInserter, db.getConfig());
+			boolean noProblems = merger.merge(masterCommit, sideCommit);
+			assertFalse(noProblems);
+		}
+	}
+
+	/**
+	 * Throws an exception if reading beyond limit.
+	 */
+	class BigReadForbiddenStream extends ObjectStream.Filter {
+		int limit;
+
+		BigReadForbiddenStream(ObjectStream orig, int limit) {
+			super(orig.getType(), orig.getSize(), orig);
+			this.limit = limit;
+		}
+
+		@Override
+		public long skip(long n) throws IOException {
+			limit -= n;
+			if (limit < 0) {
+				throw new IllegalStateException();
+			}
+
+			return super.skip(n);
+		}
+
+		@Override
+		public int read() throws IOException {
+			int r = super.read();
+			limit--;
+			if (limit < 0) {
+				throw new IllegalStateException();
+			}
+			return r;
+		}
+
+		@Override
+		public int read(byte[] b, int off, int len) throws IOException {
+			int n = super.read(b, off, len);
+			limit -= n;
+			if (limit < 0) {
+				throw new IllegalStateException();
+			}
+			return n;
+		}
+	}
+
+	class BigReadForbiddenReader extends ObjectReader.Filter {
+		ObjectReader delegate;
+		int limit;
+
+		@Override
+		protected ObjectReader delegate() {
+			return delegate;
+		}
+
+		BigReadForbiddenReader(ObjectReader delegate, int limit) {
+			this.delegate = delegate;
+			this.limit = limit;
+		}
+
+		@Override
+		public ObjectLoader open(AnyObjectId objectId, int typeHint) throws IOException {
+			ObjectLoader orig = super.open(objectId, typeHint);
+			return new ObjectLoader.Filter() {
+				@Override
+				protected ObjectLoader delegate() {
+					return orig;
+				}
+
+				@Override
+				public ObjectStream openStream() throws IOException {
+					ObjectStream os = orig.openStream();
+					return new BigReadForbiddenStream(os, limit);
+				}
+			};
+		}
+	}
+
 	@Theory
 	public void checkContentMergeConflict(MergeStrategy strategy)
 			throws Exception {
@@ -751,7 +933,7 @@ public void checkContentMergeConflict_noTree(MergeStrategy strategy)
 			merger.getMergeResults().get("file");
 			try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
 				fmt.formatMerge(out, merger.getMergeResults().get("file"),
-						"BASE", "OURS", "THEIRS", UTF_8.name());
+						"BASE", "OURS", "THEIRS", CHARSET.name());
 				String expected = "<<<<<<< OURS\n"
 						+ "1master\n"
 						+ "=======\n"
@@ -759,7 +941,7 @@ public void checkContentMergeConflict_noTree(MergeStrategy strategy)
 						+ ">>>>>>> THEIRS\n"
 						+ "2\n"
 						+ "3";
-				assertEquals(expected, new String(out.toByteArray(), UTF_8));
+				assertEquals(expected, new String(out.toByteArray(), CHARSET));
 			}
 		}
 	}
@@ -849,19 +1031,21 @@ public void checkLockedFilesToBeDeleted(MergeStrategy strategy)
 		git.commit().setMessage("added c.txt").call();
 
 		// Get a handle to the the file so on windows it can't be deleted.
-		FileInputStream fis = new FileInputStream(new File(db.getWorkTree(),
-				"b.txt"));
-		MergeResult mergeRes = git.merge().setStrategy(strategy)
-				.include(masterCommit).call();
-		if (mergeRes.getMergeStatus().equals(MergeStatus.FAILED)) {
-			// probably windows
-			assertEquals(1, mergeRes.getFailingPaths().size());
-			assertEquals(MergeFailureReason.COULD_NOT_DELETE, mergeRes
-					.getFailingPaths().get("b.txt"));
+		try (FileInputStream fis = new FileInputStream(
+				new File(db.getWorkTree(), "b.txt"))) {
+			MergeResult mergeRes = git.merge().setStrategy(strategy)
+					.include(masterCommit).call();
+			if (mergeRes.getMergeStatus().equals(MergeStatus.FAILED)) {
+				// probably windows
+				assertEquals(1, mergeRes.getFailingPaths().size());
+				assertEquals(MergeFailureReason.COULD_NOT_DELETE,
+						mergeRes.getFailingPaths().get("b.txt"));
+			}
+			assertEquals(
+					"[a.txt, mode:100644, content:master]"
+							+ "[c.txt, mode:100644, content:side]",
+					indexState(CONTENT));
 		}
-		assertEquals("[a.txt, mode:100644, content:master]"
-				+ "[c.txt, mode:100644, content:side]", indexState(CONTENT));
-		fis.close();
 	}
 
 	@Theory
@@ -957,6 +1141,146 @@ public void checkForCorrectIndex(MergeStrategy strategy) throws Exception {
 				indexState(CONTENT));
 	}
 
+	/**
+	 * Merging two conflicting submodules when the index does not contain any
+	 * entry for that submodule.
+	 *
+	 * @param strategy
+	 * @throws Exception
+	 */
+	@Theory
+	public void checkMergeConflictingSubmodulesWithoutIndex(
+			MergeStrategy strategy) throws Exception {
+		Git git = Git.wrap(db);
+		writeTrashFile("initial", "initial");
+		git.add().addFilepattern("initial").call();
+		RevCommit initial = git.commit().setMessage("initial").call();
+
+		writeSubmodule("one", ObjectId
+				.fromString("1000000000000000000000000000000000000000"));
+		git.add().addFilepattern(Constants.DOT_GIT_MODULES).call();
+		RevCommit right = git.commit().setMessage("added one").call();
+
+		// a second commit in the submodule
+
+		git.checkout().setStartPoint(initial).setName("left")
+				.setCreateBranch(true).call();
+		writeSubmodule("one", ObjectId
+				.fromString("2000000000000000000000000000000000000000"));
+
+		git.add().addFilepattern(Constants.DOT_GIT_MODULES).call();
+		git.commit().setMessage("a different one").call();
+
+		MergeResult result = git.merge().setStrategy(strategy).include(right)
+				.call();
+
+		assertEquals(MergeStatus.CONFLICTING, result.getMergeStatus());
+		Map<String, int[][]> conflicts = result.getConflicts();
+		assertEquals(1, conflicts.size());
+		assertNotNull(conflicts.get("one"));
+	}
+
+	/**
+	 * Merging two non-conflicting submodules when the index does not contain
+	 * any entry for either submodule.
+	 *
+	 * @param strategy
+	 * @throws Exception
+	 */
+	@Theory
+	public void checkMergeNonConflictingSubmodulesWithoutIndex(
+			MergeStrategy strategy) throws Exception {
+		Git git = Git.wrap(db);
+		writeTrashFile("initial", "initial");
+		git.add().addFilepattern("initial").call();
+
+		writeSubmodule("one", ObjectId
+				.fromString("1000000000000000000000000000000000000000"));
+
+		// Our initial commit should include a .gitmodules with a bunch of
+		// comment lines, so that
+		// we don't have a content merge issue when we add a new submodule at
+		// the top and a different
+		// one at the bottom. This is sort of a hack, but it should allow
+		// add/add submodule merges
+		String existing = read(Constants.DOT_GIT_MODULES);
+		String context = "\n# context\n# more context\n# yet more context\n";
+		write(new File(db.getWorkTree(), Constants.DOT_GIT_MODULES),
+				existing + context + context + context);
+
+		git.add().addFilepattern(Constants.DOT_GIT_MODULES).call();
+		RevCommit initial = git.commit().setMessage("initial").call();
+
+		writeSubmodule("two", ObjectId
+				.fromString("1000000000000000000000000000000000000000"));
+		git.add().addFilepattern(Constants.DOT_GIT_MODULES).call();
+
+		RevCommit right = git.commit().setMessage("added two").call();
+
+		git.checkout().setStartPoint(initial).setName("left")
+				.setCreateBranch(true).call();
+
+		// we need to manually create the submodule for three for the
+		// .gitmodules hackery
+		addSubmoduleToIndex("three", ObjectId
+				.fromString("1000000000000000000000000000000000000000"));
+		new File(db.getWorkTree(), "three").mkdir();
+
+		existing = read(Constants.DOT_GIT_MODULES);
+		String three = "[submodule \"three\"]\n\tpath = three\n\turl = "
+				+ db.getDirectory().toURI() + "\n";
+		write(new File(db.getWorkTree(), Constants.DOT_GIT_MODULES),
+				three + existing);
+
+		git.add().addFilepattern(Constants.DOT_GIT_MODULES).call();
+		git.commit().setMessage("a different one").call();
+
+		MergeResult result = git.merge().setStrategy(strategy).include(right)
+				.call();
+
+		assertNull(result.getCheckoutConflicts());
+		assertNull(result.getFailingPaths());
+		for (String dir : Arrays.asList("one", "two", "three")) {
+			assertTrue(new File(db.getWorkTree(), dir).isDirectory());
+		}
+	}
+
+	private void writeSubmodule(String path, ObjectId commit)
+			throws IOException, ConfigInvalidException {
+		addSubmoduleToIndex(path, commit);
+		new File(db.getWorkTree(), path).mkdir();
+
+		StoredConfig config = db.getConfig();
+		config.setString(ConfigConstants.CONFIG_SUBMODULE_SECTION, path,
+				ConfigConstants.CONFIG_KEY_URL,
+				db.getDirectory().toURI().toString());
+		config.save();
+
+		FileBasedConfig modulesConfig = new FileBasedConfig(
+				new File(db.getWorkTree(), Constants.DOT_GIT_MODULES),
+				db.getFS());
+		modulesConfig.load();
+		modulesConfig.setString(ConfigConstants.CONFIG_SUBMODULE_SECTION, path,
+				ConfigConstants.CONFIG_KEY_PATH, path);
+		modulesConfig.save();
+
+	}
+
+	private void addSubmoduleToIndex(String path, ObjectId commit)
+			throws IOException {
+		DirCache cache = db.lockDirCache();
+		DirCacheEditor editor = cache.editor();
+		editor.add(new DirCacheEditor.PathEdit(path) {
+
+			@Override
+			public void apply(DirCacheEntry ent) {
+				ent.setFileMode(FileMode.GITLINK);
+				ent.setObjectId(commit);
+			}
+		});
+		editor.commit();
+	}
+
 	// Assert that every specified index entry has the same last modification
 	// timestamp as the associated file
 	private void checkConsistentLastModified(String... pathes)
@@ -1004,6 +1328,6 @@ private String readBlob(ObjectId treeish, String path) throws Exception {
 		if (obj == null) {
 			return null;
 		}
-		return new String(rw.getObjectReader().open(obj, OBJ_BLOB).getBytes(), UTF_8);
+		return new String(rw.getObjectReader().open(obj, OBJ_BLOB).getBytes(), CHARSET);
 	}
 }
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/SimpleMergeTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/SimpleMergeTest.java
index 951568e..dd2c2e8 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/SimpleMergeTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/SimpleMergeTest.java
@@ -403,7 +403,7 @@ public void testTrivialTwoWay_rightDFconflict2() throws Exception {
 		assertFalse(merge);
 	}
 
-	private static void assertCorrectId(final DirCache treeT, final TreeWalk tw) {
+	private static void assertCorrectId(DirCache treeT, TreeWalk tw) {
 		assertEquals(treeT.getEntry(tw.getPathString()).getObjectId(), tw
 				.getObjectId(0));
 	}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/patch/EditListTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/patch/EditListTest.java
index 61bd8cf..6c107f9 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/patch/EditListTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/patch/EditListTest.java
@@ -89,18 +89,15 @@ public void testTypes() throws IOException {
 		assertEquals(new Edit(23 - 1, 25 - 1, 22 - 1, 28 - 1), e.get(2));
 	}
 
-	private Patch parseTestPatchFile(final String patchFile) throws IOException {
-		final InputStream in = getClass().getResourceAsStream(patchFile);
-		if (in == null) {
-			fail("No " + patchFile + " test vector");
-			return null; // Never happens
-		}
-		try {
+	private Patch parseTestPatchFile(String patchFile) throws IOException {
+		try (InputStream in = getClass().getResourceAsStream(patchFile)) {
+			if (in == null) {
+				fail("No " + patchFile + " test vector");
+				return null; // Never happens
+			}
 			final Patch p = new Patch();
 			p.parse(in);
 			return p;
-		} finally {
-			in.close();
 		}
 	}
 }
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/patch/FileHeaderTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/patch/FileHeaderTest.java
index 7b4e014..24fbda1 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/patch/FileHeaderTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/patch/FileHeaderTest.java
@@ -433,30 +433,30 @@ public void testParseAbbrIndexLine_NoMode() {
 		assertTrue(ObjectId.fromString(nid).startsWith(fh.getNewId()));
 	}
 
-	private static void assertParse(final FileHeader fh) {
+	private static void assertParse(FileHeader fh) {
 		int ptr = fh.parseGitFileName(0, fh.buf.length);
 		assertTrue(ptr > 0);
 		ptr = fh.parseGitHeaders(ptr, fh.buf.length);
 		assertTrue(ptr > 0);
 	}
 
-	private static FileHeader data(final String in) {
+	private static FileHeader data(String in) {
 		return new FileHeader(Constants.encodeASCII(in), 0);
 	}
 
-	private static FileHeader header(final String path) {
+	private static FileHeader header(String path) {
 		return data(gitLine(path) + "--- " + path + "\n");
 	}
 
-	private static String gitLine(final String path) {
+	private static String gitLine(String path) {
 		return "a/" + path + " b/" + path + "\n";
 	}
 
-	private static FileHeader dqHeader(final String path) {
+	private static FileHeader dqHeader(String path) {
 		return data(dqGitLine(path) + "--- " + path + "\n");
 	}
 
-	private static String dqGitLine(final String path) {
+	private static String dqGitLine(String path) {
 		return "\"a/" + path + "\" \"b/" + path + "\"\n";
 	}
 }
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/patch/GetTextTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/patch/GetTextTest.java
index 2aaf6af..7b5868a 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/patch/GetTextTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/patch/GetTextTest.java
@@ -43,6 +43,8 @@
 
 package org.eclipse.jgit.patch;
 
+import static java.nio.charset.StandardCharsets.ISO_8859_1;
+import static org.eclipse.jgit.lib.Constants.CHARSET;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
@@ -58,7 +60,7 @@
 public class GetTextTest {
 	@Test
 	public void testGetText_BothISO88591() throws IOException {
-		final Charset cs = Charset.forName("ISO-8859-1");
+		final Charset cs = ISO_8859_1;
 		final Patch p = parseTestPatchFile();
 		assertTrue(p.getErrors().isEmpty());
 		assertEquals(1, p.getFiles().size());
@@ -69,7 +71,7 @@ public void testGetText_BothISO88591() throws IOException {
 
 	@Test
 	public void testGetText_NoBinary() throws IOException {
-		final Charset cs = Charset.forName("ISO-8859-1");
+		final Charset cs = ISO_8859_1;
 		final Patch p = parseTestPatchFile();
 		assertTrue(p.getErrors().isEmpty());
 		assertEquals(1, p.getFiles().size());
@@ -80,8 +82,8 @@ public void testGetText_NoBinary() throws IOException {
 
 	@Test
 	public void testGetText_Convert() throws IOException {
-		final Charset csOld = Charset.forName("ISO-8859-1");
-		final Charset csNew = Charset.forName("UTF-8");
+		final Charset csOld = ISO_8859_1;
+		final Charset csNew = CHARSET;
 		final Patch p = parseTestPatchFile();
 		assertTrue(p.getErrors().isEmpty());
 		assertEquals(1, p.getFiles().size());
@@ -100,8 +102,8 @@ public void testGetText_Convert() throws IOException {
 
 	@Test
 	public void testGetText_DiffCc() throws IOException {
-		final Charset csOld = Charset.forName("ISO-8859-1");
-		final Charset csNew = Charset.forName("UTF-8");
+		final Charset csOld = ISO_8859_1;
+		final Charset csNew = CHARSET;
 		final Patch p = parseTestPatchFile();
 		assertTrue(p.getErrors().isEmpty());
 		assertEquals(1, p.getFiles().size());
@@ -121,28 +123,24 @@ public void testGetText_DiffCc() throws IOException {
 
 	private Patch parseTestPatchFile() throws IOException {
 		final String patchFile = JGitTestUtil.getName() + ".patch";
-		final InputStream in = getClass().getResourceAsStream(patchFile);
-		if (in == null) {
-			fail("No " + patchFile + " test vector");
-			return null; // Never happens
-		}
-		try {
+		try (InputStream in = getClass().getResourceAsStream(patchFile)) {
+			if (in == null) {
+				fail("No " + patchFile + " test vector");
+				return null; // Never happens
+			}
 			final Patch p = new Patch();
 			p.parse(in);
 			return p;
-		} finally {
-			in.close();
 		}
 	}
 
-	private String readTestPatchFile(final Charset cs) throws IOException {
+	private String readTestPatchFile(Charset cs) throws IOException {
 		final String patchFile = JGitTestUtil.getName() + ".patch";
-		final InputStream in = getClass().getResourceAsStream(patchFile);
-		if (in == null) {
-			fail("No " + patchFile + " test vector");
-			return null; // Never happens
-		}
-		try {
+		try (InputStream in = getClass().getResourceAsStream(patchFile)) {
+			if (in == null) {
+				fail("No " + patchFile + " test vector");
+				return null; // Never happens
+			}
 			final InputStreamReader r = new InputStreamReader(in, cs);
 			char[] tmp = new char[2048];
 			final StringBuilder s = new StringBuilder();
@@ -150,8 +148,6 @@ private String readTestPatchFile(final Charset cs) throws IOException {
 			while ((n = r.read(tmp)) > 0)
 				s.append(tmp, 0, n);
 			return s.toString();
-		} finally {
-			in.close();
 		}
 	}
 }
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/patch/PatchCcErrorTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/patch/PatchCcErrorTest.java
index e4b4317..6989343 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/patch/PatchCcErrorTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/patch/PatchCcErrorTest.java
@@ -96,17 +96,14 @@ public void testError_CcTruncatedOld() throws IOException {
 
 	private Patch parseTestPatchFile() throws IOException {
 		final String patchFile = JGitTestUtil.getName() + ".patch";
-		final InputStream in = getClass().getResourceAsStream(patchFile);
-		if (in == null) {
-			fail("No " + patchFile + " test vector");
-			return null; // Never happens
-		}
-		try {
+		try (InputStream in = getClass().getResourceAsStream(patchFile)) {
+			if (in == null) {
+				fail("No " + patchFile + " test vector");
+				return null; // Never happens
+			}
 			final Patch p = new Patch();
 			p.parse(in);
 			return p;
-		} finally {
-			in.close();
 		}
 	}
 
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/patch/PatchCcTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/patch/PatchCcTest.java
index 837414b..4a26d50 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/patch/PatchCcTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/patch/PatchCcTest.java
@@ -199,17 +199,14 @@ public void testParse_CcDeleteFile() throws IOException {
 
 	private Patch parseTestPatchFile() throws IOException {
 		final String patchFile = JGitTestUtil.getName() + ".patch";
-		final InputStream in = getClass().getResourceAsStream(patchFile);
-		if (in == null) {
-			fail("No " + patchFile + " test vector");
-			return null; // Never happens
-		}
-		try {
+		try (InputStream in = getClass().getResourceAsStream(patchFile)) {
+			if (in == null) {
+				fail("No " + patchFile + " test vector");
+				return null; // Never happens
+			}
 			final Patch p = new Patch();
 			p.parse(in);
 			return p;
-		} finally {
-			in.close();
 		}
 	}
 }
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/patch/PatchErrorTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/patch/PatchErrorTest.java
index 52e3874..3bdf852 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/patch/PatchErrorTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/patch/PatchErrorTest.java
@@ -177,17 +177,14 @@ public void testError_GitBinaryNoForwardHunk() throws IOException {
 
 	private Patch parseTestPatchFile() throws IOException {
 		final String patchFile = JGitTestUtil.getName() + ".patch";
-		final InputStream in = getClass().getResourceAsStream(patchFile);
-		if (in == null) {
-			fail("No " + patchFile + " test vector");
-			return null; // Never happens
-		}
-		try {
+		try (InputStream in = getClass().getResourceAsStream(patchFile)) {
+			if (in == null) {
+				fail("No " + patchFile + " test vector");
+				return null; // Never happens
+			}
 			final Patch p = new Patch();
 			p.parse(in);
 			return p;
-		} finally {
-			in.close();
 		}
 	}
 }
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/patch/PatchTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/patch/PatchTest.java
index 9f57ab9..6a09a49 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/patch/PatchTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/patch/PatchTest.java
@@ -357,17 +357,14 @@ public void testParse_AddNoNewline() throws IOException {
 
 	private Patch parseTestPatchFile() throws IOException {
 		final String patchFile = JGitTestUtil.getName() + ".patch";
-		final InputStream in = getClass().getResourceAsStream(patchFile);
-		if (in == null) {
-			fail("No " + patchFile + " test vector");
-			return null; // Never happens
-		}
-		try {
+		try (InputStream in = getClass().getResourceAsStream(patchFile)) {
+			if (in == null) {
+				fail("No " + patchFile + " test vector");
+				return null; // Never happens
+			}
 			final Patch p = new Patch();
 			p.parse(in);
 			return p;
-		} finally {
-			in.close();
 		}
 	}
 }
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/FooterLineTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/FooterLineTest.java
index 87c8547..ad8327f 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/FooterLineTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/FooterLineTest.java
@@ -353,7 +353,7 @@ public void testMatchesBugId() throws IOException {
 		assertFalse("not CC", line.matches(FooterKey.CC));
 	}
 
-	private RevCommit parse(final String msg) throws IOException {
+	private RevCommit parse(String msg) throws IOException {
 		final StringBuilder buf = new StringBuilder();
 		buf.append("tree " + ObjectId.zeroId().name() + "\n");
 		buf.append("author A. U. Thor <a@example.com> 1 +0000\n");
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevCommitParseTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevCommitParseTest.java
index 1a15842..cfefac3 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevCommitParseTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevCommitParseTest.java
@@ -43,7 +43,8 @@
 
 package org.eclipse.jgit.revwalk;
 
-import static java.nio.charset.StandardCharsets.UTF_8;
+import static java.nio.charset.StandardCharsets.ISO_8859_1;
+import static org.eclipse.jgit.lib.Constants.CHARSET;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
@@ -113,7 +114,7 @@ public void testParse_NoParents() throws Exception {
 		assertNull(c.getTree());
 		assertNull(c.parents);
 
-		c.parseCanonical(rw, body.toString().getBytes("UTF-8"));
+		c.parseCanonical(rw, body.toString().getBytes(CHARSET));
 		assertNotNull(c.getTree());
 		assertEquals(treeId, c.getTree().getId());
 		assertSame(rw.lookupTree(treeId), c.getTree());
@@ -137,7 +138,7 @@ public void testParse_NoParents() throws Exception {
 		assertEquals(TimeZone.getTimeZone("GMT" + committerTimeZone), cCommitter.getTimeZone());
 	}
 
-	private RevCommit create(final String msg) throws Exception {
+	private RevCommit create(String msg) throws Exception {
 		final StringBuilder b = new StringBuilder();
 		b.append("tree 9788669ad918b6fcce64af8882fc9a81cb6aba67\n");
 		b.append("author A U. Thor <a_u_thor@example.com> 1218123387 +0700\n");
@@ -147,7 +148,7 @@ private RevCommit create(final String msg) throws Exception {
 
 		final RevCommit c;
 		c = new RevCommit(id("9473095c4cb2f12aefe1db8a355fe3fafba42f67"));
-		c.parseCanonical(new RevWalk(db), b.toString().getBytes("UTF-8"));
+		c.parseCanonical(new RevWalk(db), b.toString().getBytes(CHARSET));
 		return c;
 	}
 
@@ -160,7 +161,7 @@ public void testParse_WeirdHeaderOnlyCommit() throws Exception {
 
 		final RevCommit c;
 		c = new RevCommit(id("9473095c4cb2f12aefe1db8a355fe3fafba42f67"));
-		c.parseCanonical(new RevWalk(db), b.toString().getBytes("UTF-8"));
+		c.parseCanonical(new RevWalk(db), b.toString().getBytes(CHARSET));
 
 		assertEquals("", c.getFullMessage());
 		assertEquals("", c.getShortMessage());
@@ -175,7 +176,7 @@ public void testParse_incompleteAuthorAndCommitter() throws Exception {
 
 		final RevCommit c;
 		c = new RevCommit(id("9473095c4cb2f12aefe1db8a355fe3fafba42f67"));
-		c.parseCanonical(new RevWalk(db), b.toString().getBytes("UTF-8"));
+		c.parseCanonical(new RevWalk(db), b.toString().getBytes(CHARSET));
 
 		assertEquals(new PersonIdent("", "a_u_thor@example.com", 1218123387000l, 7), c.getAuthorIdent());
 		assertEquals(new PersonIdent("", "", 1218123390000l, -5), c.getCommitterIdent());
@@ -184,13 +185,13 @@ public void testParse_incompleteAuthorAndCommitter() throws Exception {
 	@Test
 	public void testParse_implicit_UTF8_encoded() throws Exception {
 		final ByteArrayOutputStream b = new ByteArrayOutputStream();
-		b.write("tree 9788669ad918b6fcce64af8882fc9a81cb6aba67\n".getBytes("UTF-8"));
-		b.write("author F\u00f6r fattare <a_u_thor@example.com> 1218123387 +0700\n".getBytes("UTF-8"));
-		b.write("committer C O. Miter <c@example.com> 1218123390 -0500\n".getBytes("UTF-8"));
-		b.write("\n".getBytes("UTF-8"));
-		b.write("Sm\u00f6rg\u00e5sbord\n".getBytes("UTF-8"));
-		b.write("\n".getBytes("UTF-8"));
-		b.write("\u304d\u308c\u3044\n".getBytes("UTF-8"));
+		b.write("tree 9788669ad918b6fcce64af8882fc9a81cb6aba67\n".getBytes(CHARSET));
+		b.write("author F\u00f6r fattare <a_u_thor@example.com> 1218123387 +0700\n".getBytes(CHARSET));
+		b.write("committer C O. Miter <c@example.com> 1218123390 -0500\n".getBytes(CHARSET));
+		b.write("\n".getBytes(CHARSET));
+		b.write("Sm\u00f6rg\u00e5sbord\n".getBytes(CHARSET));
+		b.write("\n".getBytes(CHARSET));
+		b.write("\u304d\u308c\u3044\n".getBytes(CHARSET));
 		final RevCommit c;
 		c = new RevCommit(id("9473095c4cb2f12aefe1db8a355fe3fafba42f67")); // bogus id
 		c.parseCanonical(new RevWalk(db), b.toByteArray());
@@ -204,13 +205,13 @@ public void testParse_implicit_UTF8_encoded() throws Exception {
 	@Test
 	public void testParse_implicit_mixed_encoded() throws Exception {
 		final ByteArrayOutputStream b = new ByteArrayOutputStream();
-		b.write("tree 9788669ad918b6fcce64af8882fc9a81cb6aba67\n".getBytes("UTF-8"));
-		b.write("author F\u00f6r fattare <a_u_thor@example.com> 1218123387 +0700\n".getBytes("ISO-8859-1"));
-		b.write("committer C O. Miter <c@example.com> 1218123390 -0500\n".getBytes("UTF-8"));
-		b.write("\n".getBytes("UTF-8"));
-		b.write("Sm\u00f6rg\u00e5sbord\n".getBytes("UTF-8"));
-		b.write("\n".getBytes("UTF-8"));
-		b.write("\u304d\u308c\u3044\n".getBytes("UTF-8"));
+		b.write("tree 9788669ad918b6fcce64af8882fc9a81cb6aba67\n".getBytes(CHARSET));
+		b.write("author F\u00f6r fattare <a_u_thor@example.com> 1218123387 +0700\n".getBytes(ISO_8859_1));
+		b.write("committer C O. Miter <c@example.com> 1218123390 -0500\n".getBytes(CHARSET));
+		b.write("\n".getBytes(CHARSET));
+		b.write("Sm\u00f6rg\u00e5sbord\n".getBytes(CHARSET));
+		b.write("\n".getBytes(CHARSET));
+		b.write("\u304d\u308c\u3044\n".getBytes(CHARSET));
 		final RevCommit c;
 		c = new RevCommit(id("9473095c4cb2f12aefe1db8a355fe3fafba42f67")); // bogus id
 		c.parseCanonical(new RevWalk(db), b.toByteArray());
@@ -259,14 +260,14 @@ public void testParse_explicit_encoded() throws Exception {
 	@Test
 	public void testParse_explicit_bad_encoded() throws Exception {
 		final ByteArrayOutputStream b = new ByteArrayOutputStream();
-		b.write("tree 9788669ad918b6fcce64af8882fc9a81cb6aba67\n".getBytes("UTF-8"));
-		b.write("author F\u00f6r fattare <a_u_thor@example.com> 1218123387 +0700\n".getBytes("ISO-8859-1"));
-		b.write("committer C O. Miter <c@example.com> 1218123390 -0500\n".getBytes("UTF-8"));
-		b.write("encoding EUC-JP\n".getBytes("UTF-8"));
-		b.write("\n".getBytes("UTF-8"));
-		b.write("\u304d\u308c\u3044\n".getBytes("UTF-8"));
-		b.write("\n".getBytes("UTF-8"));
-		b.write("Hi\n".getBytes("UTF-8"));
+		b.write("tree 9788669ad918b6fcce64af8882fc9a81cb6aba67\n".getBytes(CHARSET));
+		b.write("author F\u00f6r fattare <a_u_thor@example.com> 1218123387 +0700\n".getBytes(ISO_8859_1));
+		b.write("committer C O. Miter <c@example.com> 1218123390 -0500\n".getBytes(CHARSET));
+		b.write("encoding EUC-JP\n".getBytes(CHARSET));
+		b.write("\n".getBytes(CHARSET));
+		b.write("\u304d\u308c\u3044\n".getBytes(CHARSET));
+		b.write("\n".getBytes(CHARSET));
+		b.write("Hi\n".getBytes(CHARSET));
 		final RevCommit c;
 		c = new RevCommit(id("9473095c4cb2f12aefe1db8a355fe3fafba42f67")); // bogus id
 		c.parseCanonical(new RevWalk(db), b.toByteArray());
@@ -290,14 +291,14 @@ public void testParse_explicit_bad_encoded() throws Exception {
 	@Test
 	public void testParse_explicit_bad_encoded2() throws Exception {
 		final ByteArrayOutputStream b = new ByteArrayOutputStream();
-		b.write("tree 9788669ad918b6fcce64af8882fc9a81cb6aba67\n".getBytes("UTF-8"));
-		b.write("author F\u00f6r fattare <a_u_thor@example.com> 1218123387 +0700\n".getBytes("UTF-8"));
-		b.write("committer C O. Miter <c@example.com> 1218123390 -0500\n".getBytes("UTF-8"));
-		b.write("encoding ISO-8859-1\n".getBytes("UTF-8"));
-		b.write("\n".getBytes("UTF-8"));
-		b.write("\u304d\u308c\u3044\n".getBytes("UTF-8"));
-		b.write("\n".getBytes("UTF-8"));
-		b.write("Hi\n".getBytes("UTF-8"));
+		b.write("tree 9788669ad918b6fcce64af8882fc9a81cb6aba67\n".getBytes(CHARSET));
+		b.write("author F\u00f6r fattare <a_u_thor@example.com> 1218123387 +0700\n".getBytes(CHARSET));
+		b.write("committer C O. Miter <c@example.com> 1218123390 -0500\n".getBytes(CHARSET));
+		b.write("encoding ISO-8859-1\n".getBytes(CHARSET));
+		b.write("\n".getBytes(CHARSET));
+		b.write("\u304d\u308c\u3044\n".getBytes(CHARSET));
+		b.write("\n".getBytes(CHARSET));
+		b.write("Hi\n".getBytes(CHARSET));
 		final RevCommit c;
 		c = new RevCommit(id("9473095c4cb2f12aefe1db8a355fe3fafba42f67")); // bogus id
 		c.parseCanonical(new RevWalk(db), b.toByteArray());
@@ -312,13 +313,13 @@ public void testParse_explicit_bad_encoded2() throws Exception {
 	public void testParse_incorrectUtf8Name() throws Exception {
 		ByteArrayOutputStream b = new ByteArrayOutputStream();
 		b.write("tree 9788669ad918b6fcce64af8882fc9a81cb6aba67\n"
-				.getBytes(UTF_8));
-		b.write("author au <a@example.com> 1218123387 +0700\n".getBytes(UTF_8));
+				.getBytes(CHARSET));
+		b.write("author au <a@example.com> 1218123387 +0700\n".getBytes(CHARSET));
 		b.write("committer co <c@example.com> 1218123390 -0500\n"
-				.getBytes(UTF_8));
-		b.write("encoding 'utf8'\n".getBytes(UTF_8));
-		b.write("\n".getBytes(UTF_8));
-		b.write("Sm\u00f6rg\u00e5sbord\n".getBytes(UTF_8));
+				.getBytes(CHARSET));
+		b.write("encoding 'utf8'\n".getBytes(CHARSET));
+		b.write("\n".getBytes(CHARSET));
+		b.write("Sm\u00f6rg\u00e5sbord\n".getBytes(CHARSET));
 
 		RevCommit c = new RevCommit(
 				id("9473095c4cb2f12aefe1db8a355fe3fafba42f67"));
@@ -337,12 +338,12 @@ public void testParse_incorrectUtf8Name() throws Exception {
 	@Test
 	public void testParse_illegalEncoding() throws Exception {
 		ByteArrayOutputStream b = new ByteArrayOutputStream();
-		b.write("tree 9788669ad918b6fcce64af8882fc9a81cb6aba67\n".getBytes(UTF_8));
-		b.write("author au <a@example.com> 1218123387 +0700\n".getBytes(UTF_8));
-		b.write("committer co <c@example.com> 1218123390 -0500\n".getBytes(UTF_8));
-		b.write("encoding utf-8logoutputencoding=gbk\n".getBytes(UTF_8));
-		b.write("\n".getBytes(UTF_8));
-		b.write("message\n".getBytes(UTF_8));
+		b.write("tree 9788669ad918b6fcce64af8882fc9a81cb6aba67\n".getBytes(CHARSET));
+		b.write("author au <a@example.com> 1218123387 +0700\n".getBytes(CHARSET));
+		b.write("committer co <c@example.com> 1218123390 -0500\n".getBytes(CHARSET));
+		b.write("encoding utf-8logoutputencoding=gbk\n".getBytes(CHARSET));
+		b.write("\n".getBytes(CHARSET));
+		b.write("message\n".getBytes(CHARSET));
 
 		RevCommit c = new RevCommit(
 				id("9473095c4cb2f12aefe1db8a355fe3fafba42f67"));
@@ -364,12 +365,12 @@ public void testParse_illegalEncoding() throws Exception {
 	@Test
 	public void testParse_unsupportedEncoding() throws Exception {
 		ByteArrayOutputStream b = new ByteArrayOutputStream();
-		b.write("tree 9788669ad918b6fcce64af8882fc9a81cb6aba67\n".getBytes(UTF_8));
-		b.write("author au <a@example.com> 1218123387 +0700\n".getBytes(UTF_8));
-		b.write("committer co <c@example.com> 1218123390 -0500\n".getBytes(UTF_8));
-		b.write("encoding it_IT.UTF8\n".getBytes(UTF_8));
-		b.write("\n".getBytes(UTF_8));
-		b.write("message\n".getBytes(UTF_8));
+		b.write("tree 9788669ad918b6fcce64af8882fc9a81cb6aba67\n".getBytes(CHARSET));
+		b.write("author au <a@example.com> 1218123387 +0700\n".getBytes(CHARSET));
+		b.write("committer co <c@example.com> 1218123390 -0500\n".getBytes(CHARSET));
+		b.write("encoding it_IT.UTF8\n".getBytes(CHARSET));
+		b.write("\n".getBytes(CHARSET));
+		b.write("message\n".getBytes(CHARSET));
 
 		RevCommit c = new RevCommit(
 				id("9473095c4cb2f12aefe1db8a355fe3fafba42f67"));
@@ -482,7 +483,7 @@ public void testParse_GitStyleMessageWithCRLF() throws Exception {
 		assertEquals(shortMsg, c.getShortMessage());
 	}
 
-	private static ObjectId id(final String str) {
+	private static ObjectId id(String str) {
 		return ObjectId.fromString(str);
 	}
 }
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevObjectTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevObjectTest.java
index 95e7ca6..8e389ae 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevObjectTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevObjectTest.java
@@ -60,6 +60,7 @@ public void testId() throws Exception {
 		assertSame(a, a.getId());
 	}
 
+	@SuppressWarnings("unlikely-arg-type")
 	@Test
 	public void testEquals() throws Exception {
 		final RevCommit a1 = commit();
@@ -75,7 +76,7 @@ public void testEquals() throws Exception {
 
 		final RevCommit a2;
 		final RevCommit b2;
-		try (final RevWalk rw2 = new RevWalk(db)) {
+		try (RevWalk rw2 = new RevWalk(db)) {
 			a2 = rw2.parseCommit(a1);
 			b2 = rw2.parseCommit(b1);
 		}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevTagParseTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevTagParseTest.java
index f97043b..e11cef7 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevTagParseTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevTagParseTest.java
@@ -43,7 +43,8 @@
 
 package org.eclipse.jgit.revwalk;
 
-import static java.nio.charset.StandardCharsets.UTF_8;
+import static java.nio.charset.StandardCharsets.ISO_8859_1;
+import static org.eclipse.jgit.lib.Constants.CHARSET;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
@@ -81,7 +82,7 @@ public void testTagTag() throws Exception {
 		testOneType(Constants.OBJ_TAG);
 	}
 
-	private void testOneType(final int typeCode) throws Exception {
+	private void testOneType(int typeCode) throws Exception {
 		final ObjectId id = id("9788669ad918b6fcce64af8882fc9a81cb6aba67");
 		final StringBuilder b = new StringBuilder();
 		b.append("object " + id.name() + "\n");
@@ -97,7 +98,7 @@ private void testOneType(final int typeCode) throws Exception {
 		assertNull(c.getObject());
 		assertNull(c.getTagName());
 
-		c.parseCanonical(rw, b.toString().getBytes("UTF-8"));
+		c.parseCanonical(rw, b.toString().getBytes(CHARSET));
 		assertNotNull(c.getObject());
 		assertEquals(id, c.getObject().getId());
 		assertSame(rw.lookupAny(id, typeCode), c.getObject());
@@ -140,7 +141,7 @@ public void testParseAllFields() throws Exception {
 		assertNull(c.getObject());
 		assertNull(c.getTagName());
 
-		c.parseCanonical(rw, body.toString().getBytes("UTF-8"));
+		c.parseCanonical(rw, body.toString().getBytes(CHARSET));
 		assertNotNull(c.getObject());
 		assertEquals(treeId, c.getObject().getId());
 		assertSame(rw.lookupTree(treeId), c.getObject());
@@ -188,7 +189,7 @@ public void testParseOldStyleNoTagger() throws Exception {
 		assertNull(c.getObject());
 		assertNull(c.getTagName());
 
-		c.parseCanonical(rw, body.toString().getBytes("UTF-8"));
+		c.parseCanonical(rw, body.toString().getBytes(CHARSET));
 		assertNotNull(c.getObject());
 		assertEquals(treeId, c.getObject().getId());
 		assertSame(rw.lookupTree(treeId), c.getObject());
@@ -201,7 +202,7 @@ public void testParseOldStyleNoTagger() throws Exception {
 		assertNull(c.getTaggerIdent());
 	}
 
-	private RevTag create(final String msg) throws Exception {
+	private RevTag create(String msg) throws Exception {
 		final StringBuilder b = new StringBuilder();
 		b.append("object 9788669ad918b6fcce64af8882fc9a81cb6aba67\n");
 		b.append("type tree\n");
@@ -212,7 +213,7 @@ private RevTag create(final String msg) throws Exception {
 
 		final RevTag c;
 		c = new RevTag(id("9473095c4cb2f12aefe1db8a355fe3fafba42f67"));
-		c.parseCanonical(new RevWalk(db), b.toString().getBytes("UTF-8"));
+		c.parseCanonical(new RevWalk(db), b.toString().getBytes(CHARSET));
 		return c;
 	}
 
@@ -220,17 +221,17 @@ private RevTag create(final String msg) throws Exception {
 	public void testParse_implicit_UTF8_encoded() throws Exception {
 		final ByteArrayOutputStream b = new ByteArrayOutputStream();
 		b.write("object 9788669ad918b6fcce64af8882fc9a81cb6aba67\n"
-				.getBytes("UTF-8"));
-		b.write("type tree\n".getBytes("UTF-8"));
-		b.write("tag v1.2.3.4.5\n".getBytes("UTF-8"));
+				.getBytes(CHARSET));
+		b.write("type tree\n".getBytes(CHARSET));
+		b.write("tag v1.2.3.4.5\n".getBytes(CHARSET));
 
 		b
 				.write("tagger F\u00f6r fattare <a_u_thor@example.com> 1218123387 +0700\n"
-						.getBytes("UTF-8"));
-		b.write("\n".getBytes("UTF-8"));
-		b.write("Sm\u00f6rg\u00e5sbord\n".getBytes("UTF-8"));
-		b.write("\n".getBytes("UTF-8"));
-		b.write("\u304d\u308c\u3044\n".getBytes("UTF-8"));
+						.getBytes(CHARSET));
+		b.write("\n".getBytes(CHARSET));
+		b.write("Sm\u00f6rg\u00e5sbord\n".getBytes(CHARSET));
+		b.write("\n".getBytes(CHARSET));
+		b.write("\u304d\u308c\u3044\n".getBytes(CHARSET));
 		final RevTag c;
 		c = new RevTag(id("9473095c4cb2f12aefe1db8a355fe3fafba42f67"));
 		c.parseCanonical(new RevWalk(db), b.toByteArray());
@@ -245,16 +246,15 @@ public void testParse_implicit_UTF8_encoded() throws Exception {
 	public void testParse_implicit_mixed_encoded() throws Exception {
 		final ByteArrayOutputStream b = new ByteArrayOutputStream();
 		b.write("object 9788669ad918b6fcce64af8882fc9a81cb6aba67\n"
-				.getBytes("UTF-8"));
-		b.write("type tree\n".getBytes("UTF-8"));
-		b.write("tag v1.2.3.4.5\n".getBytes("UTF-8"));
-		b
-				.write("tagger F\u00f6r fattare <a_u_thor@example.com> 1218123387 +0700\n"
-						.getBytes("ISO-8859-1"));
-		b.write("\n".getBytes("UTF-8"));
-		b.write("Sm\u00f6rg\u00e5sbord\n".getBytes("UTF-8"));
-		b.write("\n".getBytes("UTF-8"));
-		b.write("\u304d\u308c\u3044\n".getBytes("UTF-8"));
+				.getBytes(CHARSET));
+		b.write("type tree\n".getBytes(CHARSET));
+		b.write("tag v1.2.3.4.5\n".getBytes(CHARSET));
+		b.write("tagger F\u00f6r fattare <a_u_thor@example.com> 1218123387 +0700\n"
+				.getBytes(ISO_8859_1));
+		b.write("\n".getBytes(CHARSET));
+		b.write("Sm\u00f6rg\u00e5sbord\n".getBytes(CHARSET));
+		b.write("\n".getBytes(CHARSET));
+		b.write("\u304d\u308c\u3044\n".getBytes(CHARSET));
 		final RevTag c;
 		c = new RevTag(id("9473095c4cb2f12aefe1db8a355fe3fafba42f67"));
 		c.parseCanonical(new RevWalk(db), b.toByteArray());
@@ -307,17 +307,17 @@ public void testParse_explicit_encoded() throws Exception {
 	public void testParse_explicit_bad_encoded() throws Exception {
 		final ByteArrayOutputStream b = new ByteArrayOutputStream();
 		b.write("object 9788669ad918b6fcce64af8882fc9a81cb6aba67\n"
-				.getBytes("UTF-8"));
-		b.write("type tree\n".getBytes("UTF-8"));
-		b.write("tag v1.2.3.4.5\n".getBytes("UTF-8"));
+				.getBytes(CHARSET));
+		b.write("type tree\n".getBytes(CHARSET));
+		b.write("tag v1.2.3.4.5\n".getBytes(CHARSET));
 		b
 				.write("tagger F\u00f6r fattare <a_u_thor@example.com> 1218123387 +0700\n"
-						.getBytes("ISO-8859-1"));
-		b.write("encoding EUC-JP\n".getBytes("UTF-8"));
-		b.write("\n".getBytes("UTF-8"));
-		b.write("\u304d\u308c\u3044\n".getBytes("UTF-8"));
-		b.write("\n".getBytes("UTF-8"));
-		b.write("Hi\n".getBytes("UTF-8"));
+						.getBytes(ISO_8859_1));
+		b.write("encoding EUC-JP\n".getBytes(CHARSET));
+		b.write("\n".getBytes(CHARSET));
+		b.write("\u304d\u308c\u3044\n".getBytes(CHARSET));
+		b.write("\n".getBytes(CHARSET));
+		b.write("Hi\n".getBytes(CHARSET));
 		final RevTag c;
 		c = new RevTag(id("9473095c4cb2f12aefe1db8a355fe3fafba42f67"));
 		c.parseCanonical(new RevWalk(db), b.toByteArray());
@@ -342,17 +342,17 @@ public void testParse_explicit_bad_encoded() throws Exception {
 	public void testParse_explicit_bad_encoded2() throws Exception {
 		final ByteArrayOutputStream b = new ByteArrayOutputStream();
 		b.write("object 9788669ad918b6fcce64af8882fc9a81cb6aba67\n"
-				.getBytes("UTF-8"));
-		b.write("type tree\n".getBytes("UTF-8"));
-		b.write("tag v1.2.3.4.5\n".getBytes("UTF-8"));
+				.getBytes(CHARSET));
+		b.write("type tree\n".getBytes(CHARSET));
+		b.write("tag v1.2.3.4.5\n".getBytes(CHARSET));
 		b
 				.write("tagger F\u00f6r fattare <a_u_thor@example.com> 1218123387 +0700\n"
-						.getBytes("UTF-8"));
-		b.write("encoding ISO-8859-1\n".getBytes("UTF-8"));
-		b.write("\n".getBytes("UTF-8"));
-		b.write("\u304d\u308c\u3044\n".getBytes("UTF-8"));
-		b.write("\n".getBytes("UTF-8"));
-		b.write("Hi\n".getBytes("UTF-8"));
+						.getBytes(CHARSET));
+		b.write("encoding ISO-8859-1\n".getBytes(CHARSET));
+		b.write("\n".getBytes(CHARSET));
+		b.write("\u304d\u308c\u3044\n".getBytes(CHARSET));
+		b.write("\n".getBytes(CHARSET));
+		b.write("Hi\n".getBytes(CHARSET));
 		final RevTag c;
 		c = new RevTag(id("9473095c4cb2f12aefe1db8a355fe3fafba42f67"));
 		c.parseCanonical(new RevWalk(db), b.toByteArray());
@@ -365,13 +365,13 @@ public void testParse_explicit_bad_encoded2() throws Exception {
 	@Test
 	public void testParse_illegalEncoding() throws Exception {
 		ByteArrayOutputStream b = new ByteArrayOutputStream();
-		b.write("object 9788669ad918b6fcce64af8882fc9a81cb6aba67\n".getBytes(UTF_8));
-		b.write("type tree\n".getBytes(UTF_8));
-		b.write("tag v1.0\n".getBytes(UTF_8));
-		b.write("tagger t <t@example.com> 1218123387 +0700\n".getBytes(UTF_8));
-		b.write("encoding utf-8logoutputencoding=gbk\n".getBytes(UTF_8));
-		b.write("\n".getBytes(UTF_8));
-		b.write("message\n".getBytes(UTF_8));
+		b.write("object 9788669ad918b6fcce64af8882fc9a81cb6aba67\n".getBytes(CHARSET));
+		b.write("type tree\n".getBytes(CHARSET));
+		b.write("tag v1.0\n".getBytes(CHARSET));
+		b.write("tagger t <t@example.com> 1218123387 +0700\n".getBytes(CHARSET));
+		b.write("encoding utf-8logoutputencoding=gbk\n".getBytes(CHARSET));
+		b.write("\n".getBytes(CHARSET));
+		b.write("message\n".getBytes(CHARSET));
 
 		RevTag t = new RevTag(id("9473095c4cb2f12aefe1db8a355fe3fafba42f67"));
 		t.parseCanonical(new RevWalk(db), b.toByteArray());
@@ -384,13 +384,13 @@ public void testParse_illegalEncoding() throws Exception {
 	@Test
 	public void testParse_unsupportedEncoding() throws Exception {
 		ByteArrayOutputStream b = new ByteArrayOutputStream();
-		b.write("object 9788669ad918b6fcce64af8882fc9a81cb6aba67\n".getBytes(UTF_8));
-		b.write("type tree\n".getBytes(UTF_8));
-		b.write("tag v1.0\n".getBytes(UTF_8));
-		b.write("tagger t <t@example.com> 1218123387 +0700\n".getBytes(UTF_8));
-		b.write("encoding it_IT.UTF8\n".getBytes(UTF_8));
-		b.write("\n".getBytes(UTF_8));
-		b.write("message\n".getBytes(UTF_8));
+		b.write("object 9788669ad918b6fcce64af8882fc9a81cb6aba67\n".getBytes(CHARSET));
+		b.write("type tree\n".getBytes(CHARSET));
+		b.write("tag v1.0\n".getBytes(CHARSET));
+		b.write("tagger t <t@example.com> 1218123387 +0700\n".getBytes(CHARSET));
+		b.write("encoding it_IT.UTF8\n".getBytes(CHARSET));
+		b.write("\n".getBytes(CHARSET));
+		b.write("message\n".getBytes(CHARSET));
 
 		RevTag t = new RevTag(id("9473095c4cb2f12aefe1db8a355fe3fafba42f67"));
 		t.parseCanonical(new RevWalk(db), b.toByteArray());
@@ -480,7 +480,7 @@ public void testParse_PublicParseMethod() throws CorruptObjectException {
 		assertEquals(src.getMessage(), p.getFullMessage());
 	}
 
-	private static ObjectId id(final String str) {
+	private static ObjectId id(String str) {
 		return ObjectId.fromString(str);
 	}
 }
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkFollowFilterTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkFollowFilterTest.java
index 1860185..7005027 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkFollowFilterTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkFollowFilterTest.java
@@ -75,7 +75,7 @@ public void setUp() throws Exception {
 		diffCollector = new DiffCollector();
 	}
 
-	protected FollowFilter follow(final String followPath) {
+	protected FollowFilter follow(String followPath) {
 		FollowFilter followFilter =
 			FollowFilter.create(followPath, new Config().get(DiffConfig.KEY));
 		followFilter.setRenameCallback(diffCollector);
@@ -145,8 +145,9 @@ public void testMultiRename() throws Exception {
 
 	/**
 	 * Assert which renames should have happened, in traversal order.
+	 *
 	 * @param expectedRenames
-	 *            the rename specs, each one in the form "srcPath->destPath"
+	 *            the rename specs, each one in the form "srcPath-&gt;destPath"
 	 */
 	protected void assertRenames(String... expectedRenames) {
 		Assert.assertEquals("Unexpected number of renames. Expected: " +
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkPathFilter1Test.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkPathFilter1Test.java
index 6ec529c..b55a45a 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkPathFilter1Test.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkPathFilter1Test.java
@@ -54,7 +54,7 @@
 import org.junit.Test;
 
 public class RevWalkPathFilter1Test extends RevWalkTestCase {
-	protected void filter(final String path) {
+	protected void filter(String path) {
 		rw.setTreeFilter(AndTreeFilter.create(PathFilterGroup
 				.createFromStrings(Collections.singleton(path)),
 				TreeFilter.ANY_DIFF));
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkPathFilter6012Test.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkPathFilter6012Test.java
index 631e395..cef5521 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkPathFilter6012Test.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkPathFilter6012Test.java
@@ -102,17 +102,17 @@ public void setUp() throws Exception {
 		}
 	}
 
-	protected void check(final RevCommit... order) throws Exception {
+	protected void check(RevCommit... order) throws Exception {
 		markStart(i);
 		final StringBuilder act = new StringBuilder();
-		for (final RevCommit z : rw) {
+		for (RevCommit z : rw) {
 			final String name = byName.get(z);
 			assertNotNull(name);
 			act.append(name);
 			act.append(' ');
 		}
 		final StringBuilder exp = new StringBuilder();
-		for (final RevCommit z : order) {
+		for (RevCommit z : order) {
 			final String name = byName.get(z);
 			assertNotNull(name);
 			exp.append(name);
@@ -121,7 +121,7 @@ protected void check(final RevCommit... order) throws Exception {
 		assertEquals(exp.toString(), act.toString());
 	}
 
-	protected void filter(final String path) {
+	protected void filter(String path) {
 		rw.setTreeFilter(AndTreeFilter.create(PathFilterGroup
 				.createFromStrings(Collections.singleton(path)),
 				TreeFilter.ANY_DIFF));
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkTestCase.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkTestCase.java
index f12cc08..5443982 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkTestCase.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkTestCase.java
@@ -74,38 +74,38 @@ protected Date getDate() {
 		return util.getDate();
 	}
 
-	protected void tick(final int secDelta) {
+	protected void tick(int secDelta) {
 		util.tick(secDelta);
 	}
 
-	protected RevBlob blob(final String content) throws Exception {
+	protected RevBlob blob(String content) throws Exception {
 		return util.blob(content);
 	}
 
-	protected DirCacheEntry file(final String path, final RevBlob blob)
+	protected DirCacheEntry file(String path, RevBlob blob)
 			throws Exception {
 		return util.file(path, blob);
 	}
 
-	protected RevTree tree(final DirCacheEntry... entries) throws Exception {
+	protected RevTree tree(DirCacheEntry... entries) throws Exception {
 		return util.tree(entries);
 	}
 
-	protected RevObject get(final RevTree tree, final String path)
+	protected RevObject get(RevTree tree, String path)
 			throws Exception {
 		return util.get(tree, path);
 	}
 
-	protected RevCommit commit(final RevCommit... parents) throws Exception {
+	protected RevCommit commit(RevCommit... parents) throws Exception {
 		return util.commit(parents);
 	}
 
-	protected RevCommit commit(final RevTree tree, final RevCommit... parents)
+	protected RevCommit commit(RevTree tree, RevCommit... parents)
 			throws Exception {
 		return util.commit(tree, parents);
 	}
 
-	protected RevCommit commit(final int secDelta, final RevCommit... parents)
+	protected RevCommit commit(int secDelta, RevCommit... parents)
 			throws Exception {
 		return util.commit(secDelta, parents);
 	}
@@ -115,7 +115,7 @@ protected RevCommit commit(final int secDelta, final RevTree tree,
 		return util.commit(secDelta, tree, parents);
 	}
 
-	protected RevTag tag(final String name, final RevObject dst)
+	protected RevTag tag(String name, RevObject dst)
 			throws Exception {
 		return util.tag(name, dst);
 	}
@@ -125,19 +125,19 @@ protected CommitBuilder commitBuilder()
 		return util.commit();
 	}
 
-	protected <T extends RevObject> T parseBody(final T t) throws Exception {
+	protected <T extends RevObject> T parseBody(T t) throws Exception {
 		return util.parseBody(t);
 	}
 
-	protected void markStart(final RevCommit commit) throws Exception {
+	protected void markStart(RevCommit commit) throws Exception {
 		rw.markStart(commit);
 	}
 
-	protected void markUninteresting(final RevCommit commit) throws Exception {
+	protected void markUninteresting(RevCommit commit) throws Exception {
 		rw.markUninteresting(commit);
 	}
 
-	protected void assertCommit(final RevCommit exp, final RevCommit act) {
+	protected void assertCommit(RevCommit exp, RevCommit act) {
 		assertSame(exp, act);
 	}
 }
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkUtilsReachableTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkUtilsReachableTest.java
index 10bea0a..a26ae10 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkUtilsReachableTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkUtilsReachableTest.java
@@ -109,7 +109,7 @@ public void withCommitLoadedByDifferentRevWalk() throws Exception {
 		}
 	}
 
-	private Ref branch(final String name, final RevCommit dst) throws Exception {
+	private Ref branch(String name, RevCommit dst) throws Exception {
 		return Git.wrap(db).branchCreate().setName(name)
 				.setStartPoint(dst.name()).call();
 	}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/storage/file/FileBasedConfigTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/storage/file/FileBasedConfigTest.java
index ee845c5..0dea5ce 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/storage/file/FileBasedConfigTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/storage/file/FileBasedConfigTest.java
@@ -42,6 +42,8 @@
  */
 package org.eclipse.jgit.storage.file;
 
+import static org.eclipse.jgit.lib.Constants.CHARSET;
+import static org.eclipse.jgit.util.FileUtils.pathToString;
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
@@ -103,7 +105,7 @@ public void testSystemEncoding() throws IOException, ConfigInvalidException {
 
 	@Test
 	public void testUTF8withoutBOM() throws IOException, ConfigInvalidException {
-		final File file = createFile(CONTENT1.getBytes("UTF-8"));
+		final File file = createFile(CONTENT1.getBytes(CHARSET));
 		final FileBasedConfig config = new FileBasedConfig(file, FS.DETECTED);
 		config.load();
 		assertEquals(ALICE, config.getString(USER, null, NAME));
@@ -119,7 +121,7 @@ public void testUTF8withBOM() throws IOException, ConfigInvalidException {
 		bos1.write(0xEF);
 		bos1.write(0xBB);
 		bos1.write(0xBF);
-		bos1.write(CONTENT1.getBytes("UTF-8"));
+		bos1.write(CONTENT1.getBytes(CHARSET));
 
 		final File file = createFile(bos1.toByteArray());
 		final FileBasedConfig config = new FileBasedConfig(file, FS.DETECTED);
@@ -133,7 +135,7 @@ public void testUTF8withBOM() throws IOException, ConfigInvalidException {
 		bos2.write(0xEF);
 		bos2.write(0xBB);
 		bos2.write(0xBF);
-		bos2.write(CONTENT2.getBytes("UTF-8"));
+		bos2.write(CONTENT2.getBytes(CHARSET));
 		assertArrayEquals(bos2.toByteArray(), IO.readFully(file));
 	}
 
@@ -157,14 +159,91 @@ public void testLeadingWhitespaces() throws IOException, ConfigInvalidException
 		assertArrayEquals(bos2.toByteArray(), IO.readFully(file));
 	}
 
+	@Test
+	public void testIncludeAbsolute()
+			throws IOException, ConfigInvalidException {
+		final File includedFile = createFile(CONTENT1.getBytes());
+		final ByteArrayOutputStream bos = new ByteArrayOutputStream();
+		bos.write("[include]\npath=".getBytes());
+		bos.write(pathToString(includedFile).getBytes());
+
+		final File file = createFile(bos.toByteArray());
+		final FileBasedConfig config = new FileBasedConfig(file, FS.DETECTED);
+		config.load();
+		assertEquals(ALICE, config.getString(USER, null, NAME));
+	}
+
+	@Test
+	public void testIncludeRelativeDot()
+			throws IOException, ConfigInvalidException {
+		final File includedFile = createFile(CONTENT1.getBytes(), "dir1");
+		final ByteArrayOutputStream bos = new ByteArrayOutputStream();
+		bos.write("[include]\npath=".getBytes());
+		bos.write(("./" + includedFile.getName()).getBytes());
+
+		final File file = createFile(bos.toByteArray(), "dir1");
+		final FileBasedConfig config = new FileBasedConfig(file, FS.DETECTED);
+		config.load();
+		assertEquals(ALICE, config.getString(USER, null, NAME));
+	}
+
+	@Test
+	public void testIncludeRelativeDotDot()
+			throws IOException, ConfigInvalidException {
+		final File includedFile = createFile(CONTENT1.getBytes(), "dir1");
+		final ByteArrayOutputStream bos = new ByteArrayOutputStream();
+		bos.write("[include]\npath=".getBytes());
+		bos.write(("../" + includedFile.getParentFile().getName() + "/"
+				+ includedFile.getName()).getBytes());
+
+		final File file = createFile(bos.toByteArray(), "dir2");
+		final FileBasedConfig config = new FileBasedConfig(file, FS.DETECTED);
+		config.load();
+		assertEquals(ALICE, config.getString(USER, null, NAME));
+	}
+
+	@Test
+	public void testIncludeRelativeDotDotNotFound()
+			throws IOException, ConfigInvalidException {
+		final File includedFile = createFile(CONTENT1.getBytes());
+		final ByteArrayOutputStream bos = new ByteArrayOutputStream();
+		bos.write("[include]\npath=".getBytes());
+		bos.write(("../" + includedFile.getName()).getBytes());
+
+		final File file = createFile(bos.toByteArray());
+		final FileBasedConfig config = new FileBasedConfig(file, FS.DETECTED);
+		config.load();
+		assertEquals(null, config.getString(USER, null, NAME));
+	}
+
+	@Test
+	public void testIncludeWithTilde()
+			throws IOException, ConfigInvalidException {
+		final File includedFile = createFile(CONTENT1.getBytes(), "home");
+		final ByteArrayOutputStream bos = new ByteArrayOutputStream();
+		bos.write("[include]\npath=".getBytes());
+		bos.write(("~/" + includedFile.getName()).getBytes());
+
+		final File file = createFile(bos.toByteArray(), "repo");
+		final FS fs = FS.DETECTED.newInstance();
+		fs.setUserHome(includedFile.getParentFile());
+
+		final FileBasedConfig config = new FileBasedConfig(file, fs);
+		config.load();
+		assertEquals(ALICE, config.getString(USER, null, NAME));
+	}
+
 	private File createFile(byte[] content) throws IOException {
-		trash.mkdirs();
-		File f = File.createTempFile(getClass().getName(), null, trash);
-		FileOutputStream os = new FileOutputStream(f, true);
-		try {
+		return createFile(content, null);
+	}
+
+	private File createFile(byte[] content, String subdir) throws IOException {
+		File dir = subdir != null ? new File(trash, subdir) : trash;
+		dir.mkdirs();
+
+		File f = File.createTempFile(getClass().getName(), null, dir);
+		try (FileOutputStream os = new FileOutputStream(f, true)) {
 			os.write(content);
-		} finally {
-			os.close();
 		}
 		return f;
 	}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleAddTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleAddTest.java
index f42dd02..1a67e41 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleAddTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleAddTest.java
@@ -129,10 +129,11 @@ public void addSubmodule() throws Exception {
 			command.setPath(path);
 			String uri = db.getDirectory().toURI().toString();
 			command.setURI(uri);
-			Repository repo = command.call();
-			assertNotNull(repo);
-			ObjectId subCommit = repo.resolve(Constants.HEAD);
-			repo.close();
+			ObjectId subCommit;
+			try (Repository repo = command.call()) {
+				assertNotNull(repo);
+				subCommit = repo.resolve(Constants.HEAD);
+			}
 
 			SubmoduleWalk generator = SubmoduleWalk.forIndex(db);
 			assertTrue(generator.next());
@@ -141,10 +142,10 @@ public void addSubmodule() throws Exception {
 			assertEquals(uri, generator.getModulesUrl());
 			assertEquals(path, generator.getModulesPath());
 			assertEquals(uri, generator.getConfigUrl());
-			Repository subModRepo = generator.getRepository();
-			assertNotNull(subModRepo);
-			assertEquals(subCommit, commit);
-			subModRepo.close();
+			try (Repository subModRepo = generator.getRepository()) {
+				assertNotNull(subModRepo);
+				assertEquals(subCommit, commit);
+			}
 
 			Status status = Git.wrap(db).status().call();
 			assertTrue(status.getAdded().contains(Constants.DOT_GIT_MODULES));
@@ -209,16 +210,14 @@ public void addSubmoduleWithRelativeUri() throws Exception {
 				fullUri = fullUri.replace('\\', '/');
 			}
 			assertEquals(fullUri, generator.getConfigUrl());
-			Repository subModRepo = generator.getRepository();
-			assertNotNull(subModRepo);
-			assertEquals(
-					fullUri,
-					subModRepo
-							.getConfig()
-							.getString(ConfigConstants.CONFIG_REMOTE_SECTION,
-									Constants.DEFAULT_REMOTE_NAME,
-									ConfigConstants.CONFIG_KEY_URL));
-			subModRepo.close();
+			try (Repository subModRepo = generator.getRepository()) {
+				assertNotNull(subModRepo);
+				assertEquals(fullUri,
+						subModRepo.getConfig().getString(
+								ConfigConstants.CONFIG_REMOTE_SECTION,
+								Constants.DEFAULT_REMOTE_NAME,
+								ConfigConstants.CONFIG_KEY_URL));
+			}
 			assertEquals(commit, repo.resolve(Constants.HEAD));
 
 			Status status = Git.wrap(db).status().call();
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleDeinitTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleDeinitTest.java
new file mode 100644
index 0000000..df4b963
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleDeinitTest.java
@@ -0,0 +1,251 @@
+/*
+ * Copyright (C) 2017, Two Sigma Open Source
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ *   copyright notice, this list of conditions and the following
+ *   disclaimer in the documentation and/or other materials provided
+ *   with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ *   names of its contributors may be used to endorse or promote
+ *   products derived from this software without specific prior
+ *   written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.eclipse.jgit.submodule;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Collection;
+
+import org.eclipse.jgit.api.Git;
+import org.eclipse.jgit.api.SubmoduleDeinitCommand;
+import org.eclipse.jgit.api.SubmoduleDeinitResult;
+import org.eclipse.jgit.api.SubmoduleUpdateCommand;
+import org.eclipse.jgit.api.errors.GitAPIException;
+import org.eclipse.jgit.dircache.DirCache;
+import org.eclipse.jgit.dircache.DirCacheEditor;
+import org.eclipse.jgit.dircache.DirCacheEditor.PathEdit;
+import org.eclipse.jgit.dircache.DirCacheEntry;
+import org.eclipse.jgit.junit.JGitTestUtil;
+import org.eclipse.jgit.junit.RepositoryTestCase;
+import org.eclipse.jgit.lib.ConfigConstants;
+import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.FileMode;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.lib.StoredConfig;
+import org.eclipse.jgit.revwalk.RevCommit;
+import org.eclipse.jgit.storage.file.FileBasedConfig;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Unit tests of {@link SubmoduleDeinitCommand}
+ */
+public class SubmoduleDeinitTest extends RepositoryTestCase {
+
+	@Test
+	public void repositoryWithNoSubmodules() throws GitAPIException {
+		SubmoduleDeinitCommand command = new SubmoduleDeinitCommand(db);
+		Collection<SubmoduleDeinitResult> modules = command.call();
+		assertNotNull(modules);
+		assertTrue(modules.isEmpty());
+	}
+
+	@Test
+	public void alreadyClosedSubmodule() throws Exception {
+		final String path = "sub";
+		Git git = Git.wrap(db);
+
+		commitSubmoduleCreation(path, git);
+
+		SubmoduleDeinitResult result = runDeinit(new SubmoduleDeinitCommand(db).addPath("sub"));
+		assertEquals(path, result.getPath());
+		assertEquals(SubmoduleDeinitCommand.SubmoduleDeinitStatus.ALREADY_DEINITIALIZED, result.getStatus());
+	}
+
+	@Test
+	public void dirtySubmoduleBecauseUntracked() throws Exception {
+		final String path = "sub";
+		Git git = Git.wrap(db);
+
+		commitSubmoduleCreation(path, git);
+
+		Collection<String> updated = new SubmoduleUpdateCommand(db).addPath(path).setFetch(false).call();
+		assertEquals(1, updated.size());
+
+		File submoduleDir = assertSubmoduleIsInitialized();
+		SubmoduleWalk generator;
+
+		write(new File(submoduleDir, "untracked"), "untracked");
+
+		SubmoduleDeinitResult result = runDeinit(new SubmoduleDeinitCommand(db).addPath("sub"));
+		assertEquals(path, result.getPath());
+		assertEquals(SubmoduleDeinitCommand.SubmoduleDeinitStatus.DIRTY, result.getStatus());
+
+		generator = SubmoduleWalk.forIndex(db);
+		assertTrue(generator.next());
+		assertTrue(submoduleDir.isDirectory());
+		assertNotEquals(0, submoduleDir.list().length);
+	}
+
+	@Test
+	public void dirtySubmoduleBecauseNewCommit() throws Exception {
+		final String path = "sub";
+		Git git = Git.wrap(db);
+
+		commitSubmoduleCreation(path, git);
+
+		Collection<String> updated = new SubmoduleUpdateCommand(db).addPath(path).setFetch(false).call();
+		assertEquals(1, updated.size());
+
+		File submoduleDir = assertSubmoduleIsInitialized();
+		SubmoduleWalk generator = SubmoduleWalk.forIndex(db);
+		generator.next();
+
+		//want to create a commit inside the repo...
+		Repository submoduleLocalRepo = generator.getRepository();
+		JGitTestUtil.writeTrashFile(submoduleLocalRepo, "file.txt", "new data");
+		Git.wrap(submoduleLocalRepo).commit().setAll(true).setMessage("local commit").call();
+
+		SubmoduleDeinitResult result = runDeinit(new SubmoduleDeinitCommand(db).addPath("sub"));
+		assertEquals(path, result.getPath());
+		assertEquals(SubmoduleDeinitCommand.SubmoduleDeinitStatus.DIRTY, result.getStatus());
+
+		generator = SubmoduleWalk.forIndex(db);
+		assertTrue(generator.next());
+		assertTrue(submoduleDir.isDirectory());
+		assertNotEquals(0, submoduleDir.list().length);
+	}
+
+	private File assertSubmoduleIsInitialized() throws IOException {
+		SubmoduleWalk generator = SubmoduleWalk.forIndex(db);
+		assertTrue(generator.next());
+		File submoduleDir = new File(db.getWorkTree(), generator.getPath());
+		assertTrue(submoduleDir.isDirectory());
+		assertNotEquals(0, submoduleDir.list().length);
+		return submoduleDir;
+	}
+
+	@Test
+	public void dirtySubmoduleWithForce() throws Exception {
+		final String path = "sub";
+		Git git = Git.wrap(db);
+
+		commitSubmoduleCreation(path, git);
+
+		Collection<String> updated = new SubmoduleUpdateCommand(db).addPath(path).setFetch(false).call();
+		assertEquals(1, updated.size());
+
+		File submoduleDir = assertSubmoduleIsInitialized();
+
+		write(new File(submoduleDir, "untracked"), "untracked");
+
+		SubmoduleDeinitCommand command = new SubmoduleDeinitCommand(db).addPath("sub").setForce(true);
+		SubmoduleDeinitResult result = runDeinit(command);
+		assertEquals(path, result.getPath());
+		assertEquals(SubmoduleDeinitCommand.SubmoduleDeinitStatus.FORCED, result.getStatus());
+
+		SubmoduleWalk generator = SubmoduleWalk.forIndex(db);
+		assertTrue(generator.next());
+		assertTrue(submoduleDir.isDirectory());
+		assertEquals(0, submoduleDir.list().length);
+	}
+
+	@Test
+	public void cleanSubmodule() throws Exception {
+		final String path = "sub";
+		Git git = Git.wrap(db);
+
+		commitSubmoduleCreation(path, git);
+
+		Collection<String> updated = new SubmoduleUpdateCommand(db).addPath(path).setFetch(false).call();
+		assertEquals(1, updated.size());
+
+		File submoduleDir = assertSubmoduleIsInitialized();
+
+		SubmoduleDeinitResult result = runDeinit(new SubmoduleDeinitCommand(db).addPath("sub"));
+		assertEquals(path, result.getPath());
+		assertEquals(SubmoduleDeinitCommand.SubmoduleDeinitStatus.SUCCESS, result.getStatus());
+
+		SubmoduleWalk generator = SubmoduleWalk.forIndex(db);
+		assertTrue(generator.next());
+		assertTrue(submoduleDir.isDirectory());
+		assertEquals(0, submoduleDir.list().length);
+	}
+
+	private SubmoduleDeinitResult runDeinit(SubmoduleDeinitCommand command) throws GitAPIException {
+		Collection<SubmoduleDeinitResult> deinitialized = command.call();
+		assertNotNull(deinitialized);
+		assertEquals(1, deinitialized.size());
+		return deinitialized.iterator().next();
+	}
+
+
+	private RevCommit commitSubmoduleCreation(String path, Git git) throws IOException, GitAPIException {
+		writeTrashFile("file.txt", "content");
+		git.add().addFilepattern("file.txt").call();
+		final RevCommit commit = git.commit().setMessage("create file").call();
+
+		DirCache cache = db.lockDirCache();
+		DirCacheEditor editor = cache.editor();
+		editor.add(new PathEdit(path) {
+
+			@Override
+			public void apply(DirCacheEntry ent) {
+				ent.setFileMode(FileMode.GITLINK);
+				ent.setObjectId(commit);
+			}
+		});
+		editor.commit();
+
+		StoredConfig config = db.getConfig();
+		config.setString(ConfigConstants.CONFIG_SUBMODULE_SECTION, path,
+				ConfigConstants.CONFIG_KEY_URL, db.getDirectory().toURI()
+						.toString());
+		config.save();
+
+		FileBasedConfig modulesConfig = new FileBasedConfig(new File(
+				db.getWorkTree(), Constants.DOT_GIT_MODULES), db.getFS());
+		modulesConfig.setString(ConfigConstants.CONFIG_SUBMODULE_SECTION, path,
+				ConfigConstants.CONFIG_KEY_PATH, path);
+		modulesConfig.save();
+
+		new File(db.getWorkTree(), "sub").mkdir();
+		git.add().addFilepattern(Constants.DOT_GIT_MODULES).call();
+		git.commit().setMessage("create submodule").call();
+		return commit;
+	}
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleSyncTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleSyncTest.java
index 13db44a..6f3b52f 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleSyncTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleSyncTest.java
@@ -135,12 +135,14 @@ public void apply(DirCacheEntry ent) {
 		generator = SubmoduleWalk.forIndex(db);
 		assertTrue(generator.next());
 		assertEquals(url, generator.getConfigUrl());
-		Repository subModRepository = generator.getRepository();
-		StoredConfig submoduleConfig = subModRepository.getConfig();
-		subModRepository.close();
-		assertEquals(url, submoduleConfig.getString(
-				ConfigConstants.CONFIG_REMOTE_SECTION,
-				Constants.DEFAULT_REMOTE_NAME, ConfigConstants.CONFIG_KEY_URL));
+		try (Repository subModRepository = generator.getRepository()) {
+			StoredConfig submoduleConfig = subModRepository.getConfig();
+			assertEquals(url,
+					submoduleConfig.getString(
+							ConfigConstants.CONFIG_REMOTE_SECTION,
+							Constants.DEFAULT_REMOTE_NAME,
+							ConfigConstants.CONFIG_KEY_URL));
+		}
 	}
 
 	@Test
@@ -208,11 +210,13 @@ public void apply(DirCacheEntry ent) {
 		generator = SubmoduleWalk.forIndex(db);
 		assertTrue(generator.next());
 		assertEquals("git://server/sub.git", generator.getConfigUrl());
-		Repository subModRepository1 = generator.getRepository();
-		StoredConfig submoduleConfig = subModRepository1.getConfig();
-		subModRepository1.close();
-		assertEquals("git://server/sub.git", submoduleConfig.getString(
-				ConfigConstants.CONFIG_REMOTE_SECTION,
-				Constants.DEFAULT_REMOTE_NAME, ConfigConstants.CONFIG_KEY_URL));
+		try (Repository subModRepository1 = generator.getRepository()) {
+			StoredConfig submoduleConfig = subModRepository1.getConfig();
+			assertEquals("git://server/sub.git",
+					submoduleConfig.getString(
+							ConfigConstants.CONFIG_REMOTE_SECTION,
+							Constants.DEFAULT_REMOTE_NAME,
+							ConfigConstants.CONFIG_KEY_URL));
+		}
 	}
 }
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleUpdateTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleUpdateTest.java
index 7064f60..bbce413 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleUpdateTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleUpdateTest.java
@@ -121,10 +121,10 @@ public void apply(DirCacheEntry ent) {
 
 		SubmoduleWalk generator = SubmoduleWalk.forIndex(db);
 		assertTrue(generator.next());
-		Repository subRepo = generator.getRepository();
-		assertNotNull(subRepo);
-		assertEquals(commit, subRepo.resolve(Constants.HEAD));
-		subRepo.close();
+		try (Repository subRepo = generator.getRepository()) {
+			assertNotNull(subRepo);
+			assertEquals(commit, subRepo.resolve(Constants.HEAD));
+		}
 	}
 
 	@Test
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/symlinks/SymlinksTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/symlinks/SymlinksTest.java
index 274fa53..7d54399 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/symlinks/SymlinksTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/symlinks/SymlinksTest.java
@@ -206,7 +206,7 @@ public void fileModeTestSymlinkThenFolder() throws Exception {
 	 * Steps: 1.Add file 'b' 2.Commit 3.Create branch '1' 4.Add symlink 'a'
 	 * 5.Commit 6.Checkout branch '1'
 	 *
-	 * The working tree should not contain 'a' -> FileMode.MISSING after the
+	 * The working tree should not contain 'a' -&gt; FileMode.MISSING after the
 	 * checkout.
 	 *
 	 * @throws Exception
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/test/resources/SampleDataRepositoryTestCase.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/test/resources/SampleDataRepositoryTestCase.java
index a57ef40..85a8aa7 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/test/resources/SampleDataRepositoryTestCase.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/test/resources/SampleDataRepositoryTestCase.java
@@ -79,8 +79,7 @@ public static void copyCGitTestPacks(FileRepository repo) throws IOException {
 				"pack-e6d07037cbcf13376308a0a995d1fa48f8f76aaa",
 				"pack-3280af9c07ee18a87705ef50b0cc4cd20266cf12"
 		};
-		final File packDir = new File(repo.getObjectDatabase().getDirectory(),
-				"pack");
+		final File packDir = repo.getObjectDatabase().getPackDirectory();
 		for (String n : packs) {
 			JGitTestUtil.copyTestResource(n + ".pack", new File(packDir, n + ".pack"));
 			JGitTestUtil.copyTestResource(n + ".idx", new File(packDir, n + ".idx"));
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/BundleWriterTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/BundleWriterTest.java
index 658b971..d30ac84 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/BundleWriterTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/BundleWriterTest.java
@@ -45,7 +45,7 @@
 
 package org.eclipse.jgit.transport;
 
-import static java.nio.charset.StandardCharsets.UTF_8;
+import static org.eclipse.jgit.lib.Constants.CHARSET;
 import static org.eclipse.jgit.lib.Constants.OBJ_BLOB;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
@@ -199,7 +199,7 @@ public void testCustomObjectReader() throws Exception {
 			Ref ref = repo.exactRef(refName);
 			assertNotNull(ref);
 			assertEquals(id, ref.getObjectId());
-			assertEquals(data, new String(repo.open(id, OBJ_BLOB).getBytes(), UTF_8));
+			assertEquals(data, new String(repo.open(id, OBJ_BLOB).getBytes(), CHARSET));
 		}
 	}
 
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/NetRCTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/NetRCTest.java
index 2fea8a9..4e5d56a 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/NetRCTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/NetRCTest.java
@@ -42,6 +42,7 @@
 
 package org.eclipse.jgit.transport;
 
+import static org.eclipse.jgit.lib.Constants.CHARSET;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNull;
 
@@ -73,11 +74,11 @@ public void setUp() throws Exception {
 		configFile = new File(home, ".netrc");
 	}
 
-	private void config(final String data) throws IOException {
-		final OutputStreamWriter fw = new OutputStreamWriter(
-				new FileOutputStream(configFile), "UTF-8");
-		fw.write(data);
-		fw.close();
+	private void config(String data) throws IOException {
+		try (OutputStreamWriter fw = new OutputStreamWriter(
+				new FileOutputStream(configFile), CHARSET)) {
+			fw.write(data);
+		}
 	}
 
 	@Test
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/OpenSshConfigTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/OpenSshConfigTest.java
index d604751..abf80ec 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/OpenSshConfigTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/OpenSshConfigTest.java
@@ -43,6 +43,7 @@
 
 package org.eclipse.jgit.transport;
 
+import static org.eclipse.jgit.lib.Constants.CHARSET;
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
@@ -89,11 +90,11 @@ public void setUp() throws Exception {
 		osc = new OpenSshConfig(home, configFile);
 	}
 
-	private void config(final String data) throws IOException {
+	private void config(String data) throws IOException {
 		long lastMtime = configFile.lastModified();
 		do {
 			try (final OutputStreamWriter fw = new OutputStreamWriter(
-					new FileOutputStream(configFile), "UTF-8")) {
+					new FileOutputStream(configFile), CHARSET)) {
 				fw.write(data);
 			}
 		} while (lastMtime == configFile.lastModified());
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PackParserTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PackParserTest.java
index b2497b8..b6d0611 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PackParserTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PackParserTest.java
@@ -47,7 +47,6 @@
 package org.eclipse.jgit.transport;
 
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
@@ -94,8 +93,7 @@ public class PackParserTest extends RepositoryTestCase {
 	@Test
 	public void test1() throws  IOException {
 		File packFile = JGitTestUtil.getTestResourceFile("pack-34be9032ac282b11fa9babdc2b2a93ca996c9c2f.pack");
-		final InputStream is = new FileInputStream(packFile);
-		try {
+		try (InputStream is = new FileInputStream(packFile)) {
 			ObjectDirectoryPackParser p = (ObjectDirectoryPackParser) index(is);
 			p.parse(NullProgressMonitor.INSTANCE);
 			PackFile file = p.getPackFile();
@@ -108,8 +106,6 @@ public void test1() throws  IOException {
 			assertTrue(file.hasObject(ObjectId.fromString("902d5476fa249b7abc9d84c611577a81381f0327")));
 			assertTrue(file.hasObject(ObjectId.fromString("aabf2ffaec9b497f0950352b3e582d73035c2035")));
 			assertTrue(file.hasObject(ObjectId.fromString("c59759f143fb1fe21c197981df75a7ee00290799")));
-		} finally {
-			is.close();
 		}
 	}
 
@@ -122,8 +118,7 @@ public void test1() throws  IOException {
 	@Test
 	public void test2() throws  IOException {
 		File packFile = JGitTestUtil.getTestResourceFile("pack-df2982f284bbabb6bdb59ee3fcc6eb0983e20371.pack");
-		final InputStream is = new FileInputStream(packFile);
-		try {
+		try (InputStream is = new FileInputStream(packFile)) {
 			ObjectDirectoryPackParser p = (ObjectDirectoryPackParser) index(is);
 			p.parse(NullProgressMonitor.INSTANCE);
 			PackFile file = p.getPackFile();
@@ -141,8 +136,6 @@ public void test2() throws  IOException {
 			assertTrue(file.hasObject(ObjectId.fromString("20a8ade77639491ea0bd667bf95de8abf3a434c8")));
 			assertTrue(file.hasObject(ObjectId.fromString("2675188fd86978d5bc4d7211698b2118ae3bf658")));
 			// and lots more...
-		} finally {
-			is.close();
 		}
 	}
 
@@ -270,7 +263,7 @@ public void testMaxObjectSizeDeltaBlock() throws Exception {
 			fail("PackParser should have failed");
 		} catch (TooLargeObjectInPackException e) {
 			assertTrue(e.getMessage().contains("13")); // max obj size
-			assertFalse(e.getMessage().contains("14")); // no delta size
+			assertTrue(e.getMessage().contains("14")); // delta size
 		}
 	}
 
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PacketLineInTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PacketLineInTest.java
index 13fc68d..8b1d860 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PacketLineInTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PacketLineInTest.java
@@ -116,17 +116,6 @@ public void testReadString_LenHELO() {
 	}
 
 	@Test
-	public void testReadString_Len0001() {
-		init("0001");
-		try {
-			in.readString();
-			fail("incorrectly accepted invalid packet header");
-		} catch (IOException e) {
-			assertEquals("Invalid packet line header: 0001", e.getMessage());
-		}
-	}
-
-	@Test
 	public void testReadString_Len0002() {
 		init("0002");
 		try {
@@ -164,6 +153,13 @@ public void testReadString_End() throws IOException {
 		assertEOF();
 	}
 
+	@Test
+	public void testReadString_Delim() throws IOException {
+		init("0001");
+		assertSame(PacketLineIn.DELIM, in.readString());
+		assertEOF();
+	}
+
 	// readStringNoLF
 
 	@Test
@@ -330,7 +326,7 @@ public void testReadACK_ERR() throws IOException {
 
 	// test support
 
-	private void init(final String msg) {
+	private void init(String msg) {
 		rawIn = new ByteArrayInputStream(Constants.encodeASCII(msg));
 		in = new PacketLineIn(rawIn);
 	}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PacketLineOutTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PacketLineOutTest.java
index eca5475..391a701 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PacketLineOutTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PacketLineOutTest.java
@@ -113,6 +113,12 @@ public void flush() throws IOException {
 		assertEquals(1, flushCnt[0]);
 	}
 
+	@Test
+	public void testWriteDelim() throws IOException {
+		out.writeDelim();
+		assertBuffer("0001");
+	}
+
 	// writePacket
 
 	@Test
@@ -167,7 +173,7 @@ public void flush() throws IOException {
 		assertEquals(1, flushCnt[0]);
 	}
 
-	private void assertBuffer(final String exp) throws IOException {
+	private void assertBuffer(String exp) throws IOException {
 		assertEquals(exp, new String(rawOut.toByteArray(),
 				Constants.CHARACTER_ENCODING));
 	}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PushConnectionTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PushConnectionTest.java
index 0e4e9cc..63478f6 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PushConnectionTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PushConnectionTest.java
@@ -51,12 +51,16 @@
 
 import java.io.IOException;
 import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.Collection;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 
 import org.eclipse.jgit.errors.TransportException;
 import org.eclipse.jgit.internal.storage.dfs.DfsRepositoryDescription;
 import org.eclipse.jgit.internal.storage.dfs.InMemoryRepository;
+import org.eclipse.jgit.junit.TestRepository;
 import org.eclipse.jgit.lib.Constants;
 import org.eclipse.jgit.lib.NullProgressMonitor;
 import org.eclipse.jgit.lib.ObjectId;
@@ -76,6 +80,7 @@ public class PushConnectionTest {
 	private Object ctx = new Object();
 	private InMemoryRepository server;
 	private InMemoryRepository client;
+	private List<String> processedRefs;
 	private ObjectId obj1;
 	private ObjectId obj2;
 	private ObjectId obj3;
@@ -85,6 +90,7 @@ public class PushConnectionTest {
 	public void setUp() throws Exception {
 		server = newRepo("server");
 		client = newRepo("client");
+		processedRefs = new ArrayList<>();
 		testProtocol = new TestProtocol<>(
 				null,
 				new ReceivePackFactory<Object>() {
@@ -92,7 +98,18 @@ public void setUp() throws Exception {
 					public ReceivePack create(Object req, Repository db)
 							throws ServiceNotEnabledException,
 							ServiceNotAuthorizedException {
-						return new ReceivePack(db);
+						ReceivePack rp = new ReceivePack(db);
+						rp.setPreReceiveHook(
+								new PreReceiveHook() {
+									@Override
+									public void onPreReceive(ReceivePack receivePack,
+											Collection<ReceiveCommand> cmds) {
+										for (ReceiveCommand cmd : cmds) {
+											processedRefs.add(cmd.getRefName());
+										}
+									}
+								});
+						return rp;
 					}
 				});
 		uri = testProtocol.register(ctx, server);
@@ -184,7 +201,7 @@ public void limitCommandBytes() throws IOException {
 			updates.put(rru.getRemoteName(), rru);
 		}
 
-		server.getConfig().setInt("receive", null, "maxCommandBytes", 190);
+		server.getConfig().setInt("receive", null, "maxCommandBytes", 195);
 		try (Transport tn = testProtocol.open(uri, client, "server");
 				PushConnection connection = tn.openPush()) {
 			try {
@@ -196,4 +213,45 @@ public void limitCommandBytes() throws IOException {
 			}
 		}
 	}
+
+	@Test
+	public void commandOrder() throws Exception {
+		TestRepository<?> tr = new TestRepository<>(client);
+		List<RemoteRefUpdate> updates = new ArrayList<>();
+		// Arbitrary non-sorted order.
+		for (int i = 9; i >= 0; i--) {
+			String name = "refs/heads/b" + i;
+			tr.branch(name).commit().create();
+			RemoteRefUpdate rru = new RemoteRefUpdate(client, name, name, false, null,
+					ObjectId.zeroId());
+			updates.add(rru);
+		}
+
+		PushResult result;
+		try (Transport tn = testProtocol.open(uri, client, "server")) {
+			result = tn.push(NullProgressMonitor.INSTANCE, updates);
+		}
+
+		for (RemoteRefUpdate remoteUpdate : result.getRemoteUpdates()) {
+			assertEquals(
+					"update should succeed on " + remoteUpdate.getRemoteName(),
+					RemoteRefUpdate.Status.OK, remoteUpdate.getStatus());
+		}
+
+		List<String> expected = remoteRefNames(updates);
+		assertEquals(
+				"ref names processed by ReceivePack should match input ref names in order",
+				expected, processedRefs);
+		assertEquals(
+				"remote ref names should match input ref names in order",
+				expected, remoteRefNames(result.getRemoteUpdates()));
+	}
+
+	private static List<String> remoteRefNames(Collection<RemoteRefUpdate> updates) {
+		List<String> result = new ArrayList<>();
+		for (RemoteRefUpdate u : updates) {
+			result.add(u.getRemoteName());
+		}
+		return result;
+	}
 }
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PushProcessTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PushProcessTest.java
index 104a69c..611cd0c 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PushProcessTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PushProcessTest.java
@@ -422,7 +422,7 @@ private class MockPushConnection extends BaseConnection implements
 			PushConnection {
 		MockPushConnection() {
 			final Map<String, Ref> refsMap = new HashMap<>();
-			for (final Ref r : advertisedRefs)
+			for (Ref r : advertisedRefs)
 				refsMap.put(r.getName(), r);
 			available(refsMap);
 		}
@@ -443,7 +443,7 @@ public void push(ProgressMonitor monitor,
 		public void push(ProgressMonitor monitor,
 				Map<String, RemoteRefUpdate> refsToUpdate)
 				throws TransportException {
-			for (final RemoteRefUpdate rru : refsToUpdate.values()) {
+			for (RemoteRefUpdate rru : refsToUpdate.values()) {
 				assertEquals(Status.NOT_ATTEMPTED, rru.getStatus());
 				rru.setStatus(connectionUpdateStatus);
 			}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ReceivePackAdvertiseRefsHookTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ReceivePackAdvertiseRefsHookTest.java
index 8ef87cb..b770422 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ReceivePackAdvertiseRefsHookTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ReceivePackAdvertiseRefsHookTest.java
@@ -136,7 +136,7 @@ public void testFilterHidesPrivate() throws Exception {
 		try (TransportLocal t = new TransportLocal(src, uriOf(dst),
 				dst.getDirectory()) {
 			@Override
-			ReceivePack createReceivePack(final Repository db) {
+			ReceivePack createReceivePack(Repository db) {
 				db.close();
 				dst.incrementOpen();
 
@@ -199,6 +199,23 @@ public void advertiseRefs(UploadPack uploadPack)
 		assertFalse(haves.get().contains(P));
 	}
 
+	private TransportLocal newTransportLocalWithStrictValidation()
+			throws Exception {
+		return new TransportLocal(src, uriOf(dst), dst.getDirectory()) {
+			@Override
+			ReceivePack createReceivePack(Repository db) {
+				db.close();
+				dst.incrementOpen();
+
+				final ReceivePack rp = super.createReceivePack(dst);
+				rp.setCheckReceivedObjects(true);
+				rp.setCheckReferencedObjectsAreReachable(true);
+				rp.setAdvertiseRefsHook(new HidePrivateHook());
+				return rp;
+			}
+		};
+	}
+
 	@Test
 	public void testSuccess() throws Exception {
 		// Manually force a delta of an object so we reuse it later.
@@ -230,19 +247,7 @@ public void testSuccess() throws Exception {
 
 		// Push this new content to the remote, doing strict validation.
 		//
-		TransportLocal t = new TransportLocal(src, uriOf(dst), dst.getDirectory()) {
-			@Override
-			ReceivePack createReceivePack(final Repository db) {
-				db.close();
-				dst.incrementOpen();
-
-				final ReceivePack rp = super.createReceivePack(dst);
-				rp.setCheckReceivedObjects(true);
-				rp.setCheckReferencedObjectsAreReachable(true);
-				rp.setAdvertiseRefsHook(new HidePrivateHook());
-				return rp;
-			}
-		};
+		PushResult r;
 		RemoteRefUpdate u = new RemoteRefUpdate( //
 				src, //
 				R_MASTER, // src name
@@ -251,12 +256,9 @@ ReceivePack createReceivePack(final Repository db) {
 				null, // local tracking branch
 				null // expected id
 		);
-		PushResult r;
-		try {
+		try (TransportLocal t = newTransportLocalWithStrictValidation()) {
 			t.setPushThin(true);
 			r = t.push(PM, Collections.singleton(u));
-		} finally {
-			t.close();
 		}
 
 		assertNotNull("have result", r);
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/RemoteConfigTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/RemoteConfigTest.java
index a0cf0d2..9aabd71 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/RemoteConfigTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/RemoteConfigTest.java
@@ -67,12 +67,12 @@ public void setUp() throws Exception {
 		config = new Config();
 	}
 
-	private void readConfig(final String dat) throws ConfigInvalidException {
+	private void readConfig(String dat) throws ConfigInvalidException {
 		config = new Config();
 		config.fromText(dat);
 	}
 
-	private void checkConfig(final String exp) {
+	private void checkConfig(String exp) {
 		assertEquals(exp, config.toText());
 	}
 
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/SideBandOutputStreamTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/SideBandOutputStreamTest.java
index 4571619..4d3e162 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/SideBandOutputStreamTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/SideBandOutputStreamTest.java
@@ -259,7 +259,7 @@ public void testConstructor_RejectsBadBufferSize() throws Exception {
 		}
 	}
 
-	private void assertBuffer(final String exp) throws IOException {
+	private void assertBuffer(String exp) throws IOException {
 		assertEquals(exp, new String(rawOut.toByteArray(),
 				Constants.CHARACTER_ENCODING));
 	}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/TestProtocolTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/TestProtocolTest.java
index b926e48..86c92bb 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/TestProtocolTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/TestProtocolTest.java
@@ -60,6 +60,9 @@
 import org.eclipse.jgit.junit.TestRepository;
 import org.eclipse.jgit.lib.ObjectId;
 import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.revwalk.RevCommit;
+import org.eclipse.jgit.storage.pack.PackStatistics;
+import org.eclipse.jgit.transport.BasePackFetchConnection.FetchConfig;
 import org.eclipse.jgit.transport.resolver.ReceivePackFactory;
 import org.eclipse.jgit.transport.resolver.ServiceNotAuthorizedException;
 import org.eclipse.jgit.transport.resolver.UploadPackFactory;
@@ -70,6 +73,11 @@
 public class TestProtocolTest {
 	private static final RefSpec HEADS = new RefSpec("+refs/heads/*:refs/heads/*");
 
+	private static final RefSpec MASTER = new RefSpec(
+			"+refs/heads/master:refs/heads/master");
+
+	private static final int HAVES_PER_ROUND = 32;
+
 	private static class User {
 		private final String name;
 
@@ -81,7 +89,14 @@ private User(String name) {
 	private static class DefaultUpload implements UploadPackFactory<User> {
 		@Override
 		public UploadPack create(User req, Repository db) {
-			return new UploadPack(db);
+			UploadPack up = new UploadPack(db);
+			up.setPostUploadHook(new PostUploadHook() {
+				@Override
+				public void onPostUpload(PackStatistics stats) {
+					havesCount = stats.getHaves();
+				}
+			});
+			return up;
 		}
 	}
 
@@ -92,6 +107,8 @@ public ReceivePack create(User req, Repository db) {
 		}
 	}
 
+	private static long havesCount;
+
 	private List<TransportProtocol> protos;
 	private TestRepository<InMemoryRepository> local;
 	private TestRepository<InMemoryRepository> remote;
@@ -147,6 +164,68 @@ public void testPush() throws Exception {
 	}
 
 	@Test
+	public void testFullNegotiation() throws Exception {
+		TestProtocol<User> proto = registerDefault();
+		URIish uri = proto.register(new User("user"), remote.getRepository());
+
+		// Enough local branches to cause 10 rounds of negotiation,
+		// and a unique remote master branch commit with a later timestamp.
+		for (int i = 0; i < 10 * HAVES_PER_ROUND; i++) {
+			local.branch("local-branch-" + i).commit().create();
+		}
+		remote.tick(11 * HAVES_PER_ROUND);
+		RevCommit master = remote.branch("master").commit()
+				.add("readme.txt", "unique commit").create();
+
+		try (Git git = new Git(local.getRepository())) {
+			assertNull(local.getRepository().exactRef("refs/heads/master"));
+			git.fetch().setRemote(uri.toString()).setRefSpecs(MASTER).call();
+			assertEquals(master, local.getRepository()
+					.exactRef("refs/heads/master").getObjectId());
+			assertEquals(10 * HAVES_PER_ROUND, havesCount);
+		}
+	}
+
+	@Test
+	public void testMinimalNegotiation() throws Exception {
+		TestProtocol<User> proto = registerDefault();
+		URIish uri = proto.register(new User("user"), remote.getRepository());
+
+		// Enough local branches to cause 10 rounds of negotiation,
+		// and a unique remote master branch commit with a later timestamp.
+		for (int i = 0; i < 10 * HAVES_PER_ROUND; i++) {
+			local.branch("local-branch-" + i).commit().create();
+		}
+		remote.tick(11 * HAVES_PER_ROUND);
+		RevCommit master = remote.branch("master").commit()
+				.add("readme.txt", "unique commit").create();
+
+		TestProtocol.setFetchConfig(new FetchConfig(true, true));
+		try (Git git = new Git(local.getRepository())) {
+			assertNull(local.getRepository().exactRef("refs/heads/master"));
+			git.fetch().setRemote(uri.toString()).setRefSpecs(MASTER).call();
+			assertEquals(master, local.getRepository()
+					.exactRef("refs/heads/master").getObjectId());
+			assertTrue(havesCount <= 2 * HAVES_PER_ROUND);
+
+			// Update the remote master and add local branches for 5 more rounds
+			// of negotiation, where the local branch commits have newer
+			// timestamps. Negotiation should send 5 rounds for those newer
+			// branches before getting to the round that sends its stale version
+			// of master.
+			master = remote.branch("master").commit().parent(master).create();
+			local.tick(2 * HAVES_PER_ROUND);
+			for (int i = 0; i < 5 * HAVES_PER_ROUND; i++) {
+				local.branch("local-" + i).commit().create();
+			}
+			git.fetch().setRemote(uri.toString()).setRefSpecs(MASTER).call();
+			assertEquals(master, local.getRepository()
+					.exactRef("refs/heads/master").getObjectId());
+			assertEquals(6 * HAVES_PER_ROUND, havesCount);
+		}
+	}
+
+	@Test
 	public void testUploadPackFactory() throws Exception {
 		ObjectId master = remote.branch("master").commit().create();
 
@@ -171,7 +250,7 @@ public UploadPack create(User req, Repository db)
 			try {
 				git.fetch()
 						.setRemote(user1Uri.toString())
-						.setRefSpecs(HEADS)
+						.setRefSpecs(MASTER)
 						.call();
 			} catch (InvalidRemoteException expected) {
 				// Expected.
@@ -181,7 +260,7 @@ public UploadPack create(User req, Repository db)
 
 			git.fetch()
 					.setRemote(user2Uri.toString())
-					.setRefSpecs(HEADS)
+					.setRefSpecs(MASTER)
 					.call();
 			assertEquals(1, rejected.get());
 			assertEquals(master,
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/TransportTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/TransportTest.java
index d4c47d3..c239922 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/TransportTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/TransportTest.java
@@ -142,7 +142,7 @@ public void testFindRemoteRefUpdatesWildcardNoTracking() throws IOException {
 		assertEquals(12, result.size());
 		boolean foundA = false;
 		boolean foundB = false;
-		for (final RemoteRefUpdate rru : result) {
+		for (RemoteRefUpdate rru : result) {
 			if ("refs/heads/a".equals(rru.getSrcRef())
 					&& "refs/heads/test/a".equals(rru.getRemoteName()))
 				foundA = true;
@@ -174,7 +174,7 @@ public void testFindRemoteRefUpdatesTwoRefSpecs() throws IOException {
 		assertEquals(2, result.size());
 		boolean foundA = false;
 		boolean foundC = false;
-		for (final RemoteRefUpdate rru : result) {
+		for (RemoteRefUpdate rru : result) {
 			if ("refs/heads/a".equals(rru.getSrcRef())
 					&& "refs/heads/b".equals(rru.getRemoteName()))
 				foundA = true;
@@ -233,7 +233,7 @@ public void testFindRemoteRefUpdatesWithLeases() throws IOException {
 		assertEquals(2, result.size());
 		boolean foundA = false;
 		boolean foundC = false;
-		for (final RemoteRefUpdate rru : result) {
+		for (RemoteRefUpdate rru : result) {
 			if ("refs/heads/a".equals(rru.getSrcRef())
 					&& "refs/heads/b".equals(rru.getRemoteName())) {
 				foundA = true;
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/URIishTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/URIishTest.java
index e55d373..39cd719 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/URIishTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/URIishTest.java
@@ -198,6 +198,10 @@ public void testFileProtoWindows() throws Exception {
 		URIish u = new URIish(str);
 		assertEquals("file", u.getScheme());
 		assertFalse(u.isRemote());
+		assertEquals(null, u.getHost());
+		assertEquals(-1, u.getPort());
+		assertEquals(null, u.getUser());
+		assertEquals(null, u.getPass());
 		assertEquals("D:/m y", u.getRawPath());
 		assertEquals("D:/m y", u.getPath());
 		assertEquals("file:///D:/m y", u.toString());
@@ -206,6 +210,84 @@ public void testFileProtoWindows() throws Exception {
 	}
 
 	@Test
+	public void testFileProtoWindowsWithHost() throws Exception {
+		final String str = "file://localhost/D:/m y";
+		URIish u = new URIish(str);
+		assertEquals("file", u.getScheme());
+		assertTrue(u.isRemote());
+		assertEquals("localhost", u.getHost());
+		assertEquals(-1, u.getPort());
+		assertEquals(null, u.getUser());
+		assertEquals(null, u.getPass());
+		assertEquals("D:/m y", u.getRawPath());
+		assertEquals("D:/m y", u.getPath());
+		assertEquals("file://localhost/D:/m y", u.toString());
+		assertEquals("file://localhost/D:/m%20y", u.toASCIIString());
+		assertEquals(u, new URIish(str));
+	}
+
+	@Test
+	public void testFileProtoWindowsWithHostAndPort() throws Exception {
+		final String str = "file://localhost:80/D:/m y";
+		URIish u = new URIish(str);
+		assertEquals("file", u.getScheme());
+		assertTrue(u.isRemote());
+		assertEquals("localhost", u.getHost());
+		assertEquals(80, u.getPort());
+		assertEquals(null, u.getUser());
+		assertEquals(null, u.getPass());
+		assertEquals("D:/m y", u.getRawPath());
+		assertEquals("D:/m y", u.getPath());
+		assertEquals("file://localhost:80/D:/m y", u.toString());
+		assertEquals("file://localhost:80/D:/m%20y", u.toASCIIString());
+		assertEquals(u, new URIish(str));
+	}
+
+	@Test
+	public void testFileProtoWindowsWithHostAndEmptyPortIsAmbiguous()
+			throws Exception {
+		final String str = "file://localhost:/D:/m y";
+		URIish u = new URIish(str);
+		assertEquals("file", u.getScheme());
+		assertFalse(u.isRemote());
+		assertEquals(null, u.getHost());
+		assertEquals(-1, u.getPort());
+		assertEquals(null, u.getUser());
+		assertEquals(null, u.getPass());
+		assertEquals("localhost:/D:/m y", u.getRawPath());
+		assertEquals("localhost:/D:/m y", u.getPath());
+		assertEquals("file:///localhost:/D:/m y", u.toString());
+		assertEquals("file:///localhost:/D:/m%20y", u.toASCIIString());
+		assertEquals(u, new URIish(str));
+	}
+
+	@Test
+	public void testFileProtoWindowsMissingHostSlash() throws Exception {
+		final String str = "file://D:/m y";
+		URIish u = new URIish(str);
+		assertEquals("file", u.getScheme());
+		assertFalse(u.isRemote());
+		assertEquals("D:/m y", u.getRawPath());
+		assertEquals("D:/m y", u.getPath());
+		assertEquals("file:///D:/m y", u.toString());
+		assertEquals("file:///D:/m%20y", u.toASCIIString());
+		assertEquals(u, new URIish(str));
+	}
+
+	@Test
+	public void testFileProtoWindowsMissingHostSlash2() throws Exception {
+		final String str = "file://D: /m y";
+		URIish u = new URIish(str);
+		assertEquals("file", u.getScheme());
+		assertFalse(u.isRemote());
+		assertEquals("D: /m y", u.getRawPath());
+		assertEquals("D: /m y", u.getPath());
+		assertEquals("file:///D: /m y", u.toString());
+		assertEquals("file:///D:%20/m%20y", u.toASCIIString());
+		assertEquals(u, new URIish(str));
+	}
+
+	@Test
 	public void testGitProtoUnix() throws Exception {
 		final String str = "git://example.com/home/m y";
 		URIish u = new URIish(str);
@@ -421,6 +503,22 @@ public void testSshProtoHostWithPort() throws Exception {
 	}
 
 	@Test
+	public void testSshProtoHostWithEmptyPortAndPath() throws Exception {
+		final String str = "ssh://example.com:/path";
+		URIish u = new URIish(str);
+		assertEquals("ssh", u.getScheme());
+		assertTrue(u.isRemote());
+		assertEquals("/path", u.getRawPath());
+		assertEquals("/path", u.getPath());
+		assertEquals("example.com", u.getHost());
+		assertEquals(-1, u.getPort());
+		assertEquals("ssh://example.com/path", u.toString());
+		assertEquals("ssh://example.com/path", u.toASCIIString());
+		assertEquals(u, new URIish(str));
+		assertEquals(u, new URIish("ssh://example.com/path"));
+	}
+
+	@Test
 	public void testSshProtoWithUserAndPort() throws Exception {
 		final String str = "ssh://user@example.com:33/some/p ath";
 		URIish u = new URIish(str);
@@ -891,13 +989,6 @@ public void testFileProtocol() throws IllegalArgumentException,
 	}
 
 	@Test
-	public void testMissingPort() throws URISyntaxException {
-		final String incorrectSshUrl = "ssh://some-host:/path/to/repository.git";
-		URIish u = new URIish(incorrectSshUrl);
-		assertFalse(TransportGitSsh.PROTO_SSH.canHandle(u));
-	}
-
-	@Test
 	public void testALot() throws URISyntaxException {
 		// user pass host port path
 		// 1 2 3 4 5
@@ -961,4 +1052,32 @@ public void testStringConstructor() throws Exception {
 		assertEquals("", u.getPath());
 		assertEquals(str, u.toString());
 	}
+
+	@Test
+	public void testEqualsHashcode() throws Exception
+	{
+		String[] urls = { "http://user:pass@example.com:8081/path", "../x",
+				"ssh://x.y:23/z", "ssh://example.com:/path", "D:\\m y",
+				"\\\\some\\place", "http://localhost:1234",
+				"user@example.com:some/p ath", "a",
+				"http://user:pwd@example.com:8081/path",
+				"http://user:pass@another.com:8081/path",
+				"http://user:pass@example.com:8083/path" };
+		URIish w = new URIish("http://user:pass@example.com:8081/path/x");
+		for (String s : urls) {
+			URIish u = new URIish(s);
+			URIish v = new URIish(s);
+			assertTrue(u.equals(v));
+			assertTrue(v.equals(u));
+
+			assertFalse(u.equals(null));
+			assertFalse(u.equals(new Object()));
+			assertFalse(new Object().equals(u));
+			assertFalse(u.equals(w));
+			assertFalse(w.equals(u));
+
+			assertTrue(u.hashCode() == v.hashCode());
+			assertFalse(u.hashCode() == new Object().hashCode());
+		}
+	}
 }
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/UploadPackTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/UploadPackTest.java
index 27c7674..ef083da 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/UploadPackTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/UploadPackTest.java
@@ -1,27 +1,55 @@
 package org.eclipse.jgit.transport;
 
+import static org.hamcrest.Matchers.hasItems;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.theInstance;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertThat;
 import static org.junit.Assert.assertTrue;
 
+import java.util.Arrays;
 import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.StringWriter;
+import org.eclipse.jgit.errors.PackProtocolException;
+import org.eclipse.jgit.errors.TransportException;
+import org.eclipse.jgit.internal.storage.dfs.DfsGarbageCollector;
 import org.eclipse.jgit.internal.storage.dfs.DfsRepositoryDescription;
 import org.eclipse.jgit.internal.storage.dfs.InMemoryRepository;
 import org.eclipse.jgit.junit.TestRepository;
 import org.eclipse.jgit.lib.NullProgressMonitor;
+import org.eclipse.jgit.lib.ProgressMonitor;
+import org.eclipse.jgit.lib.Ref;
 import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.lib.Sets;
+import org.eclipse.jgit.lib.TextProgressMonitor;
+import org.eclipse.jgit.revwalk.RevBlob;
 import org.eclipse.jgit.revwalk.RevCommit;
+import org.eclipse.jgit.revwalk.RevTree;
+import org.eclipse.jgit.revwalk.RevTag;
 import org.eclipse.jgit.transport.UploadPack.RequestPolicy;
 import org.eclipse.jgit.transport.resolver.ServiceNotAuthorizedException;
 import org.eclipse.jgit.transport.resolver.ServiceNotEnabledException;
 import org.eclipse.jgit.transport.resolver.UploadPackFactory;
+import org.eclipse.jgit.util.io.NullOutputStream;
+import org.hamcrest.Matchers;
 import org.junit.After;
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
+import org.junit.rules.ExpectedException;
 
 /**
  * Tests for server upload-pack utilities.
  */
 public class UploadPackTest {
+	@Rule
+	public ExpectedException thrown = ExpectedException.none();
+
 	private URIish uri;
 
 	private TestProtocol<Object> testProtocol;
@@ -32,23 +60,14 @@ public class UploadPackTest {
 
 	private InMemoryRepository client;
 
-	private RevCommit commit0;
-
-	private RevCommit commit1;
-
-	private RevCommit tip;
+	private TestRepository<InMemoryRepository> remote;
 
 	@Before
 	public void setUp() throws Exception {
 		server = newRepo("server");
 		client = newRepo("client");
 
-		TestRepository<InMemoryRepository> remote =
-				new TestRepository<>(server);
-		commit0 = remote.commit().message("0").create();
-		commit1 = remote.commit().message("1").parent(commit0).create();
-		tip = remote.commit().message("2").parent(commit1).create();
-		remote.update("master", tip);
+		remote = new TestRepository<>(server);
 	}
 
 	@After
@@ -60,8 +79,32 @@ private static InMemoryRepository newRepo(String name) {
 		return new InMemoryRepository(new DfsRepositoryDescription(name));
 	}
 
+	private void generateBitmaps(InMemoryRepository repo) throws Exception {
+		new DfsGarbageCollector(repo).pack(null);
+		repo.scanForRepoChanges();
+	}
+
+	private static TestProtocol<Object> generateReachableCommitUploadPackProtocol() {
+		return new TestProtocol<>(
+				new UploadPackFactory<Object>() {
+					@Override
+					public UploadPack create(Object req, Repository db)
+							throws ServiceNotEnabledException,
+							ServiceNotAuthorizedException {
+						UploadPack up = new UploadPack(db);
+						up.setRequestPolicy(RequestPolicy.REACHABLE_COMMIT);
+						return up;
+					}
+				}, null);
+	}
+
 	@Test
 	public void testFetchParentOfShallowCommit() throws Exception {
+		RevCommit commit0 = remote.commit().message("0").create();
+		RevCommit commit1 = remote.commit().message("1").parent(commit0).create();
+		RevCommit tip = remote.commit().message("2").parent(commit1).create();
+		remote.update("master", tip);
+
 		testProtocol = new TestProtocol<>(
 				new UploadPackFactory<Object>() {
 					@Override
@@ -87,4 +130,958 @@ public UploadPack create(Object req, Repository db)
 			assertTrue(client.hasObject(commit0.toObjectId()));
 		}
 	}
+
+	@Test
+	public void testFetchUnreachableBlobWithBitmap() throws Exception {
+		RevBlob blob = remote.blob("foo");
+		remote.commit(remote.tree(remote.file("foo", blob)));
+		generateBitmaps(server);
+
+		testProtocol = generateReachableCommitUploadPackProtocol();
+		uri = testProtocol.register(ctx, server);
+
+		assertFalse(client.hasObject(blob.toObjectId()));
+
+		try (Transport tn = testProtocol.open(uri, client, "server")) {
+			thrown.expect(TransportException.class);
+			thrown.expectMessage(Matchers.containsString(
+						"want " + blob.name() + " not valid"));
+			tn.fetch(NullProgressMonitor.INSTANCE,
+					Collections.singletonList(new RefSpec(blob.name())));
+		}
+	}
+
+	@Test
+	public void testFetchReachableBlobWithBitmap() throws Exception {
+		RevBlob blob = remote.blob("foo");
+		RevCommit commit = remote.commit(remote.tree(remote.file("foo", blob)));
+		remote.update("master", commit);
+		generateBitmaps(server);
+
+		testProtocol = generateReachableCommitUploadPackProtocol();
+		uri = testProtocol.register(ctx, server);
+
+		assertFalse(client.hasObject(blob.toObjectId()));
+
+		try (Transport tn = testProtocol.open(uri, client, "server")) {
+			tn.fetch(NullProgressMonitor.INSTANCE,
+					Collections.singletonList(new RefSpec(blob.name())));
+			assertTrue(client.hasObject(blob.toObjectId()));
+		}
+	}
+
+	@Test
+	public void testFetchReachableBlobWithoutBitmap() throws Exception {
+		RevBlob blob = remote.blob("foo");
+		RevCommit commit = remote.commit(remote.tree(remote.file("foo", blob)));
+		remote.update("master", commit);
+
+		testProtocol = generateReachableCommitUploadPackProtocol();
+		uri = testProtocol.register(ctx, server);
+
+		assertFalse(client.hasObject(blob.toObjectId()));
+
+		try (Transport tn = testProtocol.open(uri, client, "server")) {
+			thrown.expect(TransportException.class);
+			thrown.expectMessage(Matchers.containsString(
+						"want " + blob.name() + " not valid"));
+			tn.fetch(NullProgressMonitor.INSTANCE,
+					Collections.singletonList(new RefSpec(blob.name())));
+		}
+	}
+
+	@Test
+	public void testFetchWithBlobNoneFilter() throws Exception {
+		InMemoryRepository server2 = newRepo("server2");
+		TestRepository<InMemoryRepository> remote2 =
+				new TestRepository<>(server2);
+		RevBlob blob1 = remote2.blob("foobar");
+		RevBlob blob2 = remote2.blob("fooba");
+		RevTree tree = remote2.tree(remote2.file("1", blob1),
+				remote2.file("2", blob2));
+		RevCommit commit = remote2.commit(tree);
+		remote2.update("master", commit);
+
+		server2.getConfig().setBoolean("uploadpack", null, "allowfilter", true);
+
+		testProtocol = new TestProtocol<>(
+				new UploadPackFactory<Object>() {
+					@Override
+					public UploadPack create(Object req, Repository db)
+							throws ServiceNotEnabledException,
+							ServiceNotAuthorizedException {
+						UploadPack up = new UploadPack(db);
+						return up;
+					}
+				}, null);
+		uri = testProtocol.register(ctx, server2);
+
+		try (Transport tn = testProtocol.open(uri, client, "server2")) {
+			tn.setFilterBlobLimit(0);
+			tn.fetch(NullProgressMonitor.INSTANCE,
+					Collections.singletonList(new RefSpec(commit.name())));
+			assertTrue(client.hasObject(tree.toObjectId()));
+			assertFalse(client.hasObject(blob1.toObjectId()));
+			assertFalse(client.hasObject(blob2.toObjectId()));
+		}
+	}
+
+	@Test
+	public void testFetchWithBlobLimitFilter() throws Exception {
+		InMemoryRepository server2 = newRepo("server2");
+		TestRepository<InMemoryRepository> remote2 =
+				new TestRepository<>(server2);
+		RevBlob longBlob = remote2.blob("foobar");
+		RevBlob shortBlob = remote2.blob("fooba");
+		RevTree tree = remote2.tree(remote2.file("1", longBlob),
+				remote2.file("2", shortBlob));
+		RevCommit commit = remote2.commit(tree);
+		remote2.update("master", commit);
+
+		server2.getConfig().setBoolean("uploadpack", null, "allowfilter", true);
+
+		testProtocol = new TestProtocol<>(
+				new UploadPackFactory<Object>() {
+					@Override
+					public UploadPack create(Object req, Repository db)
+							throws ServiceNotEnabledException,
+							ServiceNotAuthorizedException {
+						UploadPack up = new UploadPack(db);
+						return up;
+					}
+				}, null);
+		uri = testProtocol.register(ctx, server2);
+
+		try (Transport tn = testProtocol.open(uri, client, "server2")) {
+			tn.setFilterBlobLimit(5);
+			tn.fetch(NullProgressMonitor.INSTANCE,
+					Collections.singletonList(new RefSpec(commit.name())));
+			assertFalse(client.hasObject(longBlob.toObjectId()));
+			assertTrue(client.hasObject(shortBlob.toObjectId()));
+		}
+	}
+
+	@Test
+	public void testFetchWithBlobLimitFilterAndBitmaps() throws Exception {
+		InMemoryRepository server2 = newRepo("server2");
+		TestRepository<InMemoryRepository> remote2 =
+				new TestRepository<>(server2);
+		RevBlob longBlob = remote2.blob("foobar");
+		RevBlob shortBlob = remote2.blob("fooba");
+		RevTree tree = remote2.tree(remote2.file("1", longBlob),
+				remote2.file("2", shortBlob));
+		RevCommit commit = remote2.commit(tree);
+		remote2.update("master", commit);
+
+		server2.getConfig().setBoolean("uploadpack", null, "allowfilter", true);
+
+		// generate bitmaps
+		new DfsGarbageCollector(server2).pack(null);
+		server2.scanForRepoChanges();
+
+		testProtocol = new TestProtocol<>(
+				new UploadPackFactory<Object>() {
+					@Override
+					public UploadPack create(Object req, Repository db)
+							throws ServiceNotEnabledException,
+							ServiceNotAuthorizedException {
+						UploadPack up = new UploadPack(db);
+						return up;
+					}
+				}, null);
+		uri = testProtocol.register(ctx, server2);
+
+		try (Transport tn = testProtocol.open(uri, client, "server2")) {
+			tn.setFilterBlobLimit(5);
+			tn.fetch(NullProgressMonitor.INSTANCE,
+					Collections.singletonList(new RefSpec(commit.name())));
+			assertFalse(client.hasObject(longBlob.toObjectId()));
+			assertTrue(client.hasObject(shortBlob.toObjectId()));
+		}
+	}
+
+	@Test
+	public void testFetchWithNonSupportingServer() throws Exception {
+		InMemoryRepository server2 = newRepo("server2");
+		TestRepository<InMemoryRepository> remote2 =
+				new TestRepository<>(server2);
+		RevBlob blob = remote2.blob("foo");
+		RevTree tree = remote2.tree(remote2.file("1", blob));
+		RevCommit commit = remote2.commit(tree);
+		remote2.update("master", commit);
+
+		server2.getConfig().setBoolean("uploadpack", null, "allowfilter", false);
+
+		testProtocol = new TestProtocol<>(
+				new UploadPackFactory<Object>() {
+					@Override
+					public UploadPack create(Object req, Repository db)
+							throws ServiceNotEnabledException,
+							ServiceNotAuthorizedException {
+						UploadPack up = new UploadPack(db);
+						return up;
+					}
+				}, null);
+		uri = testProtocol.register(ctx, server2);
+
+		try (Transport tn = testProtocol.open(uri, client, "server2")) {
+			tn.setFilterBlobLimit(0);
+
+			thrown.expect(TransportException.class);
+			thrown.expectMessage("filter requires server to advertise that capability");
+
+			tn.fetch(NullProgressMonitor.INSTANCE,
+					Collections.singletonList(new RefSpec(commit.name())));
+		}
+	}
+
+	/*
+	 * Invokes UploadPack with protocol v2 and sends it the given lines,
+	 * and returns UploadPack's output stream.
+	 */
+	private ByteArrayInputStream uploadPackV2Setup(RequestPolicy requestPolicy,
+			RefFilter refFilter, String... inputLines) throws Exception {
+
+		ByteArrayOutputStream send = new ByteArrayOutputStream();
+		PacketLineOut pckOut = new PacketLineOut(send);
+		for (String line : inputLines) {
+			if (line == PacketLineIn.END) {
+				pckOut.end();
+			} else if (line == PacketLineIn.DELIM) {
+				pckOut.writeDelim();
+			} else {
+				pckOut.writeString(line);
+			}
+		}
+
+		server.getConfig().setString("protocol", null, "version", "2");
+		UploadPack up = new UploadPack(server);
+		if (requestPolicy != null)
+			up.setRequestPolicy(requestPolicy);
+		if (refFilter != null)
+			up.setRefFilter(refFilter);
+		up.setExtraParameters(Sets.of("version=2"));
+
+		ByteArrayOutputStream recv = new ByteArrayOutputStream();
+		up.upload(new ByteArrayInputStream(send.toByteArray()), recv, null);
+
+		return new ByteArrayInputStream(recv.toByteArray());
+	}
+
+	/*
+	 * Invokes UploadPack with protocol v2 and sends it the given lines.
+	 * Returns UploadPack's output stream, not including the capability
+	 * advertisement by the server.
+	 */
+	private ByteArrayInputStream uploadPackV2(RequestPolicy requestPolicy,
+			RefFilter refFilter, String... inputLines) throws Exception {
+		ByteArrayInputStream recvStream =
+			uploadPackV2Setup(requestPolicy, refFilter, inputLines);
+		PacketLineIn pckIn = new PacketLineIn(recvStream);
+
+		// drain capabilities
+		while (pckIn.readString() != PacketLineIn.END) {
+			// do nothing
+		}
+		return recvStream;
+	}
+
+	private ByteArrayInputStream uploadPackV2(String... inputLines) throws Exception {
+		return uploadPackV2(null, null, inputLines);
+	}
+
+	@Test
+	public void testV2Capabilities() throws Exception {
+		ByteArrayInputStream recvStream =
+			uploadPackV2Setup(null, null, PacketLineIn.END);
+		PacketLineIn pckIn = new PacketLineIn(recvStream);
+
+		assertThat(pckIn.readString(), is("version 2"));
+		assertThat(
+			Arrays.asList(pckIn.readString(), pckIn.readString()),
+			// TODO(jonathantanmy) This check is written this way
+			// to make it simple to see that we expect this list of
+			// capabilities, but probably should be loosened to
+			// allow additional commands to be added to the list,
+			// and additional capabilities to be added to existing
+			// commands without requiring test changes.
+			hasItems("ls-refs", "fetch=shallow"));
+		assertTrue(pckIn.readString() == PacketLineIn.END);
+	}
+
+	@Test
+	public void testV2CapabilitiesAllowFilter() throws Exception {
+		server.getConfig().setBoolean("uploadpack", null, "allowfilter", true);
+		ByteArrayInputStream recvStream =
+			uploadPackV2Setup(null, null, PacketLineIn.END);
+		PacketLineIn pckIn = new PacketLineIn(recvStream);
+
+		assertThat(pckIn.readString(), is("version 2"));
+		assertThat(
+			Arrays.asList(pckIn.readString(), pckIn.readString()),
+			// TODO(jonathantanmy) This check overspecifies the
+			// order of the capabilities of "fetch".
+			hasItems("ls-refs", "fetch=filter shallow"));
+		assertTrue(pckIn.readString() == PacketLineIn.END);
+	}
+
+	@Test
+	@SuppressWarnings("boxing")
+	public void testV2EmptyRequest() throws Exception {
+		ByteArrayInputStream recvStream = uploadPackV2(PacketLineIn.END);
+		// Verify that there is nothing more after the capability
+		// advertisement.
+		assertThat(recvStream.available(), is(0));
+	}
+
+	@Test
+	public void testV2LsRefs() throws Exception {
+		RevCommit tip = remote.commit().message("message").create();
+		remote.update("master", tip);
+		server.updateRef("HEAD").link("refs/heads/master");
+		RevTag tag = remote.tag("tag", tip);
+		remote.update("refs/tags/tag", tag);
+
+		ByteArrayInputStream recvStream = uploadPackV2("command=ls-refs\n", PacketLineIn.END);
+		PacketLineIn pckIn = new PacketLineIn(recvStream);
+
+		assertThat(pckIn.readString(), is(tip.toObjectId().getName() + " HEAD"));
+		assertThat(pckIn.readString(), is(tip.toObjectId().getName() + " refs/heads/master"));
+		assertThat(pckIn.readString(), is(tag.toObjectId().getName() + " refs/tags/tag"));
+		assertTrue(pckIn.readString() == PacketLineIn.END);
+	}
+
+	@Test
+	public void testV2LsRefsSymrefs() throws Exception {
+		RevCommit tip = remote.commit().message("message").create();
+		remote.update("master", tip);
+		server.updateRef("HEAD").link("refs/heads/master");
+		RevTag tag = remote.tag("tag", tip);
+		remote.update("refs/tags/tag", tag);
+
+		ByteArrayInputStream recvStream = uploadPackV2("command=ls-refs\n", PacketLineIn.DELIM, "symrefs", PacketLineIn.END);
+		PacketLineIn pckIn = new PacketLineIn(recvStream);
+
+		assertThat(pckIn.readString(), is(tip.toObjectId().getName() + " HEAD symref-target:refs/heads/master"));
+		assertThat(pckIn.readString(), is(tip.toObjectId().getName() + " refs/heads/master"));
+		assertThat(pckIn.readString(), is(tag.toObjectId().getName() + " refs/tags/tag"));
+		assertTrue(pckIn.readString() == PacketLineIn.END);
+	}
+
+	@Test
+	public void testV2LsRefsPeel() throws Exception {
+		RevCommit tip = remote.commit().message("message").create();
+		remote.update("master", tip);
+		server.updateRef("HEAD").link("refs/heads/master");
+		RevTag tag = remote.tag("tag", tip);
+		remote.update("refs/tags/tag", tag);
+
+		ByteArrayInputStream recvStream = uploadPackV2("command=ls-refs\n", PacketLineIn.DELIM, "peel", PacketLineIn.END);
+		PacketLineIn pckIn = new PacketLineIn(recvStream);
+
+		assertThat(pckIn.readString(), is(tip.toObjectId().getName() + " HEAD"));
+		assertThat(pckIn.readString(), is(tip.toObjectId().getName() + " refs/heads/master"));
+		assertThat(
+			pckIn.readString(),
+			is(tag.toObjectId().getName() + " refs/tags/tag peeled:"
+				+ tip.toObjectId().getName()));
+		assertTrue(pckIn.readString() == PacketLineIn.END);
+	}
+
+	@Test
+	public void testV2LsRefsMultipleCommands() throws Exception {
+		RevCommit tip = remote.commit().message("message").create();
+		remote.update("master", tip);
+		server.updateRef("HEAD").link("refs/heads/master");
+		RevTag tag = remote.tag("tag", tip);
+		remote.update("refs/tags/tag", tag);
+
+		ByteArrayInputStream recvStream = uploadPackV2(
+			"command=ls-refs\n", PacketLineIn.DELIM, "symrefs", "peel", PacketLineIn.END,
+			"command=ls-refs\n", PacketLineIn.DELIM, PacketLineIn.END);
+		PacketLineIn pckIn = new PacketLineIn(recvStream);
+
+		assertThat(pckIn.readString(), is(tip.toObjectId().getName() + " HEAD symref-target:refs/heads/master"));
+		assertThat(pckIn.readString(), is(tip.toObjectId().getName() + " refs/heads/master"));
+		assertThat(
+			pckIn.readString(),
+			is(tag.toObjectId().getName() + " refs/tags/tag peeled:"
+				+ tip.toObjectId().getName()));
+		assertTrue(pckIn.readString() == PacketLineIn.END);
+		assertThat(pckIn.readString(), is(tip.toObjectId().getName() + " HEAD"));
+		assertThat(pckIn.readString(), is(tip.toObjectId().getName() + " refs/heads/master"));
+		assertThat(pckIn.readString(), is(tag.toObjectId().getName() + " refs/tags/tag"));
+		assertTrue(pckIn.readString() == PacketLineIn.END);
+	}
+
+	@Test
+	public void testV2LsRefsRefPrefix() throws Exception {
+		RevCommit tip = remote.commit().message("message").create();
+		remote.update("master", tip);
+		remote.update("other", tip);
+		remote.update("yetAnother", tip);
+
+		ByteArrayInputStream recvStream = uploadPackV2(
+			"command=ls-refs\n",
+			PacketLineIn.DELIM,
+			"ref-prefix refs/heads/maste",
+			"ref-prefix refs/heads/other",
+			PacketLineIn.END);
+		PacketLineIn pckIn = new PacketLineIn(recvStream);
+
+		assertThat(pckIn.readString(), is(tip.toObjectId().getName() + " refs/heads/master"));
+		assertThat(pckIn.readString(), is(tip.toObjectId().getName() + " refs/heads/other"));
+		assertTrue(pckIn.readString() == PacketLineIn.END);
+	}
+
+	@Test
+	public void testV2LsRefsRefPrefixNoSlash() throws Exception {
+		RevCommit tip = remote.commit().message("message").create();
+		remote.update("master", tip);
+		remote.update("other", tip);
+
+		ByteArrayInputStream recvStream = uploadPackV2(
+			"command=ls-refs\n",
+			PacketLineIn.DELIM,
+			"ref-prefix refs/heads/maste",
+			"ref-prefix r",
+			PacketLineIn.END);
+		PacketLineIn pckIn = new PacketLineIn(recvStream);
+
+		assertThat(pckIn.readString(), is(tip.toObjectId().getName() + " refs/heads/master"));
+		assertThat(pckIn.readString(), is(tip.toObjectId().getName() + " refs/heads/other"));
+		assertTrue(pckIn.readString() == PacketLineIn.END);
+	}
+
+	@Test
+	public void testV2LsRefsUnrecognizedArgument() throws Exception {
+		thrown.expect(PackProtocolException.class);
+		thrown.expectMessage("unexpected invalid-argument");
+		uploadPackV2(
+			"command=ls-refs\n",
+			PacketLineIn.DELIM,
+			"invalid-argument\n",
+			PacketLineIn.END);
+	}
+
+	/*
+	 * Parse multiplexed packfile output from upload-pack using protocol V2
+	 * into the client repository.
+	 */
+	private ReceivedPackStatistics parsePack(ByteArrayInputStream recvStream) throws Exception {
+		return parsePack(recvStream, NullProgressMonitor.INSTANCE);
+	}
+
+	private ReceivedPackStatistics parsePack(ByteArrayInputStream recvStream, ProgressMonitor pm)
+			throws Exception {
+		SideBandInputStream sb = new SideBandInputStream(
+				recvStream, pm,
+				new StringWriter(), NullOutputStream.INSTANCE);
+		PackParser pp = client.newObjectInserter().newPackParser(sb);
+		pp.parse(NullProgressMonitor.INSTANCE);
+		return pp.getReceivedPackStatistics();
+	}
+
+	@Test
+	public void testV2FetchRequestPolicyAdvertised() throws Exception {
+		RevCommit advertized = remote.commit().message("x").create();
+		RevCommit unadvertized = remote.commit().message("y").create();
+		remote.update("branch1", advertized);
+
+		// This works
+		uploadPackV2(
+			RequestPolicy.ADVERTISED,
+			null,
+			"command=fetch\n",
+			PacketLineIn.DELIM,
+			"want " + advertized.name() + "\n",
+			PacketLineIn.END);
+
+		// This doesn't
+		thrown.expect(TransportException.class);
+		thrown.expectMessage(Matchers.containsString(
+					"want " + unadvertized.name() + " not valid"));
+		uploadPackV2(
+			RequestPolicy.ADVERTISED,
+			null,
+			"command=fetch\n",
+			PacketLineIn.DELIM,
+			"want " + unadvertized.name() + "\n",
+			PacketLineIn.END);
+	}
+
+	@Test
+	public void testV2FetchRequestPolicyReachableCommit() throws Exception {
+		RevCommit reachable = remote.commit().message("x").create();
+		RevCommit advertized = remote.commit().message("x").parent(reachable).create();
+		RevCommit unreachable = remote.commit().message("y").create();
+		remote.update("branch1", advertized);
+
+		// This works
+		uploadPackV2(
+			RequestPolicy.REACHABLE_COMMIT,
+			null,
+			"command=fetch\n",
+			PacketLineIn.DELIM,
+			"want " + reachable.name() + "\n",
+			PacketLineIn.END);
+
+		// This doesn't
+		thrown.expect(TransportException.class);
+		thrown.expectMessage(Matchers.containsString(
+					"want " + unreachable.name() + " not valid"));
+		uploadPackV2(
+			RequestPolicy.REACHABLE_COMMIT,
+			null,
+			"command=fetch\n",
+			PacketLineIn.DELIM,
+			"want " + unreachable.name() + "\n",
+			PacketLineIn.END);
+	}
+
+	@Test
+	public void testV2FetchRequestPolicyTip() throws Exception {
+		RevCommit parentOfTip = remote.commit().message("x").create();
+		RevCommit tip = remote.commit().message("y").parent(parentOfTip).create();
+		remote.update("secret", tip);
+
+		// This works
+		uploadPackV2(
+			RequestPolicy.TIP,
+			new RejectAllRefFilter(),
+			"command=fetch\n",
+			PacketLineIn.DELIM,
+			"want " + tip.name() + "\n",
+			PacketLineIn.END);
+
+		// This doesn't
+		thrown.expect(TransportException.class);
+		thrown.expectMessage(Matchers.containsString(
+					"want " + parentOfTip.name() + " not valid"));
+		uploadPackV2(
+			RequestPolicy.TIP,
+			new RejectAllRefFilter(),
+			"command=fetch\n",
+			PacketLineIn.DELIM,
+			"want " + parentOfTip.name() + "\n",
+			PacketLineIn.END);
+	}
+
+	@Test
+	public void testV2FetchRequestPolicyReachableCommitTip() throws Exception {
+		RevCommit parentOfTip = remote.commit().message("x").create();
+		RevCommit tip = remote.commit().message("y").parent(parentOfTip).create();
+		RevCommit unreachable = remote.commit().message("y").create();
+		remote.update("secret", tip);
+
+		// This works
+		uploadPackV2(
+			RequestPolicy.REACHABLE_COMMIT_TIP,
+			new RejectAllRefFilter(),
+			"command=fetch\n",
+			PacketLineIn.DELIM,
+			"want " + parentOfTip.name() + "\n",
+			PacketLineIn.END);
+
+		// This doesn't
+		thrown.expect(TransportException.class);
+		thrown.expectMessage(Matchers.containsString(
+					"want " + unreachable.name() + " not valid"));
+		uploadPackV2(
+			RequestPolicy.REACHABLE_COMMIT_TIP,
+			new RejectAllRefFilter(),
+			"command=fetch\n",
+			PacketLineIn.DELIM,
+			"want " + unreachable.name() + "\n",
+			PacketLineIn.END);
+	}
+
+	@Test
+	public void testV2FetchRequestPolicyAny() throws Exception {
+		RevCommit unreachable = remote.commit().message("y").create();
+
+		// Exercise to make sure that even unreachable commits can be fetched
+		uploadPackV2(
+			RequestPolicy.ANY,
+			null,
+			"command=fetch\n",
+			PacketLineIn.DELIM,
+			"want " + unreachable.name() + "\n",
+			PacketLineIn.END);
+	}
+
+	@Test
+	public void testV2FetchServerDoesNotStopNegotiation() throws Exception {
+		RevCommit fooParent = remote.commit().message("x").create();
+		RevCommit fooChild = remote.commit().message("x").parent(fooParent).create();
+		RevCommit barParent = remote.commit().message("y").create();
+		RevCommit barChild = remote.commit().message("y").parent(barParent).create();
+		remote.update("branch1", fooChild);
+		remote.update("branch2", barChild);
+
+		ByteArrayInputStream recvStream = uploadPackV2(
+			"command=fetch\n",
+			PacketLineIn.DELIM,
+			"want " + fooChild.toObjectId().getName() + "\n",
+			"want " + barChild.toObjectId().getName() + "\n",
+			"have " + fooParent.toObjectId().getName() + "\n",
+			PacketLineIn.END);
+		PacketLineIn pckIn = new PacketLineIn(recvStream);
+
+		assertThat(pckIn.readString(), is("acknowledgments"));
+		assertThat(pckIn.readString(), is("ACK " + fooParent.toObjectId().getName()));
+		assertThat(pckIn.readString(), theInstance(PacketLineIn.END));
+	}
+
+	@Test
+	public void testV2FetchServerStopsNegotiation() throws Exception {
+		RevCommit fooParent = remote.commit().message("x").create();
+		RevCommit fooChild = remote.commit().message("x").parent(fooParent).create();
+		RevCommit barParent = remote.commit().message("y").create();
+		RevCommit barChild = remote.commit().message("y").parent(barParent).create();
+		remote.update("branch1", fooChild);
+		remote.update("branch2", barChild);
+
+		ByteArrayInputStream recvStream = uploadPackV2(
+			"command=fetch\n",
+			PacketLineIn.DELIM,
+			"want " + fooChild.toObjectId().getName() + "\n",
+			"want " + barChild.toObjectId().getName() + "\n",
+			"have " + fooParent.toObjectId().getName() + "\n",
+			"have " + barParent.toObjectId().getName() + "\n",
+			PacketLineIn.END);
+		PacketLineIn pckIn = new PacketLineIn(recvStream);
+
+		assertThat(pckIn.readString(), is("acknowledgments"));
+		assertThat(
+			Arrays.asList(pckIn.readString(), pckIn.readString()),
+			hasItems(
+				"ACK " + fooParent.toObjectId().getName(),
+				"ACK " + barParent.toObjectId().getName()));
+		assertThat(pckIn.readString(), is("ready"));
+		assertThat(pckIn.readString(), theInstance(PacketLineIn.DELIM));
+		assertThat(pckIn.readString(), is("packfile"));
+		parsePack(recvStream);
+		assertFalse(client.hasObject(fooParent.toObjectId()));
+		assertTrue(client.hasObject(fooChild.toObjectId()));
+		assertFalse(client.hasObject(barParent.toObjectId()));
+		assertTrue(client.hasObject(barChild.toObjectId()));
+	}
+
+	@Test
+	public void testV2FetchClientStopsNegotiation() throws Exception {
+		RevCommit fooParent = remote.commit().message("x").create();
+		RevCommit fooChild = remote.commit().message("x").parent(fooParent).create();
+		RevCommit barParent = remote.commit().message("y").create();
+		RevCommit barChild = remote.commit().message("y").parent(barParent).create();
+		remote.update("branch1", fooChild);
+		remote.update("branch2", barChild);
+
+		ByteArrayInputStream recvStream = uploadPackV2(
+			"command=fetch\n",
+			PacketLineIn.DELIM,
+			"want " + fooChild.toObjectId().getName() + "\n",
+			"want " + barChild.toObjectId().getName() + "\n",
+			"have " + fooParent.toObjectId().getName() + "\n",
+			"done\n",
+			PacketLineIn.END);
+		PacketLineIn pckIn = new PacketLineIn(recvStream);
+
+		assertThat(pckIn.readString(), is("packfile"));
+		parsePack(recvStream);
+		assertFalse(client.hasObject(fooParent.toObjectId()));
+		assertTrue(client.hasObject(fooChild.toObjectId()));
+		assertTrue(client.hasObject(barParent.toObjectId()));
+		assertTrue(client.hasObject(barChild.toObjectId()));
+	}
+
+	@Test
+	public void testV2FetchThinPack() throws Exception {
+		String commonInBlob = "abcdefghijklmnopqrstuvwxyz";
+
+		RevBlob parentBlob = remote.blob(commonInBlob + "a");
+		RevCommit parent = remote.commit(remote.tree(remote.file("foo", parentBlob)));
+		RevBlob childBlob = remote.blob(commonInBlob + "b");
+		RevCommit child = remote.commit(remote.tree(remote.file("foo", childBlob)), parent);
+		remote.update("branch1", child);
+
+		// Pretend that we have parent to get a thin pack based on it.
+		ByteArrayInputStream recvStream = uploadPackV2(
+			"command=fetch\n",
+			PacketLineIn.DELIM,
+			"want " + child.toObjectId().getName() + "\n",
+			"have " + parent.toObjectId().getName() + "\n",
+			"thin-pack\n",
+			"done\n",
+			PacketLineIn.END);
+		PacketLineIn pckIn = new PacketLineIn(recvStream);
+
+		assertThat(pckIn.readString(), is("packfile"));
+
+		// Verify that we received a thin pack by trying to apply it
+		// against the client repo, which does not have parent.
+		thrown.expect(IOException.class);
+		thrown.expectMessage("pack has unresolved deltas");
+		parsePack(recvStream);
+	}
+
+	@Test
+	public void testV2FetchNoProgress() throws Exception {
+		RevCommit commit = remote.commit().message("x").create();
+		remote.update("branch1", commit);
+
+		// Without no-progress, progress is reported.
+		StringWriter sw = new StringWriter();
+		ByteArrayInputStream recvStream = uploadPackV2(
+			"command=fetch\n",
+			PacketLineIn.DELIM,
+			"want " + commit.toObjectId().getName() + "\n",
+			"done\n",
+			PacketLineIn.END);
+		PacketLineIn pckIn = new PacketLineIn(recvStream);
+		assertThat(pckIn.readString(), is("packfile"));
+		parsePack(recvStream, new TextProgressMonitor(sw));
+		assertFalse(sw.toString().isEmpty());
+
+		// With no-progress, progress is not reported.
+		sw = new StringWriter();
+		recvStream = uploadPackV2(
+			"command=fetch\n",
+			PacketLineIn.DELIM,
+			"want " + commit.toObjectId().getName() + "\n",
+			"no-progress\n",
+			"done\n",
+			PacketLineIn.END);
+		pckIn = new PacketLineIn(recvStream);
+		assertThat(pckIn.readString(), is("packfile"));
+		parsePack(recvStream, new TextProgressMonitor(sw));
+		assertTrue(sw.toString().isEmpty());
+	}
+
+	@Test
+	public void testV2FetchIncludeTag() throws Exception {
+		RevCommit commit = remote.commit().message("x").create();
+		RevTag tag = remote.tag("tag", commit);
+		remote.update("branch1", commit);
+		remote.update("refs/tags/tag", tag);
+
+		// Without include-tag.
+		ByteArrayInputStream recvStream = uploadPackV2(
+			"command=fetch\n",
+			PacketLineIn.DELIM,
+			"want " + commit.toObjectId().getName() + "\n",
+			"done\n",
+			PacketLineIn.END);
+		PacketLineIn pckIn = new PacketLineIn(recvStream);
+		assertThat(pckIn.readString(), is("packfile"));
+		parsePack(recvStream);
+		assertFalse(client.hasObject(tag.toObjectId()));
+
+		// With tag.
+		recvStream = uploadPackV2(
+			"command=fetch\n",
+			PacketLineIn.DELIM,
+			"want " + commit.toObjectId().getName() + "\n",
+			"include-tag\n",
+			"done\n",
+			PacketLineIn.END);
+		pckIn = new PacketLineIn(recvStream);
+		assertThat(pckIn.readString(), is("packfile"));
+		parsePack(recvStream);
+		assertTrue(client.hasObject(tag.toObjectId()));
+	}
+
+	@Test
+	public void testV2FetchOfsDelta() throws Exception {
+		String commonInBlob = "abcdefghijklmnopqrstuvwxyz";
+
+		RevBlob parentBlob = remote.blob(commonInBlob + "a");
+		RevCommit parent = remote.commit(remote.tree(remote.file("foo", parentBlob)));
+		RevBlob childBlob = remote.blob(commonInBlob + "b");
+		RevCommit child = remote.commit(remote.tree(remote.file("foo", childBlob)), parent);
+		remote.update("branch1", child);
+
+		// Without ofs-delta.
+		ByteArrayInputStream recvStream = uploadPackV2(
+			"command=fetch\n",
+			PacketLineIn.DELIM,
+			"want " + child.toObjectId().getName() + "\n",
+			"done\n",
+			PacketLineIn.END);
+		PacketLineIn pckIn = new PacketLineIn(recvStream);
+		assertThat(pckIn.readString(), is("packfile"));
+		ReceivedPackStatistics stats = parsePack(recvStream);
+		assertTrue(stats.getNumOfsDelta() == 0);
+
+		// With ofs-delta.
+		recvStream = uploadPackV2(
+			"command=fetch\n",
+			PacketLineIn.DELIM,
+			"want " + child.toObjectId().getName() + "\n",
+			"ofs-delta\n",
+			"done\n",
+			PacketLineIn.END);
+		pckIn = new PacketLineIn(recvStream);
+		assertThat(pckIn.readString(), is("packfile"));
+		stats = parsePack(recvStream);
+		assertTrue(stats.getNumOfsDelta() != 0);
+	}
+
+	@Test
+	public void testV2FetchShallow() throws Exception {
+		RevCommit commonParent = remote.commit().message("parent").create();
+		RevCommit fooChild = remote.commit().message("x").parent(commonParent).create();
+		RevCommit barChild = remote.commit().message("y").parent(commonParent).create();
+		remote.update("branch1", barChild);
+
+		// Without shallow, the server thinks that we have
+		// commonParent, so it doesn't send it.
+		ByteArrayInputStream recvStream = uploadPackV2(
+			"command=fetch\n",
+			PacketLineIn.DELIM,
+			"want " + barChild.toObjectId().getName() + "\n",
+			"have " + fooChild.toObjectId().getName() + "\n",
+			"done\n",
+			PacketLineIn.END);
+		PacketLineIn pckIn = new PacketLineIn(recvStream);
+		assertThat(pckIn.readString(), is("packfile"));
+		parsePack(recvStream);
+		assertTrue(client.hasObject(barChild.toObjectId()));
+		assertFalse(client.hasObject(commonParent.toObjectId()));
+
+		// With shallow, the server knows that we don't have
+		// commonParent, so it sends it.
+		recvStream = uploadPackV2(
+			"command=fetch\n",
+			PacketLineIn.DELIM,
+			"want " + barChild.toObjectId().getName() + "\n",
+			"have " + fooChild.toObjectId().getName() + "\n",
+			"shallow " + fooChild.toObjectId().getName() + "\n",
+			"done\n",
+			PacketLineIn.END);
+		pckIn = new PacketLineIn(recvStream);
+		assertThat(pckIn.readString(), is("packfile"));
+		parsePack(recvStream);
+		assertTrue(client.hasObject(commonParent.toObjectId()));
+	}
+
+	@Test
+	public void testV2FetchDeepenAndDone() throws Exception {
+		RevCommit parent = remote.commit().message("parent").create();
+		RevCommit child = remote.commit().message("x").parent(parent).create();
+		remote.update("branch1", child);
+
+		// "deepen 1" sends only the child.
+		ByteArrayInputStream recvStream = uploadPackV2(
+			"command=fetch\n",
+			PacketLineIn.DELIM,
+			"want " + child.toObjectId().getName() + "\n",
+			"deepen 1\n",
+			"done\n",
+			PacketLineIn.END);
+		PacketLineIn pckIn = new PacketLineIn(recvStream);
+		assertThat(pckIn.readString(), is("shallow-info"));
+		assertThat(pckIn.readString(), is("shallow " + child.toObjectId().getName()));
+		assertThat(pckIn.readString(), theInstance(PacketLineIn.DELIM));
+		assertThat(pckIn.readString(), is("packfile"));
+		parsePack(recvStream);
+		assertTrue(client.hasObject(child.toObjectId()));
+		assertFalse(client.hasObject(parent.toObjectId()));
+
+		// Without that, the parent is sent too.
+		recvStream = uploadPackV2(
+			"command=fetch\n",
+			PacketLineIn.DELIM,
+			"want " + child.toObjectId().getName() + "\n",
+			"done\n",
+			PacketLineIn.END);
+		pckIn = new PacketLineIn(recvStream);
+		assertThat(pckIn.readString(), is("packfile"));
+		parsePack(recvStream);
+		assertTrue(client.hasObject(parent.toObjectId()));
+	}
+
+	@Test
+	public void testV2FetchDeepenWithoutDone() throws Exception {
+		RevCommit parent = remote.commit().message("parent").create();
+		RevCommit child = remote.commit().message("x").parent(parent).create();
+		remote.update("branch1", child);
+
+		ByteArrayInputStream recvStream = uploadPackV2(
+			"command=fetch\n",
+			PacketLineIn.DELIM,
+			"want " + child.toObjectId().getName() + "\n",
+			"deepen 1\n",
+			PacketLineIn.END);
+		PacketLineIn pckIn = new PacketLineIn(recvStream);
+
+		// Verify that only the correct section is sent. "shallow-info"
+		// is not sent because, according to the specification, it is
+		// sent only if a packfile is sent.
+		assertThat(pckIn.readString(), is("acknowledgments"));
+		assertThat(pckIn.readString(), is("NAK"));
+		assertThat(pckIn.readString(), theInstance(PacketLineIn.END));
+	}
+
+	@Test
+	public void testV2FetchUnrecognizedArgument() throws Exception {
+		thrown.expect(PackProtocolException.class);
+		thrown.expectMessage("unexpected invalid-argument");
+		uploadPackV2(
+			"command=fetch\n",
+			PacketLineIn.DELIM,
+			"invalid-argument\n",
+			PacketLineIn.END);
+	}
+
+	@Test
+	public void testV2FetchFilter() throws Exception {
+		RevBlob big = remote.blob("foobar");
+		RevBlob small = remote.blob("fooba");
+		RevTree tree = remote.tree(remote.file("1", big),
+				remote.file("2", small));
+		RevCommit commit = remote.commit(tree);
+		remote.update("master", commit);
+
+		server.getConfig().setBoolean("uploadpack", null, "allowfilter", true);
+
+		ByteArrayInputStream recvStream = uploadPackV2(
+			"command=fetch\n",
+			PacketLineIn.DELIM,
+			"want " + commit.toObjectId().getName() + "\n",
+			"filter blob:limit=5\n",
+			"done\n",
+			PacketLineIn.END);
+		PacketLineIn pckIn = new PacketLineIn(recvStream);
+		assertThat(pckIn.readString(), is("packfile"));
+		parsePack(recvStream);
+
+		assertFalse(client.hasObject(big.toObjectId()));
+		assertTrue(client.hasObject(small.toObjectId()));
+	}
+
+	@Test
+	public void testV2FetchFilterWhenNotAllowed() throws Exception {
+		RevCommit commit = remote.commit().message("0").create();
+		remote.update("master", commit);
+
+		server.getConfig().setBoolean("uploadpack", null, "allowfilter", false);
+
+		thrown.expect(PackProtocolException.class);
+		thrown.expectMessage("unexpected filter blob:limit=5");
+		uploadPackV2(
+			"command=fetch\n",
+			PacketLineIn.DELIM,
+			"want " + commit.toObjectId().getName() + "\n",
+			"filter blob:limit=5\n",
+			"done\n",
+			PacketLineIn.END);
+	}
+
+	private static class RejectAllRefFilter implements RefFilter {
+		@Override
+		public Map<String, Ref> filter(Map<String, Ref> refs) {
+			return new HashMap<>();
+		}
+	}
 }
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/WalkEncryptionTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/WalkEncryptionTest.java
index 1b434d3..33e2529 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/WalkEncryptionTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/WalkEncryptionTest.java
@@ -43,7 +43,7 @@
 
 package org.eclipse.jgit.transport;
 
-import static org.eclipse.jgit.transport.WalkEncryptionTest.Util.UTF_8;
+import static org.eclipse.jgit.lib.Constants.CHARSET;
 import static org.eclipse.jgit.transport.WalkEncryptionTest.Util.cryptoCipherListPBE;
 import static org.eclipse.jgit.transport.WalkEncryptionTest.Util.cryptoCipherListTrans;
 import static org.eclipse.jgit.transport.WalkEncryptionTest.Util.folderDelete;
@@ -77,7 +77,6 @@
 import java.net.URL;
 import java.net.URLConnection;
 import java.net.UnknownHostException;
-import java.nio.charset.Charset;
 import java.nio.file.Files;
 import java.security.GeneralSecurityException;
 import java.security.Provider;
@@ -353,8 +352,6 @@ static Properties discover() throws Exception {
 	 */
 	static class Util {
 
-		static final Charset UTF_8 = Charset.forName("UTF-8");
-
 		/**
 		 * Read UTF-8 encoded text file into string.
 		 *
@@ -363,7 +360,7 @@ static class Util {
 		 * @throws Exception
 		 */
 		static String textRead(File file) throws Exception {
-			return new String(Files.readAllBytes(file.toPath()), UTF_8);
+			return new String(Files.readAllBytes(file.toPath()), CHARSET);
 		}
 
 		/**
@@ -374,7 +371,7 @@ static String textRead(File file) throws Exception {
 		 * @throws Exception
 		 */
 		static void textWrite(File file, String text) throws Exception {
-			Files.write(file.toPath(), text.getBytes(UTF_8));
+			Files.write(file.toPath(), text.getBytes(CHARSET));
 		}
 
 		static void verifyFileContent(File fileOne, File fileTwo)
@@ -422,12 +419,9 @@ static String publicAddress() throws Exception {
 				URLConnection c = url.openConnection();
 				c.setConnectTimeout(500);
 				c.setReadTimeout(500);
-				BufferedReader reader = new BufferedReader(
-						new InputStreamReader(c.getInputStream()));
-				try {
+				try (BufferedReader reader = new BufferedReader(
+						new InputStreamReader(c.getInputStream()))) {
 					return reader.readLine();
-				} finally {
-					reader.close();
 				}
 			} catch (UnknownHostException | SocketTimeoutException e) {
 				return "Can't reach http://checkip.amazonaws.com to"
@@ -657,9 +651,9 @@ static void configCreate(String algorithm) throws Exception {
 			Properties props = Props.discover();
 			props.put(AmazonS3.Keys.PASSWORD, JGIT_PASS);
 			props.put(AmazonS3.Keys.CRYPTO_ALG, algorithm);
-			PrintWriter writer = new PrintWriter(JGIT_CONF_FILE);
-			props.store(writer, "JGIT S3 connection configuration file.");
-			writer.close();
+			try (PrintWriter writer = new PrintWriter(JGIT_CONF_FILE)) {
+				props.store(writer, "JGIT S3 connection configuration file.");
+			}
 		}
 
 		/**
@@ -671,9 +665,9 @@ static void configCreate(String algorithm) throws Exception {
 		static void configCreate(Properties source) throws Exception {
 			Properties target = Props.discover();
 			target.putAll(source);
-			PrintWriter writer = new PrintWriter(JGIT_CONF_FILE);
-			target.store(writer, "JGIT S3 connection configuration file.");
-			writer.close();
+			try (PrintWriter writer = new PrintWriter(JGIT_CONF_FILE)) {
+				target.store(writer, "JGIT S3 connection configuration file.");
+			}
 		}
 
 		/**
@@ -744,7 +738,7 @@ static void remoteVerify() throws Exception {
 			AmazonS3 s3 = new AmazonS3(props);
 			String file = JGIT_USER + "-" + UUID.randomUUID().toString();
 			String path = JGIT_REMOTE_DIR + "/" + file;
-			s3.put(bucket, path, file.getBytes(UTF_8));
+			s3.put(bucket, path, file.getBytes(CHARSET));
 			s3.delete(bucket, path);
 		}
 
@@ -839,10 +833,10 @@ static void verifyCrypto(WalkEncryption crypto) throws IOException {
 			{
 				byte[] origin = sourceText.getBytes(charset);
 				ByteArrayOutputStream target = new ByteArrayOutputStream();
-				OutputStream source = crypto.encrypt(target);
-				source.write(origin);
-				source.flush();
-				source.close();
+				try (OutputStream source = crypto.encrypt(target)) {
+					source.write(origin);
+					source.flush();
+				}
 				cipherText = target.toByteArray();
 			}
 			{
@@ -1077,10 +1071,10 @@ void cryptoTest(Properties props) throws Exception {
 				remoteConfig.update(config);
 				config.save();
 
-				Git git = Git.open(dirOne);
-				git.checkout().setName("master").call();
-				git.push().setRemote(remote).setRefSpecs(specs).call();
-				git.close();
+				try (Git git = Git.open(dirOne)) {
+					git.checkout().setName("master").call();
+					git.push().setRemote(remote).setRefSpecs(specs).call();
+				}
 
 				File fileStatic = new File(dirOne, nameStatic);
 				assertTrue("Provided by setup", fileStatic.exists());
@@ -1092,11 +1086,11 @@ void cryptoTest(Properties props) throws Exception {
 				File fileStatic = new File(dirTwo, nameStatic);
 				assertFalse("Not Provided by setup", fileStatic.exists());
 
-				Git git = Git.cloneRepository().setURI(uri).setDirectory(dirTwo)
-						.call();
-				git.close();
+				try (Git git = Git.cloneRepository().setURI(uri)
+						.setDirectory(dirTwo).call()) {
+					assertTrue("Provided by clone", fileStatic.exists());
+				}
 
-				assertTrue("Provided by clone", fileStatic.exists());
 			}
 
 			{ // Verify static file content.
@@ -1114,11 +1108,11 @@ void cryptoTest(Properties props) throws Exception {
 				assertTrue("Provided by create", fileDynamic.exists());
 				assertTrue("Need content to encrypt", fileDynamic.length() > 0);
 
-				Git git = Git.open(dirOne);
-				git.add().addFilepattern(nameDynamic).call();
-				git.commit().setMessage(nameDynamic).call();
-				git.push().setRemote(remote).setRefSpecs(specs).call();
-				git.close();
+				try (Git git = Git.open(dirOne)) {
+					git.add().addFilepattern(nameDynamic).call();
+					git.commit().setMessage(nameDynamic).call();
+					git.push().setRemote(remote).setRefSpecs(specs).call();
+				}
 
 			}
 
@@ -1127,9 +1121,9 @@ void cryptoTest(Properties props) throws Exception {
 				File fileDynamic = new File(dirTwo, nameDynamic);
 				assertFalse("Not Provided by setup", fileDynamic.exists());
 
-				Git git = Git.open(dirTwo);
-				git.pull().call();
-				git.close();
+				try (Git git = Git.open(dirTwo)) {
+					git.pull().call();
+				}
 
 				assertTrue("Provided by pull", fileDynamic.exists());
 			}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/CanonicalTreeParserTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/CanonicalTreeParserTest.java
index f5e97c2..6195e64 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/CanonicalTreeParserTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/CanonicalTreeParserTest.java
@@ -91,9 +91,9 @@ public void setUp() throws Exception {
 				hash_sometree), entry(m644, "foo", hash_foo));
 	}
 
-	private static byte[] mktree(final byte[]... data) throws Exception {
+	private static byte[] mktree(byte[]... data) throws Exception {
 		final ByteArrayOutputStream out = new ByteArrayOutputStream();
-		for (final byte[] e : data)
+		for (byte[] e : data)
 			out.write(e);
 		return out.toByteArray();
 	}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/FileTreeIteratorTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/FileTreeIteratorTest.java
index e34cb97..0e009b9 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/FileTreeIteratorTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/FileTreeIteratorTest.java
@@ -821,7 +821,7 @@ private static void assertEntry(String sha1string, String path, TreeWalk tw)
 		assertEquals(sha1string, tw.getObjectId(1).getName() /* 1=filetree here */);
 	}
 
-	private static String nameOf(final AbstractTreeIterator i) {
+	private static String nameOf(AbstractTreeIterator i) {
 		return RawParseUtils.decode(Constants.CHARSET, i.path, 0, i.pathLen);
 	}
 }
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/FileTreeIteratorWithTimeControl.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/FileTreeIteratorWithTimeControl.java
index ff5730e..fc79d45 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/FileTreeIteratorWithTimeControl.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/FileTreeIteratorWithTimeControl.java
@@ -58,10 +58,10 @@
  * <p>
  * This iterator is configured by a list of strictly increasing long values
  * t(0), t(1), ..., t(n). For each file with a modification between t(x) and
- * t(x+1) [ t(x) <= time < t(x+1) ] this iterator will report t(x). For files
- * with a modification time smaller t(0) a modification time of 0 is returned.
- * For files with a modification time greater or equal t(n) t(n) will be
- * returned.
+ * t(x+1) [ t(x) &lt;= time &lt; t(x+1) ] this iterator will report t(x). For
+ * files with a modification time smaller t(0) a modification time of 0 is
+ * returned. For files with a modification time greater or equal t(n) t(n) will
+ * be returned.
  * <p>
  * This class was written especially to test racy-git problems
  */
@@ -93,7 +93,7 @@ public FileTreeIteratorWithTimeControl(File f, FS fs,
 	}
 
 	@Override
-	public AbstractTreeIterator createSubtreeIterator(final ObjectReader reader) {
+	public AbstractTreeIterator createSubtreeIterator(ObjectReader reader) {
 		return new FileTreeIteratorWithTimeControl(this,
 				((FileEntry) current()).getFile(), fs, modTimes);
 	}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/PostOrderTreeWalkTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/PostOrderTreeWalkTest.java
index 6ad47c2..232422e 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/PostOrderTreeWalkTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/PostOrderTreeWalkTest.java
@@ -60,14 +60,14 @@
 public class PostOrderTreeWalkTest extends RepositoryTestCase {
 	@Test
 	public void testInitialize_NoPostOrder() throws Exception {
-		try (final TreeWalk tw = new TreeWalk(db)) {
+		try (TreeWalk tw = new TreeWalk(db)) {
 			assertFalse(tw.isPostOrderTraversal());
 		}
 	}
 
 	@Test
 	public void testInitialize_TogglePostOrder() throws Exception {
-		try (final TreeWalk tw = new TreeWalk(db)) {
+		try (TreeWalk tw = new TreeWalk(db)) {
 			assertFalse(tw.isPostOrderTraversal());
 			tw.setPostOrderTraversal(true);
 			assertTrue(tw.isPostOrderTraversal());
@@ -78,7 +78,7 @@ public void testInitialize_TogglePostOrder() throws Exception {
 
 	@Test
 	public void testResetDoesNotAffectPostOrder() throws Exception {
-		try (final TreeWalk tw = new TreeWalk(db)) {
+		try (TreeWalk tw = new TreeWalk(db)) {
 			tw.setPostOrderTraversal(true);
 			assertTrue(tw.isPostOrderTraversal());
 			tw.reset();
@@ -104,7 +104,7 @@ public void testNoPostOrder() throws Exception {
 		b.finish();
 		assertEquals(4, tree.getEntryCount());
 
-		try (final TreeWalk tw = new TreeWalk(db)) {
+		try (TreeWalk tw = new TreeWalk(db)) {
 			tw.setPostOrderTraversal(false);
 			tw.addTree(new DirCacheIterator(tree));
 
@@ -132,7 +132,7 @@ public void testWithPostOrder_EnterSubtree() throws Exception {
 		b.finish();
 		assertEquals(4, tree.getEntryCount());
 
-		try (final TreeWalk tw = new TreeWalk(db)) {
+		try (TreeWalk tw = new TreeWalk(db)) {
 			tw.setPostOrderTraversal(true);
 			tw.addTree(new DirCacheIterator(tree));
 
@@ -166,7 +166,7 @@ public void testWithPostOrder_NoEnterSubtree() throws Exception {
 		b.finish();
 		assertEquals(4, tree.getEntryCount());
 
-		try (final TreeWalk tw = new TreeWalk(db)) {
+		try (TreeWalk tw = new TreeWalk(db)) {
 			tw.setPostOrderTraversal(true);
 			tw.addTree(new DirCacheIterator(tree));
 
@@ -180,7 +180,7 @@ public void testWithPostOrder_NoEnterSubtree() throws Exception {
 		}
 	}
 
-	private DirCacheEntry makeFile(final String path) throws Exception {
+	private DirCacheEntry makeFile(String path) throws Exception {
 		return createEntry(path, REGULAR_FILE);
 	}
 
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/filter/AlwaysCloneTreeFilter.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/filter/AlwaysCloneTreeFilter.java
index 8e2cca4..d9cfb62 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/filter/AlwaysCloneTreeFilter.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/filter/AlwaysCloneTreeFilter.java
@@ -52,7 +52,7 @@ public TreeFilter clone() {
 	}
 
 	@Override
-	public boolean include(final TreeWalk walker) {
+	public boolean include(TreeWalk walker) {
 		return false;
 	}
 
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/filter/NotTreeFilterTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/filter/NotTreeFilterTest.java
index f7a7fb8..c6389fb 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/filter/NotTreeFilterTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/filter/NotTreeFilterTest.java
@@ -57,12 +57,13 @@
 public class NotTreeFilterTest extends RepositoryTestCase {
 	@Test
 	public void testWrap() throws Exception {
-		final TreeWalk tw = new TreeWalk(db);
-		final TreeFilter a = TreeFilter.ALL;
-		final TreeFilter n = NotTreeFilter.create(a);
-		assertNotNull(n);
-		assertTrue(a.include(tw));
-		assertFalse(n.include(tw));
+		try (TreeWalk tw = new TreeWalk(db)) {
+			final TreeFilter a = TreeFilter.ALL;
+			final TreeFilter n = NotTreeFilter.create(a);
+			assertNotNull(n);
+			assertTrue(a.include(tw));
+			assertFalse(n.include(tw));
+		}
 	}
 
 	@Test
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/filter/PathFilterGroupTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/filter/PathFilterGroupTest.java
index d921aab..71a2f32 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/filter/PathFilterGroupTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/filter/PathFilterGroupTest.java
@@ -254,7 +254,7 @@ private static boolean includes(TreeFilter f, TreeWalk tw)
 		}
 	}
 
-	TreeWalk fakeWalk(final String path) throws IOException {
+	TreeWalk fakeWalk(String path) throws IOException {
 		DirCache dc = DirCache.newInCore();
 		DirCacheEditor dce = dc.editor();
 		dce.add(new DirCacheEditor.PathEdit(path) {
@@ -274,7 +274,7 @@ public void apply(DirCacheEntry ent) {
 		return ret;
 	}
 
-	TreeWalk fakeWalkAtSubtree(final String path) throws IOException {
+	TreeWalk fakeWalkAtSubtree(String path) throws IOException {
 		DirCache dc = DirCache.newInCore();
 		DirCacheEditor dce = dc.editor();
 		dce.add(new DirCacheEditor.PathEdit(path + "/README") {
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/filter/PathSuffixFilterTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/filter/PathSuffixFilterTest.java
index 38adda3..148d5ac 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/filter/PathSuffixFilterTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/filter/PathSuffixFilterTest.java
@@ -113,7 +113,7 @@ private List<String> getMatchingPaths(String suffixFilter,
 
 	private List<String> getMatchingPaths(String suffixFilter,
 			final ObjectId treeId, boolean recursiveWalk) throws IOException {
-		try (final TreeWalk tw = new TreeWalk(db)) {
+		try (TreeWalk tw = new TreeWalk(db)) {
 			tw.setFilter(PathSuffixFilter.create(suffixFilter));
 			tw.setRecursive(recursiveWalk);
 			tw.addTree(treeId);
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/filter/TreeFilterTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/filter/TreeFilterTest.java
index c3423b6..8686c4f 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/filter/TreeFilterTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/filter/TreeFilterTest.java
@@ -55,7 +55,7 @@
 public class TreeFilterTest extends RepositoryTestCase {
 	@Test
 	public void testALL_IncludesAnything() throws Exception {
-		try (final TreeWalk tw = new TreeWalk(db)) {
+		try (TreeWalk tw = new TreeWalk(db)) {
 			tw.addTree(new EmptyTreeIterator());
 			assertTrue(TreeFilter.ALL.include(tw));
 		}
@@ -73,7 +73,7 @@ public void testALL_IdentityClone() throws Exception {
 
 	@Test
 	public void testNotALL_IncludesNothing() throws Exception {
-		try (final TreeWalk tw = new TreeWalk(db)) {
+		try (TreeWalk tw = new TreeWalk(db)) {
 			tw.addTree(new EmptyTreeIterator());
 			assertFalse(TreeFilter.ALL.negate().include(tw));
 		}
@@ -81,7 +81,7 @@ public void testNotALL_IncludesNothing() throws Exception {
 
 	@Test
 	public void testANY_DIFF_IncludesSingleTreeCase() throws Exception {
-		try (final TreeWalk tw = new TreeWalk(db)) {
+		try (TreeWalk tw = new TreeWalk(db)) {
 			tw.addTree(new EmptyTreeIterator());
 			assertTrue(TreeFilter.ANY_DIFF.include(tw));
 		}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/ChangeIdUtilTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/ChangeIdUtilTest.java
index 6fed233..81467c2 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/ChangeIdUtilTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/ChangeIdUtilTest.java
@@ -680,15 +680,15 @@ public void testIndexOfChangeId() {
 				"\n"));
 	}
 
-	private void hookDoesNotModify(final String in) throws Exception {
+	private void hookDoesNotModify(String in) throws Exception {
 		assertEquals(in, call(in));
 	}
 
-	private String call(final String body) throws Exception {
+	private String call(String body) throws Exception {
 		return call(body, false);
 	}
 
-	private String call(final String body, boolean replaceExisting) throws Exception {
+	private String call(String body, boolean replaceExisting) throws Exception {
 		ObjectId computeChangeId = ChangeIdUtil.computeChangeId(treeId1,
 				parentId1, author, committer, body);
 		if (computeChangeId == null)
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/HookTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/HookTest.java
index a680ef9..e34c3ce 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/HookTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/HookTest.java
@@ -241,7 +241,7 @@ public void testFailedPreCommitHookBlockCommit() throws Exception {
 		}
 	}
 
-	private File writeHookFile(final String name, final String data)
+	private File writeHookFile(String name, String data)
 			throws IOException {
 		File path = new File(db.getWorkTree() + "/.git/hooks/", name);
 		JGitTestUtil.write(path, data);
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/NBTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/NBTest.java
index d2d44ff..830f20e 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/NBTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/NBTest.java
@@ -338,7 +338,7 @@ public void testEncodeInt64() {
 		assertOutput(b(0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff), out, 3);
 	}
 
-	private static void prepareOutput(final byte[] buf) {
+	private static void prepareOutput(byte[] buf) {
 		for (int i = 0; i < buf.length; i++)
 			buf[i] = (byte) (0x77 + i);
 	}
@@ -353,11 +353,11 @@ private static void assertOutput(final byte[] expect, final byte[] buf,
 			assertEquals((byte) (0x77 + i), buf[i]);
 	}
 
-	private static byte[] b(final int a, final int b) {
+	private static byte[] b(int a, int b) {
 		return new byte[] { (byte) a, (byte) b };
 	}
 
-	private static byte[] padb(final int len, final int a, final int b) {
+	private static byte[] padb(int len, int a, int b) {
 		final byte[] r = new byte[len + 2];
 		for (int i = 0; i < len; i++)
 			r[i] = (byte) 0xaf;
@@ -370,7 +370,7 @@ private static void assertOutput(final byte[] expect, final byte[] buf,
 		return new byte[] { (byte) a, (byte) b, (byte) c };
 	}
 
-	private static byte[] b(final int a, final int b, final int c, final int d) {
+	private static byte[] b(int a, int b, int c, int d) {
 		return new byte[] { (byte) a, (byte) b, (byte) c, (byte) d };
 	}
 
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/QuotedStringBourneStyleTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/QuotedStringBourneStyleTest.java
index 6507876..49ad55f 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/QuotedStringBourneStyleTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/QuotedStringBourneStyleTest.java
@@ -52,14 +52,14 @@
 import org.junit.Test;
 
 public class QuotedStringBourneStyleTest {
-	private static void assertQuote(final String in, final String exp) {
+	private static void assertQuote(String in, String exp) {
 		final String r = BOURNE.quote(in);
 		assertNotSame(in, r);
 		assertFalse(in.equals(r));
 		assertEquals('\'' + exp + '\'', r);
 	}
 
-	private static void assertDequote(final String exp, final String in) {
+	private static void assertDequote(String exp, String in) {
 		final byte[] b = Constants.encode('\'' + in + '\'');
 		final String r = BOURNE.dequote(b, 0, b.length);
 		assertEquals(exp, r);
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/QuotedStringBourneUserPathStyleTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/QuotedStringBourneUserPathStyleTest.java
index 7463528..17f1b77 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/QuotedStringBourneUserPathStyleTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/QuotedStringBourneUserPathStyleTest.java
@@ -52,14 +52,14 @@
 import org.junit.Test;
 
 public class QuotedStringBourneUserPathStyleTest {
-	private static void assertQuote(final String in, final String exp) {
+	private static void assertQuote(String in, String exp) {
 		final String r = BOURNE_USER_PATH.quote(in);
 		assertNotSame(in, r);
 		assertFalse(in.equals(r));
 		assertEquals('\'' + exp + '\'', r);
 	}
 
-	private static void assertDequote(final String exp, final String in) {
+	private static void assertDequote(String exp, String in) {
 		final byte[] b = Constants.encode('\'' + in + '\'');
 		final String r = BOURNE_USER_PATH.dequote(b, 0, b.length);
 		assertEquals(exp, r);
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/QuotedStringGitPathStyleTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/QuotedStringGitPathStyleTest.java
index cc73c70..9a0c96e 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/QuotedStringGitPathStyleTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/QuotedStringGitPathStyleTest.java
@@ -43,32 +43,26 @@
 
 package org.eclipse.jgit.util;
 
+import static java.nio.charset.StandardCharsets.ISO_8859_1;
 import static org.eclipse.jgit.util.QuotedString.GIT_PATH;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotSame;
 import static org.junit.Assert.assertSame;
 
-import java.io.UnsupportedEncodingException;
-
 import org.eclipse.jgit.lib.Constants;
 import org.junit.Test;
 
 public class QuotedStringGitPathStyleTest {
-	private static void assertQuote(final String exp, final String in) {
+	private static void assertQuote(String exp, String in) {
 		final String r = GIT_PATH.quote(in);
 		assertNotSame(in, r);
 		assertFalse(in.equals(r));
 		assertEquals('"' + exp + '"', r);
 	}
 
-	private static void assertDequote(final String exp, final String in) {
-		final byte[] b;
-		try {
-			b = ('"' + in + '"').getBytes("ISO-8859-1");
-		} catch (UnsupportedEncodingException e) {
-			throw new RuntimeException(e);
-		}
+	private static void assertDequote(String exp, String in) {
+		final byte[] b = ('"' + in + '"').getBytes(ISO_8859_1);
 		final String r = GIT_PATH.dequote(b, 0, b.length);
 		assertEquals(exp, r);
 	}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/RawCharUtilTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/RawCharUtilTest.java
index a8c5763..f1b3da2 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/RawCharUtilTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/RawCharUtilTest.java
@@ -43,6 +43,7 @@
 
 package org.eclipse.jgit.util;
 
+import static java.nio.charset.StandardCharsets.US_ASCII;
 import static org.eclipse.jgit.util.RawCharUtil.isWhitespace;
 import static org.eclipse.jgit.util.RawCharUtil.trimLeadingWhitespace;
 import static org.eclipse.jgit.util.RawCharUtil.trimTrailingWhitespace;
@@ -50,8 +51,6 @@
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 
-import java.io.UnsupportedEncodingException;
-
 import org.junit.Test;
 
 public class RawCharUtilTest {
@@ -78,37 +77,31 @@ public void testIsWhitespace() {
 	/**
 	 * Test method for
 	 * {@link RawCharUtil#trimTrailingWhitespace(byte[], int, int)}.
-	 *
-	 * @throws UnsupportedEncodingException
 	 */
 	@Test
-	public void testTrimTrailingWhitespace()
-			throws UnsupportedEncodingException {
-		assertEquals(0, trimTrailingWhitespace("".getBytes("US-ASCII"), 0, 0));
-		assertEquals(0, trimTrailingWhitespace(" ".getBytes("US-ASCII"), 0, 1));
-		assertEquals(1, trimTrailingWhitespace("a ".getBytes("US-ASCII"), 0, 2));
-		assertEquals(2,
-				trimTrailingWhitespace(" a ".getBytes("US-ASCII"), 0, 3));
-		assertEquals(3,
-				trimTrailingWhitespace("  a".getBytes("US-ASCII"), 0, 3));
-		assertEquals(6, trimTrailingWhitespace(
-				"  test   ".getBytes("US-ASCII"), 2, 9));
+	public void testTrimTrailingWhitespace() {
+		assertEquals(0, trimTrailingWhitespace("".getBytes(US_ASCII), 0, 0));
+		assertEquals(0, trimTrailingWhitespace(" ".getBytes(US_ASCII), 0, 1));
+		assertEquals(1, trimTrailingWhitespace("a ".getBytes(US_ASCII), 0, 2));
+		assertEquals(2, trimTrailingWhitespace(" a ".getBytes(US_ASCII), 0, 3));
+		assertEquals(3, trimTrailingWhitespace("  a".getBytes(US_ASCII), 0, 3));
+		assertEquals(6,
+				trimTrailingWhitespace("  test   ".getBytes(US_ASCII), 2, 9));
 	}
 
 	/**
 	 * Test method for
 	 * {@link RawCharUtil#trimLeadingWhitespace(byte[], int, int)}.
-	 *
-	 * @throws UnsupportedEncodingException
 	 */
 	@Test
-	public void testTrimLeadingWhitespace() throws UnsupportedEncodingException {
-		assertEquals(0, trimLeadingWhitespace("".getBytes("US-ASCII"), 0, 0));
-		assertEquals(1, trimLeadingWhitespace(" ".getBytes("US-ASCII"), 0, 1));
-		assertEquals(0, trimLeadingWhitespace("a ".getBytes("US-ASCII"), 0, 2));
-		assertEquals(1, trimLeadingWhitespace(" a ".getBytes("US-ASCII"), 0, 3));
-		assertEquals(2, trimLeadingWhitespace("  a".getBytes("US-ASCII"), 0, 3));
-		assertEquals(2, trimLeadingWhitespace("  test   ".getBytes("US-ASCII"),
+	public void testTrimLeadingWhitespace() {
+		assertEquals(0, trimLeadingWhitespace("".getBytes(US_ASCII), 0, 0));
+		assertEquals(1, trimLeadingWhitespace(" ".getBytes(US_ASCII), 0, 1));
+		assertEquals(0, trimLeadingWhitespace("a ".getBytes(US_ASCII), 0, 2));
+		assertEquals(1, trimLeadingWhitespace(" a ".getBytes(US_ASCII), 0, 3));
+		assertEquals(2, trimLeadingWhitespace("  a".getBytes(US_ASCII), 0, 3));
+		assertEquals(2,
+				trimLeadingWhitespace("  test   ".getBytes(US_ASCII),
 				2, 9));
 	}
 
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/RawParseUtils_HexParseTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/RawParseUtils_HexParseTest.java
index f5b56e7..f3c046d 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/RawParseUtils_HexParseTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/RawParseUtils_HexParseTest.java
@@ -81,7 +81,7 @@ public void testInt4_1() {
 		assertNotHex('.');
 	}
 
-	private static void assertNotHex(final char c) {
+	private static void assertNotHex(char c) {
 		try {
 			RawParseUtils.parseHexInt4((byte) c);
 			fail("Incorrectly acccepted " + c);
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/RawParseUtils_LineMapTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/RawParseUtils_LineMapTest.java
index 6efdce6..7630c11 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/RawParseUtils_LineMapTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/RawParseUtils_LineMapTest.java
@@ -43,51 +43,64 @@
 
 package org.eclipse.jgit.util;
 
+import static java.nio.charset.StandardCharsets.ISO_8859_1;
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertNotNull;
 
-import java.io.UnsupportedEncodingException;
-
+import org.eclipse.jgit.errors.BinaryBlobException;
+import org.junit.Rule;
 import org.junit.Test;
+import org.junit.rules.ExpectedException;
 
 public class RawParseUtils_LineMapTest {
+	@Rule
+	public ExpectedException exception = ExpectedException.none();
+
+
 	@Test
-	public void testEmpty() {
+	public void testEmpty() throws Exception {
 		final IntList map = RawParseUtils.lineMap(new byte[] {}, 0, 0);
 		assertNotNull(map);
 		assertArrayEquals(new int[]{Integer.MIN_VALUE, 0}, asInts(map));
 	}
 
 	@Test
-	public void testOneBlankLine() {
+	public void testOneBlankLine() throws Exception  {
 		final IntList map = RawParseUtils.lineMap(new byte[] { '\n' }, 0, 1);
 		assertArrayEquals(new int[]{Integer.MIN_VALUE, 0, 1}, asInts(map));
 	}
 
 	@Test
-	public void testTwoLineFooBar() throws UnsupportedEncodingException {
-		final byte[] buf = "foo\nbar\n".getBytes("ISO-8859-1");
+	public void testTwoLineFooBar() {
+		final byte[] buf = "foo\nbar\n".getBytes(ISO_8859_1);
 		final IntList map = RawParseUtils.lineMap(buf, 0, buf.length);
 		assertArrayEquals(new int[]{Integer.MIN_VALUE, 0, 4, buf.length}, asInts(map));
 	}
 
 	@Test
-	public void testTwoLineNoLF() throws UnsupportedEncodingException {
-		final byte[] buf = "foo\nbar".getBytes("ISO-8859-1");
+	public void testTwoLineNoLF() {
+		final byte[] buf = "foo\nbar".getBytes(ISO_8859_1);
 		final IntList map = RawParseUtils.lineMap(buf, 0, buf.length);
 		assertArrayEquals(new int[]{Integer.MIN_VALUE, 0, 4, buf.length}, asInts(map));
 	}
 
 	@Test
-	public void testBinary() throws UnsupportedEncodingException {
-		final byte[] buf = "xxxfoo\nb\0ar".getBytes("ISO-8859-1");
+	public void testBinary() {
+		final byte[] buf = "xxxfoo\nb\0ar".getBytes(ISO_8859_1);
 		final IntList map = RawParseUtils.lineMap(buf, 3, buf.length);
 		assertArrayEquals(new int[]{Integer.MIN_VALUE, 3, buf.length}, asInts(map));
 	}
 
 	@Test
-	public void testFourLineBlanks() throws UnsupportedEncodingException {
-		final byte[] buf = "foo\n\n\nbar\n".getBytes("ISO-8859-1");
+	public void testLineMapOrBinary() throws Exception {
+		final byte[] buf = "xxxfoo\nb\0ar".getBytes(ISO_8859_1);
+		exception.expect(BinaryBlobException.class);
+		RawParseUtils.lineMapOrBinary(buf, 3, buf.length);
+	}
+
+	@Test
+	public void testFourLineBlanks() {
+		final byte[] buf = "foo\n\n\nbar\n".getBytes(ISO_8859_1);
 		final IntList map = RawParseUtils.lineMap(buf, 0, buf.length);
 
 		assertArrayEquals(new int[]{
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/RawSubStringPatternTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/RawSubStringPatternTest.java
index 194fab4..a748b52 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/RawSubStringPatternTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/RawSubStringPatternTest.java
@@ -42,11 +42,10 @@
  */
 package org.eclipse.jgit.util;
 
+import static org.eclipse.jgit.lib.Constants.CHARSET;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 
-import java.io.UnsupportedEncodingException;
-
 import org.eclipse.jgit.junit.RepositoryTestCase;
 import org.junit.Test;
 
@@ -94,11 +93,7 @@ private static void assertMatchResult(String pattern, String input, int position
 	}
 
 	private static RawCharSequence raw(String text) {
-		try {
-			byte[] bytes = text.getBytes("UTF-8");
-			return new RawCharSequence(bytes, 0, bytes.length);
-		} catch (UnsupportedEncodingException e) {
-			throw new RuntimeException(e);
-		}
+		byte[] bytes = text.getBytes(CHARSET);
+		return new RawCharSequence(bytes, 0, bytes.length);
 	}
 }
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/RefListTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/RefListTest.java
index 5a1468a..d124d73 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/RefListTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/RefListTest.java
@@ -456,7 +456,7 @@ private static RefList<Ref> toList(Ref... refs) {
 		return b.toRefList();
 	}
 
-	private static Ref newRef(final String name) {
+	private static Ref newRef(String name) {
 		return new ObjectIdRef.Unpeeled(Ref.Storage.LOOSE, name, ID);
 	}
 }
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/TemporaryBufferTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/TemporaryBufferTest.java
index d978804..edcce12 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/TemporaryBufferTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/TemporaryBufferTest.java
@@ -61,6 +61,7 @@
 public class TemporaryBufferTest {
 	@Test
 	public void testEmpty() throws IOException {
+		@SuppressWarnings("resource") // Buffer is explicitly destroyed in finally block
 		final TemporaryBuffer b = new TemporaryBuffer.LocalFile(null);
 		try {
 			b.close();
@@ -75,6 +76,7 @@ public void testEmpty() throws IOException {
 
 	@Test
 	public void testOneByte() throws IOException {
+		@SuppressWarnings("resource") // Buffer is explicitly destroyed in finally block
 		final TemporaryBuffer b = new TemporaryBuffer.LocalFile(null);
 		final byte test = (byte) new TestRng(getName()).nextInt();
 		try {
@@ -87,10 +89,8 @@ public void testOneByte() throws IOException {
 				assertEquals(1, r.length);
 				assertEquals(test, r[0]);
 			}
-			{
-				final ByteArrayOutputStream o = new ByteArrayOutputStream();
+			try (ByteArrayOutputStream o = new ByteArrayOutputStream()) {
 				b.writeTo(o, null);
-				o.close();
 				final byte[] r = o.toByteArray();
 				assertEquals(1, r.length);
 				assertEquals(test, r[0]);
@@ -102,6 +102,7 @@ public void testOneByte() throws IOException {
 
 	@Test
 	public void testOneBlock_BulkWrite() throws IOException {
+		@SuppressWarnings("resource") // Buffer is explicitly destroyed in finally block
 		final TemporaryBuffer b = new TemporaryBuffer.LocalFile(null);
 		final byte[] test = new TestRng(getName())
 				.nextBytes(TemporaryBuffer.Block.SZ);
@@ -118,10 +119,8 @@ public void testOneBlock_BulkWrite() throws IOException {
 				assertEquals(test.length, r.length);
 				assertArrayEquals(test, r);
 			}
-			{
-				final ByteArrayOutputStream o = new ByteArrayOutputStream();
+			try (ByteArrayOutputStream o = new ByteArrayOutputStream()) {
 				b.writeTo(o, null);
-				o.close();
 				final byte[] r = o.toByteArray();
 				assertEquals(test.length, r.length);
 				assertArrayEquals(test, r);
@@ -133,6 +132,7 @@ public void testOneBlock_BulkWrite() throws IOException {
 
 	@Test
 	public void testOneBlockAndHalf_BulkWrite() throws IOException {
+		@SuppressWarnings("resource") // Buffer is explicitly destroyed in finally block
 		final TemporaryBuffer b = new TemporaryBuffer.LocalFile(null);
 		final byte[] test = new TestRng(getName())
 				.nextBytes(TemporaryBuffer.Block.SZ * 3 / 2);
@@ -149,10 +149,8 @@ public void testOneBlockAndHalf_BulkWrite() throws IOException {
 				assertEquals(test.length, r.length);
 				assertArrayEquals(test, r);
 			}
-			{
-				final ByteArrayOutputStream o = new ByteArrayOutputStream();
+			try (ByteArrayOutputStream o = new ByteArrayOutputStream()) {
 				b.writeTo(o, null);
-				o.close();
 				final byte[] r = o.toByteArray();
 				assertEquals(test.length, r.length);
 				assertArrayEquals(test, r);
@@ -164,6 +162,7 @@ public void testOneBlockAndHalf_BulkWrite() throws IOException {
 
 	@Test
 	public void testOneBlockAndHalf_SingleWrite() throws IOException {
+		@SuppressWarnings("resource") // Buffer is explicitly destroyed in finally block
 		final TemporaryBuffer b = new TemporaryBuffer.LocalFile(null);
 		final byte[] test = new TestRng(getName())
 				.nextBytes(TemporaryBuffer.Block.SZ * 3 / 2);
@@ -178,10 +177,8 @@ public void testOneBlockAndHalf_SingleWrite() throws IOException {
 				assertEquals(test.length, r.length);
 				assertArrayEquals(test, r);
 			}
-			{
-				final ByteArrayOutputStream o = new ByteArrayOutputStream();
+			try (ByteArrayOutputStream o = new ByteArrayOutputStream()) {
 				b.writeTo(o, null);
-				o.close();
 				final byte[] r = o.toByteArray();
 				assertEquals(test.length, r.length);
 				assertArrayEquals(test, r);
@@ -193,6 +190,7 @@ public void testOneBlockAndHalf_SingleWrite() throws IOException {
 
 	@Test
 	public void testOneBlockAndHalf_Copy() throws IOException {
+		@SuppressWarnings("resource") // Buffer is explicitly destroyed in finally block
 		final TemporaryBuffer b = new TemporaryBuffer.LocalFile(null);
 		final byte[] test = new TestRng(getName())
 				.nextBytes(TemporaryBuffer.Block.SZ * 3 / 2);
@@ -208,10 +206,8 @@ public void testOneBlockAndHalf_Copy() throws IOException {
 				assertEquals(test.length, r.length);
 				assertArrayEquals(test, r);
 			}
-			{
-				final ByteArrayOutputStream o = new ByteArrayOutputStream();
+			try (ByteArrayOutputStream o = new ByteArrayOutputStream()) {
 				b.writeTo(o, null);
-				o.close();
 				final byte[] r = o.toByteArray();
 				assertEquals(test.length, r.length);
 				assertArrayEquals(test, r);
@@ -223,6 +219,7 @@ public void testOneBlockAndHalf_Copy() throws IOException {
 
 	@Test
 	public void testLarge_SingleWrite() throws IOException {
+		@SuppressWarnings("resource") // Buffer is explicitly destroyed in finally block
 		final TemporaryBuffer b = new TemporaryBuffer.LocalFile(null);
 		final byte[] test = new TestRng(getName())
 				.nextBytes(TemporaryBuffer.DEFAULT_IN_CORE_LIMIT * 3);
@@ -236,10 +233,8 @@ public void testLarge_SingleWrite() throws IOException {
 				assertEquals(test.length, r.length);
 				assertArrayEquals(test, r);
 			}
-			{
-				final ByteArrayOutputStream o = new ByteArrayOutputStream();
+			try (ByteArrayOutputStream o = new ByteArrayOutputStream()) {
 				b.writeTo(o, null);
-				o.close();
 				final byte[] r = o.toByteArray();
 				assertEquals(test.length, r.length);
 				assertArrayEquals(test, r);
@@ -253,18 +248,18 @@ public void testLarge_SingleWrite() throws IOException {
 	public void testInCoreInputStream() throws IOException {
 		final int cnt = 256;
 		final byte[] test = new TestRng(getName()).nextBytes(cnt);
-		final TemporaryBuffer.Heap b = new TemporaryBuffer.Heap(cnt + 4);
-		b.write(test);
-		b.close();
-
-		InputStream in = b.openInputStream();
-		byte[] act = new byte[cnt];
-		IO.readFully(in, act, 0, cnt);
-		assertArrayEquals(test, act);
+		try (TemporaryBuffer.Heap b = new TemporaryBuffer.Heap(cnt + 4)) {
+			b.write(test);
+			InputStream in = b.openInputStream();
+			byte[] act = new byte[cnt];
+			IO.readFully(in, act, 0, cnt);
+			assertArrayEquals(test, act);
+		}
 	}
 
 	@Test
 	public void testInCoreLimit_SwitchOnAppendByte() throws IOException {
+		@SuppressWarnings("resource") // Buffer is explicitly destroyed in finally block
 		final TemporaryBuffer b = new TemporaryBuffer.LocalFile(null);
 		final byte[] test = new TestRng(getName())
 				.nextBytes(TemporaryBuffer.DEFAULT_IN_CORE_LIMIT + 1);
@@ -279,10 +274,8 @@ public void testInCoreLimit_SwitchOnAppendByte() throws IOException {
 				assertEquals(test.length, r.length);
 				assertArrayEquals(test, r);
 			}
-			{
-				final ByteArrayOutputStream o = new ByteArrayOutputStream();
+			try (ByteArrayOutputStream o = new ByteArrayOutputStream()) {
 				b.writeTo(o, null);
-				o.close();
 				final byte[] r = o.toByteArray();
 				assertEquals(test.length, r.length);
 				assertArrayEquals(test, r);
@@ -294,6 +287,7 @@ public void testInCoreLimit_SwitchOnAppendByte() throws IOException {
 
 	@Test
 	public void testInCoreLimit_SwitchBeforeAppendByte() throws IOException {
+		@SuppressWarnings("resource") // Buffer is explicitly destroyed in finally block
 		final TemporaryBuffer b = new TemporaryBuffer.LocalFile(null);
 		final byte[] test = new TestRng(getName())
 				.nextBytes(TemporaryBuffer.DEFAULT_IN_CORE_LIMIT * 3);
@@ -308,10 +302,8 @@ public void testInCoreLimit_SwitchBeforeAppendByte() throws IOException {
 				assertEquals(test.length, r.length);
 				assertArrayEquals(test, r);
 			}
-			{
-				final ByteArrayOutputStream o = new ByteArrayOutputStream();
+			try (ByteArrayOutputStream o = new ByteArrayOutputStream()) {
 				b.writeTo(o, null);
-				o.close();
 				final byte[] r = o.toByteArray();
 				assertEquals(test.length, r.length);
 				assertArrayEquals(test, r);
@@ -323,6 +315,7 @@ public void testInCoreLimit_SwitchBeforeAppendByte() throws IOException {
 
 	@Test
 	public void testInCoreLimit_SwitchOnCopy() throws IOException {
+		@SuppressWarnings("resource") // Buffer is explicitly destroyed in finally block
 		final TemporaryBuffer b = new TemporaryBuffer.LocalFile(null);
 		final byte[] test = new TestRng(getName())
 				.nextBytes(TemporaryBuffer.DEFAULT_IN_CORE_LIMIT * 2);
@@ -340,10 +333,8 @@ public void testInCoreLimit_SwitchOnCopy() throws IOException {
 				assertEquals(test.length, r.length);
 				assertArrayEquals(test, r);
 			}
-			{
-				final ByteArrayOutputStream o = new ByteArrayOutputStream();
+			try (ByteArrayOutputStream o = new ByteArrayOutputStream()) {
 				b.writeTo(o, null);
-				o.close();
 				final byte[] r = o.toByteArray();
 				assertEquals(test.length, r.length);
 				assertArrayEquals(test, r);
@@ -355,7 +346,7 @@ public void testInCoreLimit_SwitchOnCopy() throws IOException {
 
 	@Test
 	public void testDestroyWhileOpen() throws IOException {
-		@SuppressWarnings("resource" /* java 7 */)
+		@SuppressWarnings("resource") // Buffer is explicitly destroyed in finally block
 		final TemporaryBuffer b = new TemporaryBuffer.LocalFile(null);
 		try {
 			b.write(new TestRng(getName())
@@ -367,6 +358,7 @@ public void testDestroyWhileOpen() throws IOException {
 
 	@Test
 	public void testRandomWrites() throws IOException {
+		@SuppressWarnings("resource") // Buffer is explicitly destroyed in finally block
 		final TemporaryBuffer b = new TemporaryBuffer.LocalFile(null);
 		final TestRng rng = new TestRng(getName());
 		final int max = TemporaryBuffer.DEFAULT_IN_CORE_LIMIT * 2;
@@ -399,10 +391,8 @@ public void testRandomWrites() throws IOException {
 				assertEquals(expect.length, r.length);
 				assertArrayEquals(expect, r);
 			}
-			{
-				final ByteArrayOutputStream o = new ByteArrayOutputStream();
+			try (ByteArrayOutputStream o = new ByteArrayOutputStream()) {
 				b.writeTo(o, null);
-				o.close();
 				final byte[] r = o.toByteArray();
 				assertEquals(expect.length, r.length);
 				assertArrayEquals(expect, r);
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/io/AutoCRLFInputStreamTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/io/AutoCRLFInputStreamTest.java
index 83a53b9..1272e16 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/io/AutoCRLFInputStreamTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/io/AutoCRLFInputStreamTest.java
@@ -93,25 +93,24 @@ private void assertNoCrLfHelper(String expect, String input)
 		byte[] expectBytes = expect.getBytes();
 		for (int i = 0; i < 5; ++i) {
 			byte[] buf = new byte[i];
-			ByteArrayInputStream bis = new ByteArrayInputStream(inbytes);
-			InputStream in = new AutoCRLFInputStream(bis, true);
-			ByteArrayOutputStream out = new ByteArrayOutputStream();
-			if (i > 0) {
-				int n;
-				while ((n = in.read(buf)) >= 0) {
-					out.write(buf, 0, n);
+			try (ByteArrayInputStream bis = new ByteArrayInputStream(inbytes);
+					InputStream in = new AutoCRLFInputStream(bis, true);
+					ByteArrayOutputStream out = new ByteArrayOutputStream()) {
+				if (i > 0) {
+					int n;
+					while ((n = in.read(buf)) >= 0) {
+						out.write(buf, 0, n);
+					}
+				} else {
+					int c;
+					while ((c = in.read()) != -1)
+						out.write(c);
 				}
-			} else {
-				int c;
-				while ((c = in.read()) != -1)
-					out.write(c);
+				out.flush();
+				byte[] actualBytes = out.toByteArray();
+				Assert.assertEquals("bufsize=" + i, encode(expectBytes),
+						encode(actualBytes));
 			}
-			out.flush();
-			in.close();
-			out.close();
-			byte[] actualBytes = out.toByteArray();
-			Assert.assertEquals("bufsize=" + i, encode(expectBytes),
-					encode(actualBytes));
 		}
 	}
 
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/io/AutoCRLFOutputStreamTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/io/AutoCRLFOutputStreamTest.java
index a72d33c..0655827 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/io/AutoCRLFOutputStreamTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/io/AutoCRLFOutputStreamTest.java
@@ -96,32 +96,31 @@ private void assertNoCrLfHelper(String expect, String input)
 		for (int i = -4; i < 5; ++i) {
 			int size = Math.abs(i);
 			byte[] buf = new byte[size];
-			InputStream in = new ByteArrayInputStream(inbytes);
-			ByteArrayOutputStream bos = new ByteArrayOutputStream();
-			OutputStream out = new AutoCRLFOutputStream(bos);
-			if (i > 0) {
-				int n;
-				while ((n = in.read(buf)) >= 0) {
-					out.write(buf, 0, n);
+			try (InputStream in = new ByteArrayInputStream(inbytes);
+					ByteArrayOutputStream bos = new ByteArrayOutputStream();
+					OutputStream out = new AutoCRLFOutputStream(bos)) {
+				if (i > 0) {
+					int n;
+					while ((n = in.read(buf)) >= 0) {
+						out.write(buf, 0, n);
+					}
+				} else if (i < 0) {
+					int n;
+					while ((n = in.read(buf)) >= 0) {
+						byte[] b = new byte[n];
+						System.arraycopy(buf, 0, b, 0, n);
+						out.write(b);
+					}
+				} else {
+					int c;
+					while ((c = in.read()) != -1)
+						out.write(c);
 				}
-			} else if (i < 0) {
-				int n;
-				while ((n = in.read(buf)) >= 0) {
-					byte[] b = new byte[n];
-					System.arraycopy(buf, 0, b, 0, n);
-					out.write(b);
-				}
-			} else {
-				int c;
-				while ((c = in.read()) != -1)
-					out.write(c);
+				out.flush();
+				byte[] actualBytes = bos.toByteArray();
+				Assert.assertEquals("bufsize=" + size, encode(expectBytes),
+						encode(actualBytes));
 			}
-			out.flush();
-			in.close();
-			out.close();
-			byte[] actualBytes = bos.toByteArray();
-			Assert.assertEquals("bufsize=" + size, encode(expectBytes),
-					encode(actualBytes));
 		}
 	}
 
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/io/AutoLFInputStreamTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/io/AutoLFInputStreamTest.java
index 40cac93..5058165 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/io/AutoLFInputStreamTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/io/AutoLFInputStreamTest.java
@@ -44,12 +44,12 @@
 
 package org.eclipse.jgit.util.io;
 
+import static org.eclipse.jgit.lib.Constants.CHARSET;
 import static org.junit.Assert.assertEquals;
 
 import java.io.ByteArrayInputStream;
 import java.io.IOException;
 import java.io.InputStream;
-import java.io.UnsupportedEncodingException;
 
 import org.junit.Test;
 
@@ -97,42 +97,41 @@ public void testBinaryDontDetect() throws IOException {
 
 	private static void test(byte[] input, byte[] expected,
 			boolean detectBinary) throws IOException {
-		final InputStream bis1 = new ByteArrayInputStream(input);
-		final InputStream cis1 = new AutoLFInputStream(bis1, detectBinary);
-		int index1 = 0;
-		for (int b = cis1.read(); b != -1; b = cis1.read()) {
-			assertEquals(expected[index1], (byte) b);
-			index1++;
-		}
-
-		assertEquals(expected.length, index1);
-
-		for (int bufferSize = 1; bufferSize < 10; bufferSize++) {
-			final byte[] buffer = new byte[bufferSize];
-			final InputStream bis2 = new ByteArrayInputStream(input);
-			final InputStream cis2 = new AutoLFInputStream(bis2, detectBinary);
-
-			int read = 0;
-			for (int readNow = cis2.read(buffer, 0, buffer.length); readNow != -1
-					&& read < expected.length; readNow = cis2.read(buffer, 0,
-					buffer.length)) {
-				for (int index2 = 0; index2 < readNow; index2++) {
-					assertEquals(expected[read + index2], buffer[index2]);
-				}
-				read += readNow;
+		try (InputStream bis1 = new ByteArrayInputStream(input);
+				InputStream cis1 = new AutoLFInputStream(bis1, detectBinary)) {
+			int index1 = 0;
+			for (int b = cis1.read(); b != -1; b = cis1.read()) {
+				assertEquals(expected[index1], (byte) b);
+				index1++;
 			}
 
-			assertEquals(expected.length, read);
-			cis2.close();
+			assertEquals(expected.length, index1);
+
+			for (int bufferSize = 1; bufferSize < 10; bufferSize++) {
+				final byte[] buffer = new byte[bufferSize];
+				try (InputStream bis2 = new ByteArrayInputStream(input);
+						InputStream cis2 = new AutoLFInputStream(bis2,
+								detectBinary)) {
+
+					int read = 0;
+					for (int readNow = cis2.read(buffer, 0,
+							buffer.length); readNow != -1
+									&& read < expected.length; readNow = cis2
+											.read(buffer, 0, buffer.length)) {
+						for (int index2 = 0; index2 < readNow; index2++) {
+							assertEquals(expected[read + index2],
+									buffer[index2]);
+						}
+						read += readNow;
+					}
+
+					assertEquals(expected.length, read);
+				}
+			}
 		}
-		cis1.close();
 	}
 
 	private static byte[] asBytes(String in) {
-		try {
-			return in.getBytes("UTF-8");
-		} catch (UnsupportedEncodingException ex) {
-			throw new AssertionError();
-		}
+		return in.getBytes(CHARSET);
 	}
 }
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/io/UnionInputStreamTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/io/UnionInputStreamTest.java
index 6b5ef7e..b824fae 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/io/UnionInputStreamTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/io/UnionInputStreamTest.java
@@ -58,13 +58,13 @@
 public class UnionInputStreamTest {
 	@Test
 	public void testEmptyStream() throws IOException {
-		final UnionInputStream u = new UnionInputStream();
-		assertTrue(u.isEmpty());
-		assertEquals(-1, u.read());
-		assertEquals(-1, u.read(new byte[1], 0, 1));
-		assertEquals(0, u.available());
-		assertEquals(0, u.skip(1));
-		u.close();
+		try (UnionInputStream u = new UnionInputStream()) {
+			assertTrue(u.isEmpty());
+			assertEquals(-1, u.read());
+			assertEquals(-1, u.read(new byte[1], 0, 1));
+			assertEquals(0, u.available());
+			assertEquals(0, u.skip(1));
+		}
 	}
 
 	@Test
@@ -211,25 +211,24 @@ public void close() {
 
 	@Test
 	public void testCloseDuringClose() throws IOException {
-		final UnionInputStream u = new UnionInputStream();
 		final boolean closed[] = new boolean[2];
-		u.add(new ByteArrayInputStream(new byte[] { 1 }) {
-			@Override
-			public void close() {
-				closed[0] = true;
-			}
-		});
-		u.add(new ByteArrayInputStream(new byte[] { 2 }) {
-			@Override
-			public void close() {
-				closed[1] = true;
-			}
-		});
+		try (UnionInputStream u = new UnionInputStream()) {
+			u.add(new ByteArrayInputStream(new byte[] { 1 }) {
+				@Override
+				public void close() {
+					closed[0] = true;
+				}
+			});
+			u.add(new ByteArrayInputStream(new byte[] { 2 }) {
+				@Override
+				public void close() {
+					closed[1] = true;
+				}
+			});
 
-		assertFalse(closed[0]);
-		assertFalse(closed[1]);
-
-		u.close();
+			assertFalse(closed[0]);
+			assertFalse(closed[1]);
+		}
 
 		assertTrue(closed[0]);
 		assertTrue(closed[1]);
@@ -237,6 +236,7 @@ public void close() {
 
 	@Test
 	public void testExceptionDuringClose() {
+		@SuppressWarnings("resource") // We are testing the close() method
 		final UnionInputStream u = new UnionInputStream();
 		u.add(new ByteArrayInputStream(new byte[] { 1 }) {
 			@Override
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/sha1/SHA1Test.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/sha1/SHA1Test.java
index 0778989..3c612e1 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/sha1/SHA1Test.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/sha1/SHA1Test.java
@@ -43,6 +43,7 @@
 
 package org.eclipse.jgit.util.sha1;
 
+import static org.eclipse.jgit.lib.Constants.CHARSET;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
@@ -51,7 +52,6 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.nio.ByteBuffer;
-import java.nio.charset.StandardCharsets;
 import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;
 
@@ -95,15 +95,15 @@ public void test1() throws NoSuchAlgorithmException {
 				.fromString("a9993e364706816aba3e25717850c26c9cd0d89d");
 
 		MessageDigest m = MessageDigest.getInstance("SHA-1");
-		m.update(TEST1.getBytes(StandardCharsets.UTF_8));
+		m.update(TEST1.getBytes(CHARSET));
 		ObjectId m1 = ObjectId.fromRaw(m.digest());
 
 		SHA1 s = SHA1.newInstance();
-		s.update(TEST1.getBytes(StandardCharsets.UTF_8));
+		s.update(TEST1.getBytes(CHARSET));
 		ObjectId s1 = ObjectId.fromRaw(s.digest());
 
 		s.reset();
-		s.update(TEST1.getBytes(StandardCharsets.UTF_8));
+		s.update(TEST1.getBytes(CHARSET));
 		ObjectId s2 = s.toObjectId();
 
 		assertEquals(m1, s1);
@@ -117,15 +117,15 @@ public void test2() throws NoSuchAlgorithmException {
 				.fromString("84983e441c3bd26ebaae4aa1f95129e5e54670f1");
 
 		MessageDigest m = MessageDigest.getInstance("SHA-1");
-		m.update(TEST2.getBytes(StandardCharsets.UTF_8));
+		m.update(TEST2.getBytes(CHARSET));
 		ObjectId m1 = ObjectId.fromRaw(m.digest());
 
 		SHA1 s = SHA1.newInstance();
-		s.update(TEST2.getBytes(StandardCharsets.UTF_8));
+		s.update(TEST2.getBytes(CHARSET));
 		ObjectId s1 = ObjectId.fromRaw(s.digest());
 
 		s.reset();
-		s.update(TEST2.getBytes(StandardCharsets.UTF_8));
+		s.update(TEST2.getBytes(CHARSET));
 		ObjectId s2 = s.toObjectId();
 
 		assertEquals(m1, s1);
diff --git a/org.eclipse.jgit.ui/.settings/.api_filters b/org.eclipse.jgit.ui/.settings/.api_filters
new file mode 100644
index 0000000..aed9c7a
--- /dev/null
+++ b/org.eclipse.jgit.ui/.settings/.api_filters
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<component id="org.eclipse.jgit.ui" version="2">
+    <resource path="META-INF/MANIFEST.MF">
+        <filter id="925892614">
+            <message_arguments>
+                <message_argument value="5.0.0"/>
+                <message_argument value="4.11.0"/>
+            </message_arguments>
+        </filter>
+    </resource>
+</component>
diff --git a/org.eclipse.jgit.ui/.settings/org.eclipse.jdt.core.prefs b/org.eclipse.jgit.ui/.settings/org.eclipse.jdt.core.prefs
index ede0f7d..89394ec 100644
--- a/org.eclipse.jgit.ui/.settings/org.eclipse.jdt.core.prefs
+++ b/org.eclipse.jgit.ui/.settings/org.eclipse.jdt.core.prefs
@@ -25,7 +25,7 @@
 org.eclipse.jdt.core.compiler.problem.discouragedReference=warning
 org.eclipse.jdt.core.compiler.problem.emptyStatement=warning
 org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
-org.eclipse.jdt.core.compiler.problem.explicitlyClosedAutoCloseable=ignore
+org.eclipse.jdt.core.compiler.problem.explicitlyClosedAutoCloseable=warning
 org.eclipse.jdt.core.compiler.problem.fallthroughCase=warning
 org.eclipse.jdt.core.compiler.problem.fatalOptionalError=disabled
 org.eclipse.jdt.core.compiler.problem.fieldHiding=warning
diff --git a/org.eclipse.jgit.ui/META-INF/MANIFEST.MF b/org.eclipse.jgit.ui/META-INF/MANIFEST.MF
index 1fdb88d..221ea59 100644
--- a/org.eclipse.jgit.ui/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.ui/META-INF/MANIFEST.MF
@@ -2,15 +2,16 @@
 Manifest-Version: 1.0
 Bundle-ManifestVersion: 2
 Bundle-Name: %plugin_name
+Automatic-Module-Name: org.eclipse.jgit.ui
 Bundle-SymbolicName: org.eclipse.jgit.ui
-Bundle-Version: 4.9.3.qualifier
+Bundle-Version: 5.0.0.qualifier
 Bundle-Vendor: %provider_name
 Bundle-RequiredExecutionEnvironment: JavaSE-1.8
-Export-Package: org.eclipse.jgit.awtui;version="4.9.3"
-Import-Package: org.eclipse.jgit.errors;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.lib;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.nls;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.revplot;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.revwalk;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.transport;version="[4.9.3,4.10.0)",
- org.eclipse.jgit.util;version="[4.9.3,4.10.0)"
+Export-Package: org.eclipse.jgit.awtui;version="5.0.0"
+Import-Package: org.eclipse.jgit.errors;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.lib;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.nls;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.revplot;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.revwalk;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.transport;version="[5.0.0,5.1.0)",
+ org.eclipse.jgit.util;version="[5.0.0,5.1.0)"
diff --git a/org.eclipse.jgit.ui/pom.xml b/org.eclipse.jgit.ui/pom.xml
index 6d15ce8..c30f4b1 100644
--- a/org.eclipse.jgit.ui/pom.xml
+++ b/org.eclipse.jgit.ui/pom.xml
@@ -52,7 +52,7 @@
   <parent>
     <groupId>org.eclipse.jgit</groupId>
     <artifactId>org.eclipse.jgit-parent</artifactId>
-    <version>4.9.3-SNAPSHOT</version>
+    <version>5.0.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>org.eclipse.jgit.ui</artifactId>
diff --git a/org.eclipse.jgit.ui/src/org/eclipse/jgit/awtui/AWTPlotRenderer.java b/org.eclipse.jgit.ui/src/org/eclipse/jgit/awtui/AWTPlotRenderer.java
index 632114f..b1fffd8 100644
--- a/org.eclipse.jgit.ui/src/org/eclipse/jgit/awtui/AWTPlotRenderer.java
+++ b/org.eclipse.jgit.ui/src/org/eclipse/jgit/awtui/AWTPlotRenderer.java
@@ -66,11 +66,11 @@ final class AWTPlotRenderer extends AbstractPlotRenderer<SwingLane, Color>
 
 	transient Graphics2D g;
 
-	AWTPlotRenderer(final GraphCellRender c) {
+	AWTPlotRenderer(GraphCellRender c) {
 		cell = c;
 	}
 
-	void paint(final Graphics in, final PlotCommit<SwingLane> commit) {
+	void paint(Graphics in, PlotCommit<SwingLane> commit) {
 		g = (Graphics2D) in.create();
 		try {
 			final int h = cell.getHeight();
@@ -84,6 +84,7 @@ void paint(final Graphics in, final PlotCommit<SwingLane> commit) {
 		}
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected void drawLine(final Color color, int x1, int y1, int x2,
 			int y2, int width) {
@@ -100,6 +101,7 @@ protected void drawLine(final Color color, int x1, int y1, int x2,
 		g.drawLine(x1, y1, x2, y2);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected void drawCommitDot(final int x, final int y, final int w,
 			final int h) {
@@ -110,6 +112,7 @@ protected void drawCommitDot(final int x, final int y, final int w,
 		g.drawOval(x, y, w, h);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected void drawBoundaryDot(final int x, final int y, final int w,
 			final int h) {
@@ -120,20 +123,22 @@ protected void drawBoundaryDot(final int x, final int y, final int w,
 		g.drawOval(x, y, w, h);
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	protected void drawText(final String msg, final int x, final int y) {
+	protected void drawText(String msg, int x, int y) {
 		final int texth = g.getFontMetrics().getHeight();
 		final int y0 = (y - texth) / 2 + (cell.getHeight() - texth) / 2;
 		g.setColor(cell.getForeground());
 		g.drawString(msg, x, y0 + texth - g.getFontMetrics().getDescent());
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	protected Color laneColor(final SwingLane myLane) {
+	protected Color laneColor(SwingLane myLane) {
 		return myLane != null ? myLane.color : Color.black;
 	}
 
-	void paintTriangleDown(final int cx, final int y, final int h) {
+	void paintTriangleDown(int cx, int y, int h) {
 		final int tipX = cx;
 		final int tipY = y + h;
 		final int baseX1 = cx - 10 / 2;
@@ -147,6 +152,7 @@ void paintTriangleDown(final int cx, final int y, final int h) {
 		g.drawPolygon(triangle);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected int drawLabel(int x, int y, Ref ref) {
 		String txt;
diff --git a/org.eclipse.jgit.ui/src/org/eclipse/jgit/awtui/AwtAuthenticator.java b/org.eclipse.jgit.ui/src/org/eclipse/jgit/awtui/AwtAuthenticator.java
index 486bbf6..dfa6e2b 100644
--- a/org.eclipse.jgit.ui/src/org/eclipse/jgit/awtui/AwtAuthenticator.java
+++ b/org.eclipse.jgit.ui/src/org/eclipse/jgit/awtui/AwtAuthenticator.java
@@ -58,13 +58,18 @@
 
 import org.eclipse.jgit.util.CachedAuthenticator;
 
-/** Basic network prompt for username/password when using AWT. */
+/**
+ * Basic network prompt for username/password when using AWT.
+ */
 public class AwtAuthenticator extends CachedAuthenticator {
-	/** Install this authenticator implementation into the JVM. */
+	/**
+	 * Install this authenticator implementation into the JVM.
+	 */
 	public static void install() {
 		setDefault(new AwtAuthenticator());
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected PasswordAuthentication promptPasswordAuthentication() {
 		final GridBagConstraints gbc = new GridBagConstraints(0, 0, 1, 1, 1, 1,
diff --git a/org.eclipse.jgit.ui/src/org/eclipse/jgit/awtui/AwtCredentialsProvider.java b/org.eclipse.jgit.ui/src/org/eclipse/jgit/awtui/AwtCredentialsProvider.java
index a9967ae..edf94cf 100644
--- a/org.eclipse.jgit.ui/src/org/eclipse/jgit/awtui/AwtCredentialsProvider.java
+++ b/org.eclipse.jgit.ui/src/org/eclipse/jgit/awtui/AwtCredentialsProvider.java
@@ -62,9 +62,13 @@
 import org.eclipse.jgit.transport.NetRCCredentialsProvider;
 import org.eclipse.jgit.transport.URIish;
 
-/** Interacts with the user during authentication by using AWT/Swing dialogs. */
+/**
+ * Interacts with the user during authentication by using AWT/Swing dialogs.
+ */
 public class AwtCredentialsProvider extends CredentialsProvider {
-	/** Install this implementation as the default. */
+	/**
+	 * Install this implementation as the default.
+	 */
 	public static void install() {
 		final AwtCredentialsProvider c = new AwtCredentialsProvider();
 		CredentialsProvider cp = new ChainingCredentialsProvider(
@@ -72,11 +76,13 @@ public static void install() {
 		CredentialsProvider.setDefault(cp);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public boolean isInteractive() {
 		return true;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public boolean supports(CredentialItem... items) {
 		for (CredentialItem i : items) {
@@ -98,6 +104,7 @@ else if (i instanceof CredentialItem.InformationalMessage)
 		return true;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public boolean get(URIish uri, CredentialItem... items)
 			throws UnsupportedCredentialItem {
diff --git a/org.eclipse.jgit.ui/src/org/eclipse/jgit/awtui/CommitGraphPane.java b/org.eclipse.jgit.ui/src/org/eclipse/jgit/awtui/CommitGraphPane.java
index 4c8cf53..943a325 100644
--- a/org.eclipse.jgit.ui/src/org/eclipse/jgit/awtui/CommitGraphPane.java
+++ b/org.eclipse.jgit.ui/src/org/eclipse/jgit/awtui/CommitGraphPane.java
@@ -81,7 +81,9 @@ public class CommitGraphPane extends JTable {
 
 	private final SwingCommitList allCommits;
 
-	/** Create a new empty panel. */
+	/**
+	 * Create a new empty panel.
+	 */
 	public CommitGraphPane() {
 		allCommits = new SwingCommitList();
 		configureHeader();
@@ -110,13 +112,15 @@ public PlotCommitList getCommitList() {
 		return allCommits;
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	public void setModel(final TableModel dataModel) {
+	public void setModel(TableModel dataModel) {
 		if (dataModel != null && !(dataModel instanceof CommitTableModel))
 			throw new ClassCastException(UIText.get().mustBeSpecialTableModel);
 		super.setModel(dataModel);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected TableModel createDefaultDataModel() {
 		return new CommitTableModel();
@@ -157,7 +161,7 @@ public int getRowCount() {
 		}
 
 		@Override
-		public Object getValueAt(final int rowIndex, final int columnIndex) {
+		public Object getValueAt(int rowIndex, int columnIndex) {
 			final PlotCommit<SwingLane> c = allCommits.get(rowIndex);
 			switch (columnIndex) {
 			case 0:
@@ -171,7 +175,7 @@ public Object getValueAt(final int rowIndex, final int columnIndex) {
 			}
 		}
 
-		PersonIdent authorFor(final PlotCommit<SwingLane> c) {
+		PersonIdent authorFor(PlotCommit<SwingLane> c) {
 			if (c != lastCommit) {
 				lastCommit = c;
 				lastAuthor = c.getAuthorIdent();
@@ -240,7 +244,7 @@ public Component getTableCellRendererComponent(final JTable table,
 		}
 
 		@Override
-		protected void paintComponent(final Graphics inputGraphics) {
+		protected void paintComponent(Graphics inputGraphics) {
 			if (inputGraphics == null)
 				return;
 			renderer.paint(inputGraphics, commit);
@@ -255,7 +259,7 @@ protected void paintComponent(final Graphics inputGraphics) {
 			strokeCache[i] = new BasicStroke(i);
 	}
 
-	static Stroke stroke(final int width) {
+	static Stroke stroke(int width) {
 		if (width < strokeCache.length)
 			return strokeCache[width];
 		return new BasicStroke(width);
diff --git a/org.eclipse.jgit.ui/src/org/eclipse/jgit/awtui/SwingCommitList.java b/org.eclipse.jgit.ui/src/org/eclipse/jgit/awtui/SwingCommitList.java
index fe0c486..10519ca 100644
--- a/org.eclipse.jgit.ui/src/org/eclipse/jgit/awtui/SwingCommitList.java
+++ b/org.eclipse.jgit.ui/src/org/eclipse/jgit/awtui/SwingCommitList.java
@@ -67,6 +67,7 @@ private void repackColors() {
 		colors.add(Color.orange);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected SwingLane createLane() {
 		final SwingLane lane = new SwingLane();
@@ -76,8 +77,9 @@ protected SwingLane createLane() {
 		return lane;
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	protected void recycleLane(final SwingLane lane) {
+	protected void recycleLane(SwingLane lane) {
 		colors.add(lane.color);
 	}
 
diff --git a/org.eclipse.jgit.ui/src/org/eclipse/jgit/awtui/UIText.java b/org.eclipse.jgit.ui/src/org/eclipse/jgit/awtui/UIText.java
index d9b6d9c..b2b19ad 100644
--- a/org.eclipse.jgit.ui/src/org/eclipse/jgit/awtui/UIText.java
+++ b/org.eclipse.jgit.ui/src/org/eclipse/jgit/awtui/UIText.java
@@ -52,6 +52,8 @@
 public class UIText extends TranslationBundle {
 
 	/**
+	 * Get an instance of this translation bundle.
+	 *
 	 * @return an instance of this translation bundle
 	 */
 	public static UIText get() {
diff --git a/org.eclipse.jgit/.settings/.api_filters b/org.eclipse.jgit/.settings/.api_filters
index 1824eb2..e51bf20 100644
--- a/org.eclipse.jgit/.settings/.api_filters
+++ b/org.eclipse.jgit/.settings/.api_filters
@@ -1,102 +1,18 @@
 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
 <component id="org.eclipse.jgit" version="2">
-    <resource path="META-INF/MANIFEST.MF">
-        <filter id="924844039">
+    <resource path="src/org/eclipse/jgit/lib/ObjectIdSerializer.java" type="org.eclipse.jgit.lib.ObjectIdSerializer">
+        <filter id="1141899266">
             <message_arguments>
-                <message_argument value="4.9.1"/>
-                <message_argument value="4.9.0"/>
-            </message_arguments>
-        </filter>
-    </resource>
-    <resource path="src/org/eclipse/jgit/lib/ConfigConstants.java" type="org.eclipse.jgit.lib.ConfigConstants">
-        <filter id="336658481">
-            <message_arguments>
-                <message_argument value="org.eclipse.jgit.lib.ConfigConstants"/>
-                <message_argument value="CONFIG_KEY_IN_CORE_LIMIT"/>
-            </message_arguments>
-        </filter>
-        <filter id="336658481">
-            <message_arguments>
-                <message_argument value="org.eclipse.jgit.lib.ConfigConstants"/>
-                <message_argument value="CONFIG_KEY_SUPPORTSATOMICFILECREATION"/>
-            </message_arguments>
-        </filter>
-        <filter id="336658481">
-            <message_arguments>
-                <message_argument value="org.eclipse.jgit.lib.ConfigConstants"/>
-                <message_argument value="CONFIG_MERGE_SECTION"/>
+                <message_argument value="4.11"/>
+                <message_argument value="5.0"/>
+                <message_argument value="readWithoutMarker(InputStream)"/>
             </message_arguments>
         </filter>
         <filter id="1141899266">
             <message_arguments>
-                <message_argument value="4.5"/>
-                <message_argument value="4.9"/>
-                <message_argument value="CONFIG_KEY_SUPPORTSATOMICFILECREATION"/>
-            </message_arguments>
-        </filter>
-    </resource>
-    <resource path="src/org/eclipse/jgit/lib/ReflogEntry.java" type="org.eclipse.jgit.lib.ReflogEntry">
-        <filter comment="adding enum constant does not break binary compatibility" id="403767336">
-            <message_arguments>
-                <message_argument value="org.eclipse.jgit.lib.ReflogEntry"/>
-                <message_argument value="PREFIX_CREATED"/>
-            </message_arguments>
-        </filter>
-        <filter comment="adding enum constant does not break binary compatibility" id="403767336">
-            <message_arguments>
-                <message_argument value="org.eclipse.jgit.lib.ReflogEntry"/>
-                <message_argument value="PREFIX_FAST_FORWARD"/>
-            </message_arguments>
-        </filter>
-        <filter comment="adding enum constant does not break binary compatibility" id="403767336">
-            <message_arguments>
-                <message_argument value="org.eclipse.jgit.lib.ReflogEntry"/>
-                <message_argument value="PREFIX_FORCED_UPDATE"/>
-            </message_arguments>
-        </filter>
-    </resource>
-    <resource path="src/org/eclipse/jgit/merge/ResolveMerger.java" type="org.eclipse.jgit.merge.ResolveMerger">
-        <filter id="1141899266">
-            <message_arguments>
-                <message_argument value="3.5"/>
-                <message_argument value="4.9"/>
-                <message_argument value="processEntry(CanonicalTreeParser, CanonicalTreeParser, CanonicalTreeParser, DirCacheBuildIterator, WorkingTreeIterator, boolean)"/>
-            </message_arguments>
-        </filter>
-    </resource>
-    <resource path="src/org/eclipse/jgit/transport/http/HttpConnection.java" type="org.eclipse.jgit.transport.http.HttpConnection">
-        <filter id="403767336">
-            <message_arguments>
-                <message_argument value="org.eclipse.jgit.transport.http.HttpConnection"/>
-                <message_argument value="HTTP_11_MOVED_TEMP"/>
-            </message_arguments>
-        </filter>
-        <filter id="403767336">
-            <message_arguments>
-                <message_argument value="org.eclipse.jgit.transport.http.HttpConnection"/>
-                <message_argument value="HTTP_MOVED_TEMP"/>
-            </message_arguments>
-        </filter>
-        <filter id="403767336">
-            <message_arguments>
-                <message_argument value="org.eclipse.jgit.transport.http.HttpConnection"/>
-                <message_argument value="HTTP_SEE_OTHER"/>
-            </message_arguments>
-        </filter>
-    </resource>
-    <resource path="src/org/eclipse/jgit/util/FS.java" type="org.eclipse.jgit.util.FS">
-        <filter id="1141899266">
-            <message_arguments>
-                <message_argument value="4.5"/>
-                <message_argument value="4.9"/>
-                <message_argument value="createNewFile(File)"/>
-            </message_arguments>
-        </filter>
-        <filter id="1141899266">
-            <message_arguments>
-                <message_argument value="4.5"/>
-                <message_argument value="4.9"/>
-                <message_argument value="supportsAtomicCreateNewFile()"/>
+                <message_argument value="4.11"/>
+                <message_argument value="5.0"/>
+                <message_argument value="writeWithoutMarker(OutputStream, AnyObjectId)"/>
             </message_arguments>
         </filter>
     </resource>
diff --git a/org.eclipse.jgit/.settings/org.eclipse.jdt.core.prefs b/org.eclipse.jgit/.settings/org.eclipse.jdt.core.prefs
index 06ddbab..13c32a6 100644
--- a/org.eclipse.jgit/.settings/org.eclipse.jdt.core.prefs
+++ b/org.eclipse.jgit/.settings/org.eclipse.jdt.core.prefs
@@ -25,7 +25,7 @@
 org.eclipse.jdt.core.compiler.problem.discouragedReference=warning
 org.eclipse.jdt.core.compiler.problem.emptyStatement=warning
 org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
-org.eclipse.jdt.core.compiler.problem.explicitlyClosedAutoCloseable=ignore
+org.eclipse.jdt.core.compiler.problem.explicitlyClosedAutoCloseable=warning
 org.eclipse.jdt.core.compiler.problem.fallthroughCase=warning
 org.eclipse.jdt.core.compiler.problem.fatalOptionalError=disabled
 org.eclipse.jdt.core.compiler.problem.fieldHiding=warning
diff --git a/org.eclipse.jgit/BUILD b/org.eclipse.jgit/BUILD
index a8a53f2..6ba7796 100644
--- a/org.eclipse.jgit/BUILD
+++ b/org.eclipse.jgit/BUILD
@@ -14,12 +14,17 @@
 java_library(
     name = "jgit",
     srcs = SRCS,
+    javacopts = select({
+        "//:jdk9": ["--add-modules=java.xml.bind"],
+        "//conditions:default": [],
+    }),
     resource_strip_prefix = "org.eclipse.jgit/resources",
     resources = RESOURCES,
     deps = [
         ":insecure_cipher_factory",
         "//lib:javaewah",
         "//lib:jsch",
+        "//lib:jzlib",
         "//lib:slf4j-api",
     ],
 )
diff --git a/org.eclipse.jgit/META-INF/MANIFEST.MF b/org.eclipse.jgit/META-INF/MANIFEST.MF
index ef7dbbc..31c0bcb 100644
--- a/org.eclipse.jgit/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit/META-INF/MANIFEST.MF
@@ -1,13 +1,14 @@
 Manifest-Version: 1.0
 Bundle-ManifestVersion: 2
 Bundle-Name: %plugin_name
+Automatic-Module-Name: org.eclipse.jgit
 Bundle-SymbolicName: org.eclipse.jgit
-Bundle-Version: 4.9.3.qualifier
+Bundle-Version: 5.0.0.qualifier
 Bundle-Localization: plugin
 Bundle-Vendor: %provider_name
 Bundle-ActivationPolicy: lazy
-Export-Package: org.eclipse.jgit.annotations;version="4.9.3",
- org.eclipse.jgit.api;version="4.9.3";
+Export-Package: org.eclipse.jgit.annotations;version="5.0.0",
+ org.eclipse.jgit.api;version="5.0.0";
   uses:="org.eclipse.jgit.revwalk,
    org.eclipse.jgit.treewalk.filter,
    org.eclipse.jgit.diff,
@@ -21,52 +22,52 @@
    org.eclipse.jgit.submodule,
    org.eclipse.jgit.transport,
    org.eclipse.jgit.merge",
- org.eclipse.jgit.api.errors;version="4.9.3";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.errors",
- org.eclipse.jgit.attributes;version="4.9.3",
- org.eclipse.jgit.blame;version="4.9.3";
+ org.eclipse.jgit.api.errors;version="5.0.0";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.errors",
+ org.eclipse.jgit.attributes;version="5.0.0",
+ org.eclipse.jgit.blame;version="5.0.0";
   uses:="org.eclipse.jgit.lib,
    org.eclipse.jgit.revwalk,
    org.eclipse.jgit.treewalk.filter,
    org.eclipse.jgit.diff",
- org.eclipse.jgit.diff;version="4.9.3";
+ org.eclipse.jgit.diff;version="5.0.0";
   uses:="org.eclipse.jgit.patch,
    org.eclipse.jgit.lib,
    org.eclipse.jgit.treewalk,
    org.eclipse.jgit.revwalk,
    org.eclipse.jgit.treewalk.filter,
    org.eclipse.jgit.util",
- org.eclipse.jgit.dircache;version="4.9.3";
+ org.eclipse.jgit.dircache;version="5.0.0";
   uses:="org.eclipse.jgit.lib,
    org.eclipse.jgit.treewalk,
    org.eclipse.jgit.util,
    org.eclipse.jgit.events,
    org.eclipse.jgit.attributes",
- org.eclipse.jgit.errors;version="4.9.3";
+ org.eclipse.jgit.errors;version="5.0.0";
   uses:="org.eclipse.jgit.lib,
    org.eclipse.jgit.internal.storage.pack,
    org.eclipse.jgit.transport,
    org.eclipse.jgit.dircache",
- org.eclipse.jgit.events;version="4.9.3";uses:="org.eclipse.jgit.lib",
- org.eclipse.jgit.fnmatch;version="4.9.3",
- org.eclipse.jgit.gitrepo;version="4.9.3";
+ org.eclipse.jgit.events;version="5.0.0";uses:="org.eclipse.jgit.lib",
+ org.eclipse.jgit.fnmatch;version="5.0.0",
+ org.eclipse.jgit.gitrepo;version="5.0.0";
   uses:="org.eclipse.jgit.api,
    org.eclipse.jgit.lib,
    org.eclipse.jgit.revwalk,
    org.xml.sax.helpers,
    org.xml.sax",
- org.eclipse.jgit.gitrepo.internal;version="4.9.3";x-internal:=true,
- org.eclipse.jgit.hooks;version="4.9.3";uses:="org.eclipse.jgit.lib",
- org.eclipse.jgit.ignore;version="4.9.3",
- org.eclipse.jgit.ignore.internal;version="4.9.3";x-friends:="org.eclipse.jgit.test",
- org.eclipse.jgit.internal;version="4.9.3";x-friends:="org.eclipse.jgit.test,org.eclipse.jgit.http.test",
- org.eclipse.jgit.internal.fsck;version="4.9.3";x-friends:="org.eclipse.jgit.test",
- org.eclipse.jgit.internal.ketch;version="4.9.3";x-friends:="org.eclipse.jgit.junit,org.eclipse.jgit.test,org.eclipse.jgit.pgm",
- org.eclipse.jgit.internal.storage.dfs;version="4.9.3";
+ org.eclipse.jgit.gitrepo.internal;version="5.0.0";x-internal:=true,
+ org.eclipse.jgit.hooks;version="5.0.0";uses:="org.eclipse.jgit.lib",
+ org.eclipse.jgit.ignore;version="5.0.0",
+ org.eclipse.jgit.ignore.internal;version="5.0.0";x-friends:="org.eclipse.jgit.test",
+ org.eclipse.jgit.internal;version="5.0.0";x-friends:="org.eclipse.jgit.test,org.eclipse.jgit.http.test",
+ org.eclipse.jgit.internal.fsck;version="5.0.0";x-friends:="org.eclipse.jgit.test",
+ org.eclipse.jgit.internal.ketch;version="5.0.0";x-friends:="org.eclipse.jgit.junit,org.eclipse.jgit.test,org.eclipse.jgit.pgm",
+ org.eclipse.jgit.internal.storage.dfs;version="5.0.0";
   x-friends:="org.eclipse.jgit.test,
    org.eclipse.jgit.http.server,
    org.eclipse.jgit.http.test,
    org.eclipse.jgit.lfs.test",
- org.eclipse.jgit.internal.storage.file;version="4.9.3";
+ org.eclipse.jgit.internal.storage.file;version="5.0.0";
   x-friends:="org.eclipse.jgit.test,
    org.eclipse.jgit.junit,
    org.eclipse.jgit.junit.http,
@@ -74,11 +75,12 @@
    org.eclipse.jgit.lfs,
    org.eclipse.jgit.pgm,
    org.eclipse.jgit.pgm.test",
- org.eclipse.jgit.internal.storage.io;version="4.9.3";x-friends:="org.eclipse.jgit.junit,org.eclipse.jgit.test,org.eclipse.jgit.pgm",
- org.eclipse.jgit.internal.storage.pack;version="4.9.3";x-friends:="org.eclipse.jgit.junit,org.eclipse.jgit.test,org.eclipse.jgit.pgm",
- org.eclipse.jgit.internal.storage.reftable;version="4.9.3";x-friends:="org.eclipse.jgit.junit,org.eclipse.jgit.test,org.eclipse.jgit.pgm",
- org.eclipse.jgit.internal.storage.reftree;version="4.9.3";x-friends:="org.eclipse.jgit.junit,org.eclipse.jgit.test,org.eclipse.jgit.pgm",
- org.eclipse.jgit.lib;version="4.9.3";
+ org.eclipse.jgit.internal.storage.io;version="5.0.0";x-friends:="org.eclipse.jgit.junit,org.eclipse.jgit.test,org.eclipse.jgit.pgm",
+ org.eclipse.jgit.internal.storage.pack;version="5.0.0";x-friends:="org.eclipse.jgit.junit,org.eclipse.jgit.test,org.eclipse.jgit.pgm",
+ org.eclipse.jgit.internal.storage.reftable;version="5.0.0";
+  x-friends:="org.eclipse.jgit.http.test,org.eclipse.jgit.junit,org.eclipse.jgit.test,org.eclipse.jgit.pgm",
+ org.eclipse.jgit.internal.storage.reftree;version="5.0.0";x-friends:="org.eclipse.jgit.junit,org.eclipse.jgit.test,org.eclipse.jgit.pgm",
+ org.eclipse.jgit.lib;version="5.0.0";
   uses:="org.eclipse.jgit.revwalk,
    org.eclipse.jgit.treewalk.filter,
    org.eclipse.jgit.util,
@@ -88,33 +90,33 @@
    org.eclipse.jgit.treewalk,
    org.eclipse.jgit.transport,
    org.eclipse.jgit.submodule",
- org.eclipse.jgit.lib.internal;version="4.9.3";x-internal:=true,
- org.eclipse.jgit.merge;version="4.9.3";
+ org.eclipse.jgit.lib.internal;version="5.0.0";x-internal:=true,
+ org.eclipse.jgit.merge;version="5.0.0";
   uses:="org.eclipse.jgit.lib,
    org.eclipse.jgit.treewalk,
    org.eclipse.jgit.revwalk,
    org.eclipse.jgit.diff,
    org.eclipse.jgit.dircache,
    org.eclipse.jgit.api",
- org.eclipse.jgit.nls;version="4.9.3",
- org.eclipse.jgit.notes;version="4.9.3";
+ org.eclipse.jgit.nls;version="5.0.0",
+ org.eclipse.jgit.notes;version="5.0.0";
   uses:="org.eclipse.jgit.lib,
    org.eclipse.jgit.treewalk,
    org.eclipse.jgit.revwalk,
    org.eclipse.jgit.merge",
- org.eclipse.jgit.patch;version="4.9.3";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.diff",
- org.eclipse.jgit.revplot;version="4.9.3";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.revwalk",
- org.eclipse.jgit.revwalk;version="4.9.3";
+ org.eclipse.jgit.patch;version="5.0.0";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.diff",
+ org.eclipse.jgit.revplot;version="5.0.0";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.revwalk",
+ org.eclipse.jgit.revwalk;version="5.0.0";
   uses:="org.eclipse.jgit.lib,
    org.eclipse.jgit.treewalk,
    org.eclipse.jgit.treewalk.filter,
    org.eclipse.jgit.diff,
    org.eclipse.jgit.revwalk.filter",
- org.eclipse.jgit.revwalk.filter;version="4.9.3";uses:="org.eclipse.jgit.revwalk,org.eclipse.jgit.lib,org.eclipse.jgit.util",
- org.eclipse.jgit.storage.file;version="4.9.3";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.util",
- org.eclipse.jgit.storage.pack;version="4.9.3";uses:="org.eclipse.jgit.lib",
- org.eclipse.jgit.submodule;version="4.9.3";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.treewalk.filter,org.eclipse.jgit.treewalk",
- org.eclipse.jgit.transport;version="4.9.3";
+ org.eclipse.jgit.revwalk.filter;version="5.0.0";uses:="org.eclipse.jgit.revwalk,org.eclipse.jgit.lib,org.eclipse.jgit.util",
+ org.eclipse.jgit.storage.file;version="5.0.0";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.util",
+ org.eclipse.jgit.storage.pack;version="5.0.0";uses:="org.eclipse.jgit.lib",
+ org.eclipse.jgit.submodule;version="5.0.0";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.treewalk.filter,org.eclipse.jgit.treewalk",
+ org.eclipse.jgit.transport;version="5.0.0";
   uses:="org.eclipse.jgit.transport.resolver,
    org.eclipse.jgit.revwalk,
    org.eclipse.jgit.internal.storage.pack,
@@ -126,24 +128,24 @@
    org.eclipse.jgit.transport.http,
    org.eclipse.jgit.errors,
    org.eclipse.jgit.storage.pack",
- org.eclipse.jgit.transport.http;version="4.9.3";uses:="javax.net.ssl",
- org.eclipse.jgit.transport.resolver;version="4.9.3";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.transport",
- org.eclipse.jgit.treewalk;version="4.9.3";
+ org.eclipse.jgit.transport.http;version="5.0.0";uses:="javax.net.ssl",
+ org.eclipse.jgit.transport.resolver;version="5.0.0";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.transport",
+ org.eclipse.jgit.treewalk;version="5.0.0";
   uses:="org.eclipse.jgit.lib,
    org.eclipse.jgit.revwalk,
    org.eclipse.jgit.attributes,
    org.eclipse.jgit.treewalk.filter,
    org.eclipse.jgit.util,
    org.eclipse.jgit.dircache",
- org.eclipse.jgit.treewalk.filter;version="4.9.3";uses:="org.eclipse.jgit.treewalk",
- org.eclipse.jgit.util;version="4.9.3";
+ org.eclipse.jgit.treewalk.filter;version="5.0.0";uses:="org.eclipse.jgit.treewalk",
+ org.eclipse.jgit.util;version="5.0.0";
   uses:="org.eclipse.jgit.lib,
    org.eclipse.jgit.transport.http,
    org.eclipse.jgit.storage.file,
    org.ietf.jgss",
- org.eclipse.jgit.util.io;version="4.9.3",
- org.eclipse.jgit.util.sha1;version="4.9.3",
- org.eclipse.jgit.util.time;version="4.9.3"
+ org.eclipse.jgit.util.io;version="5.0.0",
+ org.eclipse.jgit.util.sha1;version="5.0.0",
+ org.eclipse.jgit.util.time;version="5.0.0"
 Bundle-RequiredExecutionEnvironment: JavaSE-1.8
 Import-Package: com.googlecode.javaewah;version="[1.1.6,2.0.0)",
  com.jcraft.jsch;version="[0.1.37,0.2.0)",
diff --git a/org.eclipse.jgit/META-INF/SOURCE-MANIFEST.MF b/org.eclipse.jgit/META-INF/SOURCE-MANIFEST.MF
index 02f9a3d..89926f4 100644
--- a/org.eclipse.jgit/META-INF/SOURCE-MANIFEST.MF
+++ b/org.eclipse.jgit/META-INF/SOURCE-MANIFEST.MF
@@ -3,5 +3,5 @@
 Bundle-Name: org.eclipse.jgit - Sources
 Bundle-SymbolicName: org.eclipse.jgit.source
 Bundle-Vendor: Eclipse.org - JGit
-Bundle-Version: 4.9.3.qualifier
-Eclipse-SourceBundle: org.eclipse.jgit;version="4.9.3.qualifier";roots="."
+Bundle-Version: 5.0.0.qualifier
+Eclipse-SourceBundle: org.eclipse.jgit;version="5.0.0.qualifier";roots="."
diff --git a/org.eclipse.jgit/pom.xml b/org.eclipse.jgit/pom.xml
index 7ac8e06..d94667f 100644
--- a/org.eclipse.jgit/pom.xml
+++ b/org.eclipse.jgit/pom.xml
@@ -53,7 +53,7 @@
   <parent>
     <groupId>org.eclipse.jgit</groupId>
     <artifactId>org.eclipse.jgit-parent</artifactId>
-    <version>4.9.3-SNAPSHOT</version>
+    <version>5.0.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>org.eclipse.jgit</artifactId>
@@ -75,6 +75,11 @@
     </dependency>
 
     <dependency>
+      <groupId>com.jcraft</groupId>
+      <artifactId>jzlib</artifactId>
+    </dependency>
+
+    <dependency>
       <groupId>com.googlecode.javaewah</groupId>
       <artifactId>JavaEWAH</artifactId>
     </dependency>
@@ -206,7 +211,7 @@
     <pluginManagement>
       <plugins>
         <plugin>
-          <groupId>com.github.hazendaz.spotbugs</groupId>
+          <groupId>com.github.spotbugs</groupId>
           <artifactId>spotbugs-maven-plugin</artifactId>
           <configuration>
             <excludeFilterFile>findBugs/FindBugsExcludeFilter.xml</excludeFilterFile>
diff --git a/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties b/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties
index 8bae60b..b608ca8 100644
--- a/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties
+++ b/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties
@@ -22,6 +22,7 @@
 atLeastTwoFiltersNeeded=At least two filters needed.
 atomicPushNotSupported=Atomic push not supported.
 atomicRefUpdatesNotSupported=Atomic ref updates not supported
+atomicSymRefNotSupported=Atomic symref not supported
 authenticationNotSupported=authentication not supported
 badBase64InputCharacterAt=Bad Base64 input character at {0} : {1} (decimal)
 badEntryDelimiter=Bad entry delimiter
@@ -40,7 +41,10 @@
 blameNotCommittedYet=Not Committed Yet
 blobNotFound=Blob not found: {0}
 blobNotFoundForPath=Blob not found: {0} for path: {1}
+blockLimitNotMultipleOfBlockSize=blockLimit {0} must be a multiple of blockSize {1}
+blockLimitNotPositive=blockLimit must be positive: {0}
 blockSizeNotPowerOf2=blockSize must be a power of 2
+bothRefTargetsMustNotBeNull=both old and new ref targets must not be null.
 branchNameInvalid=Branch name {0} is not allowed
 buildingBitmaps=Building bitmaps
 cachedPacksPreventsIndexCreation=Using cached packs prevents index creation
@@ -113,6 +117,7 @@
 cantPassMeATree=Can't pass me a tree!
 channelMustBeInRange1_255=channel {0} must be in range [1, 255]
 characterClassIsNotSupported=The character class {0} is not supported.
+checkingOutFiles=Checking out files
 checkoutConflictWithFile=Checkout conflict with file: {0}
 checkoutConflictWithFiles=Checkout conflict with files: {0}
 checkoutUnexpectedResult=Checkout returned unexpected result {0}
@@ -128,6 +133,9 @@
 commitOnRepoWithoutHEADCurrentlyNotSupported=Commit on repo without HEAD currently not supported
 commitAmendOnInitialNotPossible=Amending is not possible on initial commit.
 compressingObjects=Compressing objects
+configSubsectionContainsNewline=config subsection name contains newline
+configSubsectionContainsNullByte=config subsection name contains byte 0x00
+configValueContainsNullByte=config value contains byte 0x00
 configHandleIsStale=config file handle is stale, {0}. retry
 connectionFailed=connection failed
 connectionTimeOut=Connection time out: {0}
@@ -216,6 +224,8 @@
 credentialUsername=Username
 daemonAlreadyRunning=Daemon already running
 daysAgo={0} days ago
+deepenNotWithDeepen=Cannot combine deepen with deepen-not
+deepenSinceWithDeepen=Cannot combine deepen with deepen-since
 deleteBranchUnexpectedResult=Delete branch returned unexpected result {0}
 deleteFileFailed=Could not delete file {0}
 deleteRequiresZeroNewId=Delete requires new ID to be zero
@@ -282,6 +292,7 @@
 expectedACKNAKGot=Expected ACK/NAK, got: {0}
 expectedBooleanStringValue=Expected boolean string value
 expectedCharacterEncodingGuesses=Expected {0} character encoding guesses
+expectedDirectoryNotSubmodule=Expected submodule ''{0}'' to be a directory
 expectedEOFReceived=expected EOF; received ''{0}'' instead
 expectedGot=expected ''{0}'', got ''{1}''
 expectedLessThanGot=expected less than ''{0}'', got ''{1}''
@@ -299,6 +310,7 @@
 fileModeNotSetForPath=FileMode not set for path {0}
 filterExecutionFailed=Execution of filter command ''{0}'' on file ''{1}'' failed
 filterExecutionFailedRc=Execution of filter command ''{0}'' on file ''{1}'' failed with return code ''{2}'', message on stderr: ''{3}''
+filterRequiresCapability=filter requires server to advertise that capability
 findingGarbage=Finding garbage
 flagIsDisposed={0} is disposed.
 flagNotFromThis={0} not from this.
@@ -350,6 +362,7 @@
 invalidDepth=Invalid depth: {0}
 invalidEncryption=Invalid encryption
 invalidExpandWildcard=ExpandFromSource on a refspec that can have mismatched wildcards does not make sense.
+invalidFilter=Invalid filter: {0}
 invalidGitdirRef = Invalid .git reference in file ''{0}''
 invalidGitType=invalid git type: {0}
 invalidId=Invalid id: {0}
@@ -360,6 +373,7 @@
 invalidIntegerValue=Invalid integer value: {0}.{1}={2}
 invalidKey=Invalid key: {0}
 invalidLineInConfigFile=Invalid line in config file
+invalidLineInConfigFileWithParam=Invalid line in config file: {0}
 invalidModeFor=Invalid mode {0} for {1} {2} in {3}.
 invalidModeForPath=Invalid mode {0} for path {1}
 invalidObject=Invalid {0} {1}: {2}
@@ -383,6 +397,7 @@
 invalidSystemProperty=Invalid system property ''{0}'': ''{1}''; using default value {2}
 invalidTagOption=Invalid tag option: {0}
 invalidTimeout=Invalid timeout: {0}
+invalidTimestamp=Invalid timestamp in {0}
 invalidTimeUnitValue2=Invalid time unit value: {0}.{1}={2}
 invalidTimeUnitValue3=Invalid time unit value: {0}.{1}.{2}={3}
 invalidTreeZeroLengthName=Cannot append a tree entry with zero-length name
@@ -398,6 +413,7 @@
 largeObjectException={0} exceeds size limit
 largeObjectOutOfMemory=Out of memory loading {0}
 lengthExceedsMaximumArraySize=Length exceeds maximum array size
+lfsHookConflict=LFS built-in hook conflicts with existing pre-push hook in repository {0}. Either remove the pre-push hook or disable built-in LFS support.
 listingAlternates=Listing alternates
 listingPacks=Listing packs
 localObjectsIncomplete=Local objects incomplete.
@@ -437,6 +453,7 @@
 months=months
 monthsAgo={0} months ago
 multipleMergeBasesFor=Multiple merge bases for:\n  {0}\n  {1} found:\n  {2}\n  {3}
+nameMustNotBeNullOrEmpty=Ref name must not be null or empty.
 need2Arguments=Need 2 arguments
 needPackOut=need packOut
 needsAtLeastOneEntry=Needs at least one entry
@@ -451,7 +468,9 @@
 noMergeBase=No merge base could be determined. Reason={0}. {1}
 noMergeHeadSpecified=No merge head specified
 nonBareLinkFilesNotSupported=Link files are not supported with nonbare repos
+noPathAttributesFound=No Attributes found for {0}.
 noSuchRef=no such ref
+noSuchSubmodule=no such submodule {0}
 notABoolean=Not a boolean: {0}
 notABundle=not a bundle
 notADIRCFile=Not a DIRC file.
@@ -651,6 +670,7 @@
 timeIsUncertain=Time is uncertain
 timerAlreadyTerminated=Timer already terminated
 tooManyCommands=Too many commands
+tooManyFilters=Too many "filter" lines in request
 tooManyIncludeRecursions=Too many recursions; circular includes in config file(s)?
 topologicalSortRequired=Topological sort required.
 transactionAborted=transaction aborted
@@ -692,9 +712,11 @@
 unexpectedEofInPack=Unexpected EOF in partially created pack
 unexpectedHunkTrailer=Unexpected hunk trailer
 unexpectedOddResult=odd: {0} + {1} - {2}
+unexpectedPacketLine=unexpected {0}
 unexpectedRefReport={0}: unexpected ref report: {1}
 unexpectedReportLine=unexpected report line: {0}
 unexpectedReportLine2={0} unexpected report line: {1}
+unexpectedSubmoduleStatus=Unexpected submodule status: ''{0}''
 unknownOrUnsupportedCommand=Unknown or unsupported command "{0}", only "{1}" is allowed.
 unknownDIRCVersion=Unknown DIRC version {0}
 unknownHost=unknown host
@@ -705,6 +727,7 @@
 unknownObjectType2=unknown
 unknownRepositoryFormat=Unknown repository format
 unknownRepositoryFormat2=Unknown repository format "{0}"; expected "0".
+unknownTransportCommand=unknown command {0}
 unknownZlibError=Unknown zlib error.
 unmergedPath=Unmerged path: {0}
 unmergedPaths=Repository contains unmerged paths
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/annotations/NonNull.java b/org.eclipse.jgit/src/org/eclipse/jgit/annotations/NonNull.java
index 08f81cb..1cc65c9 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/annotations/NonNull.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/annotations/NonNull.java
@@ -56,7 +56,7 @@
 /**
  * JGit's replacement for the {@code javax.annotation.Nonnull}.
  * <p>
- * Denotes that a local variable, parameter, field, method return value expected
+ * Denotes that a local variable, parameter, field, method return value is expected
  * to be non {@code null}.
  *
  * @since 4.2
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/annotations/Nullable.java b/org.eclipse.jgit/src/org/eclipse/jgit/annotations/Nullable.java
index 7b91567..f8a7a36 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/annotations/Nullable.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/annotations/Nullable.java
@@ -89,7 +89,6 @@
  * @see <a href=
  *      "http://types.cs.washington.edu/checker-framework/current/checker-framework-manual.html#faq-array-syntax-meaning">
  *      The checker-framework manual</a>
- *
  * @since 4.2
  */
 @Documented
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/AddCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/AddCommand.java
index 1ed7944..f0408ab 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/AddCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/AddCommand.java
@@ -91,8 +91,10 @@ public class AddCommand extends GitCommand<DirCache> {
 	private boolean update = false;
 
 	/**
+	 * Constructor for AddCommand
 	 *
 	 * @param repo
+	 *            the {@link org.eclipse.jgit.lib.Repository}
 	 */
 	public AddCommand(Repository repo) {
 		super(repo);
@@ -119,7 +121,10 @@ public AddCommand addFilepattern(String filepattern) {
 
 	/**
 	 * Allow clients to provide their own implementation of a FileTreeIterator
+	 *
 	 * @param f
+	 *            a {@link org.eclipse.jgit.treewalk.WorkingTreeIterator}
+	 *            object.
 	 * @return {@code this}
 	 */
 	public AddCommand setWorkingTreeIterator(WorkingTreeIterator f) {
@@ -128,11 +133,11 @@ public AddCommand setWorkingTreeIterator(WorkingTreeIterator f) {
 	}
 
 	/**
+	 * {@inheritDoc}
+	 * <p>
 	 * Executes the {@code Add} command. Each instance of this class should only
 	 * be used for one invocation of the command. Don't call this method twice
 	 * on an instance.
-	 *
-	 * @return the DirCache after Add
 	 */
 	@Override
 	public DirCache call() throws GitAPIException, NoFilepatternException {
@@ -260,17 +265,18 @@ public DirCache call() throws GitAPIException, NoFilepatternException {
 	}
 
 	/**
+	 * Set whether to only match against already tracked files
+	 *
 	 * @param update
 	 *            If set to true, the command only matches {@code filepattern}
 	 *            against already tracked files in the index rather than the
 	 *            working tree. That means that it will never stage new files,
 	 *            but that it will stage modified new contents of tracked files
 	 *            and that it will remove files from the index if the
-	 *            corresponding files in the working tree have been removed.
-	 *            In contrast to the git command line a {@code filepattern} must
-	 *            exist also if update is set to true as there is no
-	 *            concept of a working directory here.
-	 *
+	 *            corresponding files in the working tree have been removed. In
+	 *            contrast to the git command line a {@code filepattern} must
+	 *            exist also if update is set to true as there is no concept of
+	 *            a working directory here.
 	 * @return {@code this}
 	 */
 	public AddCommand setUpdate(boolean update) {
@@ -279,7 +285,9 @@ public AddCommand setUpdate(boolean update) {
 	}
 
 	/**
-	 * @return is the parameter update is set
+	 * Whether to only match against already tracked files
+	 *
+	 * @return whether to only match against already tracked files
 	 */
 	public boolean isUpdate() {
 		return update;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/AddNoteCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/AddNoteCommand.java
index fa88fb7..688f5f4 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/AddNoteCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/AddNoteCommand.java
@@ -75,12 +75,16 @@ public class AddNoteCommand extends GitCommand<Note> {
 	private String notesRef = Constants.R_NOTES_COMMITS;
 
 	/**
+	 * Constructor for AddNoteCommand
+	 *
 	 * @param repo
+	 *            the {@link org.eclipse.jgit.lib.Repository}
 	 */
 	protected AddNoteCommand(Repository repo) {
 		super(repo);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public Note call() throws GitAPIException {
 		checkCallable();
@@ -95,7 +99,7 @@ public Note call() throws GitAPIException {
 				map = NoteMap.read(walk.getObjectReader(), notesCommit);
 			}
 			map.set(id, message, inserter);
-			commitNoteMap(walk, map, notesCommit, inserter,
+			commitNoteMap(repo, notesRef, walk, map, notesCommit, inserter,
 					"Notes added by 'git notes add'"); //$NON-NLS-1$
 			return map.getNote(id);
 		} catch (IOException e) {
@@ -108,6 +112,7 @@ public Note call() throws GitAPIException {
 	 * has a note, the existing note will be replaced.
 	 *
 	 * @param id
+	 *            a {@link org.eclipse.jgit.revwalk.RevObject}
 	 * @return {@code this}
 	 */
 	public AddNoteCommand setObjectId(RevObject id) {
@@ -117,6 +122,8 @@ public AddNoteCommand setObjectId(RevObject id) {
 	}
 
 	/**
+	 * Set the notes message
+	 *
 	 * @param message
 	 *            the notes message used when adding a note
 	 * @return {@code this}
@@ -127,7 +134,8 @@ public AddNoteCommand setMessage(String message) {
 		return this;
 	}
 
-	private void commitNoteMap(RevWalk walk, NoteMap map,
+	static void commitNoteMap(Repository r, String ref, RevWalk walk,
+			NoteMap map,
 			RevCommit notesCommit,
 			ObjectInserter inserter,
 			String msg)
@@ -135,14 +143,14 @@ private void commitNoteMap(RevWalk walk, NoteMap map,
 		// commit the note
 		CommitBuilder builder = new CommitBuilder();
 		builder.setTreeId(map.writeTree(inserter));
-		builder.setAuthor(new PersonIdent(repo));
+		builder.setAuthor(new PersonIdent(r));
 		builder.setCommitter(builder.getAuthor());
 		builder.setMessage(msg);
 		if (notesCommit != null)
 			builder.setParentIds(notesCommit);
 		ObjectId commit = inserter.insert(builder);
 		inserter.flush();
-		RefUpdate refUpdate = repo.updateRef(notesRef);
+		RefUpdate refUpdate = r.updateRef(ref);
 		if (notesCommit != null)
 			refUpdate.setExpectedOldObjectId(notesCommit);
 		else
@@ -152,12 +160,13 @@ private void commitNoteMap(RevWalk walk, NoteMap map,
 	}
 
 	/**
+	 * Set name of a {@code Ref} to read notes from
+	 *
 	 * @param notesRef
 	 *            the ref to read notes from. Note, the default value of
-	 *            {@link Constants#R_NOTES_COMMITS} will be used if nothing is
-	 *            set
+	 *            {@link org.eclipse.jgit.lib.Constants#R_NOTES_COMMITS} will be
+	 *            used if nothing is set
 	 * @return {@code this}
-	 *
 	 * @see Constants#R_NOTES_COMMITS
 	 */
 	public AddNoteCommand setNotesRef(String notesRef) {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/ApplyCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/ApplyCommand.java
index ba5673d..5b84032 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/ApplyCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/ApplyCommand.java
@@ -87,6 +87,8 @@ public class ApplyCommand extends GitCommand<ApplyResult> {
 	}
 
 	/**
+	 * Set patch
+	 *
 	 * @param in
 	 *            the patch to apply
 	 * @return this instance
@@ -98,16 +100,13 @@ public ApplyCommand setPatch(InputStream in) {
 	}
 
 	/**
+	 * {@inheritDoc}
+	 * <p>
 	 * Executes the {@code ApplyCommand} command with all the options and
 	 * parameters collected by the setter methods (e.g.
 	 * {@link #setPatch(InputStream)} of this class. Each instance of this class
 	 * should only be used for one invocation of the command. Don't call this
 	 * method twice on an instance.
-	 *
-	 * @return an {@link ApplyResult} object representing the command result
-	 * @throws GitAPIException
-	 * @throws PatchFormatException
-	 * @throws PatchApplyException
 	 */
 	@Override
 	public ApplyResult call() throws GitAPIException, PatchFormatException,
@@ -259,9 +258,9 @@ private void apply(File f, FileHeader fh)
 		if (sb.length() > 0) {
 			sb.deleteCharAt(sb.length() - 1);
 		}
-		FileWriter fw = new FileWriter(f);
-		fw.write(sb.toString());
-		fw.close();
+		try (FileWriter fw = new FileWriter(f)) {
+			fw.write(sb.toString());
+		}
 
 		getRepository().getFS().setExecute(f, fh.getNewMode() == FileMode.EXECUTABLE_FILE);
 	}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/ApplyResult.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/ApplyResult.java
index 2ef6650..60561fc 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/ApplyResult.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/ApplyResult.java
@@ -47,7 +47,7 @@
 import java.util.List;
 
 /**
- * Encapsulates the result of a {@link ApplyCommand}
+ * Encapsulates the result of a {@link org.eclipse.jgit.api.ApplyCommand}
  *
  * @since 2.0
  */
@@ -56,6 +56,8 @@ public class ApplyResult {
 	private List<File> updatedFiles = new ArrayList<>();
 
 	/**
+	 * Add updated file
+	 *
 	 * @param f
 	 *            an updated file
 	 * @return this instance
@@ -67,6 +69,8 @@ public ApplyResult addUpdatedFile(File f) {
 	}
 
 	/**
+	 * Get updated files
+	 *
 	 * @return updated files
 	 */
 	public List<File> getUpdatedFiles() {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/ArchiveCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/ArchiveCommand.java
index 7ea8e73..27bb5a9 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/ArchiveCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/ArchiveCommand.java
@@ -70,19 +70,16 @@
 /**
  * Create an archive of files from a named tree.
  * <p>
- * Examples (<code>git</code> is a {@link Git} instance):
+ * Examples (<code>git</code> is a {@link org.eclipse.jgit.api.Git} instance):
  * <p>
  * Create a tarball from HEAD:
  *
  * <pre>
  * ArchiveCommand.registerFormat("tar", new TarFormat());
  * try {
- *	git.archive()
- *		.setTree(db.resolve(&quot;HEAD&quot;))
- *		.setOutputStream(out)
- *		.call();
+ * 	git.archive().setTree(db.resolve(&quot;HEAD&quot;)).setOutputStream(out).call();
  * } finally {
- *	ArchiveCommand.unregisterFormat("tar");
+ * 	ArchiveCommand.unregisterFormat("tar");
  * }
  * </pre>
  * <p>
@@ -103,7 +100,6 @@
  *
  * @see <a href="http://git-htmldocs.googlecode.com/git/git-archive.html" >Git
  *      documentation about archive</a>
- *
  * @since 3.1
  */
 public class ArchiveCommand extends GitCommand<OutputStream> {
@@ -161,30 +157,6 @@ T createArchiveOutputStream(OutputStream s, Map<String, Object> o)
 		 *
 		 * @param out
 		 *            archive object from createArchiveOutputStream
-		 * @param path
-		 *            full filename relative to the root of the archive (with
-		 *            trailing '/' for directories)
-		 * @param mode
-		 *            mode (for example FileMode.REGULAR_FILE or
-		 *            FileMode.SYMLINK)
-		 * @param loader
-		 *            blob object with data for this entry (null for
-		 *            directories)
-		 * @throws IOException
-		 *             thrown by the underlying output stream for I/O errors
-		 * @deprecated use
-		 *             {@link #putEntry(Closeable, ObjectId, String, FileMode, ObjectLoader)}
-		 *             instead
-		 */
-		@Deprecated
-		void putEntry(T out, String path, FileMode mode,
-					  ObjectLoader loader) throws IOException;
-
-		/**
-		 * Write an entry to an archive.
-		 *
-		 * @param out
-		 *            archive object from createArchiveOutputStream
 		 * @param tree
 		 *            the tag, commit, or tree object to produce an archive for
 		 * @param path
@@ -383,7 +355,10 @@ private static Format<?> lookupFormat(String formatName) throws UnsupportedForma
 	private String suffix;
 
 	/**
+	 * Constructor for ArchiveCommand
+	 *
 	 * @param repo
+	 *            the {@link org.eclipse.jgit.lib.Repository}
 	 */
 	public ArchiveCommand(Repository repo) {
 		super(repo);
@@ -393,9 +368,10 @@ public ArchiveCommand(Repository repo) {
 	private <T extends Closeable> OutputStream writeArchive(Format<T> fmt) {
 		try {
 			try (TreeWalk walk = new TreeWalk(repo);
-					RevWalk rw = new RevWalk(walk.getObjectReader())) {
+					RevWalk rw = new RevWalk(walk.getObjectReader());
+					T outa = fmt.createArchiveOutputStream(out,
+							formatOptions)) {
 				String pfx = prefix == null ? "" : prefix; //$NON-NLS-1$
-				T outa = fmt.createArchiveOutputStream(out, formatOptions);
 				MutableObjectId idBuf = new MutableObjectId();
 				ObjectReader reader = walk.getObjectReader();
 
@@ -428,7 +404,6 @@ private <T extends Closeable> OutputStream writeArchive(Format<T> fmt) {
 					walk.getObjectId(idBuf, 0);
 					fmt.putEntry(outa, tree, name, mode, reader.open(idBuf));
 				}
-				outa.close();
 				return out;
 			} finally {
 				out.close();
@@ -440,9 +415,7 @@ private <T extends Closeable> OutputStream writeArchive(Format<T> fmt) {
 		}
 	}
 
-	/**
-	 * @return the stream to which the archive has been written
-	 */
+	/** {@inheritDoc} */
 	@Override
 	public OutputStream call() throws GitAPIException {
 		checkCallable();
@@ -456,6 +429,8 @@ public OutputStream call() throws GitAPIException {
 	}
 
 	/**
+	 * Set the tag, commit, or tree object to produce an archive for
+	 *
 	 * @param tree
 	 *            the tag, commit, or tree object to produce an archive for
 	 * @return this
@@ -470,6 +445,8 @@ public ArchiveCommand setTree(ObjectId tree) {
 	}
 
 	/**
+	 * Set string prefixed to filenames in archive
+	 *
 	 * @param prefix
 	 *            string prefixed to filenames in archive (e.g., "master/").
 	 *            null means to not use any leading prefix.
@@ -502,8 +479,10 @@ public ArchiveCommand setFilename(String filename) {
 	}
 
 	/**
+	 * Set output stream
+	 *
 	 * @param out
-	 *	      the stream to which to write the archive
+	 *            the stream to which to write the archive
 	 * @return this
 	 */
 	public ArchiveCommand setOutputStream(OutputStream out) {
@@ -512,10 +491,11 @@ public ArchiveCommand setOutputStream(OutputStream out) {
 	}
 
 	/**
+	 * Set archive format
+	 *
 	 * @param fmt
-	 *	      archive format (e.g., "tar" or "zip").
-	 *	      null means to choose automatically based on
-	 *	      the archive filename.
+	 *            archive format (e.g., "tar" or "zip"). null means to choose
+	 *            automatically based on the archive filename.
 	 * @return this
 	 */
 	public ArchiveCommand setFormat(String fmt) {
@@ -524,6 +504,8 @@ public ArchiveCommand setFormat(String fmt) {
 	}
 
 	/**
+	 * Set archive format options
+	 *
 	 * @param options
 	 *            archive format options (e.g., level=9 for zip compression).
 	 * @return this
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/BlameCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/BlameCommand.java
index b1c81ff..f7576e9 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/BlameCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/BlameCommand.java
@@ -69,7 +69,8 @@
 import org.eclipse.jgit.util.io.AutoLFInputStream;
 
 /**
- * Blame command for building a {@link BlameResult} for a file path.
+ * Blame command for building a {@link org.eclipse.jgit.blame.BlameResult} for a
+ * file path.
  */
 public class BlameCommand extends GitCommand<BlameResult> {
 
@@ -86,7 +87,10 @@ public class BlameCommand extends GitCommand<BlameResult> {
 	private Boolean followFileRenames;
 
 	/**
+	 * Constructor for BlameCommand
+	 *
 	 * @param repo
+	 *            the {@link org.eclipse.jgit.lib.Repository}
 	 */
 	public BlameCommand(Repository repo) {
 		super(repo);
@@ -108,6 +112,7 @@ public BlameCommand setFilePath(String filePath) {
 	 * Set diff algorithm
 	 *
 	 * @param diffAlgorithm
+	 *            a {@link org.eclipse.jgit.diff.DiffAlgorithm} object.
 	 * @return this command
 	 */
 	public BlameCommand setDiffAlgorithm(DiffAlgorithm diffAlgorithm) {
@@ -119,6 +124,7 @@ public BlameCommand setDiffAlgorithm(DiffAlgorithm diffAlgorithm) {
 	 * Set raw text comparator
 	 *
 	 * @param textComparator
+	 *            a {@link org.eclipse.jgit.diff.RawTextComparator}
 	 * @return this command
 	 */
 	public BlameCommand setTextComparator(RawTextComparator textComparator) {
@@ -130,6 +136,7 @@ public BlameCommand setTextComparator(RawTextComparator textComparator) {
 	 * Set start commit id
 	 *
 	 * @param commit
+	 *            id of a commit
 	 * @return this command
 	 */
 	public BlameCommand setStartCommit(AnyObjectId commit) {
@@ -164,7 +171,7 @@ public BlameCommand setFollowFileRenames(boolean follow) {
 	 *            most recent commit to stop traversal at. Usually an active
 	 *            branch tip, tag, or HEAD.
 	 * @return {@code this}
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the repository cannot be read.
 	 */
 	public BlameCommand reverse(AnyObjectId start, AnyObjectId end)
@@ -182,7 +189,7 @@ public BlameCommand reverse(AnyObjectId start, AnyObjectId end)
 	 *            most recent commits to stop traversal at. Usually an active
 	 *            branch tip, tag, or HEAD.
 	 * @return {@code this}
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the repository cannot be read.
 	 */
 	public BlameCommand reverse(AnyObjectId start, Collection<ObjectId> end)
@@ -193,10 +200,10 @@ public BlameCommand reverse(AnyObjectId start, Collection<ObjectId> end)
 	}
 
 	/**
+	 * {@inheritDoc}
+	 * <p>
 	 * Generate a list of lines with information about when the lines were
 	 * introduced into the file path.
-	 *
-	 * @return list of lines
 	 */
 	@Override
 	public BlameResult call() throws GitAPIException {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/CheckoutCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/CheckoutCommand.java
index 6b20da3..11edb10 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/CheckoutCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/CheckoutCommand.java
@@ -43,6 +43,8 @@
  */
 package org.eclipse.jgit.api;
 
+import static org.eclipse.jgit.treewalk.TreeWalk.OperationType.CHECKOUT_OP;
+
 import java.io.IOException;
 import java.text.MessageFormat;
 import java.util.ArrayList;
@@ -74,8 +76,10 @@
 import org.eclipse.jgit.lib.Constants;
 import org.eclipse.jgit.lib.CoreConfig.EolStreamType;
 import org.eclipse.jgit.lib.FileMode;
+import org.eclipse.jgit.lib.NullProgressMonitor;
 import org.eclipse.jgit.lib.ObjectId;
 import org.eclipse.jgit.lib.ObjectReader;
+import org.eclipse.jgit.lib.ProgressMonitor;
 import org.eclipse.jgit.lib.Ref;
 import org.eclipse.jgit.lib.RefUpdate;
 import org.eclipse.jgit.lib.RefUpdate.Result;
@@ -89,7 +93,7 @@
 /**
  * Checkout a branch to the working tree.
  * <p>
- * Examples (<code>git</code> is a {@link Git} instance):
+ * Examples (<code>git</code> is a {@link org.eclipse.jgit.api.Git} instance):
  * <p>
  * Check out an existing branch:
  *
@@ -124,9 +128,9 @@
  * 		.setStartPoint(&quot;origin/stable&quot;).call();
  * </pre>
  *
- * @see <a
- *      href="http://www.kernel.org/pub/software/scm/git/docs/git-checkout.html"
- *      >Git documentation about Checkout</a>
+ * @see <a href=
+ *      "http://www.kernel.org/pub/software/scm/git/docs/git-checkout.html" >Git
+ *      documentation about Checkout</a>
  */
 public class CheckoutCommand extends GitCommand<Ref> {
 
@@ -180,27 +184,20 @@ private Stage(int number) {
 
 	private Set<String> actuallyModifiedPaths;
 
+	private ProgressMonitor monitor = NullProgressMonitor.INSTANCE;
+
 	/**
+	 * Constructor for CheckoutCommand
+	 *
 	 * @param repo
+	 *            the {@link org.eclipse.jgit.lib.Repository}
 	 */
 	protected CheckoutCommand(Repository repo) {
 		super(repo);
 		this.paths = new LinkedList<>();
 	}
 
-	/**
-	 * @throws RefAlreadyExistsException
-	 *             when trying to create (without force) a branch with a name
-	 *             that already exists
-	 * @throws RefNotFoundException
-	 *             if the start point or branch can not be found
-	 * @throws InvalidRefNameException
-	 *             if the provided name is <code>null</code> or otherwise
-	 *             invalid
-	 * @throws CheckoutConflictException
-	 *             if the checkout results in a conflict
-	 * @return the newly created branch
-	 */
+	/** {@inheritDoc} */
 	@Override
 	public Ref call() throws GitAPIException, RefAlreadyExistsException,
 			RefNotFoundException, InvalidRefNameException,
@@ -273,6 +270,7 @@ public Ref call() throws GitAPIException, RefAlreadyExistsException,
 				dco = new DirCacheCheckout(repo, headTree, dc,
 						newCommit.getTree());
 				dco.setFailOnConflict(true);
+				dco.setProgressMonitor(monitor);
 				try {
 					dco.checkout();
 				} catch (org.eclipse.jgit.errors.CheckoutConflictException e) {
@@ -354,6 +352,20 @@ private String getShortBranchName(Ref headRef) {
 	}
 
 	/**
+	 * @param monitor
+	 *            a progress monitor
+	 * @return this instance
+	 * @since 4.11
+	 */
+	public CheckoutCommand setProgressMonitor(ProgressMonitor monitor) {
+		if (monitor == null) {
+			monitor = NullProgressMonitor.INSTANCE;
+		}
+		this.monitor = monitor;
+		return this;
+	}
+
+	/**
 	 * Add a single slash-separated path to the list of paths to check out. To
 	 * check out all paths, use {@link #setAllPaths(boolean)}.
 	 * <p>
@@ -416,11 +428,12 @@ public CheckoutCommand setAllPaths(boolean all) {
 
 	/**
 	 * Checkout paths into index and working directory, firing a
-	 * {@link WorkingTreeModifiedEvent} if the working tree was modified.
+	 * {@link org.eclipse.jgit.events.WorkingTreeModifiedEvent} if the working
+	 * tree was modified.
 	 *
 	 * @return this instance
-	 * @throws IOException
-	 * @throws RefNotFoundException
+	 * @throws java.io.IOException
+	 * @throws org.eclipse.jgit.api.errors.RefNotFoundException
 	 */
 	protected CheckoutCommand checkoutPaths() throws IOException,
 			RefNotFoundException {
@@ -468,7 +481,8 @@ private void checkoutPathsFromIndex(TreeWalk treeWalk, DirCache dc)
 			if (path.equals(previousPath))
 				continue;
 
-			final EolStreamType eolStreamType = treeWalk.getEolStreamType();
+			final EolStreamType eolStreamType = treeWalk
+					.getEolStreamType(CHECKOUT_OP);
 			final String filterCommand = treeWalk
 					.getFilterCommand(Constants.ATTR_FILTER_TYPE_SMUDGE);
 			editor.add(new PathEdit(path) {
@@ -508,7 +522,8 @@ private void checkoutPathsFromCommit(TreeWalk treeWalk, DirCache dc,
 		while (treeWalk.next()) {
 			final ObjectId blobId = treeWalk.getObjectId(0);
 			final FileMode mode = treeWalk.getFileMode(0);
-			final EolStreamType eolStreamType = treeWalk.getEolStreamType();
+			final EolStreamType eolStreamType = treeWalk
+					.getEolStreamType(CHECKOUT_OP);
 			final String filterCommand = treeWalk
 					.getFilterCommand(Constants.ATTR_FILTER_TYPE_SMUDGE);
 			final String path = treeWalk.getPathString();
@@ -735,6 +750,8 @@ public CheckoutCommand setStage(Stage stage) {
 	}
 
 	/**
+	 * Get the result, never <code>null</code>
+	 *
 	 * @return the result, never <code>null</code>
 	 */
 	public CheckoutResult getResult() {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/CheckoutResult.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/CheckoutResult.java
index 2186eb4..16f4685 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/CheckoutResult.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/CheckoutResult.java
@@ -46,8 +46,7 @@
 import java.util.List;
 
 /**
- * Encapsulates the result of a {@link CheckoutCommand}
- *
+ * Encapsulates the result of a {@link org.eclipse.jgit.api.CheckoutCommand}
  */
 public class CheckoutResult {
 
@@ -168,6 +167,8 @@ public enum Status {
 	}
 
 	/**
+	 * Get status
+	 *
 	 * @return the status
 	 */
 	public Status getStatus() {
@@ -175,33 +176,44 @@ public Status getStatus() {
 	}
 
 	/**
+	 * Get list of file that created a checkout conflict
+	 *
 	 * @return the list of files that created a checkout conflict, or an empty
-	 *         list if {@link #getStatus()} is not {@link Status#CONFLICTS};
+	 *         list if {@link #getStatus()} is not
+	 *         {@link org.eclipse.jgit.api.CheckoutResult.Status#CONFLICTS};
 	 */
 	public List<String> getConflictList() {
 		return conflictList;
 	}
 
 	/**
+	 * Get the list of files that could not be deleted during checkout
+	 *
 	 * @return the list of files that could not be deleted during checkout, or
 	 *         an empty list if {@link #getStatus()} is not
-	 *         {@link Status#NONDELETED};
+	 *         {@link org.eclipse.jgit.api.CheckoutResult.Status#NONDELETED};
 	 */
 	public List<String> getUndeletedList() {
 		return undeletedList;
 	}
 
 	/**
+	 * Get the list of files that where modified during checkout
+	 *
 	 * @return the list of files that where modified during checkout, or an
-	 *         empty list if {@link #getStatus()} is not {@link Status#OK}
+	 *         empty list if {@link #getStatus()} is not
+	 *         {@link org.eclipse.jgit.api.CheckoutResult.Status#OK}
 	 */
 	public List<String> getModifiedList() {
 		return modifiedList;
 	}
 
 	/**
+	 * Get the list of files that where removed during checkout
+	 *
 	 * @return the list of files that where removed during checkout, or an empty
-	 *         list if {@link #getStatus()} is not {@link Status#OK}
+	 *         list if {@link #getStatus()} is not
+	 *         {@link org.eclipse.jgit.api.CheckoutResult.Status#OK}
 	 */
 	public List<String> getRemovedList() {
 		return removedList;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/CherryPickCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/CherryPickCommand.java
index eed7b2a..65b72f7 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/CherryPickCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/CherryPickCommand.java
@@ -60,8 +60,10 @@
 import org.eclipse.jgit.internal.JGitText;
 import org.eclipse.jgit.lib.AnyObjectId;
 import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.NullProgressMonitor;
 import org.eclipse.jgit.lib.ObjectId;
 import org.eclipse.jgit.lib.ObjectIdRef;
+import org.eclipse.jgit.lib.ProgressMonitor;
 import org.eclipse.jgit.lib.Ref;
 import org.eclipse.jgit.lib.Ref.Storage;
 import org.eclipse.jgit.lib.Repository;
@@ -95,26 +97,25 @@ public class CherryPickCommand extends GitCommand<CherryPickResult> {
 
 	private boolean noCommit = false;
 
+	private ProgressMonitor monitor = NullProgressMonitor.INSTANCE;
+
 	/**
+	 * Constructor for CherryPickCommand
+	 *
 	 * @param repo
+	 *            the {@link org.eclipse.jgit.lib.Repository}
 	 */
 	protected CherryPickCommand(Repository repo) {
 		super(repo);
 	}
 
 	/**
+	 * {@inheritDoc}
+	 * <p>
 	 * Executes the {@code Cherry-Pick} command with all the options and
 	 * parameters collected by the setter methods (e.g. {@link #include(Ref)} of
 	 * this class. Each instance of this class should only be used for one
 	 * invocation of the command. Don't call this method twice on an instance.
-	 *
-	 * @return the result of the cherry-pick
-	 * @throws GitAPIException
-	 * @throws WrongRepositoryStateException
-	 * @throws ConcurrentRefUpdateException
-	 * @throws UnmergedPathsException
-	 * @throws NoMessageException
-	 * @throws NoHeadException
 	 */
 	@Override
 	public CherryPickResult call() throws GitAPIException, NoMessageException,
@@ -163,6 +164,7 @@ public CherryPickResult call() throws GitAPIException, NoMessageException,
 							newHead.getTree(), repo.lockDirCache(),
 							merger.getResultTreeId());
 					dco.setFailOnConflict(true);
+					dco.setProgressMonitor(monitor);
 					dco.checkout();
 					if (!noCommit)
 						newHead = new Git(getRepository()).commit()
@@ -224,6 +226,8 @@ private RevCommit getParentCommit(RevCommit srcCommit, RevWalk revWalk)
 	}
 
 	/**
+	 * Include a reference to a commit
+	 *
 	 * @param commit
 	 *            a reference to a commit which is cherry-picked to the current
 	 *            head
@@ -236,6 +240,8 @@ public CherryPickCommand include(Ref commit) {
 	}
 
 	/**
+	 * Include a commit
+	 *
 	 * @param commit
 	 *            the Id of a commit which is cherry-picked to the current head
 	 * @return {@code this}
@@ -245,6 +251,8 @@ public CherryPickCommand include(AnyObjectId commit) {
 	}
 
 	/**
+	 * Include a commit
+	 *
 	 * @param name
 	 *            a name given to the commit
 	 * @param commit
@@ -257,6 +265,8 @@ public CherryPickCommand include(String name, AnyObjectId commit) {
 	}
 
 	/**
+	 * Set the name that should be used in the "OURS" place for conflict markers
+	 *
 	 * @param ourCommitName
 	 *            the name that should be used in the "OURS" place for conflict
 	 *            markers
@@ -278,12 +288,14 @@ public CherryPickCommand setOurCommitName(String ourCommitName) {
 	 * @return {@code this}
 	 * @since 3.1
 	 */
-	public CherryPickCommand setReflogPrefix(final String prefix) {
+	public CherryPickCommand setReflogPrefix(String prefix) {
 		this.reflogPrefix = prefix;
 		return this;
 	}
 
 	/**
+	 * Set the {@code MergeStrategy}
+	 *
 	 * @param strategy
 	 *            The merge strategy to use during this Cherry-pick.
 	 * @return {@code this}
@@ -295,6 +307,8 @@ public CherryPickCommand setStrategy(MergeStrategy strategy) {
 	}
 
 	/**
+	 * Set the (1-based) parent number to diff against
+	 *
 	 * @param mainlineParentNumber
 	 *            the (1-based) parent number to diff against. This allows
 	 *            cherry-picking of merges.
@@ -323,6 +337,24 @@ public CherryPickCommand setNoCommit(boolean noCommit) {
 		return this;
 	}
 
+	/**
+	 * The progress monitor associated with the cherry-pick operation. By
+	 * default, this is set to <code>NullProgressMonitor</code>
+	 *
+	 * @see NullProgressMonitor
+	 * @param monitor
+	 *            a {@link org.eclipse.jgit.lib.ProgressMonitor}
+	 * @return {@code this}
+	 * @since 4.11
+	 */
+	public CherryPickCommand setProgressMonitor(ProgressMonitor monitor) {
+		if (monitor == null) {
+			monitor = NullProgressMonitor.INSTANCE;
+		}
+		this.monitor = monitor;
+		return this;
+	}
+
 	private String calculateOurName(Ref headRef) {
 		if (ourCommitName != null)
 			return ourCommitName;
@@ -332,6 +364,7 @@ private String calculateOurName(Ref headRef) {
 		return headName;
 	}
 
+	/** {@inheritDoc} */
 	@SuppressWarnings("nls")
 	@Override
 	public String toString() {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/CherryPickResult.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/CherryPickResult.java
index b121291..ff55aeb 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/CherryPickResult.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/CherryPickResult.java
@@ -46,12 +46,11 @@
 import java.util.Map;
 
 import org.eclipse.jgit.lib.Ref;
-import org.eclipse.jgit.merge.ResolveMerger;
 import org.eclipse.jgit.merge.ResolveMerger.MergeFailureReason;
 import org.eclipse.jgit.revwalk.RevCommit;
 
 /**
- * Encapsulates the result of a {@link CherryPickCommand}.
+ * Encapsulates the result of a {@link org.eclipse.jgit.api.CherryPickCommand}.
  */
 public class CherryPickResult {
 
@@ -91,6 +90,8 @@ public String toString() {
 	private final Map<String, MergeFailureReason> failingPaths;
 
 	/**
+	 * Constructor for CherryPickResult
+	 *
 	 * @param newHead
 	 *            commit the head points at after this cherry-pick
 	 * @param cherryPickedRefs
@@ -104,9 +105,12 @@ public CherryPickResult(RevCommit newHead, List<Ref> cherryPickedRefs) {
 	}
 
 	/**
+	 * Constructor for CherryPickResult
+	 *
 	 * @param failingPaths
 	 *            list of paths causing this cherry-pick to fail (see
-	 *            {@link ResolveMerger#getFailingPaths()} for details)
+	 *            {@link org.eclipse.jgit.merge.ResolveMerger#getFailingPaths()}
+	 *            for details)
 	 */
 	public CherryPickResult(Map<String, MergeFailureReason> failingPaths) {
 		this.status = CherryPickStatus.FAILED;
@@ -130,6 +134,8 @@ private CherryPickResult(CherryPickStatus status) {
 			CherryPickStatus.CONFLICTING);
 
 	/**
+	 * Get status
+	 *
 	 * @return the status this cherry-pick resulted in
 	 */
 	public CherryPickStatus getStatus() {
@@ -137,28 +143,34 @@ public CherryPickStatus getStatus() {
 	}
 
 	/**
+	 * Get the new head after this cherry-pick
+	 *
 	 * @return the commit the head points at after this cherry-pick,
 	 *         <code>null</code> if {@link #getStatus} is not
-	 *         {@link CherryPickStatus#OK}
+	 *         {@link org.eclipse.jgit.api.CherryPickResult.CherryPickStatus#OK}
 	 */
 	public RevCommit getNewHead() {
 		return newHead;
 	}
 
 	/**
+	 * Get the cherry-picked {@code Ref}s
+	 *
 	 * @return the list of successfully cherry-picked <code>Ref</code>'s,
 	 *         <code>null</code> if {@link #getStatus} is not
-	 *         {@link CherryPickStatus#OK}
+	 *         {@link org.eclipse.jgit.api.CherryPickResult.CherryPickStatus#OK}
 	 */
 	public List<Ref> getCherryPickedRefs() {
 		return cherryPickedRefs;
 	}
 
 	/**
+	 * Get the list of paths causing this cherry-pick to fail
+	 *
 	 * @return the list of paths causing this cherry-pick to fail (see
-	 *         {@link ResolveMerger#getFailingPaths()} for details),
-	 *         <code>null</code> if {@link #getStatus} is not
-	 *         {@link CherryPickStatus#FAILED}
+	 *         {@link org.eclipse.jgit.merge.ResolveMerger#getFailingPaths()}
+	 *         for details), <code>null</code> if {@link #getStatus} is not
+	 *         {@link org.eclipse.jgit.api.CherryPickResult.CherryPickStatus#FAILED}
 	 */
 	public Map<String, MergeFailureReason> getFailingPaths() {
 		return failingPaths;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/CleanCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/CleanCommand.java
index e41a03b..0d9fe41 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/CleanCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/CleanCommand.java
@@ -79,21 +79,22 @@ public class CleanCommand extends GitCommand<Set<String>> {
 	private boolean force = false;
 
 	/**
+	 * Constructor for CleanCommand
+	 *
 	 * @param repo
+	 *            the {@link org.eclipse.jgit.lib.Repository}
 	 */
 	protected CleanCommand(Repository repo) {
 		super(repo);
 	}
 
 	/**
+	 * {@inheritDoc}
+	 * <p>
 	 * Executes the {@code clean} command with all the options and parameters
 	 * collected by the setter methods of this class. Each instance of this
 	 * class should only be used for one invocation of the command (means: one
 	 * call to {@link #call()})
-	 *
-	 * @return a set of strings representing each file cleaned.
-	 * @throws GitAPIException
-	 * @throws NoWorkTreeException
 	 */
 	@Override
 	public Set<String> call() throws NoWorkTreeException, GitAPIException {
@@ -102,27 +103,25 @@ public Set<String> call() throws NoWorkTreeException, GitAPIException {
 			StatusCommand command = new StatusCommand(repo);
 			Status status = command.call();
 
-			Set<String> untrackedAndIgnoredFiles = new TreeSet<>(
-					status.getUntracked());
-			Set<String> untrackedAndIgnoredDirs = new TreeSet<>(
+			Set<String> untrackedFiles = new TreeSet<>(status.getUntracked());
+			Set<String> untrackedDirs = new TreeSet<>(
 					status.getUntrackedFolders());
 
 			FS fs = getRepository().getFS();
 			for (String p : status.getIgnoredNotInIndex()) {
 				File f = new File(repo.getWorkTree(), p);
-				if (fs.isFile(f) || fs.isSymLink(f))
-					untrackedAndIgnoredFiles.add(p);
-				else if (fs.isDirectory(f))
-					untrackedAndIgnoredDirs.add(p);
+				if (fs.isFile(f) || fs.isSymLink(f)) {
+					untrackedFiles.add(p);
+				} else if (fs.isDirectory(f)) {
+					untrackedDirs.add(p);
+				}
 			}
 
-			Set<String> filtered = filterFolders(untrackedAndIgnoredFiles,
-					untrackedAndIgnoredDirs);
+			Set<String> filtered = filterFolders(untrackedFiles, untrackedDirs);
 
 			Set<String> notIgnoredFiles = filterIgnorePaths(filtered,
 					status.getIgnoredNotInIndex(), true);
-			Set<String> notIgnoredDirs = filterIgnorePaths(
-					untrackedAndIgnoredDirs,
+			Set<String> notIgnoredDirs = filterIgnorePaths(untrackedDirs,
 					status.getIgnoredNotInIndex(), false);
 
 			for (String file : notIgnoredFiles)
@@ -173,20 +172,22 @@ private Set<String> cleanPath(String path, Set<String> inFiles)
 				if (new File(curFile, DOT_GIT).exists()) {
 					if (force) {
 						if (!dryRun) {
-							FileUtils.delete(curFile, FileUtils.RECURSIVE);
+							FileUtils.delete(curFile, FileUtils.RECURSIVE
+									| FileUtils.SKIP_MISSING);
 						}
 						inFiles.add(path + "/"); //$NON-NLS-1$
 					}
 				} else {
 					if (!dryRun) {
-						FileUtils.delete(curFile, FileUtils.RECURSIVE);
+						FileUtils.delete(curFile,
+								FileUtils.RECURSIVE | FileUtils.SKIP_MISSING);
 					}
 					inFiles.add(path + "/"); //$NON-NLS-1$
 				}
 			}
 		} else {
 			if (!dryRun) {
-				FileUtils.delete(curFile, FileUtils.NONE);
+				FileUtils.delete(curFile, FileUtils.SKIP_MISSING);
 			}
 			inFiles.add(path);
 		}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/CloneCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/CloneCommand.java
index bde8e63..5c06bac 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/CloneCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/CloneCommand.java
@@ -77,8 +77,8 @@
 import org.eclipse.jgit.transport.RemoteConfig;
 import org.eclipse.jgit.transport.TagOpt;
 import org.eclipse.jgit.transport.URIish;
-import org.eclipse.jgit.util.FS;
 import org.eclipse.jgit.util.FileUtils;
+import org.eclipse.jgit.util.FS;
 
 /**
  * Clone a repository into a new working directory
@@ -96,6 +96,8 @@ public class CloneCommand extends TransportCommand<CloneCommand, Git> {
 
 	private boolean bare;
 
+	private FS fs;
+
 	private String remote = Constants.DEFAULT_REMOTE_NAME;
 
 	private String branch = Constants.HEAD;
@@ -168,6 +170,8 @@ File getDirectory() {
 	}
 
 	/**
+	 * {@inheritDoc}
+	 * <p>
 	 * Executes the {@code Clone} command.
 	 *
 	 * The Git instance returned by this command needs to be closed by the
@@ -175,11 +179,6 @@ File getDirectory() {
 	 * instance. It is recommended to call this method as soon as you don't need
 	 * a reference to this {@link Git} instance and the underlying
 	 * {@link Repository} instance anymore.
-	 *
-	 * @return the newly created {@code Git} object with associated repository
-	 * @throws InvalidRemoteException
-	 * @throws org.eclipse.jgit.api.errors.TransportException
-	 * @throws GitAPIException
 	 */
 	@Override
 	public Git call() throws GitAPIException, InvalidRemoteException,
@@ -192,12 +191,12 @@ public Git call() throws GitAPIException, InvalidRemoteException,
 			throw new InvalidRemoteException(
 					MessageFormat.format(JGitText.get().invalidURL, uri));
 		}
-		Repository repository = null;
+		@SuppressWarnings("resource") // Closed by caller
+		Repository repository = init();
 		FetchResult fetchResult = null;
 		Thread cleanupHook = new Thread(() -> cleanup());
 		Runtime.getRuntime().addShutdownHook(cleanupHook);
 		try {
-			repository = init();
 			fetchResult = fetch(repository, u);
 		} catch (IOException ioe) {
 			if (repository != null) {
@@ -263,6 +262,9 @@ void verifyDirectories(URIish u) {
 	private Repository init() throws GitAPIException {
 		InitCommand command = Git.init();
 		command.setBare(bare);
+		if (fs != null) {
+			command.setFs(fs);
+		}
 		if (directory != null) {
 			command.setDirectory(directory);
 		}
@@ -304,7 +306,7 @@ private FetchResult fetch(Repository clonedRepo, URIish u)
 		return command.call();
 	}
 
-	private List<RefSpec> calculateRefSpecs(final String dst) {
+	private List<RefSpec> calculateRefSpecs(String dst) {
 		RefSpec wcrs = new RefSpec();
 		wcrs = wcrs.setForceUpdate(true);
 		wcrs = wcrs.setSourceDestination(Constants.R_HEADS + "*", dst); //$NON-NLS-1$
@@ -313,7 +315,7 @@ private List<RefSpec> calculateRefSpecs(final String dst) {
 			specs.add(wcrs);
 		else if (branchesToClone != null
 				&& branchesToClone.size() > 0) {
-			for (final String selectedRef : branchesToClone)
+			for (String selectedRef : branchesToClone)
 				if (wcrs.matchSource(selectedRef))
 					specs.add(wcrs.expandFromSource(selectedRef));
 		}
@@ -359,6 +361,7 @@ private void checkout(Repository clonedRepo, FetchResult result)
 			DirCache dc = clonedRepo.lockDirCache();
 			DirCacheCheckout co = new DirCacheCheckout(clonedRepo, dc,
 					commit.getTree());
+			co.setProgressMonitor(monitor);
 			co.checkout();
 			if (cloneSubmodules)
 				cloneSubmodules(clonedRepo);
@@ -383,12 +386,9 @@ private void cloneSubmodules(Repository clonedRepo) throws IOException,
 		if (!update.call().isEmpty()) {
 			SubmoduleWalk walk = SubmoduleWalk.forIndex(clonedRepo);
 			while (walk.next()) {
-				Repository subRepo = walk.getRepository();
-				if (subRepo != null) {
-					try {
+				try (Repository subRepo = walk.getRepository()) {
+					if (subRepo != null) {
 						cloneSubmodules(subRepo);
-					} finally {
-						subRepo.close();
 					}
 				}
 			}
@@ -410,7 +410,7 @@ private Ref findBranchToCheckout(FetchResult result) {
 		}
 
 		Ref foundBranch = null;
-		for (final Ref r : result.getAdvertisedRefs()) {
+		for (Ref r : result.getAdvertisedRefs()) {
 			final String n = r.getName();
 			if (!n.startsWith(Constants.R_HEADS))
 				continue;
@@ -440,20 +440,22 @@ private void addMergeConfig(Repository clonedRepo, Ref head)
 		clonedRepo.getConfig().save();
 	}
 
-	private RevCommit parseCommit(final Repository clonedRepo, final Ref ref)
+	private RevCommit parseCommit(Repository clonedRepo, Ref ref)
 			throws MissingObjectException, IncorrectObjectTypeException,
 			IOException {
 		final RevCommit commit;
-		try (final RevWalk rw = new RevWalk(clonedRepo)) {
+		try (RevWalk rw = new RevWalk(clonedRepo)) {
 			commit = rw.parseCommit(ref.getObjectId());
 		}
 		return commit;
 	}
 
 	/**
+	 * Set the URI to clone from
+	 *
 	 * @param uri
-	 *            the URI to clone from, or {@code null} to unset the URI.
-	 *            The URI must be set before {@link #call} is called.
+	 *            the URI to clone from, or {@code null} to unset the URI. The
+	 *            URI must be set before {@link #call} is called.
 	 * @return this instance
 	 */
 	public CloneCommand setURI(String uri) {
@@ -466,12 +468,11 @@ public CloneCommand setURI(String uri) {
 	 * directory isn't set, a name associated with the source uri will be used.
 	 *
 	 * @see URIish#getHumanishName()
-	 *
 	 * @param directory
 	 *            the directory to clone to, or {@code null} if the directory
 	 *            name should be taken from the source uri
 	 * @return this instance
-	 * @throws IllegalStateException
+	 * @throws java.lang.IllegalStateException
 	 *             if the combination of directory, gitDir and bare is illegal.
 	 *             E.g. if for a non-bare repository directory and gitDir point
 	 *             to the same directory of if for a bare repository both
@@ -484,11 +485,13 @@ public CloneCommand setDirectory(File directory) {
 	}
 
 	/**
+	 * Set the repository meta directory (.git)
+	 *
 	 * @param gitDir
 	 *            the repository meta directory, or {@code null} to choose one
 	 *            automatically at clone time
 	 * @return this instance
-	 * @throws IllegalStateException
+	 * @throws java.lang.IllegalStateException
 	 *             if the combination of directory, gitDir and bare is illegal.
 	 *             E.g. if for a non-bare repository directory and gitDir point
 	 *             to the same directory of if for a bare repository both
@@ -502,10 +505,12 @@ public CloneCommand setGitDir(File gitDir) {
 	}
 
 	/**
+	 * Set whether the cloned repository shall be bare
+	 *
 	 * @param bare
 	 *            whether the cloned repository is bare or not
 	 * @return this instance
-	 * @throws IllegalStateException
+	 * @throws java.lang.IllegalStateException
 	 *             if the combination of directory, gitDir and bare is illegal.
 	 *             E.g. if for a non-bare repository directory and gitDir point
 	 *             to the same directory of if for a bare repository both
@@ -518,6 +523,20 @@ public CloneCommand setBare(boolean bare) throws IllegalStateException {
 	}
 
 	/**
+	 * Set the file system abstraction to be used for repositories created by
+	 * this command.
+	 *
+	 * @param fs
+	 *            the abstraction.
+	 * @return {@code this} (for chaining calls).
+	 * @since 4.10
+	 */
+	public CloneCommand setFs(FS fs) {
+		this.fs = fs;
+		return this;
+	}
+
+	/**
 	 * The remote name used to keep track of the upstream repository for the
 	 * clone operation. If no remote name is set, the default value of
 	 * <code>Constants.DEFAULT_REMOTE_NAME</code> will be used.
@@ -537,13 +556,15 @@ public CloneCommand setRemote(String remote) {
 	}
 
 	/**
+	 * Set the initial branch
+	 *
 	 * @param branch
 	 *            the initial branch to check out when cloning the repository.
 	 *            Can be specified as ref name (<code>refs/heads/master</code>),
-	 *            branch name (<code>master</code>) or tag name (<code>v1.2.3</code>).
-	 *            The default is to use the branch pointed to by the cloned
-	 *            repository's HEAD and can be requested by passing {@code null}
-	 *            or <code>HEAD</code>.
+	 *            branch name (<code>master</code>) or tag name
+	 *            (<code>v1.2.3</code>). The default is to use the branch
+	 *            pointed to by the cloned repository's HEAD and can be
+	 *            requested by passing {@code null} or <code>HEAD</code>.
 	 * @return this instance
 	 */
 	public CloneCommand setBranch(String branch) {
@@ -559,8 +580,8 @@ public CloneCommand setBranch(String branch) {
 	 * this is set to <code>NullProgressMonitor</code>
 	 *
 	 * @see NullProgressMonitor
-	 *
 	 * @param monitor
+	 *            a {@link org.eclipse.jgit.lib.ProgressMonitor}
 	 * @return {@code this}
 	 */
 	public CloneCommand setProgressMonitor(ProgressMonitor monitor) {
@@ -572,6 +593,8 @@ public CloneCommand setProgressMonitor(ProgressMonitor monitor) {
 	}
 
 	/**
+	 * Set whether all branches have to be fetched
+	 *
 	 * @param cloneAllBranches
 	 *            true when all branches have to be fetched (indicates wildcard
 	 *            in created fetch refspec), false otherwise.
@@ -583,6 +606,8 @@ public CloneCommand setCloneAllBranches(boolean cloneAllBranches) {
 	}
 
 	/**
+	 * Set whether to clone submodules
+	 *
 	 * @param cloneSubmodules
 	 *            true to initialize and update submodules. Ignored when
 	 *            {@link #setBare(boolean)} is set to true.
@@ -594,6 +619,8 @@ public CloneCommand setCloneSubmodules(boolean cloneSubmodules) {
 	}
 
 	/**
+	 * Set branches to clone
+	 *
 	 * @param branchesToClone
 	 *            collection of branches to clone. Ignored when allSelected is
 	 *            true. Must be specified as full ref names (e.g.
@@ -606,6 +633,8 @@ public CloneCommand setBranchesToClone(Collection<String> branchesToClone) {
 	}
 
 	/**
+	 * Set whether to skip checking out a branch
+	 *
 	 * @param noCheckout
 	 *            if set to <code>true</code> no branch will be checked out
 	 *            after the clone. This enhances performance of the clone
@@ -681,10 +710,11 @@ private void cleanup() {
 	}
 
 	private void deleteChildren(File file) throws IOException {
-		if (!FS.DETECTED.isDirectory(file)) {
+		File[] files = file.listFiles();
+		if (files == null) {
 			return;
 		}
-		for (File child : file.listFiles()) {
+		for (File child : files) {
 			FileUtils.delete(child, FileUtils.RECURSIVE | FileUtils.SKIP_MISSING
 					| FileUtils.IGNORE_ERRORS);
 		}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/CommitCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/CommitCommand.java
index e29fc05..d07532c 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/CommitCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/CommitCommand.java
@@ -54,7 +54,7 @@
 
 import org.eclipse.jgit.api.errors.AbortedByHookException;
 import org.eclipse.jgit.api.errors.ConcurrentRefUpdateException;
-import org.eclipse.jgit.api.errors.EmtpyCommitException;
+import org.eclipse.jgit.api.errors.EmptyCommitException;
 import org.eclipse.jgit.api.errors.GitAPIException;
 import org.eclipse.jgit.api.errors.JGitInternalException;
 import org.eclipse.jgit.api.errors.NoFilepatternException;
@@ -140,33 +140,22 @@ public class CommitCommand extends GitCommand<RevCommit> {
 	private Boolean allowEmpty;
 
 	/**
+	 * Constructor for CommitCommand
+	 *
 	 * @param repo
+	 *            the {@link org.eclipse.jgit.lib.Repository}
 	 */
 	protected CommitCommand(Repository repo) {
 		super(repo);
 	}
 
 	/**
+	 * {@inheritDoc}
+	 * <p>
 	 * Executes the {@code commit} command with all the options and parameters
 	 * collected by the setter methods of this class. Each instance of this
 	 * class should only be used for one invocation of the command (means: one
 	 * call to {@link #call()})
-	 *
-	 * @return a {@link RevCommit} object representing the successful commit.
-	 * @throws NoHeadException
-	 *             when called on a git repo without a HEAD reference
-	 * @throws NoMessageException
-	 *             when called without specifying a commit message
-	 * @throws UnmergedPathsException
-	 *             when the current index contained unmerged paths (conflicts)
-	 * @throws ConcurrentRefUpdateException
-	 *             when HEAD or branch ref is updated concurrently by someone
-	 *             else
-	 * @throws WrongRepositoryStateException
-	 *             when repository is not in the right state for committing
-	 * @throws AbortedByHookException
-	 *             if there are either pre-commit or commit-msg hooks present in
-	 *             the repository and one of them rejects the commit.
 	 */
 	@Override
 	public RevCommit call() throws GitAPIException, NoHeadException,
@@ -249,7 +238,7 @@ public RevCommit call() throws GitAPIException, NoHeadException,
 					RevCommit headCommit = rw.parseCommit(headId);
 					headCommit.getTree();
 					if (indexTreeId.equals(headCommit.getTree())) {
-						throw new EmtpyCommitException(
+						throw new EmptyCommitException(
 								JGitText.get().emptyCommit);
 					}
 				}
@@ -420,14 +409,11 @@ private DirCache createTemporaryIndex(ObjectId headId, DirCache index,
 									inserter = repo.newObjectInserter();
 								long contentLength = fTree
 										.getEntryContentLength();
-								InputStream inputStream = fTree
-										.openEntryStream();
-								try {
+								try (InputStream inputStream = fTree
+										.openEntryStream()) {
 									dcEntry.setObjectId(inserter.insert(
 											Constants.OBJ_BLOB, contentLength,
 											inputStream));
-								} finally {
-									inputStream.close();
 								}
 							}
 						}
@@ -602,6 +588,8 @@ private boolean isMergeDuringRebase(RepositoryState state) {
 	}
 
 	/**
+	 * Set the commit message
+	 *
 	 * @param message
 	 *            the commit message used for the {@code commit}
 	 * @return {@code this}
@@ -613,6 +601,8 @@ public CommitCommand setMessage(String message) {
 	}
 
 	/**
+	 * Set whether to allow to create an empty commit
+	 *
 	 * @param allowEmpty
 	 *            whether it should be allowed to create a commit which has the
 	 *            same tree as it's sole predecessor (a commit which doesn't
@@ -623,8 +613,9 @@ public CommitCommand setMessage(String message) {
 	 *            <p>
 	 *            By default when creating a commit containing only specified
 	 *            paths an attempt to create an empty commit leads to a
-	 *            {@link JGitInternalException}. By setting this flag to
-	 *            <code>true</code> this exception will not be thrown.
+	 *            {@link org.eclipse.jgit.api.errors.JGitInternalException}. By
+	 *            setting this flag to <code>true</code> this exception will not
+	 *            be thrown.
 	 * @return {@code this}
 	 * @since 4.2
 	 */
@@ -634,6 +625,8 @@ public CommitCommand setAllowEmpty(boolean allowEmpty) {
 	}
 
 	/**
+	 * Get the commit message
+	 *
 	 * @return the commit message used for the <code>commit</code>
 	 */
 	public String getMessage() {
@@ -673,10 +666,12 @@ public CommitCommand setCommitter(String name, String email) {
 	}
 
 	/**
+	 * Get the committer
+	 *
 	 * @return the committer used for the {@code commit}. If no committer was
 	 *         specified {@code null} is returned and the default
-	 *         {@link PersonIdent} of this repo is used during execution of the
-	 *         command
+	 *         {@link org.eclipse.jgit.lib.PersonIdent} of this repo is used
+	 *         during execution of the command
 	 */
 	public PersonIdent getCommitter() {
 		return committer;
@@ -715,10 +710,12 @@ public CommitCommand setAuthor(String name, String email) {
 	}
 
 	/**
+	 * Get the author
+	 *
 	 * @return the author used for the {@code commit}. If no author was
 	 *         specified {@code null} is returned and the default
-	 *         {@link PersonIdent} of this repo is used during execution of the
-	 *         command
+	 *         {@link org.eclipse.jgit.lib.PersonIdent} of this repo is used
+	 *         during execution of the command
 	 */
 	public PersonIdent getAuthor() {
 		return author;
@@ -730,6 +727,8 @@ public PersonIdent getAuthor() {
 	 * not affected. This corresponds to the parameter -a on the command line.
 	 *
 	 * @param all
+	 *            whether to auto-stage all files that have been modified and
+	 *            deleted
 	 * @return {@code this}
 	 * @throws JGitInternalException
 	 *             in case of an illegal combination of arguments/ options
@@ -745,11 +744,12 @@ public CommitCommand setAll(boolean all) {
 	}
 
 	/**
-	 * Used to amend the tip of the current branch. If set to true, the previous
-	 * commit will be amended. This is equivalent to --amend on the command
-	 * line.
+	 * Used to amend the tip of the current branch. If set to {@code true}, the
+	 * previous commit will be amended. This is equivalent to --amend on the
+	 * command line.
 	 *
 	 * @param amend
+	 *            whether to ammend the tip of the current branch
 	 * @return {@code this}
 	 */
 	public CommitCommand setAmend(boolean amend) {
@@ -790,7 +790,7 @@ public CommitCommand setOnly(String only) {
 	 * will be replaced by the change id.
 	 *
 	 * @param insertChangeId
-	 *
+	 *            whether to insert a change id
 	 * @return {@code this}
 	 */
 	public CommitCommand setInsertChangeId(boolean insertChangeId) {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/CreateBranchCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/CreateBranchCommand.java
index 39420d0..ba6f3f1 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/CreateBranchCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/CreateBranchCommand.java
@@ -43,6 +43,9 @@
  */
 package org.eclipse.jgit.api;
 
+import static org.eclipse.jgit.lib.Constants.HEAD;
+import static org.eclipse.jgit.lib.Constants.R_HEADS;
+
 import java.io.IOException;
 import java.text.MessageFormat;
 
@@ -78,7 +81,7 @@ public class CreateBranchCommand extends GitCommand<Ref> {
 
 	private SetupUpstreamMode upstreamMode;
 
-	private String startPoint = Constants.HEAD;
+	private String startPoint = HEAD;
 
 	private RevCommit startCommit;
 
@@ -103,23 +106,16 @@ public enum SetupUpstreamMode {
 	}
 
 	/**
+	 * Constructor for CreateBranchCommand
+	 *
 	 * @param repo
+	 *            the {@link org.eclipse.jgit.lib.Repository}
 	 */
 	protected CreateBranchCommand(Repository repo) {
 		super(repo);
 	}
 
-	/**
-	 * @throws RefAlreadyExistsException
-	 *             when trying to create (without force) a branch with a name
-	 *             that already exists
-	 * @throws RefNotFoundException
-	 *             if the start point can not be found
-	 * @throws InvalidRefNameException
-	 *             if the provided name is <code>null</code> or otherwise
-	 *             invalid
-	 * @return the newly created branch
-	 */
+	/** {@inheritDoc} */
 	@Override
 	public Ref call() throws GitAPIException, RefAlreadyExistsException,
 			RefNotFoundException, InvalidRefNameException {
@@ -128,7 +124,7 @@ public Ref call() throws GitAPIException, RefAlreadyExistsException,
 		try (RevWalk revWalk = new RevWalk(repo)) {
 			Ref refToCheck = repo.findRef(name);
 			boolean exists = refToCheck != null
-					&& refToCheck.getName().startsWith(Constants.R_HEADS);
+					&& refToCheck.getName().startsWith(R_HEADS);
 			if (!force && exists)
 				throw new RefAlreadyExistsException(MessageFormat.format(
 						JGitText.get().refAlreadyExists1, name));
@@ -160,7 +156,7 @@ public Ref call() throws GitAPIException, RefAlreadyExistsException,
 				else
 					refLogMessage = "branch: Created from commit " + baseCommit; //$NON-NLS-1$
 
-			} else if (startPointFullName.startsWith(Constants.R_HEADS)
+			} else if (startPointFullName.startsWith(R_HEADS)
 					|| startPointFullName.startsWith(Constants.R_REMOTES)) {
 				baseBranch = startPointFullName;
 				if (exists)
@@ -178,7 +174,7 @@ public Ref call() throws GitAPIException, RefAlreadyExistsException,
 							+ startPointFullName;
 			}
 
-			RefUpdate updateRef = repo.updateRef(Constants.R_HEADS + name);
+			RefUpdate updateRef = repo.updateRef(R_HEADS + name);
 			updateRef.setNewObjectId(startAt);
 			updateRef.setRefLogMessage(refLogMessage, false);
 			Result updateResult;
@@ -286,17 +282,36 @@ private ObjectId getStartPointObjectId() throws AmbiguousObjectException,
 	}
 
 	private String getStartPointOrHead() {
-		return startPoint != null ? startPoint : Constants.HEAD;
+		return startPoint != null ? startPoint : HEAD;
 	}
 
 	private void processOptions() throws InvalidRefNameException {
 		if (name == null
-				|| !Repository.isValidRefName(Constants.R_HEADS + name))
+				|| !Repository.isValidRefName(R_HEADS + name)
+				|| !isValidBranchName(name))
 			throw new InvalidRefNameException(MessageFormat.format(JGitText
 					.get().branchNameInvalid, name == null ? "<null>" : name)); //$NON-NLS-1$
 	}
 
 	/**
+	 * Check if the given branch name is valid
+	 *
+	 * @param branchName
+	 *            branch name to check
+	 * @return {@code true} if the branch name is valid
+	 *
+	 * @since 5.0
+	 */
+	public static boolean isValidBranchName(String branchName) {
+		if (HEAD.equals(branchName)) {
+			return false;
+		}
+		return !branchName.startsWith("-"); //$NON-NLS-1$
+	}
+
+	/**
+	 * Set the name of the new branch
+	 *
 	 * @param name
 	 *            the name of the new branch
 	 * @return this instance
@@ -308,6 +323,8 @@ public CreateBranchCommand setName(String name) {
 	}
 
 	/**
+	 * Set whether to create the branch forcefully
+	 *
 	 * @param force
 	 *            if <code>true</code> and the branch with the given name
 	 *            already exists, the start-point of an existing branch will be
@@ -322,6 +339,8 @@ public CreateBranchCommand setForce(boolean force) {
 	}
 
 	/**
+	 * Set the start point
+	 *
 	 * @param startPoint
 	 *            corresponds to the start-point option; if <code>null</code>,
 	 *            the current HEAD will be used
@@ -335,6 +354,8 @@ public CreateBranchCommand setStartPoint(String startPoint) {
 	}
 
 	/**
+	 * Set the start point
+	 *
 	 * @param startPoint
 	 *            corresponds to the start-point option; if <code>null</code>,
 	 *            the current HEAD will be used
@@ -348,6 +369,8 @@ public CreateBranchCommand setStartPoint(RevCommit startPoint) {
 	}
 
 	/**
+	 * Set the upstream mode
+	 *
 	 * @param mode
 	 *            corresponds to the --track/--no-track/--set-upstream options;
 	 *            may be <code>null</code>
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/DeleteBranchCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/DeleteBranchCommand.java
index d7e7e5c..31e7281 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/DeleteBranchCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/DeleteBranchCommand.java
@@ -84,19 +84,16 @@ public class DeleteBranchCommand extends GitCommand<List<String>> {
 	private boolean force;
 
 	/**
+	 * Constructor for DeleteBranchCommand
+	 *
 	 * @param repo
+	 *            the {@link org.eclipse.jgit.lib.Repository}
 	 */
 	protected DeleteBranchCommand(Repository repo) {
 		super(repo);
 	}
 
-	/**
-	 * @throws NotMergedException
-	 *             when trying to delete a branch which has not been merged into
-	 *             the currently checked out branch without force
-	 * @throws CannotDeleteCurrentBranchException
-	 * @return the list with the (full) names of the deleted branches
-	 */
+	/** {@inheritDoc} */
 	@Override
 	public List<String> call() throws GitAPIException,
 			NotMergedException, CannotDeleteCurrentBranchException {
@@ -181,6 +178,8 @@ public List<String> call() throws GitAPIException,
 	}
 
 	/**
+	 * Set the names of the branches to delete
+	 *
 	 * @param branchnames
 	 *            the names of the branches to delete; if not set, this will do
 	 *            nothing; invalid branch names will simply be ignored
@@ -195,6 +194,8 @@ public DeleteBranchCommand setBranchNames(String... branchnames) {
 	}
 
 	/**
+	 * Set whether to forcefully delete branches
+	 *
 	 * @param force
 	 *            <code>true</code> corresponds to the -D option,
 	 *            <code>false</code> to the -d option (default) <br>
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/DeleteTagCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/DeleteTagCommand.java
index 77e3539..63a090c 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/DeleteTagCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/DeleteTagCommand.java
@@ -71,15 +71,16 @@ public class DeleteTagCommand extends GitCommand<List<String>> {
 	private final Set<String> tags = new HashSet<>();
 
 	/**
+	 * Constructor for DeleteTagCommand
+	 *
 	 * @param repo
+	 *            the {@link org.eclipse.jgit.lib.Repository}
 	 */
 	protected DeleteTagCommand(Repository repo) {
 		super(repo);
 	}
 
-	/**
-	 * @return the list with the full names of the deleted tags
-	 */
+	/** {@inheritDoc} */
 	@Override
 	public List<String> call() throws GitAPIException {
 		checkCallable();
@@ -124,6 +125,8 @@ public List<String> call() throws GitAPIException {
 	}
 
 	/**
+	 * Set names of the tags to delete
+	 *
 	 * @param tags
 	 *            the names of the tags to delete; if not set, this will do
 	 *            nothing; invalid tag names will simply be ignored
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/DescribeCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/DescribeCommand.java
index 68b1bd9..dc605a9 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/DescribeCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/DescribeCommand.java
@@ -104,8 +104,10 @@ public class DescribeCommand extends GitCommand<String> {
 	private List<IMatcher> matchers = new ArrayList<>();
 
 	/**
+	 * Constructor for DescribeCommand.
 	 *
 	 * @param repo
+	 *            the {@link org.eclipse.jgit.lib.Repository}
 	 */
 	protected DescribeCommand(Repository repo) {
 		super(repo);
@@ -123,7 +125,7 @@ protected DescribeCommand(Repository repo) {
 	 *             the supplied commit does not exist.
 	 * @throws IncorrectObjectTypeException
 	 *             the supplied id is not a commit or an annotated tag.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             a pack file or loose object could not be read.
 	 */
 	public DescribeCommand setTarget(ObjectId target) throws IOException {
@@ -135,14 +137,15 @@ public DescribeCommand setTarget(ObjectId target) throws IOException {
 	 * Sets the commit to be described.
 	 *
 	 * @param rev
-	 * 		Commit ID, tag, branch, ref, etc.
-	 * 		See {@link Repository#resolve(String)} for allowed syntax.
+	 *            Commit ID, tag, branch, ref, etc. See
+	 *            {@link org.eclipse.jgit.lib.Repository#resolve(String)} for
+	 *            allowed syntax.
 	 * @return {@code this}
 	 * @throws IncorrectObjectTypeException
 	 *             the supplied id is not a commit or an annotated tag.
-	 * @throws RefNotFoundException
-	 * 				the given rev didn't resolve to any object.
-	 * @throws IOException
+	 * @throws org.eclipse.jgit.api.errors.RefNotFoundException
+	 *             the given rev didn't resolve to any object.
+	 * @throws java.io.IOException
 	 *             a pack file or loose object could not be read.
 	 */
 	public DescribeCommand setTarget(String rev) throws IOException,
@@ -160,7 +163,6 @@ public DescribeCommand setTarget(String rev) throws IOException,
 	 * @param longDesc
 	 *            <code>true</code> if always the long format should be used.
 	 * @return {@code this}
-	 *
 	 * @see <a
 	 *      href="https://www.kernel.org/pub/software/scm/git/docs/git-describe.html"
 	 *      >Git documentation about describe</a>
@@ -180,15 +182,17 @@ private String longDescription(Ref tag, int depth, ObjectId tip)
 	}
 
 	/**
-	 * Sets one or more {@code glob(7)} patterns that tags must match to be considered.
-	 * If multiple patterns are provided, tags only need match one of them.
+	 * Sets one or more {@code glob(7)} patterns that tags must match to be
+	 * considered. If multiple patterns are provided, tags only need match one
+	 * of them.
 	 *
-	 * @param patterns the {@code glob(7)} pattern or patterns
+	 * @param patterns
+	 *            the {@code glob(7)} pattern or patterns
 	 * @return {@code this}
-	 * @throws InvalidPatternException if the pattern passed in was invalid.
-	 *
-	 * @see <a
-	 *      href="https://www.kernel.org/pub/software/scm/git/docs/git-describe.html"
+	 * @throws org.eclipse.jgit.errors.InvalidPatternException
+	 *             if the pattern passed in was invalid.
+	 * @see <a href=
+	 *      "https://www.kernel.org/pub/software/scm/git/docs/git-describe.html"
 	 *      >Git documentation about describe</a>
 	 * @since 4.9
 	 */
@@ -220,25 +224,23 @@ private Optional<Ref> getBestMatch(List<Ref> tags) {
 		}
 	}
 
-	private ObjectId getObjectIdFromRef(Ref r) {
-		ObjectId key = repo.peel(r).getPeeledObjectId();
-		if (key == null) {
-			key = r.getObjectId();
+	private ObjectId getObjectIdFromRef(Ref r) throws JGitInternalException {
+		try {
+			ObjectId key = repo.getRefDatabase().peel(r).getPeeledObjectId();
+			if (key == null) {
+				key = r.getObjectId();
+			}
+			return key;
+		} catch (IOException e) {
+			throw new JGitInternalException(e.getMessage(), e);
 		}
-		return key;
 	}
 
 	/**
+	 * {@inheritDoc}
+	 * <p>
 	 * Describes the specified commit. Target defaults to HEAD if no commit was
 	 * set explicitly.
-	 *
-	 * @return if there's a tag that points to the commit being described, this
-	 *         tag name is returned. Otherwise additional suffix is added to the
-	 *         nearest tag, just like git-describe(1).
-	 *         <p>
-	 *         If none of the ancestors of the commit being described has any
-	 *         tags at all, then this method returns null, indicating that
-	 *         there's no way to describe this tag.
 	 */
 	@Override
 	public String call() throws GitAPIException {
@@ -248,7 +250,8 @@ public String call() throws GitAPIException {
 			if (target == null)
 				setTarget(Constants.HEAD);
 
-			Collection<Ref> tagList = repo.getRefDatabase().getRefs(R_TAGS).values();
+			Collection<Ref> tagList = repo.getRefDatabase()
+					.getRefsByPrefix(R_TAGS);
 			Map<ObjectId, List<Ref>> tags = tagList.stream()
 					.collect(Collectors.groupingBy(this::getObjectIdFromRef));
 
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/DiffCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/DiffCommand.java
index b137fc5..f65b573 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/DiffCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/DiffCommand.java
@@ -95,30 +95,34 @@ public class DiffCommand extends GitCommand<List<DiffEntry>> {
 	private ProgressMonitor monitor = NullProgressMonitor.INSTANCE;
 
 	/**
+	 * Constructor for DiffCommand
+	 *
 	 * @param repo
+	 *            a {@link org.eclipse.jgit.lib.Repository} object.
 	 */
 	protected DiffCommand(Repository repo) {
 		super(repo);
 	}
 
+	private DiffFormatter getDiffFormatter() {
+		return out != null && !showNameAndStatusOnly
+				? new DiffFormatter(new BufferedOutputStream(out))
+				: new DiffFormatter(NullOutputStream.INSTANCE);
+	}
+
 	/**
+	 * {@inheritDoc}
+	 * <p>
 	 * Executes the {@code Diff} command with all the options and parameters
 	 * collected by the setter methods (e.g. {@link #setCached(boolean)} of this
 	 * class. Each instance of this class should only be used for one invocation
 	 * of the command. Don't call this method twice on an instance.
-	 *
-	 * @return a DiffEntry for each path which is different
 	 */
 	@Override
 	public List<DiffEntry> call() throws GitAPIException {
-		final DiffFormatter diffFmt;
-		if (out != null && !showNameAndStatusOnly)
-			diffFmt = new DiffFormatter(new BufferedOutputStream(out));
-		else
-			diffFmt = new DiffFormatter(NullOutputStream.INSTANCE);
-		diffFmt.setRepository(repo);
-		diffFmt.setProgressMonitor(monitor);
-		try {
+		try (DiffFormatter diffFmt = getDiffFormatter()) {
+			diffFmt.setRepository(repo);
+			diffFmt.setProgressMonitor(monitor);
 			if (cached) {
 				if (oldTree == null) {
 					ObjectId head = repo.resolve(HEAD + "^{tree}"); //$NON-NLS-1$
@@ -156,15 +160,14 @@ public List<DiffEntry> call() throws GitAPIException {
 			}
 		} catch (IOException e) {
 			throw new JGitInternalException(e.getMessage(), e);
-		} finally {
-			diffFmt.close();
 		}
 	}
 
 	/**
+	 * Whether to view the changes staged for the next commit
 	 *
 	 * @param cached
-	 *            whether to view the changes you staged for the next commit
+	 *            whether to view the changes staged for the next commit
 	 * @return this instance
 	 */
 	public DiffCommand setCached(boolean cached) {
@@ -173,6 +176,8 @@ public DiffCommand setCached(boolean cached) {
 	}
 
 	/**
+	 * Set path filter
+	 *
 	 * @param pathFilter
 	 *            parameter, used to limit the diff to the named path
 	 * @return this instance
@@ -183,6 +188,8 @@ public DiffCommand setPathFilter(TreeFilter pathFilter) {
 	}
 
 	/**
+	 * Set old tree
+	 *
 	 * @param oldTree
 	 *            the previous state
 	 * @return this instance
@@ -193,6 +200,8 @@ public DiffCommand setOldTree(AbstractTreeIterator oldTree) {
 	}
 
 	/**
+	 * Set new tree
+	 *
 	 * @param newTree
 	 *            the updated state
 	 * @return this instance
@@ -203,6 +212,8 @@ public DiffCommand setNewTree(AbstractTreeIterator newTree) {
 	}
 
 	/**
+	 * Set whether to return only names and status of changed files
+	 *
 	 * @param showNameAndStatusOnly
 	 *            whether to return only names and status of changed files
 	 * @return this instance
@@ -213,6 +224,8 @@ public DiffCommand setShowNameAndStatusOnly(boolean showNameAndStatusOnly) {
 	}
 
 	/**
+	 * Set output stream
+	 *
 	 * @param out
 	 *            the stream to write line data
 	 * @return this instance
@@ -263,7 +276,6 @@ public DiffCommand setDestinationPrefix(String destinationPrefix) {
 	 * is set to <code>NullProgressMonitor</code>
 	 *
 	 * @see NullProgressMonitor
-	 *
 	 * @param monitor
 	 *            a progress monitor
 	 * @return this instance
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/FetchCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/FetchCommand.java
index 5270283..73e93a1 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/FetchCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/FetchCommand.java
@@ -105,6 +105,8 @@ public class FetchCommand extends TransportCommand<FetchCommand, FetchResult> {
 
 	private Callback callback;
 
+	private boolean isForceUpdate;
+
 	/**
 	 * Callback for status of fetch operation.
 	 *
@@ -122,7 +124,10 @@ public interface Callback {
 	}
 
 	/**
+	 * Constructor for FetchCommand.
+	 *
 	 * @param repo
+	 *            a {@link org.eclipse.jgit.lib.Repository} object.
 	 */
 	protected FetchCommand(Repository repo) {
 		super(repo);
@@ -168,38 +173,43 @@ private void fetchSubmodules(FetchResult results)
 			}
 			walk.setTree(revWalk.parseTree(fetchHead));
 			while (walk.next()) {
-				Repository submoduleRepo = walk.getRepository();
+				try (Repository submoduleRepo = walk.getRepository()) {
 
-				// Skip submodules that don't exist locally (have not been
-				// cloned), are not registered in the .gitmodules file, or
-				// not registered in the parent repository's config.
-				if (submoduleRepo == null || walk.getModulesPath() == null
-						|| walk.getConfigUrl() == null) {
-					continue;
-				}
-
-				FetchRecurseSubmodulesMode recurseMode = getRecurseMode(
-						walk.getPath());
-
-				// When the fetch mode is "yes" we always fetch. When the mode
-				// is "on demand", we only fetch if the submodule's revision was
-				// updated to an object that is not currently present in the
-				// submodule.
-				if ((recurseMode == FetchRecurseSubmodulesMode.ON_DEMAND
-						&& !submoduleRepo.hasObject(walk.getObjectId()))
-						|| recurseMode == FetchRecurseSubmodulesMode.YES) {
-					FetchCommand f = new FetchCommand(submoduleRepo)
-							.setProgressMonitor(monitor).setTagOpt(tagOption)
-							.setCheckFetchedObjects(checkFetchedObjects)
-							.setRemoveDeletedRefs(isRemoveDeletedRefs())
-							.setThin(thin).setRefSpecs(refSpecs)
-							.setDryRun(dryRun)
-							.setRecurseSubmodules(recurseMode);
-					configure(f);
-					if (callback != null) {
-						callback.fetchingSubmodule(walk.getPath());
+					// Skip submodules that don't exist locally (have not been
+					// cloned), are not registered in the .gitmodules file, or
+					// not registered in the parent repository's config.
+					if (submoduleRepo == null || walk.getModulesPath() == null
+							|| walk.getConfigUrl() == null) {
+						continue;
 					}
-					results.addSubmodule(walk.getPath(), f.call());
+
+					FetchRecurseSubmodulesMode recurseMode = getRecurseMode(
+							walk.getPath());
+
+					// When the fetch mode is "yes" we always fetch. When the
+					// mode
+					// is "on demand", we only fetch if the submodule's revision
+					// was
+					// updated to an object that is not currently present in the
+					// submodule.
+					if ((recurseMode == FetchRecurseSubmodulesMode.ON_DEMAND
+							&& !submoduleRepo.hasObject(walk.getObjectId()))
+							|| recurseMode == FetchRecurseSubmodulesMode.YES) {
+						FetchCommand f = new FetchCommand(submoduleRepo)
+								.setProgressMonitor(monitor)
+								.setTagOpt(tagOption)
+								.setCheckFetchedObjects(checkFetchedObjects)
+								.setRemoveDeletedRefs(isRemoveDeletedRefs())
+								.setThin(thin)
+								.setRefSpecs(applyOptions(refSpecs))
+								.setDryRun(dryRun)
+								.setRecurseSubmodules(recurseMode);
+						configure(f);
+						if (callback != null) {
+							callback.fetchingSubmodule(walk.getPath());
+						}
+						results.addSubmodule(walk.getPath(), f.call());
+					}
 				}
 			}
 		} catch (IOException e) {
@@ -210,17 +220,12 @@ private void fetchSubmodules(FetchResult results)
 	}
 
 	/**
-	 * Executes the {@code fetch} command with all the options and parameters
+	 * {@inheritDoc}
+	 * <p>
+	 * Execute the {@code fetch} command with all the options and parameters
 	 * collected by the setter methods of this class. Each instance of this
 	 * class should only be used for one invocation of the command (means: one
 	 * call to {@link #call()})
-	 *
-	 * @return a {@link FetchResult} object representing the successful fetch
-	 *         result
-	 * @throws InvalidRemoteException
-	 *             when called with an invalid remote uri
-	 * @throws org.eclipse.jgit.api.errors.TransportException
-	 *             when an error occurs during transport
 	 */
 	@Override
 	public FetchResult call() throws GitAPIException, InvalidRemoteException,
@@ -235,8 +240,8 @@ public FetchResult call() throws GitAPIException, InvalidRemoteException,
 				transport.setTagOpt(tagOption);
 			transport.setFetchThin(thin);
 			configure(transport);
-
-			FetchResult result = transport.fetch(monitor, refSpecs);
+			FetchResult result = transport.fetch(monitor,
+					applyOptions(refSpecs));
 			if (!repo.isBare()) {
 				fetchSubmodules(result);
 			}
@@ -259,6 +264,17 @@ public FetchResult call() throws GitAPIException, InvalidRemoteException,
 
 	}
 
+	private List<RefSpec> applyOptions(List<RefSpec> refSpecs2) {
+		if (!isForceUpdate()) {
+			return refSpecs2;
+		}
+		List<RefSpec> updated = new ArrayList<>(3);
+		for (RefSpec refSpec : refSpecs2) {
+			updated.add(refSpec.setForceUpdate(true));
+		}
+		return updated;
+	}
+
 	/**
 	 * Set the mode to be used for recursing into submodules.
 	 *
@@ -288,6 +304,7 @@ public FetchCommand setRecurseSubmodules(
 	 *
 	 * @see Constants#DEFAULT_REMOTE_NAME
 	 * @param remote
+	 *            name of a remote
 	 * @return {@code this}
 	 */
 	public FetchCommand setRemote(String remote) {
@@ -297,6 +314,8 @@ public FetchCommand setRemote(String remote) {
 	}
 
 	/**
+	 * Get the remote
+	 *
 	 * @return the remote used for the remote operation
 	 */
 	public String getRemote() {
@@ -304,6 +323,8 @@ public String getRemote() {
 	}
 
 	/**
+	 * Get timeout
+	 *
 	 * @return the timeout used for the fetch operation
 	 */
 	public int getTimeout() {
@@ -311,16 +332,19 @@ public int getTimeout() {
 	}
 
 	/**
-	 * @return whether to check received objects checked for validity
+	 * Whether to check received objects for validity
+	 *
+	 * @return whether to check received objects for validity
 	 */
 	public boolean isCheckFetchedObjects() {
 		return checkFetchedObjects;
 	}
 
 	/**
-	 * If set to true, objects received will be checked for validity
+	 * If set to {@code true}, objects received will be checked for validity
 	 *
 	 * @param checkFetchedObjects
+	 *            whether to check objects for validity
 	 * @return {@code this}
 	 */
 	public FetchCommand setCheckFetchedObjects(boolean checkFetchedObjects) {
@@ -330,7 +354,9 @@ public FetchCommand setCheckFetchedObjects(boolean checkFetchedObjects) {
 	}
 
 	/**
-	 * @return whether or not to remove refs which no longer exist in the source
+	 * Whether to remove refs which no longer exist in the source
+	 *
+	 * @return whether to remove refs which no longer exist in the source
 	 */
 	public boolean isRemoveDeletedRefs() {
 		if (removeDeletedRefs != null)
@@ -347,9 +373,11 @@ public boolean isRemoveDeletedRefs() {
 	}
 
 	/**
-	 * If set to true, refs are removed which no longer exist in the source
+	 * If set to {@code true}, refs are removed which no longer exist in the
+	 * source
 	 *
 	 * @param removeDeletedRefs
+	 *            whether to remove deleted {@code Ref}s
 	 * @return {@code this}
 	 */
 	public FetchCommand setRemoveDeletedRefs(boolean removeDeletedRefs) {
@@ -359,6 +387,8 @@ public FetchCommand setRemoveDeletedRefs(boolean removeDeletedRefs) {
 	}
 
 	/**
+	 * Get progress monitor
+	 *
 	 * @return the progress monitor for the fetch operation
 	 */
 	public ProgressMonitor getProgressMonitor() {
@@ -370,8 +400,8 @@ public ProgressMonitor getProgressMonitor() {
 	 * this is set to <code>NullProgressMonitor</code>
 	 *
 	 * @see NullProgressMonitor
-	 *
 	 * @param monitor
+	 *            a {@link org.eclipse.jgit.lib.ProgressMonitor}
 	 * @return {@code this}
 	 */
 	public FetchCommand setProgressMonitor(ProgressMonitor monitor) {
@@ -384,6 +414,8 @@ public FetchCommand setProgressMonitor(ProgressMonitor monitor) {
 	}
 
 	/**
+	 * Get list of {@code RefSpec}s
+	 *
 	 * @return the ref specs
 	 */
 	public List<RefSpec> getRefSpecs() {
@@ -394,6 +426,7 @@ public List<RefSpec> getRefSpecs() {
 	 * The ref specs to be used in the fetch operation
 	 *
 	 * @param specs
+	 *            String representation of {@code RefSpec}s
 	 * @return {@code this}
 	 * @since 4.9
 	 */
@@ -406,6 +439,7 @@ public FetchCommand setRefSpecs(String... specs) {
 	 * The ref specs to be used in the fetch operation
 	 *
 	 * @param specs
+	 *            one or multiple {@link org.eclipse.jgit.transport.RefSpec}s
 	 * @return {@code this}
 	 */
 	public FetchCommand setRefSpecs(RefSpec... specs) {
@@ -416,6 +450,7 @@ public FetchCommand setRefSpecs(RefSpec... specs) {
 	 * The ref specs to be used in the fetch operation
 	 *
 	 * @param specs
+	 *            list of {@link org.eclipse.jgit.transport.RefSpec}s
 	 * @return {@code this}
 	 */
 	public FetchCommand setRefSpecs(List<RefSpec> specs) {
@@ -426,6 +461,8 @@ public FetchCommand setRefSpecs(List<RefSpec> specs) {
 	}
 
 	/**
+	 * Whether to do a dry run
+	 *
 	 * @return the dry run preference for the fetch operation
 	 */
 	public boolean isDryRun() {
@@ -436,6 +473,7 @@ public boolean isDryRun() {
 	 * Sets whether the fetch operation should be a dry run
 	 *
 	 * @param dryRun
+	 *            whether to do a dry run
 	 * @return {@code this}
 	 */
 	public FetchCommand setDryRun(boolean dryRun) {
@@ -445,6 +483,8 @@ public FetchCommand setDryRun(boolean dryRun) {
 	}
 
 	/**
+	 * Get thin-pack preference
+	 *
 	 * @return the thin-pack preference for fetch operation
 	 */
 	public boolean isThin() {
@@ -457,6 +497,7 @@ public boolean isThin() {
 	 * Default setting is Transport.DEFAULT_FETCH_THIN
 	 *
 	 * @param thin
+	 *            the thin-pack preference
 	 * @return {@code this}
 	 */
 	public FetchCommand setThin(boolean thin) {
@@ -469,6 +510,7 @@ public FetchCommand setThin(boolean thin) {
 	 * Sets the specification of annotated tag behavior during fetch
 	 *
 	 * @param tagOpt
+	 *            the {@link org.eclipse.jgit.transport.TagOpt}
 	 * @return {@code this}
 	 */
 	public FetchCommand setTagOpt(TagOpt tagOpt) {
@@ -489,4 +531,27 @@ public FetchCommand setCallback(Callback callback) {
 		this.callback = callback;
 		return this;
 	}
+
+	/**
+	 * Whether fetch --force option is enabled
+	 *
+	 * @return whether refs affected by the fetch are updated forcefully
+	 * @since 5.0
+	 */
+	public boolean isForceUpdate() {
+		return this.isForceUpdate;
+	}
+
+	/**
+	 * Set fetch --force option
+	 *
+	 * @param force
+	 *            whether to update refs affected by the fetch forcefully
+	 * @return this command
+	 * @since 5.0
+	 */
+	public FetchCommand setForceUpdate(boolean force) {
+		this.isForceUpdate = force;
+		return this;
+	}
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/GarbageCollectCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/GarbageCollectCommand.java
index 0f38db5..7ea2771 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/GarbageCollectCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/GarbageCollectCommand.java
@@ -61,7 +61,6 @@
 import org.eclipse.jgit.lib.Repository;
 import org.eclipse.jgit.lib.StoredConfig;
 import org.eclipse.jgit.storage.pack.PackConfig;
-import org.eclipse.jgit.util.GitDateParser;
 
 /**
  * A class used to execute a {@code gc} command. It has setters for all
@@ -97,7 +96,10 @@ public class GarbageCollectCommand extends GitCommand<Properties> {
 	private PackConfig pconfig;
 
 	/**
+	 * Constructor for GarbageCollectCommand.
+	 *
 	 * @param repo
+	 *            a {@link org.eclipse.jgit.lib.Repository} object.
 	 */
 	protected GarbageCollectCommand(Repository repo) {
 		super(repo);
@@ -105,6 +107,8 @@ protected GarbageCollectCommand(Repository repo) {
 	}
 
 	/**
+	 * Set progress monitor
+	 *
 	 * @param monitor
 	 *            a progress monitor
 	 * @return this instance
@@ -118,8 +122,8 @@ public GarbageCollectCommand setProgressMonitor(ProgressMonitor monitor) {
 	 * During gc() or prune() each unreferenced, loose object which has been
 	 * created or modified after <code>expire</code> will not be pruned. Only
 	 * older objects may be pruned. If set to null then every object is a
-	 * candidate for pruning. Use {@link GitDateParser} to parse time formats
-	 * used by git gc.
+	 * candidate for pruning. Use {@link org.eclipse.jgit.util.GitDateParser} to
+	 * parse time formats used by git gc.
 	 *
 	 * @param expire
 	 *            minimal age of objects to be pruned.
@@ -191,6 +195,7 @@ public GarbageCollectCommand setPrunePreserved(boolean prunePreserved) {
 		return this;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public Properties call() throws GitAPIException {
 		checkCallable();
@@ -229,7 +234,7 @@ public Properties call() throws GitAPIException {
 	 * Computes and returns the repository statistics.
 	 *
 	 * @return the repository statistics
-	 * @throws GitAPIException
+	 * @throws org.eclipse.jgit.api.errors.GitAPIException
 	 *             thrown if the repository statistics cannot be computed
 	 * @since 3.0
 	 */
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/Git.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/Git.java
index 9699569..400a7df 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/Git.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/Git.java
@@ -89,25 +89,30 @@ public class Git implements AutoCloseable {
 	private final boolean closeRepo;
 
 	/**
+	 * Open repository
+	 *
 	 * @param dir
 	 *            the repository to open. May be either the GIT_DIR, or the
 	 *            working tree directory that contains {@code .git}.
-	 * @return a {@link Git} object for the existing git repository
-	 * @throws IOException
+	 * @return a {@link org.eclipse.jgit.api.Git} object for the existing git
+	 *         repository
+	 * @throws java.io.IOException
 	 */
 	public static Git open(File dir) throws IOException {
 		return open(dir, FS.DETECTED);
 	}
 
 	/**
+	 * Open repository
+	 *
 	 * @param dir
 	 *            the repository to open. May be either the GIT_DIR, or the
 	 *            working tree directory that contains {@code .git}.
 	 * @param fs
 	 *            filesystem abstraction to use when accessing the repository.
-	 * @return a {@link Git} object for the existing git repository. Closing this
-	 *         instance will close the repo.
-	 * @throws IOException
+	 * @return a {@link org.eclipse.jgit.api.Git} object for the existing git
+	 *         repository. Closing this instance will close the repo.
+	 * @throws java.io.IOException
 	 */
 	public static Git open(File dir, FS fs) throws IOException {
 		RepositoryCache.FileKey key;
@@ -119,31 +124,36 @@ public static Git open(File dir, FS fs) throws IOException {
 	}
 
 	/**
+	 * Wrap repository
+	 *
 	 * @param repo
 	 *            the git repository this class is interacting with;
 	 *            {@code null} is not allowed.
-	 * @return a {@link Git} object for the existing git repository. The caller is
-	 *         responsible for closing the repository; {@link #close()} on this
-	 *         instance does not close the repo.
+	 * @return a {@link org.eclipse.jgit.api.Git} object for the existing git
+	 *         repository. The caller is responsible for closing the repository;
+	 *         {@link #close()} on this instance does not close the repo.
 	 */
 	public static Git wrap(Repository repo) {
 		return new Git(repo);
 	}
 
 	/**
-	 * Frees resources associated with this instance.
+	 * {@inheritDoc}
 	 * <p>
-	 * If the repository was opened by a static factory method in this class, then
-	 * this method calls {@link Repository#close()} on the underlying repository
-	 * instance. (Whether this actually releases underlying resources, such as
-	 * file handles, may vary; see {@link Repository} for more details.)
+	 * Free resources associated with this instance.
 	 * <p>
-	 * If the repository was created by a caller and passed into {@link
-	 * #Git(Repository)} or a static factory method in this class, then this
-	 * method does not call close on the underlying repository.
+	 * If the repository was opened by a static factory method in this class,
+	 * then this method calls {@link Repository#close()} on the underlying
+	 * repository instance. (Whether this actually releases underlying
+	 * resources, such as file handles, may vary; see {@link Repository} for
+	 * more details.)
 	 * <p>
-	 * In all cases, after calling this method you should not use this {@link Git}
-	 * instance anymore.
+	 * If the repository was created by a caller and passed into
+	 * {@link #Git(Repository)} or a static factory method in this class, then
+	 * this method does not call close on the underlying repository.
+	 * <p>
+	 * In all cases, after calling this method you should not use this
+	 * {@link Git} instance anymore.
 	 *
 	 * @since 3.2
 	 */
@@ -154,23 +164,23 @@ public void close() {
 	}
 
 	/**
-	 * Returns a command object to execute a {@code clone} command
+	 * Return a command object to execute a {@code clone} command
 	 *
-	 * @see <a
-	 *      href="http://www.kernel.org/pub/software/scm/git/docs/git-clone.html"
+	 * @see <a href=
+	 *      "http://www.kernel.org/pub/software/scm/git/docs/git-clone.html"
 	 *      >Git documentation about clone</a>
-	 * @return a {@link CloneCommand} used to collect all optional parameters
-	 *         and to finally execute the {@code clone} command
+	 * @return a {@link org.eclipse.jgit.api.CloneCommand} used to collect all
+	 *         optional parameters and to finally execute the {@code clone}
+	 *         command
 	 */
 	public static CloneCommand cloneRepository() {
 		return new CloneCommand();
 	}
 
 	/**
-	 * Returns a command to list remote branches/tags without a local
-	 * repository.
+	 * Return a command to list remote branches/tags without a local repository.
 	 *
-	 * @return a {@link LsRemoteCommand}
+	 * @return a {@link org.eclipse.jgit.api.LsRemoteCommand}
 	 * @since 3.1
 	 */
 	public static LsRemoteCommand lsRemoteRepository() {
@@ -178,24 +188,25 @@ public static LsRemoteCommand lsRemoteRepository() {
 	}
 
 	/**
-	 * Returns a command object to execute a {@code init} command
+	 * Return a command object to execute a {@code init} command
 	 *
-	 * @see <a
-	 *      href="http://www.kernel.org/pub/software/scm/git/docs/git-init.html"
-	 *      >Git documentation about init</a>
-	 * @return a {@link InitCommand} used to collect all optional parameters and
-	 *         to finally execute the {@code init} command
+	 * @see <a href=
+	 *      "http://www.kernel.org/pub/software/scm/git/docs/git-init.html" >Git
+	 *      documentation about init</a>
+	 * @return a {@link org.eclipse.jgit.api.InitCommand} used to collect all
+	 *         optional parameters and to finally execute the {@code init}
+	 *         command
 	 */
 	public static InitCommand init() {
 		return new InitCommand();
 	}
 
 	/**
-	 * Constructs a new {@link Git} object which can interact with the specified
-	 * git repository.
+	 * Construct a new {@link org.eclipse.jgit.api.Git} object which can
+	 * interact with the specified git repository.
 	 * <p>
-	 * All command classes returned by methods of this class will always interact
-	 * with this git repository.
+	 * All command classes returned by methods of this class will always
+	 * interact with this git repository.
 	 * <p>
 	 * The caller is responsible for closing the repository; {@link #close()} on
 	 * this instance does not close the repo.
@@ -216,75 +227,78 @@ public Git(Repository repo) {
 	}
 
 	/**
-	 * Returns a command object to execute a {@code Commit} command
+	 * Return a command object to execute a {@code Commit} command
 	 *
-	 * @see <a
-	 *      href="http://www.kernel.org/pub/software/scm/git/docs/git-commit.html"
+	 * @see <a href=
+	 *      "http://www.kernel.org/pub/software/scm/git/docs/git-commit.html"
 	 *      >Git documentation about Commit</a>
-	 * @return a {@link CommitCommand} used to collect all optional parameters
-	 *         and to finally execute the {@code Commit} command
+	 * @return a {@link org.eclipse.jgit.api.CommitCommand} used to collect all
+	 *         optional parameters and to finally execute the {@code Commit}
+	 *         command
 	 */
 	public CommitCommand commit() {
 		return new CommitCommand(repo);
 	}
 
 	/**
-	 * Returns a command object to execute a {@code Log} command
+	 * Return a command object to execute a {@code Log} command
 	 *
-	 * @see <a
-	 *      href="http://www.kernel.org/pub/software/scm/git/docs/git-log.html"
-	 *      >Git documentation about Log</a>
-	 * @return a {@link LogCommand} used to collect all optional parameters and
-	 *         to finally execute the {@code Log} command
+	 * @see <a href=
+	 *      "http://www.kernel.org/pub/software/scm/git/docs/git-log.html" >Git
+	 *      documentation about Log</a>
+	 * @return a {@link org.eclipse.jgit.api.LogCommand} used to collect all
+	 *         optional parameters and to finally execute the {@code Log}
+	 *         command
 	 */
 	public LogCommand log() {
 		return new LogCommand(repo);
 	}
 
 	/**
-	 * Returns a command object to execute a {@code Merge} command
+	 * Return a command object to execute a {@code Merge} command
 	 *
-	 * @see <a
-	 *      href="http://www.kernel.org/pub/software/scm/git/docs/git-merge.html"
+	 * @see <a href=
+	 *      "http://www.kernel.org/pub/software/scm/git/docs/git-merge.html"
 	 *      >Git documentation about Merge</a>
-	 * @return a {@link MergeCommand} used to collect all optional parameters
-	 *         and to finally execute the {@code Merge} command
+	 * @return a {@link org.eclipse.jgit.api.MergeCommand} used to collect all
+	 *         optional parameters and to finally execute the {@code Merge}
+	 *         command
 	 */
 	public MergeCommand merge() {
 		return new MergeCommand(repo);
 	}
 
 	/**
-	 * Returns a command object to execute a {@code Pull} command
+	 * Return a command object to execute a {@code Pull} command
 	 *
-	 * @return a {@link PullCommand}
+	 * @return a {@link org.eclipse.jgit.api.PullCommand}
 	 */
 	public PullCommand pull() {
 		return new PullCommand(repo);
 	}
 
 	/**
-	 * Returns a command object used to create branches
+	 * Return a command object used to create branches
 	 *
-	 * @return a {@link CreateBranchCommand}
+	 * @return a {@link org.eclipse.jgit.api.CreateBranchCommand}
 	 */
 	public CreateBranchCommand branchCreate() {
 		return new CreateBranchCommand(repo);
 	}
 
 	/**
-	 * Returns a command object used to delete branches
+	 * Return a command object used to delete branches
 	 *
-	 * @return a {@link DeleteBranchCommand}
+	 * @return a {@link org.eclipse.jgit.api.DeleteBranchCommand}
 	 */
 	public DeleteBranchCommand branchDelete() {
 		return new DeleteBranchCommand(repo);
 	}
 
 	/**
-	 * Returns a command object used to list branches
+	 * Return a command object used to list branches
 	 *
-	 * @return a {@link ListBranchCommand}
+	 * @return a {@link org.eclipse.jgit.api.ListBranchCommand}
 	 */
 	public ListBranchCommand branchList() {
 		return new ListBranchCommand(repo);
@@ -292,170 +306,180 @@ public ListBranchCommand branchList() {
 
 	/**
 	 *
-	 * Returns a command object used to list tags
+	 * Return a command object used to list tags
 	 *
-	 * @return a {@link ListTagCommand}
+	 * @return a {@link org.eclipse.jgit.api.ListTagCommand}
 	 */
 	public ListTagCommand tagList() {
 		return new ListTagCommand(repo);
 	}
 
 	/**
-	 * Returns a command object used to rename branches
+	 * Return a command object used to rename branches
 	 *
-	 * @return a {@link RenameBranchCommand}
+	 * @return a {@link org.eclipse.jgit.api.RenameBranchCommand}
 	 */
 	public RenameBranchCommand branchRename() {
 		return new RenameBranchCommand(repo);
 	}
 
 	/**
-	 * Returns a command object to execute a {@code Add} command
+	 * Return a command object to execute a {@code Add} command
 	 *
-	 * @see <a
-	 *      href="http://www.kernel.org/pub/software/scm/git/docs/git-add.html"
-	 *      >Git documentation about Add</a>
-	 * @return a {@link AddCommand} used to collect all optional parameters and
-	 *         to finally execute the {@code Add} command
+	 * @see <a href=
+	 *      "http://www.kernel.org/pub/software/scm/git/docs/git-add.html" >Git
+	 *      documentation about Add</a>
+	 * @return a {@link org.eclipse.jgit.api.AddCommand} used to collect all
+	 *         optional parameters and to finally execute the {@code Add}
+	 *         command
 	 */
 	public AddCommand add() {
 		return new AddCommand(repo);
 	}
 
 	/**
-	 * Returns a command object to execute a {@code Tag} command
+	 * Return a command object to execute a {@code Tag} command
 	 *
-	 * @see <a
-	 *      href="http://www.kernel.org/pub/software/scm/git/docs/git-tag.html"
-	 *      >Git documentation about Tag</a>
-	 * @return a {@link TagCommand} used to collect all optional parameters and
-	 *         to finally execute the {@code Tag} command
+	 * @see <a href=
+	 *      "http://www.kernel.org/pub/software/scm/git/docs/git-tag.html" >Git
+	 *      documentation about Tag</a>
+	 * @return a {@link org.eclipse.jgit.api.TagCommand} used to collect all
+	 *         optional parameters and to finally execute the {@code Tag}
+	 *         command
 	 */
 	public TagCommand tag() {
 		return new TagCommand(repo);
 	}
 
 	/**
-	 * Returns a command object to execute a {@code Fetch} command
+	 * Return a command object to execute a {@code Fetch} command
 	 *
-	 * @see <a
-	 *      href="http://www.kernel.org/pub/software/scm/git/docs/git-fetch.html"
+	 * @see <a href=
+	 *      "http://www.kernel.org/pub/software/scm/git/docs/git-fetch.html"
 	 *      >Git documentation about Fetch</a>
-	 * @return a {@link FetchCommand} used to collect all optional parameters
-	 *         and to finally execute the {@code Fetch} command
+	 * @return a {@link org.eclipse.jgit.api.FetchCommand} used to collect all
+	 *         optional parameters and to finally execute the {@code Fetch}
+	 *         command
 	 */
 	public FetchCommand fetch() {
 		return new FetchCommand(repo);
 	}
 
 	/**
-	 * Returns a command object to execute a {@code Push} command
+	 * Return a command object to execute a {@code Push} command
 	 *
-	 * @see <a
-	 *      href="http://www.kernel.org/pub/software/scm/git/docs/git-push.html"
-	 *      >Git documentation about Push</a>
-	 * @return a {@link PushCommand} used to collect all optional parameters and
-	 *         to finally execute the {@code Push} command
+	 * @see <a href=
+	 *      "http://www.kernel.org/pub/software/scm/git/docs/git-push.html" >Git
+	 *      documentation about Push</a>
+	 * @return a {@link org.eclipse.jgit.api.PushCommand} used to collect all
+	 *         optional parameters and to finally execute the {@code Push}
+	 *         command
 	 */
 	public PushCommand push() {
 		return new PushCommand(repo);
 	}
 
 	/**
-	 * Returns a command object to execute a {@code cherry-pick} command
+	 * Return a command object to execute a {@code cherry-pick} command
 	 *
-	 * @see <a
-	 *      href="http://www.kernel.org/pub/software/scm/git/docs/git-cherry-pick.html"
+	 * @see <a href=
+	 *      "http://www.kernel.org/pub/software/scm/git/docs/git-cherry-pick.html"
 	 *      >Git documentation about cherry-pick</a>
-	 * @return a {@link CherryPickCommand} used to collect all optional
-	 *         parameters and to finally execute the {@code cherry-pick} command
+	 * @return a {@link org.eclipse.jgit.api.CherryPickCommand} used to collect
+	 *         all optional parameters and to finally execute the
+	 *         {@code cherry-pick} command
 	 */
 	public CherryPickCommand cherryPick() {
 		return new CherryPickCommand(repo);
 	}
 
 	/**
-	 * Returns a command object to execute a {@code revert} command
+	 * Return a command object to execute a {@code revert} command
 	 *
-	 * @see <a
-	 *      href="http://www.kernel.org/pub/software/scm/git/docs/git-revert.html"
+	 * @see <a href=
+	 *      "http://www.kernel.org/pub/software/scm/git/docs/git-revert.html"
 	 *      >Git documentation about reverting changes</a>
-	 * @return a {@link RevertCommand} used to collect all optional parameters
-	 *         and to finally execute the {@code cherry-pick} command
+	 * @return a {@link org.eclipse.jgit.api.RevertCommand} used to collect all
+	 *         optional parameters and to finally execute the
+	 *         {@code cherry-pick} command
 	 */
 	public RevertCommand revert() {
 		return new RevertCommand(repo);
 	}
 
 	/**
-	 * Returns a command object to execute a {@code Rebase} command
+	 * Return a command object to execute a {@code Rebase} command
 	 *
-	 * @see <a
-	 *      href="http://www.kernel.org/pub/software/scm/git/docs/git-rebase.html"
+	 * @see <a href=
+	 *      "http://www.kernel.org/pub/software/scm/git/docs/git-rebase.html"
 	 *      >Git documentation about rebase</a>
-	 * @return a {@link RebaseCommand} used to collect all optional parameters
-	 *         and to finally execute the {@code rebase} command
+	 * @return a {@link org.eclipse.jgit.api.RebaseCommand} used to collect all
+	 *         optional parameters and to finally execute the {@code rebase}
+	 *         command
 	 */
 	public RebaseCommand rebase() {
 		return new RebaseCommand(repo);
 	}
 
 	/**
-	 * Returns a command object to execute a {@code rm} command
+	 * Return a command object to execute a {@code rm} command
 	 *
-	 * @see <a
-	 *      href="http://www.kernel.org/pub/software/scm/git/docs/git-rm.html"
-	 *      >Git documentation about rm</a>
-	 * @return a {@link RmCommand} used to collect all optional parameters and
-	 *         to finally execute the {@code rm} command
+	 * @see <a href=
+	 *      "http://www.kernel.org/pub/software/scm/git/docs/git-rm.html" >Git
+	 *      documentation about rm</a>
+	 * @return a {@link org.eclipse.jgit.api.RmCommand} used to collect all
+	 *         optional parameters and to finally execute the {@code rm} command
 	 */
 	public RmCommand rm() {
 		return new RmCommand(repo);
 	}
 
 	/**
-	 * Returns a command object to execute a {@code checkout} command
+	 * Return a command object to execute a {@code checkout} command
 	 *
-	 * @see <a
-	 *      href="http://www.kernel.org/pub/software/scm/git/docs/git-checkout.html"
+	 * @see <a href=
+	 *      "http://www.kernel.org/pub/software/scm/git/docs/git-checkout.html"
 	 *      >Git documentation about checkout</a>
-	 * @return a {@link CheckoutCommand} used to collect all optional parameters
-	 *         and to finally execute the {@code checkout} command
+	 * @return a {@link org.eclipse.jgit.api.CheckoutCommand} used to collect
+	 *         all optional parameters and to finally execute the
+	 *         {@code checkout} command
 	 */
 	public CheckoutCommand checkout() {
 		return new CheckoutCommand(repo);
 	}
 
 	/**
-	 * Returns a command object to execute a {@code reset} command
+	 * Return a command object to execute a {@code reset} command
 	 *
-	 * @see <a
-	 *      href="http://www.kernel.org/pub/software/scm/git/docs/git-reset.html"
+	 * @see <a href=
+	 *      "http://www.kernel.org/pub/software/scm/git/docs/git-reset.html"
 	 *      >Git documentation about reset</a>
-	 * @return a {@link ResetCommand} used to collect all optional parameters
-	 *         and to finally execute the {@code reset} command
+	 * @return a {@link org.eclipse.jgit.api.ResetCommand} used to collect all
+	 *         optional parameters and to finally execute the {@code reset}
+	 *         command
 	 */
 	public ResetCommand reset() {
 		return new ResetCommand(repo);
 	}
 
 	/**
-	 * Returns a command object to execute a {@code status} command
+	 * Return a command object to execute a {@code status} command
 	 *
-	 * @see <a
-	 *      href="http://www.kernel.org/pub/software/scm/git/docs/git-status.html"
+	 * @see <a href=
+	 *      "http://www.kernel.org/pub/software/scm/git/docs/git-status.html"
 	 *      >Git documentation about status</a>
-	 * @return a {@link StatusCommand} used to collect all optional parameters
-	 *         and to finally execute the {@code status} command
+	 * @return a {@link org.eclipse.jgit.api.StatusCommand} used to collect all
+	 *         optional parameters and to finally execute the {@code status}
+	 *         command
 	 */
 	public StatusCommand status() {
 		return new StatusCommand(repo);
 	}
 
 	/**
-	 * Returns a command to create an archive from a tree
+	 * Return a command to create an archive from a tree
 	 *
-	 * @return a {@link ArchiveCommand}
+	 * @return a {@link org.eclipse.jgit.api.ArchiveCommand}
 	 * @since 3.1
 	 */
 	public ArchiveCommand archive() {
@@ -463,179 +487,196 @@ public ArchiveCommand archive() {
 	}
 
 	/**
-	 * Returns a command to add notes to an object
+	 * Return a command to add notes to an object
 	 *
-	 * @return a {@link AddNoteCommand}
+	 * @return a {@link org.eclipse.jgit.api.AddNoteCommand}
 	 */
 	public AddNoteCommand notesAdd() {
 		return new AddNoteCommand(repo);
 	}
 
 	/**
-	 * Returns a command to remove notes on an object
+	 * Return a command to remove notes on an object
 	 *
-	 * @return a {@link RemoveNoteCommand}
+	 * @return a {@link org.eclipse.jgit.api.RemoveNoteCommand}
 	 */
 	public RemoveNoteCommand notesRemove() {
 		return new RemoveNoteCommand(repo);
 	}
 
 	/**
-	 * Returns a command to list all notes
+	 * Return a command to list all notes
 	 *
-	 * @return a {@link ListNotesCommand}
+	 * @return a {@link org.eclipse.jgit.api.ListNotesCommand}
 	 */
 	public ListNotesCommand notesList() {
 		return new ListNotesCommand(repo);
 	}
 
 	/**
-	 * Returns a command to show notes on an object
+	 * Return a command to show notes on an object
 	 *
-	 * @return a {@link ShowNoteCommand}
+	 * @return a {@link org.eclipse.jgit.api.ShowNoteCommand}
 	 */
 	public ShowNoteCommand notesShow() {
 		return new ShowNoteCommand(repo);
 	}
 
 	/**
-	 * Returns a command object to execute a {@code ls-remote} command
+	 * Return a command object to execute a {@code ls-remote} command
 	 *
-	 * @see <a
-	 *      href="http://www.kernel.org/pub/software/scm/git/docs/git-ls-remote.html"
+	 * @see <a href=
+	 *      "http://www.kernel.org/pub/software/scm/git/docs/git-ls-remote.html"
 	 *      >Git documentation about ls-remote</a>
-	 * @return a {@link LsRemoteCommand} used to collect all optional parameters
-	 *         and to finally execute the {@code status} command
+	 * @return a {@link org.eclipse.jgit.api.LsRemoteCommand} used to collect
+	 *         all optional parameters and to finally execute the {@code status}
+	 *         command
 	 */
 	public LsRemoteCommand lsRemote() {
 		return new LsRemoteCommand(repo);
 	}
 
 	/**
-	 * Returns a command object to execute a {@code clean} command
+	 * Return a command object to execute a {@code clean} command
 	 *
-	 * @see <a
-	 *      href="http://www.kernel.org/pub/software/scm/git/docs/git-clean.html"
+	 * @see <a href=
+	 *      "http://www.kernel.org/pub/software/scm/git/docs/git-clean.html"
 	 *      >Git documentation about Clean</a>
-	 * @return a {@link CleanCommand} used to collect all optional parameters
-	 *         and to finally execute the {@code clean} command
+	 * @return a {@link org.eclipse.jgit.api.CleanCommand} used to collect all
+	 *         optional parameters and to finally execute the {@code clean}
+	 *         command
 	 */
 	public CleanCommand clean() {
 		return new CleanCommand(repo);
 	}
 
 	/**
-	 * Returns a command object to execute a {@code blame} command
+	 * Return a command object to execute a {@code blame} command
 	 *
-	 * @see <a
-	 *      href="http://www.kernel.org/pub/software/scm/git/docs/git-blame.html"
+	 * @see <a href=
+	 *      "http://www.kernel.org/pub/software/scm/git/docs/git-blame.html"
 	 *      >Git documentation about Blame</a>
-	 * @return a {@link BlameCommand} used to collect all optional parameters
-	 *         and to finally execute the {@code blame} command
+	 * @return a {@link org.eclipse.jgit.api.BlameCommand} used to collect all
+	 *         optional parameters and to finally execute the {@code blame}
+	 *         command
 	 */
 	public BlameCommand blame() {
 		return new BlameCommand(repo);
 	}
 
 	/**
-	 * Returns a command object to execute a {@code reflog} command
+	 * Return a command object to execute a {@code reflog} command
 	 *
-	 * @see <a
-	 *      href="http://www.kernel.org/pub/software/scm/git/docs/git-reflog.html"
+	 * @see <a href=
+	 *      "http://www.kernel.org/pub/software/scm/git/docs/git-reflog.html"
 	 *      >Git documentation about reflog</a>
-	 * @return a {@link ReflogCommand} used to collect all optional parameters
-	 *         and to finally execute the {@code reflog} command
+	 * @return a {@link org.eclipse.jgit.api.ReflogCommand} used to collect all
+	 *         optional parameters and to finally execute the {@code reflog}
+	 *         command
 	 */
 	public ReflogCommand reflog() {
 		return new ReflogCommand(repo);
 	}
 
 	/**
-	 * Returns a command object to execute a {@code diff} command
+	 * Return a command object to execute a {@code diff} command
 	 *
-	 * @see <a
-	 *      href="http://www.kernel.org/pub/software/scm/git/docs/git-diff.html"
-	 *      >Git documentation about diff</a>
-	 * @return a {@link DiffCommand} used to collect all optional parameters and
-	 *         to finally execute the {@code diff} command
+	 * @see <a href=
+	 *      "http://www.kernel.org/pub/software/scm/git/docs/git-diff.html" >Git
+	 *      documentation about diff</a>
+	 * @return a {@link org.eclipse.jgit.api.DiffCommand} used to collect all
+	 *         optional parameters and to finally execute the {@code diff}
+	 *         command
 	 */
 	public DiffCommand diff() {
 		return new DiffCommand(repo);
 	}
 
 	/**
-	 * Returns a command object used to delete tags
+	 * Return a command object used to delete tags
 	 *
-	 * @return a {@link DeleteTagCommand}
+	 * @return a {@link org.eclipse.jgit.api.DeleteTagCommand}
 	 */
 	public DeleteTagCommand tagDelete() {
 		return new DeleteTagCommand(repo);
 	}
 
 	/**
-	 * Returns a command object to execute a {@code submodule add} command
+	 * Return a command object to execute a {@code submodule add} command
 	 *
-	 * @return a {@link SubmoduleAddCommand} used to add a new submodule to a
-	 *         parent repository
+	 * @return a {@link org.eclipse.jgit.api.SubmoduleAddCommand} used to add a
+	 *         new submodule to a parent repository
 	 */
 	public SubmoduleAddCommand submoduleAdd() {
 		return new SubmoduleAddCommand(repo);
 	}
 
 	/**
-	 * Returns a command object to execute a {@code submodule init} command
+	 * Return a command object to execute a {@code submodule init} command
 	 *
-	 * @return a {@link SubmoduleInitCommand} used to initialize the
-	 *         repository's config with settings from the .gitmodules file in
-	 *         the working tree
+	 * @return a {@link org.eclipse.jgit.api.SubmoduleInitCommand} used to
+	 *         initialize the repository's config with settings from the
+	 *         .gitmodules file in the working tree
 	 */
 	public SubmoduleInitCommand submoduleInit() {
 		return new SubmoduleInitCommand(repo);
 	}
 
 	/**
+	 * Returns a command object to execute a {@code submodule deinit} command
+	 *
+	 * @return a {@link org.eclipse.jgit.api.SubmoduleDeinitCommand} used to
+	 *         remove a submodule's working tree manifestation
+	 * @since 4.10
+	 */
+	public SubmoduleDeinitCommand submoduleDeinit() {
+		return new SubmoduleDeinitCommand(repo);
+	}
+
+	/**
 	 * Returns a command object to execute a {@code submodule status} command
 	 *
-	 * @return a {@link SubmoduleStatusCommand} used to report the status of a
-	 *         repository's configured submodules
+	 * @return a {@link org.eclipse.jgit.api.SubmoduleStatusCommand} used to
+	 *         report the status of a repository's configured submodules
 	 */
 	public SubmoduleStatusCommand submoduleStatus() {
 		return new SubmoduleStatusCommand(repo);
 	}
 
 	/**
-	 * Returns a command object to execute a {@code submodule sync} command
+	 * Return a command object to execute a {@code submodule sync} command
 	 *
-	 * @return a {@link SubmoduleSyncCommand} used to update the URL of a
-	 *         submodule from the parent repository's .gitmodules file
+	 * @return a {@link org.eclipse.jgit.api.SubmoduleSyncCommand} used to
+	 *         update the URL of a submodule from the parent repository's
+	 *         .gitmodules file
 	 */
 	public SubmoduleSyncCommand submoduleSync() {
 		return new SubmoduleSyncCommand(repo);
 	}
 
 	/**
-	 * Returns a command object to execute a {@code submodule update} command
+	 * Return a command object to execute a {@code submodule update} command
 	 *
-	 * @return a {@link SubmoduleUpdateCommand} used to update the submodules in
-	 *         a repository to the configured revision
+	 * @return a {@link org.eclipse.jgit.api.SubmoduleUpdateCommand} used to
+	 *         update the submodules in a repository to the configured revision
 	 */
 	public SubmoduleUpdateCommand submoduleUpdate() {
 		return new SubmoduleUpdateCommand(repo);
 	}
 
 	/**
-	 * Returns a command object used to list stashed commits
+	 * Return a command object used to list stashed commits
 	 *
-	 * @return a {@link StashListCommand}
+	 * @return a {@link org.eclipse.jgit.api.StashListCommand}
 	 */
 	public StashListCommand stashList() {
 		return new StashListCommand(repo);
 	}
 
 	/**
-	 * Returns a command object used to create a stashed commit
+	 * Return a command object used to create a stashed commit
 	 *
-	 * @return a {@link StashCreateCommand}
+	 * @return a {@link org.eclipse.jgit.api.StashCreateCommand}
 	 * @since 2.0
 	 */
 	public StashCreateCommand stashCreate() {
@@ -643,9 +684,9 @@ public StashCreateCommand stashCreate() {
 	}
 
 	/**
-	 * Returns a command object used to apply a stashed commit
+	 * Returs a command object used to apply a stashed commit
 	 *
-	 * @return a {@link StashApplyCommand}
+	 * @return a {@link org.eclipse.jgit.api.StashApplyCommand}
 	 * @since 2.0
 	 */
 	public StashApplyCommand stashApply() {
@@ -653,9 +694,9 @@ public StashApplyCommand stashApply() {
 	}
 
 	/**
-	 * Returns a command object used to drop a stashed commit
+	 * Return a command object used to drop a stashed commit
 	 *
-	 * @return a {@link StashDropCommand}
+	 * @return a {@link org.eclipse.jgit.api.StashDropCommand}
 	 * @since 2.0
 	 */
 	public StashDropCommand stashDrop() {
@@ -663,14 +704,14 @@ public StashDropCommand stashDrop() {
 	}
 
 	/**
-	 * Returns a command object to execute a {@code apply} command
+	 * Return a command object to execute a {@code apply} command
 	 *
-	 * @see <a
-	 *      href="http://www.kernel.org/pub/software/scm/git/docs/git-apply.html"
+	 * @see <a href=
+	 *      "http://www.kernel.org/pub/software/scm/git/docs/git-apply.html"
 	 *      >Git documentation about apply</a>
-	 *
-	 * @return a {@link ApplyCommand} used to collect all optional parameters
-	 *         and to finally execute the {@code apply} command
+	 * @return a {@link org.eclipse.jgit.api.ApplyCommand} used to collect all
+	 *         optional parameters and to finally execute the {@code apply}
+	 *         command
 	 * @since 2.0
 	 */
 	public ApplyCommand apply() {
@@ -678,14 +719,14 @@ public ApplyCommand apply() {
 	}
 
 	/**
-	 * Returns a command object to execute a {@code gc} command
+	 * Return a command object to execute a {@code gc} command
 	 *
-	 * @see <a
-	 *      href="http://www.kernel.org/pub/software/scm/git/docs/git-gc.html"
-	 *      >Git documentation about gc</a>
-	 *
-	 * @return a {@link GarbageCollectCommand} used to collect all optional
-	 *         parameters and to finally execute the {@code gc} command
+	 * @see <a href=
+	 *      "http://www.kernel.org/pub/software/scm/git/docs/git-gc.html" >Git
+	 *      documentation about gc</a>
+	 * @return a {@link org.eclipse.jgit.api.GarbageCollectCommand} used to
+	 *         collect all optional parameters and to finally execute the
+	 *         {@code gc} command
 	 * @since 2.2
 	 */
 	public GarbageCollectCommand gc() {
@@ -693,9 +734,9 @@ public GarbageCollectCommand gc() {
 	}
 
 	/**
-	 * Returns a command object to find human-readable names of revisions.
+	 * Return a command object to find human-readable names of revisions.
 	 *
-	 * @return a {@link NameRevCommand}.
+	 * @return a {@link org.eclipse.jgit.api.NameRevCommand}.
 	 * @since 3.0
 	 */
 	public NameRevCommand nameRev() {
@@ -703,10 +744,10 @@ public NameRevCommand nameRev() {
 	}
 
 	/**
-	 * Returns a command object to come up with a short name that describes a
+	 * Return a command object to come up with a short name that describes a
 	 * commit in terms of the nearest git tag.
 	 *
-	 * @return a {@link DescribeCommand}.
+	 * @return a {@link org.eclipse.jgit.api.DescribeCommand}.
 	 * @since 3.2
 	 */
 	public DescribeCommand describe() {
@@ -716,7 +757,7 @@ public DescribeCommand describe() {
 	/**
 	 * Return a command used to list the available remotes.
 	 *
-	 * @return a {@link RemoteListCommand}
+	 * @return a {@link org.eclipse.jgit.api.RemoteListCommand}
 	 * @since 4.2
 	 */
 	public RemoteListCommand remoteList() {
@@ -726,7 +767,7 @@ public RemoteListCommand remoteList() {
 	/**
 	 * Return a command used to add a new remote.
 	 *
-	 * @return a {@link RemoteAddCommand}
+	 * @return a {@link org.eclipse.jgit.api.RemoteAddCommand}
 	 * @since 4.2
 	 */
 	public RemoteAddCommand remoteAdd() {
@@ -736,7 +777,7 @@ public RemoteAddCommand remoteAdd() {
 	/**
 	 * Return a command used to remove an existing remote.
 	 *
-	 * @return a {@link RemoteRemoveCommand}
+	 * @return a {@link org.eclipse.jgit.api.RemoteRemoveCommand}
 	 * @since 4.2
 	 */
 	public RemoteRemoveCommand remoteRemove() {
@@ -746,7 +787,7 @@ public RemoteRemoveCommand remoteRemove() {
 	/**
 	 * Return a command used to change the URL of an existing remote.
 	 *
-	 * @return a {@link RemoteSetUrlCommand}
+	 * @return a {@link org.eclipse.jgit.api.RemoteSetUrlCommand}
 	 * @since 4.2
 	 */
 	public RemoteSetUrlCommand remoteSetUrl() {
@@ -754,6 +795,8 @@ public RemoteSetUrlCommand remoteSetUrl() {
 	}
 
 	/**
+	 * Get repository
+	 *
 	 * @return the git repository this class is interacting with; see
 	 *         {@link #close()} for notes on closing this repository.
 	 */
@@ -761,6 +804,7 @@ public Repository getRepository() {
 		return repo;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public String toString() {
 		return "Git[" + repo + "]"; //$NON-NLS-1$//$NON-NLS-2$
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/GitCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/GitCommand.java
index 2a23408..ee7d75c 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/GitCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/GitCommand.java
@@ -48,18 +48,20 @@
 /**
  * Common superclass of all commands in the package {@code org.eclipse.jgit.api}
  * <p>
- * This class ensures that all commands fulfill the {@link Callable} interface.
- * It also has a property {@link #repo} holding a reference to the git
- * {@link Repository} this command should work with.
+ * This class ensures that all commands fulfill the
+ * {@link java.util.concurrent.Callable} interface. It also has a property
+ * {@link #repo} holding a reference to the git
+ * {@link org.eclipse.jgit.lib.Repository} this command should work with.
  * <p>
  * Finally this class stores a state telling whether it is allowed to call
- * {@link #call()} on this instance. Instances of {@link GitCommand} can only be
- * used for one single successful call to {@link #call()}. Afterwards this
- * instance may not be used anymore to set/modify any properties or to call
- * {@link #call()} again. This is achieved by setting the {@link #callable}
- * property to false after the successful execution of {@link #call()} and to
- * check the state (by calling {@link #checkCallable()}) before setting of
- * properties and inside {@link #call()}.
+ * {@link #call()} on this instance. Instances of
+ * {@link org.eclipse.jgit.api.GitCommand} can only be used for one single
+ * successful call to {@link #call()}. Afterwards this instance may not be used
+ * anymore to set/modify any properties or to call {@link #call()} again. This
+ * is achieved by setting the {@link #callable} property to false after the
+ * successful execution of {@link #call()} and to check the state (by calling
+ * {@link #checkCallable()}) before setting of properties and inside
+ * {@link #call()}.
  *
  * @param <T>
  *            the return type which is expected from {@link #call()}
@@ -78,14 +80,18 @@ public abstract class GitCommand<T> implements Callable<T> {
 	 * Creates a new command which interacts with a single repository
 	 *
 	 * @param repo
-	 *            the {@link Repository} this command should interact with
+	 *            the {@link org.eclipse.jgit.lib.Repository} this command
+	 *            should interact with
 	 */
 	protected GitCommand(Repository repo) {
 		this.repo = repo;
 	}
 
 	/**
-	 * @return the {@link Repository} this command is interacting with
+	 * Get repository this command is working on
+	 *
+	 * @return the {@link org.eclipse.jgit.lib.Repository} this command is
+	 *         interacting with
 	 */
 	public Repository getRepository() {
 		return repo;
@@ -106,9 +112,9 @@ protected void setCallable(boolean callable) {
 
 	/**
 	 * Checks that the property {@link #callable} is {@code true}. If not then
-	 * an {@link IllegalStateException} is thrown
+	 * an {@link java.lang.IllegalStateException} is thrown
 	 *
-	 * @throws IllegalStateException
+	 * @throws java.lang.IllegalStateException
 	 *             when this method is called and the property {@link #callable}
 	 *             is {@code false}
 	 */
@@ -120,11 +126,9 @@ protected void checkCallable() {
 	}
 
 	/**
-	 * Executes the command
-	 *
-	 * @return T a result. Each command has its own return type
-	 * @throws GitAPIException
-	 *             or subclass thereof when an error occurs
+	 * {@inheritDoc}
+	 * <p>
+	 * Execute the command
 	 */
 	@Override
 	public abstract T call() throws GitAPIException;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/InitCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/InitCommand.java
index 649484c..d48049f 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/InitCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/InitCommand.java
@@ -53,6 +53,7 @@
 import org.eclipse.jgit.lib.Constants;
 import org.eclipse.jgit.lib.Repository;
 import org.eclipse.jgit.lib.RepositoryBuilder;
+import org.eclipse.jgit.util.FS;
 import org.eclipse.jgit.util.SystemReader;
 
 /**
@@ -68,10 +69,15 @@ public class InitCommand implements Callable<Git> {
 
 	private boolean bare;
 
+	private FS fs;
+
 	/**
+	 * {@inheritDoc}
+	 * <p>
 	 * Executes the {@code Init} command.
 	 *
-	 * @return the newly created {@code Git} object with associated repository
+	 * @return a {@code Git} instance that owns the {@code Repository} that it
+	 *         wraps.
 	 */
 	@Override
 	public Git call() throws GitAPIException {
@@ -79,6 +85,9 @@ public Git call() throws GitAPIException {
 			RepositoryBuilder builder = new RepositoryBuilder();
 			if (bare)
 				builder.setBare();
+			if (fs != null) {
+				builder.setFS(fs);
+			}
 			builder.readEnvironment();
 			if (gitDir != null)
 				builder.setGitDir(gitDir);
@@ -114,7 +123,7 @@ public Git call() throws GitAPIException {
 			Repository repository = builder.build();
 			if (!repository.getObjectDatabase().exists())
 				repository.create(bare);
-			return new Git(repository);
+			return new Git(repository, true);
 		} catch (IOException e) {
 			throw new JGitInternalException(e.getMessage(), e);
 		}
@@ -127,7 +136,7 @@ public Git call() throws GitAPIException {
 	 * @param directory
 	 *            the directory to init to
 	 * @return this instance
-	 * @throws IllegalStateException
+	 * @throws java.lang.IllegalStateException
 	 *             if the combination of directory, gitDir and bare is illegal.
 	 *             E.g. if for a non-bare repository directory and gitDir point
 	 *             to the same directory of if for a bare repository both
@@ -141,10 +150,12 @@ public InitCommand setDirectory(File directory)
 	}
 
 	/**
+	 * Set the repository meta directory (.git)
+	 *
 	 * @param gitDir
 	 *            the repository meta directory
 	 * @return this instance
-	 * @throws IllegalStateException
+	 * @throws java.lang.IllegalStateException
 	 *             if the combination of directory, gitDir and bare is illegal.
 	 *             E.g. if for a non-bare repository directory and gitDir point
 	 *             to the same directory of if for a bare repository both
@@ -176,9 +187,11 @@ private static void validateDirs(File directory, File gitDir, boolean bare)
 	}
 
 	/**
+	 * Set whether the repository is bare or not
+	 *
 	 * @param bare
 	 *            whether the repository is bare or not
-	 * @throws IllegalStateException
+	 * @throws java.lang.IllegalStateException
 	 *             if the combination of directory, gitDir and bare is illegal.
 	 *             E.g. if for a non-bare repository directory and gitDir point
 	 *             to the same directory of if for a bare repository both
@@ -190,4 +203,18 @@ public InitCommand setBare(boolean bare) {
 		this.bare = bare;
 		return this;
 	}
+
+	/**
+	 * Set the file system abstraction to be used for repositories created by
+	 * this command.
+	 *
+	 * @param fs
+	 *            the abstraction.
+	 * @return {@code this} (for chaining calls).
+	 * @since 4.10
+	 */
+	public InitCommand setFs(FS fs) {
+		this.fs = fs;
+		return this;
+	}
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/ListBranchCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/ListBranchCommand.java
index 961eeaa..28a27a9 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/ListBranchCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/ListBranchCommand.java
@@ -95,12 +95,16 @@ public enum ListMode {
 	}
 
 	/**
+	 * Constructor for ListBranchCommand.
+	 *
 	 * @param repo
+	 *            a {@link org.eclipse.jgit.lib.Repository} object.
 	 */
 	protected ListBranchCommand(Repository repo) {
 		super(repo);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public List<Ref> call() throws GitAPIException {
 		checkCallable();
@@ -154,6 +158,8 @@ private Collection<Ref> filterRefs(Collection<Ref> refs)
 	}
 
 	/**
+	 * Set the list mode
+	 *
 	 * @param listMode
 	 *            optional: corresponds to the -r/-a options; by default, only
 	 *            local branches will be listed
@@ -181,6 +187,6 @@ public ListBranchCommand setContains(String containsCommitish) {
 	}
 
 	private Collection<Ref> getRefs(String prefix) throws IOException {
-		return repo.getRefDatabase().getRefs(prefix).values();
+		return repo.getRefDatabase().getRefsByPrefix(prefix);
 	}
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/ListNotesCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/ListNotesCommand.java
index 476c10b..41691fb 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/ListNotesCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/ListNotesCommand.java
@@ -68,15 +68,16 @@ public class ListNotesCommand extends GitCommand<List<Note>> {
 	private String notesRef = Constants.R_NOTES_COMMITS;
 
 	/**
+	 * Constructor for ListNotesCommand.
+	 *
 	 * @param repo
+	 *            the {@link org.eclipse.jgit.lib.Repository}
 	 */
 	protected ListNotesCommand(Repository repo) {
 		super(repo);
 	}
 
-	/**
-	 * @return the requested notes
-	 */
+	/** {@inheritDoc} */
 	@Override
 	public List<Note> call() throws GitAPIException {
 		checkCallable();
@@ -101,12 +102,14 @@ public List<Note> call() throws GitAPIException {
 	}
 
 	/**
-	 * @param notesRef
-	 *            the ref to read notes from. Note, the default value of
-	 *            {@link Constants#R_NOTES_COMMITS} will be used if nothing is
-	 *            set
-	 * @return {@code this}
+	 * Set the {@code Ref} to read notes from
 	 *
+	 * @param notesRef
+	 *            the name of the {@code Ref} to read notes from. Note, the
+	 *            default value of
+	 *            {@link org.eclipse.jgit.lib.Constants#R_NOTES_COMMITS} will be
+	 *            used if nothing is set
+	 * @return {@code this}
 	 * @see Constants#R_NOTES_COMMITS
 	 */
 	public ListNotesCommand setNotesRef(String notesRef) {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/ListTagCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/ListTagCommand.java
index d649a53..01c1991 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/ListTagCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/ListTagCommand.java
@@ -47,7 +47,6 @@
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.List;
-import java.util.Map;
 
 import org.eclipse.jgit.api.errors.GitAPIException;
 import org.eclipse.jgit.api.errors.JGitInternalException;
@@ -65,23 +64,24 @@
 public class ListTagCommand extends GitCommand<List<Ref>> {
 
 	/**
+	 * Constructor for ListTagCommand.
+	 *
 	 * @param repo
+	 *            a {@link org.eclipse.jgit.lib.Repository} object.
 	 */
 	protected ListTagCommand(Repository repo) {
 		super(repo);
 	}
 
-	/**
-	 * @return the tags available
-	 */
+	/** {@inheritDoc} */
 	@Override
 	public List<Ref> call() throws GitAPIException {
 		checkCallable();
-		Map<String, Ref> refList;
 		List<Ref> tags = new ArrayList<>();
 		try (RevWalk revWalk = new RevWalk(repo)) {
-			refList = repo.getRefDatabase().getRefs(Constants.R_TAGS);
-			for (Ref ref : refList.values()) {
+			List<Ref> refList = repo.getRefDatabase()
+					.getRefsByPrefix(Constants.R_TAGS);
+			for (Ref ref : refList) {
 				tags.add(ref);
 			}
 		} catch (IOException e) {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/LogCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/LogCommand.java
index f8fe95a..cf3d35f 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/LogCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/LogCommand.java
@@ -42,13 +42,10 @@
  */
 package org.eclipse.jgit.api;
 
-import static org.eclipse.jgit.lib.RefDatabase.ALL;
-
 import java.io.IOException;
 import java.text.MessageFormat;
 import java.util.ArrayList;
 import java.util.List;
-import java.util.Map;
 
 import org.eclipse.jgit.api.errors.GitAPIException;
 import org.eclipse.jgit.api.errors.JGitInternalException;
@@ -78,7 +75,7 @@
  * to finally execute the command. Each instance of this class should only be
  * used for one invocation of the command (means: one call to {@link #call()})
  * <p>
- * Examples (<code>git</code> is a {@link Git} instance):
+ * Examples (<code>git</code> is a {@link org.eclipse.jgit.api.Git} instance):
  * <p>
  * Get newest 10 commits, starting from the current branch:
  *
@@ -114,7 +111,10 @@ public class LogCommand extends GitCommand<Iterable<RevCommit>> {
 	private int skip = -1;
 
 	/**
+	 * Constructor for LogCommand.
+	 *
 	 * @param repo
+	 *            the {@link org.eclipse.jgit.lib.Repository}
 	 */
 	protected LogCommand(Repository repo) {
 		super(repo);
@@ -122,15 +122,13 @@ protected LogCommand(Repository repo) {
 	}
 
 	/**
+	 * {@inheritDoc}
+	 * <p>
 	 * Executes the {@code Log} command with all the options and parameters
 	 * collected by the setter methods (e.g. {@link #add(AnyObjectId)},
 	 * {@link #not(AnyObjectId)}, ..) of this class. Each instance of this class
 	 * should only be used for one invocation of the command. Don't call this
 	 * method twice on an instance.
-	 *
-	 * @return an iteration over RevCommits
-	 * @throws NoHeadException
-	 *             of the references ref cannot be resolved
 	 */
 	@Override
 	public Iterable<RevCommit> call() throws GitAPIException, NoHeadException {
@@ -174,23 +172,26 @@ else if (maxCount > -1)
 	 *
 	 * @see RevWalk#markStart(RevCommit)
 	 * @param start
+	 *            the id of the commit to start from
 	 * @return {@code this}
-	 * @throws MissingObjectException
+	 * @throws org.eclipse.jgit.errors.MissingObjectException
 	 *             the commit supplied is not available from the object
 	 *             database. This usually indicates the supplied commit is
 	 *             invalid, but the reference was constructed during an earlier
-	 *             invocation to {@link RevWalk#lookupCommit(AnyObjectId)}.
-	 * @throws IncorrectObjectTypeException
+	 *             invocation to
+	 *             {@link org.eclipse.jgit.revwalk.RevWalk#lookupCommit(AnyObjectId)}.
+	 * @throws org.eclipse.jgit.errors.IncorrectObjectTypeException
 	 *             the object was not parsed yet and it was discovered during
 	 *             parsing that it is not actually a commit. This usually
 	 *             indicates the caller supplied a non-commit SHA-1 to
-	 *             {@link RevWalk#lookupCommit(AnyObjectId)}.
+	 *             {@link org.eclipse.jgit.revwalk.RevWalk#lookupCommit(AnyObjectId)}.
 	 * @throws JGitInternalException
 	 *             a low-level exception of JGit has occurred. The original
 	 *             exception can be retrieved by calling
-	 *             {@link Exception#getCause()}. Expect only
+	 *             {@link java.lang.Exception#getCause()}. Expect only
 	 *             {@code IOException's} to be wrapped. Subclasses of
-	 *             {@link IOException} (e.g. {@link MissingObjectException}) are
+	 *             {@link java.io.IOException} (e.g.
+	 *             {@link org.eclipse.jgit.errors.MissingObjectException}) are
 	 *             typically not wrapped here but thrown as original exception
 	 */
 	public LogCommand add(AnyObjectId start) throws MissingObjectException,
@@ -202,23 +203,26 @@ public LogCommand add(AnyObjectId start) throws MissingObjectException,
 	 * Same as {@code --not start}, or {@code ^start}
 	 *
 	 * @param start
+	 *            a {@link org.eclipse.jgit.lib.AnyObjectId}
 	 * @return {@code this}
-	 * @throws MissingObjectException
+	 * @throws org.eclipse.jgit.errors.MissingObjectException
 	 *             the commit supplied is not available from the object
 	 *             database. This usually indicates the supplied commit is
 	 *             invalid, but the reference was constructed during an earlier
-	 *             invocation to {@link RevWalk#lookupCommit(AnyObjectId)}.
-	 * @throws IncorrectObjectTypeException
+	 *             invocation to
+	 *             {@link org.eclipse.jgit.revwalk.RevWalk#lookupCommit(AnyObjectId)}.
+	 * @throws org.eclipse.jgit.errors.IncorrectObjectTypeException
 	 *             the object was not parsed yet and it was discovered during
 	 *             parsing that it is not actually a commit. This usually
 	 *             indicates the caller supplied a non-commit SHA-1 to
-	 *             {@link RevWalk#lookupCommit(AnyObjectId)}.
+	 *             {@link org.eclipse.jgit.revwalk.RevWalk#lookupCommit(AnyObjectId)}.
 	 * @throws JGitInternalException
 	 *             a low-level exception of JGit has occurred. The original
 	 *             exception can be retrieved by calling
-	 *             {@link Exception#getCause()}. Expect only
+	 *             {@link java.lang.Exception#getCause()}. Expect only
 	 *             {@code IOException's} to be wrapped. Subclasses of
-	 *             {@link IOException} (e.g. {@link MissingObjectException}) are
+	 *             {@link java.io.IOException} (e.g.
+	 *             {@link org.eclipse.jgit.errors.MissingObjectException}) are
 	 *             typically not wrapped here but thrown as original exception
 	 */
 	public LogCommand not(AnyObjectId start) throws MissingObjectException,
@@ -230,24 +234,28 @@ public LogCommand not(AnyObjectId start) throws MissingObjectException,
 	 * Adds the range {@code since..until}
 	 *
 	 * @param since
+	 *            a {@link org.eclipse.jgit.lib.AnyObjectId} object.
 	 * @param until
+	 *            a {@link org.eclipse.jgit.lib.AnyObjectId} object.
 	 * @return {@code this}
-	 * @throws MissingObjectException
+	 * @throws org.eclipse.jgit.errors.MissingObjectException
 	 *             the commit supplied is not available from the object
 	 *             database. This usually indicates the supplied commit is
 	 *             invalid, but the reference was constructed during an earlier
-	 *             invocation to {@link RevWalk#lookupCommit(AnyObjectId)}.
-	 * @throws IncorrectObjectTypeException
+	 *             invocation to
+	 *             {@link org.eclipse.jgit.revwalk.RevWalk#lookupCommit(AnyObjectId)}.
+	 * @throws org.eclipse.jgit.errors.IncorrectObjectTypeException
 	 *             the object was not parsed yet and it was discovered during
 	 *             parsing that it is not actually a commit. This usually
 	 *             indicates the caller supplied a non-commit SHA-1 to
-	 *             {@link RevWalk#lookupCommit(AnyObjectId)}.
+	 *             {@link org.eclipse.jgit.revwalk.RevWalk#lookupCommit(AnyObjectId)}.
 	 * @throws JGitInternalException
 	 *             a low-level exception of JGit has occurred. The original
 	 *             exception can be retrieved by calling
-	 *             {@link Exception#getCause()}. Expect only
+	 *             {@link java.lang.Exception#getCause()}. Expect only
 	 *             {@code IOException's} to be wrapped. Subclasses of
-	 *             {@link IOException} (e.g. {@link MissingObjectException}) are
+	 *             {@link java.io.IOException} (e.g.
+	 *             {@link org.eclipse.jgit.errors.MissingObjectException}) are
 	 *             typically not wrapped here but thrown as original exception
 	 */
 	public LogCommand addRange(AnyObjectId since, AnyObjectId until)
@@ -260,14 +268,13 @@ public LogCommand addRange(AnyObjectId since, AnyObjectId until)
 	 *
 	 * @see #add(AnyObjectId)
 	 * @return {@code this}
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the references could not be accessed
 	 */
 	public LogCommand all() throws IOException {
-		Map<String, Ref> refs = getRepository().getRefDatabase().getRefs(ALL);
-		for (Ref ref : refs.values()) {
+		for (Ref ref : getRepository().getRefDatabase().getRefs()) {
 			if(!ref.isPeeled())
-				ref = getRepository().peel(ref);
+				ref = getRepository().getRefDatabase().peel(ref);
 
 			ObjectId objectId = ref.getPeeledObjectId();
 			if (objectId == null)
@@ -354,8 +361,7 @@ private LogCommand add(boolean include, AnyObjectId start)
 
 
 	/**
-	 * Sets a filter for the <code>LogCommand</code>.
-	 *
+	 * Set a filter for the <code>LogCommand</code>.
 	 *
 	 * @param aFilter
 	 *            the filter that this instance of <code>LogCommand</code>
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/LsRemoteCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/LsRemoteCommand.java
index 5157a41..3dcc3a5 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/LsRemoteCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/LsRemoteCommand.java
@@ -83,6 +83,8 @@ public class LsRemoteCommand extends
 	private String uploadPack;
 
 	/**
+	 * Constructor for LsRemoteCommand
+	 *
 	 * @param repo
 	 *            local repository or null for operation without local
 	 *            repository
@@ -98,6 +100,7 @@ public LsRemoteCommand(Repository repo) {
 	 *
 	 * @see Constants#DEFAULT_REMOTE_NAME
 	 * @param remote
+	 *            a {@link java.lang.String} object.
 	 * @return {@code this}
 	 */
 	public LsRemoteCommand setRemote(String remote) {
@@ -110,6 +113,7 @@ public LsRemoteCommand setRemote(String remote) {
 	 * Include refs/heads in references results
 	 *
 	 * @param heads
+	 *            whether to include refs/heads
 	 * @return {@code this}
 	 */
 	public LsRemoteCommand setHeads(boolean heads) {
@@ -121,6 +125,7 @@ public LsRemoteCommand setHeads(boolean heads) {
 	 * Include refs/tags in references results
 	 *
 	 * @param tags
+	 *            whether to include tags
 	 * @return {@code this}
 	 */
 	public LsRemoteCommand setTags(boolean tags) {
@@ -132,6 +137,8 @@ public LsRemoteCommand setTags(boolean tags) {
 	 * The full path of git-upload-pack on the remote host
 	 *
 	 * @param uploadPack
+	 *            the full path of executable providing the git-upload-pack
+	 *            service on remote host
 	 * @return {@code this}
 	 */
 	public LsRemoteCommand setUploadPack(String uploadPack) {
@@ -140,18 +147,12 @@ public LsRemoteCommand setUploadPack(String uploadPack) {
 	}
 
 	/**
-	 * Executes the {@code LsRemote} command with all the options and parameters
+	 * {@inheritDoc}
+	 * <p>
+	 * Execute the {@code LsRemote} command with all the options and parameters
 	 * collected by the setter methods (e.g. {@link #setHeads(boolean)}) of this
 	 * class. Each instance of this class should only be used for one invocation
 	 * of the command. Don't call this method twice on an instance.
-	 *
-	 * @return a collection of references in the remote repository
-	 * @throws GitAPIException
-	 *             or subclass thereof when an error occurs
-	 * @throws InvalidRemoteException
-	 *             when called with an invalid remote uri
-	 * @throws org.eclipse.jgit.api.errors.TransportException
-	 *             for errors that occurs during transport
 	 */
 	@Override
 	public Collection<Ref> call() throws GitAPIException,
@@ -164,9 +165,9 @@ public Collection<Ref> call() throws GitAPIException,
 	 * Same as {@link #call()}, but return Map instead of Collection.
 	 *
 	 * @return a map from names to references in the remote repository
-	 * @throws GitAPIException
+	 * @throws org.eclipse.jgit.api.errors.GitAPIException
 	 *             or subclass thereof when an error occurs
-	 * @throws InvalidRemoteException
+	 * @throws org.eclipse.jgit.api.errors.InvalidRemoteException
 	 *             when called with an invalid remote uri
 	 * @throws org.eclipse.jgit.api.errors.TransportException
 	 *             for errors that occurs during transport
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/MergeCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/MergeCommand.java
index 75460fb..b8fa74d 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/MergeCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/MergeCommand.java
@@ -112,6 +112,8 @@ public class MergeCommand extends GitCommand<MergeResult> {
 
 	private String message;
 
+	private boolean insertChangeId;
+
 	private ProgressMonitor monitor = NullProgressMonitor.INSTANCE;
 
 	/**
@@ -211,19 +213,22 @@ public static FastForwardMode valueOf(FastForwardMode.Merge ffMode) {
 	private Boolean commit;
 
 	/**
+	 * Constructor for MergeCommand.
+	 *
 	 * @param repo
+	 *            the {@link org.eclipse.jgit.lib.Repository}
 	 */
 	protected MergeCommand(Repository repo) {
 		super(repo);
 	}
 
 	/**
-	 * Executes the {@code Merge} command with all the options and parameters
+	 * {@inheritDoc}
+	 * <p>
+	 * Execute the {@code Merge} command with all the options and parameters
 	 * collected by the setter methods (e.g. {@link #include(Ref)}) of this
 	 * class. Each instance of this class should only be used for one invocation
 	 * of the command. Don't call this method twice on an instance.
-	 *
-	 * @return the result of the merge
 	 */
 	@Override
 	@SuppressWarnings("boxing")
@@ -234,9 +239,8 @@ public MergeResult call() throws GitAPIException, NoHeadException,
 		fallBackToConfiguration();
 		checkParameters();
 
-		RevWalk revWalk = null;
 		DirCacheCheckout dco = null;
-		try {
+		try (RevWalk revWalk = new RevWalk(repo)) {
 			Ref head = repo.exactRef(Constants.HEAD);
 			if (head == null)
 				throw new NoHeadException(
@@ -244,7 +248,6 @@ public MergeResult call() throws GitAPIException, NoHeadException,
 			StringBuilder refLogMessage = new StringBuilder("merge "); //$NON-NLS-1$
 
 			// Check for FAST_FORWARD, ALREADY_UP_TO_DATE
-			revWalk = new RevWalk(repo);
 
 			// we know for now there is only one commit
 			Ref ref = commits.get(0);
@@ -252,7 +255,7 @@ public MergeResult call() throws GitAPIException, NoHeadException,
 			refLogMessage.append(ref.getName());
 
 			// handle annotated tags
-			ref = repo.peel(ref);
+			ref = repo.getRefDatabase().peel(ref);
 			ObjectId objectId = ref.getPeeledObjectId();
 			if (objectId == null)
 				objectId = ref.getObjectId();
@@ -265,6 +268,7 @@ public MergeResult call() throws GitAPIException, NoHeadException,
 				dco = new DirCacheCheckout(repo,
 						repo.lockDirCache(), srcCommit.getTree());
 				dco.setFailOnConflict(true);
+				dco.setProgressMonitor(monitor);
 				dco.checkout();
 				RefUpdate refUpdate = repo
 						.updateRef(head.getTarget().getName());
@@ -295,6 +299,7 @@ public MergeResult call() throws GitAPIException, NoHeadException,
 				dco = new DirCacheCheckout(repo,
 						headCommit.getTree(), repo.lockDirCache(),
 						srcCommit.getTree());
+				dco.setProgressMonitor(monitor);
 				dco.setFailOnConflict(true);
 				dco.checkout();
 				String msg = null;
@@ -373,6 +378,7 @@ public MergeResult call() throws GitAPIException, NoHeadException,
 							headCommit.getTree(), repo.lockDirCache(),
 							merger.getResultTreeId());
 					dco.setFailOnConflict(true);
+					dco.setProgressMonitor(monitor);
 					dco.checkout();
 
 					String msg = null;
@@ -388,6 +394,7 @@ public MergeResult call() throws GitAPIException, NoHeadException,
 						try (Git git = new Git(getRepository())) {
 							newHeadId = git.commit()
 									.setReflogComment(refLogMessage.toString())
+									.setInsertChangeId(insertChangeId)
 									.call().getId();
 						}
 						mergeStatus = MergeStatus.MERGED;
@@ -433,9 +440,6 @@ public MergeResult call() throws GitAPIException, NoHeadException,
 					MessageFormat.format(
 							JGitText.get().exceptionCaughtDuringExecutionOfMergeCommand,
 							e), e);
-		} finally {
-			if (revWalk != null)
-				revWalk.close();
 		}
 	}
 
@@ -492,9 +496,10 @@ private void updateHead(StringBuilder refLogMessage, ObjectId newHeadId,
 	}
 
 	/**
+	 * Set merge strategy
 	 *
 	 * @param mergeStrategy
-	 *            the {@link MergeStrategy} to be used
+	 *            the {@link org.eclipse.jgit.merge.MergeStrategy} to be used
 	 * @return {@code this}
 	 */
 	public MergeCommand setStrategy(MergeStrategy mergeStrategy) {
@@ -504,6 +509,8 @@ public MergeCommand setStrategy(MergeStrategy mergeStrategy) {
 	}
 
 	/**
+	 * Reference to a commit to be merged with the current head
+	 *
 	 * @param aCommit
 	 *            a reference to a commit which is merged with the current head
 	 * @return {@code this}
@@ -515,6 +522,8 @@ public MergeCommand include(Ref aCommit) {
 	}
 
 	/**
+	 * Id of a commit which is to be merged with the current head
+	 *
 	 * @param aCommit
 	 *            the Id of a commit which is merged with the current head
 	 * @return {@code this}
@@ -524,8 +533,10 @@ public MergeCommand include(AnyObjectId aCommit) {
 	}
 
 	/**
+	 * Include a commit
+	 *
 	 * @param name
-	 *            a name given to the commit
+	 *            a name of a {@code Ref} pointing to the commit
 	 * @param aCommit
 	 *            the Id of a commit which is merged with the current head
 	 * @return {@code this}
@@ -541,9 +552,10 @@ public MergeCommand include(String name, AnyObjectId aCommit) {
 	 * HEAD. Otherwise, perform the merge and commit the result.
 	 * <p>
 	 * In case the merge was successful but this flag was set to
-	 * <code>true</code> a {@link MergeResult} with status
-	 * {@link MergeStatus#MERGED_SQUASHED} or
-	 * {@link MergeStatus#FAST_FORWARD_SQUASHED} is returned.
+	 * <code>true</code> a {@link org.eclipse.jgit.api.MergeResult} with status
+	 * {@link org.eclipse.jgit.api.MergeResult.MergeStatus#MERGED_SQUASHED} or
+	 * {@link org.eclipse.jgit.api.MergeResult.MergeStatus#FAST_FORWARD_SQUASHED}
+	 * is returned.
 	 *
 	 * @param squash
 	 *            whether to squash commits or not
@@ -582,9 +594,11 @@ public MergeCommand setFastForward(
 	 *            <code>true</code> if this command should commit (this is the
 	 *            default behavior). <code>false</code> if this command should
 	 *            not commit. In case the merge was successful but this flag was
-	 *            set to <code>false</code> a {@link MergeResult} with type
-	 *            {@link MergeResult} with status
-	 *            {@link MergeStatus#MERGED_NOT_COMMITTED} is returned
+	 *            set to <code>false</code> a
+	 *            {@link org.eclipse.jgit.api.MergeResult} with type
+	 *            {@link org.eclipse.jgit.api.MergeResult} with status
+	 *            {@link org.eclipse.jgit.api.MergeResult.MergeStatus#MERGED_NOT_COMMITTED}
+	 *            is returned
 	 * @return {@code this}
 	 * @since 3.0
 	 */
@@ -608,11 +622,27 @@ public MergeCommand setMessage(String message) {
 	}
 
 	/**
+	 * If set to true a change id will be inserted into the commit message
+	 *
+	 * An existing change id is not replaced. An initial change id (I000...)
+	 * will be replaced by the change id.
+	 *
+	 * @param insertChangeId
+	 *            whether to insert a change id
+	 * @return {@code this}
+	 * @since 5.0
+	 */
+	public MergeCommand setInsertChangeId(boolean insertChangeId) {
+		checkCallable();
+		this.insertChangeId = insertChangeId;
+		return this;
+	}
+
+	/**
 	 * The progress monitor associated with the diff operation. By default, this
 	 * is set to <code>NullProgressMonitor</code>
 	 *
 	 * @see NullProgressMonitor
-	 *
 	 * @param monitor
 	 *            A progress monitor
 	 * @return this instance
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/MergeResult.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/MergeResult.java
index c487ef6..765b320 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/MergeResult.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/MergeResult.java
@@ -53,11 +53,10 @@
 import org.eclipse.jgit.merge.MergeChunk;
 import org.eclipse.jgit.merge.MergeChunk.ConflictState;
 import org.eclipse.jgit.merge.MergeStrategy;
-import org.eclipse.jgit.merge.ResolveMerger;
 import org.eclipse.jgit.merge.ResolveMerger.MergeFailureReason;
 
 /**
- * Encapsulates the result of a {@link MergeCommand}.
+ * Encapsulates the result of a {@link org.eclipse.jgit.api.MergeCommand}.
  */
 public class MergeResult {
 
@@ -249,6 +248,8 @@ public boolean isSuccessful() {
 	private List<String> checkoutConflicts;
 
 	/**
+	 * Constructor for MergeResult.
+	 *
 	 * @param newHead
 	 *            the object the head points at after the merge
 	 * @param base
@@ -260,10 +261,10 @@ public boolean isSuccessful() {
 	 * @param mergeStatus
 	 *            the status the merge resulted in
 	 * @param mergeStrategy
-	 *            the used {@link MergeStrategy}
+	 *            the used {@link org.eclipse.jgit.merge.MergeStrategy}
 	 * @param lowLevelResults
 	 *            merge results as returned by
-	 *            {@link ResolveMerger#getMergeResults()}
+	 *            {@link org.eclipse.jgit.merge.ResolveMerger#getMergeResults()}
 	 * @since 2.0
 	 */
 	public MergeResult(ObjectId newHead, ObjectId base,
@@ -275,6 +276,8 @@ public MergeResult(ObjectId newHead, ObjectId base,
 	}
 
 	/**
+	 * Constructor for MergeResult.
+	 *
 	 * @param newHead
 	 *            the object the head points at after the merge
 	 * @param base
@@ -286,9 +289,10 @@ public MergeResult(ObjectId newHead, ObjectId base,
 	 * @param mergeStatus
 	 *            the status the merge resulted in
 	 * @param mergeStrategy
-	 *            the used {@link MergeStrategy}
+	 *            the used {@link org.eclipse.jgit.merge.MergeStrategy}
 	 * @param lowLevelResults
-	 *            merge results as returned by {@link ResolveMerger#getMergeResults()}
+	 *            merge results as returned by
+	 *            {@link org.eclipse.jgit.merge.ResolveMerger#getMergeResults()}
 	 * @param description
 	 *            a user friendly description of the merge result
 	 */
@@ -302,6 +306,8 @@ public MergeResult(ObjectId newHead, ObjectId base,
 	}
 
 	/**
+	 * Constructor for MergeResult.
+	 *
 	 * @param newHead
 	 *            the object the head points at after the merge
 	 * @param base
@@ -313,13 +319,13 @@ public MergeResult(ObjectId newHead, ObjectId base,
 	 * @param mergeStatus
 	 *            the status the merge resulted in
 	 * @param mergeStrategy
-	 *            the used {@link MergeStrategy}
+	 *            the used {@link org.eclipse.jgit.merge.MergeStrategy}
 	 * @param lowLevelResults
 	 *            merge results as returned by
-	 *            {@link ResolveMerger#getMergeResults()}
+	 *            {@link org.eclipse.jgit.merge.ResolveMerger#getMergeResults()}
 	 * @param failingPaths
 	 *            list of paths causing this merge to fail as returned by
-	 *            {@link ResolveMerger#getFailingPaths()}
+	 *            {@link org.eclipse.jgit.merge.ResolveMerger#getFailingPaths()}
 	 * @param description
 	 *            a user friendly description of the merge result
 	 */
@@ -354,6 +360,8 @@ public MergeResult(List<String> checkoutConflicts) {
 	}
 
 	/**
+	 * Get the object the head points at after the merge
+	 *
 	 * @return the object the head points at after the merge
 	 */
 	public ObjectId getNewHead() {
@@ -361,6 +369,8 @@ public ObjectId getNewHead() {
 	}
 
 	/**
+	 * Get the merge status
+	 *
 	 * @return the status the merge resulted in
 	 */
 	public MergeStatus getMergeStatus() {
@@ -368,6 +378,8 @@ public MergeStatus getMergeStatus() {
 	}
 
 	/**
+	 * Get the commits which have been merged
+	 *
 	 * @return all the commits which have been merged together
 	 */
 	public ObjectId[] getMergedCommits() {
@@ -375,6 +387,8 @@ public MergeStatus getMergeStatus() {
 	}
 
 	/**
+	 * Get the common base
+	 *
 	 * @return base the common base which was used to produce a content-merge.
 	 *         May be <code>null</code> if the merge-result was produced without
 	 *         computing a common base
@@ -383,6 +397,7 @@ public ObjectId getBase() {
 		return base;
 	}
 
+	/** {@inheritDoc} */
 	@SuppressWarnings("nls")
 	@Override
 	public String toString() {
@@ -402,6 +417,8 @@ public String toString() {
 	}
 
 	/**
+	 * Set conflicts
+	 *
 	 * @param conflicts
 	 *            the conflicts to set
 	 */
@@ -410,7 +427,10 @@ public void setConflicts(Map<String, int[][]> conflicts) {
 	}
 
 	/**
+	 * Add a conflict
+	 *
 	 * @param path
+	 *            path of the file to add a conflict for
 	 * @param conflictingRanges
 	 *            the conflicts to set
 	 */
@@ -421,8 +441,12 @@ public void addConflict(String path, int[][] conflictingRanges) {
 	}
 
 	/**
+	 * Add a conflict
+	 *
 	 * @param path
+	 *            path of the file to add a conflict for
 	 * @param lowLevelResult
+	 *            a {@link org.eclipse.jgit.merge.MergeResult}
 	 */
 	public void addConflict(String path, org.eclipse.jgit.merge.MergeResult<?> lowLevelResult) {
 		if (!lowLevelResult.containsConflicts())
@@ -462,9 +486,10 @@ public void addConflict(String path, org.eclipse.jgit.merge.MergeResult<?> lowLe
 
 	/**
 	 * Returns information about the conflicts which occurred during a
-	 * {@link MergeCommand}. The returned value maps the path of a conflicting
-	 * file to a two-dimensional int-array of line-numbers telling where in the
-	 * file conflict markers for which merged commit can be found.
+	 * {@link org.eclipse.jgit.api.MergeCommand}. The returned value maps the
+	 * path of a conflicting file to a two-dimensional int-array of line-numbers
+	 * telling where in the file conflict markers for which merged commit can be
+	 * found.
 	 * <p>
 	 * If the returned value contains a mapping "path"-&gt;[x][y]=z then this
 	 * means
@@ -505,7 +530,7 @@ public void addConflict(String path, org.eclipse.jgit.merge.MergeResult<?> lowLe
 
 	/**
 	 * Returns a list of paths causing this merge to fail as returned by
-	 * {@link ResolveMerger#getFailingPaths()}
+	 * {@link org.eclipse.jgit.merge.ResolveMerger#getFailingPaths()}
 	 *
 	 * @return the list of paths causing this merge to fail or <code>null</code>
 	 *         if no failure occurred
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/NameRevCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/NameRevCommand.java
index 2a86fab..a2b2007 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/NameRevCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/NameRevCommand.java
@@ -57,7 +57,6 @@
 import org.eclipse.jgit.lib.Constants;
 import org.eclipse.jgit.lib.ObjectId;
 import org.eclipse.jgit.lib.Ref;
-import org.eclipse.jgit.lib.RefDatabase;
 import org.eclipse.jgit.lib.Repository;
 import org.eclipse.jgit.revwalk.FIFORevQueue;
 import org.eclipse.jgit.revwalk.RevCommit;
@@ -120,6 +119,7 @@ public String toString() {
 	 * Create a new name-rev command.
 	 *
 	 * @param repo
+	 *            the {@link org.eclipse.jgit.lib.Repository}
 	 */
 	protected NameRevCommand(Repository repo) {
 		super(repo);
@@ -134,6 +134,7 @@ public NameRevCommit createCommit(AnyObjectId id) {
 		};
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public Map<ObjectId, String> call() throws GitAPIException {
 		try {
@@ -199,13 +200,13 @@ public Map<ObjectId, String> call() throws GitAPIException {
 	 * @param id
 	 *            object ID to add.
 	 * @return {@code this}
-	 * @throws MissingObjectException
+	 * @throws org.eclipse.jgit.errors.MissingObjectException
 	 *             the object supplied is not available from the object
 	 *             database.
-	 * @throws JGitInternalException
+	 * @throws org.eclipse.jgit.api.errors.JGitInternalException
 	 *             a low-level exception of JGit has occurred. The original
 	 *             exception can be retrieved by calling
-	 *             {@link Exception#getCause()}.
+	 *             {@link java.lang.Exception#getCause()}.
 	 */
 	public NameRevCommand add(ObjectId id) throws MissingObjectException,
 			JGitInternalException {
@@ -227,13 +228,13 @@ public NameRevCommand add(ObjectId id) throws MissingObjectException,
 	 * @param ids
 	 *            object IDs to add.
 	 * @return {@code this}
-	 * @throws MissingObjectException
+	 * @throws org.eclipse.jgit.errors.MissingObjectException
 	 *             the object supplied is not available from the object
 	 *             database.
-	 * @throws JGitInternalException
+	 * @throws org.eclipse.jgit.api.errors.JGitInternalException
 	 *             a low-level exception of JGit has occurred. The original
 	 *             exception can be retrieved by calling
-	 *             {@link Exception#getCause()}.
+	 *             {@link java.lang.Exception#getCause()}.
 	 */
 	public NameRevCommand add(Iterable<ObjectId> ids)
 			throws MissingObjectException, JGitInternalException {
@@ -250,7 +251,7 @@ public NameRevCommand add(Iterable<ObjectId> ids)
 	 * prefix added by {@link #addPrefix(String)}.
 	 *
 	 * @param prefix
-	 *            prefix to add; see {@link RefDatabase#getRefs(String)}
+	 *            prefix to add; the prefix must end with a slash
 	 * @return {@code this}
 	 */
 	public NameRevCommand addPrefix(String prefix) {
@@ -260,8 +261,8 @@ public NameRevCommand addPrefix(String prefix) {
 	}
 
 	/**
-	 * Add all annotated tags under {@code refs/tags/} to the set that all results
-	 * must match.
+	 * Add all annotated tags under {@code refs/tags/} to the set that all
+	 * results must match.
 	 * <p>
 	 * Calls {@link #addRef(Ref)}; see that method for a note on matching
 	 * priority.
@@ -270,14 +271,15 @@ public NameRevCommand addPrefix(String prefix) {
 	 * @throws JGitInternalException
 	 *             a low-level exception of JGit has occurred. The original
 	 *             exception can be retrieved by calling
-	 *             {@link Exception#getCause()}.
+	 *             {@link java.lang.Exception#getCause()}.
 	 */
 	public NameRevCommand addAnnotatedTags() {
 		checkCallable();
 		if (refs == null)
 			refs = new ArrayList<>();
 		try {
-			for (Ref ref : repo.getRefDatabase().getRefs(Constants.R_TAGS).values()) {
+			for (Ref ref : repo.getRefDatabase()
+					.getRefsByPrefix(Constants.R_TAGS)) {
 				ObjectId id = ref.getObjectId();
 				if (id != null && (walk.parseAny(id) instanceof RevTag))
 					addRef(ref);
@@ -323,7 +325,7 @@ private void addPrefixes(Map<ObjectId, String> nonCommits,
 
 	private void addPrefix(String prefix, Map<ObjectId, String> nonCommits,
 			FIFORevQueue pending) throws IOException {
-		for (Ref ref : repo.getRefDatabase().getRefs(prefix).values())
+		for (Ref ref : repo.getRefDatabase().getRefsByPrefix(prefix))
 			addRef(ref, nonCommits, pending);
 	}
 
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/PullCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/PullCommand.java
index aa97996..f0ad29d 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/PullCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/PullCommand.java
@@ -52,7 +52,6 @@
 import org.eclipse.jgit.api.MergeCommand.FastForwardMode.Merge;
 import org.eclipse.jgit.api.RebaseCommand.Operation;
 import org.eclipse.jgit.api.errors.CanceledException;
-import org.eclipse.jgit.api.errors.DetachedHeadException;
 import org.eclipse.jgit.api.errors.GitAPIException;
 import org.eclipse.jgit.api.errors.InvalidConfigurationException;
 import org.eclipse.jgit.api.errors.InvalidRemoteException;
@@ -104,13 +103,18 @@ public class PullCommand extends TransportCommand<PullCommand, PullResult> {
 	private FetchRecurseSubmodulesMode submoduleRecurseMode = null;
 
 	/**
+	 * Constructor for PullCommand.
+	 *
 	 * @param repo
+	 *            the {@link org.eclipse.jgit.lib.Repository}
 	 */
 	protected PullCommand(Repository repo) {
 		super(repo);
 	}
 
 	/**
+	 * Set progress monitor
+	 *
 	 * @param monitor
 	 *            a progress monitor
 	 * @return this instance
@@ -139,6 +143,7 @@ public PullCommand setProgressMonitor(ProgressMonitor monitor) {
 	 * branch.[name].rebase and branch.autosetuprebase.
 	 *
 	 * @param useRebase
+	 *            whether to use rebase after fetching
 	 * @return {@code this}
 	 */
 	public PullCommand setRebase(boolean useRebase) {
@@ -149,7 +154,8 @@ public PullCommand setRebase(boolean useRebase) {
 	}
 
 	/**
-	 * Sets the {@link BranchRebaseMode} to use after fetching.
+	 * Sets the {@link org.eclipse.jgit.lib.BranchConfig.BranchRebaseMode} to
+	 * use after fetching.
 	 *
 	 * <dl>
 	 * <dt>BranchRebaseMode.REBASE</dt>
@@ -176,7 +182,8 @@ public PullCommand setRebase(boolean useRebase) {
 	 * {@code pull.rebase}.
 	 *
 	 * @param rebaseMode
-	 *            the {@link BranchRebaseMode} to use
+	 *            the {@link org.eclipse.jgit.lib.BranchConfig.BranchRebaseMode}
+	 *            to use
 	 * @return {@code this}
 	 * @since 4.5
 	 */
@@ -187,23 +194,13 @@ public PullCommand setRebase(BranchRebaseMode rebaseMode) {
 	}
 
 	/**
-	 * Executes the {@code Pull} command with all the options and parameters
+	 * {@inheritDoc}
+	 * <p>
+	 * Execute the {@code Pull} command with all the options and parameters
 	 * collected by the setter methods (e.g.
 	 * {@link #setProgressMonitor(ProgressMonitor)}) of this class. Each
 	 * instance of this class should only be used for one invocation of the
 	 * command. Don't call this method twice on an instance.
-	 *
-	 * @return the result of the pull
-	 * @throws WrongRepositoryStateException
-	 * @throws InvalidConfigurationException
-	 * @throws DetachedHeadException
-	 * @throws InvalidRemoteException
-	 * @throws CanceledException
-	 * @throws RefNotFoundException
-	 * @throws RefNotAdvertisedException
-	 * @throws NoHeadException
-	 * @throws org.eclipse.jgit.api.errors.TransportException
-	 * @throws GitAPIException
 	 */
 	@Override
 	public PullResult call() throws GitAPIException,
@@ -370,6 +367,7 @@ public PullResult call() throws GitAPIException,
 	 *
 	 * @see Constants#DEFAULT_REMOTE_NAME
 	 * @param remote
+	 *            name of the remote to pull from
 	 * @return {@code this}
 	 * @since 3.3
 	 */
@@ -386,6 +384,7 @@ public PullCommand setRemote(String remote) {
 	 * the current branch is used.
 	 *
 	 * @param remoteBranchName
+	 *            remote branch name to be used for pull operation
 	 * @return {@code this}
 	 * @since 3.3
 	 */
@@ -396,6 +395,8 @@ public PullCommand setRemoteBranchName(String remoteBranchName) {
 	}
 
 	/**
+	 * Get the remote name used for pull operation
+	 *
 	 * @return the remote used for the pull operation if it was set explicitly
 	 * @since 3.3
 	 */
@@ -404,6 +405,8 @@ public String getRemote() {
 	}
 
 	/**
+	 * Get the remote branch name for the pull operation
+	 *
 	 * @return the remote branch name used for the pull operation if it was set
 	 *         explicitly
 	 * @since 3.3
@@ -413,6 +416,8 @@ public String getRemoteBranchName() {
 	}
 
 	/**
+	 * Set the @{code MergeStrategy}
+	 *
 	 * @param strategy
 	 *            The merge strategy to use during this pull operation.
 	 * @return {@code this}
@@ -424,9 +429,10 @@ public PullCommand setStrategy(MergeStrategy strategy) {
 	}
 
 	/**
-	 * Sets the specification of annotated tag behavior during fetch
+	 * Set the specification of annotated tag behavior during fetch
 	 *
 	 * @param tagOpt
+	 *            the {@link org.eclipse.jgit.transport.TagOpt}
 	 * @return {@code this}
 	 * @since 4.7
 	 */
@@ -437,8 +443,8 @@ public PullCommand setTagOpt(TagOpt tagOpt) {
 	}
 
 	/**
-	 * Sets the fast forward mode. It is used if pull is configured to do a
-	 * merge as opposed to rebase. If non-{@code null} takes precedence over the
+	 * Set the fast forward mode. It is used if pull is configured to do a merge
+	 * as opposed to rebase. If non-{@code null} takes precedence over the
 	 * fast-forward mode configured in git config.
 	 *
 	 * @param fastForwardMode
@@ -461,6 +467,9 @@ public PullCommand setFastForward(
 	 * Set the mode to be used for recursing into submodules.
 	 *
 	 * @param recurse
+	 *            the
+	 *            {@link org.eclipse.jgit.lib.SubmoduleConfig.FetchRecurseSubmodulesMode}
+	 *            to be used for recursing into submodules
 	 * @return {@code this}
 	 * @since 4.7
 	 * @see FetchCommand#setRecurseSubmodules(FetchRecurseSubmodulesMode)
@@ -475,13 +484,14 @@ public PullCommand setRecurseSubmodules(
 	 * Reads the rebase mode to use for a pull command from the repository
 	 * configuration. This is the value defined for the configurations
 	 * {@code branch.[branchName].rebase}, or,if not set, {@code pull.rebase}.
-	 * If neither is set, yields {@link BranchRebaseMode#NONE}.
+	 * If neither is set, yields
+	 * {@link org.eclipse.jgit.lib.BranchConfig.BranchRebaseMode#NONE}.
 	 *
 	 * @param branchName
 	 *            name of the local branch
 	 * @param config
-	 *            the {@link Config} to read the value from
-	 * @return the {@link BranchRebaseMode}
+	 *            the {@link org.eclipse.jgit.lib.Config} to read the value from
+	 * @return the {@link org.eclipse.jgit.lib.BranchConfig.BranchRebaseMode}
 	 * @since 4.5
 	 */
 	public static BranchRebaseMode getRebaseMode(String branchName,
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/PullResult.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/PullResult.java
index c1eb89d..7210088 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/PullResult.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/PullResult.java
@@ -45,7 +45,7 @@
 import org.eclipse.jgit.transport.FetchResult;
 
 /**
- * Encapsulates the result of a {@link PullCommand}
+ * Encapsulates the result of a {@link org.eclipse.jgit.api.PullCommand}
  */
 public class PullResult {
 	private final FetchResult fetchResult;
@@ -73,6 +73,8 @@ public class PullResult {
 	}
 
 	/**
+	 * Get fetch result
+	 *
 	 * @return the fetch result, or <code>null</code>
 	 */
 	public FetchResult getFetchResult() {
@@ -80,6 +82,8 @@ public FetchResult getFetchResult() {
 	}
 
 	/**
+	 * Get merge result
+	 *
 	 * @return the merge result, or <code>null</code>
 	 */
 	public MergeResult getMergeResult() {
@@ -87,6 +91,8 @@ public MergeResult getMergeResult() {
 	}
 
 	/**
+	 * Get rebase result
+	 *
 	 * @return the rebase result, or <code>null</code>
 	 */
 	public RebaseResult getRebaseResult() {
@@ -94,6 +100,8 @@ public RebaseResult getRebaseResult() {
 	}
 
 	/**
+	 * Get name of the remote configuration from which fetch was tried
+	 *
 	 * @return the name of the remote configuration from which fetch was tried,
 	 *         or <code>null</code>
 	 */
@@ -102,6 +110,8 @@ public String getFetchedFrom() {
 	}
 
 	/**
+	 * Whether the pull was successful
+	 *
 	 * @return whether the pull was successful
 	 */
 	public boolean isSuccessful() {
@@ -112,6 +122,7 @@ else if (rebaseResult != null)
 		return true;
 	}
 
+	/** {@inheritDoc} */
 	@SuppressWarnings("nls")
 	@Override
 	public String toString() {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/PushCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/PushCommand.java
index bf88842..459451f 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/PushCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/PushCommand.java
@@ -105,7 +105,12 @@ public class PushCommand extends
 	private List<String> pushOptions;
 
 	/**
+	 * <p>
+	 * Constructor for PushCommand.
+	 * </p>
+	 *
 	 * @param repo
+	 *            the {@link org.eclipse.jgit.lib.Repository}
 	 */
 	protected PushCommand(Repository repo) {
 		super(repo);
@@ -114,17 +119,12 @@ protected PushCommand(Repository repo) {
 	}
 
 	/**
-	 * Executes the {@code push} command with all the options and parameters
+	 * {@inheritDoc}
+	 * <p>
+	 * Execute the {@code push} command with all the options and parameters
 	 * collected by the setter methods of this class. Each instance of this
 	 * class should only be used for one invocation of the command (means: one
 	 * call to {@link #call()})
-	 *
-	 * @return an iteration over {@link PushResult} objects
-	 * @throws InvalidRemoteException
-	 *             when called with an invalid remote uri
-	 * @throws org.eclipse.jgit.api.errors.TransportException
-	 *             when an error occurs with the transport
-	 * @throws GitAPIException
 	 */
 	@Override
 	public Iterable<PushResult> call() throws GitAPIException,
@@ -153,7 +153,8 @@ public Iterable<PushResult> call() throws GitAPIException,
 
 			final List<Transport> transports;
 			transports = Transport.openAll(repo, remote, Transport.Operation.PUSH);
-			for (final Transport transport : transports) {
+			for (@SuppressWarnings("resource") // Explicitly closed in finally
+					final Transport transport : transports) {
 				transport.setPushThin(thin);
 				transport.setPushAtomic(atomic);
 				if (receivePack != null)
@@ -209,6 +210,7 @@ public Iterable<PushResult> call() throws GitAPIException,
 	 *
 	 * @see Constants#DEFAULT_REMOTE_NAME
 	 * @param remote
+	 *            the remote name
 	 * @return {@code this}
 	 */
 	public PushCommand setRemote(String remote) {
@@ -218,6 +220,8 @@ public PushCommand setRemote(String remote) {
 	}
 
 	/**
+	 * Get remote name
+	 *
 	 * @return the remote used for the remote operation
 	 */
 	public String getRemote() {
@@ -231,6 +235,8 @@ public String getRemote() {
 	 *
 	 * @see RemoteConfig#DEFAULT_RECEIVE_PACK
 	 * @param receivePack
+	 *            name of the remote executable providing the receive-pack
+	 *            service
 	 * @return {@code this}
 	 */
 	public PushCommand setReceivePack(String receivePack) {
@@ -240,6 +246,8 @@ public PushCommand setReceivePack(String receivePack) {
 	}
 
 	/**
+	 * Get the name of the remote executable providing the receive-pack service
+	 *
 	 * @return the receive-pack used for the remote operation
 	 */
 	public String getReceivePack() {
@@ -247,6 +255,8 @@ public String getReceivePack() {
 	}
 
 	/**
+	 * Get timeout used for push operation
+	 *
 	 * @return the timeout used for the push operation
 	 */
 	public int getTimeout() {
@@ -254,6 +264,8 @@ public int getTimeout() {
 	}
 
 	/**
+	 * Get the progress monitor
+	 *
 	 * @return the progress monitor for the push operation
 	 */
 	public ProgressMonitor getProgressMonitor() {
@@ -265,8 +277,8 @@ public ProgressMonitor getProgressMonitor() {
 	 * is set to <code>NullProgressMonitor</code>
 	 *
 	 * @see NullProgressMonitor
-	 *
 	 * @param monitor
+	 *            a {@link org.eclipse.jgit.lib.ProgressMonitor}
 	 * @return {@code this}
 	 */
 	public PushCommand setProgressMonitor(ProgressMonitor monitor) {
@@ -279,7 +291,9 @@ public PushCommand setProgressMonitor(ProgressMonitor monitor) {
 	}
 
 	/**
-	 * @return the ref lease specs
+	 * Get the <code>RefLeaseSpec</code>s.
+	 *
+	 * @return the <code>RefLeaseSpec</code>s
 	 * @since 4.7
 	 */
 	public List<RefLeaseSpec> getRefLeaseSpecs() {
@@ -287,10 +301,11 @@ public List<RefLeaseSpec> getRefLeaseSpecs() {
 	}
 
 	/**
-	 * The ref lease specs to be used in the push operation,
-	 * for a force-with-lease push operation.
+	 * The ref lease specs to be used in the push operation, for a
+	 * force-with-lease push operation.
 	 *
 	 * @param specs
+	 *            a {@link org.eclipse.jgit.transport.RefLeaseSpec} object.
 	 * @return {@code this}
 	 * @since 4.7
 	 */
@@ -299,10 +314,11 @@ public PushCommand setRefLeaseSpecs(RefLeaseSpec... specs) {
 	}
 
 	/**
-	 * The ref lease specs to be used in the push operation,
-	 * for a force-with-lease push operation.
+	 * The ref lease specs to be used in the push operation, for a
+	 * force-with-lease push operation.
 	 *
 	 * @param specs
+	 *            list of {@code RefLeaseSpec}s
 	 * @return {@code this}
 	 * @since 4.7
 	 */
@@ -316,6 +332,8 @@ public PushCommand setRefLeaseSpecs(List<RefLeaseSpec> specs) {
 	}
 
 	/**
+	 * Get {@code RefSpec}s.
+	 *
 	 * @return the ref specs
 	 */
 	public List<RefSpec> getRefSpecs() {
@@ -325,7 +343,7 @@ public List<RefSpec> getRefSpecs() {
 	/**
 	 * The ref specs to be used in the push operation
 	 *
-	 * @param specs
+	 * @param specs a {@link org.eclipse.jgit.transport.RefSpec} object.
 	 * @return {@code this}
 	 */
 	public PushCommand setRefSpecs(RefSpec... specs) {
@@ -339,6 +357,7 @@ public PushCommand setRefSpecs(RefSpec... specs) {
 	 * The ref specs to be used in the push operation
 	 *
 	 * @param specs
+	 *            list of {@link org.eclipse.jgit.transport.RefSpec}s
 	 * @return {@code this}
 	 */
 	public PushCommand setRefSpecs(List<RefSpec> specs) {
@@ -408,6 +427,8 @@ public PushCommand add(String nameOrSpec) {
 	}
 
 	/**
+	 * Whether to run the push operation as a dry run
+	 *
 	 * @return the dry run preference for the push operation
 	 */
 	public boolean isDryRun() {
@@ -417,7 +438,7 @@ public boolean isDryRun() {
 	/**
 	 * Sets whether the push operation should be a dry run
 	 *
-	 * @param dryRun
+	 * @param dryRun a boolean.
 	 * @return {@code this}
 	 */
 	public PushCommand setDryRun(boolean dryRun) {
@@ -427,6 +448,8 @@ public PushCommand setDryRun(boolean dryRun) {
 	}
 
 	/**
+	 * Get the thin-pack preference
+	 *
 	 * @return the thin-pack preference for push operation
 	 */
 	public boolean isThin() {
@@ -434,11 +457,12 @@ public boolean isThin() {
 	}
 
 	/**
-	 * Sets the thin-pack preference for push operation.
+	 * Set the thin-pack preference for push operation.
 	 *
 	 * Default setting is Transport.DEFAULT_PUSH_THIN
 	 *
 	 * @param thin
+	 *            the thin-pack preference value
 	 * @return {@code this}
 	 */
 	public PushCommand setThin(boolean thin) {
@@ -448,6 +472,9 @@ public PushCommand setThin(boolean thin) {
 	}
 
 	/**
+	 * Whether this push should be executed atomically (all references updated,
+	 * or none)
+	 *
 	 * @return true if all-or-nothing behavior is requested.
 	 * @since 4.2
 	 */
@@ -461,6 +488,7 @@ public boolean isAtomic() {
 	 * Default setting is false.
 	 *
 	 * @param atomic
+	 *            whether to run the push atomically
 	 * @return {@code this}
 	 * @since 4.2
 	 */
@@ -471,6 +499,8 @@ public PushCommand setAtomic(boolean atomic) {
 	}
 
 	/**
+	 * Whether to push forcefully
+	 *
 	 * @return the force preference for push operation
 	 */
 	public boolean isForce() {
@@ -481,6 +511,7 @@ public boolean isForce() {
 	 * Sets the force preference for push operation.
 	 *
 	 * @param force
+	 *            whether to push forcefully
 	 * @return {@code this}
 	 */
 	public PushCommand setForce(boolean force) {
@@ -493,6 +524,7 @@ public PushCommand setForce(boolean force) {
 	 * Sets the output stream to write sideband messages to
 	 *
 	 * @param out
+	 *            an {@link java.io.OutputStream}
 	 * @return {@code this}
 	 * @since 3.0
 	 */
@@ -502,6 +534,8 @@ public PushCommand setOutputStream(OutputStream out) {
 	}
 
 	/**
+	 * Get push options
+	 *
 	 * @return the option strings associated with the push operation
 	 * @since 4.5
 	 */
@@ -510,9 +544,10 @@ public List<String> getPushOptions() {
 	}
 
 	/**
-	 * Sets the option strings associated with the push operation.
+	 * Set the option strings associated with the push operation.
 	 *
 	 * @param pushOptions
+	 *            a {@link java.util.List} of push option strings
 	 * @return {@code this}
 	 * @since 4.5
 	 */
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/RebaseCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/RebaseCommand.java
index 955c50b..98c16b8 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/RebaseCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/RebaseCommand.java
@@ -238,7 +238,12 @@ public enum Operation {
 	private boolean preserveMerges = false;
 
 	/**
+	 * <p>
+	 * Constructor for RebaseCommand.
+	 * </p>
+	 *
 	 * @param repo
+	 *            the {@link org.eclipse.jgit.lib.Repository}
 	 */
 	protected RebaseCommand(Repository repo) {
 		super(repo);
@@ -247,16 +252,12 @@ protected RebaseCommand(Repository repo) {
 	}
 
 	/**
+	 * {@inheritDoc}
+	 * <p>
 	 * Executes the {@code Rebase} command with all the options and parameters
 	 * collected by the setter methods of this class. Each instance of this
 	 * class should only be used for one invocation of the command. Don't call
 	 * this method twice on an instance.
-	 *
-	 * @return an object describing the result of this command
-	 * @throws GitAPIException
-	 * @throws WrongRepositoryStateException
-	 * @throws NoHeadException
-	 * @throws RefNotFoundException
 	 */
 	@Override
 	public RebaseResult call() throws GitAPIException, NoHeadException,
@@ -931,6 +932,7 @@ private RevCommit checkoutCurrentHead() throws IOException, NoHeadException {
 		try {
 			DirCacheCheckout dco = new DirCacheCheckout(repo, dc, headTree);
 			dco.setFailOnConflict(false);
+			dco.setProgressMonitor(monitor);
 			boolean needsDeleteFiles = dco.checkout();
 			if (needsDeleteFiles) {
 				List<String> fileList = dco.getToBeDeleted();
@@ -1228,12 +1230,14 @@ private boolean isInteractive() {
 	}
 
 	/**
-	 * checks if we can fast-forward and returns the new head if it is possible
+	 * Check if we can fast-forward and returns the new head if it is possible
 	 *
 	 * @param newCommit
+	 *            a {@link org.eclipse.jgit.revwalk.RevCommit} object to check
+	 *            if we can fast-forward to.
 	 * @return the new head, or null
-	 * @throws IOException
-	 * @throws GitAPIException
+	 * @throws java.io.IOException
+	 * @throws org.eclipse.jgit.api.errors.GitAPIException
 	 */
 	public RevCommit tryFastForward(RevCommit newCommit) throws IOException,
 			GitAPIException {
@@ -1262,6 +1266,7 @@ private RevCommit tryFastForward(String headName, RevCommit oldCommit,
 
 		CheckoutCommand co = new CheckoutCommand(repo);
 		try {
+			co.setProgressMonitor(monitor);
 			co.setName(newCommit.name()).call();
 			if (headName.startsWith(Constants.R_HEADS)) {
 				RefUpdate rup = repo.updateRef(headName);
@@ -1404,6 +1409,7 @@ private boolean checkoutCommit(String headName, RevCommit commit)
 			DirCacheCheckout dco = new DirCacheCheckout(repo, head.getTree(),
 					repo.lockDirCache(), commit.getTree());
 			dco.setFailOnConflict(true);
+			dco.setProgressMonitor(monitor);
 			try {
 				dco.checkout();
 			} catch (org.eclipse.jgit.errors.CheckoutConflictException cce) {
@@ -1436,6 +1442,8 @@ private boolean checkoutCommit(String headName, RevCommit commit)
 
 
 	/**
+	 * Set upstream {@code RevCommit}
+	 *
 	 * @param upstream
 	 *            the upstream commit
 	 * @return {@code this}
@@ -1447,6 +1455,8 @@ public RebaseCommand setUpstream(RevCommit upstream) {
 	}
 
 	/**
+	 * Set the upstream commit
+	 *
 	 * @param upstream
 	 *            id of the upstream commit
 	 * @return {@code this}
@@ -1464,10 +1474,12 @@ public RebaseCommand setUpstream(AnyObjectId upstream) {
 	}
 
 	/**
+	 * Set the upstream branch
+	 *
 	 * @param upstream
-	 *            the upstream branch
+	 *            the name of the upstream branch
 	 * @return {@code this}
-	 * @throws RefNotFoundException
+	 * @throws org.eclipse.jgit.api.errors.RefNotFoundException
 	 */
 	public RebaseCommand setUpstream(String upstream)
 			throws RefNotFoundException {
@@ -1502,6 +1514,8 @@ public RebaseCommand setUpstreamName(String upstreamName) {
 	}
 
 	/**
+	 * Set the operation to execute during rebase
+	 *
 	 * @param operation
 	 *            the operation to perform
 	 * @return {@code this}
@@ -1512,6 +1526,8 @@ public RebaseCommand setOperation(Operation operation) {
 	}
 
 	/**
+	 * Set progress monitor
+	 *
 	 * @param monitor
 	 *            a progress monitor
 	 * @return this instance
@@ -1525,15 +1541,18 @@ public RebaseCommand setProgressMonitor(ProgressMonitor monitor) {
 	}
 
 	/**
-	 * Enables interactive rebase
+	 * Enable interactive rebase
 	 * <p>
 	 * Does not stop after initialization of interactive rebase. This is
 	 * equivalent to
-	 * {@link RebaseCommand#runInteractively(InteractiveHandler, boolean)
+	 * {@link org.eclipse.jgit.api.RebaseCommand#runInteractively(InteractiveHandler, boolean)
 	 * runInteractively(handler, false)};
 	 * </p>
 	 *
 	 * @param handler
+	 *            the
+	 *            {@link org.eclipse.jgit.api.RebaseCommand.InteractiveHandler}
+	 *            to use
 	 * @return this
 	 */
 	public RebaseCommand runInteractively(InteractiveHandler handler) {
@@ -1541,14 +1560,17 @@ public RebaseCommand runInteractively(InteractiveHandler handler) {
 	}
 
 	/**
-	 * Enables interactive rebase
+	 * Enable interactive rebase
 	 * <p>
 	 * If stopAfterRebaseInteractiveInitialization is {@code true} the rebase
 	 * stops after initialization of interactive rebase returning
-	 * {@link RebaseResult#INTERACTIVE_PREPARED_RESULT}
+	 * {@link org.eclipse.jgit.api.RebaseResult#INTERACTIVE_PREPARED_RESULT}
 	 * </p>
 	 *
 	 * @param handler
+	 *            the
+	 *            {@link org.eclipse.jgit.api.RebaseCommand.InteractiveHandler}
+	 *            to use
 	 * @param stopAfterRebaseInteractiveInitialization
 	 *            if {@code true} the rebase stops after initialization
 	 * @return this instance
@@ -1562,6 +1584,8 @@ public RebaseCommand runInteractively(InteractiveHandler handler,
 	}
 
 	/**
+	 * Set the <code>MergeStrategy</code>.
+	 *
 	 * @param strategy
 	 *            The merge strategy to use during this rebase operation.
 	 * @return {@code this}
@@ -1573,9 +1597,11 @@ public RebaseCommand setStrategy(MergeStrategy strategy) {
 	}
 
 	/**
+	 * Whether to preserve merges during rebase
+	 *
 	 * @param preserve
-	 *            True to re-create merges during rebase. Defaults to false, a
-	 *            flattening rebase.
+	 *            {@code true} to re-create merges during rebase. Defaults to
+	 *            {@code false}, a flattening rebase.
 	 * @return {@code this}
 	 * @since 3.5
 	 */
@@ -1708,23 +1734,17 @@ private static void createFile(File parentDir, String name,
 				String content)
 				throws IOException {
 			File file = new File(parentDir, name);
-			FileOutputStream fos = new FileOutputStream(file);
-			try {
+			try (FileOutputStream fos = new FileOutputStream(file)) {
 				fos.write(content.getBytes(Constants.CHARACTER_ENCODING));
 				fos.write('\n');
-			} finally {
-				fos.close();
 			}
 		}
 
 		private static void appendToFile(File file, String content)
 				throws IOException {
-			FileOutputStream fos = new FileOutputStream(file, true);
-			try {
+			try (FileOutputStream fos = new FileOutputStream(file, true)) {
 				fos.write(content.getBytes(Constants.CHARACTER_ENCODING));
 				fos.write('\n');
-			} finally {
-				fos.close();
 			}
 		}
 	}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/RebaseResult.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/RebaseResult.java
index 92c1347..bad6a7c 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/RebaseResult.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/RebaseResult.java
@@ -45,12 +45,11 @@
 import java.util.List;
 import java.util.Map;
 
-import org.eclipse.jgit.merge.ResolveMerger;
 import org.eclipse.jgit.merge.ResolveMerger.MergeFailureReason;
 import org.eclipse.jgit.revwalk.RevCommit;
 
 /**
- * The result of a {@link RebaseCommand} execution
+ * The result of a {@link org.eclipse.jgit.api.RebaseCommand} execution
  */
 public class RebaseResult {
 	/**
@@ -279,6 +278,8 @@ static RebaseResult uncommittedChanges(List<String> uncommittedChanges) {
 	}
 
 	/**
+	 * Get the status
+	 *
 	 * @return the overall status
 	 */
 	public Status getStatus() {
@@ -286,33 +287,46 @@ public Status getStatus() {
 	}
 
 	/**
-	 * @return the current commit if status is {@link Status#STOPPED}, otherwise
-	 *         <code>null</code>
+	 * Get the current commit if status is
+	 * {@link org.eclipse.jgit.api.RebaseResult.Status#STOPPED}, otherwise
+	 * <code>null</code>
+	 *
+	 * @return the current commit if status is
+	 *         {@link org.eclipse.jgit.api.RebaseResult.Status#STOPPED},
+	 *         otherwise <code>null</code>
 	 */
 	public RevCommit getCurrentCommit() {
 		return currentCommit;
 	}
 
 	/**
+	 * Get the list of paths causing this rebase to fail
+	 *
 	 * @return the list of paths causing this rebase to fail (see
-	 *         {@link ResolveMerger#getFailingPaths()} for details) if status is
-	 *         {@link Status#FAILED}, otherwise <code>null</code>
+	 *         {@link org.eclipse.jgit.merge.ResolveMerger#getFailingPaths()}
+	 *         for details) if status is
+	 *         {@link org.eclipse.jgit.api.RebaseResult.Status#FAILED},
+	 *         otherwise <code>null</code>
 	 */
 	public Map<String, MergeFailureReason> getFailingPaths() {
 		return failingPaths;
 	}
 
 	/**
-	 * @return the list of conflicts if status is {@link Status#CONFLICTS}
+	 * Get the list of conflicts
+	 *
+	 * @return the list of conflicts if status is
+	 *         {@link org.eclipse.jgit.api.RebaseResult.Status#CONFLICTS}
 	 */
 	public List<String> getConflicts() {
 		return conflicts;
 	}
 
 	/**
-	 * @return the list of uncommitted changes if status is
-	 *         {@link Status#UNCOMMITTED_CHANGES}
+	 * <p>Getter for the field <code>uncommittedChanges</code>.</p>
 	 *
+	 * @return the list of uncommitted changes if status is
+	 *         {@link org.eclipse.jgit.api.RebaseResult.Status#UNCOMMITTED_CHANGES}
 	 * @since 3.2
 	 */
 	public List<String> getUncommittedChanges() {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/ReflogCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/ReflogCommand.java
index 394bea5..bf3163a 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/ReflogCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/ReflogCommand.java
@@ -67,7 +67,10 @@ public class ReflogCommand extends GitCommand<Collection<ReflogEntry>> {
 	private String ref = Constants.HEAD;
 
 	/**
+	 * Constructor for ReflogCommand.
+	 *
 	 * @param repo
+	 *            the {@link org.eclipse.jgit.lib.Repository}
 	 */
 	public ReflogCommand(Repository repo) {
 		super(repo);
@@ -78,6 +81,7 @@ public ReflogCommand(Repository repo) {
 	 * value of HEAD will be used.
 	 *
 	 * @param ref
+	 *            the name of the {@code Ref} to log
 	 * @return {@code this}
 	 */
 	public ReflogCommand setRef(String ref) {
@@ -87,10 +91,9 @@ public ReflogCommand setRef(String ref) {
 	}
 
 	/**
+	 * {@inheritDoc}
+	 * <p>
 	 * Run the reflog command
-	 *
-	 * @throws GitAPIException
-	 * @throws InvalidRefNameException
 	 */
 	@Override
 	public Collection<ReflogEntry> call() throws GitAPIException,
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/RemoteAddCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/RemoteAddCommand.java
index 6795669..a8fdcd2 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/RemoteAddCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/RemoteAddCommand.java
@@ -63,7 +63,6 @@
  * @see <a href=
  *      "http://www.kernel.org/pub/software/scm/git/docs/git-remote.html" > Git
  *      documentation about Remote</a>
- *
  * @since 4.2
  */
 public class RemoteAddCommand extends GitCommand<RemoteConfig> {
@@ -73,7 +72,10 @@ public class RemoteAddCommand extends GitCommand<RemoteConfig> {
 	private URIish uri;
 
 	/**
+	 * Constructor for RemoteAddCommand.
+	 *
 	 * @param repo
+	 *            the {@link org.eclipse.jgit.lib.Repository}
 	 */
 	protected RemoteAddCommand(Repository repo) {
 		super(repo);
@@ -84,9 +86,12 @@ protected RemoteAddCommand(Repository repo) {
 	 *
 	 * @param name
 	 *            a remote name
+	 * @return this instance
+	 * @since 5.0
 	 */
-	public void setName(String name) {
+	public RemoteAddCommand setName(String name) {
 		this.name = name;
+		return this;
 	}
 
 	/**
@@ -94,16 +99,19 @@ public void setName(String name) {
 	 *
 	 * @param uri
 	 *            an URL for the remote
+	 * @return this instance
+	 * @since 5.0
 	 */
-	public void setUri(URIish uri) {
+	public RemoteAddCommand setUri(URIish uri) {
 		this.uri = uri;
+		return this;
 	}
 
 	/**
+	 * {@inheritDoc}
+	 * <p>
 	 * Executes the {@code remote add} command with all the options and
 	 * parameters collected by the setter methods of this class.
-	 *
-	 * @return the {@link RemoteConfig} object of the added remote
 	 */
 	@Override
 	public RemoteConfig call() throws GitAPIException {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/RemoteListCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/RemoteListCommand.java
index f778eaa..f96651f 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/RemoteListCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/RemoteListCommand.java
@@ -59,23 +59,27 @@
  * @see <a href=
  *      "http://www.kernel.org/pub/software/scm/git/docs/git-remote.html" > Git
  *      documentation about Remote</a>
- *
  * @since 4.2
  */
 public class RemoteListCommand extends GitCommand<List<RemoteConfig>> {
 
 	/**
+	 * <p>
+	 * Constructor for RemoteListCommand.
+	 * </p>
+	 *
 	 * @param repo
+	 *            the {@link org.eclipse.jgit.lib.Repository}
 	 */
 	protected RemoteListCommand(Repository repo) {
 		super(repo);
 	}
 
 	/**
+	 * {@inheritDoc}
+	 * <p>
 	 * Executes the {@code remote} command with all the options and parameters
 	 * collected by the setter methods of this class.
-	 *
-	 * @return a list of {@link RemoteConfig} objects.
 	 */
 	@Override
 	public List<RemoteConfig> call() throws GitAPIException {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/RemoteRemoveCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/RemoteRemoveCommand.java
index 5782bf6..7a5885c 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/RemoteRemoveCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/RemoteRemoveCommand.java
@@ -61,7 +61,6 @@
  * @see <a href=
  *      "http://www.kernel.org/pub/software/scm/git/docs/git-remote.html" > Git
  *      documentation about Remote</a>
- *
  * @since 4.2
  */
 public class RemoteRemoveCommand extends GitCommand<RemoteConfig> {
@@ -69,7 +68,12 @@ public class RemoteRemoveCommand extends GitCommand<RemoteConfig> {
 	private String name;
 
 	/**
+	 * <p>
+	 * Constructor for RemoteRemoveCommand.
+	 * </p>
+	 *
 	 * @param repo
+	 *            the {@link org.eclipse.jgit.lib.Repository}
 	 */
 	protected RemoteRemoveCommand(Repository repo) {
 		super(repo);
@@ -86,10 +90,10 @@ public void setName(String name) {
 	}
 
 	/**
+	 * {@inheritDoc}
+	 * <p>
 	 * Executes the {@code remote} command with all the options and parameters
 	 * collected by the setter methods of this class.
-	 *
-	 * @return the {@link RemoteConfig} object of the removed remote
 	 */
 	@Override
 	public RemoteConfig call() throws GitAPIException {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/RemoteSetUrlCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/RemoteSetUrlCommand.java
index 6bd2ac7..d7b7a31 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/RemoteSetUrlCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/RemoteSetUrlCommand.java
@@ -62,7 +62,6 @@
  * @see <a href=
  *      "http://www.kernel.org/pub/software/scm/git/docs/git-remote.html" > Git
  *      documentation about Remote</a>
- *
  * @since 4.2
  */
 public class RemoteSetUrlCommand extends GitCommand<RemoteConfig> {
@@ -74,7 +73,12 @@ public class RemoteSetUrlCommand extends GitCommand<RemoteConfig> {
 	private boolean push;
 
 	/**
+	 * <p>
+	 * Constructor for RemoteSetUrlCommand.
+	 * </p>
+	 *
 	 * @param repo
+	 *            the {@link org.eclipse.jgit.lib.Repository}
 	 */
 	protected RemoteSetUrlCommand(Repository repo) {
 		super(repo);
@@ -112,10 +116,10 @@ public void setPush(boolean push) {
 	}
 
 	/**
+	 * {@inheritDoc}
+	 * <p>
 	 * Executes the {@code remote} command with all the options and parameters
 	 * collected by the setter methods of this class.
-	 *
-	 * @return the {@link RemoteConfig} object of the modified remote
 	 */
 	@Override
 	public RemoteConfig call() throws GitAPIException {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/RemoveNoteCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/RemoveNoteCommand.java
index fd8aac7..cfbf0dd 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/RemoveNoteCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/RemoveNoteCommand.java
@@ -46,13 +46,9 @@
 
 import org.eclipse.jgit.api.errors.GitAPIException;
 import org.eclipse.jgit.api.errors.JGitInternalException;
-import org.eclipse.jgit.lib.CommitBuilder;
 import org.eclipse.jgit.lib.Constants;
-import org.eclipse.jgit.lib.ObjectId;
 import org.eclipse.jgit.lib.ObjectInserter;
-import org.eclipse.jgit.lib.PersonIdent;
 import org.eclipse.jgit.lib.Ref;
-import org.eclipse.jgit.lib.RefUpdate;
 import org.eclipse.jgit.lib.Repository;
 import org.eclipse.jgit.notes.Note;
 import org.eclipse.jgit.notes.NoteMap;
@@ -73,12 +69,18 @@ public class RemoveNoteCommand extends GitCommand<Note> {
 	private String notesRef = Constants.R_NOTES_COMMITS;
 
 	/**
+	 * <p>
+	 * Constructor for RemoveNoteCommand.
+	 * </p>
+	 *
 	 * @param repo
+	 *            the {@link org.eclipse.jgit.lib.Repository}
 	 */
 	protected RemoveNoteCommand(Repository repo) {
 		super(repo);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public Note call() throws GitAPIException {
 		checkCallable();
@@ -93,7 +95,8 @@ public Note call() throws GitAPIException {
 				map = NoteMap.read(walk.getObjectReader(), notesCommit);
 			}
 			map.set(id, null, inserter);
-			commitNoteMap(walk, map, notesCommit, inserter,
+			AddNoteCommand.commitNoteMap(repo, notesRef, walk, map, notesCommit,
+					inserter,
 					"Notes removed by 'git notes remove'"); //$NON-NLS-1$
 			return map.getNote(id);
 		} catch (IOException e) {
@@ -105,6 +108,8 @@ public Note call() throws GitAPIException {
 	 * Sets the object id of object you want to remove a note
 	 *
 	 * @param id
+	 *            the {@link org.eclipse.jgit.revwalk.RevObject} to remove a
+	 *            note from.
 	 * @return {@code this}
 	 */
 	public RemoveNoteCommand setObjectId(RevObject id) {
@@ -113,37 +118,14 @@ public RemoveNoteCommand setObjectId(RevObject id) {
 		return this;
 	}
 
-	private void commitNoteMap(RevWalk walk, NoteMap map,
-			RevCommit notesCommit,
-			ObjectInserter inserter,
-			String msg)
-			throws IOException {
-		// commit the note
-		CommitBuilder builder = new CommitBuilder();
-		builder.setTreeId(map.writeTree(inserter));
-		builder.setAuthor(new PersonIdent(repo));
-		builder.setCommitter(builder.getAuthor());
-		builder.setMessage(msg);
-		if (notesCommit != null)
-			builder.setParentIds(notesCommit);
-		ObjectId commit = inserter.insert(builder);
-		inserter.flush();
-		RefUpdate refUpdate = repo.updateRef(notesRef);
-		if (notesCommit != null)
-			refUpdate.setExpectedOldObjectId(notesCommit);
-		else
-			refUpdate.setExpectedOldObjectId(ObjectId.zeroId());
-		refUpdate.setNewObjectId(commit);
-		refUpdate.update(walk);
-	}
-
 	/**
-	 * @param notesRef
-	 *            the ref to read notes from. Note, the default value of
-	 *            {@link Constants#R_NOTES_COMMITS} will be used if nothing is
-	 *            set
-	 * @return {@code this}
+	 * Set the name of the <code>Ref</code> to remove a note from.
 	 *
+	 * @param notesRef
+	 *            the {@code Ref} to read notes from. Note, the default value of
+	 *            {@link org.eclipse.jgit.lib.Constants#R_NOTES_COMMITS} will be
+	 *            used if nothing is set
+	 * @return {@code this}
 	 * @see Constants#R_NOTES_COMMITS
 	 */
 	public RemoveNoteCommand setNotesRef(String notesRef) {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/RenameBranchCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/RenameBranchCommand.java
index ce3a29f..24d9dd4 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/RenameBranchCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/RenameBranchCommand.java
@@ -77,25 +77,18 @@ public class RenameBranchCommand extends GitCommand<Ref> {
 	private String newName;
 
 	/**
+	 * <p>
+	 * Constructor for RenameBranchCommand.
+	 * </p>
+	 *
 	 * @param repo
+	 *            the {@link org.eclipse.jgit.lib.Repository}
 	 */
 	protected RenameBranchCommand(Repository repo) {
 		super(repo);
 	}
 
-	/**
-	 * @throws RefNotFoundException
-	 *             if the old branch can not be found (branch with provided old
-	 *             name does not exist or old name resolves to a tag)
-	 * @throws InvalidRefNameException
-	 *             if the provided new name is <code>null</code> or otherwise
-	 *             invalid
-	 * @throws RefAlreadyExistsException
-	 *             if a branch with the new name already exists
-	 * @throws DetachedHeadException
-	 *             if rename is tried without specifying the old name and HEAD
-	 *             is detached
-	 */
+	/** {@inheritDoc} */
 	@Override
 	public Ref call() throws GitAPIException, RefNotFoundException, InvalidRefNameException,
 			RefAlreadyExistsException, DetachedHeadException {
@@ -198,6 +191,8 @@ public Ref call() throws GitAPIException, RefNotFoundException, InvalidRefNameEx
 	}
 
 	/**
+	 * Set the new name of the branch
+	 *
 	 * @param newName
 	 *            the new name
 	 * @return this instance
@@ -209,6 +204,8 @@ public RenameBranchCommand setNewName(String newName) {
 	}
 
 	/**
+	 * Set the old name of the branch
+	 *
 	 * @param oldName
 	 *            the name of the branch to rename; if not set, the currently
 	 *            checked out branch (if any) will be renamed
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/ResetCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/ResetCommand.java
index c5222c2..13ce4e7 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/ResetCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/ResetCommand.java
@@ -58,7 +58,9 @@
 import org.eclipse.jgit.dircache.DirCacheIterator;
 import org.eclipse.jgit.internal.JGitText;
 import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.NullProgressMonitor;
 import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.ProgressMonitor;
 import org.eclipse.jgit.lib.Ref;
 import org.eclipse.jgit.lib.RefUpdate;
 import org.eclipse.jgit.lib.Repository;
@@ -125,21 +127,26 @@ public enum ResetType {
 
 	private boolean isReflogDisabled;
 
+	private ProgressMonitor monitor = NullProgressMonitor.INSTANCE;
+
 	/**
+	 * <p>
+	 * Constructor for ResetCommand.
+	 * </p>
 	 *
 	 * @param repo
+	 *            the {@link org.eclipse.jgit.lib.Repository}
 	 */
 	public ResetCommand(Repository repo) {
 		super(repo);
 	}
 
 	/**
+	 * {@inheritDoc}
+	 * <p>
 	 * Executes the {@code Reset} command. Each instance of this class should
 	 * only be used for one invocation of the command. Don't call this method
 	 * twice on an instance.
-	 *
-	 * @return the Ref after reset
-	 * @throws GitAPIException
 	 */
 	@Override
 	public Ref call() throws GitAPIException, CheckoutConflictException {
@@ -238,7 +245,7 @@ else if (repo.readSquashCommitMsg() != null)
 		}
 	}
 
-	private RevCommit parseCommit(final ObjectId commitId) {
+	private RevCommit parseCommit(ObjectId commitId) {
 		try (RevWalk rw = new RevWalk(repo)) {
 			return rw.parseCommit(commitId);
 		} catch (IOException e) {
@@ -258,6 +265,8 @@ private ObjectId resolveRefToCommitId() {
 	}
 
 	/**
+	 * Set the name of the <code>Ref</code> to reset to
+	 *
 	 * @param ref
 	 *            the ref to reset to, defaults to HEAD if not specified
 	 * @return this instance
@@ -268,6 +277,8 @@ public ResetCommand setRef(String ref) {
 	}
 
 	/**
+	 * Set the reset mode
+	 *
 	 * @param mode
 	 *            the mode of the reset command
 	 * @return this instance
@@ -282,6 +293,8 @@ public ResetCommand setMode(ResetType mode) {
 	}
 
 	/**
+	 * Repository relative path of file or directory to reset
+	 *
 	 * @param path
 	 *            repository-relative path of file/directory to reset (with
 	 *            <code>/</code> as separator)
@@ -297,6 +310,8 @@ public ResetCommand addPath(String path) {
 	}
 
 	/**
+	 * Whether to disable reflog
+	 *
 	 * @param disable
 	 *            if {@code true} disables writing a reflog entry for this reset
 	 *            command
@@ -309,6 +324,8 @@ public ResetCommand disableRefLog(boolean disable) {
 	}
 
 	/**
+	 * Whether reflog is disabled
+	 *
 	 * @return {@code true} if writing reflog is disabled for this reset command
 	 * @since 4.5
 	 */
@@ -323,9 +340,27 @@ private String getRefOrHEAD() {
 			return Constants.HEAD;
 	}
 
+	/**
+	 * The progress monitor associated with the reset operation. By default,
+	 * this is set to <code>NullProgressMonitor</code>
+	 *
+	 * @see NullProgressMonitor
+	 * @param monitor
+	 *            a {@link org.eclipse.jgit.lib.ProgressMonitor}
+	 * @return {@code this}
+	 * @since 4.11
+	 */
+	public ResetCommand setProgressMonitor(ProgressMonitor monitor) {
+		if (monitor == null) {
+			monitor = NullProgressMonitor.INSTANCE;
+		}
+		this.monitor = monitor;
+		return this;
+	}
+
 	private void resetIndexForPaths(ObjectId commitTree) {
 		DirCache dc = null;
-		try (final TreeWalk tw = new TreeWalk(repo)) {
+		try (TreeWalk tw = new TreeWalk(repo)) {
 			dc = repo.lockDirCache();
 			DirCacheBuilder builder = dc.builder();
 
@@ -407,6 +442,7 @@ private void checkoutIndex(ObjectId commitTree) throws IOException,
 			DirCacheCheckout checkout = new DirCacheCheckout(repo, dc,
 					commitTree);
 			checkout.setFailOnConflict(false);
+			checkout.setProgressMonitor(monitor);
 			try {
 				checkout.checkout();
 			} catch (org.eclipse.jgit.errors.CheckoutConflictException cce) {
@@ -433,6 +469,7 @@ private void resetRevert() throws IOException {
 		repo.writeMergeCommitMsg(null);
 	}
 
+	/** {@inheritDoc} */
 	@SuppressWarnings("nls")
 	@Override
 	public String toString() {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/RevertCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/RevertCommand.java
index c3152a9..46e0df7 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/RevertCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/RevertCommand.java
@@ -61,8 +61,10 @@
 import org.eclipse.jgit.internal.JGitText;
 import org.eclipse.jgit.lib.AnyObjectId;
 import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.NullProgressMonitor;
 import org.eclipse.jgit.lib.ObjectId;
 import org.eclipse.jgit.lib.ObjectIdRef;
+import org.eclipse.jgit.lib.ProgressMonitor;
 import org.eclipse.jgit.lib.Ref;
 import org.eclipse.jgit.lib.Ref.Storage;
 import org.eclipse.jgit.lib.Repository;
@@ -97,28 +99,27 @@ public class RevertCommand extends GitCommand<RevCommit> {
 
 	private MergeStrategy strategy = MergeStrategy.RECURSIVE;
 
+	private ProgressMonitor monitor = NullProgressMonitor.INSTANCE;
+
 	/**
+	 * <p>
+	 * Constructor for RevertCommand.
+	 * </p>
+	 *
 	 * @param repo
+	 *            the {@link org.eclipse.jgit.lib.Repository}
 	 */
 	protected RevertCommand(Repository repo) {
 		super(repo);
 	}
 
 	/**
+	 * {@inheritDoc}
+	 * <p>
 	 * Executes the {@code revert} command with all the options and parameters
 	 * collected by the setter methods (e.g. {@link #include(Ref)} of this
 	 * class. Each instance of this class should only be used for one invocation
 	 * of the command. Don't call this method twice on an instance.
-	 *
-	 * @return on success the {@link RevCommit} pointed to by the new HEAD is
-	 *         returned. If a failure occurred during revert <code>null</code>
-	 *         is returned. The list of successfully reverted {@link Ref}'s can
-	 *         be obtained by calling {@link #getRevertedRefs()}
-	 * @throws GitAPIException
-	 * @throws WrongRepositoryStateException
-	 * @throws ConcurrentRefUpdateException
-	 * @throws UnmergedPathsException
-	 * @throws NoMessageException
 	 */
 	@Override
 	public RevCommit call() throws NoMessageException, UnmergedPathsException,
@@ -181,6 +182,7 @@ public RevCommit call() throws NoMessageException, UnmergedPathsException,
 							headCommit.getTree(), repo.lockDirCache(),
 							merger.getResultTreeId());
 					dco.setFailOnConflict(true);
+					dco.setProgressMonitor(monitor);
 					dco.checkout();
 					try (Git git = new Git(getRepository())) {
 						newHead = git.commit().setMessage(newMessage)
@@ -227,9 +229,10 @@ public RevCommit call() throws NoMessageException, UnmergedPathsException,
 	}
 
 	/**
+	 * Include a {@code Ref} to a commit to be reverted
+	 *
 	 * @param commit
-	 *            a reference to a commit which is reverted into the current
-	 *            head
+	 *            a reference to a commit to be reverted into the current head
 	 * @return {@code this}
 	 */
 	public RevertCommand include(Ref commit) {
@@ -239,8 +242,10 @@ public RevertCommand include(Ref commit) {
 	}
 
 	/**
+	 * Include a commit to be reverted
+	 *
 	 * @param commit
-	 *            the Id of a commit which is reverted into the current head
+	 *            the Id of a commit to be reverted into the current head
 	 * @return {@code this}
 	 */
 	public RevertCommand include(AnyObjectId commit) {
@@ -248,8 +253,10 @@ public RevertCommand include(AnyObjectId commit) {
 	}
 
 	/**
+	 * Include a commit to be reverted
+	 *
 	 * @param name
-	 *            a name given to the commit
+	 *            name of a {@code Ref} referring to the commit
 	 * @param commit
 	 *            the Id of a commit which is reverted into the current head
 	 * @return {@code this}
@@ -260,6 +267,8 @@ public RevertCommand include(String name, AnyObjectId commit) {
 	}
 
 	/**
+	 * Set the name to be used in the "OURS" place for conflict markers
+	 *
 	 * @param ourCommitName
 	 *            the name that should be used in the "OURS" place for conflict
 	 *            markers
@@ -280,16 +289,20 @@ private String calculateOurName(Ref headRef) {
 	}
 
 	/**
-	 * @return the list of successfully reverted {@link Ref}'s. Never
-	 *         <code>null</code> but maybe an empty list if no commit was
-	 *         successfully cherry-picked
+	 * Get the list of successfully reverted {@link org.eclipse.jgit.lib.Ref}'s.
+	 *
+	 * @return the list of successfully reverted
+	 *         {@link org.eclipse.jgit.lib.Ref}'s. Never <code>null</code> but
+	 *         maybe an empty list if no commit was successfully cherry-picked
 	 */
 	public List<Ref> getRevertedRefs() {
 		return revertedRefs;
 	}
 
 	/**
-	 * @return the result of the merge failure, <code>null</code> if no merge
+	 * Get the result of a merge failure
+	 *
+	 * @return the result of a merge failure, <code>null</code> if no merge
 	 *         failure occurred during the revert
 	 */
 	public MergeResult getFailingResult() {
@@ -297,6 +310,8 @@ public MergeResult getFailingResult() {
 	}
 
 	/**
+	 * Get unmerged paths
+	 *
 	 * @return the unmerged paths, will be null if no merge conflicts
 	 */
 	public List<String> getUnmergedPaths() {
@@ -304,8 +319,10 @@ public List<String> getUnmergedPaths() {
 	}
 
 	/**
+	 * Set the merge strategy to use for this revert command
+	 *
 	 * @param strategy
-	 *            The merge strategy to use during this revert command.
+	 *            The merge strategy to use for this revert command.
 	 * @return {@code this}
 	 * @since 3.4
 	 */
@@ -313,4 +330,22 @@ public RevertCommand setStrategy(MergeStrategy strategy) {
 		this.strategy = strategy;
 		return this;
 	}
+
+	/**
+	 * The progress monitor associated with the revert operation. By default,
+	 * this is set to <code>NullProgressMonitor</code>
+	 *
+	 * @see NullProgressMonitor
+	 * @param monitor
+	 *            a {@link org.eclipse.jgit.lib.ProgressMonitor}
+	 * @return {@code this}
+	 * @since 4.11
+	 */
+	public RevertCommand setProgressMonitor(ProgressMonitor monitor) {
+		if (monitor == null) {
+			monitor = NullProgressMonitor.INSTANCE;
+		}
+		this.monitor = monitor;
+		return this;
+	}
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/RmCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/RmCommand.java
index 48c23f5..d2f4be8 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/RmCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/RmCommand.java
@@ -72,7 +72,7 @@
  * class should only be used for one invocation of the command (means: one call
  * to {@link #call()}).
  * <p>
- * Examples (<code>git</code> is a {@link Git} instance):
+ * Examples (<code>git</code> is a {@link org.eclipse.jgit.api.Git} instance):
  * <p>
  * Remove file "test.txt" from both index and working directory:
  *
@@ -97,8 +97,10 @@ public class RmCommand extends GitCommand<DirCache> {
 	private boolean cached = false;
 
 	/**
+	 * Constructor for RmCommand.
 	 *
 	 * @param repo
+	 *            the {@link org.eclipse.jgit.lib.Repository}
 	 */
 	public RmCommand(Repository repo) {
 		super(repo);
@@ -106,6 +108,8 @@ public RmCommand(Repository repo) {
 	}
 
 	/**
+	 * Add file name pattern of files to be removed
+	 *
 	 * @param filepattern
 	 *            repository-relative path of file to remove (with
 	 *            <code>/</code> as separator)
@@ -121,8 +125,9 @@ public RmCommand addFilepattern(String filepattern) {
 	 * Only remove the specified files from the index.
 	 *
 	 * @param cached
-	 *            true if files should only be removed from index, false if
-	 *            files should also be deleted from the working directory
+	 *            {@code true} if files should only be removed from index,
+	 *            {@code false} if files should also be deleted from the working
+	 *            directory
 	 * @return {@code this}
 	 * @since 2.2
 	 */
@@ -133,11 +138,11 @@ public RmCommand setCached(boolean cached) {
 	}
 
 	/**
+	 * {@inheritDoc}
+	 * <p>
 	 * Executes the {@code Rm} command. Each instance of this class should only
 	 * be used for one invocation of the command. Don't call this method twice
 	 * on an instance.
-	 *
-	 * @return the DirCache after Rm
 	 */
 	@Override
 	public DirCache call() throws GitAPIException,
@@ -149,7 +154,7 @@ public DirCache call() throws GitAPIException,
 		DirCache dc = null;
 
 		List<String> actuallyDeletedFiles = new ArrayList<>();
-		try (final TreeWalk tw = new TreeWalk(repo)) {
+		try (TreeWalk tw = new TreeWalk(repo)) {
 			dc = repo.lockDirCache();
 			DirCacheBuilder builder = dc.builder();
 			tw.reset(); // drop the first empty tree, which we do not need here
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/ShowNoteCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/ShowNoteCommand.java
index dbff463..eb81d20 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/ShowNoteCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/ShowNoteCommand.java
@@ -68,12 +68,16 @@ public class ShowNoteCommand extends GitCommand<Note> {
 	private String notesRef = Constants.R_NOTES_COMMITS;
 
 	/**
+	 * Constructor for ShowNoteCommand.
+	 *
 	 * @param repo
+	 *            the {@link org.eclipse.jgit.lib.Repository}
 	 */
 	protected ShowNoteCommand(Repository repo) {
 		super(repo);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public Note call() throws GitAPIException {
 		checkCallable();
@@ -96,6 +100,8 @@ public Note call() throws GitAPIException {
 	 * Sets the object id of object you want a note on
 	 *
 	 * @param id
+	 *            the {@link org.eclipse.jgit.revwalk.RevObject} to show notes
+	 *            for.
 	 * @return {@code this}
 	 */
 	public ShowNoteCommand setObjectId(RevObject id) {
@@ -105,12 +111,13 @@ public ShowNoteCommand setObjectId(RevObject id) {
 	}
 
 	/**
+	 * Set the {@code Ref} to read notes from.
+	 *
 	 * @param notesRef
 	 *            the ref to read notes from. Note, the default value of
-	 *            {@link Constants#R_NOTES_COMMITS} will be used if nothing is
-	 *            set
+	 *            {@link org.eclipse.jgit.lib.Constants#R_NOTES_COMMITS} will be
+	 *            used if nothing is set
 	 * @return {@code this}
-	 *
 	 * @see Constants#R_NOTES_COMMITS
 	 */
 	public ShowNoteCommand setNotesRef(String notesRef) {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/StashApplyCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/StashApplyCommand.java
index b56fb25..01d070c 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/StashApplyCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/StashApplyCommand.java
@@ -42,6 +42,8 @@
  */
 package org.eclipse.jgit.api;
 
+import static org.eclipse.jgit.treewalk.TreeWalk.OperationType.CHECKOUT_OP;
+
 import java.io.IOException;
 import java.text.MessageFormat;
 import java.util.HashSet;
@@ -86,7 +88,6 @@
  *
  * @see <a href="http://www.kernel.org/pub/software/scm/git/docs/git-stash.html"
  *      >Git documentation about Stash</a>
- *
  * @since 2.0
  */
 public class StashApplyCommand extends GitCommand<ObjectId> {
@@ -107,8 +108,10 @@ public class StashApplyCommand extends GitCommand<ObjectId> {
 	 * Create command to apply the changes of a stashed commit
 	 *
 	 * @param repo
+	 *            the {@link org.eclipse.jgit.lib.Repository} to apply the stash
+	 *            to
 	 */
-	public StashApplyCommand(final Repository repo) {
+	public StashApplyCommand(Repository repo) {
 		super(repo);
 	}
 
@@ -119,15 +122,19 @@ public StashApplyCommand(final Repository repo) {
 	 * unspecified
 	 *
 	 * @param stashRef
+	 *            name of the stash {@code Ref} to apply
 	 * @return {@code this}
 	 */
-	public StashApplyCommand setStashRef(final String stashRef) {
+	public StashApplyCommand setStashRef(String stashRef) {
 		this.stashRef = stashRef;
 		return this;
 	}
 
 	/**
+	 * Whether to ignore the repository state when applying the stash
+	 *
 	 * @param willIgnoreRepositoryState
+	 *            whether to ignore the repository state when applying the stash
 	 * @return {@code this}
 	 * @since 3.2
 	 */
@@ -152,14 +159,9 @@ private ObjectId getStashId() throws GitAPIException {
 	}
 
 	/**
+	 * {@inheritDoc}
+	 * <p>
 	 * Apply the changes in a stashed commit to the working directory and index
-	 *
-	 * @return id of stashed commit that was applied TODO: Does anyone depend on
-	 *         this, or could we make it more like Merge/CherryPick/Revert?
-	 * @throws GitAPIException
-	 * @throws WrongRepositoryStateException
-	 * @throws NoHeadException
-	 * @throws StashApplyFailureException
 	 */
 	@Override
 	public ObjectId call() throws GitAPIException,
@@ -271,6 +273,8 @@ public ObjectId call() throws GitAPIException,
 	}
 
 	/**
+	 * Whether to restore the index state
+	 *
 	 * @param applyIndex
 	 *            true (default) if the command should restore the index state
 	 */
@@ -279,6 +283,8 @@ public void setApplyIndex(boolean applyIndex) {
 	}
 
 	/**
+	 * Set the <code>MergeStrategy</code> to use.
+	 *
 	 * @param strategy
 	 *            The merge strategy to use in order to merge during this
 	 *            command execution.
@@ -291,6 +297,8 @@ public StashApplyCommand setStrategy(MergeStrategy strategy) {
 	}
 
 	/**
+	 * Whether the command should restore untracked files
+	 *
 	 * @param applyUntracked
 	 *            true (default) if the command should restore untracked files
 	 * @since 3.4
@@ -355,7 +363,8 @@ private void resetUntracked(RevTree tree) throws CheckoutConflictException,
 					// Not in commit, don't create untracked
 					continue;
 
-				final EolStreamType eolStreamType = walk.getEolStreamType();
+				final EolStreamType eolStreamType = walk
+						.getEolStreamType(CHECKOUT_OP);
 				final DirCacheEntry entry = new DirCacheEntry(walk.getRawPath());
 				entry.setFileMode(cIter.getEntryFileMode());
 				entry.setObjectIdFromRaw(cIter.idBuffer(), cIter.idOffset());
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/StashCreateCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/StashCreateCommand.java
index 77a7fff..c32890d 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/StashCreateCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/StashCreateCommand.java
@@ -115,6 +115,7 @@ public class StashCreateCommand extends GitCommand<RevCommit> {
 	 * Create a command to stash changes in the working directory and index
 	 *
 	 * @param repo
+	 *            a {@link org.eclipse.jgit.lib.Repository} object.
 	 */
 	public StashCreateCommand(Repository repo) {
 		super(repo);
@@ -128,6 +129,7 @@ public StashCreateCommand(Repository repo) {
 	 * id, and short commit message when used.
 	 *
 	 * @param message
+	 *            the stash message
 	 * @return {@code this}
 	 */
 	public StashCreateCommand setIndexMessage(String message) {
@@ -142,6 +144,7 @@ public StashCreateCommand setIndexMessage(String message) {
 	 * id, and short commit message when used.
 	 *
 	 * @param message
+	 *            the working directory message
 	 * @return {@code this}
 	 */
 	public StashCreateCommand setWorkingDirectoryMessage(String message) {
@@ -153,6 +156,8 @@ public StashCreateCommand setWorkingDirectoryMessage(String message) {
 	 * Set the person to use as the author and committer in the commits made
 	 *
 	 * @param person
+	 *            the {@link org.eclipse.jgit.lib.PersonIdent} of the person who
+	 *            creates the stash.
 	 * @return {@code this}
 	 */
 	public StashCreateCommand setPerson(PersonIdent person) {
@@ -161,12 +166,13 @@ public StashCreateCommand setPerson(PersonIdent person) {
 	}
 
 	/**
-	 * Set the reference to update with the stashed commit id
-	 * If null, no reference is updated
+	 * Set the reference to update with the stashed commit id If null, no
+	 * reference is updated
 	 * <p>
-	 * This value defaults to {@link Constants#R_STASH}
+	 * This value defaults to {@link org.eclipse.jgit.lib.Constants#R_STASH}
 	 *
 	 * @param ref
+	 *            the name of the {@code Ref} to update
 	 * @return {@code this}
 	 */
 	public StashCreateCommand setRef(String ref) {
@@ -178,6 +184,7 @@ public StashCreateCommand setRef(String ref) {
 	 * Whether to include untracked files in the stash.
 	 *
 	 * @param includeUntracked
+	 *            whether to include untracked files in the stash
 	 * @return {@code this}
 	 * @since 3.4
 	 */
@@ -188,7 +195,7 @@ public StashCreateCommand setIncludeUntracked(boolean includeUntracked) {
 
 	private RevCommit parseCommit(final ObjectReader reader,
 			final ObjectId headId) throws IOException {
-		try (final RevWalk walk = new RevWalk(reader)) {
+		try (RevWalk walk = new RevWalk(reader)) {
 			return walk.parseCommit(headId);
 		}
 	}
@@ -232,11 +239,10 @@ private Ref getHead() throws GitAPIException {
 	}
 
 	/**
+	 * {@inheritDoc}
+	 * <p>
 	 * Stash the contents on the working directory and index in separate commits
 	 * and reset to the current HEAD commit.
-	 *
-	 * @return stashed commit or null if no changes to stash
-	 * @throws GitAPIException
 	 */
 	@Override
 	public RevCommit call() throws GitAPIException {
@@ -297,12 +303,9 @@ public RevCommit call() throws GitAPIException {
 						entry.setLastModified(wtIter.getEntryLastModified());
 						entry.setFileMode(wtIter.getEntryFileMode());
 						long contentLength = wtIter.getEntryContentLength();
-						InputStream in = wtIter.openEntryStream();
-						try {
+						try (InputStream in = wtIter.openEntryStream()) {
 							entry.setObjectId(inserter.insert(
 									Constants.OBJ_BLOB, contentLength, in));
-						} finally {
-							in.close();
 						}
 
 						if (indexIter == null && headIter == null)
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/StashDropCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/StashDropCommand.java
index 85e7b3d..7f02aab 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/StashDropCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/StashDropCommand.java
@@ -84,7 +84,10 @@ public class StashDropCommand extends GitCommand<ObjectId> {
 	private boolean all;
 
 	/**
+	 * Constructor for StashDropCommand.
+	 *
 	 * @param repo
+	 *            a {@link org.eclipse.jgit.lib.Repository} object.
 	 */
 	public StashDropCommand(Repository repo) {
 		super(repo);
@@ -101,9 +104,10 @@ public StashDropCommand(Repository repo) {
 	 * unspecified
 	 *
 	 * @param stashRef
+	 *            the 0-based index of the stash reference
 	 * @return {@code this}
 	 */
-	public StashDropCommand setStashRef(final int stashRef) {
+	public StashDropCommand setStashRef(int stashRef) {
 		if (stashRef < 0)
 			throw new IllegalArgumentException();
 
@@ -112,14 +116,15 @@ public StashDropCommand setStashRef(final int stashRef) {
 	}
 
 	/**
-	 * Set wheter drop all stashed commits
+	 * Set whether to drop all stashed commits
 	 *
 	 * @param all
-	 *            true to drop all stashed commits, false to drop only the
-	 *            stashed commit set via calling {@link #setStashRef(int)}
+	 *            {@code true} to drop all stashed commits, {@code false} to
+	 *            drop only the stashed commit set via calling
+	 *            {@link #setStashRef(int)}
 	 * @return {@code this}
 	 */
-	public StashDropCommand setAll(final boolean all) {
+	public StashDropCommand setAll(boolean all) {
 		this.all = all;
 		return this;
 	}
@@ -133,7 +138,7 @@ private Ref getRef() throws GitAPIException {
 		}
 	}
 
-	private RefUpdate createRefUpdate(final Ref stashRef) throws IOException {
+	private RefUpdate createRefUpdate(Ref stashRef) throws IOException {
 		RefUpdate update = repo.updateRef(R_STASH);
 		update.disableRefLog();
 		update.setExpectedOldObjectId(stashRef.getObjectId());
@@ -141,7 +146,7 @@ private RefUpdate createRefUpdate(final Ref stashRef) throws IOException {
 		return update;
 	}
 
-	private void deleteRef(final Ref stashRef) {
+	private void deleteRef(Ref stashRef) {
 		try {
 			Result result = createRefUpdate(stashRef).delete();
 			if (Result.FORCED != result)
@@ -173,11 +178,10 @@ private void updateRef(Ref stashRef, ObjectId newId) {
 	}
 
 	/**
+	 * {@inheritDoc}
+	 * <p>
 	 * Drop the configured entry from the stash reflog and return value of the
 	 * stash reference after the drop occurs
-	 *
-	 * @return commit id of stash reference or null if no more stashed changes
-	 * @throws GitAPIException
 	 */
 	@Override
 	public ObjectId call() throws GitAPIException {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/StashListCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/StashListCommand.java
index 8420dd2..f316b23 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/StashListCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/StashListCommand.java
@@ -70,12 +70,13 @@ public class StashListCommand extends GitCommand<Collection<RevCommit>> {
 	/**
 	 * Create a new stash list command
 	 *
-	 * @param repo
+	 * @param repo a {@link org.eclipse.jgit.lib.Repository} object.
 	 */
-	public StashListCommand(final Repository repo) {
+	public StashListCommand(Repository repo) {
 		super(repo);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public Collection<RevCommit> call() throws GitAPIException,
 			InvalidRefNameException {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/Status.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/Status.java
index 5b7c73b..909a745 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/Status.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/Status.java
@@ -70,7 +70,10 @@ public class Status {
 	private final boolean hasUncommittedChanges;
 
 	/**
+	 * Constructor for Status.
+	 *
 	 * @param diff
+	 *            the {@link org.eclipse.jgit.lib.IndexDiff} having the status
 	 */
 	public Status(IndexDiff diff) {
 		super();
@@ -86,16 +89,20 @@ public Status(IndexDiff diff) {
 	}
 
 	/**
-	 * @return true if no differences exist between the working-tree, the index,
-	 *         and the current HEAD, false if differences do exist
+	 * Whether the status is clean
+	 *
+	 * @return {@code true} if no differences exist between the working-tree,
+	 *         the index, and the current HEAD, {@code false} if differences do
+	 *         exist
 	 */
 	public boolean isClean() {
 		return clean;
 	}
 
 	/**
-	 * @return true if any tracked file is changed
+	 * Whether there are uncommitted changes
 	 *
+	 * @return {@code true} if any tracked file is changed
 	 * @since 3.2
 	 */
 	public boolean hasUncommittedChanges() {
@@ -103,14 +110,18 @@ public boolean hasUncommittedChanges() {
 	}
 
 	/**
+	 * Get files added to the index
+	 *
 	 * @return list of files added to the index, not in HEAD (e.g. what you get
-	 *         if you call 'git add ...' on a newly created file)
+	 *         if you call {@code git add ...} on a newly created file)
 	 */
 	public Set<String> getAdded() {
 		return Collections.unmodifiableSet(diff.getAdded());
 	}
 
 	/**
+	 * Get changed files from HEAD to index
+	 *
 	 * @return list of files changed from HEAD to index (e.g. what you get if
 	 *         you modify an existing file and call 'git add ...' on it)
 	 */
@@ -119,6 +130,8 @@ public Set<String> getChanged() {
 	}
 
 	/**
+	 * Get removed files
+	 *
 	 * @return list of files removed from index, but in HEAD (e.g. what you get
 	 *         if you call 'git rm ...' on a existing file)
 	 */
@@ -127,6 +140,8 @@ public Set<String> getRemoved() {
 	}
 
 	/**
+	 * Get missing files
+	 *
 	 * @return list of files in index, but not filesystem (e.g. what you get if
 	 *         you call 'rm ...' on a existing file)
 	 */
@@ -135,6 +150,8 @@ public Set<String> getMissing() {
 	}
 
 	/**
+	 * Get modified files relative to the index
+	 *
 	 * @return list of files modified on disk relative to the index (e.g. what
 	 *         you get if you modify an existing file without adding it to the
 	 *         index)
@@ -144,6 +161,8 @@ public Set<String> getModified() {
 	}
 
 	/**
+	 * Get untracked files
+	 *
 	 * @return list of files that are not ignored, and not in the index. (e.g.
 	 *         what you get if you create a new file without adding it to the
 	 *         index)
@@ -153,6 +172,8 @@ public Set<String> getUntracked() {
 	}
 
 	/**
+	 * Get untracked folders
+	 *
 	 * @return set of directories that are not ignored, and not in the index.
 	 */
 	public Set<String> getUntrackedFolders() {
@@ -160,6 +181,8 @@ public Set<String> getUntrackedFolders() {
 	}
 
 	/**
+	 * Get conflicting files
+	 *
 	 * @return list of files that are in conflict. (e.g what you get if you
 	 *         modify file that was modified by someone else in the meantime)
 	 */
@@ -168,7 +191,10 @@ public Set<String> getConflicting() {
 	}
 
 	/**
-	 * @return a map from conflicting path to its {@link StageState}.
+	 * Get StageState of conflicting files
+	 *
+	 * @return a map from conflicting path to its
+	 *         {@link org.eclipse.jgit.lib.IndexDiff.StageState}.
 	 * @since 3.0
 	 */
 	public Map<String, StageState> getConflictingStageState() {
@@ -176,6 +202,8 @@ public Map<String, StageState> getConflictingStageState() {
 	}
 
 	/**
+	 * Get ignored files which are not in the index
+	 *
 	 * @return set of files and folders that are ignored and not in the index.
 	 */
 	public Set<String> getIgnoredNotInIndex() {
@@ -183,9 +211,11 @@ public Set<String> getIgnoredNotInIndex() {
 	}
 
 	/**
+	 * Get uncommitted changes, i.e. all files changed in the index or working
+	 * tree
+	 *
 	 * @return set of files and folders that are known to the repo and changed
 	 *         either in the index or in the working tree.
-	 *
 	 * @since 3.2
 	 */
 	public Set<String> getUncommittedChanges() {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/StatusCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/StatusCommand.java
index 8f7804a..98c5520 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/StatusCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/StatusCommand.java
@@ -64,9 +64,9 @@
  * to finally execute the command. Each instance of this class should only be
  * used for one invocation of the command (means: one call to {@link #call()})
  *
- * @see <a
- *      href="http://www.kernel.org/pub/software/scm/git/docs/git-status.html"
- *      >Git documentation about Status</a>
+ * @see <a href=
+ *      "http://www.kernel.org/pub/software/scm/git/docs/git-status.html" >Git
+ *      documentation about Status</a>
  */
 public class StatusCommand extends GitCommand<Status> {
 	private WorkingTreeIterator workingTreeIt;
@@ -76,14 +76,21 @@ public class StatusCommand extends GitCommand<Status> {
 	private IgnoreSubmoduleMode ignoreSubmoduleMode = null;
 
 	/**
+	 * Constructor for StatusCommand.
+	 *
 	 * @param repo
+	 *            a {@link org.eclipse.jgit.lib.Repository} object.
 	 */
 	protected StatusCommand(Repository repo) {
 		super(repo);
 	}
 
 	/**
+	 * Whether to ignore submodules
+	 *
 	 * @param mode
+	 *            the
+	 *            {@link org.eclipse.jgit.submodule.SubmoduleWalk.IgnoreSubmoduleMode}
 	 * @return {@code this}
 	 * @since 3.6
 	 */
@@ -126,13 +133,12 @@ public List<String> getPaths() {
 	}
 
 	/**
+	 * {@inheritDoc}
+	 * <p>
 	 * Executes the {@code Status} command with all the options and parameters
 	 * collected by the setter methods of this class. Each instance of this
 	 * class should only be used for one invocation of the command. Don't call
 	 * this method twice on an instance.
-	 *
-	 * @return a {@link Status} object telling about each path where working
-	 *         tree, index or HEAD differ from each other.
 	 */
 	@Override
 	public Status call() throws GitAPIException, NoWorkTreeException {
@@ -157,8 +163,9 @@ public Status call() throws GitAPIException, NoWorkTreeException {
 	}
 
 	/**
-	 * To set the {@link WorkingTreeIterator} which should be used. If this
-	 * method is not called a standard {@link FileTreeIterator} is used.
+	 * To set the {@link org.eclipse.jgit.treewalk.WorkingTreeIterator} which
+	 * should be used. If this method is not called a standard
+	 * {@link org.eclipse.jgit.treewalk.FileTreeIterator} is used.
 	 *
 	 * @param workingTreeIt
 	 *            a working tree iterator
@@ -170,10 +177,11 @@ public StatusCommand setWorkingTreeIt(WorkingTreeIterator workingTreeIt) {
 	}
 
 	/**
-	 * To set the {@link ProgressMonitor} which contains callback methods to
-	 * inform you about the progress of this command.
+	 * To set the {@link org.eclipse.jgit.lib.ProgressMonitor} which contains
+	 * callback methods to inform you about the progress of this command.
 	 *
 	 * @param progressMonitor
+	 *            a {@link org.eclipse.jgit.lib.ProgressMonitor} object.
 	 * @return {@code this}
 	 * @since 3.1
 	 */
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleAddCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleAddCommand.java
index 0519d45..9538d2b 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleAddCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleAddCommand.java
@@ -69,8 +69,8 @@
  * .gitmodules file and the repository config file, and also add the submodule
  * and .gitmodules file to the index.
  *
- * @see <a
- *      href="http://www.kernel.org/pub/software/scm/git/docs/git-submodule.html"
+ * @see <a href=
+ *      "http://www.kernel.org/pub/software/scm/git/docs/git-submodule.html"
  *      >Git documentation about submodules</a>
  */
 public class SubmoduleAddCommand extends
@@ -83,9 +83,12 @@ public class SubmoduleAddCommand extends
 	private ProgressMonitor monitor;
 
 	/**
+	 * Constructor for SubmoduleAddCommand.
+	 *
 	 * @param repo
+	 *            a {@link org.eclipse.jgit.lib.Repository} object.
 	 */
-	public SubmoduleAddCommand(final Repository repo) {
+	public SubmoduleAddCommand(Repository repo) {
 		super(repo);
 	}
 
@@ -96,7 +99,7 @@ public SubmoduleAddCommand(final Repository repo) {
 	 *            (with <code>/</code> as separator)
 	 * @return this command
 	 */
-	public SubmoduleAddCommand setPath(final String path) {
+	public SubmoduleAddCommand setPath(String path) {
 		this.path = path;
 		return this;
 	}
@@ -105,9 +108,10 @@ public SubmoduleAddCommand setPath(final String path) {
 	 * Set URI to clone submodule from
 	 *
 	 * @param uri
+	 *            a {@link java.lang.String} object.
 	 * @return this command
 	 */
-	public SubmoduleAddCommand setURI(final String uri) {
+	public SubmoduleAddCommand setURI(String uri) {
 		this.uri = uri;
 		return this;
 	}
@@ -118,9 +122,10 @@ public SubmoduleAddCommand setURI(final String uri) {
 	 *
 	 * @see NullProgressMonitor
 	 * @param monitor
+	 *            a {@link org.eclipse.jgit.lib.ProgressMonitor} object.
 	 * @return this command
 	 */
-	public SubmoduleAddCommand setProgressMonitor(final ProgressMonitor monitor) {
+	public SubmoduleAddCommand setProgressMonitor(ProgressMonitor monitor) {
 		this.monitor = monitor;
 		return this;
 	}
@@ -129,7 +134,7 @@ public SubmoduleAddCommand setProgressMonitor(final ProgressMonitor monitor) {
 	 * Is the configured already a submodule in the index?
 	 *
 	 * @return true if submodule exists in index, false otherwise
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 */
 	protected boolean submoduleExists() throws IOException {
 		TreeFilter filter = PathFilter.create(path);
@@ -139,15 +144,14 @@ protected boolean submoduleExists() throws IOException {
 	}
 
 	/**
+	 * {@inheritDoc}
+	 * <p>
 	 * Executes the {@code SubmoduleAddCommand}
 	 *
 	 * The {@code Repository} instance returned by this command needs to be
 	 * closed by the caller to free resources held by the {@code Repository}
 	 * instance. It is recommended to call this method as soon as you don't need
 	 * a reference to this {@code Repository} instance anymore.
-	 *
-	 * @return the newly created {@link Repository}
-	 * @throws GitAPIException
 	 */
 	@Override
 	public Repository call() throws GitAPIException {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleDeinitCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleDeinitCommand.java
new file mode 100644
index 0000000..569a8e3
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleDeinitCommand.java
@@ -0,0 +1,319 @@
+/*
+ * Copyright (C) 2017, Two Sigma Open Source
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ *   copyright notice, this list of conditions and the following
+ *   disclaimer in the documentation and/or other materials provided
+ *   with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ *   names of its contributors may be used to endorse or promote
+ *   products derived from this software without specific prior
+ *   written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.eclipse.jgit.api;
+
+import static org.eclipse.jgit.util.FileUtils.RECURSIVE;
+
+import java.io.File;
+import java.io.IOException;
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+import org.eclipse.jgit.api.errors.GitAPIException;
+import org.eclipse.jgit.api.errors.JGitInternalException;
+import org.eclipse.jgit.api.errors.NoHeadException;
+import org.eclipse.jgit.internal.JGitText;
+import org.eclipse.jgit.lib.ConfigConstants;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.Ref;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.lib.StoredConfig;
+import org.eclipse.jgit.revwalk.RevCommit;
+import org.eclipse.jgit.revwalk.RevTree;
+import org.eclipse.jgit.revwalk.RevWalk;
+import org.eclipse.jgit.submodule.SubmoduleWalk;
+import org.eclipse.jgit.treewalk.filter.PathFilter;
+import org.eclipse.jgit.treewalk.filter.PathFilterGroup;
+import org.eclipse.jgit.treewalk.filter.TreeFilter;
+import org.eclipse.jgit.util.FileUtils;
+
+/**
+ * A class used to execute a submodule deinit command.
+ * <p>
+ * This will remove the module(s) from the working tree, but won't affect
+ * .git/modules.
+ *
+ * @since 4.10
+ * @see <a href=
+ *      "http://www.kernel.org/pub/software/scm/git/docs/git-submodule.html"
+ *      >Git documentation about submodules</a>
+ */
+public class SubmoduleDeinitCommand
+		extends GitCommand<Collection<SubmoduleDeinitResult>> {
+
+	private final Collection<String> paths;
+
+	private boolean force;
+
+	/**
+	 * Constructor of SubmoduleDeinitCommand
+	 *
+	 * @param repo
+	 */
+	public SubmoduleDeinitCommand(Repository repo) {
+		super(repo);
+		paths = new ArrayList<>();
+	}
+
+	/**
+	 * {@inheritDoc}
+	 * <p>
+	 *
+	 * @return the set of repositories successfully deinitialized.
+	 * @throws NoSuchSubmoduleException
+	 *             if any of the submodules which we might want to deinitialize
+	 *             don't exist
+	 */
+	@Override
+	public Collection<SubmoduleDeinitResult> call() throws GitAPIException {
+		checkCallable();
+		try {
+			if (paths.isEmpty()) {
+				return Collections.emptyList();
+			}
+			for (String path : paths) {
+				if (!submoduleExists(path)) {
+					throw new NoSuchSubmoduleException(path);
+				}
+			}
+			List<SubmoduleDeinitResult> results = new ArrayList<>(paths.size());
+			try (RevWalk revWalk = new RevWalk(repo);
+					SubmoduleWalk generator = SubmoduleWalk.forIndex(repo)) {
+				generator.setFilter(PathFilterGroup.createFromStrings(paths));
+				StoredConfig config = repo.getConfig();
+				while (generator.next()) {
+					String path = generator.getPath();
+					String name = generator.getModuleName();
+					SubmoduleDeinitStatus status = checkDirty(revWalk, path);
+					switch (status) {
+					case SUCCESS:
+						deinit(path);
+						break;
+					case ALREADY_DEINITIALIZED:
+						break;
+					case DIRTY:
+						if (force) {
+							deinit(path);
+							status = SubmoduleDeinitStatus.FORCED;
+						}
+						break;
+					default:
+						throw new JGitInternalException(MessageFormat.format(
+								JGitText.get().unexpectedSubmoduleStatus,
+								status));
+					}
+
+					config.unsetSection(
+							ConfigConstants.CONFIG_SUBMODULE_SECTION, name);
+					results.add(new SubmoduleDeinitResult(path, status));
+				}
+			}
+			return results;
+		} catch (IOException e) {
+			throw new JGitInternalException(e.getMessage(), e);
+		}
+	}
+
+	/**
+	 * Recursively delete the *contents* of path, but leave path as an empty
+	 * directory
+	 *
+	 * @param path
+	 *            the path to clean
+	 * @throws IOException
+	 */
+	private void deinit(String path) throws IOException {
+		File dir = new File(repo.getWorkTree(), path);
+		if (!dir.isDirectory()) {
+			throw new JGitInternalException(MessageFormat.format(
+					JGitText.get().expectedDirectoryNotSubmodule, path));
+		}
+		final File[] ls = dir.listFiles();
+		if (ls != null) {
+			for (int i = 0; i < ls.length; i++) {
+				FileUtils.delete(ls[i], RECURSIVE);
+			}
+		}
+	}
+
+	/**
+	 * Check if a submodule is dirty. A submodule is dirty if there are local
+	 * changes to the submodule relative to its HEAD, including untracked files.
+	 * It is also dirty if the HEAD of the submodule does not match the value in
+	 * the parent repo's index or HEAD.
+	 *
+	 * @param revWalk
+	 * @param path
+	 * @return status of the command
+	 * @throws GitAPIException
+	 * @throws IOException
+	 */
+	private SubmoduleDeinitStatus checkDirty(RevWalk revWalk, String path)
+			throws GitAPIException, IOException {
+		Ref head = repo.exactRef("HEAD"); //$NON-NLS-1$
+		if (head == null) {
+			throw new NoHeadException(
+					JGitText.get().invalidRepositoryStateNoHead);
+		}
+		RevCommit headCommit = revWalk.parseCommit(head.getObjectId());
+		RevTree tree = headCommit.getTree();
+
+		ObjectId submoduleHead;
+		try (SubmoduleWalk w = SubmoduleWalk.forPath(repo, tree, path)) {
+			submoduleHead = w.getHead();
+			if (submoduleHead == null) {
+				// The submodule is not checked out.
+				return SubmoduleDeinitStatus.ALREADY_DEINITIALIZED;
+			}
+			if (!submoduleHead.equals(w.getObjectId())) {
+				// The submodule's current HEAD doesn't match the value in the
+				// outer repo's HEAD.
+				return SubmoduleDeinitStatus.DIRTY;
+			}
+		}
+
+		try (SubmoduleWalk w = SubmoduleWalk.forIndex(repo)) {
+			if (!w.next()) {
+				// The submodule does not exist in the index (shouldn't happen
+				// since we check this earlier)
+				return SubmoduleDeinitStatus.DIRTY;
+			}
+			if (!submoduleHead.equals(w.getObjectId())) {
+				// The submodule's current HEAD doesn't match the value in the
+				// outer repo's index.
+				return SubmoduleDeinitStatus.DIRTY;
+			}
+
+			Repository submoduleRepo = w.getRepository();
+
+			Status status = Git.wrap(submoduleRepo).status().call();
+			return status.isClean() ? SubmoduleDeinitStatus.SUCCESS
+					: SubmoduleDeinitStatus.DIRTY;
+		}
+	}
+
+	/**
+	 * Check if this path is a submodule by checking the index, which is what
+	 * git submodule deinit checks.
+	 *
+	 * @param path
+	 *            path of the submodule
+	 *
+	 * @return {@code true} if path exists and is a submodule in index,
+	 *         {@code false} otherwise
+	 * @throws IOException
+	 */
+	private boolean submoduleExists(String path) throws IOException {
+		TreeFilter filter = PathFilter.create(path);
+		try (SubmoduleWalk w = SubmoduleWalk.forIndex(repo)) {
+			return w.setFilter(filter).next();
+		}
+	}
+
+	/**
+	 * Add repository-relative submodule path to deinitialize
+	 *
+	 * @param path
+	 *            (with <code>/</code> as separator)
+	 * @return this command
+	 */
+	public SubmoduleDeinitCommand addPath(String path) {
+		paths.add(path);
+		return this;
+	}
+
+	/**
+	 * If {@code true}, call() will deinitialize modules with local changes;
+	 * else it will refuse to do so.
+	 *
+	 * @param force
+	 * @return {@code this}
+	 */
+	public SubmoduleDeinitCommand setForce(boolean force) {
+		this.force = force;
+		return this;
+	}
+
+	/**
+	 * The user tried to deinitialize a submodule that doesn't exist in the
+	 * index.
+	 */
+	public static class NoSuchSubmoduleException extends GitAPIException {
+		private static final long serialVersionUID = 1L;
+
+		/**
+		 * Constructor of NoSuchSubmoduleException
+		 *
+		 * @param path
+		 *            path of non-existing submodule
+		 */
+		public NoSuchSubmoduleException(String path) {
+			super(MessageFormat.format(JGitText.get().noSuchSubmodule, path));
+		}
+	}
+
+	/**
+	 * The effect of a submodule deinit command for a given path
+	 */
+	public enum SubmoduleDeinitStatus {
+		/**
+		 * The submodule was not initialized in the first place
+		 */
+		ALREADY_DEINITIALIZED,
+		/**
+		 * The submodule was deinitialized
+		 */
+		SUCCESS,
+		/**
+		 * The submodule had local changes, but was deinitialized successfully
+		 */
+		FORCED,
+		/**
+		 * The submodule had local changes and force was false
+		 */
+		DIRTY,
+	}
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/SafeBufferedOutputStream.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleDeinitResult.java
similarity index 61%
copy from org.eclipse.jgit/src/org/eclipse/jgit/util/io/SafeBufferedOutputStream.java
copy to org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleDeinitResult.java
index 84c3398..5a9cbc1 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/SafeBufferedOutputStream.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleDeinitResult.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011, Robin Rosenberg
+ * Copyright (C) 2017, Two Sigma Open Source
  * and other copyright owners as documented in the project's IP log.
  *
  * This program and the accompanying materials are made available
@@ -40,33 +40,66 @@
  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
-package org.eclipse.jgit.util.io;
-
-import java.io.BufferedOutputStream;
-import java.io.OutputStream;
+package org.eclipse.jgit.api;
 
 /**
- * @deprecated use BufferedOutputStream in Java 8 and later.
+ * The result of a submodule deinit command for a particular path
+ *
+ * @since 4.10
  */
-@Deprecated
-public class SafeBufferedOutputStream extends BufferedOutputStream {
+public class SubmoduleDeinitResult {
+	private String path;
+
+	private SubmoduleDeinitCommand.SubmoduleDeinitStatus status;
+
 	/**
-	 * @see BufferedOutputStream#BufferedOutputStream(OutputStream)
-	 * @param out
-	 *            underlying output stream
+	 * Constructor for SubmoduleDeinitResult
+	 *
+	 * @param path
+	 *            path of the submodule
+	 * @param status
 	 */
-	public SafeBufferedOutputStream(OutputStream out) {
-		super(out);
+	public SubmoduleDeinitResult(String path,
+			SubmoduleDeinitCommand.SubmoduleDeinitStatus status) {
+		this.path = path;
+		this.status = status;
 	}
 
 	/**
-	 * @see BufferedOutputStream#BufferedOutputStream(OutputStream, int)
-	 * @param out
-	 *            underlying output stream
-	 * @param size
-	 *            buffer size
+	 * Get the path of the submodule
+	 *
+	 * @return path of the submodule
 	 */
-	public SafeBufferedOutputStream(OutputStream out, int size) {
-		super(out, size);
+	public String getPath() {
+		return path;
+	}
+
+	/**
+	 * Set the path of the submodule
+	 *
+	 * @param path
+	 *            path of the submodule
+	 */
+	public void setPath(String path) {
+		this.path = path;
+	}
+
+	/**
+	 * Get the status of the command
+	 *
+	 * @return the status of the command
+	 */
+	public SubmoduleDeinitCommand.SubmoduleDeinitStatus getStatus() {
+		return status;
+	}
+
+	/**
+	 * Set the status of the command
+	 *
+	 * @param status
+	 *            the status of the command
+	 */
+	public void setStatus(SubmoduleDeinitCommand.SubmoduleDeinitStatus status) {
+		this.status = status;
 	}
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleInitCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleInitCommand.java
index 4c5e317..2db12b8 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleInitCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleInitCommand.java
@@ -63,8 +63,8 @@
  * .gitmodules file to a repository's config file for each submodule not
  * currently present in the repository's config file.
  *
- * @see <a
- *      href="http://www.kernel.org/pub/software/scm/git/docs/git-submodule.html"
+ * @see <a href=
+ *      "http://www.kernel.org/pub/software/scm/git/docs/git-submodule.html"
  *      >Git documentation about submodules</a>
  */
 public class SubmoduleInitCommand extends GitCommand<Collection<String>> {
@@ -72,9 +72,12 @@ public class SubmoduleInitCommand extends GitCommand<Collection<String>> {
 	private final Collection<String> paths;
 
 	/**
+	 * Constructor for SubmoduleInitCommand.
+	 *
 	 * @param repo
+	 *            a {@link org.eclipse.jgit.lib.Repository} object.
 	 */
-	public SubmoduleInitCommand(final Repository repo) {
+	public SubmoduleInitCommand(Repository repo) {
 		super(repo);
 		paths = new ArrayList<>();
 	}
@@ -86,11 +89,12 @@ public SubmoduleInitCommand(final Repository repo) {
 	 *            (with <code>/</code> as separator)
 	 * @return this command
 	 */
-	public SubmoduleInitCommand addPath(final String path) {
+	public SubmoduleInitCommand addPath(String path) {
 		paths.add(path);
 		return this;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public Collection<String> call() throws GitAPIException {
 		checkCallable();
@@ -106,16 +110,17 @@ public Collection<String> call() throws GitAPIException {
 					continue;
 
 				String path = generator.getPath();
+				String name = generator.getModuleName();
 				// Copy 'url' and 'update' fields from .gitmodules to config
 				// file
 				String url = generator.getRemoteUrl();
 				String update = generator.getModulesUpdate();
 				if (url != null)
 					config.setString(ConfigConstants.CONFIG_SUBMODULE_SECTION,
-							path, ConfigConstants.CONFIG_KEY_URL, url);
+							name, ConfigConstants.CONFIG_KEY_URL, url);
 				if (update != null)
 					config.setString(ConfigConstants.CONFIG_SUBMODULE_SECTION,
-							path, ConfigConstants.CONFIG_KEY_UPDATE, update);
+							name, ConfigConstants.CONFIG_KEY_UPDATE, update);
 				if (url != null || update != null)
 					initialized.add(path);
 			}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleStatusCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleStatusCommand.java
index 8b27e4c..0606c5b 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleStatusCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleStatusCommand.java
@@ -62,8 +62,8 @@
 /**
  * A class used to execute a submodule status command.
  *
- * @see <a
- *      href="http://www.kernel.org/pub/software/scm/git/docs/git-submodule.html"
+ * @see <a href=
+ *      "http://www.kernel.org/pub/software/scm/git/docs/git-submodule.html"
  *      >Git documentation about submodules</a>
  */
 public class SubmoduleStatusCommand extends
@@ -72,9 +72,12 @@ public class SubmoduleStatusCommand extends
 	private final Collection<String> paths;
 
 	/**
+	 * Constructor for SubmoduleStatusCommand.
+	 *
 	 * @param repo
+	 *            a {@link org.eclipse.jgit.lib.Repository} object.
 	 */
-	public SubmoduleStatusCommand(final Repository repo) {
+	public SubmoduleStatusCommand(Repository repo) {
 		super(repo);
 		paths = new ArrayList<>();
 	}
@@ -86,11 +89,12 @@ public SubmoduleStatusCommand(final Repository repo) {
 	 *            (with <code>/</code> as separator)
 	 * @return this command
 	 */
-	public SubmoduleStatusCommand addPath(final String path) {
+	public SubmoduleStatusCommand addPath(String path) {
 		paths.add(path);
 		return this;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public Map<String, SubmoduleStatus> call() throws GitAPIException {
 		checkCallable();
@@ -126,16 +130,14 @@ private SubmoduleStatus getStatus(SubmoduleWalk generator)
 					id);
 
 		// Report uninitialized if no submodule repository
-		Repository subRepo = generator.getRepository();
-		if (subRepo == null)
-			return new SubmoduleStatus(SubmoduleStatusType.UNINITIALIZED, path,
-					id);
+		ObjectId headId = null;
+		try (Repository subRepo = generator.getRepository()) {
+			if (subRepo == null) {
+				return new SubmoduleStatus(SubmoduleStatusType.UNINITIALIZED,
+						path, id);
+			}
 
-		ObjectId headId;
-		try {
 			headId = subRepo.resolve(Constants.HEAD);
-		} finally {
-			subRepo.close();
 		}
 
 		// Report uninitialized if no HEAD commit in submodule repository
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleSyncCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleSyncCommand.java
index b5c0b15..7cf4b73 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleSyncCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleSyncCommand.java
@@ -65,8 +65,8 @@
  * This will set the remote URL in a submodule's repository to the current value
  * in the .gitmodules file.
  *
- * @see <a
- *      href="http://www.kernel.org/pub/software/scm/git/docs/git-submodule.html"
+ * @see <a href=
+ *      "http://www.kernel.org/pub/software/scm/git/docs/git-submodule.html"
  *      >Git documentation about submodules</a>
  */
 public class SubmoduleSyncCommand extends GitCommand<Map<String, String>> {
@@ -74,9 +74,12 @@ public class SubmoduleSyncCommand extends GitCommand<Map<String, String>> {
 	private final Collection<String> paths;
 
 	/**
+	 * Constructor for SubmoduleSyncCommand.
+	 *
 	 * @param repo
+	 *            a {@link org.eclipse.jgit.lib.Repository} object.
 	 */
-	public SubmoduleSyncCommand(final Repository repo) {
+	public SubmoduleSyncCommand(Repository repo) {
 		super(repo);
 		paths = new ArrayList<>();
 	}
@@ -88,7 +91,7 @@ public SubmoduleSyncCommand(final Repository repo) {
 	 *            (with <code>/</code> as separator)
 	 * @return this command
 	 */
-	public SubmoduleSyncCommand addPath(final String path) {
+	public SubmoduleSyncCommand addPath(String path) {
 		paths.add(path);
 		return this;
 	}
@@ -97,10 +100,11 @@ public SubmoduleSyncCommand addPath(final String path) {
 	 * Get branch that HEAD currently points to
 	 *
 	 * @param subRepo
+	 *            a {@link org.eclipse.jgit.lib.Repository} object.
 	 * @return shortened branch name, null on failures
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 */
-	protected String getHeadBranch(final Repository subRepo) throws IOException {
+	protected String getHeadBranch(Repository subRepo) throws IOException {
 		Ref head = subRepo.exactRef(Constants.HEAD);
 		if (head != null && head.isSymbolic())
 			return Repository.shortenRefName(head.getLeaf().getName());
@@ -108,6 +112,7 @@ protected String getHeadBranch(final Repository subRepo) throws IOException {
 			return null;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public Map<String, String> call() throws GitAPIException {
 		checkCallable();
@@ -127,30 +132,31 @@ public Map<String, String> call() throws GitAPIException {
 						path, ConfigConstants.CONFIG_KEY_URL, remoteUrl);
 				synced.put(path, remoteUrl);
 
-				Repository subRepo = generator.getRepository();
-				if (subRepo == null)
-					continue;
+				try (Repository subRepo = generator.getRepository()) {
+					if (subRepo == null) {
+						continue;
+					}
 
-				StoredConfig subConfig;
-				String branch;
-				try {
+					StoredConfig subConfig;
+					String branch;
+
 					subConfig = subRepo.getConfig();
 					// Get name of remote associated with current branch and
 					// fall back to default remote name as last resort
 					branch = getHeadBranch(subRepo);
 					String remote = null;
-					if (branch != null)
+					if (branch != null) {
 						remote = subConfig.getString(
 								ConfigConstants.CONFIG_BRANCH_SECTION, branch,
 								ConfigConstants.CONFIG_KEY_REMOTE);
-					if (remote == null)
+					}
+					if (remote == null) {
 						remote = Constants.DEFAULT_REMOTE_NAME;
+					}
 
 					subConfig.setString(ConfigConstants.CONFIG_REMOTE_SECTION,
 							remote, ConfigConstants.CONFIG_KEY_URL, remoteUrl);
 					subConfig.save();
-				} finally {
-					subRepo.close();
 				}
 			}
 			if (!synced.isEmpty())
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleUpdateCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleUpdateCommand.java
index 4faaac2..398f21e 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleUpdateCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleUpdateCommand.java
@@ -96,9 +96,14 @@ public class SubmoduleUpdateCommand extends
 	private boolean fetch = false;
 
 	/**
+	 * <p>
+	 * Constructor for SubmoduleUpdateCommand.
+	 * </p>
+	 *
 	 * @param repo
+	 *            a {@link org.eclipse.jgit.lib.Repository} object.
 	 */
-	public SubmoduleUpdateCommand(final Repository repo) {
+	public SubmoduleUpdateCommand(Repository repo) {
 		super(repo);
 		paths = new ArrayList<>();
 	}
@@ -109,6 +114,7 @@ public SubmoduleUpdateCommand(final Repository repo) {
 	 *
 	 * @see NullProgressMonitor
 	 * @param monitor
+	 *            a {@link org.eclipse.jgit.lib.ProgressMonitor} object.
 	 * @return this command
 	 */
 	public SubmoduleUpdateCommand setProgressMonitor(
@@ -122,10 +128,11 @@ public SubmoduleUpdateCommand setProgressMonitor(
 	 * is set to <code>false</code>
 	 *
 	 * @param fetch
+	 *            whether to fetch the submodules before we update them
 	 * @return this command
 	 * @since 4.9
 	 */
-	public SubmoduleUpdateCommand setFetch(final boolean fetch) {
+	public SubmoduleUpdateCommand setFetch(boolean fetch) {
 		this.fetch = fetch;
 		return this;
 	}
@@ -137,24 +144,47 @@ public SubmoduleUpdateCommand setFetch(final boolean fetch) {
 	 *            (with <code>/</code> as separator)
 	 * @return this command
 	 */
-	public SubmoduleUpdateCommand addPath(final String path) {
+	public SubmoduleUpdateCommand addPath(String path) {
 		paths.add(path);
 		return this;
 	}
 
+	private Repository getOrCloneSubmodule(SubmoduleWalk generator, String url)
+			throws IOException, GitAPIException {
+		Repository repository = generator.getRepository();
+		if (repository == null) {
+			if (callback != null) {
+				callback.cloningSubmodule(generator.getPath());
+			}
+			CloneCommand clone = Git.cloneRepository();
+			configure(clone);
+			clone.setURI(url);
+			clone.setDirectory(generator.getDirectory());
+			clone.setGitDir(
+					new File(new File(repo.getDirectory(), Constants.MODULES),
+							generator.getPath()));
+			if (monitor != null) {
+				clone.setProgressMonitor(monitor);
+			}
+			repository = clone.call().getRepository();
+		} else if (this.fetch) {
+			if (fetchCallback != null) {
+				fetchCallback.fetchingSubmodule(generator.getPath());
+			}
+			FetchCommand fetchCommand = Git.wrap(repository).fetch();
+			if (monitor != null) {
+				fetchCommand.setProgressMonitor(monitor);
+			}
+			configure(fetchCommand);
+			fetchCommand.call();
+		}
+		return repository;
+	}
+
 	/**
-	 * Execute the SubmoduleUpdateCommand command.
+	 * {@inheritDoc}
 	 *
-	 * @return a collection of updated submodule paths
-	 * @throws ConcurrentRefUpdateException
-	 * @throws CheckoutConflictException
-	 * @throws InvalidMergeHeadsException
-	 * @throws InvalidConfigurationException
-	 * @throws NoHeadException
-	 * @throws NoMessageException
-	 * @throws RefNotFoundException
-	 * @throws WrongRepositoryStateException
-	 * @throws GitAPIException
+	 * Execute the SubmoduleUpdateCommand command.
 	 */
 	@Override
 	public Collection<String> call() throws InvalidConfigurationException,
@@ -177,34 +207,8 @@ public Collection<String> call() throws InvalidConfigurationException,
 				if (url == null)
 					continue;
 
-				Repository submoduleRepo = generator.getRepository();
-				// Clone repository if not present
-				if (submoduleRepo == null) {
-					if (callback != null) {
-						callback.cloningSubmodule(generator.getPath());
-					}
-					CloneCommand clone = Git.cloneRepository();
-					configure(clone);
-					clone.setURI(url);
-					clone.setDirectory(generator.getDirectory());
-					clone.setGitDir(new File(new File(repo.getDirectory(),
-							Constants.MODULES), generator.getPath()));
-					if (monitor != null)
-						clone.setProgressMonitor(monitor);
-					submoduleRepo = clone.call().getRepository();
-				} else if (this.fetch) {
-					if (fetchCallback != null) {
-						fetchCallback.fetchingSubmodule(generator.getPath());
-					}
-					FetchCommand fetchCommand = Git.wrap(submoduleRepo).fetch();
-					if (monitor != null) {
-						fetchCommand.setProgressMonitor(monitor);
-					}
-					configure(fetchCommand);
-					fetchCommand.call();
-				}
-
-				try (RevWalk walk = new RevWalk(submoduleRepo)) {
+				try (Repository submoduleRepo = getOrCloneSubmodule(generator,
+						url); RevWalk walk = new RevWalk(submoduleRepo)) {
 					RevCommit commit = walk
 							.parseCommit(generator.getObjectId());
 
@@ -228,6 +232,7 @@ public Collection<String> call() throws InvalidConfigurationException,
 								submoduleRepo, submoduleRepo.lockDirCache(),
 								commit.getTree());
 						co.setFailOnConflict(true);
+						co.setProgressMonitor(monitor);
 						co.checkout();
 						RefUpdate refUpdate = submoduleRepo.updateRef(
 								Constants.HEAD, true);
@@ -238,8 +243,6 @@ public Collection<String> call() throws InvalidConfigurationException,
 									generator.getPath());
 						}
 					}
-				} finally {
-					submoduleRepo.close();
 				}
 				updated.add(generator.getPath());
 			}
@@ -252,6 +255,8 @@ public Collection<String> call() throws InvalidConfigurationException,
 	}
 
 	/**
+	 * Setter for the field <code>strategy</code>.
+	 *
 	 * @param strategy
 	 *            The merge strategy to use during this update operation.
 	 * @return {@code this}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/TagCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/TagCommand.java
index bdbb862..c29b753 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/TagCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/TagCommand.java
@@ -68,7 +68,7 @@
 /**
  * Create/update an annotated tag object or a simple unannotated tag
  * <p>
- * Examples (<code>git</code> is a {@link Git} instance):
+ * Examples (<code>git</code> is a {@link org.eclipse.jgit.api.Git} instance):
  * <p>
  * Create a new tag for the current commit:
  *
@@ -104,21 +104,22 @@ public class TagCommand extends GitCommand<Ref> {
 	private boolean annotated = true;
 
 	/**
-	 * @param repo
+	 * <p>Constructor for TagCommand.</p>
+	 *
+	 * @param repo a {@link org.eclipse.jgit.lib.Repository} object.
 	 */
 	protected TagCommand(Repository repo) {
 		super(repo);
 	}
 
 	/**
+	 * {@inheritDoc}
+	 * <p>
 	 * Executes the {@code tag} command with all the options and parameters
 	 * collected by the setter methods of this class. Each instance of this
 	 * class should only be used for one invocation of the command (means: one
 	 * call to {@link #call()})
 	 *
-	 * @return a {@link Ref} a ref pointing to a tag
-	 * @throws NoHeadException
-	 *             when called on a git repo without a HEAD reference
 	 * @since 2.0
 	 */
 	@Override
@@ -226,6 +227,8 @@ private void processOptions(RepositoryState state)
 	}
 
 	/**
+	 * Set the tag <code>name</code>.
+	 *
 	 * @param name
 	 *            the tag name used for the {@code tag}
 	 * @return {@code this}
@@ -237,6 +240,8 @@ public TagCommand setName(String name) {
 	}
 
 	/**
+	 * Get the tag <code>name</code>.
+	 *
 	 * @return the tag name used for the <code>tag</code>
 	 */
 	public String getName() {
@@ -244,6 +249,8 @@ public String getName() {
 	}
 
 	/**
+	 * Get the tag <code>message</code>.
+	 *
 	 * @return the tag message used for the <code>tag</code>
 	 */
 	public String getMessage() {
@@ -251,6 +258,8 @@ public String getMessage() {
 	}
 
 	/**
+	 * Set the tag <code>message</code>.
+	 *
 	 * @param message
 	 *            the tag message used for the {@code tag}
 	 * @return {@code this}
@@ -262,6 +271,8 @@ public TagCommand setMessage(String message) {
 	}
 
 	/**
+	 * Whether this tag is signed
+	 *
 	 * @return whether the tag is signed
 	 */
 	public boolean isSigned() {
@@ -273,6 +284,7 @@ public boolean isSigned() {
 	 * corresponds to the parameter -s on the command line.
 	 *
 	 * @param signed
+	 *            a boolean.
 	 * @return {@code this}
 	 */
 	public TagCommand setSigned(boolean signed) {
@@ -285,6 +297,7 @@ public TagCommand setSigned(boolean signed) {
 	 * created from the info in the repository.
 	 *
 	 * @param tagger
+	 *            a {@link org.eclipse.jgit.lib.PersonIdent} object.
 	 * @return {@code this}
 	 */
 	public TagCommand setTagger(PersonIdent tagger) {
@@ -293,6 +306,8 @@ public TagCommand setTagger(PersonIdent tagger) {
 	}
 
 	/**
+	 * Get the <code>tagger</code> who created the tag.
+	 *
 	 * @return the tagger of the tag
 	 */
 	public PersonIdent getTagger() {
@@ -300,6 +315,8 @@ public PersonIdent getTagger() {
 	}
 
 	/**
+	 * Get the tag's object id
+	 *
 	 * @return the object id of the tag
 	 */
 	public RevObject getObjectId() {
@@ -311,6 +328,7 @@ public RevObject getObjectId() {
 	 * pointed to from HEAD will be used.
 	 *
 	 * @param id
+	 *            a {@link org.eclipse.jgit.revwalk.RevObject} object.
 	 * @return {@code this}
 	 */
 	public TagCommand setObjectId(RevObject id) {
@@ -319,6 +337,8 @@ public TagCommand setObjectId(RevObject id) {
 	}
 
 	/**
+	 * Whether this is a forced update
+	 *
 	 * @return is this a force update
 	 */
 	public boolean isForceUpdate() {
@@ -330,6 +350,7 @@ public boolean isForceUpdate() {
 	 * corresponds to the parameter -f on the command line.
 	 *
 	 * @param forceUpdate
+	 *            whether this is a forced update
 	 * @return {@code this}
 	 */
 	public TagCommand setForceUpdate(boolean forceUpdate) {
@@ -338,7 +359,10 @@ public TagCommand setForceUpdate(boolean forceUpdate) {
 	}
 
 	/**
+	 * Configure this tag to be created as an annotated tag
+	 *
 	 * @param annotated
+	 *            whether this shall be an annotated tag
 	 * @return {@code this}
 	 * @since 3.0
 	 */
@@ -348,6 +372,8 @@ public TagCommand setAnnotated(boolean annotated) {
 	}
 
 	/**
+	 * Whether this will create an annotated command
+	 *
 	 * @return true if this command will create an annotated tag (default is
 	 *         true)
 	 * @since 3.0
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/TransportCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/TransportCommand.java
index 1541df5..d34bb5d 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/TransportCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/TransportCommand.java
@@ -47,11 +47,12 @@
 import org.eclipse.jgit.transport.Transport;
 
 /**
- * Base class for commands that use a {@link Transport} during execution.
+ * Base class for commands that use a
+ * {@link org.eclipse.jgit.transport.Transport} during execution.
  * <p>
  * This class provides standard configuration of a transport for options such as
- * a {@link CredentialsProvider}, a timeout, and a
- * {@link TransportConfigCallback}.
+ * a {@link org.eclipse.jgit.transport.CredentialsProvider}, a timeout, and a
+ * {@link org.eclipse.jgit.api.TransportConfigCallback}.
  *
  * @param <C>
  * @param <T>
@@ -75,16 +76,21 @@ public abstract class TransportCommand<C extends GitCommand, T> extends
 	protected TransportConfigCallback transportConfigCallback;
 
 	/**
-	 * @param repo
+	 * <p>Constructor for TransportCommand.</p>
+	 *
+	 * @param repo a {@link org.eclipse.jgit.lib.Repository} object.
 	 */
-	protected TransportCommand(final Repository repo) {
+	protected TransportCommand(Repository repo) {
 		super(repo);
 		setCredentialsProvider(CredentialsProvider.getDefault());
 	}
 
 	/**
+	 * Set the <code>credentialsProvider</code>.
+	 *
 	 * @param credentialsProvider
-	 *            the {@link CredentialsProvider} to use
+	 *            the {@link org.eclipse.jgit.transport.CredentialsProvider} to
+	 *            use
 	 * @return {@code this}
 	 */
 	public C setCredentialsProvider(
@@ -94,6 +100,8 @@ public C setCredentialsProvider(
 	}
 
 	/**
+	 * Set <code>timeout</code>.
+	 *
 	 * @param timeout
 	 *            the timeout (in seconds) used for the transport step
 	 * @return {@code this}
@@ -104,12 +112,15 @@ public C setTimeout(int timeout) {
 	}
 
 	/**
+	 * Set the <code>TransportConfigCallback</code>.
+	 *
 	 * @param transportConfigCallback
 	 *            if set, the callback will be invoked after the
-	 *            {@link Transport} has created, but before the
-	 *            {@link Transport} is used. The callback can use this
-	 *            opportunity to set additional type-specific configuration on
-	 *            the {@link Transport} instance.
+	 *            {@link org.eclipse.jgit.transport.Transport} has created, but
+	 *            before the {@link org.eclipse.jgit.transport.Transport} is
+	 *            used. The callback can use this opportunity to set additional
+	 *            type-specific configuration on the
+	 *            {@link org.eclipse.jgit.transport.Transport} instance.
 	 * @return {@code this}
 	 */
 	public C setTransportConfigCallback(
@@ -118,7 +129,11 @@ public C setTransportConfigCallback(
 		return self();
 	}
 
-	/** @return {@code this} */
+	/**
+	 * Return this command cast to {@code C}
+	 *
+	 * @return {@code this} cast to {@code C}
+	 */
 	@SuppressWarnings("unchecked")
 	protected final C self() {
 		return (C) this;
@@ -129,9 +144,10 @@ protected final C self() {
 	 * callback
 	 *
 	 * @param transport
+	 *            a {@link org.eclipse.jgit.transport.Transport} object.
 	 * @return {@code this}
 	 */
-	protected C configure(final Transport transport) {
+	protected C configure(Transport transport) {
 		if (credentialsProvider != null)
 			transport.setCredentialsProvider(credentialsProvider);
 		transport.setTimeout(timeout);
@@ -145,9 +161,10 @@ protected C configure(final Transport transport) {
 	 * {@code this} command
 	 *
 	 * @param childCommand
+	 *            a {@link org.eclipse.jgit.api.TransportCommand} object.
 	 * @return {@code this}
 	 */
-	protected C configure(final TransportCommand childCommand) {
+	protected C configure(TransportCommand childCommand) {
 		childCommand.setCredentialsProvider(credentialsProvider);
 		childCommand.setTimeout(timeout);
 		childCommand.setTransportConfigCallback(transportConfigCallback);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/TransportConfigCallback.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/TransportConfigCallback.java
index 4faadba..f60926c 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/TransportConfigCallback.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/TransportConfigCallback.java
@@ -64,7 +64,9 @@ public interface TransportConfigCallback {
 
 	/**
 	 * Add any additional transport-specific configuration required.
+	 *
 	 * @param transport
+	 *            a {@link org.eclipse.jgit.transport.Transport} object.
 	 */
 	public void configure(Transport transport);
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/AbortedByHookException.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/AbortedByHookException.java
old mode 100755
new mode 100644
index 995611e..db6440b
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/AbortedByHookException.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/AbortedByHookException.java
@@ -67,6 +67,8 @@ public class AbortedByHookException extends GitAPIException {
 	private final int returnCode;
 
 	/**
+	 * Constructor for AbortedByHookException
+	 *
 	 * @param message
 	 *            The error details.
 	 * @param hookName
@@ -83,6 +85,8 @@ public AbortedByHookException(String message, String hookName,
 	}
 
 	/**
+	 * Get hook name
+	 *
 	 * @return the type of the hook that interrupted the git command.
 	 */
 	public String getHookName() {
@@ -90,12 +94,15 @@ public String getHookName() {
 	}
 
 	/**
+	 * Get return code
+	 *
 	 * @return the hook process result.
 	 */
 	public int getReturnCode() {
 		return returnCode;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public String getMessage() {
 		return MessageFormat.format(JGitText.get().commandRejectedByHook,
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/CanceledException.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/CanceledException.java
index 3ad2597..5f831e4 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/CanceledException.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/CanceledException.java
@@ -45,7 +45,9 @@ public class CanceledException extends GitAPIException {
 	private static final long serialVersionUID = 1L;
 
 	/**
-	 * @param message
+	 * <p>Constructor for CanceledException.</p>
+	 *
+	 * @param message a {@link java.lang.String} object.
 	 */
 	public CanceledException(String message) {
 		super(message);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/CannotDeleteCurrentBranchException.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/CannotDeleteCurrentBranchException.java
index 76d7732..65e05a1 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/CannotDeleteCurrentBranchException.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/CannotDeleteCurrentBranchException.java
@@ -44,8 +44,10 @@ public class CannotDeleteCurrentBranchException extends GitAPIException {
 	private static final long serialVersionUID = 1L;
 
 	/**
+	 * Constructor for CannotDeleteCurrentBranchException
+	 *
 	 * @param message
-	 *            the message
+	 *            error message
 	 */
 	public CannotDeleteCurrentBranchException(String message) {
 		super(message);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/CheckoutConflictException.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/CheckoutConflictException.java
index 7df35c9..3b71373 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/CheckoutConflictException.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/CheckoutConflictException.java
@@ -53,7 +53,6 @@ public class CheckoutConflictException extends GitAPIException {
 	 *
 	 * @param conflictingPaths
 	 *            list of conflicting paths
-	 *
 	 * @param e
 	 *            a {@link org.eclipse.jgit.errors.CheckoutConflictException}
 	 *            exception
@@ -82,7 +81,11 @@ public CheckoutConflictException(List<String> conflictingPaths,
 		this.conflictingPaths = conflictingPaths;
 	}
 
-	/** @return all the paths where unresolved conflicts have been detected */
+	/**
+	 * Get conflicting paths
+	 *
+	 * @return all the paths where unresolved conflicts have been detected
+	 */
 	public List<String> getConflictingPaths() {
 		return conflictingPaths;
 	}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/ConcurrentRefUpdateException.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/ConcurrentRefUpdateException.java
index b5e87f1..514d65e 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/ConcurrentRefUpdateException.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/ConcurrentRefUpdateException.java
@@ -55,10 +55,16 @@ public class ConcurrentRefUpdateException extends GitAPIException {
 	private Ref ref;
 
 	/**
+	 * Constructor for ConcurrentRefUpdateException.
+	 *
 	 * @param message
+	 *            error message
 	 * @param ref
+	 *            a {@link org.eclipse.jgit.lib.Ref}
 	 * @param rc
+	 *            a {@link org.eclipse.jgit.lib.RefUpdate.Result}
 	 * @param cause
+	 *            a {@link java.lang.Throwable}
 	 */
 	public ConcurrentRefUpdateException(String message, Ref ref,
 			RefUpdate.Result rc, Throwable cause) {
@@ -69,9 +75,14 @@ public ConcurrentRefUpdateException(String message, Ref ref,
 	}
 
 	/**
+	 * Constructor for ConcurrentRefUpdateException.
+	 *
 	 * @param message
+	 *            error message
 	 * @param ref
+	 *            a {@link org.eclipse.jgit.lib.Ref}
 	 * @param rc
+	 *            a {@link org.eclipse.jgit.lib.RefUpdate.Result}
 	 */
 	public ConcurrentRefUpdateException(String message, Ref ref,
 			RefUpdate.Result rc) {
@@ -82,15 +93,21 @@ public ConcurrentRefUpdateException(String message, Ref ref,
 	}
 
 	/**
-	 * @return the {@link Ref} which was tried to by updated
+	 * Get <code>Ref</code>
+	 *
+	 * @return the {@link org.eclipse.jgit.lib.Ref} which was tried to by
+	 *         updated
 	 */
 	public Ref getRef() {
 		return ref;
 	}
 
 	/**
-	 * @return the result which was returned by {@link RefUpdate#update()} and
-	 *         which caused this error
+	 * Get result
+	 *
+	 * @return the result which was returned by
+	 *         {@link org.eclipse.jgit.lib.RefUpdate#update()} and which caused
+	 *         this error
 	 */
 	public RefUpdate.Result getResult() {
 		return rc;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/DetachedHeadException.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/DetachedHeadException.java
index 01b1f31..30b5853 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/DetachedHeadException.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/DetachedHeadException.java
@@ -55,15 +55,22 @@ public DetachedHeadException() {
 	}
 
 	/**
+	 * Constructor for DetachedHeadException.
+	 *
 	 * @param message
+	 *            error message
 	 * @param cause
+	 *            a {@link java.lang.Throwable} object.
 	 */
 	public DetachedHeadException(String message, Throwable cause) {
 		super(message, cause);
 	}
 
 	/**
+	 * Constructor for DetachedHeadException.
+	 *
 	 * @param message
+	 *            error message
 	 */
 	public DetachedHeadException(String message) {
 		super(message);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/EmtpyCommitException.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/EmptyCommitException.java
similarity index 85%
rename from org.eclipse.jgit/src/org/eclipse/jgit/api/errors/EmtpyCommitException.java
rename to org.eclipse.jgit/src/org/eclipse/jgit/api/errors/EmptyCommitException.java
index b3cc1bf..87e1a6a 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/EmtpyCommitException.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/EmptyCommitException.java
@@ -40,23 +40,30 @@
 /**
  * Exception thrown when a newly created commit does not contain any changes
  *
- * @since 4.2
+ * @since 5.0
  */
-public class EmtpyCommitException extends GitAPIException {
+public class EmptyCommitException extends GitAPIException {
 	private static final long serialVersionUID = 1L;
 
 	/**
+	 * Constructor for EmptyCommitException
+	 *
 	 * @param message
+	 *            error message
 	 * @param cause
+	 *            a {@link java.lang.Throwable}
 	 */
-	public EmtpyCommitException(String message, Throwable cause) {
+	public EmptyCommitException(String message, Throwable cause) {
 		super(message, cause);
 	}
 
 	/**
+	 * Constructor for EmptyCommitException.
+	 *
 	 * @param message
+	 *            error message
 	 */
-	public EmtpyCommitException(String message) {
+	public EmptyCommitException(String message) {
 		super(message);
 	}
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/FilterFailedException.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/FilterFailedException.java
index fbc30ef..f07e79f 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/FilterFailedException.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/FilterFailedException.java
@@ -106,6 +106,8 @@ public FilterFailedException(int rc, String filterCommand, String path,
 	}
 
 	/**
+	 * Get filter command
+	 *
 	 * @return the filterCommand
 	 */
 	public String getFilterCommand() {
@@ -113,6 +115,8 @@ public String getFilterCommand() {
 	}
 
 	/**
+	 * Get path
+	 *
 	 * @return the path of the file processed by the filter command
 	 */
 	public String getPath() {
@@ -120,6 +124,8 @@ public String getPath() {
 	}
 
 	/**
+	 * Get output
+	 *
 	 * @return the output generated by the filter command. Might be truncated to
 	 *         limit memory consumption.
 	 */
@@ -128,6 +134,8 @@ public String getPath() {
 	}
 
 	/**
+	 * Get error
+	 *
 	 * @return the error output returned by the filter command
 	 */
 	public String getError() {
@@ -135,6 +143,8 @@ public String getError() {
 	}
 
 	/**
+	 * Get return code
+	 *
 	 * @return the return code returned by the filter command
 	 */
 	public int getReturnCode() {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/GitAPIException.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/GitAPIException.java
index b251c7d..a2d6996 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/GitAPIException.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/GitAPIException.java
@@ -40,7 +40,6 @@
 /**
  * Superclass of all exceptions thrown by the API classes in
  * {@code org.eclipse.jgit.api}
- *
  */
 public abstract class GitAPIException extends Exception {
 	private static final long serialVersionUID = 1L;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/InvalidConfigurationException.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/InvalidConfigurationException.java
index cb89e46..e99bfb1 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/InvalidConfigurationException.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/InvalidConfigurationException.java
@@ -45,15 +45,22 @@ public class InvalidConfigurationException extends GitAPIException {
 	private static final long serialVersionUID = 1L;
 
 	/**
+	 * Constructor for InvalidConfigurationException
+	 *
 	 * @param message
+	 *            error message
 	 * @param cause
+	 *            a {@link java.lang.Throwable}
 	 */
 	public InvalidConfigurationException(String message, Throwable cause) {
 		super(message, cause);
 	}
 
 	/**
+	 * Constructor for InvalidConfigurationException.
+	 *
 	 * @param message
+	 *            error message
 	 */
 	public InvalidConfigurationException(String message) {
 		super(message);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/InvalidMergeHeadsException.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/InvalidMergeHeadsException.java
index c8edb57..9fbdce5 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/InvalidMergeHeadsException.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/InvalidMergeHeadsException.java
@@ -47,7 +47,10 @@ public class InvalidMergeHeadsException extends GitAPIException {
 	private static final long serialVersionUID = 1L;
 
 	/**
+	 * Constructor for InvalidMergeHeadsException.
+	 *
 	 * @param msg
+	 *            error message
 	 */
 	public InvalidMergeHeadsException(String msg) {
 		super(msg);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/InvalidRebaseStepException.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/InvalidRebaseStepException.java
index ef89a98..1f03286 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/InvalidRebaseStepException.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/InvalidRebaseStepException.java
@@ -45,16 +45,24 @@
  */
 public class InvalidRebaseStepException extends GitAPIException {
 	private static final long serialVersionUID = 1L;
+
 	/**
+	 * Constructor for InvalidRebaseStepException.
+	 *
 	 * @param msg
+	 *            error message
 	 */
 	public InvalidRebaseStepException(String msg) {
 		super(msg);
 	}
 
 	/**
+	 * Constructor for InvalidRebaseStepException.
+	 *
 	 * @param msg
+	 *            error message
 	 * @param cause
+	 *            a {@link java.lang.Throwable}
 	 */
 	public InvalidRebaseStepException(String msg, Throwable cause) {
 		super(msg, cause);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/InvalidRefNameException.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/InvalidRefNameException.java
index 287713c..552c148 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/InvalidRefNameException.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/InvalidRefNameException.java
@@ -44,15 +44,22 @@ public class InvalidRefNameException extends GitAPIException {
 	private static final long serialVersionUID = 1L;
 
 	/**
+	 * Constructor for InvalidRefNameException
+	 *
 	 * @param msg
+	 *            error message
 	 */
 	public InvalidRefNameException(String msg) {
 		super(msg);
 	}
 
 	/**
+	 * Constructor for InvalidRefNameException.
+	 *
 	 * @param msg
+	 *            error message
 	 * @param cause
+	 *            a {@link java.lang.Throwable}
 	 */
 	public InvalidRefNameException(String msg, Throwable cause) {
 		super(msg, cause);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/InvalidRemoteException.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/InvalidRemoteException.java
index 3f059b7..4db5022 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/InvalidRemoteException.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/InvalidRemoteException.java
@@ -44,15 +44,22 @@ public class InvalidRemoteException extends GitAPIException {
 	private static final long serialVersionUID = 1L;
 
 	/**
-	 * @param msg message describing the invalid remote.
+	 * Constructor for InvalidRemoteException
+	 *
+	 * @param msg
+	 *            message describing the invalid remote.
 	 */
 	public InvalidRemoteException(String msg) {
 		super(msg);
 	}
 
 	/**
-	 * @param msg message describing the invalid remote.
-	 * @param cause why the remote is invalid.
+	 * Constructor for InvalidRemoteException
+	 *
+	 * @param msg
+	 *            message describing the invalid remote.
+	 * @param cause
+	 *            why the remote is invalid.
 	 */
 	public InvalidRemoteException(String msg, Throwable cause) {
 		super(msg, cause);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/InvalidTagNameException.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/InvalidTagNameException.java
index 1779c45..72ba0c3 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/InvalidTagNameException.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/InvalidTagNameException.java
@@ -45,7 +45,10 @@ public class InvalidTagNameException extends GitAPIException {
 	private static final long serialVersionUID = 1L;
 
 	/**
+	 * Constructor for InvalidTagNameException.
+	 *
 	 * @param msg
+	 *            error message
 	 */
 	public InvalidTagNameException(String msg) {
 		super(msg);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/JGitInternalException.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/JGitInternalException.java
index ca56200..57d8a13 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/JGitInternalException.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/JGitInternalException.java
@@ -63,7 +63,9 @@ public class JGitInternalException extends RuntimeException {
 	 * Construct an exception for low-level internal exceptions
 	 *
 	 * @param message
+	 *            error message
 	 * @param cause
+	 *            a {@link java.lang.Throwable}
 	 */
 	public JGitInternalException(String message, Throwable cause) {
 		super(message, cause);
@@ -73,6 +75,7 @@ public JGitInternalException(String message, Throwable cause) {
 	 * Construct an exception for low-level internal exceptions
 	 *
 	 * @param message
+	 *            error message
 	 */
 	public JGitInternalException(String message) {
 		super(message);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/MultipleParentsNotAllowedException.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/MultipleParentsNotAllowedException.java
index c71cc04..5067272 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/MultipleParentsNotAllowedException.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/MultipleParentsNotAllowedException.java
@@ -49,15 +49,22 @@ public class MultipleParentsNotAllowedException extends GitAPIException {
 	private static final long serialVersionUID = 1L;
 
 	/**
+	 * Constructor for MultipleParentsNotAllowedException.
+	 *
 	 * @param message
+	 *            error message
 	 * @param cause
+	 *            a {@link java.lang.Throwable}
 	 */
 	public MultipleParentsNotAllowedException(String message, Throwable cause) {
 		super(message, cause);
 	}
 
 	/**
+	 * Constructor for MultipleParentsNotAllowedException.
+	 *
 	 * @param message
+	 *            error message
 	 */
 	public MultipleParentsNotAllowedException(String message) {
 		super(message);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/NoFilepatternException.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/NoFilepatternException.java
index 1130c25..893bf65 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/NoFilepatternException.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/NoFilepatternException.java
@@ -48,15 +48,22 @@ public class NoFilepatternException extends GitAPIException {
 	private static final long serialVersionUID = 1L;
 
 	/**
+	 * Constructor for NoFilepatternException.
+	 *
 	 * @param message
+	 *            error message
 	 * @param cause
+	 *            a {@link java.lang.Throwable}
 	 */
 	public NoFilepatternException(String message, Throwable cause) {
 		super(message, cause);
 	}
 
 	/**
+	 * Constructor for NoFilepatternException.
+	 *
 	 * @param message
+	 *            error message
 	 */
 	public NoFilepatternException(String message) {
 		super(message);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/NoHeadException.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/NoHeadException.java
index 50c4dc9..43dbc41 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/NoHeadException.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/NoHeadException.java
@@ -45,15 +45,22 @@ public class NoHeadException extends GitAPIException {
 	private static final long serialVersionUID = 1L;
 
 	/**
+	 * Constructor for NoHeadException
+	 *
 	 * @param message
+	 *            error message
 	 * @param cause
+	 *            a {@link java.lang.Throwable}
 	 */
 	public NoHeadException(String message, Throwable cause) {
 		super(message, cause);
 	}
 
 	/**
+	 * Constructor for NoHeadException
+	 *
 	 * @param message
+	 *            error message
 	 */
 	public NoHeadException(String message) {
 		super(message);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/NoMessageException.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/NoMessageException.java
index b7d8dc8..fa6e791 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/NoMessageException.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/NoMessageException.java
@@ -47,15 +47,22 @@ public class NoMessageException extends GitAPIException {
 	private static final long serialVersionUID = 1L;
 
 	/**
+	 * Constructor for NoMessageException
+	 *
 	 * @param message
+	 *            error message
 	 * @param cause
+	 *            a {@link java.lang.Throwable}
 	 */
 	public NoMessageException(String message, Throwable cause) {
 		super(message, cause);
 	}
 
 	/**
+	 * Constructor for NoMessageException
+	 *
 	 * @param message
+	 *            error message
 	 */
 	public NoMessageException(String message) {
 		super(message);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/PatchApplyException.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/PatchApplyException.java
index 4329860..6957dca 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/PatchApplyException.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/PatchApplyException.java
@@ -46,21 +46,27 @@
  * Exception thrown when applying a patch fails
  *
  * @since 2.0
- *
  */
 public class PatchApplyException extends GitAPIException {
 	private static final long serialVersionUID = 1L;
 
 	/**
+	 * Constructor for PatchApplyException
+	 *
 	 * @param message
+	 *            error message
 	 * @param cause
+	 *            a {@link java.lang.Throwable}
 	 */
 	public PatchApplyException(String message, Throwable cause) {
 		super(message, cause);
 	}
 
 	/**
+	 * Constructor for PatchApplyException
+	 *
 	 * @param message
+	 *            error message
 	 */
 	public PatchApplyException(String message) {
 		super(message);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/PatchFormatException.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/PatchFormatException.java
index 02ab423..e10b8b4 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/PatchFormatException.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/PatchFormatException.java
@@ -52,7 +52,6 @@
  * Exception thrown when applying a patch fails due to an invalid format
  *
  * @since 2.0
- *
  */
 public class PatchFormatException extends GitAPIException {
 	private static final long serialVersionUID = 1L;
@@ -60,7 +59,10 @@ public class PatchFormatException extends GitAPIException {
 	private List<FormatError> errors;
 
 	/**
+	 * Constructor for PatchFormatException
+	 *
 	 * @param errors
+	 *            a {@link java.util.List} of {@link FormatError}s
 	 */
 	public PatchFormatException(List<FormatError> errors) {
 		super(MessageFormat.format(JGitText.get().patchFormatException, errors));
@@ -68,6 +70,8 @@ public PatchFormatException(List<FormatError> errors) {
 	}
 
 	/**
+	 * Get list of errors
+	 *
 	 * @return all the errors where unresolved conflicts have been detected
 	 */
 	public List<FormatError> getErrors() {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/RefAlreadyExistsException.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/RefAlreadyExistsException.java
index 837028c..7e39361 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/RefAlreadyExistsException.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/RefAlreadyExistsException.java
@@ -37,17 +37,18 @@
  */
 package org.eclipse.jgit.api.errors;
 
-import org.eclipse.jgit.lib.Ref;
-
 /**
- * Thrown when trying to create a {@link Ref} with the same name as an existing
- * one
+ * Thrown when trying to create a {@link org.eclipse.jgit.lib.Ref} with the same
+ * name as an existing one
  */
 public class RefAlreadyExistsException extends GitAPIException {
 	private static final long serialVersionUID = 1L;
 
 	/**
+	 * Constructor for RefAlreadyExistsException
+	 *
 	 * @param message
+	 *            error message
 	 */
 	public RefAlreadyExistsException(String message) {
 		super(message);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/RefNotAdvertisedException.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/RefNotAdvertisedException.java
index 2bd8477..b52cd58 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/RefNotAdvertisedException.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/RefNotAdvertisedException.java
@@ -46,7 +46,10 @@ public class RefNotAdvertisedException extends GitAPIException {
 	private static final long serialVersionUID = 1L;
 
 	/**
+	 * Constructor for RefNotAdvertisedException
+	 *
 	 * @param message
+	 *            error message
 	 */
 	public RefNotAdvertisedException(String message) {
 		super(message);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/RefNotFoundException.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/RefNotFoundException.java
index b9f2a56..406fa45 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/RefNotFoundException.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/RefNotFoundException.java
@@ -44,8 +44,12 @@ public class RefNotFoundException extends GitAPIException {
 	private static final long serialVersionUID = 1L;
 
 	/**
+	 * Constructor for RefNotFoundException
+	 *
 	 * @param message
+	 *            error message
 	 * @param cause
+	 *            a {@link java.lang.Throwable}
 	 * @since 4.1
 	 */
 	public RefNotFoundException(String message, Throwable cause) {
@@ -53,7 +57,10 @@ public RefNotFoundException(String message, Throwable cause) {
 	}
 
 	/**
+	 * Constructor for RefNotFoundException
+	 *
 	 * @param message
+	 *            error message
 	 */
 	public RefNotFoundException(String message) {
 		super(message);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/StashApplyFailureException.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/StashApplyFailureException.java
index 222c1db..b12c032 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/StashApplyFailureException.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/StashApplyFailureException.java
@@ -8,8 +8,12 @@ public class StashApplyFailureException extends GitAPIException {
 	private static final long serialVersionUID = 1L;
 
 	/**
+	 * Constructor for StashApplyFailureException
+	 *
 	 * @param message
+	 *            error message
 	 * @param cause
+	 *            a {@link java.lang.Throwable}
 	 * @since 4.1
 	 */
 	public StashApplyFailureException(String message, Throwable cause) {
@@ -20,8 +24,9 @@ public StashApplyFailureException(String message, Throwable cause) {
 	 * Create a StashApplyFailedException
 	 *
 	 * @param message
+	 *            error message
 	 */
-	public StashApplyFailureException(final String message) {
+	public StashApplyFailureException(String message) {
 		super(message);
 	}
 
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/TooLargeObjectInPackException.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/TooLargeObjectInPackException.java
index b841f57..ceaa6b2 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/TooLargeObjectInPackException.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/TooLargeObjectInPackException.java
@@ -47,6 +47,8 @@ public class TooLargeObjectInPackException extends TransportException {
 	private static final long serialVersionUID = 1L;
 
 	/**
+	 * Constructor for TooLargeObjectInPackException
+	 *
 	 * @param msg
 	 *            message describing the transport failure.
 	 */
@@ -55,6 +57,8 @@ public TooLargeObjectInPackException(String msg) {
 	}
 
 	/**
+	 * Constructor for TooLargeObjectInPackException
+	 *
 	 * @param msg
 	 *            message describing the transport exception.
 	 * @param cause
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/TooLargePackException.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/TooLargePackException.java
index 3833054..462b701 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/TooLargePackException.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/TooLargePackException.java
@@ -46,6 +46,8 @@ public class TooLargePackException extends TransportException {
 	private static final long serialVersionUID = 1L;
 
 	/**
+	 * Constructor for TooLargePackException
+	 *
 	 * @param msg
 	 *            message describing the transport failure.
 	 */
@@ -54,6 +56,8 @@ public TooLargePackException(String msg) {
 	}
 
 	/**
+	 * Constructor for TooLargePackException
+	 *
 	 * @param msg
 	 *            message describing the transport exception.
 	 * @param cause
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/TransportException.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/TransportException.java
index 9f0e2fb..5569928 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/TransportException.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/TransportException.java
@@ -44,6 +44,8 @@ public class TransportException extends GitAPIException {
 	private static final long serialVersionUID = 1L;
 
 	/**
+	 * Constructor for TransportException
+	 *
 	 * @param msg
 	 *            message describing the transport failure.
 	 */
@@ -52,6 +54,8 @@ public TransportException(String msg) {
 	}
 
 	/**
+	 * Constructor for TransportException
+	 *
 	 * @param msg
 	 *            message describing the transport exception.
 	 * @param cause
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/UnmergedPathsException.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/UnmergedPathsException.java
index 082f94c..9d6318e 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/UnmergedPathsException.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/UnmergedPathsException.java
@@ -63,8 +63,12 @@ public UnmergedPathsException(Throwable cause) {
 	}
 
 	/**
+	 * Constructor for UnmergedPathsException
+	 *
 	 * @param message
+	 *            the message
 	 * @param cause
+	 *            a {@link java.lang.Throwable}
 	 * @since 4.1
 	 */
 	public UnmergedPathsException(String message, Throwable cause) {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/WrongRepositoryStateException.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/WrongRepositoryStateException.java
index dd2b399..4b58711 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/WrongRepositoryStateException.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/WrongRepositoryStateException.java
@@ -46,15 +46,22 @@ public class WrongRepositoryStateException extends GitAPIException {
 	private static final long serialVersionUID = 1L;
 
 	/**
+	 * Constructor for WrongRepositoryStateException.
+	 *
 	 * @param message
+	 *            error message
 	 * @param cause
+	 *            a {@link java.lang.Throwable}
 	 */
 	public WrongRepositoryStateException(String message, Throwable cause) {
 		super(message, cause);
 	}
 
 	/**
+	 * Constructor for WrongRepositoryStateException.
+	 *
 	 * @param message
+	 *            error message
 	 */
 	public WrongRepositoryStateException(String message) {
 		super(message);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/attributes/Attribute.java b/org.eclipse.jgit/src/org/eclipse/jgit/attributes/Attribute.java
index c256b73..f1df0da 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/attributes/Attribute.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/attributes/Attribute.java
@@ -47,15 +47,17 @@
  * <p>
  * According to the man page, an attribute can have the following states:
  * <ul>
- * <li>Set - represented by {@link State#SET}</li>
- * <li>Unset - represented by {@link State#UNSET}</li>
- * <li>Set to a value - represented by {@link State#CUSTOM}</li>
+ * <li>Set - represented by
+ * {@link org.eclipse.jgit.attributes.Attribute.State#SET}</li>
+ * <li>Unset - represented by
+ * {@link org.eclipse.jgit.attributes.Attribute.State#UNSET}</li>
+ * <li>Set to a value - represented by
+ * {@link org.eclipse.jgit.attributes.Attribute.State#CUSTOM}</li>
  * <li>Unspecified - used to revert an attribute . This is crucial in order to
  * mark an attribute as unspecified in the attributes map and thus preventing
  * following (with lower priority) nodes from setting the attribute to a value
  * at all</li>
  * </ul>
- * </p>
  *
  * @since 3.7
  */
@@ -93,10 +95,11 @@ public static enum State {
 	 * @param key
 	 *            the attribute key. Should not be <code>null</code>.
 	 * @param state
-	 *            the attribute state. It should be either {@link State#SET} or
-	 *            {@link State#UNSET}. In order to create a custom value
-	 *            attribute prefer the use of {@link #Attribute(String, String)}
-	 *            constructor.
+	 *            the attribute state. It should be either
+	 *            {@link org.eclipse.jgit.attributes.Attribute.State#SET} or
+	 *            {@link org.eclipse.jgit.attributes.Attribute.State#UNSET}. In
+	 *            order to create a custom value attribute prefer the use of
+	 *            {@link #Attribute(String, String)} constructor.
 	 */
 	public Attribute(String key, State state) {
 		this(key, state, null);
@@ -127,6 +130,7 @@ public Attribute(String key, String value) {
 		this(key, State.CUSTOM, value);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public boolean equals(Object obj) {
 		if (this == obj)
@@ -147,6 +151,8 @@ public boolean equals(Object obj) {
 	}
 
 	/**
+	 * Get key
+	 *
 	 * @return the attribute key (never returns <code>null</code>)
 	 */
 	public String getKey() {
@@ -154,7 +160,7 @@ public String getKey() {
 	}
 
 	/**
-	 * Returns the state.
+	 * Return the state.
 	 *
 	 * @return the state (never returns <code>null</code>)
 	 */
@@ -163,12 +169,15 @@ public State getState() {
 	}
 
 	/**
+	 * Get value
+	 *
 	 * @return the attribute value (may be <code>null</code>)
 	 */
 	public String getValue() {
 		return value;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public int hashCode() {
 		final int prime = 31;
@@ -179,6 +188,7 @@ public int hashCode() {
 		return result;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public String toString() {
 		switch (state) {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/attributes/Attributes.java b/org.eclipse.jgit/src/org/eclipse/jgit/attributes/Attributes.java
index d3826b3..125ee59 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/attributes/Attributes.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/attributes/Attributes.java
@@ -53,7 +53,6 @@
 
 /**
  * Represents a set of attributes for a path
- * <p>
  *
  * @since 4.2
  */
@@ -64,6 +63,7 @@ public final class Attributes {
 	 * Creates a new instance
 	 *
 	 * @param attributes
+	 *            a {@link org.eclipse.jgit.attributes.Attribute}
 	 */
 	public Attributes(Attribute... attributes) {
 		if (attributes != null) {
@@ -74,6 +74,8 @@ public Attributes(Attribute... attributes) {
 	}
 
 	/**
+	 * Whether the set of attributes is empty
+	 *
 	 * @return true if the set does not contain any attributes
 	 */
 	public boolean isEmpty() {
@@ -81,7 +83,10 @@ public boolean isEmpty() {
 	}
 
 	/**
+	 * Get the attribute with the given key
+	 *
 	 * @param key
+	 *            a {@link java.lang.String} object.
 	 * @return the attribute or null
 	 */
 	public Attribute get(String key) {
@@ -89,6 +94,8 @@ public Attribute get(String key) {
 	}
 
 	/**
+	 * Get all attributes
+	 *
 	 * @return all attributes
 	 */
 	public Collection<Attribute> getAll() {
@@ -96,32 +103,42 @@ public Collection<Attribute> getAll() {
 	}
 
 	/**
+	 * Put an attribute
+	 *
 	 * @param a
+	 *            an {@link org.eclipse.jgit.attributes.Attribute}
 	 */
 	public void put(Attribute a) {
 		map.put(a.getKey(), a);
 	}
 
 	/**
+	 * Remove attribute with given key
+	 *
 	 * @param key
+	 *            an attribute name
 	 */
 	public void remove(String key) {
 		map.remove(key);
 	}
 
 	/**
+	 * Whether there is an attribute with this key
+	 *
 	 * @param key
-	 * @return true if the {@link Attributes} contains this key
+	 *            key of an attribute
+	 * @return true if the {@link org.eclipse.jgit.attributes.Attributes}
+	 *         contains this key
 	 */
 	public boolean containsKey(String key) {
 		return map.containsKey(key);
 	}
 
 	/**
-	 * Returns the state.
+	 * Return the state.
 	 *
 	 * @param key
-	 *
+	 *            key of an attribute
 	 * @return the state (never returns <code>null</code>)
 	 */
 	public Attribute.State getState(String key) {
@@ -130,41 +147,63 @@ public Attribute.State getState(String key) {
 	}
 
 	/**
+	 * Whether the attribute is set
+	 *
 	 * @param key
-	 * @return true if the key is {@link State#SET}, false in all other cases
+	 *            a {@link java.lang.String} object.
+	 * @return true if the key is
+	 *         {@link org.eclipse.jgit.attributes.Attribute.State#SET}, false in
+	 *         all other cases
 	 */
 	public boolean isSet(String key) {
 		return (getState(key) == State.SET);
 	}
 
 	/**
+	 * Whether the attribute is unset
+	 *
 	 * @param key
-	 * @return true if the key is {@link State#UNSET}, false in all other cases
+	 *            a {@link java.lang.String} object.
+	 * @return true if the key is
+	 *         {@link org.eclipse.jgit.attributes.Attribute.State#UNSET}, false
+	 *         in all other cases
 	 */
 	public boolean isUnset(String key) {
 		return (getState(key) == State.UNSET);
 	}
 
 	/**
+	 * Whether the attribute with the given key is unspecified
+	 *
 	 * @param key
-	 * @return true if the key is {@link State#UNSPECIFIED}, false in all other
-	 *         cases
+	 *            a {@link java.lang.String} object.
+	 * @return true if the key is
+	 *         {@link org.eclipse.jgit.attributes.Attribute.State#UNSPECIFIED},
+	 *         false in all other cases
 	 */
 	public boolean isUnspecified(String key) {
 		return (getState(key) == State.UNSPECIFIED);
 	}
 
 	/**
+	 * Is this a custom attribute
+	 *
 	 * @param key
-	 * @return true if the key is {@link State#CUSTOM}, false in all other cases
-	 *         see {@link #getValue(String)} for the value of the key
+	 *            a {@link java.lang.String} object.
+	 * @return true if the key is
+	 *         {@link org.eclipse.jgit.attributes.Attribute.State#CUSTOM}, false
+	 *         in all other cases see {@link #getValue(String)} for the value of
+	 *         the key
 	 */
 	public boolean isCustom(String key) {
 		return (getState(key) == State.CUSTOM);
 	}
 
 	/**
+	 * Get attribute value
+	 *
 	 * @param key
+	 *            an attribute key
 	 * @return the attribute value (may be <code>null</code>)
 	 */
 	public String getValue(String key) {
@@ -192,6 +231,7 @@ && getValue(Constants.ATTR_MERGE)
 		return true;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public String toString() {
 		StringBuilder buf = new StringBuilder();
@@ -206,11 +246,13 @@ public String toString() {
 		return buf.toString();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public int hashCode() {
 		return map.hashCode();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public boolean equals(Object obj) {
 		if (this == obj)
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/attributes/AttributesHandler.java b/org.eclipse.jgit/src/org/eclipse/jgit/attributes/AttributesHandler.java
index 8d928e3..638dd82 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/attributes/AttributesHandler.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/attributes/AttributesHandler.java
@@ -61,7 +61,8 @@
  * The attributes handler knows how to retrieve, parse and merge attributes from
  * the various gitattributes files. Furthermore it collects and expands macro
  * expressions. The method {@link #getAttributes()} yields the ready processed
- * attributes for the current path represented by the {@link TreeWalk}
+ * attributes for the current path represented by the
+ * {@link org.eclipse.jgit.treewalk.TreeWalk}
  * <p>
  * The implementation is based on the specifications in
  * http://git-scm.com/docs/gitattributes
@@ -90,11 +91,13 @@ public class AttributesHandler {
 	private final Map<String, List<Attribute>> expansions = new HashMap<>();
 
 	/**
-	 * Create an {@link AttributesHandler} with default rules as well as merged
-	 * rules from global, info and worktree root attributes
+	 * Create an {@link org.eclipse.jgit.attributes.AttributesHandler} with
+	 * default rules as well as merged rules from global, info and worktree root
+	 * attributes
 	 *
 	 * @param treeWalk
-	 * @throws IOException
+	 *            a {@link org.eclipse.jgit.treewalk.TreeWalk}
+	 * @throws java.io.IOException
 	 */
 	public AttributesHandler(TreeWalk treeWalk) throws IOException {
 		this.treeWalk = treeWalk;
@@ -129,11 +132,12 @@ public AttributesHandler(TreeWalk treeWalk) throws IOException {
 	}
 
 	/**
-	 * see {@link TreeWalk#getAttributes()}
+	 * See {@link org.eclipse.jgit.treewalk.TreeWalk#getAttributes()}
 	 *
-	 * @return the {@link Attributes} for the current path represented by the
-	 *         {@link TreeWalk}
-	 * @throws IOException
+	 * @return the {@link org.eclipse.jgit.attributes.Attributes} for the
+	 *         current path represented by the
+	 *         {@link org.eclipse.jgit.treewalk.TreeWalk}
+	 * @throws java.io.IOException
 	 */
 	public Attributes getAttributes() throws IOException {
 		String entryPath = treeWalk.getPathString();
@@ -282,7 +286,10 @@ protected void mergeAttributes(@Nullable AttributesNode node,
 	}
 
 	/**
+	 * Expand a macro
+	 *
 	 * @param attr
+	 *            a {@link org.eclipse.jgit.attributes.Attribute}
 	 * @param result
 	 *            contains the (recursive) expanded and merged macro attributes
 	 *            including the attribute iself
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/attributes/AttributesNode.java b/org.eclipse.jgit/src/org/eclipse/jgit/attributes/AttributesNode.java
index 13aeaee..62bf9f2 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/attributes/AttributesNode.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/attributes/AttributesNode.java
@@ -63,7 +63,9 @@ public class AttributesNode {
 	/** The rules that have been parsed into this node. */
 	private final List<AttributesRule> rules;
 
-	/** Create an empty ignore node with no rules. */
+	/**
+	 * Create an empty ignore node with no rules.
+	 */
 	public AttributesNode() {
 		rules = new ArrayList<>();
 	}
@@ -73,7 +75,7 @@ public AttributesNode() {
 	 *
 	 * @param rules
 	 *            list of rules.
-	 **/
+	 */
 	public AttributesNode(List<AttributesRule> rules) {
 		this.rules = rules;
 	}
@@ -84,7 +86,7 @@ public AttributesNode(List<AttributesRule> rules) {
 	 * @param in
 	 *            input stream holding the standard ignore format. The caller is
 	 *            responsible for closing the stream.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             Error thrown when reading an ignore file.
 	 */
 	public void parse(InputStream in) throws IOException {
@@ -116,7 +118,11 @@ private static BufferedReader asReader(InputStream in) {
 		return new BufferedReader(new InputStreamReader(in, Constants.CHARSET));
 	}
 
-	/** @return list of all ignore rules held by this node. */
+	/**
+	 * Getter for the field <code>rules</code>.
+	 *
+	 * @return list of all ignore rules held by this node
+	 */
 	public List<AttributesRule> getRules() {
 		return Collections.unmodifiableList(rules);
 	}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/attributes/AttributesNodeProvider.java b/org.eclipse.jgit/src/org/eclipse/jgit/attributes/AttributesNodeProvider.java
index 6f2ebad..f1d7d7b 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/attributes/AttributesNodeProvider.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/attributes/AttributesNodeProvider.java
@@ -47,32 +47,32 @@
 import org.eclipse.jgit.lib.CoreConfig;
 
 /**
- * An interface used to retrieve the global and info {@link AttributesNode}s.
+ * An interface used to retrieve the global and info
+ * {@link org.eclipse.jgit.attributes.AttributesNode}s.
  *
  * @since 4.2
- *
  */
 public interface AttributesNodeProvider {
 
 	/**
-	 * Retrieve the {@link AttributesNode} that holds the information located
-	 * in $GIT_DIR/info/attributes file.
+	 * Retrieve the {@link org.eclipse.jgit.attributes.AttributesNode} that
+	 * holds the information located in $GIT_DIR/info/attributes file.
 	 *
-	 * @return the {@link AttributesNode} that holds the information located in
-	 *         $GIT_DIR/info/attributes file.
-	 * @throws IOException
+	 * @return the {@link org.eclipse.jgit.attributes.AttributesNode} that holds
+	 *         the information located in $GIT_DIR/info/attributes file.
+	 * @throws java.io.IOException
 	 *             if an error is raised while parsing the attributes file
 	 */
 	public AttributesNode getInfoAttributesNode() throws IOException;
 
 	/**
-	 * Retrieve the {@link AttributesNode} that holds the information located
-	 * in the global gitattributes file.
+	 * Retrieve the {@link org.eclipse.jgit.attributes.AttributesNode} that
+	 * holds the information located in the global gitattributes file.
 	 *
-	 * @return the {@link AttributesNode} that holds the information located in
-	 *         the global gitattributes file.
-	 * @throws IOException
-	 *             IOException if an error is raised while parsing the
+	 * @return the {@link org.eclipse.jgit.attributes.AttributesNode} that holds
+	 *         the information located in the global gitattributes file.
+	 * @throws java.io.IOException
+	 *             java.io.IOException if an error is raised while parsing the
 	 *             attributes file
 	 * @see CoreConfig#getAttributesFile()
 	 */
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/attributes/AttributesProvider.java b/org.eclipse.jgit/src/org/eclipse/jgit/attributes/AttributesProvider.java
index 1037f69..1545e35 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/attributes/AttributesProvider.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/attributes/AttributesProvider.java
@@ -49,6 +49,8 @@
  */
 public interface AttributesProvider {
 	/**
+	 * Get attributes
+	 *
 	 * @return the currently active attributes
 	 */
 	public Attributes getAttributes();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/attributes/AttributesRule.java b/org.eclipse.jgit/src/org/eclipse/jgit/attributes/AttributesRule.java
index 3cf5de8..a91d8c2 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/attributes/AttributesRule.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/attributes/AttributesRule.java
@@ -57,7 +57,7 @@
 /**
  * A single attributes rule corresponding to one line in a .gitattributes file.
  *
- * Inspiration from: {@link FastIgnoreRule}
+ * Inspiration from: {@link org.eclipse.jgit.ignore.FastIgnoreRule}
  *
  * @since 3.7
  */
@@ -162,7 +162,9 @@ public AttributesRule(String pattern, String attributes) {
 	}
 
 	/**
-	 * @return True if the pattern should match directories only
+	 * Whether to match directories only
+	 *
+	 * @return {@code true} if the pattern should match directories only
 	 * @since 4.3
 	 */
 	public boolean isDirOnly() {
@@ -170,7 +172,7 @@ public boolean isDirOnly() {
 	}
 
 	/**
-	 * Returns the attributes.
+	 * Return the attributes.
 	 *
 	 * @return an unmodifiable list of attributes (never returns
 	 *         <code>null</code>)
@@ -180,6 +182,8 @@ public List<Attribute> getAttributes() {
 	}
 
 	/**
+	 * Whether the pattern is only a file name and not a path
+	 *
 	 * @return <code>true</code> if the pattern is just a file name and not a
 	 *         path
 	 */
@@ -188,6 +192,8 @@ public boolean isNameOnly() {
 	}
 
 	/**
+	 * Get the pattern
+	 *
 	 * @return The blob pattern to be used as a matcher (never returns
 	 *         <code>null</code>)
 	 */
@@ -214,6 +220,7 @@ public boolean isMatch(String relativeTarget, boolean isDirectory) {
 		return match;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public String toString() {
 		StringBuilder sb = new StringBuilder();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/attributes/FilterCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/attributes/FilterCommand.java
index 10be588..c4357d1 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/attributes/FilterCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/attributes/FilterCommand.java
@@ -50,7 +50,7 @@
  * An abstraction for JGit's builtin implementations for hooks and filters.
  * Instead of spawning an external processes to start a filter/hook and to pump
  * data from/to stdin/stdout these builtin commmands may be used. They are
- * constructed by {@link FilterCommandFactory}.
+ * constructed by {@link org.eclipse.jgit.attributes.FilterCommandFactory}.
  *
  * @since 4.6
  */
@@ -66,10 +66,15 @@ public abstract class FilterCommand {
 	protected OutputStream out;
 
 	/**
+	 * Constructor for FilterCommand
+	 * <p>
+	 * FilterCommand implementors are required to manage the in and out streams
+	 * (close on success and/or exception).
+	 *
 	 * @param in
-	 *            The {@link InputStream} this command should read from
+	 *            The {@link java.io.InputStream} this command should read from
 	 * @param out
-	 *            The {@link OutputStream} this command should write to
+	 *            The {@link java.io.OutputStream} this command should write to
 	 */
 	public FilterCommand(InputStream in, OutputStream out) {
 		this.in = in;
@@ -80,15 +85,18 @@ public FilterCommand(InputStream in, OutputStream out) {
 	 * Execute the command. The command is supposed to read data from
 	 * {@link #in} and to write the result to {@link #out}. It returns the
 	 * number of bytes it read from {@link #in}. It should be called in a loop
-	 * until it returns -1 signaling that the {@link InputStream} is completely
-	 * processed.
+	 * until it returns -1 signaling that the {@link java.io.InputStream} is
+	 * completely processed.
+	 * <p>
+	 * On successful completion (return -1) or on Exception, the streams
+	 * {@link #in} and {@link #out} are closed by the implementation.
 	 *
-	 * @return the number of bytes read from the {@link InputStream} or -1. -1
-	 *         means that the {@link InputStream} is completely processed.
-	 * @throws IOException
-	 *             when {@link IOException} occured while reading from
+	 * @return the number of bytes read from the {@link java.io.InputStream} or
+	 *         -1. -1 means that the {@link java.io.InputStream} is completely
+	 *         processed.
+	 * @throws java.io.IOException
+	 *             when {@link java.io.IOException} occured while reading from
 	 *             {@link #in} or writing to {@link #out}
-	 *
 	 */
 	public abstract int run() throws IOException;
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/attributes/FilterCommandFactory.java b/org.eclipse.jgit/src/org/eclipse/jgit/attributes/FilterCommandFactory.java
index 6b973da..11b76b0 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/attributes/FilterCommandFactory.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/attributes/FilterCommandFactory.java
@@ -49,23 +49,25 @@
 import org.eclipse.jgit.lib.Repository;
 
 /**
- * The factory responsible for creating instances of {@link FilterCommand}.
+ * The factory responsible for creating instances of
+ * {@link org.eclipse.jgit.attributes.FilterCommand}.
  *
  * @since 4.6
  */
 public interface FilterCommandFactory {
 	/**
-	 * Create a new {@link FilterCommand}.
+	 * Create a new {@link org.eclipse.jgit.attributes.FilterCommand}.
 	 *
 	 * @param db
 	 *            the repository this command should work on
 	 * @param in
-	 *            the {@link InputStream} this command should read from
+	 *            the {@link java.io.InputStream} this command should read from
 	 * @param out
-	 *            the {@link OutputStream} this command should write to
-	 * @return the created {@link FilterCommand}
-	 * @throws IOException
-	 *             thrown when the command constructor throws an IOException
+	 *            the {@link java.io.OutputStream} this command should write to
+	 * @return the created {@link org.eclipse.jgit.attributes.FilterCommand}
+	 * @throws java.io.IOException
+	 *             thrown when the command constructor throws an
+	 *             java.io.IOException
 	 */
 	public FilterCommand create(Repository db, InputStream in,
 			OutputStream out) throws IOException;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/attributes/FilterCommandRegistry.java b/org.eclipse.jgit/src/org/eclipse/jgit/attributes/FilterCommandRegistry.java
index 3fbaedb..7e511a8 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/attributes/FilterCommandRegistry.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/attributes/FilterCommandRegistry.java
@@ -59,17 +59,20 @@ public class FilterCommandRegistry {
 	private static ConcurrentHashMap<String, FilterCommandFactory> filterCommandRegistry = new ConcurrentHashMap<>();
 
 	/**
-	 * Registers a {@link FilterCommandFactory} responsible for creating
-	 * {@link FilterCommand}s for a certain command name. If the factory f1 is
-	 * registered for the name "jgit://builtin/x" then a call to
-	 * <code>getCommand("jgit://builtin/x", ...)</code> will call
-	 * <code>f1(...)</code> to create a new instance of {@link FilterCommand}
+	 * Register a {@link org.eclipse.jgit.attributes.FilterCommandFactory}
+	 * responsible for creating
+	 * {@link org.eclipse.jgit.attributes.FilterCommand}s for a certain command
+	 * name. If the factory f1 is registered for the name "jgit://builtin/x"
+	 * then a call to <code>getCommand("jgit://builtin/x", ...)</code> will call
+	 * <code>f1(...)</code> to create a new instance of
+	 * {@link org.eclipse.jgit.attributes.FilterCommand}
 	 *
 	 * @param filterCommandName
 	 *            the command name for which this factory is registered
 	 * @param factory
-	 *            the factory responsible for creating {@link FilterCommand}s
-	 *            for the specified name
+	 *            the factory responsible for creating
+	 *            {@link org.eclipse.jgit.attributes.FilterCommand}s for the
+	 *            specified name
 	 * @return the previous factory associated with <tt>commandName</tt>, or
 	 *         <tt>null</tt> if there was no mapping for <tt>commandName</tt>
 	 */
@@ -79,8 +82,8 @@ public static FilterCommandFactory register(String filterCommandName,
 	}
 
 	/**
-	 * Unregisters the {@link FilterCommandFactory} registered for the given
-	 * command name
+	 * Unregister the {@link org.eclipse.jgit.attributes.FilterCommandFactory}
+	 * registered for the given command name
 	 *
 	 * @param filterCommandName
 	 *            the FilterCommandFactory's filter command name
@@ -92,8 +95,9 @@ public static FilterCommandFactory unregister(String filterCommandName) {
 	}
 
 	/**
-	 * Checks whether any {@link FilterCommandFactory} is registered for a given
-	 * command name
+	 * Check whether any
+	 * {@link org.eclipse.jgit.attributes.FilterCommandFactory} is registered
+	 * for a given command name
 	 *
 	 * @param filterCommandName
 	 *            the name for which the registry should be checked
@@ -104,7 +108,10 @@ public static boolean isRegistered(String filterCommandName) {
 	}
 
 	/**
-	 * @return Set of commandNames for which a {@link FilterCommandFactory} is
+	 * Get registered filter commands
+	 *
+	 * @return Set of commandNames for which a
+	 *         {@link org.eclipse.jgit.attributes.FilterCommandFactory} is
 	 *         registered
 	 */
 	public static Set<String> getRegisteredFilterCommands() {
@@ -112,23 +119,26 @@ public static Set<String> getRegisteredFilterCommands() {
 	}
 
 	/**
-	 * Creates a new {@link FilterCommand} for the given name. A factory must be
-	 * registered for the name in advance.
+	 * Create a new {@link org.eclipse.jgit.attributes.FilterCommand} for the
+	 * given name. A factory must be registered for the name in advance.
 	 *
 	 * @param filterCommandName
-	 *            The name for which a new {@link FilterCommand} should be
+	 *            The name for which a new
+	 *            {@link org.eclipse.jgit.attributes.FilterCommand} should be
 	 *            created
 	 * @param db
 	 *            the repository this command should work on
 	 * @param in
-	 *            the {@link InputStream} this {@link FilterCommand} should read
+	 *            the {@link java.io.InputStream} this
+	 *            {@link org.eclipse.jgit.attributes.FilterCommand} should read
 	 *            from
 	 * @param out
-	 *            the {@link OutputStream} this {@link FilterCommand} should
-	 *            write to
+	 *            the {@link java.io.OutputStream} this
+	 *            {@link org.eclipse.jgit.attributes.FilterCommand} should write
+	 *            to
 	 * @return the command if a command could be created or <code>null</code> if
 	 *         there was no factory registered for that name
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 */
 	public static FilterCommand createFilterCommand(String filterCommandName,
 			Repository db, InputStream in, OutputStream out)
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/blame/BlameGenerator.java b/org.eclipse.jgit/src/org/eclipse/jgit/blame/BlameGenerator.java
index 4ad58c3..1ad7a30 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/blame/BlameGenerator.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/blame/BlameGenerator.java
@@ -88,8 +88,10 @@
  * <p>
  * Applications that want more incremental update behavior may use either the
  * raw {@link #next()} streaming approach supported by this class, or construct
- * a {@link BlameResult} using {@link BlameResult#create(BlameGenerator)} and
- * incrementally construct the result with {@link BlameResult#computeNext()}.
+ * a {@link org.eclipse.jgit.blame.BlameResult} using
+ * {@link org.eclipse.jgit.blame.BlameResult#create(BlameGenerator)} and
+ * incrementally construct the result with
+ * {@link org.eclipse.jgit.blame.BlameResult#computeNext()}.
  * <p>
  * This class is not thread-safe.
  * <p>
@@ -186,12 +188,20 @@ private void initRevPool(boolean reverse) {
 		treeWalk.setRecursive(true);
 	}
 
-	/** @return repository being scanned for revision history. */
+	/**
+	 * Get repository
+	 *
+	 * @return repository being scanned for revision history
+	 */
 	public Repository getRepository() {
 		return repository;
 	}
 
-	/** @return path file path being processed. */
+	/**
+	 * Get result path
+	 *
+	 * @return path file path being processed
+	 */
 	public String getResultPath() {
 		return resultPath.getPath();
 	}
@@ -200,6 +210,7 @@ public String getResultPath() {
 	 * Difference algorithm to use when comparing revisions.
 	 *
 	 * @param algorithm
+	 *            a {@link org.eclipse.jgit.diff.DiffAlgorithm}
 	 * @return {@code this}
 	 */
 	public BlameGenerator setDiffAlgorithm(DiffAlgorithm algorithm) {
@@ -211,6 +222,7 @@ public BlameGenerator setDiffAlgorithm(DiffAlgorithm algorithm) {
 	 * Text comparator to use when comparing revisions.
 	 *
 	 * @param comparator
+	 *            a {@link org.eclipse.jgit.diff.RawTextComparator}
 	 * @return {@code this}
 	 */
 	public BlameGenerator setTextComparator(RawTextComparator comparator) {
@@ -255,15 +267,15 @@ public RenameDetector getRenameDetector() {
 	 * <p>
 	 * Candidates should be pushed in history order from oldest-to-newest.
 	 * Applications should push the starting commit first, then the index
-	 * revision (if the index is interesting), and finally the working tree
-	 * copy (if the working tree is interesting).
+	 * revision (if the index is interesting), and finally the working tree copy
+	 * (if the working tree is interesting).
 	 *
 	 * @param description
 	 *            description of the blob revision, such as "Working Tree".
 	 * @param contents
 	 *            contents of the file.
 	 * @return {@code this}
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the repository cannot be read.
 	 */
 	public BlameGenerator push(String description, byte[] contents)
@@ -284,14 +296,15 @@ public BlameGenerator push(String description, byte[] contents)
 	 * @param contents
 	 *            contents of the file.
 	 * @return {@code this}
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the repository cannot be read.
 	 */
 	public BlameGenerator push(String description, RawText contents)
 			throws IOException {
 		if (description == null)
 			description = JGitText.get().blameNotCommittedYet;
-		BlobCandidate c = new BlobCandidate(description, resultPath);
+		BlobCandidate c = new BlobCandidate(getRepository(), description,
+				resultPath);
 		c.sourceText = contents;
 		c.regionList = new Region(0, 0, contents.size());
 		remaining = contents.size();
@@ -312,7 +325,7 @@ public BlameGenerator push(String description, RawText contents)
 	 * @param id
 	 *            may be a commit or a blob.
 	 * @return {@code this}
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the repository cannot be read.
 	 */
 	public BlameGenerator push(String description, AnyObjectId id)
@@ -321,7 +334,8 @@ public BlameGenerator push(String description, AnyObjectId id)
 		if (ldr.getType() == OBJ_BLOB) {
 			if (description == null)
 				description = JGitText.get().blameNotCommittedYet;
-			BlobCandidate c = new BlobCandidate(description, resultPath);
+			BlobCandidate c = new BlobCandidate(getRepository(), description,
+					resultPath);
 			c.sourceBlob = id.toObjectId();
 			c.sourceText = new RawText(ldr.getCachedBytes(Integer.MAX_VALUE));
 			c.regionList = new Region(0, 0, c.sourceText.size());
@@ -334,7 +348,7 @@ public BlameGenerator push(String description, AnyObjectId id)
 		if (!find(commit, resultPath))
 			return this;
 
-		Candidate c = new Candidate(commit, resultPath);
+		Candidate c = new Candidate(getRepository(), commit, resultPath);
 		c.sourceBlob = idBuf.toObjectId();
 		c.loadText(reader);
 		c.regionList = new Region(0, 0, c.sourceText.size());
@@ -357,8 +371,8 @@ public BlameGenerator push(String description, AnyObjectId id)
 	 * each of these is a descendant commit that removed the line, typically
 	 * this occurs when the same deletion appears in multiple side branches such
 	 * as due to a cherry-pick. Applications relying on reverse should use
-	 * {@link BlameResult} as it filters these duplicate sources and only
-	 * remembers the first (oldest) deletion.
+	 * {@link org.eclipse.jgit.blame.BlameResult} as it filters these duplicate
+	 * sources and only remembers the first (oldest) deletion.
 	 *
 	 * @param start
 	 *            oldest commit to traverse from. The result file will be loaded
@@ -367,7 +381,7 @@ public BlameGenerator push(String description, AnyObjectId id)
 	 *            most recent commit to stop traversal at. Usually an active
 	 *            branch tip, tag, or HEAD.
 	 * @return {@code this}
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the repository cannot be read.
 	 */
 	public BlameGenerator reverse(AnyObjectId start, AnyObjectId end)
@@ -389,8 +403,8 @@ public BlameGenerator reverse(AnyObjectId start, AnyObjectId end)
 	 * each of these is a descendant commit that removed the line, typically
 	 * this occurs when the same deletion appears in multiple side branches such
 	 * as due to a cherry-pick. Applications relying on reverse should use
-	 * {@link BlameResult} as it filters these duplicate sources and only
-	 * remembers the first (oldest) deletion.
+	 * {@link org.eclipse.jgit.blame.BlameResult} as it filters these duplicate
+	 * sources and only remembers the first (oldest) deletion.
 	 *
 	 * @param start
 	 *            oldest commit to traverse from. The result file will be loaded
@@ -399,7 +413,7 @@ public BlameGenerator reverse(AnyObjectId start, AnyObjectId end)
 	 *            most recent commits to stop traversal at. Usually an active
 	 *            branch tip, tag, or HEAD.
 	 * @return {@code this}
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the repository cannot be read.
 	 */
 	public BlameGenerator reverse(AnyObjectId start,
@@ -418,7 +432,8 @@ public BlameGenerator reverse(AnyObjectId start,
 			// just pump the queue
 		}
 
-		ReverseCandidate c = new ReverseCandidate(result, resultPath);
+		ReverseCandidate c = new ReverseCandidate(getRepository(), result,
+				resultPath);
 		c.sourceBlob = idBuf.toObjectId();
 		c.loadText(reader);
 		c.regionList = new Region(0, 0, c.sourceText.size());
@@ -443,7 +458,7 @@ public RevFlag newFlag(String name) {
 	 * Execute the generator in a blocking fashion until all data is ready.
 	 *
 	 * @return the complete result. Null if no file exists for the given path.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the repository cannot be read.
 	 */
 	public BlameResult computeBlameResult() throws IOException {
@@ -464,7 +479,7 @@ public BlameResult computeBlameResult() throws IOException {
 	 *         and {@link #getResultStart()}, {@link #getResultEnd()} methods
 	 *         can be used to inspect the region found. False if there are no
 	 *         more regions to describe.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             repository cannot be read.
 	 */
 	public boolean next() throws IOException {
@@ -625,7 +640,8 @@ private boolean processOne(Candidate n) throws IOException {
 			return false;
 		}
 
-		Candidate next = n.create(parent, PathFilter.create(r.getOldPath()));
+		Candidate next = n.create(getRepository(), parent,
+				PathFilter.create(r.getOldPath()));
 		next.sourceBlob = r.getOldId().toObjectId();
 		next.renameScore = r.getScore();
 		next.loadText(reader);
@@ -641,7 +657,7 @@ private boolean blameEntireRegionOnParent(Candidate n, RevCommit parent) {
 
 	private boolean splitBlameWithParent(Candidate n, RevCommit parent)
 			throws IOException {
-		Candidate next = n.create(parent, n.sourcePath);
+		Candidate next = n.create(getRepository(), parent, n.sourcePath);
 		next.sourceBlob = idBuf.toObjectId();
 		next.loadText(reader);
 		return split(next, n);
@@ -728,12 +744,12 @@ private boolean processMerge(Candidate n) throws IOException {
 
 			Candidate p;
 			if (renames != null && renames[pIdx] != null) {
-				p = n.create(parent,
+				p = n.create(getRepository(), parent,
 						PathFilter.create(renames[pIdx].getOldPath()));
 				p.renameScore = renames[pIdx].getScore();
 				p.sourceBlob = renames[pIdx].getOldId().toObjectId();
 			} else if (ids != null && ids[pIdx] != null) {
-				p = n.create(parent, n.sourcePath);
+				p = n.create(getRepository(), parent, n.sourcePath);
 				p.sourceBlob = ids[pIdx];
 			} else {
 				continue;
@@ -842,28 +858,47 @@ public RevCommit getSourceCommit() {
 		return outCandidate.sourceCommit;
 	}
 
-	/** @return current author being blamed. */
+	/**
+	 * Get source author
+	 *
+	 * @return current author being blamed
+	 */
 	public PersonIdent getSourceAuthor() {
 		return outCandidate.getAuthor();
 	}
 
-	/** @return current committer being blamed. */
+	/**
+	 * Get source committer
+	 *
+	 * @return current committer being blamed
+	 */
 	public PersonIdent getSourceCommitter() {
 		RevCommit c = getSourceCommit();
 		return c != null ? c.getCommitterIdent() : null;
 	}
 
-	/** @return path of the file being blamed. */
+	/**
+	 * Get source path
+	 *
+	 * @return path of the file being blamed
+	 */
 	public String getSourcePath() {
 		return outCandidate.sourcePath.getPath();
 	}
 
-	/** @return rename score if a rename occurred in {@link #getSourceCommit}. */
+	/**
+	 * Get rename score
+	 *
+	 * @return rename score if a rename occurred in {@link #getSourceCommit}
+	 */
 	public int getRenameScore() {
 		return outCandidate.renameScore;
 	}
 
 	/**
+	 * Get first line of the source data that has been blamed for the current
+	 * region
+	 *
 	 * @return first line of the source data that has been blamed for the
 	 *         current region. This is line number of where the region was added
 	 *         during {@link #getSourceCommit()} in file
@@ -874,6 +909,9 @@ public int getSourceStart() {
 	}
 
 	/**
+	 * Get one past the range of the source data that has been blamed for the
+	 * current region
+	 *
 	 * @return one past the range of the source data that has been blamed for
 	 *         the current region. This is line number of where the region was
 	 *         added during {@link #getSourceCommit()} in file
@@ -885,6 +923,9 @@ public int getSourceEnd() {
 	}
 
 	/**
+	 * Get first line of the result that {@link #getSourceCommit()} has been
+	 * blamed for providing
+	 *
 	 * @return first line of the result that {@link #getSourceCommit()} has been
 	 *         blamed for providing. Line numbers use 0 based indexing.
 	 */
@@ -893,6 +934,9 @@ public int getResultStart() {
 	}
 
 	/**
+	 * Get one past the range of the result that {@link #getSourceCommit()} has
+	 * been blamed for providing
+	 *
 	 * @return one past the range of the result that {@link #getSourceCommit()}
 	 *         has been blamed for providing. Line numbers use 0 based indexing.
 	 *         Because a source cannot be blamed for an empty region of the
@@ -905,6 +949,9 @@ public int getResultEnd() {
 	}
 
 	/**
+	 * Get number of lines in the current region being blamed to
+	 * {@link #getSourceCommit()}
+	 *
 	 * @return number of lines in the current region being blamed to
 	 *         {@link #getSourceCommit()}. This is always the value of the
 	 *         expression {@code getResultEnd() - getResultStart()}, but also
@@ -915,6 +962,9 @@ public int getRegionLength() {
 	}
 
 	/**
+	 * Get complete contents of the source file blamed for the current output
+	 * region
+	 *
 	 * @return complete contents of the source file blamed for the current
 	 *         output region. This is the contents of {@link #getSourcePath()}
 	 *         within {@link #getSourceCommit()}. The source contents is
@@ -926,13 +976,15 @@ public RawText getSourceContents() {
 	}
 
 	/**
+	 * Get complete file contents of the result file blame is annotating
+	 *
 	 * @return complete file contents of the result file blame is annotating.
 	 *         This value is accessible only after being configured and only
 	 *         immediately before the first call to {@link #next()}. Returns
 	 *         null if the path does not exist.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             repository cannot be read.
-	 * @throws IllegalStateException
+	 * @throws java.lang.IllegalStateException
 	 *             {@link #next()} has already been invoked.
 	 */
 	public RawText getResultContents() throws IOException {
@@ -940,6 +992,8 @@ public RawText getResultContents() throws IOException {
 	}
 
 	/**
+	 * {@inheritDoc}
+	 * <p>
 	 * Release the current blame session.
 	 *
 	 * @since 4.0
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/blame/BlameResult.java b/org.eclipse.jgit/src/org/eclipse/jgit/blame/BlameResult.java
index e34db38..5fb7750 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/blame/BlameResult.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/blame/BlameResult.java
@@ -78,7 +78,7 @@ public class BlameResult {
 	 *            the generator the result will consume records from.
 	 * @return the new result object. null if the generator cannot find the path
 	 *         it starts from.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the repository cannot be read.
 	 */
 	public static BlameResult create(BlameGenerator gen) throws IOException {
@@ -123,17 +123,27 @@ public static BlameResult create(BlameGenerator gen) throws IOException {
 		sourcePaths = new String[cnt];
 	}
 
-	/** @return path of the file this result annotates. */
+	/**
+	 * Get result path
+	 *
+	 * @return path of the file this result annotates
+	 */
 	public String getResultPath() {
 		return resultPath;
 	}
 
-	/** @return contents of the result file, available for display. */
+	/**
+	 * Get result contents
+	 *
+	 * @return contents of the result file, available for display
+	 */
 	public RawText getResultContents() {
 		return resultContents;
 	}
 
-	/** Throw away the {@link #getResultContents()}. */
+	/**
+	 * Throw away the {@link #getResultContents()}.
+	 */
 	public void discardResultContents() {
 		resultContents = null;
 	}
@@ -227,7 +237,7 @@ public int getSourceLine(int idx) {
 	/**
 	 * Compute all pending information.
 	 *
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the repository cannot be read.
 	 */
 	public void computeAll() throws IOException {
@@ -252,7 +262,7 @@ public void computeAll() throws IOException {
 	 * to determine how many lines of the result were computed.
 	 *
 	 * @return index that is now available. -1 if no more are available.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the repository cannot be read.
 	 */
 	public int computeNext() throws IOException {
@@ -271,7 +281,11 @@ public int computeNext() throws IOException {
 		}
 	}
 
-	/** @return length of the last segment found by {@link #computeNext()}. */
+	/**
+	 * Get last length
+	 *
+	 * @return length of the last segment found by {@link #computeNext()}
+	 */
 	public int lastLength() {
 		return lastLength;
 	}
@@ -283,7 +297,7 @@ public int lastLength() {
 	 *            first index to examine (inclusive).
 	 * @param end
 	 *            end index (exclusive).
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the repository cannot be read.
 	 */
 	public void computeRange(int start, int end) throws IOException {
@@ -322,6 +336,7 @@ public void computeRange(int start, int end) throws IOException {
 		}
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public String toString() {
 		StringBuilder r = new StringBuilder();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/blame/Candidate.java b/org.eclipse.jgit/src/org/eclipse/jgit/blame/Candidate.java
index 72d8abe..457d1d2 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/blame/Candidate.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/blame/Candidate.java
@@ -55,10 +55,12 @@
 import org.eclipse.jgit.lib.ObjectLoader;
 import org.eclipse.jgit.lib.ObjectReader;
 import org.eclipse.jgit.lib.PersonIdent;
+import org.eclipse.jgit.lib.Repository;
 import org.eclipse.jgit.revwalk.RevCommit;
 import org.eclipse.jgit.revwalk.RevFlag;
 import org.eclipse.jgit.revwalk.RevWalk;
 import org.eclipse.jgit.treewalk.filter.PathFilter;
+import org.eclipse.jgit.util.LfsFactory;
 
 /**
  * A source that may have supplied some (or all) of the result file.
@@ -109,7 +111,11 @@ class Candidate {
 	 */
 	int renameScore;
 
-	Candidate(RevCommit commit, PathFilter path) {
+	/** repository used for LFS blob handling */
+	private Repository sourceRepository;
+
+	Candidate(Repository repo, RevCommit commit, PathFilter path) {
+		sourceRepository = repo;
 		sourceCommit = commit;
 		sourcePath = path;
 	}
@@ -150,12 +156,12 @@ PersonIdent getAuthor() {
 		return sourceCommit.getAuthorIdent();
 	}
 
-	Candidate create(RevCommit commit, PathFilter path) {
-		return new Candidate(commit, path);
+	Candidate create(Repository repo, RevCommit commit, PathFilter path) {
+		return new Candidate(repo, commit, path);
 	}
 
 	Candidate copy(RevCommit commit) {
-		Candidate r = create(commit, sourcePath);
+		Candidate r = create(sourceRepository, commit, sourcePath);
 		r.sourceBlob = sourceBlob;
 		r.sourceText = sourceText;
 		r.regionList = regionList;
@@ -164,7 +170,11 @@ Candidate copy(RevCommit commit) {
 	}
 
 	void loadText(ObjectReader reader) throws IOException {
-		ObjectLoader ldr = reader.open(sourceBlob, Constants.OBJ_BLOB);
+		ObjectLoader ldr = LfsFactory.getInstance().applySmudgeFilter(sourceRepository,
+				reader.open(sourceBlob, Constants.OBJ_BLOB),
+				LfsFactory.getAttributesForPath(sourceRepository,
+						sourcePath.getPath(), sourceCommit)
+						.get(Constants.ATTR_DIFF));
 		sourceText = new RawText(ldr.getCachedBytes(Integer.MAX_VALUE));
 	}
 
@@ -325,6 +335,7 @@ void mergeRegions(Candidate other) {
 		}
 	}
 
+	/** {@inheritDoc} */
 	@SuppressWarnings("nls")
 	@Override
 	public String toString() {
@@ -348,8 +359,9 @@ public String toString() {
 	 * children pointers, allowing reverse navigation of history.
 	 */
 	static final class ReverseCandidate extends Candidate {
-		ReverseCandidate(ReverseCommit commit, PathFilter path) {
-			super(commit, path);
+		ReverseCandidate(Repository repo, ReverseCommit commit,
+				PathFilter path) {
+			super(repo, commit, path);
 		}
 
 		@Override
@@ -369,8 +381,8 @@ int getTime() {
 		}
 
 		@Override
-		Candidate create(RevCommit commit, PathFilter path) {
-			return new ReverseCandidate((ReverseCommit) commit, path);
+		Candidate create(Repository repo, RevCommit commit, PathFilter path) {
+			return new ReverseCandidate(repo, (ReverseCommit) commit, path);
 		}
 
 		@Override
@@ -399,8 +411,8 @@ static final class BlobCandidate extends Candidate {
 		/** Author name to refer to this blob with. */
 		String description;
 
-		BlobCandidate(String name, PathFilter path) {
-			super(null, path);
+		BlobCandidate(Repository repo, String name, PathFilter path) {
+			super(repo, null, path);
 			description = name;
 		}
 
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/blame/Region.java b/org.eclipse.jgit/src/org/eclipse/jgit/blame/Region.java
index 9ea346b..18281f0 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/blame/Region.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/blame/Region.java
@@ -116,6 +116,7 @@ Region deepCopy() {
 		return head;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public String toString() {
 		StringBuilder buf = new StringBuilder();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/blame/ReverseWalk.java b/org.eclipse.jgit/src/org/eclipse/jgit/blame/ReverseWalk.java
index 5b59804..1067378 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/blame/ReverseWalk.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/blame/ReverseWalk.java
@@ -57,6 +57,7 @@ final class ReverseWalk extends RevWalk {
 		super(repo);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public ReverseCommit next() throws MissingObjectException,
 			IncorrectObjectTypeException, IOException {
@@ -68,6 +69,7 @@ public ReverseCommit next() throws MissingObjectException,
 		return c;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected RevCommit createCommit(AnyObjectId id) {
 		return new ReverseCommit(id);
@@ -106,7 +108,7 @@ int getChildCount() {
 			return children.length;
 		}
 
-		ReverseCommit getChild(final int nth) {
+		ReverseCommit getChild(int nth) {
 			return children[nth];
 		}
 	}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/diff/ContentSource.java b/org.eclipse.jgit/src/org/eclipse/jgit/diff/ContentSource.java
index 444ab1c..f3e986a 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/diff/ContentSource.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/diff/ContentSource.java
@@ -55,13 +55,13 @@
 import org.eclipse.jgit.lib.ObjectLoader;
 import org.eclipse.jgit.lib.ObjectReader;
 import org.eclipse.jgit.lib.ObjectStream;
-import org.eclipse.jgit.treewalk.FileTreeIterator;
 import org.eclipse.jgit.treewalk.TreeWalk;
 import org.eclipse.jgit.treewalk.WorkingTreeIterator;
 import org.eclipse.jgit.treewalk.filter.PathFilter;
 
 /**
- * Supplies the content of a file for {@link DiffFormatter}.
+ * Supplies the content of a file for
+ * {@link org.eclipse.jgit.diff.DiffFormatter}.
  * <p>
  * A content source is not thread-safe. Sources may contain state, including
  * information about the last ObjectLoader they returned. Callers must be
@@ -83,8 +83,9 @@ public static ContentSource create(ObjectReader reader) {
 	/**
 	 * Construct a content source for a working directory.
 	 *
-	 * If the iterator is a {@link FileTreeIterator} an optimized version is
-	 * used that doesn't require seeking through a TreeWalk.
+	 * If the iterator is a {@link org.eclipse.jgit.treewalk.FileTreeIterator}
+	 * an optimized version is used that doesn't require seeking through a
+	 * TreeWalk.
 	 *
 	 * @param iterator
 	 *            the iterator to obtain source files through.
@@ -102,7 +103,7 @@ public static ContentSource create(WorkingTreeIterator iterator) {
 	 * @param id
 	 *            blob id of the file, if known.
 	 * @return the size in bytes.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the file cannot be accessed.
 	 */
 	public abstract long size(String path, ObjectId id) throws IOException;
@@ -117,7 +118,7 @@ public static ContentSource create(WorkingTreeIterator iterator) {
 	 * @return a loader that can supply the content of the file. The loader must
 	 *         be used before another loader can be obtained from this same
 	 *         source.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the file cannot be accessed.
 	 */
 	public abstract ObjectLoader open(String path, ObjectId id)
@@ -169,10 +170,11 @@ public long size(String path, ObjectId id) throws IOException {
 		@Override
 		public ObjectLoader open(String path, ObjectId id) throws IOException {
 			seek(path);
+			long entrySize = ptr.getEntryContentLength();
 			return new ObjectLoader() {
 				@Override
 				public long getSize() {
-					return ptr.getEntryLength();
+					return entrySize;
 				}
 
 				@Override
@@ -183,7 +185,7 @@ public int getType() {
 				@Override
 				public ObjectStream openStream() throws MissingObjectException,
 						IOException {
-					long contentLength = ptr.getEntryContentLength();
+					long contentLength = entrySize;
 					InputStream in = ptr.openEntryStream();
 					in = new BufferedInputStream(in);
 					return new ObjectStream.Filter(getType(), contentLength, in);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/diff/DiffAlgorithm.java b/org.eclipse.jgit/src/org/eclipse/jgit/diff/DiffAlgorithm.java
index 5f01366..19eb39d 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/diff/DiffAlgorithm.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/diff/DiffAlgorithm.java
@@ -44,7 +44,8 @@
 package org.eclipse.jgit.diff;
 
 /**
- * Compares two {@link Sequence}s to create an {@link EditList} of changes.
+ * Compares two {@link org.eclipse.jgit.diff.Sequence}s to create an
+ * {@link org.eclipse.jgit.diff.EditList} of changes.
  * <p>
  * An algorithm's {@code diff} method must be callable from concurrent threads
  * without data collisions. This permits some algorithms to use a singleton
@@ -69,6 +70,8 @@ public enum SupportedAlgorithm {
 	}
 
 	/**
+	 * Get diff algorithm
+	 *
 	 * @param alg
 	 *            the diff algorithm for which an implementation should be
 	 *            returned
@@ -88,18 +91,18 @@ public static DiffAlgorithm getAlgorithm(SupportedAlgorithm alg) {
 	/**
 	 * Compare two sequences and identify a list of edits between them.
 	 *
-	 * @param <S>
-	 *            type of sequence being compared.
 	 * @param cmp
 	 *            the comparator supplying the element equivalence function.
 	 * @param a
 	 *            the first (also known as old or pre-image) sequence. Edits
 	 *            returned by this algorithm will reference indexes using the
-	 *            'A' side: {@link Edit#getBeginA()}, {@link Edit#getEndA()}.
+	 *            'A' side: {@link org.eclipse.jgit.diff.Edit#getBeginA()},
+	 *            {@link org.eclipse.jgit.diff.Edit#getEndA()}.
 	 * @param b
 	 *            the second (also known as new or post-image) sequence. Edits
 	 *            returned by this algorithm will reference indexes using the
-	 *            'B' side: {@link Edit#getBeginB()}, {@link Edit#getEndB()}.
+	 *            'B' side: {@link org.eclipse.jgit.diff.Edit#getBeginB()},
+	 *            {@link org.eclipse.jgit.diff.Edit#getEndB()}.
 	 * @return a modifiable edit list comparing the two sequences. If empty, the
 	 *         sequences are identical according to {@code cmp}'s rules. The
 	 *         result list is never null.
@@ -244,20 +247,21 @@ private static <S extends Sequence> EditList normalize(
 	 * proven to have no common starting or ending elements. The expected
 	 * elimination of common starting and ending elements is automatically
 	 * performed by the {@link #diff(SequenceComparator, Sequence, Sequence)}
-	 * method, which invokes this method using {@link Subsequence}s.
+	 * method, which invokes this method using
+	 * {@link org.eclipse.jgit.diff.Subsequence}s.
 	 *
-	 * @param <S>
-	 *            type of sequence being compared.
 	 * @param cmp
 	 *            the comparator supplying the element equivalence function.
 	 * @param a
 	 *            the first (also known as old or pre-image) sequence. Edits
 	 *            returned by this algorithm will reference indexes using the
-	 *            'A' side: {@link Edit#getBeginA()}, {@link Edit#getEndA()}.
+	 *            'A' side: {@link org.eclipse.jgit.diff.Edit#getBeginA()},
+	 *            {@link org.eclipse.jgit.diff.Edit#getEndA()}.
 	 * @param b
 	 *            the second (also known as new or post-image) sequence. Edits
 	 *            returned by this algorithm will reference indexes using the
-	 *            'B' side: {@link Edit#getBeginB()}, {@link Edit#getEndB()}.
+	 *            'B' side: {@link org.eclipse.jgit.diff.Edit#getBeginB()},
+	 *            {@link org.eclipse.jgit.diff.Edit#getEndB()}.
 	 * @return a modifiable edit list comparing the two sequences.
 	 */
 	public abstract <S extends Sequence> EditList diffNonCommon(
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/diff/DiffConfig.java b/org.eclipse.jgit/src/org/eclipse/jgit/diff/DiffConfig.java
index ee70949..21dca6b 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/diff/DiffConfig.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/diff/DiffConfig.java
@@ -51,7 +51,9 @@
 import org.eclipse.jgit.lib.ConfigConstants;
 import org.eclipse.jgit.util.StringUtils;
 
-/** Keeps track of diff related configuration options. */
+/**
+ * Keeps track of diff related configuration options.
+ */
 public class DiffConfig {
 	/** Key for {@link Config#get(SectionParser)}. */
 	public static final Config.SectionParser<DiffConfig> KEY = DiffConfig::new;
@@ -74,7 +76,7 @@ public static enum RenameDetectionType {
 
 	private final int renameLimit;
 
-	private DiffConfig(final Config rc) {
+	private DiffConfig(Config rc) {
 		noPrefix = rc.getBoolean(ConfigConstants.CONFIG_DIFF_SECTION,
 				ConfigConstants.CONFIG_KEY_NOPREFIX, false);
 		renameDetectionType = parseRenameDetectionType(rc.getString(
@@ -83,22 +85,38 @@ private DiffConfig(final Config rc) {
 				ConfigConstants.CONFIG_KEY_RENAMELIMIT, 200);
 	}
 
-	/** @return true if the prefix "a/" and "b/" should be suppressed. */
+	/**
+	 * If prefix should be suppressed
+	 *
+	 * @return true if the prefix "a/" and "b/" should be suppressed
+	 */
 	public boolean isNoPrefix() {
 		return noPrefix;
 	}
 
-	/** @return true if rename detection is enabled by default. */
+	/**
+	 * If rename detection is enabled
+	 *
+	 * @return true if rename detection is enabled by default
+	 */
 	public boolean isRenameDetectionEnabled() {
 		return renameDetectionType != RenameDetectionType.FALSE;
 	}
 
-	/** @return type of rename detection to perform. */
+	/**
+	 * Get the rename detection type
+	 *
+	 * @return type of rename detection to perform
+	 */
 	public RenameDetectionType getRenameDetectionType() {
 		return renameDetectionType;
 	}
 
-	/** @return limit on number of paths to perform inexact rename detection. */
+	/**
+	 * Get the rename limit
+	 *
+	 * @return limit on number of paths to perform inexact rename detection
+	 */
 	public int getRenameLimit() {
 		return renameLimit;
 	}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/diff/DiffEntry.java b/org.eclipse.jgit/src/org/eclipse/jgit/diff/DiffEntry.java
index 5eb1942..5c8343f 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/diff/DiffEntry.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/diff/DiffEntry.java
@@ -48,9 +48,11 @@
 import java.util.Arrays;
 import java.util.List;
 
+import org.eclipse.jgit.attributes.Attribute;
 import org.eclipse.jgit.internal.JGitText;
 import org.eclipse.jgit.lib.AbbreviatedObjectId;
 import org.eclipse.jgit.lib.AnyObjectId;
+import org.eclipse.jgit.lib.Constants;
 import org.eclipse.jgit.lib.FileMode;
 import org.eclipse.jgit.lib.MutableObjectId;
 import org.eclipse.jgit.lib.ObjectId;
@@ -58,7 +60,9 @@
 import org.eclipse.jgit.treewalk.filter.TreeFilter;
 import org.eclipse.jgit.treewalk.filter.TreeFilterMarker;
 
-/** A value class representing a change to a file */
+/**
+ * A value class representing a change to a file
+ */
 public class DiffEntry {
 	/** Magical SHA1 used for file adds or deletes */
 	static final AbbreviatedObjectId A_ZERO = AbbreviatedObjectId
@@ -107,9 +111,9 @@ protected DiffEntry(){
 	 * @param walk
 	 *            the TreeWalk to walk through. Must have exactly two trees.
 	 * @return headers describing the changed files.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the repository cannot be accessed.
-	 * @throws IllegalArgumentException
+	 * @throws java.lang.IllegalArgumentException
 	 *             When given TreeWalk doesn't have exactly two trees.
 	 */
 	public static List<DiffEntry> scan(TreeWalk walk) throws IOException {
@@ -127,9 +131,9 @@ public static List<DiffEntry> scan(TreeWalk walk) throws IOException {
 	 * @param includeTrees
 	 *            include tree objects.
 	 * @return headers describing the changed files.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the repository cannot be accessed.
-	 * @throws IllegalArgumentException
+	 * @throws java.lang.IllegalArgumentException
 	 *             when {@code includeTrees} is true and given TreeWalk is
 	 *             recursive. Or when given TreeWalk doesn't have exactly two
 	 *             trees
@@ -155,9 +159,9 @@ public static List<DiffEntry> scan(TreeWalk walk, boolean includeTrees)
 	 *            queried through {{@link #isMarked(int)} (with the index from
 	 *            this passed array).
 	 * @return headers describing the changed files.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the repository cannot be accessed.
-	 * @throws IllegalArgumentException
+	 * @throws java.lang.IllegalArgumentException
 	 *             when {@code includeTrees} is true and given TreeWalk is
 	 *             recursive. Or when given TreeWalk doesn't have exactly two
 	 *             trees
@@ -194,6 +198,11 @@ public static List<DiffEntry> scan(TreeWalk walk, boolean includeTrees,
 			entry.newMode = walk.getFileMode(1);
 			entry.newPath = entry.oldPath = walk.getPathString();
 
+			if (walk.getAttributesNodeProvider() != null) {
+				entry.diffAttribute = walk.getAttributes()
+						.get(Constants.ATTR_DIFF);
+			}
+
 			if (treeFilterMarker != null)
 				entry.treeFilterMarks = treeFilterMarker.getMarks(walk);
 
@@ -280,6 +289,7 @@ static List<DiffEntry> breakModify(DiffEntry entry) {
 		del.newMode = FileMode.MISSING;
 		del.newPath = DiffEntry.DEV_NULL;
 		del.changeType = ChangeType.DELETE;
+		del.diffAttribute = entry.diffAttribute;
 
 		DiffEntry add = new DiffEntry();
 		add.oldId = A_ZERO;
@@ -290,6 +300,7 @@ static List<DiffEntry> breakModify(DiffEntry entry) {
 		add.newMode = entry.getNewMode();
 		add.newPath = entry.getNewPath();
 		add.changeType = ChangeType.ADD;
+		add.diffAttribute = entry.diffAttribute;
 		return Arrays.asList(del, add);
 	}
 
@@ -304,6 +315,7 @@ static DiffEntry pair(ChangeType changeType, DiffEntry src, DiffEntry dst,
 		r.newId = dst.newId;
 		r.newMode = dst.newMode;
 		r.newPath = dst.newPath;
+		r.diffAttribute = dst.diffAttribute;
 
 		r.changeType = changeType;
 		r.score = score;
@@ -319,6 +331,13 @@ static DiffEntry pair(ChangeType changeType, DiffEntry src, DiffEntry dst,
 	/** File name of the new (post-image). */
 	protected String newPath;
 
+	/**
+	 * diff filter attribute
+	 *
+	 * @since 4.11
+	 */
+	protected Attribute diffAttribute;
+
 	/** Old mode of the file, if described by the patch, else null. */
 	protected FileMode oldMode;
 
@@ -392,12 +411,28 @@ public String getPath(Side side) {
 		return side == Side.OLD ? getOldPath() : getNewPath();
 	}
 
-	/** @return the old file mode, if described in the patch */
+	/**
+	 * @return the {@link Attribute} determining filters to be applied.
+	 * @since 4.11
+	 */
+	public Attribute getDiffAttribute() {
+		return diffAttribute;
+	}
+
+	/**
+	 * Get the old file mode
+	 *
+	 * @return the old file mode, if described in the patch
+	 */
 	public FileMode getOldMode() {
 		return oldMode;
 	}
 
-	/** @return the new file mode, if described in the patch */
+	/**
+	 * Get the new file mode
+	 *
+	 * @return the new file mode, if described in the patch
+	 */
 	public FileMode getNewMode() {
 		return newMode;
 	}
@@ -413,15 +448,22 @@ public FileMode getMode(Side side) {
 		return side == Side.OLD ? getOldMode() : getNewMode();
 	}
 
-	/** @return the type of change this patch makes on {@link #getNewPath()} */
+	/**
+	 * Get the change type
+	 *
+	 * @return the type of change this patch makes on {@link #getNewPath()}
+	 */
 	public ChangeType getChangeType() {
 		return changeType;
 	}
 
 	/**
+	 * Get similarity score
+	 *
 	 * @return similarity score between {@link #getOldPath()} and
 	 *         {@link #getNewPath()} if {@link #getChangeType()} is
-	 *         {@link ChangeType#COPY} or {@link ChangeType#RENAME}.
+	 *         {@link org.eclipse.jgit.diff.DiffEntry.ChangeType#COPY} or
+	 *         {@link org.eclipse.jgit.diff.DiffEntry.ChangeType#RENAME}.
 	 */
 	public int getScore() {
 		return score;
@@ -466,10 +508,9 @@ public AbbreviatedObjectId getNewId() {
 	 *
 	 * @param index
 	 *            the index of the tree filter to check for (must be between 0
-	 *            and {@link Integer#SIZE}).
-	 *
-	 * @return true, if the tree filter matched; false if not
+	 *            and {@link java.lang.Integer#SIZE}).
 	 * @since 2.3
+	 * @return a boolean.
 	 */
 	public boolean isMarked(int index) {
 		return (treeFilterMarks & (1L << index)) != 0;
@@ -498,6 +539,7 @@ public AbbreviatedObjectId getId(Side side) {
 		return side == Side.OLD ? getOldId() : getNewId();
 	}
 
+	/** {@inheritDoc} */
 	@SuppressWarnings("nls")
 	@Override
 	public String toString() {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/diff/DiffFormatter.java b/org.eclipse.jgit/src/org/eclipse/jgit/diff/DiffFormatter.java
index fa7cc0d..7aaa500 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/diff/DiffFormatter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/diff/DiffFormatter.java
@@ -66,9 +66,9 @@
 import org.eclipse.jgit.diff.DiffEntry.ChangeType;
 import org.eclipse.jgit.dircache.DirCacheIterator;
 import org.eclipse.jgit.errors.AmbiguousObjectException;
+import org.eclipse.jgit.errors.BinaryBlobException;
 import org.eclipse.jgit.errors.CorruptObjectException;
 import org.eclipse.jgit.errors.IncorrectObjectTypeException;
-import org.eclipse.jgit.errors.LargeObjectException;
 import org.eclipse.jgit.errors.MissingObjectException;
 import org.eclipse.jgit.internal.JGitText;
 import org.eclipse.jgit.lib.AbbreviatedObjectId;
@@ -84,7 +84,6 @@
 import org.eclipse.jgit.lib.Repository;
 import org.eclipse.jgit.patch.FileHeader;
 import org.eclipse.jgit.patch.FileHeader.PatchType;
-import org.eclipse.jgit.patch.HunkHeader;
 import org.eclipse.jgit.revwalk.FollowFilter;
 import org.eclipse.jgit.revwalk.RevTree;
 import org.eclipse.jgit.revwalk.RevWalk;
@@ -99,8 +98,8 @@
 import org.eclipse.jgit.treewalk.filter.NotIgnoredFilter;
 import org.eclipse.jgit.treewalk.filter.PathFilter;
 import org.eclipse.jgit.treewalk.filter.TreeFilter;
+import org.eclipse.jgit.util.LfsFactory;
 import org.eclipse.jgit.util.QuotedString;
-import org.eclipse.jgit.util.io.DisabledOutputStream;
 
 /**
  * Format a Git style patch script.
@@ -113,9 +112,6 @@ public class DiffFormatter implements AutoCloseable {
 	/** Magic return content indicating it is empty or no content present. */
 	private static final byte[] EMPTY = new byte[] {};
 
-	/** Magic return indicating the content is binary. */
-	private static final byte[] BINARY = new byte[] {};
-
 	private final OutputStream out;
 
 	private ObjectReader reader;
@@ -146,6 +142,8 @@ public class DiffFormatter implements AutoCloseable {
 
 	private ContentSource.Pair source;
 
+	private Repository repository;
+
 	/**
 	 * Create a new formatter with a default level of context.
 	 *
@@ -158,7 +156,11 @@ public DiffFormatter(OutputStream out) {
 		this.out = out;
 	}
 
-	/** @return the stream we are outputting data to. */
+	/**
+	 * Get output stream
+	 *
+	 * @return the stream we are outputting data to
+	 */
 	protected OutputStream getOutputStream() {
 		return out;
 	}
@@ -173,6 +175,7 @@ protected OutputStream getOutputStream() {
 	 *            source repository holding referenced objects.
 	 */
 	public void setRepository(Repository repository) {
+		this.repository = repository;
 		setReader(repository.newObjectReader(), repository.getConfig(), true);
 	}
 
@@ -219,7 +222,7 @@ private void setReader(ObjectReader reader, Config cfg, boolean closeReader) {
 	 *            modification and after the last modification within a hunk of
 	 *            the modified file.
 	 */
-	public void setContext(final int lineCount) {
+	public void setContext(int lineCount) {
 		if (lineCount < 0)
 			throw new IllegalArgumentException(
 					JGitText.get().contextMustBeNonNegative);
@@ -232,7 +235,7 @@ public void setContext(final int lineCount) {
 	 * @param count
 	 *            number of digits to show in an ObjectId.
 	 */
-	public void setAbbreviationLength(final int count) {
+	public void setAbbreviationLength(int count) {
 		if (count < 0)
 			throw new IllegalArgumentException(
 					JGitText.get().abbreviationLengthMustBeNonNegative);
@@ -327,7 +330,11 @@ public String getNewPrefix() {
 		return this.newPrefix;
 	}
 
-	/** @return true if rename detection is enabled. */
+	/**
+	 * Get if rename detection is enabled
+	 *
+	 * @return true if rename detection is enabled
+	 */
 	public boolean isDetectRenames() {
 		return renameDetector != null;
 	}
@@ -351,7 +358,11 @@ public void setDetectRenames(boolean on) {
 			renameDetector = null;
 	}
 
-	/** @return the rename detector if rename detection is enabled. */
+	/**
+	 * Get rename detector
+	 *
+	 * @return the rename detector if rename detection is enabled
+	 */
 	public RenameDetector getRenameDetector() {
 		return renameDetector;
 	}
@@ -369,9 +380,10 @@ public void setProgressMonitor(ProgressMonitor pm) {
 	/**
 	 * Set the filter to produce only specific paths.
 	 *
-	 * If the filter is an instance of {@link FollowFilter}, the filter path
-	 * will be updated during successive scan or format invocations. The updated
-	 * path can be obtained from {@link #getPathFilter()}.
+	 * If the filter is an instance of
+	 * {@link org.eclipse.jgit.revwalk.FollowFilter}, the filter path will be
+	 * updated during successive scan or format invocations. The updated path
+	 * can be obtained from {@link #getPathFilter()}.
 	 *
 	 * @param filter
 	 *            the tree filter to apply.
@@ -380,7 +392,11 @@ public void setPathFilter(TreeFilter filter) {
 		pathFilter = filter != null ? filter : TreeFilter.ALL;
 	}
 
-	/** @return the current path filter. */
+	/**
+	 * Get path filter
+	 *
+	 * @return the current path filter
+	 */
 	public TreeFilter getPathFilter() {
 		return pathFilter;
 	}
@@ -388,7 +404,7 @@ public TreeFilter getPathFilter() {
 	/**
 	 * Flush the underlying output stream of this formatter.
 	 *
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the stream's own flush method threw an exception.
 	 */
 	public void flush() throws IOException {
@@ -396,6 +412,8 @@ public void flush() throws IOException {
 	}
 
 	/**
+	 * {@inheritDoc}
+	 * <p>
 	 * Release the internal ObjectReader state.
 	 *
 	 * @since 4.0
@@ -412,8 +430,8 @@ public void close() {
 	 *
 	 * No output is created, instead only the file paths that are different are
 	 * returned. Callers may choose to format these paths themselves, or convert
-	 * them into {@link FileHeader} instances with a complete edit list by
-	 * calling {@link #toFileHeader(DiffEntry)}.
+	 * them into {@link org.eclipse.jgit.patch.FileHeader} instances with a
+	 * complete edit list by calling {@link #toFileHeader(DiffEntry)}.
 	 * <p>
 	 * Either side may be null to indicate that the tree has beed added or
 	 * removed. The diff will be computed against nothing.
@@ -423,7 +441,7 @@ public void close() {
 	 * @param b
 	 *            the new (or updated) side or null
 	 * @return the paths that are different.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             trees cannot be read or file contents cannot be read.
 	 */
 	public List<DiffEntry> scan(AnyObjectId a, AnyObjectId b)
@@ -442,8 +460,8 @@ public List<DiffEntry> scan(AnyObjectId a, AnyObjectId b)
 	 *
 	 * No output is created, instead only the file paths that are different are
 	 * returned. Callers may choose to format these paths themselves, or convert
-	 * them into {@link FileHeader} instances with a complete edit list by
-	 * calling {@link #toFileHeader(DiffEntry)}.
+	 * them into {@link org.eclipse.jgit.patch.FileHeader} instances with a
+	 * complete edit list by calling {@link #toFileHeader(DiffEntry)}.
 	 * <p>
 	 * Either side may be null to indicate that the tree has beed added or
 	 * removed. The diff will be computed against nothing.
@@ -453,7 +471,7 @@ public List<DiffEntry> scan(AnyObjectId a, AnyObjectId b)
 	 * @param b
 	 *            the new (or updated) side or null
 	 * @return the paths that are different.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             trees cannot be read or file contents cannot be read.
 	 */
 	public List<DiffEntry> scan(RevTree a, RevTree b) throws IOException {
@@ -479,15 +497,15 @@ private AbstractTreeIterator makeIteratorFromTreeOrNull(RevTree tree)
 	 *
 	 * No output is created, instead only the file paths that are different are
 	 * returned. Callers may choose to format these paths themselves, or convert
-	 * them into {@link FileHeader} instances with a complete edit list by
-	 * calling {@link #toFileHeader(DiffEntry)}.
+	 * them into {@link org.eclipse.jgit.patch.FileHeader} instances with a
+	 * complete edit list by calling {@link #toFileHeader(DiffEntry)}.
 	 *
 	 * @param a
 	 *            the old (or previous) side.
 	 * @param b
 	 *            the new (or updated) side.
 	 * @return the paths that are different.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             trees cannot be read or file contents cannot be read.
 	 */
 	public List<DiffEntry> scan(AbstractTreeIterator a, AbstractTreeIterator b)
@@ -599,7 +617,7 @@ private static boolean isRename(DiffEntry ent) {
 	 *            the old (or previous) side or null
 	 * @param b
 	 *            the new (or updated) side or null
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             trees cannot be read, file contents cannot be read, or the
 	 *             patch cannot be output.
 	 */
@@ -621,7 +639,7 @@ public void format(AnyObjectId a, AnyObjectId b) throws IOException {
 	 *            the old (or previous) side or null
 	 * @param b
 	 *            the new (or updated) side or null
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             trees cannot be read, file contents cannot be read, or the
 	 *             patch cannot be output.
 	 */
@@ -642,7 +660,7 @@ public void format(RevTree a, RevTree b) throws IOException {
 	 *            the old (or previous) side or null
 	 * @param b
 	 *            the new (or updated) side or null
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             trees cannot be read, file contents cannot be read, or the
 	 *             patch cannot be output.
 	 */
@@ -658,7 +676,7 @@ public void format(AbstractTreeIterator a, AbstractTreeIterator b)
 	 *
 	 * @param entries
 	 *            entries describing the affected files.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             a file's content cannot be read, or the output stream cannot
 	 *             be written to.
 	 */
@@ -672,7 +690,7 @@ public void format(List<? extends DiffEntry> entries) throws IOException {
 	 *
 	 * @param ent
 	 *            the entry to be formatted.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             a file's content cannot be read, or the output stream cannot
 	 *             be written to.
 	 */
@@ -715,14 +733,16 @@ private static String quotePath(String name) {
 	 *            existing file header containing the header lines to copy.
 	 * @param a
 	 *            text source for the pre-image version of the content. This
-	 *            must match the content of {@link FileHeader#getOldId()}.
+	 *            must match the content of
+	 *            {@link org.eclipse.jgit.patch.FileHeader#getOldId()}.
 	 * @param b
 	 *            text source for the post-image version of the content. This
-	 *            must match the content of {@link FileHeader#getNewId()}.
-	 * @throws IOException
+	 *            must match the content of
+	 *            {@link org.eclipse.jgit.patch.FileHeader#getNewId()}.
+	 * @throws java.io.IOException
 	 *             writing to the supplied stream failed.
 	 */
-	public void format(final FileHeader head, final RawText a, final RawText b)
+	public void format(FileHeader head, RawText a, RawText b)
 			throws IOException {
 		// Reuse the existing FileHeader as-is by blindly copying its
 		// header lines, but avoiding its hunks. Instead we recreate
@@ -746,9 +766,9 @@ public void format(final FileHeader head, final RawText a, final RawText b)
 	 *            the text A which was compared
 	 * @param b
 	 *            the text B which was compared
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 */
-	public void format(final EditList edits, final RawText a, final RawText b)
+	public void format(EditList edits, RawText a, RawText b)
 			throws IOException {
 		for (int curIdx = 0; curIdx < edits.size();) {
 			Edit curEdit = edits.get(curIdx);
@@ -794,14 +814,14 @@ public void format(final EditList edits, final RawText a, final RawText b)
 	 *            RawText for accessing raw data
 	 * @param line
 	 *            the line number within text
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 */
-	protected void writeContextLine(final RawText text, final int line)
+	protected void writeContextLine(RawText text, int line)
 			throws IOException {
 		writeLine(' ', text, line);
 	}
 
-	private static boolean isEndOfLineMissing(final RawText text, final int line) {
+	private static boolean isEndOfLineMissing(RawText text, int line) {
 		return line + 1 == text.size() && text.isMissingNewlineAtEnd();
 	}
 
@@ -812,9 +832,9 @@ private static boolean isEndOfLineMissing(final RawText text, final int line) {
 	 *            RawText for accessing raw data
 	 * @param line
 	 *            the line number within text
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 */
-	protected void writeAddedLine(final RawText text, final int line)
+	protected void writeAddedLine(RawText text, int line)
 			throws IOException {
 		writeLine('+', text, line);
 	}
@@ -826,9 +846,9 @@ protected void writeAddedLine(final RawText text, final int line)
 	 *            RawText for accessing raw data
 	 * @param line
 	 *            the line number within text
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 */
-	protected void writeRemovedLine(final RawText text, final int line)
+	protected void writeRemovedLine(RawText text, int line)
 			throws IOException {
 		writeLine('-', text, line);
 	}
@@ -844,7 +864,7 @@ protected void writeRemovedLine(final RawText text, final int line)
 	 *            within second source
 	 * @param bEndLine
 	 *            within second source
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 */
 	protected void writeHunkHeader(int aStartLine, int aEndLine,
 			int bStartLine, int bEndLine) throws IOException {
@@ -858,7 +878,7 @@ protected void writeHunkHeader(int aStartLine, int aEndLine,
 		out.write('\n');
 	}
 
-	private void writeRange(final char prefix, final int begin, final int cnt)
+	private void writeRange(char prefix, int begin, int cnt)
 			throws IOException {
 		out.write(' ');
 		out.write(prefix);
@@ -897,7 +917,7 @@ private void writeRange(final char prefix, final int begin, final int cnt)
 	 *            the text object to obtain the line from.
 	 * @param cur
 	 *            line number to output.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the stream threw an exception while writing to it.
 	 */
 	protected void writeLine(final char prefix, final RawText text,
@@ -908,24 +928,26 @@ protected void writeLine(final char prefix, final RawText text,
 	}
 
 	/**
-	 * Creates a {@link FileHeader} representing the given {@link DiffEntry}
+	 * Creates a {@link org.eclipse.jgit.patch.FileHeader} representing the
+	 * given {@link org.eclipse.jgit.diff.DiffEntry}
 	 * <p>
 	 * This method does not use the OutputStream associated with this
 	 * DiffFormatter instance. It is therefore safe to instantiate this
-	 * DiffFormatter instance with a {@link DisabledOutputStream} if this method
-	 * is the only one that will be used.
+	 * DiffFormatter instance with a
+	 * {@link org.eclipse.jgit.util.io.DisabledOutputStream} if this method is
+	 * the only one that will be used.
 	 *
 	 * @param ent
 	 *            the DiffEntry to create the FileHeader for
 	 * @return a FileHeader representing the DiffEntry. The FileHeader's buffer
 	 *         will contain only the header of the diff output. It will also
-	 *         contain one {@link HunkHeader}.
-	 * @throws IOException
+	 *         contain one {@link org.eclipse.jgit.patch.HunkHeader}.
+	 * @throws java.io.IOException
 	 *             the stream threw an exception while writing to it, or one of
 	 *             the blobs referenced by the DiffEntry could not be read.
-	 * @throws CorruptObjectException
+	 * @throws org.eclipse.jgit.errors.CorruptObjectException
 	 *             one of the blobs referenced by the DiffEntry is corrupt.
-	 * @throws MissingObjectException
+	 * @throws org.eclipse.jgit.errors.MissingObjectException
 	 *             one of the blobs referenced by the DiffEntry is missing.
 	 */
 	public FileHeader toFileHeader(DiffEntry ent) throws IOException,
@@ -954,47 +976,50 @@ private FormatResult createFormatResult(DiffEntry ent) throws IOException,
 			// Content not changed (e.g. only mode, pure rename)
 			editList = new EditList();
 			type = PatchType.UNIFIED;
+			res.header = new FileHeader(buf.toByteArray(), editList, type);
+			return res;
+		}
 
+		assertHaveReader();
+
+		RawText aRaw = null;
+		RawText bRaw = null;
+		if (ent.getOldMode() == GITLINK || ent.getNewMode() == GITLINK) {
+			aRaw = new RawText(writeGitLinkText(ent.getOldId()));
+			bRaw = new RawText(writeGitLinkText(ent.getNewId()));
 		} else {
-			assertHaveReader();
-
-			byte[] aRaw, bRaw;
-
-			if (ent.getOldMode() == GITLINK || ent.getNewMode() == GITLINK) {
-				aRaw = writeGitLinkText(ent.getOldId());
-				bRaw = writeGitLinkText(ent.getNewId());
-			} else {
+			try {
 				aRaw = open(OLD, ent);
 				bRaw = open(NEW, ent);
-			}
-
-			if (aRaw == BINARY || bRaw == BINARY //
-					|| RawText.isBinary(aRaw) || RawText.isBinary(bRaw)) {
+			} catch (BinaryBlobException e) {
+				// Do nothing; we check for null below.
 				formatOldNewPaths(buf, ent);
 				buf.write(encodeASCII("Binary files differ\n")); //$NON-NLS-1$
 				editList = new EditList();
 				type = PatchType.BINARY;
-
-			} else {
-				res.a = new RawText(aRaw);
-				res.b = new RawText(bRaw);
-				editList = diff(res.a, res.b);
-				type = PatchType.UNIFIED;
-
-				switch (ent.getChangeType()) {
-				case RENAME:
-				case COPY:
-					if (!editList.isEmpty())
-						formatOldNewPaths(buf, ent);
-					break;
-
-				default:
-					formatOldNewPaths(buf, ent);
-					break;
-				}
+				res.header = new FileHeader(buf.toByteArray(), editList, type);
+				return res;
 			}
 		}
 
+		res.a = aRaw;
+		res.b = bRaw;
+		editList = diff(res.a, res.b);
+		type = PatchType.UNIFIED;
+
+		switch (ent.getChangeType()) {
+			case RENAME:
+			case COPY:
+				if (!editList.isEmpty())
+					formatOldNewPaths(buf, ent);
+				break;
+
+			default:
+				formatOldNewPaths(buf, ent);
+				break;
+		}
+
+
 		res.header = new FileHeader(buf.toByteArray(), editList, type);
 		return res;
 	}
@@ -1009,13 +1034,13 @@ private void assertHaveReader() {
 		}
 	}
 
-	private byte[] open(DiffEntry.Side side, DiffEntry entry)
-			throws IOException {
+	private RawText open(DiffEntry.Side side, DiffEntry entry)
+			throws IOException, BinaryBlobException {
 		if (entry.getMode(side) == FileMode.MISSING)
-			return EMPTY;
+			return RawText.EMPTY_TEXT;
 
 		if (entry.getMode(side).getObjectType() != Constants.OBJ_BLOB)
-			return EMPTY;
+			return RawText.EMPTY_TEXT;
 
 		AbbreviatedObjectId id = entry.getId(side);
 		if (!id.isComplete()) {
@@ -1036,23 +1061,9 @@ private void assertHaveReader() {
 				throw new AmbiguousObjectException(id, ids);
 		}
 
-		try {
-			ObjectLoader ldr = source.open(side, entry);
-			return ldr.getBytes(binaryFileThreshold);
-
-		} catch (LargeObjectException.ExceedsLimit overLimit) {
-			return BINARY;
-
-		} catch (LargeObjectException.ExceedsByteArrayLimit overLimit) {
-			return BINARY;
-
-		} catch (LargeObjectException.OutOfMemory tooBig) {
-			return BINARY;
-
-		} catch (LargeObjectException tooBig) {
-			tooBig.setObjectId(id.toObjectId());
-			throw tooBig;
-		}
+		ObjectLoader ldr = LfsFactory.getInstance().applySmudgeFilter(repository,
+				source.open(side, entry), entry.getDiffAttribute());
+		return RawText.load(ldr, binaryFileThreshold);
 	}
 
 	/**
@@ -1061,12 +1072,12 @@ private void assertHaveReader() {
 	 * @param o
 	 *            The stream the formatter will write the first header line to
 	 * @param type
-	 *            The {@link ChangeType}
+	 *            The {@link org.eclipse.jgit.diff.DiffEntry.ChangeType}
 	 * @param oldPath
 	 *            old path to the file
 	 * @param newPath
 	 *            new path to the file
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the stream threw an exception while writing to it.
 	 */
 	protected void formatGitDiffFirstHeaderLine(ByteArrayOutputStream o,
@@ -1151,11 +1162,13 @@ private void formatHeader(ByteArrayOutputStream o, DiffEntry ent)
 	}
 
 	/**
+	 * Format index line
+	 *
 	 * @param o
 	 *            the stream the formatter will write line data to
 	 * @param ent
 	 *            the DiffEntry to create the FileHeader for
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             writing to the supplied stream failed.
 	 */
 	protected void formatIndexLine(OutputStream o, DiffEntry ent)
@@ -1200,7 +1213,7 @@ private void formatOldNewPaths(ByteArrayOutputStream o, DiffEntry ent)
 		o.write(encode("+++ " + newp + "\n")); //$NON-NLS-1$ //$NON-NLS-2$
 	}
 
-	private int findCombinedEnd(final List<Edit> edits, final int i) {
+	private int findCombinedEnd(List<Edit> edits, int i) {
 		int end = i + 1;
 		while (end < edits.size()
 				&& (combineA(edits, end) || combineB(edits, end)))
@@ -1208,15 +1221,15 @@ private int findCombinedEnd(final List<Edit> edits, final int i) {
 		return end - 1;
 	}
 
-	private boolean combineA(final List<Edit> e, final int i) {
+	private boolean combineA(List<Edit> e, int i) {
 		return e.get(i).getBeginA() - e.get(i - 1).getEndA() <= 2 * context;
 	}
 
-	private boolean combineB(final List<Edit> e, final int i) {
+	private boolean combineB(List<Edit> e, int i) {
 		return e.get(i).getBeginB() - e.get(i - 1).getEndB() <= 2 * context;
 	}
 
-	private static boolean end(final Edit edit, final int a, final int b) {
+	private static boolean end(Edit edit, int a, int b) {
 		return edit.getEndA() <= a && edit.getEndB() <= b;
 	}
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/diff/Edit.java b/org.eclipse.jgit/src/org/eclipse/jgit/diff/Edit.java
index a2e167f..5c876e8 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/diff/Edit.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/diff/Edit.java
@@ -94,7 +94,7 @@ public static enum Type {
 	 * @param bs
 	 *            beginB: start and end of region in sequence B; 0 based.
 	 */
-	public Edit(final int as, final int bs) {
+	public Edit(int as, int bs) {
 		this(as, as, bs, bs);
 	}
 
@@ -110,7 +110,7 @@ public Edit(final int as, final int bs) {
 	 * @param be
 	 *            endB: end of region in sequence B; must be &gt; = bs.
 	 */
-	public Edit(final int as, final int ae, final int bs, final int be) {
+	public Edit(int as, int ae, int bs, int be) {
 		beginA = as;
 		endA = ae;
 
@@ -118,7 +118,11 @@ public Edit(final int as, final int ae, final int bs, final int be) {
 		endB = be;
 	}
 
-	/** @return the type of this region */
+	/**
+	 * Get type
+	 *
+	 * @return the type of this region
+	 */
 	public final Type getType() {
 		if (beginA < endA) {
 			if (beginB < endB)
@@ -134,37 +138,66 @@ public final Type getType() {
 		}
 	}
 
-	/** @return true if the edit is empty (lengths of both a and b is zero). */
+	/**
+	 * Whether edit is empty
+	 *
+	 * @return {@code true} if the edit is empty (lengths of both a and b is
+	 *         zero)
+	 */
 	public final boolean isEmpty() {
 		return beginA == endA && beginB == endB;
 	}
 
-	/** @return start point in sequence A. */
+	/**
+	 * Get start point in sequence A
+	 *
+	 * @return start point in sequence A
+	 */
 	public final int getBeginA() {
 		return beginA;
 	}
 
-	/** @return end point in sequence A. */
+	/**
+	 * Get end point in sequence A
+	 *
+	 * @return end point in sequence A
+	 */
 	public final int getEndA() {
 		return endA;
 	}
 
-	/** @return start point in sequence B. */
+	/**
+	 * Get start point in sequence B
+	 *
+	 * @return start point in sequence B
+	 */
 	public final int getBeginB() {
 		return beginB;
 	}
 
-	/** @return end point in sequence B. */
+	/**
+	 * Get end point in sequence B
+	 *
+	 * @return end point in sequence B
+	 */
 	public final int getEndB() {
 		return endB;
 	}
 
-	/** @return length of the region in A. */
+	/**
+	 * Get length of the region in A
+	 *
+	 * @return length of the region in A
+	 */
 	public final int getLengthA() {
 		return endA - beginA;
 	}
 
-	/** @return length of the region in B. */
+	/**
+	 * Get length of the region in B
+	 *
+	 * @return return length of the region in B
+	 */
 	public final int getLengthB() {
 		return endB - beginB;
 	}
@@ -210,17 +243,23 @@ public final Edit after(Edit cut) {
 		return new Edit(cut.endA, endA, cut.endB, endB);
 	}
 
-	/** Increase {@link #getEndA()} by 1. */
+	/**
+	 * Increase {@link #getEndA()} by 1.
+	 */
 	public void extendA() {
 		endA++;
 	}
 
-	/** Increase {@link #getEndB()} by 1. */
+	/**
+	 * Increase {@link #getEndB()} by 1.
+	 */
 	public void extendB() {
 		endB++;
 	}
 
-	/** Swap A and B, so the edit goes the other direction. */
+	/**
+	 * Swap A and B, so the edit goes the other direction.
+	 */
 	public void swap() {
 		final int sBegin = beginA;
 		final int sEnd = endA;
@@ -232,13 +271,15 @@ public void swap() {
 		endB = sEnd;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public int hashCode() {
 		return beginA ^ endA;
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	public boolean equals(final Object o) {
+	public boolean equals(Object o) {
 		if (o instanceof Edit) {
 			final Edit e = (Edit) o;
 			return this.beginA == e.beginA && this.endA == e.endA
@@ -247,6 +288,7 @@ public boolean equals(final Object o) {
 		return false;
 	}
 
+	/** {@inheritDoc} */
 	@SuppressWarnings("nls")
 	@Override
 	public String toString() {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/diff/EditList.java b/org.eclipse.jgit/src/org/eclipse/jgit/diff/EditList.java
index 14f7b42..617e0d8 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/diff/EditList.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/diff/EditList.java
@@ -45,7 +45,9 @@
 
 import java.util.ArrayList;
 
-/** Specialized list of {@link Edit}s in a document. */
+/**
+ * Specialized list of {@link org.eclipse.jgit.diff.Edit}s in a document.
+ */
 public class EditList extends ArrayList<Edit> {
 	private static final long serialVersionUID = 1L;
 
@@ -62,7 +64,9 @@ public static EditList singleton(Edit edit) {
 		return res;
 	}
 
-	/** Create a new, empty edit list. */
+	/**
+	 * Create a new, empty edit list.
+	 */
 	public EditList() {
 		super(16);
 	}
@@ -78,6 +82,7 @@ public EditList(int capacity) {
 		super(capacity);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public String toString() {
 		return "EditList" + super.toString(); //$NON-NLS-1$
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/diff/HashedSequence.java b/org.eclipse.jgit/src/org/eclipse/jgit/diff/HashedSequence.java
index cb1def6..0492120 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/diff/HashedSequence.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/diff/HashedSequence.java
@@ -44,13 +44,15 @@
 package org.eclipse.jgit.diff;
 
 /**
- * Wraps a {@link Sequence} to assign hash codes to elements.
+ * Wraps a {@link org.eclipse.jgit.diff.Sequence} to assign hash codes to
+ * elements.
  * <p>
  * This sequence acts as a proxy for the real sequence, caching element hash
  * codes so they don't need to be recomputed each time. Sequences of this type
- * must be used with a {@link HashedSequenceComparator}.
+ * must be used with a {@link org.eclipse.jgit.diff.HashedSequenceComparator}.
  * <p>
- * To construct an instance of this type use {@link HashedSequencePair}.
+ * To construct an instance of this type use
+ * {@link org.eclipse.jgit.diff.HashedSequencePair}.
  *
  * @param <S>
  *            the base sequence type.
@@ -65,6 +67,7 @@ public final class HashedSequence<S extends Sequence> extends Sequence {
 		this.hashes = hashes;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public int size() {
 		return base.size();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/diff/HashedSequenceComparator.java b/org.eclipse.jgit/src/org/eclipse/jgit/diff/HashedSequenceComparator.java
index 1ca7fdd..bd9618e 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/diff/HashedSequenceComparator.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/diff/HashedSequenceComparator.java
@@ -44,13 +44,16 @@
 package org.eclipse.jgit.diff;
 
 /**
- * Wrap another comparator for use with {@link HashedSequence}.
+ * Wrap another comparator for use with
+ * {@link org.eclipse.jgit.diff.HashedSequence}.
  * <p>
  * This comparator acts as a proxy for the real comparator, evaluating the
  * cached hash code before testing the underlying comparator's equality.
- * Comparators of this type must be used with a {@link HashedSequence}.
+ * Comparators of this type must be used with a
+ * {@link org.eclipse.jgit.diff.HashedSequence}.
  * <p>
- * To construct an instance of this type use {@link HashedSequencePair}.
+ * To construct an instance of this type use
+ * {@link org.eclipse.jgit.diff.HashedSequencePair}.
  *
  * @param <S>
  *            the base sequence type.
@@ -63,6 +66,7 @@ public final class HashedSequenceComparator<S extends Sequence> extends
 		this.cmp = cmp;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public boolean equals(HashedSequence<S> a, int ai, //
 			HashedSequence<S> b, int bi) {
@@ -70,6 +74,7 @@ public boolean equals(HashedSequence<S> a, int ai, //
 				&& cmp.equals(a.base, ai, b.base, bi);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public int hash(HashedSequence<S> seq, int ptr) {
 		return seq.hashes[ptr];
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/diff/HashedSequencePair.java b/org.eclipse.jgit/src/org/eclipse/jgit/diff/HashedSequencePair.java
index bf6d967..8d12015 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/diff/HashedSequencePair.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/diff/HashedSequencePair.java
@@ -44,7 +44,8 @@
 package org.eclipse.jgit.diff;
 
 /**
- * Wraps two {@link Sequence} instances to cache their element hash codes.
+ * Wraps two {@link org.eclipse.jgit.diff.Sequence} instances to cache their
+ * element hash codes.
  * <p>
  * This pair wraps two sequences that contain cached hash codes for the input
  * sequences.
@@ -79,19 +80,31 @@ public HashedSequencePair(SequenceComparator<? super S> cmp, S a, S b) {
 		this.baseB = b;
 	}
 
-	/** @return obtain a comparator that uses the cached hash codes. */
+	/**
+	 * Get comparator
+	 *
+	 * @return obtain a comparator that uses the cached hash codes
+	 */
 	public HashedSequenceComparator<S> getComparator() {
 		return new HashedSequenceComparator<>(cmp);
 	}
 
-	/** @return wrapper around A that includes cached hash codes. */
+	/**
+	 * Get A
+	 *
+	 * @return wrapper around A that includes cached hash codes
+	 */
 	public HashedSequence<S> getA() {
 		if (cachedA == null)
 			cachedA = wrap(baseA);
 		return cachedA;
 	}
 
-	/** @return wrapper around B that includes cached hash codes. */
+	/**
+	 * Get B
+	 *
+	 * @return wrapper around B that includes cached hash codes
+	 */
 	public HashedSequence<S> getB() {
 		if (cachedB == null)
 			cachedB = wrap(baseB);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/diff/HistogramDiff.java b/org.eclipse.jgit/src/org/eclipse/jgit/diff/HistogramDiff.java
index 4ef5845..c1c6e9a 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/diff/HistogramDiff.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/diff/HistogramDiff.java
@@ -85,8 +85,9 @@
  * So long as {@link #setMaxChainLength(int)} is a small constant (such as 64),
  * the algorithm runs in O(N * D) time, where N is the sum of the input lengths
  * and D is the number of edits in the resulting EditList. If the supplied
- * {@link SequenceComparator} has a good hash function, this implementation
- * typically out-performs {@link MyersDiff}, even though its theoretical running
+ * {@link org.eclipse.jgit.diff.SequenceComparator} has a good hash function,
+ * this implementation typically out-performs
+ * {@link org.eclipse.jgit.diff.MyersDiff}, even though its theoretical running
  * time is the same.
  * <p>
  * This implementation has an internal limitation that prevents it from handling
@@ -130,6 +131,7 @@ public void setMaxChainLength(int maxLen) {
 		maxChainLength = maxLen;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public <S extends Sequence> void diffNonCommon(EditList edits,
 			HashedSequenceComparator<S> cmp, HashedSequence<S> a,
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/diff/HistogramDiffIndex.java b/org.eclipse.jgit/src/org/eclipse/jgit/diff/HistogramDiffIndex.java
index 04c79fc..3f813d8 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/diff/HistogramDiffIndex.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/diff/HistogramDiffIndex.java
@@ -230,7 +230,7 @@ private boolean scanA() {
 		return true;
 	}
 
-	private int tryLongestCommonSequence(final int bPtr) {
+	private int tryLongestCommonSequence(int bPtr) {
 		int bNext = bPtr + 1;
 		int rIdx = table[hash(b, bPtr)];
 		for (long rec; rIdx != 0; rIdx = recNext(rec)) {
@@ -328,7 +328,7 @@ private static int recCnt(long rec) {
 		return ((int) rec) & REC_CNT_MASK;
 	}
 
-	private static int tableBits(final int sz) {
+	private static int tableBits(int sz) {
 		int bits = 31 - Integer.numberOfLeadingZeros(sz);
 		if (bits == 0)
 			bits = 1;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/diff/LowLevelDiffAlgorithm.java b/org.eclipse.jgit/src/org/eclipse/jgit/diff/LowLevelDiffAlgorithm.java
index 55ceec8..9e5ff25 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/diff/LowLevelDiffAlgorithm.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/diff/LowLevelDiffAlgorithm.java
@@ -43,8 +43,11 @@
 
 package org.eclipse.jgit.diff;
 
-/** Compares two sequences primarily based upon hash codes. */
+/**
+ * Compares two sequences primarily based upon hash codes.
+ */
 public abstract class LowLevelDiffAlgorithm extends DiffAlgorithm {
+	/** {@inheritDoc} */
 	@Override
 	public <S extends Sequence> EditList diffNonCommon(
 			SequenceComparator<? super S> cmp, S a, S b) {
@@ -67,10 +70,9 @@ public <S extends Sequence> EditList diffNonCommon(
 	 * proven to have no common starting or ending elements. The expected
 	 * elimination of common starting and ending elements is automatically
 	 * performed by the {@link #diff(SequenceComparator, Sequence, Sequence)}
-	 * method, which invokes this method using {@link Subsequence}s.
+	 * method, which invokes this method using
+	 * {@link org.eclipse.jgit.diff.Subsequence}s.
 	 *
-	 * @param <S>
-	 *            type of sequence being compared.
 	 * @param edits
 	 *            result list to append the region's edits onto.
 	 * @param cmp
@@ -78,11 +80,13 @@ public <S extends Sequence> EditList diffNonCommon(
 	 * @param a
 	 *            the first (also known as old or pre-image) sequence. Edits
 	 *            returned by this algorithm will reference indexes using the
-	 *            'A' side: {@link Edit#getBeginA()}, {@link Edit#getEndA()}.
+	 *            'A' side: {@link org.eclipse.jgit.diff.Edit#getBeginA()},
+	 *            {@link org.eclipse.jgit.diff.Edit#getEndA()}.
 	 * @param b
 	 *            the second (also known as new or post-image) sequence. Edits
 	 *            returned by this algorithm will reference indexes using the
-	 *            'B' side: {@link Edit#getBeginB()}, {@link Edit#getEndB()}.
+	 *            'B' side: {@link org.eclipse.jgit.diff.Edit#getBeginB()},
+	 *            {@link org.eclipse.jgit.diff.Edit#getEndB()}.
 	 * @param region
 	 *            the region being compared within the two sequences.
 	 */
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/diff/MyersDiff.java b/org.eclipse.jgit/src/org/eclipse/jgit/diff/MyersDiff.java
index a3860de..caaffe3 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/diff/MyersDiff.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/diff/MyersDiff.java
@@ -359,7 +359,7 @@ void initialize(int k, int x, int minK, int maxK) {
 			abstract int getLeft(int x);
 			abstract int getRight(int x);
 			abstract boolean isBetter(int left, int right);
-			abstract void adjustMinMaxK(final int k, final int x);
+			abstract void adjustMinMaxK(int k, int x);
 			abstract boolean meets(int d, int k, int x, long snake);
 
 			final long newSnake(int k, int x) {
@@ -469,22 +469,22 @@ final int snake(int k, int x) {
 			}
 
 			@Override
-			final int getLeft(final int x) {
+			final int getLeft(int x) {
 				return x;
 			}
 
 			@Override
-			final int getRight(final int x) {
+			final int getRight(int x) {
 				return x + 1;
 			}
 
 			@Override
-			final boolean isBetter(final int left, final int right) {
+			final boolean isBetter(int left, int right) {
 				return left > right;
 			}
 
 			@Override
-			final void adjustMinMaxK(final int k, final int x) {
+			final void adjustMinMaxK(int k, int x) {
 				if (x >= endA || k + x >= endB) {
 					if (k > backward.middleK)
 						maxK = k;
@@ -517,22 +517,22 @@ final int snake(int k, int x) {
 			}
 
 			@Override
-			final int getLeft(final int x) {
+			final int getLeft(int x) {
 				return x - 1;
 			}
 
 			@Override
-			final int getRight(final int x) {
+			final int getRight(int x) {
 				return x;
 			}
 
 			@Override
-			final boolean isBetter(final int left, final int right) {
+			final boolean isBetter(int left, int right) {
 				return left < right;
 			}
 
 			@Override
-			final void adjustMinMaxK(final int k, final int x) {
+			final void adjustMinMaxK(int k, int x) {
 				if (x <= beginA || k + x <= beginB) {
 					if (k > forward.middleK)
 						maxK = k;
@@ -557,7 +557,10 @@ final boolean meets(int d, int k, int x, long snake) {
 	}
 
 	/**
-	 * @param args two filenames specifying the contents to be diffed
+	 * Main method
+	 *
+	 * @param args
+	 *            two filenames specifying the contents to be diffed
 	 */
 	public static void main(String[] args) {
 		if (args.length != 2) {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/diff/PatchIdDiffFormatter.java b/org.eclipse.jgit/src/org/eclipse/jgit/diff/PatchIdDiffFormatter.java
index 146b910..7f6aa9a 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/diff/PatchIdDiffFormatter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/diff/PatchIdDiffFormatter.java
@@ -58,7 +58,9 @@ public class PatchIdDiffFormatter extends DiffFormatter {
 
 	private final MessageDigest digest;
 
-	/** Initialize a formatter to compute a patch id. */
+	/**
+	 * Initialize a formatter to compute a patch id.
+	 */
 	public PatchIdDiffFormatter() {
 		super(new DigestOutputStream(NullOutputStream.INSTANCE,
 				Constants.newMessageDigest()));
@@ -74,12 +76,14 @@ public ObjectId getCalulatedPatchId() {
 		return ObjectId.fromRaw(digest.digest());
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected void writeHunkHeader(int aStartLine, int aEndLine,
 			int bStartLine, int bEndLine) throws IOException {
 		// The hunk header is not taken into account for patch id calculation
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected void formatIndexLine(OutputStream o, DiffEntry ent)
 			throws IOException {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/diff/RawText.java b/org.eclipse.jgit/src/org/eclipse/jgit/diff/RawText.java
index 5bfee75..bd41d90 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/diff/RawText.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/diff/RawText.java
@@ -44,11 +44,15 @@
 
 package org.eclipse.jgit.diff;
 
+import java.io.EOFException;
 import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
 
+import org.eclipse.jgit.errors.BinaryBlobException;
+import org.eclipse.jgit.errors.LargeObjectException;
+import org.eclipse.jgit.lib.ObjectLoader;
 import org.eclipse.jgit.util.IO;
 import org.eclipse.jgit.util.IntList;
 import org.eclipse.jgit.util.RawParseUtils;
@@ -66,11 +70,11 @@
  * they are converting from "line number" to "element index".
  */
 public class RawText extends Sequence {
-	/** A Rawtext of length 0 */
+	/** A RawText of length 0 */
 	public static final RawText EMPTY_TEXT = new RawText(new byte[0]);
 
 	/** Number of bytes to check for heuristics in {@link #isBinary(byte[])} */
-	private static final int FIRST_FEW_BYTES = 8000;
+	static final int FIRST_FEW_BYTES = 8000;
 
 	/** The file content for this sequence. */
 	protected final byte[] content;
@@ -84,12 +88,29 @@ public class RawText extends Sequence {
 	 * The entire array (indexes 0 through length-1) is used as the content.
 	 *
 	 * @param input
-	 *            the content array. The array is never modified, so passing
-	 *            through cached arrays is safe.
+	 *            the content array. The object retains a reference to this
+	 *            array, so it should be immutable.
 	 */
-	public RawText(final byte[] input) {
+	public RawText(byte[] input) {
+		this(input, RawParseUtils.lineMap(input, 0, input.length));
+	}
+
+	/**
+	 * Create a new sequence from the existing content byte array and the line
+	 * map indicating line boundaries.
+	 *
+	 * @param input
+	 *            the content array. The object retains a reference to this
+	 *            array, so it should be immutable.
+	 * @param lineMap
+	 *            an array with 1-based offsets for the start of each line.
+	 *            The first and last entries should be {@link Integer#MIN_VALUE}
+	 *            and an offset one past the end of the last line, respectively.
+	 * @since 5.0
+	 */
+	public RawText(byte[] input, IntList lineMap) {
 		content = input;
-		lines = RawParseUtils.lineMap(content, 0, content.length);
+		lines = lineMap;
 	}
 
 	/**
@@ -99,14 +120,23 @@ public RawText(final byte[] input) {
 	 *
 	 * @param file
 	 *            the text file.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             if Exceptions occur while reading the file
 	 */
 	public RawText(File file) throws IOException {
 		this(IO.readFully(file));
 	}
 
+	/**
+	 * @return the raw, unprocessed content read.
+	 * @since 4.11
+	 */
+	public byte[] getRawContent() {
+		return content;
+	}
+
 	/** @return total number of items in the sequence. */
+	/** {@inheritDoc} */
 	@Override
 	public int size() {
 		// The line map is always 2 entries larger than the number of lines in
@@ -131,10 +161,10 @@ public int size() {
 	 * @param i
 	 *            index of the line to extract. Note this is 0-based, so line
 	 *            number 1 is actually index 0.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the stream write operation failed.
 	 */
-	public void writeLine(final OutputStream out, final int i)
+	public void writeLine(OutputStream out, int i)
 			throws IOException {
 		int start = getStart(i);
 		int end = getEnd(i);
@@ -208,11 +238,11 @@ protected String decode(int start, int end) {
 		return RawParseUtils.decode(content, start, end);
 	}
 
-	private int getStart(final int i) {
+	private int getStart(int i) {
 		return lines.get(i + 1);
 	}
 
-	private int getEnd(final int i) {
+	private int getEnd(int i) {
 		return lines.get(i + 2);
 	}
 
@@ -240,7 +270,7 @@ public static boolean isBinary(byte[] raw) {
 	 * @param raw
 	 *            input stream containing the raw file content.
 	 * @return true if raw is likely to be a binary file, false otherwise
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             if input stream could not be read
 	 */
 	public static boolean isBinary(InputStream raw) throws IOException {
@@ -295,4 +325,69 @@ public String getLineDelimiter() {
 		else
 			return "\n"; //$NON-NLS-1$
 	}
+
+	/**
+	 * Read a blob object into RawText, or throw BinaryBlobException if the blob
+	 * is binary.
+	 *
+	 * @param ldr
+	 *            the ObjectLoader for the blob
+	 * @param threshold
+	 *            if the blob is larger than this size, it is always assumed to
+	 *            be binary.
+	 * @since 4.10
+	 * @return the RawText representing the blob.
+	 * @throws org.eclipse.jgit.errors.BinaryBlobException
+	 *             if the blob contains binary data.
+	 * @throws java.io.IOException
+	 *             if the input could not be read.
+	 */
+	public static RawText load(ObjectLoader ldr, int threshold)
+			throws IOException, BinaryBlobException {
+		long sz = ldr.getSize();
+
+		if (sz > threshold) {
+			throw new BinaryBlobException();
+		}
+
+		if (sz <= FIRST_FEW_BYTES) {
+			byte[] data = ldr.getCachedBytes(FIRST_FEW_BYTES);
+			if (isBinary(data)) {
+				throw new BinaryBlobException();
+			}
+			return new RawText(data);
+		}
+
+		byte[] head = new byte[FIRST_FEW_BYTES];
+		try (InputStream stream = ldr.openStream()) {
+			int off = 0;
+			int left = head.length;
+			while (left > 0) {
+				int n = stream.read(head, off, left);
+				if (n < 0) {
+					throw new EOFException();
+				}
+				left -= n;
+
+				while (n > 0) {
+					if (head[off] == '\0') {
+						throw new BinaryBlobException();
+					}
+					off++;
+					n--;
+				}
+			}
+
+			byte data[];
+			try {
+				data = new byte[(int)sz];
+			} catch (OutOfMemoryError e) {
+				throw new LargeObjectException.OutOfMemory(e);
+			}
+
+			System.arraycopy(head, 0, data, 0, head.length);
+			IO.readFully(stream, data, off, (int) (sz-off));
+			return new RawText(data, RawParseUtils.lineMapOrBinary(data, 0, (int) sz));
+		}
+	}
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/diff/RawTextComparator.java b/org.eclipse.jgit/src/org/eclipse/jgit/diff/RawTextComparator.java
index 2793fa2..1e68c2f 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/diff/RawTextComparator.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/diff/RawTextComparator.java
@@ -50,7 +50,9 @@
 
 import org.eclipse.jgit.util.IntList;
 
-/** Equivalence function for {@link RawText}. */
+/**
+ * Equivalence function for {@link org.eclipse.jgit.diff.RawText}.
+ */
 public abstract class RawTextComparator extends SequenceComparator<RawText> {
 	/** No special treatment. */
 	public static final RawTextComparator DEFAULT = new RawTextComparator() {
@@ -75,7 +77,7 @@ public boolean equals(RawText a, int ai, RawText b, int bi) {
 		}
 
 		@Override
-		protected int hashRegion(final byte[] raw, int ptr, final int end) {
+		protected int hashRegion(byte[] raw, int ptr, int end) {
 			int hash = 5381;
 			for (; ptr < end; ptr++)
 				hash = ((hash << 5) + hash) + (raw[ptr] & 0xff);
@@ -134,7 +136,9 @@ protected int hashRegion(byte[] raw, int ptr, int end) {
 		}
 	};
 
-	/** Ignores leading whitespace. */
+	/**
+	 * Ignore leading whitespace.
+	 **/
 	public static final RawTextComparator WS_IGNORE_LEADING = new RawTextComparator() {
 		@Override
 		public boolean equals(RawText a, int ai, RawText b, int bi) {
@@ -160,7 +164,7 @@ public boolean equals(RawText a, int ai, RawText b, int bi) {
 		}
 
 		@Override
-		protected int hashRegion(final byte[] raw, int ptr, int end) {
+		protected int hashRegion(byte[] raw, int ptr, int end) {
 			int hash = 5381;
 			ptr = trimLeadingWhitespace(raw, ptr, end);
 			for (; ptr < end; ptr++)
@@ -195,7 +199,7 @@ public boolean equals(RawText a, int ai, RawText b, int bi) {
 		}
 
 		@Override
-		protected int hashRegion(final byte[] raw, int ptr, int end) {
+		protected int hashRegion(byte[] raw, int ptr, int end) {
 			int hash = 5381;
 			end = trimTrailingWhitespace(raw, ptr, end);
 			for (; ptr < end; ptr++)
@@ -240,7 +244,7 @@ public boolean equals(RawText a, int ai, RawText b, int bi) {
 		}
 
 		@Override
-		protected int hashRegion(final byte[] raw, int ptr, int end) {
+		protected int hashRegion(byte[] raw, int ptr, int end) {
 			int hash = 5381;
 			end = trimTrailingWhitespace(raw, ptr, end);
 			while (ptr < end) {
@@ -262,6 +266,7 @@ public int hash(RawText seq, int lno) {
 		return hashRegion(seq.content, begin, end);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public Edit reduceCommonStartEnd(RawText a, RawText b, Edit e) {
 		// This is a faster exact match based form that tries to improve
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/diff/RenameDetector.java b/org.eclipse.jgit/src/org/eclipse/jgit/diff/RenameDetector.java
index d899429..7bb217d 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/diff/RenameDetector.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/diff/RenameDetector.java
@@ -65,7 +65,9 @@
 import org.eclipse.jgit.lib.ProgressMonitor;
 import org.eclipse.jgit.lib.Repository;
 
-/** Detect and resolve object renames. */
+/**
+ * Detect and resolve object renames.
+ */
 public class RenameDetector {
 	private static final int EXACT_RENAME_SCORE = 100;
 
@@ -156,6 +158,8 @@ public RenameDetector(ObjectReader reader, DiffConfig cfg) {
 	}
 
 	/**
+	 * Get rename score
+	 *
 	 * @return minimum score required to pair an add/delete as a rename. The
 	 *         score ranges are within the bounds of (0, 100).
 	 */
@@ -173,7 +177,7 @@ public int getRenameScore() {
 	 *
 	 * @param score
 	 *            new rename score, must be within [0, 100].
-	 * @throws IllegalArgumentException
+	 * @throws java.lang.IllegalArgumentException
 	 *             the score was not within [0, 100].
 	 */
 	public void setRenameScore(int score) {
@@ -184,6 +188,8 @@ public void setRenameScore(int score) {
 	}
 
 	/**
+	 * Get break score
+	 *
 	 * @return the similarity score required to keep modified file pairs
 	 *         together. Any modify pairs that score below this will be broken
 	 *         apart into separate add/deletes. Values less than or equal to
@@ -195,6 +201,8 @@ public int getBreakScore() {
 	}
 
 	/**
+	 * Set break score
+	 *
 	 * @param breakScore
 	 *            the similarity score required to keep modified file pairs
 	 *            together. Any modify pairs that score below this will be
@@ -206,7 +214,11 @@ public void setBreakScore(int breakScore) {
 		this.breakScore = breakScore;
 	}
 
-	/** @return limit on number of paths to perform inexact rename detection. */
+	/**
+	 * Get rename limit
+	 *
+	 * @return limit on number of paths to perform inexact rename detection
+	 */
 	public int getRenameLimit() {
 		return renameLimit;
 	}
@@ -250,7 +262,7 @@ public boolean isOverRenameLimit() {
 	 *
 	 * @param entriesToAdd
 	 *            one or more entries to add.
-	 * @throws IllegalStateException
+	 * @throws java.lang.IllegalStateException
 	 *             if {@code getEntries} was already invoked.
 	 */
 	public void addAll(Collection<DiffEntry> entriesToAdd) {
@@ -290,7 +302,7 @@ public void addAll(Collection<DiffEntry> entriesToAdd) {
 	 *
 	 * @param entry
 	 *            to add.
-	 * @throws IllegalStateException
+	 * @throws java.lang.IllegalStateException
 	 *             if {@code getEntries} was already invoked.
 	 */
 	public void add(DiffEntry entry) {
@@ -302,9 +314,9 @@ public void add(DiffEntry entry) {
 	 * <p>
 	 * This convenience function runs without a progress monitor.
 	 *
-	 * @return an unmodifiable list of {@link DiffEntry}s representing all files
-	 *         that have been changed.
-	 * @throws IOException
+	 * @return an unmodifiable list of {@link org.eclipse.jgit.diff.DiffEntry}s
+	 *         representing all files that have been changed.
+	 * @throws java.io.IOException
 	 *             file contents cannot be read from the repository.
 	 */
 	public List<DiffEntry> compute() throws IOException {
@@ -316,9 +328,9 @@ public List<DiffEntry> compute() throws IOException {
 	 *
 	 * @param pm
 	 *            report progress during the detection phases.
-	 * @return an unmodifiable list of {@link DiffEntry}s representing all files
-	 *         that have been changed.
-	 * @throws IOException
+	 * @return an unmodifiable list of {@link org.eclipse.jgit.diff.DiffEntry}s
+	 *         representing all files that have been changed.
+	 * @throws java.io.IOException
 	 *             file contents cannot be read from the repository.
 	 */
 	public List<DiffEntry> compute(ProgressMonitor pm) throws IOException {
@@ -339,9 +351,9 @@ public List<DiffEntry> compute(ProgressMonitor pm) throws IOException {
 	 *            reader to obtain objects from the repository with.
 	 * @param pm
 	 *            report progress during the detection phases.
-	 * @return an unmodifiable list of {@link DiffEntry}s representing all files
-	 *         that have been changed.
-	 * @throws IOException
+	 * @return an unmodifiable list of {@link org.eclipse.jgit.diff.DiffEntry}s
+	 *         representing all files that have been changed.
+	 * @throws java.io.IOException
 	 *             file contents cannot be read from the repository.
 	 */
 	public List<DiffEntry> compute(ObjectReader reader, ProgressMonitor pm)
@@ -357,9 +369,9 @@ public List<DiffEntry> compute(ObjectReader reader, ProgressMonitor pm)
 	 *            reader to obtain objects from the repository with.
 	 * @param pm
 	 *            report progress during the detection phases.
-	 * @return an unmodifiable list of {@link DiffEntry}s representing all files
-	 *         that have been changed.
-	 * @throws IOException
+	 * @return an unmodifiable list of {@link org.eclipse.jgit.diff.DiffEntry}s
+	 *         representing all files that have been changed.
+	 * @throws java.io.IOException
 	 *             file contents cannot be read from the repository.
 	 */
 	public List<DiffEntry> compute(ContentSource.Pair reader, ProgressMonitor pm)
@@ -393,7 +405,9 @@ public List<DiffEntry> compute(ContentSource.Pair reader, ProgressMonitor pm)
 		return Collections.unmodifiableList(entries);
 	}
 
-	/** Reset this rename detector for another rename detection pass. */
+	/**
+	 * Reset this rename detector for another rename detection pass.
+	 */
 	public void reset() {
 		entries = new ArrayList<>();
 		deleted = new ArrayList<>();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/diff/Sequence.java b/org.eclipse.jgit/src/org/eclipse/jgit/diff/Sequence.java
index 53ab2f9..c475132 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/diff/Sequence.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/diff/Sequence.java
@@ -52,13 +52,19 @@
  * Unlike a List, the members of the sequence are not directly obtainable.
  * <p>
  * Implementations of Sequence are primarily intended for use in content
- * difference detection algorithms, to produce an {@link EditList} of
- * {@link Edit} instances describing how two Sequence instances differ.
+ * difference detection algorithms, to produce an
+ * {@link org.eclipse.jgit.diff.EditList} of {@link org.eclipse.jgit.diff.Edit}
+ * instances describing how two Sequence instances differ.
  * <p>
  * To be compared against another Sequence of the same type, a supporting
- * {@link SequenceComparator} must also be supplied.
+ * {@link org.eclipse.jgit.diff.SequenceComparator} must also be supplied.
  */
 public abstract class Sequence {
 	/** @return total number of items in the sequence. */
+	/**
+	 * Get size
+	 *
+	 * @return size
+	 */
 	public abstract int size();
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/diff/SequenceComparator.java b/org.eclipse.jgit/src/org/eclipse/jgit/diff/SequenceComparator.java
index cc38d4b..ccd0055 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/diff/SequenceComparator.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/diff/SequenceComparator.java
@@ -44,7 +44,8 @@
 package org.eclipse.jgit.diff;
 
 /**
- * Equivalence function for a {@link Sequence} compared by difference algorithm.
+ * Equivalence function for a {@link org.eclipse.jgit.diff.Sequence} compared by
+ * difference algorithm.
  * <p>
  * Difference algorithms can use a comparator to compare portions of two
  * sequences and discover the minimal edits required to transform from one
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/diff/SimilarityIndex.java b/org.eclipse.jgit/src/org/eclipse/jgit/diff/SimilarityIndex.java
index 1c40d7f..5897ffb 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/diff/SimilarityIndex.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/diff/SimilarityIndex.java
@@ -56,8 +56,9 @@
  * Index structure of lines/blocks in one file.
  * <p>
  * This structure can be used to compute an approximation of the similarity
- * between two files. The index is used by {@link SimilarityRenameDetector} to
- * compute scores between files.
+ * between two files. The index is used by
+ * {@link org.eclipse.jgit.diff.SimilarityRenameDetector} to compute scores
+ * between files.
  * <p>
  * To save space in memory, this index uses a space efficient encoding which
  * will not exceed 1 MiB per instance. The index starts out at a smaller size
@@ -114,9 +115,9 @@ public class SimilarityIndex {
 	 * @param obj
 	 *            the object to hash
 	 * @return similarity index for this object
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             file contents cannot be read from the repository.
-	 * @throws TableFullException
+	 * @throws org.eclipse.jgit.diff.SimilarityIndex.TableFullException
 	 *             object hashing overflowed the storage capacity of the
 	 *             SimilarityIndex.
 	 */
@@ -146,23 +147,17 @@ void hash(ObjectLoader obj) throws MissingObjectException, IOException,
 
 	private void hashLargeObject(ObjectLoader obj) throws IOException,
 			TableFullException {
-		ObjectStream in1 = obj.openStream();
 		boolean text;
-		try {
+		try (ObjectStream in1 = obj.openStream()) {
 			text = !RawText.isBinary(in1);
-		} finally {
-			in1.close();
 		}
 
-		ObjectStream in2 = obj.openStream();
-		try {
+		try (ObjectStream in2 = obj.openStream()) {
 			hash(in2, in2.getSize(), text);
-		} finally {
-			in2.close();
 		}
 	}
 
-	void hash(byte[] raw, int ptr, final int end) throws TableFullException {
+	void hash(byte[] raw, int ptr, int end) throws TableFullException {
 		final boolean text = !RawText.isBinary(raw);
 		hashedCnt = 0;
 		while (ptr < end) {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/diff/Subsequence.java b/org.eclipse.jgit/src/org/eclipse/jgit/diff/Subsequence.java
index 50ca613..aa10f6c 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/diff/Subsequence.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/diff/Subsequence.java
@@ -44,11 +44,12 @@
 package org.eclipse.jgit.diff;
 
 /**
- * Wraps a {@link Sequence} to have a narrower range of elements.
+ * Wraps a {@link org.eclipse.jgit.diff.Sequence} to have a narrower range of
+ * elements.
  * <p>
  * This sequence acts as a proxy for the real sequence, translating element
  * indexes on the fly by adding {@code begin} to them. Sequences of this type
- * must be used with a {@link SubsequenceComparator}.
+ * must be used with a {@link org.eclipse.jgit.diff.SubsequenceComparator}.
  *
  * @param <S>
  *            the base sequence type.
@@ -57,8 +58,6 @@ public final class Subsequence<S extends Sequence> extends Sequence {
 	/**
 	 * Construct a subsequence around the A region/base sequence.
 	 *
-	 * @param <S>
-	 *            the base sequence type.
 	 * @param a
 	 *            the A sequence.
 	 * @param region
@@ -72,8 +71,6 @@ public static <S extends Sequence> Subsequence<S> a(S a, Edit region) {
 	/**
 	 * Construct a subsequence around the B region/base sequence.
 	 *
-	 * @param <S>
-	 *            the base sequence type.
 	 * @param b
 	 *            the B sequence.
 	 * @param region
@@ -87,8 +84,6 @@ public static <S extends Sequence> Subsequence<S> b(S b, Edit region) {
 	/**
 	 * Adjust the Edit to reflect positions in the base sequence.
 	 *
-	 * @param <S>
-	 *            the base sequence type.
 	 * @param e
 	 *            edit to adjust in-place. Prior to invocation the indexes are
 	 *            in terms of the two subsequences; after invocation the indexes
@@ -110,8 +105,6 @@ public static <S extends Sequence> void toBase(Edit e, Subsequence<S> a,
 	/**
 	 * Adjust the Edits to reflect positions in the base sequence.
 	 *
-	 * @param <S>
-	 *            the base sequence type.
 	 * @param edits
 	 *            edits to adjust in-place. Prior to invocation the indexes are
 	 *            in terms of the two subsequences; after invocation the indexes
@@ -156,6 +149,7 @@ public Subsequence(S base, int begin, int end) {
 		this.size = end - begin;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public int size() {
 		return size;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/diff/SubsequenceComparator.java b/org.eclipse.jgit/src/org/eclipse/jgit/diff/SubsequenceComparator.java
index dff2a42..9b3889b 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/diff/SubsequenceComparator.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/diff/SubsequenceComparator.java
@@ -44,11 +44,13 @@
 package org.eclipse.jgit.diff;
 
 /**
- * Wrap another comparator for use with {@link Subsequence}.
+ * Wrap another comparator for use with
+ * {@link org.eclipse.jgit.diff.Subsequence}.
  * <p>
  * This comparator acts as a proxy for the real comparator, translating element
  * indexes on the fly by adding the subsequence's begin offset to them.
- * Comparators of this type must be used with a {@link Subsequence}.
+ * Comparators of this type must be used with a
+ * {@link org.eclipse.jgit.diff.Subsequence}.
  *
  * @param <S>
  *            the base sequence type.
@@ -67,11 +69,13 @@ public SubsequenceComparator(SequenceComparator<? super S> cmp) {
 		this.cmp = cmp;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public boolean equals(Subsequence<S> a, int ai, Subsequence<S> b, int bi) {
 		return cmp.equals(a.base, ai + a.begin, b.base, bi + b.begin);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public int hash(Subsequence<S> seq, int ptr) {
 		return cmp.hash(seq.base, ptr + seq.begin);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/BaseDirCacheEditor.java b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/BaseDirCacheEditor.java
index 0fbc1f8..aa229f7 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/BaseDirCacheEditor.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/BaseDirCacheEditor.java
@@ -85,12 +85,14 @@ abstract class BaseDirCacheEditor {
 	 *            estimated number of entries the editor will have upon
 	 *            completion. This sizes the initial entry table.
 	 */
-	protected BaseDirCacheEditor(final DirCache dc, final int ecnt) {
+	protected BaseDirCacheEditor(DirCache dc, int ecnt) {
 		cache = dc;
 		entries = new DirCacheEntry[ecnt];
 	}
 
 	/**
+	 * Get the {@code DirCache}
+	 *
 	 * @return the cache we will update on {@link #finish()}.
 	 */
 	public DirCache getDirCache() {
@@ -109,7 +111,7 @@ public DirCache getDirCache() {
 	 * @param newEntry
 	 *            the new entry to add.
 	 */
-	protected void fastAdd(final DirCacheEntry newEntry) {
+	protected void fastAdd(DirCacheEntry newEntry) {
 		if (entries.length == entryCnt) {
 			final DirCacheEntry[] n = new DirCacheEntry[(entryCnt + 16) * 3 / 2];
 			System.arraycopy(entries, 0, n, 0, entryCnt);
@@ -138,7 +140,7 @@ protected void fastAdd(final DirCacheEntry newEntry) {
 	 * @param cnt
 	 *            number of entries to copy.
 	 */
-	protected void fastKeep(final int pos, int cnt) {
+	protected void fastKeep(int pos, int cnt) {
 		if (entryCnt + cnt > entries.length) {
 			final int m1 = (entryCnt + 16) * 3 / 2;
 			final int m2 = entryCnt + cnt;
@@ -152,7 +154,8 @@ protected void fastKeep(final int pos, int cnt) {
 	}
 
 	/**
-	 * Finish this builder and update the destination {@link DirCache}.
+	 * Finish this builder and update the destination
+	 * {@link org.eclipse.jgit.dircache.DirCache}.
 	 * <p>
 	 * When this method completes this builder instance is no longer usable by
 	 * the calling application. A new builder must be created to make additional
@@ -263,9 +266,9 @@ private static boolean startsWith(byte[] a, byte[] b, int n) {
 	 * @return true if the commit was successful and the file contains the new
 	 *         data; false if the commit failed and the file remains with the
 	 *         old data.
-	 * @throws IllegalStateException
+	 * @throws java.lang.IllegalStateException
 	 *             the lock is not held.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the output file could not be created. The caller no longer
 	 *             holds the lock.
 	 */
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCache.java b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCache.java
index ce52fed..14653fe 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCache.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCache.java
@@ -45,16 +45,16 @@
 
 package org.eclipse.jgit.dircache;
 
+import static java.nio.charset.StandardCharsets.ISO_8859_1;
+
 import java.io.BufferedInputStream;
 import java.io.BufferedOutputStream;
 import java.io.EOFException;
 import java.io.File;
-import java.io.FileInputStream;
 import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
-import java.io.UnsupportedEncodingException;
 import java.security.DigestOutputStream;
 import java.security.MessageDigest;
 import java.text.MessageFormat;
@@ -87,6 +87,7 @@
 import org.eclipse.jgit.util.MutableInteger;
 import org.eclipse.jgit.util.NB;
 import org.eclipse.jgit.util.TemporaryBuffer;
+import org.eclipse.jgit.util.io.SilentFileInputStream;
 
 /**
  * Support for the Git dircache (aka index file).
@@ -112,7 +113,7 @@ public class DirCache {
 
 	static final Comparator<DirCacheEntry> ENT_CMP = new Comparator<DirCacheEntry>() {
 		@Override
-		public int compare(final DirCacheEntry o1, final DirCacheEntry o2) {
+		public int compare(DirCacheEntry o1, DirCacheEntry o2) {
 			final int cr = cmp(o1, o2);
 			if (cr != 0)
 				return cr;
@@ -120,11 +121,11 @@ public int compare(final DirCacheEntry o1, final DirCacheEntry o2) {
 		}
 	};
 
-	static int cmp(final DirCacheEntry a, final DirCacheEntry b) {
+	static int cmp(DirCacheEntry a, DirCacheEntry b) {
 		return cmp(a.path, a.path.length, b);
 	}
 
-	static int cmp(final byte[] aPath, final int aLen, final DirCacheEntry b) {
+	static int cmp(byte[] aPath, int aLen, DirCacheEntry b) {
 		return cmp(aPath, aLen, b.path, b.path.length);
 	}
 
@@ -158,7 +159,7 @@ public static DirCache newInCore() {
 	 *            tree to read. Must identify a tree, not a tree-ish.
 	 * @return a new cache which has no backing store file, but contains the
 	 *         contents of {@code treeId}.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             one or more trees not available from the ObjectReader.
 	 * @since 4.2
 	 */
@@ -182,13 +183,13 @@ public static DirCache read(ObjectReader reader, AnyObjectId treeId)
 	 *            repository containing the index to read
 	 * @return a cache representing the contents of the specified index file (if
 	 *         it exists) or an empty cache if the file does not exist.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the index file is present but could not be read.
-	 * @throws CorruptObjectException
+	 * @throws org.eclipse.jgit.errors.CorruptObjectException
 	 *             the index file is using a format or extension that this
 	 *             library does not support.
 	 */
-	public static DirCache read(final Repository repository)
+	public static DirCache read(Repository repository)
 			throws CorruptObjectException, IOException {
 		final DirCache c = read(repository.getIndexFile(), repository.getFS());
 		c.repository = repository;
@@ -209,13 +210,13 @@ public static DirCache read(final Repository repository)
 	 *            certain file system operations.
 	 * @return a cache representing the contents of the specified index file (if
 	 *         it exists) or an empty cache if the file does not exist.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the index file is present but could not be read.
-	 * @throws CorruptObjectException
+	 * @throws org.eclipse.jgit.errors.CorruptObjectException
 	 *             the index file is using a format or extension that this
 	 *             library does not support.
 	 */
-	public static DirCache read(final File indexLocation, final FS fs)
+	public static DirCache read(File indexLocation, FS fs)
 			throws CorruptObjectException, IOException {
 		final DirCache c = new DirCache(indexLocation, fs);
 		c.read();
@@ -237,14 +238,14 @@ public static DirCache read(final File indexLocation, final FS fs)
 	 *            certain file system operations.
 	 * @return a cache representing the contents of the specified index file (if
 	 *         it exists) or an empty cache if the file does not exist.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the index file is present but could not be read, or the lock
 	 *             could not be obtained.
-	 * @throws CorruptObjectException
+	 * @throws org.eclipse.jgit.errors.CorruptObjectException
 	 *             the index file is using a format or extension that this
 	 *             library does not support.
 	 */
-	public static DirCache lock(final File indexLocation, final FS fs)
+	public static DirCache lock(File indexLocation, FS fs)
 			throws CorruptObjectException, IOException {
 		final DirCache c = new DirCache(indexLocation, fs);
 		if (!c.lock())
@@ -280,10 +281,10 @@ public static DirCache lock(final File indexLocation, final FS fs)
 	 *            listener to be informed when DirCache is committed
 	 * @return a cache representing the contents of the specified index file (if
 	 *         it exists) or an empty cache if the file does not exist.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the index file is present but could not be read, or the lock
 	 *             could not be obtained.
-	 * @throws CorruptObjectException
+	 * @throws org.eclipse.jgit.errors.CorruptObjectException
 	 *             the index file is using a format or extension that this
 	 *             library does not support.
 	 * @since 2.0
@@ -314,10 +315,10 @@ public static DirCache lock(final Repository repository,
 	 *            listener to be informed when DirCache is committed
 	 * @return a cache representing the contents of the specified index file (if
 	 *         it exists) or an empty cache if the file does not exist.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the index file is present but could not be read, or the lock
 	 *             could not be obtained.
-	 * @throws CorruptObjectException
+	 * @throws org.eclipse.jgit.errors.CorruptObjectException
 	 *             the index file is using a format or extension that this
 	 *             library does not support.
 	 */
@@ -372,7 +373,7 @@ public static DirCache lock(final File indexLocation, final FS fs,
 	 *            the file system abstraction which will be necessary to perform
 	 *            certain file system operations.
 	 */
-	public DirCache(final File indexLocation, final FS fs) {
+	public DirCache(File indexLocation, FS fs) {
 		liveFile = indexLocation;
 		clear();
 	}
@@ -381,7 +382,8 @@ public DirCache(final File indexLocation, final FS fs) {
 	 * Create a new builder to update this cache.
 	 * <p>
 	 * Callers should add all entries to the builder, then use
-	 * {@link DirCacheBuilder#finish()} to update this instance.
+	 * {@link org.eclipse.jgit.dircache.DirCacheBuilder#finish()} to update this
+	 * instance.
 	 *
 	 * @return a new builder instance for this cache.
 	 */
@@ -393,7 +395,8 @@ public DirCacheBuilder builder() {
 	 * Create a new editor to recreate this cache.
 	 * <p>
 	 * Callers should add commands to the editor, then use
-	 * {@link DirCacheEditor#finish()} to update this instance.
+	 * {@link org.eclipse.jgit.dircache.DirCacheEditor#finish()} to update this
+	 * instance.
 	 *
 	 * @return a new builder instance for this cache.
 	 */
@@ -401,7 +404,7 @@ public DirCacheEditor editor() {
 		return new DirCacheEditor(this, entryCnt + 16);
 	}
 
-	void replace(final DirCacheEntry[] e, final int cnt) {
+	void replace(DirCacheEntry[] e, int cnt) {
 		sortedEntries = e;
 		entryCnt = cnt;
 		tree = null;
@@ -414,10 +417,10 @@ void replace(final DirCacheEntry[] e, final int cnt) {
 	 * the last time we consulted it. A missing index file will be treated as
 	 * though it were present but had no file entries in it.
 	 *
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the index file is present but could not be read. This
 	 *             DirCache instance may not be populated correctly.
-	 * @throws CorruptObjectException
+	 * @throws org.eclipse.jgit.errors.CorruptObjectException
 	 *             the index file is using a format or extension that this
 	 *             library does not support.
 	 */
@@ -427,18 +430,10 @@ public void read() throws IOException, CorruptObjectException {
 		if (!liveFile.exists())
 			clear();
 		else if (snapshot == null || snapshot.isModified(liveFile)) {
-			try {
-				final FileInputStream inStream = new FileInputStream(liveFile);
-				try {
-					clear();
-					readFrom(inStream);
-				} finally {
-					try {
-						inStream.close();
-					} catch (IOException err2) {
-						// Ignore any close failures.
-					}
-				}
+			try (SilentFileInputStream inStream = new SilentFileInputStream(
+					liveFile)) {
+				clear();
+				readFrom(inStream);
 			} catch (FileNotFoundException fnfe) {
 				if (liveFile.exists()) {
 					// Panic: the index file exists but we can't read it
@@ -456,8 +451,10 @@ else if (snapshot == null || snapshot.isModified(liveFile)) {
 	}
 
 	/**
-	 * @return true if the memory state differs from the index file
-	 * @throws IOException
+	 * Whether the memory state differs from the index file
+	 *
+	 * @return {@code true} if the memory state differs from the index file
+	 * @throws java.io.IOException
 	 */
 	public boolean isOutdated() throws IOException {
 		if (liveFile == null || !liveFile.exists())
@@ -465,7 +462,9 @@ public boolean isOutdated() throws IOException {
 		return snapshot == null || snapshot.isModified(liveFile);
 	}
 
-	/** Empty this index, removing all entries. */
+	/**
+	 * Empty this index, removing all entries.
+	 */
 	public void clear() {
 		snapshot = null;
 		sortedEntries = NO_ENTRIES;
@@ -474,7 +473,7 @@ public void clear() {
 		readIndexChecksum = NO_CHECKSUM;
 	}
 
-	private void readFrom(final InputStream inStream) throws IOException,
+	private void readFrom(InputStream inStream) throws IOException,
 			CorruptObjectException {
 		final BufferedInputStream in = new BufferedInputStream(inStream);
 		final MessageDigest md = Constants.newMessageDigest();
@@ -582,12 +581,11 @@ private void skipOptionalExtension(final InputStream in,
 		}
 	}
 
-	private static String formatExtensionName(final byte[] hdr)
-			throws UnsupportedEncodingException {
-		return "'" + new String(hdr, 0, 4, "ISO-8859-1") + "'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+	private static String formatExtensionName(byte[] hdr) {
+		return "'" + new String(hdr, 0, 4, ISO_8859_1) + "'"; //$NON-NLS-1$ //$NON-NLS-2$
 	}
 
-	private static boolean is_DIRC(final byte[] hdr) {
+	private static boolean is_DIRC(byte[] hdr) {
 		if (hdr.length < SIG_DIRC.length)
 			return false;
 		for (int i = 0; i < SIG_DIRC.length; i++)
@@ -601,7 +599,7 @@ private static boolean is_DIRC(final byte[] hdr) {
 	 *
 	 * @return true if the lock is now held by the caller; false if it is held
 	 *         by someone else.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the output file could not be created. The caller does not
 	 *             hold the lock.
 	 */
@@ -628,7 +626,7 @@ public boolean lock() throws IOException {
 	 * Once written the lock is closed and must be either committed with
 	 * {@link #commit()} or rolled back with {@link #unlock()}.
 	 *
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the output file could not be created. The caller no longer
 	 *             holds the lock.
 	 */
@@ -650,13 +648,17 @@ public void write() throws IOException {
 		}
 	}
 
-	void writeTo(File dir, final OutputStream os) throws IOException {
+	void writeTo(File dir, OutputStream os) throws IOException {
 		final MessageDigest foot = Constants.newMessageDigest();
 		final DigestOutputStream dos = new DigestOutputStream(os, foot);
 
 		boolean extended = false;
-		for (int i = 0; i < entryCnt; i++)
-			extended |= sortedEntries[i].isExtended();
+		for (int i = 0; i < entryCnt; i++) {
+			if (sortedEntries[i].isExtended()) {
+				extended = true;
+				break;
+			}
+		}
 
 		// Write the header.
 		//
@@ -700,6 +702,8 @@ void writeTo(File dir, final OutputStream os) throws IOException {
 		}
 
 		if (writeTree) {
+			@SuppressWarnings("resource") // Explicitly closed in try block, and
+											// destroyed in finally
 			TemporaryBuffer bb = new TemporaryBuffer.LocalFile(dir, 5 << 20);
 			try {
 				tree.write(tmp, bb);
@@ -726,23 +730,25 @@ void writeTo(File dir, final OutputStream os) throws IOException {
 	 * @return true if the commit was successful and the file contains the new
 	 *         data; false if the commit failed and the file remains with the
 	 *         old data.
-	 * @throws IllegalStateException
+	 * @throws java.lang.IllegalStateException
 	 *             the lock is not held.
 	 */
 	public boolean commit() {
 		final LockFile tmp = myLock;
 		requireLocked(tmp);
 		myLock = null;
-		if (!tmp.commit())
+		if (!tmp.commit()) {
 			return false;
+		}
 		snapshot = tmp.getCommitSnapshot();
 		if (indexChangedListener != null
-				&& !Arrays.equals(readIndexChecksum, writeIndexChecksum))
-			indexChangedListener.onIndexChanged(new IndexChangedEvent());
+				&& !Arrays.equals(readIndexChecksum, writeIndexChecksum)) {
+			indexChangedListener.onIndexChanged(new IndexChangedEvent(true));
+		}
 		return true;
 	}
 
-	private void requireLocked(final LockFile tmp) {
+	private void requireLocked(LockFile tmp) {
 		if (liveFile == null)
 			throw new IllegalStateException(JGitText.get().dirCacheIsNotLocked);
 		if (tmp == null)
@@ -773,7 +779,7 @@ public void unlock() {
 	 *         the index; pass to {@link #getEntry(int)} to obtain the entry
 	 *         information. If &lt; 0 the entry does not exist in the index.
 	 */
-	public int findEntry(final String path) {
+	public int findEntry(String path) {
 		final byte[] p = Constants.encode(path);
 		return findEntry(p, p.length);
 	}
@@ -829,7 +835,7 @@ else if (cmp == 0) {
 	 *            entry position of the path that should be skipped.
 	 * @return position of the next entry whose path is after the input.
 	 */
-	public int nextEntry(final int position) {
+	public int nextEntry(int position) {
 		DirCacheEntry last = sortedEntries[position];
 		int nextIdx = position + 1;
 		while (nextIdx < entryCnt) {
@@ -842,7 +848,7 @@ public int nextEntry(final int position) {
 		return nextIdx;
 	}
 
-	int nextEntry(final byte[] p, final int pLen, int nextIdx) {
+	int nextEntry(byte[] p, int pLen, int nextIdx) {
 		while (nextIdx < entryCnt) {
 			final DirCacheEntry next = sortedEntries[nextIdx];
 			if (!DirCacheTree.peq(p, next.path, pLen))
@@ -876,7 +882,7 @@ public int getEntryCount() {
 	 *            position of the entry to get.
 	 * @return the entry at position <code>i</code>.
 	 */
-	public DirCacheEntry getEntry(final int i) {
+	public DirCacheEntry getEntry(int i) {
 		return sortedEntries[i];
 	}
 
@@ -887,7 +893,7 @@ public DirCacheEntry getEntry(final int i) {
 	 *            the path to search for.
 	 * @return the entry for the given <code>path</code>.
 	 */
-	public DirCacheEntry getEntry(final String path) {
+	public DirCacheEntry getEntry(String path) {
 		final int i = findEntry(path);
 		return i < 0 ? null : sortedEntries[i];
 	}
@@ -936,7 +942,7 @@ void toArray(final int i, final DirCacheEntry[] dst, final int off,
 	 * @return the cache tree; null if there is no current cache tree available
 	 *         and <code>build</code> was false.
 	 */
-	public DirCacheTree getCacheTree(final boolean build) {
+	public DirCacheTree getCacheTree(boolean build) {
 		if (build) {
 			if (tree == null)
 				tree = new DirCacheTree();
@@ -953,16 +959,16 @@ public DirCacheTree getCacheTree(final boolean build) {
 	 *            responsible for flushing the inserter before trying to use the
 	 *            returned tree identity.
 	 * @return identity for the root tree.
-	 * @throws UnmergedPathException
+	 * @throws org.eclipse.jgit.errors.UnmergedPathException
 	 *             one or more paths contain higher-order stages (stage &gt; 0),
 	 *             which cannot be stored in a tree object.
-	 * @throws IllegalStateException
+	 * @throws java.lang.IllegalStateException
 	 *             one or more paths contain an invalid mode which should never
 	 *             appear in a tree object.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             an unexpected error occurred writing to the object store.
 	 */
-	public ObjectId writeTree(final ObjectInserter ow)
+	public ObjectId writeTree(ObjectInserter ow)
 			throws UnmergedPathException, IOException {
 		return getCacheTree(true).writeTree(sortedEntries, 0, 0, ow);
 	}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheBuildIterator.java b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheBuildIterator.java
index c10e416..e80544e 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheBuildIterator.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheBuildIterator.java
@@ -54,12 +54,14 @@
 import org.eclipse.jgit.treewalk.AbstractTreeIterator;
 
 /**
- * Iterate and update a {@link DirCache} as part of a <code>TreeWalk</code>.
+ * Iterate and update a {@link org.eclipse.jgit.dircache.DirCache} as part of a
+ * <code>TreeWalk</code>.
  * <p>
- * Like {@link DirCacheIterator} this iterator allows a DirCache to be used in
- * parallel with other sorts of iterators in a TreeWalk. However any entry which
- * appears in the source DirCache and which is skipped by the TreeFilter is
- * automatically copied into {@link DirCacheBuilder}, thus retaining it in the
+ * Like {@link org.eclipse.jgit.dircache.DirCacheIterator} this iterator allows
+ * a DirCache to be used in parallel with other sorts of iterators in a
+ * TreeWalk. However any entry which appears in the source DirCache and which is
+ * skipped by the TreeFilter is automatically copied into
+ * {@link org.eclipse.jgit.dircache.DirCacheBuilder}, thus retaining it in the
  * newly updated index.
  * <p>
  * This iterator is suitable for update processes, or even a simple delete
@@ -94,7 +96,7 @@ public class DirCacheBuildIterator extends DirCacheIterator {
 	 *            the cache builder for the cache to walk. The cache must be
 	 *            already loaded into memory.
 	 */
-	public DirCacheBuildIterator(final DirCacheBuilder dcb) {
+	public DirCacheBuildIterator(DirCacheBuilder dcb) {
 		super(dcb.getDirCache());
 		builder = dcb;
 	}
@@ -105,8 +107,9 @@ public DirCacheBuildIterator(final DirCacheBuilder dcb) {
 		builder = p.builder;
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	public AbstractTreeIterator createSubtreeIterator(final ObjectReader reader)
+	public AbstractTreeIterator createSubtreeIterator(ObjectReader reader)
 			throws IncorrectObjectTypeException, IOException {
 		if (currentSubtree == null)
 			throw new IncorrectObjectTypeException(getEntryObjectId(),
@@ -114,6 +117,7 @@ public AbstractTreeIterator createSubtreeIterator(final ObjectReader reader)
 		return new DirCacheBuildIterator(this, currentSubtree);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void skip() throws CorruptObjectException {
 		if (currentSubtree != null)
@@ -123,6 +127,7 @@ public void skip() throws CorruptObjectException {
 		next(1);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void stopWalk() {
 		final int cur = ptr;
@@ -131,6 +136,7 @@ public void stopWalk() {
 			builder.keep(cur, cnt - cur);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected boolean needsStopWalk() {
 		return ptr < cache.getEntryCount();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheBuilder.java b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheBuilder.java
index 676a6ab..c5ff9ac 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheBuilder.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheBuilder.java
@@ -57,7 +57,8 @@
 import org.eclipse.jgit.treewalk.CanonicalTreeParser;
 
 /**
- * Updates a {@link DirCache} by adding individual {@link DirCacheEntry}s.
+ * Updates a {@link org.eclipse.jgit.dircache.DirCache} by adding individual
+ * {@link org.eclipse.jgit.dircache.DirCacheEntry}s.
  * <p>
  * A builder always starts from a clean slate and appends in every single
  * <code>DirCacheEntry</code> which the final updated index must have to reflect
@@ -82,7 +83,7 @@ public class DirCacheBuilder extends BaseDirCacheEditor {
 	 *            estimated number of entries the builder will have upon
 	 *            completion. This sizes the initial entry table.
 	 */
-	protected DirCacheBuilder(final DirCache dc, final int ecnt) {
+	protected DirCacheBuilder(DirCache dc, int ecnt) {
 		super(dc, ecnt);
 	}
 
@@ -98,10 +99,10 @@ protected DirCacheBuilder(final DirCache dc, final int ecnt) {
 	 *
 	 * @param newEntry
 	 *            the new entry to add.
-	 * @throws IllegalArgumentException
+	 * @throws java.lang.IllegalArgumentException
 	 *             If the FileMode of the entry was not set by the caller.
 	 */
-	public void add(final DirCacheEntry newEntry) {
+	public void add(DirCacheEntry newEntry) {
 		if (newEntry.getRawMode() == 0)
 			throw new IllegalArgumentException(MessageFormat.format(
 					JGitText.get().fileModeNotSetForPath,
@@ -130,7 +131,7 @@ public void add(final DirCacheEntry newEntry) {
 	 * @param cnt
 	 *            number of entries to copy.
 	 */
-	public void keep(final int pos, int cnt) {
+	public void keep(int pos, int cnt) {
 		beforeAdd(cache.getEntry(pos));
 		fastKeep(pos, cnt);
 	}
@@ -161,7 +162,7 @@ public void keep(final int pos, int cnt) {
 	 *            under <code>pathPrefix</code>. The ObjectId must be that of a
 	 *            tree; the caller is responsible for dereferencing a tag or
 	 *            commit (if necessary).
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             a tree cannot be read to iterate through its entries.
 	 */
 	public void addTree(byte[] pathPrefix, int stage, ObjectReader reader,
@@ -218,6 +219,7 @@ private static DirCacheEntry toEntry(int stage, CanonicalTreeParser i) {
 		return e;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void finish() {
 		if (!sorted)
@@ -225,7 +227,7 @@ public void finish() {
 		replace();
 	}
 
-	private void beforeAdd(final DirCacheEntry newEntry) {
+	private void beforeAdd(DirCacheEntry newEntry) {
 		if (sorted && entryCnt > 0) {
 			final DirCacheEntry lastEntry = entries[entryCnt - 1];
 			final int cr = DirCache.cmp(lastEntry, newEntry);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java
index a6ab9c8..0b03eb1 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java
@@ -42,6 +42,8 @@
 
 package org.eclipse.jgit.dircache;
 
+import static org.eclipse.jgit.treewalk.TreeWalk.OperationType.CHECKOUT_OP;
+
 import java.io.File;
 import java.io.FileOutputStream;
 import java.io.IOException;
@@ -54,6 +56,7 @@
 import java.util.List;
 import java.util.Map;
 
+import org.eclipse.jgit.api.errors.CanceledException;
 import org.eclipse.jgit.api.errors.FilterFailedException;
 import org.eclipse.jgit.attributes.FilterCommand;
 import org.eclipse.jgit.attributes.FilterCommandRegistry;
@@ -64,6 +67,7 @@
 import org.eclipse.jgit.errors.MissingObjectException;
 import org.eclipse.jgit.events.WorkingTreeModifiedEvent;
 import org.eclipse.jgit.internal.JGitText;
+import org.eclipse.jgit.lib.ConfigConstants;
 import org.eclipse.jgit.lib.Constants;
 import org.eclipse.jgit.lib.CoreConfig.AutoCRLF;
 import org.eclipse.jgit.lib.CoreConfig.EolStreamType;
@@ -74,6 +78,7 @@
 import org.eclipse.jgit.lib.ObjectId;
 import org.eclipse.jgit.lib.ObjectLoader;
 import org.eclipse.jgit.lib.ObjectReader;
+import org.eclipse.jgit.lib.ProgressMonitor;
 import org.eclipse.jgit.lib.Repository;
 import org.eclipse.jgit.treewalk.AbstractTreeIterator;
 import org.eclipse.jgit.treewalk.CanonicalTreeParser;
@@ -156,7 +161,11 @@ public CheckoutMetadata(EolStreamType eolStreamType,
 
 	private boolean performingCheckout;
 
+	private ProgressMonitor monitor = NullProgressMonitor.INSTANCE;
+
 	/**
+	 * Get list of updated paths and smudgeFilterCommands
+	 *
 	 * @return a list of updated paths and smudgeFilterCommands
 	 */
 	public Map<String, CheckoutMetadata> getUpdated() {
@@ -164,6 +173,8 @@ public Map<String, CheckoutMetadata> getUpdated() {
 	}
 
 	/**
+	 * Get a list of conflicts created by this checkout
+	 *
 	 * @return a list of conflicts created by this checkout
 	 */
 	public List<String> getConflicts() {
@@ -171,19 +182,24 @@ public List<String> getConflicts() {
 	}
 
 	/**
+	 * Get list of paths of files which couldn't be deleted during last call to
+	 * {@link #checkout()}
+	 *
 	 * @return a list of paths (relative to the start of the working tree) of
 	 *         files which couldn't be deleted during last call to
 	 *         {@link #checkout()} . {@link #checkout()} detected that these
 	 *         files should be deleted but the deletion in the filesystem failed
 	 *         (e.g. because a file was locked). To have a consistent state of
 	 *         the working tree these files have to be deleted by the callers of
-	 *         {@link DirCacheCheckout}.
+	 *         {@link org.eclipse.jgit.dircache.DirCacheCheckout}.
 	 */
 	public List<String> getToBeDeleted() {
 		return toBeDeleted;
 	}
 
 	/**
+	 * Get list of all files removed by this checkout
+	 *
 	 * @return a list of all files removed by this checkout
 	 */
 	public List<String> getRemoved() {
@@ -204,7 +220,7 @@ public List<String> getRemoved() {
 	 *            the id of the tree we want to fast-forward to
 	 * @param workingTree
 	 *            an iterator over the repositories Working Tree
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 */
 	public DirCacheCheckout(Repository repo, ObjectId headCommitTree, DirCache dc,
 			ObjectId mergeCommitTree, WorkingTreeIterator workingTree)
@@ -220,7 +236,8 @@ public DirCacheCheckout(Repository repo, ObjectId headCommitTree, DirCache dc,
 	/**
 	 * Constructs a DirCacheCeckout for merging and checking out two trees (HEAD
 	 * and mergeCommitTree) and the index. As iterator over the working tree
-	 * this constructor creates a standard {@link FileTreeIterator}
+	 * this constructor creates a standard
+	 * {@link org.eclipse.jgit.treewalk.FileTreeIterator}
 	 *
 	 * @param repo
 	 *            the repository in which we do the checkout
@@ -230,7 +247,7 @@ public DirCacheCheckout(Repository repo, ObjectId headCommitTree, DirCache dc,
 	 *            the (already locked) Dircache for this repo
 	 * @param mergeCommitTree
 	 *            the id of the tree we want to fast-forward to
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 */
 	public DirCacheCheckout(Repository repo, ObjectId headCommitTree,
 			DirCache dc, ObjectId mergeCommitTree) throws IOException {
@@ -249,7 +266,7 @@ public DirCacheCheckout(Repository repo, ObjectId headCommitTree,
 	 *            the id of the tree we want to fast-forward to
 	 * @param workingTree
 	 *            an iterator over the repositories Working Tree
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 */
 	public DirCacheCheckout(Repository repo, DirCache dc,
 			ObjectId mergeCommitTree, WorkingTreeIterator workingTree)
@@ -260,7 +277,7 @@ public DirCacheCheckout(Repository repo, DirCache dc,
 	/**
 	 * Constructs a DirCacheCeckout for checking out one tree, merging with the
 	 * index. As iterator over the working tree this constructor creates a
-	 * standard {@link FileTreeIterator}
+	 * standard {@link org.eclipse.jgit.treewalk.FileTreeIterator}
 	 *
 	 * @param repo
 	 *            the repository in which we do the checkout
@@ -268,7 +285,7 @@ public DirCacheCheckout(Repository repo, DirCache dc,
 	 *            the (already locked) Dircache for this repo
 	 * @param mergeCommitTree
 	 *            the id of the tree of the
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 */
 	public DirCacheCheckout(Repository repo, DirCache dc,
 			ObjectId mergeCommitTree) throws IOException {
@@ -276,11 +293,23 @@ public DirCacheCheckout(Repository repo, DirCache dc,
 	}
 
 	/**
+	 * Set a progress monitor which can be passed to built-in filter commands,
+	 * providing progress information for long running tasks.
+	 *
+	 * @param monitor
+	 *            the {@link ProgressMonitor}
+	 * @since 4.11
+	 */
+	public void setProgressMonitor(ProgressMonitor monitor) {
+		this.monitor = monitor != null ? monitor : NullProgressMonitor.INSTANCE;
+	}
+
+	/**
 	 * Scan head, index and merge tree. Used during normal checkout or merge
 	 * operations.
 	 *
-	 * @throws CorruptObjectException
-	 * @throws IOException
+	 * @throws org.eclipse.jgit.errors.CorruptObjectException
+	 * @throws java.io.IOException
 	 */
 	public void preScanTwoTrees() throws CorruptObjectException, IOException {
 		removed.clear();
@@ -316,10 +345,10 @@ private void addTree(TreeWalk tw, ObjectId id) throws MissingObjectException, In
 	 * Scan index and merge tree (no HEAD). Used e.g. for initial checkout when
 	 * there is no head yet.
 	 *
-	 * @throws MissingObjectException
-	 * @throws IncorrectObjectTypeException
-	 * @throws CorruptObjectException
-	 * @throws IOException
+	 * @throws org.eclipse.jgit.errors.MissingObjectException
+	 * @throws org.eclipse.jgit.errors.IncorrectObjectTypeException
+	 * @throws org.eclipse.jgit.errors.CorruptObjectException
+	 * @throws java.io.IOException
 	 */
 	public void prescanOneTree()
 			throws MissingObjectException, IncorrectObjectTypeException,
@@ -437,7 +466,8 @@ void processEntry(CanonicalTreeParser m, DirCacheBuildIterator i,
 	}
 
 	/**
-	 * Execute this checkout. A {@link WorkingTreeModifiedEvent} is fired if the
+	 * Execute this checkout. A
+	 * {@link org.eclipse.jgit.events.WorkingTreeModifiedEvent} is fired if the
 	 * working tree was modified; even if the checkout fails.
 	 *
 	 * @return <code>false</code> if this method could not delete all the files
@@ -447,12 +477,15 @@ void processEntry(CanonicalTreeParser m, DirCacheBuildIterator i,
 	 *         Although <code>false</code> is returned the checkout was
 	 *         successful and the working tree was updated for all other files.
 	 *         <code>true</code> is returned when no such problem occurred
-	 *
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 */
 	public boolean checkout() throws IOException {
 		try {
 			return doCheckout();
+		} catch (CanceledException ce) {
+			// should actually be propagated, but this would change a LOT of
+			// APIs
+			throw new IOException(ce);
 		} finally {
 			try {
 				dc.unlock();
@@ -470,7 +503,7 @@ public boolean checkout() throws IOException {
 
 	private boolean doCheckout() throws CorruptObjectException, IOException,
 			MissingObjectException, IncorrectObjectTypeException,
-			CheckoutConflictException, IndexWriteException {
+			CheckoutConflictException, IndexWriteException, CanceledException {
 		toBeDeleted.clear();
 		try (ObjectReader objectReader = repo.getObjectDatabase().newReader()) {
 			if (headCommitTree != null)
@@ -488,6 +521,10 @@ private boolean doCheckout() throws CorruptObjectException, IOException,
 			// update our index
 			builder.finish();
 
+			// init progress reporting
+			int numTotal = removed.size() + updated.size();
+			monitor.beginTask(JGitText.get().checkingOutFiles, numTotal);
+
 			performingCheckout = true;
 			File file = null;
 			String last = null;
@@ -513,6 +550,12 @@ private boolean doCheckout() throws CorruptObjectException, IOException,
 						removeEmptyParents(new File(repo.getWorkTree(), last));
 					last = r;
 				}
+				monitor.update(1);
+				if (monitor.isCancelled()) {
+					throw new CanceledException(MessageFormat.format(
+							JGitText.get().operationCanceled,
+							JGitText.get().checkingOutFiles));
+				}
 			}
 			if (file != null) {
 				removeEmptyParents(file);
@@ -528,10 +571,19 @@ private boolean doCheckout() throws CorruptObjectException, IOException,
 					String path = e.getKey();
 					CheckoutMetadata meta = e.getValue();
 					DirCacheEntry entry = dc.getEntry(path);
-					if (!FileMode.GITLINK.equals(entry.getRawMode())) {
+					if (FileMode.GITLINK.equals(entry.getRawMode())) {
+						checkoutGitlink(path, entry);
+					} else {
 						checkoutEntry(repo, entry, objectReader, false, meta);
 					}
 					e = null;
+
+					monitor.update(1);
+					if (monitor.isCancelled()) {
+						throw new CanceledException(MessageFormat.format(
+								JGitText.get().operationCanceled,
+								JGitText.get().checkingOutFiles));
+					}
 				}
 			} catch (Exception ex) {
 				// We didn't actually modify the current entry nor any that
@@ -545,6 +597,8 @@ private boolean doCheckout() throws CorruptObjectException, IOException,
 				}
 				throw ex;
 			}
+			monitor.endTask();
+
 			// commit the index builder - a new index is persisted
 			if (!builder.commit())
 				throw new IndexWriteException();
@@ -552,6 +606,14 @@ private boolean doCheckout() throws CorruptObjectException, IOException,
 		return toBeDeleted.size() == 0;
 	}
 
+	private void checkoutGitlink(String path, DirCacheEntry entry)
+			throws IOException {
+		File gitlinkDir = new File(repo.getWorkTree(), path);
+		FileUtils.mkdirs(gitlinkDir, true);
+		FS fs = repo.getFS();
+		entry.setLastModified(fs.lastModified(gitlinkDir));
+	}
+
 	private static ArrayList<String> filterOut(ArrayList<String> strings,
 			IntList indicesToRemove) {
 		int n = indicesToRemove.size();
@@ -1148,7 +1210,8 @@ private void remove(String path) {
 	private void update(String path, ObjectId mId, FileMode mode)
 			throws IOException {
 		if (!FileMode.TREE.equals(mode)) {
-			updated.put(path, new CheckoutMetadata(walk.getEolStreamType(),
+			updated.put(path, new CheckoutMetadata(
+					walk.getEolStreamType(CHECKOUT_OP),
 					walk.getFilterCommand(Constants.ATTR_FILTER_TYPE_SMUDGE)));
 
 			DirCacheEntry entry = new DirCacheEntry(path, DirCacheEntry.STAGE_0);
@@ -1160,10 +1223,12 @@ private void update(String path, ObjectId mId, FileMode mode)
 
 	/**
 	 * If <code>true</code>, will scan first to see if it's possible to check
-	 * out, otherwise throw {@link CheckoutConflictException}. If
+	 * out, otherwise throw
+	 * {@link org.eclipse.jgit.errors.CheckoutConflictException}. If
 	 * <code>false</code>, it will silently deal with the problem.
 	 *
 	 * @param failOnConflict
+	 *            a boolean.
 	 */
 	public void setFailOnConflict(boolean failOnConflict) {
 		this.failOnConflict = failOnConflict;
@@ -1283,8 +1348,8 @@ private boolean isModifiedSubtree_IndexTree(String path, ObjectId tree)
 	 * <p>
 	 * <b>Note:</b> if the entry path on local file system exists as a non-empty
 	 * directory, and the target entry type is a link or file, the checkout will
-	 * fail with {@link IOException} since existing non-empty directory cannot
-	 * be renamed to file or link without deleting it recursively.
+	 * fail with {@link java.io.IOException} since existing non-empty directory
+	 * cannot be renamed to file or link without deleting it recursively.
 	 * </p>
 	 *
 	 * <p>
@@ -1299,7 +1364,7 @@ private boolean isModifiedSubtree_IndexTree(String path, ObjectId tree)
 	 *            the entry containing new mode and content
 	 * @param or
 	 *            object reader to use for checkout
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 * @since 3.6
 	 */
 	public static void checkoutEntry(Repository repo, DirCacheEntry entry,
@@ -1341,8 +1406,7 @@ public static void checkoutEntry(Repository repo, DirCacheEntry entry,
 	 *            checked out</li>
 	 *            <li>eolStreamType used for stream conversion</li>
 	 *            </ul>
-	 *
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 * @since 4.2
 	 */
 	public static void checkoutEntry(Repository repo, DirCacheEntry entry,
@@ -1476,6 +1540,10 @@ private static void runExternalFilterCommand(Repository repo,
 	private static void runBuiltinFilterCommand(Repository repo,
 			CheckoutMetadata checkoutMetadata, ObjectLoader ol,
 			OutputStream channel) throws MissingObjectException, IOException {
+		boolean isMandatory = repo.getConfig().getBoolean(
+				ConfigConstants.CONFIG_FILTER_SECTION,
+				ConfigConstants.CONFIG_SECTION_LFS,
+				ConfigConstants.CONFIG_KEY_REQUIRED, false);
 		FilterCommand command = null;
 		try {
 			command = FilterCommandRegistry.createFilterCommand(
@@ -1483,9 +1551,14 @@ private static void runBuiltinFilterCommand(Repository repo,
 					channel);
 		} catch (IOException e) {
 			LOG.error(JGitText.get().failedToDetermineFilterDefinition, e);
-			// In case an IOException occurred during creating of the command
-			// then proceed as if there would not have been a builtin filter.
-			ol.copyTo(channel);
+			if (!isMandatory) {
+				// In case an IOException occurred during creating of the
+				// command then proceed as if there would not have been a
+				// builtin filter (only if the filter is not mandatory).
+				ol.copyTo(channel);
+			} else {
+				throw e;
+			}
 		}
 		if (command != null) {
 			while (command.run() != -1) {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheEditor.java b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheEditor.java
index 22bedcf..74ba97f 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheEditor.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheEditor.java
@@ -60,14 +60,16 @@
 import org.eclipse.jgit.util.Paths;
 
 /**
- * Updates a {@link DirCache} by supplying discrete edit commands.
+ * Updates a {@link org.eclipse.jgit.dircache.DirCache} by supplying discrete
+ * edit commands.
  * <p>
- * An editor updates a DirCache by taking a list of {@link PathEdit} commands
- * and executing them against the entries of the destination cache to produce a
- * new cache. This edit style allows applications to insert a few commands and
- * then have the editor compute the proper entry indexes necessary to perform an
+ * An editor updates a DirCache by taking a list of
+ * {@link org.eclipse.jgit.dircache.DirCacheEditor.PathEdit} commands and
+ * executing them against the entries of the destination cache to produce a new
+ * cache. This edit style allows applications to insert a few commands and then
+ * have the editor compute the proper entry indexes necessary to perform an
  * efficient in-order update of the index records. This can be easier to use
- * than {@link DirCacheBuilder}.
+ * than {@link org.eclipse.jgit.dircache.DirCacheBuilder}.
  * <p>
  *
  * @see DirCacheBuilder
@@ -75,7 +77,7 @@
 public class DirCacheEditor extends BaseDirCacheEditor {
 	private static final Comparator<PathEdit> EDIT_CMP = new Comparator<PathEdit>() {
 		@Override
-		public int compare(final PathEdit o1, final PathEdit o2) {
+		public int compare(PathEdit o1, PathEdit o2) {
 			final byte[] a = o1.path;
 			final byte[] b = o2.path;
 			return cmp(a, a.length, b, b.length);
@@ -94,7 +96,7 @@ public int compare(final PathEdit o1, final PathEdit o2) {
 	 *            estimated number of entries the editor will have upon
 	 *            completion. This sizes the initial entry table.
 	 */
-	protected DirCacheEditor(final DirCache dc, final int ecnt) {
+	protected DirCacheEditor(DirCache dc, int ecnt) {
 		super(dc, ecnt);
 		edits = new ArrayList<>();
 	}
@@ -109,10 +111,11 @@ protected DirCacheEditor(final DirCache dc, final int ecnt) {
 	 * @param edit
 	 *            another edit command.
 	 */
-	public void add(final PathEdit edit) {
+	public void add(PathEdit edit) {
 		edits.add(edit);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public boolean commit() throws IOException {
 		if (edits.isEmpty()) {
@@ -124,6 +127,7 @@ public boolean commit() throws IOException {
 		return super.commit();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void finish() {
 		if (!edits.isEmpty()) {
@@ -300,7 +304,7 @@ public abstract static class PathEdit {
 		 * @param entryPath
 		 *            path of the file within the repository.
 		 */
-		public PathEdit(final String entryPath) {
+		public PathEdit(String entryPath) {
 			path = Constants.encode(entryPath);
 		}
 
@@ -315,7 +319,7 @@ public PathEdit(final String entryPath) {
 		 *            entry instance to match path of. Only the path of this
 		 *            entry is actually considered during command evaluation.
 		 */
-		public PathEdit(final DirCacheEntry ent) {
+		public PathEdit(DirCacheEntry ent) {
 			path = ent.path;
 		}
 
@@ -370,7 +374,7 @@ public static final class DeletePath extends PathEdit {
 		 * @param entryPath
 		 *            path of the file within the repository.
 		 */
-		public DeletePath(final String entryPath) {
+		public DeletePath(String entryPath) {
 			super(entryPath);
 		}
 
@@ -381,12 +385,12 @@ public DeletePath(final String entryPath) {
 		 *            entry instance to remove. Only the path of this entry is
 		 *            actually considered during command evaluation.
 		 */
-		public DeletePath(final DirCacheEntry ent) {
+		public DeletePath(DirCacheEntry ent) {
 			super(ent);
 		}
 
 		@Override
-		public void apply(final DirCacheEntry ent) {
+		public void apply(DirCacheEntry ent) {
 			throw new UnsupportedOperationException(JGitText.get().noApplyInDelete);
 		}
 	}
@@ -436,7 +440,7 @@ public DeleteTree(String entryPath) {
 		}
 
 		@Override
-		public void apply(final DirCacheEntry ent) {
+		public void apply(DirCacheEntry ent) {
 			throw new UnsupportedOperationException(JGitText.get().noApplyInDelete);
 		}
 	}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheEntry.java b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheEntry.java
index 4ebf2e0..fee9f51 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheEntry.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheEntry.java
@@ -68,7 +68,8 @@
 import org.eclipse.jgit.util.SystemReader;
 
 /**
- * A single file (or stage of a file) in a {@link DirCache}.
+ * A single file (or stage of a file) in a
+ * {@link org.eclipse.jgit.dircache.DirCache}.
  * <p>
  * An entry represents exactly one stage of a file. If a file path is unmerged
  * then multiple DirCacheEntry instances may appear for the same path name.
@@ -221,12 +222,12 @@ public class DirCacheEntry {
 	 *
 	 * @param newPath
 	 *            name of the cache entry.
-	 * @throws IllegalArgumentException
+	 * @throws java.lang.IllegalArgumentException
 	 *             If the path starts or ends with "/", or contains "//" either
 	 *             "\0". These sequences are not permitted in a git tree object
 	 *             or DirCache file.
 	 */
-	public DirCacheEntry(final String newPath) {
+	public DirCacheEntry(String newPath) {
 		this(Constants.encode(newPath), STAGE_0);
 	}
 
@@ -237,13 +238,13 @@ public DirCacheEntry(final String newPath) {
 	 *            name of the cache entry.
 	 * @param stage
 	 *            the stage index of the new entry.
-	 * @throws IllegalArgumentException
+	 * @throws java.lang.IllegalArgumentException
 	 *             If the path starts or ends with "/", or contains "//" either
 	 *             "\0". These sequences are not permitted in a git tree object
 	 *             or DirCache file.  Or if {@code stage} is outside of the
 	 *             range 0..3, inclusive.
 	 */
-	public DirCacheEntry(final String newPath, final int stage) {
+	public DirCacheEntry(String newPath, int stage) {
 		this(Constants.encode(newPath), stage);
 	}
 
@@ -252,12 +253,12 @@ public DirCacheEntry(final String newPath, final int stage) {
 	 *
 	 * @param newPath
 	 *            name of the cache entry, in the standard encoding.
-	 * @throws IllegalArgumentException
+	 * @throws java.lang.IllegalArgumentException
 	 *             If the path starts or ends with "/", or contains "//" either
 	 *             "\0". These sequences are not permitted in a git tree object
 	 *             or DirCache file.
 	 */
-	public DirCacheEntry(final byte[] newPath) {
+	public DirCacheEntry(byte[] newPath) {
 		this(newPath, STAGE_0);
 	}
 
@@ -268,14 +269,14 @@ public DirCacheEntry(final byte[] newPath) {
 	 *            name of the cache entry, in the standard encoding.
 	 * @param stage
 	 *            the stage index of the new entry.
-	 * @throws IllegalArgumentException
+	 * @throws java.lang.IllegalArgumentException
 	 *             If the path starts or ends with "/", or contains "//" either
 	 *             "\0". These sequences are not permitted in a git tree object
 	 *             or DirCache file.  Or if {@code stage} is outside of the
 	 *             range 0..3, inclusive.
 	 */
 	@SuppressWarnings("boxing")
-	public DirCacheEntry(byte[] path, final int stage) {
+	public DirCacheEntry(byte[] path, int stage) {
 		checkPath(path);
 		if (stage < 0 || 3 < stage)
 			throw new IllegalArgumentException(MessageFormat.format(
@@ -311,7 +312,7 @@ public DirCacheEntry(DirCacheEntry src) {
 		System.arraycopy(src.info, src.infoOffset, info, 0, INFO_LEN);
 	}
 
-	void write(final OutputStream os) throws IOException {
+	void write(OutputStream os) throws IOException {
 		final int len = isExtended() ? INFO_LEN_EXTENDED : INFO_LEN;
 		final int pathLen = path.length;
 		os.write(info, infoOffset, len);
@@ -342,7 +343,7 @@ void write(final OutputStream os) throws IOException {
 	 *            nanoseconds component of the index's last modified time.
 	 * @return true if extra careful checks should be used.
 	 */
-	public final boolean mightBeRacilyClean(final int smudge_s, final int smudge_ns) {
+	public final boolean mightBeRacilyClean(int smudge_s, int smudge_ns) {
 		// If the index has a modification time then it came from disk
 		// and was not generated from scratch in memory. In such cases
 		// the entry is 'racily clean' if the entry's cached modification
@@ -378,8 +379,9 @@ public final void smudgeRacilyClean() {
 	/**
 	 * Check whether this entry has been smudged or not
 	 * <p>
-	 * If a blob has length 0 we know his id see {@link Constants#EMPTY_BLOB_ID}. If an entry
-	 * has length 0 and an ID different from the one for empty blob we know this
+	 * If a blob has length 0 we know its id, see
+	 * {@link org.eclipse.jgit.lib.Constants#EMPTY_BLOB_ID}. If an entry has
+	 * length 0 and an ID different from the one for empty blob we know this
 	 * entry was smudged.
 	 *
 	 * @return <code>true</code> if the entry is smudged, <code>false</code>
@@ -418,7 +420,7 @@ public boolean isAssumeValid() {
 	 *            true to ignore apparent modifications; false to look at last
 	 *            modified to detect file modifications.
 	 */
-	public void setAssumeValid(final boolean assume) {
+	public void setAssumeValid(boolean assume) {
 		if (assume)
 			info[infoOffset + P_FLAGS] |= ASSUME_VALID;
 		else
@@ -426,7 +428,9 @@ public void setAssumeValid(final boolean assume) {
 	}
 
 	/**
-	 * @return true if this entry should be checked for changes
+	 * Whether this entry should be checked for changes
+	 *
+	 * @return {@code true} if this entry should be checked for changes
 	 */
 	public boolean isUpdateNeeded() {
 		return (inCoreFlags & UPDATE_NEEDED) != 0;
@@ -436,6 +440,7 @@ public boolean isUpdateNeeded() {
 	 * Set whether this entry must be checked for changes
 	 *
 	 * @param updateNeeded
+	 *            whether this entry must be checked for changes
 	 */
 	public void setUpdateNeeded(boolean updateNeeded) {
 		if (updateNeeded)
@@ -484,7 +489,7 @@ public boolean isMerged() {
 	}
 
 	/**
-	 * Obtain the raw {@link FileMode} bits for this entry.
+	 * Obtain the raw {@link org.eclipse.jgit.lib.FileMode} bits for this entry.
 	 *
 	 * @return mode bits for the entry.
 	 * @see FileMode#fromBits(int)
@@ -494,7 +499,7 @@ public int getRawMode() {
 	}
 
 	/**
-	 * Obtain the {@link FileMode} for this entry.
+	 * Obtain the {@link org.eclipse.jgit.lib.FileMode} for this entry.
 	 *
 	 * @return the file mode singleton for this entry.
 	 */
@@ -507,12 +512,13 @@ public FileMode getFileMode() {
 	 *
 	 * @param mode
 	 *            the new mode constant.
-	 * @throws IllegalArgumentException
-	 *             If {@code mode} is {@link FileMode#MISSING},
-	 *             {@link FileMode#TREE}, or any other type code not permitted
-	 *             in a tree object.
+	 * @throws java.lang.IllegalArgumentException
+	 *             If {@code mode} is
+	 *             {@link org.eclipse.jgit.lib.FileMode#MISSING},
+	 *             {@link org.eclipse.jgit.lib.FileMode#TREE}, or any other type
+	 *             code not permitted in a tree object.
 	 */
-	public void setFileMode(final FileMode mode) {
+	public void setFileMode(FileMode mode) {
 		switch (mode.getBits() & FileMode.TYPE_MASK) {
 		case FileMode.TYPE_MISSING:
 		case FileMode.TYPE_TREE:
@@ -542,7 +548,7 @@ public long getCreationTime() {
 	 * @param when
 	 *            new cached creation time of the file, in milliseconds.
 	 */
-	public void setCreationTime(final long when) {
+	public void setCreationTime(long when) {
 		encodeTS(P_CTIME, when);
 	}
 
@@ -566,7 +572,7 @@ public long getLastModified() {
 	 * @param when
 	 *            new cached modification date of the file, in milliseconds.
 	 */
-	public void setLastModified(final long when) {
+	public void setLastModified(long when) {
 		encodeTS(P_MTIME, when);
 	}
 
@@ -598,7 +604,7 @@ public int getLength() {
 	 *            new cached size of the file, as bytes. If the file is larger
 	 *            than 2G, cast it to (int) before calling this method.
 	 */
-	public void setLength(final int sz) {
+	public void setLength(int sz) {
 		NB.encodeInt32(info, infoOffset + P_SIZE, sz);
 	}
 
@@ -608,7 +614,7 @@ public void setLength(final int sz) {
 	 * @param sz
 	 *            new cached size of the file, as bytes.
 	 */
-	public void setLength(final long sz) {
+	public void setLength(long sz) {
 		setLength((int) sz);
 	}
 
@@ -629,9 +635,10 @@ public ObjectId getObjectId() {
 	 *
 	 * @param id
 	 *            new object identifier for the entry. May be
-	 *            {@link ObjectId#zeroId()} to remove the current identifier.
+	 *            {@link org.eclipse.jgit.lib.ObjectId#zeroId()} to remove the
+	 *            current identifier.
 	 */
-	public void setObjectId(final AnyObjectId id) {
+	public void setObjectId(AnyObjectId id) {
 		id.copyRawTo(idBuffer(), idOffset());
 	}
 
@@ -644,7 +651,7 @@ public void setObjectId(final AnyObjectId id) {
 	 * @param p
 	 *            position to read the first byte of data from.
 	 */
-	public void setObjectIdFromRaw(final byte[] bs, final int p) {
+	public void setObjectIdFromRaw(byte[] bs, int p) {
 		final int n = Constants.OBJECT_ID_LENGTH;
 		System.arraycopy(bs, p, idBuffer(), idOffset(), n);
 	}
@@ -676,6 +683,8 @@ public String getPathString() {
 	}
 
 	/**
+	 * {@inheritDoc}
+	 * <p>
 	 * Use for debugging only !
 	 */
 	@SuppressWarnings("nls")
@@ -695,7 +704,7 @@ public String toString() {
 	 * @param src
 	 *            the entry to copy ObjectId and meta fields from.
 	 */
-	public void copyMetaData(final DirCacheEntry src) {
+	public void copyMetaData(DirCacheEntry src) {
 		copyMetaData(src, false);
 	}
 
@@ -710,7 +719,7 @@ public void copyMetaData(final DirCacheEntry src) {
 	 * @param keepStage
 	 *            if true, the stage attribute will not be copied
 	 */
-	void copyMetaData(final DirCacheEntry src, boolean keepStage) {
+	void copyMetaData(DirCacheEntry src, boolean keepStage) {
 		int origflags = NB.decodeUInt16(info, infoOffset + P_FLAGS);
 		int newflags = NB.decodeUInt16(src.info, src.infoOffset + P_FLAGS);
 		System.arraycopy(src.info, src.infoOffset, info, infoOffset, INFO_LEN);
@@ -732,14 +741,14 @@ boolean isExtended() {
 		return (info[infoOffset + P_FLAGS] & EXTENDED) != 0;
 	}
 
-	private long decodeTS(final int pIdx) {
+	private long decodeTS(int pIdx) {
 		final int base = infoOffset + pIdx;
 		final int sec = NB.decodeInt32(info, base);
 		final int ms = NB.decodeInt32(info, base + 4) / 1000000;
 		return 1000L * sec + ms;
 	}
 
-	private void encodeTS(final int pIdx, final long when) {
+	private void encodeTS(int pIdx, long when) {
 		final int base = infoOffset + pIdx;
 		NB.encodeInt32(info, base, (int) (when / 1000));
 		NB.encodeInt32(info, base + 4, ((int) (when % 1000)) * 1000000);
@@ -762,7 +771,7 @@ private static void checkPath(byte[] path) {
 		}
 	}
 
-	static String toString(final byte[] path) {
+	static String toString(byte[] path) {
 		return Constants.CHARSET.decode(ByteBuffer.wrap(path)).toString();
 	}
 
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheIterator.java b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheIterator.java
index ad93f72..19c916f 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheIterator.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheIterator.java
@@ -61,7 +61,8 @@
 import org.eclipse.jgit.util.RawParseUtils;
 
 /**
- * Iterate a {@link DirCache} as part of a <code>TreeWalk</code>.
+ * Iterate a {@link org.eclipse.jgit.dircache.DirCache} as part of a
+ * <code>TreeWalk</code>.
  * <p>
  * This is an iterator to adapt a loaded <code>DirCache</code> instance (such as
  * read from an existing <code>.git/index</code> file) to the tree structure
@@ -113,7 +114,7 @@ public class DirCacheIterator extends AbstractTreeIterator {
 	 * @param dc
 	 *            the cache to walk. It must be already loaded into memory.
 	 */
-	public DirCacheIterator(final DirCache dc) {
+	public DirCacheIterator(DirCache dc) {
 		cache = dc;
 		tree = dc.getCacheTree(true);
 		treeStart = 0;
@@ -123,7 +124,7 @@ public DirCacheIterator(final DirCache dc) {
 			parseEntry();
 	}
 
-	DirCacheIterator(final DirCacheIterator p, final DirCacheTree dct) {
+	DirCacheIterator(DirCacheIterator p, DirCacheTree dct) {
 		super(p, p.path, p.pathLen + 1);
 		cache = p.cache;
 		tree = dct;
@@ -134,8 +135,9 @@ public DirCacheIterator(final DirCache dc) {
 		parseEntry();
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	public AbstractTreeIterator createSubtreeIterator(final ObjectReader reader)
+	public AbstractTreeIterator createSubtreeIterator(ObjectReader reader)
 			throws IncorrectObjectTypeException, IOException {
 		if (currentSubtree == null)
 			throw new IncorrectObjectTypeException(getEntryObjectId(),
@@ -143,6 +145,7 @@ public AbstractTreeIterator createSubtreeIterator(final ObjectReader reader)
 		return new DirCacheIterator(this, currentSubtree);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public EmptyTreeIterator createEmptyTreeIterator() {
 		final byte[] n = new byte[Math.max(pathLen + 1, DEFAULT_PATH_SIZE)];
@@ -151,6 +154,7 @@ public EmptyTreeIterator createEmptyTreeIterator() {
 		return new EmptyTreeIterator(this, n, pathLen + 1);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public boolean hasId() {
 		if (currentSubtree != null)
@@ -158,6 +162,7 @@ public boolean hasId() {
 		return currentEntry != null;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public byte[] idBuffer() {
 		if (currentSubtree != null)
@@ -167,6 +172,7 @@ public boolean hasId() {
 		return zeroid;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public int idOffset() {
 		if (currentSubtree != null)
@@ -176,6 +182,7 @@ public int idOffset() {
 		return 0;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void reset() {
 		if (!first()) {
@@ -188,16 +195,19 @@ public void reset() {
 		}
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public boolean first() {
 		return ptr == treeStart;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public boolean eof() {
 		return ptr == treeEnd;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void next(int delta) {
 		while (--delta >= 0) {
@@ -211,6 +221,7 @@ public void next(int delta) {
 		}
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void back(int delta) {
 		while (--delta >= 0) {
@@ -282,12 +293,15 @@ public DirCacheEntry getDirCacheEntry() {
 	}
 
 	/**
-	 * Retrieves the {@link AttributesNode} for the current entry.
+	 * Retrieves the {@link org.eclipse.jgit.attributes.AttributesNode} for the
+	 * current entry.
 	 *
 	 * @param reader
-	 *            {@link ObjectReader} used to parse the .gitattributes entry.
-	 * @return {@link AttributesNode} for the current entry.
-	 * @throws IOException
+	 *            {@link org.eclipse.jgit.lib.ObjectReader} used to parse the
+	 *            .gitattributes entry.
+	 * @return {@link org.eclipse.jgit.attributes.AttributesNode} for the
+	 *         current entry.
+	 * @throws java.io.IOException
 	 * @since 3.7
 	 */
 	public AttributesNode getEntryAttributesNode(ObjectReader reader)
@@ -315,11 +329,8 @@ AttributesNode load(ObjectReader reader) throws IOException {
 			AttributesNode r = new AttributesNode();
 			ObjectLoader loader = reader.open(objectId);
 			if (loader != null) {
-				InputStream in = loader.openStream();
-				try {
+				try (InputStream in = loader.openStream()) {
 					r.parse(in);
-				} finally {
-					in.close();
 				}
 			}
 			return r.getRules().isEmpty() ? null : r;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheTree.java b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheTree.java
index a06f9d3..b605f3c 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheTree.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheTree.java
@@ -62,13 +62,14 @@
 import org.eclipse.jgit.util.RawParseUtils;
 
 /**
- * Single tree record from the 'TREE' {@link DirCache} extension.
+ * Single tree record from the 'TREE' {@link org.eclipse.jgit.dircache.DirCache}
+ * extension.
  * <p>
  * A valid cache tree record contains the object id of a tree object and the
- * total number of {@link DirCacheEntry} instances (counted recursively) from
- * the DirCache contained within the tree. This information facilitates faster
- * traversal of the index and quicker generation of tree objects prior to
- * creating a new commit.
+ * total number of {@link org.eclipse.jgit.dircache.DirCacheEntry} instances
+ * (counted recursively) from the DirCache contained within the tree. This
+ * information facilitates faster traversal of the index and quicker generation
+ * of tree objects prior to creating a new commit.
  * <p>
  * An invalid cache tree record indicates a known subtree whose file entries
  * have changed in ways that cause the tree to no longer have a known object id.
@@ -81,7 +82,7 @@ public class DirCacheTree {
 
 	private static final Comparator<DirCacheTree> TREE_CMP = new Comparator<DirCacheTree>() {
 		@Override
-		public int compare(final DirCacheTree o1, final DirCacheTree o2) {
+		public int compare(DirCacheTree o1, DirCacheTree o2) {
 			final byte[] a = o1.encodedName;
 			final byte[] b = o2.encodedName;
 			final int aLen = a.length;
@@ -184,7 +185,7 @@ private DirCacheTree(final DirCacheTree myParent, final byte[] path,
 		childCnt = subcnt;
 	}
 
-	void write(final byte[] tmp, final OutputStream os) throws IOException {
+	void write(byte[] tmp, OutputStream os) throws IOException {
 		int ptr = tmp.length;
 		tmp[--ptr] = '\n';
 		ptr = RawParseUtils.formatBase10(tmp, ptr, childCnt);
@@ -205,10 +206,11 @@ void write(final byte[] tmp, final OutputStream os) throws IOException {
 	/**
 	 * Determine if this cache is currently valid.
 	 * <p>
-	 * A valid cache tree knows how many {@link DirCacheEntry} instances from
-	 * the parent {@link DirCache} reside within this tree (recursively
-	 * enumerated). It also knows the object id of the tree, as the tree should
-	 * be readily available from the repository's object database.
+	 * A valid cache tree knows how many
+	 * {@link org.eclipse.jgit.dircache.DirCacheEntry} instances from the parent
+	 * {@link org.eclipse.jgit.dircache.DirCache} reside within this tree
+	 * (recursively enumerated). It also knows the object id of the tree, as the
+	 * tree should be readily available from the repository's object database.
 	 *
 	 * @return true if this tree is knows key details about itself; false if the
 	 *         tree needs to be regenerated.
@@ -246,7 +248,7 @@ public int getChildCount() {
 	 *            index of the child to obtain.
 	 * @return the child tree.
 	 */
-	public DirCacheTree getChild(final int i) {
+	public DirCacheTree getChild(int i) {
 		return children[i];
 	}
 
@@ -387,7 +389,7 @@ private int computeSize(final DirCacheEntry[] cache, int cIdx,
 		return size;
 	}
 
-	private void appendName(final StringBuilder r) {
+	private void appendName(StringBuilder r) {
 		if (parent != null) {
 			parent.appendName(r);
 			r.append(getNameString());
@@ -402,7 +404,7 @@ final int nameLength() {
 		return encodedName.length;
 	}
 
-	final boolean contains(final byte[] a, int aOff, final int aLen) {
+	final boolean contains(byte[] a, int aOff, int aLen) {
 		final byte[] e = encodedName;
 		final int eLen = e.length;
 		for (int eOff = 0; eOff < eLen && aOff < aLen; eOff++, aOff++)
@@ -501,7 +503,7 @@ void validate(final DirCacheEntry[] cache, final int cCnt, int cIdx,
 			removeChild(childCnt - 1);
 	}
 
-	private void insertChild(final int stIdx, final DirCacheTree st) {
+	private void insertChild(int stIdx, DirCacheTree st) {
 		final DirCacheTree[] c = children;
 		if (childCnt + 1 <= c.length) {
 			if (stIdx < childCnt)
@@ -522,14 +524,14 @@ private void insertChild(final int stIdx, final DirCacheTree st) {
 		childCnt++;
 	}
 
-	private void removeChild(final int stIdx) {
+	private void removeChild(int stIdx) {
 		final int n = --childCnt;
 		if (stIdx < n)
 			System.arraycopy(children, stIdx + 1, children, stIdx, n - stIdx);
 		children[n] = null;
 	}
 
-	static boolean peq(final byte[] a, final byte[] b, int aLen) {
+	static boolean peq(byte[] a, byte[] b, int aLen) {
 		if (b.length < aLen)
 			return false;
 		for (aLen--; aLen >= 0; aLen--)
@@ -538,7 +540,7 @@ static boolean peq(final byte[] a, final byte[] b, int aLen) {
 		return true;
 	}
 
-	private static int namecmp(final byte[] a, int aPos, final DirCacheTree ct) {
+	private static int namecmp(byte[] a, int aPos, DirCacheTree ct) {
 		if (ct == null)
 			return -1;
 		final byte[] b = ct.encodedName;
@@ -555,7 +557,7 @@ private static int namecmp(final byte[] a, int aPos, final DirCacheTree ct) {
 		return aLen - bLen;
 	}
 
-	private static int slash(final byte[] a, int aPos) {
+	private static int slash(byte[] a, int aPos) {
 		final int aLen = a.length;
 		for (; aPos < aLen; aPos++)
 			if (a[aPos] == '/')
@@ -563,6 +565,7 @@ private static int slash(final byte[] a, int aPos) {
 		return -1;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public String toString() {
 		return getNameString();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/InvalidPathException.java b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/InvalidPathException.java
index 50d1c4c..7e81b8b 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/InvalidPathException.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/InvalidPathException.java
@@ -57,7 +57,10 @@ public class InvalidPathException extends IllegalArgumentException {
 	private static final long serialVersionUID = 1L;
 
 	/**
+	 * Constructor for InvalidPathException
+	 *
 	 * @param path
+	 *            the invalid path
 	 */
 	public InvalidPathException(String path) {
 		this(JGitText.get().invalidPath, path);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/errors/AmbiguousObjectException.java b/org.eclipse.jgit/src/org/eclipse/jgit/errors/AmbiguousObjectException.java
index 93d57f0..389ec45 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/errors/AmbiguousObjectException.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/errors/AmbiguousObjectException.java
@@ -51,7 +51,9 @@
 import org.eclipse.jgit.lib.AbbreviatedObjectId;
 import org.eclipse.jgit.lib.ObjectId;
 
-/** An {@link AbbreviatedObjectId} cannot be extended. */
+/**
+ * An {@link org.eclipse.jgit.lib.AbbreviatedObjectId} cannot be extended.
+ */
 public class AmbiguousObjectException extends IOException {
 	private static final long serialVersionUID = 1L;
 
@@ -76,12 +78,20 @@ public AmbiguousObjectException(final AbbreviatedObjectId id,
 		this.candidates = candidates;
 	}
 
-	/** @return the AbbreviatedObjectId that has more than one result. */
+	/**
+	 * Get the {@code AbbreviatedObjectId} that has more than one result
+	 *
+	 * @return the {@code AbbreviatedObjectId} that has more than one result
+	 */
 	public AbbreviatedObjectId getAbbreviatedObjectId() {
 		return missing;
 	}
 
-	/** @return the matching candidates (or at least a subset of them). */
+	/**
+	 * Get the matching candidates (or at least a subset of them)
+	 *
+	 * @return the matching candidates (or at least a subset of them)
+	 */
 	public Collection<ObjectId> getCandidates() {
 		return candidates;
 	}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/SafeBufferedOutputStream.java b/org.eclipse.jgit/src/org/eclipse/jgit/errors/BinaryBlobException.java
similarity index 71%
copy from org.eclipse.jgit/src/org/eclipse/jgit/util/io/SafeBufferedOutputStream.java
copy to org.eclipse.jgit/src/org/eclipse/jgit/errors/BinaryBlobException.java
index 84c3398..a345fe4 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/SafeBufferedOutputStream.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/errors/BinaryBlobException.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011, Robin Rosenberg
+ * Copyright (C) 2017 Google Inc.
  * and other copyright owners as documented in the project's IP log.
  *
  * This program and the accompanying materials are made available
@@ -40,33 +40,19 @@
  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
-package org.eclipse.jgit.util.io;
-
-import java.io.BufferedOutputStream;
-import java.io.OutputStream;
+package org.eclipse.jgit.errors;
 
 /**
- * @deprecated use BufferedOutputStream in Java 8 and later.
+ * BinaryBlobException is used to signal that binary data was found
+ * in a context that requires text (eg. for generating textual diffs).
+ *
+ * @since 4.10
  */
-@Deprecated
-public class SafeBufferedOutputStream extends BufferedOutputStream {
-	/**
-	 * @see BufferedOutputStream#BufferedOutputStream(OutputStream)
-	 * @param out
-	 *            underlying output stream
-	 */
-	public SafeBufferedOutputStream(OutputStream out) {
-		super(out);
-	}
+public class BinaryBlobException extends Exception {
+	private static final long serialVersionUID = 1L;
 
 	/**
-	 * @see BufferedOutputStream#BufferedOutputStream(OutputStream, int)
-	 * @param out
-	 *            underlying output stream
-	 * @param size
-	 *            buffer size
+	 * Construct a BinaryBlobException.
 	 */
-	public SafeBufferedOutputStream(OutputStream out, int size) {
-		super(out, size);
-	}
+	public BinaryBlobException() {}
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/errors/CancelledException.java b/org.eclipse.jgit/src/org/eclipse/jgit/errors/CancelledException.java
index c2833a1..d7c553c 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/errors/CancelledException.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/errors/CancelledException.java
@@ -54,7 +54,10 @@ public class CancelledException extends IOException {
 	private static final long serialVersionUID = 1L;
 
 	/**
+	 * Constructor for CancelledException
+	 *
 	 * @param message
+	 *            error message
 	 */
 	public CancelledException(String message) {
 		super(message);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/errors/CheckoutConflictException.java b/org.eclipse.jgit/src/org/eclipse/jgit/errors/CheckoutConflictException.java
index b6010b6..9b7b618 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/errors/CheckoutConflictException.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/errors/CheckoutConflictException.java
@@ -62,6 +62,7 @@ public class CheckoutConflictException extends IOException {
 	 * Construct a CheckoutConflictException for the specified file
 	 *
 	 * @param file
+	 *            relative path of a file
 	 */
 	public CheckoutConflictException(String file) {
 		super(MessageFormat.format(JGitText.get().checkoutConflictWithFile, file));
@@ -72,6 +73,7 @@ public CheckoutConflictException(String file) {
 	 * Construct a CheckoutConflictException for the specified set of files
 	 *
 	 * @param files
+	 *            an array of relative file paths
 	 */
 	public CheckoutConflictException(String[] files) {
 		super(MessageFormat.format(JGitText.get().checkoutConflictWithFiles, buildList(files)));
@@ -79,6 +81,8 @@ public CheckoutConflictException(String[] files) {
 	}
 
 	/**
+	 * Get the relative paths of the conflicting files
+	 *
 	 * @return the relative paths of the conflicting files (relative to the
 	 *         working directory root).
 	 * @since 4.4
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/errors/CommandFailedException.java b/org.eclipse.jgit/src/org/eclipse/jgit/errors/CommandFailedException.java
index 93749f5..5df41c2 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/errors/CommandFailedException.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/errors/CommandFailedException.java
@@ -54,6 +54,8 @@ public class CommandFailedException extends Exception {
 	private int returnCode;
 
 	/**
+	 * Constructor for CommandFailedException
+	 *
 	 * @param returnCode
 	 *            return code returned by the command
 	 * @param message
@@ -65,6 +67,8 @@ public CommandFailedException(int returnCode, String message) {
 	}
 
 	/**
+	 * Constructor for CommandFailedException
+	 *
 	 * @param returnCode
 	 *            return code returned by the command
 	 * @param message
@@ -79,6 +83,8 @@ public CommandFailedException(int returnCode, String message,
 	}
 
 	/**
+	 * Get return code returned by the command
+	 *
 	 * @return return code returned by the command
 	 */
 	public int getReturnCode() {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/errors/CompoundException.java b/org.eclipse.jgit/src/org/eclipse/jgit/errors/CompoundException.java
index 3a7b2c6..1df70e3 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/errors/CompoundException.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/errors/CompoundException.java
@@ -50,14 +50,16 @@
 
 import org.eclipse.jgit.internal.JGitText;
 
-/** An exception detailing multiple reasons for failure. */
+/**
+ * An exception detailing multiple reasons for failure.
+ */
 public class CompoundException extends Exception {
 	private static final long serialVersionUID = 1L;
 
-	private static String format(final Collection<Throwable> causes) {
+	private static String format(Collection<Throwable> causes) {
 		final StringBuilder msg = new StringBuilder();
 		msg.append(JGitText.get().failureDueToOneOfTheFollowing);
-		for (final Throwable c : causes) {
+		for (Throwable c : causes) {
 			msg.append("  "); //$NON-NLS-1$
 			msg.append(c.getMessage());
 			msg.append("\n"); //$NON-NLS-1$
@@ -73,7 +75,7 @@ private static String format(final Collection<Throwable> causes) {
 	 * @param why
 	 *            Two or more exceptions that may have been the problem.
 	 */
-	public CompoundException(final Collection<Throwable> why) {
+	public CompoundException(Collection<Throwable> why) {
 		super(format(why));
 		causeList = Collections.unmodifiableList(new ArrayList<>(why));
 	}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/errors/ConfigInvalidException.java b/org.eclipse.jgit/src/org/eclipse/jgit/errors/ConfigInvalidException.java
index 43fb4bc..24f43cf 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/errors/ConfigInvalidException.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/errors/ConfigInvalidException.java
@@ -43,7 +43,9 @@
 
 package org.eclipse.jgit.errors;
 
-/** Indicates a text string is not a valid Git style configuration. */
+/**
+ * Indicates a text string is not a valid Git style configuration.
+ */
 public class ConfigInvalidException extends Exception {
 	private static final long serialVersionUID = 1L;
 
@@ -53,7 +55,7 @@ public class ConfigInvalidException extends Exception {
 	 * @param message
 	 *            why the configuration is invalid.
 	 */
-	public ConfigInvalidException(final String message) {
+	public ConfigInvalidException(String message) {
 		super(message);
 	}
 
@@ -65,7 +67,7 @@ public ConfigInvalidException(final String message) {
 	 * @param cause
 	 *            root cause of the error.
 	 */
-	public ConfigInvalidException(final String message, final Throwable cause) {
+	public ConfigInvalidException(String message, Throwable cause) {
 		super(message, cause);
 	}
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/errors/CorruptObjectException.java b/org.eclipse.jgit/src/org/eclipse/jgit/errors/CorruptObjectException.java
index e4db40b..4b503a3 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/errors/CorruptObjectException.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/errors/CorruptObjectException.java
@@ -86,7 +86,9 @@ public CorruptObjectException(ObjectChecker.ErrorType type, AnyObjectId id,
 	 * object id
 	 *
 	 * @param id
+	 *            a {@link org.eclipse.jgit.lib.AnyObjectId}
 	 * @param why
+	 *            error message
 	 */
 	public CorruptObjectException(AnyObjectId id, String why) {
 		super(MessageFormat.format(JGitText.get().objectIsCorrupt, id.name(), why));
@@ -97,7 +99,9 @@ public CorruptObjectException(AnyObjectId id, String why) {
 	 * object id
 	 *
 	 * @param id
+	 *            a {@link org.eclipse.jgit.lib.ObjectId}
 	 * @param why
+	 *            error message
 	 */
 	public CorruptObjectException(ObjectId id, String why) {
 		super(MessageFormat.format(JGitText.get().objectIsCorrupt, id.name(), why));
@@ -108,6 +112,7 @@ public CorruptObjectException(ObjectId id, String why) {
 	 * with a specific object id.
 	 *
 	 * @param why
+	 *            error message
 	 */
 	public CorruptObjectException(String why) {
 		super(why);
@@ -129,7 +134,8 @@ public CorruptObjectException(String why, Throwable cause) {
 	}
 
 	/**
-	 * Specific error condition identified by {@link ObjectChecker}.
+	 * Specific error condition identified by
+	 * {@link org.eclipse.jgit.lib.ObjectChecker}.
 	 *
 	 * @return error condition or null.
 	 * @since 4.2
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/errors/DiffInterruptedException.java b/org.eclipse.jgit/src/org/eclipse/jgit/errors/DiffInterruptedException.java
index 5f9ce35..1df8773 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/errors/DiffInterruptedException.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/errors/DiffInterruptedException.java
@@ -53,8 +53,12 @@ public class DiffInterruptedException extends RuntimeException {
 	private static final long serialVersionUID = 1L;
 
 	/**
+	 * Constructor for DiffInterruptedException
+	 *
 	 * @param message
+	 *            error message
 	 * @param cause
+	 *            a {@link java.lang.Throwable}
 	 * @since 4.1
 	 */
 	public DiffInterruptedException(String message, Throwable cause) {
@@ -62,14 +66,19 @@ public DiffInterruptedException(String message, Throwable cause) {
 	}
 
 	/**
+	 * Constructor for DiffInterruptedException
+	 *
 	 * @param message
+	 *            error message
 	 * @since 4.1
 	 */
 	public DiffInterruptedException(String message) {
 		super(message);
 	}
 
-	/** Indicates that the thread computing a diff was interrupted. */
+	/**
+	 * Indicates that the thread computing a diff was interrupted.
+	 */
 	public DiffInterruptedException() {
 		super();
 	}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/errors/DirCacheNameConflictException.java b/org.eclipse.jgit/src/org/eclipse/jgit/errors/DirCacheNameConflictException.java
index 5f67e34..4d08dfd 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/errors/DirCacheNameConflictException.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/errors/DirCacheNameConflictException.java
@@ -68,12 +68,20 @@ public DirCacheNameConflictException(String path1, String path2) {
 		this.path2 = path2;
 	}
 
-	/** @return one of the paths that has a conflict. */
+	/**
+	 * Get one of the paths that has a conflict
+	 *
+	 * @return one of the paths that has a conflict
+	 */
 	public String getPath1() {
 		return path1;
 	}
 
-	/** @return another path that has a conflict. */
+	/**
+	 * Get another path that has a conflict
+	 *
+	 * @return another path that has a conflict
+	 */
 	public String getPath2() {
 		return path2;
 	}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/errors/EntryExistsException.java b/org.eclipse.jgit/src/org/eclipse/jgit/errors/EntryExistsException.java
index 8dd0d53..b97d237 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/errors/EntryExistsException.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/errors/EntryExistsException.java
@@ -61,7 +61,7 @@ public class EntryExistsException extends IOException {
 	 *
 	 * @param name workdir relative file name
 	 */
-	public EntryExistsException(final String name) {
+	public EntryExistsException(String name) {
 		super(MessageFormat.format(JGitText.get().treeEntryAlreadyExists, name));
 	}
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/errors/IllegalTodoFileModification.java b/org.eclipse.jgit/src/org/eclipse/jgit/errors/IllegalTodoFileModification.java
index dae150c..785cb95 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/errors/IllegalTodoFileModification.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/errors/IllegalTodoFileModification.java
@@ -51,9 +51,12 @@ public class IllegalTodoFileModification extends Exception {
 	private static final long serialVersionUID = 1L;
 
 	/**
+	 * Constructor for IllegalTodoFileModification
+	 *
 	 * @param msg
+	 *            error message
 	 */
-	public IllegalTodoFileModification(final String msg) {
+	public IllegalTodoFileModification(String msg) {
 		super(msg);
 	}
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/errors/IncorrectObjectTypeException.java b/org.eclipse.jgit/src/org/eclipse/jgit/errors/IncorrectObjectTypeException.java
index 7ba3a00..5abd0c3 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/errors/IncorrectObjectTypeException.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/errors/IncorrectObjectTypeException.java
@@ -70,7 +70,7 @@ public class IncorrectObjectTypeException extends IOException {
 	 * @param id SHA-1
 	 * @param type object type
 	 */
-	public IncorrectObjectTypeException(final ObjectId id, final String type) {
+	public IncorrectObjectTypeException(ObjectId id, String type) {
 		super(MessageFormat.format(JGitText.get().objectIsNotA, id.name(), type));
 	}
 
@@ -82,7 +82,7 @@ public IncorrectObjectTypeException(final ObjectId id, final String type) {
 	 * @param id SHA-1
 	 * @param type object type
 	 */
-	public IncorrectObjectTypeException(final ObjectId id, final int type) {
+	public IncorrectObjectTypeException(ObjectId id, int type) {
 		this(id, Constants.typeString(type));
 	}
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/errors/IndexReadException.java b/org.eclipse.jgit/src/org/eclipse/jgit/errors/IndexReadException.java
index 70f650d..e07d308 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/errors/IndexReadException.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/errors/IndexReadException.java
@@ -63,7 +63,7 @@ public IndexReadException() {
 	 * @param s
 	 *            message
 	 */
-	public IndexReadException(final String s) {
+	public IndexReadException(String s) {
 		super(s);
 	}
 
@@ -75,7 +75,7 @@ public IndexReadException(final String s) {
 	 * @param cause
 	 *            root cause exception
 	 */
-	public IndexReadException(final String s, final Throwable cause) {
+	public IndexReadException(String s, Throwable cause) {
 		super(s);
 		initCause(cause);
 	}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/errors/IndexWriteException.java b/org.eclipse.jgit/src/org/eclipse/jgit/errors/IndexWriteException.java
index de19c06..34fd7a8 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/errors/IndexWriteException.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/errors/IndexWriteException.java
@@ -60,7 +60,7 @@ public IndexWriteException() {
 	 *
 	 * @param s message
 	 */
-	public IndexWriteException(final String s) {
+	public IndexWriteException(String s) {
 		super(s);
 	}
 
@@ -70,7 +70,7 @@ public IndexWriteException(final String s) {
 	 * @param s message
 	 * @param cause root cause exception
 	 */
-	public IndexWriteException(final String s, final Throwable cause) {
+	public IndexWriteException(String s, Throwable cause) {
 		super(s);
 		initCause(cause);
 	}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/errors/InvalidObjectIdException.java b/org.eclipse.jgit/src/org/eclipse/jgit/errors/InvalidObjectIdException.java
index 390545f..4abbf1e 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/errors/InvalidObjectIdException.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/errors/InvalidObjectIdException.java
@@ -69,8 +69,10 @@ public InvalidObjectIdException(byte[] bytes, int offset, int length) {
 	}
 
 	/**
-	 * @param id the invalid id.
+	 * Constructor for InvalidObjectIdException
 	 *
+	 * @param id
+	 *            the invalid id.
 	 * @since 4.1
 	 */
 	public InvalidObjectIdException(String id) {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/errors/InvalidPatternException.java b/org.eclipse.jgit/src/org/eclipse/jgit/errors/InvalidPatternException.java
index 18e78ff..949c4ff 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/errors/InvalidPatternException.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/errors/InvalidPatternException.java
@@ -47,7 +47,6 @@
 
 /**
  * Thrown when a pattern passed in an argument was wrong.
- *
  */
 public class InvalidPatternException extends Exception {
 	private static final long serialVersionUID = 1L;
@@ -55,6 +54,8 @@ public class InvalidPatternException extends Exception {
 	private final String pattern;
 
 	/**
+	 * Constructor for InvalidPatternException
+	 *
 	 * @param message
 	 *            explains what was wrong with the pattern.
 	 * @param pattern
@@ -66,6 +67,25 @@ public InvalidPatternException(String message, String pattern) {
 	}
 
 	/**
+	 * Constructor for InvalidPatternException
+	 *
+	 * @param message
+	 *            explains what was wrong with the pattern.
+	 * @param pattern
+	 *            the invalid pattern.
+	 * @param cause
+	 *            the cause.
+	 * @since 4.10
+	 */
+	public InvalidPatternException(String message, String pattern,
+			Throwable cause) {
+		this(message, pattern);
+		initCause(cause);
+	}
+
+	/**
+	 * Get the invalid pattern
+	 *
 	 * @return the invalid pattern.
 	 */
 	public String getPattern() {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/errors/LargeObjectException.java b/org.eclipse.jgit/src/org/eclipse/jgit/errors/LargeObjectException.java
index a69bdc4..dfdf50d 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/errors/LargeObjectException.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/errors/LargeObjectException.java
@@ -49,18 +49,33 @@
 import org.eclipse.jgit.lib.AnyObjectId;
 import org.eclipse.jgit.lib.ObjectId;
 
-/** An object is too big to load into memory as a single byte array. */
+/**
+ * An object is too big to load into memory as a single byte array.
+ */
 public class LargeObjectException extends RuntimeException {
 	private static final long serialVersionUID = 1L;
 
 	private ObjectId objectId;
 
-	/** Create a large object exception, where the object isn't known. */
+	/**
+	 * Create a large object exception, where the object isn't known.
+	 */
 	public LargeObjectException() {
 		// Do nothing.
 	}
 
 	/**
+	 * Create a large object exception, where the object isn't known.
+	 *
+	 * @param cause
+	 *            the cause
+	 * @since 4.10
+	 */
+	public LargeObjectException(Throwable cause) {
+		initCause(cause);
+	}
+
+	/**
 	 * Create a large object exception, naming the object that is too big.
 	 *
 	 * @param id
@@ -71,12 +86,20 @@ public LargeObjectException(AnyObjectId id) {
 		setObjectId(id);
 	}
 
-	/** @return identity of the object that is too large; may be null. */
+	/**
+	 * Get identity of the object that is too large; may be null
+	 *
+	 * @return identity of the object that is too large; may be null
+	 */
 	public ObjectId getObjectId() {
 		return objectId;
 	}
 
-	/** @return either the hex encoded name of the object, or 'unknown object'. */
+	/**
+	 * Get the hex encoded name of the object, or 'unknown object'
+	 *
+	 * @return either the hex encoded name of the object, or 'unknown object'
+	 */
 	protected String getObjectName() {
 		if (getObjectId() != null)
 			return getObjectId().name();
@@ -94,6 +117,7 @@ public void setObjectId(AnyObjectId id) {
 			objectId = id.copy();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public String getMessage() {
 		return MessageFormat.format(JGitText.get().largeObjectException,
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/errors/LockFailedException.java b/org.eclipse.jgit/src/org/eclipse/jgit/errors/LockFailedException.java
index 0142e17..bf958bd 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/errors/LockFailedException.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/errors/LockFailedException.java
@@ -57,12 +57,15 @@ public class LockFailedException extends IOException {
 	private File file;
 
 	/**
+	 * Constructor for LockFailedException
+	 *
 	 * @param file
 	 *            file that could not be locked
 	 * @param message
 	 *            exception message
 	 * @param cause
-	 *            cause, for later retrieval by {@link Throwable#getCause()}
+	 *            cause, for later retrieval by
+	 *            {@link java.lang.Throwable#getCause()}
 	 * @since 4.1
 	 */
 	public LockFailedException(File file, String message, Throwable cause) {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/errors/MissingBundlePrerequisiteException.java b/org.eclipse.jgit/src/org/eclipse/jgit/errors/MissingBundlePrerequisiteException.java
index 09bb4a9..b37d20d 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/errors/MissingBundlePrerequisiteException.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/errors/MissingBundlePrerequisiteException.java
@@ -56,10 +56,10 @@
 public class MissingBundlePrerequisiteException extends TransportException {
 	private static final long serialVersionUID = 1L;
 
-	private static String format(final Map<ObjectId, String> missingCommits) {
+	private static String format(Map<ObjectId, String> missingCommits) {
 		final StringBuilder r = new StringBuilder();
 		r.append(JGitText.get().missingPrerequisiteCommits);
-		for (final Map.Entry<ObjectId, String> e : missingCommits.entrySet()) {
+		for (Map.Entry<ObjectId, String> e : missingCommits.entrySet()) {
 			r.append("\n  "); //$NON-NLS-1$
 			r.append(e.getKey().name());
 			if (e.getValue() != null)
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/errors/MissingObjectException.java b/org.eclipse.jgit/src/org/eclipse/jgit/errors/MissingObjectException.java
index d1157c4..c6c47f9 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/errors/MissingObjectException.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/errors/MissingObjectException.java
@@ -69,7 +69,7 @@ public class MissingObjectException extends IOException {
 	 * @param id SHA-1
 	 * @param type object type
 	 */
-	public MissingObjectException(final ObjectId id, final String type) {
+	public MissingObjectException(ObjectId id, String type) {
 		super(MessageFormat.format(JGitText.get().missingObject, type, id.name()));
 		missing = id.copy();
 	}
@@ -81,7 +81,7 @@ public MissingObjectException(final ObjectId id, final String type) {
 	 * @param id SHA-1
 	 * @param type object type
 	 */
-	public MissingObjectException(final ObjectId id, final int type) {
+	public MissingObjectException(ObjectId id, int type) {
 		this(id, Constants.typeString(type));
 	}
 
@@ -94,13 +94,17 @@ public MissingObjectException(final ObjectId id, final int type) {
 	 * @param type
 	 *            object type
 	 */
-	public MissingObjectException(final AbbreviatedObjectId id, final int type) {
+	public MissingObjectException(AbbreviatedObjectId id, int type) {
 		super(MessageFormat.format(JGitText.get().missingObject, Constants
 				.typeString(type), id.name()));
 		missing = null;
 	}
 
-	/** @return the ObjectId that was not found. */
+	/**
+	 * Get the ObjectId that was not found
+	 *
+	 * @return the ObjectId that was not found
+	 */
 	public ObjectId getObjectId() {
 		return missing;
 	}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/errors/NoClosingBracketException.java b/org.eclipse.jgit/src/org/eclipse/jgit/errors/NoClosingBracketException.java
index 6601591..1f79c5d 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/errors/NoClosingBracketException.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/errors/NoClosingBracketException.java
@@ -58,6 +58,8 @@ public class NoClosingBracketException extends InvalidPatternException {
 	private static final long serialVersionUID = 1L;
 
 	/**
+	 * Constructor for NoClosingBracketException
+	 *
 	 * @param indexOfOpeningBracket
 	 *            the position of the [ character which has no ] character.
 	 * @param openingBracket
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/errors/NoMergeBaseException.java b/org.eclipse.jgit/src/org/eclipse/jgit/errors/NoMergeBaseException.java
index 0c419d7..97214b0 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/errors/NoMergeBaseException.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/errors/NoMergeBaseException.java
@@ -118,6 +118,8 @@ public NoMergeBaseException(MergeBaseFailureReason reason, String message,
 	}
 
 	/**
+	 * Get the reason why no merge base could be found
+	 *
 	 * @return the reason why no merge base could be found
 	 */
 	public MergeBaseFailureReason getReason() {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/errors/NoPackSignatureException.java b/org.eclipse.jgit/src/org/eclipse/jgit/errors/NoPackSignatureException.java
index 28e9788..8c2e872 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/errors/NoPackSignatureException.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/errors/NoPackSignatureException.java
@@ -60,7 +60,7 @@ public class NoPackSignatureException extends IOException {
 	 * @param why
 	 *            description of the type of error.
 	 */
-	public NoPackSignatureException(final String why) {
+	public NoPackSignatureException(String why) {
 		super(why);
 	}
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/errors/NoRemoteRepositoryException.java b/org.eclipse.jgit/src/org/eclipse/jgit/errors/NoRemoteRepositoryException.java
index fe073d5..524968d 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/errors/NoRemoteRepositoryException.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/errors/NoRemoteRepositoryException.java
@@ -59,7 +59,7 @@ public class NoRemoteRepositoryException extends TransportException {
 	 * @param s
 	 *            message
 	 */
-	public NoRemoteRepositoryException(final URIish uri, final String s) {
+	public NoRemoteRepositoryException(URIish uri, String s) {
 		super(uri, s);
 	}
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/errors/NoWorkTreeException.java b/org.eclipse.jgit/src/org/eclipse/jgit/errors/NoWorkTreeException.java
index 6f61806..82ed7ef 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/errors/NoWorkTreeException.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/errors/NoWorkTreeException.java
@@ -44,15 +44,17 @@
 package org.eclipse.jgit.errors;
 
 import org.eclipse.jgit.internal.JGitText;
-import org.eclipse.jgit.lib.Repository;
 
 /**
- * Indicates a {@link Repository} has no working directory, and is thus bare.
+ * Indicates a {@link org.eclipse.jgit.lib.Repository} has no working directory,
+ * and is thus bare.
  */
 public class NoWorkTreeException extends IllegalStateException {
 	private static final long serialVersionUID = 1L;
 
-	/** Creates an exception indicating there is no work tree for a repository. */
+	/**
+	 * Creates an exception indicating there is no work tree for a repository.
+	 */
 	public NoWorkTreeException() {
 		super(JGitText.get().bareRepositoryNoWorkdirAndIndex);
 	}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/errors/NotSupportedException.java b/org.eclipse.jgit/src/org/eclipse/jgit/errors/NotSupportedException.java
index 124680e..114e662 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/errors/NotSupportedException.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/errors/NotSupportedException.java
@@ -58,7 +58,7 @@ public class NotSupportedException extends IOException {
 	 *
 	 * @param s message describing the issue
 	 */
-	public NotSupportedException(final String s) {
+	public NotSupportedException(String s) {
 		super(s);
 	}
 
@@ -70,7 +70,7 @@ public NotSupportedException(final String s) {
 	 * @param why
 	 *            a lower level implementation specific issue.
 	 */
-	public NotSupportedException(final String s, final Throwable why) {
+	public NotSupportedException(String s, Throwable why) {
 		super(s);
 		initCause(why);
 	}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/errors/ObjectWritingException.java b/org.eclipse.jgit/src/org/eclipse/jgit/errors/ObjectWritingException.java
index 8af1991..bbee42f 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/errors/ObjectWritingException.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/errors/ObjectWritingException.java
@@ -58,7 +58,7 @@ public class ObjectWritingException extends IOException {
 	 *
 	 * @param s message
 	 */
-	public ObjectWritingException(final String s) {
+	public ObjectWritingException(String s) {
 		super(s);
 	}
 
@@ -68,7 +68,7 @@ public ObjectWritingException(final String s) {
 	 * @param s message
 	 * @param cause root cause exception
 	 */
-	public ObjectWritingException(final String s, final Throwable cause) {
+	public ObjectWritingException(String s, Throwable cause) {
 		super(s);
 		initCause(cause);
 	}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/errors/PackInvalidException.java b/org.eclipse.jgit/src/org/eclipse/jgit/errors/PackInvalidException.java
index 8c216c3..a83de06 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/errors/PackInvalidException.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/errors/PackInvalidException.java
@@ -49,7 +49,9 @@
 
 import org.eclipse.jgit.internal.JGitText;
 
-/** Thrown when a PackFile previously failed and is known to be unusable */
+/**
+ * Thrown when a PackFile previously failed and is known to be unusable
+ */
 public class PackInvalidException extends IOException {
 	private static final long serialVersionUID = 1L;
 
@@ -59,7 +61,7 @@ public class PackInvalidException extends IOException {
 	 * @param path
 	 *            path of the invalid pack file.
 	 */
-	public PackInvalidException(final File path) {
+	public PackInvalidException(File path) {
 		this(path.getAbsolutePath());
 	}
 
@@ -69,7 +71,7 @@ public PackInvalidException(final File path) {
 	 * @param path
 	 *            path of the invalid pack file.
 	 */
-	public PackInvalidException(final String path) {
+	public PackInvalidException(String path) {
 		super(MessageFormat.format(JGitText.get().packFileInvalid, path));
 	}
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/errors/PackMismatchException.java b/org.eclipse.jgit/src/org/eclipse/jgit/errors/PackMismatchException.java
index b828465..ea1e65b 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/errors/PackMismatchException.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/errors/PackMismatchException.java
@@ -45,7 +45,9 @@
 
 import java.io.IOException;
 
-/** Thrown when a PackFile no longer matches the PackIndex. */
+/**
+ * Thrown when a PackFile no longer matches the PackIndex.
+ */
 public class PackMismatchException extends IOException {
 	private static final long serialVersionUID = 1L;
 
@@ -55,7 +57,7 @@ public class PackMismatchException extends IOException {
 	 * @param why
 	 *            description of the type of error.
 	 */
-	public PackMismatchException(final String why) {
+	public PackMismatchException(String why) {
 		super(why);
 	}
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/errors/PackProtocolException.java b/org.eclipse.jgit/src/org/eclipse/jgit/errors/PackProtocolException.java
index 44bc164..dd13740 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/errors/PackProtocolException.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/errors/PackProtocolException.java
@@ -62,7 +62,7 @@ public class PackProtocolException extends TransportException {
 	 * @param s
 	 *            message, which may be shown to an end-user.
 	 */
-	public PackProtocolException(final URIish uri, final String s) {
+	public PackProtocolException(URIish uri, String s) {
 		super(uri + ": " + s); //$NON-NLS-1$
 	}
 
@@ -88,7 +88,7 @@ public PackProtocolException(final URIish uri, final String s,
 	 * @param s
 	 *            message, which may be shown to an end-user.
 	 */
-	public PackProtocolException(final String s) {
+	public PackProtocolException(String s) {
 		super(s);
 	}
 
@@ -100,7 +100,7 @@ public PackProtocolException(final String s) {
 	 * @param cause
 	 *            root cause exception
 	 */
-	public PackProtocolException(final String s, final Throwable cause) {
+	public PackProtocolException(String s, Throwable cause) {
 		super(s);
 		initCause(cause);
 	}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/errors/RepositoryNotFoundException.java b/org.eclipse.jgit/src/org/eclipse/jgit/errors/RepositoryNotFoundException.java
index 33429d6..04fd8ea 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/errors/RepositoryNotFoundException.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/errors/RepositoryNotFoundException.java
@@ -48,7 +48,9 @@
 
 import org.eclipse.jgit.internal.JGitText;
 
-/** Indicates a local repository does not exist. */
+/**
+ * Indicates a local repository does not exist.
+ */
 public class RepositoryNotFoundException extends TransportException {
 	private static final long serialVersionUID = 1L;
 
@@ -58,7 +60,7 @@ public class RepositoryNotFoundException extends TransportException {
 	 * @param location
 	 *            description of the repository not found, usually file path.
 	 */
-	public RepositoryNotFoundException(final File location) {
+	public RepositoryNotFoundException(File location) {
 		this(location.getPath());
 	}
 
@@ -70,7 +72,7 @@ public RepositoryNotFoundException(final File location) {
 	 * @param why
 	 *            why the repository does not exist.
 	 */
-	public RepositoryNotFoundException(final File location, Throwable why) {
+	public RepositoryNotFoundException(File location, Throwable why) {
 		this(location.getPath(), why);
 	}
 
@@ -80,7 +82,7 @@ public RepositoryNotFoundException(final File location, Throwable why) {
 	 * @param location
 	 *            description of the repository not found, usually file path.
 	 */
-	public RepositoryNotFoundException(final String location) {
+	public RepositoryNotFoundException(String location) {
 		super(message(location));
 	}
 
@@ -96,7 +98,7 @@ public RepositoryNotFoundException(String location, Throwable why) {
 		super(message(location), why);
 	}
 
-	private static String message(final String location) {
+	private static String message(String location) {
 		return MessageFormat.format(JGitText.get().repositoryNotFound, location);
 	}
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/errors/RevWalkException.java b/org.eclipse.jgit/src/org/eclipse/jgit/errors/RevWalkException.java
index 757a45b..f6852b5 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/errors/RevWalkException.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/errors/RevWalkException.java
@@ -45,16 +45,16 @@
 package org.eclipse.jgit.errors;
 
 import org.eclipse.jgit.internal.JGitText;
-import org.eclipse.jgit.revwalk.RevWalk;
 
 /**
- * Indicates a checked exception was thrown inside of {@link RevWalk}.
+ * Indicates a checked exception was thrown inside of
+ * {@link org.eclipse.jgit.revwalk.RevWalk}.
  * <p>
  * Usually this exception is thrown from the Iterator created around a RevWalk
  * instance, as the Iterator API does not allow checked exceptions to be thrown
- * from hasNext() or next(). The {@link Exception#getCause()} of this exception
- * is the original checked exception that we really wanted to throw back to the
- * application for handling and recovery.
+ * from hasNext() or next(). The {@link java.lang.Exception#getCause()} of this
+ * exception is the original checked exception that we really wanted to throw
+ * back to the application for handling and recovery.
  */
 public class RevWalkException extends RuntimeException {
 	private static final long serialVersionUID = 1L;
@@ -65,7 +65,7 @@ public class RevWalkException extends RuntimeException {
 	 * @param cause
 	 *            the checked exception that describes why the walk failed.
 	 */
-	public RevWalkException(final Throwable cause) {
+	public RevWalkException(Throwable cause) {
 		super(JGitText.get().walkFailure, cause);
 	}
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/errors/RevisionSyntaxException.java b/org.eclipse.jgit/src/org/eclipse/jgit/errors/RevisionSyntaxException.java
index a039c7d..be3ca1b 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/errors/RevisionSyntaxException.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/errors/RevisionSyntaxException.java
@@ -77,6 +77,7 @@ public RevisionSyntaxException(String message, String revstr) {
 		this.revstr = revstr;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public String toString() {
 		return super.toString() + ":" + revstr; //$NON-NLS-1$
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/errors/StoredObjectRepresentationNotAvailableException.java b/org.eclipse.jgit/src/org/eclipse/jgit/errors/StoredObjectRepresentationNotAvailableException.java
index 0bd035b..611fd66 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/errors/StoredObjectRepresentationNotAvailableException.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/errors/StoredObjectRepresentationNotAvailableException.java
@@ -45,8 +45,10 @@
 
 import org.eclipse.jgit.internal.storage.pack.ObjectToPack;
 
-/** A previously selected representation is no longer available. */
-public class StoredObjectRepresentationNotAvailableException extends Exception {
+/**
+ * A previously selected representation is no longer available.
+ */
+public class StoredObjectRepresentationNotAvailableException extends Exception { //TODO remove unused ObjectToPack in 5.0
 	private static final long serialVersionUID = 1L;
 
 	/**
@@ -54,9 +56,13 @@ public class StoredObjectRepresentationNotAvailableException extends Exception {
 	 *
 	 * @param otp
 	 *            the object whose current representation is no longer present.
-	 * @since 3.0
+	 * @param cause
+	 *            cause
+	 * @since 4.10
 	 */
-	public StoredObjectRepresentationNotAvailableException(ObjectToPack otp) {
+	public StoredObjectRepresentationNotAvailableException(ObjectToPack otp,
+			Throwable cause) {
+		super(cause);
 		// Do nothing.
 	}
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/errors/SymlinksNotSupportedException.java b/org.eclipse.jgit/src/org/eclipse/jgit/errors/SymlinksNotSupportedException.java
index 60d7aa0..dc59c8c 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/errors/SymlinksNotSupportedException.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/errors/SymlinksNotSupportedException.java
@@ -58,7 +58,7 @@ public class SymlinksNotSupportedException extends IOException {
 	 *
 	 * @param s name of link in tree or workdir
 	 */
-	public SymlinksNotSupportedException(final String s) {
+	public SymlinksNotSupportedException(String s) {
 		super(s);
 	}
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/errors/TooLargeObjectInPackException.java b/org.eclipse.jgit/src/org/eclipse/jgit/errors/TooLargeObjectInPackException.java
index ece76ed..fb413d8 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/errors/TooLargeObjectInPackException.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/errors/TooLargeObjectInPackException.java
@@ -48,7 +48,9 @@
 import org.eclipse.jgit.internal.JGitText;
 import org.eclipse.jgit.transport.URIish;
 
-/** Thrown when PackParser finds an object larger than a predefined limit */
+/**
+ * Thrown when PackParser finds an object larger than a predefined limit
+ */
 public class TooLargeObjectInPackException extends TransportException {
 	private static final long serialVersionUID = 1L;
 
@@ -72,7 +74,9 @@ public TooLargeObjectInPackException(long maxObjectSizeLimit) {
 	 * too large object is known.
 	 *
 	 * @param objectSize
+	 *            a long.
 	 * @param maxObjectSizeLimit
+	 *            a long.
 	 */
 	public TooLargeObjectInPackException(long objectSize,
 			long maxObjectSizeLimit) {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/errors/TranslationBundleException.java b/org.eclipse.jgit/src/org/eclipse/jgit/errors/TranslationBundleException.java
index dc5f7a4..70760f3 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/errors/TranslationBundleException.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/errors/TranslationBundleException.java
@@ -43,7 +43,6 @@
 package org.eclipse.jgit.errors;
 
 import java.util.Locale;
-import java.util.ResourceBundle;
 
 /**
  * Common base class for all translation bundle related exceptions.
@@ -55,7 +54,8 @@ public abstract class TranslationBundleException extends RuntimeException {
 	private final Locale locale;
 
 	/**
-	 * To construct an instance of {@link TranslationBundleException}
+	 * Construct an instance of
+	 * {@link org.eclipse.jgit.errors.TranslationBundleException}
 	 *
 	 * @param message
 	 *            exception message
@@ -65,7 +65,7 @@ public abstract class TranslationBundleException extends RuntimeException {
 	 *            locale for which the exception occurred
 	 * @param cause
 	 *            original exception that caused this exception. Usually thrown
-	 *            from the {@link ResourceBundle} class.
+	 *            from the {@link java.util.ResourceBundle} class.
 	 */
 	protected TranslationBundleException(String message, Class bundleClass, Locale locale, Exception cause) {
 		super(message, cause);
@@ -74,6 +74,8 @@ protected TranslationBundleException(String message, Class bundleClass, Locale l
 	}
 
 	/**
+	 * Get bundle class
+	 *
 	 * @return bundle class for which the exception occurred
 	 */
 	final public Class getBundleClass() {
@@ -81,6 +83,8 @@ final public Class getBundleClass() {
 	}
 
 	/**
+	 * Get locale for which the exception occurred
+	 *
 	 * @return locale for which the exception occurred
 	 */
 	final public Locale getLocale() {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/errors/TranslationBundleLoadingException.java b/org.eclipse.jgit/src/org/eclipse/jgit/errors/TranslationBundleLoadingException.java
index 6cb332d..4033ee1 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/errors/TranslationBundleLoadingException.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/errors/TranslationBundleLoadingException.java
@@ -43,7 +43,6 @@
 package org.eclipse.jgit.errors;
 
 import java.util.Locale;
-import java.util.ResourceBundle;
 
 /**
  * This exception will be thrown when a translation bundle loading
@@ -53,8 +52,9 @@ public class TranslationBundleLoadingException extends TranslationBundleExceptio
 	private static final long serialVersionUID = 1L;
 
 	/**
-	 * Construct a {@link TranslationBundleLoadingException} for the specified
-	 * bundle class and locale.
+	 * Construct a
+	 * {@link org.eclipse.jgit.errors.TranslationBundleLoadingException} for the
+	 * specified bundle class and locale.
 	 *
 	 * @param bundleClass
 	 *            the bundle class for which the loading failed
@@ -62,7 +62,8 @@ public class TranslationBundleLoadingException extends TranslationBundleExceptio
 	 *            the locale for which the loading failed
 	 * @param cause
 	 *            the original exception thrown from the
-	 *            {@link ResourceBundle#getBundle(String, Locale)} method.
+	 *            {@link java.util.ResourceBundle#getBundle(String, Locale)}
+	 *            method.
 	 */
 	public TranslationBundleLoadingException(Class bundleClass, Locale locale, Exception cause) {
 		super("Loading of translation bundle failed for [" //$NON-NLS-1$
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/errors/TranslationStringMissingException.java b/org.eclipse.jgit/src/org/eclipse/jgit/errors/TranslationStringMissingException.java
index 05c3842..d30c1be 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/errors/TranslationStringMissingException.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/errors/TranslationStringMissingException.java
@@ -43,7 +43,6 @@
 package org.eclipse.jgit.errors;
 
 import java.util.Locale;
-import java.util.ResourceBundle;
 
 /**
  * This exception will be thrown when a translation string for a translation
@@ -55,8 +54,9 @@ public class TranslationStringMissingException extends TranslationBundleExceptio
 	private final String key;
 
 	/**
-	 * Construct a {@link TranslationStringMissingException} for the specified
-	 * bundle class, locale and translation key
+	 * Construct a
+	 * {@link org.eclipse.jgit.errors.TranslationStringMissingException} for the
+	 * specified bundle class, locale and translation key
 	 *
 	 * @param bundleClass
 	 *            the bundle class for which a translation string was missing
@@ -66,7 +66,7 @@ public class TranslationStringMissingException extends TranslationBundleExceptio
 	 *            the key of the missing translation string
 	 * @param cause
 	 *            the original exception thrown from the
-	 *            {@link ResourceBundle#getString(String)} method.
+	 *            {@link java.util.ResourceBundle#getString(String)} method.
 	 */
 	public TranslationStringMissingException(Class bundleClass, Locale locale, String key, Exception cause) {
 		super("Translation missing for [" + bundleClass.getName() + ", " //$NON-NLS-1$ //$NON-NLS-2$
@@ -76,6 +76,8 @@ public TranslationStringMissingException(Class bundleClass, Locale locale, Strin
 	}
 
 	/**
+	 * Get the key of the missing translation string
+	 *
 	 * @return the key of the missing translation string
 	 */
 	public String getKey() {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/errors/TransportException.java b/org.eclipse.jgit/src/org/eclipse/jgit/errors/TransportException.java
index 86dea82..5fecf0e 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/errors/TransportException.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/errors/TransportException.java
@@ -64,7 +64,7 @@ public class TransportException extends IOException {
 	 * @param s
 	 *            message
 	 */
-	public TransportException(final URIish uri, final String s) {
+	public TransportException(URIish uri, String s) {
 		super(uri.setPass(null) + ": " + s); //$NON-NLS-1$
 	}
 
@@ -90,7 +90,7 @@ public TransportException(final URIish uri, final String s,
 	 * @param s
 	 *            message
 	 */
-	public TransportException(final String s) {
+	public TransportException(String s) {
 		super(s);
 	}
 
@@ -102,7 +102,7 @@ public TransportException(final String s) {
 	 * @param cause
 	 *            root cause exception
 	 */
-	public TransportException(final String s, final Throwable cause) {
+	public TransportException(String s, Throwable cause) {
 		super(s);
 		initCause(cause);
 	}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/errors/UnmergedPathException.java b/org.eclipse.jgit/src/org/eclipse/jgit/errors/UnmergedPathException.java
index 3dbfb5f..6de9153 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/errors/UnmergedPathException.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/errors/UnmergedPathException.java
@@ -63,12 +63,16 @@ public class UnmergedPathException extends IOException {
 	 * @param dce
 	 *            the first non-zero stage of the unmerged path.
 	 */
-	public UnmergedPathException(final DirCacheEntry dce) {
+	public UnmergedPathException(DirCacheEntry dce) {
 		super(MessageFormat.format(JGitText.get().unmergedPath, dce.getPathString()));
 		entry = dce;
 	}
 
-	/** @return the first non-zero stage of the unmerged path */
+	/**
+	 * Get the first non-zero stage of the unmerged path
+	 *
+	 * @return the first non-zero stage of the unmerged path
+	 */
 	public DirCacheEntry getDirCacheEntry() {
 		return entry;
 	}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/errors/UnpackException.java b/org.eclipse.jgit/src/org/eclipse/jgit/errors/UnpackException.java
index a9b0113..0e0ff58 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/errors/UnpackException.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/errors/UnpackException.java
@@ -47,7 +47,9 @@
 
 import org.eclipse.jgit.internal.JGitText;
 
-/** Indicates a ReceivePack failure while scanning the pack stream. */
+/**
+ * Indicates a ReceivePack failure while scanning the pack stream.
+ */
 public class UnpackException extends IOException {
 	private static final long serialVersionUID = 1L;
 
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/errors/UnsupportedCredentialItem.java b/org.eclipse.jgit/src/org/eclipse/jgit/errors/UnsupportedCredentialItem.java
index daba576..9bab687 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/errors/UnsupportedCredentialItem.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/errors/UnsupportedCredentialItem.java
@@ -43,13 +43,12 @@
  */
 package org.eclipse.jgit.errors;
 
-import org.eclipse.jgit.transport.CredentialItem;
-import org.eclipse.jgit.transport.CredentialsProvider;
 import org.eclipse.jgit.transport.URIish;
 
 /**
- * An exception thrown when a {@link CredentialItem} is requested from a
- * {@link CredentialsProvider} which is not supported by this provider.
+ * An exception thrown when a {@link org.eclipse.jgit.transport.CredentialItem}
+ * is requested from a {@link org.eclipse.jgit.transport.CredentialsProvider}
+ * which is not supported by this provider.
  */
 public class UnsupportedCredentialItem extends RuntimeException {
 	private static final long serialVersionUID = 1L;
@@ -63,7 +62,7 @@ public class UnsupportedCredentialItem extends RuntimeException {
 	 * @param s
 	 *            message
 	 */
-	public UnsupportedCredentialItem(final URIish uri, final String s) {
+	public UnsupportedCredentialItem(URIish uri, String s) {
 		super(uri.setPass(null) + ": " + s); //$NON-NLS-1$
 	}
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/errors/UnsupportedPackIndexVersionException.java b/org.eclipse.jgit/src/org/eclipse/jgit/errors/UnsupportedPackIndexVersionException.java
index 0b7ccf5..0a4fef1 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/errors/UnsupportedPackIndexVersionException.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/errors/UnsupportedPackIndexVersionException.java
@@ -62,7 +62,7 @@ public class UnsupportedPackIndexVersionException extends IOException {
 	 * @param version
 	 *            pack index version
 	 */
-	public UnsupportedPackIndexVersionException(final int version) {
+	public UnsupportedPackIndexVersionException(int version) {
 		super(MessageFormat.format(JGitText.get().unsupportedPackIndexVersion,
 				Integer.valueOf(version)));
 	}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/errors/UnsupportedPackVersionException.java b/org.eclipse.jgit/src/org/eclipse/jgit/errors/UnsupportedPackVersionException.java
index 2361186..cbf8f3a 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/errors/UnsupportedPackVersionException.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/errors/UnsupportedPackVersionException.java
@@ -62,7 +62,7 @@ public class UnsupportedPackVersionException extends IOException {
 	 * @param version
 	 *            pack version
 	 */
-	public UnsupportedPackVersionException(final long version) {
+	public UnsupportedPackVersionException(long version) {
 		super(MessageFormat.format(JGitText.get().unsupportedPackVersion,
 				Long.valueOf(version)));
 	}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/events/ConfigChangedEvent.java b/org.eclipse.jgit/src/org/eclipse/jgit/events/ConfigChangedEvent.java
index 79598ea..69f6ff8 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/events/ConfigChangedEvent.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/events/ConfigChangedEvent.java
@@ -43,13 +43,17 @@
 
 package org.eclipse.jgit.events;
 
-/** Describes a change to one or more keys in the configuration. */
+/**
+ * Describes a change to one or more keys in the configuration.
+ */
 public class ConfigChangedEvent extends RepositoryEvent<ConfigChangedListener> {
+	/** {@inheritDoc} */
 	@Override
 	public Class<ConfigChangedListener> getListenerType() {
 		return ConfigChangedListener.class;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void dispatch(ConfigChangedListener listener) {
 		listener.onConfigChanged(this);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/events/ConfigChangedListener.java b/org.eclipse.jgit/src/org/eclipse/jgit/events/ConfigChangedListener.java
index 322cf7f..34fe90a 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/events/ConfigChangedListener.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/events/ConfigChangedListener.java
@@ -43,7 +43,9 @@
 
 package org.eclipse.jgit.events;
 
-/** Receives {@link ConfigChangedEvent}s. */
+/**
+ * Receives {@link org.eclipse.jgit.events.ConfigChangedEvent}s.
+ */
 public interface ConfigChangedListener extends RepositoryListener {
 	/**
 	 * Invoked when any change is made to the configuration.
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/events/IndexChangedEvent.java b/org.eclipse.jgit/src/org/eclipse/jgit/events/IndexChangedEvent.java
index a54288e..dcce86a 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/events/IndexChangedEvent.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/events/IndexChangedEvent.java
@@ -43,13 +43,39 @@
 
 package org.eclipse.jgit.events;
 
-/** Describes a change to one or more paths in the index file. */
+/**
+ * Describes a change to one or more paths in the index file.
+ */
 public class IndexChangedEvent extends RepositoryEvent<IndexChangedListener> {
+	private boolean internal;
+
+	/**
+	 * Notify that the index changed
+	 *
+	 * @param internal
+	 *                     {@code true} if the index was changed by the same
+	 *                     JGit process
+	 * @since 5.0
+	 */
+	public IndexChangedEvent(boolean internal) {
+		this.internal = internal;
+	}
+
+	/**
+	 * @return {@code true} if the index was changed by the same JGit process
+	 * @since 5.0
+	 */
+	public boolean isInternal() {
+		return internal;
+	}
+
+	/** {@inheritDoc} */
 	@Override
 	public Class<IndexChangedListener> getListenerType() {
 		return IndexChangedListener.class;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void dispatch(IndexChangedListener listener) {
 		listener.onIndexChanged(this);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/events/IndexChangedListener.java b/org.eclipse.jgit/src/org/eclipse/jgit/events/IndexChangedListener.java
index d41ef74..682cea5 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/events/IndexChangedListener.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/events/IndexChangedListener.java
@@ -43,7 +43,9 @@
 
 package org.eclipse.jgit.events;
 
-/** Receives {@link IndexChangedEvent}s. */
+/**
+ * Receives {@link org.eclipse.jgit.events.IndexChangedEvent}s.
+ */
 public interface IndexChangedListener extends RepositoryListener {
 	/**
 	 * Invoked when any change is made to the index.
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/events/ListenerHandle.java b/org.eclipse.jgit/src/org/eclipse/jgit/events/ListenerHandle.java
index d8cd756..dcd5374 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/events/ListenerHandle.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/events/ListenerHandle.java
@@ -43,7 +43,9 @@
 
 package org.eclipse.jgit.events;
 
-/** Tracks a previously registered {@link RepositoryListener}. */
+/**
+ * Tracks a previously registered {@link org.eclipse.jgit.events.RepositoryListener}.
+ */
 public class ListenerHandle {
 	private final ListenerList parent;
 
@@ -59,11 +61,14 @@ public class ListenerHandle {
 		this.listener = listener;
 	}
 
-	/** Remove the listener and stop receiving events. */
+	/**
+	 * Remove the listener and stop receiving events.
+	 */
 	public void remove() {
 		parent.remove(this);
 	}
 
+	/** {@inheritDoc} */
 	@SuppressWarnings("nls")
 	@Override
 	public String toString() {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/events/ListenerList.java b/org.eclipse.jgit/src/org/eclipse/jgit/events/ListenerList.java
index cea03db..9be1c96 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/events/ListenerList.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/events/ListenerList.java
@@ -48,12 +48,14 @@
 import java.util.concurrent.ConcurrentMap;
 import java.util.concurrent.CopyOnWriteArrayList;
 
-/** Manages a thread-safe list of {@link RepositoryListener}s. */
+/**
+ * Manages a thread-safe list of {@link org.eclipse.jgit.events.RepositoryListener}s.
+ */
 public class ListenerList {
 	private final ConcurrentMap<Class<? extends RepositoryListener>, CopyOnWriteArrayList<ListenerHandle>> lists = new ConcurrentHashMap<>();
 
 	/**
-	 * Register a {@link WorkingTreeModifiedListener}.
+	 * Register a {@link org.eclipse.jgit.events.WorkingTreeModifiedListener}.
 	 *
 	 * @param listener
 	 *            the listener implementation.
@@ -102,8 +104,6 @@ public ListenerHandle addConfigChangedListener(
 	/**
 	 * Add a listener to the list.
 	 *
-	 * @param <T>
-	 *            the type of listener being registered.
 	 * @param type
 	 *            type of listener being registered.
 	 * @param listener
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/events/RefsChangedEvent.java b/org.eclipse.jgit/src/org/eclipse/jgit/events/RefsChangedEvent.java
index 36af3f8..f1923af 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/events/RefsChangedEvent.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/events/RefsChangedEvent.java
@@ -43,13 +43,17 @@
 
 package org.eclipse.jgit.events;
 
-/** Describes a change to one or more references of a repository. */
+/**
+ * Describes a change to one or more references of a repository.
+ */
 public class RefsChangedEvent extends RepositoryEvent<RefsChangedListener> {
+	/** {@inheritDoc} */
 	@Override
 	public Class<RefsChangedListener> getListenerType() {
 		return RefsChangedListener.class;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void dispatch(RefsChangedListener listener) {
 		listener.onRefsChanged(this);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/events/RefsChangedListener.java b/org.eclipse.jgit/src/org/eclipse/jgit/events/RefsChangedListener.java
index 9c0f4ed..f3cdad1 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/events/RefsChangedListener.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/events/RefsChangedListener.java
@@ -43,7 +43,9 @@
 
 package org.eclipse.jgit.events;
 
-/** Receives {@link RefsChangedEvent}s. */
+/**
+ * Receives {@link org.eclipse.jgit.events.RefsChangedEvent}s.
+ */
 public interface RefsChangedListener extends RepositoryListener {
 	/**
 	 * Invoked when any reference changes.
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/events/RepositoryEvent.java b/org.eclipse.jgit/src/org/eclipse/jgit/events/RepositoryEvent.java
index 1b7d28c..576b21b 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/events/RepositoryEvent.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/events/RepositoryEvent.java
@@ -59,7 +59,8 @@ public abstract class RepositoryEvent<T extends RepositoryListener> {
 	 * Set the repository this event occurred on.
 	 * <p>
 	 * This method should only be invoked once on each event object, and is
-	 * automatically set by {@link Repository#fireEvent(RepositoryEvent)}.
+	 * automatically set by
+	 * {@link org.eclipse.jgit.lib.Repository#fireEvent(RepositoryEvent)}.
 	 *
 	 * @param r
 	 *            the repository.
@@ -69,12 +70,20 @@ public void setRepository(Repository r) {
 			repository = r;
 	}
 
-	/** @return the repository that was changed. */
+	/**
+	 * Get the repository that was changed
+	 *
+	 * @return the repository that was changed
+	 */
 	public Repository getRepository() {
 		return repository;
 	}
 
-	/** @return type of listener this event dispatches to. */
+	/**
+	 * Get type of listener this event dispatches to
+	 *
+	 * @return type of listener this event dispatches to
+	 */
 	public abstract Class<T> getListenerType();
 
 	/**
@@ -85,6 +94,7 @@ public Repository getRepository() {
 	 */
 	public abstract void dispatch(T listener);
 
+	/** {@inheritDoc} */
 	@SuppressWarnings("nls")
 	@Override
 	public String toString() {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/events/RepositoryListener.java b/org.eclipse.jgit/src/org/eclipse/jgit/events/RepositoryListener.java
index 4f951e5..a2cf0cc 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/events/RepositoryListener.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/events/RepositoryListener.java
@@ -43,7 +43,9 @@
 
 package org.eclipse.jgit.events;
 
-/** A listener can register for event delivery. */
+/**
+ * A listener can register for event delivery.
+ */
 public interface RepositoryListener {
 	// Empty marker interface; see extensions for actual methods.
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/events/WorkingTreeModifiedEvent.java b/org.eclipse.jgit/src/org/eclipse/jgit/events/WorkingTreeModifiedEvent.java
index 6517823..9fbcc4d 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/events/WorkingTreeModifiedEvent.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/events/WorkingTreeModifiedEvent.java
@@ -48,8 +48,9 @@
 import org.eclipse.jgit.annotations.NonNull;
 
 /**
- * A {@link RepositoryEvent} describing changes to the working tree. It is fired
- * whenever a {@link org.eclipse.jgit.dircache.DirCacheCheckout} modifies
+ * A {@link org.eclipse.jgit.events.RepositoryEvent} describing changes to the
+ * working tree. It is fired whenever a
+ * {@link org.eclipse.jgit.dircache.DirCacheCheckout} modifies
  * (adds/deletes/updates) files in the working tree.
  *
  * @since 4.9
@@ -62,8 +63,8 @@ public class WorkingTreeModifiedEvent
 	private Collection<String> deleted;
 
 	/**
-	 * Creates a new {@link WorkingTreeModifiedEvent} with the given
-	 * collections.
+	 * Creates a new {@link org.eclipse.jgit.events.WorkingTreeModifiedEvent}
+	 * with the given collections.
 	 *
 	 * @param modified
 	 *            repository-relative paths that were added or updated
@@ -88,8 +89,8 @@ public boolean isEmpty() {
 	}
 
 	/**
-	 * Retrieves the {@link Collection} of repository-relative paths of files
-	 * that were modified (added or updated).
+	 * Retrieves the {@link java.util.Collection} of repository-relative paths
+	 * of files that were modified (added or updated).
 	 *
 	 * @return the set
 	 */
@@ -103,8 +104,8 @@ public boolean isEmpty() {
 	}
 
 	/**
-	 * Retrieves the {@link Collection} of repository-relative paths of files
-	 * that were deleted.
+	 * Retrieves the {@link java.util.Collection} of repository-relative paths
+	 * of files that were deleted.
 	 *
 	 * @return the set
 	 */
@@ -117,11 +118,13 @@ public boolean isEmpty() {
 		return result;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public Class<WorkingTreeModifiedListener> getListenerType() {
 		return WorkingTreeModifiedListener.class;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void dispatch(WorkingTreeModifiedListener listener) {
 		listener.onWorkingTreeModified(this);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/events/WorkingTreeModifiedListener.java b/org.eclipse.jgit/src/org/eclipse/jgit/events/WorkingTreeModifiedListener.java
index 402a900..728ce26 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/events/WorkingTreeModifiedListener.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/events/WorkingTreeModifiedListener.java
@@ -44,8 +44,8 @@
 package org.eclipse.jgit.events;
 
 /**
- * Receives {@link WorkingTreeModifiedEvent}s, which are fired whenever a
- * {@link org.eclipse.jgit.dircache.DirCacheCheckout} modifies
+ * Receives {@link org.eclipse.jgit.events.WorkingTreeModifiedEvent}s, which are
+ * fired whenever a {@link org.eclipse.jgit.dircache.DirCacheCheckout} modifies
  * (adds/deletes/updates) files in the working tree.
  *
  * @since 4.9
@@ -56,6 +56,8 @@ public interface WorkingTreeModifiedListener extends RepositoryListener {
 	 * Respond to working tree modifications.
 	 *
 	 * @param event
+	 *            a {@link org.eclipse.jgit.events.WorkingTreeModifiedEvent}
+	 *            object.
 	 */
 	void onWorkingTreeModified(WorkingTreeModifiedEvent event);
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/fnmatch/AbstractHead.java b/org.eclipse.jgit/src/org/eclipse/jgit/fnmatch/AbstractHead.java
index 10c84c4..60669bb 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/fnmatch/AbstractHead.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/fnmatch/AbstractHead.java
@@ -53,6 +53,13 @@ abstract class AbstractHead implements Head {
 
 	private final boolean star;
 
+	/**
+	 * Whether the char matches
+	 *
+	 * @param c
+	 *            a char.
+	 * @return whether the char matches
+	 */
 	protected abstract boolean matches(char c);
 
 	AbstractHead(boolean star) {
@@ -60,9 +67,11 @@ abstract class AbstractHead implements Head {
 	}
 
 	/**
+	 * Set {@link org.eclipse.jgit.fnmatch.Head}s which will not be modified.
 	 *
 	 * @param newHeads
-	 *            a list of {@link Head}s which will not be modified.
+	 *            a list of {@link org.eclipse.jgit.fnmatch.Head}s which will
+	 *            not be modified.
 	 */
 	public final void setNewHeads(List<Head> newHeads) {
 		if (this.newHeads != null)
@@ -70,6 +79,7 @@ public final void setNewHeads(List<Head> newHeads) {
 		this.newHeads = newHeads;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public List<Head> getNextHeads(char c) {
 		if (matches(c))
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/fnmatch/CharacterHead.java b/org.eclipse.jgit/src/org/eclipse/jgit/fnmatch/CharacterHead.java
index 6211b24..7039c3d 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/fnmatch/CharacterHead.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/fnmatch/CharacterHead.java
@@ -47,16 +47,24 @@
 final class CharacterHead extends AbstractHead {
 	private final char expectedCharacter;
 
-	protected CharacterHead(final char expectedCharacter) {
+	/**
+	 * Constructor for CharacterHead
+	 *
+	 * @param expectedCharacter
+	 *            expected {@code char}
+	 */
+	protected CharacterHead(char expectedCharacter) {
 		super(false);
 		this.expectedCharacter = expectedCharacter;
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	protected final boolean matches(final char c) {
+	protected final boolean matches(char c) {
 		return c == expectedCharacter;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public String toString() {
 		return String.valueOf(expectedCharacter);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/fnmatch/FileNameMatcher.java b/org.eclipse.jgit/src/org/eclipse/jgit/fnmatch/FileNameMatcher.java
index 856d74e..bfcc580 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/fnmatch/FileNameMatcher.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/fnmatch/FileNameMatcher.java
@@ -105,7 +105,7 @@ public class FileNameMatcher {
 	 * @param headsStartValue
 	 *            must be a list which will never be modified.
 	 */
-	private FileNameMatcher(final List<Head> headsStartValue) {
+	private FileNameMatcher(List<Head> headsStartValue) {
 		this(headsStartValue, headsStartValue);
 	}
 
@@ -126,12 +126,14 @@ private FileNameMatcher(final List<Head> headsStartValue,
 	}
 
 	/**
+	 * Constructor for FileNameMatcher
+	 *
 	 * @param patternString
 	 *            must contain a pattern which fnmatch would accept.
 	 * @param invalidWildgetCharacter
 	 *            if this parameter isn't null then this character will not
 	 *            match at wildcards(* and ? are wildcards).
-	 * @throws InvalidPatternException
+	 * @throws org.eclipse.jgit.errors.InvalidPatternException
 	 *             if the patternString contains a invalid fnmatch pattern.
 	 */
 	public FileNameMatcher(final String patternString,
@@ -141,11 +143,13 @@ public FileNameMatcher(final String patternString,
 	}
 
 	/**
-	 * A Copy Constructor which creates a new {@link FileNameMatcher} with the
-	 * same state and reset point like <code>other</code>.
+	 * A Copy Constructor which creates a new
+	 * {@link org.eclipse.jgit.fnmatch.FileNameMatcher} with the same state and
+	 * reset point like <code>other</code>.
 	 *
 	 * @param other
-	 *            another {@link FileNameMatcher} instance.
+	 *            another {@link org.eclipse.jgit.fnmatch.FileNameMatcher}
+	 *            instance.
 	 */
 	public FileNameMatcher(FileNameMatcher other) {
 		this(other.headsStartValue, other.heads);
@@ -311,7 +315,7 @@ private static AbstractHead createWildCardHead(
 	 * @param c new character to append
 	 * @return true to continue, false if the matcher can stop appending
 	 */
-	private boolean extendStringToMatchByOneCharacter(final char c) {
+	private boolean extendStringToMatchByOneCharacter(char c) {
 		final List<Head> newHeads = listForLocalUseage;
 		newHeads.clear();
 		List<Head> lastAddedHeads = null;
@@ -347,12 +351,13 @@ private static int indexOfUnescaped(final String searchString,
 	}
 
 	/**
+	 * Append to the string which is matched against the patterns of this class
 	 *
 	 * @param stringToMatch
 	 *            extends the string which is matched against the patterns of
 	 *            this class.
 	 */
-	public void append(final String stringToMatch) {
+	public void append(String stringToMatch) {
 		for (int i = 0; i < stringToMatch.length(); i++) {
 			final char c = stringToMatch.charAt(i);
 			if (!extendStringToMatchByOneCharacter(c))
@@ -369,10 +374,13 @@ public void reset() {
 	}
 
 	/**
+	 * Create a {@link org.eclipse.jgit.fnmatch.FileNameMatcher} instance which
+	 * uses the same pattern like this matcher, but has the current state of
+	 * this matcher as reset and start point
 	 *
-	 * @return a {@link FileNameMatcher} instance which uses the same pattern
-	 *         like this matcher, but has the current state of this matcher as
-	 *         reset and start point.
+	 * @return a {@link org.eclipse.jgit.fnmatch.FileNameMatcher} instance which
+	 *         uses the same pattern like this matcher, but has the current
+	 *         state of this matcher as reset and start point.
 	 */
 	public FileNameMatcher createMatcherForSuffix() {
 		final List<Head> copyOfHeads = new ArrayList<>(heads.size());
@@ -381,8 +389,9 @@ public FileNameMatcher createMatcherForSuffix() {
 	}
 
 	/**
+	 * Whether the matcher matches
 	 *
-	 * @return true, if the string currently being matched does match.
+	 * @return whether the matcher matches
 	 */
 	public boolean isMatch() {
 		if (heads.isEmpty())
@@ -400,9 +409,9 @@ public boolean isMatch() {
 	}
 
 	/**
+	 * Whether a match can be appended
 	 *
-	 * @return false, if the string being matched will not match when the string
-	 *         gets extended.
+	 * @return a boolean.
 	 */
 	public boolean canAppendMatch() {
 		for (int i = 0; i < heads.size(); i++) {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/fnmatch/GroupHead.java b/org.eclipse.jgit/src/org/eclipse/jgit/fnmatch/GroupHead.java
index 5c18756..1dc5931 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/fnmatch/GroupHead.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/fnmatch/GroupHead.java
@@ -61,7 +61,7 @@ final class GroupHead extends AbstractHead {
 
 	private final boolean inverse;
 
-	GroupHead(String pattern, final String wholePattern)
+	GroupHead(String pattern, String wholePattern)
 			throws InvalidPatternException {
 		super(false);
 		this.characterClasses = new ArrayList<>();
@@ -130,8 +130,9 @@ final class GroupHead extends AbstractHead {
 		}
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	protected final boolean matches(final char c) {
+	protected final boolean matches(char c) {
 		for (CharacterPattern pattern : characterClasses) {
 			if (pattern.matches(c)) {
 				return !inverse;
@@ -213,7 +214,7 @@ public final boolean matches(char c) {
 	private static final class OneCharacterPattern implements CharacterPattern {
 		private char expectedCharacter;
 
-		OneCharacterPattern(final char c) {
+		OneCharacterPattern(char c) {
 			this.expectedCharacter = c;
 		}
 
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/fnmatch/Head.java b/org.eclipse.jgit/src/org/eclipse/jgit/fnmatch/Head.java
index 3de18a7..49839f8 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/fnmatch/Head.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/fnmatch/Head.java
@@ -48,6 +48,7 @@
 
 interface Head {
 	/**
+	 * Get the character which decides which heads are returned
 	 *
 	 * @param c
 	 *            the character which decides which heads are returned.
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/fnmatch/LastHead.java b/org.eclipse.jgit/src/org/eclipse/jgit/fnmatch/LastHead.java
index f9ddd9e..726d1f2 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/fnmatch/LastHead.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/fnmatch/LastHead.java
@@ -56,6 +56,7 @@ private LastHead() {
 		// defined because of javadoc and visibility modifier.
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public List<Head> getNextHeads(char c) {
 		return FileNameMatcher.EMPTY_HEAD_LIST;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/fnmatch/RestrictedWildCardHead.java b/org.eclipse.jgit/src/org/eclipse/jgit/fnmatch/RestrictedWildCardHead.java
index 4a0a03d..45e6ed2 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/fnmatch/RestrictedWildCardHead.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/fnmatch/RestrictedWildCardHead.java
@@ -47,16 +47,18 @@
 final class RestrictedWildCardHead extends AbstractHead {
 	private final char excludedCharacter;
 
-	RestrictedWildCardHead(final char excludedCharacter, final boolean star) {
+	RestrictedWildCardHead(char excludedCharacter, boolean star) {
 		super(star);
 		this.excludedCharacter = excludedCharacter;
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	protected final boolean matches(final char c) {
+	protected final boolean matches(char c) {
 		return c != excludedCharacter;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public String toString() {
 		return isStar() ? "*" : "?"; //$NON-NLS-1$ //$NON-NLS-2$
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/fnmatch/WildCardHead.java b/org.eclipse.jgit/src/org/eclipse/jgit/fnmatch/WildCardHead.java
index b5173d9..07362aa 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/fnmatch/WildCardHead.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/fnmatch/WildCardHead.java
@@ -49,8 +49,9 @@ final class WildCardHead extends AbstractHead {
 		super(star);
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	protected final boolean matches(final char c) {
+	protected final boolean matches(char c) {
 		return true;
 	}
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/ManifestParser.java b/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/ManifestParser.java
index ddc6add..929ffac 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/ManifestParser.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/ManifestParser.java
@@ -113,12 +113,22 @@ public InputStream readIncludeFile(String path)
 	}
 
 	/**
+	 * Constructor for ManifestParser
+	 *
 	 * @param includedReader
+	 *            a
+	 *            {@link org.eclipse.jgit.gitrepo.ManifestParser.IncludedFileReader}
+	 *            object.
 	 * @param filename
+	 *            a {@link java.lang.String} object.
 	 * @param defaultBranch
+	 *            a {@link java.lang.String} object.
 	 * @param baseUrl
+	 *            a {@link java.lang.String} object.
 	 * @param groups
+	 *            a {@link java.lang.String} object.
 	 * @param rootRepo
+	 *            a {@link org.eclipse.jgit.lib.Repository} object.
 	 */
 	public ManifestParser(IncludedFileReader includedReader, String filename,
 			String defaultBranch, String baseUrl, String groups,
@@ -153,7 +163,8 @@ public ManifestParser(IncludedFileReader includedReader, String filename,
 	 * Read the xml file.
 	 *
 	 * @param inputStream
-	 * @throws IOException
+	 *            a {@link java.io.InputStream} object.
+	 * @throws java.io.IOException
 	 */
 	public void read(InputStream inputStream) throws IOException {
 		xmlInRead++;
@@ -167,13 +178,11 @@ public void read(InputStream inputStream) throws IOException {
 		try {
 			xr.parse(new InputSource(inputStream));
 		} catch (SAXException e) {
-			IOException error = new IOException(
-						RepoText.get().errorParsingManifestFile);
-			error.initCause(e);
-			throw error;
+			throw new IOException(RepoText.get().errorParsingManifestFile, e);
 		}
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void startElement(
 			String uri,
@@ -246,6 +255,7 @@ public void startElement(
 		}
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void endElement(
 			String uri,
@@ -257,6 +267,7 @@ public void endElement(
 		}
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void endDocument() throws SAXException {
 		xmlInRead--;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoCommand.java
index 219babd..80fd3cf 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoCommand.java
@@ -54,6 +54,7 @@
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 import java.util.Set;
 import java.util.StringJoiner;
 
@@ -124,7 +125,6 @@ public class RepoCommand extends GitCommand<RevCommit> {
 	private boolean ignoreRemoteFailures = false;
 
 	private List<RepoProject> bareProjects;
-	private Git git;
 	private ProgressMonitor monitor;
 
 	/**
@@ -232,7 +232,10 @@ private static class RemoteUnavailableException extends GitAPIException {
 	}
 
 	/**
+	 * Constructor for RepoCommand
+	 *
 	 * @param repo
+	 *            the {@link org.eclipse.jgit.lib.Repository}
 	 */
 	public RepoCommand(Repository repo) {
 		super(repo);
@@ -258,7 +261,7 @@ public RepoCommand setPath(String path) {
 	 * Setting inputStream will ignore the path set. It will be closed in
 	 * {@link #call}.
 	 *
-	 * @param inputStream
+	 * @param inputStream a {@link java.io.InputStream} object.
 	 * @return this command
 	 * @since 3.5
 	 */
@@ -271,10 +274,11 @@ public RepoCommand setInputStream(InputStream inputStream) {
 	 * Set base URI of the paths inside the XML. This is typically the name of
 	 * the directory holding the manifest repository, eg. for
 	 * https://android.googlesource.com/platform/manifest, this should be
-	 * /platform (if you would run this on android.googlesource.com)
-	 * or https://android.googlesource.com/platform elsewhere.
+	 * /platform (if you would run this on android.googlesource.com) or
+	 * https://android.googlesource.com/platform elsewhere.
 	 *
 	 * @param uri
+	 *            the base URI
 	 * @return this command
 	 */
 	public RepoCommand setURI(String uri) {
@@ -319,6 +323,7 @@ public RepoCommand setGroups(String groups) {
 	 * revision specified in project, this branch will be used.
 	 *
 	 * @param branch
+	 *            a branch name
 	 * @return this command
 	 */
 	public RepoCommand setBranch(String branch) {
@@ -336,6 +341,7 @@ public RepoCommand setBranch(String branch) {
 	 * ignored.
 	 *
 	 * @param branch
+	 *            branch name
 	 * @return this command
 	 * @since 4.1
 	 */
@@ -404,9 +410,10 @@ public RepoCommand setRecommendShallow(boolean enable) {
 	 *
 	 * @see org.eclipse.jgit.lib.NullProgressMonitor
 	 * @param monitor
+	 *            a {@link org.eclipse.jgit.lib.ProgressMonitor}
 	 * @return this command
 	 */
-	public RepoCommand setProgressMonitor(final ProgressMonitor monitor) {
+	public RepoCommand setProgressMonitor(ProgressMonitor monitor) {
 		this.monitor = monitor;
 		return this;
 	}
@@ -438,9 +445,10 @@ public RepoCommand setIgnoreRemoteFailures(boolean ignore) {
 	 * ignored.
 	 *
 	 * @param author
+	 *            the author's {@link org.eclipse.jgit.lib.PersonIdent}
 	 * @return this command
 	 */
-	public RepoCommand setAuthor(final PersonIdent author) {
+	public RepoCommand setAuthor(PersonIdent author) {
 		this.author = author;
 		return this;
 	}
@@ -451,9 +459,11 @@ public RepoCommand setAuthor(final PersonIdent author) {
 	 * This is only used in bare repositories.
 	 *
 	 * @param callback
+	 *            a {@link org.eclipse.jgit.gitrepo.RepoCommand.RemoteReader}
+	 *            object.
 	 * @return this command
 	 */
-	public RepoCommand setRemoteReader(final RemoteReader callback) {
+	public RepoCommand setRemoteReader(RemoteReader callback) {
 		this.callback = callback;
 		return this;
 	}
@@ -462,6 +472,9 @@ public RepoCommand setRemoteReader(final RemoteReader callback) {
 	 * Set the IncludedFileReader callback.
 	 *
 	 * @param reader
+	 *            a
+	 *            {@link org.eclipse.jgit.gitrepo.ManifestParser.IncludedFileReader}
+	 *            object.
 	 * @return this command
 	 * @since 4.0
 	 */
@@ -470,60 +483,53 @@ public RepoCommand setIncludedFileReader(IncludedFileReader reader) {
 		return this;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public RevCommit call() throws GitAPIException {
-		try {
-			checkCallable();
-			if (baseUri == null) {
-				baseUri = ""; //$NON-NLS-1$
-			}
-			if (inputStream == null) {
-				if (manifestPath == null || manifestPath.length() == 0)
-					throw new IllegalArgumentException(
-							JGitText.get().pathNotConfigured);
-				try {
-					inputStream = new FileInputStream(manifestPath);
-				} catch (IOException e) {
-					throw new IllegalArgumentException(
-							JGitText.get().pathNotConfigured);
-				}
-			}
-
-			if (repo.isBare()) {
-				bareProjects = new ArrayList<>();
-				if (author == null)
-					author = new PersonIdent(repo);
-				if (callback == null)
-					callback = new DefaultRemoteReader();
-			} else
-				git = new Git(repo);
-
-			ManifestParser parser = new ManifestParser(
-					includedReader, manifestPath, branch, baseUri, groupsParam, repo);
+		checkCallable();
+		if (baseUri == null) {
+			baseUri = ""; //$NON-NLS-1$
+		}
+		if (inputStream == null) {
+			if (manifestPath == null || manifestPath.length() == 0)
+				throw new IllegalArgumentException(
+						JGitText.get().pathNotConfigured);
 			try {
-				parser.read(inputStream);
-				for (RepoProject proj : parser.getFilteredProjects()) {
-					addSubmodule(proj.getUrl(),
-							proj.getPath(),
-							proj.getRevision(),
-							proj.getCopyFiles(),
-							proj.getLinkFiles(),
-							proj.getGroups(),
-							proj.getRecommendShallow());
-				}
-			} catch (GitAPIException | IOException e) {
-				throw new ManifestErrorException(e);
+				inputStream = new FileInputStream(manifestPath);
+			} catch (IOException e) {
+				throw new IllegalArgumentException(
+						JGitText.get().pathNotConfigured);
 			}
+		}
+
+		List<RepoProject> filteredProjects;
+		try {
+			ManifestParser parser = new ManifestParser(includedReader,
+					manifestPath, branch, baseUri, groupsParam, repo);
+			parser.read(inputStream);
+			filteredProjects = parser.getFilteredProjects();
+		} catch (IOException e) {
+			throw new ManifestErrorException(e);
 		} finally {
 			try {
-				if (inputStream != null)
-					inputStream.close();
+				inputStream.close();
 			} catch (IOException e) {
 				// Just ignore it, it's not important.
 			}
 		}
 
 		if (repo.isBare()) {
+			bareProjects = new ArrayList<>();
+			if (author == null)
+				author = new PersonIdent(repo);
+			if (callback == null)
+				callback = new DefaultRemoteReader();
+			for (RepoProject proj : filteredProjects) {
+				addSubmoduleBare(proj.getUrl(), proj.getPath(),
+						proj.getRevision(), proj.getCopyFiles(),
+						proj.getLinkFiles(), proj.getGroups(),
+						proj.getRecommendShallow());
+			}
 			DirCache index = DirCache.newInCore();
 			DirCacheBuilder builder = index.builder();
 			ObjectInserter inserter = repo.newObjectInserter();
@@ -534,15 +540,11 @@ public RevCommit call() throws GitAPIException {
 					String path = proj.getPath();
 					String nameUri = proj.getName();
 					ObjectId objectId;
-					if (ObjectId.isId(proj.getRevision())
-							&& !ignoreRemoteFailures) {
+					if (ObjectId.isId(proj.getRevision())) {
 						objectId = ObjectId.fromString(proj.getRevision());
 					} else {
 						objectId = callback.sha1(nameUri, proj.getRevision());
-						if (objectId == null) {
-							if (ignoreRemoteFailures) {
-								continue;
-							}
+						if (objectId == null && !ignoreRemoteFailures) {
 							throw new RemoteUnavailableException(nameUri);
 						}
 						if (recordRemoteBranch) {
@@ -581,38 +583,40 @@ public RevCommit call() throws GitAPIException {
 					cfg.setString("submodule", path, "url", submodUrl.toString()); //$NON-NLS-1$ //$NON-NLS-2$
 
 					// create gitlink
-					DirCacheEntry dcEntry = new DirCacheEntry(path);
-					dcEntry.setObjectId(objectId);
-					dcEntry.setFileMode(FileMode.GITLINK);
-					builder.add(dcEntry);
+					if (objectId != null) {
+						DirCacheEntry dcEntry = new DirCacheEntry(path);
+						dcEntry.setObjectId(objectId);
+						dcEntry.setFileMode(FileMode.GITLINK);
+						builder.add(dcEntry);
 
-					for (CopyFile copyfile : proj.getCopyFiles()) {
-						byte[] src = callback.readFile(
+						for (CopyFile copyfile : proj.getCopyFiles()) {
+							byte[] src = callback.readFile(
 								nameUri, proj.getRevision(), copyfile.src);
-						objectId = inserter.insert(Constants.OBJ_BLOB, src);
-						dcEntry = new DirCacheEntry(copyfile.dest);
-						dcEntry.setObjectId(objectId);
-						dcEntry.setFileMode(FileMode.REGULAR_FILE);
-						builder.add(dcEntry);
-					}
-					for (LinkFile linkfile : proj.getLinkFiles()) {
-						String link;
-						if (linkfile.dest.contains("/")) { //$NON-NLS-1$
-							link = FileUtils.relativizeGitPath(
-									linkfile.dest.substring(0,
-											linkfile.dest.lastIndexOf('/')),
-									proj.getPath() + "/" + linkfile.src); //$NON-NLS-1$
-						} else {
-							link = proj.getPath() + "/" + linkfile.src; //$NON-NLS-1$
+							objectId = inserter.insert(Constants.OBJ_BLOB, src);
+							dcEntry = new DirCacheEntry(copyfile.dest);
+							dcEntry.setObjectId(objectId);
+							dcEntry.setFileMode(FileMode.REGULAR_FILE);
+							builder.add(dcEntry);
 						}
+						for (LinkFile linkfile : proj.getLinkFiles()) {
+							String link;
+							if (linkfile.dest.contains("/")) { //$NON-NLS-1$
+								link = FileUtils.relativizeGitPath(
+									linkfile.dest.substring(0,
+										linkfile.dest.lastIndexOf('/')),
+									proj.getPath() + "/" + linkfile.src); //$NON-NLS-1$
+							} else {
+								link = proj.getPath() + "/" + linkfile.src; //$NON-NLS-1$
+							}
 
-						objectId = inserter.insert(Constants.OBJ_BLOB,
+							objectId = inserter.insert(Constants.OBJ_BLOB,
 								link.getBytes(
-										Constants.CHARACTER_ENCODING));
-						dcEntry = new DirCacheEntry(linkfile.dest);
-						dcEntry.setObjectId(objectId);
-						dcEntry.setFileMode(FileMode.SYMLINK);
-						builder.add(dcEntry);
+									Constants.CHARACTER_ENCODING));
+							dcEntry = new DirCacheEntry(linkfile.dest);
+							dcEntry.setObjectId(objectId);
+							dcEntry.setFileMode(FileMode.SYMLINK);
+							builder.add(dcEntry);
+						}
 					}
 				}
 				String content = cfg.toText();
@@ -640,6 +644,11 @@ public RevCommit call() throws GitAPIException {
 
 				// Create a Commit object, populate it and write it
 				ObjectId headId = repo.resolve(targetBranch + "^{commit}"); //$NON-NLS-1$
+				if (headId != null && rw.parseCommit(headId).getTree().getId().equals(treeId)) {
+					// No change. Do nothing.
+					return rw.parseCommit(headId);
+				}
+
 				CommitBuilder commit = new CommitBuilder();
 				commit.setTreeId(treeId);
 				if (headId != null)
@@ -676,53 +685,62 @@ public RevCommit call() throws GitAPIException {
 				}
 
 				return rw.parseCommit(commitId);
-			} catch (IOException e) {
+			} catch (GitAPIException | IOException e) {
 				throw new ManifestErrorException(e);
 			}
 		} else {
-			return git
-				.commit()
-				.setMessage(RepoText.get().repoCommitMessage)
-				.call();
+			try (Git git = new Git(repo)) {
+				for (RepoProject proj : filteredProjects) {
+					addSubmodule(proj.getUrl(), proj.getPath(),
+							proj.getRevision(), proj.getCopyFiles(),
+							proj.getLinkFiles(), git);
+				}
+				return git.commit().setMessage(RepoText.get().repoCommitMessage)
+						.call();
+			} catch (GitAPIException | IOException e) {
+				throw new ManifestErrorException(e);
+			}
 		}
 	}
 
 	private void addSubmodule(String url, String path, String revision,
-			List<CopyFile> copyfiles, List<LinkFile> linkfiles,
-			Set<String> groups, String recommendShallow)
+			List<CopyFile> copyfiles, List<LinkFile> linkfiles, Git git)
 			throws GitAPIException, IOException {
-		if (repo.isBare()) {
-			RepoProject proj = new RepoProject(url, path, revision, null, groups, recommendShallow);
-			proj.addCopyFiles(copyfiles);
-			proj.addLinkFiles(linkfiles);
-			bareProjects.add(proj);
-		} else {
-			if (!linkfiles.isEmpty()) {
-				throw new UnsupportedOperationException(
-						JGitText.get().nonBareLinkFilesNotSupported);
-			}
-
-			SubmoduleAddCommand add = git
-				.submoduleAdd()
-				.setPath(path)
-				.setURI(url);
-			if (monitor != null)
-				add.setProgressMonitor(monitor);
-
-			Repository subRepo = add.call();
-			if (revision != null) {
-				try (Git sub = new Git(subRepo)) {
-					sub.checkout().setName(findRef(revision, subRepo))
-							.call();
-				}
-				subRepo.close();
-				git.add().addFilepattern(path).call();
-			}
-			for (CopyFile copyfile : copyfiles) {
-				copyfile.copy();
-				git.add().addFilepattern(copyfile.dest).call();
-			}
+		assert (!repo.isBare());
+		assert (git != null);
+		if (!linkfiles.isEmpty()) {
+			throw new UnsupportedOperationException(
+					JGitText.get().nonBareLinkFilesNotSupported);
 		}
+
+		SubmoduleAddCommand add = git.submoduleAdd().setPath(path).setURI(url);
+		if (monitor != null)
+			add.setProgressMonitor(monitor);
+
+		Repository subRepo = add.call();
+		if (revision != null) {
+			try (Git sub = new Git(subRepo)) {
+				sub.checkout().setName(findRef(revision, subRepo)).call();
+			}
+			subRepo.close();
+			git.add().addFilepattern(path).call();
+		}
+		for (CopyFile copyfile : copyfiles) {
+			copyfile.copy();
+			git.add().addFilepattern(copyfile.dest).call();
+		}
+	}
+
+	private void addSubmoduleBare(String url, String path, String revision,
+			List<CopyFile> copyfiles, List<LinkFile> linkfiles,
+			Set<String> groups, String recommendShallow) {
+		assert (repo.isBare());
+		assert (bareProjects != null);
+		RepoProject proj = new RepoProject(url, path, revision, null, groups,
+				recommendShallow);
+		proj.addCopyFiles(copyfiles);
+		proj.addLinkFiles(linkfiles);
+		bareProjects.add(proj);
 	}
 
 	/*
@@ -732,12 +750,7 @@ private void addSubmodule(String url, String path, String revision,
 	 */
 	private static final String SLASH = "/"; //$NON-NLS-1$
 	static URI relativize(URI current, URI target) {
-
-		// We only handle bare paths for now.
-		if (!target.toString().equals(target.getPath())) {
-			return target;
-		}
-		if (!current.toString().equals(current.getPath())) {
+		if (!Objects.equals(current.getHost(), target.getHost())) {
 			return target;
 		}
 
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoProject.java b/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoProject.java
index 00cd38d..7ba83c7 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoProject.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoProject.java
@@ -131,18 +131,10 @@ public void copy() throws IOException {
 			File srcFile = new File(repo.getWorkTree(),
 					path + "/" + src); //$NON-NLS-1$
 			File destFile = new File(repo.getWorkTree(), dest);
-			FileInputStream input = new FileInputStream(srcFile);
-			try {
-				FileOutputStream output = new FileOutputStream(destFile);
-				try {
-					FileChannel channel = input.getChannel();
-					output.getChannel().transferFrom(
-							channel, 0, channel.size());
-				} finally {
-					output.close();
-				}
-			} finally {
-				input.close();
+			try (FileInputStream input = new FileInputStream(srcFile);
+					FileOutputStream output = new FileOutputStream(destFile)) {
+				FileChannel channel = input.getChannel();
+				output.getChannel().transferFrom(channel, 0, channel.size());
 			}
 		}
 	}
@@ -169,6 +161,8 @@ public LinkFile(Repository repo, String path, String src, String dest) {
 	}
 
 	/**
+	 * Constructor for RepoProject
+	 *
 	 * @param name
 	 *            the relative path to the {@code remote}
 	 * @param path
@@ -203,6 +197,8 @@ public RepoProject(String name, String path, String revision,
 	}
 
 	/**
+	 * Constructor for RepoProject
+	 *
 	 * @param name
 	 *            the relative path to the {@code remote}
 	 * @param path
@@ -225,6 +221,7 @@ public RepoProject(String name, String path, String revision,
 	 * Set the url of the sub repo.
 	 *
 	 * @param url
+	 *            project url
 	 * @return this for chaining.
 	 */
 	public RepoProject setUrl(String url) {
@@ -250,6 +247,7 @@ public RepoProject setGroups(String groupsParam) {
 	 * Set the default revision for the sub repo.
 	 *
 	 * @param defaultRevision
+	 *            the name of the default revision
 	 * @return this for chaining.
 	 */
 	public RepoProject setDefaultRevision(String defaultRevision) {
@@ -325,6 +323,7 @@ public String getRemote() {
 	 * Test whether this sub repo belongs to a specified group.
 	 *
 	 * @param group
+	 *            a group
 	 * @return true if {@code group} is present.
 	 */
 	public boolean inGroup(String group) {
@@ -365,7 +364,7 @@ public void setRecommendShallow(String recommendShallow) {
 	/**
 	 * Add a copy file configuration.
 	 *
-	 * @param copyfile
+	 * @param copyfile a {@link org.eclipse.jgit.gitrepo.RepoProject.CopyFile} object.
 	 */
 	public void addCopyFile(CopyFile copyfile) {
 		copyfiles.add(copyfile);
@@ -375,6 +374,8 @@ public void addCopyFile(CopyFile copyfile) {
 	 * Add a bunch of copyfile configurations.
 	 *
 	 * @param copyFiles
+	 *            a collection of
+	 *            {@link org.eclipse.jgit.gitrepo.RepoProject.CopyFile} objects
 	 */
 	public void addCopyFiles(Collection<CopyFile> copyFiles) {
 		this.copyfiles.addAll(copyFiles);
@@ -392,7 +393,7 @@ public void clearCopyFiles() {
 	/**
 	 * Add a link file configuration.
 	 *
-	 * @param linkfile
+	 * @param linkfile a {@link org.eclipse.jgit.gitrepo.RepoProject.LinkFile} object.
 	 * @since 4.8
 	 */
 	public void addLinkFile(LinkFile linkfile) {
@@ -403,6 +404,7 @@ public void addLinkFile(LinkFile linkfile) {
 	 * Add a bunch of linkfile configurations.
 	 *
 	 * @param linkFiles
+	 *            a collection of {@link LinkFile}s
 	 * @since 4.8
 	 */
 	public void addLinkFiles(Collection<LinkFile> linkFiles) {
@@ -448,6 +450,7 @@ public boolean isAncestorOf(String thatPath) {
 		return thatPath.startsWith(getPathWithSlash());
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public boolean equals(Object o) {
 		if (o instanceof RepoProject) {
@@ -457,11 +460,13 @@ public boolean equals(Object o) {
 		return false;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public int hashCode() {
 		return this.getPathWithSlash().hashCode();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public int compareTo(RepoProject that) {
 		return this.getPathWithSlash().compareTo(that.getPathWithSlash());
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/internal/RepoText.java b/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/internal/RepoText.java
index 02a2565..ccafff6 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/internal/RepoText.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/internal/RepoText.java
@@ -52,6 +52,8 @@
 public class RepoText extends TranslationBundle {
 
 	/**
+	 * Get an instance of this translation bundle
+	 *
 	 * @return an instance of this translation bundle
 	 */
 	public static RepoText get() {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/hooks/CommitMsgHook.java b/org.eclipse.jgit/src/org/eclipse/jgit/hooks/CommitMsgHook.java
index fa17075..f33168d 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/hooks/CommitMsgHook.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/hooks/CommitMsgHook.java
@@ -71,6 +71,8 @@ public class CommitMsgHook extends GitHook<String> {
 	private String commitMessage;
 
 	/**
+	 * Constructor for CommitMsgHook
+	 *
 	 * @param repo
 	 *            The repository
 	 * @param outputStream
@@ -81,6 +83,7 @@ protected CommitMsgHook(Repository repo, PrintStream outputStream) {
 		super(repo, outputStream);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public String call() throws IOException, AbortedByHookException {
 		if (commitMessage == null) {
@@ -103,12 +106,15 @@ private boolean canRun() {
 		return getCommitEditMessageFilePath() != null && commitMessage != null;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public String getHookName() {
 		return NAME;
 	}
 
 	/**
+	 * {@inheritDoc}
+	 *
 	 * This hook receives one parameter, which is the path to the file holding
 	 * the current commit-msg, relative to the repository's work tree.
 	 */
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/hooks/GitHook.java b/org.eclipse.jgit/src/org/eclipse/jgit/hooks/GitHook.java
index b684dd6..8a61d1b 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/hooks/GitHook.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/hooks/GitHook.java
@@ -42,7 +42,7 @@
  */
 package org.eclipse.jgit.hooks;
 
-import static java.nio.charset.StandardCharsets.UTF_8;
+import static org.eclipse.jgit.lib.Constants.CHARSET;
 
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
@@ -79,7 +79,10 @@ abstract class GitHook<T> implements Callable<T> {
 	protected final PrintStream outputStream;
 
 	/**
+	 * Constructor for GitHook
+	 *
 	 * @param repo
+	 *            a {@link org.eclipse.jgit.lib.Repository} object.
 	 * @param outputStream
 	 *            The output stream the hook must use. {@code null} is allowed,
 	 *            in which case the hook will use {@code System.out}.
@@ -90,23 +93,23 @@ protected GitHook(Repository repo, PrintStream outputStream) {
 	}
 
 	/**
+	 * {@inheritDoc}
+	 * <p>
 	 * Run the hook.
-	 *
-	 * @throws IOException
-	 *             if IO goes wrong.
-	 * @throws AbortedByHookException
-	 *             If the hook has been run and a returned an exit code
-	 *             different from zero.
 	 */
 	@Override
 	public abstract T call() throws IOException, AbortedByHookException;
 
 	/**
+	 * Get name of the hook
+	 *
 	 * @return The name of the hook, which must not be {@code null}.
 	 */
 	public abstract String getHookName();
 
 	/**
+	 * Get the repository
+	 *
 	 * @return The repository.
 	 */
 	protected Repository getRepository() {
@@ -135,6 +138,8 @@ protected String getStdinArgs() {
 	}
 
 	/**
+	 * Get output stream
+	 *
 	 * @return The output stream the hook must use. Never {@code null},
 	 *         {@code System.out} is returned by default.
 	 */
@@ -145,7 +150,7 @@ protected PrintStream getOutputStream() {
 	/**
 	 * Runs the hook, without performing any validity checks.
 	 *
-	 * @throws AbortedByHookException
+	 * @throws org.eclipse.jgit.api.errors.AbortedByHookException
 	 *             If the underlying hook script exited with non-zero.
 	 */
 	protected void doRun() throws AbortedByHookException {
@@ -153,7 +158,7 @@ protected void doRun() throws AbortedByHookException {
 		PrintStream hookErrRedirect = null;
 		try {
 			hookErrRedirect = new PrintStream(errorByteArray, false,
-					UTF_8.name());
+					CHARSET.name());
 		} catch (UnsupportedEncodingException e) {
 			// UTF-8 is guaranteed to be available
 		}
@@ -162,9 +167,20 @@ protected void doRun() throws AbortedByHookException {
 				hookErrRedirect, getStdinArgs());
 		if (result.isExecutedWithError()) {
 			throw new AbortedByHookException(
-					new String(errorByteArray.toByteArray(), UTF_8),
+					new String(errorByteArray.toByteArray(), CHARSET),
 					getHookName(), result.getExitCode());
 		}
 	}
 
+	/**
+	 * Check whether a 'native' (i.e. script) hook is installed in the
+	 * repository.
+	 *
+	 * @return whether a native hook script is installed in the repository.
+	 * @since 4.11
+	 */
+	public boolean isNativeHookPresent() {
+		return FS.DETECTED.findHook(getRepository(), getHookName()) != null;
+	}
+
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/hooks/Hooks.java b/org.eclipse.jgit/src/org/eclipse/jgit/hooks/Hooks.java
index 46e8840..b801d68 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/hooks/Hooks.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/hooks/Hooks.java
@@ -43,8 +43,11 @@
 package org.eclipse.jgit.hooks;
 
 import java.io.PrintStream;
+import java.text.MessageFormat;
 
+import org.eclipse.jgit.internal.JGitText;
 import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.util.LfsFactory;
 
 /**
  * Factory class for instantiating supported hooks.
@@ -54,7 +57,10 @@
 public class Hooks {
 
 	/**
+	 * Create pre-commit hook for the given repository
+	 *
 	 * @param repo
+	 *            a {@link org.eclipse.jgit.lib.Repository} object.
 	 * @param outputStream
 	 *            The output stream, or {@code null} to use {@code System.out}
 	 * @return The pre-commit hook for the given repository.
@@ -65,7 +71,10 @@ public static PreCommitHook preCommit(Repository repo,
 	}
 
 	/**
+	 * Create post-commit hook for the given repository
+	 *
 	 * @param repo
+	 *            a {@link org.eclipse.jgit.lib.Repository} object.
 	 * @param outputStream
 	 *            The output stream, or {@code null} to use {@code System.out}
 	 * @return The post-commit hook for the given repository.
@@ -77,7 +86,10 @@ public static PostCommitHook postCommit(Repository repo,
 	}
 
 	/**
+	 * Create commit-msg hook for the given repository
+	 *
 	 * @param repo
+	 *            a {@link org.eclipse.jgit.lib.Repository} object.
 	 * @param outputStream
 	 *            The output stream, or {@code null} to use {@code System.out}
 	 * @return The commit-msg hook for the given repository.
@@ -88,13 +100,31 @@ public static CommitMsgHook commitMsg(Repository repo,
 	}
 
 	/**
+	 * Create pre-push hook for the given repository
+	 *
 	 * @param repo
+	 *            a {@link org.eclipse.jgit.lib.Repository} object.
 	 * @param outputStream
 	 *            The output stream, or {@code null} to use {@code System.out}
 	 * @return The pre-push hook for the given repository.
 	 * @since 4.2
 	 */
 	public static PrePushHook prePush(Repository repo, PrintStream outputStream) {
+		if (LfsFactory.getInstance().isAvailable()) {
+			PrePushHook hook = LfsFactory.getInstance().getPrePushHook(repo,
+					outputStream);
+			if (hook != null) {
+				if (hook.isNativeHookPresent()) {
+					PrintStream ps = outputStream;
+					if (ps == null) {
+						ps = System.out;
+					}
+					ps.println(MessageFormat
+							.format(JGitText.get().lfsHookConflict, repo));
+				}
+				return hook;
+			}
+		}
 		return new PrePushHook(repo, outputStream);
 	}
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/hooks/PostCommitHook.java b/org.eclipse.jgit/src/org/eclipse/jgit/hooks/PostCommitHook.java
index 70679e0..24bad16 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/hooks/PostCommitHook.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/hooks/PostCommitHook.java
@@ -60,6 +60,8 @@ public class PostCommitHook extends GitHook<Void> {
 	public static final String NAME = "post-commit"; //$NON-NLS-1$
 
 	/**
+	 * Constructor for PostCommitHook
+	 *
 	 * @param repo
 	 *            The repository
 	 * @param outputStream
@@ -70,12 +72,14 @@ protected PostCommitHook(Repository repo, PrintStream outputStream) {
 		super(repo, outputStream);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public Void call() throws IOException, AbortedByHookException {
 		doRun();
 		return null;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public String getHookName() {
 		return NAME;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/hooks/PreCommitHook.java b/org.eclipse.jgit/src/org/eclipse/jgit/hooks/PreCommitHook.java
index 1ab32e0..0d9290d 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/hooks/PreCommitHook.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/hooks/PreCommitHook.java
@@ -60,6 +60,8 @@ public class PreCommitHook extends GitHook<Void> {
 	public static final String NAME = "pre-commit"; //$NON-NLS-1$
 
 	/**
+	 * Constructor for PreCommitHook
+	 *
 	 * @param repo
 	 *            The repository
 	 * @param outputStream
@@ -70,12 +72,14 @@ protected PreCommitHook(Repository repo, PrintStream outputStream) {
 		super(repo, outputStream);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public Void call() throws IOException, AbortedByHookException {
 		doRun();
 		return null;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public String getHookName() {
 		return NAME;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/hooks/PrePushHook.java b/org.eclipse.jgit/src/org/eclipse/jgit/hooks/PrePushHook.java
index a501fee..051a1d1 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/hooks/PrePushHook.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/hooks/PrePushHook.java
@@ -72,6 +72,8 @@ public class PrePushHook extends GitHook<String> {
 	private String refs;
 
 	/**
+	 * Constructor for PrePushHook
+	 *
 	 * @param repo
 	 *            The repository
 	 * @param outputStream
@@ -82,11 +84,13 @@ protected PrePushHook(Repository repo, PrintStream outputStream) {
 		super(repo, outputStream);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected String getStdinArgs() {
 		return refs;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public String call() throws IOException, AbortedByHookException {
 		if (canRun()) {
@@ -102,12 +106,15 @@ private boolean canRun() {
 		return true;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public String getHookName() {
 		return NAME;
 	}
 
 	/**
+	 * {@inheritDoc}
+	 * <p>
 	 * This hook receives two parameters, which is the name and the location of
 	 * the remote repository.
 	 */
@@ -120,21 +127,40 @@ public String getHookName() {
 	}
 
 	/**
+	 * Set remote name
+	 *
 	 * @param name
+	 *            remote name
 	 */
 	public void setRemoteName(String name) {
 		remoteName = name;
 	}
 
 	/**
+	 * Get remote name
+	 *
+	 * @return remote name or null
+	 * @since 4.11
+	 */
+	protected String getRemoteName() {
+		return remoteName;
+	}
+
+	/**
+	 * Set remote location
+	 *
 	 * @param location
+	 *            a remote location
 	 */
 	public void setRemoteLocation(String location) {
 		remoteLocation = location;
 	}
 
 	/**
+	 * Set Refs
+	 *
 	 * @param toRefs
+	 *            a collection of {@code RemoteRefUpdate}s
 	 */
 	public void setRefs(Collection<RemoteRefUpdate> toRefs) {
 		StringBuilder b = new StringBuilder();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/ignore/FastIgnoreRule.java b/org.eclipse.jgit/src/org/eclipse/jgit/ignore/FastIgnoreRule.java
index 7298a08..31e173b 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/ignore/FastIgnoreRule.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/ignore/FastIgnoreRule.java
@@ -55,7 +55,7 @@
 
 /**
  * "Fast" (compared with IgnoreRule) git ignore rule implementation supporting
- * also double star <code>**<code> pattern.
+ * also double star {@code **} pattern.
  * <p>
  * This class is immutable and thread safe.
  *
@@ -77,6 +77,7 @@ public class FastIgnoreRule {
 	private final boolean dirOnly;
 
 	/**
+	 * Constructor for FastIgnoreRule
 	 *
 	 * @param pattern
 	 *            ignore pattern as described in <a href=
@@ -151,24 +152,51 @@ public FastIgnoreRule(String pattern) {
 	 *         result.
 	 */
 	public boolean isMatch(String path, boolean directory) {
+		return isMatch(path, directory, false);
+	}
+
+	/**
+	 * Returns true if a match was made. <br>
+	 * This function does NOT return the actual ignore status of the target!
+	 * Please consult {@link #getResult()} for the negation status. The actual
+	 * ignore status may be true or false depending on whether this rule is an
+	 * ignore rule or a negation rule.
+	 *
+	 * @param path
+	 *            Name pattern of the file, relative to the base directory of
+	 *            this rule
+	 * @param directory
+	 *            Whether the target file is a directory or not
+	 * @param pathMatch
+	 *            {@code true} if the match is for the full path: see
+	 *            {@link IMatcher#matches(String, int, int)}
+	 * @return True if a match was made. This does not necessarily mean that the
+	 *         target is ignored. Call {@link #getResult() getResult()} for the
+	 *         result.
+	 * @since 4.11
+	 */
+	public boolean isMatch(String path, boolean directory, boolean pathMatch) {
 		if (path == null)
 			return false;
 		if (path.length() == 0)
 			return false;
-		boolean match = matcher.matches(path, directory, false);
+		boolean match = matcher.matches(path, directory, pathMatch);
 		return match;
 	}
 
 	/**
-	 * @return True if the pattern is just a file name and not a path
+	 * Whether the pattern is just a file name and not a path
+	 *
+	 * @return {@code true} if the pattern is just a file name and not a path
 	 */
 	public boolean getNameOnly() {
 		return !(matcher instanceof PathMatcher);
 	}
 
 	/**
+	 * Whether the pattern should match directories only
 	 *
-	 * @return True if the pattern should match directories only
+	 * @return {@code true} if the pattern should match directories only
 	 */
 	public boolean dirOnly() {
 		return dirOnly;
@@ -193,13 +221,17 @@ public boolean getResult() {
 	}
 
 	/**
-	 * @return true if the rule never matches (comment line or broken pattern)
+	 * Whether the rule never matches
+	 *
+	 * @return {@code true} if the rule never matches (comment line or broken
+	 *         pattern)
 	 * @since 4.1
 	 */
 	public boolean isEmpty() {
 		return matcher == NO_MATCH;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public String toString() {
 		StringBuilder sb = new StringBuilder();
@@ -212,6 +244,7 @@ public String toString() {
 
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public int hashCode() {
 		final int prime = 31;
@@ -222,6 +255,7 @@ public int hashCode() {
 		return result;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public boolean equals(Object obj) {
 		if (this == obj)
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/ignore/IgnoreNode.java b/org.eclipse.jgit/src/org/eclipse/jgit/ignore/IgnoreNode.java
index 6314c63..d570fde 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/ignore/IgnoreNode.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/ignore/IgnoreNode.java
@@ -81,7 +81,9 @@ public static enum MatchResult {
 	/** The rules that have been parsed into this node. */
 	private final List<FastIgnoreRule> rules;
 
-	/** Create an empty ignore node with no rules. */
+	/**
+	 * Create an empty ignore node with no rules.
+	 */
 	public IgnoreNode() {
 		rules = new ArrayList<>();
 	}
@@ -91,7 +93,7 @@ public IgnoreNode() {
 	 *
 	 * @param rules
 	 *            list of rules.
-	 **/
+	 */
 	public IgnoreNode(List<FastIgnoreRule> rules) {
 		this.rules = rules;
 	}
@@ -102,7 +104,7 @@ public IgnoreNode(List<FastIgnoreRule> rules) {
 	 * @param in
 	 *            input stream holding the standard ignore format. The caller is
 	 *            responsible for closing the stream.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             Error thrown when reading an ignore file.
 	 */
 	public void parse(InputStream in) throws IOException {
@@ -122,7 +124,11 @@ private static BufferedReader asReader(InputStream in) {
 		return new BufferedReader(new InputStreamReader(in, Constants.CHARSET));
 	}
 
-	/** @return list of all ignore rules held by this node. */
+	/**
+	 * Get list of all ignore rules held by this node
+	 *
+	 * @return list of all ignore rules held by this node
+	 */
 	public List<FastIgnoreRule> getRules() {
 		return Collections.unmodifiableList(rules);
 	}
@@ -139,7 +145,13 @@ public List<FastIgnoreRule> getRules() {
 	 * @return status of the path.
 	 */
 	public MatchResult isIgnored(String entryPath, boolean isDirectory) {
-		return isIgnored(entryPath, isDirectory, false);
+		final Boolean result = checkIgnored(entryPath, isDirectory);
+		if (result == null) {
+			return MatchResult.CHECK_PARENT;
+		}
+
+		return result.booleanValue() ? MatchResult.IGNORED
+				: MatchResult.NOT_IGNORED;
 	}
 
 	/**
@@ -151,49 +163,24 @@ public MatchResult isIgnored(String entryPath, boolean isDirectory) {
 	 *            (uses '/' and not '\').
 	 * @param isDirectory
 	 *            true if the target item is a directory.
-	 * @param negateFirstMatch
-	 *            true if the first match should be negated
-	 * @return status of the path.
-	 * @since 3.6
+	 * @return Boolean.TRUE, if the entry is ignored; Boolean.FALSE, if the
+	 *         entry is forced to be not ignored (negated match); or null, if
+	 *         undetermined
+	 * @since 4.11
 	 */
-	public MatchResult isIgnored(String entryPath, boolean isDirectory,
-			boolean negateFirstMatch) {
-		if (rules.isEmpty())
-			if (negateFirstMatch)
-				return MatchResult.CHECK_PARENT_NEGATE_FIRST_MATCH;
-			else
-				return MatchResult.CHECK_PARENT;
-
-		// Parse rules in the reverse order that they were read
+	public Boolean checkIgnored(String entryPath, boolean isDirectory) {
+		// Parse rules in the reverse order that they were read because later
+		// rules have higher priority
 		for (int i = rules.size() - 1; i > -1; i--) {
 			FastIgnoreRule rule = rules.get(i);
-			if (rule.isMatch(entryPath, isDirectory)) {
-				if (rule.getResult()) {
-					// rule matches: path could be ignored
-					if (negateFirstMatch)
-						// ignore current match, reset "negate" flag, continue
-						negateFirstMatch = false;
-					else
-						// valid match, just return
-						return MatchResult.IGNORED;
-				} else {
-					// found negated rule
-					if (negateFirstMatch)
-						// not possible to re-include excluded ignore rule
-						return MatchResult.NOT_IGNORED;
-					else
-						// set the flag and continue
-						negateFirstMatch = true;
-				}
+			if (rule.isMatch(entryPath, isDirectory, true)) {
+				return Boolean.valueOf(rule.getResult());
 			}
 		}
-		if (negateFirstMatch)
-			// negated rule found but there is no previous rule in *this* file
-			return MatchResult.CHECK_PARENT_NEGATE_FIRST_MATCH;
-		// *this* file has no matching rules
-		return MatchResult.CHECK_PARENT;
+		return null;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public String toString() {
 		return rules.toString();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/AbstractMatcher.java b/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/AbstractMatcher.java
index 64c2a74..8e8e571 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/AbstractMatcher.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/AbstractMatcher.java
@@ -64,16 +64,19 @@ public abstract class AbstractMatcher implements IMatcher {
 		this.dirOnly = dirOnly;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public String toString() {
 		return pattern;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public int hashCode() {
 		return pattern.hashCode();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public boolean equals(Object obj) {
 		if (this == obj)
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/IMatcher.java b/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/IMatcher.java
index 5b184cb..14440d2 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/IMatcher.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/IMatcher.java
@@ -58,8 +58,7 @@ public boolean matches(String path, boolean assumeDirectory,
 		}
 
 		@Override
-		public boolean matches(String segment, int startIncl, int endExcl,
-				boolean assumeDirectory) {
+		public boolean matches(String segment, int startIncl, int endExcl) {
 			return false;
 		}
 	};
@@ -74,9 +73,10 @@ public boolean matches(String segment, int startIncl, int endExcl,
 	 *            with a slash)
 	 * @param pathMatch
 	 *            {@code true} if the match is for the full path: prefix-only
-	 *            matches are not allowed, and {@link NameMatcher}s must match
-	 *            only the last component (if they can -- they may not, if they
-	 *            are anchored at the beginning)
+	 *            matches are not allowed, and
+	 *            {@link org.eclipse.jgit.ignore.internal.NameMatcher}s must
+	 *            match only the last component (if they can -- they may not, if
+	 *            they are anchored at the beginning)
 	 * @return true if this matcher pattern matches given string
 	 */
 	boolean matches(String path, boolean assumeDirectory, boolean pathMatch);
@@ -90,11 +90,7 @@ public boolean matches(String segment, int startIncl, int endExcl,
 	 *            start index, inclusive
 	 * @param endExcl
 	 *            end index, exclusive
-	 * @param assumeDirectory
-	 *            true to assume this path as directory (even if it doesn't end
-	 *            with a slash)
 	 * @return true if this matcher pattern matches given string
 	 */
-	boolean matches(String segment, int startIncl, int endExcl,
-			boolean assumeDirectory);
+	boolean matches(String segment, int startIncl, int endExcl);
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/LeadingAsteriskMatcher.java b/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/LeadingAsteriskMatcher.java
index cc0fe93..fdd39bc 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/LeadingAsteriskMatcher.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/LeadingAsteriskMatcher.java
@@ -55,9 +55,9 @@ public class LeadingAsteriskMatcher extends NameMatcher {
 					"Pattern must have leading asterisk: " + pattern); //$NON-NLS-1$
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	public boolean matches(String segment, int startIncl, int endExcl,
-			boolean assumeDirectory) {
+	public boolean matches(String segment, int startIncl, int endExcl) {
 		// faster local access, same as in string.indexOf()
 		String s = subPattern;
 
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/NameMatcher.java b/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/NameMatcher.java
index 9667837..33f0fe7 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/NameMatcher.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/NameMatcher.java
@@ -71,6 +71,7 @@ public class NameMatcher extends AbstractMatcher {
 		}
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public boolean matches(String path, boolean assumeDirectory,
 			boolean pathMatch) {
@@ -90,12 +91,12 @@ public boolean matches(String path, boolean assumeDirectory,
 			}
 			boolean match;
 			if (lastSlash < start) {
-				match = matches(path, start, stop, assumeDirectory);
+				match = matches(path, start, stop);
 			} else {
 				// Can't match if the path contains a slash if the pattern is
 				// anchored at the beginning
 				match = !beginning
-						&& matches(path, lastSlash + 1, stop, assumeDirectory);
+						&& matches(path, lastSlash + 1, stop);
 			}
 			if (match && dirOnly) {
 				match = assumeDirectory;
@@ -107,7 +108,7 @@ public boolean matches(String path, boolean assumeDirectory,
 			if (end < 0) {
 				end = stop;
 			}
-			if (end > start && matches(path, start, end, assumeDirectory)) {
+			if (end > start && matches(path, start, end)) {
 				// make sure the directory matches: either if we are done with
 				// segment and there is next one, or if the directory is assumed
 				return !dirOnly || assumeDirectory || end < stop;
@@ -120,9 +121,9 @@ public boolean matches(String path, boolean assumeDirectory,
 		return false;
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	public boolean matches(String segment, int startIncl, int endExcl,
-			boolean assumeDirectory) {
+	public boolean matches(String segment, int startIncl, int endExcl) {
 		// faster local access, same as in string.indexOf()
 		String s = subPattern;
 		int length = s.length();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/PathMatcher.java b/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/PathMatcher.java
index 9b3a2aa..3c0f17a 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/PathMatcher.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/PathMatcher.java
@@ -61,7 +61,10 @@
  */
 public class PathMatcher extends AbstractMatcher {
 
-	private static final WildMatcher WILD = WildMatcher.INSTANCE;
+	private static final WildMatcher WILD_NO_DIRECTORY = new WildMatcher(false);
+
+	private static final WildMatcher WILD_ONLY_DIRECTORY = new WildMatcher(
+			true);
 
 	private final List<IMatcher> matchers;
 
@@ -94,25 +97,32 @@ private static List<IMatcher> createMatchers(List<String> segments,
 		for (int i = 0; i < segments.size(); i++) {
 			String segment = segments.get(i);
 			IMatcher matcher = createNameMatcher0(segment, pathSeparator,
-					dirOnly);
-			if (matcher == WILD && i > 0
-					&& matchers.get(matchers.size() - 1) == WILD)
-				// collapse wildmatchers **/** is same as **
-				continue;
+					dirOnly, i == segments.size() - 1);
+			if (i > 0) {
+				final IMatcher last = matchers.get(matchers.size() - 1);
+				if (isWild(matcher) && isWild(last))
+					// collapse wildmatchers **/** is same as **, but preserve
+					// dirOnly flag (i.e. always use the last wildmatcher)
+					matchers.remove(matchers.size() - 1);
+			}
+
 			matchers.add(matcher);
 		}
 		return matchers;
 	}
 
 	/**
+	 * Create path matcher
 	 *
 	 * @param pattern
+	 *            a pattern
 	 * @param pathSeparator
 	 *            if this parameter isn't null then this character will not
 	 *            match at wildcards(* and ? are wildcards).
 	 * @param dirOnly
+	 *            a boolean.
 	 * @return never null
-	 * @throws InvalidPatternException
+	 * @throws org.eclipse.jgit.errors.InvalidPatternException
 	 */
 	public static IMatcher createPathMatcher(String pattern,
 			Character pathSeparator, boolean dirOnly)
@@ -123,7 +133,7 @@ public static IMatcher createPathMatcher(String pattern,
 		int slashIdx = pattern.indexOf(slash, 1);
 		if (slashIdx > 0 && slashIdx < pattern.length() - 1)
 			return new PathMatcher(pattern, pathSeparator, dirOnly);
-		return createNameMatcher0(pattern, pathSeparator, dirOnly);
+		return createNameMatcher0(pattern, pathSeparator, dirOnly, true);
 	}
 
 	/**
@@ -150,12 +160,13 @@ private static String trim(String pattern) {
 	}
 
 	private static IMatcher createNameMatcher0(String segment,
-			Character pathSeparator, boolean dirOnly)
+			Character pathSeparator, boolean dirOnly, boolean lastSegment)
 			throws InvalidPatternException {
 		// check if we see /** or ** segments => double star pattern
 		if (WildMatcher.WILDMATCH.equals(segment)
 				|| WildMatcher.WILDMATCH2.equals(segment))
-			return WILD;
+			return dirOnly && lastSegment ? WILD_ONLY_DIRECTORY
+					: WILD_NO_DIRECTORY;
 
 		PatternState state = checkWildCards(segment);
 		switch (state) {
@@ -170,6 +181,7 @@ private static IMatcher createNameMatcher0(String segment,
 		}
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public boolean matches(String path, boolean assumeDirectory,
 			boolean pathMatch) {
@@ -212,9 +224,9 @@ private boolean simpleMatch(String path, boolean assumeDirectory,
 		return false;
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	public boolean matches(String segment, int startIncl, int endExcl,
-			boolean assumeDirectory) {
+	public boolean matches(String segment, int startIncl, int endExcl) {
 		throw new UnsupportedOperationException(
 				"Path matcher works only on entire paths"); //$NON-NLS-1$
 	}
@@ -236,18 +248,18 @@ private boolean iterate(final String path, final int startIncl,
 			if (right == -1) {
 				if (left < endExcl) {
 					match = matches(matcher, path, left, endExcl,
-							assumeDirectory);
+							assumeDirectory, pathMatch);
 				} else {
 					// a/** should not match a/ or a
-					match = match && matchers.get(matcher) != WILD;
+					match = match && !isWild(matchers.get(matcher));
 				}
 				if (match) {
 					if (matcher < matchers.size() - 1
-							&& matchers.get(matcher) == WILD) {
+							&& isWild(matchers.get(matcher))) {
 						// ** can match *nothing*: a/**/b match also a/b
 						matcher++;
 						match = matches(matcher, path, left, endExcl,
-								assumeDirectory);
+								assumeDirectory, pathMatch);
 					} else if (dirOnly && !assumeDirectory) {
 						// Directory expectations not met
 						return false;
@@ -259,14 +271,15 @@ private boolean iterate(final String path, final int startIncl,
 				wildmatchBacktrackPos = right;
 			}
 			if (right - left > 0) {
-				match = matches(matcher, path, left, right, assumeDirectory);
+				match = matches(matcher, path, left, right, assumeDirectory,
+						pathMatch);
 			} else {
 				// path starts with slash???
 				right++;
 				continue;
 			}
 			if (match) {
-				boolean wasWild = matchers.get(matcher) == WILD;
+				boolean wasWild = isWild(matchers.get(matcher));
 				if (wasWild) {
 					lastWildmatch = matcher;
 					wildmatchBacktrackPos = -1;
@@ -312,9 +325,19 @@ private boolean iterate(final String path, final int startIncl,
 	}
 
 	private boolean matches(int matcherIdx, String path, int startIncl,
-			int endExcl,
-			boolean assumeDirectory) {
+			int endExcl, boolean assumeDirectory, boolean pathMatch) {
 		IMatcher matcher = matchers.get(matcherIdx);
-		return matcher.matches(path, startIncl, endExcl, assumeDirectory);
+
+		final boolean matches = matcher.matches(path, startIncl, endExcl);
+		if (!matches || !pathMatch || matcherIdx < matchers.size() - 1
+				|| !(matcher instanceof AbstractMatcher)) {
+			return matches;
+		}
+
+		return assumeDirectory || !((AbstractMatcher) matcher).dirOnly;
+	}
+
+	private static boolean isWild(IMatcher matcher) {
+		return matcher == WILD_NO_DIRECTORY || matcher == WILD_ONLY_DIRECTORY;
 	}
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/Strings.java b/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/Strings.java
index 800cdb9..9b255b4 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/Strings.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/Strings.java
@@ -56,8 +56,8 @@
 import org.eclipse.jgit.internal.JGitText;
 
 /**
- * Various {@link String} related utility methods, written mostly to avoid
- * generation of new String objects (e.g. via splitting Strings etc).
+ * Various {@link java.lang.String} related utility methods, written mostly to
+ * avoid generation of new String objects (e.g. via splitting Strings etc).
  */
 public class Strings {
 
@@ -67,6 +67,8 @@ static char getPathSeparator(Character pathSeparator) {
 	}
 
 	/**
+	 * Strip trailing characters
+	 *
 	 * @param pattern
 	 *            non null
 	 * @param c
@@ -87,6 +89,8 @@ public static String stripTrailing(String pattern, char c) {
 	}
 
 	/**
+	 * Strip trailing whitespace characters
+	 *
 	 * @param pattern
 	 *            non null
 	 * @return new string with all trailing whitespace removed
@@ -105,10 +109,12 @@ public static String stripTrailingWhitespace(String pattern) {
 	}
 
 	/**
+	 * Check if pattern is a directory pattern ending with a path separator
+	 *
 	 * @param pattern
 	 *            non null
-	 * @return true if the last character, which is not whitespace, is a path
-	 *         separator
+	 * @return {@code true} if the last character, which is not whitespace, is a
+	 *         path separator
 	 */
 	public static boolean isDirectoryPattern(String pattern) {
 		for (int i = pattern.length() - 1; i >= 0; i--) {
@@ -439,12 +445,10 @@ && isLetter(lookAhead(pattern, i)))
 		try {
 			return Pattern.compile(sb.toString());
 		} catch (PatternSyntaxException e) {
-			InvalidPatternException patternException = new InvalidPatternException(
+			throw new InvalidPatternException(
 					MessageFormat.format(JGitText.get().invalidIgnoreRule,
 							pattern),
-					pattern);
-			patternException.initCause(e);
-			throw patternException;
+					pattern, e);
 		}
 	}
 
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/TrailingAsteriskMatcher.java b/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/TrailingAsteriskMatcher.java
index 2e148f4..1e0335c 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/TrailingAsteriskMatcher.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/TrailingAsteriskMatcher.java
@@ -55,9 +55,9 @@ public class TrailingAsteriskMatcher extends NameMatcher {
 					"Pattern must have trailing asterisk: " + pattern); //$NON-NLS-1$
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	public boolean matches(String segment, int startIncl, int endExcl,
-			boolean assumeDirectory) {
+	public boolean matches(String segment, int startIncl, int endExcl) {
 		// faster local access, same as in string.indexOf()
 		String s = subPattern;
 		// we don't need to count '*' character itself
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/WildCardMatcher.java b/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/WildCardMatcher.java
index f64050f..3bbac81 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/WildCardMatcher.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/WildCardMatcher.java
@@ -50,7 +50,7 @@
 
 /**
  * Matcher built from path segments containing wildcards. This matcher converts
- * glob wildcards to Java {@link Pattern}'s.
+ * glob wildcards to Java {@link java.util.regex.Pattern}'s.
  * <p>
  * This class is immutable and thread safe.
  */
@@ -64,9 +64,9 @@ public class WildCardMatcher extends NameMatcher {
 		p = convertGlob(subPattern);
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	public boolean matches(String segment, int startIncl, int endExcl,
-			boolean assumeDirectory) {
+	public boolean matches(String segment, int startIncl, int endExcl) {
 		return p.matcher(segment.substring(startIncl, endExcl)).matches();
 	}
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/WildMatcher.java b/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/WildMatcher.java
index 363b3ce..2ad87da 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/WildMatcher.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/WildMatcher.java
@@ -55,22 +55,26 @@ public final class WildMatcher extends AbstractMatcher {
 	// double star for the beginning of pattern
 	static final String WILDMATCH2 = "/**"; //$NON-NLS-1$
 
-	static final WildMatcher INSTANCE = new WildMatcher();
-
-	private WildMatcher() {
-		super(WILDMATCH, false);
+	WildMatcher(boolean dirOnly) {
+		super(WILDMATCH, dirOnly);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public final boolean matches(String path, boolean assumeDirectory,
 			boolean pathMatch) {
-		return true;
+		return !dirOnly || assumeDirectory
+				|| !pathMatch && isSubdirectory(path);
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	public final boolean matches(String segment, int startIncl, int endExcl,
-			boolean assumeDirectory) {
+	public final boolean matches(String segment, int startIncl, int endExcl) {
 		return true;
 	}
 
+	private static boolean isSubdirectory(String path) {
+		final int slashIndex = path.indexOf('/');
+		return slashIndex >= 0 && slashIndex < path.length() - 1;
+	}
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java
index 9d757a5..2ac75e1 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java
@@ -53,6 +53,8 @@
 public class JGitText extends TranslationBundle {
 
 	/**
+	 * Get an instance of this translation bundle
+	 *
 	 * @return an instance of this translation bundle
 	 */
 	public static JGitText get() {
@@ -81,6 +83,7 @@ public static JGitText get() {
 	/***/ public String atLeastTwoFiltersNeeded;
 	/***/ public String atomicPushNotSupported;
 	/***/ public String atomicRefUpdatesNotSupported;
+	/***/ public String atomicSymRefNotSupported;
 	/***/ public String authenticationNotSupported;
 	/***/ public String badBase64InputCharacterAt;
 	/***/ public String badEntryDelimiter;
@@ -99,7 +102,10 @@ public static JGitText get() {
 	/***/ public String blameNotCommittedYet;
 	/***/ public String blobNotFound;
 	/***/ public String blobNotFoundForPath;
+	/***/ public String blockLimitNotMultipleOfBlockSize;
+	/***/ public String blockLimitNotPositive;
 	/***/ public String blockSizeNotPowerOf2;
+	/***/ public String bothRefTargetsMustNotBeNull;
 	/***/ public String branchNameInvalid;
 	/***/ public String buildingBitmaps;
 	/***/ public String cachedPacksPreventsIndexCreation;
@@ -172,6 +178,7 @@ public static JGitText get() {
 	/***/ public String cantPassMeATree;
 	/***/ public String channelMustBeInRange1_255;
 	/***/ public String characterClassIsNotSupported;
+	/***/ public String checkingOutFiles;
 	/***/ public String checkoutConflictWithFile;
 	/***/ public String checkoutConflictWithFiles;
 	/***/ public String checkoutUnexpectedResult;
@@ -187,6 +194,9 @@ public static JGitText get() {
 	/***/ public String commitOnRepoWithoutHEADCurrentlyNotSupported;
 	/***/ public String commitAmendOnInitialNotPossible;
 	/***/ public String compressingObjects;
+	/***/ public String configSubsectionContainsNewline;
+	/***/ public String configSubsectionContainsNullByte;
+	/***/ public String configValueContainsNullByte;
 	/***/ public String configHandleIsStale;
 	/***/ public String connectionFailed;
 	/***/ public String connectionTimeOut;
@@ -275,6 +285,8 @@ public static JGitText get() {
 	/***/ public String credentialUsername;
 	/***/ public String daemonAlreadyRunning;
 	/***/ public String daysAgo;
+	/***/ public String deepenNotWithDeepen;
+	/***/ public String deepenSinceWithDeepen;
 	/***/ public String deleteBranchUnexpectedResult;
 	/***/ public String deleteFileFailed;
 	/***/ public String deleteRequiresZeroNewId;
@@ -341,6 +353,7 @@ public static JGitText get() {
 	/***/ public String expectedACKNAKGot;
 	/***/ public String expectedBooleanStringValue;
 	/***/ public String expectedCharacterEncodingGuesses;
+	/***/ public String expectedDirectoryNotSubmodule;
 	/***/ public String expectedEOFReceived;
 	/***/ public String expectedGot;
 	/***/ public String expectedLessThanGot;
@@ -358,6 +371,7 @@ public static JGitText get() {
 	/***/ public String fileModeNotSetForPath;
 	/***/ public String filterExecutionFailed;
 	/***/ public String filterExecutionFailedRc;
+	/***/ public String filterRequiresCapability;
 	/***/ public String findingGarbage;
 	/***/ public String flagIsDisposed;
 	/***/ public String flagNotFromThis;
@@ -409,6 +423,7 @@ public static JGitText get() {
 	/***/ public String invalidDepth;
 	/***/ public String invalidEncryption;
 	/***/ public String invalidExpandWildcard;
+	/***/ public String invalidFilter;
 	/***/ public String invalidGitdirRef;
 	/***/ public String invalidGitType;
 	/***/ public String invalidId;
@@ -419,6 +434,7 @@ public static JGitText get() {
 	/***/ public String invalidIntegerValue;
 	/***/ public String invalidKey;
 	/***/ public String invalidLineInConfigFile;
+	/***/ public String invalidLineInConfigFileWithParam;
 	/***/ public String invalidModeFor;
 	/***/ public String invalidModeForPath;
 	/***/ public String invalidObject;
@@ -441,6 +457,7 @@ public static JGitText get() {
 	/***/ public String invalidSystemProperty;
 	/***/ public String invalidTagOption;
 	/***/ public String invalidTimeout;
+	/***/ public String invalidTimestamp;
 	/***/ public String invalidTimeUnitValue2;
 	/***/ public String invalidTimeUnitValue3;
 	/***/ public String invalidTreeZeroLengthName;
@@ -457,6 +474,7 @@ public static JGitText get() {
 	/***/ public String largeObjectException;
 	/***/ public String largeObjectOutOfMemory;
 	/***/ public String lengthExceedsMaximumArraySize;
+	/***/ public String lfsHookConflict;
 	/***/ public String listingAlternates;
 	/***/ public String listingPacks;
 	/***/ public String localObjectsIncomplete;
@@ -496,6 +514,7 @@ public static JGitText get() {
 	/***/ public String months;
 	/***/ public String monthsAgo;
 	/***/ public String multipleMergeBasesFor;
+	/***/ public String nameMustNotBeNullOrEmpty;
 	/***/ public String need2Arguments;
 	/***/ public String needPackOut;
 	/***/ public String needsAtLeastOneEntry;
@@ -510,7 +529,9 @@ public static JGitText get() {
 	/***/ public String noMergeBase;
 	/***/ public String noMergeHeadSpecified;
 	/***/ public String nonBareLinkFilesNotSupported;
+	/***/ public String noPathAttributesFound;
 	/***/ public String noSuchRef;
+	/***/ public String noSuchSubmodule;
 	/***/ public String notABoolean;
 	/***/ public String notABundle;
 	/***/ public String notADIRCFile;
@@ -711,6 +732,7 @@ public static JGitText get() {
 	/***/ public String timeIsUncertain;
 	/***/ public String timerAlreadyTerminated;
 	/***/ public String tooManyCommands;
+	/***/ public String tooManyFilters;
 	/***/ public String tooManyIncludeRecursions;
 	/***/ public String topologicalSortRequired;
 	/***/ public String transportExceptionBadRef;
@@ -751,9 +773,11 @@ public static JGitText get() {
 	/***/ public String unexpectedEofInPack;
 	/***/ public String unexpectedHunkTrailer;
 	/***/ public String unexpectedOddResult;
+	/***/ public String unexpectedPacketLine;
 	/***/ public String unexpectedRefReport;
 	/***/ public String unexpectedReportLine;
 	/***/ public String unexpectedReportLine2;
+	/***/ public String unexpectedSubmoduleStatus;
 	/***/ public String unknownOrUnsupportedCommand;
 	/***/ public String unknownDIRCVersion;
 	/***/ public String unknownHost;
@@ -764,6 +788,7 @@ public static JGitText get() {
 	/***/ public String unknownObjectType2;
 	/***/ public String unknownRepositoryFormat;
 	/***/ public String unknownRepositoryFormat2;
+	/***/ public String unknownTransportCommand;
 	/***/ public String unknownZlibError;
 	/***/ public String unmergedPath;
 	/***/ public String unmergedPaths;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/fsck/FsckError.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/fsck/FsckError.java
index 588ed9b..131b004 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/fsck/FsckError.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/fsck/FsckError.java
@@ -51,7 +51,9 @@
 import org.eclipse.jgit.lib.ObjectChecker;
 import org.eclipse.jgit.lib.ObjectId;
 
-/** Holds all fsck errors of a git repository. */
+/**
+ * Holds all fsck errors of a git repository.
+ */
 public class FsckError {
 	/** Represents a corrupt object. */
 	public static class CorruptObject {
@@ -130,22 +132,38 @@ public ErrorType getErrorType() {
 
 	private final Set<String> nonCommitHeads = new HashSet<>();
 
-	/** @return corrupt objects from all pack files. */
+	/**
+	 * Get corrupt objects from all pack files
+	 *
+	 * @return corrupt objects from all pack files
+	 */
 	public Set<CorruptObject> getCorruptObjects() {
 		return corruptObjects;
 	}
 
-	/** @return missing objects that should present in pack files. */
+	/**
+	 * Get missing objects that should present in pack files
+	 *
+	 * @return missing objects that should present in pack files
+	 */
 	public Set<ObjectId> getMissingObjects() {
 		return missingObjects;
 	}
 
-	/** @return corrupt index files associated with the packs. */
+	/**
+	 * Get corrupt index files associated with the packs
+	 *
+	 * @return corrupt index files associated with the packs
+	 */
 	public Set<CorruptIndex> getCorruptIndices() {
 		return corruptIndices;
 	}
 
-	/** @return refs/heads/* point to non-commit object. */
+	/**
+	 * Get refs/heads/* which point to non-commit object
+	 *
+	 * @return refs/heads/* which point to non-commit object
+	 */
 	public Set<String> getNonCommitHeads() {
 		return nonCommitHeads;
 	}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/fsck/FsckPackParser.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/fsck/FsckPackParser.java
index 3a678a7..5397ba4 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/fsck/FsckPackParser.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/fsck/FsckPackParser.java
@@ -62,13 +62,14 @@
 import org.eclipse.jgit.internal.storage.file.PackIndex;
 import org.eclipse.jgit.internal.storage.file.PackIndex.MutableEntry;
 import org.eclipse.jgit.lib.AnyObjectId;
-import org.eclipse.jgit.lib.ObjectChecker;
 import org.eclipse.jgit.lib.ObjectDatabase;
 import org.eclipse.jgit.lib.ObjectIdOwnerMap;
 import org.eclipse.jgit.transport.PackParser;
 import org.eclipse.jgit.transport.PackedObjectInfo;
 
-/** A read-only pack parser for object validity checking. */
+/**
+ * A read-only pack parser for object validity checking.
+ */
 public class FsckPackParser extends PackParser {
 	private final CRC32 crc;
 
@@ -83,6 +84,8 @@ public class FsckPackParser extends PackParser {
 	private int blockSize;
 
 	/**
+	 * Constructor for FsckPackParser
+	 *
 	 * @param db
 	 *            the object database which stores repository's data.
 	 * @param channel
@@ -96,6 +99,7 @@ public FsckPackParser(ObjectDatabase db, ReadableChannel channel) {
 		this.blockSize = channel.blockSize() > 0 ? channel.blockSize() : 65536;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected void onPackHeader(long objCnt) throws IOException {
 		if (expectedObjectCount >= 0) {
@@ -107,41 +111,48 @@ protected void onPackHeader(long objCnt) throws IOException {
 		}
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected void onBeginWholeObject(long streamPosition, int type,
 			long inflatedSize) throws IOException {
 		crc.reset();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected void onObjectHeader(Source src, byte[] raw, int pos, int len)
 			throws IOException {
 		crc.update(raw, pos, len);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected void onObjectData(Source src, byte[] raw, int pos, int len)
 			throws IOException {
 		crc.update(raw, pos, len);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected void onEndWholeObject(PackedObjectInfo info) throws IOException {
 		info.setCRC((int) crc.getValue());
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected void onBeginOfsDelta(long deltaStreamPosition,
 			long baseStreamPosition, long inflatedSize) throws IOException {
 		crc.reset();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected void onBeginRefDelta(long deltaStreamPosition, AnyObjectId baseId,
 			long inflatedSize) throws IOException {
 		crc.reset();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected UnresolvedDelta onEndDelta() throws IOException {
 		UnresolvedDelta delta = new UnresolvedDelta();
@@ -149,12 +160,14 @@ protected UnresolvedDelta onEndDelta() throws IOException {
 		return delta;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected void onInflatedObjectData(PackedObjectInfo obj, int typeCode,
 			byte[] data) throws IOException {
 		// FsckPackParser ignores this event.
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected void verifySafeObject(final AnyObjectId id, final int type,
 			final byte[] data) {
@@ -170,11 +183,13 @@ protected void verifySafeObject(final AnyObjectId id, final int type,
 		}
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected void onPackFooter(byte[] hash) throws IOException {
 		// Do nothing.
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected boolean onAppendBase(int typeCode, byte[] data,
 			PackedObjectInfo info) throws IOException {
@@ -182,11 +197,13 @@ protected boolean onAppendBase(int typeCode, byte[] data,
 		return false;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected void onEndThinPack() throws IOException {
 		// Do nothing.
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected ObjectTypeAndSize seekDatabase(PackedObjectInfo obj,
 			ObjectTypeAndSize info) throws IOException {
@@ -195,6 +212,7 @@ protected ObjectTypeAndSize seekDatabase(PackedObjectInfo obj,
 		return readObjectHeader(info);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected ObjectTypeAndSize seekDatabase(UnresolvedDelta delta,
 			ObjectTypeAndSize info) throws IOException {
@@ -203,6 +221,7 @@ protected ObjectTypeAndSize seekDatabase(UnresolvedDelta delta,
 		return readObjectHeader(info);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected int readDatabase(byte[] dst, int pos, int cnt)
 			throws IOException {
@@ -247,11 +266,13 @@ int read(long channelPosition, byte[] dst, int pos, int cnt)
 		return buf.array();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected boolean checkCRC(int oldCRC) {
 		return oldCRC == (int) crc.getValue();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected void onStoreStream(byte[] raw, int pos, int len)
 			throws IOException {
@@ -259,7 +280,11 @@ protected void onStoreStream(byte[] raw, int pos, int len)
 	}
 
 	/**
-	 * @return corrupt objects that reported by {@link ObjectChecker}.
+	 * Get corrupt objects reported by
+	 * {@link org.eclipse.jgit.lib.ObjectChecker}
+	 *
+	 * @return corrupt objects that are reported by
+	 *         {@link org.eclipse.jgit.lib.ObjectChecker}.
 	 */
 	public Set<CorruptObject> getCorruptObjects() {
 		return corruptObjects;
@@ -270,7 +295,7 @@ public Set<CorruptObject> getCorruptObjects() {
 	 *
 	 * @param idx
 	 *            index file associate with the pack
-	 * @throws CorruptPackIndexException
+	 * @throws org.eclipse.jgit.errors.CorruptPackIndexException
 	 *             when the index file is corrupt.
 	 */
 	public void verifyIndex(PackIndex idx)
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/ketch/KetchConstants.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/ketch/KetchConstants.java
index 171c059..168ab8c 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/ketch/KetchConstants.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/ketch/KetchConstants.java
@@ -45,7 +45,9 @@
 
 import org.eclipse.jgit.revwalk.FooterKey;
 
-/** Frequently used constants in a Ketch system. */
+/**
+ * Frequently used constants in a Ketch system.
+ */
 public class KetchConstants {
 	/**
 	 * Default reference namespace holding {@link #ACCEPTED} and
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/ketch/KetchLeader.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/ketch/KetchLeader.java
index 3bcd6bc..bc5ba39 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/ketch/KetchLeader.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/ketch/KetchLeader.java
@@ -69,11 +69,15 @@
 /**
  * A leader managing consensus across remote followers.
  * <p>
- * A leader instance starts up in {@link State#CANDIDATE} and tries to begin a
- * new term by sending an {@link ElectionRound} to all replicas. Its term starts
- * if a majority of replicas have accepted this leader instance for the term.
+ * A leader instance starts up in
+ * {@link org.eclipse.jgit.internal.ketch.KetchLeader.State#CANDIDATE} and tries
+ * to begin a new term by sending an
+ * {@link org.eclipse.jgit.internal.ketch.ElectionRound} to all replicas. Its
+ * term starts if a majority of replicas have accepted this leader instance for
+ * the term.
  * <p>
- * Once elected by a majority the instance enters {@link State#LEADER} and runs
+ * Once elected by a majority the instance enters
+ * {@link org.eclipse.jgit.internal.ketch.KetchLeader.State#LEADER} and runs
  * proposals offered to {@link #queueProposal(Proposal)}. This continues until
  * the leader is timed out for inactivity, or is deposed by a competing leader
  * gaining its own majority.
@@ -81,36 +85,42 @@
  * Once timed out or deposed this {@code KetchLeader} instance should be
  * discarded, and a new instance takes over.
  * <p>
- * Each leader instance coordinates a group of {@link KetchReplica}s. Replica
- * instances are owned by the leader instance and must be discarded when the
- * leader is discarded.
+ * Each leader instance coordinates a group of
+ * {@link org.eclipse.jgit.internal.ketch.KetchReplica}s. Replica instances are
+ * owned by the leader instance and must be discarded when the leader is
+ * discarded.
  * <p>
  * In Ketch all push requests are issued through the leader. The steps are as
- * follows (see {@link KetchPreReceive} for an example):
+ * follows (see {@link org.eclipse.jgit.internal.ketch.KetchPreReceive} for an
+ * example):
  * <ul>
- * <li>Create a {@link Proposal} with the
+ * <li>Create a {@link org.eclipse.jgit.internal.ketch.Proposal} with the
  * {@link org.eclipse.jgit.transport.ReceiveCommand}s that represent the push.
  * <li>Invoke {@link #queueProposal(Proposal)} on the leader instance.
- * <li>Wait for consensus with {@link Proposal#await()}.
- * <li>To examine the status of the push, check {@link Proposal#getCommands()},
- * looking at
+ * <li>Wait for consensus with
+ * {@link org.eclipse.jgit.internal.ketch.Proposal#await()}.
+ * <li>To examine the status of the push, check
+ * {@link org.eclipse.jgit.internal.ketch.Proposal#getCommands()}, looking at
  * {@link org.eclipse.jgit.internal.storage.reftree.Command#getResult()}.
  * </ul>
  * <p>
  * The leader gains consensus by first pushing the needed objects and a
- * {@link RefTree} representing the desired target repository state to the
- * {@code refs/txn/accepted} branch on each of the replicas. Once a majority has
- * succeeded, the leader commits the state by either pushing the
- * {@code refs/txn/accepted} value to {@code refs/txn/committed} (for
- * Ketch-aware replicas) or by pushing updates to {@code refs/heads/master},
- * etc. for stock Git replicas.
+ * {@link org.eclipse.jgit.internal.storage.reftree.RefTree} representing the
+ * desired target repository state to the {@code refs/txn/accepted} branch on
+ * each of the replicas. Once a majority has succeeded, the leader commits the
+ * state by either pushing the {@code refs/txn/accepted} value to
+ * {@code refs/txn/committed} (for Ketch-aware replicas) or by pushing updates
+ * to {@code refs/heads/master}, etc. for stock Git replicas.
  * <p>
  * Internally, the actual transport to replicas is performed on background
- * threads via the {@link KetchSystem}'s executor service. For performance, the
- * {@link KetchLeader}, {@link KetchReplica} and {@link Proposal} objects share
- * some state, and may invoke each other's methods on different threads. This
- * access is protected by the leader's {@link #lock} object. Care must be taken
- * to prevent concurrent access by correctly obtaining the leader's lock.
+ * threads via the {@link org.eclipse.jgit.internal.ketch.KetchSystem}'s
+ * executor service. For performance, the
+ * {@link org.eclipse.jgit.internal.ketch.KetchLeader},
+ * {@link org.eclipse.jgit.internal.ketch.KetchReplica} and
+ * {@link org.eclipse.jgit.internal.ketch.Proposal} objects share some state,
+ * and may invoke each other's methods on different threads. This access is
+ * protected by the leader's {@link #lock} object. Care must be taken to prevent
+ * concurrent access by correctly obtaining the leader's lock.
  */
 public abstract class KetchLeader {
 	private static final Logger log = LoggerFactory.getLogger(KetchLeader.class);
@@ -295,7 +305,7 @@ private static LocalReplica findLocal(Collection<KetchReplica> voters) {
 	 * The caller will close the repository.
 	 *
 	 * @return opened repository for use by the leader thread.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             cannot reopen the repository for the leader.
 	 */
 	protected abstract Repository openRepository() throws IOException;
@@ -307,16 +317,17 @@ private static LocalReplica findLocal(Collection<KetchReplica> voters) {
 	 * checked to look for risks of conflicts, and then submitted into the queue
 	 * for distribution as soon as possible.
 	 * <p>
-	 * Callers must use {@link Proposal#await()} to see if the proposal is done.
+	 * Callers must use {@link org.eclipse.jgit.internal.ketch.Proposal#await()}
+	 * to see if the proposal is done.
 	 *
 	 * @param proposal
 	 *            the proposed reference updates to queue for consideration.
 	 *            Once execution is complete the individual reference result
 	 *            fields will be populated with the outcome.
-	 * @throws InterruptedException
+	 * @throws java.lang.InterruptedException
 	 *             current thread was interrupted. The proposal may have been
 	 *             aborted if it was not yet queued for execution.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             unrecoverable error preventing proposals from being attempted
 	 *             by this leader.
 	 */
@@ -577,7 +588,11 @@ void nextRound() {
 		}
 	}
 
-	/** @return snapshot this leader. */
+	/**
+	 * Snapshot this leader
+	 *
+	 * @return snapshot of this leader
+	 */
 	public LeaderSnapshot snapshot() {
 		lock.lock();
 		try {
@@ -599,7 +614,9 @@ public LeaderSnapshot snapshot() {
 		}
 	}
 
-	/** Gracefully shutdown this leader and cancel outstanding operations. */
+	/**
+	 * Gracefully shutdown this leader and cancel outstanding operations.
+	 */
 	public void shutdown() {
 		lock.lock();
 		try {
@@ -617,6 +634,7 @@ public void shutdown() {
 		}
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public String toString() {
 		return snapshot().toString();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/ketch/KetchLeaderCache.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/ketch/KetchLeaderCache.java
index ba033c1..de0da4f 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/ketch/KetchLeaderCache.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/ketch/KetchLeaderCache.java
@@ -82,7 +82,7 @@ public KetchLeaderCache(KetchSystem system) {
 	 * @param repo
 	 *            repository to get the leader for.
 	 * @return the leader instance for the repository.
-	 * @throws URISyntaxException
+	 * @throws java.net.URISyntaxException
 	 *             remote configuration contains an invalid URL.
 	 */
 	public KetchLeader get(Repository repo)
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/ketch/KetchPreReceive.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/ketch/KetchPreReceive.java
index 1b4307f..53d2865 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/ketch/KetchPreReceive.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/ketch/KetchPreReceive.java
@@ -64,9 +64,10 @@
 /**
  * PreReceiveHook for handling push traffic in a Ketch system.
  * <p>
- * Install an instance on {@link ReceivePack} to capture the commands and other
- * connection state and relay them through the {@link KetchLeader}, allowing the
- * leader to gain consensus about the new reference state.
+ * Install an instance on {@link org.eclipse.jgit.transport.ReceivePack} to
+ * capture the commands and other connection state and relay them through the
+ * {@link org.eclipse.jgit.internal.ketch.KetchLeader}, allowing the leader to
+ * gain consensus about the new reference state.
  */
 public class KetchPreReceive implements PreReceiveHook {
 	private static final Logger log = LoggerFactory.getLogger(KetchPreReceive.class);
@@ -74,7 +75,8 @@ public class KetchPreReceive implements PreReceiveHook {
 	private final KetchLeader leader;
 
 	/**
-	 * Construct a hook executing updates through a {@link KetchLeader}.
+	 * Construct a hook executing updates through a
+	 * {@link org.eclipse.jgit.internal.ketch.KetchLeader}.
 	 *
 	 * @param leader
 	 *            leader for this repository.
@@ -83,6 +85,7 @@ public KetchPreReceive(KetchLeader leader) {
 		this.leader = leader;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void onPreReceive(ReceivePack rp, Collection<ReceiveCommand> cmds) {
 		cmds = ReceiveCommand.filter(cmds, NOT_ATTEMPTED);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/ketch/KetchReplica.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/ketch/KetchReplica.java
index a30bbb2..a0176d7 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/ketch/KetchReplica.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/ketch/KetchReplica.java
@@ -82,26 +82,32 @@
 import org.slf4j.LoggerFactory;
 
 /**
- * A Ketch replica, either {@link LocalReplica} or {@link RemoteGitReplica}.
+ * A Ketch replica, either {@link org.eclipse.jgit.internal.ketch.LocalReplica}
+ * or {@link org.eclipse.jgit.internal.ketch.RemoteGitReplica}.
  * <p>
  * Replicas can be either a stock Git replica, or a Ketch-aware replica.
  * <p>
  * A stock Git replica has no special knowledge of Ketch and simply stores
  * objects and references. Ketch communicates with the stock Git replica using
- * the Git push wire protocol. The {@link KetchLeader} commits an agreed upon
+ * the Git push wire protocol. The
+ * {@link org.eclipse.jgit.internal.ketch.KetchLeader} commits an agreed upon
  * state by pushing all references to the Git replica, for example
  * {@code "refs/heads/master"} is pushed during commit. Stock Git replicas use
- * {@link CommitMethod#ALL_REFS} to record the final state.
+ * {@link org.eclipse.jgit.internal.ketch.KetchReplica.CommitMethod#ALL_REFS} to
+ * record the final state.
  * <p>
  * Ketch-aware replicas understand the {@code RefTree} sent during the proposal
  * and during commit are able to update their own reference space to match the
  * state represented by the {@code RefTree}. Ketch-aware replicas typically use
  * a {@link org.eclipse.jgit.internal.storage.reftree.RefTreeDatabase} and
- * {@link CommitMethod#TXN_COMMITTED} to record the final state.
+ * {@link org.eclipse.jgit.internal.ketch.KetchReplica.CommitMethod#TXN_COMMITTED}
+ * to record the final state.
  * <p>
- * KetchReplica instances are tightly coupled with a single {@link KetchLeader}.
- * Some state may be accessed by the leader thread and uses the leader's own
- * {@link KetchLeader#lock} to protect shared data.
+ * KetchReplica instances are tightly coupled with a single
+ * {@link org.eclipse.jgit.internal.ketch.KetchLeader}. Some state may be
+ * accessed by the leader thread and uses the leader's own
+ * {@link org.eclipse.jgit.internal.ketch.KetchLeader#lock} to protect shared
+ * data.
  */
 public abstract class KetchReplica {
 	static final Logger log = LoggerFactory.getLogger(KetchReplica.class);
@@ -223,37 +229,65 @@ protected KetchReplica(KetchLeader leader, String name, ReplicaConfig cfg) {
 		this.queued = new ArrayList<>(4);
 	}
 
-	/** @return system configuration. */
+	/**
+	 * Get system configuration.
+	 *
+	 * @return system configuration.
+	 */
 	public KetchSystem getSystem() {
 		return getLeader().getSystem();
 	}
 
-	/** @return leader instance this replica follows. */
+	/**
+	 * Get leader instance this replica follows.
+	 *
+	 * @return leader instance this replica follows.
+	 */
 	public KetchLeader getLeader() {
 		return leader;
 	}
 
-	/** @return unique-ish name for debugging. */
+	/**
+	 * Get unique-ish name for debugging.
+	 *
+	 * @return unique-ish name for debugging.
+	 */
 	public String getName() {
 		return replicaName;
 	}
 
-	/** @return description of this replica for error/debug logging purposes. */
+	/**
+	 * Get description of this replica for error/debug logging purposes.
+	 *
+	 * @return description of this replica for error/debug logging purposes.
+	 */
 	protected String describeForLog() {
 		return getName();
 	}
 
-	/** @return how the replica participates in this Ketch system. */
+	/**
+	 * Get how the replica participates in this Ketch system.
+	 *
+	 * @return how the replica participates in this Ketch system.
+	 */
 	public Participation getParticipation() {
 		return participation;
 	}
 
-	/** @return how Ketch will commit to the repository. */
+	/**
+	 * Get how Ketch will commit to the repository.
+	 *
+	 * @return how Ketch will commit to the repository.
+	 */
 	public CommitMethod getCommitMethod() {
 		return commitMethod;
 	}
 
-	/** @return when Ketch will commit to the repository. */
+	/**
+	 * Get when Ketch will commit to the repository.
+	 *
+	 * @return when Ketch will commit to the repository.
+	 */
 	public CommitSpeed getCommitSpeed() {
 		return commitSpeed;
 	}
@@ -264,7 +298,8 @@ public CommitSpeed getCommitSpeed() {
 	 * Default implementation cancels any scheduled retry. Subclasses may add
 	 * additional logic before or after calling {@code super.shutdown()}.
 	 * <p>
-	 * Called with {@link KetchLeader#lock} held by caller.
+	 * Called with {@link org.eclipse.jgit.internal.ketch.KetchLeader#lock} held
+	 * by caller.
 	 */
 	protected void shutdown() {
 		Future<?> f = retryFuture;
@@ -541,8 +576,8 @@ private void doRetryPush() {
 	/**
 	 * Begin executing a single push.
 	 * <p>
-	 * This method must move processing onto another thread.
-	 * Called with {@link KetchLeader#lock} held by caller.
+	 * This method must move processing onto another thread. Called with
+	 * {@link org.eclipse.jgit.internal.ketch.KetchLeader#lock} held by caller.
 	 *
 	 * @param req
 	 *            the request to send to the replica.
@@ -666,20 +701,21 @@ private static ObjectId readId(ReplicaPushRequest req,
 	/**
 	 * Fetch objects from the remote using the calling thread.
 	 * <p>
-	 * Called without {@link KetchLeader#lock}.
+	 * Called without {@link org.eclipse.jgit.internal.ketch.KetchLeader#lock}.
 	 *
 	 * @param repo
 	 *            local repository to fetch objects into.
 	 * @param req
 	 *            the request to fetch from a replica.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             communication with the replica was not possible.
 	 */
 	protected abstract void blockingFetch(Repository repo,
 			ReplicaFetchRequest req) throws IOException;
 
 	/**
-	 * Build a list of commands to commit {@link CommitMethod#ALL_REFS}.
+	 * Build a list of commands to commit
+	 * {@link org.eclipse.jgit.internal.ketch.KetchReplica.CommitMethod#ALL_REFS}.
 	 *
 	 * @param git
 	 *            local leader repository to read committed state from.
@@ -689,7 +725,7 @@ protected abstract void blockingFetch(Repository repo,
 	 * @param committed
 	 *            state being pushed to {@code refs/txn/committed}.
 	 * @return commands to update during commit.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             cannot read the committed state.
 	 */
 	protected Collection<ReceiveCommand> prepareCommit(Repository git,
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/ketch/KetchSystem.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/ketch/KetchSystem.java
index 33f526e..d1d4f67 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/ketch/KetchSystem.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/ketch/KetchSystem.java
@@ -81,12 +81,17 @@
  * Full scale installations are expected to subclass and override methods to
  * provide consistent configuration across all managed repositories.
  * <p>
- * Servers should configure their own {@link ScheduledExecutorService}.
+ * Servers should configure their own
+ * {@link java.util.concurrent.ScheduledExecutorService}.
  */
 public class KetchSystem {
 	private static final Random RNG = new Random();
 
-	/** @return default executor, one thread per available processor. */
+	/**
+	 * Get default executor, one thread per available processor.
+	 *
+	 * @return default executor, one thread per available processor.
+	 */
 	public static ScheduledExecutorService defaultExecutor() {
 		return DefaultExecutorHolder.I;
 	}
@@ -98,7 +103,9 @@ public static ScheduledExecutorService defaultExecutor() {
 	private final String txnCommitted;
 	private final String txnStage;
 
-	/** Create a default system with a thread pool of 1 thread per CPU. */
+	/**
+	 * Create a default system with a thread pool of 1 thread per CPU.
+	 */
 	public KetchSystem() {
 		this(defaultExecutor(), new MonotonicSystemClock(), DEFAULT_TXN_NAMESPACE);
 	}
@@ -125,17 +132,29 @@ public KetchSystem(ScheduledExecutorService executor, MonotonicClock clock,
 		this.txnStage = txnNamespace + STAGE;
 	}
 
-	/** @return executor to perform background operations. */
+	/**
+	 * Get executor to perform background operations.
+	 *
+	 * @return executor to perform background operations.
+	 */
 	public ScheduledExecutorService getExecutor() {
 		return executor;
 	}
 
-	/** @return clock to obtain timestamps from. */
+	/**
+	 * Get clock to obtain timestamps from.
+	 *
+	 * @return clock to obtain timestamps from.
+	 */
 	public MonotonicClock getClock() {
 		return clock;
 	}
 
 	/**
+	 * Get how long the leader will wait for the {@link #getClock()}'s
+	 * {@code ProposedTimestamp} used in commits proposed to the RefTree graph
+	 * ({@link #getTxnAccepted()})
+	 *
 	 * @return how long the leader will wait for the {@link #getClock()}'s
 	 *         {@code ProposedTimestamp} used in commits proposed to the RefTree
 	 *         graph ({@link #getTxnAccepted()}). Defaults to 5 seconds.
@@ -145,8 +164,12 @@ public Duration getMaxWaitForMonotonicClock() {
 	}
 
 	/**
-	 * @return true if elections should require monotonically increasing commit
-	 *         timestamps. This requires a very good {@link MonotonicClock}.
+	 * Whether elections should require monotonically increasing commit
+	 * timestamps
+	 *
+	 * @return {@code true} if elections should require monotonically increasing
+	 *         commit timestamps. This requires a very good
+	 *         {@link org.eclipse.jgit.util.time.MonotonicClock}.
 	 */
 	public boolean requireMonotonicLeaderElections() {
 		return false;
@@ -161,22 +184,36 @@ public String getTxnNamespace() {
 		return txnNamespace;
 	}
 
-	/** @return name of the accepted RefTree graph. */
+	/**
+	 * Get name of the accepted RefTree graph.
+	 *
+	 * @return name of the accepted RefTree graph.
+	 */
 	public String getTxnAccepted() {
 		return txnAccepted;
 	}
 
-	/** @return name of the committed RefTree graph. */
+	/**
+	 * Get name of the committed RefTree graph.
+	 *
+	 * @return name of the committed RefTree graph.
+	 */
 	public String getTxnCommitted() {
 		return txnCommitted;
 	}
 
-	/** @return prefix for staged objects, e.g. {@code "refs/txn/stage/"}. */
+	/**
+	 * Get prefix for staged objects, e.g. {@code "refs/txn/stage/"}.
+	 *
+	 * @return prefix for staged objects, e.g. {@code "refs/txn/stage/"}.
+	 */
 	public String getTxnStage() {
 		return txnStage;
 	}
 
 	/**
+	 * Create new committer {@code PersonIdent} for ketch system
+	 *
 	 * @param time
 	 *            timestamp for the committer.
 	 * @return identity line for the committer header of a RefTreeGraph.
@@ -220,10 +257,10 @@ public String newLeaderTag() {
 	 * @param repo
 	 *            local repository stored by the leader.
 	 * @return leader instance.
-	 * @throws URISyntaxException
+	 * @throws java.net.URISyntaxException
 	 *             a follower configuration contains an unsupported URI.
 	 */
-	public KetchLeader createLeader(final Repository repo)
+	public KetchLeader createLeader(Repository repo)
 			throws URISyntaxException {
 		KetchLeader leader = new KetchLeader(this) {
 			@Override
@@ -246,7 +283,7 @@ protected Repository openRepository() {
 	 * @param repo
 	 *            repository to get the replicas of.
 	 * @return collection of replicas for the specified repository.
-	 * @throws URISyntaxException
+	 * @throws java.net.URISyntaxException
 	 *             a configured URI is invalid.
 	 */
 	protected List<KetchReplica> createReplicas(KetchLeader leader,
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/ketch/KetchText.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/ketch/KetchText.java
index b6c3bc9..fa34a88 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/ketch/KetchText.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/ketch/KetchText.java
@@ -46,9 +46,15 @@
 import org.eclipse.jgit.nls.NLS;
 import org.eclipse.jgit.nls.TranslationBundle;
 
-/** Translation bundle for the Ketch implementation. */
+/**
+ * Translation bundle for the Ketch implementation.
+ */
 public class KetchText extends TranslationBundle {
-	/** @return instance of this translation bundle. */
+	/**
+	 * Get an instance of this translation bundle.
+	 *
+	 * @return instance of this translation bundle.
+	 */
 	public static KetchText get() {
 		return NLS.getBundleFor(KetchText.class);
 	}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/ketch/LagCheck.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/ketch/LagCheck.java
index 757c19a..c09d872 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/ketch/LagCheck.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/ketch/LagCheck.java
@@ -86,6 +86,7 @@ private void initRevWalk() {
 		rw.setRetainBody(false);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void close() {
 		if (rw != null) {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/ketch/LeaderSnapshot.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/ketch/LeaderSnapshot.java
index 28a49df..4c8bd06 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/ketch/LeaderSnapshot.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/ketch/LeaderSnapshot.java
@@ -53,7 +53,9 @@
 import org.eclipse.jgit.annotations.Nullable;
 import org.eclipse.jgit.lib.ObjectId;
 
-/** A snapshot of a leader and its view of the world. */
+/**
+ * A snapshot of a leader and its view of the world.
+ */
 public class LeaderSnapshot {
 	final List<ReplicaSnapshot> replicas = new ArrayList<>();
 	KetchLeader.State state;
@@ -65,17 +67,28 @@ public class LeaderSnapshot {
 	LeaderSnapshot() {
 	}
 
-	/** @return unmodifiable view of configured replicas. */
+	/**
+	 * Get unmodifiable view of configured replicas.
+	 *
+	 * @return unmodifiable view of configured replicas.
+	 */
 	public Collection<ReplicaSnapshot> getReplicas() {
 		return Collections.unmodifiableList(replicas);
 	}
 
-	/** @return current state of the leader. */
+	/**
+	 * Get current state of the leader.
+	 *
+	 * @return current state of the leader.
+	 */
 	public KetchLeader.State getState() {
 		return state;
 	}
 
 	/**
+	 * Whether the leader is not running a round to reach consensus, and has no
+	 * rounds queued.
+	 *
 	 * @return {@code true} if the leader is not running a round to reach
 	 *         consensus, and has no rounds queued.
 	 */
@@ -84,14 +97,19 @@ public boolean isIdle() {
 	}
 
 	/**
+	 * Get term of this leader
+	 *
 	 * @return term of this leader. Valid only if {@link #getState()} is
-	 *         currently {@link KetchLeader.State#LEADER}.
+	 *         currently
+	 *         {@link org.eclipse.jgit.internal.ketch.KetchLeader.State#LEADER}.
 	 */
 	public long getTerm() {
 		return term;
 	}
 
 	/**
+	 * Get end of the leader's log
+	 *
 	 * @return end of the leader's log; null if leader hasn't started up enough
 	 *         to begin its own election.
 	 */
@@ -101,6 +119,9 @@ public LogIndex getHead() {
 	}
 
 	/**
+	 * Get state the leader knows is committed on a majority of participant
+	 * replicas
+	 *
 	 * @return state the leader knows is committed on a majority of participant
 	 *         replicas. Null until the leader instance has committed a log
 	 *         index within its own term.
@@ -110,6 +131,7 @@ public LogIndex getCommitted() {
 		return committedIndex;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public String toString() {
 		StringBuilder s = new StringBuilder();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/ketch/LocalReplica.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/ketch/LocalReplica.java
index 907eecb..7ddde63 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/ketch/LocalReplica.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/ketch/LocalReplica.java
@@ -67,7 +67,10 @@
 import org.eclipse.jgit.util.time.MonotonicClock;
 import org.eclipse.jgit.util.time.ProposedTimestamp;
 
-/** Ketch replica running on the same system as the {@link KetchLeader}. */
+/**
+ * Ketch replica running on the same system as the
+ * {@link org.eclipse.jgit.internal.ketch.KetchLeader}.
+ */
 public class LocalReplica extends KetchReplica {
 	/**
 	 * Configure a local replica.
@@ -83,6 +86,7 @@ public LocalReplica(KetchLeader leader, String name, ReplicaConfig cfg) {
 		super(leader, name, cfg);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected String describeForLog() {
 		return String.format("%s (leader)", getName()); //$NON-NLS-1$
@@ -116,8 +120,9 @@ void initialize(Repository repo) throws IOException {
 				getSystem().getTxnCommitted()));
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	protected void startPush(final ReplicaPushRequest req) {
+	protected void startPush(ReplicaPushRequest req) {
 		getSystem().getExecutor().execute(new Runnable() {
 			@Override
 			public void run() {
@@ -137,6 +142,7 @@ public void run() {
 		});
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected void blockingFetch(Repository repo, ReplicaFetchRequest req)
 			throws IOException {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/ketch/LogIndex.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/ketch/LogIndex.java
index 350c8ed..eb600bb 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/ketch/LogIndex.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/ketch/LogIndex.java
@@ -54,17 +54,18 @@
  * LogIndex provides a performance optimization for Ketch, the same information
  * can be obtained from {@link org.eclipse.jgit.revwalk.RevWalk}.
  * <p>
- * Index values are only valid within a single {@link KetchLeader} instance
- * after it has won an election. By restricting scope to a single leader new
- * leaders do not need to traverse the entire history to determine the next
- * {@code index} for new proposals. This differs from Raft, where leader
- * election uses the log index and the term number to determine which replica
- * holds a sufficiently up-to-date log. Since Ketch uses Git objects for storage
- * of its replicated log, it keeps the term number as Raft does but uses
- * standard Git operations to imply the log index.
+ * Index values are only valid within a single
+ * {@link org.eclipse.jgit.internal.ketch.KetchLeader} instance after it has won
+ * an election. By restricting scope to a single leader new leaders do not need
+ * to traverse the entire history to determine the next {@code index} for new
+ * proposals. This differs from Raft, where leader election uses the log index
+ * and the term number to determine which replica holds a sufficiently
+ * up-to-date log. Since Ketch uses Git objects for storage of its replicated
+ * log, it keeps the term number as Raft does but uses standard Git operations
+ * to imply the log index.
  * <p>
- * {@link Round#runAsync(AnyObjectId)} bumps the index as each new round is
- * constructed.
+ * {@link org.eclipse.jgit.internal.ketch.Round#runAsync(AnyObjectId)} bumps the
+ * index as each new round is constructed.
  */
 public class LogIndex extends ObjectId {
 	static LogIndex unknown(AnyObjectId id) {
@@ -82,7 +83,11 @@ LogIndex nextIndex(AnyObjectId id) {
 		return new LogIndex(id, index + 1);
 	}
 
-	/** @return index provided by the current leader instance. */
+	/**
+	 * Get index provided by the current leader instance.
+	 *
+	 * @return index provided by the current leader instance.
+	 */
 	public long getIndex() {
 		return index;
 	}
@@ -103,6 +108,9 @@ boolean isBefore(LogIndex c) {
 	}
 
 	/**
+	 * Create string suitable for debug logging containing the log index and
+	 * abbreviated ObjectId.
+	 *
 	 * @return string suitable for debug logging containing the log index and
 	 *         abbreviated ObjectId.
 	 */
@@ -111,6 +119,7 @@ public String describeForLog() {
 		return String.format("%5d/%s", index, abbreviate(6).name()); //$NON-NLS-1$
 	}
 
+	/** {@inheritDoc} */
 	@SuppressWarnings("boxing")
 	@Override
 	public String toString() {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/ketch/Proposal.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/ketch/Proposal.java
index 12d3f4c..db2ad23 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/ketch/Proposal.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/ketch/Proposal.java
@@ -78,10 +78,11 @@
  * area under the {@code refs/txn/stage/} namespace. If the proposal succeeds
  * then the changes are durable and the leader can commit the proposal.
  * <p>
- * Proposals are executed by {@link KetchLeader#queueProposal(Proposal)}, which
- * runs them asynchronously in the background. Proposals are thread-safe futures
- * allowing callers to {@link #await()} for results or be notified by callback
- * using {@link #addListener(Runnable)}.
+ * Proposals are executed by
+ * {@link org.eclipse.jgit.internal.ketch.KetchLeader#queueProposal(Proposal)},
+ * which runs them asynchronously in the background. Proposals are thread-safe
+ * futures allowing callers to {@link #await()} for results or be notified by
+ * callback using {@link #addListener(Runnable)}.
  */
 public class Proposal {
 	/** Current state of the proposal. */
@@ -146,9 +147,9 @@ public Proposal(List<Command> cmds) {
 	 *            walker to assist in preparing commands.
 	 * @param cmds
 	 *            list of pending commands.
-	 * @throws MissingObjectException
+	 * @throws org.eclipse.jgit.errors.MissingObjectException
 	 *             newId of a command is not found locally.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             local objects cannot be accessed.
 	 */
 	public Proposal(RevWalk rw, Collection<ReceiveCommand> cmds)
@@ -166,12 +167,20 @@ private static List<Command> asCommandList(RevWalk rw,
 		return Collections.unmodifiableList(commands);
 	}
 
-	/** @return commands from this proposal. */
+	/**
+	 * Get commands from this proposal.
+	 *
+	 * @return commands from this proposal.
+	 */
 	public Collection<Command> getCommands() {
 		return commands;
 	}
 
-	/** @return optional author of the proposal. */
+	/**
+	 * Get optional author of the proposal.
+	 *
+	 * @return optional author of the proposal.
+	 */
 	@Nullable
 	public PersonIdent getAuthor() {
 		return author;
@@ -189,7 +198,11 @@ public Proposal setAuthor(@Nullable PersonIdent who) {
 		return this;
 	}
 
-	/** @return optional message for the commit log of the RefTree. */
+	/**
+	 * Get optional message for the commit log of the RefTree.
+	 *
+	 * @return optional message for the commit log of the RefTree.
+	 */
 	@Nullable
 	public String getMessage() {
 		return message;
@@ -207,7 +220,11 @@ public Proposal setMessage(@Nullable String msg) {
 		return this;
 	}
 
-	/** @return optional certificate signing the references. */
+	/**
+	 * Get optional certificate signing the references.
+	 *
+	 * @return optional certificate signing the references.
+	 */
 	@Nullable
 	public PushCertificate getPushCertificate() {
 		return pushCert;
@@ -226,6 +243,8 @@ public Proposal setPushCertificate(@Nullable PushCertificate cert) {
 	}
 
 	/**
+	 * Get timestamps that Ketch must block for.
+	 *
 	 * @return timestamps that Ketch must block for. These may have been used as
 	 *         commit times inside the objects involved in the proposal.
 	 */
@@ -240,6 +259,7 @@ public List<ProposedTimestamp> getProposedTimestamps() {
 	 * Request the proposal to wait for the affected timestamps to resolve.
 	 *
 	 * @param ts
+	 *            a {@link org.eclipse.jgit.util.time.ProposedTimestamp} object.
 	 * @return {@code this}.
 	 */
 	public Proposal addProposedTimestamp(ProposedTimestamp ts) {
@@ -253,9 +273,11 @@ public Proposal addProposedTimestamp(ProposedTimestamp ts) {
 	/**
 	 * Add a callback to be invoked when the proposal is done.
 	 * <p>
-	 * A proposal is done when it has entered either {@link State#EXECUTED} or
-	 * {@link State#ABORTED} state. If the proposal is already done
-	 * {@code callback.run()} is immediately invoked on the caller's thread.
+	 * A proposal is done when it has entered either
+	 * {@link org.eclipse.jgit.internal.ketch.Proposal.State#EXECUTED} or
+	 * {@link org.eclipse.jgit.internal.ketch.Proposal.State#ABORTED} state. If
+	 * the proposal is already done {@code callback.run()} is immediately
+	 * invoked on the caller's thread.
 	 *
 	 * @param callback
 	 *            method to run after the proposal is done. The callback may be
@@ -291,12 +313,18 @@ void abort() {
 		notifyState(ABORTED);
 	}
 
-	/** @return read the current state of the proposal. */
+	/**
+	 * Read the current state of the proposal.
+	 *
+	 * @return read the current state of the proposal.
+	 */
 	public State getState() {
 		return state.get();
 	}
 
 	/**
+	 * Whether the proposal was attempted
+	 *
 	 * @return {@code true} if the proposal was attempted. A true value does not
 	 *         mean consensus was reached, only that the proposal was considered
 	 *         and will not be making any more progress beyond its current
@@ -309,7 +337,7 @@ public boolean isDone() {
 	/**
 	 * Wait for the proposal to be attempted and {@link #isDone()} to be true.
 	 *
-	 * @throws InterruptedException
+	 * @throws java.lang.InterruptedException
 	 *             caller was interrupted before proposal executed.
 	 */
 	public void await() throws InterruptedException {
@@ -328,7 +356,7 @@ public void await() throws InterruptedException {
 	 * @param unit
 	 *            unit describing the wait time.
 	 * @return true if the proposal is done; false if the method timed out.
-	 * @throws InterruptedException
+	 * @throws java.lang.InterruptedException
 	 *             caller was interrupted before proposal executed.
 	 */
 	public boolean await(long wait, TimeUnit unit) throws InterruptedException {
@@ -351,7 +379,7 @@ public boolean await(long wait, TimeUnit unit) throws InterruptedException {
 	 * @param unit
 	 *            unit describing the wait time.
 	 * @return true if the proposal exited the state; false on time out.
-	 * @throws InterruptedException
+	 * @throws java.lang.InterruptedException
 	 *             caller was interrupted before proposal executed.
 	 */
 	public boolean awaitStateChange(State notIn, long wait, TimeUnit unit)
@@ -378,6 +406,7 @@ void notifyState(State s) {
 		}
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public String toString() {
 		StringBuilder s = new StringBuilder();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/ketch/RemoteGitReplica.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/ketch/RemoteGitReplica.java
index a0ac608..b61274e 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/ketch/RemoteGitReplica.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/ketch/RemoteGitReplica.java
@@ -80,7 +80,8 @@
 /**
  * Representation of a Git repository on a remote replica system.
  * <p>
- * {@link KetchLeader} will contact the replica using the Git wire protocol.
+ * {@link org.eclipse.jgit.internal.ketch.KetchLeader} will contact the replica
+ * using the Git wire protocol.
  * <p>
  * The remote replica may be fully Ketch-aware, or a standard Git server.
  */
@@ -110,24 +111,34 @@ public RemoteGitReplica(KetchLeader leader, String name, URIish uri,
 		this.remoteConfig = rc;
 	}
 
-	/** @return URI to contact the remote peer repository. */
+	/**
+	 * Get URI to contact the remote peer repository.
+	 *
+	 * @return URI to contact the remote peer repository.
+	 */
 	public URIish getURI() {
 		return uri;
 	}
 
-	/** @return optional configuration describing how to contact the peer. */
+	/**
+	 * Get optional configuration describing how to contact the peer.
+	 *
+	 * @return optional configuration describing how to contact the peer.
+	 */
 	@Nullable
 	protected RemoteConfig getRemoteConfig() {
 		return remoteConfig;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected String describeForLog() {
 		return String.format("%s @ %s", getName(), getURI()); //$NON-NLS-1$
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	protected void startPush(final ReplicaPushRequest req) {
+	protected void startPush(ReplicaPushRequest req) {
 		getSystem().getExecutor().execute(new Runnable() {
 			@Override
 			public void run() {
@@ -240,6 +251,7 @@ private static void abort(List<RemoteCommand> cmds) {
 		ReceiveCommand.abort(tmp);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected void blockingFetch(Repository repo, ReplicaFetchRequest req)
 			throws NotSupportedException, TransportException {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/ketch/ReplicaConfig.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/ketch/ReplicaConfig.java
index e16e63a..84261f1 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/ketch/ReplicaConfig.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/ketch/ReplicaConfig.java
@@ -65,7 +65,9 @@
 import org.eclipse.jgit.internal.ketch.KetchReplica.Participation;
 import org.eclipse.jgit.lib.Config;
 
-/** Configures a {@link KetchReplica}. */
+/**
+ * Configures a {@link org.eclipse.jgit.internal.ketch.KetchReplica}.
+ */
 public class ReplicaConfig {
 	/**
 	 * Read a configuration from a config block.
@@ -86,17 +88,29 @@ public static ReplicaConfig newFromConfig(Config cfg, String name) {
 	private long minRetry = SECONDS.toMillis(5);
 	private long maxRetry = MINUTES.toMillis(1);
 
-	/** @return participation of the replica in the system. */
+	/**
+	 * Get participation of the replica in the system.
+	 *
+	 * @return participation of the replica in the system.
+	 */
 	public Participation getParticipation() {
 		return participation;
 	}
 
-	/** @return how Ketch should apply committed changes. */
+	/**
+	 * Get how Ketch should apply committed changes.
+	 *
+	 * @return how Ketch should apply committed changes.
+	 */
 	public CommitMethod getCommitMethod() {
 		return commitMethod;
 	}
 
-	/** @return how quickly should Ketch commit. */
+	/**
+	 * Get how quickly should Ketch commit.
+	 *
+	 * @return how quickly should Ketch commit.
+	 */
 	public CommitSpeed getCommitSpeed() {
 		return commitSpeed;
 	}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/ketch/ReplicaFetchRequest.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/ketch/ReplicaFetchRequest.java
index 201d9e9..11c5b61 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/ketch/ReplicaFetchRequest.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/ketch/ReplicaFetchRequest.java
@@ -50,7 +50,9 @@
 import org.eclipse.jgit.lib.ObjectId;
 import org.eclipse.jgit.lib.Ref;
 
-/** A fetch request to obtain objects from a replica, and its result. */
+/**
+ * A fetch request to obtain objects from a replica, and its result.
+ */
 public class ReplicaFetchRequest {
 	private final Set<String> wantRefs;
 	private final Set<ObjectId> wantObjects;
@@ -70,23 +72,37 @@ public ReplicaFetchRequest(Set<String> wantRefs,
 		this.wantObjects = wantObjects;
 	}
 
-	/** @return references to be fetched. */
+	/**
+	 * Get references to be fetched.
+	 *
+	 * @return references to be fetched.
+	 */
 	public Set<String> getWantRefs() {
 		return wantRefs;
 	}
 
-	/** @return objects to be fetched. */
+	/**
+	 * Get objects to be fetched.
+	 *
+	 * @return objects to be fetched.
+	 */
 	public Set<ObjectId> getWantObjects() {
 		return wantObjects;
 	}
 
-	/** @return remote references, usually from the advertisement. */
+	/**
+	 * Get remote references, usually from the advertisement.
+	 *
+	 * @return remote references, usually from the advertisement.
+	 */
 	@Nullable
 	public Map<String, Ref> getRefs() {
 		return refs;
 	}
 
 	/**
+	 * Set references observed from the replica.
+	 *
 	 * @param refs
 	 *            references observed from the replica.
 	 */
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/ketch/ReplicaPushRequest.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/ketch/ReplicaPushRequest.java
index 691b142..603288e 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/ketch/ReplicaPushRequest.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/ketch/ReplicaPushRequest.java
@@ -54,8 +54,8 @@
 /**
  * A push request sending objects to a replica, and its result.
  * <p>
- * Implementors of {@link KetchReplica} must populate the command result fields,
- * {@link #setRefs(Map)}, and call one of
+ * Implementors of {@link org.eclipse.jgit.internal.ketch.KetchReplica} must
+ * populate the command result fields, {@link #setRefs(Map)}, and call one of
  * {@link #setException(Repository, Throwable)} or {@link #done(Repository)} to
  * finish processing.
  */
@@ -80,18 +80,28 @@ public ReplicaPushRequest(KetchReplica replica,
 		this.commands = commands;
 	}
 
-	/** @return commands to be executed, and their results. */
+	/**
+	 * Get commands to be executed, and their results.
+	 *
+	 * @return commands to be executed, and their results.
+	 */
 	public Collection<ReceiveCommand> getCommands() {
 		return commands;
 	}
 
-	/** @return remote references, usually from the advertisement. */
+	/**
+	 * Get remote references, usually from the advertisement.
+	 *
+	 * @return remote references, usually from the advertisement.
+	 */
 	@Nullable
 	public Map<String, Ref> getRefs() {
 		return refs;
 	}
 
 	/**
+	 * Set references observed from the replica.
+	 *
 	 * @param refs
 	 *            references observed from the replica.
 	 */
@@ -99,7 +109,11 @@ public void setRefs(Map<String, Ref> refs) {
 		this.refs = refs;
 	}
 
-	/** @return exception thrown, if any. */
+	/**
+	 * Get exception thrown, if any.
+	 *
+	 * @return exception thrown, if any.
+	 */
 	@Nullable
 	public Throwable getException() {
 		return exception;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/ketch/ReplicaSnapshot.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/ketch/ReplicaSnapshot.java
index 8c3de02..263be77 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/ketch/ReplicaSnapshot.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/ketch/ReplicaSnapshot.java
@@ -65,31 +65,50 @@ public class ReplicaSnapshot {
 		this.replica = replica;
 	}
 
-	/** @return the replica this snapshot describes the state of. */
+	/**
+	 * Get the replica this snapshot describes the state of
+	 *
+	 * @return the replica this snapshot describes the state of
+	 */
 	public KetchReplica getReplica() {
 		return replica;
 	}
 
-	/** @return current state of the replica. */
+	/**
+	 * Get current state of the replica
+	 *
+	 * @return current state of the replica
+	 */
 	public KetchReplica.State getState() {
 		return state;
 	}
 
-	/** @return last known Git commit at {@code refs/txn/accepted}. */
+	/**
+	 * Get last known Git commit at {@code refs/txn/accepted}
+	 *
+	 * @return last known Git commit at {@code refs/txn/accepted}
+	 */
 	@Nullable
 	public ObjectId getAccepted() {
 		return accepted;
 	}
 
-	/** @return last known Git commit at {@code refs/txn/committed}. */
+	/**
+	 * Get last known Git commit at {@code refs/txn/committed}
+	 *
+	 * @return last known Git commit at {@code refs/txn/committed}
+	 */
 	@Nullable
 	public ObjectId getCommitted() {
 		return committed;
 	}
 
 	/**
-	 * @return if {@link #getState()} == {@link KetchReplica.State#OFFLINE} an
-	 *         optional human-readable message from the transport system
+	 * Get error message
+	 *
+	 * @return if {@link #getState()} ==
+	 *         {@link org.eclipse.jgit.internal.ketch.KetchReplica.State#OFFLINE}
+	 *         an optional human-readable message from the transport system
 	 *         explaining the failure.
 	 */
 	@Nullable
@@ -98,6 +117,9 @@ public String getErrorMessage() {
 	}
 
 	/**
+	 * Get when the leader will retry communication with the offline or lagging
+	 * replica
+	 *
 	 * @return time (usually in the future) when the leader will retry
 	 *         communication with the offline or lagging replica; null if no
 	 *         retry is scheduled or necessary.
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/ketch/StageBuilder.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/ketch/StageBuilder.java
index 61871a4..ae82dce 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/ketch/StageBuilder.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/ketch/StageBuilder.java
@@ -66,7 +66,9 @@
 import org.eclipse.jgit.treewalk.TreeWalk;
 import org.eclipse.jgit.treewalk.filter.TreeFilter;
 
-/** Constructs a set of commands to stage content during a proposal. */
+/**
+ * Constructs a set of commands to stage content during a proposal.
+ */
 public class StageBuilder {
 	/**
 	 * Acceptable number of references to send in a single stage transaction.
@@ -119,14 +121,15 @@ public StageBuilder(String txnStageNamespace, ObjectId txnId) {
 	 *            from.
 	 * @param oldTree
 	 *            accepted RefTree on the replica ({@code refs/txn/accepted}).
-	 *            Use {@link ObjectId#zeroId()} if the remote does not have any
-	 *            ref tree, e.g. a new replica catching up.
+	 *            Use {@link org.eclipse.jgit.lib.ObjectId#zeroId()} if the
+	 *            remote does not have any ref tree, e.g. a new replica catching
+	 *            up.
 	 * @param newTree
 	 *            RefTree being sent to the replica. The trees will be compared.
 	 * @return list of commands to create {@code "refs/txn/stage/..."}
 	 *         references on replicas anchoring new objects into the repository
 	 *         while a transaction gains consensus.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             {@code git} cannot be accessed to compare {@code oldTree} and
 	 *             {@code newTree} to build the object set.
 	 */
@@ -172,7 +175,7 @@ public List<ReceiveCommand> makeStageList(Repository git, ObjectId oldTree,
 	 * @return list of commands to create {@code "refs/txn/stage/..."}
 	 *         references on replicas anchoring {@code newObjs} into the
 	 *         repository while a transaction gains consensus.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             {@code git} cannot be accessed to perform minification of
 	 *             {@code newObjs}.
 	 */
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/revwalk/AddToBitmapFilter.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/revwalk/AddToBitmapFilter.java
new file mode 100644
index 0000000..468d930
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/revwalk/AddToBitmapFilter.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2017, Google Inc.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ *   copyright notice, this list of conditions and the following
+ *   disclaimer in the documentation and/or other materials provided
+ *   with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ *   names of its contributors may be used to endorse or promote
+ *   products derived from this software without specific prior
+ *   written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.internal.revwalk;
+
+import org.eclipse.jgit.lib.BitmapIndex.Bitmap;
+import org.eclipse.jgit.lib.BitmapIndex.BitmapBuilder;
+import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.revwalk.filter.RevFilter;
+import org.eclipse.jgit.revwalk.RevWalk;
+import org.eclipse.jgit.revwalk.RevCommit;
+import org.eclipse.jgit.revwalk.RevFlag;
+
+/**
+ * A RevFilter that adds the visited commits to {@code bitmap} as a side
+ * effect.
+ * <p>
+ * When the walk hits a commit that is part of {@code bitmap}'s
+ * BitmapIndex, that entire bitmap is ORed into {@code bitmap} and the
+ * commit and its parents are marked as SEEN so that the walk does not
+ * have to visit its ancestors.  This ensures the walk is very short if
+ * there is good bitmap coverage.
+ */
+public class AddToBitmapFilter extends RevFilter {
+	private final BitmapBuilder bitmap;
+
+	/**
+	 * Create a filter that adds visited commits to the given bitmap.
+	 *
+	 * @param bitmap bitmap to write visited commits to
+	 */
+	public AddToBitmapFilter(BitmapBuilder bitmap) {
+		this.bitmap = bitmap;
+	}
+
+	/** {@inheritDoc} */
+	@Override
+	public final boolean include(RevWalk walker, RevCommit cmit) {
+		Bitmap visitedBitmap;
+
+		if (bitmap.contains(cmit)) {
+			// already included
+		} else if ((visitedBitmap = bitmap.getBitmapIndex()
+				.getBitmap(cmit)) != null) {
+			bitmap.or(visitedBitmap);
+		} else {
+			bitmap.addObject(cmit, Constants.OBJ_COMMIT);
+			return true;
+		}
+
+		for (RevCommit p : cmit.getParents()) {
+			p.add(RevFlag.SEEN);
+		}
+		return false;
+	}
+
+	/** {@inheritDoc} */
+	@Override
+	public final RevFilter clone() {
+		throw new UnsupportedOperationException();
+	}
+
+	/** {@inheritDoc} */
+	@Override
+	public final boolean requiresCommitBody() {
+		return false;
+	}
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/revwalk/AddUnseenToBitmapFilter.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/revwalk/AddUnseenToBitmapFilter.java
new file mode 100644
index 0000000..a52c6a2
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/revwalk/AddUnseenToBitmapFilter.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2017, Google Inc.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ *   copyright notice, this list of conditions and the following
+ *   disclaimer in the documentation and/or other materials provided
+ *   with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ *   names of its contributors may be used to endorse or promote
+ *   products derived from this software without specific prior
+ *   written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.internal.revwalk;
+
+import org.eclipse.jgit.lib.BitmapIndex.Bitmap;
+import org.eclipse.jgit.lib.BitmapIndex.BitmapBuilder;
+import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.revwalk.filter.RevFilter;
+import org.eclipse.jgit.revwalk.RevWalk;
+import org.eclipse.jgit.revwalk.RevCommit;
+import org.eclipse.jgit.revwalk.RevFlag;
+
+/**
+ * A RevFilter that adds the visited commits to {@code bitmap} as a side
+ * effect.
+ * <p>
+ * When the walk hits a commit that is part of {@code bitmap}'s
+ * BitmapIndex, that entire bitmap is ORed into {@code bitmap} and the
+ * commit and its parents are marked as SEEN so that the walk does not
+ * have to visit its ancestors.  This ensures the walk is very short if
+ * there is good bitmap coverage.
+ * <p>
+ * Commits named in {@code seen} are considered already seen.  If one is
+ * encountered, that commit and its parents will be marked with the SEEN
+ * flag to prevent the walk from visiting its ancestors.
+ */
+public class AddUnseenToBitmapFilter extends RevFilter {
+	private final BitmapBuilder seen;
+	private final BitmapBuilder bitmap;
+
+	/**
+	 * Create a filter that adds visited commits to the given bitmap, but does not walk
+	 * through the objects in {@code seen}.
+	 *
+	 * @param seen objects that are already seen
+	 * @param bitmap bitmap to write visited commits to
+	 */
+	public AddUnseenToBitmapFilter(BitmapBuilder seen, BitmapBuilder bitmap) {
+		this.seen = seen;
+		this.bitmap = bitmap;
+	}
+
+	/** {@inheritDoc} */
+	@Override
+	public final boolean include(RevWalk walker, RevCommit cmit) {
+		Bitmap visitedBitmap;
+
+		if (seen.contains(cmit) || bitmap.contains(cmit)) {
+			// already seen or included
+		} else if ((visitedBitmap = bitmap.getBitmapIndex()
+				.getBitmap(cmit)) != null) {
+			bitmap.or(visitedBitmap);
+		} else {
+			bitmap.addObject(cmit, Constants.OBJ_COMMIT);
+			return true;
+		}
+
+		for (RevCommit p : cmit.getParents()) {
+			p.add(RevFlag.SEEN);
+		}
+		return false;
+	}
+
+	/** {@inheritDoc} */
+	@Override
+	public final RevFilter clone() {
+		throw new UnsupportedOperationException();
+	}
+
+	/** {@inheritDoc} */
+	@Override
+	public final boolean requiresCommitBody() {
+		return false;
+	}
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/BeforeDfsPackIndexLoadedEvent.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/BeforeDfsPackIndexLoadedEvent.java
index 75ccb07..10d8e89 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/BeforeDfsPackIndexLoadedEvent.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/BeforeDfsPackIndexLoadedEvent.java
@@ -46,10 +46,10 @@
 import org.eclipse.jgit.events.RepositoryEvent;
 
 /**
- * Describes the {@link DfsPackFile} just before its index is loaded. Currently,
- * DfsPackFile directly dispatches the event on
- * {@link org.eclipse.jgit.lib.Repository#getGlobalListenerList}. Which means
- * the call to {@link #getRepository} will always return null.
+ * Describes the {@link org.eclipse.jgit.internal.storage.dfs.DfsPackFile} just
+ * before its index is loaded. Currently, DfsPackFile directly dispatches the
+ * event on {@link org.eclipse.jgit.lib.Repository#getGlobalListenerList}. Which
+ * means the call to {@link #getRepository} will always return null.
  */
 public class BeforeDfsPackIndexLoadedEvent
 		extends RepositoryEvent<BeforeDfsPackIndexLoadedListener> {
@@ -65,16 +65,22 @@ public BeforeDfsPackIndexLoadedEvent(DfsPackFile pack) {
 		this.pack = pack;
 	}
 
-	/** @return the PackFile containing the index that will be loaded. */
+	/**
+	 * Get the PackFile containing the index that will be loaded.
+	 *
+	 * @return the PackFile containing the index that will be loaded.
+	 */
 	public DfsPackFile getPackFile() {
 		return pack;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public Class<BeforeDfsPackIndexLoadedListener> getListenerType() {
 		return BeforeDfsPackIndexLoadedListener.class;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void dispatch(BeforeDfsPackIndexLoadedListener listener) {
 		listener.onBeforeDfsPackIndexLoaded(this);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/BeforeDfsPackIndexLoadedListener.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/BeforeDfsPackIndexLoadedListener.java
index 9f7f350..517e42b 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/BeforeDfsPackIndexLoadedListener.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/BeforeDfsPackIndexLoadedListener.java
@@ -46,7 +46,8 @@
 import org.eclipse.jgit.events.RepositoryListener;
 
 /**
- * Receives {@link BeforeDfsPackIndexLoadedEvent}s.
+ * Receives
+ * {@link org.eclipse.jgit.internal.storage.dfs.BeforeDfsPackIndexLoadedEvent}s.
  */
 public interface BeforeDfsPackIndexLoadedListener extends RepositoryListener {
 	/**
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsBlockCache.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsBlockCache.java
index 45202b5..4687952 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsBlockCache.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsBlockCache.java
@@ -46,14 +46,19 @@
 
 import java.io.IOException;
 import java.util.concurrent.atomic.AtomicLong;
+import java.util.concurrent.atomic.AtomicReference;
 import java.util.concurrent.atomic.AtomicReferenceArray;
 import java.util.concurrent.locks.ReentrantLock;
+import java.util.stream.LongStream;
 
 import org.eclipse.jgit.annotations.Nullable;
 import org.eclipse.jgit.internal.JGitText;
+import org.eclipse.jgit.internal.storage.pack.PackExt;
 
 /**
- * Caches slices of a {@link BlockBasedFile} in memory for faster read access.
+ * Caches slices of a
+ * {@link org.eclipse.jgit.internal.storage.dfs.BlockBasedFile} in memory for
+ * faster read access.
  * <p>
  * The DfsBlockCache serves as a Java based "buffer cache", loading segments of
  * a BlockBasedFile into the JVM heap prior to use. As JGit often wants to do
@@ -61,8 +66,8 @@
  * these tiny reads into larger block-sized IO operations.
  * <p>
  * Whenever a cache miss occurs, loading is invoked by exactly one thread for
- * the given <code>(DfsPackKey,position)</code> key tuple. This is ensured by an
- * array of locks, with the tuple hashed to a lock instance.
+ * the given <code>(DfsStreamKey,position)</code> key tuple. This is ensured by
+ * an array of locks, with the tuple hashed to a lock instance.
  * <p>
  * Its too expensive during object access to be accurate with a least recently
  * used (LRU) algorithm. Strictly ordering every read is a lot of overhead that
@@ -100,7 +105,7 @@ public final class DfsBlockCache {
 	 *
 	 * @param cfg
 	 *            the new window cache configuration.
-	 * @throws IllegalArgumentException
+	 * @throws java.lang.IllegalArgumentException
 	 *             the cache configuration contains one or more invalid
 	 *             settings, usually too low of a limit.
 	 */
@@ -108,7 +113,11 @@ public static void reconfigure(DfsBlockCacheConfig cfg) {
 		cache = new DfsBlockCache(cfg);
 	}
 
-	/** @return the currently active DfsBlockCache. */
+	/**
+	 * Get the currently active DfsBlockCache.
+	 *
+	 * @return the currently active DfsBlockCache.
+	 */
 	public static DfsBlockCache getInstance() {
 		return cache;
 	}
@@ -143,14 +152,27 @@ public static DfsBlockCache getInstance() {
 	/** As {@link #blockSize} is a power of 2, bits to shift for a / blockSize. */
 	private final int blockSizeShift;
 
-	/** Number of times a block was found in the cache. */
-	private final AtomicLong statHit;
+	/**
+	 * Number of times a block was found in the cache, per pack file extension.
+	 */
+	private final AtomicReference<AtomicLong[]> statHit;
 
-	/** Number of times a block was not found, and had to be loaded. */
-	private final AtomicLong statMiss;
+	/**
+	 * Number of times a block was not found, and had to be loaded, per pack
+	 * file extension.
+	 */
+	private final AtomicReference<AtomicLong[]> statMiss;
 
-	/** Number of blocks evicted due to cache being full. */
-	private volatile long statEvict;
+	/**
+	 * Number of blocks evicted due to cache being full, per pack file
+	 * extension.
+	 */
+	private final AtomicReference<AtomicLong[]> statEvict;
+
+	/**
+	 * Number of bytes currently loaded in the cache, per pack file extension.
+	 */
+	private final AtomicReference<AtomicLong[]> liveBytes;
 
 	/** Protects the clock and its related data. */
 	private final ReentrantLock clockLock;
@@ -158,11 +180,8 @@ public static DfsBlockCache getInstance() {
 	/** Current position of the clock. */
 	private Ref clockHand;
 
-	/** Number of bytes currently loaded in the cache. */
-	private volatile long liveBytes;
-
 	@SuppressWarnings("unchecked")
-	private DfsBlockCache(final DfsBlockCacheConfig cfg) {
+	private DfsBlockCache(DfsBlockCacheConfig cfg) {
 		tableSize = tableSize(cfg);
 		if (tableSize < 1)
 			throw new IllegalArgumentException(JGitText.get().tSizeMustBeGreaterOrEqual1);
@@ -180,56 +199,127 @@ private DfsBlockCache(final DfsBlockCacheConfig cfg) {
 		clockLock = new ReentrantLock(true /* fair */);
 		String none = ""; //$NON-NLS-1$
 		clockHand = new Ref<>(
-				DfsStreamKey.of(new DfsRepositoryDescription(none), none),
+				DfsStreamKey.of(new DfsRepositoryDescription(none), none, null),
 				-1, 0, null);
 		clockHand.next = clockHand;
 
-		statHit = new AtomicLong();
-		statMiss = new AtomicLong();
+		statHit = new AtomicReference<>(newCounters());
+		statMiss = new AtomicReference<>(newCounters());
+		statEvict = new AtomicReference<>(newCounters());
+		liveBytes = new AtomicReference<>(newCounters());
 	}
 
 	boolean shouldCopyThroughCache(long length) {
 		return length <= maxStreamThroughCache;
 	}
 
-	/** @return total number of bytes in the cache. */
-	public long getCurrentSize() {
-		return liveBytes;
+	/**
+	 * Get total number of bytes in the cache, per pack file extension.
+	 *
+	 * @return total number of bytes in the cache, per pack file extension.
+	 */
+	public long[] getCurrentSize() {
+		return getStatVals(liveBytes);
 	}
 
-	/** @return 0..100, defining how full the cache is. */
+	/**
+	 * Get 0..100, defining how full the cache is.
+	 *
+	 * @return 0..100, defining how full the cache is.
+	 */
 	public long getFillPercentage() {
-		return getCurrentSize() * 100 / maxBytes;
+		return LongStream.of(getCurrentSize()).sum() * 100 / maxBytes;
 	}
 
-	/** @return number of requests for items in the cache. */
-	public long getHitCount() {
-		return statHit.get();
+	/**
+	 * Get number of requests for items in the cache, per pack file extension.
+	 *
+	 * @return number of requests for items in the cache, per pack file
+	 *         extension.
+	 */
+	public long[] getHitCount() {
+		return getStatVals(statHit);
 	}
 
-	/** @return number of requests for items not in the cache. */
-	public long getMissCount() {
-		return statMiss.get();
+	/**
+	 * Get number of requests for items not in the cache, per pack file
+	 * extension.
+	 *
+	 * @return number of requests for items not in the cache, per pack file
+	 *         extension.
+	 */
+	public long[] getMissCount() {
+		return getStatVals(statMiss);
 	}
 
-	/** @return total number of requests (hit + miss). */
-	public long getTotalRequestCount() {
-		return getHitCount() + getMissCount();
+	/**
+	 * Get total number of requests (hit + miss), per pack file extension.
+	 *
+	 * @return total number of requests (hit + miss), per pack file extension.
+	 */
+	public long[] getTotalRequestCount() {
+		AtomicLong[] hit = statHit.get();
+		AtomicLong[] miss = statMiss.get();
+		long[] cnt = new long[Math.max(hit.length, miss.length)];
+		for (int i = 0; i < hit.length; i++) {
+			cnt[i] += hit[i].get();
+		}
+		for (int i = 0; i < miss.length; i++) {
+			cnt[i] += miss[i].get();
+		}
+		return cnt;
 	}
 
-	/** @return 0..100, defining number of cache hits. */
-	public long getHitRatio() {
-		long hits = statHit.get();
-		long miss = statMiss.get();
-		long total = hits + miss;
-		if (total == 0)
-			return 0;
-		return hits * 100 / total;
+	/**
+	 * Get hit ratios
+	 *
+	 * @return hit ratios
+	 */
+	public long[] getHitRatio() {
+		AtomicLong[] hit = statHit.get();
+		AtomicLong[] miss = statMiss.get();
+		long[] ratio = new long[Math.max(hit.length, miss.length)];
+		for (int i = 0; i < ratio.length; i++) {
+			if (i >= hit.length) {
+				ratio[i] = 0;
+			} else if (i >= miss.length) {
+				ratio[i] = 100;
+			} else {
+				long hitVal = hit[i].get();
+				long missVal = miss[i].get();
+				long total = hitVal + missVal;
+				ratio[i] = total == 0 ? 0 : hitVal * 100 / total;
+			}
+		}
+		return ratio;
 	}
 
-	/** @return number of evictions performed due to cache being full. */
-	public long getEvictions() {
-		return statEvict;
+	/**
+	 * Get number of evictions performed due to cache being full, per pack file
+	 * extension.
+	 *
+	 * @return number of evictions performed due to cache being full, per pack
+	 *         file extension.
+	 */
+	public long[] getEvictions() {
+		return getStatVals(statEvict);
+	}
+
+	/**
+	 * Quickly check if the cache contains block 0 of the given stream.
+	 * <p>
+	 * This can be useful for sophisticated pre-read algorithms to quickly
+	 * determine if a file is likely already in cache, especially small
+	 * reftables which may be smaller than a typical DFS block size.
+	 *
+	 * @param key
+	 *            the file to check.
+	 * @return true if block 0 (the first block) is in the cache.
+	 */
+	public boolean hasBlock0(DfsStreamKey key) {
+		HashEntry e1 = table.get(slot(key, 0));
+		DfsBlock v = scan(e1, key, 0);
+		return v != null && v.contains(key, 0);
 	}
 
 	private int hash(int packHash, long off) {
@@ -240,7 +330,7 @@ int getBlockSize() {
 		return blockSize;
 	}
 
-	private static int tableSize(final DfsBlockCacheConfig cfg) {
+	private static int tableSize(DfsBlockCacheConfig cfg) {
 		final int wsz = cfg.getBlockSize();
 		final long limit = cfg.getBlockLimit();
 		if (wsz <= 0)
@@ -276,11 +366,11 @@ DfsBlock getOrLoad(BlockBasedFile file, long position, DfsReader ctx,
 		DfsBlock v = scan(e1, key, position);
 		if (v != null && v.contains(key, requestedPosition)) {
 			ctx.stats.blockCacheHit++;
-			statHit.incrementAndGet();
+			getStat(statHit, key).incrementAndGet();
 			return v;
 		}
 
-		reserveSpace(blockSize);
+		reserveSpace(blockSize, key);
 		ReentrantLock regionLock = lockFor(key, position);
 		regionLock.lock();
 		try {
@@ -289,20 +379,20 @@ DfsBlock getOrLoad(BlockBasedFile file, long position, DfsReader ctx,
 				v = scan(e2, key, position);
 				if (v != null) {
 					ctx.stats.blockCacheHit++;
-					statHit.incrementAndGet();
-					creditSpace(blockSize);
+					getStat(statHit, key).incrementAndGet();
+					creditSpace(blockSize, key);
 					return v;
 				}
 			}
 
-			statMiss.incrementAndGet();
+			getStat(statMiss, key).incrementAndGet();
 			boolean credit = true;
 			try {
 				v = file.readOneBlock(requestedPosition, ctx, fileChannel);
 				credit = false;
 			} finally {
 				if (credit)
-					creditSpace(blockSize);
+					creditSpace(blockSize, key);
 			}
 			if (position != v.start) {
 				// The file discovered its blockSize and adjusted.
@@ -332,10 +422,10 @@ DfsBlock getOrLoad(BlockBasedFile file, long position, DfsReader ctx,
 	}
 
 	@SuppressWarnings("unchecked")
-	private void reserveSpace(int reserve) {
+	private void reserveSpace(int reserve, DfsStreamKey key) {
 		clockLock.lock();
 		try {
-			long live = liveBytes + reserve;
+			long live = LongStream.of(getCurrentSize()).sum() + reserve;
 			if (maxBytes < live) {
 				Ref prev = clockHand;
 				Ref hand = clockHand.next;
@@ -358,28 +448,33 @@ private void reserveSpace(int reserve) {
 					dead.next = null;
 					dead.value = null;
 					live -= dead.size;
-					statEvict++;
+					getStat(liveBytes, dead.key).addAndGet(-dead.size);
+					getStat(statEvict, dead.key).incrementAndGet();
 				} while (maxBytes < live);
 				clockHand = prev;
 			}
-			liveBytes = live;
+			getStat(liveBytes, key).addAndGet(reserve);
 		} finally {
 			clockLock.unlock();
 		}
 	}
 
-	private void creditSpace(int credit) {
+	private void creditSpace(int credit, DfsStreamKey key) {
 		clockLock.lock();
-		liveBytes -= credit;
-		clockLock.unlock();
+		try {
+			getStat(liveBytes, key).addAndGet(-credit);
+		} finally {
+			clockLock.unlock();
+		}
 	}
 
 	@SuppressWarnings("unchecked")
 	private void addToClock(Ref ref, int credit) {
 		clockLock.lock();
 		try {
-			if (credit != 0)
-				liveBytes -= credit;
+			if (credit != 0) {
+				getStat(liveBytes, ref.key).addAndGet(-credit);
+			}
 			Ref ptr = clockHand;
 			ref.next = ptr.next;
 			ptr.next = ref;
@@ -404,7 +499,7 @@ <T> Ref<T> put(DfsStreamKey key, long pos, int size, T v) {
 		if (ref != null)
 			return ref;
 
-		reserveSpace(size);
+		reserveSpace(size, key);
 		ReentrantLock regionLock = lockFor(key, pos);
 		regionLock.lock();
 		try {
@@ -412,7 +507,7 @@ <T> Ref<T> put(DfsStreamKey key, long pos, int size, T v) {
 			if (e2 != e1) {
 				ref = scanRef(e2, key, pos);
 				if (ref != null) {
-					creditSpace(size);
+					creditSpace(size, key);
 					return ref;
 				}
 			}
@@ -440,9 +535,9 @@ boolean contains(DfsStreamKey key, long position) {
 	<T> T get(DfsStreamKey key, long position) {
 		T val = (T) scan(table.get(slot(key, position)), key, position);
 		if (val == null)
-			statMiss.incrementAndGet();
+			getStat(statMiss, key).incrementAndGet();
 		else
-			statHit.incrementAndGet();
+			getStat(statHit, key).incrementAndGet();
 		return val;
 	}
 
@@ -454,9 +549,9 @@ private <T> T scan(HashEntry n, DfsStreamKey key, long position) {
 	<T> Ref<T> getRef(DfsStreamKey key) {
 		Ref<T> r = scanRef(table.get(slot(key, 0)), key, 0);
 		if (r != null)
-			statHit.incrementAndGet();
+			getStat(statHit, key).incrementAndGet();
 		else
-			statMiss.incrementAndGet();
+			getStat(statMiss, key).incrementAndGet();
 		return r;
 	}
 
@@ -478,6 +573,43 @@ private ReentrantLock lockFor(DfsStreamKey key, long position) {
 		return loadLocks[(hash(key.hash, position) >>> 1) % loadLocks.length];
 	}
 
+	private static AtomicLong[] newCounters() {
+		AtomicLong[] ret = new AtomicLong[PackExt.values().length];
+		for (int i = 0; i < ret.length; i++) {
+			ret[i] = new AtomicLong();
+		}
+		return ret;
+	}
+
+	private static AtomicLong getStat(AtomicReference<AtomicLong[]> stats,
+			DfsStreamKey key) {
+		int pos = key.packExtPos;
+		while (true) {
+			AtomicLong[] vals = stats.get();
+			if (pos < vals.length) {
+				return vals[pos];
+			}
+			AtomicLong[] expect = vals;
+			vals = new AtomicLong[Math.max(pos + 1, PackExt.values().length)];
+			System.arraycopy(expect, 0, vals, 0, expect.length);
+			for (int i = expect.length; i < vals.length; i++) {
+				vals[i] = new AtomicLong();
+			}
+			if (stats.compareAndSet(expect, vals)) {
+				return vals[pos];
+			}
+		}
+	}
+
+	private static long[] getStatVals(AtomicReference<AtomicLong[]> stat) {
+		AtomicLong[] stats = stat.get();
+		long[] cnt = new long[stats.length];
+		for (int i = 0; i < stats.length; i++) {
+			cnt[i] = stats[i].get();
+		}
+		return cnt;
+	}
+
 	private static HashEntry clean(HashEntry top) {
 		while (top != null && top.ref.next == null)
 			top = top.next;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsBlockCacheConfig.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsBlockCacheConfig.java
index feadedb..dd7cb89 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsBlockCacheConfig.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsBlockCacheConfig.java
@@ -55,7 +55,10 @@
 import org.eclipse.jgit.internal.JGitText;
 import org.eclipse.jgit.lib.Config;
 
-/** Configuration parameters for {@link DfsBlockCache}. */
+/**
+ * Configuration parameters for
+ * {@link org.eclipse.jgit.internal.storage.dfs.DfsBlockCache}.
+ */
 public class DfsBlockCacheConfig {
 	/** 1024 (number of bytes in one kibibyte/kilobyte) */
 	public static final int KB = 1024;
@@ -68,7 +71,9 @@ public class DfsBlockCacheConfig {
 	private double streamRatio;
 	private int concurrencyLevel;
 
-	/** Create a default configuration. */
+	/**
+	 * Create a default configuration.
+	 */
 	public DfsBlockCacheConfig() {
 		setBlockLimit(32 * MB);
 		setBlockSize(64 * KB);
@@ -77,6 +82,9 @@ public DfsBlockCacheConfig() {
 	}
 
 	/**
+	 * Get maximum number bytes of heap memory to dedicate to caching pack file
+	 * data.
+	 *
 	 * @return maximum number bytes of heap memory to dedicate to caching pack
 	 *         file data. <b>Default is 32 MB.</b>
 	 */
@@ -85,17 +93,33 @@ public long getBlockLimit() {
 	}
 
 	/**
+	 * Set maximum number bytes of heap memory to dedicate to caching pack file
+	 * data.
+	 * <p>
+	 * It is strongly recommended to set the block limit to be an integer multiple
+	 * of the block size. This constraint is not enforced by this method (since
+	 * it may be called before {@link #setBlockSize(int)}), but it is enforced by
+	 * {@link #fromConfig(Config)}.
+	 *
 	 * @param newLimit
 	 *            maximum number bytes of heap memory to dedicate to caching
-	 *            pack file data.
+	 *            pack file data; must be positive.
 	 * @return {@code this}
 	 */
-	public DfsBlockCacheConfig setBlockLimit(final long newLimit) {
+	public DfsBlockCacheConfig setBlockLimit(long newLimit) {
+		if (newLimit <= 0) {
+			throw new IllegalArgumentException(MessageFormat.format(
+					JGitText.get().blockLimitNotPositive,
+					Long.valueOf(newLimit)));
+		}
 		blockLimit = newLimit;
 		return this;
 	}
 
 	/**
+	 * Get size in bytes of a single window mapped or read in from the pack
+	 * file.
+	 *
 	 * @return size in bytes of a single window mapped or read in from the pack
 	 *         file. <b>Default is 64 KB.</b>
 	 */
@@ -104,12 +128,14 @@ public int getBlockSize() {
 	}
 
 	/**
+	 * Set size in bytes of a single window read in from the pack file.
+	 *
 	 * @param newSize
 	 *            size in bytes of a single window read in from the pack file.
 	 *            The value must be a power of 2.
 	 * @return {@code this}
 	 */
-	public DfsBlockCacheConfig setBlockSize(final int newSize) {
+	public DfsBlockCacheConfig setBlockSize(int newSize) {
 		int size = Math.max(512, newSize);
 		if ((size & (size - 1)) != 0) {
 			throw new IllegalArgumentException(
@@ -120,6 +146,8 @@ public DfsBlockCacheConfig setBlockSize(final int newSize) {
 	}
 
 	/**
+	 * Get the estimated number of threads concurrently accessing the cache.
+	 *
 	 * @return the estimated number of threads concurrently accessing the cache.
 	 *         <b>Default is 32.</b>
 	 */
@@ -128,6 +156,8 @@ public int getConcurrencyLevel() {
 	}
 
 	/**
+	 * Set the estimated number of threads concurrently accessing the cache.
+	 *
 	 * @param newConcurrencyLevel
 	 *            the estimated number of threads concurrently accessing the
 	 *            cache.
@@ -140,6 +170,9 @@ public DfsBlockCacheConfig setConcurrencyLevel(
 	}
 
 	/**
+	 * Get highest percentage of {@link #getBlockLimit()} a single pack can
+	 * occupy while being copied by the pack reuse strategy.
+	 *
 	 * @return highest percentage of {@link #getBlockLimit()} a single pack can
 	 *         occupy while being copied by the pack reuse strategy. <b>Default
 	 *         is 0.30, or 30%</b>.
@@ -149,6 +182,8 @@ public double getStreamRatio() {
 	}
 
 	/**
+	 * Set percentage of cache to occupy with a copied pack.
+	 *
 	 * @param ratio
 	 *            percentage of cache to occupy with a copied pack.
 	 * @return {@code this}
@@ -163,23 +198,34 @@ public DfsBlockCacheConfig setStreamRatio(double ratio) {
 	 * <p>
 	 * If a property is not defined in the configuration, then it is left
 	 * unmodified.
+	 * <p>
+	 * Enforces certain constraints on the combination of settings in the config,
+	 * for example that the block limit is a multiple of the block size.
 	 *
 	 * @param rc
 	 *            configuration to read properties from.
 	 * @return {@code this}
 	 */
-	public DfsBlockCacheConfig fromConfig(final Config rc) {
-		setBlockLimit(rc.getLong(
+	public DfsBlockCacheConfig fromConfig(Config rc) {
+		long cfgBlockLimit = rc.getLong(
 				CONFIG_CORE_SECTION,
 				CONFIG_DFS_SECTION,
 				CONFIG_KEY_BLOCK_LIMIT,
-				getBlockLimit()));
-
-		setBlockSize(rc.getInt(
+				getBlockLimit());
+		int cfgBlockSize = rc.getInt(
 				CONFIG_CORE_SECTION,
 				CONFIG_DFS_SECTION,
 				CONFIG_KEY_BLOCK_SIZE,
-				getBlockSize()));
+				getBlockSize());
+		if (cfgBlockLimit % cfgBlockSize != 0) {
+			throw new IllegalArgumentException(MessageFormat.format(
+					JGitText.get().blockLimitNotMultipleOfBlockSize,
+					Long.valueOf(cfgBlockLimit),
+					Long.valueOf(cfgBlockSize)));
+		}
+
+		setBlockLimit(cfgBlockLimit);
+		setBlockSize(cfgBlockSize);
 
 		setConcurrencyLevel(rc.getInt(
 				CONFIG_CORE_SECTION,
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsCachedPack.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsCachedPack.java
index a5308f6..3605236e 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsCachedPack.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsCachedPack.java
@@ -50,7 +50,9 @@
 import org.eclipse.jgit.internal.storage.pack.PackOutputStream;
 import org.eclipse.jgit.internal.storage.pack.StoredObjectRepresentation;
 
-/** A DfsPackFile available for reuse as-is. */
+/**
+ * A DfsPackFile available for reuse as-is.
+ */
 public class DfsCachedPack extends CachedPack {
 	private final DfsPackFile pack;
 
@@ -58,21 +60,28 @@ public class DfsCachedPack extends CachedPack {
 		this.pack = pack;
 	}
 
-	/** @return the description of the pack. */
+	/**
+	 * Get the description of the pack.
+	 *
+	 * @return the description of the pack.
+	 */
 	public DfsPackDescription getPackDescription() {
 		return pack.getPackDescription();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public long getObjectCount() throws IOException {
 		return getPackDescription().getObjectCount();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public long getDeltaCount() throws IOException {
 		return getPackDescription().getDeltaCount();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public boolean hasObject(ObjectToPack obj, StoredObjectRepresentation rep) {
 		return ((DfsObjectRepresentation) rep).pack == pack;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsConfig.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsConfig.java
index 696595c..3e2963a 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsConfig.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsConfig.java
@@ -49,11 +49,13 @@
 import org.eclipse.jgit.lib.StoredConfig;
 
 final class DfsConfig extends StoredConfig {
+	/** {@inheritDoc} */
 	@Override
 	public void load() throws IOException, ConfigInvalidException {
 		clear();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void save() throws IOException {
 		// TODO actually store this configuration.
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsFsck.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsFsck.java
index 75eade2..985393c 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsFsck.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsFsck.java
@@ -55,19 +55,24 @@
 import org.eclipse.jgit.internal.fsck.FsckError;
 import org.eclipse.jgit.internal.fsck.FsckError.CorruptIndex;
 import org.eclipse.jgit.internal.fsck.FsckPackParser;
+import org.eclipse.jgit.internal.storage.dfs.DfsObjDatabase.PackSource;
 import org.eclipse.jgit.lib.Constants;
 import org.eclipse.jgit.lib.NullProgressMonitor;
 import org.eclipse.jgit.lib.ObjectChecker;
+import org.eclipse.jgit.lib.ObjectId;
 import org.eclipse.jgit.lib.ProgressMonitor;
 import org.eclipse.jgit.lib.Ref;
 import org.eclipse.jgit.revwalk.ObjectWalk;
 import org.eclipse.jgit.revwalk.RevObject;
 
-/** Verify the validity and connectivity of a DFS repository. */
+/**
+ * Verify the validity and connectivity of a DFS repository.
+ */
 public class DfsFsck {
 	private final DfsRepository repo;
 	private final DfsObjDatabase objdb;
 	private ObjectChecker objChecker = new ObjectChecker();
+	private boolean connectivityOnly;
 
 	/**
 	 * Initialize DFS fsck.
@@ -87,7 +92,7 @@ public DfsFsck(DfsRepository repository) {
 	 * @param pm
 	 *            callback to provide progress feedback during the check.
 	 * @return all errors about the repository.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             if encounters IO errors during the process.
 	 */
 	public FsckError check(ProgressMonitor pm) throws IOException {
@@ -96,7 +101,9 @@ public FsckError check(ProgressMonitor pm) throws IOException {
 		}
 
 		FsckError errors = new FsckError();
-		checkPacks(pm, errors);
+		if (!connectivityOnly) {
+			checkPacks(pm, errors);
+		}
 		checkConnectivity(pm, errors);
 		return errors;
 	}
@@ -106,6 +113,10 @@ private void checkPacks(ProgressMonitor pm, FsckError errors)
 		try (DfsReader ctx = objdb.newReader()) {
 			for (DfsPackFile pack : objdb.getPacks()) {
 				DfsPackDescription packDesc = pack.getPackDescription();
+				if (packDesc.getPackSource()
+						== PackSource.UNREACHABLE_GARBAGE) {
+					continue;
+				}
 				try (ReadableChannel rc = objdb.openFile(packDesc, PACK)) {
 					verifyPack(pm, errors, ctx, pack, rc);
 				} catch (MissingObjectException e) {
@@ -136,19 +147,24 @@ private void checkConnectivity(ProgressMonitor pm, FsckError errors)
 		pm.beginTask(JGitText.get().countingObjects, ProgressMonitor.UNKNOWN);
 		try (ObjectWalk ow = new ObjectWalk(repo)) {
 			for (Ref r : repo.getAllRefs().values()) {
+				ObjectId objectId = r.getObjectId();
+				if (objectId == null) {
+					// skip unborn branch
+					continue;
+				}
 				RevObject tip;
 				try {
-					tip = ow.parseAny(r.getObjectId());
+					tip = ow.parseAny(objectId);
 					if (r.getLeaf().getName().startsWith(Constants.R_HEADS)
 							&& tip.getType() != Constants.OBJ_COMMIT) {
 						// heads should only point to a commit object
 						errors.getNonCommitHeads().add(r.getLeaf().getName());
 					}
+					ow.markStart(tip);
 				} catch (MissingObjectException e) {
 					errors.getMissingObjects().add(e.getObjectId());
 					continue;
 				}
-				ow.markStart(tip);
 			}
 			try {
 				ow.checkConnectivity();
@@ -169,4 +185,17 @@ private void checkConnectivity(ProgressMonitor pm, FsckError errors)
 	public void setObjectChecker(ObjectChecker objChecker) {
 		this.objChecker = objChecker;
 	}
+
+	/**
+	 * Whether fsck should bypass object validity and integrity checks and only
+	 * check connectivity.
+	 *
+	 * @param connectivityOnly
+	 *            whether fsck should bypass object validity and integrity
+	 *            checks and only check connectivity. The default is
+	 *            {@code false}, meaning to run all checks.
+	 */
+	public void setConnectivityOnly(boolean connectivityOnly) {
+		this.connectivityOnly = connectivityOnly;
+	}
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsGarbageCollector.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsGarbageCollector.java
index 304a931..ca11fb9 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsGarbageCollector.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsGarbageCollector.java
@@ -93,7 +93,9 @@
 import org.eclipse.jgit.util.SystemReader;
 import org.eclipse.jgit.util.io.CountingOutputStream;
 
-/** Repack and garbage collect a repository. */
+/**
+ * Repack and garbage collect a repository.
+ */
 public class DfsGarbageCollector {
 	private final DfsRepository repo;
 	private final RefDatabase refdb;
@@ -108,6 +110,7 @@ public class DfsGarbageCollector {
 	private PackConfig packConfig;
 	private ReftableConfig reftableConfig;
 	private boolean convertToReftable = true;
+	private boolean includeDeletes;
 	private long reftableInitialMinUpdateIndex = 1;
 	private long reftableInitialMaxUpdateIndex = 1;
 
@@ -146,12 +149,18 @@ public DfsGarbageCollector(DfsRepository repository) {
 		packConfig.setIndexVersion(2);
 	}
 
-	/** @return configuration used to generate the new pack file. */
+	/**
+	 * Get configuration used to generate the new pack file.
+	 *
+	 * @return configuration used to generate the new pack file.
+	 */
 	public PackConfig getPackConfig() {
 		return packConfig;
 	}
 
 	/**
+	 * Set the new configuration to use when creating the pack file.
+	 *
 	 * @param newConfig
 	 *            the new configuration to use when creating the pack file.
 	 * @return {@code this}
@@ -162,6 +171,8 @@ public DfsGarbageCollector setPackConfig(PackConfig newConfig) {
 	}
 
 	/**
+	 * Set configuration to write a reftable.
+	 *
 	 * @param cfg
 	 *            configuration to write a reftable. Reftable writing is
 	 *            disabled (default) when {@code cfg} is {@code null}.
@@ -173,11 +184,14 @@ public DfsGarbageCollector setReftableConfig(ReftableConfig cfg) {
 	}
 
 	/**
+	 * Whether the garbage collector should convert references to reftable.
+	 *
 	 * @param convert
-	 *            if true, {@link #setReftableConfig(ReftableConfig)} has been
-	 *            set non-null, and a GC reftable doesn't yet exist, the garbage
-	 *            collector will make one by scanning the existing references,
-	 *            and writing a new reftable. Default is {@code true}.
+	 *            if {@code true}, {@link #setReftableConfig(ReftableConfig)}
+	 *            has been set non-null, and a GC reftable doesn't yet exist,
+	 *            the garbage collector will make one by scanning the existing
+	 *            references, and writing a new reftable. Default is
+	 *            {@code true}.
 	 * @return {@code this}
 	 */
 	public DfsGarbageCollector setConvertToReftable(boolean convert) {
@@ -186,13 +200,29 @@ public DfsGarbageCollector setConvertToReftable(boolean convert) {
 	}
 
 	/**
+	 * Whether the garbage collector will include tombstones for deleted
+	 * references in the reftable.
+	 *
+	 * @param include
+	 *            if {@code true}, the garbage collector will include tombstones
+	 *            for deleted references in the reftable. Default is
+	 *            {@code false}.
+	 * @return {@code this}
+	 */
+	public DfsGarbageCollector setIncludeDeletes(boolean include) {
+		includeDeletes = include;
+		return this;
+	}
+
+	/**
 	 * Set minUpdateIndex for the initial reftable created during conversion.
 	 *
 	 * @param u
 	 *            minUpdateIndex for the initial reftable created by scanning
-	 *            {@link DfsRefDatabase#getRefs(String)}. Ignored unless caller
-	 *            has also set {@link #setReftableConfig(ReftableConfig)}.
-	 *            Defaults to {@code 1}. Must be {@code u >= 0}.
+	 *            {@link org.eclipse.jgit.internal.storage.dfs.DfsRefDatabase#getRefs(String)}.
+	 *            Ignored unless caller has also set
+	 *            {@link #setReftableConfig(ReftableConfig)}. Defaults to
+	 *            {@code 1}. Must be {@code u >= 0}.
 	 * @return {@code this}
 	 */
 	public DfsGarbageCollector setReftableInitialMinUpdateIndex(long u) {
@@ -205,9 +235,10 @@ public DfsGarbageCollector setReftableInitialMinUpdateIndex(long u) {
 	 *
 	 * @param u
 	 *            maxUpdateIndex for the initial reftable created by scanning
-	 *            {@link DfsRefDatabase#getRefs(String)}. Ignored unless caller
-	 *            has also set {@link #setReftableConfig(ReftableConfig)}.
-	 *            Defaults to {@code 1}. Must be {@code u >= 0}.
+	 *            {@link org.eclipse.jgit.internal.storage.dfs.DfsRefDatabase#getRefs(String)}.
+	 *            Ignored unless caller has also set
+	 *            {@link #setReftableConfig(ReftableConfig)}. Defaults to
+	 *            {@code 1}. Must be {@code u >= 0}.
 	 * @return {@code this}
 	 */
 	public DfsGarbageCollector setReftableInitialMaxUpdateIndex(long u) {
@@ -215,7 +246,12 @@ public DfsGarbageCollector setReftableInitialMaxUpdateIndex(long u) {
 		return this;
 	}
 
-	/** @return garbage packs smaller than this size will be repacked. */
+	/**
+	 * Get coalesce garbage limit
+	 *
+	 * @return coalesce garbage limit, packs smaller than this size will be
+	 *         repacked.
+	 */
 	public long getCoalesceGarbageLimit() {
 		return coalesceGarbageLimit;
 	}
@@ -232,7 +268,8 @@ public long getCoalesceGarbageLimit() {
 	 * reading and copying the objects.
 	 * <p>
 	 * If limit is set to 0 the UNREACHABLE_GARBAGE coalesce is disabled.<br>
-	 * If limit is set to {@link Long#MAX_VALUE}, everything is coalesced.
+	 * If limit is set to {@link java.lang.Long#MAX_VALUE}, everything is
+	 * coalesced.
 	 * <p>
 	 * Keeping unreachable garbage prevents race conditions with repository
 	 * changes that may suddenly need an object whose only copy was stored in
@@ -248,9 +285,11 @@ public DfsGarbageCollector setCoalesceGarbageLimit(long limit) {
 	}
 
 	/**
+	 * Get time to live for garbage packs.
+	 *
 	 * @return garbage packs older than this limit (in milliseconds) will be
 	 *         pruned as part of the garbage collection process if the value is
-	 *         > 0, otherwise garbage packs are retained.
+	 *         &gt; 0, otherwise garbage packs are retained.
 	 */
 	public long getGarbageTtlMillis() {
 		return garbageTtlMillis;
@@ -288,7 +327,7 @@ public DfsGarbageCollector setGarbageTtl(long ttl, TimeUnit unit) {
 	 * @return true if the repack was successful without race conditions. False
 	 *         if a race condition was detected and the repack should be run
 	 *         again later.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             a new pack cannot be created.
 	 */
 	public boolean pack(ProgressMonitor pm) throws IOException {
@@ -364,7 +403,7 @@ public boolean pack(ProgressMonitor pm) throws IOException {
 	}
 
 	private Collection<Ref> getAllRefs() throws IOException {
-		Collection<Ref> refs = refdb.getRefs(RefDatabase.ALL).values();
+		Collection<Ref> refs = refdb.getRefs();
 		List<Ref> addl = refdb.getAdditionalRefs();
 		if (!addl.isEmpty()) {
 			List<Ref> all = new ArrayList<>(refs.size() + addl.size());
@@ -476,17 +515,31 @@ private static long dayStartInMillis(long timeInMillis) {
 		return cal.getTimeInMillis();
 	}
 
-	/** @return all of the source packs that fed into this compaction. */
+	/**
+	 * Get all of the source packs that fed into this compaction.
+	 *
+	 * @return all of the source packs that fed into this compaction.
+	 */
 	public Set<DfsPackDescription> getSourcePacks() {
 		return toPrune();
 	}
 
-	/** @return new packs created by this compaction. */
+	/**
+	 * Get new packs created by this compaction.
+	 *
+	 * @return new packs created by this compaction.
+	 */
 	public List<DfsPackDescription> getNewPacks() {
 		return newPackDesc;
 	}
 
-	/** @return statistics corresponding to the {@link #getNewPacks()}. */
+	/**
+	 * Get statistics corresponding to the {@link #getNewPacks()}.
+	 * <p>
+	 * The elements can be null if the stat is not available for the pack file.
+	 *
+	 * @return statistics corresponding to the {@link #getNewPacks()}.
+	 */
 	public List<PackStatistics> getNewPackStatistics() {
 		return newPackStats;
 	}
@@ -637,7 +690,6 @@ private DfsPackDescription writePack(PackSource source, PackWriter pw,
 			ProgressMonitor pm, long estimatedPackSize) throws IOException {
 		DfsPackDescription pack = repo.getObjectDatabase().newPack(source,
 				estimatedPackSize);
-		newPackDesc.add(pack);
 
 		if (source == GC && reftableConfig != null) {
 			writeReftable(pack);
@@ -671,6 +723,7 @@ private DfsPackDescription writePack(PackSource source, PackWriter pw,
 		PackStatistics stats = pw.getStatistics();
 		pack.setPackStats(stats);
 		pack.setLastModified(startTimeMillis);
+		newPackDesc.add(pack);
 		newPackStats.add(stats);
 		newPackObj.add(pw.getObjectSet());
 		return pack;
@@ -680,6 +733,7 @@ private void writeReftable() throws IOException {
 		if (reftableConfig != null) {
 			DfsPackDescription pack = objdb.newPack(GC);
 			newPackDesc.add(pack);
+			newPackStats.add(null);
 			writeReftable(pack);
 		}
 	}
@@ -693,7 +747,7 @@ private void writeReftable(DfsPackDescription pack) throws IOException {
 		try (ReftableStack stack = ReftableStack.open(ctx, reftablesBefore)) {
 			ReftableCompactor compact = new ReftableCompactor();
 			compact.addAll(stack.readers());
-			compact.setIncludeDeletes(false);
+			compact.setIncludeDeletes(includeDeletes);
 			compactReftable(pack, compact);
 		}
 	}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsInserter.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsInserter.java
index 19e8652..0d9e2c1 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsInserter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsInserter.java
@@ -68,6 +68,7 @@
 import java.util.zip.Inflater;
 import java.util.zip.InflaterInputStream;
 
+import org.eclipse.jgit.annotations.Nullable;
 import org.eclipse.jgit.errors.CorruptObjectException;
 import org.eclipse.jgit.errors.IncorrectObjectTypeException;
 import org.eclipse.jgit.errors.LargeObjectException;
@@ -92,7 +93,9 @@
 import org.eclipse.jgit.util.io.CountingOutputStream;
 import org.eclipse.jgit.util.sha1.SHA1;
 
-/** Inserts objects into the DFS. */
+/**
+ * Inserts objects into the DFS.
+ */
 public class DfsInserter extends ObjectInserter {
 	/** Always produce version 2 indexes, to get CRC data. */
 	private static final int INDEX_VERSION = 2;
@@ -121,9 +124,12 @@ protected DfsInserter(DfsObjDatabase db) {
 	}
 
 	/**
+	 * Check existence
+	 *
 	 * @param check
-	 *            if false, will write out possibly-duplicate objects without
-	 *            first checking whether they exist in the repo; default is true.
+	 *            if {@code false}, will write out possibly-duplicate objects
+	 *            without first checking whether they exist in the repo; default
+	 *            is true.
 	 */
 	public void checkExisting(boolean check) {
 		checkExisting = check;
@@ -133,16 +139,19 @@ void setCompressionLevel(int compression) {
 		this.compression = compression;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public DfsPackParser newPackParser(InputStream in) throws IOException {
 		return new DfsPackParser(db, this, in);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public ObjectReader newReader() {
 		return new Reader();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public ObjectId insert(int type, byte[] data, int off, int len)
 			throws IOException {
@@ -159,6 +168,7 @@ public ObjectId insert(int type, byte[] data, int off, int len)
 		return endObject(id, offset);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public ObjectId insert(int type, long len, InputStream in)
 			throws IOException {
@@ -201,6 +211,7 @@ public ObjectId insert(int type, long len, InputStream in)
 		return buf;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void flush() throws IOException {
 		if (packDsc == null)
@@ -228,6 +239,7 @@ public void flush() throws IOException {
 		clear();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void close() {
 		if (packOut != null) {
@@ -298,6 +310,15 @@ private void sortObjectsById() {
 		Collections.sort(objectList);
 	}
 
+	@Nullable
+	private TemporaryBuffer.Heap maybeGetTemporaryBuffer(
+			List<PackedObjectInfo> list) {
+		if (list.size() <= 58000) {
+			return new TemporaryBuffer.Heap(2 << 20);
+		}
+		return null;
+	}
+
 	PackIndex writePackIndex(DfsPackDescription pack, byte[] packHash,
 			List<PackedObjectInfo> list) throws IOException {
 		pack.setIndexVersion(INDEX_VERSION);
@@ -306,27 +327,20 @@ PackIndex writePackIndex(DfsPackDescription pack, byte[] packHash,
 		// If there are less than 58,000 objects, the entire index fits in under
 		// 2 MiB. Callers will probably need the index immediately, so buffer
 		// the index in process and load from the buffer.
-		TemporaryBuffer.Heap buf = null;
 		PackIndex packIndex = null;
-		if (list.size() <= 58000) {
-			buf = new TemporaryBuffer.Heap(2 << 20);
-			index(buf, packHash, list);
-			packIndex = PackIndex.read(buf.openInputStream());
-		}
-
-		try (DfsOutputStream os = db.writeFile(pack, INDEX)) {
-			CountingOutputStream cnt = new CountingOutputStream(os);
-			if (buf != null)
+		try (TemporaryBuffer.Heap buf = maybeGetTemporaryBuffer(list);
+				DfsOutputStream os = db.writeFile(pack, INDEX);
+				CountingOutputStream cnt = new CountingOutputStream(os)) {
+			if (buf != null) {
+				index(buf, packHash, list);
+				packIndex = PackIndex.read(buf.openInputStream());
 				buf.writeTo(cnt, null);
-			else
+			} else {
 				index(cnt, packHash, list);
+			}
 			pack.addFileExt(INDEX);
 			pack.setBlockSize(INDEX, os.blockSize());
 			pack.setFileSize(INDEX, cnt.getCount());
-		} finally {
-			if (buf != null) {
-				buf.close();
-			}
 		}
 		return packIndex;
 	}
@@ -392,7 +406,7 @@ private int encodeTypeSize(int type, long rawLength) {
 		}
 
 		@Override
-		public void write(final int b) throws IOException {
+		public void write(int b) throws IOException {
 			hdrBuf[0] = (byte) b;
 			write(hdrBuf, 0, 1);
 		}
@@ -605,17 +619,22 @@ public ObjectLoader open(AnyObjectId objectId, int typeHint)
 			try {
 				return packOut.inflate(ctx, zpos, sz);
 			} catch (DataFormatException dfe) {
-				CorruptObjectException coe = new CorruptObjectException(
+				throw new CorruptObjectException(
 						MessageFormat.format(
 								JGitText.get().objectAtHasBadZlibStream,
 								Long.valueOf(obj.getOffset()),
-								packDsc.getFileName(PackExt.PACK)));
-				coe.initCause(dfe);
-				throw coe;
+								packDsc.getFileName(PackExt.PACK)),
+						dfe);
 			}
 		}
 
 		@Override
+		public boolean has(AnyObjectId objectId) throws IOException {
+			return (objectMap != null && objectMap.contains(objectId))
+					|| ctx.has(objectId);
+		}
+
+		@Override
 		public Set<ObjectId> getShallowCommits() throws IOException {
 			return ctx.getShallowCommits();
 		}
@@ -650,6 +669,7 @@ private class StreamLoader extends ObjectLoader {
 
 		@Override
 		public ObjectStream openStream() throws IOException {
+			@SuppressWarnings("resource") // Explicitly closed below
 			final DfsReader ctx = db.newReader();
 			if (srcPack != packKey) {
 				try {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsObjDatabase.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsObjDatabase.java
index 9439822..ca54ee2 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsObjDatabase.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsObjDatabase.java
@@ -52,6 +52,7 @@
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 import java.util.concurrent.atomic.AtomicReference;
 
 import org.eclipse.jgit.internal.storage.pack.PackExt;
@@ -60,7 +61,11 @@
 import org.eclipse.jgit.lib.ObjectInserter;
 import org.eclipse.jgit.lib.ObjectReader;
 
-/** Manages objects stored in {@link DfsPackFile} on a storage system. */
+/**
+ * Manages objects stored in
+ * {@link org.eclipse.jgit.internal.storage.dfs.DfsPackFile} on a storage
+ * system.
+ */
 public abstract class DfsObjDatabase extends ObjectDatabase {
 	private static final PackList NO_PACKS = new PackList(
 			new DfsPackFile[0],
@@ -156,7 +161,6 @@ public static enum PackSource {
 	 *
 	 * @param repository
 	 *            repository owning this object database.
-	 *
 	 * @param options
 	 *            how readers should access the object database.
 	 */
@@ -167,16 +171,22 @@ protected DfsObjDatabase(DfsRepository repository,
 		this.readerOptions = options;
 	}
 
-	/** @return configured reader options, such as read-ahead. */
+	/**
+	 * Get configured reader options, such as read-ahead.
+	 *
+	 * @return configured reader options, such as read-ahead.
+	 */
 	public DfsReaderOptions getReaderOptions() {
 		return readerOptions;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public DfsReader newReader() {
 		return new DfsReader(this);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public ObjectInserter newInserter() {
 		return new DfsInserter(this);
@@ -187,7 +197,7 @@ public ObjectInserter newInserter() {
 	 *
 	 * @return list of available packs. The returned array is shared with the
 	 *         implementation and must not be modified by the caller.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the pack list cannot be initialized.
 	 */
 	public DfsPackFile[] getPacks() throws IOException {
@@ -199,7 +209,7 @@ public ObjectInserter newInserter() {
 	 *
 	 * @return list of available reftables. The returned array is shared with
 	 *         the implementation and must not be modified by the caller.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the pack list cannot be initialized.
 	 */
 	public DfsReftable[] getReftables() throws IOException {
@@ -212,14 +222,18 @@ public ObjectInserter newInserter() {
 	 * @return list of available packs, with some additional metadata. The
 	 *         returned array is shared with the implementation and must not be
 	 *         modified by the caller.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the pack list cannot be initialized.
 	 */
 	public PackList getPackList() throws IOException {
 		return scanPacks(NO_PACKS);
 	}
 
-	/** @return repository owning this object database. */
+	/**
+	 * Get repository owning this object database.
+	 *
+	 * @return repository owning this object database.
+	 */
 	protected DfsRepository getRepository() {
 		return repository;
 	}
@@ -266,7 +280,7 @@ public PackList getCurrentPackList() {
 	 * @param avoidUnreachableObjects
 	 *            if true, ignore objects that are unreachable.
 	 * @return true if the specified object is stored in this database.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the object store cannot be accessed.
 	 */
 	public boolean has(AnyObjectId objectId, boolean avoidUnreachableObjects)
@@ -284,7 +298,7 @@ public boolean has(AnyObjectId objectId, boolean avoidUnreachableObjects)
 	 *            where the pack stream is created.
 	 * @return a unique name for the pack file. Must not collide with any other
 	 *         pack file name in the same DFS.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             a new unique pack description cannot be generated.
 	 */
 	protected abstract DfsPackDescription newPack(PackSource source)
@@ -298,7 +312,8 @@ protected abstract DfsPackDescription newPack(PackSource source)
 	 * {@code newPack(source).setEstimatedPackSize(estimatedPackSize)}. But the
 	 * clients can override this method to use the given
 	 * {@code estomatedPackSize} value more efficiently in the process of
-	 * creating a new {@link DfsPackDescription} object.
+	 * creating a new
+	 * {@link org.eclipse.jgit.internal.storage.dfs.DfsPackDescription} object.
 	 *
 	 * @param source
 	 *            where the pack stream is created.
@@ -306,7 +321,7 @@ protected abstract DfsPackDescription newPack(PackSource source)
 	 *            the estimated size of the pack.
 	 * @return a unique name for the pack file. Must not collide with any other
 	 *         pack file name in the same DFS.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             a new unique pack description cannot be generated.
 	 */
 	protected DfsPackDescription newPack(PackSource source,
@@ -337,7 +352,7 @@ protected DfsPackDescription newPack(PackSource source,
 	 *            description of the new packs.
 	 * @param replaces
 	 *            if not null, list of packs to remove.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the packs cannot be committed. On failure a rollback must
 	 *             also be attempted by the caller.
 	 */
@@ -351,12 +366,11 @@ protected void commitPack(Collection<DfsPackDescription> desc,
 	 * Implementation of pack commit.
 	 *
 	 * @see #commitPack(Collection, Collection)
-	 *
 	 * @param desc
 	 *            description of the new packs.
 	 * @param replaces
 	 *            if not null, list of packs to remove.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the packs cannot be committed.
 	 */
 	protected abstract void commitPackImpl(Collection<DfsPackDescription> desc,
@@ -387,7 +401,7 @@ protected abstract void commitPackImpl(Collection<DfsPackDescription> desc,
 	 * DfsPackDescription objects.
 	 *
 	 * @return available packs. May be empty if there are no packs.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the packs cannot be listed and the object database is not
 	 *             functional to the caller.
 	 */
@@ -404,9 +418,9 @@ protected abstract void commitPackImpl(Collection<DfsPackDescription> desc,
 	 * @param ext
 	 *            file extension that will be read i.e "pack" or "idx".
 	 * @return channel to read the file.
-	 * @throws FileNotFoundException
+	 * @throws java.io.FileNotFoundException
 	 *             the file does not exist.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the file cannot be opened.
 	 */
 	protected abstract ReadableChannel openFile(
@@ -423,7 +437,7 @@ protected abstract ReadableChannel openFile(
 	 * @param ext
 	 *            file extension that will be written i.e "pack" or "idx".
 	 * @return channel to write the file.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the file cannot be opened.
 	 */
 	protected abstract DfsOutputStream writeFile(
@@ -445,8 +459,9 @@ void addPack(DfsPackFile newPack) throws IOException {
 				// add, as the pack was already committed via commitPack().
 				// If this is the case return without changing the list.
 				for (DfsPackFile p : o.packs) {
-					if (p == newPack)
+					if (p.key.equals(newPack.key)) {
 						return;
+					}
 				}
 			}
 
@@ -457,7 +472,32 @@ void addPack(DfsPackFile newPack) throws IOException {
 		} while (!packList.compareAndSet(o, n));
 	}
 
-	PackList scanPacks(final PackList original) throws IOException {
+	void addReftable(DfsPackDescription add, Set<DfsPackDescription> remove)
+			throws IOException {
+		PackList o, n;
+		do {
+			o = packList.get();
+			if (o == NO_PACKS) {
+				o = scanPacks(o);
+				for (DfsReftable t : o.reftables) {
+					if (t.getPackDescription().equals(add)) {
+						return;
+					}
+				}
+			}
+
+			List<DfsReftable> tables = new ArrayList<>(1 + o.reftables.length);
+			for (DfsReftable t : o.reftables) {
+				if (!remove.contains(t.getPackDescription())) {
+					tables.add(t);
+				}
+			}
+			tables.add(new DfsReftable(add));
+			n = new PackListImpl(o.packs, tables.toArray(new DfsReftable[0]));
+		} while (!packList.compareAndSet(o, n));
+	}
+
+	PackList scanPacks(PackList original) throws IOException {
 		PackList o, n;
 		synchronized (packList) {
 			do {
@@ -506,7 +546,7 @@ private PackList scanPacksImpl(PackList old) throws IOException {
 			}
 		}
 
-		if (newPacks.isEmpty())
+		if (newPacks.isEmpty() && newReftables.isEmpty())
 			return new PackListImpl(NO_PACKS.packs, NO_PACKS.reftables);
 		if (!foundNew) {
 			old.clearDirty();
@@ -538,7 +578,11 @@ private static Map<DfsPackDescription, DfsReftable> reftableMap(PackList old) {
 		return forReuse;
 	}
 
-	/** @return comparator to sort {@link DfsReftable} by priority. */
+	/**
+	 * Get comparator to sort {@link DfsReftable} by priority.
+	 *
+	 * @return comparator to sort {@link DfsReftable} by priority.
+	 */
 	protected Comparator<DfsReftable> reftableComparator() {
 		return (fa, fb) -> {
 			DfsPackDescription a = fa.getPackDescription();
@@ -566,11 +610,14 @@ static int category(DfsPackDescription d) {
 		return s != null ? s.category : 0;
 	}
 
-	/** Clears the cached list of packs, forcing them to be scanned again. */
+	/**
+	 * Clears the cached list of packs, forcing them to be scanned again.
+	 */
 	protected void clearCache() {
 		packList.set(NO_PACKS);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void close() {
 		packList.set(NO_PACKS);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsObjectRepresentation.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsObjectRepresentation.java
index ddcfff6..1e388fd 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsObjectRepresentation.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsObjectRepresentation.java
@@ -57,21 +57,25 @@ class DfsObjectRepresentation extends StoredObjectRepresentation {
 		this.pack = pack;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public int getFormat() {
 		return format;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public int getWeight() {
 		return (int) Math.min(length, Integer.MAX_VALUE);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public ObjectId getDeltaBase() {
 		return baseId;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public boolean wasDeltaAttempted() {
 		switch (pack.getPackDescription().getPackSource()) {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsObjectToPack.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsObjectToPack.java
index ff270bf..5f4dee2 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsObjectToPack.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsObjectToPack.java
@@ -60,7 +60,7 @@ class DfsObjectToPack extends ObjectToPack {
 	/** Length of the data section of the object. */
 	long length;
 
-	DfsObjectToPack(AnyObjectId src, final int type) {
+	DfsObjectToPack(AnyObjectId src, int type) {
 		super(src, type);
 	}
 
@@ -72,12 +72,14 @@ final void setFound() {
 		setExtendedFlag(FLAG_FOUND);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected void clearReuseAsIs() {
 		super.clearReuseAsIs();
 		pack = null;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void select(StoredObjectRepresentation ref) {
 		DfsObjectRepresentation ptr = (DfsObjectRepresentation) ref;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsOutputStream.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsOutputStream.java
index ef3173e..c286570 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsOutputStream.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsOutputStream.java
@@ -72,11 +72,13 @@ public int blockSize() {
 		return 0;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void write(int b) throws IOException {
 		write(new byte[] { (byte) b });
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public abstract void write(byte[] buf, int off, int len) throws IOException;
 
@@ -91,7 +93,7 @@ public void write(int b) throws IOException {
 	 *            buffer to populate. Up to {@code buf.remaining()} bytes will
 	 *            be read from {@code position}.
 	 * @return number of bytes actually read.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             reading is not supported, or the read cannot be performed due
 	 *             to DFS errors.
 	 */
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackCompactor.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackCompactor.java
index 99663eb..b43b9b1 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackCompactor.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackCompactor.java
@@ -126,6 +126,8 @@ public DfsPackCompactor(DfsRepository repository) {
 	}
 
 	/**
+	 * Set configuration to write a reftable.
+	 *
 	 * @param cfg
 	 *            configuration to write a reftable. Reftable compacting is
 	 *            disabled (default) when {@code cfg} is {@code null}.
@@ -172,7 +174,7 @@ public DfsPackCompactor add(DfsReftable table) {
 	 * ones are omitted.
 	 *
 	 * @return {@code this}
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             existing packs cannot be read.
 	 */
 	public DfsPackCompactor autoAdd() throws IOException {
@@ -215,7 +217,7 @@ public DfsPackCompactor exclude(ObjectIdSet set) {
 	 * @param pack
 	 *            objects to not include.
 	 * @return {@code this}.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             pack index cannot be loaded.
 	 */
 	public DfsPackCompactor exclude(DfsPackFile pack) throws IOException {
@@ -232,7 +234,7 @@ public DfsPackCompactor exclude(DfsPackFile pack) throws IOException {
 	 * @param pm
 	 *            progress monitor to receive updates on as packing may take a
 	 *            while, depending on the size of the repository.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the packs cannot be compacted.
 	 */
 	public void compact(ProgressMonitor pm) throws IOException {
@@ -266,8 +268,7 @@ private void compactPacks(DfsReader ctx, ProgressMonitor pm)
 		pc.setReuseDeltas(true);
 		pc.setReuseObjects(true);
 
-		PackWriter pw = new PackWriter(pc, ctx);
-		try {
+		try (PackWriter pw = new PackWriter(pc, ctx)) {
 			pw.setDeltaBaseAsOffset(true);
 			pw.setReuseDeltaCommits(false);
 
@@ -283,8 +284,6 @@ private void compactPacks(DfsReader ctx, ProgressMonitor pm)
 				writeIndex(objdb, outDesc, pw);
 
 				PackStatistics stats = pw.getStatistics();
-				pw.close();
-				pw = null;
 
 				outDesc.setPackStats(stats);
 				newStats = stats;
@@ -294,10 +293,6 @@ private void compactPacks(DfsReader ctx, ProgressMonitor pm)
 					objdb.rollbackPack(Collections.singletonList(outDesc));
 				}
 			}
-		} finally {
-			if (pw != null) {
-				pw.close();
-			}
 		}
 	}
 
@@ -331,7 +326,11 @@ private void initOutDesc(DfsObjDatabase objdb) throws IOException {
 		}
 	}
 
-	/** @return all of the source packs that fed into this compaction. */
+	/**
+	 * Get all of the source packs that fed into this compaction.
+	 *
+	 * @return all of the source packs that fed into this compaction.
+	 */
 	public Collection<DfsPackDescription> getSourcePacks() {
 		Set<DfsPackDescription> src = new HashSet<>();
 		for (DfsPackFile pack : srcPacks) {
@@ -343,16 +342,26 @@ public Collection<DfsPackDescription> getSourcePacks() {
 		return src;
 	}
 
-	/** @return new packs created by this compaction. */
+	/**
+	 * Get new packs created by this compaction.
+	 *
+	 * @return new packs created by this compaction.
+	 */
 	public List<DfsPackDescription> getNewPacks() {
 		return outDesc != null
 				? Collections.singletonList(outDesc)
 				: Collections.emptyList();
 	}
 
-	/** @return statistics corresponding to the {@link #getNewPacks()}. */
+	/**
+	 * Get statistics corresponding to the {@link #getNewPacks()}.
+	 * May be null if statistics are not available.
+	 *
+	 * @return statistics corresponding to the {@link #getNewPacks()}.
+	 *
+	 */
 	public List<PackStatistics> getNewPackStatistics() {
-		return newStats != null
+		return outDesc != null
 				? Collections.singletonList(newStats)
 				: Collections.emptyList();
 	}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackDescription.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackDescription.java
index e865e6b..45eb7b0 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackDescription.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackDescription.java
@@ -104,7 +104,11 @@ public DfsPackDescription(DfsRepositoryDescription repoDesc, String name) {
 		blockSizeMap = new int[extCnt];
 	}
 
-	/** @return description of the repository. */
+	/**
+	 * Get description of the repository.
+	 *
+	 * @return description of the repository.
+	 */
 	public DfsRepositoryDescription getRepositoryDescription() {
 		return repoDesc;
 	}
@@ -120,15 +124,19 @@ public void addFileExt(PackExt ext) {
 	}
 
 	/**
+	 * Whether the pack file extension is known to exist.
+	 *
 	 * @param ext
 	 *            the file extension
-	 * @return whether the pack file extensions is known to exist.
+	 * @return whether the pack file extension is known to exist.
 	 */
 	public boolean hasFileExt(PackExt ext) {
 		return (extensions & ext.getBit()) != 0;
 	}
 
 	/**
+	 * Get file name
+	 *
 	 * @param ext
 	 *            the file extension
 	 * @return name of the file.
@@ -138,20 +146,29 @@ public String getFileName(PackExt ext) {
 	}
 
 	/**
+	 * Get cache key for use by the block cache.
+	 *
 	 * @param ext
 	 *            the file extension.
 	 * @return cache key for use by the block cache.
 	 */
 	public DfsStreamKey getStreamKey(PackExt ext) {
-		return DfsStreamKey.of(getRepositoryDescription(), getFileName(ext));
+		return DfsStreamKey.of(getRepositoryDescription(), getFileName(ext),
+				ext);
 	}
 
-	/** @return the source of the pack. */
+	/**
+	 * Get the source of the pack.
+	 *
+	 * @return the source of the pack.
+	 */
 	public PackSource getPackSource() {
 		return packSource;
 	}
 
 	/**
+	 * Set the source of the pack.
+	 *
 	 * @param source
 	 *            the source of the pack.
 	 * @return {@code this}
@@ -161,12 +178,18 @@ public DfsPackDescription setPackSource(PackSource source) {
 		return this;
 	}
 
-	/** @return time the pack was created, in milliseconds. */
+	/**
+	 * Get time the pack was created, in milliseconds.
+	 *
+	 * @return time the pack was created, in milliseconds.
+	 */
 	public long getLastModified() {
 		return lastModified;
 	}
 
 	/**
+	 * Set time the pack was created, in milliseconds.
+	 *
 	 * @param timeMillis
 	 *            time the pack was created, in milliseconds. 0 if not known.
 	 * @return {@code this}
@@ -176,14 +199,20 @@ public DfsPackDescription setLastModified(long timeMillis) {
 		return this;
 	}
 
-	/** @return minUpdateIndex for the reftable, if present. */
+	/**
+	 * Get minUpdateIndex for the reftable, if present.
+	 *
+	 * @return minUpdateIndex for the reftable, if present.
+	 */
 	public long getMinUpdateIndex() {
 		return minUpdateIndex;
 	}
 
 	/**
+	 * Set minUpdateIndex for the reftable.
+	 *
 	 * @param min
-	 *            minUpdateIndex for the reftable, or 0.
+	 *            minUpdateIndex for the reftable.
 	 * @return {@code this}
 	 */
 	public DfsPackDescription setMinUpdateIndex(long min) {
@@ -191,14 +220,20 @@ public DfsPackDescription setMinUpdateIndex(long min) {
 		return this;
 	}
 
-	/** @return maxUpdateIndex for the reftable, if present. */
+	/**
+	 * Get maxUpdateIndex for the reftable, if present.
+	 *
+	 * @return maxUpdateIndex for the reftable, if present.
+	 */
 	public long getMaxUpdateIndex() {
 		return maxUpdateIndex;
 	}
 
 	/**
+	 * Set maxUpdateIndex for the reftable.
+	 *
 	 * @param max
-	 *            maxUpdateIndex for the reftable, or 0.
+	 *            maxUpdateIndex for the reftable.
 	 * @return {@code this}
 	 */
 	public DfsPackDescription setMaxUpdateIndex(long max) {
@@ -207,6 +242,8 @@ public DfsPackDescription setMaxUpdateIndex(long max) {
 	}
 
 	/**
+	 * Set size of the file in bytes.
+	 *
 	 * @param ext
 	 *            the file extension.
 	 * @param bytes
@@ -224,6 +261,8 @@ public DfsPackDescription setFileSize(PackExt ext, long bytes) {
 	}
 
 	/**
+	 * Get size of the file, in bytes.
+	 *
 	 * @param ext
 	 *            the file extension.
 	 * @return size of the file, in bytes. If 0 the file size is not yet known.
@@ -234,6 +273,8 @@ public long getFileSize(PackExt ext) {
 	}
 
 	/**
+	 * Get blockSize of the file, in bytes.
+	 *
 	 * @param ext
 	 *            the file extension.
 	 * @return blockSize of the file, in bytes. If 0 the blockSize size is not
@@ -245,6 +286,8 @@ public int getBlockSize(PackExt ext) {
 	}
 
 	/**
+	 * Set blockSize of the file, in bytes.
+	 *
 	 * @param ext
 	 *            the file extension.
 	 * @param blockSize
@@ -262,6 +305,8 @@ public DfsPackDescription setBlockSize(PackExt ext, int blockSize) {
 	}
 
 	/**
+	 * Set estimated size of the .pack file in bytes.
+	 *
 	 * @param estimatedPackSize
 	 *            estimated size of the .pack file in bytes. If 0 the pack file
 	 *            size is unknown.
@@ -273,6 +318,8 @@ public DfsPackDescription setEstimatedPackSize(long estimatedPackSize) {
 	}
 
 	/**
+	 * Get estimated size of the .pack file in bytes.
+	 *
 	 * @return estimated size of the .pack file in bytes. If 0 the pack file
 	 *         size is unknown.
 	 */
@@ -280,12 +327,18 @@ public long getEstimatedPackSize() {
 		return estimatedPackSize;
 	}
 
-	/** @return number of objects in the pack. */
+	/**
+	 * Get number of objects in the pack.
+	 *
+	 * @return number of objects in the pack.
+	 */
 	public long getObjectCount() {
 		return objectCount;
 	}
 
 	/**
+	 * Set number of objects in the pack.
+	 *
 	 * @param cnt
 	 *            number of objects in the pack.
 	 * @return {@code this}
@@ -295,12 +348,18 @@ public DfsPackDescription setObjectCount(long cnt) {
 		return this;
 	}
 
-	/** @return number of delta compressed objects in the pack. */
+	/**
+	 * Get number of delta compressed objects in the pack.
+	 *
+	 * @return number of delta compressed objects in the pack.
+	 */
 	public long getDeltaCount() {
 		return deltaCount;
 	}
 
 	/**
+	 * Set number of delta compressed objects in the pack.
+	 *
 	 * @param cnt
 	 *            number of delta compressed objects in the pack.
 	 * @return {@code this}
@@ -311,6 +370,8 @@ public DfsPackDescription setDeltaCount(long cnt) {
 	}
 
 	/**
+	 * Get statistics from PackWriter, if the pack was built with it.
+	 *
 	 * @return statistics from PackWriter, if the pack was built with it.
 	 *         Generally this is only available for packs created by
 	 *         DfsGarbageCollector or DfsPackCompactor, and only when the pack
@@ -328,7 +389,11 @@ DfsPackDescription setPackStats(PackStatistics stats) {
 		return this;
 	}
 
-	/** @return stats from the sibling reftable, if created. */
+	/**
+	 * Get stats from the sibling reftable, if created.
+	 *
+	 * @return stats from the sibling reftable, if created.
+	 */
 	public ReftableWriter.Stats getReftableStats() {
 		return refStats;
 	}
@@ -352,12 +417,18 @@ public DfsPackDescription clearPackStats() {
 		return this;
 	}
 
-	/** @return the version of the index file written. */
+	/**
+	 * Get the version of the index file written.
+	 *
+	 * @return the version of the index file written.
+	 */
 	public int getIndexVersion() {
 		return indexVersion;
 	}
 
 	/**
+	 * Set the version of the index file written.
+	 *
 	 * @param version
 	 *            the version of the index file written.
 	 * @return {@code this}
@@ -367,11 +438,13 @@ public DfsPackDescription setIndexVersion(int version) {
 		return this;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public int hashCode() {
 		return packName.hashCode();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public boolean equals(Object b) {
 		if (b instanceof DfsPackDescription) {
@@ -383,15 +456,14 @@ public boolean equals(Object b) {
 	}
 
 	/**
+	 * {@inheritDoc}
+	 * <p>
 	 * Sort packs according to the optimal lookup ordering.
 	 * <p>
 	 * This method tries to position packs in the order readers should examine
 	 * them when looking for objects by SHA-1. The default tries to sort packs
 	 * with more recent modification dates before older packs, and packs with
 	 * fewer objects before packs with more objects.
-	 *
-	 * @param b
-	 *            the other pack.
 	 */
 	@Override
 	public int compareTo(DfsPackDescription b) {
@@ -437,6 +509,7 @@ static boolean isGC(PackSource s) {
 		}
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public String toString() {
 		return getFileName(PackExt.PACK);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackFile.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackFile.java
index dfb41e2..05b8f61 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackFile.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackFile.java
@@ -133,12 +133,18 @@ public final class DfsPackFile extends BlockBasedFile {
 		length = sz > 0 ? sz : -1;
 	}
 
-	/** @return description that was originally used to configure this pack file. */
+	/**
+	 * Get description that was originally used to configure this pack file.
+	 *
+	 * @return description that was originally used to configure this pack file.
+	 */
 	public DfsPackDescription getPackDescription() {
 		return desc;
 	}
 
 	/**
+	 * Whether the pack index file is loaded and cached in memory.
+	 *
 	 * @return whether the pack index file is loaded and cached in memory.
 	 */
 	public boolean isIndexLoaded() {
@@ -160,7 +166,7 @@ void setPackIndex(PackIndex idx) {
 	 *            reader context to support reading from the backing store if
 	 *            the index is not already loaded in memory.
 	 * @return the PackIndex.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the pack index is not available, or is corrupt.
 	 */
 	public PackIndex getPackIndex(DfsReader ctx) throws IOException {
@@ -203,8 +209,7 @@ private PackIndex idx(DfsReader ctx) throws IOException {
 			try {
 				ctx.stats.readIdx++;
 				long start = System.nanoTime();
-				ReadableChannel rc = ctx.db.openFile(desc, INDEX);
-				try {
+				try (ReadableChannel rc = ctx.db.openFile(desc, INDEX)) {
 					InputStream in = Channels.newInputStream(rc);
 					int wantSize = 8192;
 					int bs = rc.blockSize();
@@ -215,7 +220,6 @@ else if (bs <= 0)
 					idx = PackIndex.read(new BufferedInputStream(in, bs));
 					ctx.stats.readIdxBytes += rc.position();
 				} finally {
-					rc.close();
 					ctx.stats.readIdxMicros += elapsedMicros(start);
 				}
 			} catch (EOFException e) {
@@ -270,10 +274,9 @@ PackBitmapIndex getBitmapIndex(DfsReader ctx) throws IOException {
 
 			long size;
 			PackBitmapIndex idx;
-			try {
-				ctx.stats.readBitmap++;
-				long start = System.nanoTime();
-				ReadableChannel rc = ctx.db.openFile(desc, BITMAP_INDEX);
+			ctx.stats.readBitmap++;
+			long start = System.nanoTime();
+			try (ReadableChannel rc = ctx.db.openFile(desc, BITMAP_INDEX)) {
 				try {
 					InputStream in = Channels.newInputStream(rc);
 					int wantSize = 8192;
@@ -287,7 +290,6 @@ else if (bs <= 0)
 							in, idx(ctx), getReverseIdx(ctx));
 				} finally {
 					size = rc.position();
-					rc.close();
 					ctx.stats.readIdxBytes += size;
 					ctx.stats.readIdxMicros += elapsedMicros(start);
 				}
@@ -350,7 +352,7 @@ PackReverseIndex getReverseIdx(DfsReader ctx) throws IOException {
 	 * @param id
 	 *            object to be located.
 	 * @return true if the object exists in this pack; false if it does not.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the pack index is not available, or is corrupt.
 	 */
 	public boolean hasObject(DfsReader ctx, AnyObjectId id) throws IOException {
@@ -437,6 +439,7 @@ void copyPackAsIs(PackOutputStream out, DfsReader ctx)
 
 	private void copyPackThroughCache(PackOutputStream out, DfsReader ctx)
 			throws IOException {
+		@SuppressWarnings("resource") // Explicitly closed in finally block
 		ReadableChannel rc = null;
 		try {
 			long position = 12;
@@ -533,10 +536,8 @@ void copyAsIs(PackOutputStream out, DfsObjectToPack src,
 		try {
 			readFully(src.offset, buf, 0, 20, ctx);
 		} catch (IOException ioError) {
-			StoredObjectRepresentationNotAvailableException gone;
-			gone = new StoredObjectRepresentationNotAvailableException(src);
-			gone.initCause(ioError);
-			throw gone;
+			throw new StoredObjectRepresentationNotAvailableException(src,
+					ioError);
 		}
 		int c = buf[0] & 0xff;
 		final int typeCode = (c >> 4) & 7;
@@ -653,19 +654,15 @@ void copyAsIs(PackOutputStream out, DfsObjectToPack src,
 			CorruptObjectException corruptObject = new CorruptObjectException(
 					MessageFormat.format(
 							JGitText.get().objectAtHasBadZlibStream,
-							Long.valueOf(src.offset), getFileName()));
-			corruptObject.initCause(dataFormat);
+							Long.valueOf(src.offset), getFileName()),
+					dataFormat);
 
-			StoredObjectRepresentationNotAvailableException gone;
-			gone = new StoredObjectRepresentationNotAvailableException(src);
-			gone.initCause(corruptObject);
-			throw gone;
+			throw new StoredObjectRepresentationNotAvailableException(src,
+					corruptObject);
 
 		} catch (IOException ioError) {
-			StoredObjectRepresentationNotAvailableException gone;
-			gone = new StoredObjectRepresentationNotAvailableException(src);
-			gone.initCause(ioError);
-			throw gone;
+			throw new StoredObjectRepresentationNotAvailableException(src,
+					ioError);
 		}
 
 		if (quickCopy != null) {
@@ -866,12 +863,11 @@ else if (delta.next == null)
 			return new ObjectLoader.SmallObject(type, data);
 
 		} catch (DataFormatException dfe) {
-			CorruptObjectException coe = new CorruptObjectException(
+			throw new CorruptObjectException(
 					MessageFormat.format(
 							JGitText.get().objectAtHasBadZlibStream, Long.valueOf(pos),
-							getFileName()));
-			coe.initCause(dfe);
-			throw coe;
+							getFileName()),
+					dfe);
 		}
 	}
 
@@ -1014,12 +1010,11 @@ long getObjectSize(DfsReader ctx, long pos)
 		try {
 			return BinaryDelta.getResultSize(getDeltaHeader(ctx, deltaAt));
 		} catch (DataFormatException dfe) {
-			CorruptObjectException coe = new CorruptObjectException(
+			throw new CorruptObjectException(
 					MessageFormat.format(
 							JGitText.get().objectAtHasBadZlibStream, Long.valueOf(pos),
-							getFileName()));
-			coe.initCause(dfe);
-			throw coe;
+							getFileName()),
+					dfe);
 		}
 	}
 
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackParser.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackParser.java
index fd99db1..3a30d7d 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackParser.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackParser.java
@@ -63,7 +63,9 @@
 import org.eclipse.jgit.transport.PackParser;
 import org.eclipse.jgit.transport.PackedObjectInfo;
 
-/** Parses a pack stream into the DFS, by creating a new pack and index. */
+/**
+ * Parses a pack stream into the DFS, by creating a new pack and index.
+ */
 public class DfsPackParser extends PackParser {
 	private final DfsObjDatabase objdb;
 
@@ -132,6 +134,7 @@ protected DfsPackParser(DfsObjDatabase db, DfsInserter ins, InputStream in) {
 		this.packDigest = Constants.newMessageDigest();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public PackLock parse(ProgressMonitor receiving, ProgressMonitor resolving)
 			throws IOException {
@@ -193,11 +196,16 @@ public PackLock parse(ProgressMonitor receiving, ProgressMonitor resolving)
 		}
 	}
 
-	/** @return description of the imported pack, if one was made. */
+	/**
+	 * Get description of the imported pack, if one was made.
+	 *
+	 * @return description of the imported pack, if one was made.
+	 */
 	public DfsPackDescription getPackDescription() {
 		return packDsc;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected void onPackHeader(long objectCount) throws IOException {
 		if (objectCount == 0) {
@@ -219,29 +227,34 @@ else if (size < blockCache.getBlockSize())
 		currBuf = new byte[blockSize];
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected void onBeginWholeObject(long streamPosition, int type,
 			long inflatedSize) throws IOException {
 		crc.reset();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected void onEndWholeObject(PackedObjectInfo info) throws IOException {
 		info.setCRC((int) crc.getValue());
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected void onBeginOfsDelta(long streamPosition,
 			long baseStreamPosition, long inflatedSize) throws IOException {
 		crc.reset();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected void onBeginRefDelta(long streamPosition, AnyObjectId baseId,
 			long inflatedSize) throws IOException {
 		crc.reset();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected UnresolvedDelta onEndDelta() throws IOException {
 		UnresolvedDelta delta = new UnresolvedDelta();
@@ -249,24 +262,28 @@ protected UnresolvedDelta onEndDelta() throws IOException {
 		return delta;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected void onInflatedObjectData(PackedObjectInfo obj, int typeCode,
 			byte[] data) throws IOException {
 		// DfsPackParser ignores this event.
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected void onObjectHeader(Source src, byte[] raw, int pos, int len)
 			throws IOException {
 		crc.update(raw, pos, len);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected void onObjectData(Source src, byte[] raw, int pos, int len)
 			throws IOException {
 		crc.update(raw, pos, len);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected void onStoreStream(byte[] raw, int pos, int len)
 			throws IOException {
@@ -313,6 +330,7 @@ private DfsBlock flushBlock() throws IOException {
 		return v;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected void onPackFooter(byte[] hash) throws IOException {
 		// The base class will validate the original hash matches
@@ -322,6 +340,7 @@ protected void onPackFooter(byte[] hash) throws IOException {
 		packHash = hash;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected ObjectTypeAndSize seekDatabase(PackedObjectInfo obj,
 			ObjectTypeAndSize info) throws IOException {
@@ -330,6 +349,7 @@ protected ObjectTypeAndSize seekDatabase(PackedObjectInfo obj,
 		return readObjectHeader(info);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected ObjectTypeAndSize seekDatabase(UnresolvedDelta delta,
 			ObjectTypeAndSize info) throws IOException {
@@ -338,6 +358,7 @@ protected ObjectTypeAndSize seekDatabase(UnresolvedDelta delta,
 		return readObjectHeader(info);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected int readDatabase(byte[] dst, int pos, int cnt) throws IOException {
 		if (cnt == 0)
@@ -393,11 +414,13 @@ private long toBlockStart(long pos) {
 		return (pos / blockSize) * blockSize;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected boolean checkCRC(int oldCRC) {
 		return oldCRC == (int) crc.getValue();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected boolean onAppendBase(final int typeCode, final byte[] data,
 			final PackedObjectInfo info) throws IOException {
@@ -437,6 +460,7 @@ protected boolean onAppendBase(final int typeCode, final byte[] data,
 		return true;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected void onEndThinPack() throws IOException {
 		// Normally when a thin pack is closed the pack header gets
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPacksChangedEvent.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPacksChangedEvent.java
index 14d67c0..d9fc71f 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPacksChangedEvent.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPacksChangedEvent.java
@@ -45,14 +45,19 @@
 
 import org.eclipse.jgit.events.RepositoryEvent;
 
-/** Describes a change to the list of packs in a {@link DfsRepository}. */
+/**
+ * Describes a change to the list of packs in a
+ * {@link org.eclipse.jgit.internal.storage.dfs.DfsRepository}.
+ */
 public class DfsPacksChangedEvent
 		extends RepositoryEvent<DfsPacksChangedListener> {
+	/** {@inheritDoc} */
 	@Override
 	public Class<DfsPacksChangedListener> getListenerType() {
 		return DfsPacksChangedListener.class;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void dispatch(DfsPacksChangedListener listener) {
 		listener.onPacksChanged(this);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPacksChangedListener.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPacksChangedListener.java
index 324626c..3ea8213 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPacksChangedListener.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPacksChangedListener.java
@@ -45,7 +45,9 @@
 
 import org.eclipse.jgit.events.RepositoryListener;
 
-/** Receives {@link DfsPacksChangedEvent}s. */
+/**
+ * Receives {@link org.eclipse.jgit.internal.storage.dfs.DfsPacksChangedEvent}s.
+ */
 public interface DfsPacksChangedListener extends RepositoryListener {
 	/**
 	 * Invoked when all packs in a repository are listed.
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsReader.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsReader.java
index 3c84220..197114b 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsReader.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsReader.java
@@ -44,12 +44,12 @@
 
 package org.eclipse.jgit.internal.storage.dfs;
 
+import static org.eclipse.jgit.internal.storage.dfs.DfsObjDatabase.PackSource.UNREACHABLE_GARBAGE;
 import static org.eclipse.jgit.internal.storage.pack.PackExt.PACK;
 import static org.eclipse.jgit.lib.Constants.OBJECT_ID_LENGTH;
 
 import java.io.IOException;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Comparator;
@@ -92,8 +92,8 @@
 /**
  * Reader to access repository content through.
  * <p>
- * See the base {@link ObjectReader} documentation for details. Notably, a
- * reader is not thread safe.
+ * See the base {@link org.eclipse.jgit.lib.ObjectReader} documentation for
+ * details. Notably, a reader is not thread safe.
  */
 public class DfsReader extends ObjectReader implements ObjectReuseAsIs {
 	private static final int MAX_RESOLVE_MATCHES = 256;
@@ -133,16 +133,19 @@ DeltaBaseCache getDeltaBaseCache() {
 		return baseCache;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public ObjectReader newReader() {
 		return db.newReader();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void setAvoidUnreachableObjects(boolean avoid) {
 		avoidUnreachable = avoid;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public BitmapIndex getBitmapIndex() throws IOException {
 		for (DfsPackFile pack : db.getPacks()) {
@@ -153,6 +156,7 @@ public BitmapIndex getBitmapIndex() throws IOException {
 		return null;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public Collection<CachedPack> getCachedPacksAndUpdate(
 		BitmapBuilder needBitmap) throws IOException {
@@ -165,6 +169,7 @@ public Collection<CachedPack> getCachedPacksAndUpdate(
 		return Collections.emptyList();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public Collection<ObjectId> resolve(AbbreviatedObjectId id)
 			throws IOException {
@@ -193,6 +198,7 @@ private void resolveImpl(PackList packList, AbbreviatedObjectId id,
 		}
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public boolean has(AnyObjectId objectId) throws IOException {
 		if (last != null
@@ -222,6 +228,7 @@ private boolean hasImpl(PackList packList, AnyObjectId objectId)
 		return false;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public ObjectLoader open(AnyObjectId objectId, int typeHint)
 			throws MissingObjectException, IncorrectObjectTypeException,
@@ -276,6 +283,7 @@ private ObjectLoader openImpl(PackList packList, AnyObjectId objectId)
 		return null;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public Set<ObjectId> getShallowCommits() {
 		return Collections.emptySet();
@@ -385,6 +393,7 @@ private boolean skipGarbagePack(DfsPackFile pack) {
 		return avoidUnreachable && pack.isGarbage();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public <T extends ObjectId> AsyncObjectLoaderQueue<T> open(
 			Iterable<T> objectIds, final boolean reportMissing) {
@@ -444,6 +453,7 @@ public void release() {
 		};
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public <T extends ObjectId> AsyncObjectSizeQueue<T> getObjectSize(
 			Iterable<T> objectIds, final boolean reportMissing) {
@@ -505,6 +515,7 @@ public void release() {
 		};
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public long getObjectSize(AnyObjectId objectId, int typeHint)
 			throws MissingObjectException, IncorrectObjectTypeException,
@@ -550,6 +561,7 @@ private long getObjectSizeImpl(PackList packList, AnyObjectId objectId)
 		return -1;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public DfsObjectToPack newObjectToPack(AnyObjectId objectId, int type) {
 		return new DfsObjectToPack(objectId, type);
@@ -566,10 +578,22 @@ public int compare(DfsObjectToPack a, DfsObjectToPack b) {
 	public void selectObjectRepresentation(PackWriter packer,
 			ProgressMonitor monitor, Iterable<ObjectToPack> objects)
 			throws IOException, MissingObjectException {
-		// Don't check dirty bit on PackList; assume ObjectToPacks all came from the
-		// current list.
-		for (DfsPackFile pack : sortPacksForSelectRepresentation()) {
-			List<DfsObjectToPack> tmp = findAllFromPack(pack, objects);
+		// Don't check dirty bit on PackList; assume ObjectToPacks all came
+		// from the current list.
+		List<DfsPackFile> packs = sortPacksForSelectRepresentation();
+		trySelectRepresentation(packer, monitor, objects, packs, false);
+
+		List<DfsPackFile> garbage = garbagePacksForSelectRepresentation();
+		if (!garbage.isEmpty() && checkGarbagePacks(objects)) {
+			trySelectRepresentation(packer, monitor, objects, garbage, true);
+		}
+	}
+
+	private void trySelectRepresentation(PackWriter packer,
+			ProgressMonitor monitor, Iterable<ObjectToPack> objects,
+			List<DfsPackFile> packs, boolean skipFound) throws IOException {
+		for (DfsPackFile pack : packs) {
+			List<DfsObjectToPack> tmp = findAllFromPack(pack, objects, skipFound);
 			if (tmp.isEmpty())
 				continue;
 			Collections.sort(tmp, OFFSET_SORT);
@@ -608,29 +632,60 @@ public int compare(DfsPackFile af, DfsPackFile bf) {
 		}
 	};
 
-	private DfsPackFile[] sortPacksForSelectRepresentation()
+	private List<DfsPackFile> sortPacksForSelectRepresentation()
 			throws IOException {
 		DfsPackFile[] packs = db.getPacks();
-		DfsPackFile[] sorted = new DfsPackFile[packs.length];
-		System.arraycopy(packs, 0, sorted, 0, packs.length);
-		Arrays.sort(sorted, PACK_SORT_FOR_REUSE);
+		List<DfsPackFile> sorted = new ArrayList<>(packs.length);
+		for (DfsPackFile p : packs) {
+			if (p.getPackDescription().getPackSource() != UNREACHABLE_GARBAGE) {
+				sorted.add(p);
+			}
+		}
+		Collections.sort(sorted, PACK_SORT_FOR_REUSE);
 		return sorted;
 	}
 
+	private List<DfsPackFile> garbagePacksForSelectRepresentation()
+			throws IOException {
+		DfsPackFile[] packs = db.getPacks();
+		List<DfsPackFile> garbage = new ArrayList<>(packs.length);
+		for (DfsPackFile p : packs) {
+			if (p.getPackDescription().getPackSource() == UNREACHABLE_GARBAGE) {
+				garbage.add(p);
+			}
+		}
+		return garbage;
+	}
+
+	private static boolean checkGarbagePacks(Iterable<ObjectToPack> objects) {
+		for (ObjectToPack otp : objects) {
+			if (!((DfsObjectToPack) otp).isFound()) {
+				return true;
+			}
+		}
+		return false;
+	}
+
 	private List<DfsObjectToPack> findAllFromPack(DfsPackFile pack,
-			Iterable<ObjectToPack> objects) throws IOException {
+			Iterable<ObjectToPack> objects, boolean skipFound)
+					throws IOException {
 		List<DfsObjectToPack> tmp = new BlockList<>();
 		PackIndex idx = pack.getPackIndex(this);
-		for (ObjectToPack otp : objects) {
+		for (ObjectToPack obj : objects) {
+			DfsObjectToPack otp = (DfsObjectToPack) obj;
+			if (skipFound && otp.isFound()) {
+				continue;
+			}
 			long p = idx.findOffset(otp);
 			if (0 < p && !pack.isCorrupt(p)) {
 				otp.setOffset(p);
-				tmp.add((DfsObjectToPack) otp);
+				tmp.add(otp);
 			}
 		}
 		return tmp;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void copyObjectAsIs(PackOutputStream out, ObjectToPack otp,
 			boolean validate) throws IOException,
@@ -639,6 +694,7 @@ public void copyObjectAsIs(PackOutputStream out, ObjectToPack otp,
 		src.pack.copyAsIs(out, src, validate, this);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void writeObjects(PackOutputStream out, List<ObjectToPack> list)
 			throws IOException {
@@ -646,6 +702,7 @@ public void writeObjects(PackOutputStream out, List<ObjectToPack> list)
 			out.writeObject(otp);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void copyPackAsIs(PackOutputStream out, CachedPack pack)
 			throws IOException {
@@ -771,12 +828,20 @@ void unpin() {
 		block = null;
 	}
 
-	/** @return IO statistics accumulated by this reader. */
+	/**
+	 * Get IO statistics accumulated by this reader.
+	 *
+	 * @return IO statistics accumulated by this reader.
+	 */
 	public DfsReaderIoStats getIoStats() {
 		return new DfsReaderIoStats(stats);
 	}
 
-	/** Release the current window cursor. */
+	/**
+	 * {@inheritDoc}
+	 * <p>
+	 * Release the current window cursor.
+	 */
 	@Override
 	public void close() {
 		last = null;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsReaderIoStats.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsReaderIoStats.java
index 9a174c8..c35801f 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsReaderIoStats.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsReaderIoStats.java
@@ -43,7 +43,9 @@
 
 package org.eclipse.jgit.internal.storage.dfs;
 
-/** IO statistics for a {@link DfsReader}. */
+/**
+ * IO statistics for a {@link org.eclipse.jgit.internal.storage.dfs.DfsReader}.
+ */
 public class DfsReaderIoStats {
 	/** POJO to accumulate IO statistics. */
 	public static class Accumulator {
@@ -65,10 +67,16 @@ public static class Accumulator {
 		/** Total number of block cache hits. */
 		long blockCacheHit;
 
-		/** Total number of discrete blocks read from pack file(s). */
+		/**
+		 * Total number of discrete blocks actually read from pack file(s), that is,
+		 * block cache misses.
+		 */
 		long readBlock;
 
-		/** Total number of compressed bytes read as block sized units. */
+		/**
+		 * Total number of compressed bytes read during cache misses, as block sized
+		 * units.
+		 */
 		long readBlockBytes;
 
 		/** Total microseconds spent reading {@link #readBlock} blocks. */
@@ -87,52 +95,94 @@ public static class Accumulator {
 		this.stats = stats;
 	}
 
-	/** @return number of times the reader explicitly called scanPacks. */
+	/**
+	 * Get number of times the reader explicitly called scanPacks.
+	 *
+	 * @return number of times the reader explicitly called scanPacks.
+	 */
 	public long getScanPacks() {
 		return stats.scanPacks;
 	}
 
-	/** @return total number of complete pack indexes read into memory. */
+	/**
+	 * Get total number of complete pack indexes read into memory.
+	 *
+	 * @return total number of complete pack indexes read into memory.
+	 */
 	public long getReadPackIndexCount() {
 		return stats.readIdx;
 	}
 
-	/** @return total number of complete bitmap indexes read into memory. */
+	/**
+	 * Get total number of complete bitmap indexes read into memory.
+	 *
+	 * @return total number of complete bitmap indexes read into memory.
+	 */
 	public long getReadBitmapIndexCount() {
 		return stats.readBitmap;
 	}
 
-	/** @return total number of bytes read from indexes. */
+	/**
+	 * Get total number of bytes read from indexes.
+	 *
+	 * @return total number of bytes read from indexes.
+	 */
 	public long getReadIndexBytes() {
 		return stats.readIdxBytes;
 	}
 
-	/** @return total microseconds spent reading pack or bitmap indexes. */
+	/**
+	 * Get total microseconds spent reading pack or bitmap indexes.
+	 *
+	 * @return total microseconds spent reading pack or bitmap indexes.
+	 */
 	public long getReadIndexMicros() {
 		return stats.readIdxMicros;
 	}
 
-	/** @return total number of block cache hits. */
+	/**
+	 * Get total number of block cache hits.
+	 *
+	 * @return total number of block cache hits.
+	 */
 	public long getBlockCacheHits() {
 		return stats.blockCacheHit;
 	}
 
-	/** @return total number of discrete blocks read from pack file(s). */
+	/**
+	 * Get total number of discrete blocks actually read from pack file(s), that
+	 * is, block cache misses.
+	 *
+	 * @return total number of discrete blocks read from pack file(s).
+	 */
 	public long getReadBlocksCount() {
 		return stats.readBlock;
 	}
 
-	/** @return total number of compressed bytes read as block sized units. */
+	/**
+	 * Get total number of compressed bytes read during cache misses, as block
+	 * sized units.
+	 *
+	 * @return total number of compressed bytes read as block sized units.
+	 */
 	public long getReadBlocksBytes() {
 		return stats.readBlockBytes;
 	}
 
-	/** @return total microseconds spent reading blocks. */
+	/**
+	 * Get total microseconds spent reading blocks during cache misses.
+	 *
+	 * @return total microseconds spent reading blocks.
+	 */
 	public long getReadBlocksMicros() {
 		return stats.readBlockMicros;
 	}
 
-	/** @return total number of bytes decompressed. */
+	/**
+	 * Get total number of bytes decompressed.
+	 *
+	 * @return total number of bytes decompressed.
+	 */
 	public long getInflatedBytes() {
 		return stats.inflatedBytes;
 	}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsReaderOptions.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsReaderOptions.java
index d07c13d..2ea5c39 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsReaderOptions.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsReaderOptions.java
@@ -52,7 +52,9 @@
 import org.eclipse.jgit.lib.Config;
 import org.eclipse.jgit.storage.pack.PackConfig;
 
-/** Options controlling how objects are read from a DFS stored repository. */
+/**
+ * Options controlling how objects are read from a DFS stored repository.
+ */
 public class DfsReaderOptions {
 	/** 1024 (number of bytes in one kibibyte/kilobyte) */
 	public static final int KiB = 1024;
@@ -65,13 +67,19 @@ public class DfsReaderOptions {
 
 	private int streamPackBufferSize;
 
-	/** Create a default reader configuration. */
+	/**
+	 * Create a default reader configuration.
+	 */
 	public DfsReaderOptions() {
 		setDeltaBaseCacheLimit(10 * MiB);
 		setStreamFileThreshold(PackConfig.DEFAULT_BIG_FILE_THRESHOLD);
 	}
 
-	/** @return maximum number of bytes to hold in per-reader DeltaBaseCache. */
+	/**
+	 * Get maximum number of bytes to hold in per-reader DeltaBaseCache.
+	 *
+	 * @return maximum number of bytes to hold in per-reader DeltaBaseCache.
+	 */
 	public int getDeltaBaseCacheLimit() {
 		return deltaBaseCacheLimit;
 	}
@@ -88,12 +96,18 @@ public DfsReaderOptions setDeltaBaseCacheLimit(int maxBytes) {
 		return this;
 	}
 
-	/** @return the size threshold beyond which objects must be streamed. */
+	/**
+	 * Get the size threshold beyond which objects must be streamed.
+	 *
+	 * @return the size threshold beyond which objects must be streamed.
+	 */
 	public int getStreamFileThreshold() {
 		return streamFileThreshold;
 	}
 
 	/**
+	 * Set new byte limit for objects that must be streamed.
+	 *
 	 * @param newLimit
 	 *            new byte limit for objects that must be streamed. Objects
 	 *            smaller than this size can be obtained as a contiguous byte
@@ -101,12 +115,15 @@ public int getStreamFileThreshold() {
 	 *            {@link org.eclipse.jgit.lib.ObjectStream}.
 	 * @return {@code this}
 	 */
-	public DfsReaderOptions setStreamFileThreshold(final int newLimit) {
+	public DfsReaderOptions setStreamFileThreshold(int newLimit) {
 		streamFileThreshold = Math.max(0, newLimit);
 		return this;
 	}
 
 	/**
+	 * Get number of bytes to use for buffering when streaming a pack file
+	 * during copying.
+	 *
 	 * @return number of bytes to use for buffering when streaming a pack file
 	 *         during copying. If 0 the block size of the pack is used.
 	 */
@@ -115,6 +132,9 @@ public int getStreamPackBufferSize() {
 	}
 
 	/**
+	 * Set new buffer size in bytes for buffers used when streaming pack files
+	 * during copying.
+	 *
 	 * @param bufsz
 	 *            new buffer size in bytes for buffers used when streaming pack
 	 *            files during copying.
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsRefDatabase.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsRefDatabase.java
index b41c18b..a884346 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsRefDatabase.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsRefDatabase.java
@@ -64,7 +64,10 @@
 import org.eclipse.jgit.util.RefList;
 import org.eclipse.jgit.util.RefMap;
 
-/** */
+/**
+ * Abstract DfsRefDatabase class.
+ *
+ */
 public abstract class DfsRefDatabase extends RefDatabase {
 	private final DfsRepository repository;
 
@@ -81,7 +84,11 @@ protected DfsRefDatabase(DfsRepository repository) {
 		this.cache = new AtomicReference<>();
 	}
 
-	/** @return the repository the database holds the references of. */
+	/**
+	 * Get the repository the database holds the references of.
+	 *
+	 * @return the repository the database holds the references of.
+	 */
 	protected DfsRepository getRepository() {
 		return repository;
 	}
@@ -90,6 +97,7 @@ boolean exists() throws IOException {
 		return 0 < read().size();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public Ref exactRef(String name) throws IOException {
 		RefCache curr = read();
@@ -97,6 +105,7 @@ public Ref exactRef(String name) throws IOException {
 		return ref != null ? resolve(ref, 0, curr.ids) : null;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public Ref getRef(String needle) throws IOException {
 		RefCache curr = read();
@@ -110,11 +119,13 @@ public Ref getRef(String needle) throws IOException {
 		return null;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public List<Ref> getAdditionalRefs() {
 		return Collections.emptyList();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public Map<String, Ref> getRefs(String prefix) throws IOException {
 		RefCache curr = read();
@@ -161,6 +172,7 @@ private Ref resolve(Ref ref, int depth, RefList<Ref> loose)
 		return new SymbolicRef(ref.getName(), dst);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public Ref peel(Ref ref) throws IOException {
 		final Ref oldLeaf = ref.getLeaf();
@@ -180,7 +192,7 @@ public Ref peel(Ref ref) throws IOException {
 		return recreate(ref, newLeaf);
 	}
 
-	private Ref doPeel(final Ref leaf) throws MissingObjectException,
+	Ref doPeel(Ref leaf) throws MissingObjectException,
 			IOException {
 		try (RevWalk rw = new RevWalk(repository)) {
 			RevObject obj = rw.parseAny(leaf.getObjectId());
@@ -199,7 +211,7 @@ private Ref doPeel(final Ref leaf) throws MissingObjectException,
 		}
 	}
 
-	private static Ref recreate(Ref old, Ref leaf) {
+	static Ref recreate(Ref old, Ref leaf) {
 		if (old.isSymbolic()) {
 			Ref dst = recreate(old.getTarget(), leaf);
 			return new SymbolicRef(old.getName(), dst);
@@ -207,6 +219,7 @@ private static Ref recreate(Ref old, Ref leaf) {
 		return leaf;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public RefUpdate newUpdate(String refName, boolean detach)
 			throws IOException {
@@ -223,6 +236,7 @@ public RefUpdate newUpdate(String refName, boolean detach)
 		return update;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public RefRename newRename(String fromName, String toName)
 			throws IOException {
@@ -231,6 +245,7 @@ public RefRename newRename(String fromName, String toName)
 		return new DfsRefRename(src, dst);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public boolean isNameConflicting(String refName) throws IOException {
 		RefList<Ref> all = read().ids;
@@ -252,16 +267,19 @@ public boolean isNameConflicting(String refName) throws IOException {
 		return false;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void create() {
 		// Nothing to do.
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void refresh() {
 		clearCache();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void close() {
 		clearCache();
@@ -304,7 +322,7 @@ private RefCache read() throws IOException {
 	 * Read all known references in the repository.
 	 *
 	 * @return all current references of the repository.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             references cannot be accessed.
 	 */
 	protected abstract RefCache scanAllRefs() throws IOException;
@@ -329,7 +347,7 @@ private RefCache read() throws IOException {
 	 * @param newRef
 	 *            new reference to store.
 	 * @return true if the put was successful; false otherwise.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the reference cannot be put due to a system error.
 	 */
 	protected abstract boolean compareAndPut(Ref oldRef, Ref newRef)
@@ -341,7 +359,7 @@ protected abstract boolean compareAndPut(Ref oldRef, Ref newRef)
 	 * @param oldRef
 	 *            the old reference information that was previously read.
 	 * @return true if the remove was successful; false otherwise.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the reference could not be removed due to a system error.
 	 */
 	protected abstract boolean compareAndRemove(Ref oldRef) throws IOException;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsRefRename.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsRefRename.java
index d9c2bc7..65ef366 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsRefRename.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsRefRename.java
@@ -55,6 +55,7 @@ final class DfsRefRename extends RefRename {
 		super(src, dst);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected Result doRename() throws IOException {
 		// TODO Correctly handle renaming foo/bar to foo.
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsRefUpdate.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsRefUpdate.java
index 1f26fe3..de65c68 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsRefUpdate.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsRefUpdate.java
@@ -66,16 +66,19 @@ final class DfsRefUpdate extends RefUpdate {
 		this.refdb = refdb;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected DfsRefDatabase getRefDatabase() {
 		return refdb;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected DfsRepository getRepository() {
 		return refdb.getRepository();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected boolean tryLock(boolean deref) throws IOException {
 		dstRef = getRef();
@@ -90,11 +93,13 @@ protected boolean tryLock(boolean deref) throws IOException {
 		return true;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected void unlock() {
 		// No state is held while "locked".
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public Result update(RevWalk walk) throws IOException {
 		try {
@@ -105,6 +110,7 @@ public Result update(RevWalk walk) throws IOException {
 		}
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected Result doUpdate(Result desiredResult) throws IOException {
 		ObjectIdRef newRef;
@@ -129,6 +135,7 @@ protected Result doUpdate(Result desiredResult) throws IOException {
 		return Result.LOCK_FAILURE;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected Result doDelete(Result desiredResult) throws IOException {
 		if (getRefDatabase().compareAndRemove(dstRef)) {
@@ -138,6 +145,7 @@ protected Result doDelete(Result desiredResult) throws IOException {
 		return Result.LOCK_FAILURE;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected Result doLink(String target) throws IOException {
 		final SymbolicRef newRef = new SymbolicRef(
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsReftable.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsReftable.java
index 5a8ea92..7502471 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsReftable.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsReftable.java
@@ -51,7 +51,9 @@
 import org.eclipse.jgit.internal.storage.io.BlockSource;
 import org.eclipse.jgit.internal.storage.reftable.ReftableReader;
 
-/** A reftable stored in {@link DfsBlockCache}. */
+/**
+ * A reftable stored in {@link org.eclipse.jgit.internal.storage.dfs.DfsBlockCache}.
+ */
 public class DfsReftable extends BlockBasedFile {
 	/**
 	 * Construct a reader for an existing reftable.
@@ -83,7 +85,11 @@ public DfsReftable(DfsBlockCache cache, DfsPackDescription desc) {
 		length = sz > 0 ? sz : -1;
 	}
 
-	/** @return description that was originally used to configure this file. */
+	/**
+	 * Get description that was originally used to configure this file.
+	 *
+	 * @return description that was originally used to configure this file.
+	 */
 	public DfsPackDescription getPackDescription() {
 		return desc;
 	}
@@ -96,7 +102,7 @@ public DfsPackDescription getPackDescription() {
 	 * @param ctx
 	 *            reader to access the DFS storage.
 	 * @return cursor to read the table; caller must close.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             table cannot be opened.
 	 */
 	public ReftableReader open(DfsReader ctx) throws IOException {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsReftableDatabase.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsReftableDatabase.java
new file mode 100644
index 0000000..40cfb71
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsReftableDatabase.java
@@ -0,0 +1,390 @@
+/*
+ * Copyright (C) 2017, Google Inc.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ *   copyright notice, this list of conditions and the following
+ *   disclaimer in the documentation and/or other materials provided
+ *   with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ *   names of its contributors may be used to endorse or promote
+ *   products derived from this software without specific prior
+ *   written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.internal.storage.dfs;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Map;
+import java.util.concurrent.locks.ReentrantLock;
+
+import org.eclipse.jgit.annotations.Nullable;
+import org.eclipse.jgit.internal.storage.reftable.MergedReftable;
+import org.eclipse.jgit.internal.storage.reftable.RefCursor;
+import org.eclipse.jgit.internal.storage.reftable.Reftable;
+import org.eclipse.jgit.internal.storage.reftable.ReftableConfig;
+import org.eclipse.jgit.lib.BatchRefUpdate;
+import org.eclipse.jgit.lib.NullProgressMonitor;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.Ref;
+import org.eclipse.jgit.revwalk.RevWalk;
+import org.eclipse.jgit.transport.ReceiveCommand;
+import org.eclipse.jgit.util.RefList;
+import org.eclipse.jgit.util.RefMap;
+
+/**
+ * A {@link org.eclipse.jgit.internal.storage.dfs.DfsRefDatabase} that uses
+ * reftable for storage.
+ * <p>
+ * A {@code DfsRefDatabase} instance is thread-safe.
+ * <p>
+ * Implementors may wish to use
+ * {@link org.eclipse.jgit.internal.storage.dfs.DfsPackDescription#getMaxUpdateIndex()}
+ * as the primary key identifier for a
+ * {@link org.eclipse.jgit.internal.storage.pack.PackExt#REFTABLE} only pack
+ * description, ensuring that when there are competing transactions one wins,
+ * and one will fail.
+ */
+public class DfsReftableDatabase extends DfsRefDatabase {
+	private final ReentrantLock lock = new ReentrantLock(true);
+
+	private DfsReader ctx;
+
+	private ReftableStack tableStack;
+
+	private MergedReftable mergedTables;
+
+	/**
+	 * Initialize the reference database for a repository.
+	 *
+	 * @param repo
+	 *            the repository this database instance manages references for.
+	 */
+	protected DfsReftableDatabase(DfsRepository repo) {
+		super(repo);
+	}
+
+	/** {@inheritDoc} */
+	@Override
+	public boolean performsAtomicTransactions() {
+		return true;
+	}
+
+	/** {@inheritDoc} */
+	@Override
+	public BatchRefUpdate newBatchUpdate() {
+		DfsObjDatabase odb = getRepository().getObjectDatabase();
+		return new ReftableBatchRefUpdate(this, odb);
+	}
+
+	/**
+	 * Get configuration to write new reftables with.
+	 *
+	 * @return configuration to write new reftables with.
+	 */
+	public ReftableConfig getReftableConfig() {
+		return new ReftableConfig(getRepository().getConfig());
+	}
+
+	/**
+	 * Get the lock protecting this instance's state.
+	 *
+	 * @return the lock protecting this instance's state.
+	 */
+	protected ReentrantLock getLock() {
+		return lock;
+	}
+
+	/**
+	 * Whether to compact reftable instead of extending the stack depth.
+	 *
+	 * @return {@code true} if commit of a new small reftable should try to
+	 *         replace a prior small reftable by performing a compaction,
+	 *         instead of extending the stack depth.
+	 */
+	protected boolean compactDuringCommit() {
+		return true;
+	}
+
+	/**
+	 * Obtain a handle to the merged reader.
+	 *
+	 * @return (possibly cached) handle to the merged reader.
+	 * @throws java.io.IOException
+	 *             if tables cannot be opened.
+	 */
+	protected Reftable reader() throws IOException {
+		lock.lock();
+		try {
+			if (mergedTables == null) {
+				mergedTables = new MergedReftable(stack().readers());
+			}
+			return mergedTables;
+		} finally {
+			lock.unlock();
+		}
+	}
+
+	/**
+	 * Obtain a handle to the stack of reftables.
+	 *
+	 * @return (possibly cached) handle to the stack.
+	 * @throws java.io.IOException
+	 *             if tables cannot be opened.
+	 */
+	protected ReftableStack stack() throws IOException {
+		lock.lock();
+		try {
+			if (tableStack == null) {
+				DfsObjDatabase odb = getRepository().getObjectDatabase();
+				if (ctx == null) {
+					ctx = odb.newReader();
+				}
+				tableStack = ReftableStack.open(ctx,
+						Arrays.asList(odb.getReftables()));
+			}
+			return tableStack;
+		} finally {
+			lock.unlock();
+		}
+	}
+
+	/** {@inheritDoc} */
+	@Override
+	public boolean isNameConflicting(String refName) throws IOException {
+		lock.lock();
+		try {
+			Reftable table = reader();
+
+			// Cannot be nested within an existing reference.
+			int lastSlash = refName.lastIndexOf('/');
+			while (0 < lastSlash) {
+				if (table.hasRef(refName.substring(0, lastSlash))) {
+					return true;
+				}
+				lastSlash = refName.lastIndexOf('/', lastSlash - 1);
+			}
+
+			// Cannot be the container of an existing reference.
+			return table.hasRef(refName + '/');
+		} finally {
+			lock.unlock();
+		}
+	}
+
+	/** {@inheritDoc} */
+	@Override
+	public Ref exactRef(String name) throws IOException {
+		lock.lock();
+		try {
+			Reftable table = reader();
+			Ref ref = table.exactRef(name);
+			if (ref != null && ref.isSymbolic()) {
+				return table.resolve(ref);
+			}
+			return ref;
+		} finally {
+			lock.unlock();
+		}
+	}
+
+	/** {@inheritDoc} */
+	@Override
+	public Ref getRef(String needle) throws IOException {
+		for (String prefix : SEARCH_PATH) {
+			Ref ref = exactRef(prefix + needle);
+			if (ref != null) {
+				return ref;
+			}
+		}
+		return null;
+	}
+
+	/** {@inheritDoc} */
+	@Override
+	public Map<String, Ref> getRefs(String prefix) throws IOException {
+		RefList.Builder<Ref> all = new RefList.Builder<>();
+		lock.lock();
+		try {
+			Reftable table = reader();
+			try (RefCursor rc = ALL.equals(prefix) ? table.allRefs()
+					: table.seekRef(prefix)) {
+				while (rc.next()) {
+					Ref ref = table.resolve(rc.getRef());
+					if (ref != null && ref.getObjectId() != null) {
+						all.add(ref);
+					}
+				}
+			}
+		} finally {
+			lock.unlock();
+		}
+
+		RefList<Ref> none = RefList.emptyList();
+		return new RefMap(prefix, all.toRefList(), none, none);
+	}
+
+	/** {@inheritDoc} */
+	@Override
+	public Ref peel(Ref ref) throws IOException {
+		Ref oldLeaf = ref.getLeaf();
+		if (oldLeaf.isPeeled() || oldLeaf.getObjectId() == null) {
+			return ref;
+		}
+		return recreate(ref, doPeel(oldLeaf));
+	}
+
+	@Override
+	boolean exists() throws IOException {
+		DfsObjDatabase odb = getRepository().getObjectDatabase();
+		return odb.getReftables().length > 0;
+	}
+
+	@Override
+	void clearCache() {
+		lock.lock();
+		try {
+			if (tableStack != null) {
+				tableStack.close();
+				tableStack = null;
+			}
+			if (ctx != null) {
+				ctx.close();
+				ctx = null;
+			}
+			mergedTables = null;
+		} finally {
+			lock.unlock();
+		}
+	}
+
+	/** {@inheritDoc} */
+	@Override
+	protected boolean compareAndPut(Ref oldRef, @Nullable Ref newRef)
+			throws IOException {
+		ReceiveCommand cmd = toCommand(oldRef, newRef);
+		try (RevWalk rw = new RevWalk(getRepository())) {
+			newBatchUpdate().setAllowNonFastForwards(true).addCommand(cmd)
+					.execute(rw, NullProgressMonitor.INSTANCE);
+		}
+		switch (cmd.getResult()) {
+		case OK:
+			return true;
+		case REJECTED_OTHER_REASON:
+			throw new IOException(cmd.getMessage());
+		case LOCK_FAILURE:
+		default:
+			return false;
+		}
+	}
+
+	private static ReceiveCommand toCommand(Ref oldRef, Ref newRef) {
+		ObjectId oldId = toId(oldRef);
+		ObjectId newId = toId(newRef);
+		String name = toName(oldRef, newRef);
+
+		if (oldRef != null && oldRef.isSymbolic()) {
+			if (newRef != null) {
+				if (newRef.isSymbolic()) {
+					return ReceiveCommand.link(oldRef.getTarget().getName(),
+							newRef.getTarget().getName(), name);
+				} else {
+					return ReceiveCommand.unlink(oldRef.getTarget().getName(),
+							newId, name);
+				}
+			} else {
+				return ReceiveCommand.unlink(oldRef.getTarget().getName(),
+						ObjectId.zeroId(), name);
+			}
+		}
+
+		if (newRef != null && newRef.isSymbolic()) {
+			if (oldRef != null) {
+				if (oldRef.isSymbolic()) {
+					return ReceiveCommand.link(oldRef.getTarget().getName(),
+							newRef.getTarget().getName(), name);
+				} else {
+					return ReceiveCommand.link(oldId,
+							newRef.getTarget().getName(), name);
+				}
+			} else {
+				return ReceiveCommand.link(ObjectId.zeroId(),
+						newRef.getTarget().getName(), name);
+			}
+		}
+
+		return new ReceiveCommand(oldId, newId, name);
+	}
+
+	private static ObjectId toId(Ref ref) {
+		if (ref != null) {
+			ObjectId id = ref.getObjectId();
+			if (id != null) {
+				return id;
+			}
+		}
+		return ObjectId.zeroId();
+	}
+
+	private static String toName(Ref oldRef, Ref newRef) {
+		return oldRef != null ? oldRef.getName() : newRef.getName();
+	}
+
+	/** {@inheritDoc} */
+	@Override
+	protected boolean compareAndRemove(Ref oldRef) throws IOException {
+		return compareAndPut(oldRef, null);
+	}
+
+	/** {@inheritDoc} */
+	@Override
+	protected RefCache scanAllRefs() throws IOException {
+		throw new UnsupportedOperationException();
+	}
+
+	@Override
+	void stored(Ref ref) {
+		// Unnecessary; ReftableBatchRefUpdate calls clearCache().
+	}
+
+	@Override
+	void removed(String refName) {
+		// Unnecessary; ReftableBatchRefUpdate calls clearCache().
+	}
+
+	/** {@inheritDoc} */
+	@Override
+	protected void cachePeeledState(Ref oldLeaf, Ref newLeaf) {
+		// Do not cache peeled state in reftable.
+	}
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsRepository.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsRepository.java
index a5dd514..5169e92 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsRepository.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsRepository.java
@@ -58,7 +58,9 @@
 import org.eclipse.jgit.lib.Repository;
 import org.eclipse.jgit.lib.StoredConfig;
 
-/** A Git repository on a DFS. */
+/**
+ * A Git repository on a DFS.
+ */
 public abstract class DfsRepository extends Repository {
 	private final DfsConfig config;
 
@@ -76,10 +78,15 @@ protected DfsRepository(DfsRepositoryBuilder builder) {
 		this.description = builder.getRepositoryDescription();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public abstract DfsObjDatabase getObjectDatabase();
 
-	/** @return a description of this repository. */
+	/**
+	 * Get the description of this repository.
+	 *
+	 * @return the description of this repository.
+	 */
 	public DfsRepositoryDescription getDescription() {
 		return description;
 	}
@@ -88,7 +95,7 @@ public DfsRepositoryDescription getDescription() {
 	 * Check if the repository already exists.
 	 *
 	 * @return true if the repository exists; false if it is new.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the repository cannot be checked.
 	 */
 	public boolean exists() throws IOException {
@@ -98,6 +105,7 @@ public boolean exists() throws IOException {
 		return true;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void create(boolean bare) throws IOException {
 		if (exists())
@@ -110,28 +118,33 @@ public void create(boolean bare) throws IOException {
 			throw new IOException(result.name());
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public StoredConfig getConfig() {
 		return config;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void scanForRepoChanges() throws IOException {
 		getRefDatabase().refresh();
 		getObjectDatabase().clearCache();
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	public void notifyIndexChanged() {
+	public void notifyIndexChanged(boolean internal) {
 		// Do not send notifications.
 		// There is no index, as there is no working tree.
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public ReflogReader getReflogReader(String refName) throws IOException {
 		throw new UnsupportedOperationException();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public AttributesNodeProvider createAttributesNodeProvider() {
 		// TODO Check if the implementation used in FileRepository can be used
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsRepositoryBuilder.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsRepositoryBuilder.java
index 77e060a..2b67fd9 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsRepositoryBuilder.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsRepositoryBuilder.java
@@ -50,7 +50,7 @@
 import org.eclipse.jgit.lib.BaseRepositoryBuilder;
 
 /**
- * Constructs a {@link DfsRepository}.
+ * Constructs a {@link org.eclipse.jgit.internal.storage.dfs.DfsRepository}.
  *
  * @param <B>
  *            type of the builder class.
@@ -63,7 +63,11 @@ public abstract class DfsRepositoryBuilder<B extends DfsRepositoryBuilder, R ext
 
 	private DfsRepositoryDescription repoDesc;
 
-	/** @return options used by readers accessing the repository. */
+	/**
+	 * Get options used by readers accessing the repository.
+	 *
+	 * @return options used by readers accessing the repository.
+	 */
 	public DfsReaderOptions getReaderOptions() {
 		return readerOptions;
 	}
@@ -80,7 +84,11 @@ public B setReaderOptions(DfsReaderOptions opt) {
 		return self();
 	}
 
-	/** @return a description of the repository. */
+	/**
+	 * Get the description of the repository.
+	 *
+	 * @return the description of the repository.
+	 */
 	public DfsRepositoryDescription getRepositoryDescription() {
 		return repoDesc;
 	}
@@ -97,6 +105,7 @@ public B setRepositoryDescription(DfsRepositoryDescription desc) {
 		return self();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public B setup() throws IllegalArgumentException, IOException {
 		super.setup();
@@ -108,24 +117,20 @@ public B setup() throws IllegalArgumentException, IOException {
 	}
 
 	/**
+	 * {@inheritDoc}
+	 * <p>
 	 * Create a repository matching the configuration in this builder.
 	 * <p>
 	 * If an option was not set, the build method will try to default the option
 	 * based on other options. If insufficient information is available, an
 	 * exception is thrown to the caller.
-	 *
-	 * @return a repository matching this configuration.
-	 * @throws IllegalArgumentException
-	 *             insufficient parameters were set.
-	 * @throws IOException
-	 *             the repository could not be accessed to configure the rest of
-	 *             the builder's parameters.
 	 */
 	@Override
 	public abstract R build() throws IOException;
 
 	// We don't support local file IO and thus shouldn't permit these to set.
 
+	/** {@inheritDoc} */
 	@Override
 	public B setGitDir(File gitDir) {
 		if (gitDir != null)
@@ -133,6 +138,7 @@ public B setGitDir(File gitDir) {
 		return self();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public B setObjectDirectory(File objectDirectory) {
 		if (objectDirectory != null)
@@ -140,12 +146,14 @@ public B setObjectDirectory(File objectDirectory) {
 		return self();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public B addAlternateObjectDirectory(File other) {
 		throw new UnsupportedOperationException(
 				JGitText.get().unsupportedAlternates);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public B setWorkTree(File workTree) {
 		if (workTree != null)
@@ -153,6 +161,7 @@ public B setWorkTree(File workTree) {
 		return self();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public B setIndexFile(File indexFile) {
 		if (indexFile != null)
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsRepositoryDescription.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsRepositoryDescription.java
index 8afad0e..5e6c7e1 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsRepositoryDescription.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsRepositoryDescription.java
@@ -43,11 +43,15 @@
 
 package org.eclipse.jgit.internal.storage.dfs;
 
-/** A description of a Git repository on a DFS. */
+/**
+ * A description of a Git repository on a DFS.
+ */
 public class DfsRepositoryDescription {
 	private final String repositoryName;
 
-	/** Initialize a new, empty repository description. */
+	/**
+	 * Initialize a new, empty repository description.
+	 */
 	public DfsRepositoryDescription() {
 		this(null);
 	}
@@ -62,11 +66,16 @@ public DfsRepositoryDescription(String repositoryName) {
 		this.repositoryName = repositoryName;
 	}
 
-	/** @return the name of the repository. */
+	/**
+	 * Get the name of the repository.
+	 *
+	 * @return the name of the repository.
+	 */
 	public String getRepositoryName() {
 		return repositoryName;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public int hashCode() {
 		if (getRepositoryName() != null)
@@ -74,6 +83,7 @@ public int hashCode() {
 		return System.identityHashCode(this);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public boolean equals(Object b) {
 		if (b instanceof DfsRepositoryDescription){
@@ -84,6 +94,7 @@ public boolean equals(Object b) {
 		return false;
 	}
 
+	/** {@inheritDoc} */
 	@SuppressWarnings("nls")
 	@Override
 	public String toString() {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsStreamKey.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsStreamKey.java
index 54a7489..c11f696 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsStreamKey.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsStreamKey.java
@@ -43,43 +43,63 @@
 
 package org.eclipse.jgit.internal.storage.dfs;
 
-import static java.nio.charset.StandardCharsets.UTF_8;
+import static org.eclipse.jgit.lib.Constants.CHARSET;
 
 import java.util.Arrays;
 
-/** Key used by {@link DfsBlockCache} to disambiguate streams. */
+import org.eclipse.jgit.annotations.Nullable;
+import org.eclipse.jgit.internal.storage.pack.PackExt;
+
+/**
+ * Key used by {@link org.eclipse.jgit.internal.storage.dfs.DfsBlockCache} to disambiguate streams.
+ */
 public abstract class DfsStreamKey {
 	/**
+	 * Create a {@code DfsStreamKey}
+	 *
 	 * @param repo
 	 *            description of the containing repository.
 	 * @param name
 	 *            compute the key from a string name.
+	 * @param ext
+	 *            pack file extension, or {@code null}.
 	 * @return key for {@code name}
 	 */
-	public static DfsStreamKey of(DfsRepositoryDescription repo, String name) {
-		return new ByteArrayDfsStreamKey(repo, name.getBytes(UTF_8));
+	public static DfsStreamKey of(DfsRepositoryDescription repo, String name,
+			@Nullable PackExt ext) {
+		return new ByteArrayDfsStreamKey(repo, name.getBytes(CHARSET), ext);
 	}
 
 	final int hash;
 
+	final int packExtPos;
+
 	/**
+	 * Constructor for DfsStreamKey.
+	 *
 	 * @param hash
 	 *            hash of the other identifying components of the key.
+	 * @param ext
+	 *            pack file extension, or {@code null}.
 	 */
-	protected DfsStreamKey(int hash) {
+	protected DfsStreamKey(int hash, @Nullable PackExt ext) {
 		// Multiply by 31 here so we can more directly combine with another
 		// value without doing the multiply there.
 		this.hash = hash * 31;
+		this.packExtPos = ext == null ? 0 : ext.getPosition();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public int hashCode() {
 		return hash;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public abstract boolean equals(Object o);
 
+	/** {@inheritDoc} */
 	@SuppressWarnings("boxing")
 	@Override
 	public String toString() {
@@ -88,10 +108,12 @@ public String toString() {
 
 	private static final class ByteArrayDfsStreamKey extends DfsStreamKey {
 		private final DfsRepositoryDescription repo;
+
 		private final byte[] name;
 
-		ByteArrayDfsStreamKey(DfsRepositoryDescription repo, byte[] name) {
-			super(repo.hashCode() * 31 + Arrays.hashCode(name));
+		ByteArrayDfsStreamKey(DfsRepositoryDescription repo, byte[] name,
+				@Nullable PackExt ext) {
+			super(repo.hashCode() * 31 + Arrays.hashCode(name), ext);
 			this.repo = repo;
 			this.name = name;
 		}
@@ -100,8 +122,7 @@ private static final class ByteArrayDfsStreamKey extends DfsStreamKey {
 		public boolean equals(Object o) {
 			if (o instanceof ByteArrayDfsStreamKey) {
 				ByteArrayDfsStreamKey k = (ByteArrayDfsStreamKey) o;
-				return hash == k.hash
-						&& repo.equals(k.repo)
+				return hash == k.hash && repo.equals(k.repo)
 						&& Arrays.equals(name, k.name);
 			}
 			return false;
@@ -112,7 +133,7 @@ static final class ForReverseIndex extends DfsStreamKey {
 		private final DfsStreamKey idxKey;
 
 		ForReverseIndex(DfsStreamKey idxKey) {
-			super(idxKey.hash + 1);
+			super(idxKey.hash + 1, null);
 			this.idxKey = idxKey;
 		}
 
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsText.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsText.java
index dedcab0..9327bd1 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsText.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsText.java
@@ -46,9 +46,15 @@
 import org.eclipse.jgit.nls.NLS;
 import org.eclipse.jgit.nls.TranslationBundle;
 
-/** Translation bundle for the DFS storage implementation. */
+/**
+ * Translation bundle for the DFS storage implementation.
+ */
 public class DfsText extends TranslationBundle {
-	/** @return instance of this translation bundle */
+	/**
+	 * Get an instance of this translation bundle.
+	 *
+	 * @return instance of this translation bundle.
+	 */
 	public static DfsText get() {
 		return NLS.getBundleFor(DfsText.class);
 	}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/InMemoryRepository.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/InMemoryRepository.java
index 1e31878..662c3fe 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/InMemoryRepository.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/InMemoryRepository.java
@@ -6,30 +6,13 @@
 import java.nio.ByteBuffer;
 import java.util.ArrayList;
 import java.util.Collection;
-import java.util.HashMap;
 import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
 import java.util.concurrent.atomic.AtomicInteger;
-import java.util.concurrent.locks.ReadWriteLock;
-import java.util.concurrent.locks.ReentrantReadWriteLock;
 
 import org.eclipse.jgit.annotations.Nullable;
 import org.eclipse.jgit.internal.storage.pack.PackExt;
-import org.eclipse.jgit.lib.BatchRefUpdate;
-import org.eclipse.jgit.lib.ObjectId;
-import org.eclipse.jgit.lib.ObjectIdRef;
-import org.eclipse.jgit.lib.ProgressMonitor;
-import org.eclipse.jgit.lib.Ref;
-import org.eclipse.jgit.lib.Ref.Storage;
+import org.eclipse.jgit.internal.storage.reftable.ReftableConfig;
 import org.eclipse.jgit.lib.RefDatabase;
-import org.eclipse.jgit.revwalk.RevObject;
-import org.eclipse.jgit.revwalk.RevTag;
-import org.eclipse.jgit.revwalk.RevWalk;
-import org.eclipse.jgit.transport.ReceiveCommand;
-import org.eclipse.jgit.util.RefList;
 
 /**
  * Git repository stored entirely in the local process memory.
@@ -54,9 +37,8 @@ public InMemoryRepository build() throws IOException {
 	static final AtomicInteger packId = new AtomicInteger();
 
 	private final MemObjDatabase objdb;
-	private final RefDatabase refdb;
+	private final MemRefDatabase refdb;
 	private String gitwebDescription;
-	private boolean performsAtomicTransactions = true;
 
 	/**
 	 * Initialize a new in-memory repository.
@@ -74,11 +56,13 @@ public InMemoryRepository(DfsRepositoryDescription repoDesc) {
 		refdb = new MemRefDatabase();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public MemObjDatabase getObjectDatabase() {
 		return objdb;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public RefDatabase getRefDatabase() {
 		return refdb;
@@ -90,17 +74,20 @@ public RefDatabase getRefDatabase() {
 	 * Useful for testing atomic support enabled or disabled.
 	 *
 	 * @param atomic
+	 *            whether to use atomic reference transaction support
 	 */
 	public void setPerformsAtomicTransactions(boolean atomic) {
-		performsAtomicTransactions = atomic;
+		refdb.performsAtomicTransactions = atomic;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	@Nullable
 	public String getGitwebDescription() {
 		return gitwebDescription;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void setGitwebDescription(@Nullable String d) {
 		gitwebDescription = d;
@@ -148,6 +135,7 @@ protected synchronized void commitPackImpl(
 			if (replace != null)
 				n.removeAll(replace);
 			packs = n;
+			clearCache();
 		}
 
 		@Override
@@ -159,37 +147,43 @@ protected void rollbackPack(Collection<DfsPackDescription> desc) {
 		protected ReadableChannel openFile(DfsPackDescription desc, PackExt ext)
 				throws FileNotFoundException, IOException {
 			MemPack memPack = (MemPack) desc;
-			byte[] file = memPack.fileMap.get(ext);
+			byte[] file = memPack.get(ext);
 			if (file == null)
 				throw new FileNotFoundException(desc.getFileName(ext));
 			return new ByteArrayReadableChannel(file, blockSize);
 		}
 
 		@Override
-		protected DfsOutputStream writeFile(
-				DfsPackDescription desc, final PackExt ext) throws IOException {
-			final MemPack memPack = (MemPack) desc;
+		protected DfsOutputStream writeFile(DfsPackDescription desc,
+				PackExt ext) throws IOException {
+			MemPack memPack = (MemPack) desc;
 			return new Out() {
 				@Override
 				public void flush() {
-					memPack.fileMap.put(ext, getData());
+					memPack.put(ext, getData());
 				}
 			};
 		}
 	}
 
 	private static class MemPack extends DfsPackDescription {
-		final Map<PackExt, byte[]>
-				fileMap = new HashMap<>();
+		final byte[][] fileMap = new byte[PackExt.values().length][];
 
 		MemPack(String name, DfsRepositoryDescription repoDesc) {
 			super(repoDesc, name);
 		}
+
+		void put(PackExt ext, byte[] data) {
+			fileMap[ext.getPosition()] = data;
+		}
+
+		byte[] get(PackExt ext) {
+			return fileMap[ext.getPosition()];
+		}
 	}
 
 	private abstract static class Out extends DfsOutputStream {
 		private final ByteArrayOutputStream dst = new ByteArrayOutputStream();
-
 		private byte[] data;
 
 		@Override
@@ -221,7 +215,6 @@ public int read(long position, ByteBuffer buf) {
 		public void close() {
 			flush();
 		}
-
 	}
 
 	private static class ByteArrayReadableChannel implements ReadableChannel {
@@ -281,193 +274,27 @@ public void setReadAheadBytes(int b) {
 		}
 	}
 
-	/**
-	 * A ref database storing all refs in-memory.
-	 * <p>
-	 * This class is protected (and not private) to facilitate testing using
-	 * subclasses of InMemoryRepository.
-	 */
-    protected class MemRefDatabase extends DfsRefDatabase {
-		private final ConcurrentMap<String, Ref> refs = new ConcurrentHashMap<>();
-		private final ReadWriteLock lock = new ReentrantReadWriteLock(true /* fair */);
+	/** DfsRefDatabase used by InMemoryRepository. */
+	protected class MemRefDatabase extends DfsReftableDatabase {
+		boolean performsAtomicTransactions = true;
 
-		/**
-		 * Initialize a new in-memory ref database.
-		 */
+		/** Initialize a new in-memory ref database. */
 		protected MemRefDatabase() {
 			super(InMemoryRepository.this);
 		}
 
 		@Override
+		public ReftableConfig getReftableConfig() {
+			ReftableConfig cfg = new ReftableConfig();
+			cfg.setAlignBlocks(false);
+			cfg.setIndexObjects(false);
+			cfg.fromConfig(getRepository().getConfig());
+			return cfg;
+		}
+
+		@Override
 		public boolean performsAtomicTransactions() {
 			return performsAtomicTransactions;
 		}
-
-		@Override
-		public BatchRefUpdate newBatchUpdate() {
-			return new BatchRefUpdate(this) {
-				@Override
-				public void execute(RevWalk walk, ProgressMonitor monitor)
-						throws IOException {
-					if (performsAtomicTransactions() && isAtomic()) {
-						try {
-							lock.writeLock().lock();
-							batch(getCommands());
-						} finally {
-							lock.writeLock().unlock();
-						}
-					} else {
-						super.execute(walk, monitor);
-					}
-				}
-			};
-		}
-
-		@Override
-		protected RefCache scanAllRefs() throws IOException {
-			RefList.Builder<Ref> ids = new RefList.Builder<>();
-			RefList.Builder<Ref> sym = new RefList.Builder<>();
-			try {
-				lock.readLock().lock();
-				for (Ref ref : refs.values()) {
-					if (ref.isSymbolic())
-						sym.add(ref);
-					ids.add(ref);
-				}
-			} finally {
-				lock.readLock().unlock();
-			}
-			ids.sort();
-			sym.sort();
-			objdb.getCurrentPackList().markDirty();
-			return new RefCache(ids.toRefList(), sym.toRefList());
-		}
-
-		private void batch(List<ReceiveCommand> cmds) {
-			// Validate that the target exists in a new RevWalk, as the RevWalk
-			// from the RefUpdate might be reading back unflushed objects.
-			Map<ObjectId, ObjectId> peeled = new HashMap<>();
-			try (RevWalk rw = new RevWalk(getRepository())) {
-				for (ReceiveCommand c : cmds) {
-					if (c.getResult() != ReceiveCommand.Result.NOT_ATTEMPTED) {
-						ReceiveCommand.abort(cmds);
-						return;
-					}
-
-					if (!ObjectId.zeroId().equals(c.getNewId())) {
-						try {
-							RevObject o = rw.parseAny(c.getNewId());
-							if (o instanceof RevTag) {
-								peeled.put(o, rw.peel(o).copy());
-							}
-						} catch (IOException e) {
-							c.setResult(ReceiveCommand.Result.REJECTED_MISSING_OBJECT);
-							ReceiveCommand.abort(cmds);
-							return;
-						}
-					}
-				}
-			}
-
-			// Check all references conform to expected old value.
-			for (ReceiveCommand c : cmds) {
-				Ref r = refs.get(c.getRefName());
-				if (r == null) {
-					if (c.getType() != ReceiveCommand.Type.CREATE) {
-						c.setResult(ReceiveCommand.Result.LOCK_FAILURE);
-						ReceiveCommand.abort(cmds);
-						return;
-					}
-				} else {
-					ObjectId objectId = r.getObjectId();
-					if (r.isSymbolic() || objectId == null
-							|| !objectId.equals(c.getOldId())) {
-						c.setResult(ReceiveCommand.Result.LOCK_FAILURE);
-						ReceiveCommand.abort(cmds);
-						return;
-					}
-				}
-			}
-
-			// Write references.
-			for (ReceiveCommand c : cmds) {
-				if (c.getType() == ReceiveCommand.Type.DELETE) {
-					refs.remove(c.getRefName());
-					c.setResult(ReceiveCommand.Result.OK);
-					continue;
-				}
-
-				ObjectId p = peeled.get(c.getNewId());
-				Ref r;
-				if (p != null) {
-					r = new ObjectIdRef.PeeledTag(Storage.PACKED,
-							c.getRefName(), c.getNewId(), p);
-				} else {
-					r = new ObjectIdRef.PeeledNonTag(Storage.PACKED,
-							c.getRefName(), c.getNewId());
-				}
-				refs.put(r.getName(), r);
-				c.setResult(ReceiveCommand.Result.OK);
-			}
-			clearCache();
-		}
-
-		@Override
-		protected boolean compareAndPut(Ref oldRef, Ref newRef)
-				throws IOException {
-			try {
-				lock.writeLock().lock();
-				ObjectId id = newRef.getObjectId();
-				if (id != null) {
-					try (RevWalk rw = new RevWalk(getRepository())) {
-						// Validate that the target exists in a new RevWalk, as the RevWalk
-						// from the RefUpdate might be reading back unflushed objects.
-						rw.parseAny(id);
-					}
-				}
-				String name = newRef.getName();
-				if (oldRef == null)
-					return refs.putIfAbsent(name, newRef) == null;
-
-				Ref cur = refs.get(name);
-				if (cur != null) {
-					if (eq(cur, oldRef))
-						return refs.replace(name, cur, newRef);
-				}
-
-				if (oldRef.getStorage() == Storage.NEW)
-					return refs.putIfAbsent(name, newRef) == null;
-
-				return false;
-			} finally {
-				lock.writeLock().unlock();
-			}
-		}
-
-		@Override
-		protected boolean compareAndRemove(Ref oldRef) throws IOException {
-			try {
-				lock.writeLock().lock();
-				String name = oldRef.getName();
-				Ref cur = refs.get(name);
-				if (cur != null && eq(cur, oldRef))
-					return refs.remove(name, cur);
-				else
-					return false;
-			} finally {
-				lock.writeLock().unlock();
-			}
-		}
-
-		private boolean eq(Ref a, Ref b) {
-			if (!Objects.equals(a.getName(), b.getName()))
-				return false;
-			if (a.isSymbolic() != b.isSymbolic())
-				return false;
-			if (a.isSymbolic())
-				return Objects.equals(a.getTarget().getName(), b.getTarget().getName());
-			else
-				return Objects.equals(a.getObjectId(), b.getObjectId());
-		}
 	}
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/LargePackedWholeObject.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/LargePackedWholeObject.java
index 73a93e6..37d8d1c 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/LargePackedWholeObject.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/LargePackedWholeObject.java
@@ -77,53 +77,61 @@ final class LargePackedWholeObject extends ObjectLoader {
 		this.db = db;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public int getType() {
 		return type;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public long getSize() {
 		return size;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public boolean isLarge() {
 		return true;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public byte[] getCachedBytes() throws LargeObjectException {
 		throw new LargeObjectException();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public ObjectStream openStream() throws MissingObjectException, IOException {
+		PackInputStream packIn;
+		// ctx is closed by PackInputStream, or explicitly in the finally block
+		@SuppressWarnings("resource")
 		DfsReader ctx = db.newReader();
-		InputStream in;
 		try {
-			in = new PackInputStream(pack, objectOffset + headerLength, ctx);
-		} catch (IOException packGone) {
-			// If the pack file cannot be pinned into the cursor, it
-			// probably was repacked recently. Go find the object
-			// again and open the stream from that location instead.
-			//
 			try {
+				packIn = new PackInputStream(
+						pack, objectOffset + headerLength, ctx);
+				ctx = null; // owned by packIn
+			} catch (IOException packGone) {
+				// If the pack file cannot be pinned into the cursor, it
+				// probably was repacked recently. Go find the object
+				// again and open the stream from that location instead.
 				ObjectId obj = pack.getReverseIdx(ctx).findObject(objectOffset);
 				return ctx.open(obj, type).openStream();
-			} finally {
-				ctx.close();
 			}
 		} finally {
-			ctx.close();
+			if (ctx != null) {
+				ctx.close();
+			}
 		}
 
 		// Align buffer to inflater size, at a larger than default block.
 		// This reduces the number of context switches from the
 		// caller down into the pack stream inflation.
 		int bufsz = 8192;
-		in = new BufferedInputStream(
-				new InflaterInputStream(in, ctx.inflater(), bufsz),
+		InputStream in = new BufferedInputStream(
+				new InflaterInputStream(packIn, packIn.ctx.inflater(), bufsz),
 				bufsz);
 		return new ObjectStream.Filter(type, size, in);
 	}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/PackInputStream.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/PackInputStream.java
index bb8445b..b859d9d 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/PackInputStream.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/PackInputStream.java
@@ -47,7 +47,7 @@
 import java.io.InputStream;
 
 final class PackInputStream extends InputStream {
-	private final DfsReader ctx;
+	final DfsReader ctx;
 
 	private final DfsPackFile pack;
 
@@ -64,6 +64,7 @@ final class PackInputStream extends InputStream {
 		ctx.pin(pack, pos);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public int read(byte[] b, int off, int len) throws IOException {
 		int n = ctx.copy(pack, pos, b, off, len);
@@ -71,6 +72,7 @@ public int read(byte[] b, int off, int len) throws IOException {
 		return n;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public int read() throws IOException {
 		byte[] buf = new byte[1];
@@ -78,6 +80,7 @@ public int read() throws IOException {
 		return n == 1 ? buf[0] & 0xff : -1;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void close() {
 		ctx.close();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/ReadableChannel.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/ReadableChannel.java
index 240d552..9b98250 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/ReadableChannel.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/ReadableChannel.java
@@ -46,13 +46,15 @@
 import java.io.IOException;
 import java.nio.channels.ReadableByteChannel;
 
-/** Readable random access byte channel from a file. */
+/**
+ * Readable random access byte channel from a file.
+ */
 public interface ReadableChannel extends ReadableByteChannel {
 	/**
 	 * Get the current position of the channel.
 	 *
 	 * @return r current offset.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the channel's current position cannot be obtained.
 	 */
 	public long position() throws IOException;
@@ -63,7 +65,7 @@ public interface ReadableChannel extends ReadableByteChannel {
 	 * @param newPosition
 	 *            position to move the channel to. The next read will start from
 	 *            here. This should be a multiple of the {@link #blockSize()}.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the position cannot be updated. This may be because the
 	 *             channel only supports block aligned IO and the current
 	 *             position is not block aligned.
@@ -78,7 +80,7 @@ public interface ReadableChannel extends ReadableByteChannel {
 	 * read has been completed, the underlying file size should be available.
 	 *
 	 * @return r total size of the channel; -1 if not yet available.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the size cannot be determined.
 	 */
 	public long size() throws IOException;
@@ -92,9 +94,10 @@ public interface ReadableChannel extends ReadableByteChannel {
 	 * <p>
 	 * Channels should not recommend large block sizes. Sizes up to 1-4 MiB may
 	 * be reasonable, but sizes above that may be horribly inefficient. The
-	 * {@link DfsBlockCache} favors the alignment suggested by the channel
-	 * rather than the configured size under the assumption that reads are very
-	 * expensive and the channel knows what size is best to access it with.
+	 * {@link org.eclipse.jgit.internal.storage.dfs.DfsBlockCache} favors the
+	 * alignment suggested by the channel rather than the configured size under
+	 * the assumption that reads are very expensive and the channel knows what
+	 * size is best to access it with.
 	 *
 	 * @return recommended alignment size for randomly positioned reads. Does
 	 *         not need to be a power of 2.
@@ -125,7 +128,7 @@ public interface ReadableChannel extends ReadableByteChannel {
 	 *
 	 * @param bufferSize
 	 *            requested size of the read ahead buffer, in bytes.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             if the read ahead cannot be adjusted.
 	 */
 	public void setReadAheadBytes(int bufferSize) throws IOException;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/ReftableBatchRefUpdate.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/ReftableBatchRefUpdate.java
new file mode 100644
index 0000000..e0c056a
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/ReftableBatchRefUpdate.java
@@ -0,0 +1,465 @@
+/*
+ * Copyright (C) 2017, Google Inc.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ *   copyright notice, this list of conditions and the following
+ *   disclaimer in the documentation and/or other materials provided
+ *   with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ *   names of its contributors may be used to endorse or promote
+ *   products derived from this software without specific prior
+ *   written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.internal.storage.dfs;
+
+import static org.eclipse.jgit.internal.storage.pack.PackExt.REFTABLE;
+import static org.eclipse.jgit.lib.Ref.Storage.NEW;
+import static org.eclipse.jgit.lib.Ref.Storage.PACKED;
+import static org.eclipse.jgit.transport.ReceiveCommand.Result.LOCK_FAILURE;
+import static org.eclipse.jgit.transport.ReceiveCommand.Result.NOT_ATTEMPTED;
+import static org.eclipse.jgit.transport.ReceiveCommand.Result.OK;
+import static org.eclipse.jgit.transport.ReceiveCommand.Result.REJECTED_MISSING_OBJECT;
+import static org.eclipse.jgit.transport.ReceiveCommand.Result.REJECTED_NONFASTFORWARD;
+import static org.eclipse.jgit.transport.ReceiveCommand.Type.UPDATE_NONFASTFORWARD;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.locks.ReentrantLock;
+
+import org.eclipse.jgit.annotations.Nullable;
+import org.eclipse.jgit.errors.MissingObjectException;
+import org.eclipse.jgit.internal.storage.dfs.DfsObjDatabase.PackSource;
+import org.eclipse.jgit.internal.storage.io.BlockSource;
+import org.eclipse.jgit.internal.storage.pack.PackExt;
+import org.eclipse.jgit.internal.storage.reftable.RefCursor;
+import org.eclipse.jgit.internal.storage.reftable.Reftable;
+import org.eclipse.jgit.internal.storage.reftable.ReftableCompactor;
+import org.eclipse.jgit.internal.storage.reftable.ReftableConfig;
+import org.eclipse.jgit.internal.storage.reftable.ReftableReader;
+import org.eclipse.jgit.internal.storage.reftable.ReftableWriter;
+import org.eclipse.jgit.lib.AnyObjectId;
+import org.eclipse.jgit.lib.BatchRefUpdate;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.ObjectIdRef;
+import org.eclipse.jgit.lib.PersonIdent;
+import org.eclipse.jgit.lib.ProgressMonitor;
+import org.eclipse.jgit.lib.Ref;
+import org.eclipse.jgit.lib.ReflogEntry;
+import org.eclipse.jgit.lib.SymbolicRef;
+import org.eclipse.jgit.revwalk.RevObject;
+import org.eclipse.jgit.revwalk.RevTag;
+import org.eclipse.jgit.revwalk.RevWalk;
+import org.eclipse.jgit.transport.ReceiveCommand;
+
+/**
+ * {@link org.eclipse.jgit.lib.BatchRefUpdate} for
+ * {@link org.eclipse.jgit.internal.storage.dfs.DfsReftableDatabase}.
+ */
+public class ReftableBatchRefUpdate extends BatchRefUpdate {
+	private static final int AVG_BYTES = 36;
+
+	private final DfsReftableDatabase refdb;
+
+	private final DfsObjDatabase odb;
+
+	private final ReentrantLock lock;
+
+	private final ReftableConfig reftableConfig;
+
+	/**
+	 * Initialize batch update.
+	 *
+	 * @param refdb
+	 *            database the update will modify.
+	 * @param odb
+	 *            object database to store the reftable.
+	 */
+	protected ReftableBatchRefUpdate(DfsReftableDatabase refdb,
+			DfsObjDatabase odb) {
+		super(refdb);
+		this.refdb = refdb;
+		this.odb = odb;
+		lock = refdb.getLock();
+		reftableConfig = refdb.getReftableConfig();
+	}
+
+	/** {@inheritDoc} */
+	@Override
+	public void execute(RevWalk rw, ProgressMonitor pm, List<String> options) {
+		List<ReceiveCommand> pending = getPending();
+		if (pending.isEmpty()) {
+			return;
+		}
+		if (options != null) {
+			setPushOptions(options);
+		}
+		try {
+			if (!checkObjectExistence(rw, pending)) {
+				return;
+			}
+			if (!checkNonFastForwards(rw, pending)) {
+				return;
+			}
+
+			lock.lock();
+			try {
+				Reftable table = refdb.reader();
+				if (!checkExpected(table, pending)) {
+					return;
+				}
+				if (!checkConflicting(pending)) {
+					return;
+				}
+				if (!blockUntilTimestamps(MAX_WAIT)) {
+					return;
+				}
+				applyUpdates(rw, pending);
+				for (ReceiveCommand cmd : pending) {
+					cmd.setResult(OK);
+				}
+			} finally {
+				lock.unlock();
+			}
+		} catch (IOException e) {
+			pending.get(0).setResult(LOCK_FAILURE, "io error"); //$NON-NLS-1$
+			ReceiveCommand.abort(pending);
+		}
+	}
+
+	private List<ReceiveCommand> getPending() {
+		return ReceiveCommand.filter(getCommands(), NOT_ATTEMPTED);
+	}
+
+	private boolean checkObjectExistence(RevWalk rw,
+			List<ReceiveCommand> pending) throws IOException {
+		for (ReceiveCommand cmd : pending) {
+			try {
+				if (!cmd.getNewId().equals(ObjectId.zeroId())) {
+					rw.parseAny(cmd.getNewId());
+				}
+			} catch (MissingObjectException e) {
+				// ReceiveCommand#setResult(Result) converts REJECTED to
+				// REJECTED_NONFASTFORWARD, even though that result is also
+				// used for a missing object. Eagerly handle this case so we
+				// can set the right result.
+				cmd.setResult(REJECTED_MISSING_OBJECT);
+				ReceiveCommand.abort(pending);
+				return false;
+			}
+		}
+		return true;
+	}
+
+	private boolean checkNonFastForwards(RevWalk rw,
+			List<ReceiveCommand> pending) throws IOException {
+		if (isAllowNonFastForwards()) {
+			return true;
+		}
+		for (ReceiveCommand cmd : pending) {
+			cmd.updateType(rw);
+			if (cmd.getType() == UPDATE_NONFASTFORWARD) {
+				cmd.setResult(REJECTED_NONFASTFORWARD);
+				ReceiveCommand.abort(pending);
+				return false;
+			}
+		}
+		return true;
+	}
+
+	private boolean checkConflicting(List<ReceiveCommand> pending)
+			throws IOException {
+		Set<String> names = new HashSet<>();
+		for (ReceiveCommand cmd : pending) {
+			names.add(cmd.getRefName());
+		}
+
+		boolean ok = true;
+		for (ReceiveCommand cmd : pending) {
+			String name = cmd.getRefName();
+			if (refdb.isNameConflicting(name)) {
+				cmd.setResult(LOCK_FAILURE);
+				ok = false;
+			} else {
+				int s = name.lastIndexOf('/');
+				while (0 < s) {
+					if (names.contains(name.substring(0, s))) {
+						cmd.setResult(LOCK_FAILURE);
+						ok = false;
+						break;
+					}
+					s = name.lastIndexOf('/', s - 1);
+				}
+			}
+		}
+		if (!ok && isAtomic()) {
+			ReceiveCommand.abort(pending);
+			return false;
+		}
+		return ok;
+	}
+
+	private boolean checkExpected(Reftable table, List<ReceiveCommand> pending)
+			throws IOException {
+		for (ReceiveCommand cmd : pending) {
+			Ref ref;
+			try (RefCursor rc = table.seekRef(cmd.getRefName())) {
+				ref = rc.next() ? rc.getRef() : null;
+			}
+			if (!matchOld(cmd, ref)) {
+				cmd.setResult(LOCK_FAILURE);
+				if (isAtomic()) {
+					ReceiveCommand.abort(pending);
+					return false;
+				}
+			}
+		}
+		return true;
+	}
+
+	private static boolean matchOld(ReceiveCommand cmd, @Nullable Ref ref) {
+		if (ref == null) {
+			return AnyObjectId.equals(ObjectId.zeroId(), cmd.getOldId())
+					&& cmd.getOldSymref() == null;
+		} else if (ref.isSymbolic()) {
+			return ref.getTarget().getName().equals(cmd.getOldSymref());
+		}
+		ObjectId id = ref.getObjectId();
+		if (id == null) {
+			id = ObjectId.zeroId();
+		}
+		return cmd.getOldId().equals(id);
+	}
+
+	private void applyUpdates(RevWalk rw, List<ReceiveCommand> pending)
+			throws IOException {
+		List<Ref> newRefs = toNewRefs(rw, pending);
+		long updateIndex = nextUpdateIndex();
+		Set<DfsPackDescription> prune = Collections.emptySet();
+		DfsPackDescription pack = odb.newPack(PackSource.INSERT);
+		try (DfsOutputStream out = odb.writeFile(pack, REFTABLE)) {
+			ReftableConfig cfg = DfsPackCompactor
+					.configureReftable(reftableConfig, out);
+
+			ReftableWriter.Stats stats;
+			if (refdb.compactDuringCommit()
+					&& newRefs.size() * AVG_BYTES <= cfg.getRefBlockSize()
+					&& canCompactTopOfStack(cfg)) {
+				ByteArrayOutputStream tmp = new ByteArrayOutputStream();
+				write(tmp, cfg, updateIndex, newRefs, pending);
+				stats = compactTopOfStack(out, cfg, tmp.toByteArray());
+				prune = toPruneTopOfStack();
+			} else {
+				stats = write(out, cfg, updateIndex, newRefs, pending);
+			}
+			pack.addFileExt(REFTABLE);
+			pack.setReftableStats(stats);
+		}
+
+		odb.commitPack(Collections.singleton(pack), prune);
+		odb.addReftable(pack, prune);
+		refdb.clearCache();
+	}
+
+	private ReftableWriter.Stats write(OutputStream os, ReftableConfig cfg,
+			long updateIndex, List<Ref> newRefs, List<ReceiveCommand> pending)
+			throws IOException {
+		ReftableWriter writer = new ReftableWriter(cfg)
+				.setMinUpdateIndex(updateIndex).setMaxUpdateIndex(updateIndex)
+				.begin(os).sortAndWriteRefs(newRefs);
+		if (!isRefLogDisabled()) {
+			writeLog(writer, updateIndex, pending);
+		}
+		writer.finish();
+		return writer.getStats();
+	}
+
+	private void writeLog(ReftableWriter writer, long updateIndex,
+			List<ReceiveCommand> pending) throws IOException {
+		Map<String, ReceiveCommand> cmds = new HashMap<>();
+		List<String> byName = new ArrayList<>(pending.size());
+		for (ReceiveCommand cmd : pending) {
+			cmds.put(cmd.getRefName(), cmd);
+			byName.add(cmd.getRefName());
+		}
+		Collections.sort(byName);
+
+		PersonIdent ident = getRefLogIdent();
+		if (ident == null) {
+			ident = new PersonIdent(refdb.getRepository());
+		}
+		for (String name : byName) {
+			ReceiveCommand cmd = cmds.get(name);
+			if (isRefLogDisabled(cmd)) {
+				continue;
+			}
+			String msg = getRefLogMessage(cmd);
+			if (isRefLogIncludingResult(cmd)) {
+				String strResult = toResultString(cmd);
+				if (strResult != null) {
+					msg = msg.isEmpty() ? strResult : msg + ": " + strResult; //$NON-NLS-1$
+				}
+			}
+			writer.writeLog(name, updateIndex, ident, cmd.getOldId(),
+					cmd.getNewId(), msg);
+		}
+	}
+
+	private String toResultString(ReceiveCommand cmd) {
+		switch (cmd.getType()) {
+		case CREATE:
+			return ReflogEntry.PREFIX_CREATED;
+		case UPDATE:
+			// Match the behavior of a single RefUpdate. In that case, setting
+			// the force bit completely bypasses the potentially expensive
+			// isMergedInto check, by design, so the reflog message may be
+			// inaccurate.
+			//
+			// Similarly, this class bypasses the isMergedInto checks when the
+			// force bit is set, meaning we can't actually distinguish between
+			// UPDATE and UPDATE_NONFASTFORWARD when isAllowNonFastForwards()
+			// returns true.
+			return isAllowNonFastForwards() ? ReflogEntry.PREFIX_FORCED_UPDATE
+					: ReflogEntry.PREFIX_FAST_FORWARD;
+		case UPDATE_NONFASTFORWARD:
+			return ReflogEntry.PREFIX_FORCED_UPDATE;
+		default:
+			return null;
+		}
+	}
+
+	private static List<Ref> toNewRefs(RevWalk rw, List<ReceiveCommand> pending)
+			throws IOException {
+		List<Ref> refs = new ArrayList<>(pending.size());
+		for (ReceiveCommand cmd : pending) {
+			String name = cmd.getRefName();
+			ObjectId newId = cmd.getNewId();
+			String newSymref = cmd.getNewSymref();
+			if (AnyObjectId.equals(ObjectId.zeroId(), newId)
+					&& newSymref == null) {
+				refs.add(new ObjectIdRef.Unpeeled(NEW, name, null));
+				continue;
+			} else if (newSymref != null) {
+				refs.add(new SymbolicRef(name,
+						new ObjectIdRef.Unpeeled(NEW, newSymref, null)));
+				continue;
+			}
+
+			RevObject obj = rw.parseAny(newId);
+			RevObject peel = null;
+			if (obj instanceof RevTag) {
+				peel = rw.peel(obj);
+			}
+			if (peel != null) {
+				refs.add(new ObjectIdRef.PeeledTag(PACKED, name, newId,
+						peel.copy()));
+			} else {
+				refs.add(new ObjectIdRef.PeeledNonTag(PACKED, name, newId));
+			}
+		}
+		return refs;
+	}
+
+	private long nextUpdateIndex() throws IOException {
+		long updateIndex = 0;
+		for (Reftable r : refdb.stack().readers()) {
+			if (r instanceof ReftableReader) {
+				updateIndex = Math.max(updateIndex,
+						((ReftableReader) r).maxUpdateIndex());
+			}
+		}
+		return updateIndex + 1;
+	}
+
+	private boolean canCompactTopOfStack(ReftableConfig cfg)
+			throws IOException {
+		ReftableStack stack = refdb.stack();
+		List<Reftable> readers = stack.readers();
+		if (readers.isEmpty()) {
+			return false;
+		}
+
+		int lastIdx = readers.size() - 1;
+		DfsReftable last = stack.files().get(lastIdx);
+		DfsPackDescription desc = last.getPackDescription();
+		if (desc.getPackSource() != PackSource.INSERT
+				|| !packOnlyContainsReftable(desc)) {
+			return false;
+		}
+
+		Reftable table = readers.get(lastIdx);
+		int bs = cfg.getRefBlockSize();
+		return table instanceof ReftableReader
+				&& ((ReftableReader) table).size() <= 3 * bs;
+	}
+
+	private ReftableWriter.Stats compactTopOfStack(OutputStream out,
+			ReftableConfig cfg, byte[] newTable) throws IOException {
+		List<Reftable> stack = refdb.stack().readers();
+		Reftable last = stack.get(stack.size() - 1);
+
+		List<Reftable> tables = new ArrayList<>(2);
+		tables.add(last);
+		tables.add(new ReftableReader(BlockSource.from(newTable)));
+
+		ReftableCompactor compactor = new ReftableCompactor();
+		compactor.setConfig(cfg);
+		compactor.setIncludeDeletes(true);
+		compactor.addAll(tables);
+		compactor.compact(out);
+		return compactor.getStats();
+	}
+
+	private Set<DfsPackDescription> toPruneTopOfStack() throws IOException {
+		List<DfsReftable> stack = refdb.stack().files();
+		DfsReftable last = stack.get(stack.size() - 1);
+		return Collections.singleton(last.getPackDescription());
+	}
+
+	private boolean packOnlyContainsReftable(DfsPackDescription desc) {
+		for (PackExt ext : PackExt.values()) {
+			if (ext != REFTABLE && desc.hasFileExt(ext)) {
+				return false;
+			}
+		}
+		return true;
+	}
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/ReftableStack.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/ReftableStack.java
index 8d1cc98..50ba0e0 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/ReftableStack.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/ReftableStack.java
@@ -50,7 +50,10 @@
 
 import org.eclipse.jgit.internal.storage.reftable.Reftable;
 
-/** Tracks multiple open {@link Reftable} instances. */
+/**
+ * Tracks multiple open
+ * {@link org.eclipse.jgit.internal.storage.reftable.Reftable} instances.
+ */
 public class ReftableStack implements AutoCloseable {
 	/**
 	 * Opens a stack of tables for reading.
@@ -58,18 +61,19 @@ public class ReftableStack implements AutoCloseable {
 	 * @param ctx
 	 *            context to read the tables with. This {@code ctx} will be
 	 *            retained by the stack and each of the table readers.
-	 * @param tables
+	 * @param files
 	 *            the tables to open.
 	 * @return stack reference to close the tables.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             a table could not be opened
 	 */
-	public static ReftableStack open(DfsReader ctx, List<DfsReftable> tables)
+	public static ReftableStack open(DfsReader ctx, List<DfsReftable> files)
 			throws IOException {
-		ReftableStack stack = new ReftableStack(tables.size());
+		ReftableStack stack = new ReftableStack(files.size());
 		boolean close = true;
 		try {
-			for (DfsReftable t : tables) {
+			for (DfsReftable t : files) {
+				stack.files.add(t);
 				stack.tables.add(t.open(ctx));
 			}
 			close = false;
@@ -81,13 +85,27 @@ public static ReftableStack open(DfsReader ctx, List<DfsReftable> tables)
 		}
 	}
 
+	private final List<DfsReftable> files;
 	private final List<Reftable> tables;
 
 	private ReftableStack(int tableCnt) {
+		this.files = new ArrayList<>(tableCnt);
 		this.tables = new ArrayList<>(tableCnt);
 	}
 
 	/**
+	 * Get unmodifiable list of DfsRefatble files
+	 *
+	 * @return unmodifiable list of DfsRefatble files, in the same order the
+	 *         files were passed to {@link #open(DfsReader, List)}.
+	 */
+	public List<DfsReftable> files() {
+		return Collections.unmodifiableList(files);
+	}
+
+	/**
+	 * Get unmodifiable list of tables
+	 *
 	 * @return unmodifiable list of tables, in the same order the files were
 	 *         passed to {@link #open(DfsReader, List)}.
 	 */
@@ -95,6 +113,7 @@ public List<Reftable> readers() {
 		return Collections.unmodifiableList(tables);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void close() {
 		for (Reftable t : tables) {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/BasePackBitmapIndex.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/BasePackBitmapIndex.java
index b78ff2a..407061f 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/BasePackBitmapIndex.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/BasePackBitmapIndex.java
@@ -58,6 +58,7 @@ abstract class BasePackBitmapIndex extends PackBitmapIndex {
 		this.bitmaps = bitmaps;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public EWAHCompressedBitmap getBitmap(AnyObjectId objectId) {
 		StoredBitmap sb = bitmaps.get(objectId);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/BitmapIndexImpl.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/BitmapIndexImpl.java
index 88eef4c..1da4304 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/BitmapIndexImpl.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/BitmapIndexImpl.java
@@ -59,7 +59,9 @@
 import com.googlecode.javaewah.EWAHCompressedBitmap;
 import com.googlecode.javaewah.IntIterator;
 
-/** A compressed bitmap representation of the entire object graph. */
+/**
+ * A compressed bitmap representation of the entire object graph.
+ */
 public class BitmapIndexImpl implements BitmapIndex {
 	private static final int EXTRA_BITS = 10 * 1024;
 
@@ -85,6 +87,7 @@ PackBitmapIndex getPackBitmapIndex() {
 		return packIndex;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public CompressedBitmap getBitmap(AnyObjectId objectId) {
 		EWAHCompressedBitmap compressed = packIndex.getBitmap(objectId);
@@ -93,6 +96,7 @@ public CompressedBitmap getBitmap(AnyObjectId objectId) {
 		return new CompressedBitmap(compressed, this);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public CompressedBitmapBuilder newBitmapBuilder() {
 		return new CompressedBitmapBuilder(this);
@@ -209,22 +213,6 @@ private static final class CompressedBitmapBuilder implements BitmapBuilder {
 		}
 
 		@Override
-		public boolean add(AnyObjectId objectId, int type) {
-			int position = bitmapIndex.findOrInsert(objectId, type);
-			if (bitset.contains(position))
-				return false;
-
-			Bitmap entry = bitmapIndex.getBitmap(objectId);
-			if (entry != null) {
-				or(entry);
-				return false;
-			}
-
-			bitset.set(position);
-			return true;
-		}
-
-		@Override
 		public boolean contains(AnyObjectId objectId) {
 			int position = bitmapIndex.findPosition(objectId);
 			return 0 <= position && bitset.contains(position);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ByteArrayWindow.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ByteArrayWindow.java
index dc720bc..c6fdeb0 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ByteArrayWindow.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ByteArrayWindow.java
@@ -58,20 +58,22 @@
 final class ByteArrayWindow extends ByteWindow {
 	private final byte[] array;
 
-	ByteArrayWindow(final PackFile pack, final long o, final byte[] b) {
+	ByteArrayWindow(PackFile pack, long o, byte[] b) {
 		super(pack, o, b.length);
 		array = b;
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	protected int copy(final int p, final byte[] b, final int o, int n) {
+	protected int copy(int p, byte[] b, int o, int n) {
 		n = Math.min(array.length - p, n);
 		System.arraycopy(array, p, b, o, n);
 		return n;
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	protected int setInput(final int pos, final Inflater inf)
+	protected int setInput(int pos, Inflater inf)
 			throws DataFormatException {
 		int n = array.length - pos;
 		inf.setInput(array, pos, n);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ByteBufferWindow.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ByteBufferWindow.java
index 05ddd69..8e7904f 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ByteBufferWindow.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ByteBufferWindow.java
@@ -60,13 +60,14 @@
 final class ByteBufferWindow extends ByteWindow {
 	private final ByteBuffer buffer;
 
-	ByteBufferWindow(final PackFile pack, final long o, final ByteBuffer b) {
+	ByteBufferWindow(PackFile pack, long o, ByteBuffer b) {
 		super(pack, o, b.capacity());
 		buffer = b;
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	protected int copy(final int p, final byte[] b, final int o, int n) {
+	protected int copy(int p, byte[] b, int o, int n) {
 		final ByteBuffer s = buffer.slice();
 		s.position(p);
 		n = Math.min(s.remaining(), n);
@@ -89,8 +90,9 @@ void write(PackOutputStream out, long pos, int cnt)
 		}
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	protected int setInput(final int pos, final Inflater inf)
+	protected int setInput(int pos, Inflater inf)
 			throws DataFormatException {
 		final ByteBuffer s = buffer.slice();
 		s.position(pos);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ByteWindow.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ByteWindow.java
index e774a14..60073f3 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ByteWindow.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ByteWindow.java
@@ -66,7 +66,17 @@ abstract class ByteWindow {
 
 	protected final long end;
 
-	protected ByteWindow(final PackFile p, final long s, final int n) {
+	/**
+	 * Constructor for ByteWindow.
+	 *
+	 * @param p
+	 *            a {@link org.eclipse.jgit.internal.storage.file.PackFile}.
+	 * @param s
+	 *            where the byte window starts in the pack file
+	 * @param n
+	 *            size of the byte window
+	 */
+	protected ByteWindow(PackFile p, long s, int n) {
 		pack = p;
 		start = s;
 		end = start + n;
@@ -76,7 +86,7 @@ final int size() {
 		return (int) (end - start);
 	}
 
-	final boolean contains(final PackFile neededFile, final long neededPos) {
+	final boolean contains(PackFile neededFile, long neededPos) {
 		return pack == neededFile && start <= neededPos && neededPos < end;
 	}
 
@@ -127,6 +137,17 @@ final int setInput(long pos, Inflater inf) throws DataFormatException {
 		return setInput((int) (pos - start), inf);
 	}
 
+	/**
+	 * Set the input
+	 *
+	 * @param pos
+	 *            position
+	 * @param inf
+	 *            an {@link java.util.zip.Inflater} object.
+	 * @return size of the byte window
+	 * @throws java.util.zip.DataFormatException
+	 *             if any.
+	 */
 	protected abstract int setInput(int pos, Inflater inf)
 			throws DataFormatException;
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/CachedObjectDirectory.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/CachedObjectDirectory.java
index ae8260a..7f7ecc2 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/CachedObjectDirectory.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/CachedObjectDirectory.java
@@ -117,11 +117,13 @@ private ObjectIdOwnerMap<UnpackedObjectId> scanLoose() {
 		return m;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void close() {
 		// Don't close anything.
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public ObjectDatabase newCachedDatabase() {
 		return this;
@@ -177,12 +179,13 @@ void resolve(Set<ObjectId> matches, AbbreviatedObjectId id)
 		wrapped.resolve(matches, id);
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	public boolean has(final AnyObjectId objectId) throws IOException {
+	public boolean has(AnyObjectId objectId) throws IOException {
 		return has(objectId, null);
 	}
 
-	private boolean has(final AnyObjectId objectId, Set<AlternateHandle.Id> skips)
+	private boolean has(AnyObjectId objectId, Set<AlternateHandle.Id> skips)
 			throws IOException {
 		if (unpackedObjects.contains(objectId)) {
 			return true;
@@ -202,7 +205,7 @@ private boolean has(final AnyObjectId objectId, Set<AlternateHandle.Id> skips)
 	}
 
 	@Override
-	ObjectLoader openObject(final WindowCursor curs, final AnyObjectId objectId)
+	ObjectLoader openObject(WindowCursor curs, AnyObjectId objectId)
 			throws IOException {
 		return openObject(curs, objectId, null);
 	}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/CheckoutEntryImpl.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/CheckoutEntryImpl.java
index 2eacb7a..05cabba 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/CheckoutEntryImpl.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/CheckoutEntryImpl.java
@@ -65,11 +65,13 @@ public class CheckoutEntryImpl implements CheckoutEntry {
 		to = comment.substring(p2 + " to ".length(), p3); //$NON-NLS-1$
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public String getFromBranch() {
 		return from;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public String getToBranch() {
 		return to;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/DeltaBaseCache.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/DeltaBaseCache.java
index b397989..ed73e72 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/DeltaBaseCache.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/DeltaBaseCache.java
@@ -52,7 +52,7 @@ class DeltaBaseCache {
 
 	static final SoftReference<Entry> DEAD;
 
-	private static int hash(final long position) {
+	private static int hash(long position) {
 		return (((int) position) << 22) >>> 22;
 	}
 
@@ -82,7 +82,7 @@ static void reconfigure(WindowCacheConfig cfg) {
 		cache = new Slot[CACHE_SZ];
 	}
 
-	Entry get(final PackFile pack, final long position) {
+	Entry get(PackFile pack, long position) {
 		Slot e = cache[hash(position)];
 		if (e == null)
 			return null;
@@ -136,7 +136,7 @@ private void releaseMemory() {
 		}
 	}
 
-	private void moveToHead(final Slot e) {
+	private void moveToHead(Slot e) {
 		unlink(e);
 		e.lruPrev = null;
 		e.lruNext = lruHead;
@@ -147,7 +147,7 @@ private void moveToHead(final Slot e) {
 		lruHead = e;
 	}
 
-	private void unlink(final Slot e) {
+	private void unlink(Slot e) {
 		final Slot prev = e.lruPrev;
 		final Slot next = e.lruNext;
 		if (prev != null)
@@ -156,7 +156,7 @@ private void unlink(final Slot e) {
 			next.lruPrev = prev;
 	}
 
-	private void clearEntry(final Slot e) {
+	private void clearEntry(Slot e) {
 		openByteCount -= e.sz;
 		e.provider = null;
 		e.data = DEAD;
@@ -168,7 +168,7 @@ static class Entry {
 
 		final int type;
 
-		Entry(final byte[] aData, final int aType) {
+		Entry(byte[] aData, int aType) {
 			data = aData;
 			type = aType;
 		}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileObjectDatabase.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileObjectDatabase.java
index 3afc050..1f6b20a 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileObjectDatabase.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileObjectDatabase.java
@@ -64,11 +64,13 @@ static enum InsertLooseObjectResult {
 		INSERTED, EXISTS_PACKED, EXISTS_LOOSE, FAILURE;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public ObjectReader newReader() {
 		return new WindowCursor(this);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public ObjectDirectoryInserter newInserter() {
 		return new ObjectDirectoryInserter(this, getConfig());
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileRepository.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileRepository.java
index 646feac..d02888a 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileRepository.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileRepository.java
@@ -46,8 +46,6 @@
 
 package org.eclipse.jgit.internal.storage.file;
 
-import static org.eclipse.jgit.lib.RefDatabase.ALL;
-
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileNotFoundException;
@@ -116,7 +114,6 @@
  * This class is thread-safe.
  * <p>
  * This implementation only handles a subtly undocumented subset of git features.
- *
  */
 public class FileRepository extends Repository {
 	private static final String UNNAMED = "Unnamed repository; edit this file to name it for gitweb."; //$NON-NLS-1$
@@ -126,6 +123,10 @@ public class FileRepository extends Repository {
 	private final FileBasedConfig repoConfig;
 	private final RefDatabase refs;
 	private final ObjectDirectory objectDatabase;
+
+	private final Object snapshotLock = new Object();
+
+	// protected by snapshotLock
 	private FileSnapshot snapshot;
 
 	/**
@@ -133,8 +134,9 @@ public class FileRepository extends Repository {
 	 * <p>
 	 * The work tree, object directory, alternate object directories and index
 	 * file locations are deduced from the given git directory and the default
-	 * rules by running {@link FileRepositoryBuilder}. This constructor is the
-	 * same as saying:
+	 * rules by running
+	 * {@link org.eclipse.jgit.storage.file.FileRepositoryBuilder}. This
+	 * constructor is the same as saying:
 	 *
 	 * <pre>
 	 * new FileRepositoryBuilder().setGitDir(gitDir).build()
@@ -142,12 +144,12 @@ public class FileRepository extends Repository {
 	 *
 	 * @param gitDir
 	 *            GIT_DIR (the location of the repository metadata).
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the repository appears to already exist but cannot be
 	 *             accessed.
 	 * @see FileRepositoryBuilder
 	 */
-	public FileRepository(final File gitDir) throws IOException {
+	public FileRepository(File gitDir) throws IOException {
 		this(new FileRepositoryBuilder().setGitDir(gitDir).setup());
 	}
 
@@ -156,12 +158,12 @@ public FileRepository(final File gitDir) throws IOException {
 	 *
 	 * @param gitDir
 	 *            GIT_DIR (the location of the repository metadata).
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the repository appears to already exist but cannot be
 	 *             accessed.
 	 * @see FileRepositoryBuilder
 	 */
-	public FileRepository(final String gitDir) throws IOException {
+	public FileRepository(String gitDir) throws IOException {
 		this(new File(gitDir));
 	}
 
@@ -170,11 +172,11 @@ public FileRepository(final String gitDir) throws IOException {
 	 *
 	 * @param options
 	 *            description of the repository's important paths.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the user configuration file or repository configuration file
 	 *             cannot be accessed.
 	 */
-	public FileRepository(final BaseRepositoryBuilder options) throws IOException {
+	public FileRepository(BaseRepositoryBuilder options) throws IOException {
 		super(options);
 
 		if (StringUtils.isEmptyOrNull(SystemReader.getInstance().getenv(
@@ -240,53 +242,46 @@ public void onConfigChanged(ConfigChangedEvent event) {
 						Long.valueOf(repositoryFormatVersion)));
 		}
 
-		if (!isBare())
+		if (!isBare()) {
 			snapshot = FileSnapshot.save(getIndexFile());
+		}
 	}
 
 	private void loadSystemConfig() throws IOException {
 		try {
 			systemConfig.load();
-		} catch (ConfigInvalidException e1) {
-			IOException e2 = new IOException(MessageFormat.format(JGitText
+		} catch (ConfigInvalidException e) {
+			throw new IOException(MessageFormat.format(JGitText
 					.get().systemConfigFileInvalid, systemConfig.getFile()
-					.getAbsolutePath(), e1));
-			e2.initCause(e1);
-			throw e2;
+							.getAbsolutePath(),
+					e), e);
 		}
 	}
 
 	private void loadUserConfig() throws IOException {
 		try {
 			userConfig.load();
-		} catch (ConfigInvalidException e1) {
-			IOException e2 = new IOException(MessageFormat.format(JGitText
+		} catch (ConfigInvalidException e) {
+			throw new IOException(MessageFormat.format(JGitText
 					.get().userConfigFileInvalid, userConfig.getFile()
-					.getAbsolutePath(), e1));
-			e2.initCause(e1);
-			throw e2;
+							.getAbsolutePath(),
+					e), e);
 		}
 	}
 
 	private void loadRepoConfig() throws IOException {
 		try {
 			repoConfig.load();
-		} catch (ConfigInvalidException e1) {
-			IOException e2 = new IOException(JGitText.get().unknownRepositoryFormat);
-			e2.initCause(e1);
-			throw e2;
+		} catch (ConfigInvalidException e) {
+			throw new IOException(JGitText.get().unknownRepositoryFormat, e);
 		}
 	}
 
 	/**
+	 * {@inheritDoc}
+	 * <p>
 	 * Create a new Git repository initializing the necessary files and
 	 * directories.
-	 *
-	 * @param bare
-	 *            if true, a bare repository is created.
-	 *
-	 * @throws IOException
-	 *             in case of IO problem
 	 */
 	@Override
 	public void create(boolean bare) throws IOException {
@@ -380,25 +375,27 @@ ConfigConstants.CONFIG_KEY_WORKTREE, getWorkTree()
 	}
 
 	/**
+	 * Get the directory containing the objects owned by this repository
+	 *
 	 * @return the directory containing the objects owned by this repository.
 	 */
 	public File getObjectsDirectory() {
 		return objectDatabase.getDirectory();
 	}
 
-	/** @return the object database storing this repository's data. */
+	/** {@inheritDoc} */
 	@Override
 	public ObjectDirectory getObjectDatabase() {
 		return objectDatabase;
 	}
 
-	/** @return the reference database which stores the reference namespace. */
+	/** {@inheritDoc} */
 	@Override
 	public RefDatabase getRefDatabase() {
 		return refs;
 	}
 
-	/** @return the configuration of this repository. */
+	/** {@inheritDoc} */
 	@Override
 	public FileBasedConfig getConfig() {
 		if (systemConfig.isOutdated()) {
@@ -425,6 +422,7 @@ public FileBasedConfig getConfig() {
 		return repoConfig;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	@Nullable
 	public String getGitwebDescription() throws IOException {
@@ -443,6 +441,7 @@ public String getGitwebDescription() throws IOException {
 		return d;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void setGitwebDescription(@Nullable String description)
 			throws IOException {
@@ -479,14 +478,14 @@ private File descriptionFile() {
 	}
 
 	/**
+	 * {@inheritDoc}
+	 * <p>
 	 * Objects known to exist but not expressed by {@link #getAllRefs()}.
 	 * <p>
 	 * When a repository borrows objects from another repository, it can
 	 * advertise that it safely has that other repository's references, without
-	 * exposing any other details about the other repository.  This may help
-	 * a client trying to push changes avoid pushing more than it needs to.
-	 *
-	 * @return unmodifiable collection of other known objects.
+	 * exposing any other details about the other repository. This may help a
+	 * client trying to push changes avoid pushing more than it needs to.
 	 */
 	@Override
 	public Set<ObjectId> getAdditionalHaves() {
@@ -531,44 +530,50 @@ private Set<ObjectId> getAdditionalHaves(Set<AlternateHandle.Id> skips) {
 	 *
 	 * @param pack
 	 *            path of the pack file to open.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             index file could not be opened, read, or is not recognized as
 	 *             a Git pack file index.
 	 */
-	public void openPack(final File pack) throws IOException {
+	public void openPack(File pack) throws IOException {
 		objectDatabase.openPack(pack);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void scanForRepoChanges() throws IOException {
-		getRefDatabase().getRefs(ALL); // This will look for changes to refs
+		getRefDatabase().getRefs(); // This will look for changes to refs
 		detectIndexChanges();
 	}
 
 	/** Detect index changes. */
 	private void detectIndexChanges() {
-		if (isBare())
+		if (isBare()) {
 			return;
+		}
 
 		File indexFile = getIndexFile();
-		if (snapshot == null)
-			snapshot = FileSnapshot.save(indexFile);
-		else if (snapshot.isModified(indexFile))
-			notifyIndexChanged();
+		synchronized (snapshotLock) {
+			if (snapshot == null) {
+				snapshot = FileSnapshot.save(indexFile);
+				return;
+			}
+			if (!snapshot.isModified(indexFile)) {
+				return;
+			}
+		}
+		notifyIndexChanged(false);
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	public void notifyIndexChanged() {
-		snapshot = FileSnapshot.save(getIndexFile());
-		fireEvent(new IndexChangedEvent());
+	public void notifyIndexChanged(boolean internal) {
+		synchronized (snapshotLock) {
+			snapshot = FileSnapshot.save(getIndexFile());
+		}
+		fireEvent(new IndexChangedEvent(internal));
 	}
 
-	/**
-	 * @param refName
-	 * @return a {@link ReflogReader} for the supplied refname, or null if the
-	 *         named ref does not exist.
-	 * @throws IOException the ref could not be accessed.
-	 */
+	/** {@inheritDoc} */
 	@Override
 	public ReflogReader getReflogReader(String refName) throws IOException {
 		Ref ref = findRef(refName);
@@ -577,6 +582,7 @@ public ReflogReader getReflogReader(String refName) throws IOException {
 		return null;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public AttributesNodeProvider createAttributesNodeProvider() {
 		return new AttributesNodeProviderImpl(this);
@@ -626,11 +632,8 @@ public AttributesNode getGlobalAttributesNode() throws IOException {
 		static void loadRulesFromFile(AttributesNode r, File attrs)
 				throws FileNotFoundException, IOException {
 			if (attrs.exists()) {
-				FileInputStream in = new FileInputStream(attrs);
-				try {
+				try (FileInputStream in = new FileInputStream(attrs)) {
 					r.parse(in);
-				} finally {
-					in.close();
 				}
 			}
 		}
@@ -642,6 +645,7 @@ private boolean shouldAutoDetach() {
 				ConfigConstants.CONFIG_KEY_AUTODETACH, true);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void autoGC(ProgressMonitor monitor) {
 		GC gc = new GC(this);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileSnapshot.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileSnapshot.java
index 97f3b57..10adc6c 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileSnapshot.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileSnapshot.java
@@ -121,7 +121,6 @@ public static FileSnapshot save(File path) {
 	 *
 	 * @param modified
 	 *            the last modification time of the file
-	 *
 	 * @return the snapshot.
 	 */
 	public static FileSnapshot save(long modified) {
@@ -145,6 +144,8 @@ private FileSnapshot(long read, long modified) {
 	}
 
 	/**
+	 * Get time of last snapshot update
+	 *
 	 * @return time of last snapshot update
 	 */
 	public long lastModified() {
@@ -208,6 +209,7 @@ public boolean equals(FileSnapshot other) {
 		return lastModified == other.lastModified;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public boolean equals(Object other) {
 		if (other instanceof FileSnapshot)
@@ -215,6 +217,7 @@ public boolean equals(Object other) {
 		return false;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public int hashCode() {
 		// This is pretty pointless, but override hashCode to ensure that
@@ -223,6 +226,7 @@ public int hashCode() {
 		return (int) lastModified;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public String toString() {
 		if (this == DIRTY)
@@ -235,7 +239,7 @@ public String toString() {
 				+ ", read: " + f.format(new Date(lastRead)) + "]"; //$NON-NLS-1$ //$NON-NLS-2$
 	}
 
-	private boolean notRacyClean(final long read) {
+	private boolean notRacyClean(long read) {
 		// The last modified time granularity of FAT filesystems is 2 seconds.
 		// Using 2.5 seconds here provides a reasonably high assurance that
 		// a modification was not missed.
@@ -243,7 +247,7 @@ private boolean notRacyClean(final long read) {
 		return read - lastModified > 2500;
 	}
 
-	private boolean isModified(final long currLastModified) {
+	private boolean isModified(long currLastModified) {
 		// Any difference indicates the path was modified.
 		//
 		if (lastModified != currLastModified)
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GC.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GC.java
index 60d6652..342e2c8 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GC.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GC.java
@@ -57,7 +57,6 @@
 import java.nio.file.DirectoryStream;
 import java.nio.file.Files;
 import java.nio.file.Path;
-import java.nio.file.Paths;
 import java.nio.file.StandardCopyOption;
 import java.text.MessageFormat;
 import java.text.ParseException;
@@ -125,8 +124,10 @@
 import org.slf4j.LoggerFactory;
 
 /**
- * A garbage collector for git {@link FileRepository}. Instances of this class
- * are not thread-safe. Don't use the same instance from multiple threads.
+ * A garbage collector for git
+ * {@link org.eclipse.jgit.internal.storage.file.FileRepository}. Instances of
+ * this class are not thread-safe. Don't use the same instance from multiple
+ * threads.
  *
  * This class started as a copy of DfsGarbageCollector from Shawn O. Pearce
  * adapted to FileRepositories.
@@ -219,7 +220,8 @@ public GC(FileRepository repo) {
 	}
 
 	/**
-	 * Runs a garbage collector on a {@link FileRepository}. It will
+	 * Runs a garbage collector on a
+	 * {@link org.eclipse.jgit.internal.storage.file.FileRepository}. It will
 	 * <ul>
 	 * <li>pack loose references into packed-refs</li>
 	 * <li>repack all reachable objects into new pack files and delete the old
@@ -236,9 +238,11 @@ public GC(FileRepository repo) {
 	 * return immediately. In this case, errors will not be reported except in
 	 * gc.log.
 	 *
-	 * @return the collection of {@link PackFile}'s which are newly created
-	 * @throws IOException
-	 * @throws ParseException
+	 * @return the collection of
+	 *         {@link org.eclipse.jgit.internal.storage.file.PackFile}'s which
+	 *         are newly created
+	 * @throws java.io.IOException
+	 * @throws java.text.ParseException
 	 *             If the configuration parameter "gc.pruneexpire" couldn't be
 	 *             parsed
 	 */
@@ -309,7 +313,7 @@ private Collection<PackFile> doGc() throws IOException, ParseException {
 		packRefs();
 		// TODO: implement reflog_expire(pm, repo);
 		Collection<PackFile> newPacks = repack();
-		prune(Collections.<ObjectId> emptySet());
+		prune(Collections.emptySet());
 		// TODO: implement rerere_gc(pm);
 		return newPacks;
 	}
@@ -476,7 +480,7 @@ private void prunePack(String packName) {
 	 * which can be found in packs. If certain objects can't be pruned (e.g.
 	 * because the filesystem delete operation fails) this is silently ignored.
 	 *
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 */
 	public void prunePacked() throws IOException {
 		ObjectDirectory objdb = repo.getObjectDatabase();
@@ -534,9 +538,8 @@ public void prunePacked() throws IOException {
 	 *
 	 * @param objectsToKeep
 	 *            a set of objects which should explicitly not be pruned
-	 *
-	 * @throws IOException
-	 * @throws ParseException
+	 * @throws java.io.IOException
+	 * @throws java.text.ParseException
 	 *             If the configuration parameter "gc.pruneexpire" couldn't be
 	 *             parsed
 	 */
@@ -583,7 +586,6 @@ public void prune(Set<ObjectId> objectsToKeep) throws IOException,
 					} catch (IllegalArgumentException notAnObject) {
 						// ignoring the file that does not represent loose
 						// object
-						continue;
 					}
 				}
 			}
@@ -750,43 +752,41 @@ private void removeReferenced(Map<ObjectId, File> id2File,
 		RevObject ro = w.next();
 		while (ro != null) {
 			checkCancelled();
-			if (id2File.remove(ro.getId()) != null)
-				if (id2File.isEmpty())
-					return;
+			if (id2File.remove(ro.getId()) != null && id2File.isEmpty()) {
+				return;
+			}
 			ro = w.next();
 		}
 		ro = w.nextObject();
 		while (ro != null) {
 			checkCancelled();
-			if (id2File.remove(ro.getId()) != null)
-				if (id2File.isEmpty())
-					return;
+			if (id2File.remove(ro.getId()) != null && id2File.isEmpty()) {
+				return;
+			}
 			ro = w.nextObject();
 		}
 	}
 
 	private static boolean equals(Ref r1, Ref r2) {
-		if (r1 == null || r2 == null)
+		if (r1 == null || r2 == null) {
 			return false;
-		if (r1.isSymbolic()) {
-			if (!r2.isSymbolic())
-				return false;
-			return r1.getTarget().getName().equals(r2.getTarget().getName());
-		} else {
-			if (r2.isSymbolic()) {
-				return false;
-			}
-			return Objects.equals(r1.getObjectId(), r2.getObjectId());
 		}
+		if (r1.isSymbolic()) {
+			return r2.isSymbolic() && r1.getTarget().getName()
+					.equals(r2.getTarget().getName());
+		}
+		return !r2.isSymbolic()
+				&& Objects.equals(r1.getObjectId(), r2.getObjectId());
 	}
 
 	/**
 	 * Packs all non-symbolic, loose refs into packed-refs.
 	 *
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 */
 	public void packRefs() throws IOException {
-		Collection<Ref> refs = repo.getRefDatabase().getRefs(Constants.R_REFS).values();
+		Collection<Ref> refs = repo.getRefDatabase()
+				.getRefsByPrefix(Constants.R_REFS);
 		List<String> refsToBePacked = new ArrayList<>(refs.size());
 		pm.beginTask(JGitText.get().packRefs, refs.size());
 		try {
@@ -811,10 +811,10 @@ public void packRefs() throws IOException {
 	 * repacked. All old pack files which existed before are deleted.
 	 *
 	 * @return a collection of the newly created pack files
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             when during reading of refs, index, packfiles, objects,
 	 *             reflog-entries or during writing to the packfiles
-	 *             {@link IOException} occurs
+	 *             {@link java.io.IOException} occurs
 	 */
 	public Collection<PackFile> repack() throws IOException {
 		Collection<PackFile> toBeDeleted = repo.getObjectDatabase().getPacks();
@@ -852,7 +852,7 @@ public Collection<PackFile> repack() throws IOException {
 		}
 
 		List<ObjectIdSet> excluded = new LinkedList<>();
-		for (final PackFile f : repo.getObjectDatabase().getPacks()) {
+		for (PackFile f : repo.getObjectDatabase().getPacks()) {
 			checkCancelled();
 			if (f.shouldBeKept())
 				excluded.add(f.getIndex());
@@ -904,6 +904,7 @@ public Collection<PackFile> repack() throws IOException {
 			throw new IOException(e);
 		}
 		prunePacked();
+		deleteEmptyRefsFolders();
 		deleteOrphans();
 		deleteTempPacksIdx();
 
@@ -920,6 +921,49 @@ private static boolean isTag(Ref ref) {
 		return ref.getName().startsWith(Constants.R_TAGS);
 	}
 
+	private void deleteEmptyRefsFolders() throws IOException {
+		Path refs = repo.getDirectory().toPath().resolve("refs"); //$NON-NLS-1$
+		try (Stream<Path> entries = Files.list(refs)) {
+			Iterator<Path> iterator = entries.iterator();
+			while (iterator.hasNext()) {
+				try (Stream<Path> s = Files.list(iterator.next())) {
+					s.forEach(this::deleteDir);
+				}
+			}
+		}
+	}
+
+	private void deleteDir(Path dir) {
+		try (Stream<Path> dirs = Files.walk(dir)) {
+			dirs.filter(this::isDirectory).sorted(Comparator.reverseOrder())
+					.forEach(this::delete);
+		} catch (IOException e) {
+			LOG.error(e.getMessage(), e);
+		}
+	}
+
+	private boolean isDirectory(Path p) {
+		return p.toFile().isDirectory();
+	}
+
+	private boolean delete(Path d) {
+		try {
+			// Avoid deleting a folder that was just created so that concurrent
+			// operations trying to create a reference are not impacted
+			Instant threshold = Instant.now().minus(30, ChronoUnit.SECONDS);
+			Instant lastModified = Files.getLastModifiedTime(d).toInstant();
+			if (lastModified.isBefore(threshold)) {
+				// If the folder is not empty, the delete operation will fail
+				// silently. This is a cheaper alternative to filtering the
+				// stream in the calling method.
+				return d.toFile().delete();
+			}
+		} catch (IOException e) {
+			LOG.error(e.getMessage(), e);
+		}
+		return false;
+	}
+
 	/**
 	 * Deletes orphans
 	 * <p>
@@ -928,16 +972,14 @@ private static boolean isTag(Ref ref) {
 	 * </p>
 	 */
 	private void deleteOrphans() {
-		Path packDir = Paths.get(repo.getObjectsDirectory().getAbsolutePath(),
-				"pack"); //$NON-NLS-1$
+		Path packDir = repo.getObjectDatabase().getPackDirectory().toPath();
 		List<String> fileNames = null;
 		try (Stream<Path> files = Files.list(packDir)) {
 			fileNames = files.map(path -> path.getFileName().toString())
-					.filter(name -> {
-						return (name.endsWith(PACK_EXT)
-								|| name.endsWith(BITMAP_EXT)
-								|| name.endsWith(INDEX_EXT));
-					}).sorted(Collections.reverseOrder())
+					.filter(name -> (name.endsWith(PACK_EXT)
+							|| name.endsWith(BITMAP_EXT)
+							|| name.endsWith(INDEX_EXT)))
+					.sorted(Collections.reverseOrder())
 					.collect(Collectors.toList());
 		} catch (IOException e1) {
 			// ignore
@@ -953,7 +995,7 @@ private void deleteOrphans() {
 			} else {
 				if (base == null || !n.startsWith(base)) {
 					try {
-						Files.delete(new File(packDir.toFile(), n).toPath());
+						Files.delete(packDir.resolve(n));
 					} catch (IOException e) {
 						LOG.error(e.getMessage(), e);
 					}
@@ -963,8 +1005,7 @@ private void deleteOrphans() {
 	}
 
 	private void deleteTempPacksIdx() {
-		Path packDir = Paths.get(repo.getObjectsDirectory().getAbsolutePath(),
-				"pack"); //$NON-NLS-1$
+		Path packDir = repo.getObjectDatabase().getPackDirectory().toPath();
 		Instant threshold = Instant.now().minus(1, ChronoUnit.DAYS);
 		try (DirectoryStream<Path> stream =
 				Files.newDirectoryStream(packDir, "gc_*_tmp")) { //$NON-NLS-1$
@@ -999,7 +1040,7 @@ private Set<ObjectId> listRefLogObjects(Ref ref, long minTime) throws IOExceptio
 		List<ReflogEntry> rlEntries = reflogReader
 				.getReverseEntries();
 		if (rlEntries == null || rlEntries.isEmpty())
-			return Collections.<ObjectId> emptySet();
+			return Collections.emptySet();
 		Set<ObjectId> ret = new HashSet<>();
 		for (ReflogEntry e : rlEntries) {
 			if (e.getWho().getWhen().getTime() < minTime)
@@ -1027,7 +1068,7 @@ private Set<ObjectId> listRefLogObjects(Ref ref, long minTime) throws IOExceptio
 	 */
 	private Collection<Ref> getAllRefs() throws IOException {
 		RefDatabase refdb = repo.getRefDatabase();
-		Collection<Ref> refs = refdb.getRefs(RefDatabase.ALL).values();
+		Collection<Ref> refs = refdb.getRefs();
 		List<Ref> addl = refdb.getAdditionalRefs();
 		if (!addl.isEmpty()) {
 			List<Ref> all = new ArrayList<>(refs.size() + addl.size());
@@ -1103,23 +1144,21 @@ private PackFile writePack(@NonNull Set<? extends ObjectId> want,
 			throws IOException {
 		checkCancelled();
 		File tmpPack = null;
-		Map<PackExt, File> tmpExts = new TreeMap<>(
-				new Comparator<PackExt>() {
-					@Override
-					public int compare(PackExt o1, PackExt o2) {
-						// INDEX entries must be returned last, so the pack
-						// scanner does pick up the new pack until all the
-						// PackExt entries have been written.
-						if (o1 == o2)
-							return 0;
-						if (o1 == PackExt.INDEX)
-							return 1;
-						if (o2 == PackExt.INDEX)
-							return -1;
-						return Integer.signum(o1.hashCode() - o2.hashCode());
-					}
-
-				});
+		Map<PackExt, File> tmpExts = new TreeMap<>((o1, o2) -> {
+			// INDEX entries must be returned last, so the pack
+			// scanner does pick up the new pack until all the
+			// PackExt entries have been written.
+			if (o1 == o2) {
+				return 0;
+			}
+			if (o1 == PackExt.INDEX) {
+				return 1;
+			}
+			if (o2 == PackExt.INDEX) {
+				return -1;
+			}
+			return Integer.signum(o1.hashCode() - o2.hashCode());
+		});
 		try (PackWriter pw = new PackWriter(
 				(pconfig == null) ? new PackConfig(repo) : pconfig,
 				repo.newObjectReader())) {
@@ -1139,7 +1178,7 @@ public int compare(PackExt o1, PackExt o2) {
 
 			// create temporary files
 			String id = pw.computeName().getName();
-			File packdir = new File(repo.getObjectsDirectory(), "pack"); //$NON-NLS-1$
+			File packdir = repo.getObjectDatabase().getPackDirectory();
 			tmpPack = File.createTempFile("gc_", ".pack_tmp", packdir); //$NON-NLS-1$ //$NON-NLS-2$
 			final String tmpBase = tmpPack.getName()
 					.substring(0, tmpPack.getName().lastIndexOf('.'));
@@ -1151,27 +1190,21 @@ public int compare(PackExt o1, PackExt o2) {
 						JGitText.get().cannotCreateIndexfile, tmpIdx.getPath()));
 
 			// write the packfile
-			FileOutputStream fos = new FileOutputStream(tmpPack);
-			FileChannel channel = fos.getChannel();
-			OutputStream channelStream = Channels.newOutputStream(channel);
-			try {
+			try (FileOutputStream fos = new FileOutputStream(tmpPack);
+					FileChannel channel = fos.getChannel();
+					OutputStream channelStream = Channels
+							.newOutputStream(channel)) {
 				pw.writePack(pm, pm, channelStream);
-			} finally {
 				channel.force(true);
-				channelStream.close();
-				fos.close();
 			}
 
 			// write the packindex
-			fos = new FileOutputStream(tmpIdx);
-			FileChannel idxChannel = fos.getChannel();
-			OutputStream idxStream = Channels.newOutputStream(idxChannel);
-			try {
+			try (FileOutputStream fos = new FileOutputStream(tmpIdx);
+					FileChannel idxChannel = fos.getChannel();
+					OutputStream idxStream = Channels
+							.newOutputStream(idxChannel)) {
 				pw.writeIndex(idxStream);
-			} finally {
 				idxChannel.force(true);
-				idxStream.close();
-				fos.close();
 			}
 
 			if (pw.prepareBitmapIndex(pm)) {
@@ -1183,15 +1216,12 @@ public int compare(PackExt o1, PackExt o2) {
 							JGitText.get().cannotCreateIndexfile,
 							tmpBitmapIdx.getPath()));
 
-				fos = new FileOutputStream(tmpBitmapIdx);
-				idxChannel = fos.getChannel();
-				idxStream = Channels.newOutputStream(idxChannel);
-				try {
+				try (FileOutputStream fos = new FileOutputStream(tmpBitmapIdx);
+						FileChannel idxChannel = fos.getChannel();
+						OutputStream idxStream = Channels
+								.newOutputStream(idxChannel)) {
 					pw.writeBitmapIndex(idxStream);
-				} finally {
 					idxChannel.force(true);
-					idxStream.close();
-					fos.close();
 				}
 			}
 
@@ -1239,7 +1269,7 @@ public int compare(PackExt o1, PackExt o2) {
 	}
 
 	private File nameFor(String name, String ext) {
-		File packdir = new File(repo.getObjectsDirectory(), "pack"); //$NON-NLS-1$
+		File packdir = repo.getObjectDatabase().getPackDirectory();
 		return new File(packdir, "pack-" + name + ext); //$NON-NLS-1$
 	}
 
@@ -1315,7 +1345,7 @@ public String toString() {
 	 * Returns information about objects and pack files for a FileRepository.
 	 *
 	 * @return information about objects and pack files for a FileRepository
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 */
 	public RepoStatistics getStatistics() throws IOException {
 		RepoStatistics ret = new RepoStatistics();
@@ -1346,7 +1376,7 @@ public RepoStatistics getStatistics() throws IOException {
 		}
 
 		RefDatabase refDb = repo.getRefDatabase();
-		for (Ref r : refDb.getRefs(RefDatabase.ALL).values()) {
+		for (Ref r : refDb.getRefs()) {
 			Storage storage = r.getStorage();
 			if (storage == Storage.LOOSE || storage == Storage.LOOSE_PACKED)
 				ret.numberOfLooseRefs++;
@@ -1360,7 +1390,7 @@ public RepoStatistics getStatistics() throws IOException {
 	/**
 	 * Set the progress monitor used for garbage collection methods.
 	 *
-	 * @param pm
+	 * @param pm a {@link org.eclipse.jgit.lib.ProgressMonitor} object.
 	 * @return this
 	 */
 	public GC setProgressMonitor(ProgressMonitor pm) {
@@ -1402,7 +1432,8 @@ public void setPackExpireAgeMillis(long packExpireAgeMillis) {
 	 * "git gc --aggressive"
 	 *
 	 * @param pconfig
-	 *            the {@link PackConfig} used when writing packs
+	 *            the {@link org.eclipse.jgit.storage.pack.PackConfig} used when
+	 *            writing packs
 	 */
 	public void setPackConfig(PackConfig pconfig) {
 		this.pconfig = pconfig;
@@ -1446,7 +1477,7 @@ public void setPackExpire(Date packExpire) {
 	 * it exits without performing any work. Some JGit commands run
 	 * {@code gc --auto} after performing operations that could create many
 	 * loose objects.
-	 * <p/>
+	 * <p>
 	 * Housekeeping is required if there are too many loose objects or too many
 	 * packs in the repository. If the number of loose objects exceeds the value
 	 * of the gc.auto option JGit GC consolidates all existing packs into a
@@ -1454,13 +1485,13 @@ public void setPackExpire(Date packExpire) {
 	 * combine all loose objects into a single pack using {@code repack -d -l}.
 	 * Setting the value of {@code gc.auto} to 0 disables automatic packing of
 	 * loose objects.
-	 * <p/>
+	 * <p>
 	 * If the number of packs exceeds the value of {@code gc.autoPackLimit},
 	 * then existing packs (except those marked with a .keep file) are
 	 * consolidated into a single pack by using the {@code -A} option of repack.
 	 * Setting {@code gc.autoPackLimit} to 0 disables automatic consolidation of
 	 * packs.
-	 * <p/>
+	 * <p>
 	 * Like git the following jgit commands run auto gc:
 	 * <ul>
 	 * <li>fetch</li>
@@ -1489,8 +1520,8 @@ void setBackground(boolean background) {
 	private boolean needGc() {
 		if (tooManyPacks()) {
 			addRepackAllOption();
-		} else if (!tooManyLooseObjects()) {
-			return false;
+		} else {
+			return tooManyLooseObjects();
 		}
 		// TODO run pre-auto-gc hook, if it fails return false
 		return true;
@@ -1531,22 +1562,17 @@ boolean tooManyLooseObjects() {
 		int n = 0;
 		int threshold = (auto + 255) / 256;
 		Path dir = repo.getObjectsDirectory().toPath().resolve("17"); //$NON-NLS-1$
-		if (!Files.exists(dir)) {
+		if (!dir.toFile().exists()) {
 			return false;
 		}
-		try (DirectoryStream<Path> stream = Files.newDirectoryStream(dir,
-				new DirectoryStream.Filter<Path>() {
-
-					@Override
-					public boolean accept(Path file) throws IOException {
-						Path fileName = file.getFileName();
-						return Files.isRegularFile(file) && fileName != null
-								&& PATTERN_LOOSE_OBJECT
-										.matcher(fileName.toString()).matches();
-					}
+		try (DirectoryStream<Path> stream = Files.newDirectoryStream(dir, file -> {
+					Path fileName = file.getFileName();
+					return file.toFile().isFile() && fileName != null
+							&& PATTERN_LOOSE_OBJECT.matcher(fileName.toString())
+									.matches();
 				})) {
-			for (Iterator<Path> iter = stream.iterator(); iter.hasNext();
-					iter.next()) {
+			for (Iterator<Path> iter = stream.iterator(); iter.hasNext(); iter
+					.next()) {
 				if (++n > threshold) {
 					return true;
 				}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GcLog.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GcLog.java
index 994a432..c159a94 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GcLog.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GcLog.java
@@ -43,7 +43,7 @@
 
 package org.eclipse.jgit.internal.storage.file;
 
-import static java.nio.charset.StandardCharsets.UTF_8;
+import static org.eclipse.jgit.lib.Constants.CHARSET;
 
 import java.io.BufferedReader;
 import java.io.File;
@@ -58,6 +58,7 @@
 import org.eclipse.jgit.api.errors.JGitInternalException;
 import org.eclipse.jgit.internal.JGitText;
 import org.eclipse.jgit.lib.ConfigConstants;
+import org.eclipse.jgit.util.FileUtils;
 import org.eclipse.jgit.util.GitDateParser;
 import org.eclipse.jgit.util.SystemReader;
 
@@ -105,12 +106,12 @@ private Instant getLogExpiry() throws ParseException {
 
 	private boolean autoGcBlockedByOldLockFile(boolean background) {
 		try {
-			FileTime lastModified = Files.getLastModifiedTime(logFile.toPath());
+			FileTime lastModified = Files.getLastModifiedTime(FileUtils.toPath(logFile));
 			if (lastModified.toInstant().compareTo(getLogExpiry()) > 0) {
 				// There is an existing log file, which is too recent to ignore
 				if (!background) {
 					try (BufferedReader reader = Files
-							.newBufferedReader(logFile.toPath())) {
+							.newBufferedReader(FileUtils.toPath(logFile))) {
 						char[] buf = new char[1000];
 						int len = reader.read(buf, 0, 1000);
 						String oldError = new String(buf, 0, len);
@@ -186,6 +187,6 @@ void write(String content) throws IOException {
 		if (content.length() > 0) {
 			nonEmpty = true;
 		}
-		lock.write(content.getBytes(UTF_8));
+		lock.write(content.getBytes(CHARSET));
 	}
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GlobalAttributesNode.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GlobalAttributesNode.java
index 454d3bf..2f5de04 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GlobalAttributesNode.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GlobalAttributesNode.java
@@ -51,20 +51,27 @@
 import org.eclipse.jgit.lib.Repository;
 import org.eclipse.jgit.util.FS;
 
-/** Attribute node loaded from global system-wide file. */
+/**
+ * Attribute node loaded from global system-wide file.
+ */
 public class GlobalAttributesNode extends AttributesNode {
 	final Repository repository;
 
 	/**
+	 * Constructor for GlobalAttributesNode.
+	 *
 	 * @param repository
+	 *            the {@link org.eclipse.jgit.lib.Repository}.
 	 */
 	public GlobalAttributesNode(Repository repository) {
 		this.repository = repository;
 	}
 
 	/**
+	 * Load the attributes node
+	 *
 	 * @return the attributes node
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 */
 	public AttributesNode load() throws IOException {
 		AttributesNode r = new AttributesNode();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/InfoAttributesNode.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/InfoAttributesNode.java
index 3f82e2a..cd093741 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/InfoAttributesNode.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/InfoAttributesNode.java
@@ -51,20 +51,27 @@
 import org.eclipse.jgit.lib.Repository;
 import org.eclipse.jgit.util.FS;
 
-/** Attribute node loaded from the $GIT_DIR/info/attributes file. */
+/**
+ * Attribute node loaded from the $GIT_DIR/info/attributes file.
+ */
 public class InfoAttributesNode extends AttributesNode {
 	final Repository repository;
 
 	/**
+	 * Constructor for InfoAttributesNode.
+	 *
 	 * @param repository
+	 *            the {@link org.eclipse.jgit.lib.Repository}.
 	 */
 	public InfoAttributesNode(Repository repository) {
 		this.repository = repository;
 	}
 
 	/**
+	 * Load the attributes node
+	 *
 	 * @return the attributes node
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 */
 	public AttributesNode load() throws IOException {
 		AttributesNode r = new AttributesNode();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/LargePackedWholeObject.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/LargePackedWholeObject.java
index 4d6e4dd..8c42aaa 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/LargePackedWholeObject.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/LargePackedWholeObject.java
@@ -77,32 +77,35 @@ class LargePackedWholeObject extends ObjectLoader {
 		this.db = db;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public int getType() {
 		return type;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public long getSize() {
 		return size;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public boolean isLarge() {
 		return true;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public byte[] getCachedBytes() throws LargeObjectException {
 		try {
 			throw new LargeObjectException(getObjectId());
 		} catch (IOException cannotObtainId) {
-			LargeObjectException err = new LargeObjectException();
-			err.initCause(cannotObtainId);
-			throw err;
+			throw new LargeObjectException(cannotObtainId);
 		}
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public ObjectStream openStream() throws MissingObjectException, IOException {
 		WindowCursor wc = new WindowCursor(db);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/LazyObjectIdSetFile.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/LazyObjectIdSetFile.java
index 1e2617c..c82d52e 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/LazyObjectIdSetFile.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/LazyObjectIdSetFile.java
@@ -43,7 +43,7 @@
 
 package org.eclipse.jgit.internal.storage.file;
 
-import static java.nio.charset.StandardCharsets.UTF_8;
+import static org.eclipse.jgit.lib.Constants.CHARSET;
 
 import java.io.BufferedReader;
 import java.io.File;
@@ -57,7 +57,9 @@
 import org.eclipse.jgit.lib.ObjectIdOwnerMap;
 import org.eclipse.jgit.lib.ObjectIdSet;
 
-/** Lazily loads a set of ObjectIds, one per line. */
+/**
+ * Lazily loads a set of ObjectIds, one per line.
+ */
 public class LazyObjectIdSetFile implements ObjectIdSet {
 	private final File src;
 	private ObjectIdOwnerMap<Entry> set;
@@ -72,6 +74,7 @@ public LazyObjectIdSetFile(File src) {
 		this.src = src;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public boolean contains(AnyObjectId objectId) {
 		if (set == null) {
@@ -83,7 +86,7 @@ public boolean contains(AnyObjectId objectId) {
 	private ObjectIdOwnerMap<Entry> load() {
 		ObjectIdOwnerMap<Entry> r = new ObjectIdOwnerMap<>();
 		try (FileInputStream fin = new FileInputStream(src);
-				Reader rin = new InputStreamReader(fin, UTF_8);
+				Reader rin = new InputStreamReader(fin, CHARSET);
 				BufferedReader br = new BufferedReader(rin)) {
 			MutableObjectId id = new MutableObjectId();
 			for (String line; (line = br.readLine()) != null;) {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/LocalCachedPack.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/LocalCachedPack.java
index fd9dcda..289d89d 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/LocalCachedPack.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/LocalCachedPack.java
@@ -71,6 +71,7 @@ class LocalCachedPack extends CachedPack {
 		this.packs = packs.toArray(new PackFile[packs.size()]);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public long getObjectCount() throws IOException {
 		long cnt = 0;
@@ -85,6 +86,7 @@ void copyAsIs(PackOutputStream out, WindowCursor wc)
 			pack.copyPackAsIs(out, wc);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public boolean hasObject(ObjectToPack obj, StoredObjectRepresentation rep) {
 		try {
@@ -118,7 +120,7 @@ private PackFile getPackFile(String packName) throws FileNotFoundException {
 	}
 
 	private String getPackFilePath(String packName) {
-		final File packDir = new File(odb.getDirectory(), "pack"); //$NON-NLS-1$
+		final File packDir = odb.getPackDirectory();
 		return new File(packDir, "pack-" + packName + ".pack").getPath(); //$NON-NLS-1$ //$NON-NLS-2$
 	}
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/LocalObjectRepresentation.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/LocalObjectRepresentation.java
index a42e679..35f9773 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/LocalObjectRepresentation.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/LocalObjectRepresentation.java
@@ -92,11 +92,13 @@ static LocalObjectRepresentation newDelta(PackFile f, long p, long n,
 
 	private ObjectId baseId;
 
+	/** {@inheritDoc} */
 	@Override
 	public int getWeight() {
 		return (int) Math.min(length, Integer.MAX_VALUE);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public ObjectId getDeltaBase() {
 		if (baseId == null && getFormat() == PACK_DELTA) {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/LocalObjectToPack.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/LocalObjectToPack.java
index fafe132..ed5cbfc 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/LocalObjectToPack.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/LocalObjectToPack.java
@@ -58,16 +58,18 @@ class LocalObjectToPack extends ObjectToPack {
 	/** Length of the data section of the object. */
 	long length;
 
-	LocalObjectToPack(AnyObjectId src, final int type) {
+	LocalObjectToPack(AnyObjectId src, int type) {
 		super(src, type);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected void clearReuseAsIs() {
 		super.clearReuseAsIs();
 		pack = null;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void select(StoredObjectRepresentation ref) {
 		LocalObjectRepresentation ptr = (LocalObjectRepresentation) ref;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/LockFile.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/LockFile.java
index 9b1fe8c..da9a050 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/LockFile.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/LockFile.java
@@ -44,6 +44,8 @@
 
 package org.eclipse.jgit.internal.storage.file;
 
+import static org.eclipse.jgit.lib.Constants.LOCK_SUFFIX;
+
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileNotFoundException;
@@ -57,7 +59,6 @@
 import java.nio.file.StandardCopyOption;
 import java.text.MessageFormat;
 
-import org.eclipse.jgit.errors.LockFailedException;
 import org.eclipse.jgit.internal.JGitText;
 import org.eclipse.jgit.lib.Constants;
 import org.eclipse.jgit.lib.ObjectId;
@@ -75,19 +76,20 @@
  * name.
  */
 public class LockFile {
-	static final String SUFFIX = ".lock"; //$NON-NLS-1$
 
 	/**
 	 * Unlock the given file.
 	 * <p>
 	 * This method can be used for recovering from a thrown
-	 * {@link LockFailedException} . This method does not validate that the lock
-	 * is or is not currently held before attempting to unlock it.
+	 * {@link org.eclipse.jgit.errors.LockFailedException} . This method does
+	 * not validate that the lock is or is not currently held before attempting
+	 * to unlock it.
 	 *
 	 * @param file
+	 *            a {@link java.io.File} object.
 	 * @return true if unlocked, false if unlocking failed
 	 */
-	public static boolean unlock(final File file) {
+	public static boolean unlock(File file) {
 		final File lockFile = getLockFile(file);
 		final int flags = FileUtils.RETRY | FileUtils.SKIP_MISSING;
 		try {
@@ -105,14 +107,15 @@ public static boolean unlock(final File file) {
 	 * @return lock file
 	 */
 	static File getLockFile(File file) {
-		return new File(file.getParentFile(), file.getName() + SUFFIX);
+		return new File(file.getParentFile(),
+				file.getName() + LOCK_SUFFIX);
 	}
 
 	/** Filter to skip over active lock files when listing a directory. */
 	static final FilenameFilter FILTER = new FilenameFilter() {
 		@Override
 		public boolean accept(File dir, String name) {
-			return !name.endsWith(SUFFIX);
+			return !name.endsWith(LOCK_SUFFIX);
 		}
 	};
 
@@ -135,24 +138,8 @@ public boolean accept(File dir, String name) {
 	 *
 	 * @param f
 	 *            the file that will be locked.
-	 * @param fs
-	 *            the file system abstraction which will be necessary to perform
-	 *            certain file system operations.
-	 * @deprecated use {@link LockFile#LockFile(File)} instead
 	 */
-	@Deprecated
-	public LockFile(final File f, final FS fs) {
-		ref = f;
-		lck = getLockFile(ref);
-	}
-
-	/**
-	 * Create a new lock for any file.
-	 *
-	 * @param f
-	 *            the file that will be locked.
-	 */
-	public LockFile(final File f) {
+	public LockFile(File f) {
 		ref = f;
 		lck = getLockFile(ref);
 	}
@@ -162,7 +149,7 @@ public LockFile(final File f) {
 	 *
 	 * @return true if the lock is now held by the caller; false if it is held
 	 *         by someone else.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the temporary output file could not be created. The caller
 	 *             does not hold the lock.
 	 */
@@ -185,7 +172,7 @@ public boolean lock() throws IOException {
 	 *
 	 * @return true if the lock is now held by the caller; false if it is held
 	 *         by someone else.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the temporary output file could not be created. The caller
 	 *             does not hold the lock.
 	 */
@@ -206,20 +193,19 @@ public boolean lockForAppend() throws IOException {
 	 * This method does nothing if the current file does not exist, or exists
 	 * but is empty.
 	 *
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the temporary file could not be written, or a read error
 	 *             occurred while reading from the current file. The lock is
 	 *             released before throwing the underlying IO exception to the
 	 *             caller.
-	 * @throws RuntimeException
+	 * @throws java.lang.RuntimeException
 	 *             the temporary file could not be written. The lock is released
 	 *             before throwing the underlying exception to the caller.
 	 */
 	public void copyCurrentContent() throws IOException {
 		requireLock();
 		try {
-			final FileInputStream fis = new FileInputStream(ref);
-			try {
+			try (FileInputStream fis = new FileInputStream(ref)) {
 				if (fsync) {
 					FileChannel in = fis.getChannel();
 					long pos = 0;
@@ -235,8 +221,6 @@ public void copyCurrentContent() throws IOException {
 					while ((r = fis.read(buf)) >= 0)
 						os.write(buf, 0, r);
 				}
-			} finally {
-				fis.close();
 			}
 		} catch (FileNotFoundException fnfe) {
 			if (ref.exists()) {
@@ -264,14 +248,14 @@ public void copyCurrentContent() throws IOException {
 	 * @param id
 	 *            the id to store in the file. The id will be written in hex,
 	 *            followed by a sole LF.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the temporary file could not be written. The lock is released
 	 *             before throwing the underlying IO exception to the caller.
-	 * @throws RuntimeException
+	 * @throws java.lang.RuntimeException
 	 *             the temporary file could not be written. The lock is released
 	 *             before throwing the underlying exception to the caller.
 	 */
-	public void write(final ObjectId id) throws IOException {
+	public void write(ObjectId id) throws IOException {
 		byte[] buf = new byte[Constants.OBJECT_ID_STRING_LENGTH + 1];
 		id.copyTo(buf, 0);
 		buf[Constants.OBJECT_ID_STRING_LENGTH] = '\n';
@@ -285,14 +269,14 @@ public void write(final ObjectId id) throws IOException {
 	 *            the bytes to store in the temporary file. No additional bytes
 	 *            are added, so if the file must end with an LF it must appear
 	 *            at the end of the byte array.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the temporary file could not be written. The lock is released
 	 *             before throwing the underlying IO exception to the caller.
-	 * @throws RuntimeException
+	 * @throws java.lang.RuntimeException
 	 *             the temporary file could not be written. The lock is released
 	 *             before throwing the underlying exception to the caller.
 	 */
-	public void write(final byte[] content) throws IOException {
+	public void write(byte[] content) throws IOException {
 		requireLock();
 		try {
 			if (fsync) {
@@ -338,18 +322,18 @@ public OutputStream getOutputStream() {
 
 		return new OutputStream() {
 			@Override
-			public void write(final byte[] b, final int o, final int n)
+			public void write(byte[] b, int o, int n)
 					throws IOException {
 				out.write(b, o, n);
 			}
 
 			@Override
-			public void write(final byte[] b) throws IOException {
+			public void write(byte[] b) throws IOException {
 				out.write(b);
 			}
 
 			@Override
-			public void write(final int b) throws IOException {
+			public void write(int b) throws IOException {
 				out.write(b);
 			}
 
@@ -389,17 +373,18 @@ void requireLock() {
 	 * @param on
 	 *            true if the commit method must remember the modification time.
 	 */
-	public void setNeedStatInformation(final boolean on) {
+	public void setNeedStatInformation(boolean on) {
 		setNeedSnapshot(on);
 	}
 
 	/**
-	 * Request that {@link #commit()} remember the {@link FileSnapshot}.
+	 * Request that {@link #commit()} remember the
+	 * {@link org.eclipse.jgit.internal.storage.file.FileSnapshot}.
 	 *
 	 * @param on
 	 *            true if the commit method must remember the FileSnapshot.
 	 */
-	public void setNeedSnapshot(final boolean on) {
+	public void setNeedSnapshot(boolean on) {
 		needSnapshot = on;
 	}
 
@@ -409,7 +394,7 @@ public void setNeedSnapshot(final boolean on) {
 	 * @param on
 	 *            true if dirty data should be forced to the drive.
 	 */
-	public void setFSync(final boolean on) {
+	public void setFSync(boolean on) {
 		fsync = on;
 	}
 
@@ -420,7 +405,7 @@ public void setFSync(final boolean on) {
 	 * method sleeps until it can force the new lock file's modification date to
 	 * be later than the target file.
 	 *
-	 * @throws InterruptedException
+	 * @throws java.lang.InterruptedException
 	 *             the thread was interrupted before the last modified date of
 	 *             the lock file was different from the last modified date of
 	 *             the target file.
@@ -443,7 +428,7 @@ public void waitForStatChange() throws InterruptedException {
 	 * @return true if the commit was successful and the file contains the new
 	 *         data; false if the commit failed and the file remains with the
 	 *         old data.
-	 * @throws IllegalStateException
+	 * @throws java.lang.IllegalStateException
 	 *             the lock is not held.
 	 */
 	public boolean commit() {
@@ -477,7 +462,11 @@ public long getCommitLastModified() {
 		return commitSnapshot.lastModified();
 	}
 
-	/** @return get the {@link FileSnapshot} just before commit. */
+	/**
+	 * Get the {@link FileSnapshot} just before commit.
+	 *
+	 * @return get the {@link FileSnapshot} just before commit.
+	 */
 	public FileSnapshot getCommitSnapshot() {
 		return commitSnapshot;
 	}
@@ -517,6 +506,7 @@ public void unlock() {
 		}
 	}
 
+	/** {@inheritDoc} */
 	@SuppressWarnings("nls")
 	@Override
 	public String toString() {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectory.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectory.java
index 153c7dd..51c5702 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectory.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectory.java
@@ -91,12 +91,12 @@
 import org.slf4j.LoggerFactory;
 
 /**
- * Traditional file system based {@link ObjectDatabase}.
+ * Traditional file system based {@link org.eclipse.jgit.lib.ObjectDatabase}.
  * <p>
  * This is the classical object database representation for a Git repository,
  * where objects are stored loose by hashing them into directories by their
- * {@link ObjectId}, or are stored in compressed containers known as
- * {@link PackFile}s.
+ * {@link org.eclipse.jgit.lib.ObjectId}, or are stored in compressed containers
+ * known as {@link org.eclipse.jgit.internal.storage.file.PackFile}s.
  * <p>
  * Optionally an object database can reference one or more alternates; other
  * ObjectDatabase instances that are searched in addition to the current
@@ -161,7 +161,7 @@ public class ObjectDirectory extends FileObjectDatabase {
 	 * @param shallowFile
 	 *            file which contains IDs of shallow commits, null if shallow
 	 *            commits handling should be turned off
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             an alternate object cannot be opened.
 	 */
 	public ObjectDirectory(final Config cfg, final File dir,
@@ -188,26 +188,38 @@ public ObjectDirectory(final Config cfg, final File dir,
 		}
 	}
 
-	/**
-	 * @return the location of the <code>objects</code> directory.
-	 */
+	/** {@inheritDoc} */
 	@Override
 	public final File getDirectory() {
 		return objects;
 	}
 
 	/**
+	 * <p>Getter for the field <code>packDirectory</code>.</p>
+	 *
+	 * @return the location of the <code>pack</code> directory.
+	 * @since 4.10
+	 */
+	public final File getPackDirectory() {
+		return packDirectory;
+	}
+
+	/**
+	 * <p>Getter for the field <code>preservedDirectory</code>.</p>
+	 *
 	 * @return the location of the <code>preserved</code> directory.
 	 */
 	public final File getPreservedDirectory() {
 		return preservedDirectory;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public boolean exists() {
 		return fs.exists(objects);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void create() throws IOException {
 		FileUtils.mkdirs(objects);
@@ -215,6 +227,7 @@ public void create() throws IOException {
 		FileUtils.mkdir(packDirectory);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public ObjectDirectoryInserter newInserter() {
 		return new ObjectDirectoryInserter(this, config);
@@ -230,6 +243,7 @@ public PackInserter newPackInserter() {
 		return new PackInserter(this);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void close() {
 		unpackedObjectCache.clear();
@@ -243,18 +257,12 @@ public void close() {
 		// Fully close all loaded alternates and clear the alternate list.
 		AlternateHandle[] alt = alternates.get();
 		if (alt != null && alternates.compareAndSet(alt, null)) {
-			for(final AlternateHandle od : alt)
+			for(AlternateHandle od : alt)
 				od.close();
 		}
 	}
 
-	/**
-	 * @return unmodifiable collection of all known pack files local to this
-	 *         directory. Most recent packs are presented first. Packs most
-	 *         likely to contain more recent objects appear before packs
-	 *         containing objects referenced by commits further back in the
-	 *         history of the repository.
-	 */
+	/** {@inheritDoc} */
 	@Override
 	public Collection<PackFile> getPacks() {
 		PackList list = packList.get();
@@ -265,17 +273,12 @@ public Collection<PackFile> getPacks() {
 	}
 
 	/**
+	 * {@inheritDoc}
+	 * <p>
 	 * Add a single existing pack to the list of available pack files.
-	 *
-	 * @param pack
-	 *            path of the pack file to open.
-	 * @return the pack that was opened and added to the database.
-	 * @throws IOException
-	 *             index file could not be opened, read, or is not recognized as
-	 *             a Git pack file index.
 	 */
 	@Override
-	public PackFile openPack(final File pack)
+	public PackFile openPack(File pack)
 			throws IOException {
 		final String p = pack.getName();
 		if (p.length() != 50 || !p.startsWith("pack-") || !p.endsWith(".pack")) //$NON-NLS-1$ //$NON-NLS-2$
@@ -299,11 +302,13 @@ public PackFile openPack(final File pack)
 		return res;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public String toString() {
 		return "ObjectDirectory[" + getDirectory() + "]"; //$NON-NLS-1$ //$NON-NLS-2$
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public boolean has(AnyObjectId objectId) {
 		return unpackedObjectCache.isUnpacked(objectId)
@@ -614,7 +619,7 @@ private void selectObjectRepresentation(PackWriter packer, ObjectToPack otp,
 			WindowCursor curs, Set<AlternateHandle.Id> skips) throws IOException {
 		PackList pList = packList.get();
 		SEARCH: for (;;) {
-			for (final PackFile p : pList.packs) {
+			for (PackFile p : pList.packs) {
 				try {
 					LocalObjectRepresentation rep = p.representation(curs, otp);
 					p.resetTransientErrorCount();
@@ -715,7 +720,7 @@ InsertLooseObjectResult insertUnpackedObject(File tmp, ObjectId id,
 			return InsertLooseObjectResult.EXISTS_LOOSE;
 		}
 		try {
-			Files.move(tmp.toPath(), dst.toPath(),
+			Files.move(FileUtils.toPath(tmp), FileUtils.toPath(dst),
 					StandardCopyOption.ATOMIC_MOVE);
 			dst.setReadOnly();
 			unpackedObjectCache.add(id);
@@ -732,7 +737,7 @@ InsertLooseObjectResult insertUnpackedObject(File tmp, ObjectId id,
 		//
 		FileUtils.mkdir(dst.getParentFile(), true);
 		try {
-			Files.move(tmp.toPath(), dst.toPath(),
+			Files.move(FileUtils.toPath(tmp), FileUtils.toPath(dst),
 					StandardCopyOption.ATOMIC_MOVE);
 			dst.setReadOnly();
 			unpackedObjectCache.add(id);
@@ -791,8 +796,7 @@ Set<ObjectId> getShallowCommits() throws IOException {
 				|| shallowFileSnapshot.isModified(shallowFile)) {
 			shallowCommitsIds = new HashSet<>();
 
-			final BufferedReader reader = open(shallowFile);
-			try {
+			try (BufferedReader reader = open(shallowFile)) {
 				String line;
 				while ((line = reader.readLine()) != null) {
 					try {
@@ -802,8 +806,6 @@ Set<ObjectId> getShallowCommits() throws IOException {
 								.format(JGitText.get().badShallowLine, line));
 					}
 				}
-			} finally {
-				reader.close();
 			}
 
 			shallowFileSnapshot = FileSnapshot.save(shallowFile);
@@ -812,7 +814,7 @@ Set<ObjectId> getShallowCommits() throws IOException {
 		return shallowCommitsIds;
 	}
 
-	private void insertPack(final PackFile pf) {
+	private void insertPack(PackFile pf) {
 		PackList o, n;
 		do {
 			o = packList.get();
@@ -835,7 +837,7 @@ private void insertPack(final PackFile pf) {
 		} while (!packList.compareAndSet(o, n));
 	}
 
-	private void removePack(final PackFile deadPack) {
+	private void removePack(PackFile deadPack) {
 		PackList o, n;
 		do {
 			o = packList.get();
@@ -853,7 +855,7 @@ private void removePack(final PackFile deadPack) {
 		deadPack.close();
 	}
 
-	private static int indexOf(final PackFile[] list, final PackFile pack) {
+	private static int indexOf(PackFile[] list, PackFile pack) {
 		for (int i = 0; i < list.length; i++) {
 			if (list[i] == pack)
 				return i;
@@ -861,7 +863,7 @@ private static int indexOf(final PackFile[] list, final PackFile pack) {
 		return -1;
 	}
 
-	private PackList scanPacks(final PackList original) {
+	private PackList scanPacks(PackList original) {
 		synchronized (packList) {
 			PackList o, n;
 			do {
@@ -880,13 +882,13 @@ private PackList scanPacks(final PackList original) {
 		}
 	}
 
-	private PackList scanPacksImpl(final PackList old) {
+	private PackList scanPacksImpl(PackList old) {
 		final Map<String, PackFile> forReuse = reuseMap(old);
 		final FileSnapshot snapshot = FileSnapshot.save(packDirectory);
 		final Set<String> names = listPackDirectory();
 		final List<PackFile> list = new ArrayList<>(names.size() >> 2);
 		boolean foundNew = false;
-		for (final String indexName : names) {
+		for (String indexName : names) {
 			// Must match "pack-[0-9a-f]{40}.idx" to be an index.
 			//
 			if (indexName.length() != 49 || !indexName.endsWith(".idx")) //$NON-NLS-1$
@@ -929,7 +931,7 @@ private PackList scanPacksImpl(final PackList old) {
 			return old;
 		}
 
-		for (final PackFile p : forReuse.values()) {
+		for (PackFile p : forReuse.values()) {
 			p.close();
 		}
 
@@ -941,9 +943,9 @@ private PackList scanPacksImpl(final PackList old) {
 		return new PackList(snapshot, r);
 	}
 
-	private static Map<String, PackFile> reuseMap(final PackList old) {
+	private static Map<String, PackFile> reuseMap(PackList old) {
 		final Map<String, PackFile> forReuse = new HashMap<>();
-		for (final PackFile p : old.packs) {
+		for (PackFile p : old.packs) {
 			if (p.invalid()) {
 				// The pack instance is corrupted, and cannot be safely used
 				// again. Do not include it in our reuse map.
@@ -972,7 +974,7 @@ private Set<String> listPackDirectory() {
 		if (nameList == null)
 			return Collections.emptySet();
 		final Set<String> nameSet = new HashSet<>(nameList.length << 1);
-		for (final String name : nameList) {
+		for (String name : nameList) {
 			if (name.startsWith("pack-")) //$NON-NLS-1$
 				nameSet.add(name);
 		}
@@ -1022,24 +1024,21 @@ Set<AlternateHandle.Id> addMe(Set<AlternateHandle.Id> skips) {
 
 	private AlternateHandle[] loadAlternates() throws IOException {
 		final List<AlternateHandle> l = new ArrayList<>(4);
-		final BufferedReader br = open(alternatesFile);
-		try {
+		try (BufferedReader br = open(alternatesFile)) {
 			String line;
 			while ((line = br.readLine()) != null) {
 				l.add(openAlternate(line));
 			}
-		} finally {
-			br.close();
 		}
 		return l.toArray(new AlternateHandle[l.size()]);
 	}
 
-	private static BufferedReader open(final File f)
+	private static BufferedReader open(File f)
 			throws FileNotFoundException {
 		return new BufferedReader(new FileReader(f));
 	}
 
-	private AlternateHandle openAlternate(final String location)
+	private AlternateHandle openAlternate(String location)
 			throws IOException {
 		final File objdir = fs.resolve(objects, location);
 		return openAlternate(objdir);
@@ -1058,11 +1057,9 @@ private AlternateHandle openAlternate(File objdir) throws IOException {
 	}
 
 	/**
+	 * {@inheritDoc}
+	 * <p>
 	 * Compute the location of a loose object file.
-	 *
-	 * @param objectId
-	 *            identity of the loose object to map to the directory.
-	 * @return location of the object, if it were to exist as a loose object.
 	 */
 	@Override
 	public File fileFor(AnyObjectId objectId) {
@@ -1079,7 +1076,7 @@ private static final class PackList {
 		/** All known packs, sorted by {@link PackFile#SORT}. */
 		final PackFile[] packs;
 
-		PackList(final FileSnapshot monitor, final PackFile[] packs) {
+		PackList(FileSnapshot monitor, PackFile[] packs) {
 			this.snapshot = monitor;
 			this.packs = packs;
 		}
@@ -1147,6 +1144,7 @@ void close() {
 		}
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public ObjectDatabase newCachedDatabase() {
 		return newCachedFileObjectDatabase();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectoryInserter.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectoryInserter.java
index aa435bf..e5a54e3 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectoryInserter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectoryInserter.java
@@ -78,11 +78,12 @@ class ObjectDirectoryInserter extends ObjectInserter {
 
 	private Deflater deflate;
 
-	ObjectDirectoryInserter(final FileObjectDatabase dest, final Config cfg) {
+	ObjectDirectoryInserter(FileObjectDatabase dest, Config cfg) {
 		db = dest;
 		config = cfg.get(WriteConfig.KEY);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public ObjectId insert(int type, byte[] data, int off, int len)
 			throws IOException {
@@ -114,8 +115,9 @@ private ObjectId insert(
 		}
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	public ObjectId insert(final int type, long len, final InputStream is)
+	public ObjectId insert(int type, long len, InputStream is)
 			throws IOException {
 		return insert(type, len, is, false);
 	}
@@ -166,21 +168,25 @@ private ObjectId insertOneObject(
 				.format(JGitText.get().unableToCreateNewObject, dst));
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public PackParser newPackParser(InputStream in) throws IOException {
 		return new ObjectDirectoryPackParser(db, in);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public ObjectReader newReader() {
 		return new WindowCursor(db, this);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void flush() throws IOException {
 		// Do nothing. Loose objects are immediately visible.
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void close() {
 		if (deflate != null) {
@@ -261,7 +267,7 @@ private File toTemp(final int type, final byte[] buf, final int pos,
 		}
 	}
 
-	void writeHeader(OutputStream out, final int type, long len)
+	void writeHeader(OutputStream out, int type, long len)
 			throws IOException {
 		out.write(Constants.encodedTypeString(type));
 		out.write((byte) ' ');
@@ -273,7 +279,7 @@ File newTempFile() throws IOException {
 		return File.createTempFile("noz", null, db.getDirectory()); //$NON-NLS-1$
 	}
 
-	DeflaterOutputStream compress(final OutputStream out) {
+	DeflaterOutputStream compress(OutputStream out) {
 		if (deflate == null)
 			deflate = new Deflater(config.getCompression());
 		else
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectoryPackParser.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectoryPackParser.java
index 2e6c245..0cec2d5 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectoryPackParser.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectoryPackParser.java
@@ -64,7 +64,6 @@
 import org.eclipse.jgit.lib.Constants;
 import org.eclipse.jgit.lib.CoreConfig;
 import org.eclipse.jgit.lib.ObjectId;
-import org.eclipse.jgit.lib.ObjectInserter;
 import org.eclipse.jgit.lib.ProgressMonitor;
 import org.eclipse.jgit.transport.PackParser;
 import org.eclipse.jgit.transport.PackedObjectInfo;
@@ -72,10 +71,11 @@
 import org.eclipse.jgit.util.NB;
 
 /**
- * Consumes a pack stream and stores as a pack file in {@link ObjectDirectory}.
+ * Consumes a pack stream and stores as a pack file in
+ * {@link org.eclipse.jgit.internal.storage.file.ObjectDirectory}.
  * <p>
  * To obtain an instance of a parser, applications should use
- * {@link ObjectInserter#newPackParser(InputStream)}.
+ * {@link org.eclipse.jgit.lib.ObjectInserter#newPackParser(InputStream)}.
  */
 public class ObjectDirectoryPackParser extends PackParser {
 	private final FileObjectDatabase db;
@@ -153,12 +153,12 @@ public void setIndexVersion(int version) {
 	 * @param empty
 	 *            true to enable keeping an empty pack.
 	 */
-	public void setKeepEmpty(final boolean empty) {
+	public void setKeepEmpty(boolean empty) {
 		keepEmpty = empty;
 	}
 
 	/**
-	 * Get the imported {@link PackFile}.
+	 * Get the imported {@link org.eclipse.jgit.internal.storage.file.PackFile}.
 	 * <p>
 	 * This method is supplied only to support testing; applications shouldn't
 	 * be using it directly to access the imported data.
@@ -169,6 +169,7 @@ public PackFile getPackFile() {
 		return newPack;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public long getPackSize() {
 		if (newPack == null)
@@ -184,6 +185,7 @@ public long getPackSize() {
 		return size;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public PackLock parse(ProgressMonitor receiving, ProgressMonitor resolving)
 			throws IOException {
@@ -218,34 +220,40 @@ public PackLock parse(ProgressMonitor receiving, ProgressMonitor resolving)
 		}
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected void onPackHeader(long objectCount) throws IOException {
 		// Ignored, the count is not required.
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected void onBeginWholeObject(long streamPosition, int type,
 			long inflatedSize) throws IOException {
 		crc.reset();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected void onEndWholeObject(PackedObjectInfo info) throws IOException {
 		info.setCRC((int) crc.getValue());
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected void onBeginOfsDelta(long streamPosition,
 			long baseStreamPosition, long inflatedSize) throws IOException {
 		crc.reset();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected void onBeginRefDelta(long streamPosition, AnyObjectId baseId,
 			long inflatedSize) throws IOException {
 		crc.reset();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected UnresolvedDelta onEndDelta() throws IOException {
 		UnresolvedDelta delta = new UnresolvedDelta();
@@ -253,30 +261,35 @@ protected UnresolvedDelta onEndDelta() throws IOException {
 		return delta;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected void onInflatedObjectData(PackedObjectInfo obj, int typeCode,
 			byte[] data) throws IOException {
 		// ObjectDirectory ignores this event.
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected void onObjectHeader(Source src, byte[] raw, int pos, int len)
 			throws IOException {
 		crc.update(raw, pos, len);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected void onObjectData(Source src, byte[] raw, int pos, int len)
 			throws IOException {
 		crc.update(raw, pos, len);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected void onStoreStream(byte[] raw, int pos, int len)
 			throws IOException {
 		out.write(raw, pos, len);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected void onPackFooter(byte[] hash) throws IOException {
 		packEnd = out.getFilePointer();
@@ -285,6 +298,7 @@ protected void onPackFooter(byte[] hash) throws IOException {
 		packHash = hash;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected ObjectTypeAndSize seekDatabase(UnresolvedDelta delta,
 			ObjectTypeAndSize info) throws IOException {
@@ -293,6 +307,7 @@ protected ObjectTypeAndSize seekDatabase(UnresolvedDelta delta,
 		return readObjectHeader(info);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected ObjectTypeAndSize seekDatabase(PackedObjectInfo obj,
 			ObjectTypeAndSize info) throws IOException {
@@ -301,11 +316,13 @@ protected ObjectTypeAndSize seekDatabase(PackedObjectInfo obj,
 		return readObjectHeader(info);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected int readDatabase(byte[] dst, int pos, int cnt) throws IOException {
 		return out.read(dst, pos, cnt);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected boolean checkCRC(int oldCRC) {
 		return oldCRC == (int) crc.getValue();
@@ -323,6 +340,7 @@ private void cleanupTemporaryFiles() {
 			tmpPack.deleteOnExit();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected boolean onAppendBase(final int typeCode, final byte[] data,
 			final PackedObjectInfo info) throws IOException {
@@ -365,6 +383,7 @@ protected boolean onAppendBase(final int typeCode, final byte[] data,
 		return true;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected void onEndThinPack() throws IOException {
 		final byte[] buf = buffer();
@@ -410,8 +429,7 @@ protected void onEndThinPack() throws IOException {
 
 	private void writeIdx() throws IOException {
 		List<PackedObjectInfo> list = getSortedObjectList(null /* by ObjectId */);
-		final FileOutputStream os = new FileOutputStream(tmpIdx);
-		try {
+		try (FileOutputStream os = new FileOutputStream(tmpIdx)) {
 			final PackIndexWriter iw;
 			if (indexVersion <= 0)
 				iw = PackIndexWriter.createOldestPossible(os, list);
@@ -419,12 +437,10 @@ private void writeIdx() throws IOException {
 				iw = PackIndexWriter.createVersion(os, indexVersion);
 			iw.write(list, packHash);
 			os.getChannel().force(true);
-		} finally {
-			os.close();
 		}
 	}
 
-	private PackLock renameAndOpenPack(final String lockMessage)
+	private PackLock renameAndOpenPack(String lockMessage)
 			throws IOException {
 		if (!keepEmpty && getObjectCount() == 0) {
 			cleanupTemporaryFiles();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackBitmapIndex.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackBitmapIndex.java
index 7fb8e6d..6772e2c 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackBitmapIndex.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackBitmapIndex.java
@@ -44,7 +44,6 @@
 package org.eclipse.jgit.internal.storage.file;
 
 import java.io.File;
-import java.io.FileInputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.text.MessageFormat;
@@ -53,16 +52,17 @@
 import org.eclipse.jgit.internal.JGitText;
 import org.eclipse.jgit.lib.AnyObjectId;
 import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.util.io.SilentFileInputStream;
 
 import com.googlecode.javaewah.EWAHCompressedBitmap;
 
 /**
  * Logical representation of the bitmap data stored in the pack index.
- * {@link ObjectId}s are encoded as a single integer in the range [0,
- * {@link #getObjectCount()}). Compressed bitmaps are available at certain
- * {@code ObjectId}s, which represent all of the objects reachable from that
- * {@code ObjectId} (include the {@code ObjectId} itself). The meaning of the
- * positions in the bitmaps can be decoded using {@link #getObject(int)} and
+ * {@link org.eclipse.jgit.lib.ObjectId}s are encoded as a single integer in the
+ * range [0, {@link #getObjectCount()}). Compressed bitmaps are available at
+ * certain {@code ObjectId}s, which represent all of the objects reachable from
+ * that {@code ObjectId} (include the {@code ObjectId} itself). The meaning of
+ * the positions in the bitmaps can be decoded using {@link #getObject(int)} and
  * {@link #ofObjectType(EWAHCompressedBitmap, int)}. Furthermore,
  * {@link #findPosition(AnyObjectId)} can be used to build other bitmaps that a
  * compatible with the encoded bitmaps available from the index.
@@ -85,7 +85,7 @@ public abstract class PackBitmapIndex {
 	 * @param reverseIndex
 	 *            the pack reverse index for the corresponding pack file.
 	 * @return a copy of the index in-memory.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the stream cannot be read.
 	 * @throws CorruptObjectException
 	 *             the stream does not contain a valid pack bitmap index.
@@ -93,21 +93,15 @@ public abstract class PackBitmapIndex {
 	public static PackBitmapIndex open(
 			File idxFile, PackIndex packIndex, PackReverseIndex reverseIndex)
 			throws IOException {
-		final FileInputStream fd = new FileInputStream(idxFile);
-		try {
-			return read(fd, packIndex, reverseIndex);
-		} catch (IOException ioe) {
-			final String path = idxFile.getAbsolutePath();
-			final IOException err;
-			err = new IOException(MessageFormat.format(
-					JGitText.get().unreadablePackIndex, path));
-			err.initCause(ioe);
-			throw err;
-		} finally {
+		try (SilentFileInputStream fd = new SilentFileInputStream(
+				idxFile)) {
 			try {
-				fd.close();
-			} catch (IOException err2) {
-				// ignore
+				return read(fd, packIndex, reverseIndex);
+			} catch (IOException ioe) {
+				throw new IOException(
+						MessageFormat.format(JGitText.get().unreadablePackIndex,
+								idxFile.getAbsolutePath()),
+						ioe);
 			}
 		}
 	}
@@ -128,7 +122,7 @@ public static PackBitmapIndex open(
 	 * @param reverseIndex
 	 *            the pack reverse index for the corresponding pack file.
 	 * @return a copy of the index in-memory.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the stream cannot be read.
 	 * @throws CorruptObjectException
 	 *             the stream does not contain a valid pack bitmap index.
@@ -157,7 +151,7 @@ public static PackBitmapIndex read(
 	 * @param position
 	 *            the id for which the object will be found.
 	 * @return the ObjectId.
-	 * @throws IllegalArgumentException
+	 * @throws java.lang.IllegalArgumentException
 	 *             when the item is not found.
 	 */
 	public abstract ObjectId getObject(int position) throws IllegalArgumentException;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackBitmapIndexBuilder.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackBitmapIndexBuilder.java
index bfd60fc..70eb10e 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackBitmapIndexBuilder.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackBitmapIndexBuilder.java
@@ -64,7 +64,8 @@
 import com.googlecode.javaewah.EWAHCompressedBitmap;
 
 /**
- * Helper for constructing {@link PackBitmapIndex}es.
+ * Helper for constructing
+ * {@link org.eclipse.jgit.internal.storage.file.PackBitmapIndex}es.
  */
 public class PackBitmapIndexBuilder extends BasePackBitmapIndex {
 	private static final int MAX_XOR_OFFSET_SEARCH = 10;
@@ -145,7 +146,11 @@ public int compare(ObjectToPack a, ObjectToPack b) {
 		}
 	}
 
-	/** @return set of objects included in the pack. */
+	/**
+	 * Get set of objects included in the pack.
+	 *
+	 * @return set of objects included in the pack.
+	 */
 	public ObjectIdOwnerMap<ObjectIdOwnerMap.Entry> getObjectSet() {
 		ObjectIdOwnerMap<ObjectIdOwnerMap.Entry> r = new ObjectIdOwnerMap<>();
 		for (PositionEntry e : byOffset) {
@@ -197,6 +202,7 @@ public void addBitmap(
 		byAddOrder.add(result);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public EWAHCompressedBitmap ofObjectType(
 			EWAHCompressedBitmap bitmap, int type) {
@@ -213,6 +219,7 @@ public EWAHCompressedBitmap ofObjectType(
 		throw new IllegalArgumentException();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public int findPosition(AnyObjectId objectId) {
 		PositionEntry entry = positionEntries.get(objectId);
@@ -221,6 +228,7 @@ public int findPosition(AnyObjectId objectId) {
 		return entry.offsetPosition;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public ObjectId getObject(int position) throws IllegalArgumentException {
 		ObjectId objectId = byOffset.get(position);
@@ -229,48 +237,76 @@ public ObjectId getObject(int position) throws IllegalArgumentException {
 		return objectId;
 	}
 
-	/** @return the commit object bitmap. */
+	/**
+	 * Get the commit object bitmap.
+	 *
+	 * @return the commit object bitmap.
+	 */
 	public EWAHCompressedBitmap getCommits() {
 		return commits;
 	}
 
-	/** @return the tree object bitmap. */
+	/**
+	 * Get the tree object bitmap.
+	 *
+	 * @return the tree object bitmap.
+	 */
 	public EWAHCompressedBitmap getTrees() {
 		return trees;
 	}
 
-	/** @return the blob object bitmap. */
+	/**
+	 * Get the blob object bitmap.
+	 *
+	 * @return the blob object bitmap.
+	 */
 	public EWAHCompressedBitmap getBlobs() {
 		return blobs;
 	}
 
-	/** @return the tag object bitmap. */
+	/**
+	 * Get the tag object bitmap.
+	 *
+	 * @return the tag object bitmap.
+	 */
 	public EWAHCompressedBitmap getTags() {
 		return tags;
 	}
 
-	/** @return the index storage options. */
+	/**
+	 * Get the index storage options.
+	 *
+	 * @return the index storage options.
+	 */
 	public int getOptions() {
 		return PackBitmapIndexV1.OPT_FULL;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public int getBitmapCount() {
 		return getBitmaps().size();
 	}
 
-	/** Removes all the bitmaps entries added. */
+	/**
+	 * Remove all the bitmaps entries added.
+	 */
 	public void clearBitmaps() {
 		byAddOrder.clear();
 		getBitmaps().clear();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public int getObjectCount() {
 		return byOffset.size();
 	}
 
-	/** @return an iterator over the xor compressed entries. */
+	/**
+	 * Get an iterator over the xor compressed entries.
+	 *
+	 * @return an iterator over the xor compressed entries.
+	 */
 	public Iterable<StoredEntry> getCompressedBitmaps() {
 		// Add order is from oldest to newest. The reverse add order is the
 		// output order.
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackBitmapIndexRemapper.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackBitmapIndexRemapper.java
index 9a8c275..c04c90f 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackBitmapIndexRemapper.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackBitmapIndexRemapper.java
@@ -116,27 +116,32 @@ private PackBitmapIndexRemapper(
 					oldPackIndex.getObject(pos));
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public int findPosition(AnyObjectId objectId) {
 		return newPackIndex.findPosition(objectId);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public ObjectId getObject(int position) throws IllegalArgumentException {
 		return newPackIndex.getObject(position);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public int getObjectCount() {
 		return newPackIndex.getObjectCount();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public EWAHCompressedBitmap ofObjectType(
 			EWAHCompressedBitmap bitmap, int type) {
 		return newPackIndex.ofObjectType(bitmap, type);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public Iterator<Entry> iterator() {
 		if (oldPackIndex == null)
@@ -173,6 +178,7 @@ public void remove() {
 		};
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public EWAHCompressedBitmap getBitmap(AnyObjectId objectId) {
 		EWAHCompressedBitmap bitmap = newPackIndex.getBitmap(objectId);
@@ -214,6 +220,7 @@ public int getFlags() {
 		}
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public int getBitmapCount() {
 		// The count is only useful for the end index, not the remapper.
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackBitmapIndexV1.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackBitmapIndexV1.java
index 9d2c70b..b172ca4 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackBitmapIndexV1.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackBitmapIndexV1.java
@@ -175,6 +175,7 @@ class PackBitmapIndexV1 extends BasePackBitmapIndex {
 		}
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public int findPosition(AnyObjectId objectId) {
 		long offset = packIndex.findOffset(objectId);
@@ -183,6 +184,7 @@ public int findPosition(AnyObjectId objectId) {
 		return reverseIndex.findPostion(offset);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public ObjectId getObject(int position) throws IllegalArgumentException {
 		ObjectId objectId = reverseIndex.findObjectByPosition(position);
@@ -191,11 +193,13 @@ public ObjectId getObject(int position) throws IllegalArgumentException {
 		return objectId;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public int getObjectCount() {
 		return (int) packIndex.getObjectCount();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public EWAHCompressedBitmap ofObjectType(
 			EWAHCompressedBitmap bitmap, int type) {
@@ -212,11 +216,13 @@ public EWAHCompressedBitmap ofObjectType(
 		throw new IllegalArgumentException();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public int getBitmapCount() {
 		return bitmaps.size();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public boolean equals(Object o) {
 		// TODO(cranger): compare the pack checksum?
@@ -225,6 +231,7 @@ public boolean equals(Object o) {
 		return false;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public int hashCode() {
 		return getPackIndex().hashCode();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackBitmapIndexWriterV1.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackBitmapIndexWriterV1.java
index f8f02e9..d0c84da 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackBitmapIndexWriterV1.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackBitmapIndexWriterV1.java
@@ -89,7 +89,7 @@ public PackBitmapIndexWriterV1(final OutputStream dst) {
 	 * @param packDataChecksum
 	 *            checksum signature of the entire pack data content. This is
 	 *            traditionally the last 20 bytes of the pack file's own stream.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             an error occurred while writing to the output stream, or this
 	 *             index format cannot store the object data supplied.
 	 */
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackFile.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackFile.java
index 0611d3e..71f64ae 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackFile.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackFile.java
@@ -103,7 +103,7 @@ public class PackFile implements Iterable<PackIndex.MutableEntry> {
 	/** Sorts PackFiles to be most recently created to least recently created. */
 	public static final Comparator<PackFile> SORT = new Comparator<PackFile>() {
 		@Override
-		public int compare(final PackFile a, final PackFile b) {
+		public int compare(PackFile a, PackFile b) {
 			return b.packLastModified - a.packLastModified;
 		}
 	};
@@ -162,7 +162,7 @@ public int compare(final PackFile a, final PackFile b) {
 	 * @param extensions
 	 *            additional pack file extensions with the same base as the pack
 	 */
-	public PackFile(final File packFile, int extensions) {
+	public PackFile(File packFile, int extensions) {
 		this.packFile = packFile;
 		this.packLastModified = (int) (packFile.lastModified() >> 10);
 		this.extensions = extensions;
@@ -201,20 +201,30 @@ private synchronized PackIndex idx() throws IOException {
 		return loadedIdx;
 	}
 
-	/** @return the File object which locates this pack on disk. */
+	/**
+	 * Get the File object which locates this pack on disk.
+	 *
+	 * @return the File object which locates this pack on disk.
+	 */
 	public File getPackFile() {
 		return packFile;
 	}
 
 	/**
+	 * Get the index for this pack file.
+	 *
 	 * @return the index for this pack file.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 */
 	public PackIndex getIndex() throws IOException {
 		return idx();
 	}
 
-	/** @return name extracted from {@code pack-*.pack} pattern. */
+	/**
+	 * Get name extracted from {@code pack-*.pack} pattern.
+	 *
+	 * @return name extracted from {@code pack-*.pack} pattern.
+	 */
 	public String getPackName() {
 		String name = packName;
 		if (name == null) {
@@ -238,10 +248,10 @@ public String getPackName() {
 	 * @param id
 	 *            the object to look for. Must not be null.
 	 * @return true if the object is in this pack; false otherwise.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the index file cannot be loaded into memory.
 	 */
-	public boolean hasObject(final AnyObjectId id) throws IOException {
+	public boolean hasObject(AnyObjectId id) throws IOException {
 		final long offset = idx().findOffset(id);
 		return 0 < offset && !isCorrupt(offset);
 	}
@@ -269,7 +279,7 @@ public boolean shouldBeKept() {
 	 * @throws IOException
 	 *             the pack file or the index could not be read.
 	 */
-	ObjectLoader get(final WindowCursor curs, final AnyObjectId id)
+	ObjectLoader get(WindowCursor curs, AnyObjectId id)
 			throws IOException {
 		final long offset = idx().findOffset(id);
 		return 0 < offset && !isCorrupt(offset) ? load(curs, offset) : null;
@@ -292,6 +302,8 @@ public void close() {
 	}
 
 	/**
+	 * {@inheritDoc}
+	 * <p>
 	 * Provide iterator over entries in associated pack index, that should also
 	 * exist in this pack file. Objects returned by such iterator are mutable
 	 * during iteration.
@@ -299,8 +311,6 @@ public void close() {
 	 * Iterator returns objects in SHA-1 lexicographical order.
 	 * </p>
 	 *
-	 * @return iterator over entries of associated pack index
-	 *
 	 * @see PackIndex#iterator()
 	 */
 	@Override
@@ -334,7 +344,7 @@ long getObjectCount() throws IOException {
 	 * @throws IOException
 	 *             the index file cannot be loaded into memory.
 	 */
-	ObjectId findObjectForOffset(final long offset) throws IOException {
+	ObjectId findObjectForOffset(long offset) throws IOException {
 		return getReverseIdx().findObject(offset);
 	}
 
@@ -505,19 +515,15 @@ private void copyAsIs2(PackOutputStream out, LocalObjectToPack src,
 			CorruptObjectException corruptObject = new CorruptObjectException(
 					MessageFormat.format(
 							JGitText.get().objectAtHasBadZlibStream,
-							Long.valueOf(src.offset), getPackFile()));
-			corruptObject.initCause(dataFormat);
+							Long.valueOf(src.offset), getPackFile()),
+					dataFormat);
 
-			StoredObjectRepresentationNotAvailableException gone;
-			gone = new StoredObjectRepresentationNotAvailableException(src);
-			gone.initCause(corruptObject);
-			throw gone;
+			throw new StoredObjectRepresentationNotAvailableException(src,
+					corruptObject);
 
 		} catch (IOException ioError) {
-			StoredObjectRepresentationNotAvailableException gone;
-			gone = new StoredObjectRepresentationNotAvailableException(src);
-			gone.initCause(ioError);
-			throw gone;
+			throw new StoredObjectRepresentationNotAvailableException(src,
+					ioError);
 		}
 
 		if (quickCopy != null) {
@@ -602,11 +608,8 @@ private synchronized void beginCopyAsIs(ObjectToPack otp)
 			try {
 				doOpen();
 			} catch (IOException thisPackNotValid) {
-				StoredObjectRepresentationNotAvailableException gone;
-
-				gone = new StoredObjectRepresentationNotAvailableException(otp);
-				gone.initCause(thisPackNotValid);
-				throw gone;
+				throw new StoredObjectRepresentationNotAvailableException(otp,
+						thisPackNotValid);
 			}
 		}
 	}
@@ -689,7 +692,7 @@ private void doClose() {
 		}
 	}
 
-	ByteArrayWindow read(final long pos, int size) throws IOException {
+	ByteArrayWindow read(long pos, int size) throws IOException {
 		synchronized (readLock) {
 			if (length < pos + size)
 				size = (int) (length - pos);
@@ -700,7 +703,7 @@ ByteArrayWindow read(final long pos, int size) throws IOException {
 		}
 	}
 
-	ByteWindow mmap(final long pos, int size) throws IOException {
+	ByteWindow mmap(long pos, int size) throws IOException {
 		synchronized (readLock) {
 			if (length < pos + size)
 				size = (int) (length - pos);
@@ -757,7 +760,7 @@ private void onOpenPack() throws IOException {
 		}
 	}
 
-	ObjectLoader load(final WindowCursor curs, long pos)
+	ObjectLoader load(WindowCursor curs, long pos)
 			throws IOException, LargeObjectException {
 		try {
 			final byte[] ib = curs.tempId;
@@ -892,12 +895,11 @@ else if (delta.next == null)
 			return new ObjectLoader.SmallObject(type, data);
 
 		} catch (DataFormatException dfe) {
-			CorruptObjectException coe = new CorruptObjectException(
+			throw new CorruptObjectException(
 					MessageFormat.format(
 							JGitText.get().objectAtHasBadZlibStream,
-							Long.valueOf(pos), getPackFile()));
-			coe.initCause(dfe);
-			throw coe;
+							Long.valueOf(pos), getPackFile()),
+					dfe);
 		}
 	}
 
@@ -947,7 +949,7 @@ private static class Delta {
 		return hdr;
 	}
 
-	int getObjectType(final WindowCursor curs, long pos) throws IOException {
+	int getObjectType(WindowCursor curs, long pos) throws IOException {
 		final byte[] ib = curs.tempId;
 		for (;;) {
 			readFully(pos, ib, 0, 20, curs);
@@ -994,13 +996,13 @@ int getObjectType(final WindowCursor curs, long pos) throws IOException {
 		}
 	}
 
-	long getObjectSize(final WindowCursor curs, final AnyObjectId id)
+	long getObjectSize(WindowCursor curs, AnyObjectId id)
 			throws IOException {
 		final long offset = idx().findOffset(id);
 		return 0 < offset ? getObjectSize(curs, offset) : -1;
 	}
 
-	long getObjectSize(final WindowCursor curs, final long pos)
+	long getObjectSize(WindowCursor curs, long pos)
 			throws IOException {
 		final byte[] ib = curs.tempId;
 		readFully(pos, ib, 0, 20, curs);
@@ -1098,7 +1100,7 @@ LocalObjectRepresentation representation(final WindowCursor curs,
 		}
 	}
 
-	private long findEndOffset(final long startOffset)
+	private long findEndOffset(long startOffset)
 			throws IOException, CorruptObjectException {
 		final long maxOffset = length - 20;
 		return getReverseIdx().findNextOffset(startOffset, maxOffset);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackIndex.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackIndex.java
index 2252778..72699b0 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackIndex.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackIndex.java
@@ -45,7 +45,6 @@
 package org.eclipse.jgit.internal.storage.file;
 
 import java.io.File;
-import java.io.FileInputStream;
 import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.InputStream;
@@ -64,9 +63,11 @@
 import org.eclipse.jgit.lib.ObjectIdSet;
 import org.eclipse.jgit.util.IO;
 import org.eclipse.jgit.util.NB;
+import org.eclipse.jgit.util.io.SilentFileInputStream;
 
 /**
- * Access path to locate objects by {@link ObjectId} in a {@link PackFile}.
+ * Access path to locate objects by {@link org.eclipse.jgit.lib.ObjectId} in a
+ * {@link org.eclipse.jgit.internal.storage.file.PackFile}.
  * <p>
  * Indexes are strictly redundant information in that we can rebuild all of the
  * data held in the index file from the on disk representation of the pack file
@@ -89,26 +90,19 @@ public abstract class PackIndex
 	 * @return access implementation for the requested file.
 	 * @throws FileNotFoundException
 	 *             the file does not exist.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the file exists but could not be read due to security errors,
 	 *             unrecognized data version, or unexpected data corruption.
 	 */
-	public static PackIndex open(final File idxFile) throws IOException {
-		final FileInputStream fd = new FileInputStream(idxFile);
-		try {
-			return read(fd);
+	public static PackIndex open(File idxFile) throws IOException {
+		try (SilentFileInputStream fd = new SilentFileInputStream(
+				idxFile)) {
+				return read(fd);
 		} catch (IOException ioe) {
-			final String path = idxFile.getAbsolutePath();
-			final IOException err;
-			err = new IOException(MessageFormat.format(JGitText.get().unreadablePackIndex, path));
-			err.initCause(ioe);
-			throw err;
-		} finally {
-			try {
-				fd.close();
-			} catch (IOException err2) {
-				// ignore
-			}
+			throw new IOException(
+					MessageFormat.format(JGitText.get().unreadablePackIndex,
+							idxFile.getAbsolutePath()),
+					ioe);
 		}
 	}
 
@@ -124,9 +118,9 @@ public static PackIndex open(final File idxFile) throws IOException {
 	 *            buffered as some small IOs are performed against the stream.
 	 *            The caller is responsible for closing the stream.
 	 * @return a copy of the index in-memory.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the stream cannot be read.
-	 * @throws CorruptObjectException
+	 * @throws org.eclipse.jgit.errors.CorruptObjectException
 	 *             the stream does not contain a valid pack index.
 	 */
 	public static PackIndex read(InputStream fd) throws IOException,
@@ -145,7 +139,7 @@ public static PackIndex read(InputStream fd) throws IOException,
 		return new PackIndexV1(fd, hdr);
 	}
 
-	private static boolean isTOC(final byte[] h) {
+	private static boolean isTOC(byte[] h) {
 		final byte[] toc = PackIndexWriter.TOC;
 		for (int i = 0; i < toc.length; i++)
 			if (h[i] != toc[i])
@@ -163,16 +157,19 @@ private static boolean isTOC(final byte[] h) {
 	 *            the object to look for. Must not be null.
 	 * @return true if the object is listed in this index; false otherwise.
 	 */
-	public boolean hasObject(final AnyObjectId id) {
+	public boolean hasObject(AnyObjectId id) {
 		return findOffset(id) != -1;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public boolean contains(AnyObjectId id) {
 		return findOffset(id) != -1;
 	}
 
 	/**
+	 * {@inheritDoc}
+	 * <p>
 	 * Provide iterator that gives access to index entries. Note, that iterator
 	 * returns reference to mutable object, the same reference in each call -
 	 * for performance reason. If client needs immutable objects, it must copy
@@ -180,8 +177,6 @@ public boolean contains(AnyObjectId id) {
 	 * <p>
 	 * Iterator returns objects in SHA-1 lexicographical order.
 	 * </p>
-	 *
-	 * @return iterator over pack index entries
 	 */
 	@Override
 	public abstract Iterator<MutableEntry> iterator();
@@ -218,7 +213,8 @@ public boolean contains(AnyObjectId id) {
 	 * @param nthPosition
 	 *            position within the traversal of {@link #iterator()} that the
 	 *            caller needs the object for. The first returned
-	 *            {@link MutableEntry} is 0, the second is 1, etc.
+	 *            {@link org.eclipse.jgit.internal.storage.file.PackIndex.MutableEntry}
+	 *            is 0, the second is 1, etc.
 	 * @return the ObjectId for the corresponding entry.
 	 */
 	public abstract ObjectId getObjectId(long nthPosition);
@@ -239,11 +235,13 @@ public boolean contains(AnyObjectId id) {
 	 * @param nthPosition
 	 *            unsigned 32 bit position within the traversal of
 	 *            {@link #iterator()} that the caller needs the object for. The
-	 *            first returned {@link MutableEntry} is 0, the second is 1,
-	 *            etc. Positions past 2**31-1 are negative, but still valid.
+	 *            first returned
+	 *            {@link org.eclipse.jgit.internal.storage.file.PackIndex.MutableEntry}
+	 *            is 0, the second is 1, etc. Positions past 2**31-1 are
+	 *            negative, but still valid.
 	 * @return the ObjectId for the corresponding entry.
 	 */
-	public final ObjectId getObjectId(final int nthPosition) {
+	public final ObjectId getObjectId(int nthPosition) {
 		if (nthPosition >= 0)
 			return getObjectId((long) nthPosition);
 		final int u31 = nthPosition >>> 1;
@@ -282,9 +280,9 @@ public final ObjectId getObjectId(final int nthPosition) {
 	 * @param objId
 	 *            id of object to look for
 	 * @return CRC32 checksum of specified object (at 32 less significant bits)
-	 * @throws MissingObjectException
+	 * @throws org.eclipse.jgit.errors.MissingObjectException
 	 *             when requested ObjectId was not found in this index
-	 * @throws UnsupportedOperationException
+	 * @throws java.lang.UnsupportedOperationException
 	 *             when this index doesn't support CRC32 checksum
 	 */
 	public abstract long findCRC32(AnyObjectId objId)
@@ -308,7 +306,7 @@ public abstract long findCRC32(AnyObjectId objId)
 	 * @param matchLimit
 	 *            maximum number of results to return. At most this many
 	 *            ObjectIds should be added to matches before returning.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the index cannot be read.
 	 */
 	public abstract void resolve(Set<ObjectId> matches, AbbreviatedObjectId id,
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackIndexV1.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackIndexV1.java
index 8a08456..4444dd6 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackIndexV1.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackIndexV1.java
@@ -103,22 +103,24 @@ class PackIndexV1 extends PackIndex {
 		IO.readFully(fd, packChecksum, 0, packChecksum.length);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public long getObjectCount() {
 		return objectCnt;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public long getOffset64Count() {
 		long n64 = 0;
-		for (final MutableEntry e : this) {
+		for (MutableEntry e : this) {
 			if (e.getOffset() >= Integer.MAX_VALUE)
 				n64++;
 		}
 		return n64;
 	}
 
-	private int findLevelOne(final long nthPosition) {
+	private int findLevelOne(long nthPosition) {
 		int levelOne = Arrays.binarySearch(idxHeader, nthPosition + 1);
 		if (levelOne >= 0) {
 			// If we hit the bucket exactly the item is in the bucket, or
@@ -135,13 +137,14 @@ private int findLevelOne(final long nthPosition) {
 		return levelOne;
 	}
 
-	private int getLevelTwo(final long nthPosition, final int levelOne) {
+	private int getLevelTwo(long nthPosition, int levelOne) {
 		final long base = levelOne > 0 ? idxHeader[levelOne - 1] : 0;
 		return (int) (nthPosition - base);
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	public ObjectId getObjectId(final long nthPosition) {
+	public ObjectId getObjectId(long nthPosition) {
 		final int levelOne = findLevelOne(nthPosition);
 		final int p = getLevelTwo(nthPosition, levelOne);
 		final int dataIdx = idOffset(p);
@@ -156,8 +159,9 @@ long getOffset(long nthPosition) {
 		return NB.decodeUInt32(idxdata[levelOne], p);
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	public long findOffset(final AnyObjectId objId) {
+	public long findOffset(AnyObjectId objId) {
 		final int levelOne = objId.getFirstByte();
 		byte[] data = idxdata[levelOne];
 		if (data == null)
@@ -182,21 +186,25 @@ else if (cmp == 0) {
 		return -1;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public long findCRC32(AnyObjectId objId) {
 		throw new UnsupportedOperationException();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public boolean hasCRC32Support() {
 		return false;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public Iterator<MutableEntry> iterator() {
 		return new IndexV1Iterator();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void resolve(Set<ObjectId> matches, AbbreviatedObjectId id,
 			int matchLimit) throws IOException {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackIndexV2.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackIndexV2.java
index 5c2986a..a9606cf 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackIndexV2.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackIndexV2.java
@@ -164,17 +164,19 @@ class PackIndexV2 extends PackIndex {
 		IO.readFully(fd, packChecksum, 0, packChecksum.length);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public long getObjectCount() {
 		return objectCnt;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public long getOffset64Count() {
 		return offset64.length / 8;
 	}
 
-	private int findLevelOne(final long nthPosition) {
+	private int findLevelOne(long nthPosition) {
 		int levelOne = Arrays.binarySearch(fanoutTable, nthPosition + 1);
 		if (levelOne >= 0) {
 			// If we hit the bucket exactly the item is in the bucket, or
@@ -191,28 +193,31 @@ private int findLevelOne(final long nthPosition) {
 		return levelOne;
 	}
 
-	private int getLevelTwo(final long nthPosition, final int levelOne) {
+	private int getLevelTwo(long nthPosition, int levelOne) {
 		final long base = levelOne > 0 ? fanoutTable[levelOne - 1] : 0;
 		return (int) (nthPosition - base);
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	public ObjectId getObjectId(final long nthPosition) {
+	public ObjectId getObjectId(long nthPosition) {
 		final int levelOne = findLevelOne(nthPosition);
 		final int p = getLevelTwo(nthPosition, levelOne);
 		final int p4 = p << 2;
 		return ObjectId.fromRaw(names[levelOne], p4 + p); // p * 5
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	public long getOffset(final long nthPosition) {
+	public long getOffset(long nthPosition) {
 		final int levelOne = findLevelOne(nthPosition);
 		final int levelTwo = getLevelTwo(nthPosition, levelOne);
 		return getOffset(levelOne, levelTwo);
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	public long findOffset(final AnyObjectId objId) {
+	public long findOffset(AnyObjectId objId) {
 		final int levelOne = objId.getFirstByte();
 		final int levelTwo = binarySearchLevelTwo(objId, levelOne);
 		if (levelTwo == -1)
@@ -220,13 +225,14 @@ public long findOffset(final AnyObjectId objId) {
 		return getOffset(levelOne, levelTwo);
 	}
 
-	private long getOffset(final int levelOne, final int levelTwo) {
+	private long getOffset(int levelOne, int levelTwo) {
 		final long p = NB.decodeUInt32(offset32[levelOne], levelTwo << 2);
 		if ((p & IS_O64) != 0)
 			return NB.decodeUInt64(offset64, (8 * (int) (p & ~IS_O64)));
 		return p;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public long findCRC32(AnyObjectId objId) throws MissingObjectException {
 		final int levelOne = objId.getFirstByte();
@@ -236,16 +242,19 @@ public long findCRC32(AnyObjectId objId) throws MissingObjectException {
 		return NB.decodeUInt32(crc32[levelOne], levelTwo << 2);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public boolean hasCRC32Support() {
 		return true;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public Iterator<MutableEntry> iterator() {
 		return new EntriesIteratorV2();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void resolve(Set<ObjectId> matches, AbbreviatedObjectId id,
 			int matchLimit) throws IOException {
@@ -281,7 +290,7 @@ private static int idOffset(int p) {
 		return (p << 2) + p; // p * 5
 	}
 
-	private int binarySearchLevelTwo(final AnyObjectId objId, final int levelOne) {
+	private int binarySearchLevelTwo(AnyObjectId objId, int levelOne) {
 		final int[] data = names[levelOne];
 		int high = offset32[levelOne].length >>> 2;
 		if (high == 0)
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackIndexWriter.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackIndexWriter.java
index 5153911..553f7c9 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackIndexWriter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackIndexWriter.java
@@ -53,16 +53,16 @@
 
 import org.eclipse.jgit.internal.JGitText;
 import org.eclipse.jgit.lib.Constants;
-import org.eclipse.jgit.lib.ObjectId;
 import org.eclipse.jgit.transport.PackedObjectInfo;
 import org.eclipse.jgit.util.NB;
 
 /**
- * Creates a table of contents to support random access by {@link PackFile}.
+ * Creates a table of contents to support random access by
+ * {@link org.eclipse.jgit.internal.storage.file.PackFile}.
  * <p>
- * Pack index files (the <code>.idx</code> suffix in a pack file pair)
- * provides random access to any object in the pack by associating an ObjectId
- * to the byte offset within the pack where the object's data can be read.
+ * Pack index files (the <code>.idx</code> suffix in a pack file pair) provides
+ * random access to any object in the pack by associating an ObjectId to the
+ * byte offset within the pack where the object's data can be read.
  */
 public abstract class PackIndexWriter {
 	/** Magic constant indicating post-version 1 format. */
@@ -90,7 +90,7 @@ public abstract class PackIndexWriter {
 	 *            will be examined until a format can be conclusively selected.
 	 * @return a new writer to output an index file of the requested format to
 	 *         the supplied stream.
-	 * @throws IllegalArgumentException
+	 * @throws java.lang.IllegalArgumentException
 	 *             no recognized pack index version can support the supplied
 	 *             objects. This is likely a bug in the implementation.
 	 * @see #oldestPossibleFormat(List)
@@ -117,13 +117,13 @@ public static PackIndexWriter createOldestPossible(final OutputStream dst,
 	 *            the objects the caller needs to store in the index. Entries
 	 *            will be examined until a format can be conclusively selected.
 	 * @return the index format.
-	 * @throws IllegalArgumentException
+	 * @throws java.lang.IllegalArgumentException
 	 *             no recognized pack index version can support the supplied
 	 *             objects. This is likely a bug in the implementation.
 	 */
 	public static int oldestPossibleFormat(
 			final List<? extends PackedObjectInfo> objs) {
-		for (final PackedObjectInfo oe : objs) {
+		for (PackedObjectInfo oe : objs) {
 			if (!PackIndexWriterV1.canStore(oe))
 				return 2;
 		}
@@ -143,7 +143,7 @@ public static int oldestPossibleFormat(
 	 *            this formatted version will be written.
 	 * @return a new writer to output an index file of the requested format to
 	 *         the supplied stream.
-	 * @throws IllegalArgumentException
+	 * @throws java.lang.IllegalArgumentException
 	 *             the version requested is not supported by this
 	 *             implementation.
 	 */
@@ -180,7 +180,7 @@ public static PackIndexWriter createVersion(final OutputStream dst,
 	 *            the stream this instance outputs to. If not already buffered
 	 *            it will be automatically wrapped in a buffered stream.
 	 */
-	protected PackIndexWriter(final OutputStream dst) {
+	protected PackIndexWriter(OutputStream dst) {
 		out = new DigestOutputStream(dst instanceof BufferedOutputStream ? dst
 				: new BufferedOutputStream(dst),
 				Constants.newMessageDigest());
@@ -195,12 +195,13 @@ protected PackIndexWriter(final OutputStream dst) {
 	 *
 	 * @param toStore
 	 *            sorted list of objects to store in the index. The caller must
-	 *            have previously sorted the list using {@link PackedObjectInfo}'s
-	 *            native {@link Comparable} implementation.
+	 *            have previously sorted the list using
+	 *            {@link org.eclipse.jgit.transport.PackedObjectInfo}'s native
+	 *            {@link java.lang.Comparable} implementation.
 	 * @param packDataChecksum
 	 *            checksum signature of the entire pack data content. This is
 	 *            traditionally the last 20 bytes of the pack file's own stream.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             an error occurred while writing to the output stream, or this
 	 *             index format cannot store the object data supplied.
 	 */
@@ -230,7 +231,7 @@ public void write(final List<? extends PackedObjectInfo> toStore,
 	 * the {@link #entries} collection may be iterated over more than once if
 	 * necessary. Implementors therefore have complete control over the data.
 	 *
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             an error occurred while writing to the output stream, or this
 	 *             index format cannot store the object data supplied.
 	 */
@@ -246,10 +247,10 @@ public void write(final List<? extends PackedObjectInfo> toStore,
 	 *
 	 * @param version
 	 *            version number of this index format being written.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             an error occurred while writing to the output stream.
 	 */
-	protected void writeTOC(final int version) throws IOException {
+	protected void writeTOC(int version) throws IOException {
 		out.write(TOC);
 		NB.encodeInt32(tmp, 0, version);
 		out.write(tmp, 0, 4);
@@ -260,19 +261,19 @@ protected void writeTOC(final int version) throws IOException {
 	 * <p>
 	 * The fan-out table is 4 KB in size, holding 256 32-bit unsigned integer
 	 * counts. Each count represents the number of objects within this index
-	 * whose {@link ObjectId#getFirstByte()} matches the count's position in the
-	 * fan-out table.
+	 * whose {@link org.eclipse.jgit.lib.ObjectId#getFirstByte()} matches the
+	 * count's position in the fan-out table.
 	 *
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             an error occurred while writing to the output stream.
 	 */
 	protected void writeFanOutTable() throws IOException {
 		final int[] fanout = new int[256];
-		for (final PackedObjectInfo po : entries)
+		for (PackedObjectInfo po : entries)
 			fanout[po.getFirstByte() & 0xff]++;
 		for (int i = 1; i < 256; i++)
 			fanout[i] += fanout[i - 1];
-		for (final int n : fanout) {
+		for (int n : fanout) {
 			NB.encodeInt32(tmp, 0, n);
 			out.write(tmp, 0, 4);
 		}
@@ -288,7 +289,7 @@ protected void writeFanOutTable() throws IOException {
 	 * the pack data checksum above.</li>
 	 * </ol>
 	 *
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             an error occurred while writing to the output stream.
 	 */
 	protected void writeChecksumFooter() throws IOException {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackIndexWriterV1.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackIndexWriterV1.java
index 6017b99..877f7c8 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackIndexWriterV1.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackIndexWriterV1.java
@@ -58,7 +58,7 @@
  * @see PackIndexV1
  */
 class PackIndexWriterV1 extends PackIndexWriter {
-	static boolean canStore(final PackedObjectInfo oe) {
+	static boolean canStore(PackedObjectInfo oe) {
 		// We are limited to 4 GB per pack as offset is 32 bit unsigned int.
 		//
 		return oe.getOffset() >>> 1 < Integer.MAX_VALUE;
@@ -68,11 +68,12 @@ static boolean canStore(final PackedObjectInfo oe) {
 		super(dst);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected void writeImpl() throws IOException {
 		writeFanOutTable();
 
-		for (final PackedObjectInfo oe : entries) {
+		for (PackedObjectInfo oe : entries) {
 			if (!canStore(oe))
 				throw new IOException(JGitText.get().packTooLargeForIndexVersion1);
 			NB.encodeInt32(tmp, 0, (int) oe.getOffset());
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackIndexWriterV2.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackIndexWriterV2.java
index 770549d..9505d35 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackIndexWriterV2.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackIndexWriterV2.java
@@ -63,6 +63,7 @@ class PackIndexWriterV2 extends PackIndexWriter {
 		super(dst);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected void writeImpl() throws IOException {
 		writeTOC(2);
@@ -75,12 +76,12 @@ protected void writeImpl() throws IOException {
 	}
 
 	private void writeObjectNames() throws IOException {
-		for (final PackedObjectInfo oe : entries)
+		for (PackedObjectInfo oe : entries)
 			oe.copyRawTo(out);
 	}
 
 	private void writeCRCs() throws IOException {
-		for (final PackedObjectInfo oe : entries) {
+		for (PackedObjectInfo oe : entries) {
 			NB.encodeInt32(tmp, 0, oe.getCRC());
 			out.write(tmp, 0, 4);
 		}
@@ -88,7 +89,7 @@ private void writeCRCs() throws IOException {
 
 	private void writeOffset32() throws IOException {
 		int o64 = 0;
-		for (final PackedObjectInfo oe : entries) {
+		for (PackedObjectInfo oe : entries) {
 			final long o = oe.getOffset();
 			if (o <= MAX_OFFSET_32)
 				NB.encodeInt32(tmp, 0, (int) o);
@@ -99,7 +100,7 @@ private void writeOffset32() throws IOException {
 	}
 
 	private void writeOffset64() throws IOException {
-		for (final PackedObjectInfo oe : entries) {
+		for (PackedObjectInfo oe : entries) {
 			final long o = oe.getOffset();
 			if (MAX_OFFSET_32 < o) {
 				NB.encodeInt64(tmp, 0, o);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackInputStream.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackInputStream.java
index 962f765..8a4104a 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackInputStream.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackInputStream.java
@@ -64,6 +64,7 @@ class PackInputStream extends InputStream {
 		wc.pin(pack, pos);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public int read(byte[] b, int off, int len) throws IOException {
 		int n = wc.copy(pack, pos, b, off, len);
@@ -71,6 +72,7 @@ public int read(byte[] b, int off, int len) throws IOException {
 		return n;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public int read() throws IOException {
 		byte[] buf = new byte[1];
@@ -78,6 +80,7 @@ public int read() throws IOException {
 		return n == 1 ? buf[0] & 0xff : -1;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void close() {
 		wc.close();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackInserter.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackInserter.java
index ff959e8..0ce3cc9 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackInserter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackInserter.java
@@ -120,15 +120,20 @@ public class PackInserter extends ObjectInserter {
 	}
 
 	/**
+	 * Whether to check if objects exist in the repo
+	 *
 	 * @param check
-	 *            if false, will write out possibly-duplicate objects without
-	 *            first checking whether they exist in the repo; default is true.
+	 *            if {@code false}, will write out possibly-duplicate objects
+	 *            without first checking whether they exist in the repo; default
+	 *            is true.
 	 */
 	public void checkExisting(boolean check) {
 		checkExisting = check;
 	}
 
 	/**
+	 * Set compression level for zlib deflater.
+	 *
 	 * @param compression
 	 *            compression level for zlib deflater.
 	 */
@@ -140,6 +145,7 @@ int getBufferSize() {
 		return buffer().length;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public ObjectId insert(int type, byte[] data, int off, int len)
 			throws IOException {
@@ -158,6 +164,7 @@ public ObjectId insert(int type, byte[] data, int off, int len)
 		return endObject(id, offset);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public ObjectId insert(int type, long len, InputStream in)
 			throws IOException {
@@ -231,16 +238,19 @@ private static int writePackHeader(byte[] buf, int objectCount) {
 		return 12;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public PackParser newPackParser(InputStream in) {
 		throw new UnsupportedOperationException();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public ObjectReader newReader() {
 		return new Reader();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void flush() throws IOException {
 		if (tmpPack == null) {
@@ -262,8 +272,7 @@ public void flush() throws IOException {
 		File tmpIdx = idxFor(tmpPack);
 		writePackIndex(tmpIdx, packHash, objectList);
 
-		File realPack = new File(
-				new File(db.getDirectory(), "pack"), //$NON-NLS-1$
+		File realPack = new File(db.getPackDirectory(),
 				"pack-" + computeName(objectList).name() + ".pack"); //$NON-NLS-1$ //$NON-NLS-2$
 		db.closeAllPackHandles(realPack);
 		tmpPack.setReadOnly();
@@ -310,6 +319,7 @@ private ObjectId computeName(List<PackedObjectInfo> list) {
 		return ObjectId.fromRaw(md.digest());
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void close() {
 		try {
@@ -428,7 +438,7 @@ private int encodeTypeSize(int type, long rawLength) {
 		}
 
 		@Override
-		public void write(final int b) throws IOException {
+		public void write(int b) throws IOException {
 			hdrBuf[0] = (byte) b;
 			write(hdrBuf, 0, 1);
 		}
@@ -613,13 +623,12 @@ public ObjectLoader open(AnyObjectId objectId, int typeHint)
 			try {
 				return packOut.inflate(zpos, sz);
 			} catch (DataFormatException dfe) {
-				CorruptObjectException coe = new CorruptObjectException(
+				throw new CorruptObjectException(
 						MessageFormat.format(
 								JGitText.get().objectAtHasBadZlibStream,
 								Long.valueOf(obj.getOffset()),
-								tmpPack.getAbsolutePath()));
-				coe.initCause(dfe);
-				throw coe;
+								tmpPack.getAbsolutePath()),
+						dfe);
 			}
 		}
 
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackLock.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackLock.java
index a433dec..0fb8911 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackLock.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackLock.java
@@ -50,7 +50,10 @@
 import org.eclipse.jgit.util.FS;
 import org.eclipse.jgit.util.FileUtils;
 
-/** Keeps track of a {@link PackFile}'s associated <code>.keep</code> file. */
+/**
+ * Keeps track of a {@link org.eclipse.jgit.internal.storage.file.PackFile}'s
+ * associated <code>.keep</code> file.
+ */
 public class PackLock {
 	private final File keepFile;
 
@@ -62,7 +65,7 @@ public class PackLock {
 	 * @param fs
 	 *            the filesystem abstraction used by the repository.
 	 */
-	public PackLock(final File packFile, final FS fs) {
+	public PackLock(File packFile, FS fs) {
 		final File p = packFile.getParentFile();
 		final String n = packFile.getName();
 		keepFile = new File(p, n.substring(0, n.length() - 5) + ".keep"); //$NON-NLS-1$
@@ -74,7 +77,7 @@ public PackLock(final File packFile, final FS fs) {
 	 * @param msg
 	 *            message to store in the file.
 	 * @return true if the keep file was successfully written; false otherwise.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the keep file could not be written.
 	 */
 	public boolean lock(String msg) throws IOException {
@@ -92,7 +95,7 @@ public boolean lock(String msg) throws IOException {
 	/**
 	 * Remove the <code>.keep</code> file that holds this pack in place.
 	 *
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             if deletion of .keep file failed
 	 */
 	public void unlock() throws IOException {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackReverseIndex.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackReverseIndex.java
index fe9f700..dfe23ba 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackReverseIndex.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackReverseIndex.java
@@ -88,7 +88,7 @@ public class PackReverseIndex {
 	 * @param packIndex
 	 *            forward index - entries to (reverse) index.
 	 */
-	public PackReverseIndex(final PackIndex packIndex) {
+	public PackReverseIndex(PackIndex packIndex) {
 		index = packIndex;
 
 		final long cnt = index.getObjectCount();
@@ -107,7 +107,7 @@ public PackReverseIndex(final PackIndex packIndex) {
 
 		long maxOffset = 0;
 		int ith = 0;
-		for (final MutableEntry me : index) {
+		for (MutableEntry me : index) {
 			final long o = me.getOffset();
 			offsetsBySha1[ith++] = o;
 			if (o > maxOffset)
@@ -155,7 +155,7 @@ public PackReverseIndex(final PackIndex packIndex) {
 	 *            start offset of object to find.
 	 * @return object id for this offset, or null if no object was found.
 	 */
-	public ObjectId findObject(final long offset) {
+	public ObjectId findObject(long offset) {
 		final int ith = binarySearch(offset);
 		if (ith < 0)
 			return null;
@@ -174,10 +174,10 @@ public ObjectId findObject(final long offset) {
 	 *            offset).
 	 * @return offset of the next object in a pack or maxOffset if provided
 	 *         offset was the last one.
-	 * @throws CorruptObjectException
+	 * @throws org.eclipse.jgit.errors.CorruptObjectException
 	 *             when there is no object with the provided offset.
 	 */
-	public long findNextOffset(final long offset, final long maxOffset)
+	public long findNextOffset(long offset, long maxOffset)
 			throws CorruptObjectException {
 		final int ith = binarySearch(offset);
 		if (ith < 0)
@@ -195,7 +195,7 @@ int findPostion(long offset) {
 		return binarySearch(offset);
 	}
 
-	private int binarySearch(final long offset) {
+	private int binarySearch(long offset) {
 		int bucket = (int) (offset / bucketSize);
 		int low = bucket == 0 ? 0 : offsetIndex[bucket - 1];
 		int high = offsetIndex[bucket];
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackedBatchRefUpdate.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackedBatchRefUpdate.java
index c1f5476..200c63c 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackedBatchRefUpdate.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackedBatchRefUpdate.java
@@ -47,6 +47,7 @@
 import static org.eclipse.jgit.transport.ReceiveCommand.Result.LOCK_FAILURE;
 import static org.eclipse.jgit.transport.ReceiveCommand.Result.NOT_ATTEMPTED;
 import static org.eclipse.jgit.transport.ReceiveCommand.Result.REJECTED_NONFASTFORWARD;
+import static org.eclipse.jgit.transport.ReceiveCommand.Result.REJECTED_OTHER_REASON;
 
 import java.io.IOException;
 import java.text.MessageFormat;
@@ -124,6 +125,7 @@ class PackedBatchRefUpdate extends BatchRefUpdate {
 		this.refdb = refdb;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void execute(RevWalk walk, ProgressMonitor monitor,
 			List<String> options) throws IOException {
@@ -142,6 +144,12 @@ public void execute(RevWalk walk, ProgressMonitor monitor,
 			super.execute(walk, monitor, options);
 			return;
 		}
+		if (containsSymrefs(pending)) {
+			// packed-refs file cannot store symrefs
+			reject(pending.get(0), REJECTED_OTHER_REASON,
+					JGitText.get().atomicSymRefNotSupported, pending);
+			return;
+		}
 
 		// Required implementation details copied from super.execute.
 		if (!blockUntilTimestamps(MAX_WAIT)) {
@@ -217,6 +225,15 @@ public void execute(RevWalk walk, ProgressMonitor monitor,
 		writeReflog(pending);
 	}
 
+	private static boolean containsSymrefs(List<ReceiveCommand> commands) {
+		for (ReceiveCommand cmd : commands) {
+			if (cmd.getOldSymref() != null || cmd.getNewSymref() != null) {
+				return true;
+			}
+		}
+		return false;
+	}
+
 	private boolean checkConflictingNames(List<ReceiveCommand> commands)
 			throws IOException {
 		Set<String> takenNames = new HashSet<>();
@@ -518,7 +535,12 @@ private static void lockFailure(ReceiveCommand cmd,
 
 	private static void reject(ReceiveCommand cmd, ReceiveCommand.Result result,
 			List<ReceiveCommand> commands) {
-		cmd.setResult(result);
+		reject(cmd, result, null, commands);
+	}
+
+	private static void reject(ReceiveCommand cmd, ReceiveCommand.Result result,
+			String why, List<ReceiveCommand> commands) {
+		cmd.setResult(result, why);
 		for (ReceiveCommand c2 : commands) {
 			if (c2.getResult() == ReceiveCommand.Result.OK) {
 				// Undo OK status so ReceiveCommand#abort aborts it. Assumes this method
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/RefDirectory.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/RefDirectory.java
index bd39e65..a27b991 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/RefDirectory.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/RefDirectory.java
@@ -66,6 +66,7 @@
 import java.io.InputStreamReader;
 import java.io.InterruptedIOException;
 import java.nio.file.Files;
+import java.nio.file.Path;
 import java.security.DigestInputStream;
 import java.security.MessageDigest;
 import java.text.MessageFormat;
@@ -78,6 +79,7 @@
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.atomic.AtomicReference;
 import java.util.concurrent.locks.ReentrantLock;
+import java.util.stream.Stream;
 
 import org.eclipse.jgit.annotations.NonNull;
 import org.eclipse.jgit.annotations.Nullable;
@@ -111,14 +113,14 @@
 import org.slf4j.LoggerFactory;
 
 /**
- * Traditional file system based {@link RefDatabase}.
+ * Traditional file system based {@link org.eclipse.jgit.lib.RefDatabase}.
  * <p>
  * This is the classical reference database representation for a Git repository.
  * References are stored in two formats: loose, and packed.
  * <p>
  * Loose references are stored as individual files within the {@code refs/}
  * directory. The file name matches the reference name and the file contents is
- * the current {@link ObjectId} in string form.
+ * the current {@link org.eclipse.jgit.lib.ObjectId} in string form.
  * <p>
  * Packed references are stored in a single text file named {@code packed-refs}.
  * In the packed format, each reference is stored on its own line. This file
@@ -206,7 +208,7 @@ public class RefDirectory extends RefDatabase {
 
 	private List<Integer> retrySleepMs = RETRY_SLEEP_MS;
 
-	RefDirectory(final FileRepository db) {
+	RefDirectory(FileRepository db) {
 		final FS fs = db.getFS();
 		parent = db;
 		gitDir = db.getDirectory();
@@ -243,6 +245,7 @@ public File logFor(String name) {
 		return new File(logsDir, name);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void create() throws IOException {
 		FileUtils.mkdir(refsDir);
@@ -251,6 +254,7 @@ public void create() throws IOException {
 		newLogWriter(false).create();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void close() {
 		clearReferences();
@@ -261,12 +265,14 @@ private void clearReferences() {
 		packedRefs.set(NO_PACKED_REFS);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void refresh() {
 		super.refresh();
 		clearReferences();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public boolean isNameConflicting(String name) throws IOException {
 		RefList<Ref> packed = getPackedRefs();
@@ -312,6 +318,7 @@ private RefList<LooseRef> getLooseRefs() {
 		return loose;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public Ref exactRef(String name) throws IOException {
 		RefList<Ref> packed = getPackedRefs();
@@ -336,8 +343,9 @@ public Ref exactRef(String name) throws IOException {
 		return ref;
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	public Ref getRef(final String needle) throws IOException {
+	public Ref getRef(String needle) throws IOException {
 		final RefList<Ref> packed = getPackedRefs();
 		Ref ref = null;
 		for (String prefix : SEARCH_PATH) {
@@ -360,6 +368,7 @@ public Ref getRef(final String needle) throws IOException {
 		return ref;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public Map<String, Ref> getRefs(String prefix) throws IOException {
 		final RefList<LooseRef> oldLoose = looseRefs.get();
@@ -399,6 +408,7 @@ public Map<String, Ref> getRefs(String prefix) throws IOException {
 		return new RefMap(prefix, packed, upcast(loose), symbolic.toRefList());
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public List<Ref> getAdditionalRefs() throws IOException {
 		List<Ref> ret = new LinkedList<>();
@@ -424,7 +434,7 @@ private class LooseScanner {
 
 		RefList.Builder<LooseRef> newLoose;
 
-		LooseScanner(final RefList<LooseRef> curLoose) {
+		LooseScanner(RefList<LooseRef> curLoose) {
 			this.curLoose = curLoose;
 		}
 
@@ -533,8 +543,9 @@ private void scanOne(String name) {
 		}
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	public Ref peel(final Ref ref) throws IOException {
+	public Ref peel(Ref ref) throws IOException {
 		final Ref leaf = ref.getLeaf();
 		if (leaf.isPeeled() || leaf.getObjectId() == null)
 			return ref;
@@ -556,7 +567,7 @@ public Ref peel(final Ref ref) throws IOException {
 		return recreate(ref, newLeaf);
 	}
 
-	private ObjectIdRef doPeel(final Ref leaf) throws MissingObjectException,
+	private ObjectIdRef doPeel(Ref leaf) throws MissingObjectException,
 			IOException {
 		try (RevWalk rw = new RevWalk(getRepository())) {
 			RevObject obj = rw.parseAny(leaf.getObjectId());
@@ -570,7 +581,7 @@ private ObjectIdRef doPeel(final Ref leaf) throws MissingObjectException,
 		}
 	}
 
-	private static Ref recreate(final Ref old, final ObjectIdRef leaf) {
+	private static Ref recreate(Ref old, ObjectIdRef leaf) {
 		if (old.isSymbolic()) {
 			Ref dst = recreate(old.getTarget(), leaf);
 			return new SymbolicRef(old.getName(), dst);
@@ -584,6 +595,7 @@ void storedSymbolicRef(RefDirectoryUpdate u, FileSnapshot snapshot,
 		fireRefsChanged();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public RefDirectoryUpdate newUpdate(String name, boolean detach)
 			throws IOException {
@@ -603,6 +615,7 @@ public RefDirectoryUpdate newUpdate(String name, boolean detach)
 		return refDirUpdate;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public RefDirectoryRename newRename(String fromName, String toName)
 			throws IOException {
@@ -611,11 +624,13 @@ public RefDirectoryRename newRename(String fromName, String toName)
 		return new RefDirectoryRename(from, to);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public PackedBatchRefUpdate newBatchUpdate() {
 		return new PackedBatchRefUpdate(this);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public boolean performsAtomicTransactions() {
 		return true;
@@ -695,7 +710,7 @@ void delete(RefDirectoryUpdate update) throws IOException {
 	 *
 	 * @param refs
 	 *            the refs to be added. Must be fully qualified.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 */
 	public void pack(List<String> refs) throws IOException {
 		pack(refs, Collections.emptyMap());
@@ -925,12 +940,27 @@ private PackedRefList readPackedRefs() throws IOException {
 		int retries = 0;
 		while (true) {
 			final FileSnapshot snapshot = FileSnapshot.save(packedRefsFile);
-			final BufferedReader br;
 			final MessageDigest digest = Constants.newMessageDigest();
-			try {
-				br = new BufferedReader(new InputStreamReader(
-						new DigestInputStream(new FileInputStream(packedRefsFile),
-								digest), CHARSET));
+			try (BufferedReader br = new BufferedReader(new InputStreamReader(
+					new DigestInputStream(new FileInputStream(packedRefsFile),
+							digest),
+					CHARSET))) {
+				try {
+					return new PackedRefList(parsePackedRefs(br), snapshot,
+							ObjectId.fromRaw(digest.digest()));
+				} catch (IOException e) {
+					if (FileUtils.isStaleFileHandleInCausalChain(e)
+							&& retries < maxStaleRetries) {
+						if (LOG.isDebugEnabled()) {
+							LOG.debug(MessageFormat.format(
+									JGitText.get().packedRefsHandleIsStale,
+									Integer.valueOf(retries)), e);
+						}
+						retries++;
+						continue;
+					}
+					throw e;
+				}
 			} catch (FileNotFoundException noPackedRefs) {
 				if (packedRefsFile.exists()) {
 					throw noPackedRefs;
@@ -938,28 +968,10 @@ private PackedRefList readPackedRefs() throws IOException {
 				// Ignore it and leave the new list empty.
 				return NO_PACKED_REFS;
 			}
-			try {
-				return new PackedRefList(parsePackedRefs(br), snapshot,
-						ObjectId.fromRaw(digest.digest()));
-			} catch (IOException e) {
-				if (FileUtils.isStaleFileHandleInCausalChain(e)
-						&& retries < maxStaleRetries) {
-					if (LOG.isDebugEnabled()) {
-						LOG.debug(MessageFormat.format(
-								JGitText.get().packedRefsHandleIsStale,
-								Integer.valueOf(retries)), e);
-					}
-					retries++;
-					continue;
-				}
-				throw e;
-			} finally {
-				br.close();
-			}
 		}
 	}
 
-	private RefList<Ref> parsePackedRefs(final BufferedReader br)
+	private RefList<Ref> parsePackedRefs(BufferedReader br)
 			throws IOException {
 		RefList.Builder<Ref> all = new RefList.Builder<>();
 		Ref last = null;
@@ -1011,7 +1023,7 @@ private RefList<Ref> parsePackedRefs(final BufferedReader br)
 		return all.toRefList();
 	}
 
-	private static String copy(final String src, final int off, final int end) {
+	private static String copy(String src, int off, int end) {
 		// Don't use substring since it could leave a reference to the much
 		// larger existing string. Force construction of a full new object.
 		return new StringBuilder(end - off).append(src, off, end).toString();
@@ -1171,15 +1183,13 @@ LooseRef scanRef(LooseRef ref, String name) throws IOException {
 				n--;
 			String content = RawParseUtils.decode(buf, 0, n);
 
-			IOException ioException = new IOException(MessageFormat.format(JGitText.get().notARef,
-					name, content));
-			ioException.initCause(notRef);
-			throw ioException;
+			throw new IOException(MessageFormat.format(JGitText.get().notARef,
+					name, content), notRef);
 		}
 		return new LooseUnpeeled(otherSnapshot, name, id);
 	}
 
-	private static boolean isSymRef(final byte[] buf, int n) {
+	private static boolean isSymRef(byte[] buf, int n) {
 		if (n < 6)
 			return false;
 		return /**/buf[0] == 'r' //
@@ -1209,7 +1219,9 @@ private boolean hasDanglingHead() throws IOException {
 	}
 
 	private boolean hasLooseRef() throws IOException {
-		return Files.walk(refsDir.toPath()).anyMatch(Files::isRegularFile);
+		try (Stream<Path> stream = Files.walk(refsDir.toPath())) {
+			return stream.anyMatch(Files::isRegularFile);
+		}
 	}
 
 	/** If the parent should fire listeners, fires them. */
@@ -1250,18 +1262,18 @@ File fileFor(String name) {
 		return new File(gitDir, name);
 	}
 
-	static int levelsIn(final String name) {
+	static int levelsIn(String name) {
 		int count = 0;
 		for (int p = name.indexOf('/'); p >= 0; p = name.indexOf('/', p + 1))
 			count++;
 		return count;
 	}
 
-	static void delete(final File file, final int depth) throws IOException {
+	static void delete(File file, int depth) throws IOException {
 		delete(file, depth, null);
 	}
 
-	private static void delete(final File file, final int depth, LockFile rLck)
+	private static void delete(File file, int depth, LockFile rLck)
 			throws IOException {
 		if (!file.delete() && file.isFile()) {
 			throw new IOException(MessageFormat.format(
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/RefDirectoryRename.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/RefDirectoryRename.java
index 09456c8..ec7ec73 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/RefDirectoryRename.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/RefDirectoryRename.java
@@ -95,6 +95,7 @@ class RefDirectoryRename extends RefRename {
 		refdb = src.getRefDatabase();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected Result doRename() throws IOException {
 		if (source.getRef().isSymbolic())
@@ -103,7 +104,7 @@ protected Result doRename() throws IOException {
 		objId = source.getOldObjectId();
 		updateHEAD = needToUpdateHEAD();
 		tmp = refdb.newTemporaryUpdate();
-		try (final RevWalk rw = new RevWalk(refdb.getRepository())) {
+		try (RevWalk rw = new RevWalk(refdb.getRepository())) {
 			// First backup the source so its never unreachable.
 			tmp.setNewObjectId(objId);
 			tmp.setForceUpdate(true);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/RefDirectoryUpdate.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/RefDirectoryUpdate.java
index 7ab30fa..45ce634 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/RefDirectoryUpdate.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/RefDirectoryUpdate.java
@@ -60,21 +60,24 @@ class RefDirectoryUpdate extends RefUpdate {
 	private boolean shouldDeref;
 	private LockFile lock;
 
-	RefDirectoryUpdate(final RefDirectory r, final Ref ref) {
+	RefDirectoryUpdate(RefDirectory r, Ref ref) {
 		super(ref);
 		database = r;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected RefDirectory getRefDatabase() {
 		return database;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected Repository getRepository() {
 		return database.getRepository();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected boolean tryLock(boolean deref) throws IOException {
 		shouldDeref = deref;
@@ -92,6 +95,7 @@ protected boolean tryLock(boolean deref) throws IOException {
 		}
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected void unlock() {
 		if (lock != null) {
@@ -100,8 +104,9 @@ protected void unlock() {
 		}
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	protected Result doUpdate(final Result status) throws IOException {
+	protected Result doUpdate(Result status) throws IOException {
 		WriteConfig wc = database.getRepository().getConfig()
 				.get(WriteConfig.KEY);
 
@@ -141,15 +146,17 @@ private String toResultString(Result status) {
 		}
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	protected Result doDelete(final Result status) throws IOException {
+	protected Result doDelete(Result status) throws IOException {
 		if (getRef().getStorage() != Ref.Storage.NEW)
 			database.delete(this);
 		return status;
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	protected Result doLink(final String target) throws IOException {
+	protected Result doLink(String target) throws IOException {
 		WriteConfig wc = database.getRepository().getConfig()
 				.get(WriteConfig.KEY);
 
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ReflogEntryImpl.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ReflogEntryImpl.java
index 8723a8b..08a14b2 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ReflogEntryImpl.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ReflogEntryImpl.java
@@ -93,6 +93,7 @@ public class ReflogEntryImpl implements Serializable, ReflogEntry {
 	/* (non-Javadoc)
 	 * @see org.eclipse.jgit.internal.storage.file.ReflogEntry#getOldId()
 	 */
+	/** {@inheritDoc} */
 	@Override
 	public ObjectId getOldId() {
 		return oldId;
@@ -101,6 +102,7 @@ public ObjectId getOldId() {
 	/* (non-Javadoc)
 	 * @see org.eclipse.jgit.internal.storage.file.ReflogEntry#getNewId()
 	 */
+	/** {@inheritDoc} */
 	@Override
 	public ObjectId getNewId() {
 		return newId;
@@ -109,6 +111,7 @@ public ObjectId getNewId() {
 	/* (non-Javadoc)
 	 * @see org.eclipse.jgit.internal.storage.file.ReflogEntry#getWho()
 	 */
+	/** {@inheritDoc} */
 	@Override
 	public PersonIdent getWho() {
 		return who;
@@ -117,11 +120,13 @@ public PersonIdent getWho() {
 	/* (non-Javadoc)
 	 * @see org.eclipse.jgit.internal.storage.file.ReflogEntry#getComment()
 	 */
+	/** {@inheritDoc} */
 	@Override
 	public String getComment() {
 		return comment;
 	}
 
+	/** {@inheritDoc} */
 	@SuppressWarnings("nls")
 	@Override
 	public String toString() {
@@ -132,6 +137,7 @@ public String toString() {
 	/* (non-Javadoc)
 	 * @see org.eclipse.jgit.internal.storage.file.ReflogEntry#parseCheckout()
 	 */
+	/** {@inheritDoc} */
 	@Override
 	public CheckoutEntry parseCheckout() {
 		if (getComment().startsWith(CheckoutEntryImpl.CHECKOUT_MOVING_FROM))
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ReflogReaderImpl.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ReflogReaderImpl.java
index c3702fe..e95e1c2 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ReflogReaderImpl.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ReflogReaderImpl.java
@@ -74,6 +74,7 @@ class ReflogReaderImpl implements ReflogReader {
 	/* (non-Javadoc)
 	 * @see org.eclipse.jgit.internal.storage.file.ReflogReaader#getLastEntry()
 	 */
+	/** {@inheritDoc} */
 	@Override
 	public ReflogEntry getLastEntry() throws IOException {
 		return getReverseEntry(0);
@@ -82,6 +83,7 @@ public ReflogEntry getLastEntry() throws IOException {
 	/* (non-Javadoc)
 	 * @see org.eclipse.jgit.internal.storage.file.ReflogReaader#getReverseEntries()
 	 */
+	/** {@inheritDoc} */
 	@Override
 	public List<ReflogEntry> getReverseEntries() throws IOException {
 		return getReverseEntries(Integer.MAX_VALUE);
@@ -90,6 +92,7 @@ public List<ReflogEntry> getReverseEntries() throws IOException {
 	/* (non-Javadoc)
 	 * @see org.eclipse.jgit.internal.storage.file.ReflogReaader#getReverseEntry(int)
 	 */
+	/** {@inheritDoc} */
 	@Override
 	public ReflogEntry getReverseEntry(int number) throws IOException {
 		if (number < 0)
@@ -119,6 +122,7 @@ public ReflogEntry getReverseEntry(int number) throws IOException {
 	/* (non-Javadoc)
 	 * @see org.eclipse.jgit.internal.storage.file.ReflogReaader#getReverseEntries(int)
 	 */
+	/** {@inheritDoc} */
 	@Override
 	public List<ReflogEntry> getReverseEntries(int max) throws IOException {
 		final byte[] log;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ReflogWriter.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ReflogWriter.java
index d1bd922..495c752 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ReflogWriter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ReflogWriter.java
@@ -46,6 +46,7 @@
 package org.eclipse.jgit.internal.storage.file;
 
 import static org.eclipse.jgit.lib.Constants.HEAD;
+import static org.eclipse.jgit.lib.Constants.LOCK_SUFFIX;
 import static org.eclipse.jgit.lib.Constants.R_HEADS;
 import static org.eclipse.jgit.lib.Constants.R_NOTES;
 import static org.eclipse.jgit.lib.Constants.R_REFS;
@@ -84,7 +85,7 @@ public class ReflogWriter {
 	 * @return the name of the ref's lock ref.
 	 */
 	public static String refLockFor(String name) {
-		return name + LockFile.SUFFIX;
+		return name + LOCK_SUFFIX;
 	}
 
 	private final RefDirectory refdb;
@@ -95,6 +96,8 @@ public static String refLockFor(String name) {
 	 * Create writer for ref directory.
 	 *
 	 * @param refdb
+	 *            a {@link org.eclipse.jgit.internal.storage.file.RefDirectory}
+	 *            object.
 	 */
 	public ReflogWriter(RefDirectory refdb) {
 		this(refdb, false);
@@ -104,6 +107,8 @@ public ReflogWriter(RefDirectory refdb) {
 	 * Create writer for ref directory.
 	 *
 	 * @param refdb
+	 *            a {@link org.eclipse.jgit.internal.storage.file.RefDirectory}
+	 *            object.
 	 * @param forceWrite
 	 *            true to write to disk all entries logged, false to respect the
 	 *            repository's config and current log file status.
@@ -116,7 +121,7 @@ public ReflogWriter(RefDirectory refdb, boolean forceWrite) {
 	/**
 	 * Create the log directories.
 	 *
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 * @return this writer.
 	 */
 	public ReflogWriter create() throws IOException {
@@ -131,9 +136,11 @@ public ReflogWriter create() throws IOException {
 	 * Write the given entry to the ref's log.
 	 *
 	 * @param refName
+	 *            a {@link java.lang.String} object.
 	 * @param entry
+	 *            a {@link org.eclipse.jgit.lib.ReflogEntry} object.
 	 * @return this writer
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 */
 	public ReflogWriter log(String refName, ReflogEntry entry)
 			throws IOException {
@@ -145,12 +152,17 @@ public ReflogWriter log(String refName, ReflogEntry entry)
 	 * Write the given entry information to the ref's log
 	 *
 	 * @param refName
+	 *            ref name
 	 * @param oldId
+	 *            old object id
 	 * @param newId
+	 *            new object id
 	 * @param ident
+	 *            a {@link org.eclipse.jgit.lib.PersonIdent}
 	 * @param message
+	 *            reflog message
 	 * @return this writer
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 */
 	public ReflogWriter log(String refName, ObjectId oldId,
 			ObjectId newId, PersonIdent ident, String message) throws IOException {
@@ -162,10 +174,13 @@ public ReflogWriter log(String refName, ObjectId oldId,
 	 * Write the given ref update to the ref's log.
 	 *
 	 * @param update
+	 *            a {@link org.eclipse.jgit.lib.RefUpdate}
 	 * @param msg
+	 *            reflog message
 	 * @param deref
+	 *            whether to dereference symbolic refs
 	 * @return this writer
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 */
 	public ReflogWriter log(RefUpdate update, String msg,
 			boolean deref) throws IOException {
@@ -205,6 +220,22 @@ public ReflogWriter log(RefUpdate update, String msg,
 		return Constants.encode(r.toString());
 	}
 
+	private FileOutputStream getFileOutputStream(File log) throws IOException {
+		try {
+			return new FileOutputStream(log, true);
+		} catch (FileNotFoundException err) {
+			File dir = log.getParentFile();
+			if (dir.exists()) {
+				throw err;
+			}
+			if (!dir.mkdirs() && !dir.isDirectory()) {
+				throw new IOException(MessageFormat
+						.format(JGitText.get().cannotCreateDirectory, dir));
+			}
+			return new FileOutputStream(log, true);
+		}
+	}
+
 	private ReflogWriter log(String refName, byte[] rec) throws IOException {
 		File log = refdb.logFor(refName);
 		boolean write = forceWrite
@@ -214,29 +245,17 @@ private ReflogWriter log(String refName, byte[] rec) throws IOException {
 			return this;
 
 		WriteConfig wc = refdb.getRepository().getConfig().get(WriteConfig.KEY);
-		FileOutputStream out;
-		try {
-			out = new FileOutputStream(log, true);
-		} catch (FileNotFoundException err) {
-			File dir = log.getParentFile();
-			if (dir.exists())
-				throw err;
-			if (!dir.mkdirs() && !dir.isDirectory())
-				throw new IOException(MessageFormat.format(
-						JGitText.get().cannotCreateDirectory, dir));
-			out = new FileOutputStream(log, true);
-		}
-		try {
+		try (FileOutputStream out = getFileOutputStream(log)) {
 			if (wc.getFSyncRefFiles()) {
 				FileChannel fc = out.getChannel();
 				ByteBuffer buf = ByteBuffer.wrap(rec);
-				while (0 < buf.remaining())
+				while (0 < buf.remaining()) {
 					fc.write(buf);
+				}
 				fc.force(true);
-			} else
+			} else {
 				out.write(rec);
-		} finally {
-			out.close();
+			}
 		}
 		return this;
 	}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/SimpleDataInput.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/SimpleDataInput.java
index 452636d..3b815b5 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/SimpleDataInput.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/SimpleDataInput.java
@@ -64,83 +64,105 @@ class SimpleDataInput implements DataInput {
 		this.fd = fd;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public int readInt() throws IOException {
 		readFully(buf, 0, 4);
 		return NB.decodeInt32(buf, 0);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public long readLong() throws IOException {
 		readFully(buf, 0, 8);
 		return NB.decodeInt64(buf, 0);
 	}
 
+	/**
+	 * Read unsigned int
+	 *
+	 * @return a long.
+	 * @throws java.io.IOException
+	 *             if any.
+	 */
 	public long readUnsignedInt() throws IOException {
 		readFully(buf, 0, 4);
 		return NB.decodeUInt32(buf, 0);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void readFully(byte[] b) throws IOException {
 		readFully(b, 0, b.length);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void readFully(byte[] b, int off, int len) throws IOException {
 		IO.readFully(fd, b, off, len);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public int skipBytes(int n) throws IOException {
 		throw new UnsupportedOperationException();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public boolean readBoolean() throws IOException {
 		throw new UnsupportedOperationException();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public byte readByte() throws IOException {
 		throw new UnsupportedOperationException();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public int readUnsignedByte() throws IOException {
 		throw new UnsupportedOperationException();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public short readShort() throws IOException {
 		throw new UnsupportedOperationException();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public int readUnsignedShort() throws IOException {
 		throw new UnsupportedOperationException();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public char readChar() throws IOException {
 		throw new UnsupportedOperationException();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public float readFloat() throws IOException {
 		throw new UnsupportedOperationException();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public double readDouble() throws IOException {
 		throw new UnsupportedOperationException();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public String readLine() throws IOException {
 		throw new UnsupportedOperationException();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public String readUTF() throws IOException {
 		throw new UnsupportedOperationException();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/SimpleDataOutput.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/SimpleDataOutput.java
index 5fe0429..7825b84 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/SimpleDataOutput.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/SimpleDataOutput.java
@@ -64,74 +64,88 @@ class SimpleDataOutput implements DataOutput {
 		this.fd = fd;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void writeShort(int v) throws IOException {
 		NB.encodeInt16(buf, 0, v);
 		fd.write(buf, 0, 2);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void writeInt(int v) throws IOException {
 		NB.encodeInt32(buf, 0, v);
 		fd.write(buf, 0, 4);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void writeLong(long v) throws IOException {
 		NB.encodeInt64(buf, 0, v);
 		fd.write(buf, 0, 8);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void write(int b) throws IOException {
 		throw new UnsupportedOperationException();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void write(byte[] b) throws IOException {
 		throw new UnsupportedOperationException();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void write(byte[] b, int off, int len) throws IOException {
 		throw new UnsupportedOperationException();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void writeBoolean(boolean v) throws IOException {
 		throw new UnsupportedOperationException();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void writeByte(int v) throws IOException {
 		throw new UnsupportedOperationException();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void writeChar(int v) throws IOException {
 		throw new UnsupportedOperationException();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void writeFloat(float v) throws IOException {
 		throw new UnsupportedOperationException();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void writeDouble(double v) throws IOException {
 		throw new UnsupportedOperationException();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void writeBytes(String s) throws IOException {
 		throw new UnsupportedOperationException();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void writeChars(String s) throws IOException {
 		throw new UnsupportedOperationException();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void writeUTF(String s) throws IOException {
 		throw new UnsupportedOperationException();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/UnpackedObject.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/UnpackedObject.java
index a027437..cf474af 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/UnpackedObject.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/UnpackedObject.java
@@ -86,7 +86,7 @@ public class UnpackedObject {
 	 *            expected ObjectId of the object, used only for error reporting
 	 *            in exceptions.
 	 * @return loader to read the inflated contents.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the object cannot be parsed.
 	 */
 	public static ObjectLoader parse(byte[] raw, AnyObjectId id)
@@ -266,7 +266,7 @@ static void checkValidEndOfStream(InputStream in, Inflater inf,
 		}
 	}
 
-	static boolean isStandardFormat(final byte[] hdr) {
+	static boolean isStandardFormat(byte[] hdr) {
 		/*
 		 * We must determine if the buffer contains the standard
 		 * zlib-deflated stream or the experimental format based
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/WindowCache.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/WindowCache.java
index 6196006..8cf1d4e 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/WindowCache.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/WindowCache.java
@@ -57,7 +57,8 @@
 import org.eclipse.jgit.storage.file.WindowCacheConfig;
 
 /**
- * Caches slices of a {@link PackFile} in memory for faster read access.
+ * Caches slices of a {@link org.eclipse.jgit.internal.storage.file.PackFile} in
+ * memory for faster read access.
  * <p>
  * The WindowCache serves as a Java based "buffer cache", loading segments of a
  * PackFile into the JVM heap prior to use. As JGit often wants to do reads of
@@ -111,8 +112,9 @@
  * {@link #createRef(PackFile, long, ByteWindow)} methods, and matching
  * decrements during {@link #clear(Ref)}. Implementors may need to override
  * {@link #createRef(PackFile, long, ByteWindow)} in order to embed additional
- * accounting information into an implementation specific {@link Ref} subclass,
- * as the cached entity may have already been evicted by the JRE's garbage
+ * accounting information into an implementation specific
+ * {@link org.eclipse.jgit.internal.storage.file.WindowCache.Ref} subclass, as
+ * the cached entity may have already been evicted by the JRE's garbage
  * collector.
  * <p>
  * To maintain higher concurrency workloads, during eviction only one thread
@@ -150,12 +152,12 @@ private static final int bits(int newSize) {
 	 * @deprecated use {@code cfg.install()} to avoid internal reference.
 	 * @param cfg
 	 *            the new window cache configuration.
-	 * @throws IllegalArgumentException
+	 * @throws java.lang.IllegalArgumentException
 	 *             the cache configuration contains one or more invalid
 	 *             settings, usually too low of a limit.
 	 */
 	@Deprecated
-	public static void reconfigure(final WindowCacheConfig cfg) {
+	public static void reconfigure(WindowCacheConfig cfg) {
 		final WindowCache nc = new WindowCache(cfg);
 		final WindowCache oc = cache;
 		if (oc != null)
@@ -169,11 +171,14 @@ static int getStreamFileThreshold() {
 		return streamFileThreshold;
 	}
 
-	static WindowCache getInstance() {
+	/**
+	 * @return the cached instance.
+	 */
+	public static WindowCache getInstance() {
 		return cache;
 	}
 
-	static final ByteWindow get(final PackFile pack, final long offset)
+	static final ByteWindow get(PackFile pack, long offset)
 			throws IOException {
 		final WindowCache c = cache;
 		final ByteWindow r = c.getOrLoad(pack, c.toStart(offset));
@@ -188,7 +193,7 @@ static final ByteWindow get(final PackFile pack, final long offset)
 		return r;
 	}
 
-	static final void purge(final PackFile pack) {
+	static final void purge(PackFile pack) {
 		cache.removeAll(pack);
 	}
 
@@ -227,7 +232,7 @@ static final void purge(final PackFile pack) {
 
 	private final AtomicLong openBytes;
 
-	private WindowCache(final WindowCacheConfig cfg) {
+	private WindowCache(WindowCacheConfig cfg) {
 		tableSize = tableSize(cfg);
 		final int lockCount = lockCount(cfg);
 		if (tableSize < 1)
@@ -267,19 +272,25 @@ else if (eb < 4)
 			throw new IllegalArgumentException(JGitText.get().windowSizeMustBeLesserThanLimit);
 	}
 
-	int getOpenFiles() {
+	/**
+	 * @return the number of open files.
+	 */
+	public int getOpenFiles() {
 		return openFiles.get();
 	}
 
-	long getOpenBytes() {
+	/**
+	 * @return the number of open bytes.
+	 */
+	public long getOpenBytes() {
 		return openBytes.get();
 	}
 
-	private int hash(final int packHash, final long off) {
+	private int hash(int packHash, long off) {
 		return packHash + (int) (off >>> windowSizeShift);
 	}
 
-	private ByteWindow load(final PackFile pack, final long offset)
+	private ByteWindow load(PackFile pack, long offset)
 			throws IOException {
 		if (pack.beginWindowCache())
 			openFiles.incrementAndGet();
@@ -299,18 +310,18 @@ private ByteWindow load(final PackFile pack, final long offset)
 		}
 	}
 
-	private Ref createRef(final PackFile p, final long o, final ByteWindow v) {
+	private Ref createRef(PackFile p, long o, ByteWindow v) {
 		final Ref ref = new Ref(p, o, v, queue);
 		openBytes.addAndGet(ref.size);
 		return ref;
 	}
 
-	private void clear(final Ref ref) {
+	private void clear(Ref ref) {
 		openBytes.addAndGet(-ref.size);
 		close(ref.pack);
 	}
 
-	private void close(final PackFile pack) {
+	private void close(PackFile pack) {
 		if (pack.endWindowCache())
 			openFiles.decrementAndGet();
 	}
@@ -319,11 +330,11 @@ private boolean isFull() {
 		return maxFiles < openFiles.get() || maxBytes < openBytes.get();
 	}
 
-	private long toStart(final long offset) {
+	private long toStart(long offset) {
 		return (offset >>> windowSizeShift) << windowSizeShift;
 	}
 
-	private static int tableSize(final WindowCacheConfig cfg) {
+	private static int tableSize(WindowCacheConfig cfg) {
 		final int wsz = cfg.getPackedGitWindowSize();
 		final long limit = cfg.getPackedGitLimit();
 		if (wsz <= 0)
@@ -333,7 +344,7 @@ private static int tableSize(final WindowCacheConfig cfg) {
 		return (int) Math.min(5 * (limit / wsz) / 2, 2000000000);
 	}
 
-	private static int lockCount(final WindowCacheConfig cfg) {
+	private static int lockCount(WindowCacheConfig cfg) {
 		return Math.max(cfg.getPackedGitOpenFiles(), 32);
 	}
 
@@ -349,7 +360,7 @@ private static int lockCount(final WindowCacheConfig cfg) {
 	 *             the object reference was not in the cache and could not be
 	 *             obtained by {@link #load(PackFile, long)}.
 	 */
-	private ByteWindow getOrLoad(final PackFile pack, final long position)
+	private ByteWindow getOrLoad(PackFile pack, long position)
 			throws IOException {
 		final int slot = slot(pack, position);
 		final Entry e1 = table.get(slot);
@@ -388,7 +399,7 @@ private ByteWindow getOrLoad(final PackFile pack, final long position)
 		return v;
 	}
 
-	private ByteWindow scan(Entry n, final PackFile pack, final long position) {
+	private ByteWindow scan(Entry n, PackFile pack, long position) {
 		for (; n != null; n = n.next) {
 			final Ref r = n.ref;
 			if (r.pack == pack && r.position == position) {
@@ -404,7 +415,7 @@ private ByteWindow scan(Entry n, final PackFile pack, final long position) {
 		return null;
 	}
 
-	private void hit(final Ref r) {
+	private void hit(Ref r) {
 		// We don't need to be 100% accurate here. Its sufficient that at least
 		// one thread performs the increment. Any other concurrent access at
 		// exactly the same time can simply use the same clock value.
@@ -476,7 +487,7 @@ private void removeAll() {
 	 * @param pack
 	 *            the file to purge all entries of.
 	 */
-	private void removeAll(final PackFile pack) {
+	private void removeAll(PackFile pack) {
 		for (int s = 0; s < tableSize; s++) {
 			final Entry e1 = table.get(s);
 			boolean hasDead = false;
@@ -510,11 +521,11 @@ private void gc() {
 		}
 	}
 
-	private int slot(final PackFile pack, final long position) {
+	private int slot(PackFile pack, long position) {
 		return (hash(pack.hash, position) >>> 1) % tableSize;
 	}
 
-	private Lock lock(final PackFile pack, final long position) {
+	private Lock lock(PackFile pack, long position) {
 		return locks[(hash(pack.hash, position) >>> 1) % locks.length];
 	}
 
@@ -545,7 +556,7 @@ private static class Entry {
 		 */
 		volatile boolean dead;
 
-		Entry(final Entry n, final Ref r) {
+		Entry(Entry n, Ref r) {
 			next = n;
 			ref = r;
 		}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/WindowCursor.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/WindowCursor.java
index 83b236e..010c142 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/WindowCursor.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/WindowCursor.java
@@ -110,11 +110,13 @@ DeltaBaseCache getDeltaBaseCache() {
 		return baseCache;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public ObjectReader newReader() {
 		return new WindowCursor(db);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public BitmapIndex getBitmapIndex() throws IOException {
 		for (PackFile pack : db.getPacks()) {
@@ -125,6 +127,7 @@ public BitmapIndex getBitmapIndex() throws IOException {
 		return null;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public Collection<CachedPack> getCachedPacksAndUpdate(
 			BitmapBuilder needBitmap) throws IOException {
@@ -137,6 +140,7 @@ public Collection<CachedPack> getCachedPacksAndUpdate(
 		return Collections.emptyList();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public Collection<ObjectId> resolve(AbbreviatedObjectId id)
 			throws IOException {
@@ -147,11 +151,13 @@ public Collection<ObjectId> resolve(AbbreviatedObjectId id)
 		return matches;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public boolean has(AnyObjectId objectId) throws IOException {
 		return db.has(objectId);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public ObjectLoader open(AnyObjectId objectId, int typeHint)
 			throws MissingObjectException, IncorrectObjectTypeException,
@@ -168,11 +174,13 @@ public ObjectLoader open(AnyObjectId objectId, int typeHint)
 		return ldr;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public Set<ObjectId> getShallowCommits() throws IOException {
 		return db.getShallowCommits();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public long getObjectSize(AnyObjectId objectId, int typeHint)
 			throws MissingObjectException, IncorrectObjectTypeException,
@@ -187,11 +195,13 @@ public long getObjectSize(AnyObjectId objectId, int typeHint)
 		return sz;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public LocalObjectToPack newObjectToPack(AnyObjectId objectId, int type) {
 		return new LocalObjectToPack(objectId, type);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void selectObjectRepresentation(PackWriter packer,
 			ProgressMonitor monitor, Iterable<ObjectToPack> objects)
@@ -202,6 +212,7 @@ public void selectObjectRepresentation(PackWriter packer,
 		}
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void copyObjectAsIs(PackOutputStream out, ObjectToPack otp,
 			boolean validate) throws IOException,
@@ -210,6 +221,7 @@ public void copyObjectAsIs(PackOutputStream out, ObjectToPack otp,
 		src.pack.copyAsIs(out, src, validate, this);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void writeObjects(PackOutputStream out, List<ObjectToPack> list)
 			throws IOException {
@@ -253,6 +265,7 @@ int copy(final PackFile pack, long position, final byte[] dstbuf,
 		return cnt - need;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void copyPackAsIs(PackOutputStream out, CachedPack pack)
 			throws IOException {
@@ -334,7 +347,7 @@ private void prepareInflater() {
 			inf.reset();
 	}
 
-	void pin(final PackFile pack, final long position)
+	void pin(PackFile pack, long position)
 			throws IOException {
 		final ByteWindow w = window;
 		if (w == null || !w.contains(pack, position)) {
@@ -348,13 +361,18 @@ void pin(final PackFile pack, final long position)
 		}
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	@Nullable
 	public ObjectInserter getCreatedFromInserter() {
 		return createdFromInserter;
 	}
 
-	/** Release the current window cursor. */
+	/**
+	 * {@inheritDoc}
+	 * <p>
+	 * Release the current window cursor.
+	 */
 	@Override
 	public void close() {
 		window = null;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/WriteConfig.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/WriteConfig.java
index d9cbbd8..23055ee 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/WriteConfig.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/WriteConfig.java
@@ -57,7 +57,7 @@ class WriteConfig {
 
 	private final boolean fsyncRefFiles;
 
-	private WriteConfig(final Config rc) {
+	private WriteConfig(Config rc) {
 		compression = rc.get(CoreConfig.KEY).getCompression();
 		fsyncObjectFiles = rc.getBoolean("core", "fsyncobjectfiles", false); //$NON-NLS-1$ //$NON-NLS-2$
 		fsyncRefFiles = rc.getBoolean("core", "fsyncreffiles", false); //$NON-NLS-1$ //$NON-NLS-2$
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/io/BlockSource.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/io/BlockSource.java
index 0a5f9c1..5677298 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/io/BlockSource.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/io/BlockSource.java
@@ -153,7 +153,7 @@ public void close() {
 	 * @param blockSize
 	 *            size to read.
 	 * @return buffer containing the block content.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             if block cannot be read.
 	 */
 	public abstract ByteBuffer read(long position, int blockSize)
@@ -163,7 +163,7 @@ public abstract ByteBuffer read(long position, int blockSize)
 	 * Determine the size of the file.
 	 *
 	 * @return total number of bytes in the file.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             if size cannot be obtained.
 	 */
 	public abstract long size() throws IOException;
@@ -180,6 +180,7 @@ public void adviseSequentialRead(long startPos, long endPos) {
 		// Do nothing by default.
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public abstract void close();
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/BinaryDelta.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/BinaryDelta.java
index 2565931..c7e5ad6 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/BinaryDelta.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/BinaryDelta.java
@@ -64,7 +64,7 @@ public class BinaryDelta {
 	 *            the delta stream, or at least the header of it.
 	 * @return the base object's size.
 	 */
-	public static long getBaseSize(final byte[] delta) {
+	public static long getBaseSize(byte[] delta) {
 		int p = 0;
 		long baseLen = 0;
 		int c, shift = 0;
@@ -83,7 +83,7 @@ public static long getBaseSize(final byte[] delta) {
 	 *            the delta stream, or at least the header of it.
 	 * @return the resulting object's size.
 	 */
-	public static long getResultSize(final byte[] delta) {
+	public static long getResultSize(byte[] delta) {
 		int p = 0;
 
 		// Skip length of the base object.
@@ -114,7 +114,7 @@ public static long getResultSize(final byte[] delta) {
 	 *            another.
 	 * @return patched base
 	 */
-	public static final byte[] apply(final byte[] base, final byte[] delta) {
+	public static final byte[] apply(byte[] base, byte[] delta) {
 		return apply(base, delta, null);
 	}
 
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/CachedPack.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/CachedPack.java
index 6498ea3..81f4055 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/CachedPack.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/CachedPack.java
@@ -45,13 +45,17 @@
 
 import java.io.IOException;
 
-/** Describes a pack file {@link ObjectReuseAsIs} can append onto a stream. */
+/**
+ * Describes a pack file
+ * {@link org.eclipse.jgit.internal.storage.pack.ObjectReuseAsIs} can append
+ * onto a stream.
+ */
 public abstract class CachedPack {
 	/**
 	 * Get the number of objects in this pack.
 	 *
 	 * @return the total object count for the pack.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             if the object count cannot be read.
 	 */
 	public abstract long getObjectCount() throws IOException;
@@ -70,7 +74,7 @@ public abstract class CachedPack {
 	 *
 	 * @return the number of deltas; 0 if the number is not known or there are
 	 *         no deltas.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             if the delta count cannot be read.
 	 */
 	public long getDeltaCount() throws IOException {
@@ -88,15 +92,16 @@ public long getDeltaCount() throws IOException {
 	 * only and using its internal state to decide if this object is within this
 	 * pack. Implementors should ensure a representation from this cached pack
 	 * is tested as part of
-	 * {@link ObjectReuseAsIs#selectObjectRepresentation(PackWriter, org.eclipse.jgit.lib.ProgressMonitor, Iterable)}
+	 * {@link org.eclipse.jgit.internal.storage.pack.ObjectReuseAsIs#selectObjectRepresentation(PackWriter, org.eclipse.jgit.lib.ProgressMonitor, Iterable)}
 	 * , ensuring this method would eventually return true if the object would
 	 * be included by this cached pack.
 	 *
 	 * @param obj
 	 *            the object being packed. Can be used as an ObjectId.
 	 * @param rep
-	 *            representation from the {@link ObjectReuseAsIs} instance that
-	 *            originally supplied this CachedPack.
+	 *            representation from the
+	 *            {@link org.eclipse.jgit.internal.storage.pack.ObjectReuseAsIs}
+	 *            instance that originally supplied this CachedPack.
 	 * @return true if this pack contains this object.
 	 */
 	public abstract boolean hasObject(ObjectToPack obj,
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/DeltaEncoder.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/DeltaEncoder.java
index cccbc59..343faf4 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/DeltaEncoder.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/DeltaEncoder.java
@@ -48,7 +48,10 @@
 
 import org.eclipse.jgit.lib.Constants;
 
-/** Encodes an instruction stream for {@link BinaryDelta}. */
+/**
+ * Encodes an instruction stream for
+ * {@link org.eclipse.jgit.internal.storage.pack.BinaryDelta}.
+ */
 public class DeltaEncoder {
 	/**
 	 * Maximum number of bytes to be copied in pack v2 format.
@@ -91,7 +94,7 @@ public class DeltaEncoder {
 	 * @param resultSize
 	 *            size of the resulting object, after applying this instruction
 	 *            stream to the base object, in bytes.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the output buffer cannot store the instruction stream's
 	 *             header with the size fields.
 	 */
@@ -114,7 +117,7 @@ public DeltaEncoder(OutputStream out, long baseSize, long resultSize)
 	 *            maximum number of bytes to write to the out buffer declaring
 	 *            the stream is over limit and should be discarded. May be 0 to
 	 *            specify an infinite limit.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the output buffer cannot store the instruction stream's
 	 *             header with the size fields.
 	 */
@@ -138,7 +141,11 @@ private void writeVarint(long sz) throws IOException {
 			out.write(buf, 0, p);
 	}
 
-	/** @return current size of the delta stream, in bytes. */
+	/**
+	 * Get current size of the delta stream, in bytes.
+	 *
+	 * @return current size of the delta stream, in bytes.
+	 */
 	public int getSize() {
 		return size;
 	}
@@ -150,7 +157,7 @@ public int getSize() {
 	 *            the string to insert.
 	 * @return true if the insert fits within the limit; false if the insert
 	 *         would cause the instruction stream to exceed the limit.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the instruction buffer can't store the instructions.
 	 */
 	public boolean insert(String text) throws IOException {
@@ -164,7 +171,7 @@ public boolean insert(String text) throws IOException {
 	 *            the binary to insert.
 	 * @return true if the insert fits within the limit; false if the insert
 	 *         would cause the instruction stream to exceed the limit.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the instruction buffer can't store the instructions.
 	 */
 	public boolean insert(byte[] text) throws IOException {
@@ -182,7 +189,7 @@ public boolean insert(byte[] text) throws IOException {
 	 *            number of bytes to insert.
 	 * @return true if the insert fits within the limit; false if the insert
 	 *         would cause the instruction stream to exceed the limit.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the instruction buffer can't store the instructions.
 	 */
 	public boolean insert(byte[] text, int off, int cnt)
@@ -217,7 +224,7 @@ public boolean insert(byte[] text, int off, int cnt)
 	 *            number of bytes to copy.
 	 * @return true if the copy fits within the limit; false if the copy
 	 *         would cause the instruction stream to exceed the limit.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the instruction buffer cannot store the instructions.
 	 */
 	public boolean copy(long offset, int cnt) throws IOException {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/DeltaIndex.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/DeltaIndex.java
index 0f22de0..6f3e2ac 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/DeltaIndex.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/DeltaIndex.java
@@ -51,8 +51,9 @@
  * <p>
  * The index can be passed a result buffer, and output an instruction sequence
  * that transforms the source buffer used by the index into the result buffer.
- * The instruction sequence can be executed by {@link BinaryDelta} to recreate
- * the result buffer.
+ * The instruction sequence can be executed by
+ * {@link org.eclipse.jgit.internal.storage.pack.BinaryDelta} to recreate the
+ * result buffer.
  * <p>
  * An index stores the entire contents of the source buffer, but also a table of
  * block identities mapped to locations where the block appears in the source
@@ -191,7 +192,11 @@ private void copyEntries(DeltaIndexScanner scan) {
 		}
 	}
 
-	/** @return size of the source buffer this index has scanned. */
+	/**
+	 * Get size of the source buffer this index has scanned.
+	 *
+	 * @return size of the source buffer this index has scanned.
+	 */
 	public long getSourceSize() {
 		return src.length;
 	}
@@ -244,7 +249,7 @@ private static int sizeOfArray(int entSize, int len) {
 	 *            the desired result buffer. The generated instructions will
 	 *            recreate this buffer when applied to the source buffer stored
 	 *            within this index.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the output stream refused to write the instructions.
 	 */
 	public void encode(OutputStream out, byte[] res) throws IOException {
@@ -274,7 +279,7 @@ public void encode(OutputStream out, byte[] res) throws IOException {
 	 * @return true if the delta is smaller than deltaSizeLimit; false if the
 	 *         encoder aborted because the encoded delta instructions would be
 	 *         longer than deltaSizeLimit bytes.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the output stream refused to write the instructions.
 	 */
 	public boolean encode(OutputStream out, byte[] res, int deltaSizeLimit)
@@ -421,6 +426,7 @@ private static int negmatch(byte[] res, int resPtr, byte[] src, int srcPtr,
 		return start - resPtr;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	@SuppressWarnings("nls")
 	public String toString() {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/DeltaIndexScanner.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/DeltaIndexScanner.java
index 969d02b..944a9e5 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/DeltaIndexScanner.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/DeltaIndexScanner.java
@@ -89,7 +89,7 @@ class DeltaIndexScanner {
 		}
 	}
 
-	private void scan(byte[] raw, final int end) {
+	private void scan(byte[] raw, int end) {
 		// We scan the input backwards, and always insert onto the
 		// front of the chain. This ensures that chains will have lower
 		// offsets at the front of the chain, allowing us to prefer the
@@ -120,7 +120,7 @@ private void scan(byte[] raw, final int end) {
 		} while (0 <= ptr);
 	}
 
-	private static int tableSize(final int worstCaseBlockCnt) {
+	private static int tableSize(int worstCaseBlockCnt) {
 		int shift = 32 - Integer.numberOfLeadingZeros(worstCaseBlockCnt);
 		int sz = 1 << (shift - 1);
 		if (sz < worstCaseBlockCnt)
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/DeltaTask.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/DeltaTask.java
index 0c4e444..0347644 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/DeltaTask.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/DeltaTask.java
@@ -292,6 +292,7 @@ void add(Slice s) {
 		slices.add(s);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public Object call() throws Exception {
 		or = block.templateReader.newReader();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/DeltaWindow.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/DeltaWindow.java
index 73b285a..a047534 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/DeltaWindow.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/DeltaWindow.java
@@ -266,7 +266,7 @@ private void searchInWindow() throws IOException {
 		deltaBuf = null;
 	}
 
-	private boolean delta(final DeltaWindowEntry src)
+	private boolean delta(DeltaWindowEntry src)
 			throws IOException {
 		// If the sizes are radically different, this is a bad pairing.
 		if (res.size() < src.size() >>> 4)
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/ObjectReuseAsIs.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/ObjectReuseAsIs.java
index 2e5d599..f759e23 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/ObjectReuseAsIs.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/ObjectReuseAsIs.java
@@ -51,26 +51,27 @@
 import org.eclipse.jgit.errors.StoredObjectRepresentationNotAvailableException;
 import org.eclipse.jgit.lib.AnyObjectId;
 import org.eclipse.jgit.lib.BitmapIndex.BitmapBuilder;
-import org.eclipse.jgit.lib.ObjectReader;
 import org.eclipse.jgit.lib.ProgressMonitor;
 
 /**
- * Extension of {@link ObjectReader} that supports reusing objects in packs.
+ * Extension of {@link org.eclipse.jgit.lib.ObjectReader} that supports reusing
+ * objects in packs.
  * <p>
  * {@code ObjectReader} implementations may also optionally implement this
- * interface to support {@link PackWriter} with a means of copying an object
- * that is already in pack encoding format directly into the output stream,
- * without incurring decompression and recompression overheads.
+ * interface to support
+ * {@link org.eclipse.jgit.internal.storage.pack.PackWriter} with a means of
+ * copying an object that is already in pack encoding format directly into the
+ * output stream, without incurring decompression and recompression overheads.
  */
 public interface ObjectReuseAsIs {
 	/**
 	 * Allocate a new {@code PackWriter} state structure for an object.
 	 * <p>
-	 * {@link PackWriter} allocates these objects to keep track of the
-	 * per-object state, and how to load the objects efficiently into the
-	 * generated stream. Implementers may subclass this type with additional
-	 * object state, such as to remember what file and offset contains the
-	 * object's pack encoded data.
+	 * {@link org.eclipse.jgit.internal.storage.pack.PackWriter} allocates these
+	 * objects to keep track of the per-object state, and how to load the
+	 * objects efficiently into the generated stream. Implementers may subclass
+	 * this type with additional object state, such as to remember what file and
+	 * offset contains the object's pack encoded data.
 	 *
 	 * @param objectId
 	 *            the id of the object that will be packed.
@@ -85,15 +86,16 @@ public interface ObjectReuseAsIs {
 	 * <p>
 	 * Implementations should iterate through all available representations of
 	 * an object, and pass them in turn to the PackWriter though
-	 * {@link PackWriter#select(ObjectToPack, StoredObjectRepresentation)} so
-	 * the writer can select the most suitable representation to reuse into the
-	 * output stream.
+	 * {@link org.eclipse.jgit.internal.storage.pack.PackWriter#select(ObjectToPack, StoredObjectRepresentation)}
+	 * so the writer can select the most suitable representation to reuse into
+	 * the output stream.
 	 * <p>
-	 * If the implementation returns CachedPack from {@link #getCachedPacksAndUpdate(BitmapBuilder)}
-	 * it must consider the representation of any object that is stored in any
-	 * of the offered CachedPacks. PackWriter relies on this behavior to prune
-	 * duplicate objects out of the pack stream when it selects a CachedPack and
-	 * the object was also reached through the thin-pack enumeration.
+	 * If the implementation returns CachedPack from
+	 * {@link #getCachedPacksAndUpdate(BitmapBuilder)} it must consider the
+	 * representation of any object that is stored in any of the offered
+	 * CachedPacks. PackWriter relies on this behavior to prune duplicate
+	 * objects out of the pack stream when it selects a CachedPack and the
+	 * object was also reached through the thin-pack enumeration.
 	 * <p>
 	 * The implementation may choose to consider multiple objects at once on
 	 * concurrent threads, but must evaluate all representations of an object
@@ -106,10 +108,10 @@ public interface ObjectReuseAsIs {
 	 *            once for each item in the iteration when selection is done.
 	 * @param objects
 	 *            the objects that are being packed.
-	 * @throws MissingObjectException
+	 * @throws org.eclipse.jgit.errors.MissingObjectException
 	 *             there is no representation available for the object, as it is
 	 *             no longer in the repository. Packing will abort.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the repository cannot be accessed. Packing will abort.
 	 */
 	public void selectObjectRepresentation(PackWriter packer,
@@ -136,7 +138,9 @@ public void selectObjectRepresentation(PackWriter packer,
 	 * format to reach a delta base that is later in the stream. It may also
 	 * reduce data locality for the reader, slowing down data access.
 	 *
-	 * Invoking {@link PackOutputStream#writeObject(ObjectToPack)} will cause
+	 * Invoking
+	 * {@link org.eclipse.jgit.internal.storage.pack.PackOutputStream#writeObject(ObjectToPack)}
+	 * will cause
 	 * {@link #copyObjectAsIs(PackOutputStream, ObjectToPack, boolean)} to be
 	 * invoked recursively on {@code this} if the current object is scheduled
 	 * for reuse.
@@ -147,7 +151,7 @@ public void selectObjectRepresentation(PackWriter packer,
 	 *            the list of objects to write. Objects should be written in
 	 *            approximately this order. Implementors may resort the list
 	 *            elements in-place during writing if desired.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the stream cannot be written to, or one or more required
 	 *             objects cannot be accessed from the object database.
 	 */
@@ -186,13 +190,13 @@ public void writeObjects(PackOutputStream out, List<ObjectToPack> list)
 	 *            corrupt before being reused. If false, validation may be
 	 *            skipped as it will be performed elsewhere in the processing
 	 *            pipeline.
-	 * @throws StoredObjectRepresentationNotAvailableException
+	 * @throws org.eclipse.jgit.errors.StoredObjectRepresentationNotAvailableException
 	 *             the previously selected representation is no longer
 	 *             available. If thrown before {@code out.writeHeader} the pack
 	 *             writer will try to find another representation, and write
 	 *             that one instead. If throw after {@code out.writeHeader},
 	 *             packing will abort.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the stream's write method threw an exception. Packing will
 	 *             abort.
 	 */
@@ -209,7 +213,7 @@ public void copyObjectAsIs(PackOutputStream out, ObjectToPack otp,
 	 *            stream to append the pack onto.
 	 * @param pack
 	 *            the cached pack to send.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the pack cannot be read, or stream did not accept a write.
 	 */
 	public abstract void copyPackAsIs(PackOutputStream out, CachedPack pack)
@@ -225,7 +229,7 @@ public abstract void copyPackAsIs(PackOutputStream out, CachedPack pack)
 	 * @param needBitmap
 	 *            the bitmap that contains all of the objects the client wants.
 	 * @return the available cached packs.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the cached packs cannot be listed from the repository.
 	 *             Callers may choose to ignore this and continue as-if there
 	 *             were no cached packs.
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/ObjectToPack.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/ObjectToPack.java
index bc7a603..a30bf98 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/ObjectToPack.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/ObjectToPack.java
@@ -50,7 +50,8 @@
 import org.eclipse.jgit.transport.PackedObjectInfo;
 
 /**
- * Per-object state used by {@link PackWriter}.
+ * Per-object state used by
+ * {@link org.eclipse.jgit.internal.storage.pack.PackWriter}.
  * <p>
  * {@code PackWriter} uses this class to track the things it needs to include in
  * the newly generated pack file, and how to efficiently obtain the raw data for
@@ -102,25 +103,31 @@ public class ObjectToPack extends PackedObjectInfo {
 	 * @param type
 	 *            real type code of the object, not its in-pack type.
 	 */
-	public ObjectToPack(AnyObjectId src, final int type) {
+	public ObjectToPack(AnyObjectId src, int type) {
 		super(src);
 		flags = type << TYPE_SHIFT;
 	}
 
 	/**
+	 * Get delta base object id if object is going to be packed in delta
+	 * representation
+	 *
 	 * @return delta base object id if object is going to be packed in delta
-	 *         representation; null otherwise - if going to be packed as a
-	 *         whole object.
+	 *         representation; null otherwise - if going to be packed as a whole
+	 *         object.
 	 */
 	public final ObjectId getDeltaBaseId() {
 		return deltaBase;
 	}
 
 	/**
+	 * Get delta base object to pack if object is going to be packed in delta
+	 * representation and delta is specified as object to pack
+	 *
 	 * @return delta base object to pack if object is going to be packed in
-	 *         delta representation and delta is specified as object to
-	 *         pack; null otherwise - if going to be packed as a whole
-	 *         object or delta base is specified only as id.
+	 *         delta representation and delta is specified as object to pack;
+	 *         null otherwise - if going to be packed as a whole object or delta
+	 *         base is specified only as id.
 	 */
 	public final ObjectToPack getDeltaBase() {
 		if (deltaBase instanceof ObjectToPack)
@@ -164,8 +171,9 @@ final void clearDeltaBase() {
 	}
 
 	/**
-	 * @return true if object is going to be written as delta; false
-	 *         otherwise.
+	 * Whether object is going to be written as delta
+	 *
+	 * @return true if object is going to be written as delta; false otherwise.
 	 */
 	public final boolean isDeltaRepresentation() {
 		return deltaBase != null;
@@ -181,7 +189,7 @@ public final boolean isWritten() {
 		return 1 < getOffset(); // markWantWrite sets 1.
 	}
 
-	/** @return the type of this object. */
+	/** {@inheritDoc} */
 	@Override
 	public final int getType() {
 		return (flags >> TYPE_SHIFT) & 0x7;
@@ -216,6 +224,9 @@ final void markWantWrite() {
 	}
 
 	/**
+	 * Whether an existing representation was selected to be reused as-is into
+	 * the pack stream.
+	 *
 	 * @return true if an existing representation was selected to be reused
 	 *         as-is into the pack stream.
 	 */
@@ -266,7 +277,11 @@ final void setDeltaAttempted(boolean deltaAttempted) {
 			flags &= ~DELTA_ATTEMPTED;
 	}
 
-	/** @return the extended flags on this object, in the range [0x0, 0xf]. */
+	/**
+	 * Get the extended flags on this object, in the range [0x0, 0xf].
+	 *
+	 * @return the extended flags on this object, in the range [0x0, 0xf].
+	 */
 	protected final int getExtendedFlags() {
 		return (flags >>> EXT_SHIFT) & EXT_MASK;
 	}
@@ -363,9 +378,10 @@ final void setCachedSize(int sz) {
 	 * Remember a specific representation for reuse at a later time.
 	 * <p>
 	 * Implementers should remember the representation chosen, so it can be
-	 * reused at a later time. {@link PackWriter} may invoke this method
-	 * multiple times for the same object, each time saving the current best
-	 * representation found.
+	 * reused at a later time.
+	 * {@link org.eclipse.jgit.internal.storage.pack.PackWriter} may invoke this
+	 * method multiple times for the same object, each time saving the current
+	 * best representation found.
 	 *
 	 * @param ref
 	 *            the object representation.
@@ -374,6 +390,7 @@ public void select(StoredObjectRepresentation ref) {
 		// Empty by default.
 	}
 
+	/** {@inheritDoc} */
 	@SuppressWarnings("nls")
 	@Override
 	public String toString() {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackExt.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackExt.java
index e8bbf78..292fd36 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackExt.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackExt.java
@@ -43,7 +43,9 @@
 
 package org.eclipse.jgit.internal.storage.pack;
 
-/** A pack file extension. */
+/**
+ * A pack file extension.
+ */
 public class PackExt {
 	private static volatile PackExt[] VALUES = new PackExt[] {};
 
@@ -62,7 +64,11 @@ public class PackExt {
 	/** A reftable file. */
 	public static final PackExt REFTABLE = newPackExt("ref"); //$NON-NLS-1$
 
-	/** @return all of the PackExt values. */
+	/**
+	 * Get all of the PackExt values.
+	 *
+	 * @return all of the PackExt values.
+	 */
 	public static PackExt[] values() {
 		return VALUES;
 	}
@@ -102,21 +108,34 @@ private PackExt(String ext, int pos) {
 		this.pos = pos;
 	}
 
-	/** @return the file extension. */
+	/**
+	 * Get the file extension.
+	 *
+	 * @return the file extension.
+	 */
 	public String getExtension() {
 		return ext;
 	}
 
-	/** @return the position of the extension in the values array. */
+	/**
+	 * Get the position of the extension in the values array.
+	 *
+	 * @return the position of the extension in the values array.
+	 */
 	public int getPosition() {
 		return pos;
 	}
 
-	/** @return the bit mask of the extension e.g {@code 1 << getPosition()}. */
+	/**
+	 * Get the bit mask of the extension e.g {@code 1 << getPosition()}.
+	 *
+	 * @return the bit mask of the extension e.g {@code 1 << getPosition()}.
+	 */
 	public int getBit() {
 		return 1 << getPosition();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public String toString() {
 		return String.format("PackExt[%s, bit=0x%s]", getExtension(), //$NON-NLS-1$
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackOutputStream.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackOutputStream.java
index 59166e6..7f38a7b 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackOutputStream.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackOutputStream.java
@@ -57,7 +57,10 @@
 import org.eclipse.jgit.lib.ProgressMonitor;
 import org.eclipse.jgit.util.NB;
 
-/** Custom output stream to support {@link PackWriter}. */
+/**
+ * Custom output stream to support
+ * {@link org.eclipse.jgit.internal.storage.pack.PackWriter}.
+ */
 public final class PackOutputStream extends OutputStream {
 	private static final int BYTES_TO_WRITE_BEFORE_CANCEL_CHECK = 128 * 1024;
 
@@ -84,7 +87,8 @@ public final class PackOutputStream extends OutputStream {
 	 * <p>
 	 * This constructor is exposed to support debugging the JGit library only.
 	 * Application or storage level code should not create a PackOutputStream,
-	 * instead use {@link PackWriter}, and let the writer create the stream.
+	 * instead use {@link org.eclipse.jgit.internal.storage.pack.PackWriter},
+	 * and let the writer create the stream.
 	 *
 	 * @param writeMonitor
 	 *            monitor to update on object output progress.
@@ -101,15 +105,17 @@ public PackOutputStream(final ProgressMonitor writeMonitor,
 		this.checkCancelAt = BYTES_TO_WRITE_BEFORE_CANCEL_CHECK;
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	public final void write(final int b) throws IOException {
+	public final void write(int b) throws IOException {
 		count++;
 		out.write(b);
 		md.update((byte) b);
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	public final void write(final byte[] b, int off, int len)
+	public final void write(byte[] b, int off, int len)
 			throws IOException {
 		while (0 < len) {
 			final int n = Math.min(len, BYTES_TO_WRITE_BEFORE_CANCEL_CHECK);
@@ -131,6 +137,7 @@ public final void write(final byte[] b, int off, int len)
 		}
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void flush() throws IOException {
 		out.flush();
@@ -154,7 +161,7 @@ final void writeFileHeader(int version, long objectCount)
 	 *
 	 * @param otp
 	 *            the object to write.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the object cannot be read from the object reader, or the
 	 *             output stream is no longer accepting output. Caller must
 	 *             examine the type of exception and possibly its message to
@@ -177,7 +184,7 @@ public final void writeObject(ObjectToPack otp) throws IOException {
 	 *            in whole object format, this is the same as the object size.
 	 *            For an object that is in a delta format, this is the size of
 	 *            the inflated delta instruction stream.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the underlying stream refused to accept the header.
 	 */
 	public final void writeHeader(ObjectToPack otp, long rawLength)
@@ -224,7 +231,11 @@ private static final int ofsDeltaVarIntLength(long v) {
 		return n;
 	}
 
-	/** @return a temporary buffer writers can use to copy data with. */
+	/**
+	 * Get a temporary buffer writers can use to copy data with.
+	 *
+	 * @return a temporary buffer writers can use to copy data with.
+	 */
 	public final byte[] getCopyBuffer() {
 		return copyBuffer;
 	}
@@ -233,7 +244,11 @@ void endObject() {
 		writeMonitor.update(1);
 	}
 
-	/** @return total number of bytes written since stream start. */
+	/**
+	 * Get total number of bytes written since stream start.
+	 *
+	 * @return total number of bytes written since stream start.
+	 */
 	public final long length() {
 		return count;
 	}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackWriter.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackWriter.java
index 7271560..36d6f0a 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackWriter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackWriter.java
@@ -81,6 +81,7 @@
 import java.util.zip.DeflaterOutputStream;
 
 import org.eclipse.jgit.annotations.NonNull;
+import org.eclipse.jgit.annotations.Nullable;
 import org.eclipse.jgit.errors.CorruptObjectException;
 import org.eclipse.jgit.errors.IncorrectObjectTypeException;
 import org.eclipse.jgit.errors.LargeObjectException;
@@ -107,6 +108,7 @@
 import org.eclipse.jgit.lib.Repository;
 import org.eclipse.jgit.lib.ThreadSafeProgressMonitor;
 import org.eclipse.jgit.revwalk.AsyncRevObjectQueue;
+import org.eclipse.jgit.revwalk.BitmapWalker;
 import org.eclipse.jgit.revwalk.DepthWalk;
 import org.eclipse.jgit.revwalk.ObjectWalk;
 import org.eclipse.jgit.revwalk.RevCommit;
@@ -134,8 +136,8 @@
  * <li>(usually) by providing sets of interesting and uninteresting objects in
  * repository - all interesting objects and their ancestors except uninteresting
  * objects and their ancestors will be included in pack, or</li>
- * <li>by providing iterator of {@link RevObject} specifying exact list and
- * order of objects in pack</li>
+ * <li>by providing iterator of {@link org.eclipse.jgit.revwalk.RevObject}
+ * specifying exact list and order of objects in pack</li>
  * </ul>
  * <p>
  * Typical usage consists of creating an instance, configuring options,
@@ -148,10 +150,11 @@
  * followed by {@link #writeBitmapIndex(OutputStream)}.
  * </p>
  * <p>
- * Class provide set of configurable options and {@link ProgressMonitor}
- * support, as operations may take a long time for big repositories. Deltas
- * searching algorithm is <b>NOT IMPLEMENTED</b> yet - this implementation
- * relies only on deltas and objects reuse.
+ * Class provide set of configurable options and
+ * {@link org.eclipse.jgit.lib.ProgressMonitor} support, as operations may take
+ * a long time for big repositories. Deltas searching algorithm is <b>NOT
+ * IMPLEMENTED</b> yet - this implementation relies only on deltas and objects
+ * reuse.
  * </p>
  * <p>
  * This class is not thread safe. It is intended to be used in one thread as a
@@ -209,7 +212,11 @@ public void remove() {
 		}
 	};
 
-	/** @return all allocated, non-released PackWriters instances. */
+	/**
+	 * Get all allocated, non-released PackWriters instances.
+	 *
+	 * @return all allocated, non-released PackWriters instances.
+	 */
 	public static Iterable<PackWriter> getInstances() {
 		return instancesIterable;
 	}
@@ -296,6 +303,8 @@ public static Iterable<PackWriter> getInstances() {
 
 	private ObjectCountCallback callback;
 
+	private long filterBlobLimit = -1;
+
 	/**
 	 * Create writer for specified repository.
 	 * <p>
@@ -305,7 +314,7 @@ public static Iterable<PackWriter> getInstances() {
 	 * @param repo
 	 *            repository where objects are stored.
 	 */
-	public PackWriter(final Repository repo) {
+	public PackWriter(Repository repo) {
 		this(repo, repo.newObjectReader());
 	}
 
@@ -318,7 +327,7 @@ public PackWriter(final Repository repo) {
 	 * @param reader
 	 *            reader to read from the repository with.
 	 */
-	public PackWriter(final ObjectReader reader) {
+	public PackWriter(ObjectReader reader) {
 		this(new PackConfig(), reader);
 	}
 
@@ -333,7 +342,7 @@ public PackWriter(final ObjectReader reader) {
 	 * @param reader
 	 *            reader to read from the repository with.
 	 */
-	public PackWriter(final Repository repo, final ObjectReader reader) {
+	public PackWriter(Repository repo, ObjectReader reader) {
 		this(new PackConfig(repo), reader);
 	}
 
@@ -348,7 +357,25 @@ public PackWriter(final Repository repo, final ObjectReader reader) {
 	 * @param reader
 	 *            reader to read from the repository with.
 	 */
-	public PackWriter(final PackConfig config, final ObjectReader reader) {
+	public PackWriter(PackConfig config, ObjectReader reader) {
+		this(config, reader, null);
+	}
+
+	/**
+	 * Create writer with a specified configuration.
+	 * <p>
+	 * Objects for packing are specified in {@link #preparePack(Iterator)} or
+	 * {@link #preparePack(ProgressMonitor, Set, Set)}.
+	 *
+	 * @param config
+	 *            configuration for the pack writer.
+	 * @param reader
+	 *            reader to read from the repository with.
+	 * @param statsAccumulator
+	 *            accumulator for statics
+	 */
+	public PackWriter(PackConfig config, final ObjectReader reader,
+			@Nullable PackStatistics.Accumulator statsAccumulator) {
 		this.config = config;
 		this.reader = reader;
 		if (reader instanceof ObjectReuseAsIs)
@@ -359,7 +386,8 @@ public PackWriter(final PackConfig config, final ObjectReader reader) {
 		deltaBaseAsOffset = config.isDeltaBaseAsOffset();
 		reuseDeltas = config.isReuseDeltas();
 		reuseValidate = true; // be paranoid by default
-		stats = new PackStatistics.Accumulator();
+		stats = statsAccumulator != null ? statsAccumulator
+				: new PackStatistics.Accumulator();
 		state = new MutableState();
 		selfRef = new WeakReference<>(this);
 		instances.put(selfRef, Boolean.TRUE);
@@ -373,7 +401,6 @@ public PackWriter(final PackConfig config, final ObjectReader reader) {
 	 *
 	 * @param callback
 	 *            the callback to set
-	 *
 	 * @return this object for chaining.
 	 */
 	public PackWriter setObjectCountCallback(ObjectCountCallback callback) {
@@ -465,12 +492,19 @@ public void setReuseValidatingObjects(boolean validate) {
 		reuseValidate = validate;
 	}
 
-	/** @return true if this writer is producing a thin pack. */
+	/**
+	 * Whether this writer is producing a thin pack.
+	 *
+	 * @return true if this writer is producing a thin pack.
+	 */
 	public boolean isThin() {
 		return thin;
 	}
 
 	/**
+	 * Whether writer may pack objects with delta base object not within set of
+	 * objects to pack
+	 *
 	 * @param packthin
 	 *            a boolean indicating whether writer may pack objects with
 	 *            delta base object not within set of objects to pack, but
@@ -478,20 +512,27 @@ public boolean isThin() {
 	 *            determined by set; this kind of pack is used only for
 	 *            transport; true - to produce thin pack, false - otherwise.
 	 */
-	public void setThin(final boolean packthin) {
+	public void setThin(boolean packthin) {
 		thin = packthin;
 	}
 
-	/** @return true to reuse cached packs. If true index creation isn't available. */
+	/**
+	 * Whether to reuse cached packs.
+	 *
+	 * @return {@code true} to reuse cached packs. If true index creation isn't
+	 *         available.
+	 */
 	public boolean isUseCachedPacks() {
 		return useCachedPacks;
 	}
 
 	/**
+	 * Whether to use cached packs
+	 *
 	 * @param useCached
-	 *            if set to true and a cached pack is present, it will be
-	 *            appended onto the end of a thin-pack, reducing the amount of
-	 *            working set space and CPU used by PackWriter. Enabling this
+	 *            if set to {@code true} and a cached pack is present, it will
+	 *            be appended onto the end of a thin-pack, reducing the amount
+	 *            of working set space and CPU used by PackWriter. Enabling this
 	 *            feature prevents PackWriter from creating an index for the
 	 *            newly created pack, so its only suitable for writing to a
 	 *            network client, where the client will make the index.
@@ -500,12 +541,18 @@ public void setUseCachedPacks(boolean useCached) {
 		useCachedPacks = useCached;
 	}
 
-	/** @return true to use bitmaps for ObjectWalks, if available. */
+	/**
+	 * Whether to use bitmaps
+	 *
+	 * @return {@code true} to use bitmaps for ObjectWalks, if available.
+	 */
 	public boolean isUseBitmaps() {
 		return useBitmaps;
 	}
 
 	/**
+	 * Whether to use bitmaps
+	 *
 	 * @param useBitmaps
 	 *            if set to true, bitmaps will be used when preparing a pack.
 	 */
@@ -513,23 +560,33 @@ public void setUseBitmaps(boolean useBitmaps) {
 		this.useBitmaps = useBitmaps;
 	}
 
-	/** @return true if the index file cannot be created by this PackWriter. */
+	/**
+	 * Whether the index file cannot be created by this PackWriter.
+	 *
+	 * @return {@code true} if the index file cannot be created by this
+	 *         PackWriter.
+	 */
 	public boolean isIndexDisabled() {
 		return indexDisabled || !cachedPacks.isEmpty();
 	}
 
 	/**
+	 * Whether to disable creation of the index file.
+	 *
 	 * @param noIndex
-	 *            true to disable creation of the index file.
+	 *            {@code true} to disable creation of the index file.
 	 */
 	public void setIndexDisabled(boolean noIndex) {
 		this.indexDisabled = noIndex;
 	}
 
 	/**
-	 * @return true to ignore objects that are uninteresting and also not found
-	 *         on local disk; false to throw a {@link MissingObjectException}
-	 *         out of {@link #preparePack(ProgressMonitor, Set, Set)} if an
+	 * Whether to ignore missing uninteresting objects
+	 *
+	 * @return {@code true} to ignore objects that are uninteresting and also
+	 *         not found on local disk; false to throw a
+	 *         {@link org.eclipse.jgit.errors.MissingObjectException} out of
+	 *         {@link #preparePack(ProgressMonitor, Set, Set)} if an
 	 *         uninteresting object is not in the source repository. By default,
 	 *         true, permitting gracefully ignoring of uninteresting objects.
 	 */
@@ -538,13 +595,15 @@ public boolean isIgnoreMissingUninteresting() {
 	}
 
 	/**
+	 * Whether writer should ignore non existing uninteresting objects
+	 *
 	 * @param ignore
-	 *            true if writer should ignore non existing uninteresting
-	 *            objects during construction set of objects to pack; false
-	 *            otherwise - non existing uninteresting objects may cause
-	 *            {@link MissingObjectException}
+	 *            {@code true} if writer should ignore non existing
+	 *            uninteresting objects during construction set of objects to
+	 *            pack; false otherwise - non existing uninteresting objects may
+	 *            cause {@link org.eclipse.jgit.errors.MissingObjectException}
 	 */
-	public void setIgnoreMissingUninteresting(final boolean ignore) {
+	public void setIgnoreMissingUninteresting(boolean ignore) {
 		ignoreMissingUninteresting = ignore;
 	}
 
@@ -582,10 +641,18 @@ public void setShallowPack(int depth,
 	}
 
 	/**
+	 * @param bytes exclude blobs of size greater than this
+	 * @since 5.0
+	 */
+	public void setFilterBlobLimit(long bytes) {
+		filterBlobLimit = bytes;
+	}
+
+	/**
 	 * Returns objects number in a pack file that was created by this writer.
 	 *
 	 * @return number of objects in pack.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             a cached pack cannot supply its object count.
 	 */
 	public long getObjectCount() throws IOException {
@@ -612,7 +679,7 @@ public long getObjectCount() throws IOException {
 	 * been invoked and completed successfully.
 	 *
 	 * @return set of objects in pack.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             a cached pack cannot supply its object ids.
 	 */
 	public ObjectIdOwnerMap<ObjectIdOwnerMap.Entry> getObjectSet()
@@ -671,12 +738,14 @@ public void excludeObjects(ObjectIdSet idx) {
 	 * @param objectsSource
 	 *            iterator of object to store in a pack; order of objects within
 	 *            each type is important, ordering by type is not needed;
-	 *            allowed types for objects are {@link Constants#OBJ_COMMIT},
-	 *            {@link Constants#OBJ_TREE}, {@link Constants#OBJ_BLOB} and
-	 *            {@link Constants#OBJ_TAG}; objects returned by iterator may be
-	 *            later reused by caller as object id and type are internally
-	 *            copied in each iteration.
-	 * @throws IOException
+	 *            allowed types for objects are
+	 *            {@link org.eclipse.jgit.lib.Constants#OBJ_COMMIT},
+	 *            {@link org.eclipse.jgit.lib.Constants#OBJ_TREE},
+	 *            {@link org.eclipse.jgit.lib.Constants#OBJ_BLOB} and
+	 *            {@link org.eclipse.jgit.lib.Constants#OBJ_TAG}; objects
+	 *            returned by iterator may be later reused by caller as object
+	 *            id and type are internally copied in each iteration.
+	 * @throws java.io.IOException
 	 *             when some I/O problem occur during reading objects.
 	 */
 	public void preparePack(@NonNull Iterator<RevObject> objectsSource)
@@ -692,10 +761,10 @@ public void preparePack(@NonNull Iterator<RevObject> objectsSource)
 	 * Basing on these 2 sets, another set of objects to put in a pack file is
 	 * created: this set consists of all objects reachable (ancestors) from
 	 * interesting objects, except uninteresting objects and their ancestors.
-	 * This method uses class {@link ObjectWalk} extensively to find out that
-	 * appropriate set of output objects and their optimal order in output pack.
-	 * Order is consistent with general git in-pack rules: sort by object type,
-	 * recency, path and delta-base first.
+	 * This method uses class {@link org.eclipse.jgit.revwalk.ObjectWalk}
+	 * extensively to find out that appropriate set of output objects and their
+	 * optimal order in output pack. Order is consistent with general git
+	 * in-pack rules: sort by object type, recency, path and delta-base first.
 	 * </p>
 	 *
 	 * @param countingMonitor
@@ -708,7 +777,7 @@ public void preparePack(@NonNull Iterator<RevObject> objectsSource)
 	 *            points of graph traversal). Pass {@link #NONE} if all objects
 	 *            reachable from {@code want} are desired, such as when serving
 	 *            a clone.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             when some I/O problem occur during reading objects.
 	 */
 	public void preparePack(ProgressMonitor countingMonitor,
@@ -743,7 +812,7 @@ public void preparePack(ProgressMonitor countingMonitor,
 	 *            {@code shallow} commits and earlier generations will be
 	 *            included in the pack if requested by {@code want}. Must not be
 	 *            {@code null}.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             an I/O problem occurred while reading objects.
 	 */
 	public void preparePack(ProgressMonitor countingMonitor,
@@ -782,7 +851,7 @@ public void preparePack(ProgressMonitor countingMonitor,
 	 * @param noBitmaps
 	 *            collection of objects to be excluded from bitmap commit
 	 *            selection.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             an I/O problem occurred while reading objects.
 	 */
 	public void preparePack(ProgressMonitor countingMonitor,
@@ -807,10 +876,10 @@ private ObjectWalk getObjectWalk() {
 	 * Basing on these 2 sets, another set of objects to put in a pack file is
 	 * created: this set consists of all objects reachable (ancestors) from
 	 * interesting objects, except uninteresting objects and their ancestors.
-	 * This method uses class {@link ObjectWalk} extensively to find out that
-	 * appropriate set of output objects and their optimal order in output pack.
-	 * Order is consistent with general git in-pack rules: sort by object type,
-	 * recency, path and delta-base first.
+	 * This method uses class {@link org.eclipse.jgit.revwalk.ObjectWalk}
+	 * extensively to find out that appropriate set of output objects and their
+	 * optimal order in output pack. Order is consistent with general git
+	 * in-pack rules: sort by object type, recency, path and delta-base first.
 	 * </p>
 	 *
 	 * @param countingMonitor
@@ -828,7 +897,7 @@ private ObjectWalk getObjectWalk() {
 	 * @param noBitmaps
 	 *            collection of objects to be excluded from bitmap commit
 	 *            selection.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             when some I/O problem occur during reading objects.
 	 */
 	public void preparePack(ProgressMonitor countingMonitor,
@@ -852,10 +921,10 @@ public void preparePack(ProgressMonitor countingMonitor,
 	 * @param id
 	 *            the object to test the existence of.
 	 * @return true if the object will appear in the output pack file.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             a cached pack cannot be examined.
 	 */
-	public boolean willInclude(final AnyObjectId id) throws IOException {
+	public boolean willInclude(AnyObjectId id) throws IOException {
 		ObjectToPack obj = objectsMap.get(id);
 		return obj != null && !obj.isEdge();
 	}
@@ -919,10 +988,10 @@ public int getIndexVersion() {
 	 * @param indexStream
 	 *            output for the index data. Caller is responsible for closing
 	 *            this stream.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the index data could not be written to the supplied stream.
 	 */
-	public void writeIndex(final OutputStream indexStream) throws IOException {
+	public void writeIndex(OutputStream indexStream) throws IOException {
 		if (isIndexDisabled())
 			throw new IOException(JGitText.get().cachedPacksPreventsIndexCreation);
 
@@ -941,10 +1010,10 @@ public void writeIndex(final OutputStream indexStream) throws IOException {
 	 * @param bitmapIndexStream
 	 *            output for the bitmap index data. Caller is responsible for
 	 *            closing this stream.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the index data could not be written to the supplied stream.
 	 */
-	public void writeBitmapIndex(final OutputStream bitmapIndexStream)
+	public void writeBitmapIndex(OutputStream bitmapIndexStream)
 			throws IOException {
 		if (writeBitmaps == null)
 			throw new IOException(JGitText.get().bitmapsMustBePrepared);
@@ -1026,13 +1095,13 @@ private void endPhase(ProgressMonitor monitor) {
 	 * @param packStream
 	 *            output stream of pack data. The stream should be buffered by
 	 *            the caller. The caller is responsible for closing the stream.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             an error occurred reading a local object's data to include in
 	 *             the pack, or writing compressed object data to the output
 	 *             stream.
 	 * @throws WriteAbortedException
-	 *             the write operation is aborted by {@link ObjectCountCallback}
-	 *             .
+	 *             the write operation is aborted by
+	 *             {@link org.eclipse.jgit.transport.ObjectCountCallback} .
 	 */
 	public void writePack(ProgressMonitor compressMonitor,
 			ProgressMonitor writeMonitor, OutputStream packStream)
@@ -1121,6 +1190,9 @@ public void writePack(ProgressMonitor compressMonitor,
 	}
 
 	/**
+	 * Get statistics of what this PackWriter did in order to create the final
+	 * pack stream.
+	 *
 	 * @return description of what this PackWriter did in order to create the
 	 *         final pack stream. This should only be invoked after the calls to
 	 *         create the pack/index/bitmap have completed.
@@ -1129,12 +1201,18 @@ public PackStatistics getStatistics() {
 		return new PackStatistics(stats);
 	}
 
-	/** @return snapshot of the current state of this PackWriter. */
+	/**
+	 * Get snapshot of the current state of this PackWriter.
+	 *
+	 * @return snapshot of the current state of this PackWriter.
+	 */
 	public State getState() {
 		return state.snapshot();
 	}
 
 	/**
+	 * {@inheritDoc}
+	 * <p>
 	 * Release all resources used by this writer.
 	 */
 	@Override
@@ -1448,7 +1526,7 @@ private void parallelDeltaSearch(ProgressMonitor monitor,
 			// The caller gave us an executor, but it might not do
 			// asynchronous execution.  Wrap everything and hope it
 			// can schedule these for us.
-			for (final DeltaTask task : taskBlock.tasks) {
+			for (DeltaTask task : taskBlock.tasks) {
 				executor.execute(new Runnable() {
 					@Override
 					public void run() {
@@ -1483,9 +1561,7 @@ public void run() {
 			if (err instanceof IOException)
 				throw (IOException) err;
 
-			IOException fail = new IOException(err.getMessage());
-			fail.initCause(err);
-			throw fail;
+			throw new IOException(err.getMessage(), err);
 		}
 		endPhase(monitor);
 	}
@@ -1657,7 +1733,7 @@ private void writeDeltaObjectDeflate(PackOutputStream out,
 		typeStats.deltaBytes += out.length() - otp.getOffset();
 	}
 
-	private TemporaryBuffer.Heap delta(final ObjectToPack otp)
+	private TemporaryBuffer.Heap delta(ObjectToPack otp)
 			throws IOException {
 		DeltaIndex index = new DeltaIndex(buffer(otp.getDeltaBaseId()));
 		byte[] res = buffer(otp);
@@ -1714,7 +1790,7 @@ private void findObjectsToPack(@NonNull ProgressMonitor countingMonitor,
 		if (!shallowPack && useBitmaps) {
 			BitmapIndex bitmapIndex = reader.getBitmapIndex();
 			if (bitmapIndex != null) {
-				PackWriterBitmapWalker bitmapWalker = new PackWriterBitmapWalker(
+				BitmapWalker bitmapWalker = new BitmapWalker(
 						walker, bitmapIndex, countingMonitor);
 				findObjectsToPackUsingBitmaps(bitmapWalker, want, have);
 				endPhase(countingMonitor);
@@ -1894,7 +1970,7 @@ private void findObjectsToPack(@NonNull ProgressMonitor countingMonitor,
 				byte[] pathBuf = walker.getPathBuffer();
 				int pathLen = walker.getPathLength();
 				bases.addBase(o.getType(), pathBuf, pathLen, pathHash);
-				addObject(o, pathHash);
+				filterAndAddObject(o, o.getType(), pathHash);
 				countingMonitor.update(1);
 			}
 		} else {
@@ -1904,7 +1980,7 @@ private void findObjectsToPack(@NonNull ProgressMonitor countingMonitor,
 					continue;
 				if (exclude(o))
 					continue;
-				addObject(o, walker.getPathHashCode());
+				filterAndAddObject(o, o.getType(), walker.getPathHashCode());
 				countingMonitor.update(1);
 			}
 		}
@@ -1917,7 +1993,7 @@ private void findObjectsToPack(@NonNull ProgressMonitor countingMonitor,
 	}
 
 	private void findObjectsToPackUsingBitmaps(
-			PackWriterBitmapWalker bitmapWalker, Set<? extends ObjectId> want,
+			BitmapWalker bitmapWalker, Set<? extends ObjectId> want,
 			Set<? extends ObjectId> have)
 			throws MissingObjectException, IncorrectObjectTypeException,
 			IOException {
@@ -1937,7 +2013,7 @@ private void findObjectsToPackUsingBitmaps(
 				needBitmap.remove(objectId);
 				continue;
 			}
-			addObject(objectId, obj.getType(), 0);
+			filterAndAddObject(objectId, obj.getType(), 0);
 		}
 
 		if (thin)
@@ -1971,16 +2047,16 @@ private static void pruneEdgesFromObjectList(List<ObjectToPack> list) {
 	 *
 	 * @param object
 	 *            the object to add.
-	 * @throws IncorrectObjectTypeException
+	 * @throws org.eclipse.jgit.errors.IncorrectObjectTypeException
 	 *             the object is an unsupported type.
 	 */
-	public void addObject(final RevObject object)
+	public void addObject(RevObject object)
 			throws IncorrectObjectTypeException {
 		if (!exclude(object))
 			addObject(object, 0);
 	}
 
-	private void addObject(final RevObject object, final int pathHashCode) {
+	private void addObject(RevObject object, int pathHashCode) {
 		addObject(object, object.getType(), pathHashCode);
 	}
 
@@ -1996,6 +2072,21 @@ private void addObject(
 		objectsMap.add(otp);
 	}
 
+	// Adds the given object as an object to be packed, first performing
+	// filtering on blobs at or exceeding a given size.
+	private void filterAndAddObject(@NonNull AnyObjectId src, int type,
+			int pathHashCode) throws IOException {
+
+		// Check if this object needs to be rejected, doing the cheaper
+		// checks first.
+		boolean reject = filterBlobLimit >= 0 &&
+			type == OBJ_BLOB &&
+			reader.getObjectSize(src, OBJ_BLOB) > filterBlobLimit;
+		if (!reject) {
+			addObject(src, type, pathHashCode);
+		}
+	}
+
 	private boolean exclude(AnyObjectId objectId) {
 		if (excludeInPacks == null)
 			return false;
@@ -2013,9 +2104,9 @@ private boolean exclude(AnyObjectId objectId) {
 	/**
 	 * Select an object representation for this writer.
 	 * <p>
-	 * An {@link ObjectReader} implementation should invoke this method once for
-	 * each representation available for an object, to allow the writer to find
-	 * the most suitable one for the output.
+	 * An {@link org.eclipse.jgit.lib.ObjectReader} implementation should invoke
+	 * this method once for each representation available for an object, to
+	 * allow the writer to find the most suitable one for the output.
 	 *
 	 * @param otp
 	 *            the object being packed.
@@ -2096,7 +2187,7 @@ private final boolean have(ObjectToPack ptr, AnyObjectId objectId) {
 	 * @param pm
 	 *            progress monitor to report bitmap building work.
 	 * @return whether a bitmap index may be written.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             when some I/O problem occur during reading objects.
 	 */
 	public boolean prepareBitmapIndex(ProgressMonitor pm) throws IOException {
@@ -2123,7 +2214,7 @@ public boolean prepareBitmapIndex(ProgressMonitor pm) throws IOException {
 
 		beginPhase(PackingPhase.BUILDING_BITMAPS, pm, selectedCommits.size());
 
-		PackWriterBitmapWalker walker = bitmapPreparer.newBitmapWalker();
+		BitmapWalker walker = bitmapPreparer.newBitmapWalker();
 		AnyObjectId last = null;
 		for (PackWriterBitmapPreparer.BitmapCommit cmit : selectedCommits) {
 			if (!cmit.isReuseWalker()) {
@@ -2157,290 +2248,6 @@ private boolean reuseDeltaFor(ObjectToPack otp) {
 		return true;
 	}
 
-	/**
-	 * Summary of how PackWriter created the pack.
-	 *
-	 * @deprecated Use {@link PackStatistics} instead.
-	 */
-	@Deprecated
-	public static class Statistics {
-		/** Statistics about a single class of object. */
-		public static class ObjectType {
-			// All requests are forwarded to this object.
-			private PackStatistics.ObjectType objectType;
-
-			/**
-			 * Wraps an
-			 * {@link org.eclipse.jgit.storage.pack.PackStatistics.ObjectType}
-			 * instance to maintain backwards compatibility with existing API.
-			 *
-			 * @param type
-			 *            the wrapped instance
-			 */
-			public ObjectType(PackStatistics.ObjectType type) {
-				objectType = type;
-			}
-
-			/**
-			 * @return total number of objects output. This total includes the
-			 *         value of {@link #getDeltas()}.
-			 */
-			public long getObjects() {
-				return objectType.getObjects();
-			}
-
-			/**
-			 * @return total number of deltas output. This may be lower than the
-			 *         actual number of deltas if a cached pack was reused.
-			 */
-			public long getDeltas() {
-				return objectType.getDeltas();
-			}
-
-			/**
-			 * @return number of objects whose existing representation was
-			 *         reused in the output. This count includes
-			 *         {@link #getReusedDeltas()}.
-			 */
-			public long getReusedObjects() {
-				return objectType.getReusedObjects();
-			}
-
-			/**
-			 * @return number of deltas whose existing representation was reused
-			 *         in the output, as their base object was also output or
-			 *         was assumed present for a thin pack. This may be lower
-			 *         than the actual number of reused deltas if a cached pack
-			 *         was reused.
-			 */
-			public long getReusedDeltas() {
-				return objectType.getReusedDeltas();
-			}
-
-			/**
-			 * @return total number of bytes written. This size includes the
-			 *         object headers as well as the compressed data. This size
-			 *         also includes all of {@link #getDeltaBytes()}.
-			 */
-			public long getBytes() {
-				return objectType.getBytes();
-			}
-
-			/**
-			 * @return number of delta bytes written. This size includes the
-			 *         object headers for the delta objects.
-			 */
-			public long getDeltaBytes() {
-				return objectType.getDeltaBytes();
-			}
-		}
-
-		// All requests are forwarded to this object.
-		private PackStatistics statistics;
-
-		/**
-		 * Wraps a {@link PackStatistics} object to maintain backwards
-		 * compatibility with existing API.
-		 *
-		 * @param stats
-		 *            the wrapped PackStatitics object
-		 */
-		public Statistics(PackStatistics stats) {
-			statistics = stats;
-		}
-
-		/**
-		 * @return unmodifiable collection of objects to be included in the
-		 *         pack. May be null if the pack was hand-crafted in a unit
-		 *         test.
-		 */
-		public Set<ObjectId> getInterestingObjects() {
-			return statistics.getInterestingObjects();
-		}
-
-		/**
-		 * @return unmodifiable collection of objects that should be excluded
-		 *         from the pack, as the peer that will receive the pack already
-		 *         has these objects.
-		 */
-		public Set<ObjectId> getUninterestingObjects() {
-			return statistics.getUninterestingObjects();
-		}
-
-		/**
-		 * @return unmodifiable collection of the cached packs that were reused
-		 *         in the output, if any were selected for reuse.
-		 */
-		public Collection<CachedPack> getReusedPacks() {
-			return statistics.getReusedPacks();
-		}
-
-		/**
-		 * @return number of objects in the output pack that went through the
-		 *         delta search process in order to find a potential delta base.
-		 */
-		public int getDeltaSearchNonEdgeObjects() {
-			return statistics.getDeltaSearchNonEdgeObjects();
-		}
-
-		/**
-		 * @return number of objects in the output pack that went through delta
-		 *         base search and found a suitable base. This is a subset of
-		 *         {@link #getDeltaSearchNonEdgeObjects()}.
-		 */
-		public int getDeltasFound() {
-			return statistics.getDeltasFound();
-		}
-
-		/**
-		 * @return total number of objects output. This total includes the value
-		 *         of {@link #getTotalDeltas()}.
-		 */
-		public long getTotalObjects() {
-			return statistics.getTotalObjects();
-		}
-
-		/**
-		 * @return the count of objects that needed to be discovered through an
-		 *         object walk because they were not found in bitmap indices.
-		 *         Returns -1 if no bitmap indices were found.
-		 */
-		public long getBitmapIndexMisses() {
-			return statistics.getBitmapIndexMisses();
-		}
-
-		/**
-		 * @return total number of deltas output. This may be lower than the
-		 *         actual number of deltas if a cached pack was reused.
-		 */
-		public long getTotalDeltas() {
-			return statistics.getTotalDeltas();
-		}
-
-		/**
-		 * @return number of objects whose existing representation was reused in
-		 *         the output. This count includes {@link #getReusedDeltas()}.
-		 */
-		public long getReusedObjects() {
-			return statistics.getReusedObjects();
-		}
-
-		/**
-		 * @return number of deltas whose existing representation was reused in
-		 *         the output, as their base object was also output or was
-		 *         assumed present for a thin pack. This may be lower than the
-		 *         actual number of reused deltas if a cached pack was reused.
-		 */
-		public long getReusedDeltas() {
-			return statistics.getReusedDeltas();
-		}
-
-		/**
-		 * @return total number of bytes written. This size includes the pack
-		 *         header, trailer, thin pack, and reused cached pack(s).
-		 */
-		public long getTotalBytes() {
-			return statistics.getTotalBytes();
-		}
-
-		/**
-		 * @return size of the thin pack in bytes, if a thin pack was generated.
-		 *         A thin pack is created when the client already has objects
-		 *         and some deltas are created against those objects, or if a
-		 *         cached pack is being used and some deltas will reference
-		 *         objects in the cached pack. This size does not include the
-		 *         pack header or trailer.
-		 */
-		public long getThinPackBytes() {
-			return statistics.getThinPackBytes();
-		}
-
-		/**
-		 * @param typeCode
-		 *            object type code, e.g. OBJ_COMMIT or OBJ_TREE.
-		 * @return information about this type of object in the pack.
-		 */
-		public ObjectType byObjectType(int typeCode) {
-			return new ObjectType(statistics.byObjectType(typeCode));
-		}
-
-		/** @return true if the resulting pack file was a shallow pack. */
-		public boolean isShallow() {
-			return statistics.isShallow();
-		}
-
-		/** @return depth (in commits) the pack includes if shallow. */
-		public int getDepth() {
-			return statistics.getDepth();
-		}
-
-		/**
-		 * @return time in milliseconds spent enumerating the objects that need
-		 *         to be included in the output. This time includes any restarts
-		 *         that occur when a cached pack is selected for reuse.
-		 */
-		public long getTimeCounting() {
-			return statistics.getTimeCounting();
-		}
-
-		/**
-		 * @return time in milliseconds spent matching existing representations
-		 *         against objects that will be transmitted, or that the client
-		 *         can be assumed to already have.
-		 */
-		public long getTimeSearchingForReuse() {
-			return statistics.getTimeSearchingForReuse();
-		}
-
-		/**
-		 * @return time in milliseconds spent finding the sizes of all objects
-		 *         that will enter the delta compression search window. The
-		 *         sizes need to be known to better match similar objects
-		 *         together and improve delta compression ratios.
-		 */
-		public long getTimeSearchingForSizes() {
-			return statistics.getTimeSearchingForSizes();
-		}
-
-		/**
-		 * @return time in milliseconds spent on delta compression. This is
-		 *         observed wall-clock time and does not accurately track CPU
-		 *         time used when multiple threads were used to perform the
-		 *         delta compression.
-		 */
-		public long getTimeCompressing() {
-			return statistics.getTimeCompressing();
-		}
-
-		/**
-		 * @return time in milliseconds spent writing the pack output, from
-		 *         start of header until end of trailer. The transfer speed can
-		 *         be approximated by dividing {@link #getTotalBytes()} by this
-		 *         value.
-		 */
-		public long getTimeWriting() {
-			return statistics.getTimeWriting();
-		}
-
-		/** @return total time spent processing this pack. */
-		public long getTimeTotal() {
-			return statistics.getTimeTotal();
-		}
-
-		/**
-		 * @return get the average output speed in terms of bytes-per-second.
-		 *         {@code getTotalBytes() / (getTimeWriting() / 1000.0)}.
-		 */
-		public double getTransferRate() {
-			return statistics.getTransferRate();
-		}
-
-		/** @return formatted message string for display to clients. */
-		public String getMessage() {
-			return statistics.getMessage();
-		}
-	}
-
 	private class MutableState {
 		/** Estimated size of a single ObjectToPack instance. */
 		// Assume 64-bit pointers, since this is just an estimate.
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackWriterBitmapPreparer.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackWriterBitmapPreparer.java
index 8bedddb..38d3458 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackWriterBitmapPreparer.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackWriterBitmapPreparer.java
@@ -59,18 +59,19 @@
 import org.eclipse.jgit.errors.IncorrectObjectTypeException;
 import org.eclipse.jgit.errors.MissingObjectException;
 import org.eclipse.jgit.internal.JGitText;
+import org.eclipse.jgit.internal.revwalk.AddUnseenToBitmapFilter;
 import org.eclipse.jgit.internal.storage.file.BitmapIndexImpl;
 import org.eclipse.jgit.internal.storage.file.BitmapIndexImpl.CompressedBitmap;
 import org.eclipse.jgit.internal.storage.file.PackBitmapIndex;
 import org.eclipse.jgit.internal.storage.file.PackBitmapIndexBuilder;
 import org.eclipse.jgit.internal.storage.file.PackBitmapIndexRemapper;
-import org.eclipse.jgit.internal.storage.pack.PackWriterBitmapWalker.AddUnseenToBitmapFilter;
 import org.eclipse.jgit.lib.AnyObjectId;
 import org.eclipse.jgit.lib.BitmapIndex.BitmapBuilder;
 import org.eclipse.jgit.lib.Constants;
 import org.eclipse.jgit.lib.ObjectId;
 import org.eclipse.jgit.lib.ObjectReader;
 import org.eclipse.jgit.lib.ProgressMonitor;
+import org.eclipse.jgit.revwalk.BitmapWalker;
 import org.eclipse.jgit.revwalk.ObjectWalk;
 import org.eclipse.jgit.revwalk.RevCommit;
 import org.eclipse.jgit.revwalk.RevObject;
@@ -508,8 +509,8 @@ int nextSpan(int distanceFromTip) {
 		return Math.max(next, recentCommitSpan);
 	}
 
-	PackWriterBitmapWalker newBitmapWalker() {
-		return new PackWriterBitmapWalker(
+	BitmapWalker newBitmapWalker() {
+		return new BitmapWalker(
 				new ObjectWalk(reader), bitmapIndex, null);
 	}
 
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/StoredObjectRepresentation.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/StoredObjectRepresentation.java
index c48b1bb..2377820 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/StoredObjectRepresentation.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/StoredObjectRepresentation.java
@@ -46,7 +46,9 @@
 import org.eclipse.jgit.lib.ObjectId;
 
 /**
- * An object representation {@link PackWriter} can consider for packing.
+ * An object representation
+ * {@link org.eclipse.jgit.internal.storage.pack.PackWriter} can consider for
+ * packing.
  */
 public class StoredObjectRepresentation {
 	/** Special unknown value for {@link #getWeight()}. */
@@ -62,6 +64,8 @@ public class StoredObjectRepresentation {
 	public static final int FORMAT_OTHER = 2;
 
 	/**
+	 * Get relative size of this object's packed form.
+	 *
 	 * @return relative size of this object's packed form. The special value
 	 *         {@link #WEIGHT_UNKNOWN} can be returned to indicate the
 	 *         implementation doesn't know, or cannot supply the weight up
@@ -72,6 +76,8 @@ public int getWeight() {
 	}
 
 	/**
+	 * Get the storage format type
+	 *
 	 * @return the storage format type, which must be one of
 	 *         {@link #PACK_DELTA}, {@link #PACK_WHOLE}, or
 	 *         {@link #FORMAT_OTHER}.
@@ -81,6 +87,9 @@ public int getFormat() {
 	}
 
 	/**
+	 * Get identity of the object this delta applies to in order to recover the
+	 * original object content.
+	 *
 	 * @return identity of the object this delta applies to in order to recover
 	 *         the original object content. This method should only be called if
 	 *         {@link #getFormat()} returned {@link #PACK_DELTA}.
@@ -90,6 +99,9 @@ public ObjectId getDeltaBase() {
 	}
 
 	/**
+	 * Whether the current representation of the object has had delta
+	 * compression attempted on it.
+	 *
 	 * @return whether the current representation of the object has had delta
 	 *         compression attempted on it.
 	 */
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/BlockReader.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/BlockReader.java
index ce2ba4a..942d72f 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/BlockReader.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/BlockReader.java
@@ -43,7 +43,7 @@
 
 package org.eclipse.jgit.internal.storage.reftable;
 
-import static java.nio.charset.StandardCharsets.UTF_8;
+import static org.eclipse.jgit.lib.Constants.CHARSET;
 import static org.eclipse.jgit.internal.storage.reftable.BlockWriter.compare;
 import static org.eclipse.jgit.internal.storage.reftable.ReftableConstants.FILE_BLOCK_TYPE;
 import static org.eclipse.jgit.internal.storage.reftable.ReftableConstants.FILE_HEADER_LEN;
@@ -138,7 +138,7 @@ String name() {
 		if (blockType == LOG_BLOCK_TYPE) {
 			len -= 9;
 		}
-		return RawParseUtils.decode(UTF_8, nameBuf, 0, len);
+		return RawParseUtils.decode(CHARSET, nameBuf, 0, len);
 	}
 
 	boolean match(byte[] match, boolean matchIsPrefix) {
@@ -171,7 +171,7 @@ long readUpdateIndexDelta() {
 	}
 
 	Ref readRef() throws IOException {
-		String name = RawParseUtils.decode(UTF_8, nameBuf, 0, nameLen);
+		String name = RawParseUtils.decode(CHARSET, nameBuf, 0, nameLen);
 		switch (valueType & VALUE_TYPE_MASK) {
 		case VALUE_NONE: // delete
 			return newRef(name);
@@ -266,7 +266,7 @@ private ObjectId readValueId() {
 	private String readValueString() {
 		int len = readVarint32();
 		int end = ptr + len;
-		String s = RawParseUtils.decode(UTF_8, buf, ptr, end);
+		String s = RawParseUtils.decode(CHARSET, buf, ptr, end);
 		ptr = end;
 		return s;
 	}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/BlockSizeTooSmallException.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/BlockSizeTooSmallException.java
index cb0f988..991306e 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/BlockSizeTooSmallException.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/BlockSizeTooSmallException.java
@@ -45,7 +45,10 @@
 
 import java.io.IOException;
 
-/** Thrown if {@link ReftableWriter} cannot fit a reference. */
+/**
+ * Thrown if {@link org.eclipse.jgit.internal.storage.reftable.ReftableWriter}
+ * cannot fit a reference.
+ */
 public class BlockSizeTooSmallException extends IOException {
 	private static final long serialVersionUID = 1L;
 
@@ -55,7 +58,11 @@ public class BlockSizeTooSmallException extends IOException {
 		minBlockSize = b;
 	}
 
-	/** @return minimum block size in bytes reftable requires to write a ref. */
+	/**
+	 * Get minimum block size in bytes reftable requires to write a ref.
+	 *
+	 * @return minimum block size in bytes reftable requires to write a ref.
+	 */
 	public int getMinimumBlockSize() {
 		return minBlockSize;
 	}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/BlockWriter.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/BlockWriter.java
index b3173e8..3d8fbf4 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/BlockWriter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/BlockWriter.java
@@ -43,7 +43,7 @@
 
 package org.eclipse.jgit.internal.storage.reftable;
 
-import static java.nio.charset.StandardCharsets.UTF_8;
+import static org.eclipse.jgit.lib.Constants.CHARSET;
 import static org.eclipse.jgit.internal.storage.reftable.ReftableConstants.FILE_HEADER_LEN;
 import static org.eclipse.jgit.internal.storage.reftable.ReftableConstants.INDEX_BLOCK_TYPE;
 import static org.eclipse.jgit.internal.storage.reftable.ReftableConstants.LOG_BLOCK_TYPE;
@@ -440,7 +440,7 @@ void writeValue(ReftableOutputStream os) throws IOException {
 		}
 
 		private static byte[] nameUtf8(Ref ref) {
-			return ref.getName().getBytes(UTF_8);
+			return ref.getName().getBytes(CHARSET);
 		}
 	}
 
@@ -559,13 +559,13 @@ static class LogEntry extends Entry {
 			this.newId = newId;
 			this.timeSecs = who.getWhen().getTime() / 1000L;
 			this.tz = (short) who.getTimeZoneOffset();
-			this.name = who.getName().getBytes(UTF_8);
-			this.email = who.getEmailAddress().getBytes(UTF_8);
-			this.msg = message.getBytes(UTF_8);
+			this.name = who.getName().getBytes(CHARSET);
+			this.email = who.getEmailAddress().getBytes(CHARSET);
+			this.msg = message.getBytes(CHARSET);
 		}
 
 		static byte[] key(String ref, long index) {
-			byte[] name = ref.getBytes(UTF_8);
+			byte[] name = ref.getBytes(CHARSET);
 			byte[] key = Arrays.copyOf(name, name.length + 1 + 8);
 			NB.encodeInt64(key, key.length - 8, reverseUpdateIndex(index));
 			return key;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/EmptyLogCursor.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/EmptyLogCursor.java
index d774589..de5baa1 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/EmptyLogCursor.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/EmptyLogCursor.java
@@ -49,26 +49,31 @@
 
 /** Empty {@link LogCursor} with no results. */
 class EmptyLogCursor extends LogCursor {
+	/** {@inheritDoc} */
 	@Override
 	public boolean next() throws IOException {
 		return false;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public String getRefName() {
 		return null;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public long getUpdateIndex() {
 		return 0;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public ReflogEntry getReflogEntry() {
 		return null;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void close() {
 		// Do nothing.
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/LogCursor.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/LogCursor.java
index c19968c..486fd28 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/LogCursor.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/LogCursor.java
@@ -47,26 +47,42 @@
 
 import org.eclipse.jgit.lib.ReflogEntry;
 
-/** Iterator over logs inside a {@link Reftable}. */
+/**
+ * Iterator over logs inside a
+ * {@link org.eclipse.jgit.internal.storage.reftable.Reftable}.
+ */
 public abstract class LogCursor implements AutoCloseable {
 	/**
 	 * Check if another log record is available.
 	 *
 	 * @return {@code true} if there is another result.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             logs cannot be read.
 	 */
 	public abstract boolean next() throws IOException;
 
-	/** @return name of the current reference. */
+	/**
+	 * Get name of the current reference.
+	 *
+	 * @return name of the current reference.
+	 */
 	public abstract String getRefName();
 
-	/** @return identifier of the transaction that created the log record. */
+	/**
+	 * Get identifier of the transaction that created the log record.
+	 *
+	 * @return identifier of the transaction that created the log record.
+	 */
 	public abstract long getUpdateIndex();
 
-	/** @return current log entry. */
+	/**
+	 * Get current log entry.
+	 *
+	 * @return current log entry.
+	 */
 	public abstract ReflogEntry getReflogEntry();
 
+	/** {@inheritDoc} */
 	@Override
 	public abstract void close();
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/MergedReftable.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/MergedReftable.java
index 9fc6ae2..ef686a3 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/MergedReftable.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/MergedReftable.java
@@ -54,8 +54,10 @@
 /**
  * Merges multiple reference tables together.
  * <p>
- * A {@link MergedReftable} merge-joins multiple {@link ReftableReader} on the
- * fly. Tables higher/later in the stack shadow lower/earlier tables, hiding
+ * A {@link org.eclipse.jgit.internal.storage.reftable.MergedReftable}
+ * merge-joins multiple
+ * {@link org.eclipse.jgit.internal.storage.reftable.ReftableReader} on the fly.
+ * Tables higher/later in the stack shadow lower/earlier tables, hiding
  * references that been updated/replaced.
  * <p>
  * By default deleted references are skipped and not returned to the caller.
@@ -89,6 +91,7 @@ public MergedReftable(List<Reftable> tableStack) {
 		}
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public RefCursor allRefs() throws IOException {
 		MergedRefCursor m = new MergedRefCursor();
@@ -98,6 +101,7 @@ public RefCursor allRefs() throws IOException {
 		return m;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public RefCursor seekRef(String name) throws IOException {
 		MergedRefCursor m = new MergedRefCursor();
@@ -107,6 +111,7 @@ public RefCursor seekRef(String name) throws IOException {
 		return m;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public RefCursor byObjectId(AnyObjectId name) throws IOException {
 		MergedRefCursor m = new MergedRefCursor();
@@ -116,6 +121,7 @@ public RefCursor byObjectId(AnyObjectId name) throws IOException {
 		return m;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public LogCursor allLogs() throws IOException {
 		MergedLogCursor m = new MergedLogCursor();
@@ -125,6 +131,7 @@ public LogCursor allLogs() throws IOException {
 		return m;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public LogCursor seekLog(String refName, long updateIdx)
 			throws IOException {
@@ -135,6 +142,7 @@ public LogCursor seekLog(String refName, long updateIdx)
 		return m;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void close() throws IOException {
 		for (Reftable t : tables) {
@@ -190,8 +198,8 @@ public boolean next() throws IOException {
 				ref = t.rc.getRef();
 				updateIndex = t.rc.getUpdateIndex();
 				boolean include = includeDeletes || !t.rc.wasDeleted();
-				skipShadowedRefs(ref.getName());
 				add(t);
+				skipShadowedRefs(ref.getName());
 				if (include) {
 					return true;
 				}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/RefCursor.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/RefCursor.java
index d8e9c60..5d4af30 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/RefCursor.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/RefCursor.java
@@ -47,29 +47,45 @@
 
 import org.eclipse.jgit.lib.Ref;
 
-/** Iterator over references inside a {@link Reftable}. */
+/**
+ * Iterator over references inside a
+ * {@link org.eclipse.jgit.internal.storage.reftable.Reftable}.
+ */
 public abstract class RefCursor implements AutoCloseable {
 	/**
 	 * Check if another reference is available.
 	 *
 	 * @return {@code true} if there is another result.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             references cannot be read.
 	 */
 	public abstract boolean next() throws IOException;
 
-	/** @return reference at the current position. */
+	/**
+	 * Get reference at the current position.
+	 *
+	 * @return reference at the current position.
+	 */
 	public abstract Ref getRef();
 
-	/** @return updateIndex that last modified the current reference, */
+	/**
+	 * Get updateIndex that last modified the current reference.
+	 *
+	 * @return updateIndex that last modified the current reference.
+	 */
 	public abstract long getUpdateIndex();
 
-	/** @return {@code true} if the current reference was deleted. */
+	/**
+	 * Whether the current reference was deleted.
+	 *
+	 * @return {@code true} if the current reference was deleted.
+	 */
 	public boolean wasDeleted() {
 		Ref r = getRef();
 		return r.getStorage() == Ref.Storage.NEW && r.getObjectId() == null;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public abstract void close();
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/Reftable.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/Reftable.java
index 1189ed3..510c1a1 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/Reftable.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/Reftable.java
@@ -55,9 +55,13 @@
 import org.eclipse.jgit.lib.Ref;
 import org.eclipse.jgit.lib.SymbolicRef;
 
-/** Abstract table of references. */
+/**
+ * Abstract table of references.
+ */
 public abstract class Reftable implements AutoCloseable {
 	/**
+	 * References to convert into a reftable
+	 *
 	 * @param refs
 	 *            references to convert into a reftable; may be empty.
 	 * @return a reader for the supplied references.
@@ -83,6 +87,8 @@ public static Reftable from(Collection<Ref> refs) {
 	protected boolean includeDeletes;
 
 	/**
+	 * Whether deleted references will be returned.
+	 *
 	 * @param deletes
 	 *            if {@code true} deleted references will be returned. If
 	 *            {@code false} (default behavior), deleted references will be
@@ -96,7 +102,7 @@ public void setIncludeDeletes(boolean deletes) {
 	 * Seek to the first reference, to iterate in order.
 	 *
 	 * @return cursor to iterate.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             if references cannot be read.
 	 */
 	public abstract RefCursor allRefs() throws IOException;
@@ -115,7 +121,7 @@ public void setIncludeDeletes(boolean deletes) {
 	 * @param refName
 	 *            reference name or subtree to find.
 	 * @return cursor to iterate; empty cursor if no references match.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             if references cannot be read.
 	 */
 	public abstract RefCursor seekRef(String refName) throws IOException;
@@ -126,7 +132,7 @@ public void setIncludeDeletes(boolean deletes) {
 	 * @param id
 	 *            object to find.
 	 * @return cursor to iterate; empty cursor if no references match.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             if references cannot be read.
 	 */
 	public abstract RefCursor byObjectId(AnyObjectId id) throws IOException;
@@ -135,7 +141,7 @@ public void setIncludeDeletes(boolean deletes) {
 	 * Seek reader to read log records.
 	 *
 	 * @return cursor to iterate; empty cursor if no logs are present.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             if logs cannot be read.
 	 */
 	public abstract LogCursor allLogs() throws IOException;
@@ -146,7 +152,7 @@ public void setIncludeDeletes(boolean deletes) {
 	 * @param refName
 	 *            exact name of the reference whose log to read.
 	 * @return cursor to iterate; empty cursor if no logs match.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             if logs cannot be read.
 	 */
 	public LogCursor seekLog(String refName) throws IOException {
@@ -162,7 +168,7 @@ public LogCursor seekLog(String refName) throws IOException {
 	 *            most recent index to return first in the log cursor. Log
 	 *            records at or before {@code updateIndex} will be returned.
 	 * @return cursor to iterate; empty cursor if no logs match.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             if logs cannot be read.
 	 */
 	public abstract LogCursor seekLog(String refName, long updateIndex)
@@ -174,7 +180,7 @@ public abstract LogCursor seekLog(String refName, long updateIndex)
 	 * @param refName
 	 *            reference name to find.
 	 * @return the reference, or {@code null} if not found.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             if references cannot be read.
 	 */
 	@Nullable
@@ -196,7 +202,7 @@ public Ref exactRef(String refName) throws IOException {
 	 *            reference name or subtree to find.
 	 * @return {@code true} if the reference exists, or at least one reference
 	 *         exists in the subtree.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             if references cannot be read.
 	 */
 	public boolean hasRef(String refName) throws IOException {
@@ -212,7 +218,7 @@ public boolean hasRef(String refName) throws IOException {
 	 *            ObjectId to find.
 	 * @return {@code true} if any reference exists directly referencing
 	 *         {@code id}, or a annotated tag that peels to {@code id}.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             if references cannot be read.
 	 */
 	public boolean hasId(AnyObjectId id) throws IOException {
@@ -227,7 +233,7 @@ public boolean hasId(AnyObjectId id) throws IOException {
 	 * @param symref
 	 *            reference to resolve.
 	 * @return resolved {@code symref}, or {@code null}.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             if references cannot be read.
 	 */
 	@Nullable
@@ -257,6 +263,7 @@ private Ref resolve(Ref ref, int depth) throws IOException {
 		return new SymbolicRef(ref.getName(), dst);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public abstract void close() throws IOException;
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/ReftableCompactor.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/ReftableCompactor.java
index c221577..ed73a9e 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/ReftableCompactor.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/ReftableCompactor.java
@@ -74,12 +74,14 @@ public class ReftableCompactor {
 	private long compactBytesLimit;
 	private long bytesToCompact;
 	private boolean includeDeletes;
-	private long minUpdateIndex;
+	private long minUpdateIndex = -1;
 	private long maxUpdateIndex;
 	private long oldestReflogTimeMillis;
 	private Stats stats;
 
 	/**
+	 * Set configuration for the reftable.
+	 *
 	 * @param cfg
 	 *            configuration for the reftable.
 	 * @return {@code this}
@@ -90,6 +92,8 @@ public ReftableCompactor setConfig(ReftableConfig cfg) {
 	}
 
 	/**
+	 * Set limit on number of bytes from source tables to compact.
+	 *
 	 * @param bytes
 	 *            limit on number of bytes from source tables to compact.
 	 * @return {@code this}
@@ -100,6 +104,9 @@ public ReftableCompactor setCompactBytesLimit(long bytes) {
 	}
 
 	/**
+	 * Whether to include deletions in the output, which may be necessary for
+	 * partial compaction.
+	 *
 	 * @param deletes
 	 *            {@code true} to include deletions in the output, which may be
 	 *            necessary for partial compaction.
@@ -111,6 +118,9 @@ public ReftableCompactor setIncludeDeletes(boolean deletes) {
 	}
 
 	/**
+	 * Set the minimum update index for log entries that appear in the compacted
+	 * reftable.
+	 *
 	 * @param min
 	 *            the minimum update index for log entries that appear in the
 	 *            compacted reftable. This should be 1 higher than the prior
@@ -124,6 +134,9 @@ public ReftableCompactor setMinUpdateIndex(long min) {
 	}
 
 	/**
+	 * Set the maximum update index for log entries that appear in the compacted
+	 * reftable.
+	 *
 	 * @param max
 	 *            the maximum update index for log entries that appear in the
 	 *            compacted reftable. This should be at least 1 higher than the
@@ -137,6 +150,8 @@ public ReftableCompactor setMaxUpdateIndex(long max) {
 	}
 
 	/**
+	 * Set oldest reflog time to preserve.
+	 *
 	 * @param timeMillis
 	 *            oldest log time to preserve. Entries whose timestamps are
 	 *            {@code >= timeMillis} will be copied into the output file. Log
@@ -159,7 +174,7 @@ public ReftableCompactor setOldestReflogTimeMillis(long timeMillis) {
 	 *            tables to compact. Tables should be ordered oldest first/most
 	 *            recent last so that the more recent tables can shadow the
 	 *            older results. Caller is responsible for closing the readers.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             update indexes of a reader cannot be accessed.
 	 */
 	public void addAll(List<? extends Reftable> readers) throws IOException {
@@ -184,7 +199,7 @@ public void addAll(List<? extends Reftable> readers) throws IOException {
 	 *            responsible for closing the reader.
 	 * @return {@code true} if the compactor accepted this table; {@code false}
 	 *         if the compactor has reached its limit.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             if size of {@code reader}, or its update indexes cannot be read.
 	 */
 	public boolean tryAddFirst(ReftableReader reader) throws IOException {
@@ -199,7 +214,7 @@ public boolean tryAddFirst(ReftableReader reader) throws IOException {
 	}
 
 	private void adjustUpdateIndexes(ReftableReader reader) throws IOException {
-		if (minUpdateIndex == 0) {
+		if (minUpdateIndex == -1) {
 			minUpdateIndex = reader.minUpdateIndex();
 		} else {
 			minUpdateIndex = Math.min(minUpdateIndex, reader.minUpdateIndex());
@@ -213,14 +228,14 @@ private void adjustUpdateIndexes(ReftableReader reader) throws IOException {
 	 * @param out
 	 *            stream to write the compacted tables to. Caller is responsible
 	 *            for closing {@code out}.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             if tables cannot be read, or cannot be written.
 	 */
 	public void compact(OutputStream out) throws IOException {
 		MergedReftable mr = new MergedReftable(new ArrayList<>(tables));
 		mr.setIncludeDeletes(includeDeletes);
 
-		writer.setMinUpdateIndex(minUpdateIndex);
+		writer.setMinUpdateIndex(Math.max(minUpdateIndex, 0));
 		writer.setMaxUpdateIndex(maxUpdateIndex);
 		writer.begin(out);
 		mergeRefs(mr);
@@ -229,7 +244,11 @@ public void compact(OutputStream out) throws IOException {
 		stats = writer.getStats();
 	}
 
-	/** @return statistics of the last written reftable. */
+	/**
+	 * Get statistics of the last written reftable.
+	 *
+	 * @return statistics of the last written reftable.
+	 */
 	public Stats getStats() {
 		return stats;
 	}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/ReftableConfig.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/ReftableConfig.java
index f7a1fbe..66c113d 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/ReftableConfig.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/ReftableConfig.java
@@ -48,7 +48,9 @@
 import org.eclipse.jgit.lib.Config;
 import org.eclipse.jgit.lib.Repository;
 
-/** Configuration used by a reftable writer when constructing the stream. */
+/**
+ * Configuration used by a reftable writer when constructing the stream.
+ */
 public class ReftableConfig {
 	private int refBlockSize = 4 << 10;
 	private int logBlockSize;
@@ -57,7 +59,9 @@ public class ReftableConfig {
 	private boolean alignBlocks = true;
 	private boolean indexObjects = true;
 
-	/** Create a default configuration. */
+	/**
+	 * Create a default configuration.
+	 */
 	public ReftableConfig() {
 	}
 
@@ -74,7 +78,8 @@ public ReftableConfig(Repository db) {
 	}
 
 	/**
-	 * Create a configuration honoring settings in a {@link Config}.
+	 * Create a configuration honoring settings in a
+	 * {@link org.eclipse.jgit.lib.Config}.
 	 *
 	 * @param cfg
 	 *            the source to read settings from. The source is not retained
@@ -100,12 +105,18 @@ public ReftableConfig(ReftableConfig cfg) {
 		this.indexObjects = cfg.indexObjects;
 	}
 
-	/** @return desired output block size for references, in bytes */
+	/**
+	 * Get desired output block size for references, in bytes.
+	 *
+	 * @return desired output block size for references, in bytes.
+	 */
 	public int getRefBlockSize() {
 		return refBlockSize;
 	}
 
 	/**
+	 * Set desired output block size for references, in bytes.
+	 *
 	 * @param szBytes
 	 *            desired output block size for references, in bytes.
 	 */
@@ -117,6 +128,8 @@ public void setRefBlockSize(int szBytes) {
 	}
 
 	/**
+	 * Get desired output block size for log entries, in bytes.
+	 *
 	 * @return desired output block size for log entries, in bytes. If 0 the
 	 *         writer will default to {@code 2 * getRefBlockSize()}.
 	 */
@@ -125,6 +138,8 @@ public int getLogBlockSize() {
 	}
 
 	/**
+	 * Set desired output block size for log entries, in bytes.
+	 *
 	 * @param szBytes
 	 *            desired output block size for log entries, in bytes. If 0 will
 	 *            default to {@code 2 * getRefBlockSize()}.
@@ -136,12 +151,18 @@ public void setLogBlockSize(int szBytes) {
 		logBlockSize = Math.max(0, szBytes);
 	}
 
-	/** @return number of references between binary search markers. */
+	/**
+	 * Get number of references between binary search markers.
+	 *
+	 * @return number of references between binary search markers.
+	 */
 	public int getRestartInterval() {
 		return restartInterval;
 	}
 
 	/**
+	 * <p>Setter for the field <code>restartInterval</code>.</p>
+	 *
 	 * @param interval
 	 *            number of references between binary search markers. If
 	 *            {@code interval} is 0 (default), the writer will select a
@@ -151,12 +172,18 @@ public void setRestartInterval(int interval) {
 		restartInterval = Math.max(0, interval);
 	}
 
-	/** @return maximum depth of the index; 0 for unlimited. */
+	/**
+	 * Get maximum depth of the index; 0 for unlimited.
+	 *
+	 * @return maximum depth of the index; 0 for unlimited.
+	 */
 	public int getMaxIndexLevels() {
 		return maxIndexLevels;
 	}
 
 	/**
+	 * Set maximum number of levels to use in indexes.
+	 *
 	 * @param levels
 	 *            maximum number of levels to use in indexes. Lower levels of
 	 *            the index respect {@link #getRefBlockSize()}, and the highest
@@ -166,12 +193,19 @@ public void setMaxIndexLevels(int levels) {
 		maxIndexLevels = Math.max(0, levels);
 	}
 
-	/** @return {@code true} if the writer should align blocks. */
+	/**
+	 * Whether the writer should align blocks.
+	 *
+	 * @return {@code true} if the writer should align blocks.
+	 */
 	public boolean isAlignBlocks() {
 		return alignBlocks;
 	}
 
 	/**
+	 * Whether blocks are written aligned to multiples of
+	 * {@link #getRefBlockSize()}.
+	 *
 	 * @param align
 	 *            if {@code true} blocks are written aligned to multiples of
 	 *            {@link #getRefBlockSize()}. May increase file size due to NUL
@@ -181,12 +215,19 @@ public void setAlignBlocks(boolean align) {
 		alignBlocks = align;
 	}
 
-	/** @return {@code true} if the writer should index object to ref. */
+	/**
+	 * Whether the writer should index object to ref.
+	 *
+	 * @return {@code true} if the writer should index object to ref.
+	 */
 	public boolean isIndexObjects() {
 		return indexObjects;
 	}
 
 	/**
+	 * Whether the reftable may include additional storage to efficiently map
+	 * from {@code ObjectId} to reference names.
+	 *
 	 * @param index
 	 *            if {@code true} the reftable may include additional storage to
 	 *            efficiently map from {@code ObjectId} to reference names. By
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/ReftableOutputStream.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/ReftableOutputStream.java
index a24619b..44bbb16 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/ReftableOutputStream.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/ReftableOutputStream.java
@@ -43,7 +43,7 @@
 
 package org.eclipse.jgit.internal.storage.reftable;
 
-import static java.nio.charset.StandardCharsets.UTF_8;
+import static org.eclipse.jgit.lib.Constants.CHARSET;
 import static org.eclipse.jgit.internal.storage.reftable.ReftableConstants.FILE_HEADER_LEN;
 import static org.eclipse.jgit.internal.storage.reftable.ReftableConstants.INDEX_BLOCK_TYPE;
 import static org.eclipse.jgit.internal.storage.reftable.ReftableConstants.LOG_BLOCK_TYPE;
@@ -92,12 +92,14 @@ void setBlockSize(int bs) {
 		blockSize = bs;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void write(int b) {
 		ensureBytesAvailableInBlockBuf(1);
 		blockBuf[cur++] = (byte) b;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void write(byte[] b, int off, int cnt) {
 		ensureBytesAvailableInBlockBuf(cnt);
@@ -158,7 +160,7 @@ void writeId(ObjectId id) {
 	}
 
 	void writeVarintString(String s) {
-		writeVarintString(s.getBytes(UTF_8));
+		writeVarintString(s.getBytes(CHARSET));
 	}
 
 	void writeVarintString(byte[] msg) {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/ReftableReader.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/ReftableReader.java
index 407a77c..5356952 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/ReftableReader.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/ReftableReader.java
@@ -43,7 +43,7 @@
 
 package org.eclipse.jgit.internal.storage.reftable;
 
-import static java.nio.charset.StandardCharsets.UTF_8;
+import static org.eclipse.jgit.lib.Constants.CHARSET;
 import static org.eclipse.jgit.internal.storage.reftable.BlockReader.decodeBlockLen;
 import static org.eclipse.jgit.internal.storage.reftable.ReftableConstants.FILE_BLOCK_TYPE;
 import static org.eclipse.jgit.internal.storage.reftable.ReftableConstants.FILE_FOOTER_LEN;
@@ -112,10 +112,13 @@ public ReftableReader(BlockSource src) {
 	}
 
 	/**
+	 * Get the block size in bytes chosen for this file by the writer.
+	 *
 	 * @return the block size in bytes chosen for this file by the writer. Most
-	 *         reads from the {@link BlockSource} will be aligned to the block
-	 *         size.
-	 * @throws IOException
+	 *         reads from the
+	 *         {@link org.eclipse.jgit.internal.storage.io.BlockSource} will be
+	 *         aligned to the block size.
+	 * @throws java.io.IOException
 	 *             file cannot be read.
 	 */
 	public int blockSize() throws IOException {
@@ -126,10 +129,13 @@ public int blockSize() throws IOException {
 	}
 
 	/**
+	 * Get the minimum update index for log entries that appear in this
+	 * reftable.
+	 *
 	 * @return the minimum update index for log entries that appear in this
 	 *         reftable. This should be 1 higher than the prior reftable's
 	 *         {@code maxUpdateIndex} if this table is used in a stack.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             file cannot be read.
 	 */
 	public long minUpdateIndex() throws IOException {
@@ -140,10 +146,13 @@ public long minUpdateIndex() throws IOException {
 	}
 
 	/**
+	 * Get the maximum update index for log entries that appear in this
+	 * reftable.
+	 *
 	 * @return the maximum update index for log entries that appear in this
 	 *         reftable. This should be 1 higher than the prior reftable's
 	 *         {@code maxUpdateIndex} if this table is used in a stack.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             file cannot be read.
 	 */
 	public long maxUpdateIndex() throws IOException {
@@ -153,6 +162,7 @@ public long maxUpdateIndex() throws IOException {
 		return maxUpdateIndex;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public RefCursor allRefs() throws IOException {
 		if (blockSize == -1) {
@@ -167,11 +177,12 @@ public RefCursor allRefs() throws IOException {
 		return i;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public RefCursor seekRef(String refName) throws IOException {
 		initRefIndex();
 
-		byte[] key = refName.getBytes(UTF_8);
+		byte[] key = refName.getBytes(CHARSET);
 		boolean prefix = key[key.length - 1] == '/';
 
 		RefCursorImpl i = new RefCursorImpl(refEnd, key, prefix);
@@ -179,6 +190,7 @@ public RefCursor seekRef(String refName) throws IOException {
 		return i;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public RefCursor byObjectId(AnyObjectId id) throws IOException {
 		initObjIndex();
@@ -191,6 +203,7 @@ public RefCursor byObjectId(AnyObjectId id) throws IOException {
 		return i;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public LogCursor allLogs() throws IOException {
 		initLogIndex();
@@ -203,13 +216,14 @@ public LogCursor allLogs() throws IOException {
 		return new EmptyLogCursor();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public LogCursor seekLog(String refName, long updateIndex)
 			throws IOException {
 		initLogIndex();
 		if (logPosition > 0) {
 			byte[] key = LogEntry.key(refName, updateIndex);
-			byte[] match = refName.getBytes(UTF_8);
+			byte[] match = refName.getBytes(CHARSET);
 			LogCursorImpl i = new LogCursorImpl(logEnd, match);
 			i.block = seek(LOG_BLOCK_TYPE, key, logIndex, logPosition, logEnd);
 			return i;
@@ -437,13 +451,14 @@ private int blocksIn(long pos, long end) {
 	 * Get size of the reftable, in bytes.
 	 *
 	 * @return size of the reftable, in bytes.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             size cannot be obtained.
 	 */
 	public long size() throws IOException {
 		return src.size();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void close() throws IOException {
 		src.close();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/ReftableWriter.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/ReftableWriter.java
index 0ac2445..f8b9ffd 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/ReftableWriter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/ReftableWriter.java
@@ -89,7 +89,9 @@
  * Writes a reftable formatted file.
  * <p>
  * A reftable can be written in a streaming fashion, provided the caller sorts
- * all references. A {@link ReftableWriter} is single-use, and not thread-safe.
+ * all references. A
+ * {@link org.eclipse.jgit.internal.storage.reftable.ReftableWriter} is
+ * single-use, and not thread-safe.
  */
 public class ReftableWriter {
 	private ReftableConfig config;
@@ -113,7 +115,9 @@ public class ReftableWriter {
 	private int objIdLen;
 	private Stats stats;
 
-	/** Initialize a writer with a default configuration. */
+	/**
+	 * Initialize a writer with a default configuration.
+	 */
 	public ReftableWriter() {
 		this(new ReftableConfig());
 	}
@@ -129,6 +133,8 @@ public ReftableWriter(ReftableConfig cfg) {
 	}
 
 	/**
+	 * Set configuration for the writer.
+	 *
 	 * @param cfg
 	 *            configuration for the writer.
 	 * @return {@code this}
@@ -139,6 +145,9 @@ public ReftableWriter setConfig(ReftableConfig cfg) {
 	}
 
 	/**
+	 * Set the minimum update index for log entries that appear in this
+	 * reftable.
+	 *
 	 * @param min
 	 *            the minimum update index for log entries that appear in this
 	 *            reftable. This should be 1 higher than the prior reftable's
@@ -151,6 +160,9 @@ public ReftableWriter setMinUpdateIndex(long min) {
 	}
 
 	/**
+	 * Set the maximum update index for log entries that appear in this
+	 * reftable.
+	 *
 	 * @param max
 	 *            the maximum update index for log entries that appear in this
 	 *            reftable. This should be at least 1 higher than the prior
@@ -170,7 +182,7 @@ public ReftableWriter setMaxUpdateIndex(long max) {
 	 *            stream to write the table to. Caller is responsible for
 	 *            closing the stream after invoking {@link #finish()}.
 	 * @return {@code this}
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             if reftable header cannot be written.
 	 */
 	public ReftableWriter begin(OutputStream os) throws IOException {
@@ -208,7 +220,7 @@ public ReftableWriter begin(OutputStream os) throws IOException {
 	 * @param refsToPack
 	 *            references to sort and write.
 	 * @return {@code this}
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             if reftable cannot be written.
 	 */
 	public ReftableWriter sortAndWriteRefs(Collection<Ref> refsToPack)
@@ -232,7 +244,7 @@ public ReftableWriter sortAndWriteRefs(Collection<Ref> refsToPack)
 	 *
 	 * @param ref
 	 *            the reference to store.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             if reftable cannot be written.
 	 */
 	public void writeRef(Ref ref) throws IOException {
@@ -249,7 +261,7 @@ public void writeRef(Ref ref) throws IOException {
 	 * @param updateIndex
 	 *            the updateIndex that modified this reference. Must be
 	 *            {@code >= minUpdateIndex} for this file.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             if reftable cannot be written.
 	 */
 	public void writeRef(Ref ref, long updateIndex) throws IOException {
@@ -295,12 +307,14 @@ private void indexId(ObjectId id, long blockPos) {
 	 * @param who
 	 *            committer of the reflog entry.
 	 * @param oldId
-	 *            prior id; pass {@link ObjectId#zeroId()} for creations.
+	 *            prior id; pass {@link org.eclipse.jgit.lib.ObjectId#zeroId()}
+	 *            for creations.
 	 * @param newId
-	 *            new id; pass {@link ObjectId#zeroId()} for deletions.
+	 *            new id; pass {@link org.eclipse.jgit.lib.ObjectId#zeroId()}
+	 *            for deletions.
 	 * @param message
 	 *            optional message (may be null).
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             if reftable cannot be written.
 	 */
 	public void writeLog(String ref, long updateIndex, PersonIdent who,
@@ -327,7 +341,7 @@ public void writeLog(String ref, long updateIndex, PersonIdent who,
 	 *            the ref to delete (hide) a reflog entry from.
 	 * @param updateIndex
 	 *            the update index that must be hidden.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             if reftable cannot be written.
 	 */
 	public void deleteLog(String ref, long updateIndex) throws IOException {
@@ -345,10 +359,14 @@ private void beginLog() throws IOException {
 	}
 
 	/**
+	 * Get an estimate of the current size in bytes of the reftable
+	 *
 	 * @return an estimate of the current size in bytes of the reftable, if it
 	 *         was finished right now. Estimate is only accurate if
-	 *         {@link ReftableConfig#setIndexObjects(boolean)} is {@code false}
-	 *         and {@link ReftableConfig#setMaxIndexLevels(int)} is {@code 1}.
+	 *         {@link org.eclipse.jgit.internal.storage.reftable.ReftableConfig#setIndexObjects(boolean)}
+	 *         is {@code false} and
+	 *         {@link org.eclipse.jgit.internal.storage.reftable.ReftableConfig#setMaxIndexLevels(int)}
+	 *         is {@code 1}.
 	 */
 	public long estimateTotalBytes() {
 		long bytes = out.size();
@@ -381,7 +399,7 @@ public long estimateTotalBytes() {
 	 * Finish writing the reftable by writing its trailer.
 	 *
 	 * @return {@code this}
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             if reftable cannot be written.
 	 */
 	public ReftableWriter finish() throws IOException {
@@ -480,7 +498,11 @@ private static long indexPosition(@Nullable Section s) {
 		return s != null && s.idx != null ? s.idx.rootPosition : 0;
 	}
 
-	/** @return statistics of the last written reftable. */
+	/**
+	 * Get statistics of the last written reftable.
+	 *
+	 * @return statistics of the last written reftable.
+	 */
 	public Stats getStats() {
 		return stats;
 	}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftree/AlwaysFailUpdate.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftree/AlwaysFailUpdate.java
index 12ef873..9d673e5 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftree/AlwaysFailUpdate.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftree/AlwaysFailUpdate.java
@@ -61,36 +61,43 @@ class AlwaysFailUpdate extends RefUpdate {
 		setCheckConflicting(false);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected RefDatabase getRefDatabase() {
 		return refdb;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected Repository getRepository() {
 		return refdb.getRepository();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected boolean tryLock(boolean deref) throws IOException {
 		return false;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected void unlock() {
 		// No locks are held here.
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected Result doUpdate(Result desiredResult) {
 		return Result.LOCK_FAILURE;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected Result doDelete(Result desiredResult) {
 		return Result.LOCK_FAILURE;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected Result doLink(String target) {
 		return Result.LOCK_FAILURE;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftree/Command.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftree/Command.java
index dd08375..11837fd 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftree/Command.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftree/Command.java
@@ -61,6 +61,7 @@
 import org.eclipse.jgit.lib.ObjectIdRef;
 import org.eclipse.jgit.lib.ObjectInserter;
 import org.eclipse.jgit.lib.Ref;
+import org.eclipse.jgit.lib.SymbolicRef;
 import org.eclipse.jgit.revwalk.RevObject;
 import org.eclipse.jgit.revwalk.RevTag;
 import org.eclipse.jgit.revwalk.RevWalk;
@@ -68,25 +69,31 @@
 import org.eclipse.jgit.transport.ReceiveCommand.Result;
 
 /**
- * Command to create, update or delete an entry inside a {@link RefTree}.
+ * Command to create, update or delete an entry inside a
+ * {@link org.eclipse.jgit.internal.storage.reftree.RefTree}.
  * <p>
- * Unlike {@link ReceiveCommand} (which can only update a reference to an
- * {@link ObjectId}), a RefTree Command can also create, modify or delete
- * symbolic references to a target reference.
+ * Unlike {@link org.eclipse.jgit.transport.ReceiveCommand} (which can only
+ * update a reference to an {@link org.eclipse.jgit.lib.ObjectId}), a RefTree
+ * Command can also create, modify or delete symbolic references to a target
+ * reference.
  * <p>
  * RefTree Commands may wrap a {@code ReceiveCommand} to allow callers to
  * process an existing ReceiveCommand against a RefTree.
  * <p>
- * Commands should be passed into {@link RefTree#apply(java.util.Collection)}
+ * Commands should be passed into
+ * {@link org.eclipse.jgit.internal.storage.reftree.RefTree#apply(java.util.Collection)}
  * for processing.
  */
 public class Command {
 	/**
 	 * Set unprocessed commands as failed due to transaction aborted.
 	 * <p>
-	 * If a command is still {@link Result#NOT_ATTEMPTED} it will be set to
-	 * {@link Result#REJECTED_OTHER_REASON}. If {@code why} is non-null its
-	 * contents will be used as the message for the first command status.
+	 * If a command is still
+	 * {@link org.eclipse.jgit.transport.ReceiveCommand.Result#NOT_ATTEMPTED} it
+	 * will be set to
+	 * {@link org.eclipse.jgit.transport.ReceiveCommand.Result#REJECTED_OTHER_REASON}.
+	 * If {@code why} is non-null its contents will be used as the message for
+	 * the first command status.
 	 *
 	 * @param commands
 	 *            commands to mark as failed.
@@ -146,21 +153,27 @@ public Command(@Nullable Ref oldRef, @Nullable Ref newRef) {
 	 *            walk instance to peel the {@code newId}.
 	 * @param cmd
 	 *            command received from a push client.
-	 * @throws MissingObjectException
+	 * @throws org.eclipse.jgit.errors.MissingObjectException
 	 *             {@code oldId} or {@code newId} is missing.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             {@code oldId} or {@code newId} cannot be peeled.
 	 */
 	public Command(RevWalk rw, ReceiveCommand cmd)
 			throws MissingObjectException, IOException {
-		this.oldRef = toRef(rw, cmd.getOldId(), cmd.getRefName(), false);
-		this.newRef = toRef(rw, cmd.getNewId(), cmd.getRefName(), true);
+		this.oldRef = toRef(rw, cmd.getOldId(), cmd.getOldSymref(),
+				cmd.getRefName(), false);
+		this.newRef = toRef(rw, cmd.getNewId(), cmd.getNewSymref(),
+				cmd.getRefName(), true);
 		this.cmd = cmd;
 	}
 
-	static Ref toRef(RevWalk rw, ObjectId id, String name,
-			boolean mustExist) throws MissingObjectException, IOException {
-		if (ObjectId.zeroId().equals(id)) {
+	static Ref toRef(RevWalk rw, ObjectId id, @Nullable String target,
+			String name, boolean mustExist)
+			throws MissingObjectException, IOException {
+		if (target != null) {
+			return new SymbolicRef(name,
+					new ObjectIdRef.Unpeeled(NETWORK, target, id));
+		} else if (ObjectId.zeroId().equals(id)) {
 			return null;
 		}
 
@@ -179,7 +192,11 @@ static Ref toRef(RevWalk rw, ObjectId id, String name,
 		}
 	}
 
-	/** @return name of the reference affected by this command. */
+	/**
+	 * Get name of the reference affected by this command.
+	 *
+	 * @return name of the reference affected by this command.
+	 */
 	public String getRefName() {
 		if (cmd != null) {
 			return cmd.getRefName();
@@ -215,12 +232,20 @@ public void setResult(Result result, @Nullable String why) {
 		}
 	}
 
-	/** @return result of executing this command. */
+	/**
+	 * Get result of executing this command.
+	 *
+	 * @return result of executing this command.
+	 */
 	public Result getResult() {
 		return cmd != null ? cmd.getResult() : result;
 	}
 
-	/** @return optional message explaining command failure. */
+	/**
+	 * Get optional message explaining command failure.
+	 *
+	 * @return optional message explaining command failure.
+	 */
 	@Nullable
 	public String getMessage() {
 		return cmd != null ? cmd.getMessage() : null;
@@ -246,6 +271,7 @@ public Ref getNewRef() {
 		return newRef;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public String toString() {
 		StringBuilder s = new StringBuilder();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftree/RefTree.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftree/RefTree.java
index 85690c8..5751dd6 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftree/RefTree.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftree/RefTree.java
@@ -74,7 +74,6 @@
 import org.eclipse.jgit.errors.IncorrectObjectTypeException;
 import org.eclipse.jgit.errors.MissingObjectException;
 import org.eclipse.jgit.internal.JGitText;
-import org.eclipse.jgit.lib.FileMode;
 import org.eclipse.jgit.lib.ObjectId;
 import org.eclipse.jgit.lib.ObjectIdRef;
 import org.eclipse.jgit.lib.ObjectInserter;
@@ -92,11 +91,13 @@
  * default reference {@code "refs/heads/master"} is stored at path
  * {@code "heads/master"} in a {@code RefTree}.
  * <p>
- * Normal references are stored as {@link FileMode#GITLINK} tree entries. The
- * ObjectId in the tree entry is the ObjectId the reference refers to.
+ * Normal references are stored as {@link org.eclipse.jgit.lib.FileMode#GITLINK}
+ * tree entries. The ObjectId in the tree entry is the ObjectId the reference
+ * refers to.
  * <p>
- * Symbolic references are stored as {@link FileMode#SYMLINK} entries, with the
- * blob storing the name of the target reference.
+ * Symbolic references are stored as
+ * {@link org.eclipse.jgit.lib.FileMode#SYMLINK} entries, with the blob storing
+ * the name of the target reference.
  * <p>
  * Annotated tags also store the peeled object using a {@code GITLINK} entry
  * with the suffix <code>" ^"</code> (space carrot), for example
@@ -127,13 +128,13 @@ public static RefTree newEmptyTree() {
 	 * @param tree
 	 *            the tree to read.
 	 * @return the ref tree read from the commit.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the repository cannot be accessed through the reader.
-	 * @throws CorruptObjectException
+	 * @throws org.eclipse.jgit.errors.CorruptObjectException
 	 *             a tree object is corrupt and cannot be read.
-	 * @throws IncorrectObjectTypeException
+	 * @throws org.eclipse.jgit.errors.IncorrectObjectTypeException
 	 *             a tree object wasn't actually a tree.
-	 * @throws MissingObjectException
+	 * @throws org.eclipse.jgit.errors.MissingObjectException
 	 *             a reference tree object doesn't exist.
 	 */
 	public static RefTree read(ObjectReader reader, RevTree tree)
@@ -152,9 +153,10 @@ private RefTree(DirCache dc) {
 	/**
 	 * Read one reference.
 	 * <p>
-	 * References are always returned peeled ({@link Ref#isPeeled()} is true).
-	 * If the reference points to an annotated tag, the returned reference will
-	 * be peeled and contain {@link Ref#getPeeledObjectId()}.
+	 * References are always returned peeled
+	 * ({@link org.eclipse.jgit.lib.Ref#isPeeled()} is true). If the reference
+	 * points to an annotated tag, the returned reference will be peeled and
+	 * contain {@link org.eclipse.jgit.lib.Ref#getPeeledObjectId()}.
 	 * <p>
 	 * If the reference is a symbolic reference and the chain depth is less than
 	 * {@link org.eclipse.jgit.lib.RefDatabase#MAX_SYMBOLIC_REF_DEPTH} the
@@ -166,7 +168,7 @@ private RefTree(DirCache dc) {
 	 * @param name
 	 *            name of the reference to read.
 	 * @return the reference; null if it does not exist.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             cannot read a symbolic reference target.
 	 */
 	@Nullable
@@ -277,7 +279,7 @@ private static boolean isValidRef(Command cmd) {
 		return HEAD.equals(n) || Repository.isValidRefName(n);
 	}
 
-	private void apply(DirCacheEditor ed, final Command cmd) {
+	private void apply(DirCacheEditor ed, Command cmd) {
 		String path = refPath(cmd.getRefName());
 		Ref oldRef = cmd.getOldRef();
 		final Ref newRef = cmd.getNewRef();
@@ -378,7 +380,7 @@ private static String peeledPath(String name) {
 	 *            Caller is responsible for flushing the inserter before trying
 	 *            to read the objects, or exposing them through a reference.
 	 * @return the top level tree.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             a tree could not be written.
 	 */
 	public ObjectId writeTree(ObjectInserter inserter) throws IOException {
@@ -391,7 +393,11 @@ public ObjectId writeTree(ObjectInserter inserter) throws IOException {
 		return contents.writeTree(inserter);
 	}
 
-	/** @return a deep copy of this RefTree. */
+	/**
+	 * Create a deep copy of this RefTree.
+	 *
+	 * @return a deep copy of this RefTree.
+	 */
 	public RefTree copy() {
 		RefTree r = new RefTree(DirCache.newInCore());
 		DirCacheBuilder b = r.contents.builder();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftree/RefTreeBatch.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftree/RefTreeBatch.java
index 1cccd79..da98e3f 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftree/RefTreeBatch.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftree/RefTreeBatch.java
@@ -87,6 +87,7 @@ class RefTreeBatch extends BatchRefUpdate {
 		this.refdb = refdb;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void execute(RevWalk rw, ProgressMonitor monitor)
 			throws IOException {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftree/RefTreeDatabase.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftree/RefTreeDatabase.java
index df93ce8..27daaf0 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftree/RefTreeDatabase.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftree/RefTreeDatabase.java
@@ -74,13 +74,15 @@
 import org.eclipse.jgit.util.RefMap;
 
 /**
- * Reference database backed by a {@link RefTree}.
+ * Reference database backed by a
+ * {@link org.eclipse.jgit.internal.storage.reftree.RefTree}.
  * <p>
  * The storage for RefTreeDatabase has two parts. The main part is a native Git
  * tree object stored under the {@code refs/txn} namespace. To avoid cycles,
  * references to {@code refs/txn} are not stored in that tree object, but
- * instead in a "bootstrap" layer, which is a separate {@link RefDatabase} such
- * as {@link org.eclipse.jgit.internal.storage.file.RefDirectory} using local
+ * instead in a "bootstrap" layer, which is a separate
+ * {@link org.eclipse.jgit.lib.RefDatabase} such as
+ * {@link org.eclipse.jgit.internal.storage.file.RefDirectory} using local
  * reference files inside of {@code $GIT_DIR/refs}.
  */
 public class RefTreeDatabase extends RefDatabase {
@@ -99,7 +101,8 @@ public class RefTreeDatabase extends RefDatabase {
 	 *            the repository using references in this database.
 	 * @param bootstrap
 	 *            bootstrap reference database storing the references that
-	 *            anchor the {@link RefTree}.
+	 *            anchor the
+	 *            {@link org.eclipse.jgit.internal.storage.reftree.RefTree}.
 	 */
 	public RefTreeDatabase(Repository repo, RefDatabase bootstrap) {
 		Config cfg = repo.getConfig();
@@ -121,7 +124,8 @@ public RefTreeDatabase(Repository repo, RefDatabase bootstrap) {
 	 *            the repository using references in this database.
 	 * @param bootstrap
 	 *            bootstrap reference database storing the references that
-	 *            anchor the {@link RefTree}.
+	 *            anchor the
+	 *            {@link org.eclipse.jgit.internal.storage.reftree.RefTree}.
 	 * @param txnCommitted
 	 *            name of the bootstrap reference holding the committed RefTree.
 	 */
@@ -146,6 +150,8 @@ Repository getRepository() {
 	}
 
 	/**
+	 * Get the bootstrap reference database
+	 *
 	 * @return the bootstrap reference database, which must be used to access
 	 *         {@link #getTxnCommitted()}, {@link #getTxnNamespace()}.
 	 */
@@ -153,41 +159,52 @@ public RefDatabase getBootstrap() {
 		return bootstrap;
 	}
 
-	/** @return name of bootstrap reference anchoring committed RefTree. */
+	/**
+	 * Get name of bootstrap reference anchoring committed RefTree.
+	 *
+	 * @return name of bootstrap reference anchoring committed RefTree.
+	 */
 	public String getTxnCommitted() {
 		return txnCommitted;
 	}
 
 	/**
-	 * @return namespace used by bootstrap layer, e.g. {@code refs/txn/}.
-	 *         Always ends in {@code '/'}.
+	 * Get namespace used by bootstrap layer.
+	 *
+	 * @return namespace used by bootstrap layer, e.g. {@code refs/txn/}. Always
+	 *         ends in {@code '/'}.
 	 */
 	@Nullable
 	public String getTxnNamespace() {
 		return txnNamespace;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void create() throws IOException {
 		bootstrap.create();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public boolean performsAtomicTransactions() {
 		return true;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void refresh() {
 		bootstrap.refresh();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void close() {
 		refs = null;
 		bootstrap.close();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public Ref getRef(String name) throws IOException {
 		String[] needle = new String[SEARCH_PATH.length];
@@ -197,6 +214,7 @@ public Ref getRef(String name) throws IOException {
 		return firstExactRef(needle);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public Ref exactRef(String name) throws IOException {
 		if (!repo.isBare() && name.indexOf('/') < 0 && !HEAD.equals(name)) {
@@ -235,6 +253,7 @@ private static String prefixOf(String name) {
 		return ""; //$NON-NLS-1$
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public Map<String, Ref> getRefs(String prefix) throws IOException {
 		if (!prefix.isEmpty() && prefix.charAt(prefix.length() - 1) != '/') {
@@ -258,11 +277,12 @@ private static ObjectId idOf(@Nullable Ref src) {
 				: ObjectId.zeroId();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public List<Ref> getAdditionalRefs() throws IOException {
 		Collection<Ref> txnRefs;
 		if (txnNamespace != null) {
-			txnRefs = bootstrap.getRefs(txnNamespace).values();
+			txnRefs = bootstrap.getRefsByPrefix(txnNamespace);
 		} else {
 			Ref r = bootstrap.exactRef(txnCommitted);
 			if (r != null && r.getObjectId() != null) {
@@ -279,6 +299,7 @@ public List<Ref> getAdditionalRefs() throws IOException {
 		return all;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public Ref peel(Ref ref) throws IOException {
 		Ref i = ref.getLeaf();
@@ -306,17 +327,20 @@ private static Ref recreate(Ref old, Ref leaf) {
 		return leaf;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public boolean isNameConflicting(String name) throws IOException {
 		return conflictsWithBootstrap(name)
 				|| !getConflictingNames(name).isEmpty();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public BatchRefUpdate newBatchUpdate() {
 		return new RefTreeBatch(this);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public RefUpdate newUpdate(String name, boolean detach) throws IOException {
 		if (!repo.isBare() && name.indexOf('/') < 0 && !HEAD.equals(name)) {
@@ -343,6 +367,7 @@ public RefUpdate newUpdate(String name, boolean detach) throws IOException {
 		return u;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public RefRename newRename(String fromName, String toName)
 			throws IOException {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftree/RefTreeNames.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftree/RefTreeNames.java
index c53d6de..080304d 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftree/RefTreeNames.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftree/RefTreeNames.java
@@ -45,7 +45,9 @@
 
 import org.eclipse.jgit.lib.RefDatabase;
 
-/** Magic reference name logic for RefTrees. */
+/**
+ * Magic reference name logic for RefTrees.
+ */
 public class RefTreeNames {
 	/**
 	 * Suffix used on a {@link RefTreeDatabase#getTxnNamespace()} for user data.
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftree/RefTreeRename.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftree/RefTreeRename.java
index 5fd7ecd..4faf96b 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftree/RefTreeRename.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftree/RefTreeRename.java
@@ -69,6 +69,7 @@ class RefTreeRename extends RefRename {
 		this.refdb = refdb;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected Result doRename() throws IOException {
 		try (RevWalk rw = new RevWalk(refdb.getRepository())) {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftree/RefTreeUpdate.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftree/RefTreeUpdate.java
index 8829c11..dda2be4 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftree/RefTreeUpdate.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftree/RefTreeUpdate.java
@@ -76,16 +76,19 @@ class RefTreeUpdate extends RefUpdate {
 		setCheckConflicting(false); // Done automatically by doUpdate.
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected RefDatabase getRefDatabase() {
 		return refdb;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected Repository getRepository() {
 		return refdb.getRepository();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected boolean tryLock(boolean deref) throws IOException {
 		rw = new RevWalk(getRepository());
@@ -100,6 +103,7 @@ protected boolean tryLock(boolean deref) throws IOException {
 		return true;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected void unlock() {
 		batch = null;
@@ -109,6 +113,7 @@ protected void unlock() {
 		}
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected Result doUpdate(Result desiredResult) throws IOException {
 		return run(newRef(getName(), getNewObjectId()), desiredResult);
@@ -124,11 +129,13 @@ private Ref newRef(String name, ObjectId id)
 		return new ObjectIdRef.PeeledNonTag(LOOSE, name, id);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected Result doDelete(Result desiredResult) throws IOException {
 		return run(null, desiredResult);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected Result doLink(String target) throws IOException {
 		Ref dst = new ObjectIdRef.Unpeeled(NEW, target, null);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/AbbreviatedObjectId.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/AbbreviatedObjectId.java
index 0567051..d105d0d 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/AbbreviatedObjectId.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/AbbreviatedObjectId.java
@@ -52,7 +52,7 @@
 import org.eclipse.jgit.util.RawParseUtils;
 
 /**
- * A prefix abbreviation of an {@link ObjectId}.
+ * A prefix abbreviation of an {@link org.eclipse.jgit.lib.ObjectId}.
  * <p>
  * Sometimes Git produces abbreviated SHA-1 strings, using sufficient leading
  * digits from the ObjectId name to still be unique within the repository the
@@ -74,7 +74,7 @@ public final class AbbreviatedObjectId implements Serializable {
 	 *            the string to test.
 	 * @return true if the string can converted into an AbbreviatedObjectId.
 	 */
-	public static final boolean isId(final String id) {
+	public static final boolean isId(String id) {
 		if (id.length() < 2 || Constants.OBJECT_ID_STRING_LENGTH < id.length())
 			return false;
 		try {
@@ -109,13 +109,14 @@ public static final AbbreviatedObjectId fromString(final byte[] buf,
 	}
 
 	/**
-	 * Convert an AbbreviatedObjectId from an {@link AnyObjectId}.
+	 * Convert an AbbreviatedObjectId from an
+	 * {@link org.eclipse.jgit.lib.AnyObjectId}.
 	 * <p>
 	 * This method copies over all bits of the Id, and is therefore complete
 	 * (see {@link #isComplete()}).
 	 *
 	 * @param id
-	 *            the {@link ObjectId} to convert from.
+	 *            the {@link org.eclipse.jgit.lib.ObjectId} to convert from.
 	 * @return the converted object id.
 	 */
 	public static final AbbreviatedObjectId fromObjectId(AnyObjectId id) {
@@ -130,7 +131,7 @@ public static final AbbreviatedObjectId fromObjectId(AnyObjectId id) {
 	 *            the string to read from. Must be &lt;= 40 characters.
 	 * @return the converted object id.
 	 */
-	public static final AbbreviatedObjectId fromString(final String str) {
+	public static final AbbreviatedObjectId fromString(String str) {
 		if (str.length() > Constants.OBJECT_ID_STRING_LENGTH)
 			throw new IllegalArgumentException(MessageFormat.format(JGitText.get().invalidId, str));
 		final byte[] b = Constants.encodeASCII(str);
@@ -164,7 +165,7 @@ private static final int hexUInt32(final byte[] bs, int p, final int end) {
 		return r << (8 - n) * 4;
 	}
 
-	static int mask(final int nibbles, final int word, final int v) {
+	static int mask(int nibbles, int word, int v) {
 		final int b = (word - 1) * 8;
 		if (b + 8 <= nibbles) {
 			// We have all of the bits required for this word.
@@ -205,17 +206,29 @@ static int mask(final int nibbles, final int word, final int v) {
 		w5 = new_5;
 	}
 
-	/** @return number of hex digits appearing in this id */
+	/**
+	 * Get number of hex digits appearing in this id.
+	 *
+	 * @return number of hex digits appearing in this id.
+	 */
 	public int length() {
 		return nibbles;
 	}
 
-	/** @return true if this ObjectId is actually a complete id. */
+	/**
+	 * Whether this ObjectId is actually a complete id.
+	 *
+	 * @return true if this ObjectId is actually a complete id.
+	 */
 	public boolean isComplete() {
 		return length() == Constants.OBJECT_ID_STRING_LENGTH;
 	}
 
-	/** @return a complete ObjectId; null if {@link #isComplete()} is false */
+	/**
+	 * A complete ObjectId; null if {@link #isComplete()} is false
+	 *
+	 * @return a complete ObjectId; null if {@link #isComplete()} is false
+	 */
 	public ObjectId toObjectId() {
 		return isComplete() ? new ObjectId(w1, w2, w3, w4, w5) : null;
 	}
@@ -231,7 +244,7 @@ public ObjectId toObjectId() {
 	 *         &gt;0 if this abbreviation names an object that is after
 	 *         <code>other</code>.
 	 */
-	public final int prefixCompare(final AnyObjectId other) {
+	public final int prefixCompare(AnyObjectId other) {
 		int cmp;
 
 		cmp = NB.compareUInt32(w1, mask(1, other.w1));
@@ -267,7 +280,7 @@ public final int prefixCompare(final AnyObjectId other) {
 	 *         &gt;0 if this abbreviation names an object that is after
 	 *         <code>other</code>.
 	 */
-	public final int prefixCompare(final byte[] bs, final int p) {
+	public final int prefixCompare(byte[] bs, int p) {
 		int cmp;
 
 		cmp = NB.compareUInt32(w1, mask(1, NB.decodeInt32(bs, p)));
@@ -303,7 +316,7 @@ public final int prefixCompare(final byte[] bs, final int p) {
 	 *         &gt;0 if this abbreviation names an object that is after
 	 *         <code>other</code>.
 	 */
-	public final int prefixCompare(final int[] bs, final int p) {
+	public final int prefixCompare(int[] bs, int p) {
 		int cmp;
 
 		cmp = NB.compareUInt32(w1, mask(1, bs[p]));
@@ -325,22 +338,28 @@ public final int prefixCompare(final int[] bs, final int p) {
 		return NB.compareUInt32(w5, mask(5, bs[p + 4]));
 	}
 
-	/** @return value for a fan-out style map, only valid of length &gt;= 2. */
+	/**
+	 * Get value for a fan-out style map, only valid of length &gt;= 2.
+	 *
+	 * @return value for a fan-out style map, only valid of length &gt;= 2.
+	 */
 	public final int getFirstByte() {
 		return w1 >>> 24;
 	}
 
-	private int mask(final int word, final int v) {
+	private int mask(int word, int v) {
 		return mask(nibbles, word, v);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public int hashCode() {
 		return w1;
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	public boolean equals(final Object o) {
+	public boolean equals(Object o) {
 		if (o instanceof AbbreviatedObjectId) {
 			final AbbreviatedObjectId b = (AbbreviatedObjectId) o;
 			return nibbles == b.nibbles && w1 == b.w1 && w2 == b.w2
@@ -350,6 +369,8 @@ public boolean equals(final Object o) {
 	}
 
 	/**
+	 * Get string form of the abbreviation, in lower case hexadecimal.
+	 *
 	 * @return string form of the abbreviation, in lower case hexadecimal.
 	 */
 	public final String name() {
@@ -375,6 +396,7 @@ public final String name() {
 		return new String(b, 0, nibbles);
 	}
 
+	/** {@inheritDoc} */
 	@SuppressWarnings("nls")
 	@Override
 	public String toString() {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/AnyObjectId.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/AnyObjectId.java
index f964bf2..978dd3a 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/AnyObjectId.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/AnyObjectId.java
@@ -53,9 +53,9 @@
 /**
  * A (possibly mutable) SHA-1 abstraction.
  * <p>
- * If this is an instance of {@link MutableObjectId} the concept of equality
- * with this instance can alter at any time, if this instance is modified to
- * represent a different object name.
+ * If this is an instance of {@link org.eclipse.jgit.lib.MutableObjectId} the
+ * concept of equality with this instance can alter at any time, if this
+ * instance is modified to represent a different object name.
  */
 public abstract class AnyObjectId implements Comparable<AnyObjectId> {
 
@@ -73,17 +73,19 @@ public static boolean equals(final AnyObjectId firstObjectId,
 		if (firstObjectId == secondObjectId)
 			return true;
 
-		// We test word 2 first as odds are someone already used our
-		// word 1 as a hash code, and applying that came up with these
-		// two instances we are comparing for equality. Therefore the
-		// first two words are very likely to be identical. We want to
-		// break away from collisions as quickly as possible.
+		// We test word 3 first since the git file-based ODB
+		// uses the first byte of w1, and we use w2 as the
+		// hash code, one of those probably came up with these
+		// two instances which we are comparing for equality.
+		// Therefore the first two words are very likely to be
+		// identical. We want to break away from collisions as
+		// quickly as possible.
 		//
-		return firstObjectId.w2 == secondObjectId.w2
-				&& firstObjectId.w3 == secondObjectId.w3
+		return firstObjectId.w3 == secondObjectId.w3
 				&& firstObjectId.w4 == secondObjectId.w4
 				&& firstObjectId.w5 == secondObjectId.w5
-				&& firstObjectId.w1 == secondObjectId.w1;
+				&& firstObjectId.w1 == secondObjectId.w1
+				&& firstObjectId.w2 == secondObjectId.w2;
 	}
 
 	int w1;
@@ -117,14 +119,16 @@ public final int getFirstByte() {
 	 *
 	 * @param index
 	 *            index of the byte to obtain from the raw form of the ObjectId.
-	 *            Must be in range [0, {@link Constants#OBJECT_ID_LENGTH}).
+	 *            Must be in range [0,
+	 *            {@link org.eclipse.jgit.lib.Constants#OBJECT_ID_LENGTH}).
 	 * @return the value of the requested byte at {@code index}. Returned values
 	 *         are unsigned and thus are in the range [0,255] rather than the
 	 *         signed byte range of [-128, 127].
-	 * @throws ArrayIndexOutOfBoundsException
+	 * @throws java.lang.ArrayIndexOutOfBoundsException
 	 *             {@code index} is less than 0, equal to
-	 *             {@link Constants#OBJECT_ID_LENGTH}, or greater than
-	 *             {@link Constants#OBJECT_ID_LENGTH}.
+	 *             {@link org.eclipse.jgit.lib.Constants#OBJECT_ID_LENGTH}, or
+	 *             greater than
+	 *             {@link org.eclipse.jgit.lib.Constants#OBJECT_ID_LENGTH}.
 	 */
 	public final int getByte(int index) {
 		int w;
@@ -152,15 +156,12 @@ public final int getByte(int index) {
 	}
 
 	/**
+	 * {@inheritDoc}
+	 * <p>
 	 * Compare this ObjectId to another and obtain a sort ordering.
-	 *
-	 * @param other
-	 *            the other id to compare to. Must not be null.
-	 * @return &lt; 0 if this id comes before other; 0 if this id is equal to
-	 *         other; &gt; 0 if this id comes after other.
 	 */
 	@Override
-	public final int compareTo(final AnyObjectId other) {
+	public final int compareTo(AnyObjectId other) {
 		if (this == other)
 			return 0;
 
@@ -196,7 +197,7 @@ public final int compareTo(final AnyObjectId other) {
 	 * @return a negative integer, zero, or a positive integer as this object is
 	 *         less than, equal to, or greater than the specified object.
 	 */
-	public final int compareTo(final byte[] bs, final int p) {
+	public final int compareTo(byte[] bs, int p) {
 		int cmp;
 
 		cmp = NB.compareUInt32(w1, NB.decodeInt32(bs, p));
@@ -229,7 +230,7 @@ public final int compareTo(final byte[] bs, final int p) {
 	 * @return a negative integer, zero, or a positive integer as this object is
 	 *         less than, equal to, or greater than the specified object.
 	 */
-	public final int compareTo(final int[] bs, final int p) {
+	public final int compareTo(int[] bs, int p) {
 		int cmp;
 
 		cmp = NB.compareUInt32(w1, bs[p]);
@@ -258,10 +259,11 @@ public final int compareTo(final int[] bs, final int p) {
 	 *            the abbreviation.
 	 * @return true if this ObjectId begins with the abbreviation; else false.
 	 */
-	public boolean startsWith(final AbbreviatedObjectId abbr) {
+	public boolean startsWith(AbbreviatedObjectId abbr) {
 		return abbr.prefixCompare(this) == 0;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public final int hashCode() {
 		return w2;
@@ -274,12 +276,13 @@ public final int hashCode() {
 	 *            the other id to compare to. May be null.
 	 * @return true only if both ObjectIds have identical bits.
 	 */
-	public final boolean equals(final AnyObjectId other) {
+	public final boolean equals(AnyObjectId other) {
 		return other != null ? equals(this, other) : false;
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	public final boolean equals(final Object o) {
+	public final boolean equals(Object o) {
 		if (o instanceof AnyObjectId)
 			return equals((AnyObjectId) o);
 		else
@@ -292,7 +295,7 @@ public final boolean equals(final Object o) {
 	 * @param w
 	 *            the buffer to copy to. Must be in big endian order.
 	 */
-	public void copyRawTo(final ByteBuffer w) {
+	public void copyRawTo(ByteBuffer w) {
 		w.putInt(w1);
 		w.putInt(w2);
 		w.putInt(w3);
@@ -308,7 +311,7 @@ public void copyRawTo(final ByteBuffer w) {
 	 * @param o
 	 *            the offset within b to write at.
 	 */
-	public void copyRawTo(final byte[] b, final int o) {
+	public void copyRawTo(byte[] b, int o) {
 		NB.encodeInt32(b, o, w1);
 		NB.encodeInt32(b, o + 4, w2);
 		NB.encodeInt32(b, o + 8, w3);
@@ -324,7 +327,7 @@ public void copyRawTo(final byte[] b, final int o) {
 	 * @param o
 	 *            the offset within b to write at.
 	 */
-	public void copyRawTo(final int[] b, final int o) {
+	public void copyRawTo(int[] b, int o) {
 		b[o] = w1;
 		b[o + 1] = w2;
 		b[o + 2] = w3;
@@ -337,10 +340,10 @@ public void copyRawTo(final int[] b, final int o) {
 	 *
 	 * @param w
 	 *            the stream to write to.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the stream writing failed.
 	 */
-	public void copyRawTo(final OutputStream w) throws IOException {
+	public void copyRawTo(OutputStream w) throws IOException {
 		writeRawInt(w, w1);
 		writeRawInt(w, w2);
 		writeRawInt(w, w3);
@@ -348,7 +351,7 @@ public void copyRawTo(final OutputStream w) throws IOException {
 		writeRawInt(w, w5);
 	}
 
-	private static void writeRawInt(final OutputStream w, int v)
+	private static void writeRawInt(OutputStream w, int v)
 			throws IOException {
 		w.write(v >>> 24);
 		w.write(v >>> 16);
@@ -361,10 +364,10 @@ private static void writeRawInt(final OutputStream w, int v)
 	 *
 	 * @param w
 	 *            the stream to copy to.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the stream writing failed.
 	 */
-	public void copyTo(final OutputStream w) throws IOException {
+	public void copyTo(OutputStream w) throws IOException {
 		w.write(toHexByteArray());
 	}
 
@@ -407,7 +410,7 @@ public void copyTo(ByteBuffer b) {
 	private static final byte[] hexbyte = { '0', '1', '2', '3', '4', '5', '6',
 			'7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
 
-	private static void formatHexByte(final byte[] dst, final int p, int w) {
+	private static void formatHexByte(byte[] dst, int p, int w) {
 		int o = p + 7;
 		while (o >= p && w != 0) {
 			dst[o--] = hexbyte[w & 0xf];
@@ -422,10 +425,10 @@ private static void formatHexByte(final byte[] dst, final int p, int w) {
 	 *
 	 * @param w
 	 *            the stream to copy to.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the stream writing failed.
 	 */
-	public void copyTo(final Writer w) throws IOException {
+	public void copyTo(Writer w) throws IOException {
 		w.write(toHexCharArray());
 	}
 
@@ -438,10 +441,10 @@ public void copyTo(final Writer w) throws IOException {
 	 *            of object id (40 characters or larger).
 	 * @param w
 	 *            the stream to copy to.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the stream writing failed.
 	 */
-	public void copyTo(final char[] tmp, final Writer w) throws IOException {
+	public void copyTo(char[] tmp, Writer w) throws IOException {
 		toHexCharArray(tmp);
 		w.write(tmp, 0, Constants.OBJECT_ID_STRING_LENGTH);
 	}
@@ -456,7 +459,7 @@ public void copyTo(final char[] tmp, final Writer w) throws IOException {
 	 * @param w
 	 *            the string to append onto.
 	 */
-	public void copyTo(final char[] tmp, final StringBuilder w) {
+	public void copyTo(char[] tmp, StringBuilder w) {
 		toHexCharArray(tmp);
 		w.append(tmp, 0, Constants.OBJECT_ID_STRING_LENGTH);
 	}
@@ -467,7 +470,7 @@ public void copyTo(final char[] tmp, final StringBuilder w) {
 		return dst;
 	}
 
-	private void toHexCharArray(final char[] dst) {
+	private void toHexCharArray(char[] dst) {
 		formatHexChar(dst, 0, w1);
 		formatHexChar(dst, 8, w2);
 		formatHexChar(dst, 16, w3);
@@ -478,7 +481,7 @@ private void toHexCharArray(final char[] dst) {
 	private static final char[] hexchar = { '0', '1', '2', '3', '4', '5', '6',
 			'7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
 
-	static void formatHexChar(final char[] dst, final int p, int w) {
+	static void formatHexChar(char[] dst, int p, int w) {
 		int o = p + 7;
 		while (o >= p && w != 0) {
 			dst[o--] = hexchar[w & 0xf];
@@ -488,6 +491,7 @@ static void formatHexChar(final char[] dst, final int p, int w) {
 			dst[o--] = '0';
 	}
 
+	/** {@inheritDoc} */
 	@SuppressWarnings("nls")
 	@Override
 	public String toString() {
@@ -495,6 +499,8 @@ public String toString() {
 	}
 
 	/**
+	 * <p>name.</p>
+	 *
 	 * @return string form of the SHA-1, in lower case hexadecimal.
 	 */
 	public final String name() {
@@ -502,6 +508,8 @@ public final String name() {
 	}
 
 	/**
+	 * Get string form of the SHA-1, in lower case hexadecimal.
+	 *
 	 * @return string form of the SHA-1, in lower case hexadecimal.
 	 */
 	public final String getName() {
@@ -511,15 +519,17 @@ public final String getName() {
 	/**
 	 * Return an abbreviation (prefix) of this object SHA-1.
 	 * <p>
-	 * This implementation does not guarantee uniqueness. Callers should
-	 * instead use {@link ObjectReader#abbreviate(AnyObjectId, int)} to obtain a
-	 * unique abbreviation within the scope of a particular object database.
+	 * This implementation does not guarantee uniqueness. Callers should instead
+	 * use
+	 * {@link org.eclipse.jgit.lib.ObjectReader#abbreviate(AnyObjectId, int)} to
+	 * obtain a unique abbreviation within the scope of a particular object
+	 * database.
 	 *
 	 * @param len
 	 *            length of the abbreviated string.
 	 * @return SHA-1 abbreviation.
 	 */
-	public AbbreviatedObjectId abbreviate(final int len) {
+	public AbbreviatedObjectId abbreviate(int len) {
 		final int a = AbbreviatedObjectId.mask(len, 1, w1);
 		final int b = AbbreviatedObjectId.mask(len, 2, w2);
 		final int c = AbbreviatedObjectId.mask(len, 3, w3);
@@ -532,8 +542,8 @@ public AbbreviatedObjectId abbreviate(final int len) {
 	 * Obtain an immutable copy of this current object name value.
 	 * <p>
 	 * Only returns <code>this</code> if this instance is an unsubclassed
-	 * instance of {@link ObjectId}; otherwise a new instance is returned
-	 * holding the same value.
+	 * instance of {@link org.eclipse.jgit.lib.ObjectId}; otherwise a new
+	 * instance is returned holding the same value.
 	 * <p>
 	 * This method is useful to shed any additional memory that may be tied to
 	 * the subclass, yet retain the unique identity of the object id for future
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/AsyncObjectLoaderQueue.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/AsyncObjectLoaderQueue.java
index a3732ea..b4ea0e9 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/AsyncObjectLoaderQueue.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/AsyncObjectLoaderQueue.java
@@ -63,30 +63,37 @@ public interface AsyncObjectLoaderQueue<T extends ObjectId> extends
 	 * Position this queue onto the next available result.
 	 *
 	 * Even if this method returns true, {@link #open()} may still throw
-	 * {@link MissingObjectException} if the underlying object database was
-	 * concurrently modified and the current object is no longer available.
+	 * {@link org.eclipse.jgit.errors.MissingObjectException} if the underlying
+	 * object database was concurrently modified and the current object is no
+	 * longer available.
 	 *
 	 * @return true if there is a result available; false if the queue has
 	 *         finished its input iteration.
-	 * @throws MissingObjectException
+	 * @throws org.eclipse.jgit.errors.MissingObjectException
 	 *             the object does not exist. If the implementation is retaining
 	 *             the application's objects {@link #getCurrent()} will be the
 	 *             current object that is missing. There may be more results
 	 *             still available, so the caller should continue invoking next
 	 *             to examine another result.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the object store cannot be accessed.
 	 */
 	public boolean next() throws MissingObjectException, IOException;
 
 	/**
+	 * Get the current object, null if the implementation lost track.
+	 *
 	 * @return the current object, null if the implementation lost track.
 	 *         Implementations may for performance reasons discard the caller's
 	 *         ObjectId and provider their own through {@link #getObjectId()}.
 	 */
 	public T getCurrent();
 
-	/** @return the ObjectId of the current object. Never null. */
+	/**
+	 * Get the ObjectId of the current object. Never null.
+	 *
+	 * @return the ObjectId of the current object. Never null.
+	 */
 	public ObjectId getObjectId();
 
 	/**
@@ -105,7 +112,7 @@ public interface AsyncObjectLoaderQueue<T extends ObjectId> extends
 	 *             current object that is missing. There may be more results
 	 *             still available, so the caller should continue invoking next
 	 *             to examine another result.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the object store cannot be accessed.
 	 */
 	public ObjectLoader open() throws IOException;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/AsyncObjectSizeQueue.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/AsyncObjectSizeQueue.java
index c966724..03efcd2 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/AsyncObjectSizeQueue.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/AsyncObjectSizeQueue.java
@@ -64,27 +64,37 @@ public interface AsyncObjectSizeQueue<T extends ObjectId> extends
 	 *
 	 * @return true if there is a result available; false if the queue has
 	 *         finished its input iteration.
-	 * @throws MissingObjectException
+	 * @throws org.eclipse.jgit.errors.MissingObjectException
 	 *             the object does not exist. If the implementation is retaining
 	 *             the application's objects {@link #getCurrent()} will be the
 	 *             current object that is missing. There may be more results
 	 *             still available, so the caller should continue invoking next
 	 *             to examine another result.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the object store cannot be accessed.
 	 */
 	public boolean next() throws MissingObjectException, IOException;
 
 	/**
+	 * <p>getCurrent.</p>
+	 *
 	 * @return the current object, null if the implementation lost track.
 	 *         Implementations may for performance reasons discard the caller's
 	 *         ObjectId and provider their own through {@link #getObjectId()}.
 	 */
 	public T getCurrent();
 
-	/** @return the ObjectId of the current object. Never null. */
+	/**
+	 * Get the ObjectId of the current object. Never null.
+	 *
+	 * @return the ObjectId of the current object. Never null.
+	 */
 	public ObjectId getObjectId();
 
-	/** @return the size of the current object. */
+	/**
+	 * Get the size of the current object.
+	 *
+	 * @return the size of the current object.
+	 */
 	public long getSize();
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/AsyncOperation.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/AsyncOperation.java
index fb73dc1..00555b0 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/AsyncOperation.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/AsyncOperation.java
@@ -70,6 +70,8 @@ public interface AsyncOperation {
 	 */
 	public boolean cancel(boolean mayInterruptIfRunning);
 
-	/** Release resources used by the operation, including cancellation. */
+	/**
+	 * Release resources used by the operation, including cancellation.
+	 */
 	public void release();
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/BaseRepositoryBuilder.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/BaseRepositoryBuilder.java
index 825c1f7..2c7c6cb 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/BaseRepositoryBuilder.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/BaseRepositoryBuilder.java
@@ -160,7 +160,11 @@ public B setFS(FS fs) {
 		return self();
 	}
 
-	/** @return the file system abstraction, or null if not set. */
+	/**
+	 * Get the file system abstraction, or null if not set.
+	 *
+	 * @return the file system abstraction, or null if not set.
+	 */
 	public FS getFS() {
 		return fs;
 	}
@@ -182,7 +186,11 @@ public B setGitDir(File gitDir) {
 		return self();
 	}
 
-	/** @return the meta data directory; null if not set. */
+	/**
+	 * Get the meta data directory; null if not set.
+	 *
+	 * @return the meta data directory; null if not set.
+	 */
 	public File getGitDir() {
 		return gitDir;
 	}
@@ -200,7 +208,11 @@ public B setObjectDirectory(File objectDirectory) {
 		return self();
 	}
 
-	/** @return the object directory; null if not set. */
+	/**
+	 * Get the object directory; null if not set.
+	 *
+	 * @return the object directory; null if not set.
+	 */
 	public File getObjectDirectory() {
 		return objectDirectory;
 	}
@@ -262,7 +274,11 @@ public B addAlternateObjectDirectories(File[] inList) {
 		return self();
 	}
 
-	/** @return ordered array of alternate directories; null if non were set. */
+	/**
+	 * Get ordered array of alternate directories; null if non were set.
+	 *
+	 * @return ordered array of alternate directories; null if non were set.
+	 */
 	public File[] getAlternateObjectDirectories() {
 		final List<File> alts = alternateObjectDirectories;
 		if (alts == null)
@@ -285,7 +301,11 @@ public B setBare() {
 		return self();
 	}
 
-	/** @return true if this repository was forced bare by {@link #setBare()}. */
+	/**
+	 * Whether this repository was forced bare by {@link #setBare()}.
+	 *
+	 * @return true if this repository was forced bare by {@link #setBare()}.
+	 */
 	public boolean isBare() {
 		return bare;
 	}
@@ -303,7 +323,11 @@ public B setMustExist(boolean mustExist) {
 		return self();
 	}
 
-	/** @return true if the repository must exist before being opened. */
+	/**
+	 * Whether the repository must exist before being opened.
+	 *
+	 * @return true if the repository must exist before being opened.
+	 */
 	public boolean isMustExist() {
 		return mustExist;
 	}
@@ -320,7 +344,11 @@ public B setWorkTree(File workTree) {
 		return self();
 	}
 
-	/** @return the work tree directory, or null if not set. */
+	/**
+	 * Get the work tree directory, or null if not set.
+	 *
+	 * @return the work tree directory, or null if not set.
+	 */
 	public File getWorkTree() {
 		return workTree;
 	}
@@ -341,7 +369,11 @@ public B setIndexFile(File indexFile) {
 		return self();
 	}
 
-	/** @return the index file location, or null if not set. */
+	/**
+	 * Get the index file location, or null if not set.
+	 *
+	 * @return the index file location, or null if not set.
+	 */
 	public File getIndexFile() {
 		return indexFile;
 	}
@@ -544,10 +576,10 @@ public B findGitDir(File current) {
 	 * exception is thrown to the caller.
 	 *
 	 * @return {@code this}
-	 * @throws IllegalArgumentException
+	 * @throws java.lang.IllegalArgumentException
 	 *             insufficient parameters were set, or some parameters are
 	 *             incompatible with one another.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the repository could not be accessed to configure the rest of
 	 *             the builder's parameters.
 	 */
@@ -569,9 +601,9 @@ public B setup() throws IllegalArgumentException, IOException {
 	 * @return a repository matching this configuration. The caller is
 	 *         responsible to close the repository instance when it is no longer
 	 *         needed.
-	 * @throws IllegalArgumentException
+	 * @throws java.lang.IllegalArgumentException
 	 *             insufficient parameters were set.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the repository could not be accessed to configure the rest of
 	 *             the builder's parameters.
 	 */
@@ -583,7 +615,9 @@ public R build() throws IOException {
 		return repo;
 	}
 
-	/** Require either {@code gitDir} or {@code workTree} to be set. */
+	/**
+	 * Require either {@code gitDir} or {@code workTree} to be set.
+	 */
 	protected void requireGitDirOrWorkTree() {
 		if (getGitDir() == null && getWorkTree() == null)
 			throw new IllegalArgumentException(
@@ -593,7 +627,7 @@ protected void requireGitDirOrWorkTree() {
 	/**
 	 * Perform standard gitDir initialization.
 	 *
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the repository could not be accessed
 	 */
 	protected void setupGitDir() throws IOException {
@@ -615,7 +649,7 @@ protected void setupGitDir() throws IOException {
 	 * end after the repository has been identified and its configuration is
 	 * available for inspection.
 	 *
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the repository configuration could not be read.
 	 */
 	protected void setupWorkTree() throws IOException {
@@ -642,7 +676,7 @@ protected void setupWorkTree() throws IOException {
 	/**
 	 * Configure the internal implementation details of the repository.
 	 *
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the repository could not be accessed
 	 */
 	protected void setupInternals() throws IOException {
@@ -654,7 +688,7 @@ protected void setupInternals() throws IOException {
 	 * Get the cached repository configuration, loading if not yet available.
 	 *
 	 * @return the configuration of the repository.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the configuration is not available, or is badly formed.
 	 */
 	protected Config getConfig() throws IOException {
@@ -670,7 +704,7 @@ protected Config getConfig() throws IOException {
 	 * empty configuration if gitDir was not set.
 	 *
 	 * @return the repository's configuration.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the configuration is not available.
 	 */
 	protected Config loadConfig() throws IOException {
@@ -728,12 +762,20 @@ private File guessWorkTreeOrFail() throws IOException {
 		return null;
 	}
 
-	/** @return the configured FS, or {@link FS#DETECTED}. */
+	/**
+	 * Get the configured FS, or {@link FS#DETECTED}.
+	 *
+	 * @return the configured FS, or {@link FS#DETECTED}.
+	 */
 	protected FS safeFS() {
 		return getFS() != null ? getFS() : FS.DETECTED;
 	}
 
-	/** @return {@code this} */
+	/**
+	 * Get this object
+	 *
+	 * @return {@code this}
+	 */
 	@SuppressWarnings("unchecked")
 	protected final B self() {
 		return (B) this;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/BatchRefUpdate.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/BatchRefUpdate.java
index bcf9065..925b6be 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/BatchRefUpdate.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/BatchRefUpdate.java
@@ -46,6 +46,7 @@
 
 import static org.eclipse.jgit.transport.ReceiveCommand.Result.NOT_ATTEMPTED;
 import static org.eclipse.jgit.transport.ReceiveCommand.Result.REJECTED_OTHER_REASON;
+import static java.util.stream.Collectors.toCollection;
 
 import java.io.IOException;
 import java.text.MessageFormat;
@@ -135,6 +136,9 @@ protected BatchRefUpdate(RefDatabase refdb) {
 	}
 
 	/**
+	 * Whether the batch update will permit a non-fast-forward update to an
+	 * existing reference.
+	 *
 	 * @return true if the batch update will permit a non-fast-forward update to
 	 *         an existing reference.
 	 */
@@ -154,7 +158,11 @@ public BatchRefUpdate setAllowNonFastForwards(boolean allow) {
 		return this;
 	}
 
-	/** @return identity of the user making the change in the reflog. */
+	/**
+	 * Get identity of the user making the change in the reflog.
+	 *
+	 * @return identity of the user making the change in the reflog.
+	 */
 	public PersonIdent getRefLogIdent() {
 		return refLogIdent;
 	}
@@ -172,7 +180,7 @@ public PersonIdent getRefLogIdent() {
 	 *            configuration.
 	 * @return {@code this}.
 	 */
-	public BatchRefUpdate setRefLogIdent(final PersonIdent pi) {
+	public BatchRefUpdate setRefLogIdent(PersonIdent pi) {
 		refLogIdent = pi;
 		return this;
 	}
@@ -193,7 +201,8 @@ public String getRefLogMessage() {
 	 * such as fast-forward or force-update.
 	 * <p>
 	 * Describes the default for commands in this batch that do not override it
-	 * with {@link ReceiveCommand#setRefLogMessage(String, boolean)}.
+	 * with
+	 * {@link org.eclipse.jgit.transport.ReceiveCommand#setRefLogMessage(String, boolean)}.
 	 *
 	 * @return true if the message should include the result.
 	 */
@@ -204,21 +213,23 @@ public boolean isRefLogIncludingResult() {
 	/**
 	 * Set the message to include in the reflog.
 	 * <p>
-	 * Repository implementations may limit which reflogs are written by default,
-	 * based on the project configuration. If a repo is not configured to write
-	 * logs for this ref by default, setting the message alone may have no effect.
-	 * To indicate that the repo should write logs for this update in spite of
-	 * configured defaults, use {@link #setForceRefLog(boolean)}.
+	 * Repository implementations may limit which reflogs are written by
+	 * default, based on the project configuration. If a repo is not configured
+	 * to write logs for this ref by default, setting the message alone may have
+	 * no effect. To indicate that the repo should write logs for this update in
+	 * spite of configured defaults, use {@link #setForceRefLog(boolean)}.
 	 * <p>
 	 * Describes the default for commands in this batch that do not override it
-	 * with {@link ReceiveCommand#setRefLogMessage(String, boolean)}.
+	 * with
+	 * {@link org.eclipse.jgit.transport.ReceiveCommand#setRefLogMessage(String, boolean)}.
 	 *
 	 * @param msg
-	 *            the message to describe this change. If null and appendStatus is
-	 *            false, the reflog will not be updated.
+	 *            the message to describe this change. If null and appendStatus
+	 *            is false, the reflog will not be updated.
 	 * @param appendStatus
 	 *            true if the status of the ref change (fast-forward or
-	 *            forced-update) should be appended to the user supplied message.
+	 *            forced-update) should be appended to the user supplied
+	 *            message.
 	 * @return {@code this}.
 	 */
 	public BatchRefUpdate setRefLogMessage(String msg, boolean appendStatus) {
@@ -286,12 +297,15 @@ protected boolean isForceRefLog() {
 	 * {@code REJECTED_OTHER_REASON}.
 	 * <p>
 	 * This method only works if the underlying ref database supports atomic
-	 * transactions, i.e. {@link RefDatabase#performsAtomicTransactions()} returns
-	 * true. Calling this method with true if the underlying ref database does not
-	 * support atomic transactions will cause all commands to fail with {@code
+	 * transactions, i.e.
+	 * {@link org.eclipse.jgit.lib.RefDatabase#performsAtomicTransactions()}
+	 * returns true. Calling this method with true if the underlying ref
+	 * database does not support atomic transactions will cause all commands to
+	 * fail with {@code
 	 * REJECTED_OTHER_REASON}.
 	 *
-	 * @param atomic whether updates should be atomic.
+	 * @param atomic
+	 *            whether updates should be atomic.
 	 * @return {@code this}
 	 * @since 4.4
 	 */
@@ -301,6 +315,8 @@ public BatchRefUpdate setAtomic(boolean atomic) {
 	}
 
 	/**
+	 * Whether updates should be atomic.
+	 *
 	 * @return atomic whether updates should be atomic.
 	 * @since 4.4
 	 */
@@ -335,7 +351,11 @@ protected PushCertificate getPushCertificate() {
 		return pushCert;
 	}
 
-	/** @return commands this update will process. */
+	/**
+	 * Get commands this update will process.
+	 *
+	 * @return commands this update will process.
+	 */
 	public List<ReceiveCommand> getCommands() {
 		return Collections.unmodifiableList(commands);
 	}
@@ -401,6 +421,8 @@ protected void setPushOptions(List<String> options) {
 	}
 
 	/**
+	 * Get list of timestamps the batch must wait for.
+	 *
 	 * @return list of timestamps the batch must wait for.
 	 * @since 4.6
 	 */
@@ -415,6 +437,7 @@ public List<ProposedTimestamp> getProposedTimestamps() {
 	 * Request the batch to wait for the affected timestamps to resolve.
 	 *
 	 * @param ts
+	 *            a {@link org.eclipse.jgit.util.time.ProposedTimestamp} object.
 	 * @return {@code this}.
 	 * @since 4.6
 	 */
@@ -434,7 +457,7 @@ public BatchRefUpdate addProposedTimestamp(ProposedTimestamp ts) {
 	 * <p>
 	 * Implementations must respect the atomicity requirements of the underlying
 	 * database as described in {@link #setAtomic(boolean)} and
-	 * {@link RefDatabase#performsAtomicTransactions()}.
+	 * {@link org.eclipse.jgit.lib.RefDatabase#performsAtomicTransactions()}.
 	 *
 	 * @param walk
 	 *            a RevWalk to parse tags in case the storage system wants to
@@ -443,7 +466,7 @@ public BatchRefUpdate addProposedTimestamp(ProposedTimestamp ts) {
 	 *            progress monitor to receive update status on.
 	 * @param options
 	 *            a list of option strings; set null to execute without
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the database is unable to accept the update. Individual
 	 *             command status must be tested to determine if there is a
 	 *             partial failure, or a total failure.
@@ -506,8 +529,9 @@ public void execute(RevWalk walk, ProgressMonitor monitor,
 		}
 		if (!commands2.isEmpty()) {
 			// What part of the name space is already taken
-			Collection<String> takenNames = new HashSet<>(refdb.getRefs(
-					RefDatabase.ALL).keySet());
+			Collection<String> takenNames = refdb.getRefs().stream()
+					.map(Ref::getName)
+					.collect(toCollection(HashSet::new));
 			Collection<String> takenPrefixes = getTakenPrefixes(takenNames);
 
 			// Now to the update that may require more room in the name space
@@ -601,7 +625,7 @@ protected boolean blockUntilTimestamps(Duration maxWait) {
 	 *            store them pre-peeled, a common performance optimization.
 	 * @param monitor
 	 *            progress monitor to receive update status on.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the database is unable to accept the update. Individual
 	 *             command status must be tested to determine if there is a
 	 *             partial failure, or a total failure.
@@ -658,7 +682,7 @@ protected static void addPrefixesTo(String name, Collection<String> out) {
 	 * @param cmd
 	 *            specific command the update should be created to copy.
 	 * @return a single reference update command.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the reference database cannot make a new update object for
 	 *             the given reference.
 	 */
@@ -746,6 +770,7 @@ protected boolean isForceRefLog(ReceiveCommand cmd) {
 				: isForceRefLog();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public String toString() {
 		StringBuilder r = new StringBuilder();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/BatchingProgressMonitor.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/BatchingProgressMonitor.java
index a75293d..4eb7b7f 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/BatchingProgressMonitor.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/BatchingProgressMonitor.java
@@ -48,7 +48,9 @@
 
 import org.eclipse.jgit.lib.internal.WorkQueue;
 
-/** ProgressMonitor that batches update events. */
+/**
+ * ProgressMonitor that batches update events.
+ */
 public abstract class BatchingProgressMonitor implements ProgressMonitor {
 	private long delayStartTime;
 
@@ -70,11 +72,13 @@ public void setDelayStart(long time, TimeUnit unit) {
 		delayStartUnit = unit;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void start(int totalTasks) {
 		// Ignore the number of tasks.
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void beginTask(String title, int work) {
 		endTask();
@@ -83,12 +87,14 @@ public void beginTask(String title, int work) {
 			task.delay(delayStartTime, delayStartUnit);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void update(int completed) {
 		if (task != null)
 			task.update(this, completed);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void endTask() {
 		if (task != null) {
@@ -97,6 +103,7 @@ public void endTask() {
 		}
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public boolean isCancelled() {
 		return false;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/BitmapIndex.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/BitmapIndex.java
index 00f42a4..9f64f35 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/BitmapIndex.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/BitmapIndex.java
@@ -63,7 +63,11 @@ public interface BitmapIndex {
 	 */
 	Bitmap getBitmap(AnyObjectId objectId);
 
-	/** @return a new {@code BitmapBuilder} based on the values in the index. */
+	/**
+	 * Create a new {@code BitmapBuilder} based on the values in the index.
+	 *
+	 * @return a new {@code BitmapBuilder} based on the values in the index.
+	 */
 	BitmapBuilder newBitmapBuilder();
 
 	/**
@@ -117,19 +121,6 @@ public interface Bitmap extends Iterable<BitmapObject> {
 	 * return a reference to the current builder.
 	 */
 	public interface BitmapBuilder extends Bitmap {
-		/**
-		 * Adds the id and the existing bitmap for the id, if one exists, to the
-		 * bitmap.
-		 *
-		 * @param objectId
-		 *            the object ID
-		 * @param type
-		 *            the Git object type. See {@link Constants}.
-		 * @return true if the value was not contained or able to be loaded.
-		 * @deprecated use {@link #or} or {@link #addObject} instead.
-		 */
-		@Deprecated
-		boolean add(AnyObjectId objectId, int type);
 
 		/**
 		 * Whether the bitmap has the id set.
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/BitmapObject.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/BitmapObject.java
index 4e0dc2c..f2917dc 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/BitmapObject.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/BitmapObject.java
@@ -50,7 +50,7 @@
  */
 public abstract class BitmapObject {
 	/**
-	 * Get Git object type. See {@link Constants}.
+	 * Get Git object type. See {@link org.eclipse.jgit.lib.Constants}.
 	 *
 	 * @return object type
 	 */
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/BlobBasedConfig.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/BlobBasedConfig.java
index 8958ce7..e008be3 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/BlobBasedConfig.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/BlobBasedConfig.java
@@ -45,6 +45,8 @@
 
 package org.eclipse.jgit.lib;
 
+import static org.eclipse.jgit.lib.Constants.CHARSET;
+
 import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.text.MessageFormat;
@@ -73,16 +75,15 @@ public class BlobBasedConfig extends Config {
 	 *            the base configuration file
 	 * @param blob
 	 *            the byte array, should be UTF-8 encoded text.
-	 * @throws ConfigInvalidException
+	 * @throws org.eclipse.jgit.errors.ConfigInvalidException
 	 *             the byte array is not a valid configuration format.
 	 */
-	public BlobBasedConfig(Config base, final byte[] blob)
+	public BlobBasedConfig(Config base, byte[] blob)
 			throws ConfigInvalidException {
 		super(base);
 		final String decoded;
 		if (isUtf8(blob)) {
-			decoded = RawParseUtils.decode(RawParseUtils.UTF8_CHARSET,
-					blob, 3, blob.length);
+			decoded = RawParseUtils.decode(CHARSET, blob, 3, blob.length);
 		} else {
 			decoded = RawParseUtils.decode(blob);
 		}
@@ -98,9 +99,9 @@ public BlobBasedConfig(Config base, final byte[] blob)
 	 *            the repository
 	 * @param objectId
 	 *            the object identifier
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the blob cannot be read from the repository.
-	 * @throws ConfigInvalidException
+	 * @throws org.eclipse.jgit.errors.ConfigInvalidException
 	 *             the blob is not a valid configuration format.
 	 */
 	public BlobBasedConfig(Config base, Repository db, AnyObjectId objectId)
@@ -134,11 +135,11 @@ public BlobBasedConfig(Config base, Repository db, AnyObjectId objectId)
 	 *            the tree (or commit) that contains the object
 	 * @param path
 	 *            the path within the tree
-	 * @throws FileNotFoundException
+	 * @throws java.io.FileNotFoundException
 	 *             the path does not exist in the commit's tree.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the tree and/or blob cannot be accessed.
-	 * @throws ConfigInvalidException
+	 * @throws org.eclipse.jgit.errors.ConfigInvalidException
 	 *             the blob is not a valid configuration format.
 	 */
 	public BlobBasedConfig(Config base, Repository db, AnyObjectId treeish,
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/BlobObjectChecker.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/BlobObjectChecker.java
index 0fe63ae..3fa3168 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/BlobObjectChecker.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/BlobObjectChecker.java
@@ -85,7 +85,7 @@ public void endBlob(AnyObjectId id) {
 	 *
 	 * @param id
 	 *            identity of the object being checked.
-	 * @throws CorruptObjectException
+	 * @throws org.eclipse.jgit.errors.CorruptObjectException
 	 *             if any error was detected.
 	 */
 	void endBlob(AnyObjectId id) throws CorruptObjectException;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/BranchConfig.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/BranchConfig.java
index f1b7fb2..be53c4b 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/BranchConfig.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/BranchConfig.java
@@ -107,12 +107,14 @@ public boolean matchConfigValue(String s) {
 	 * @param branchName
 	 *            the short branch name of the section to read
 	 */
-	public BranchConfig(final Config config, String branchName) {
+	public BranchConfig(Config config, String branchName) {
 		this.config = config;
 		this.branchName = branchName;
 	}
 
 	/**
+	 * Get the full tracking branch name
+	 *
 	 * @return the full tracking branch name or <code>null</code> if it could
 	 *         not be determined
 	 */
@@ -129,6 +131,8 @@ public String getTrackingBranch() {
 	}
 
 	/**
+	 * Get the full remote-tracking branch name
+	 *
 	 * @return the full remote-tracking branch name or {@code null} if it could
 	 *         not be determined. If you also want local tracked branches use
 	 *         {@link #getTrackingBranch()} instead.
@@ -143,6 +147,9 @@ public String getRemoteTrackingBranch() {
 	}
 
 	/**
+	 * Whether the "remote" setting points to the local repository (with
+	 * {@value #LOCAL_REPOSITORY})
+	 *
 	 * @return {@code true} if the "remote" setting points to the local
 	 *         repository (with {@value #LOCAL_REPOSITORY}), false otherwise
 	 * @since 3.5
@@ -152,6 +159,8 @@ public boolean isRemoteLocal() {
 	}
 
 	/**
+	 * Get the remote this branch is configured to fetch from/push to
+	 *
 	 * @return the remote this branch is configured to fetch from/push to, or
 	 *         {@code null} if not defined
 	 * @since 3.5
@@ -162,6 +171,8 @@ public String getRemote() {
 	}
 
 	/**
+	 * Get the name of the upstream branch as it is called on the remote
+	 *
 	 * @return the name of the upstream branch as it is called on the remote, or
 	 *         {@code null} if not defined
 	 * @since 3.5
@@ -172,6 +183,8 @@ public String getMerge() {
 	}
 
 	/**
+	 * Whether the branch is configured to be rebased
+	 *
 	 * @return {@code true} if the branch is configured to be rebased
 	 * @since 3.5
 	 */
@@ -182,7 +195,7 @@ public boolean isRebase() {
 	/**
 	 * Retrieves the config value of branch.[name].rebase.
 	 *
-	 * @return the {@link BranchRebaseMode}
+	 * @return the {@link org.eclipse.jgit.lib.BranchConfig.BranchRebaseMode}
 	 * @since 4.5
 	 */
 	public BranchRebaseMode getRebaseMode() {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/BranchTrackingStatus.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/BranchTrackingStatus.java
index d4fccf9..51b5b80 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/BranchTrackingStatus.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/BranchTrackingStatus.java
@@ -65,7 +65,7 @@ public class BranchTrackingStatus {
 	 * @param branchName
 	 *            the local branch
 	 * @return the tracking status, or null if it is not known
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 */
 	public static BranchTrackingStatus of(Repository repository, String branchName)
 			throws IOException {
@@ -87,22 +87,25 @@ public static BranchTrackingStatus of(Repository repository, String branchName)
 		if (local == null)
 			return null;
 
-		RevWalk walk = new RevWalk(repository);
+		try (RevWalk walk = new RevWalk(repository)) {
 
-		RevCommit localCommit = walk.parseCommit(local.getObjectId());
-		RevCommit trackingCommit = walk.parseCommit(tracking.getObjectId());
+			RevCommit localCommit = walk.parseCommit(local.getObjectId());
+			RevCommit trackingCommit = walk.parseCommit(tracking.getObjectId());
 
-		walk.setRevFilter(RevFilter.MERGE_BASE);
-		walk.markStart(localCommit);
-		walk.markStart(trackingCommit);
-		RevCommit mergeBase = walk.next();
+			walk.setRevFilter(RevFilter.MERGE_BASE);
+			walk.markStart(localCommit);
+			walk.markStart(trackingCommit);
+			RevCommit mergeBase = walk.next();
 
-		walk.reset();
-		walk.setRevFilter(RevFilter.ALL);
-		int aheadCount = RevWalkUtils.count(walk, localCommit, mergeBase);
-		int behindCount = RevWalkUtils.count(walk, trackingCommit, mergeBase);
+			walk.reset();
+			walk.setRevFilter(RevFilter.ALL);
+			int aheadCount = RevWalkUtils.count(walk, localCommit, mergeBase);
+			int behindCount = RevWalkUtils.count(walk, trackingCommit,
+					mergeBase);
 
-		return new BranchTrackingStatus(trackingBranch, aheadCount, behindCount);
+			return new BranchTrackingStatus(trackingBranch, aheadCount,
+					behindCount);
+		}
 	}
 
 	private final String remoteTrackingBranch;
@@ -119,6 +122,8 @@ private BranchTrackingStatus(String remoteTrackingBranch, int aheadCount,
 	}
 
 	/**
+	 * Get full remote-tracking branch name
+	 *
 	 * @return full remote-tracking branch name
 	 */
 	public String getRemoteTrackingBranch() {
@@ -126,6 +131,9 @@ public String getRemoteTrackingBranch() {
 	}
 
 	/**
+	 * Get number of commits that the local branch is ahead of the
+	 * remote-tracking branch
+	 *
 	 * @return number of commits that the local branch is ahead of the
 	 *         remote-tracking branch
 	 */
@@ -134,6 +142,9 @@ public int getAheadCount() {
 	}
 
 	/**
+	 * Get number of commits that the local branch is behind of the
+	 * remote-tracking branch
+	 *
 	 * @return number of commits that the local branch is behind of the
 	 *         remote-tracking branch
 	 */
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/CheckoutEntry.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/CheckoutEntry.java
index 34d0b14..cfc0cc8 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/CheckoutEntry.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/CheckoutEntry.java
@@ -8,11 +8,15 @@
 public interface CheckoutEntry {
 
 	/**
+	 * Get the name of the branch before checkout
+	 *
 	 * @return the name of the branch before checkout
 	 */
 	public abstract String getFromBranch();
 
 	/**
+	 * Get the name of the branch after checkout
+	 *
 	 * @return the name of the branch after checkout
 	 */
 	public abstract String getToBranch();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/CommitBuilder.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/CommitBuilder.java
index c5c488d..59a13f6 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/CommitBuilder.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/CommitBuilder.java
@@ -88,13 +88,19 @@ public class CommitBuilder {
 
 	private Charset encoding;
 
-	/** Initialize an empty commit. */
+	/**
+	 * Initialize an empty commit.
+	 */
 	public CommitBuilder() {
 		parentIds = EMPTY_OBJECTID_LIST;
 		encoding = Constants.CHARSET;
 	}
 
-	/** @return id of the root tree listing this commit's snapshot. */
+	/**
+	 * Get id of the root tree listing this commit's snapshot.
+	 *
+	 * @return id of the root tree listing this commit's snapshot.
+	 */
 	public ObjectId getTreeId() {
 		return treeId;
 	}
@@ -109,7 +115,11 @@ public void setTreeId(AnyObjectId id) {
 		treeId = id.copy();
 	}
 
-	/** @return the author of this commit (who wrote it). */
+	/**
+	 * Get the author of this commit (who wrote it).
+	 *
+	 * @return the author of this commit (who wrote it).
+	 */
 	public PersonIdent getAuthor() {
 		return author;
 	}
@@ -124,7 +134,11 @@ public void setAuthor(PersonIdent newAuthor) {
 		author = newAuthor;
 	}
 
-	/** @return the committer and commit time for this object. */
+	/**
+	 * Get the committer and commit time for this object.
+	 *
+	 * @return the committer and commit time for this object.
+	 */
 	public PersonIdent getCommitter() {
 		return committer;
 	}
@@ -139,7 +153,11 @@ public void setCommitter(PersonIdent newCommitter) {
 		committer = newCommitter;
 	}
 
-	/** @return the ancestors of this commit. Never null. */
+	/**
+	 * Get the ancestors of this commit.
+	 *
+	 * @return the ancestors of this commit. Never null.
+	 */
 	public ObjectId[] getParentIds() {
 		return parentIds;
 	}
@@ -210,7 +228,11 @@ public void addParentId(AnyObjectId additionalParent) {
 		}
 	}
 
-	/** @return the complete commit message. */
+	/**
+	 * Get the complete commit message.
+	 *
+	 * @return the complete commit message.
+	 */
 	public String getMessage() {
 		return message;
 	}
@@ -221,7 +243,7 @@ public String getMessage() {
 	 * @param newMessage
 	 *            the commit message. Should not be null.
 	 */
-	public void setMessage(final String newMessage) {
+	public void setMessage(String newMessage) {
 		message = newMessage;
 	}
 
@@ -229,7 +251,8 @@ public void setMessage(final String newMessage) {
 	 * Set the encoding for the commit information
 	 *
 	 * @param encodingName
-	 *            the encoding name. See {@link Charset#forName(String)}.
+	 *            the encoding name. See
+	 *            {@link java.nio.charset.Charset#forName(String)}.
 	 */
 	public void setEncoding(String encodingName) {
 		encoding = Charset.forName(encodingName);
@@ -245,7 +268,11 @@ public void setEncoding(Charset enc) {
 		encoding = enc;
 	}
 
-	/** @return the encoding that should be used for the commit message text. */
+	/**
+	 * Get the encoding that should be used for the commit message text.
+	 *
+	 * @return the encoding that should be used for the commit message text.
+	 */
 	public Charset getEncoding() {
 		return encoding;
 	}
@@ -255,7 +282,7 @@ public Charset getEncoding() {
 	 *
 	 * @return this object in the canonical commit format, suitable for storage
 	 *         in a repository.
-	 * @throws UnsupportedEncodingException
+	 * @throws java.io.UnsupportedEncodingException
 	 *             the encoding specified by {@link #getEncoding()} is not
 	 *             supported by this Java runtime.
 	 */
@@ -314,7 +341,7 @@ public Charset getEncoding() {
 	 *
 	 * @return this object in the canonical commit format, suitable for storage
 	 *         in a repository.
-	 * @throws UnsupportedEncodingException
+	 * @throws java.io.UnsupportedEncodingException
 	 *             the encoding specified by {@link #getEncoding()} is not
 	 *             supported by this Java runtime.
 	 */
@@ -322,6 +349,7 @@ public Charset getEncoding() {
 		return build();
 	}
 
+	/** {@inheritDoc} */
 	@SuppressWarnings("nls")
 	@Override
 	public String toString() {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Config.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Config.java
index b0f5c2c..0e01cca 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Config.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Config.java
@@ -51,6 +51,8 @@
 
 package org.eclipse.jgit.lib;
 
+import static org.eclipse.jgit.lib.Constants.CHARSET;
+
 import java.text.MessageFormat;
 import java.util.ArrayList;
 import java.util.Collections;
@@ -60,6 +62,7 @@
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicReference;
 
+import org.eclipse.jgit.annotations.Nullable;
 import org.eclipse.jgit.errors.ConfigInvalidException;
 import org.eclipse.jgit.events.ConfigChangedEvent;
 import org.eclipse.jgit.events.ConfigChangedListener;
@@ -67,6 +70,7 @@
 import org.eclipse.jgit.events.ListenerList;
 import org.eclipse.jgit.internal.JGitText;
 import org.eclipse.jgit.transport.RefSpec;
+import org.eclipse.jgit.util.RawParseUtils;
 
 /**
  * Git style {@code .config}, {@code .gitconfig}, {@code .gitmodules} file.
@@ -106,7 +110,9 @@ public class Config {
 	 */
 	static final String MAGIC_EMPTY_VALUE = new String();
 
-	/** Create a configuration with no default fallback. */
+	/**
+	 * Create a configuration with no default fallback.
+	 */
 	public Config() {
 		this(null);
 	}
@@ -124,8 +130,8 @@ public Config(Config defaultConfig) {
 	}
 
 	/**
-	 * Globally sets a {@link TypedConfigGetter} that is subsequently used to
-	 * read typed values from all git configs.
+	 * Globally sets a {@link org.eclipse.jgit.lib.TypedConfigGetter} that is
+	 * subsequently used to read typed values from all git configs.
 	 *
 	 * @param getter
 	 *            to use; if {@code null} use the default getter.
@@ -142,65 +148,105 @@ public static void setTypedConfigGetter(TypedConfigGetter getter) {
 	 *            the value to escape
 	 * @return the escaped value
 	 */
-	private static String escapeValue(final String x) {
-		boolean inquote = false;
-		int lineStart = 0;
-		final StringBuilder r = new StringBuilder(x.length());
+	static String escapeValue(String x) {
+		if (x.isEmpty()) {
+			return ""; //$NON-NLS-1$
+		}
+
+		boolean needQuote = x.charAt(0) == ' ' || x.charAt(x.length() - 1) == ' ';
+		StringBuilder r = new StringBuilder(x.length());
 		for (int k = 0; k < x.length(); k++) {
-			final char c = x.charAt(k);
+			char c = x.charAt(k);
+			// git-config(1) lists the limited set of supported escape sequences, but
+			// the documentation is otherwise not especially normative. In particular,
+			// which ones of these produce and/or require escaping and/or quoting
+			// around them is not documented and was discovered by trial and error.
+			// In summary:
+			//
+			// * Quotes are only required if there is leading/trailing whitespace or a
+			//   comment character.
+			// * Bytes that have a supported escape sequence are escaped, except for
+			//   \b for some reason which isn't.
+			// * Needing an escape sequence is not sufficient reason to quote the
+			//   value.
 			switch (c) {
+			case '\0':
+				// Unix command line calling convention cannot pass a '\0' as an
+				// argument, so there is no equivalent way in C git to store a null byte
+				// in a config value.
+				throw new IllegalArgumentException(
+						JGitText.get().configValueContainsNullByte);
+
 			case '\n':
-				if (inquote) {
-					r.append('"');
-					inquote = false;
-				}
-				r.append("\\n\\\n"); //$NON-NLS-1$
-				lineStart = r.length();
+				r.append('\\').append('n');
 				break;
 
 			case '\t':
-				r.append("\\t"); //$NON-NLS-1$
+				r.append('\\').append('t');
 				break;
 
 			case '\b':
-				r.append("\\b"); //$NON-NLS-1$
+				// Doesn't match `git config foo.bar $'x\by'`, which doesn't escape the
+				// \x08, but since both escaped and unescaped forms are readable, we'll
+				// prefer internal consistency here.
+				r.append('\\').append('b');
 				break;
 
 			case '\\':
-				r.append("\\\\"); //$NON-NLS-1$
+				r.append('\\').append('\\');
 				break;
 
 			case '"':
-				r.append("\\\""); //$NON-NLS-1$
+				r.append('\\').append('"');
 				break;
 
-			case ';':
 			case '#':
-				if (!inquote) {
-					r.insert(lineStart, '"');
-					inquote = true;
-				}
+			case ';':
+				needQuote = true;
 				r.append(c);
 				break;
 
-			case ' ':
-				if (!inquote && r.length() > 0
-						&& r.charAt(r.length() - 1) == ' ') {
-					r.insert(lineStart, '"');
-					inquote = true;
-				}
-				r.append(' ');
-				break;
-
 			default:
 				r.append(c);
 				break;
 			}
 		}
-		if (inquote) {
-			r.append('"');
+
+		return needQuote ? '"' + r.toString() + '"' : r.toString();
+	}
+
+	static String escapeSubsection(String x) {
+		if (x.isEmpty()) {
+			return "\"\""; //$NON-NLS-1$
 		}
-		return r.toString();
+
+		StringBuilder r = new StringBuilder(x.length() + 2).append('"');
+		for (int k = 0; k < x.length(); k++) {
+			char c = x.charAt(k);
+
+			// git-config(1) lists the limited set of supported escape sequences
+			// (which is even more limited for subsection names than for values).
+			switch (c) {
+			case '\0':
+				throw new IllegalArgumentException(
+						JGitText.get().configSubsectionContainsNullByte);
+
+			case '\n':
+				throw new IllegalArgumentException(
+						JGitText.get().configSubsectionContainsNewline);
+
+			case '\\':
+			case '"':
+				r.append('\\').append(c);
+				break;
+
+			default:
+				r.append(c);
+				break;
+			}
+		}
+
+		return r.append('"').toString();
 	}
 
 	/**
@@ -312,8 +358,6 @@ public boolean getBoolean(final String section, String subsection,
 	/**
 	 * Parse an enumeration from the configuration.
 	 *
-	 * @param <T>
-	 *            type of the enumeration object.
 	 * @param section
 	 *            section the key is grouped within.
 	 * @param subsection
@@ -332,7 +376,7 @@ public <T extends Enum<?>> T getEnum(final String section,
 	}
 
 	@SuppressWarnings("unchecked")
-	private static <T> T[] allValuesOf(final T value) {
+	private static <T> T[] allValuesOf(T value) {
 		try {
 			return (T[]) value.getClass().getMethod("values").invoke(null); //$NON-NLS-1$
 		} catch (Exception err) {
@@ -346,8 +390,6 @@ public <T extends Enum<?>> T getEnum(final String section,
 	/**
 	 * Parse an enumeration from the configuration.
 	 *
-	 * @param <T>
-	 *            type of the enumeration object.
 	 * @param all
 	 *            all possible values in the enumeration which should be
 	 *            recognized. Typically {@code EnumType.values()}.
@@ -443,7 +485,8 @@ public long getTimeUnit(String section, String subsection, String name,
 	}
 
 	/**
-	 * Parse a list of {@link RefSpec}s from the configuration.
+	 * Parse a list of {@link org.eclipse.jgit.transport.RefSpec}s from the
+	 * configuration.
 	 *
 	 * @param section
 	 *            section the key is in.
@@ -451,7 +494,8 @@ public long getTimeUnit(String section, String subsection, String name,
 	 *            subsection the key is in, or null if not in a subsection.
 	 * @param name
 	 *            the key name.
-	 * @return a possibly empty list of {@link RefSpec}s
+	 * @return a possibly empty list of
+	 *         {@link org.eclipse.jgit.transport.RefSpec}s
 	 * @since 4.9
 	 */
 	public List<RefSpec> getRefSpecs(String section, String subsection,
@@ -460,6 +504,9 @@ public List<RefSpec> getRefSpecs(String section, String subsection,
 	}
 
 	/**
+	 * Get set of all subsections of specified section within this configuration
+	 * and its base configuration
+	 *
 	 * @param section
 	 *            section to search for.
 	 * @return set of all subsections of specified section within this
@@ -468,21 +515,25 @@ public List<RefSpec> getRefSpecs(String section, String subsection,
 	 *         order they are declared by the configuration starting from this
 	 *         instance and progressing through the base.
 	 */
-	public Set<String> getSubsections(final String section) {
+	public Set<String> getSubsections(String section) {
 		return getState().getSubsections(section);
 	}
 
 	/**
-	 * @return the sections defined in this {@link Config}. The set's iterator
-	 *         returns sections in the order they are declared by the
-	 *         configuration starting from this instance and progressing through
-	 *         the base.
+	 * Get the sections defined in this {@link org.eclipse.jgit.lib.Config}.
+	 *
+	 * @return the sections defined in this {@link org.eclipse.jgit.lib.Config}.
+	 *         The set's iterator returns sections in the order they are
+	 *         declared by the configuration starting from this instance and
+	 *         progressing through the base.
 	 */
 	public Set<String> getSections() {
 		return getState().getSections();
 	}
 
 	/**
+	 * Get the list of names defined for this section
+	 *
 	 * @param section
 	 *            the section
 	 * @return the list of names defined for this section
@@ -492,6 +543,8 @@ public Set<String> getNames(String section) {
 	}
 
 	/**
+	 * Get the list of names defined for this subsection
+	 *
 	 * @param section
 	 *            the section
 	 * @param subsection
@@ -503,6 +556,8 @@ public Set<String> getNames(String section, String subsection) {
 	}
 
 	/**
+	 * Get the list of names defined for this section
+	 *
 	 * @param section
 	 *            the section
 	 * @param recursive
@@ -516,6 +571,8 @@ public Set<String> getNames(String section, boolean recursive) {
 	}
 
 	/**
+	 * Get the list of names defined for this section
+	 *
 	 * @param section
 	 *            the section
 	 * @param subsection
@@ -544,7 +601,7 @@ public Set<String> getNames(String section, String subsection,
 	 * @return the parsed object instance, which is cached inside this config.
 	 */
 	@SuppressWarnings("unchecked")
-	public <T> T get(final SectionParser<T> parser) {
+	public <T> T get(SectionParser<T> parser) {
 		final ConfigSnapshot myState = getState();
 		T obj = (T) myState.cache.get(parser);
 		if (obj == null) {
@@ -564,7 +621,7 @@ public <T> T get(final SectionParser<T> parser) {
 	 *            parser used to obtain the configuration object.
 	 * @see #get(SectionParser)
 	 */
-	public void uncache(final SectionParser<?> parser) {
+	public void uncache(SectionParser<?> parser) {
 		state.get().cache.remove(parser);
 	}
 
@@ -572,7 +629,8 @@ public void uncache(final SectionParser<?> parser) {
 	 * Adds a listener to be notified about changes.
 	 * <p>
 	 * Clients are supposed to remove the listeners after they are done with
-	 * them using the {@link ListenerHandle#remove()} method
+	 * them using the {@link org.eclipse.jgit.events.ListenerHandle#remove()}
+	 * method
 	 *
 	 * @param listener
 	 *            the listener
@@ -727,8 +785,6 @@ public void setBoolean(final String section, final String subsection,
 	 *         name = value
 	 * </pre>
 	 *
-	 * @param <T>
-	 *            type of the enumeration object.
 	 * @param section
 	 *            section name, e.g "branch"
 	 * @param subsection
@@ -948,11 +1004,13 @@ private static int findSectionEnd(final List<ConfigLine> entries,
 	}
 
 	/**
+	 * Get this configuration, formatted as a Git style text file.
+	 *
 	 * @return this configuration, formatted as a Git style text file.
 	 */
 	public String toText() {
 		final StringBuilder out = new StringBuilder();
-		for (final ConfigLine e : state.get().entryList) {
+		for (ConfigLine e : state.get().entryList) {
 			if (e.prefix != null)
 				out.append(e.prefix);
 			if (e.section != null && e.name == null) {
@@ -997,15 +1055,15 @@ public String toText() {
 	 *
 	 * @param text
 	 *            Git style text file listing configuration properties.
-	 * @throws ConfigInvalidException
+	 * @throws org.eclipse.jgit.errors.ConfigInvalidException
 	 *             the text supplied is not formatted correctly. No changes were
 	 *             made to {@code this}.
 	 */
-	public void fromText(final String text) throws ConfigInvalidException {
+	public void fromText(String text) throws ConfigInvalidException {
 		state.set(newState(fromTextRecurse(text, 1)));
 	}
 
-	private List<ConfigLine> fromTextRecurse(final String text, int depth)
+	private List<ConfigLine> fromTextRecurse(String text, int depth)
 			throws ConfigInvalidException {
 		if (depth > MAX_DEPTH) {
 			throw new ConfigInvalidException(
@@ -1050,7 +1108,7 @@ private List<ConfigLine> fromTextRecurse(final String text, int depth)
 				e.section = readSectionName(in);
 				input = in.read();
 				if ('"' == input) {
-					e.subsection = readValue(in, true, '"');
+					e.subsection = readSubsectionName(in);
 					input = in.read();
 				}
 				if (']' != input)
@@ -1067,7 +1125,11 @@ private List<ConfigLine> fromTextRecurse(final String text, int depth)
 					e.name = e.name.substring(0, e.name.length() - 1);
 					e.value = MAGIC_EMPTY_VALUE;
 				} else
-					e.value = readValue(in, false, -1);
+					e.value = readValue(in);
+
+				if (e.section.equalsIgnoreCase("include")) { //$NON-NLS-1$
+					addIncludedConfig(newEntries, e, depth);
+				}
 			} else
 				throw new ConfigInvalidException(JGitText.get().invalidLineInConfigFile);
 		}
@@ -1075,12 +1137,55 @@ private List<ConfigLine> fromTextRecurse(final String text, int depth)
 		return newEntries;
 	}
 
+	/**
+	 * Read the included config from the specified (possibly) relative path
+	 *
+	 * @param relPath
+	 *            possibly relative path to the included config, as specified in
+	 *            this config
+	 * @return the read bytes, or null if the included config should be ignored
+	 * @throws org.eclipse.jgit.errors.ConfigInvalidException
+	 *             if something went wrong while reading the config
+	 * @since 4.10
+	 */
+	@Nullable
+	protected byte[] readIncludedConfig(String relPath)
+			throws ConfigInvalidException {
+		return null;
+	}
+
+	private void addIncludedConfig(final List<ConfigLine> newEntries,
+			ConfigLine line, int depth) throws ConfigInvalidException {
+		if (!line.name.equalsIgnoreCase("path") || //$NON-NLS-1$
+				line.value == null || line.value.equals(MAGIC_EMPTY_VALUE)) {
+			throw new ConfigInvalidException(MessageFormat.format(
+					JGitText.get().invalidLineInConfigFileWithParam, line));
+		}
+		byte[] bytes = readIncludedConfig(line.value);
+		if (bytes == null) {
+			return;
+		}
+
+		String decoded;
+		if (isUtf8(bytes)) {
+			decoded = RawParseUtils.decode(CHARSET, bytes, 3, bytes.length);
+		} else {
+			decoded = RawParseUtils.decode(bytes);
+		}
+		try {
+			newEntries.addAll(fromTextRecurse(decoded, depth + 1));
+		} catch (ConfigInvalidException e) {
+			throw new ConfigInvalidException(MessageFormat
+					.format(JGitText.get().cannotReadFile, line.value), e);
+		}
+	}
+
 	private ConfigSnapshot newState() {
 		return new ConfigSnapshot(Collections.<ConfigLine> emptyList(),
 				getBaseState());
 	}
 
-	private ConfigSnapshot newState(final List<ConfigLine> entries) {
+	private ConfigSnapshot newState(List<ConfigLine> entries) {
 		return new ConfigSnapshot(Collections.unmodifiableList(entries),
 				getBaseState());
 	}
@@ -1105,7 +1210,7 @@ protected boolean isUtf8(final byte[] bytes) {
 				&& bytes[1] == (byte) 0xBB && bytes[2] == (byte) 0xBF;
 	}
 
-	private static String readSectionName(final StringReader in)
+	private static String readSectionName(StringReader in)
 			throws ConfigInvalidException {
 		final StringBuilder name = new StringBuilder();
 		for (;;) {
@@ -1144,7 +1249,7 @@ private static String readSectionName(final StringReader in)
 		return name.toString();
 	}
 
-	private static String readKeyName(final StringReader in)
+	private static String readKeyName(StringReader in)
 			throws ConfigInvalidException {
 		final StringBuilder name = new StringBuilder();
 		for (;;) {
@@ -1191,10 +1296,9 @@ private static String readKeyName(final StringReader in)
 		return name.toString();
 	}
 
-	private static String readValue(final StringReader in, boolean quote,
-			final int eol) throws ConfigInvalidException {
-		final StringBuilder value = new StringBuilder();
-		boolean space = false;
+	private static String readSubsectionName(StringReader in)
+			throws ConfigInvalidException {
+		StringBuilder r = new StringBuilder();
 		for (;;) {
 			int c = in.read();
 			if (c < 0) {
@@ -1202,30 +1306,81 @@ private static String readValue(final StringReader in, boolean quote,
 			}
 
 			if ('\n' == c) {
-				if (quote)
-					throw new ConfigInvalidException(JGitText.get().newlineInQuotesNotAllowed);
+				throw new ConfigInvalidException(
+						JGitText.get().newlineInQuotesNotAllowed);
+			}
+			if ('\\' == c) {
+				c = in.read();
+				switch (c) {
+				case -1:
+					throw new ConfigInvalidException(JGitText.get().endOfFileInEscape);
+
+				case '\\':
+				case '"':
+					r.append((char) c);
+					continue;
+
+				default:
+					// C git simply drops backslashes if the escape sequence is not
+					// recognized.
+					r.append((char) c);
+					continue;
+				}
+			}
+			if ('"' == c) {
+				break;
+			}
+
+			r.append((char) c);
+		}
+		return r.toString();
+	}
+
+	private static String readValue(StringReader in)
+			throws ConfigInvalidException {
+		StringBuilder value = new StringBuilder();
+		StringBuilder trailingSpaces = null;
+		boolean quote = false;
+		boolean inLeadingSpace = true;
+
+		for (;;) {
+			int c = in.read();
+			if (c < 0) {
+				break;
+			}
+			if ('\n' == c) {
+				if (quote) {
+					throw new ConfigInvalidException(
+							JGitText.get().newlineInQuotesNotAllowed);
+				}
 				in.reset();
 				break;
 			}
 
-			if (eol == c)
+			if (!quote && (';' == c || '#' == c)) {
+				if (trailingSpaces != null) {
+					trailingSpaces.setLength(0);
+				}
+				in.reset();
 				break;
-
-			if (!quote) {
-				if (Character.isWhitespace((char) c)) {
-					space = true;
-					continue;
-				}
-				if (';' == c || '#' == c) {
-					in.reset();
-					break;
-				}
 			}
 
-			if (space) {
-				if (value.length() > 0)
-					value.append(' ');
-				space = false;
+			char cc = (char) c;
+			if (Character.isWhitespace(cc)) {
+				if (inLeadingSpace) {
+					continue;
+				}
+				if (trailingSpaces == null) {
+					trailingSpaces = new StringBuilder();
+				}
+				trailingSpaces.append(cc);
+				continue;
+			} else {
+				inLeadingSpace = false;
+				if (trailingSpaces != null) {
+					value.append(trailingSpaces);
+					trailingSpaces.setLength(0);
+				}
 			}
 
 			if ('\\' == c) {
@@ -1262,7 +1417,7 @@ private static String readValue(final StringReader in, boolean quote,
 				continue;
 			}
 
-			value.append((char) c);
+			value.append(cc);
 		}
 		return value.length() > 0 ? value.toString() : null;
 	}
@@ -1297,7 +1452,7 @@ private static class StringReader {
 
 		private int pos;
 
-		StringReader(final String in) {
+		StringReader(String in) {
 			buf = in.toCharArray();
 		}
 
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java
index 08c883a..5a79035 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java
@@ -420,4 +420,16 @@ public class ConfigConstants {
 	 * @since 4.7
 	 */
 	public static final String CONFIG_KEY_RECURSE_SUBMODULES = "recurseSubmodules";
+
+	/**
+	 * The "required" key
+	 * @since 4.11
+	 */
+	public static final String CONFIG_KEY_REQUIRED = "required";
+
+	/**
+	 * The "lfs" section
+	 * @since 4.11
+	 */
+	public static final String CONFIG_SECTION_LFS = "lfs";
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigLine.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigLine.java
index 8a49bdb..937ba92 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigLine.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigLine.java
@@ -73,7 +73,7 @@ class ConfigLine {
 	/** The text content after entry. */
 	String suffix;
 
-	ConfigLine forValue(final String newValue) {
+	ConfigLine forValue(String newValue) {
 		final ConfigLine e = new ConfigLine();
 		e.prefix = prefix;
 		e.section = section;
@@ -91,12 +91,12 @@ && eqSameCase(subsection, aSubsection)
 				&& eqIgnoreCase(name, aKey);
 	}
 
-	boolean match(final String aSection, final String aSubsection) {
+	boolean match(String aSection, String aSubsection) {
 		return eqIgnoreCase(section, aSection)
 				&& eqSameCase(subsection, aSubsection);
 	}
 
-	private static boolean eqIgnoreCase(final String a, final String b) {
+	private static boolean eqIgnoreCase(String a, String b) {
 		if (a == null && b == null)
 			return true;
 		if (a == null || b == null)
@@ -104,7 +104,7 @@ private static boolean eqIgnoreCase(final String a, final String b) {
 		return StringUtils.equalsIgnoreCase(a, b);
 	}
 
-	private static boolean eqSameCase(final String a, final String b) {
+	private static boolean eqSameCase(String a, String b) {
 		if (a == null && b == null)
 			return true;
 		if (a == null || b == null)
@@ -112,6 +112,7 @@ private static boolean eqSameCase(final String a, final String b) {
 		return a.equals(b);
 	}
 
+	/** {@inheritDoc} */
 	@SuppressWarnings("nls")
 	@Override
 	public String toString() {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Constants.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Constants.java
index bb7316d..ecebd54 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Constants.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Constants.java
@@ -45,6 +45,8 @@
 
 package org.eclipse.jgit.lib;
 
+import static java.nio.charset.StandardCharsets.UTF_8;
+
 import java.nio.ByteBuffer;
 import java.nio.charset.Charset;
 import java.security.MessageDigest;
@@ -55,7 +57,9 @@
 import org.eclipse.jgit.internal.JGitText;
 import org.eclipse.jgit.util.MutableInteger;
 
-/** Misc. constants used throughout JGit. */
+/**
+ * Misc. constants used throughout JGit.
+ */
 @SuppressWarnings("nls")
 public final class Constants {
 	/** Hash function used natively by Git for all objects. */
@@ -224,10 +228,10 @@ public final class Constants {
 	public static final byte[] PACK_SIGNATURE = { 'P', 'A', 'C', 'K' };
 
 	/** Native character encoding for commit messages, file names... */
-	public static final String CHARACTER_ENCODING = "UTF-8";
+	public static final Charset CHARSET;
 
 	/** Native character encoding for commit messages, file names... */
-	public static final Charset CHARSET;
+	public static final String CHARACTER_ENCODING;
 
 	/** Default main branch name */
 	public static final String MASTER = "master";
@@ -436,6 +440,13 @@ public final class Constants {
 	public static final String ATTR_MERGE = "merge"; //$NON-NLS-1$
 
 	/**
+	 * Diff attribute.
+	 *
+	 * @since 4.11
+	 */
+	public static final String ATTR_DIFF = "diff"; //$NON-NLS-1$
+
+	/**
 	 * Binary value for custom merger.
 	 *
 	 * @since 4.9
@@ -446,7 +457,7 @@ public final class Constants {
 	 * Create a new digest function for objects.
 	 *
 	 * @return a new digest object.
-	 * @throws RuntimeException
+	 * @throws java.lang.RuntimeException
 	 *             this Java virtual machine does not support the required hash
 	 *             function. Very unlikely given that JGit uses a hash function
 	 *             that is in the Java reference specification.
@@ -466,7 +477,7 @@ public static MessageDigest newMessageDigest() {
 	 * @param typeCode the type code, from a pack representation.
 	 * @return the canonical string name of this type.
 	 */
-	public static String typeString(final int typeCode) {
+	public static String typeString(int typeCode) {
 		switch (typeCode) {
 		case OBJ_COMMIT:
 			return TYPE_COMMIT;
@@ -491,7 +502,7 @@ public static String typeString(final int typeCode) {
 	 * @param typeCode the type code, from a pack representation.
 	 * @return the canonical ASCII encoded name of this type.
 	 */
-	public static byte[] encodedTypeString(final int typeCode) {
+	public static byte[] encodedTypeString(int typeCode) {
 		switch (typeCode) {
 		case OBJ_COMMIT:
 			return ENCODED_TYPE_COMMIT;
@@ -524,7 +535,7 @@ public static String typeString(final int typeCode) {
 	 *            <code>endMark</code> when the parse is successful.
 	 * @return a type code constant (one of {@link #OBJ_BLOB},
 	 *         {@link #OBJ_COMMIT}, {@link #OBJ_TAG}, {@link #OBJ_TREE}.
-	 * @throws CorruptObjectException
+	 * @throws org.eclipse.jgit.errors.CorruptObjectException
 	 *             there is no valid type identified by <code>typeString</code>.
 	 */
 	public static int decodeTypeString(final AnyObjectId id,
@@ -590,7 +601,7 @@ public static int decodeTypeString(final AnyObjectId id,
 	 * @return a decimal representation of the input integer. The returned array
 	 *         is the smallest array that will hold the value.
 	 */
-	public static byte[] encodeASCII(final long s) {
+	public static byte[] encodeASCII(long s) {
 		return encodeASCII(Long.toString(s));
 	}
 
@@ -602,11 +613,11 @@ public static int decodeTypeString(final AnyObjectId id,
 	 *            127 (outside of 7-bit ASCII).
 	 * @return a byte array of the same length as the input string, holding the
 	 *         same characters, in the same order.
-	 * @throws IllegalArgumentException
+	 * @throws java.lang.IllegalArgumentException
 	 *             the input string contains one or more characters outside of
 	 *             the 7-bit ASCII character space.
 	 */
-	public static byte[] encodeASCII(final String s) {
+	public static byte[] encodeASCII(String s) {
 		final byte[] r = new byte[s.length()];
 		for (int k = r.length - 1; k >= 0; k--) {
 			final char c = s.charAt(k);
@@ -626,7 +637,7 @@ public static int decodeTypeString(final AnyObjectId id,
 	 *         default character encoding (UTF-8).
 	 * @see #CHARACTER_ENCODING
 	 */
-	public static byte[] encode(final String str) {
+	public static byte[] encode(String str) {
 		final ByteBuffer bb = Constants.CHARSET.encode(str);
 		final int len = bb.limit();
 		if (bb.hasArray() && bb.arrayOffset() == 0) {
@@ -643,7 +654,8 @@ public static int decodeTypeString(final AnyObjectId id,
 	static {
 		if (OBJECT_ID_LENGTH != newMessageDigest().getDigestLength())
 			throw new LinkageError(JGitText.get().incorrectOBJECT_ID_LENGTH);
-		CHARSET = Charset.forName(CHARACTER_ENCODING);
+		CHARSET = UTF_8;
+		CHARACTER_ENCODING = CHARSET.name();
 	}
 
 	/** name of the file containing the commit msg for a merge commit */
@@ -679,6 +691,13 @@ public static int decodeTypeString(final AnyObjectId id,
 	public static final ObjectId EMPTY_BLOB_ID = ObjectId
 			.fromString("e69de29bb2d1d6434b8b29ae775ad8c2e48c5391");
 
+	/**
+	 * Suffix of lock file name
+	 *
+	 * @since 5.0
+	 */
+	public static final String LOCK_SUFFIX = ".lock"; //$NON-NLS-1$
+
 	private Constants() {
 		// Hide the default constructor
 	}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/CoreConfig.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/CoreConfig.java
index fdbbe39..98de3a9 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/CoreConfig.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/CoreConfig.java
@@ -166,7 +166,7 @@ public static enum HideDotFiles {
 		DOTGITONLY
 	}
 
-	private CoreConfig(final Config rc) {
+	private CoreConfig(Config rc) {
 		compression = rc.getInt(ConfigConstants.CONFIG_CORE_SECTION,
 				ConfigConstants.CONFIG_KEY_COMPRESSION, DEFAULT_COMPRESSION);
 		packIndexVersion = rc.getInt(ConfigConstants.CONFIG_PACK_SECTION,
@@ -180,6 +180,8 @@ private CoreConfig(final Config rc) {
 	}
 
 	/**
+	 * Get the compression level to use when storing loose objects
+	 *
 	 * @return The compression level to use when storing loose objects
 	 */
 	public int getCompression() {
@@ -187,6 +189,8 @@ public int getCompression() {
 	}
 
 	/**
+	 * Get the preferred pack index file format; 0 for oldest possible.
+	 *
 	 * @return the preferred pack index file format; 0 for oldest possible.
 	 */
 	public int getPackIndexVersion() {
@@ -194,6 +198,8 @@ public int getPackIndexVersion() {
 	}
 
 	/**
+	 * Whether to log all refUpdates
+	 *
 	 * @return whether to log all refUpdates
 	 */
 	public boolean isLogAllRefUpdates() {
@@ -201,6 +207,8 @@ public boolean isLogAllRefUpdates() {
 	}
 
 	/**
+	 * Get path of excludesfile
+	 *
 	 * @return path of excludesfile
 	 */
 	public String getExcludesFile() {
@@ -208,6 +216,8 @@ public String getExcludesFile() {
 	}
 
 	/**
+	 * Get path of attributesfile
+	 *
 	 * @return path of attributesfile
 	 * @since 3.7
 	 */
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/DefaultTypedConfigGetter.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/DefaultTypedConfigGetter.java
index fd37747..891c7f2 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/DefaultTypedConfigGetter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/DefaultTypedConfigGetter.java
@@ -57,13 +57,14 @@
 import org.eclipse.jgit.util.StringUtils;
 
 /**
- * An {@link TypedConfigGetter} that throws {@link IllegalArgumentException} on
- * invalid values.
+ * An {@link org.eclipse.jgit.lib.TypedConfigGetter} that throws
+ * {@link java.lang.IllegalArgumentException} on invalid values.
  *
  * @since 4.9
  */
 public class DefaultTypedConfigGetter implements TypedConfigGetter {
 
+	/** {@inheritDoc} */
 	@Override
 	public boolean getBoolean(Config config, String section, String subsection,
 			String name, boolean defaultValue) {
@@ -82,6 +83,7 @@ public boolean getBoolean(Config config, String section, String subsection,
 		}
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public <T extends Enum<?>> T getEnum(Config config, T[] all, String section,
 			String subsection, String name, T defaultValue) {
@@ -139,6 +141,7 @@ public <T extends Enum<?>> T getEnum(Config config, T[] all, String section,
 		}
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public int getInt(Config config, String section, String subsection,
 			String name, int defaultValue) {
@@ -150,6 +153,7 @@ public int getInt(Config config, String section, String subsection,
 				.format(JGitText.get().integerValueOutOfRange, section, name));
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public long getLong(Config config, String section, String subsection,
 			String name, long defaultValue) {
@@ -187,6 +191,7 @@ public long getLong(Config config, String section, String subsection,
 		}
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public long getTimeUnit(Config config, String section, String subsection,
 			String name, long defaultValue, TimeUnit wantUnit) {
@@ -265,8 +270,8 @@ public long getTimeUnit(Config config, String section, String subsection,
 		}
 	}
 
-	private static boolean match(final String a, final String... cases) {
-		for (final String b : cases) {
+	private static boolean match(String a, String... cases) {
+		for (String b : cases) {
 			if (b != null && b.equalsIgnoreCase(a)) {
 				return true;
 			}
@@ -286,6 +291,7 @@ private static IllegalArgumentException notTimeUnit(String section,
 						section, name, valueString));
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public @NonNull List<RefSpec> getRefSpecs(Config config, String section,
 			String subsection, String name) {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/EmptyProgressMonitor.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/EmptyProgressMonitor.java
index c236c35..8ae90c6 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/EmptyProgressMonitor.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/EmptyProgressMonitor.java
@@ -51,26 +51,31 @@
  */
 public abstract class EmptyProgressMonitor implements ProgressMonitor {
 
+	/** {@inheritDoc} */
 	@Override
 	public void start(int totalTasks) {
 		// empty
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void beginTask(String title, int totalWork) {
 		// empty
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void update(int completed) {
 		// empty
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void endTask() {
 		// empty
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public boolean isCancelled() {
 		return false;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/FileMode.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/FileMode.java
index edbc709..d4c4d5b 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/FileMode.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/FileMode.java
@@ -82,11 +82,13 @@ public abstract class FileMode {
 	/** Bit pattern for {@link #TYPE_MASK} matching {@link #MISSING}. */
 	public static final int TYPE_MISSING = 0000000;
 
-	/** Mode indicating an entry is a tree (aka directory). */
+	/**
+	 * Mode indicating an entry is a tree (aka directory).
+	 */
 	public static final FileMode TREE = new FileMode(TYPE_TREE,
 			Constants.OBJ_TREE) {
 		@Override
-		public boolean equals(final int modeBits) {
+		public boolean equals(int modeBits) {
 			return (modeBits & TYPE_MASK) == TYPE_TREE;
 		}
 	};
@@ -95,7 +97,7 @@ public boolean equals(final int modeBits) {
 	public static final FileMode SYMLINK = new FileMode(TYPE_SYMLINK,
 			Constants.OBJ_BLOB) {
 		@Override
-		public boolean equals(final int modeBits) {
+		public boolean equals(int modeBits) {
 			return (modeBits & TYPE_MASK) == TYPE_SYMLINK;
 		}
 	};
@@ -104,7 +106,7 @@ public boolean equals(final int modeBits) {
 	public static final FileMode REGULAR_FILE = new FileMode(0100644,
 			Constants.OBJ_BLOB) {
 		@Override
-		public boolean equals(final int modeBits) {
+		public boolean equals(int modeBits) {
 			return (modeBits & TYPE_MASK) == TYPE_FILE && (modeBits & 0111) == 0;
 		}
 	};
@@ -113,7 +115,7 @@ public boolean equals(final int modeBits) {
 	public static final FileMode EXECUTABLE_FILE = new FileMode(0100755,
 			Constants.OBJ_BLOB) {
 		@Override
-		public boolean equals(final int modeBits) {
+		public boolean equals(int modeBits) {
 			return (modeBits & TYPE_MASK) == TYPE_FILE && (modeBits & 0111) != 0;
 		}
 	};
@@ -122,7 +124,7 @@ public boolean equals(final int modeBits) {
 	public static final FileMode GITLINK = new FileMode(TYPE_GITLINK,
 			Constants.OBJ_COMMIT) {
 		@Override
-		public boolean equals(final int modeBits) {
+		public boolean equals(int modeBits) {
 			return (modeBits & TYPE_MASK) == TYPE_GITLINK;
 		}
 	};
@@ -131,7 +133,7 @@ public boolean equals(final int modeBits) {
 	public static final FileMode MISSING = new FileMode(TYPE_MISSING,
 			Constants.OBJ_BAD) {
 		@Override
-		public boolean equals(final int modeBits) {
+		public boolean equals(int modeBits) {
 			return modeBits == 0;
 		}
 	};
@@ -143,7 +145,7 @@ public boolean equals(final int modeBits) {
 	 *            the mode bits the caller has somehow obtained.
 	 * @return the FileMode instance that represents the given bits.
 	 */
-	public static final FileMode fromBits(final int bits) {
+	public static final FileMode fromBits(int bits) {
 		switch (bits & TYPE_MASK) {
 		case TYPE_MISSING:
 			if (bits == 0)
@@ -163,7 +165,7 @@ public static final FileMode fromBits(final int bits) {
 
 		return new FileMode(bits, Constants.OBJ_BAD) {
 			@Override
-			public boolean equals(final int a) {
+			public boolean equals(int a) {
 				return bits == a;
 			}
 		};
@@ -175,7 +177,7 @@ public boolean equals(final int a) {
 
 	private final int objectType;
 
-	private FileMode(int mode, final int expType) {
+	private FileMode(int mode, int expType) {
 		modeBits = mode;
 		objectType = expType;
 		if (mode != 0) {
@@ -197,12 +199,14 @@ private FileMode(int mode, final int expType) {
 	}
 
 	/**
-	 * Test a file mode for equality with this {@link FileMode} object.
+	 * Test a file mode for equality with this
+	 * {@link org.eclipse.jgit.lib.FileMode} object.
 	 *
 	 * @param modebits
+	 *            a int.
 	 * @return true if the mode bits represent the same mode as this object
 	 */
-	public abstract boolean equals(final int modebits);
+	public abstract boolean equals(int modebits);
 
 	/**
 	 * Copy this mode as a sequence of octal US-ASCII bytes.
@@ -215,10 +219,10 @@ private FileMode(int mode, final int expType) {
 	 *
 	 * @param os
 	 *            stream to copy the mode to.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the stream encountered an error during the copy.
 	 */
-	public void copyTo(final OutputStream os) throws IOException {
+	public void copyTo(OutputStream os) throws IOException {
 		os.write(octalBytes);
 	}
 
@@ -240,6 +244,8 @@ public void copyTo(byte[] buf, int ptr) {
 	}
 
 	/**
+	 * Copy the number of bytes written by {@link #copyTo(OutputStream)}.
+	 *
 	 * @return the number of bytes written by {@link #copyTo(OutputStream)}.
 	 */
 	public int copyToLength() {
@@ -249,7 +255,7 @@ public int copyToLength() {
 	/**
 	 * Get the object type that should appear for this type of mode.
 	 * <p>
-	 * See the object type constants in {@link Constants}.
+	 * See the object type constants in {@link org.eclipse.jgit.lib.Constants}.
 	 *
 	 * @return one of the well known object type constants.
 	 */
@@ -257,13 +263,19 @@ public int getObjectType() {
 		return objectType;
 	}
 
-	/** Format this mode as an octal string (for debugging only). */
+	/**
+	 * {@inheritDoc}
+	 * <p>
+	 * Format this mode as an octal string (for debugging only).
+	 */
 	@Override
 	public String toString() {
 		return Integer.toOctalString(modeBits);
 	}
 
 	/**
+	 * Get the mode bits as an integer.
+	 *
 	 * @return The mode bits as an integer.
 	 */
 	public int getBits() {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/IndexDiff.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/IndexDiff.java
index ea573a4..94b9ddc 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/IndexDiff.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/IndexDiff.java
@@ -285,12 +285,13 @@ public TreeFilter clone() {
 	 * Construct an IndexDiff
 	 *
 	 * @param repository
+	 *            a {@link org.eclipse.jgit.lib.Repository} object.
 	 * @param revstr
-	 *            symbolic name e.g. HEAD
-	 *            An EmptyTreeIterator is used if <code>revstr</code> cannot be resolved.
+	 *            symbolic name e.g. HEAD An EmptyTreeIterator is used if
+	 *            <code>revstr</code> cannot be resolved.
 	 * @param workingTreeIterator
 	 *            iterator for working directory
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 */
 	public IndexDiff(Repository repository, String revstr,
 			WorkingTreeIterator workingTreeIterator) throws IOException {
@@ -301,11 +302,12 @@ public IndexDiff(Repository repository, String revstr,
 	 * Construct an Indexdiff
 	 *
 	 * @param repository
+	 *            a {@link org.eclipse.jgit.lib.Repository} object.
 	 * @param objectId
 	 *            tree id. If null, an EmptyTreeIterator is used.
 	 * @param workingTreeIterator
 	 *            iterator for working directory
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 */
 	public IndexDiff(Repository repository, ObjectId objectId,
 			WorkingTreeIterator workingTreeIterator) throws IOException {
@@ -321,6 +323,8 @@ public IndexDiff(Repository repository, ObjectId objectId,
 	}
 
 	/**
+	 * Defines how modifications in submodules are treated
+	 *
 	 * @param mode
 	 *            defines how modifications in submodules are treated
 	 * @since 3.6
@@ -336,7 +340,8 @@ public void setIgnoreSubmoduleMode(IgnoreSubmoduleMode mode) {
 	public interface WorkingTreeIteratorFactory {
 		/**
 		 * @param repo
-		 * @return a WorkingTreeIterator for repo
+		 *            the repository
+		 * @return working tree iterator
 		 */
 		public WorkingTreeIterator getWorkingTreeIterator(Repository repo);
 	}
@@ -363,6 +368,7 @@ public void setWorkingTreeItFactory(WorkingTreeIteratorFactory wTreeIt) {
 	 * files.
 	 *
 	 * @param filter
+	 *            a {@link org.eclipse.jgit.treewalk.filter.TreeFilter} object.
 	 */
 	public void setFilter(TreeFilter filter) {
 		this.filter = filter;
@@ -374,7 +380,7 @@ public void setFilter(TreeFilter filter) {
 	 * monitor is required.
 	 *
 	 * @return if anything is different between index, tree, and workdir
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 */
 	public boolean diff() throws IOException {
 		return diff(null, 0, 0, ""); //$NON-NLS-1$
@@ -396,10 +402,9 @@ public boolean diff() throws IOException {
 	 *            number or estimated files in the working tree
 	 * @param estIndexSize
 	 *            number of estimated entries in the cache
-	 * @param title
-	 *
+	 * @param title a {@link java.lang.String} object.
 	 * @return if anything is different between index, tree, and workdir
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 */
 	public boolean diff(final ProgressMonitor monitor, int estWorkTreeSize,
 			int estIndexSize, final String title)
@@ -533,16 +538,13 @@ public boolean diff(final ProgressMonitor monitor, int estWorkTreeSize,
 							.equals(localIgnoreSubmoduleMode))
 						continue;
 				} catch (ConfigInvalidException e) {
-					IOException e1 = new IOException(MessageFormat.format(
+					throw new IOException(MessageFormat.format(
 							JGitText.get().invalidIgnoreParamSubmodule,
-							smw.getPath()));
-					e1.initCause(e);
-					throw e1;
+							smw.getPath()), e);
 				}
-				Repository subRepo = smw.getRepository();
-				if (subRepo != null) {
-					String subRepoPath = smw.getPath();
-					try {
+				try (Repository subRepo = smw.getRepository()) {
+					if (subRepo != null) {
+						String subRepoPath = smw.getPath();
 						ObjectId subHead = subRepo.resolve("HEAD"); //$NON-NLS-1$
 						if (subHead != null
 								&& !subHead.equals(smw.getObjectId())) {
@@ -571,8 +573,6 @@ public boolean diff(final ProgressMonitor monitor, int estWorkTreeSize,
 								recordFileMode(subRepoPath, FileMode.GITLINK);
 							}
 						}
-					} finally {
-						subRepo.close();
 					}
 				}
 			}
@@ -621,6 +621,8 @@ private void addConflict(String path, int stage) {
 	}
 
 	/**
+	 * Get list of files added to the index, not in the tree
+	 *
 	 * @return list of files added to the index, not in the tree
 	 */
 	public Set<String> getAdded() {
@@ -628,6 +630,8 @@ public Set<String> getAdded() {
 	}
 
 	/**
+	 * Get list of files changed from tree to index
+	 *
 	 * @return list of files changed from tree to index
 	 */
 	public Set<String> getChanged() {
@@ -635,6 +639,8 @@ public Set<String> getChanged() {
 	}
 
 	/**
+	 * Get list of files removed from index, but in tree
+	 *
 	 * @return list of files removed from index, but in tree
 	 */
 	public Set<String> getRemoved() {
@@ -642,6 +648,8 @@ public Set<String> getRemoved() {
 	}
 
 	/**
+	 * Get list of files in index, but not filesystem
+	 *
 	 * @return list of files in index, but not filesystem
 	 */
 	public Set<String> getMissing() {
@@ -649,6 +657,8 @@ public Set<String> getMissing() {
 	}
 
 	/**
+	 * Get list of files modified on disk relative to the index
+	 *
 	 * @return list of files modified on disk relative to the index
 	 */
 	public Set<String> getModified() {
@@ -656,6 +666,8 @@ public Set<String> getModified() {
 	}
 
 	/**
+	 * Get list of files that are not ignored, and not in the index.
+	 *
 	 * @return list of files that are not ignored, and not in the index.
 	 */
 	public Set<String> getUntracked() {
@@ -663,6 +675,9 @@ public Set<String> getUntracked() {
 	}
 
 	/**
+	 * Get list of files that are in conflict, corresponds to the keys of
+	 * {@link #getConflictingStageStates()}
+	 *
 	 * @return list of files that are in conflict, corresponds to the keys of
 	 *         {@link #getConflictingStageStates()}
 	 */
@@ -671,8 +686,11 @@ public Set<String> getConflicting() {
 	}
 
 	/**
+	 * Get the map from each path of {@link #getConflicting()} to its
+	 * corresponding {@link org.eclipse.jgit.lib.IndexDiff.StageState}
+	 *
 	 * @return the map from each path of {@link #getConflicting()} to its
-	 *         corresponding {@link StageState}
+	 *         corresponding {@link org.eclipse.jgit.lib.IndexDiff.StageState}
 	 * @since 3.0
 	 */
 	public Map<String, StageState> getConflictingStageStates() {
@@ -693,6 +711,8 @@ public Set<String> getIgnoredNotInIndex() {
 	}
 
 	/**
+	 * Get list of files with the flag assume-unchanged
+	 *
 	 * @return list of files with the flag assume-unchanged
 	 */
 	public Set<String> getAssumeUnchanged() {
@@ -707,6 +727,8 @@ public Set<String> getAssumeUnchanged() {
 	}
 
 	/**
+	 * Get list of folders containing only untracked files/folders
+	 *
 	 * @return list of folders containing only untracked files/folders
 	 */
 	public Set<String> getUntrackedFolders() {
@@ -717,10 +739,10 @@ public Set<String> getUntrackedFolders() {
 	/**
 	 * Get the file mode of the given path in the index
 	 *
-	 * @param path
+	 * @param path a {@link java.lang.String} object.
 	 * @return file mode
 	 */
-	public FileMode getIndexMode(final String path) {
+	public FileMode getIndexMode(String path) {
 		final DirCacheEntry entry = dirCache.getEntry(path);
 		return entry != null ? entry.getFileMode() : FileMode.MISSING;
 	}
@@ -729,12 +751,12 @@ public FileMode getIndexMode(final String path) {
 	 * Get the list of paths that IndexDiff has detected to differ and have the
 	 * given file mode
 	 *
-	 * @param mode
+	 * @param mode a {@link org.eclipse.jgit.lib.FileMode} object.
 	 * @return the list of paths that IndexDiff has detected to differ and have
 	 *         the given file mode
 	 * @since 3.6
 	 */
-	public Set<String> getPathsWithIndexMode(final FileMode mode) {
+	public Set<String> getPathsWithIndexMode(FileMode mode) {
 		Set<String> paths = fileModes.get(mode);
 		if (paths == null)
 			paths = new HashSet<>();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/InflaterCache.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/InflaterCache.java
index f9517a0..dd0f18e 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/InflaterCache.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/InflaterCache.java
@@ -46,7 +46,9 @@
 
 import java.util.zip.Inflater;
 
-/** Creates zlib based inflaters as necessary for object decompression. */
+/**
+ * Creates zlib based inflaters as necessary for object decompression.
+ */
 public class InflaterCache {
 	private static final int SZ = 4;
 
@@ -87,7 +89,7 @@ private synchronized static Inflater getImpl() {
 	 *            the inflater to return. May be null, in which case this method
 	 *            does nothing.
 	 */
-	public static void release(final Inflater i) {
+	public static void release(Inflater i) {
 		if (i != null) {
 			i.reset();
 			if (releaseImpl(i))
@@ -95,7 +97,7 @@ public static void release(final Inflater i) {
 		}
 	}
 
-	private static synchronized boolean releaseImpl(final Inflater i) {
+	private static synchronized boolean releaseImpl(Inflater i) {
 		if (openInflaterCount < SZ) {
 			inflaterCache[openInflaterCount++] = i;
 			return false;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/MutableObjectId.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/MutableObjectId.java
index 4b14d12..8cf0fd0 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/MutableObjectId.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/MutableObjectId.java
@@ -79,15 +79,17 @@ public MutableObjectId() {
 	 *
 	 * @param index
 	 *            index of the byte to set in the raw form of the ObjectId. Must
-	 *            be in range [0, {@link Constants#OBJECT_ID_LENGTH}).
+	 *            be in range [0,
+	 *            {@link org.eclipse.jgit.lib.Constants#OBJECT_ID_LENGTH}).
 	 * @param value
 	 *            the value of the specified byte at {@code index}. Values are
 	 *            unsigned and thus are in the range [0,255] rather than the
 	 *            signed byte range of [-128, 127].
-	 * @throws ArrayIndexOutOfBoundsException
+	 * @throws java.lang.ArrayIndexOutOfBoundsException
 	 *             {@code index} is less than 0, equal to
-	 *             {@link Constants#OBJECT_ID_LENGTH}, or greater than
-	 *             {@link Constants#OBJECT_ID_LENGTH}.
+	 *             {@link org.eclipse.jgit.lib.Constants#OBJECT_ID_LENGTH}, or
+	 *             greater than
+	 *             {@link org.eclipse.jgit.lib.Constants#OBJECT_ID_LENGTH}.
 	 */
 	public void setByte(int index, int value) {
 		switch (index >> 2) {
@@ -128,7 +130,9 @@ private static int set(int w, int index, int value) {
 		}
 	}
 
-	/** Make this id match {@link ObjectId#zeroId()}. */
+	/**
+	 * Make this id match {@link org.eclipse.jgit.lib.ObjectId#zeroId()}.
+	 */
 	public void clear() {
 		w1 = 0;
 		w2 = 0;
@@ -158,7 +162,7 @@ public void fromObjectId(AnyObjectId src) {
 	 *            the raw byte buffer to read from. At least 20 bytes must be
 	 *            available within this byte array.
 	 */
-	public void fromRaw(final byte[] bs) {
+	public void fromRaw(byte[] bs) {
 		fromRaw(bs, 0);
 	}
 
@@ -171,7 +175,7 @@ public void fromRaw(final byte[] bs) {
 	 * @param p
 	 *            position to read the first byte of data from.
 	 */
-	public void fromRaw(final byte[] bs, final int p) {
+	public void fromRaw(byte[] bs, int p) {
 		w1 = NB.decodeInt32(bs, p);
 		w2 = NB.decodeInt32(bs, p + 4);
 		w3 = NB.decodeInt32(bs, p + 8);
@@ -186,7 +190,7 @@ public void fromRaw(final byte[] bs, final int p) {
 	 *            the raw int buffer to read from. At least 5 integers must be
 	 *            available within this integers array.
 	 */
-	public void fromRaw(final int[] ints) {
+	public void fromRaw(int[] ints) {
 		fromRaw(ints, 0);
 	}
 
@@ -198,9 +202,8 @@ public void fromRaw(final int[] ints) {
 	 *            must be available within this integers array.
 	 * @param p
 	 *            position to read the first integer of data from.
-	 *
 	 */
-	public void fromRaw(final int[] ints, final int p) {
+	public void fromRaw(int[] ints, int p) {
 		w1 = ints[p];
 		w2 = ints[p + 1];
 		w3 = ints[p + 2];
@@ -212,10 +215,15 @@ public void fromRaw(final int[] ints, final int p) {
 	 * Convert an ObjectId from binary representation expressed in integers.
 	 *
 	 * @param a
+	 *            an int.
 	 * @param b
+	 *            an int.
 	 * @param c
+	 *            an int.
 	 * @param d
+	 *            an int.
 	 * @param e
+	 *            an int.
 	 * @since 4.7
 	 */
 	public void set(int a, int b, int c, int d, int e) {
@@ -235,7 +243,7 @@ public void set(int a, int b, int c, int d, int e) {
 	 * @param offset
 	 *            position to read the first character from.
 	 */
-	public void fromString(final byte[] buf, final int offset) {
+	public void fromString(byte[] buf, int offset) {
 		fromHexString(buf, offset);
 	}
 
@@ -245,14 +253,14 @@ public void fromString(final byte[] buf, final int offset) {
 	 * @param str
 	 *            the string to read from. Must be 40 characters long.
 	 */
-	public void fromString(final String str) {
+	public void fromString(String str) {
 		if (str.length() != Constants.OBJECT_ID_STRING_LENGTH)
 			throw new IllegalArgumentException(MessageFormat.format(
 					JGitText.get().invalidId, str));
 		fromHexString(Constants.encodeASCII(str), 0);
 	}
 
-	private void fromHexString(final byte[] bs, int p) {
+	private void fromHexString(byte[] bs, int p) {
 		try {
 			w1 = RawParseUtils.parseHexInt32(bs, p);
 			w2 = RawParseUtils.parseHexInt32(bs, p + 8);
@@ -265,6 +273,7 @@ private void fromHexString(final byte[] bs, int p) {
 		}
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public ObjectId toObjectId() {
 		return new ObjectId(this);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/NullProgressMonitor.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/NullProgressMonitor.java
index 497beb0..37fcd78 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/NullProgressMonitor.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/NullProgressMonitor.java
@@ -56,26 +56,31 @@ private NullProgressMonitor() {
 		// Do not let others instantiate
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void start(int totalTasks) {
 		// Do not report.
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void beginTask(String title, int totalWork) {
 		// Do not report.
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void update(int completed) {
 		// Do not report.
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public boolean isCancelled() {
 		return false;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void endTask() {
 		// Do not report.
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectChecker.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectChecker.java
index 19c5c7e..689659b 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectChecker.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectChecker.java
@@ -317,12 +317,12 @@ public ObjectChecker setSafeForMacOS(boolean mac) {
 	 *
 	 * @param objType
 	 *            type of the object. Must be a valid object type code in
-	 *            {@link Constants}.
+	 *            {@link org.eclipse.jgit.lib.Constants}.
 	 * @param raw
 	 *            the raw data which comprises the object. This should be in the
 	 *            canonical format (that is the format used to generate the
 	 *            ObjectId of the object). The array is never modified.
-	 * @throws CorruptObjectException
+	 * @throws org.eclipse.jgit.errors.CorruptObjectException
 	 *             if an error is identified.
 	 */
 	public void check(int objType, byte[] raw)
@@ -337,12 +337,12 @@ public void check(int objType, byte[] raw)
 	 *            identify of the object being checked.
 	 * @param objType
 	 *            type of the object. Must be a valid object type code in
-	 *            {@link Constants}.
+	 *            {@link org.eclipse.jgit.lib.Constants}.
 	 * @param raw
 	 *            the raw data which comprises the object. This should be in the
 	 *            canonical format (that is the format used to generate the
 	 *            ObjectId of the object). The array is never modified.
-	 * @throws CorruptObjectException
+	 * @throws org.eclipse.jgit.errors.CorruptObjectException
 	 *             if an error is identified.
 	 * @since 4.2
 	 */
@@ -449,7 +449,7 @@ private void checkPersonIdent(byte[] raw, @Nullable AnyObjectId id)
 	 *
 	 * @param raw
 	 *            the commit data. The array is never modified.
-	 * @throws CorruptObjectException
+	 * @throws org.eclipse.jgit.errors.CorruptObjectException
 	 *             if any error was detected.
 	 */
 	public void checkCommit(byte[] raw) throws CorruptObjectException {
@@ -463,7 +463,7 @@ public void checkCommit(byte[] raw) throws CorruptObjectException {
 	 *            identity of the object being checked.
 	 * @param raw
 	 *            the commit data. The array is never modified.
-	 * @throws CorruptObjectException
+	 * @throws org.eclipse.jgit.errors.CorruptObjectException
 	 *             if any error was detected.
 	 * @since 4.2
 	 */
@@ -503,7 +503,7 @@ public void checkCommit(@Nullable AnyObjectId id, byte[] raw)
 	 *
 	 * @param raw
 	 *            the tag data. The array is never modified.
-	 * @throws CorruptObjectException
+	 * @throws org.eclipse.jgit.errors.CorruptObjectException
 	 *             if any error was detected.
 	 */
 	public void checkTag(byte[] raw) throws CorruptObjectException {
@@ -517,7 +517,7 @@ public void checkTag(byte[] raw) throws CorruptObjectException {
 	 *            identity of the object being checked.
 	 * @param raw
 	 *            the tag data. The array is never modified.
-	 * @throws CorruptObjectException
+	 * @throws org.eclipse.jgit.errors.CorruptObjectException
 	 *             if any error was detected.
 	 * @since 4.2
 	 */
@@ -593,7 +593,7 @@ else if (cmp == 0)
 	 *
 	 * @param raw
 	 *            the raw tree data. The array is never modified.
-	 * @throws CorruptObjectException
+	 * @throws org.eclipse.jgit.errors.CorruptObjectException
 	 *             if any error was detected.
 	 */
 	public void checkTree(byte[] raw) throws CorruptObjectException {
@@ -607,7 +607,7 @@ public void checkTree(byte[] raw) throws CorruptObjectException {
 	 *            identity of the object being checked.
 	 * @param raw
 	 *            the raw tree data. The array is never modified.
-	 * @throws CorruptObjectException
+	 * @throws org.eclipse.jgit.errors.CorruptObjectException
 	 *             if any error was detected.
 	 * @since 4.2
 	 */
@@ -739,11 +739,13 @@ private void report(@NonNull ErrorType err, @Nullable AnyObjectId id,
 	/**
 	 * Check tree path entry for validity.
 	 * <p>
-	 * Unlike {@link #checkPathSegment(byte[], int, int)}, this version
-	 * scans a multi-directory path string such as {@code "src/main.c"}.
+	 * Unlike {@link #checkPathSegment(byte[], int, int)}, this version scans a
+	 * multi-directory path string such as {@code "src/main.c"}.
 	 *
-	 * @param path path string to scan.
-	 * @throws CorruptObjectException path is invalid.
+	 * @param path
+	 *            path string to scan.
+	 * @throws org.eclipse.jgit.errors.CorruptObjectException
+	 *             path is invalid.
 	 * @since 3.6
 	 */
 	public void checkPath(String path) throws CorruptObjectException {
@@ -754,13 +756,17 @@ public void checkPath(String path) throws CorruptObjectException {
 	/**
 	 * Check tree path entry for validity.
 	 * <p>
-	 * Unlike {@link #checkPathSegment(byte[], int, int)}, this version
-	 * scans a multi-directory path string such as {@code "src/main.c"}.
+	 * Unlike {@link #checkPathSegment(byte[], int, int)}, this version scans a
+	 * multi-directory path string such as {@code "src/main.c"}.
 	 *
-	 * @param raw buffer to scan.
-	 * @param ptr offset to first byte of the name.
-	 * @param end offset to one past last byte of name.
-	 * @throws CorruptObjectException path is invalid.
+	 * @param raw
+	 *            buffer to scan.
+	 * @param ptr
+	 *            offset to first byte of the name.
+	 * @param end
+	 *            offset to one past last byte of name.
+	 * @throws org.eclipse.jgit.errors.CorruptObjectException
+	 *             path is invalid.
 	 * @since 3.6
 	 */
 	public void checkPath(byte[] raw, int ptr, int end)
@@ -778,10 +784,14 @@ public void checkPath(byte[] raw, int ptr, int end)
 	/**
 	 * Check tree path entry for validity.
 	 *
-	 * @param raw buffer to scan.
-	 * @param ptr offset to first byte of the name.
-	 * @param end offset to one past last byte of name.
-	 * @throws CorruptObjectException name is invalid.
+	 * @param raw
+	 *            buffer to scan.
+	 * @param ptr
+	 *            offset to first byte of the name.
+	 * @param end
+	 *            offset to one past last byte of name.
+	 * @throws org.eclipse.jgit.errors.CorruptObjectException
+	 *             name is invalid.
 	 * @since 3.4
 	 */
 	public void checkPathSegment(byte[] raw, int ptr, int end)
@@ -1073,7 +1083,7 @@ private static boolean isPositiveDigit(byte b) {
 	}
 
 	/**
-	 * Create a new {@link BlobObjectChecker}.
+	 * Create a new {@link org.eclipse.jgit.lib.BlobObjectChecker}.
 	 *
 	 * @return new BlobObjectChecker or null if it's not provided.
 	 * @since 4.9
@@ -1086,15 +1096,16 @@ public BlobObjectChecker newBlobObjectChecker() {
 	/**
 	 * Check a blob for errors.
 	 *
-	 * <p>This may not be called from PackParser in some cases. Use {@link
-	 * #newBlobObjectChecker} instead.
+	 * <p>
+	 * This may not be called from PackParser in some cases. Use
+	 * {@link #newBlobObjectChecker} instead.
 	 *
 	 * @param raw
 	 *            the blob data. The array is never modified.
-	 * @throws CorruptObjectException
+	 * @throws org.eclipse.jgit.errors.CorruptObjectException
 	 *             if any error was detected.
 	 */
-	public void checkBlob(final byte[] raw) throws CorruptObjectException {
+	public void checkBlob(byte[] raw) throws CorruptObjectException {
 		// We can always assume the blob is valid.
 	}
 
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectDatabase.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectDatabase.java
index 2abd6da..93add5c 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectDatabase.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectDatabase.java
@@ -52,10 +52,12 @@
  * Abstraction of arbitrary object storage.
  * <p>
  * An object database stores one or more Git objects, indexed by their unique
- * {@link ObjectId}.
+ * {@link org.eclipse.jgit.lib.ObjectId}.
  */
 public abstract class ObjectDatabase {
-	/** Initialize a new database instance for access. */
+	/**
+	 * Initialize a new database instance for access.
+	 */
 	protected ObjectDatabase() {
 		// Protected to force extension.
 	}
@@ -73,7 +75,7 @@ public boolean exists() {
 	/**
 	 * Initialize a new object database at this location.
 	 *
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the database could not be created.
 	 */
 	public void create() throws IOException {
@@ -116,11 +118,11 @@ public void create() throws IOException {
 	 * @param objectId
 	 *            identity of the object to test for existence of.
 	 * @return true if the specified object is stored in this database.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the object store cannot be accessed.
 	 */
-	public boolean has(final AnyObjectId objectId) throws IOException {
-		try (final ObjectReader or = newReader()) {
+	public boolean has(AnyObjectId objectId) throws IOException {
+		try (ObjectReader or = newReader()) {
 			return or.has(objectId);
 		}
 	}
@@ -133,13 +135,13 @@ public boolean has(final AnyObjectId objectId) throws IOException {
 	 *
 	 * @param objectId
 	 *            identity of the object to open.
-	 * @return a {@link ObjectLoader} for accessing the object.
+	 * @return a {@link org.eclipse.jgit.lib.ObjectLoader} for accessing the object.
 	 * @throws MissingObjectException
 	 *             the object does not exist.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the object store cannot be accessed.
 	 */
-	public ObjectLoader open(final AnyObjectId objectId)
+	public ObjectLoader open(AnyObjectId objectId)
 			throws IOException {
 		return open(objectId, ObjectReader.OBJ_ANY);
 	}
@@ -154,22 +156,23 @@ public ObjectLoader open(final AnyObjectId objectId)
 	 *            identity of the object to open.
 	 * @param typeHint
 	 *            hint about the type of object being requested, e.g.
-	 *            {@link Constants#OBJ_BLOB}; {@link ObjectReader#OBJ_ANY} if
-	 *            the object type is not known, or does not matter to the
-	 *            caller.
-	 * @return a {@link ObjectLoader} for accessing the object.
-	 * @throws MissingObjectException
+	 *            {@link org.eclipse.jgit.lib.Constants#OBJ_BLOB};
+	 *            {@link org.eclipse.jgit.lib.ObjectReader#OBJ_ANY} if the
+	 *            object type is not known, or does not matter to the caller.
+	 * @return a {@link org.eclipse.jgit.lib.ObjectLoader} for accessing the
+	 *         object.
+	 * @throws org.eclipse.jgit.errors.MissingObjectException
 	 *             the object does not exist.
-	 * @throws IncorrectObjectTypeException
+	 * @throws org.eclipse.jgit.errors.IncorrectObjectTypeException
 	 *             typeHint was not OBJ_ANY, and the object's actual type does
 	 *             not match typeHint.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the object store cannot be accessed.
 	 */
 	public ObjectLoader open(AnyObjectId objectId, int typeHint)
 			throws MissingObjectException, IncorrectObjectTypeException,
 			IOException {
-		try (final ObjectReader or = newReader()) {
+		try (ObjectReader or = newReader()) {
 			return or.open(objectId, typeHint);
 		}
 	}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectId.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectId.java
index 991f03f..764f890 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectId.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectId.java
@@ -86,7 +86,7 @@ public static final ObjectId zeroId() {
 	 *            the string to test.
 	 * @return true if the string can converted into an ObjectId.
 	 */
-	public static final boolean isId(final String id) {
+	public static final boolean isId(String id) {
 		if (id.length() != Constants.OBJECT_ID_STRING_LENGTH)
 			return false;
 		try {
@@ -106,7 +106,7 @@ public static final boolean isId(final String id) {
 	 *            the id to convert. May be null.
 	 * @return the hex string conversion of this id's content.
 	 */
-	public static final String toString(final ObjectId i) {
+	public static final String toString(ObjectId i) {
 		return i != null ? i.name() : ZEROID_STR;
 	}
 
@@ -157,7 +157,7 @@ public static boolean equals(final byte[] firstBuffer, final int fi,
 	 *            available within this byte array.
 	 * @return the converted object id.
 	 */
-	public static final ObjectId fromRaw(final byte[] bs) {
+	public static final ObjectId fromRaw(byte[] bs) {
 		return fromRaw(bs, 0);
 	}
 
@@ -171,7 +171,7 @@ public static final ObjectId fromRaw(final byte[] bs) {
 	 *            position to read the first byte of data from.
 	 * @return the converted object id.
 	 */
-	public static final ObjectId fromRaw(final byte[] bs, final int p) {
+	public static final ObjectId fromRaw(byte[] bs, int p) {
 		final int a = NB.decodeInt32(bs, p);
 		final int b = NB.decodeInt32(bs, p + 4);
 		final int c = NB.decodeInt32(bs, p + 8);
@@ -188,7 +188,7 @@ public static final ObjectId fromRaw(final byte[] bs, final int p) {
 	 *            be available within this int array.
 	 * @return the converted object id.
 	 */
-	public static final ObjectId fromRaw(final int[] is) {
+	public static final ObjectId fromRaw(int[] is) {
 		return fromRaw(is, 0);
 	}
 
@@ -202,7 +202,7 @@ public static final ObjectId fromRaw(final int[] is) {
 	 *            position to read the first integer of data from.
 	 * @return the converted object id.
 	 */
-	public static final ObjectId fromRaw(final int[] is, final int p) {
+	public static final ObjectId fromRaw(int[] is, int p) {
 		return new ObjectId(is[p], is[p + 1], is[p + 2], is[p + 3], is[p + 4]);
 	}
 
@@ -216,7 +216,7 @@ public static final ObjectId fromRaw(final int[] is, final int p) {
 	 *            position to read the first character from.
 	 * @return the converted object id.
 	 */
-	public static final ObjectId fromString(final byte[] buf, final int offset) {
+	public static final ObjectId fromString(byte[] buf, int offset) {
 		return fromHexString(buf, offset);
 	}
 
@@ -227,14 +227,14 @@ public static final ObjectId fromString(final byte[] buf, final int offset) {
 	 *            the string to read from. Must be 40 characters long.
 	 * @return the converted object id.
 	 */
-	public static ObjectId fromString(final String str) {
+	public static ObjectId fromString(String str) {
 		if (str.length() != Constants.OBJECT_ID_STRING_LENGTH) {
 			throw new InvalidObjectIdException(str);
 		}
 		return fromHexString(Constants.encodeASCII(str), 0);
 	}
 
-	private static final ObjectId fromHexString(final byte[] bs, int p) {
+	private static final ObjectId fromHexString(byte[] bs, int p) {
 		try {
 			final int a = RawParseUtils.parseHexInt32(bs, p);
 			final int b = RawParseUtils.parseHexInt32(bs, p + 8);
@@ -252,10 +252,15 @@ private static final ObjectId fromHexString(final byte[] bs, int p) {
 	 * Construct an ObjectId from 160 bits provided in 5 words.
 	 *
 	 * @param new_1
+	 *            an int
 	 * @param new_2
+	 *            an int
 	 * @param new_3
+	 *            an int
 	 * @param new_4
+	 *            an int
 	 * @param new_5
+	 *            an int
 	 * @since 4.7
 	 */
 	public ObjectId(int new_1, int new_2, int new_3, int new_4, int new_5) {
@@ -276,7 +281,7 @@ public ObjectId(int new_1, int new_2, int new_3, int new_4, int new_5) {
 	 * @param src
 	 *            another already parsed ObjectId to copy the value out of.
 	 */
-	protected ObjectId(final AnyObjectId src) {
+	protected ObjectId(AnyObjectId src) {
 		w1 = src.w1;
 		w2 = src.w2;
 		w3 = src.w3;
@@ -284,6 +289,7 @@ protected ObjectId(final AnyObjectId src) {
 		w5 = src.w5;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public ObjectId toObjectId() {
 		return this;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectIdOwnerMap.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectIdOwnerMap.java
index 95cb976..9df5933 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectIdOwnerMap.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectIdOwnerMap.java
@@ -48,10 +48,12 @@
 import java.util.NoSuchElementException;
 
 /**
- * Fast, efficient map for {@link ObjectId} subclasses in only one map.
+ * Fast, efficient map for {@link org.eclipse.jgit.lib.ObjectId} subclasses in
+ * only one map.
  * <p>
  * To use this map type, applications must have their entry value type extend
- * from {@link ObjectIdOwnerMap.Entry}, which itself extends from ObjectId.
+ * from {@link org.eclipse.jgit.lib.ObjectIdOwnerMap.Entry}, which itself
+ * extends from ObjectId.
  * <p>
  * Object instances may only be stored in <b>ONE</b> ObjectIdOwnerMap. This
  * restriction exists because the map stores internal map state within each
@@ -59,10 +61,11 @@
  * could corrupt one or both map's internal state.
  * <p>
  * If an object instance must be in more than one map, applications may use
- * ObjectIdOwnerMap for one of the maps, and {@link ObjectIdSubclassMap} for the
- * other map(s). It is encouraged to use ObjectIdOwnerMap for the map that is
- * accessed most often, as this implementation runs faster than the more general
- * ObjectIdSubclassMap implementation.
+ * ObjectIdOwnerMap for one of the maps, and
+ * {@link org.eclipse.jgit.lib.ObjectIdSubclassMap} for the other map(s). It is
+ * encouraged to use ObjectIdOwnerMap for the map that is accessed most often,
+ * as this implementation runs faster than the more general ObjectIdSubclassMap
+ * implementation.
  *
  * @param <V>
  *            type of subclass of ObjectId that will be stored in the map.
@@ -97,7 +100,9 @@ public class ObjectIdOwnerMap<V extends ObjectIdOwnerMap.Entry>
 	/** Low bit mask to index into {@link #directory}, {@code 2^bits-1}. */
 	private int mask;
 
-	/** Create an empty map. */
+	/**
+	 * Create an empty map.
+	 */
 	@SuppressWarnings("unchecked")
 	public ObjectIdOwnerMap() {
 		bits = 0;
@@ -108,7 +113,9 @@ public ObjectIdOwnerMap() {
 		directory[0] = newSegment();
 	}
 
-	/** Remove all entries from this map. */
+	/**
+	 * Remove all entries from this map.
+	 */
 	public void clear() {
 		size = 0;
 
@@ -127,7 +134,7 @@ public void clear() {
 	 * @return the instance mapped to toFind, or null if no mapping exists.
 	 */
 	@SuppressWarnings("unchecked")
-	public V get(final AnyObjectId toFind) {
+	public V get(AnyObjectId toFind) {
 		int h = toFind.w1;
 		V obj = directory[h & mask][h >>> SEGMENT_SHIFT];
 		for (; obj != null; obj = (V) obj.next)
@@ -137,14 +144,12 @@ public V get(final AnyObjectId toFind) {
 	}
 
 	/**
+	 * {@inheritDoc}
+	 * <p>
 	 * Returns true if this map contains the specified object.
-	 *
-	 * @param toFind
-	 *            object to find.
-	 * @return true if the mapping exists for this object; false otherwise.
 	 */
 	@Override
-	public boolean contains(final AnyObjectId toFind) {
+	public boolean contains(AnyObjectId toFind) {
 		return get(toFind) != null;
 	}
 
@@ -157,10 +162,8 @@ public boolean contains(final AnyObjectId toFind) {
 	 *
 	 * @param newValue
 	 *            the object to store.
-	 * @param <Q>
-	 *            type of instance to store.
 	 */
-	public <Q extends V> void add(final Q newValue) {
+	public <Q extends V> void add(Q newValue) {
 		if (++size == grow)
 			grow();
 
@@ -189,11 +192,9 @@ public <Q extends V> void add(final Q newValue) {
 	 * @return {@code newValue} if stored, or the prior value already stored and
 	 *         that would have been returned had the caller used
 	 *         {@code get(newValue)} first.
-	 * @param <Q>
-	 *            type of instance to store.
 	 */
 	@SuppressWarnings("unchecked")
-	public <Q extends V> V addIfAbsent(final Q newValue) {
+	public <Q extends V> V addIfAbsent(Q newValue) {
 		int h = newValue.w1;
 		V[] table = directory[h & mask];
 		h >>>= SEGMENT_SHIFT;
@@ -210,16 +211,25 @@ public <Q extends V> V addIfAbsent(final Q newValue) {
 		return newValue;
 	}
 
-	/** @return number of objects in this map. */
+	/**
+	 * Get number of objects in this map.
+	 *
+	 * @return number of objects in this map.
+	 */
 	public int size() {
 		return size;
 	}
 
-	/** @return true if {@link #size()} is 0. */
+	/**
+	 * Whether this map is empty
+	 *
+	 * @return true if {@link #size()} is 0.
+	 */
 	public boolean isEmpty() {
 		return size == 0;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public Iterator<V> iterator() {
 		return new Iterator<V>() {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectIdRef.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectIdRef.java
index 636716b..22aaa3a 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectIdRef.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectIdRef.java
@@ -47,7 +47,10 @@
 import org.eclipse.jgit.annotations.NonNull;
 import org.eclipse.jgit.annotations.Nullable;
 
-/** A {@link Ref} that points directly at an {@link ObjectId}. */
+/**
+ * A {@link org.eclipse.jgit.lib.Ref} that points directly at an
+ * {@link org.eclipse.jgit.lib.ObjectId}.
+ */
 public abstract class ObjectIdRef implements Ref {
 	/** Any reference whose peeled value is not yet known. */
 	public static class Unpeeled extends ObjectIdRef {
@@ -167,41 +170,48 @@ protected ObjectIdRef(@NonNull Storage st, @NonNull String name,
 		this.objectId = id;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	@NonNull
 	public String getName() {
 		return name;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public boolean isSymbolic() {
 		return false;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	@NonNull
 	public Ref getLeaf() {
 		return this;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	@NonNull
 	public Ref getTarget() {
 		return this;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	@Nullable
 	public ObjectId getObjectId() {
 		return objectId;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	@NonNull
 	public Storage getStorage() {
 		return storage;
 	}
 
+	/** {@inheritDoc} */
 	@NonNull
 	@Override
 	public String toString() {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectIdSerializer.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectIdSerializer.java
new file mode 100644
index 0000000..4f8bd32
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectIdSerializer.java
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2009, The Android Open Source Project
+ * Copyright (C) 2009, Shawn O. Pearce <spearce@spearce.org>
+ * Copyright (C) 2018, David Pursehouse <david.pursehouse@gmail.com>
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ *   copyright notice, this list of conditions and the following
+ *   disclaimer in the documentation and/or other materials provided
+ *   with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ *   names of its contributors may be used to endorse or promote
+ *   products derived from this software without specific prior
+ *   written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.lib;
+
+import static org.eclipse.jgit.lib.Constants.OBJECT_ID_LENGTH;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import org.eclipse.jgit.annotations.NonNull;
+import org.eclipse.jgit.annotations.Nullable;
+import org.eclipse.jgit.util.IO;
+
+/**
+ * Helper to serialize {@link ObjectId} instances. {@link ObjectId} is already
+ * serializable, but this class provides methods to handle null and non-null
+ * instances.
+ *
+ * @since 4.11
+ */
+public class ObjectIdSerializer {
+	/*
+	 * Marker to indicate a null ObjectId instance.
+	 */
+	private static final byte NULL_MARKER = 0;
+
+	/*
+	 * Marker to indicate a non-null ObjectId instance.
+	 */
+	private static final byte NON_NULL_MARKER = 1;
+
+	/**
+	 * Write a possibly null {@link ObjectId} to the stream, using markers to
+	 * differentiate null and non-null instances.
+	 *
+	 * <p>
+	 * If the id is non-null, writes a {@link #NON_NULL_MARKER} followed by the
+	 * id's words. If it is null, writes a {@link #NULL_MARKER} and nothing
+	 * else.
+	 *
+	 * @param out
+	 *            the output stream
+	 * @param id
+	 *            the object id to serialize; may be null
+	 * @throws IOException
+	 *             the stream writing failed
+	 */
+	public static void write(OutputStream out, @Nullable AnyObjectId id)
+			throws IOException {
+		if (id != null) {
+			out.write(NON_NULL_MARKER);
+			writeWithoutMarker(out, id);
+		} else {
+			out.write(NULL_MARKER);
+		}
+	}
+
+	/**
+	 * Write a non-null {@link ObjectId} to the stream.
+	 *
+	 * @param out
+	 *            the output stream
+	 * @param id
+	 *            the object id to serialize; never null
+	 * @throws IOException
+	 *             the stream writing failed
+	 * @since 4.11
+	 */
+	public static void writeWithoutMarker(OutputStream out, @NonNull AnyObjectId id)
+			throws IOException {
+		id.copyRawTo(out);
+	}
+
+	/**
+	 * Read a possibly null {@link ObjectId} from the stream.
+	 *
+	 * Reads the first byte of the stream, which is expected to be either
+	 * {@link #NON_NULL_MARKER} or {@link #NULL_MARKER}.
+	 *
+	 * @param in
+	 *            the input stream
+	 * @return the object id, or null
+	 * @throws IOException
+	 *             there was an error reading the stream
+	 */
+	@Nullable
+	public static ObjectId read(InputStream in) throws IOException {
+		byte marker = (byte) in.read();
+		switch (marker) {
+		case NULL_MARKER:
+			return null;
+		case NON_NULL_MARKER:
+			return readWithoutMarker(in);
+		default:
+			throw new IOException("Invalid flag before ObjectId: " + marker); //$NON-NLS-1$
+		}
+	}
+
+	/**
+	 * Read a non-null {@link ObjectId} from the stream.
+	 *
+	 * @param in
+	 *            the input stream
+	 * @return the object id; never null
+	 * @throws IOException
+	 *             there was an error reading the stream
+	 * @since 4.11
+	 */
+	@NonNull
+	public static ObjectId readWithoutMarker(InputStream in) throws IOException {
+		final byte[] b = new byte[OBJECT_ID_LENGTH];
+		IO.readFully(in, b, 0, OBJECT_ID_LENGTH);
+		return ObjectId.fromRaw(b);
+	}
+
+	private ObjectIdSerializer() {
+	}
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectIdSet.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectIdSet.java
index 0b58484..51bd902 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectIdSet.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectIdSet.java
@@ -48,7 +48,8 @@
  * <p>
  * Usually backed by a read-only data structure such as
  * {@link org.eclipse.jgit.internal.storage.file.PackIndex}. Mutable types like
- * {@link ObjectIdOwnerMap} also implement the interface by checking keys.
+ * {@link org.eclipse.jgit.lib.ObjectIdOwnerMap} also implement the interface by
+ * checking keys.
  *
  * @since 4.2
  */
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectIdSubclassMap.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectIdSubclassMap.java
index 43fc7bf..cd57bda 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectIdSubclassMap.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectIdSubclassMap.java
@@ -49,13 +49,15 @@
 import java.util.NoSuchElementException;
 
 /**
- * Fast, efficient map specifically for {@link ObjectId} subclasses.
+ * Fast, efficient map specifically for {@link org.eclipse.jgit.lib.ObjectId}
+ * subclasses.
  * <p>
  * This map provides an efficient translation from any ObjectId instance to a
  * cached subclass of ObjectId that has the same value.
  * <p>
- * If object instances are stored in only one map, {@link ObjectIdOwnerMap} is a
- * more efficient implementation.
+ * If object instances are stored in only one map,
+ * {@link org.eclipse.jgit.lib.ObjectIdOwnerMap} is a more efficient
+ * implementation.
  *
  * @param <V>
  *            type of subclass of ObjectId that will be stored in the map.
@@ -72,12 +74,16 @@ public class ObjectIdSubclassMap<V extends ObjectId>
 
 	V[] table;
 
-	/** Create an empty map. */
+	/**
+	 * Create an empty map.
+	 */
 	public ObjectIdSubclassMap() {
 		initTable(INITIAL_TABLE_SIZE);
 	}
 
-	/** Remove all entries from this map. */
+	/**
+	 * Remove all entries from this map.
+	 */
 	public void clear() {
 		size = 0;
 		initTable(INITIAL_TABLE_SIZE);
@@ -90,7 +96,7 @@ public void clear() {
 	 *            the object identifier to find.
 	 * @return the instance mapped to toFind, or null if no mapping exists.
 	 */
-	public V get(final AnyObjectId toFind) {
+	public V get(AnyObjectId toFind) {
 		final int msk = mask;
 		int i = toFind.w1 & msk;
 		final V[] tbl = table;
@@ -105,14 +111,12 @@ public V get(final AnyObjectId toFind) {
 	}
 
 	/**
+	 * {@inheritDoc}
+	 * <p>
 	 * Returns true if this map contains the specified object.
-	 *
-	 * @param toFind
-	 *            object to find.
-	 * @return true if the mapping exists for this object; false otherwise.
 	 */
 	@Override
-	public boolean contains(final AnyObjectId toFind) {
+	public boolean contains(AnyObjectId toFind) {
 		return get(toFind) != null;
 	}
 
@@ -126,10 +130,8 @@ public boolean contains(final AnyObjectId toFind) {
 	 *
 	 * @param newValue
 	 *            the object to store.
-	 * @param <Q>
-	 *            type of instance to store.
 	 */
-	public <Q extends V> void add(final Q newValue) {
+	public <Q extends V> void add(Q newValue) {
 		if (++size == grow)
 			grow();
 		insert(newValue);
@@ -152,10 +154,8 @@ public <Q extends V> void add(final Q newValue) {
 	 * @return {@code newValue} if stored, or the prior value already stored and
 	 *         that would have been returned had the caller used
 	 *         {@code get(newValue)} first.
-	 * @param <Q>
-	 *            type of instance to store.
 	 */
-	public <Q extends V> V addIfAbsent(final Q newValue) {
+	public <Q extends V> V addIfAbsent(Q newValue) {
 		final int msk = mask;
 		int i = newValue.w1 & msk;
 		final V[] tbl = table;
@@ -177,17 +177,24 @@ public <Q extends V> V addIfAbsent(final Q newValue) {
 	}
 
 	/**
+	 * Get number of objects in map
+	 *
 	 * @return number of objects in map
 	 */
 	public int size() {
 		return size;
 	}
 
-	/** @return true if {@link #size()} is 0. */
+	/**
+	 * Whether {@link #size()} is 0.
+	 *
+	 * @return true if {@link #size()} is 0.
+	 */
 	public boolean isEmpty() {
 		return size == 0;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public Iterator<V> iterator() {
 		return new Iterator<V>() {
@@ -219,7 +226,7 @@ public void remove() {
 		};
 	}
 
-	private void insert(final V newValue) {
+	private void insert(V newValue) {
 		final int msk = mask;
 		int j = newValue.w1 & msk;
 		final V[] tbl = table;
@@ -247,7 +254,7 @@ private void initTable(int sz) {
 	}
 
 	@SuppressWarnings("unchecked")
-	private final V[] createArray(final int sz) {
+	private final V[] createArray(int sz) {
 		return (V[]) new ObjectId[sz];
 	}
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectInserter.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectInserter.java
index b2ffbe6..77fa1b2 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectInserter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectInserter.java
@@ -182,7 +182,9 @@ public void close() {
 	/** Temporary working buffer for streaming data through. */
 	private byte[] tempBuffer;
 
-	/** Create a new inserter for a database. */
+	/**
+	 * Create a new inserter for a database.
+	 */
 	protected ObjectInserter() {
 	}
 
@@ -218,6 +220,8 @@ protected ObjectInserter() {
 	}
 
 	/**
+	 * Compute digest to help compute an ObjectId
+	 *
 	 * @return digest to help compute an ObjectId
 	 * @since 4.7
 	 */
@@ -272,7 +276,7 @@ public ObjectId idFor(int type, byte[] data, int off, int len) {
 	 *            stream providing the object content. The caller is responsible
 	 *            for closing the stream.
 	 * @return the name of the object.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the source stream could not be read.
 	 */
 	public ObjectId idFor(int objectType, long length, InputStream in)
@@ -297,6 +301,7 @@ public ObjectId idFor(int objectType, long length, InputStream in)
 	 * Compute the ObjectId for the given tree without inserting it.
 	 *
 	 * @param formatter
+	 *            a {@link org.eclipse.jgit.lib.TreeFormatter} object.
 	 * @return the computed ObjectId
 	 */
 	public ObjectId idFor(TreeFormatter formatter) {
@@ -309,7 +314,7 @@ public ObjectId idFor(TreeFormatter formatter) {
 	 * @param formatter
 	 *            the formatter containing the proposed tree's data.
 	 * @return the name of the tree object.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the object could not be stored.
 	 */
 	public final ObjectId insert(TreeFormatter formatter) throws IOException {
@@ -325,7 +330,7 @@ public final ObjectId insert(TreeFormatter formatter) throws IOException {
 	 * @param builder
 	 *            the builder containing the proposed commit's data.
 	 * @return the name of the commit object.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the object could not be stored.
 	 */
 	public final ObjectId insert(CommitBuilder builder) throws IOException {
@@ -338,7 +343,7 @@ public final ObjectId insert(CommitBuilder builder) throws IOException {
 	 * @param builder
 	 *            the builder containing the proposed tag's data.
 	 * @return the name of the tag object.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the object could not be stored.
 	 */
 	public final ObjectId insert(TagBuilder builder) throws IOException {
@@ -353,10 +358,10 @@ public final ObjectId insert(TagBuilder builder) throws IOException {
 	 * @param data
 	 *            complete content of the object.
 	 * @return the name of the object.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the object could not be stored.
 	 */
-	public ObjectId insert(final int type, final byte[] data)
+	public ObjectId insert(int type, byte[] data)
 			throws IOException {
 		return insert(type, data, 0, data.length);
 	}
@@ -373,7 +378,7 @@ public ObjectId insert(final int type, final byte[] data)
 	 * @param len
 	 *            number of bytes to copy from {@code data}.
 	 * @return the name of the object.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the object could not be stored.
 	 */
 	public ObjectId insert(int type, byte[] data, int off, int len)
@@ -392,7 +397,7 @@ public ObjectId insert(int type, byte[] data, int off, int len)
 	 *            stream providing the object content. The caller is responsible
 	 *            for closing the stream.
 	 * @return the name of the object.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the object could not be stored, or the source stream could
 	 *             not be read.
 	 */
@@ -406,7 +411,7 @@ public abstract ObjectId insert(int objectType, long length, InputStream in)
 	 *            the input stream. The stream is not closed by the parser, and
 	 *            must instead be closed by the caller once parsing is complete.
 	 * @return the pack parser.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the parser instance, which can be configured and then used to
 	 *             parse objects into the ObjectDatabase.
 	 */
@@ -443,13 +448,15 @@ public abstract ObjectId insert(int objectType, long length, InputStream in)
 	 * The flush may take some period of time to make the objects available to
 	 * other threads.
 	 *
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the flush could not be completed; objects inserted thus far
 	 *             are in an indeterminate state.
 	 */
 	public abstract void flush() throws IOException;
 
 	/**
+	 * {@inheritDoc}
+	 * <p>
 	 * Release any resources used by this inserter.
 	 * <p>
 	 * An inserter that has been released can be used again, but may need to be
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectLoader.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectLoader.java
index b2cc294..2e52f03 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectLoader.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectLoader.java
@@ -61,16 +61,23 @@
  */
 public abstract class ObjectLoader {
 	/**
-	 * @return Git in pack object type, see {@link Constants}.
+	 * Get Git in pack object type
+	 *
+	 * @return Git in pack object type, see
+	 *         {@link org.eclipse.jgit.lib.Constants}.
 	 */
 	public abstract int getType();
 
 	/**
+	 * Get size of object in bytes
+	 *
 	 * @return size of object in bytes
 	 */
 	public abstract long getSize();
 
 	/**
+	 * Whether this object is too large to obtain as a byte array.
+	 *
 	 * @return true if this object is too large to obtain as a byte array.
 	 *         Objects over a certain threshold should be accessed only by their
 	 *         {@link #openStream()} to prevent overflowing the JVM heap.
@@ -91,7 +98,7 @@ public boolean isLarge() {
 	 * be modified by the caller.
 	 *
 	 * @return the bytes of this object.
-	 * @throws LargeObjectException
+	 * @throws org.eclipse.jgit.errors.LargeObjectException
 	 *             if the object won't fit into a byte array, because
 	 *             {@link #isLarge()} returns true. Callers should use
 	 *             {@link #openStream()} instead to access the contents.
@@ -113,16 +120,18 @@ public boolean isLarge() {
 	 *
 	 * @param sizeLimit
 	 *            maximum number of bytes to return. If the object is larger
-	 *            than this limit, {@link LargeObjectException} will be thrown.
+	 *            than this limit,
+	 *            {@link org.eclipse.jgit.errors.LargeObjectException} will be
+	 *            thrown.
 	 * @return the bytes of this object.
-	 * @throws LargeObjectException
+	 * @throws org.eclipse.jgit.errors.LargeObjectException
 	 *             if the object is bigger than {@code sizeLimit}, or if
-	 *             {@link OutOfMemoryError} occurs during allocation of the
-	 *             result array. Callers should use {@link #openStream()}
+	 *             {@link java.lang.OutOfMemoryError} occurs during allocation
+	 *             of the result array. Callers should use {@link #openStream()}
 	 *             instead to access the contents.
-	 * @throws MissingObjectException
+	 * @throws org.eclipse.jgit.errors.MissingObjectException
 	 *             the object is large, and it no longer exists.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the object store cannot be accessed.
 	 */
 	public final byte[] getBytes(int sizeLimit) throws LargeObjectException,
@@ -144,7 +153,7 @@ public boolean isLarge() {
 	 * Changes (if made) will affect the cache but not the repository itself.
 	 *
 	 * @return the cached bytes of this object. Do not modify it.
-	 * @throws LargeObjectException
+	 * @throws org.eclipse.jgit.errors.LargeObjectException
 	 *             if the object won't fit into a byte array, because
 	 *             {@link #isLarge()} returns true. Callers should use
 	 *             {@link #openStream()} instead to access the contents.
@@ -167,16 +176,17 @@ public boolean isLarge() {
 	 * @param sizeLimit
 	 *            maximum number of bytes to return. If the object size is
 	 *            larger than this limit and {@link #isLarge()} is true,
-	 *            {@link LargeObjectException} will be thrown.
+	 *            {@link org.eclipse.jgit.errors.LargeObjectException} will be
+	 *            thrown.
 	 * @return the cached bytes of this object. Do not modify it.
-	 * @throws LargeObjectException
+	 * @throws org.eclipse.jgit.errors.LargeObjectException
 	 *             if the object is bigger than {@code sizeLimit}, or if
-	 *             {@link OutOfMemoryError} occurs during allocation of the
-	 *             result array. Callers should use {@link #openStream()}
+	 *             {@link java.lang.OutOfMemoryError} occurs during allocation
+	 *             of the result array. Callers should use {@link #openStream()}
 	 *             instead to access the contents.
-	 * @throws MissingObjectException
+	 * @throws org.eclipse.jgit.errors.MissingObjectException
 	 *             the object is large, and it no longer exists.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the object store cannot be accessed.
 	 */
 	public byte[] getCachedBytes(int sizeLimit) throws LargeObjectException,
@@ -184,8 +194,7 @@ public boolean isLarge() {
 		if (!isLarge())
 			return getCachedBytes();
 
-		ObjectStream in = openStream();
-		try {
+		try (ObjectStream in = openStream()) {
 			long sz = in.getSize();
 			if (sizeLimit < sz)
 				throw new LargeObjectException.ExceedsLimit(sizeLimit, sz);
@@ -202,8 +211,6 @@ public boolean isLarge() {
 
 			IO.readFully(in, buf, 0, buf.length);
 			return buf;
-		} finally {
-			in.close();
 		}
 	}
 
@@ -213,9 +220,9 @@ public boolean isLarge() {
 	 * @return a stream of this object's data. Caller must close the stream when
 	 *         through with it. The returned stream is buffered with a
 	 *         reasonable buffer size.
-	 * @throws MissingObjectException
+	 * @throws org.eclipse.jgit.errors.MissingObjectException
 	 *             the object no longer exists.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the object store cannot be accessed.
 	 */
 	public abstract ObjectStream openStream() throws MissingObjectException,
@@ -236,17 +243,16 @@ public abstract ObjectStream openStream() throws MissingObjectException,
 	 *            stream to receive the complete copy of this object's data.
 	 *            Caller is responsible for flushing or closing this stream
 	 *            after this method returns.
-	 * @throws MissingObjectException
+	 * @throws org.eclipse.jgit.errors.MissingObjectException
 	 *             the object no longer exists.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the object store cannot be accessed, or the stream cannot be
 	 *             written to.
 	 */
 	public void copyTo(OutputStream out) throws MissingObjectException,
 			IOException {
 		if (isLarge()) {
-			ObjectStream in = openStream();
-			try {
+			try (ObjectStream in = openStream()) {
 				final long sz = in.getSize();
 				byte[] tmp = new byte[8192];
 				long copied = 0;
@@ -259,15 +265,13 @@ public void copyTo(OutputStream out) throws MissingObjectException,
 				}
 				if (0 <= in.read())
 					throw new EOFException();
-			} finally {
-				in.close();
 			}
 		} else {
 			out.write(getCachedBytes());
 		}
 	}
 
-	private static byte[] cloneArray(final byte[] data) {
+	private static byte[] cloneArray(byte[] data) {
 		final byte[] copy = new byte[data.length];
 		System.arraycopy(data, 0, copy, 0, data.length);
 		return copy;
@@ -323,4 +327,42 @@ public ObjectStream openStream() {
 			return new ObjectStream.SmallStream(this);
 		}
 	}
+
+	/**
+	 * Wraps a delegate ObjectLoader.
+	 *
+	 * @since 4.10
+	 */
+	public static abstract class Filter extends ObjectLoader {
+		/**
+		 * @return delegate ObjectLoader to handle all processing.
+		 * @since 4.10
+		 */
+		protected abstract ObjectLoader delegate();
+
+		@Override
+		public int getType() {
+			return delegate().getType();
+		}
+
+		@Override
+		public long getSize() {
+			return delegate().getSize();
+		}
+
+		@Override
+		public boolean isLarge() {
+			return delegate().isLarge();
+		}
+
+		@Override
+		public byte[] getCachedBytes() {
+			return delegate().getCachedBytes();
+		}
+
+		@Override
+		public ObjectStream openStream() throws IOException {
+			return delegate().openStream();
+		}
+	}
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectReader.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectReader.java
index f39f291..700b9db 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectReader.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectReader.java
@@ -53,13 +53,13 @@
 import org.eclipse.jgit.annotations.Nullable;
 import org.eclipse.jgit.errors.IncorrectObjectTypeException;
 import org.eclipse.jgit.errors.MissingObjectException;
-import org.eclipse.jgit.internal.storage.pack.ObjectReuseAsIs;
 
 /**
- * Reads an {@link ObjectDatabase} for a single thread.
+ * Reads an {@link org.eclipse.jgit.lib.ObjectDatabase} for a single thread.
  * <p>
  * Readers that can support efficient reuse of pack encoded objects should also
- * implement the companion interface {@link ObjectReuseAsIs}.
+ * implement the companion interface
+ * {@link org.eclipse.jgit.internal.storage.pack.ObjectReuseAsIs}.
  */
 public abstract class ObjectReader implements AutoCloseable {
 	/** Type hint indicating the caller doesn't know the type. */
@@ -95,7 +95,7 @@ public abstract class ObjectReader implements AutoCloseable {
 	 * @param objectId
 	 *            object identity that needs to be abbreviated.
 	 * @return SHA-1 abbreviation.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the object store cannot be read.
 	 */
 	public AbbreviatedObjectId abbreviate(AnyObjectId objectId)
@@ -122,7 +122,7 @@ public AbbreviatedObjectId abbreviate(AnyObjectId objectId)
 	 *            [2, {@value Constants#OBJECT_ID_STRING_LENGTH}].
 	 * @return SHA-1 abbreviation. If no matching objects exist in the
 	 *         repository, the abbreviation will match the minimum length.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the object store cannot be read.
 	 */
 	public AbbreviatedObjectId abbreviate(AnyObjectId objectId, int len)
@@ -174,7 +174,7 @@ public AbbreviatedObjectId abbreviate(AnyObjectId objectId, int len)
 	 *            abbreviated id to resolve to a complete identity. The
 	 *            abbreviation must have a length of at least 2.
 	 * @return candidates that begin with the abbreviated identity.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the object store cannot be read.
 	 */
 	public abstract Collection<ObjectId> resolve(AbbreviatedObjectId id)
@@ -186,7 +186,7 @@ public abstract Collection<ObjectId> resolve(AbbreviatedObjectId id)
 	 * @param objectId
 	 *            identity of the object to test for existence of.
 	 * @return true if the specified object is stored in this database.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the object store cannot be accessed.
 	 */
 	public boolean has(AnyObjectId objectId) throws IOException {
@@ -200,13 +200,14 @@ public boolean has(AnyObjectId objectId) throws IOException {
 	 *            identity of the object to test for existence of.
 	 * @param typeHint
 	 *            hint about the type of object being requested, e.g.
-	 *            {@link Constants#OBJ_BLOB}; {@link #OBJ_ANY} if the object
-	 *            type is not known, or does not matter to the caller.
+	 *            {@link org.eclipse.jgit.lib.Constants#OBJ_BLOB};
+	 *            {@link #OBJ_ANY} if the object type is not known, or does not
+	 *            matter to the caller.
 	 * @return true if the specified object is stored in this database.
 	 * @throws IncorrectObjectTypeException
 	 *             typeHint was not OBJ_ANY, and the object's actual type does
 	 *             not match typeHint.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the object store cannot be accessed.
 	 */
 	public boolean has(AnyObjectId objectId, int typeHint) throws IOException {
@@ -223,10 +224,11 @@ public boolean has(AnyObjectId objectId, int typeHint) throws IOException {
 	 *
 	 * @param objectId
 	 *            identity of the object to open.
-	 * @return a {@link ObjectLoader} for accessing the object.
-	 * @throws MissingObjectException
+	 * @return a {@link org.eclipse.jgit.lib.ObjectLoader} for accessing the
+	 *         object.
+	 * @throws org.eclipse.jgit.errors.MissingObjectException
 	 *             the object does not exist.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the object store cannot be accessed.
 	 */
 	public ObjectLoader open(AnyObjectId objectId)
@@ -241,15 +243,17 @@ public ObjectLoader open(AnyObjectId objectId)
 	 *            identity of the object to open.
 	 * @param typeHint
 	 *            hint about the type of object being requested, e.g.
-	 *            {@link Constants#OBJ_BLOB}; {@link #OBJ_ANY} if the object
-	 *            type is not known, or does not matter to the caller.
-	 * @return a {@link ObjectLoader} for accessing the object.
-	 * @throws MissingObjectException
+	 *            {@link org.eclipse.jgit.lib.Constants#OBJ_BLOB};
+	 *            {@link #OBJ_ANY} if the object type is not known, or does not
+	 *            matter to the caller.
+	 * @return a {@link org.eclipse.jgit.lib.ObjectLoader} for accessing the
+	 *         object.
+	 * @throws org.eclipse.jgit.errors.MissingObjectException
 	 *             the object does not exist.
-	 * @throws IncorrectObjectTypeException
+	 * @throws org.eclipse.jgit.errors.IncorrectObjectTypeException
 	 *             typeHint was not OBJ_ANY, and the object's actual type does
 	 *             not match typeHint.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the object store cannot be accessed.
 	 */
 	public abstract ObjectLoader open(AnyObjectId objectId, int typeHint)
@@ -260,15 +264,13 @@ public abstract ObjectLoader open(AnyObjectId objectId, int typeHint)
 	 * Returns IDs for those commits which should be considered as shallow.
 	 *
 	 * @return IDs of shallow commits
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 */
 	public abstract Set<ObjectId> getShallowCommits() throws IOException;
 
 	/**
 	 * Asynchronous object opening.
 	 *
-	 * @param <T>
-	 *            type of identifier being supplied.
 	 * @param objectIds
 	 *            objects to open from the object store. The supplied collection
 	 *            must not be modified until the queue has finished.
@@ -335,15 +337,16 @@ public void release() {
 	 *            identity of the object to open.
 	 * @param typeHint
 	 *            hint about the type of object being requested, e.g.
-	 *            {@link Constants#OBJ_BLOB}; {@link #OBJ_ANY} if the object
-	 *            type is not known, or does not matter to the caller.
+	 *            {@link org.eclipse.jgit.lib.Constants#OBJ_BLOB};
+	 *            {@link #OBJ_ANY} if the object type is not known, or does not
+	 *            matter to the caller.
 	 * @return size of object in bytes.
-	 * @throws MissingObjectException
+	 * @throws org.eclipse.jgit.errors.MissingObjectException
 	 *             the object does not exist.
-	 * @throws IncorrectObjectTypeException
+	 * @throws org.eclipse.jgit.errors.IncorrectObjectTypeException
 	 *             typeHint was not OBJ_ANY, and the object's actual type does
 	 *             not match typeHint.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the object store cannot be accessed.
 	 */
 	public long getObjectSize(AnyObjectId objectId, int typeHint)
@@ -355,8 +358,6 @@ public long getObjectSize(AnyObjectId objectId, int typeHint)
 	/**
 	 * Asynchronous object size lookup.
 	 *
-	 * @param <T>
-	 *            type of identifier being supplied.
 	 * @param objectIds
 	 *            objects to get the size of from the object store. The supplied
 	 *            collection must not be modified until the queue has finished.
@@ -433,7 +434,7 @@ public void setAvoidUnreachableObjects(boolean avoid) {
 	 * An index that can be used to speed up ObjectWalks.
 	 *
 	 * @return the index or null if one does not exist.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             when the index fails to load
 	 * @since 3.0
 	 */
@@ -442,9 +443,12 @@ public BitmapIndex getBitmapIndex() throws IOException {
 	}
 
 	/**
-	 * @return the {@link ObjectInserter} from which this reader was created
-	 *         using {@code inserter.newReader()}, or null if this reader was not
-	 *         created from an inserter.
+	 * Get the {@link org.eclipse.jgit.lib.ObjectInserter} from which this
+	 * reader was created using {@code inserter.newReader()}
+	 *
+	 * @return the {@link org.eclipse.jgit.lib.ObjectInserter} from which this
+	 *         reader was created using {@code inserter.newReader()}, or null if
+	 *         this reader was not created from an inserter.
 	 * @since 4.4
 	 */
 	@Nullable
@@ -453,6 +457,8 @@ public ObjectInserter getCreatedFromInserter() {
 	}
 
 	/**
+	 * {@inheritDoc}
+	 * <p>
 	 * Release any resources used by this reader.
 	 * <p>
 	 * A reader that has been released can be used again, but may need to be
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectStream.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectStream.java
index 4b3fe6a..ad123c4 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectStream.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectStream.java
@@ -46,12 +46,22 @@
 import java.io.IOException;
 import java.io.InputStream;
 
-/** Stream of data coming from an object loaded by {@link ObjectLoader}. */
+/**
+ * Stream of data coming from an object loaded by {@link org.eclipse.jgit.lib.ObjectLoader}.
+ */
 public abstract class ObjectStream extends InputStream {
-	/** @return Git object type, see {@link Constants}. */
+	/**
+	 * Get Git object type, see {@link Constants}.
+	 *
+	 * @return Git object type, see {@link Constants}.
+	 */
 	public abstract int getType();
 
-	/** @return total size of object in bytes */
+	/**
+	 * Get total size of object in bytes
+	 *
+	 * @return total size of object in bytes
+	 */
 	public abstract long getSize();
 
 	/**
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/PersonIdent.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/PersonIdent.java
index 45757e4..c16a2b6 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/PersonIdent.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/PersonIdent.java
@@ -65,6 +65,8 @@ public class PersonIdent implements Serializable {
 	private static final long serialVersionUID = 1L;
 
 	/**
+	 * Get timezone object for the given offset.
+	 *
 	 * @param tzOffset
 	 *            timezone offset as in {@link #getTimeZoneOffset()}.
 	 * @return time zone object for the given offset.
@@ -163,38 +165,45 @@ public static void appendSanitized(StringBuilder r, String str) {
 	 * This new PersonIdent gets the info from the default committer as available
 	 * from the configuration.
 	 *
-	 * @param repo
+	 * @param repo a {@link org.eclipse.jgit.lib.Repository} object.
 	 */
-	public PersonIdent(final Repository repo) {
+	public PersonIdent(Repository repo) {
 		this(repo.getConfig().get(UserConfig.KEY));
 	}
 
 	/**
-	 * Copy a {@link PersonIdent}.
+	 * Copy a {@link org.eclipse.jgit.lib.PersonIdent}.
 	 *
 	 * @param pi
-	 *            Original {@link PersonIdent}
+	 *            Original {@link org.eclipse.jgit.lib.PersonIdent}
 	 */
-	public PersonIdent(final PersonIdent pi) {
+	public PersonIdent(PersonIdent pi) {
 		this(pi.getName(), pi.getEmailAddress());
 	}
 
 	/**
-	 * Construct a new {@link PersonIdent} with current time.
+	 * Construct a new {@link org.eclipse.jgit.lib.PersonIdent} with current
+	 * time.
 	 *
 	 * @param aName
+	 *            a {@link java.lang.String} object.
 	 * @param aEmailAddress
+	 *            a {@link java.lang.String} object.
 	 */
-	public PersonIdent(final String aName, final String aEmailAddress) {
+	public PersonIdent(String aName, String aEmailAddress) {
 		this(aName, aEmailAddress, SystemReader.getInstance().getCurrentTime());
 	}
 
 	/**
-	 * Construct a new {@link PersonIdent} with current time.
+	 * Construct a new {@link org.eclipse.jgit.lib.PersonIdent} with current
+	 * time.
 	 *
 	 * @param aName
+	 *            a {@link java.lang.String} object.
 	 * @param aEmailAddress
+	 *            a {@link java.lang.String} object.
 	 * @param when
+	 *            a {@link org.eclipse.jgit.util.time.ProposedTimestamp} object.
 	 * @since 4.6
 	 */
 	public PersonIdent(String aName, String aEmailAddress,
@@ -206,33 +215,34 @@ public PersonIdent(String aName, String aEmailAddress,
 	 * Copy a PersonIdent, but alter the clone's time stamp
 	 *
 	 * @param pi
-	 *            original {@link PersonIdent}
+	 *            original {@link org.eclipse.jgit.lib.PersonIdent}
 	 * @param when
 	 *            local time
 	 * @param tz
 	 *            time zone
 	 */
-	public PersonIdent(final PersonIdent pi, final Date when, final TimeZone tz) {
+	public PersonIdent(PersonIdent pi, Date when, TimeZone tz) {
 		this(pi.getName(), pi.getEmailAddress(), when, tz);
 	}
 
 	/**
-	 * Copy a {@link PersonIdent}, but alter the clone's time stamp
+	 * Copy a {@link org.eclipse.jgit.lib.PersonIdent}, but alter the clone's
+	 * time stamp
 	 *
 	 * @param pi
-	 *            original {@link PersonIdent}
+	 *            original {@link org.eclipse.jgit.lib.PersonIdent}
 	 * @param aWhen
 	 *            local time
 	 */
-	public PersonIdent(final PersonIdent pi, final Date aWhen) {
+	public PersonIdent(PersonIdent pi, Date aWhen) {
 		this(pi.getName(), pi.getEmailAddress(), aWhen.getTime(), pi.tzOffset);
 	}
 
 	/**
 	 * Construct a PersonIdent from simple data
 	 *
-	 * @param aName
-	 * @param aEmailAddress
+	 * @param aName a {@link java.lang.String} object.
+	 * @param aEmailAddress a {@link java.lang.String} object.
 	 * @param aWhen
 	 *            local time stamp
 	 * @param aTZ
@@ -248,13 +258,13 @@ public PersonIdent(final String aName, final String aEmailAddress,
 	 * Copy a PersonIdent, but alter the clone's time stamp
 	 *
 	 * @param pi
-	 *            original {@link PersonIdent}
+	 *            original {@link org.eclipse.jgit.lib.PersonIdent}
 	 * @param aWhen
 	 *            local time stamp
 	 * @param aTZ
 	 *            time zone
 	 */
-	public PersonIdent(final PersonIdent pi, final long aWhen, final int aTZ) {
+	public PersonIdent(PersonIdent pi, long aWhen, int aTZ) {
 		this(pi.getName(), pi.getEmailAddress(), aWhen, aTZ);
 	}
 
@@ -264,12 +274,12 @@ private PersonIdent(final String aName, final String aEmailAddress,
 				.getTimezone(when));
 	}
 
-	private PersonIdent(final UserConfig config) {
+	private PersonIdent(UserConfig config) {
 		this(config.getCommitterName(), config.getCommitterEmail());
 	}
 
 	/**
-	 * Construct a {@link PersonIdent}.
+	 * Construct a {@link org.eclipse.jgit.lib.PersonIdent}.
 	 * <p>
 	 * Whitespace in the name and email is preserved for the lifetime of this
 	 * object, but are trimmed by {@link #toExternalString()}. This means that
@@ -277,7 +287,9 @@ private PersonIdent(final UserConfig config) {
 	 * equivalent instance.
 	 *
 	 * @param aName
+	 *            a {@link java.lang.String} object.
 	 * @param aEmailAddress
+	 *            a {@link java.lang.String} object.
 	 * @param aWhen
 	 *            local time stamp
 	 * @param aTZ
@@ -298,6 +310,8 @@ public PersonIdent(final String aName, final String aEmailAddress,
 	}
 
 	/**
+	 * Get name of person
+	 *
 	 * @return Name of person
 	 */
 	public String getName() {
@@ -305,6 +319,8 @@ public String getName() {
 	}
 
 	/**
+	 * Get email address of person
+	 *
 	 * @return email address of person
 	 */
 	public String getEmailAddress() {
@@ -312,6 +328,8 @@ public String getEmailAddress() {
 	}
 
 	/**
+	 * Get timestamp
+	 *
 	 * @return timestamp
 	 */
 	public Date getWhen() {
@@ -319,6 +337,8 @@ public Date getWhen() {
 	}
 
 	/**
+	 * Get this person's declared time zone
+	 *
 	 * @return this person's declared time zone; null if time zone is unknown.
 	 */
 	public TimeZone getTimeZone() {
@@ -326,6 +346,8 @@ public TimeZone getTimeZone() {
 	}
 
 	/**
+	 * Get this person's declared time zone as minutes east of UTC.
+	 *
 	 * @return this person's declared time zone as minutes east of UTC. If the
 	 *         timezone is to the west of UTC it is negative.
 	 */
@@ -334,6 +356,8 @@ public int getTimeZoneOffset() {
 	}
 
 	/**
+	 * {@inheritDoc}
+	 * <p>
 	 * Hashcode is based only on the email address and timestamp.
 	 */
 	@Override
@@ -344,8 +368,9 @@ public int hashCode() {
 		return hc;
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	public boolean equals(final Object o) {
+	public boolean equals(Object o) {
 		if (o instanceof PersonIdent) {
 			final PersonIdent p = (PersonIdent) o;
 			return getName().equals(p.getName())
@@ -372,6 +397,7 @@ public String toExternalString() {
 		return r.toString();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	@SuppressWarnings("nls")
 	public String toString() {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ProgressMonitor.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ProgressMonitor.java
index 7748140..d81ee45 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ProgressMonitor.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ProgressMonitor.java
@@ -44,7 +44,9 @@
 
 package org.eclipse.jgit.lib;
 
-/** A progress reporting interface. */
+/**
+ * A progress reporting interface.
+ */
 public interface ProgressMonitor {
 	/** Constant indicating the total work units cannot be predicted. */
 	public static final int UNKNOWN = 0;
@@ -85,7 +87,9 @@ public interface ProgressMonitor {
 	 */
 	void update(int completed);
 
-	/** Finish the current task, so the next can begin. */
+	/**
+	 * Finish the current task, so the next can begin.
+	 */
 	void endTask();
 
 	/**
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/RebaseTodoFile.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/RebaseTodoFile.java
index c4923a3..3871605 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/RebaseTodoFile.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/RebaseTodoFile.java
@@ -43,7 +43,7 @@
 
 package org.eclipse.jgit.lib;
 
-import static java.nio.charset.StandardCharsets.UTF_8;
+import static org.eclipse.jgit.lib.Constants.CHARSET;
 
 import java.io.BufferedOutputStream;
 import java.io.File;
@@ -67,7 +67,10 @@ public class RebaseTodoFile {
 	private Repository repo;
 
 	/**
+	 * Constructor for RebaseTodoFile.
+	 *
 	 * @param repo
+	 *            a {@link org.eclipse.jgit.lib.Repository} object.
 	 */
 	public RebaseTodoFile(Repository repo) {
 		this.repo = repo;
@@ -84,7 +87,7 @@ public RebaseTodoFile(Repository repo) {
 	 * @param includeComments
 	 *            <code>true</code> if also comments should be reported
 	 * @return the list of steps
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 */
 	public List<RebaseTodoLine> readRebaseTodo(String path,
 			boolean includeComments) throws IOException {
@@ -180,7 +183,7 @@ private static RebaseTodoLine parseLine(byte[] buf, int tokenBegin,
 			switch (tokenCount) {
 			case 0:
 				String actionToken = new String(buf, tokenBegin,
-						nextSpace - tokenBegin - 1, UTF_8);
+						nextSpace - tokenBegin - 1, CHARSET);
 				tokenBegin = nextSpace;
 				action = RebaseTodoLine.Action.parse(actionToken);
 				if (action == null)
@@ -189,7 +192,7 @@ private static RebaseTodoLine parseLine(byte[] buf, int tokenBegin,
 			case 1:
 				nextSpace = RawParseUtils.next(buf, tokenBegin, ' ');
 				String commitToken = new String(buf, tokenBegin,
-						nextSpace - tokenBegin - 1, UTF_8);
+						nextSpace - tokenBegin - 1, CHARSET);
 				tokenBegin = nextSpace;
 				commit = AbbreviatedObjectId.fromString(commitToken);
 				break;
@@ -214,7 +217,7 @@ private static RebaseTodoLine parseLine(byte[] buf, int tokenBegin,
 	 *            the steps to be written
 	 * @param append
 	 *            whether to append to an existing file or to write a new file
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 */
 	public void writeRebaseTodoFile(String path, List<RebaseTodoLine> steps,
 			boolean append) throws IOException {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/RebaseTodoLine.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/RebaseTodoLine.java
index 9af8d76..4e235b0 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/RebaseTodoLine.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/RebaseTodoLine.java
@@ -142,8 +142,11 @@ public RebaseTodoLine(String newComment) {
 	 * Create a new non-comment line
 	 *
 	 * @param action
+	 *            a {@link org.eclipse.jgit.lib.RebaseTodoLine.Action} object.
 	 * @param commit
+	 *            a {@link org.eclipse.jgit.lib.AbbreviatedObjectId} object.
 	 * @param shortMessage
+	 *            a {@link java.lang.String} object.
 	 */
 	public RebaseTodoLine(Action action, AbbreviatedObjectId commit,
 			String shortMessage) {
@@ -154,6 +157,8 @@ public RebaseTodoLine(Action action, AbbreviatedObjectId commit,
 	}
 
 	/**
+	 * Get rebase action type
+	 *
 	 * @return rebase action type
 	 */
 	public Action getAction() {
@@ -167,7 +172,8 @@ public Action getAction() {
 	 * non-comment.
 	 *
 	 * @param newAction
-	 * @throws IllegalTodoFileModification
+	 *            a {@link org.eclipse.jgit.lib.RebaseTodoLine.Action} object.
+	 * @throws org.eclipse.jgit.errors.IllegalTodoFileModification
 	 *             on attempt to set a non-comment action on a line which was a
 	 *             comment line before.
 	 */
@@ -193,7 +199,7 @@ public void setAction(Action newAction) throws IllegalTodoFileModification {
 	/**
 	 * <p>
 	 * Set a comment for this line that is used if this line's
-	 * {@link RebaseTodoLine#action} is a {@link Action#COMMENT}
+	 * {@link org.eclipse.jgit.lib.RebaseTodoLine#action} is a {@link org.eclipse.jgit.lib.RebaseTodoLine.Action#COMMENT}
 	 * </p>
 	 * It's allowed to unset the comment by calling
 	 * <code>setComment(null)</code> <br>
@@ -230,6 +236,8 @@ private static IllegalArgumentException createInvalidCommentException(
 	}
 
 	/**
+	 * Get abbreviated commit SHA-1 of commit that action will be performed on
+	 *
 	 * @return abbreviated commit SHA-1 of commit that action will be performed
 	 *         on
 	 */
@@ -238,6 +246,9 @@ public AbbreviatedObjectId getCommit() {
 	}
 
 	/**
+	 * Get the first line of the commit message of the commit the action will be
+	 * performed on.
+	 *
 	 * @return the first line of the commit message of the commit the action
 	 *         will be performed on.
 	 */
@@ -246,13 +257,18 @@ public String getShortMessage() {
 	}
 
 	/**
+	 * Set short message
+	 *
 	 * @param shortMessage
+	 *            a short message.
 	 */
 	public void setShortMessage(String shortMessage) {
 		this.shortMessage = shortMessage;
 	}
 
 	/**
+	 * Get a comment
+	 *
 	 * @return a comment. If the line is a comment line then the comment is
 	 *         returned. Lines starting with # or blank lines or lines
 	 *         containing only spaces and tabs are considered as comment lines.
@@ -262,6 +278,7 @@ public String getComment() {
 		return comment;
 	}
 
+	/** {@inheritDoc} */
 	@SuppressWarnings("nls")
 	@Override
 	public String toString() {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Ref.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Ref.java
index a78a90f..b000558 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Ref.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Ref.java
@@ -47,7 +47,8 @@
 import org.eclipse.jgit.annotations.Nullable;
 
 /**
- * Pairing of a name and the {@link ObjectId} it currently has.
+ * Pairing of a name and the {@link org.eclipse.jgit.lib.ObjectId} it currently
+ * has.
  * <p>
  * A ref in Git is (more or less) a variable that holds a single object
  * identifier. The object identifier can be any valid Git object (blob, tree,
@@ -104,7 +105,7 @@ public static enum Storage {
 
 		private final boolean packed;
 
-		private Storage(final boolean l, final boolean p) {
+		private Storage(boolean l, boolean p) {
 			loose = l;
 			packed = p;
 		}
@@ -135,9 +136,10 @@ public boolean isPacked() {
 	/**
 	 * Test if this reference is a symbolic reference.
 	 * <p>
-	 * A symbolic reference does not have its own {@link ObjectId} value, but
-	 * instead points to another {@code Ref} in the same database and always
-	 * uses that other reference's value as its own.
+	 * A symbolic reference does not have its own
+	 * {@link org.eclipse.jgit.lib.ObjectId} value, but instead points to
+	 * another {@code Ref} in the same database and always uses that other
+	 * reference's value as its own.
 	 *
 	 * @return true if this is a symbolic reference; false if this reference
 	 *         contains its own ObjectId.
@@ -199,7 +201,9 @@ public boolean isPacked() {
 	public abstract ObjectId getPeeledObjectId();
 
 	/**
-	 * @return whether the Ref represents a peeled tag
+	 * Whether the Ref represents a peeled tag.
+	 *
+	 * @return whether the Ref represents a peeled tag.
 	 */
 	public abstract boolean isPeeled();
 
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefComparator.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefComparator.java
index 95e3386..8bcac00 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefComparator.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefComparator.java
@@ -60,8 +60,9 @@ public class RefComparator implements Comparator<Ref> {
 	/** Singleton instance of RefComparator */
 	public static final RefComparator INSTANCE = new RefComparator();
 
+	/** {@inheritDoc} */
 	@Override
-	public int compare(final Ref o1, final Ref o2) {
+	public int compare(Ref o1, Ref o2) {
 		return compareTo(o1, o2);
 	}
 
@@ -72,7 +73,7 @@ public int compare(final Ref o1, final Ref o2) {
 	 *            collection to be sorted
 	 * @return sorted collection of refs
 	 */
-	public static Collection<Ref> sort(final Collection<Ref> refs) {
+	public static Collection<Ref> sort(Collection<Ref> refs) {
 		final List<Ref> r = new ArrayList<>(refs);
 		Collections.sort(r, INSTANCE);
 		return r;
@@ -100,7 +101,7 @@ public static int compareTo(Ref o1, String o2) {
 	 *            the other reference instance.
 	 * @return standard Comparator result of &lt; 0, 0, &gt; 0.
 	 */
-	public static int compareTo(final Ref o1, final Ref o2) {
+	public static int compareTo(Ref o1, Ref o2) {
 		return o1.getName().compareTo(o2.getName());
 	}
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefDatabase.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefDatabase.java
index 59a104b..3170787 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefDatabase.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefDatabase.java
@@ -43,6 +43,8 @@
 
 package org.eclipse.jgit.lib;
 
+import static java.util.stream.Collectors.toList;
+
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Collection;
@@ -55,11 +57,13 @@
 import org.eclipse.jgit.annotations.Nullable;
 
 /**
- * Abstraction of name to {@link ObjectId} mapping.
+ * Abstraction of name to {@link org.eclipse.jgit.lib.ObjectId} mapping.
  * <p>
- * A reference database stores a mapping of reference names to {@link ObjectId}.
- * Every {@link Repository} has a single reference database, mapping names to
- * the tips of the object graph contained by the {@link ObjectDatabase}.
+ * A reference database stores a mapping of reference names to
+ * {@link org.eclipse.jgit.lib.ObjectId}. Every
+ * {@link org.eclipse.jgit.lib.Repository} has a single reference database,
+ * mapping names to the tips of the object graph contained by the
+ * {@link org.eclipse.jgit.lib.ObjectDatabase}.
  */
 public abstract class RefDatabase {
 	/**
@@ -87,18 +91,23 @@ public abstract class RefDatabase {
 	 */
 	public static final int MAX_SYMBOLIC_REF_DEPTH = 5;
 
-	/** Magic value for {@link #getRefs(String)} to return all references. */
+	/**
+	 * Magic value for {@link #getRefsByPrefix(String)} to return all
+	 * references.
+	 */
 	public static final String ALL = "";//$NON-NLS-1$
 
 	/**
 	 * Initialize a new reference database at this location.
 	 *
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the database could not be created.
 	 */
 	public abstract void create() throws IOException;
 
-	/** Close any resources held by this database. */
+	/**
+	 * Close any resources held by this database.
+	 */
 	public abstract void close();
 
 	/**
@@ -118,7 +127,7 @@ public abstract class RefDatabase {
 	 *            proposed name.
 	 * @return true if the name overlaps with an existing reference; false if
 	 *         using this name right now would be safe.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the database could not be read to check for conflicts.
 	 * @see #getConflictingNames(String)
 	 */
@@ -133,7 +142,7 @@ public abstract class RefDatabase {
 	 * @return a collection of full names of existing refs which would conflict
 	 *         with the passed ref name; empty collection when there are no
 	 *         conflicts
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 * @since 2.3
 	 * @see #isNameConflicting(String)
 	 */
@@ -167,12 +176,13 @@ public Collection<String> getConflictingNames(String name)
 	 *            the name of the reference.
 	 * @param detach
 	 *            if {@code true} and {@code name} is currently a
-	 *            {@link SymbolicRef}, the update will replace it with an
-	 *            {@link ObjectIdRef}. Otherwise, the update will recursively
-	 *            traverse {@link SymbolicRef}s and operate on the leaf
-	 *            {@link ObjectIdRef}.
+	 *            {@link org.eclipse.jgit.lib.SymbolicRef}, the update will
+	 *            replace it with an {@link org.eclipse.jgit.lib.ObjectIdRef}.
+	 *            Otherwise, the update will recursively traverse
+	 *            {@link org.eclipse.jgit.lib.SymbolicRef}s and operate on the
+	 *            leaf {@link org.eclipse.jgit.lib.ObjectIdRef}.
 	 * @return a new update for the requested name; never null.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the reference space cannot be accessed.
 	 */
 	@NonNull
@@ -187,7 +197,7 @@ public abstract RefUpdate newUpdate(String name, boolean detach)
 	 * @param toName
 	 *            name of reference to rename to
 	 * @return an update command that knows how to rename a branch to another.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the reference space cannot be accessed.
 	 */
 	@NonNull
@@ -210,20 +220,21 @@ public BatchRefUpdate newBatchUpdate() {
 	 * Whether the database is capable of performing batch updates as atomic
 	 * transactions.
 	 * <p>
-	 * If true, by default {@link BatchRefUpdate} instances will perform updates
-	 * atomically, meaning either all updates will succeed, or all updates will
-	 * fail. It is still possible to turn off this behavior on a per-batch basis
-	 * by calling {@code update.setAtomic(false)}.
+	 * If true, by default {@link org.eclipse.jgit.lib.BatchRefUpdate} instances
+	 * will perform updates atomically, meaning either all updates will succeed,
+	 * or all updates will fail. It is still possible to turn off this behavior
+	 * on a per-batch basis by calling {@code update.setAtomic(false)}.
 	 * <p>
-	 * If false, {@link BatchRefUpdate} instances will never perform updates
-	 * atomically, and calling {@code update.setAtomic(true)} will cause the
-	 * entire batch to fail with {@code REJECTED_OTHER_REASON}.
+	 * If false, {@link org.eclipse.jgit.lib.BatchRefUpdate} instances will
+	 * never perform updates atomically, and calling
+	 * {@code update.setAtomic(true)} will cause the entire batch to fail with
+	 * {@code REJECTED_OTHER_REASON}.
 	 * <p>
 	 * This definition of atomicity is stronger than what is provided by
 	 * {@link org.eclipse.jgit.transport.ReceivePack}. {@code ReceivePack} will
 	 * attempt to reject all commands if it knows in advance some commands may
-	 * fail, even if the storage layer does not support atomic transactions. Here,
-	 * atomicity applies even in the case of unforeseeable errors.
+	 * fail, even if the storage layer does not support atomic transactions.
+	 * Here, atomicity applies even in the case of unforeseeable errors.
 	 *
 	 * @return whether transactions are atomic by default.
 	 * @since 3.6
@@ -246,7 +257,7 @@ public boolean performsAtomicTransactions() {
 	 *            the name of the reference. May be a short name which must be
 	 *            searched for using the standard {@link #SEARCH_PATH}.
 	 * @return the reference (if it exists); else {@code null}.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the reference space cannot be accessed.
 	 */
 	@Nullable
@@ -261,7 +272,7 @@ public boolean performsAtomicTransactions() {
 	 * @param name
 	 *             the unabbreviated name of the reference.
 	 * @return the reference (if it exists); else {@code null}.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the reference space cannot be accessed.
 	 * @since 4.1
 	 */
@@ -285,7 +296,7 @@ public Ref exactRef(String name) throws IOException {
 	 *             the unabbreviated names of references to look up.
 	 * @return modifiable map describing any refs that exist among the ref
 	 *         ref names supplied. The map can be an unsorted map.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the reference space cannot be accessed.
 	 * @since 4.1
 	 */
@@ -310,7 +321,7 @@ public Map<String, Ref> exactRef(String... refs) throws IOException {
 	 * @param refs
 	 *             the unabbreviated names of references to look up.
 	 * @return the first named reference that exists (if any); else {@code null}.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the reference space cannot be accessed.
 	 * @since 4.1
 	 */
@@ -326,6 +337,29 @@ public Ref firstExactRef(String... refs) throws IOException {
 	}
 
 	/**
+	 * Returns all refs.
+	 * <p>
+	 * This includes {@code HEAD}, branches under {@code ref/heads/}, tags
+	 * under {@code refs/tags/}, etc. It does not include pseudo-refs like
+	 * {@code FETCH_HEAD}; for those, see {@link #getAdditionalRefs}.
+	 * <p>
+	 * Symbolic references to a non-existent ref (for example,
+	 * {@code HEAD} pointing to a branch yet to be born) are not included.
+	 * <p>
+	 * Callers interested in only a portion of the ref hierarchy can call
+	 * {@link #getRefsByPrefix} instead.
+	 *
+	 * @return immutable list of all refs.
+	 * @throws java.io.IOException
+	 *             the reference space cannot be accessed.
+	 * @since 5.0
+	 */
+	@NonNull
+	public List<Ref> getRefs() throws IOException {
+		return getRefsByPrefix(ALL);
+	}
+
+	/**
 	 * Get a section of the reference namespace.
 	 *
 	 * @param prefix
@@ -335,22 +369,79 @@ public Ref firstExactRef(String... refs) throws IOException {
 	 * @return modifiable map that is a complete snapshot of the current
 	 *         reference namespace, with {@code prefix} removed from the start
 	 *         of each key. The map can be an unsorted map.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the reference space cannot be accessed.
+	 * @deprecated use {@link #getRefsByPrefix} instead
 	 */
 	@NonNull
+	@Deprecated
 	public abstract Map<String, Ref> getRefs(String prefix) throws IOException;
 
 	/**
+	 * Returns refs whose names start with a given prefix.
+	 * <p>
+	 * The default implementation uses {@link #getRefs(String)}. Implementors of
+	 * {@link RefDatabase} should override this method directly if a better
+	 * implementation is possible.
+	 *
+	 * @param prefix string that names of refs should start with; may be
+	 *             empty (to return all refs).
+	 * @return immutable list of refs whose names start with {@code prefix}.
+	 * @throws java.io.IOException
+	 *             the reference space cannot be accessed.
+	 * @since 5.0
+	 */
+	@NonNull
+	public List<Ref> getRefsByPrefix(String prefix) throws IOException {
+		Map<String, Ref> coarseRefs;
+		int lastSlash = prefix.lastIndexOf('/');
+		if (lastSlash == -1) {
+			coarseRefs = getRefs(ALL);
+		} else {
+			coarseRefs = getRefs(prefix.substring(0, lastSlash + 1));
+		}
+
+		List<Ref> result;
+		if (lastSlash + 1 == prefix.length()) {
+			result = coarseRefs.values().stream().collect(toList());
+		} else {
+			String p = prefix.substring(lastSlash + 1);
+			result = coarseRefs.entrySet().stream()
+					.filter(e -> e.getKey().startsWith(p))
+					.map(e -> e.getValue())
+					.collect(toList());
+		}
+		return Collections.unmodifiableList(result);
+	}
+
+	/**
+	 * Check if any refs exist in the ref database.
+	 * <p>
+	 * This uses the same definition of refs as {@link #getRefs()}. In
+	 * particular, returns {@code false} in a new repository with no refs
+	 * under {@code refs/} and {@code HEAD} pointing to a branch yet to be
+	 * born, and returns {@code true} in a repository with no refs under
+	 * {@code refs/} and a detached {@code HEAD} pointing to history.
+	 *
+	 * @return true if the database has refs.
+	 * @throws java.io.IOException
+	 *             the reference space cannot be accessed.
+	 * @since 5.0
+	 */
+	public boolean hasRefs() throws IOException {
+		return !getRefs().isEmpty();
+	}
+
+	/**
 	 * Get the additional reference-like entities from the repository.
 	 * <p>
 	 * The result list includes non-ref items such as MERGE_HEAD and
 	 * FETCH_RESULT cast to be refs. The names of these refs are not returned by
-	 * <code>getRefs(ALL)</code> but are accepted by {@link #getRef(String)}
+	 * <code>getRefs()</code> but are accepted by {@link #getRef(String)}
 	 * and {@link #exactRef(String)}.
 	 *
 	 * @return a list of additional refs
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the reference space cannot be accessed.
 	 */
 	@NonNull
@@ -360,10 +451,11 @@ public Ref firstExactRef(String... refs) throws IOException {
 	 * Peel a possibly unpeeled reference by traversing the annotated tags.
 	 * <p>
 	 * If the reference cannot be peeled (as it does not refer to an annotated
-	 * tag) the peeled id stays null, but {@link Ref#isPeeled()} will be true.
+	 * tag) the peeled id stays null, but
+	 * {@link org.eclipse.jgit.lib.Ref#isPeeled()} will be true.
 	 * <p>
-	 * Implementors should check {@link Ref#isPeeled()} before performing any
-	 * additional work effort.
+	 * Implementors should check {@link org.eclipse.jgit.lib.Ref#isPeeled()}
+	 * before performing any additional work effort.
 	 *
 	 * @param ref
 	 *            The reference to peel
@@ -371,7 +463,7 @@ public Ref firstExactRef(String... refs) throws IOException {
 	 *         Ref object representing the same data as Ref, but isPeeled() will
 	 *         be true and getPeeledObjectId() will contain the peeled object
 	 *         (or {@code null}).
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the reference space or object space cannot be accessed.
 	 */
 	@NonNull
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefRename.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefRename.java
index 59f852b..a05daa0 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefRename.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefRename.java
@@ -73,7 +73,7 @@ public abstract class RefRename {
 	 * @param dst
 	 *            operation to create (or overwrite) the destination.
 	 */
-	protected RefRename(final RefUpdate src, final RefUpdate dst) {
+	protected RefRename(RefUpdate src, RefUpdate dst) {
 		source = src;
 		destination = dst;
 
@@ -86,7 +86,11 @@ protected RefRename(final RefUpdate src, final RefUpdate dst) {
 				+ Repository.shortenRefName(destination.getName()));
 	}
 
-	/** @return identity of the user making the change in the reflog. */
+	/**
+	 * Get identity of the user making the change in the reflog.
+	 *
+	 * @return identity of the user making the change in the reflog.
+	 */
 	public PersonIdent getRefLogIdent() {
 		return destination.getRefLogIdent();
 	}
@@ -103,7 +107,7 @@ public PersonIdent getRefLogIdent() {
 	 *            automatically determined based on the repository
 	 *            configuration.
 	 */
-	public void setRefLogIdent(final PersonIdent pi) {
+	public void setRefLogIdent(PersonIdent pi) {
 		destination.setRefLogIdent(pi);
 	}
 
@@ -123,19 +127,23 @@ public String getRefLogMessage() {
 	 * @param msg
 	 *            the message to describe this change.
 	 */
-	public void setRefLogMessage(final String msg) {
+	public void setRefLogMessage(String msg) {
 		if (msg == null)
 			disableRefLog();
 		else
 			destination.setRefLogMessage(msg, false);
 	}
 
-	/** Don't record this rename in the ref's associated reflog. */
+	/**
+	 * Don't record this rename in the ref's associated reflog.
+	 */
 	public void disableRefLog() {
 		destination.setRefLogMessage("", false); //$NON-NLS-1$
 	}
 
 	/**
+	 * Get result of rename operation
+	 *
 	 * @return result of rename operation
 	 */
 	public Result getResult() {
@@ -143,8 +151,10 @@ public Result getResult() {
 	}
 
 	/**
+	 * Rename
+	 *
 	 * @return the result of the new ref update
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 */
 	public Result rename() throws IOException {
 		try {
@@ -157,15 +167,20 @@ public Result rename() throws IOException {
 	}
 
 	/**
+	 * Do the actual rename
+	 *
 	 * @return the result of the rename operation.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 */
 	protected abstract Result doRename() throws IOException;
 
 	/**
+	 * Whether the {@code Constants#HEAD} reference needs to be linked to the
+	 * new destination name.
+	 *
 	 * @return true if the {@code Constants#HEAD} reference needs to be linked
 	 *         to the new destination name.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the current value of {@code HEAD} cannot be read.
 	 */
 	protected boolean needToUpdateHEAD() throws IOException {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefUpdate.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefUpdate.java
index 766b21d..5cd593e 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefUpdate.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefUpdate.java
@@ -227,16 +227,24 @@ public static enum Result {
 	 * @param ref
 	 *            the reference that will be updated by this operation.
 	 */
-	protected RefUpdate(final Ref ref) {
+	protected RefUpdate(Ref ref) {
 		this.ref = ref;
 		oldValue = ref.getObjectId();
 		refLogMessage = ""; //$NON-NLS-1$
 	}
 
-	/** @return the reference database this update modifies. */
+	/**
+	 * Get the reference database this update modifies.
+	 *
+	 * @return the reference database this update modifies.
+	 */
 	protected abstract RefDatabase getRefDatabase();
 
-	/** @return the repository storing the database's objects. */
+	/**
+	 * Get the repository storing the database's objects.
+	 *
+	 * @return the repository storing the database's objects.
+	 */
 	protected abstract Repository getRepository();
 
 	/**
@@ -251,33 +259,44 @@ protected RefUpdate(final Ref ref) {
 	 *            current reference.
 	 * @return true if the lock was acquired and the reference is likely
 	 *         protected from concurrent modification; false if it failed.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the lock couldn't be taken due to an unexpected storage
 	 *             failure, and not because of a concurrent update.
 	 */
 	protected abstract boolean tryLock(boolean deref) throws IOException;
 
-	/** Releases the lock taken by {@link #tryLock} if it succeeded. */
+	/**
+	 * Releases the lock taken by {@link #tryLock} if it succeeded.
+	 */
 	protected abstract void unlock();
 
 	/**
+	 * Do update
+	 *
 	 * @param desiredResult
+	 *            a {@link org.eclipse.jgit.lib.RefUpdate.Result} object.
 	 * @return {@code result}
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 */
 	protected abstract Result doUpdate(Result desiredResult) throws IOException;
 
 	/**
+	 * Do delete
+	 *
 	 * @param desiredResult
+	 *            a {@link org.eclipse.jgit.lib.RefUpdate.Result} object.
 	 * @return {@code result}
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 */
 	protected abstract Result doDelete(Result desiredResult) throws IOException;
 
 	/**
+	 * Do link
+	 *
 	 * @param target
-	 * @return {@link Result#NEW} on success.
-	 * @throws IOException
+	 *            a {@link java.lang.String} object.
+	 * @return {@link org.eclipse.jgit.lib.RefUpdate.Result#NEW} on success.
+	 * @throws java.io.IOException
 	 */
 	protected abstract Result doLink(String target) throws IOException;
 
@@ -290,7 +309,11 @@ public String getName() {
 		return getRef().getName();
 	}
 
-	/** @return the reference this update will create or modify. */
+	/**
+	 * Get the reference this update will create or modify.
+	 *
+	 * @return the reference this update will create or modify.
+	 */
 	public Ref getRef() {
 		return ref;
 	}
@@ -327,28 +350,34 @@ public boolean isDetachingSymbolicRef() {
 	 * @param id
 	 *            the new value.
 	 */
-	public void setNewObjectId(final AnyObjectId id) {
+	public void setNewObjectId(AnyObjectId id) {
 		newValue = id.copy();
 	}
 
 	/**
+	 * Get the expected value of the ref after the lock is taken, but before
+	 * update occurs.
+	 *
 	 * @return the expected value of the ref after the lock is taken, but before
 	 *         update occurs. Null to avoid the compare and swap test. Use
-	 *         {@link ObjectId#zeroId()} to indicate expectation of a
-	 *         non-existant ref.
+	 *         {@link org.eclipse.jgit.lib.ObjectId#zeroId()} to indicate
+	 *         expectation of a non-existant ref.
 	 */
 	public ObjectId getExpectedOldObjectId() {
 		return expValue;
 	}
 
 	/**
+	 * Set the expected value of the ref after the lock is taken, but before
+	 * update occurs.
+	 *
 	 * @param id
 	 *            the expected value of the ref after the lock is taken, but
 	 *            before update occurs. Null to avoid the compare and swap test.
-	 *            Use {@link ObjectId#zeroId()} to indicate expectation of a
-	 *            non-existant ref.
+	 *            Use {@link org.eclipse.jgit.lib.ObjectId#zeroId()} to indicate
+	 *            expectation of a non-existant ref.
 	 */
-	public void setExpectedOldObjectId(final AnyObjectId id) {
+	public void setExpectedOldObjectId(AnyObjectId id) {
 		expValue = id != null ? id.toObjectId() : null;
 	}
 
@@ -367,11 +396,15 @@ public boolean isForceUpdate() {
 	 * @param b
 	 *            true if this update should ignore merge tests.
 	 */
-	public void setForceUpdate(final boolean b) {
+	public void setForceUpdate(boolean b) {
 		force = b;
 	}
 
-	/** @return identity of the user making the change in the reflog. */
+	/**
+	 * Get identity of the user making the change in the reflog.
+	 *
+	 * @return identity of the user making the change in the reflog.
+	 */
 	public PersonIdent getRefLogIdent() {
 		return refLogIdent;
 	}
@@ -388,7 +421,7 @@ public PersonIdent getRefLogIdent() {
 	 *            automatically determined based on the repository
 	 *            configuration.
 	 */
-	public void setRefLogIdent(final PersonIdent pi) {
+	public void setRefLogIdent(PersonIdent pi) {
 		refLogIdent = pi;
 	}
 
@@ -402,7 +435,11 @@ public String getRefLogMessage() {
 		return refLogMessage;
 	}
 
-	/** @return {@code true} if the ref log message should show the result. */
+	/**
+	 * Whether the ref log message should show the result.
+	 *
+	 * @return {@code true} if the ref log message should show the result.
+	 */
 	protected boolean isRefLogIncludingResult() {
 		return refLogIncludeResult;
 	}
@@ -424,7 +461,7 @@ protected boolean isRefLogIncludingResult() {
 	 *            forced-update) should be appended to the user supplied
 	 *            message.
 	 */
-	public void setRefLogMessage(final String msg, final boolean appendStatus) {
+	public void setRefLogMessage(String msg, boolean appendStatus) {
 		if (msg == null && !appendStatus)
 			disableRefLog();
 		else if (msg == null && appendStatus) {
@@ -436,7 +473,9 @@ else if (msg == null && appendStatus) {
 		}
 	}
 
-	/** Don't record this update in the ref's associated reflog. */
+	/**
+	 * Don't record this update in the ref's associated reflog.
+	 */
 	public void disableRefLog() {
 		refLogMessage = null;
 		refLogIncludeResult = false;
@@ -535,7 +574,7 @@ private void requireCanDoUpdate() {
 	 * the merge test is performed.
 	 *
 	 * @return the result status of the update.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             an unexpected IO error occurred while writing changes.
 	 */
 	public Result forceUpdate() throws IOException {
@@ -555,7 +594,7 @@ public Result forceUpdate() throws IOException {
 	 * </pre>
 	 *
 	 * @return the result status of the update.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             an unexpected IO error occurred while writing changes.
 	 */
 	public Result update() throws IOException {
@@ -573,10 +612,10 @@ public Result update() throws IOException {
 	 *            a RevWalk instance this update command can borrow to perform
 	 *            the merge test. The walk will be reset to perform the test.
 	 * @return the result status of the update.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             an unexpected IO error occurred while writing changes.
 	 */
-	public Result update(final RevWalk walk) throws IOException {
+	public Result update(RevWalk walk) throws IOException {
 		requireCanDoUpdate();
 		try {
 			return result = updateImpl(walk, new Store() {
@@ -603,7 +642,7 @@ Result execute(Result status) throws IOException {
 	 * </pre>
 	 *
 	 * @return the result status of the delete.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 */
 	public Result delete() throws IOException {
 		try (RevWalk rw = new RevWalk(getRepository())) {
@@ -618,9 +657,9 @@ public Result delete() throws IOException {
 	 *            a RevWalk instance this delete command can borrow to perform
 	 *            the merge test. The walk will be reset to perform the test.
 	 * @return the result status of the delete.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 */
-	public Result delete(final RevWalk walk) throws IOException {
+	public Result delete(RevWalk walk) throws IOException {
 		final String myName = detachingSymbolicRef
 				? getRef().getName()
 				: getRef().getLeaf().getName();
@@ -656,8 +695,9 @@ Result execute(Result status) throws IOException {
 	 * @param target
 	 *            name of the new target for this reference. The new target name
 	 *            must be absolute, so it must begin with {@code refs/}.
-	 * @return {@link Result#NEW} or {@link Result#FORCED} on success.
-	 * @throws IOException
+	 * @return {@link org.eclipse.jgit.lib.RefUpdate.Result#NEW} or
+	 *         {@link org.eclipse.jgit.lib.RefUpdate.Result#FORCED} on success.
+	 * @throws java.io.IOException
 	 */
 	public Result link(String target) throws IOException {
 		if (!target.startsWith(Constants.R_REFS))
@@ -691,7 +731,7 @@ public Result link(String target) throws IOException {
 		}
 	}
 
-	private Result updateImpl(final RevWalk walk, final Store store)
+	private Result updateImpl(RevWalk walk, Store store)
 			throws IOException {
 		RevObject newObj;
 		RevObject oldObj;
@@ -751,6 +791,7 @@ && getRefDatabase().isNameConflicting(getName())) {
 	 * are checked explicitly.
 	 *
 	 * @param check
+	 *            whether to enable the check for conflicting ref names.
 	 * @since 3.0
 	 */
 	public void setCheckConflicting(boolean check) {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefWriter.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefWriter.java
index 3a02b22..71ee963 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefWriter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefWriter.java
@@ -56,8 +56,8 @@
 import org.eclipse.jgit.util.RefMap;
 
 /**
- * Writes out refs to the {@link Constants#INFO_REFS} and
- * {@link Constants#PACKED_REFS} files.
+ * Writes out refs to the {@link org.eclipse.jgit.lib.Constants#INFO_REFS} and
+ * {@link org.eclipse.jgit.lib.Constants#PACKED_REFS} files.
  *
  * This class is abstract as the writing of the files must be handled by the
  * caller. This is because it is used by transport classes as well.
@@ -67,6 +67,8 @@ public abstract class RefWriter {
 	private final Collection<Ref> refs;
 
 	/**
+	 * <p>Constructor for RefWriter.</p>
+	 *
 	 * @param refs
 	 *            the complete set of references. This should have been computed
 	 *            by applying updates to the advertised refs already discovered.
@@ -76,6 +78,8 @@ public RefWriter(Collection<Ref> refs) {
 	}
 
 	/**
+	 * <p>Constructor for RefWriter.</p>
+	 *
 	 * @param refs
 	 *            the complete set of references. This should have been computed
 	 *            by applying updates to the advertised refs already discovered.
@@ -88,6 +92,8 @@ public RefWriter(Map<String, Ref> refs) {
 	}
 
 	/**
+	 * <p>Constructor for RefWriter.</p>
+	 *
 	 * @param refs
 	 *            the complete set of references. This should have been computed
 	 *            by applying updates to the advertised refs already discovered.
@@ -97,20 +103,20 @@ public RefWriter(RefList<Ref> refs) {
 	}
 
 	/**
-	 * Rebuild the {@link Constants#INFO_REFS}.
+	 * Rebuild the {@link org.eclipse.jgit.lib.Constants#INFO_REFS}.
 	 * <p>
-	 * This method rebuilds the contents of the {@link Constants#INFO_REFS} file
-	 * to match the passed list of references.
+	 * This method rebuilds the contents of the
+	 * {@link org.eclipse.jgit.lib.Constants#INFO_REFS} file to match the passed
+	 * list of references.
 	 *
-	 *
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             writing is not supported, or attempting to write the file
 	 *             failed, possibly due to permissions or remote disk full, etc.
 	 */
 	public void writeInfoRefs() throws IOException {
 		final StringWriter w = new StringWriter();
 		final char[] tmp = new char[Constants.OBJECT_ID_STRING_LENGTH];
-		for (final Ref r : refs) {
+		for (Ref r : refs) {
 			if (Constants.HEAD.equals(r.getName())) {
 				// Historically HEAD has never been published through
 				// the INFO_REFS file. This is a mistake, but its the
@@ -142,19 +148,20 @@ public void writeInfoRefs() throws IOException {
 	}
 
 	/**
-	 * Rebuild the {@link Constants#PACKED_REFS} file.
+	 * Rebuild the {@link org.eclipse.jgit.lib.Constants#PACKED_REFS} file.
 	 * <p>
-	 * This method rebuilds the contents of the {@link Constants#PACKED_REFS}
-	 * file to match the passed list of references, including only those refs
-	 * that have a storage type of {@link Ref.Storage#PACKED}.
+	 * This method rebuilds the contents of the
+	 * {@link org.eclipse.jgit.lib.Constants#PACKED_REFS} file to match the
+	 * passed list of references, including only those refs that have a storage
+	 * type of {@link org.eclipse.jgit.lib.Ref.Storage#PACKED}.
 	 *
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             writing is not supported, or attempting to write the file
 	 *             failed, possibly due to permissions or remote disk full, etc.
 	 */
 	public void writePackedRefs() throws IOException {
 		boolean peeled = false;
-		for (final Ref r : refs) {
+		for (Ref r : refs) {
 			if (r.getStorage().isPacked() && r.isPeeled()) {
 				peeled = true;
 				break;
@@ -170,7 +177,7 @@ public void writePackedRefs() throws IOException {
 		}
 
 		final char[] tmp = new char[Constants.OBJECT_ID_STRING_LENGTH];
-		for (final Ref r : refs) {
+		for (Ref r : refs) {
 			if (r.getStorage() != Ref.Storage.PACKED)
 				continue;
 
@@ -203,7 +210,7 @@ public void writePackedRefs() throws IOException {
 	 *            path to ref file.
 	 * @param content
 	 *            byte content of file to be written.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 */
 	protected abstract void writeFile(String file, byte[] content)
 			throws IOException;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ReflogEntry.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ReflogEntry.java
index afa6521..51f2ea0 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ReflogEntry.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ReflogEntry.java
@@ -83,28 +83,39 @@ public interface ReflogEntry {
 	public static final String PREFIX_FORCED_UPDATE = "forced-update"; //$NON-NLS-1$
 
 	/**
+	 * Get the commit id before the change
+	 *
 	 * @return the commit id before the change
 	 */
 	public abstract ObjectId getOldId();
 
 	/**
+	 * Get the commit id after the change
+	 *
 	 * @return the commit id after the change
 	 */
 	public abstract ObjectId getNewId();
 
 	/**
+	 * Get user performing the change
+	 *
 	 * @return user performing the change
 	 */
 	public abstract PersonIdent getWho();
 
 	/**
+	 * Get textual description of the change
+	 *
 	 * @return textual description of the change
 	 */
 	public abstract String getComment();
 
 	/**
-	 * @return a {@link CheckoutEntry} with parsed information about a branch
-	 *         switch, or null if the entry is not a checkout
+	 * Parse checkout
+	 *
+	 * @return a {@link org.eclipse.jgit.lib.CheckoutEntry} with parsed
+	 *         information about a branch switch, or null if the entry is not a
+	 *         checkout
 	 */
 	public abstract CheckoutEntry parseCheckout();
 
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ReflogReader.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ReflogReader.java
index d3f2536..f97b07e 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ReflogReader.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ReflogReader.java
@@ -57,13 +57,15 @@ public interface ReflogReader {
 	 * Get the last entry in the reflog
 	 *
 	 * @return the latest reflog entry, or null if no log
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 */
 	public abstract ReflogEntry getLastEntry() throws IOException;
 
 	/**
+	 * Get all reflog entries in reverse order
+	 *
 	 * @return all reflog entries in reverse order
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 */
 	public abstract List<ReflogEntry> getReverseEntries() throws IOException;
 
@@ -71,17 +73,19 @@ public interface ReflogReader {
 	 * Get specific entry in the reflog relative to the last entry which is
 	 * considered entry zero.
 	 *
-	 * @param number
+	 * @param number a int.
 	 * @return reflog entry or null if not found
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 */
 	public abstract ReflogEntry getReverseEntry(int number) throws IOException;
 
 	/**
+	 * Get all reflog entries in reverse order
+	 *
 	 * @param max
 	 *            max number of entries to read
 	 * @return all reflog entries in reverse order
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 */
 	public abstract List<ReflogEntry> getReverseEntries(int max)
 			throws IOException;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Repository.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Repository.java
index 72f79f4..29cc19c 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Repository.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Repository.java
@@ -48,6 +48,8 @@
 
 package org.eclipse.jgit.lib;
 
+import static org.eclipse.jgit.lib.Constants.LOCK_SUFFIX;
+
 import java.io.BufferedOutputStream;
 import java.io.File;
 import java.io.FileNotFoundException;
@@ -83,7 +85,6 @@
 import org.eclipse.jgit.events.ListenerList;
 import org.eclipse.jgit.events.RepositoryEvent;
 import org.eclipse.jgit.internal.JGitText;
-import org.eclipse.jgit.internal.storage.file.GC;
 import org.eclipse.jgit.revwalk.RevBlob;
 import org.eclipse.jgit.revwalk.RevCommit;
 import org.eclipse.jgit.revwalk.RevObject;
@@ -106,9 +107,9 @@
  * A repository holds all objects and refs used for managing source code (could
  * be any type of file, but source code is what SCM's are typically used for).
  * <p>
- * The thread-safety of a {@link Repository} very much depends on the concrete
- * implementation. Applications working with a generic {@code Repository} type
- * must not assume the instance is thread-safe.
+ * The thread-safety of a {@link org.eclipse.jgit.lib.Repository} very much
+ * depends on the concrete implementation. Applications working with a generic
+ * {@code Repository} type must not assume the instance is thread-safe.
  * <ul>
  * <li>{@code FileRepository} is thread-safe.
  * <li>{@code DfsRepository} thread-safety is determined by its subclass.
@@ -129,7 +130,11 @@ public abstract class Repository implements AutoCloseable {
 					"(^|/)(aux|com[1-9]|con|lpt[1-9]|nul|prn)(\\.[^/]*)?", //$NON-NLS-1$
 					Pattern.CASE_INSENSITIVE);
 
-	/** @return the global listener list observing all events in this JVM. */
+	/**
+	 * Get the global listener list observing all events in this JVM.
+	 *
+	 * @return the global listener list observing all events in this JVM.
+	 */
 	public static ListenerList getGlobalListenerList() {
 		return globalListeners;
 	}
@@ -159,14 +164,18 @@ public static ListenerList getGlobalListenerList() {
 	 * @param options
 	 *            options to configure the repository.
 	 */
-	protected Repository(final BaseRepositoryBuilder options) {
+	protected Repository(BaseRepositoryBuilder options) {
 		gitDir = options.getGitDir();
 		fs = options.getFS();
 		workTree = options.getWorkTree();
 		indexFile = options.getIndexFile();
 	}
 
-	/** @return listeners observing only events on this repository. */
+	/**
+	 * Get listeners observing only events on this repository.
+	 *
+	 * @return listeners observing only events on this repository.
+	 */
 	@NonNull
 	public ListenerList getListenerList() {
 		return myListeners;
@@ -193,7 +202,7 @@ public void fireEvent(RepositoryEvent<?> event) {
 	 * Repository with working tree is created using this method. This method is
 	 * the same as {@code create(false)}.
 	 *
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 * @see #create(boolean)
 	 */
 	public void create() throws IOException {
@@ -207,12 +216,14 @@ public void create() throws IOException {
 	 * @param bare
 	 *            if true, a bare repository (a repository without a working
 	 *            directory) is created.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             in case of IO problem
 	 */
 	public abstract void create(boolean bare) throws IOException;
 
 	/**
+	 * Get local metadata directory
+	 *
 	 * @return local metadata directory; {@code null} if repository isn't local.
 	 */
 	/*
@@ -227,44 +238,64 @@ public File getDirectory() {
 	}
 
 	/**
+	 * Get the object database which stores this repository's data.
+	 *
 	 * @return the object database which stores this repository's data.
 	 */
 	@NonNull
 	public abstract ObjectDatabase getObjectDatabase();
 
-	/** @return a new inserter to create objects in {@link #getObjectDatabase()} */
+	/**
+	 * Create a new inserter to create objects in {@link #getObjectDatabase()}.
+	 *
+	 * @return a new inserter to create objects in {@link #getObjectDatabase()}.
+	 */
 	@NonNull
 	public ObjectInserter newObjectInserter() {
 		return getObjectDatabase().newInserter();
 	}
 
-	/** @return a new reader to read objects from {@link #getObjectDatabase()} */
+	/**
+	 * Create a new reader to read objects from {@link #getObjectDatabase()}.
+	 *
+	 * @return a new reader to read objects from {@link #getObjectDatabase()}.
+	 */
 	@NonNull
 	public ObjectReader newObjectReader() {
 		return getObjectDatabase().newReader();
 	}
 
-	/** @return the reference database which stores the reference namespace. */
+	/**
+	 * Get the reference database which stores the reference namespace.
+	 *
+	 * @return the reference database which stores the reference namespace.
+	 */
 	@NonNull
 	public abstract RefDatabase getRefDatabase();
 
 	/**
-	 * @return the configuration of this repository
+	 * Get the configuration of this repository.
+	 *
+	 * @return the configuration of this repository.
 	 */
 	@NonNull
 	public abstract StoredConfig getConfig();
 
 	/**
-	 * @return a new {@link AttributesNodeProvider}. This
-	 *         {@link AttributesNodeProvider} is lazy loaded only once. It means
-	 *         that it will not be updated after loading. Prefer creating new
-	 *         instance for each use.
+	 * Create a new {@link org.eclipse.jgit.attributes.AttributesNodeProvider}.
+	 *
+	 * @return a new {@link org.eclipse.jgit.attributes.AttributesNodeProvider}.
+	 *         This {@link org.eclipse.jgit.attributes.AttributesNodeProvider}
+	 *         is lazy loaded only once. It means that it will not be updated
+	 *         after loading. Prefer creating new instance for each use.
 	 * @since 4.2
 	 */
 	@NonNull
 	public abstract AttributesNodeProvider createAttributesNodeProvider();
 
 	/**
+	 * Get the used file system abstraction.
+	 *
 	 * @return the used file system abstraction, or or {@code null} if
 	 *         repository isn't local.
 	 */
@@ -280,7 +311,11 @@ public FS getFS() {
 	}
 
 	/**
+	 * Whether the specified object is stored in this repo or any of the known
+	 * shared repositories.
+	 *
 	 * @param objectId
+	 *            a {@link org.eclipse.jgit.lib.AnyObjectId} object.
 	 * @return true if the specified object is stored in this repo or any of the
 	 *         known shared repositories.
 	 */
@@ -301,14 +336,15 @@ public boolean hasObject(AnyObjectId objectId) {
 	 *
 	 * @param objectId
 	 *            identity of the object to open.
-	 * @return a {@link ObjectLoader} for accessing the object.
-	 * @throws MissingObjectException
+	 * @return a {@link org.eclipse.jgit.lib.ObjectLoader} for accessing the
+	 *         object.
+	 * @throws org.eclipse.jgit.errors.MissingObjectException
 	 *             the object does not exist.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the object store cannot be accessed.
 	 */
 	@NonNull
-	public ObjectLoader open(final AnyObjectId objectId)
+	public ObjectLoader open(AnyObjectId objectId)
 			throws MissingObjectException, IOException {
 		return getObjectDatabase().open(objectId);
 	}
@@ -323,16 +359,17 @@ public ObjectLoader open(final AnyObjectId objectId)
 	 *            identity of the object to open.
 	 * @param typeHint
 	 *            hint about the type of object being requested, e.g.
-	 *            {@link Constants#OBJ_BLOB}; {@link ObjectReader#OBJ_ANY} if
-	 *            the object type is not known, or does not matter to the
-	 *            caller.
-	 * @return a {@link ObjectLoader} for accessing the object.
-	 * @throws MissingObjectException
+	 *            {@link org.eclipse.jgit.lib.Constants#OBJ_BLOB};
+	 *            {@link org.eclipse.jgit.lib.ObjectReader#OBJ_ANY} if the
+	 *            object type is not known, or does not matter to the caller.
+	 * @return a {@link org.eclipse.jgit.lib.ObjectLoader} for accessing the
+	 *         object.
+	 * @throws org.eclipse.jgit.errors.MissingObjectException
 	 *             the object does not exist.
-	 * @throws IncorrectObjectTypeException
+	 * @throws org.eclipse.jgit.errors.IncorrectObjectTypeException
 	 *             typeHint was not OBJ_ANY, and the object's actual type does
 	 *             not match typeHint.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the object store cannot be accessed.
 	 */
 	@NonNull
@@ -350,12 +387,12 @@ public ObjectLoader open(AnyObjectId objectId, int typeHint)
 	 * @return an update command. The caller must finish populating this command
 	 *         and then invoke one of the update methods to actually make a
 	 *         change.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             a symbolic ref was passed in and could not be resolved back
 	 *             to the base ref, as the symbolic ref could not be read.
 	 */
 	@NonNull
-	public RefUpdate updateRef(final String ref) throws IOException {
+	public RefUpdate updateRef(String ref) throws IOException {
 		return updateRef(ref, false);
 	}
 
@@ -369,12 +406,12 @@ public RefUpdate updateRef(final String ref) throws IOException {
 	 * @return an update command. The caller must finish populating this command
 	 *         and then invoke one of the update methods to actually make a
 	 *         change.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             a symbolic ref was passed in and could not be resolved back
 	 *             to the base ref, as the symbolic ref could not be read.
 	 */
 	@NonNull
-	public RefUpdate updateRef(final String ref, final boolean detach) throws IOException {
+	public RefUpdate updateRef(String ref, boolean detach) throws IOException {
 		return getRefDatabase().newUpdate(ref, detach);
 	}
 
@@ -386,12 +423,11 @@ public RefUpdate updateRef(final String ref, final boolean detach) throws IOExce
 	 * @param toRef
 	 *            name of ref to rename to
 	 * @return an update command that knows how to rename a branch to another.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the rename could not be performed.
-	 *
 	 */
 	@NonNull
-	public RefRename renameRef(final String fromRef, final String toRef) throws IOException {
+	public RefRename renameRef(String fromRef, String toRef) throws IOException {
 		return getRefDatabase().newRename(fromRef, toRef);
 	}
 
@@ -432,27 +468,27 @@ public RefRename renameRef(final String fromRef, final String toRef) throws IOEx
 	 *            A git object references expression
 	 * @return an ObjectId or {@code null} if revstr can't be resolved to any
 	 *         ObjectId
-	 * @throws AmbiguousObjectException
+	 * @throws org.eclipse.jgit.errors.AmbiguousObjectException
 	 *             {@code revstr} contains an abbreviated ObjectId and this
 	 *             repository contains more than one object which match to the
 	 *             input abbreviation.
-	 * @throws IncorrectObjectTypeException
+	 * @throws org.eclipse.jgit.errors.IncorrectObjectTypeException
 	 *             the id parsed does not meet the type required to finish
 	 *             applying the operators in the expression.
-	 * @throws RevisionSyntaxException
+	 * @throws org.eclipse.jgit.errors.RevisionSyntaxException
 	 *             the expression is not supported by this implementation, or
 	 *             does not meet the standard syntax.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             on serious errors
 	 */
 	@Nullable
-	public ObjectId resolve(final String revstr)
+	public ObjectId resolve(String revstr)
 			throws AmbiguousObjectException, IncorrectObjectTypeException,
 			RevisionSyntaxException, IOException {
 		try (RevWalk rw = new RevWalk(this)) {
 			Object resolved = resolve(rw, revstr);
 			if (resolved instanceof String) {
-				final Ref ref = getRef((String)resolved);
+				final Ref ref = findRef((String) resolved);
 				return ref != null ? ref.getLeaf().getObjectId() : null;
 			} else {
 				return (ObjectId) resolved;
@@ -466,14 +502,14 @@ public ObjectId resolve(final String revstr)
 	 * Thus this method can be used to process an expression to a method that
 	 * expects a branch or revision id.
 	 *
-	 * @param revstr
+	 * @param revstr a {@link java.lang.String} object.
 	 * @return object id or ref name from resolved expression or {@code null} if
 	 *         given expression cannot be resolved
-	 * @throws AmbiguousObjectException
-	 * @throws IOException
+	 * @throws org.eclipse.jgit.errors.AmbiguousObjectException
+	 * @throws java.io.IOException
 	 */
 	@Nullable
-	public String simplify(final String revstr)
+	public String simplify(String revstr)
 			throws AmbiguousObjectException, IOException {
 		try (RevWalk rw = new RevWalk(this)) {
 			Object resolved = resolve(rw, revstr);
@@ -487,7 +523,7 @@ public String simplify(final String revstr)
 	}
 
 	@Nullable
-	private Object resolve(final RevWalk rw, final String revstr)
+	private Object resolve(RevWalk rw, String revstr)
 			throws IOException {
 		char[] revChars = revstr.toCharArray();
 		RevObject rev = null;
@@ -652,6 +688,8 @@ private Object resolve(final RevWalk rw, final String revstr)
 			case '@':
 				if (rev != null)
 					throw new RevisionSyntaxException(revstr);
+				if (i + 1 == revChars.length)
+					continue;
 				if (i + 1 < revChars.length && revChars[i + 1] != '{')
 					continue;
 				int m;
@@ -675,7 +713,7 @@ private Object resolve(final RevWalk rw, final String revstr)
 									.format(JGitText.get().invalidRefName,
 											name),
 									revstr);
-						Ref ref = getRef(name);
+						Ref ref = findRef(name);
 						name = null;
 						if (ref == null)
 							return null;
@@ -728,7 +766,7 @@ private Object resolve(final RevWalk rw, final String revstr)
 									.format(JGitText.get().invalidRefName,
 											name),
 									revstr);
-						Ref ref = getRef(name);
+						Ref ref = findRef(name);
 						name = null;
 						if (ref == null)
 							return null;
@@ -779,7 +817,7 @@ private Object resolve(final RevWalk rw, final String revstr)
 			throw new RevisionSyntaxException(
 					MessageFormat.format(JGitText.get().invalidRefName, name),
 					revstr);
-		if (getRef(name) != null)
+		if (findRef(name) != null)
 			return name;
 		return resolveSimple(name);
 	}
@@ -805,7 +843,7 @@ private RevObject parseSimple(RevWalk rw, String revstr) throws IOException {
 	}
 
 	@Nullable
-	private ObjectId resolveSimple(final String revstr) throws IOException {
+	private ObjectId resolveSimple(String revstr) throws IOException {
 		if (ObjectId.isId(revstr))
 			return ObjectId.fromString(revstr);
 
@@ -875,7 +913,7 @@ private RevCommit resolveReflog(RevWalk rw, Ref ref, String time)
 	}
 
 	@Nullable
-	private ObjectId resolveAbbreviation(final String revstr) throws IOException,
+	private ObjectId resolveAbbreviation(String revstr) throws IOException,
 			AmbiguousObjectException {
 		AbbreviatedObjectId id = AbbreviatedObjectId.fromString(revstr);
 		try (ObjectReader reader = newObjectReader()) {
@@ -889,12 +927,18 @@ else if (matches.size() == 1)
 		}
 	}
 
-	/** Increment the use counter by one, requiring a matched {@link #close()}. */
+	/**
+	 * Increment the use counter by one, requiring a matched {@link #close()}.
+	 */
 	public void incrementOpen() {
 		useCnt.incrementAndGet();
 	}
 
-	/** Decrement the use count, and maybe close resources. */
+	/**
+	 * {@inheritDoc}
+	 * <p>
+	 * Decrement the use count, and maybe close resources.
+	 */
 	@Override
 	public void close() {
 		int newCount = useCnt.decrementAndGet();
@@ -930,6 +974,7 @@ protected void doClose() {
 		getRefDatabase().close();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	@NonNull
 	public String toString() {
@@ -959,7 +1004,7 @@ public String toString() {
 	 *         an ObjectId in hex format if the current branch is detached, or
 	 *         {@code null} if the repository is corrupt and has no HEAD
 	 *         reference.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 */
 	@Nullable
 	public String getFullBranch() throws IOException {
@@ -987,7 +1032,7 @@ public String getFullBranch() throws IOException {
 	 * @return name of current branch (for example {@code master}), an ObjectId
 	 *         in hex format if the current branch is detached, or {@code null}
 	 *         if the repository is corrupt and has no HEAD reference.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 */
 	@Nullable
 	public String getBranch() throws IOException {
@@ -1016,33 +1061,15 @@ public Set<ObjectId> getAdditionalHaves() {
 	 * Get a ref by name.
 	 *
 	 * @param name
-	 *            the name of the ref to lookup. May be a short-hand form, e.g.
-	 *            "master" which is is automatically expanded to
-	 *            "refs/heads/master" if "refs/heads/master" already exists.
-	 * @return the Ref with the given name, or {@code null} if it does not exist
-	 * @throws IOException
-	 * @deprecated Use {@link #exactRef(String)} or {@link #findRef(String)}
-	 * instead.
-	 */
-	@Deprecated
-	@Nullable
-	public Ref getRef(final String name) throws IOException {
-		return findRef(name);
-	}
-
-	/**
-	 * Get a ref by name.
-	 *
-	 * @param name
 	 *            the name of the ref to lookup. Must not be a short-hand
 	 *            form; e.g., "master" is not automatically expanded to
 	 *            "refs/heads/master".
 	 * @return the Ref with the given name, or {@code null} if it does not exist
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 * @since 4.2
 	 */
 	@Nullable
-	public Ref exactRef(String name) throws IOException {
+	public final Ref exactRef(String name) throws IOException {
 		return getRefDatabase().exactRef(name);
 	}
 
@@ -1054,15 +1081,18 @@ public Ref exactRef(String name) throws IOException {
 	 *            "master" which is is automatically expanded to
 	 *            "refs/heads/master" if "refs/heads/master" already exists.
 	 * @return the Ref with the given name, or {@code null} if it does not exist
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 * @since 4.2
 	 */
 	@Nullable
-	public Ref findRef(String name) throws IOException {
+	public final Ref findRef(String name) throws IOException {
 		return getRefDatabase().getRef(name);
 	}
 
 	/**
+	 * Get mutable map of all known refs, including symrefs like HEAD that may
+	 * not point to any object yet.
+	 *
 	 * @return mutable map of all known refs (heads, tags, remotes).
 	 */
 	@NonNull
@@ -1075,10 +1105,14 @@ public Map<String, Ref> getAllRefs() {
 	}
 
 	/**
+	 * Get mutable map of all tags
+	 *
 	 * @return mutable map of all tags; key is short tag name ("v1.0") and value
 	 *         of the entry contains the ref with the full tag name
 	 *         ("refs/tags/v1.0").
+	 * @deprecated use {@code getRefDatabase().getRefsByPrefix(R_TAGS)} instead
 	 */
+	@Deprecated
 	@NonNull
 	public Map<String, Ref> getTags() {
 		try {
@@ -1092,7 +1126,8 @@ public Map<String, Ref> getTags() {
 	 * Peel a possibly unpeeled reference to an annotated tag.
 	 * <p>
 	 * If the ref cannot be peeled (as it does not refer to an annotated tag)
-	 * the peeled id stays null, but {@link Ref#isPeeled()} will be true.
+	 * the peeled id stays null, but {@link org.eclipse.jgit.lib.Ref#isPeeled()}
+	 * will be true.
 	 *
 	 * @param ref
 	 *            The ref to peel
@@ -1100,9 +1135,11 @@ public Map<String, Ref> getTags() {
 	 *         new Ref object representing the same data as Ref, but isPeeled()
 	 *         will be true and getPeeledObjectId will contain the peeled object
 	 *         (or null).
+	 * @deprecated use {@code getRefDatabase().peel(ref)} instead.
 	 */
+	@Deprecated
 	@NonNull
-	public Ref peel(final Ref ref) {
+	public Ref peel(Ref ref) {
 		try {
 			return getRefDatabase().peel(ref);
 		} catch (IOException e) {
@@ -1114,6 +1151,8 @@ public Ref peel(final Ref ref) {
 	}
 
 	/**
+	 * Get a map with all objects referenced by a peeled ref.
+	 *
 	 * @return a map with all objects referenced by a peeled ref.
 	 */
 	@NonNull
@@ -1141,9 +1180,11 @@ public Map<AnyObjectId, Set<Ref>> getAllRefsByPeeledObjectId() {
 	}
 
 	/**
+	 * Get the index file location or {@code null} if repository isn't local.
+	 *
 	 * @return the index file location or {@code null} if repository isn't
 	 *         local.
-	 * @throws NoWorkTreeException
+	 * @throws org.eclipse.jgit.errors.NoWorkTreeException
 	 *             if this is bare, which implies it has no working directory.
 	 *             See {@link #isBare()}.
 	 */
@@ -1163,11 +1204,11 @@ public File getIndexFile() throws NoWorkTreeException {
 	 * @param id
 	 *            name of the commit object.
 	 * @return reference to the commit object. Never null.
-	 * @throws MissingObjectException
+	 * @throws org.eclipse.jgit.errors.MissingObjectException
 	 *             the supplied commit does not exist.
-	 * @throws IncorrectObjectTypeException
+	 * @throws org.eclipse.jgit.errors.IncorrectObjectTypeException
 	 *             the supplied id is not a commit or an annotated tag.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             a pack file or loose object could not be read.
 	 * @since 4.8
 	 */
@@ -1190,12 +1231,12 @@ public RevCommit parseCommit(AnyObjectId id) throws IncorrectObjectTypeException
 	 *
 	 * @return a cache representing the contents of the specified index file (if
 	 *         it exists) or an empty cache if the file does not exist.
-	 * @throws NoWorkTreeException
+	 * @throws org.eclipse.jgit.errors.NoWorkTreeException
 	 *             if this is bare, which implies it has no working directory.
 	 *             See {@link #isBare()}.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the index file is present but could not be read.
-	 * @throws CorruptObjectException
+	 * @throws org.eclipse.jgit.errors.CorruptObjectException
 	 *             the index file is using a format or extension that this
 	 *             library does not support.
 	 */
@@ -1214,13 +1255,13 @@ public DirCache readDirCache() throws NoWorkTreeException,
 	 *
 	 * @return a cache representing the contents of the specified index file (if
 	 *         it exists) or an empty cache if the file does not exist.
-	 * @throws NoWorkTreeException
+	 * @throws org.eclipse.jgit.errors.NoWorkTreeException
 	 *             if this is bare, which implies it has no working directory.
 	 *             See {@link #isBare()}.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the index file is present but could not be read, or the lock
 	 *             could not be obtained.
-	 * @throws CorruptObjectException
+	 * @throws org.eclipse.jgit.errors.CorruptObjectException
 	 *             the index file is using a format or extension that this
 	 *             library does not support.
 	 */
@@ -1232,14 +1273,16 @@ public DirCache lockDirCache() throws NoWorkTreeException,
 		IndexChangedListener l = new IndexChangedListener() {
 			@Override
 			public void onIndexChanged(IndexChangedEvent event) {
-				notifyIndexChanged();
+				notifyIndexChanged(true);
 			}
 		};
 		return DirCache.lock(this, l);
 	}
 
 	/**
-	 * @return an important state
+	 * Get the repository state
+	 *
+	 * @return the repository state
 	 */
 	@NonNull
 	public RepositoryState getRepositoryState() {
@@ -1320,16 +1363,17 @@ public RepositoryState getRepositoryState() {
 	 *
 	 * For portability reasons '\' is excluded
 	 *
-	 * @param refName
-	 *
+	 * @param refName a {@link java.lang.String} object.
 	 * @return true if refName is a valid ref name
 	 */
-	public static boolean isValidRefName(final String refName) {
+	public static boolean isValidRefName(String refName) {
 		final int len = refName.length();
-		if (len == 0)
+		if (len == 0) {
 			return false;
-		if (refName.endsWith(".lock")) //$NON-NLS-1$
+		}
+		if (refName.endsWith(LOCK_SUFFIX)) {
 			return false;
+		}
 
 		// Refs may be stored as loose files so invalid paths
 		// on the local system must also be invalid refs.
@@ -1380,10 +1424,10 @@ public static boolean isValidRefName(final String refName) {
 	 * Normalizes the passed branch name into a possible valid branch name. The
 	 * validity of the returned name should be checked by a subsequent call to
 	 * {@link #isValidRefName(String)}.
-	 * <p/>
+	 * <p>
 	 * Future implementations of this method could be more restrictive or more
 	 * lenient about the validity of specific characters in the returned name.
-	 * <p/>
+	 * <p>
 	 * The current implementation returns the trimmed input string if this is
 	 * already a valid branch name. Otherwise it returns a trimmed string with
 	 * special characters not allowed by {@link #isValidRefName(String)}
@@ -1392,7 +1436,6 @@ public static boolean isValidRefName(final String refName) {
 	 *
 	 * @param name
 	 *            to normalize
-	 *
 	 * @return The normalized name or an empty String if it is {@code null} or
 	 *         empty.
 	 * @since 4.7
@@ -1499,6 +1542,8 @@ public static String stripWorkDir(File workDir, File file) {
 	}
 
 	/**
+	 * Whether this repository is bare
+	 *
 	 * @return true if this is bare, which implies it has no working directory.
 	 */
 	public boolean isBare() {
@@ -1506,9 +1551,12 @@ public boolean isBare() {
 	}
 
 	/**
+	 * Get the root directory of the working tree, where files are checked out
+	 * for viewing and editing.
+	 *
 	 * @return the root directory of the working tree, where files are checked
 	 *         out for viewing and editing.
-	 * @throws NoWorkTreeException
+	 * @throws org.eclipse.jgit.errors.NoWorkTreeException
 	 *             if this is bare, which implies it has no working directory.
 	 *             See {@link #isBare()}.
 	 */
@@ -1520,20 +1568,28 @@ public File getWorkTree() throws NoWorkTreeException {
 	}
 
 	/**
-	 * Force a scan for changed refs.
+	 * Force a scan for changed refs. Fires an IndexChangedEvent(false) if
+	 * changes are detected.
 	 *
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 */
 	public abstract void scanForRepoChanges() throws IOException;
 
 	/**
-	 * Notify that the index changed
+	 * Notify that the index changed by firing an IndexChangedEvent.
+	 *
+	 * @param internal
+	 *                     {@code true} if the index was changed by the same
+	 *                     JGit process
+	 * @since 5.0
 	 */
-	public abstract void notifyIndexChanged();
+	public abstract void notifyIndexChanged(boolean internal);
 
 	/**
-	 * @param refName
+	 * Get a shortened more user friendly ref name
 	 *
+	 * @param refName
+	 *            a {@link java.lang.String} object.
 	 * @return a more user friendly ref name
 	 */
 	@NonNull
@@ -1548,7 +1604,10 @@ public static String shortenRefName(String refName) {
 	}
 
 	/**
+	 * Get a shortened more user friendly remote tracking branch name
+	 *
 	 * @param refName
+	 *            a {@link java.lang.String} object.
 	 * @return the remote branch name part of <code>refName</code>, i.e. without
 	 *         the <code>refs/remotes/&lt;remote&gt;</code> prefix, if
 	 *         <code>refName</code> represents a remote tracking branch;
@@ -1566,7 +1625,10 @@ public String shortenRemoteBranchName(String refName) {
 	}
 
 	/**
+	 * Get remote name
+	 *
 	 * @param refName
+	 *            a {@link java.lang.String} object.
 	 * @return the remote name part of <code>refName</code>, i.e. without the
 	 *         <code>refs/remotes/&lt;remote&gt;</code> prefix, if
 	 *         <code>refName</code> represents a remote tracking branch;
@@ -1587,7 +1649,7 @@ public String getRemoteName(String refName) {
 	 * Read the {@code GIT_DIR/description} file for gitweb.
 	 *
 	 * @return description text; null if no description has been configured.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             description cannot be accessed.
 	 * @since 4.6
 	 */
@@ -1601,7 +1663,7 @@ public String getGitwebDescription() throws IOException {
 	 *
 	 * @param description
 	 *            new description; null to clear the description.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             description cannot be persisted.
 	 * @since 4.6
 	 */
@@ -1611,10 +1673,13 @@ public void setGitwebDescription(@Nullable String description)
 	}
 
 	/**
+	 * Get the reflog reader
+	 *
 	 * @param refName
-	 * @return a {@link ReflogReader} for the supplied refname, or {@code null}
-	 *         if the named ref does not exist.
-	 * @throws IOException
+	 *            a {@link java.lang.String} object.
+	 * @return a {@link org.eclipse.jgit.lib.ReflogReader} for the supplied
+	 *         refname, or {@code null} if the named ref does not exist.
+	 * @throws java.io.IOException
 	 *             the ref could not be accessed.
 	 * @since 3.0
 	 */
@@ -1629,8 +1694,8 @@ public abstract ReflogReader getReflogReader(String refName)
 	 *
 	 * @return a String containing the content of the MERGE_MSG file or
 	 *         {@code null} if this file doesn't exist
-	 * @throws IOException
-	 * @throws NoWorkTreeException
+	 * @throws java.io.IOException
+	 * @throws org.eclipse.jgit.errors.NoWorkTreeException
 	 *             if this is bare, which implies it has no working directory.
 	 *             See {@link #isBare()}.
 	 */
@@ -1648,8 +1713,7 @@ public String readMergeCommitMsg() throws IOException, NoWorkTreeException {
 	 * @param msg
 	 *            the message which should be written or <code>null</code> to
 	 *            delete the file
-	 *
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 */
 	public void writeMergeCommitMsg(String msg) throws IOException {
 		File mergeMsgFile = new File(gitDir, Constants.MERGE_MSG);
@@ -1663,8 +1727,8 @@ public void writeMergeCommitMsg(String msg) throws IOException {
 	 *
 	 * @return a String containing the content of the COMMIT_EDITMSG file or
 	 *         {@code null} if this file doesn't exist
-	 * @throws IOException
-	 * @throws NoWorkTreeException
+	 * @throws java.io.IOException
+	 * @throws org.eclipse.jgit.errors.NoWorkTreeException
 	 *             if this is bare, which implies it has no working directory.
 	 *             See {@link #isBare()}.
 	 * @since 4.0
@@ -1682,8 +1746,7 @@ public String readCommitEditMsg() throws IOException, NoWorkTreeException {
 	 * @param msg
 	 *            the message which should be written or {@code null} to delete
 	 *            the file
-	 *
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 * @since 4.0
 	 */
 	public void writeCommitEditMsg(String msg) throws IOException {
@@ -1699,8 +1762,8 @@ public void writeCommitEditMsg(String msg) throws IOException {
 	 * @return a list of commits which IDs are listed in the MERGE_HEAD file or
 	 *         {@code null} if this file doesn't exist. Also if the file exists
 	 *         but is empty {@code null} will be returned
-	 * @throws IOException
-	 * @throws NoWorkTreeException
+	 * @throws java.io.IOException
+	 * @throws org.eclipse.jgit.errors.NoWorkTreeException
 	 *             if this is bare, which implies it has no working directory.
 	 *             See {@link #isBare()}.
 	 */
@@ -1731,7 +1794,7 @@ public List<ObjectId> readMergeHeads() throws IOException, NoWorkTreeException {
 	 * @param heads
 	 *            a list of commits which IDs should be written to
 	 *            $GIT_DIR/MERGE_HEAD or <code>null</code> to delete the file
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 */
 	public void writeMergeHeads(List<? extends ObjectId> heads) throws IOException {
 		writeHeadsFile(heads, Constants.MERGE_HEAD);
@@ -1743,8 +1806,8 @@ public void writeMergeHeads(List<? extends ObjectId> heads) throws IOException {
 	 * @return object id from CHERRY_PICK_HEAD file or {@code null} if this file
 	 *         doesn't exist. Also if the file exists but is empty {@code null}
 	 *         will be returned
-	 * @throws IOException
-	 * @throws NoWorkTreeException
+	 * @throws java.io.IOException
+	 * @throws org.eclipse.jgit.errors.NoWorkTreeException
 	 *             if this is bare, which implies it has no working directory.
 	 *             See {@link #isBare()}.
 	 */
@@ -1767,8 +1830,8 @@ public ObjectId readCherryPickHead() throws IOException,
 	 * @return object id from REVERT_HEAD file or {@code null} if this file
 	 *         doesn't exist. Also if the file exists but is empty {@code null}
 	 *         will be returned
-	 * @throws IOException
-	 * @throws NoWorkTreeException
+	 * @throws java.io.IOException
+	 * @throws org.eclipse.jgit.errors.NoWorkTreeException
 	 *             if this is bare, which implies it has no working directory.
 	 *             See {@link #isBare()}.
 	 */
@@ -1790,7 +1853,7 @@ public ObjectId readRevertHead() throws IOException, NoWorkTreeException {
 	 * @param head
 	 *            an object id of the cherry commit or <code>null</code> to
 	 *            delete the file
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 */
 	public void writeCherryPickHead(ObjectId head) throws IOException {
 		List<ObjectId> heads = (head != null) ? Collections.singletonList(head)
@@ -1805,7 +1868,7 @@ public void writeCherryPickHead(ObjectId head) throws IOException {
 	 * @param head
 	 *            an object id of the revert commit or <code>null</code> to
 	 *            delete the file
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 */
 	public void writeRevertHead(ObjectId head) throws IOException {
 		List<ObjectId> heads = (head != null) ? Collections.singletonList(head)
@@ -1819,7 +1882,7 @@ public void writeRevertHead(ObjectId head) throws IOException {
 	 * @param head
 	 *            an object id of the original HEAD commit or <code>null</code>
 	 *            to delete the file
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 */
 	public void writeOrigHead(ObjectId head) throws IOException {
 		List<ObjectId> heads = head != null ? Collections.singletonList(head)
@@ -1833,8 +1896,8 @@ public void writeOrigHead(ObjectId head) throws IOException {
 	 * @return object id from ORIG_HEAD file or {@code null} if this file
 	 *         doesn't exist. Also if the file exists but is empty {@code null}
 	 *         will be returned
-	 * @throws IOException
-	 * @throws NoWorkTreeException
+	 * @throws java.io.IOException
+	 * @throws org.eclipse.jgit.errors.NoWorkTreeException
 	 *             if this is bare, which implies it has no working directory.
 	 *             See {@link #isBare()}.
 	 */
@@ -1854,7 +1917,7 @@ public ObjectId readOrigHead() throws IOException, NoWorkTreeException {
 	 *
 	 * @return a String containing the content of the SQUASH_MSG file or
 	 *         {@code null} if this file doesn't exist
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 * @throws NoWorkTreeException
 	 *             if this is bare, which implies it has no working directory.
 	 *             See {@link #isBare()}.
@@ -1873,8 +1936,7 @@ public String readSquashCommitMsg() throws IOException {
 	 * @param msg
 	 *            the message which should be written or <code>null</code> to
 	 *            delete the file
-	 *
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 */
 	public void writeSquashCommitMsg(String msg) throws IOException {
 		File squashMsgFile = new File(gitDir, Constants.SQUASH_MSG);
@@ -1900,11 +1962,8 @@ private String readCommitMsgFile(String msgFilename) throws IOException {
 
 	private void writeCommitMsg(File msgFile, String msg) throws IOException {
 		if (msg != null) {
-			FileOutputStream fos = new FileOutputStream(msgFile);
-			try {
+			try (FileOutputStream fos = new FileOutputStream(msgFile)) {
 				fos.write(msg.getBytes(Constants.CHARACTER_ENCODING));
-			} finally {
-				fos.close();
 			}
 		} else {
 			FileUtils.delete(msgFile, FileUtils.SKIP_MISSING);
@@ -1970,7 +2029,7 @@ private void writeHeadsFile(List<? extends ObjectId> heads, String filename)
 	 * @param includeComments
 	 *            <code>true</code> if also comments should be reported
 	 * @return the list of steps
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 * @since 3.2
 	 */
 	@NonNull
@@ -1990,7 +2049,7 @@ public List<RebaseTodoLine> readRebaseTodo(String path,
 	 *            the steps to be written
 	 * @param append
 	 *            whether to append to an existing file or to write a new file
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 * @since 3.2
 	 */
 	public void writeRebaseTodoFile(String path, List<RebaseTodoLine> steps,
@@ -2000,6 +2059,8 @@ public void writeRebaseTodoFile(String path, List<RebaseTodoLine> steps,
 	}
 
 	/**
+	 * Get the names of all known remotes
+	 *
 	 * @return the names of all known remotes
 	 * @since 3.4
 	 */
@@ -2014,9 +2075,10 @@ public Set<String> getRemoteNames() {
 	 * collection; if not, exit without performing any work. Some JGit commands
 	 * run autoGC after performing operations that could create many loose
 	 * objects.
-	 * <p/>
+	 * <p>
 	 * Currently this option is supported for repositories of type
-	 * {@code FileRepository} only. See {@link GC#setAuto(boolean)} for
+	 * {@code FileRepository} only. See
+	 * {@link org.eclipse.jgit.internal.storage.file.GC#setAuto(boolean)} for
 	 * configuration details.
 	 *
 	 * @param monitor
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/RepositoryBuilder.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/RepositoryBuilder.java
index 95be2d1..65196a8 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/RepositoryBuilder.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/RepositoryBuilder.java
@@ -46,7 +46,7 @@
 import java.io.File;
 
 /**
- * Base class to support constructing a {@link Repository}.
+ * Base class to support constructing a {@link org.eclipse.jgit.lib.Repository}.
  * <p>
  * Applications must set one of {@link #setGitDir(File)} or
  * {@link #setWorkTree(File)}, or use {@link #readEnvironment()} or
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/RepositoryCache.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/RepositoryCache.java
index 53e9fe3..400342b1 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/RepositoryCache.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/RepositoryCache.java
@@ -62,29 +62,33 @@
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-/** Cache of active {@link Repository} instances. */
+/**
+ * Cache of active {@link org.eclipse.jgit.lib.Repository} instances.
+ */
 public class RepositoryCache {
-	private static final RepositoryCache cache = new RepositoryCache();
-
 	private final static Logger LOG = LoggerFactory
 			.getLogger(RepositoryCache.class);
 
+	private static final RepositoryCache cache = new RepositoryCache();
+
 	/**
 	 * Open an existing repository, reusing a cached instance if possible.
 	 * <p>
 	 * When done with the repository, the caller must call
-	 * {@link Repository#close()} to decrement the repository's usage counter.
+	 * {@link org.eclipse.jgit.lib.Repository#close()} to decrement the
+	 * repository's usage counter.
 	 *
 	 * @param location
-	 *            where the local repository is. Typically a {@link FileKey}.
+	 *            where the local repository is. Typically a
+	 *            {@link org.eclipse.jgit.lib.RepositoryCache.FileKey}.
 	 * @return the repository instance requested; caller must close when done.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the repository could not be read (likely its core.version
 	 *             property is not supported).
-	 * @throws RepositoryNotFoundException
+	 * @throws org.eclipse.jgit.errors.RepositoryNotFoundException
 	 *             there is no repository at the given location.
 	 */
-	public static Repository open(final Key location) throws IOException,
+	public static Repository open(Key location) throws IOException,
 			RepositoryNotFoundException {
 		return open(location, true);
 	}
@@ -93,23 +97,25 @@ public static Repository open(final Key location) throws IOException,
 	 * Open a repository, reusing a cached instance if possible.
 	 * <p>
 	 * When done with the repository, the caller must call
-	 * {@link Repository#close()} to decrement the repository's usage counter.
+	 * {@link org.eclipse.jgit.lib.Repository#close()} to decrement the
+	 * repository's usage counter.
 	 *
 	 * @param location
-	 *            where the local repository is. Typically a {@link FileKey}.
+	 *            where the local repository is. Typically a
+	 *            {@link org.eclipse.jgit.lib.RepositoryCache.FileKey}.
 	 * @param mustExist
 	 *            If true, and the repository is not found, throws {@code
 	 *            RepositoryNotFoundException}. If false, a repository instance
 	 *            is created and registered anyway.
 	 * @return the repository instance requested; caller must close when done.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the repository could not be read (likely its core.version
 	 *             property is not supported).
 	 * @throws RepositoryNotFoundException
 	 *             There is no repository at the given location, only thrown if
 	 *             {@code mustExist} is true.
 	 */
-	public static Repository open(final Key location, final boolean mustExist)
+	public static Repository open(Key location, boolean mustExist)
 			throws IOException {
 		return cache.openRepository(location, mustExist);
 	}
@@ -118,9 +124,10 @@ public static Repository open(final Key location, final boolean mustExist)
 	 * Register one repository into the cache.
 	 * <p>
 	 * During registration the cache automatically increments the usage counter,
-	 * permitting it to retain the reference. A {@link FileKey} for the
-	 * repository's {@link Repository#getDirectory()} is used to index the
-	 * repository in the cache.
+	 * permitting it to retain the reference. A
+	 * {@link org.eclipse.jgit.lib.RepositoryCache.FileKey} for the repository's
+	 * {@link org.eclipse.jgit.lib.Repository#getDirectory()} is used to index
+	 * the repository in the cache.
 	 * <p>
 	 * If another repository already is registered in the cache at this
 	 * location, the other instance is closed.
@@ -128,7 +135,7 @@ public static Repository open(final Key location, final boolean mustExist)
 	 * @param db
 	 *            repository to register.
 	 */
-	public static void register(final Repository db) {
+	public static void register(Repository db) {
 		if (db.getDirectory() != null) {
 			FileKey key = FileKey.exact(db.getDirectory(), db.getFS());
 			cache.registerRepository(key, db);
@@ -144,7 +151,7 @@ public static void register(final Repository db) {
 	 * @param db
 	 *            repository to unregister.
 	 */
-	public static void close(@NonNull final Repository db) {
+	public static void close(@NonNull Repository db) {
 		if (db.getDirectory() != null) {
 			FileKey key = FileKey.exact(db.getDirectory(), db.getFS());
 			cache.unregisterAndCloseRepository(key);
@@ -156,14 +163,14 @@ public static void close(@NonNull final Repository db) {
 	 * <p>
 	 * Removes a repository from the cache, if it is still registered here. This
 	 * method will not close the repository, only remove it from the cache. See
-	 * {@link RepositoryCache#close(Repository)} to remove and close the
-	 * repository.
+	 * {@link org.eclipse.jgit.lib.RepositoryCache#close(Repository)} to remove
+	 * and close the repository.
 	 *
 	 * @param db
 	 *            repository to unregister.
 	 * @since 4.3
 	 */
-	public static void unregister(final Repository db) {
+	public static void unregister(Repository db) {
 		if (db.getDirectory() != null) {
 			unregister(FileKey.exact(db.getDirectory(), db.getFS()));
 		}
@@ -174,8 +181,8 @@ public static void unregister(final Repository db) {
 	 * <p>
 	 * Removes a repository from the cache, if it is still registered here. This
 	 * method will not close the repository, only remove it from the cache. See
-	 * {@link RepositoryCache#close(Repository)} to remove and close the
-	 * repository.
+	 * {@link org.eclipse.jgit.lib.RepositoryCache#close(Repository)} to remove
+	 * and close the repository.
 	 *
 	 * @param location
 	 *            location of the repository to remove.
@@ -186,6 +193,8 @@ public static void unregister(Key location) {
 	}
 
 	/**
+	 * Get the locations of all repositories registered in the cache.
+	 *
 	 * @return the locations of all repositories registered in the cache.
 	 * @since 4.1
 	 */
@@ -202,7 +211,9 @@ static boolean isCached(@NonNull Repository repo) {
 		return cache.cacheMap.get(key) == repo;
 	}
 
-	/** Unregister all repositories from the cache. */
+	/**
+	 * Unregister all repositories from the cache.
+	 */
 	public static void clear() {
 		cache.clearAll();
 	}
@@ -276,13 +287,13 @@ private Repository openRepository(final Key location,
 		return db;
 	}
 
-	private void registerRepository(final Key location, final Repository db) {
-		Repository oldDb = cacheMap.put(location, db);
-		if (oldDb != null)
-			oldDb.close();
+	private void registerRepository(Key location, Repository db) {
+		try (Repository oldDb = cacheMap.put(location, db)) {
+			// oldDb is auto-closed
+		}
 	}
 
-	private Repository unregisterRepository(final Key location) {
+	private Repository unregisterRepository(Key location) {
 		return cacheMap.remove(location);
 	}
 
@@ -291,7 +302,7 @@ private boolean isExpired(Repository db) {
 			&& (System.currentTimeMillis() - db.closedAt.get() > expireAfter);
 	}
 
-	private void unregisterAndCloseRepository(final Key location) {
+	private void unregisterAndCloseRepository(Key location) {
 		synchronized (lockFor(location)) {
 			Repository oldDb = unregisterRepository(location);
 			if (oldDb != null) {
@@ -318,7 +329,7 @@ private void clearAll() {
 		}
 	}
 
-	private Lock lockFor(final Key location) {
+	private Lock lockFor(Key location) {
 		return openLocks[(location.hashCode() >>> 1) % openLocks.length];
 	}
 
@@ -372,7 +383,7 @@ public static class FileKey implements Key {
 		 * @return a key for the given directory.
 		 * @see #lenient(File, FS)
 		 */
-		public static FileKey exact(final File directory, FS fs) {
+		public static FileKey exact(File directory, FS fs) {
 			return new FileKey(directory, fs);
 		}
 
@@ -395,7 +406,7 @@ public static FileKey exact(final File directory, FS fs) {
 		 * @return a key for the given directory.
 		 * @see #exact(File, FS)
 		 */
-		public static FileKey lenient(final File directory, FS fs) {
+		public static FileKey lenient(File directory, FS fs) {
 			final File gitdir = resolve(directory, fs);
 			return new FileKey(gitdir != null ? gitdir : directory, fs);
 		}
@@ -410,12 +421,12 @@ public static FileKey lenient(final File directory, FS fs) {
 		 *            the file system abstraction which will be necessary to
 		 *            perform certain file system operations.
 		 */
-		protected FileKey(final File directory, FS fs) {
+		protected FileKey(File directory, FS fs) {
 			path = canonical(directory);
 			this.fs = fs;
 		}
 
-		private static File canonical(final File path) {
+		private static File canonical(File path) {
 			try {
 				return path.getCanonicalFile();
 			} catch (IOException e) {
@@ -429,7 +440,7 @@ public final File getFile() {
 		}
 
 		@Override
-		public Repository open(final boolean mustExist) throws IOException {
+		public Repository open(boolean mustExist) throws IOException {
 			if (mustExist && !isGitRepository(path, fs))
 				throw new RepositoryNotFoundException(path);
 			return new FileRepository(path);
@@ -441,7 +452,7 @@ public int hashCode() {
 		}
 
 		@Override
-		public boolean equals(final Object o) {
+		public boolean equals(Object o) {
 			return o instanceof FileKey && path.equals(((FileKey) o).path);
 		}
 
@@ -465,19 +476,19 @@ public String toString() {
 		 *         it doesn't look enough like a Git directory to really be a
 		 *         Git directory.
 		 */
-		public static boolean isGitRepository(final File dir, FS fs) {
+		public static boolean isGitRepository(File dir, FS fs) {
 			return fs.resolve(dir, "objects").exists() //$NON-NLS-1$
 					&& fs.resolve(dir, "refs").exists() //$NON-NLS-1$
 					&& isValidHead(new File(dir, Constants.HEAD));
 		}
 
-		private static boolean isValidHead(final File head) {
+		private static boolean isValidHead(File head) {
 			final String ref = readFirstLine(head);
 			return ref != null
 					&& (ref.startsWith("ref: refs/") || ObjectId.isId(ref)); //$NON-NLS-1$
 		}
 
-		private static String readFirstLine(final File head) {
+		private static String readFirstLine(File head) {
 			try {
 				final byte[] buf = IO.readFully(head, 4096);
 				int n = buf.length;
@@ -510,7 +521,7 @@ private static String readFirstLine(final File head) {
 		 * @return the actual directory location if a better match is found;
 		 *         null if there is no suitable match.
 		 */
-		public static File resolve(final File directory, FS fs) {
+		public static File resolve(File directory, FS fs) {
 			if (isGitRepository(directory, fs))
 				return directory;
 			if (isGitRepository(new File(directory, Constants.DOT_GIT), fs))
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/RepositoryCacheConfig.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/RepositoryCacheConfig.java
index 28cdaae..3680dee 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/RepositoryCacheConfig.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/RepositoryCacheConfig.java
@@ -68,23 +68,32 @@ public class RepositoryCacheConfig {
 
 	private long cleanupDelayMillis;
 
-	/** Create a default configuration. */
+	/**
+	 * Create a default configuration.
+	 */
 	public RepositoryCacheConfig() {
 		expireAfterMillis = TimeUnit.HOURS.toMillis(1);
 		cleanupDelayMillis = AUTO_CLEANUP_DELAY;
 	}
 
 	/**
-	 * @return the time an unused repository should expired and be evicted from
-	 *         the RepositoryCache in milliseconds. <b>Default is 1 hour.</b>
+	 * Get the time an unused repository should be expired and be evicted from
+	 * the RepositoryCache in milliseconds.
+	 *
+	 * @return the time an unused repository should be expired and be evicted
+	 *         from the RepositoryCache in milliseconds. <b>Default is 1
+	 *         hour.</b>
 	 */
 	public long getExpireAfter() {
 		return expireAfterMillis;
 	}
 
 	/**
+	 * Set the time an unused repository should be expired and be evicted from
+	 * the RepositoryCache in milliseconds.
+	 *
 	 * @param expireAfterMillis
-	 *            the time an unused repository should expired and be evicted
+	 *            the time an unused repository should be expired and be evicted
 	 *            from the RepositoryCache in milliseconds.
 	 */
 	public void setExpireAfter(long expireAfterMillis) {
@@ -92,6 +101,9 @@ public void setExpireAfter(long expireAfterMillis) {
 	}
 
 	/**
+	 * Get the delay between the periodic cleanup of expired repository in
+	 * milliseconds.
+	 *
 	 * @return the delay between the periodic cleanup of expired repository in
 	 *         milliseconds. <b>Default is minimum of 1/10 of expireAfterMillis
 	 *         and 10 minutes</b>
@@ -105,6 +117,9 @@ public long getCleanupDelay() {
 	}
 
 	/**
+	 * Set the delay between the periodic cleanup of expired repository in
+	 * milliseconds.
+	 *
 	 * @param cleanupDelayMillis
 	 *            the delay between the periodic cleanup of expired repository
 	 *            in milliseconds. Set it to {@link #AUTO_CLEANUP_DELAY} to
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/RepositoryState.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/RepositoryState.java
index 9b7234b..c5d81b3 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/RepositoryState.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/RepositoryState.java
@@ -381,7 +381,9 @@ public String getDescription() {
 	};
 
 	/**
-	 * @return true if changing HEAD is sane.
+	 * Whether checkout can be done.
+	 *
+	 * @return whether checkout can be done.
 	 */
 	public abstract boolean canCheckout();
 
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/StoredConfig.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/StoredConfig.java
index 344d520..42ab891 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/StoredConfig.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/StoredConfig.java
@@ -51,7 +51,9 @@
  * Persistent configuration that can be stored and loaded from a location.
  */
 public abstract class StoredConfig extends Config {
-	/** Create a configuration with no default fallback. */
+	/**
+	 * Create a configuration with no default fallback.
+	 */
 	public StoredConfig() {
 		super();
 	}
@@ -73,9 +75,9 @@ public StoredConfig(Config defaultConfig) {
 	 * If the configuration does not exist, this configuration is cleared, and
 	 * thus behaves the same as though the backing store exists, but is empty.
 	 *
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the configuration could not be read (but does exist).
-	 * @throws ConfigInvalidException
+	 * @throws org.eclipse.jgit.errors.ConfigInvalidException
 	 *             the configuration is not properly formatted.
 	 */
 	public abstract void load() throws IOException, ConfigInvalidException;
@@ -83,11 +85,12 @@ public StoredConfig(Config defaultConfig) {
 	/**
 	 * Save the configuration to the persistent store.
 	 *
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the configuration could not be written.
 	 */
 	public abstract void save() throws IOException;
 
+	/** {@inheritDoc} */
 	@Override
 	public void clear() {
 		super.clear();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/SymbolicRef.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/SymbolicRef.java
index 71d5cd7..d4b83b0 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/SymbolicRef.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/SymbolicRef.java
@@ -47,7 +47,8 @@
 import org.eclipse.jgit.annotations.Nullable;
 
 /**
- * A reference that indirectly points at another {@link Ref}.
+ * A reference that indirectly points at another
+ * {@link org.eclipse.jgit.lib.Ref}.
  * <p>
  * A symbolic reference always derives its current value from the target
  * reference.
@@ -70,17 +71,20 @@ public SymbolicRef(@NonNull String refName, @NonNull Ref target) {
 		this.target = target;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	@NonNull
 	public String getName() {
 		return name;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public boolean isSymbolic() {
 		return true;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	@NonNull
 	public Ref getLeaf() {
@@ -90,35 +94,41 @@ public Ref getLeaf() {
 		return dst;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	@NonNull
 	public Ref getTarget() {
 		return target;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	@Nullable
 	public ObjectId getObjectId() {
 		return getLeaf().getObjectId();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	@NonNull
 	public Storage getStorage() {
 		return Storage.LOOSE;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	@Nullable
 	public ObjectId getPeeledObjectId() {
 		return getLeaf().getPeeledObjectId();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public boolean isPeeled() {
 		return getLeaf().isPeeled();
 	}
 
+	/** {@inheritDoc} */
 	@SuppressWarnings("nls")
 	@Override
 	public String toString() {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/TagBuilder.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/TagBuilder.java
index 3490a5b..bd03165 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/TagBuilder.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/TagBuilder.java
@@ -72,12 +72,20 @@ public class TagBuilder {
 
 	private String message;
 
-	/** @return the type of object this tag refers to. */
+	/**
+	 * Get the type of object this tag refers to.
+	 *
+	 * @return the type of object this tag refers to.
+	 */
 	public int getObjectType() {
 		return type;
 	}
 
-	/** @return the object this tag refers to. */
+	/**
+	 * Get the object this tag refers to.
+	 *
+	 * @return the object this tag refers to.
+	 */
 	public ObjectId getObjectId() {
 		return object;
 	}
@@ -105,7 +113,11 @@ public void setObjectId(RevObject obj) {
 		setObjectId(obj, obj.getType());
 	}
 
-	/** @return short name of the tag (no {@code refs/tags/} prefix). */
+	/**
+	 * Get short name of the tag (no {@code refs/tags/} prefix).
+	 *
+	 * @return short name of the tag (no {@code refs/tags/} prefix).
+	 */
 	public String getTag() {
 		return tag;
 	}
@@ -122,7 +134,11 @@ public void setTag(String shortName) {
 		this.tag = shortName;
 	}
 
-	/** @return creator of this tag. May be null. */
+	/**
+	 * Get creator of this tag.
+	 *
+	 * @return creator of this tag. May be null.
+	 */
 	public PersonIdent getTagger() {
 		return tagger;
 	}
@@ -137,7 +153,11 @@ public void setTagger(PersonIdent taggerIdent) {
 		tagger = taggerIdent;
 	}
 
-	/** @return the complete commit message. */
+	/**
+	 * Get the complete commit message.
+	 *
+	 * @return the complete commit message.
+	 */
 	public String getMessage() {
 		return message;
 	}
@@ -148,7 +168,7 @@ public String getMessage() {
 	 * @param newMessage
 	 *            the tag's message.
 	 */
-	public void setMessage(final String newMessage) {
+	public void setMessage(String newMessage) {
 		message = newMessage;
 	}
 
@@ -160,8 +180,8 @@ public void setMessage(final String newMessage) {
 	 */
 	public byte[] build() {
 		ByteArrayOutputStream os = new ByteArrayOutputStream();
-		OutputStreamWriter w = new OutputStreamWriter(os, Constants.CHARSET);
-		try {
+		try (OutputStreamWriter w = new OutputStreamWriter(os,
+				Constants.CHARSET)) {
 			w.write("object "); //$NON-NLS-1$
 			getObjectId().copyTo(w);
 			w.write('\n');
@@ -183,7 +203,6 @@ public void setMessage(final String newMessage) {
 			w.write('\n');
 			if (getMessage() != null)
 				w.write(getMessage());
-			w.close();
 		} catch (IOException err) {
 			// This should never occur, the only way to get it above is
 			// for the ByteArrayOutputStream to throw, but it doesn't.
@@ -203,6 +222,7 @@ public void setMessage(final String newMessage) {
 		return build();
 	}
 
+	/** {@inheritDoc} */
 	@SuppressWarnings("nls")
 	@Override
 	public String toString() {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/TextProgressMonitor.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/TextProgressMonitor.java
index c31c3c6..2f759e5 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/TextProgressMonitor.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/TextProgressMonitor.java
@@ -44,22 +44,26 @@
 
 package org.eclipse.jgit.lib;
 
-import static java.nio.charset.StandardCharsets.UTF_8;
+import static org.eclipse.jgit.lib.Constants.CHARSET;
 
 import java.io.IOException;
 import java.io.OutputStreamWriter;
 import java.io.PrintWriter;
 import java.io.Writer;
 
-/** A simple progress reporter printing on a stream. */
+/**
+ * A simple progress reporter printing on a stream.
+ */
 public class TextProgressMonitor extends BatchingProgressMonitor {
 	private final Writer out;
 
 	private boolean write;
 
-	/** Initialize a new progress monitor. */
+	/**
+	 * Initialize a new progress monitor.
+	 */
 	public TextProgressMonitor() {
-		this(new PrintWriter(new OutputStreamWriter(System.err, UTF_8)));
+		this(new PrintWriter(new OutputStreamWriter(System.err, CHARSET)));
 	}
 
 	/**
@@ -73,6 +77,7 @@ public TextProgressMonitor(Writer out) {
 		this.write = true;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected void onUpdate(String taskName, int workCurr) {
 		StringBuilder s = new StringBuilder();
@@ -80,6 +85,7 @@ protected void onUpdate(String taskName, int workCurr) {
 		send(s);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected void onEndTask(String taskName, int workCurr) {
 		StringBuilder s = new StringBuilder();
@@ -97,6 +103,7 @@ private void format(StringBuilder s, String taskName, int workCurr) {
 		s.append(workCurr);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected void onUpdate(String taskName, int cmp, int totalWork, int pcnt) {
 		StringBuilder s = new StringBuilder();
@@ -104,6 +111,7 @@ protected void onUpdate(String taskName, int cmp, int totalWork, int pcnt) {
 		send(s);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected void onEndTask(String taskName, int cmp, int totalWork, int pcnt) {
 		StringBuilder s = new StringBuilder();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ThreadSafeProgressMonitor.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ThreadSafeProgressMonitor.java
index 5824a55..7e7d45d 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ThreadSafeProgressMonitor.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ThreadSafeProgressMonitor.java
@@ -48,7 +48,8 @@
 import java.util.concurrent.locks.ReentrantLock;
 
 /**
- * Wrapper around the general {@link ProgressMonitor} to make it thread safe.
+ * Wrapper around the general {@link org.eclipse.jgit.lib.ProgressMonitor} to
+ * make it thread safe.
  *
  * Updates to the underlying ProgressMonitor are made only from the thread that
  * allocated this wrapper. Callers are responsible for ensuring the allocating
@@ -87,6 +88,7 @@ public ThreadSafeProgressMonitor(ProgressMonitor pm) {
 		this.process = new Semaphore(0);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void start(int totalTasks) {
 		if (!isMainThread())
@@ -94,6 +96,7 @@ public void start(int totalTasks) {
 		pm.start(totalTasks);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void beginTask(String title, int totalWork) {
 		if (!isMainThread())
@@ -101,7 +104,9 @@ public void beginTask(String title, int totalWork) {
 		pm.beginTask(title, totalWork);
 	}
 
-	/** Notify the monitor a worker is starting. */
+	/**
+	 * Notify the monitor a worker is starting.
+	 */
 	public void startWorker() {
 		startWorkers(1);
 	}
@@ -116,7 +121,9 @@ public void startWorkers(int count) {
 		workers.addAndGet(count);
 	}
 
-	/** Notify the monitor a worker is finished. */
+	/**
+	 * Notify the monitor a worker is finished.
+	 */
 	public void endWorker() {
 		if (workers.decrementAndGet() == 0)
 			process.release();
@@ -139,7 +146,7 @@ public void pollForUpdates() {
 	 * This method can only be invoked by the same thread that allocated this
 	 * ThreadSafeProgressMonior.
 	 *
-	 * @throws InterruptedException
+	 * @throws java.lang.InterruptedException
 	 *             if the main thread is interrupted while waiting for
 	 *             completion of workers.
 	 */
@@ -158,12 +165,14 @@ private void doUpdates() {
 			pm.update(cnt);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void update(int completed) {
 		if (0 == pendingUpdates.getAndAdd(completed))
 			process.release();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public boolean isCancelled() {
 		lock.lock();
@@ -174,6 +183,7 @@ public boolean isCancelled() {
 		}
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void endTask() {
 		if (!isMainThread())
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/TreeFormatter.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/TreeFormatter.java
index 777ce94..0d78d59 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/TreeFormatter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/TreeFormatter.java
@@ -94,7 +94,9 @@ public static int entrySize(FileMode mode, int nameLen) {
 
 	private TemporaryBuffer.Heap overflowBuffer;
 
-	/** Create an empty formatter with a default buffer size. */
+	/**
+	 * Create an empty formatter with a default buffer size.
+	 */
 	public TreeFormatter() {
 		this(8192);
 	}
@@ -112,7 +114,7 @@ public TreeFormatter(int size) {
 	}
 
 	/**
-	 * Add a link to a submodule commit, mode is {@link FileMode#GITLINK}.
+	 * Add a link to a submodule commit, mode is {@link org.eclipse.jgit.lib.FileMode#GITLINK}.
 	 *
 	 * @param name
 	 *            name of the entry.
@@ -124,7 +126,7 @@ public void append(String name, RevCommit commit) {
 	}
 
 	/**
-	 * Add a subtree, mode is {@link FileMode#TREE}.
+	 * Add a subtree, mode is {@link org.eclipse.jgit.lib.FileMode#TREE}.
 	 *
 	 * @param name
 	 *            name of the entry.
@@ -136,7 +138,7 @@ public void append(String name, RevTree tree) {
 	}
 
 	/**
-	 * Add a regular file, mode is {@link FileMode#REGULAR_FILE}.
+	 * Add a regular file, mode is {@link org.eclipse.jgit.lib.FileMode#REGULAR_FILE}.
 	 *
 	 * @param name
 	 *            name of the entry.
@@ -307,7 +309,7 @@ private void fmtOverflowBuffer(byte[] nameBuf, int namePos, int nameLen,
 	 * @param ins
 	 *            the inserter to store the tree.
 	 * @return computed ObjectId of the tree
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the tree could not be stored.
 	 */
 	public ObjectId insertTo(ObjectInserter ins) throws IOException {
@@ -321,7 +323,7 @@ public ObjectId insertTo(ObjectInserter ins) throws IOException {
 	/**
 	 * Compute the ObjectId for this tree
 	 *
-	 * @param ins
+	 * @param ins a {@link org.eclipse.jgit.lib.ObjectInserter} object.
 	 * @return ObjectId for this tree
 	 */
 	public ObjectId computeId(ObjectInserter ins) {
@@ -343,7 +345,8 @@ public ObjectId computeId(ObjectInserter ins) {
 	 * This method is not efficient, as it needs to create a copy of the
 	 * internal buffer in order to supply an array of the correct size to the
 	 * caller. If the buffer is just to pass to an ObjectInserter, consider
-	 * using {@link ObjectInserter#insert(TreeFormatter)} instead.
+	 * using {@link org.eclipse.jgit.lib.ObjectInserter#insert(TreeFormatter)}
+	 * instead.
 	 *
 	 * @return a copy of this formatter's buffer.
 	 */
@@ -362,6 +365,7 @@ public ObjectId computeId(ObjectInserter ins) {
 		}
 	}
 
+	/** {@inheritDoc} */
 	@SuppressWarnings("nls")
 	@Override
 	public String toString() {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/TypedConfigGetter.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/TypedConfigGetter.java
index 594edef..aca2ad2 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/TypedConfigGetter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/TypedConfigGetter.java
@@ -50,15 +50,15 @@
 import org.eclipse.jgit.transport.RefSpec;
 
 /**
- * Something that knows how to convert plain strings from a git {@link Config}
- * to typed values.
+ * Something that knows how to convert plain strings from a git
+ * {@link org.eclipse.jgit.lib.Config} to typed values.
  *
  * @since 4.9
  */
 public interface TypedConfigGetter {
 
 	/**
-	 * Get a boolean value from a git {@link Config}.
+	 * Get a boolean value from a git {@link org.eclipse.jgit.lib.Config}.
 	 *
 	 * @param config
 	 *            to get the value from
@@ -77,10 +77,8 @@ boolean getBoolean(Config config, String section, String subsection,
 			String name, boolean defaultValue);
 
 	/**
-	 * Parse an enumeration from a git {@link Config}.
+	 * Parse an enumeration from a git {@link org.eclipse.jgit.lib.Config}.
 	 *
-	 * @param <T>
-	 *            type of the enumeration object.
 	 * @param config
 	 *            to get the value from
 	 * @param all
@@ -100,7 +98,7 @@ <T extends Enum<?>> T getEnum(Config config, T[] all, String section,
 			String subsection, String name, T defaultValue);
 
 	/**
-	 * Obtain an integer value from a git {@link Config}.
+	 * Obtain an integer value from a git {@link org.eclipse.jgit.lib.Config}.
 	 *
 	 * @param config
 	 *            to get the value from
@@ -118,7 +116,7 @@ int getInt(Config config, String section, String subsection, String name,
 			int defaultValue);
 
 	/**
-	 * Obtain a long value from a git {@link Config}.
+	 * Obtain a long value from a git {@link org.eclipse.jgit.lib.Config}.
 	 *
 	 * @param config
 	 *            to get the value from
@@ -137,7 +135,7 @@ long getLong(Config config, String section, String subsection, String name,
 
 	/**
 	 * Parse a numerical time unit, such as "1 minute", from a git
-	 * {@link Config}.
+	 * {@link org.eclipse.jgit.lib.Config}.
 	 *
 	 * @param config
 	 *            to get the value from
@@ -161,7 +159,8 @@ long getTimeUnit(Config config, String section, String subsection,
 
 
 	/**
-	 * Parse a list of {@link RefSpec}s from a git {@link Config}.
+	 * Parse a list of {@link org.eclipse.jgit.transport.RefSpec}s from a git
+	 * {@link org.eclipse.jgit.lib.Config}.
 	 *
 	 * @param config
 	 *            to get the list from
@@ -171,7 +170,8 @@ long getTimeUnit(Config config, String section, String subsection,
 	 *            subsection the key is in, or null if not in a subsection.
 	 * @param name
 	 *            the key name.
-	 * @return a possibly empty list of {@link RefSpec}s
+	 * @return a possibly empty list of
+	 *         {@link org.eclipse.jgit.transport.RefSpec}s
 	 */
 	@NonNull
 	List<RefSpec> getRefSpecs(Config config, String section, String subsection,
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/UserConfig.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/UserConfig.java
index 102a451..bfb5e2f 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/UserConfig.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/UserConfig.java
@@ -48,7 +48,9 @@
 import org.eclipse.jgit.lib.Config.SectionParser;
 import org.eclipse.jgit.util.SystemReader;
 
-/** The standard "user" configuration parameters. */
+/**
+ * The standard "user" configuration parameters.
+ */
 public class UserConfig {
 	/** Key for {@link Config#get(SectionParser)}. */
 	public static final Config.SectionParser<UserConfig> KEY = UserConfig::new;
@@ -69,7 +71,7 @@ public class UserConfig {
 
 	private boolean isCommitterEmailImplicit;
 
-	private UserConfig(final Config rc) {
+	private UserConfig(Config rc) {
 		authorName = getNameInternal(rc, Constants.GIT_AUTHOR_NAME_KEY);
 		if (authorName == null) {
 			authorName = getDefaultUserName();
@@ -94,6 +96,8 @@ private UserConfig(final Config rc) {
 	}
 
 	/**
+	 * Get the author name as defined in the git variables and configurations.
+	 *
 	 * @return the author name as defined in the git variables and
 	 *         configurations. If no name could be found, try to use the system
 	 *         user name instead.
@@ -103,6 +107,9 @@ public String getAuthorName() {
 	}
 
 	/**
+	 * Get the committer name as defined in the git variables and
+	 * configurations.
+	 *
 	 * @return the committer name as defined in the git variables and
 	 *         configurations. If no name could be found, try to use the system
 	 *         user name instead.
@@ -112,26 +119,31 @@ public String getCommitterName() {
 	}
 
 	/**
-	 * @return the author email as defined in git variables and
-	 *         configurations. If no email could be found, try to
-	 *         propose one default with the user name and the
-	 *         host name.
+	 * Get the author email as defined in git variables and configurations.
+	 *
+	 * @return the author email as defined in git variables and configurations.
+	 *         If no email could be found, try to propose one default with the
+	 *         user name and the host name.
 	 */
 	public String getAuthorEmail() {
 		return authorEmail;
 	}
 
 	/**
+	 * Get the committer email as defined in git variables and configurations.
+	 *
 	 * @return the committer email as defined in git variables and
-	 *         configurations. If no email could be found, try to
-	 *         propose one default with the user name and the
-	 *         host name.
+	 *         configurations. If no email could be found, try to propose one
+	 *         default with the user name and the host name.
 	 */
 	public String getCommitterEmail() {
 		return committerEmail;
 	}
 
 	/**
+	 * Whether the author name was not explicitly configured but constructed
+	 * from information the system has about the logged on user
+	 *
 	 * @return true if the author name was not explicitly configured but
 	 *         constructed from information the system has about the logged on
 	 *         user
@@ -141,6 +153,9 @@ public boolean isAuthorNameImplicit() {
 	}
 
 	/**
+	 * Whether the author email was not explicitly configured but constructed
+	 * from information the system has about the logged on user
+	 *
 	 * @return true if the author email was not explicitly configured but
 	 *         constructed from information the system has about the logged on
 	 *         user
@@ -150,6 +165,9 @@ public boolean isAuthorEmailImplicit() {
 	}
 
 	/**
+	 * Whether the committer name was not explicitly configured but constructed
+	 * from information the system has about the logged on user
+	 *
 	 * @return true if the committer name was not explicitly configured but
 	 *         constructed from information the system has about the logged on
 	 *         user
@@ -159,6 +177,9 @@ public boolean isCommitterNameImplicit() {
 	}
 
 	/**
+	 * Whether the author email was not explicitly configured but constructed
+	 * from information the system has about the logged on user
+	 *
 	 * @return true if the author email was not explicitly configured but
 	 *         constructed from information the system has about the logged on
 	 *         user
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/internal/WorkQueue.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/internal/WorkQueue.java
index 3303f47..8f8aad5 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/internal/WorkQueue.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/internal/WorkQueue.java
@@ -71,6 +71,7 @@ public class WorkQueue {
 					public Thread newThread(Runnable taskBody) {
 						Thread thr = baseFactory.newThread(taskBody);
 						thr.setName("JGit-WorkQueue"); //$NON-NLS-1$
+						thr.setContextClassLoader(null);
 						thr.setDaemon(true);
 						return thr;
 					}
@@ -95,6 +96,8 @@ protected void finalize() {
 	}
 
 	/**
+	 * Get the WorkQueue's executor
+	 *
 	 * @return the WorkQueue's executor
 	 */
 	public static ScheduledThreadPoolExecutor getExecutor() {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/merge/EolAwareOutputStream.java b/org.eclipse.jgit/src/org/eclipse/jgit/merge/EolAwareOutputStream.java
index 1ddac18..e44970a 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/merge/EolAwareOutputStream.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/merge/EolAwareOutputStream.java
@@ -79,12 +79,14 @@ boolean isBeginln() {
 		return bol;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void write(int val) throws IOException {
 		out.write(val);
 		bol = (val == '\n');
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void write(byte[] buf, int pos, int cnt) throws IOException {
 		if (cnt > 0) {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeAlgorithm.java b/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeAlgorithm.java
index 04c65ef..dd42e43 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeAlgorithm.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeAlgorithm.java
@@ -57,14 +57,15 @@
 
 /**
  * Provides the merge algorithm which does a three-way merge on content provided
- * as RawText. By default {@link HistogramDiff} is used as diff algorithm.
+ * as RawText. By default {@link org.eclipse.jgit.diff.HistogramDiff} is used as
+ * diff algorithm.
  */
 public final class MergeAlgorithm {
 	private final DiffAlgorithm diffAlg;
 
 	/**
-	 * Creates a new MergeAlgorithm which uses {@link HistogramDiff} as diff
-	 * algorithm
+	 * Creates a new MergeAlgorithm which uses
+	 * {@link org.eclipse.jgit.diff.HistogramDiff} as diff algorithm
 	 */
 	public MergeAlgorithm() {
 		this(new HistogramDiff());
@@ -88,8 +89,6 @@ public MergeAlgorithm(DiffAlgorithm diff) {
 	/**
 	 * Does the three way merge between a common base and two sequences.
 	 *
-	 * @param <S>
-	 *            type of sequence.
 	 * @param cmp comparison method for this execution.
 	 * @param base the common base sequence
 	 * @param ours the first sequence to be merged
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeChunk.java b/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeChunk.java
index 72857ff..3867eea 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeChunk.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeChunk.java
@@ -97,7 +97,8 @@ public enum ConflictState {
 	 *            merge result. All elements between begin (including begin) and
 	 *            this element are added.
 	 * @param conflictState
-	 *            the state of this chunk. See {@link ConflictState}
+	 *            the state of this chunk. See
+	 *            {@link org.eclipse.jgit.merge.MergeChunk.ConflictState}
 	 */
 	protected MergeChunk(int sequenceIndex, int begin, int end,
 			ConflictState conflictState) {
@@ -108,7 +109,9 @@ protected MergeChunk(int sequenceIndex, int begin, int end,
 	}
 
 	/**
-	 * @return the index of the sequence to which sequence this chunks belongs
+	 * Get the index of the sequence to which this sequence chunks belongs to.
+	 *
+	 * @return the index of the sequence to which this sequence chunks belongs
 	 *         to. Same as in {@link org.eclipse.jgit.merge.MergeResult#add}
 	 */
 	public int getSequenceIndex() {
@@ -116,6 +119,9 @@ public int getSequenceIndex() {
 	}
 
 	/**
+	 * Get the first element from the specified sequence which should be
+	 * included in the merge result.
+	 *
 	 * @return the first element from the specified sequence which should be
 	 *         included in the merge result. Indexes start with 0.
 	 */
@@ -124,17 +130,22 @@ public int getBegin() {
 	}
 
 	/**
-	 * @return the end of the range of this chunk. The element this index
-	 *         points to is the first element which not added to the merge
-	 *         result. All elements between begin (including begin) and this
-	 *         element are added.
+	 * Get the end of the range of this chunk.
+	 *
+	 * @return the end of the range of this chunk. The element this index points
+	 *         to is the first element which not added to the merge result. All
+	 *         elements between begin (including begin) and this element are
+	 *         added.
 	 */
 	public int getEnd() {
 		return end;
 	}
 
 	/**
-	 * @return the state of this chunk. See {@link ConflictState}
+	 * Get the state of this chunk.
+	 *
+	 * @return the state of this chunk. See
+	 *         {@link org.eclipse.jgit.merge.MergeChunk.ConflictState}
 	 */
 	public ConflictState getConflictState() {
 		return conflictState;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeConfig.java b/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeConfig.java
index d059391..cdbe3cd 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeConfig.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeConfig.java
@@ -58,7 +58,10 @@
 public class MergeConfig {
 
 	/**
+	 * Get merge configuration for the current branch of the repository
+	 *
 	 * @param repo
+	 *            a {@link org.eclipse.jgit.lib.Repository} object.
 	 * @return merge configuration for the current branch of the repository
 	 */
 	public static MergeConfig getConfigForCurrentBranch(Repository repo) {
@@ -74,10 +77,14 @@ public static MergeConfig getConfigForCurrentBranch(Repository repo) {
 	}
 
 	/**
+	 * Get a parser for use with
+	 * {@link org.eclipse.jgit.lib.Config#get(SectionParser)}
+	 *
 	 * @param branch
 	 *            short branch name to get the configuration for, as returned
-	 *            e.g. by {@link Repository#getBranch()}
-	 * @return a parser for use with {@link Config#get(SectionParser)}
+	 *            e.g. by {@link org.eclipse.jgit.lib.Repository#getBranch()}
+	 * @return a parser for use with
+	 *         {@link org.eclipse.jgit.lib.Config#get(SectionParser)}
 	 */
 	public static final SectionParser<MergeConfig> getParser(
 			final String branch) {
@@ -104,6 +111,8 @@ private MergeConfig() {
 	}
 
 	/**
+	 * Get the fast forward mode configured for this branch
+	 *
 	 * @return the fast forward mode configured for this branch
 	 */
 	public FastForwardMode getFastForwardMode() {
@@ -111,6 +120,9 @@ public FastForwardMode getFastForwardMode() {
 	}
 
 	/**
+	 * Whether merges into this branch are configured to be squash merges, false
+	 * otherwise
+	 *
 	 * @return true if merges into this branch are configured to be squash
 	 *         merges, false otherwise
 	 */
@@ -119,8 +131,10 @@ public boolean isSquash() {
 	}
 
 	/**
-	 * @return false if --no-commit is configured for this branch, true
-	 *         otherwise (event if --squash is configured)
+	 * Whether {@code --no-commit} option is not set.
+	 *
+	 * @return {@code false} if --no-commit is configured for this branch,
+	 *         {@code true} otherwise (even if --squash is configured)
 	 */
 	public boolean isCommit() {
 		return commit;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeFormatter.java b/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeFormatter.java
index 43876a6..036917e 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeFormatter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeFormatter.java
@@ -55,11 +55,12 @@
  */
 public class MergeFormatter {
 	/**
-	 * Formats the results of a merge of {@link RawText} objects in a Git
-	 * conformant way. This method also assumes that the {@link RawText} objects
-	 * being merged are line oriented files which use LF as delimiter. This
-	 * method will also use LF to separate chunks and conflict metadata,
-	 * therefore it fits only to texts that are LF-separated lines.
+	 * Formats the results of a merge of {@link org.eclipse.jgit.diff.RawText}
+	 * objects in a Git conformant way. This method also assumes that the
+	 * {@link org.eclipse.jgit.diff.RawText} objects being merged are line
+	 * oriented files which use LF as delimiter. This method will also use LF to
+	 * separate chunks and conflict metadata, therefore it fits only to texts
+	 * that are LF-separated lines.
 	 *
 	 * @param out
 	 *            the outputstream where to write the textual presentation
@@ -67,13 +68,13 @@ public class MergeFormatter {
 	 *            the merge result which should be presented
 	 * @param seqName
 	 *            When a conflict is reported each conflicting range will get a
-	 *            name. This name is following the "&lt;&lt;&lt;&lt;&lt;&lt;&lt; " or "&gt;&gt;&gt;&gt;&gt;&gt;&gt; "
-	 *            conflict markers. The names for the sequences are given in
-	 *            this list
+	 *            name. This name is following the "&lt;&lt;&lt;&lt;&lt;&lt;&lt;
+	 *            " or "&gt;&gt;&gt;&gt;&gt;&gt;&gt; " conflict markers. The
+	 *            names for the sequences are given in this list
 	 * @param charsetName
 	 *            the name of the characterSet used when writing conflict
 	 *            metadata
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 */
 	public void formatMerge(OutputStream out, MergeResult<RawText> res,
 			List<String> seqName, String charsetName) throws IOException {
@@ -81,13 +82,14 @@ public void formatMerge(OutputStream out, MergeResult<RawText> res,
 	}
 
 	/**
-	 * Formats the results of a merge of exactly two {@link RawText} objects in
-	 * a Git conformant way. This convenience method accepts the names for the
-	 * three sequences (base and the two merged sequences) as explicit
-	 * parameters and doesn't require the caller to specify a List
+	 * Formats the results of a merge of exactly two
+	 * {@link org.eclipse.jgit.diff.RawText} objects in a Git conformant way.
+	 * This convenience method accepts the names for the three sequences (base
+	 * and the two merged sequences) as explicit parameters and doesn't require
+	 * the caller to specify a List
 	 *
 	 * @param out
-	 *            the {@link OutputStream} where to write the textual
+	 *            the {@link java.io.OutputStream} where to write the textual
 	 *            presentation
 	 * @param res
 	 *            the merge result which should be presented
@@ -100,7 +102,7 @@ public void formatMerge(OutputStream out, MergeResult<RawText> res,
 	 * @param charsetName
 	 *            the name of the characterSet used when writing conflict
 	 *            metadata
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 */
 	@SuppressWarnings("unchecked")
 	public void formatMerge(OutputStream out, MergeResult res, String baseName,
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeResult.java b/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeResult.java
index ff3c8ab..062d86f 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeResult.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeResult.java
@@ -51,14 +51,14 @@
 import org.eclipse.jgit.util.IntList;
 
 /**
- * The result of merging a number of {@link Sequence} objects. These sequences
- * have one common predecessor sequence. The result of a merge is a list of
- * MergeChunks. Each MergeChunk contains either a range (a subsequence) from
- * one of the merged sequences, a range from the common predecessor or a
- * conflicting range from one of the merged sequences. A conflict will be
- * reported as multiple chunks, one for each conflicting range. The first chunk
- * for a conflict is marked specially to distinguish the border between two
- * consecutive conflicts.
+ * The result of merging a number of {@link org.eclipse.jgit.diff.Sequence}
+ * objects. These sequences have one common predecessor sequence. The result of
+ * a merge is a list of MergeChunks. Each MergeChunk contains either a range (a
+ * subsequence) from one of the merged sequences, a range from the common
+ * predecessor or a conflicting range from one of the merged sequences. A
+ * conflict will be reported as multiple chunks, one for each conflicting range.
+ * The first chunk for a conflict is marked specially to distinguish the border
+ * between two consecutive conflicts.
  * <p>
  * This class does not know anything about how to present the merge result to
  * the end-user. MergeFormatters have to be used to construct something human
@@ -80,7 +80,8 @@ public class MergeResult<S extends Sequence> implements Iterable<MergeChunk> {
 	 * @param sequences
 	 *            contains the common predecessor sequence at position 0
 	 *            followed by the merged sequences. This list should not be
-	 *            modified anymore during the lifetime of this {@link MergeResult}.
+	 *            modified anymore during the lifetime of this
+	 *            {@link org.eclipse.jgit.merge.MergeResult}.
 	 */
 	public MergeResult(List<S> sequences) {
 		this.sequences = sequences;
@@ -129,10 +130,7 @@ public List<S> getSequences() {
 
 	static final ConflictState[] states = ConflictState.values();
 
-	/**
-	 * @return an iterator over the MergeChunks. The iterator does not support
-	 * the remove operation
-	 */
+	/** {@inheritDoc} */
 	@Override
 	public Iterator<MergeChunk> iterator() {
 		return new Iterator<MergeChunk>() {
@@ -160,6 +158,8 @@ public void remove() {
 	}
 
 	/**
+	 * Whether this merge result contains conflicts
+	 *
 	 * @return true if this merge result contains conflicts
 	 */
 	public boolean containsConflicts() {
@@ -173,6 +173,8 @@ public boolean containsConflicts() {
 	 * markers!) as new conflict-free content
 	 *
 	 * @param containsConflicts
+	 *            whether this merge should be seen as containing a conflict or
+	 *            not.
 	 * @since 3.5
 	 */
 	protected void setContainsConflicts(boolean containsConflicts) {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeStrategy.java b/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeStrategy.java
index af3d5ca..98a706c 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeStrategy.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeStrategy.java
@@ -97,10 +97,10 @@ public abstract class MergeStrategy {
 	 *
 	 * @param imp
 	 *            the strategy to register.
-	 * @throws IllegalArgumentException
+	 * @throws java.lang.IllegalArgumentException
 	 *             a strategy by the same name has already been registered.
 	 */
-	public static void register(final MergeStrategy imp) {
+	public static void register(MergeStrategy imp) {
 		register(imp.getName(), imp);
 	}
 
@@ -111,7 +111,7 @@ public static void register(final MergeStrategy imp) {
 	 *            name the strategy can be looked up under.
 	 * @param imp
 	 *            the strategy to register.
-	 * @throws IllegalArgumentException
+	 * @throws java.lang.IllegalArgumentException
 	 *             a strategy by the same name has already been registered.
 	 */
 	public static synchronized void register(final String name,
@@ -129,7 +129,7 @@ public static synchronized void register(final String name,
 	 *            name of the strategy to locate.
 	 * @return the strategy instance; null if no strategy matches the name.
 	 */
-	public static synchronized MergeStrategy get(final String name) {
+	public static synchronized MergeStrategy get(String name) {
 		return STRATEGIES.get(name);
 	}
 
@@ -146,7 +146,11 @@ public static synchronized MergeStrategy get(final String name) {
 		return r;
 	}
 
-	/** @return default name of this strategy implementation. */
+	/**
+	 * Get default name of this strategy implementation.
+	 *
+	 * @return default name of this strategy implementation.
+	 */
 	public abstract String getName();
 
 	/**
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/merge/Merger.java b/org.eclipse.jgit/src/org/eclipse/jgit/merge/Merger.java
index 0c4488c..25eb1af 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/merge/Merger.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/merge/Merger.java
@@ -68,7 +68,8 @@
 import org.eclipse.jgit.treewalk.CanonicalTreeParser;
 
 /**
- * Instance of a specific {@link MergeStrategy} for a single {@link Repository}.
+ * Instance of a specific {@link org.eclipse.jgit.merge.MergeStrategy} for a
+ * single {@link org.eclipse.jgit.lib.Repository}.
  */
 public abstract class Merger {
 	/**
@@ -112,7 +113,7 @@ public abstract class Merger {
 	 * @param local
 	 *            the repository this merger will read and write data on.
 	 */
-	protected Merger(final Repository local) {
+	protected Merger(Repository local) {
 		if (local == null) {
 			throw new NullPointerException(JGitText.get().repositoryIsRequired);
 		}
@@ -138,6 +139,8 @@ protected Merger(ObjectInserter oi) {
 	}
 
 	/**
+	 * Get the repository this merger operates on.
+	 *
 	 * @return the repository this merger operates on.
 	 */
 	@Nullable
@@ -146,8 +149,10 @@ public Repository getRepository() {
 	}
 
 	/**
+	 * Get non-null repository instance
+	 *
 	 * @return non-null repository instance
-	 * @throws NullPointerException
+	 * @throws java.lang.NullPointerException
 	 *             if the merger was constructed without a repository.
 	 * @since 4.8
 	 */
@@ -159,8 +164,11 @@ protected Repository nonNullRepo() {
 	}
 
 	/**
-	 * @return an object writer to create objects, writing objects to {@link
-	 * #getRepository()} (if a repository was provided).
+	 * Get an object writer to create objects, writing objects to
+	 * {@link #getRepository()}
+	 *
+	 * @return an object writer to create objects, writing objects to
+	 *         {@link #getRepository()} (if a repository was provided).
 	 */
 	public ObjectInserter getObjectInserter() {
 		return inserter;
@@ -203,11 +211,11 @@ public void setObjectInserter(ObjectInserter oi) {
 	 * @throws IncorrectObjectTypeException
 	 *             one of the input objects is not a commit, but the strategy
 	 *             requires it to be a commit.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             one or more sources could not be read, or outputs could not
 	 *             be written to the Repository.
 	 */
-	public boolean merge(final AnyObjectId... tips) throws IOException {
+	public boolean merge(AnyObjectId... tips) throws IOException {
 		return merge(true, tips);
 	}
 
@@ -231,11 +239,11 @@ public boolean merge(final AnyObjectId... tips) throws IOException {
 	 * @throws IncorrectObjectTypeException
 	 *             one of the input objects is not a commit, but the strategy
 	 *             requires it to be a commit.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             one or more sources could not be read, or outputs could not
 	 *             be written to the Repository.
 	 */
-	public boolean merge(final boolean flush, final AnyObjectId... tips)
+	public boolean merge(boolean flush, AnyObjectId... tips)
 			throws IOException {
 		sourceObjects = new RevObject[tips.length];
 		for (int i = 0; i < tips.length; i++)
@@ -267,6 +275,8 @@ public boolean merge(final boolean flush, final AnyObjectId... tips)
 	}
 
 	/**
+	 * Get the ID of the commit that was used as merge base for merging
+	 *
 	 * @return the ID of the commit that was used as merge base for merging, or
 	 *         null if no merge base was used or it was set manually
 	 * @since 3.2
@@ -281,9 +291,9 @@ public boolean merge(final boolean flush, final AnyObjectId... tips)
 	 * @param b
 	 *            the second commit in {@link #sourceObjects}.
 	 * @return the merge base of two commits
-	 * @throws IncorrectObjectTypeException
+	 * @throws org.eclipse.jgit.errors.IncorrectObjectTypeException
 	 *             one of the input objects is not a commit.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             objects are missing or multiple merge bases were found.
 	 * @since 3.0
 	 */
@@ -313,12 +323,12 @@ protected RevCommit getBaseCommit(RevCommit a, RevCommit b)
 	 * @param treeId
 	 *            the tree to scan; must be a tree (not a treeish).
 	 * @return an iterator for the tree.
-	 * @throws IncorrectObjectTypeException
+	 * @throws org.eclipse.jgit.errors.IncorrectObjectTypeException
 	 *             the input object is not a tree.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the tree object is not found or cannot be read.
 	 */
-	protected AbstractTreeIterator openTree(final AnyObjectId treeId)
+	protected AbstractTreeIterator openTree(AnyObjectId treeId)
 			throws IncorrectObjectTypeException, IOException {
 		return new CanonicalTreeParser(null, reader, treeId);
 	}
@@ -336,13 +346,15 @@ protected AbstractTreeIterator openTree(final AnyObjectId treeId)
 	 * @throws IncorrectObjectTypeException
 	 *             one of the input objects is not a commit, but the strategy
 	 *             requires it to be a commit.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             one or more sources could not be read, or outputs could not
 	 *             be written to the Repository.
 	 */
 	protected abstract boolean mergeImpl() throws IOException;
 
 	/**
+	 * Get resulting tree.
+	 *
 	 * @return resulting tree, if {@link #merge(AnyObjectId[])} returned true.
 	 */
 	public abstract ObjectId getResultTreeId();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/merge/RecursiveMerger.java b/org.eclipse.jgit/src/org/eclipse/jgit/merge/RecursiveMerger.java
index 1375cd3..a621a05 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/merge/RecursiveMerger.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/merge/RecursiveMerger.java
@@ -83,6 +83,7 @@
  * - uses "Lists" instead of Arrays for chained types
  *
  * - recursively merges the merge bases together to compute a usable base
+ *
  * @since 3.0
  */
 public class RecursiveMerger extends ResolveMerger {
@@ -97,7 +98,9 @@ public class RecursiveMerger extends ResolveMerger {
 	 * inCore
 	 *
 	 * @param local
+	 *            a {@link org.eclipse.jgit.lib.Repository} object.
 	 * @param inCore
+	 *            a boolean.
 	 */
 	protected RecursiveMerger(Repository local, boolean inCore) {
 		super(local, inCore);
@@ -106,7 +109,7 @@ protected RecursiveMerger(Repository local, boolean inCore) {
 	/**
 	 * Normal recursive merge, implies not inCore
 	 *
-	 * @param local
+	 * @param local a {@link org.eclipse.jgit.lib.Repository} object.
 	 */
 	protected RecursiveMerger(Repository local) {
 		this(local, false);
@@ -116,7 +119,9 @@ protected RecursiveMerger(Repository local) {
 	 * Normal recursive merge, implies inCore.
 	 *
 	 * @param inserter
+	 *            an {@link org.eclipse.jgit.lib.ObjectInserter} object.
 	 * @param config
+	 *            the repository configuration
 	 * @since 4.8
 	 */
 	protected RecursiveMerger(ObjectInserter inserter, Config config) {
@@ -124,12 +129,11 @@ protected RecursiveMerger(ObjectInserter inserter, Config config) {
 	}
 
 	/**
+	 * {@inheritDoc}
+	 * <p>
 	 * Get a single base commit for two given commits. If the two source commits
 	 * have more than one base commit recursively merge the base commits
 	 * together until you end up with a single base commit.
-	 *
-	 * @throws IOException
-	 * @throws IncorrectObjectTypeException
 	 */
 	@Override
 	protected RevCommit getBaseCommit(RevCommit a, RevCommit b)
@@ -151,7 +155,7 @@ protected RevCommit getBaseCommit(RevCommit a, RevCommit b)
 	 * @return the merge base of two commits. If a criss-cross merge required a
 	 *         synthetic merge base this commit is visible only the merger's
 	 *         RevWalk and will not be in the repository.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 * @throws IncorrectObjectTypeException
 	 *             one of the input objects is not a commit.
 	 * @throws NoMergeBaseException
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java b/org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java
index 23fdc35..a908db7 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java
@@ -3,6 +3,7 @@
  * Copyright (C) 2010-2012, Matthias Sohn <matthias.sohn@sap.com>
  * Copyright (C) 2012, Research In Motion Limited
  * Copyright (C) 2017, Obeo (mathieu.cartaud@obeo.fr)
+ * Copyright (C) 2018, Thomas Wolf <thomas.wolf@paranor.ch>
  * and other copyright owners as documented in the project's IP log.
  *
  * This program and the accompanying materials are made available
@@ -53,7 +54,6 @@
 
 import java.io.BufferedOutputStream;
 import java.io.File;
-import java.io.FileInputStream;
 import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
 import java.io.IOException;
@@ -79,6 +79,7 @@
 import org.eclipse.jgit.dircache.DirCacheBuilder;
 import org.eclipse.jgit.dircache.DirCacheCheckout;
 import org.eclipse.jgit.dircache.DirCacheEntry;
+import org.eclipse.jgit.errors.BinaryBlobException;
 import org.eclipse.jgit.errors.CorruptObjectException;
 import org.eclipse.jgit.errors.IncorrectObjectTypeException;
 import org.eclipse.jgit.errors.IndexWriteException;
@@ -86,20 +87,29 @@
 import org.eclipse.jgit.errors.NoWorkTreeException;
 import org.eclipse.jgit.lib.Config;
 import org.eclipse.jgit.lib.ConfigConstants;
+import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.CoreConfig.EolStreamType;
 import org.eclipse.jgit.lib.FileMode;
 import org.eclipse.jgit.lib.ObjectId;
 import org.eclipse.jgit.lib.ObjectInserter;
-import org.eclipse.jgit.lib.ObjectReader;
+import org.eclipse.jgit.lib.ObjectLoader;
 import org.eclipse.jgit.lib.Repository;
 import org.eclipse.jgit.revwalk.RevTree;
+import org.eclipse.jgit.storage.pack.PackConfig;
+import org.eclipse.jgit.submodule.SubmoduleConflict;
 import org.eclipse.jgit.treewalk.AbstractTreeIterator;
 import org.eclipse.jgit.treewalk.CanonicalTreeParser;
 import org.eclipse.jgit.treewalk.NameConflictTreeWalk;
 import org.eclipse.jgit.treewalk.TreeWalk;
+import org.eclipse.jgit.treewalk.TreeWalk.OperationType;
 import org.eclipse.jgit.treewalk.WorkingTreeIterator;
+import org.eclipse.jgit.treewalk.WorkingTreeOptions;
 import org.eclipse.jgit.treewalk.filter.TreeFilter;
 import org.eclipse.jgit.util.FS;
+import org.eclipse.jgit.util.LfsFactory;
+import org.eclipse.jgit.util.LfsFactory.LfsInputStream;
 import org.eclipse.jgit.util.TemporaryBuffer;
+import org.eclipse.jgit.util.io.EolStreamTypeUtil;
 
 /**
  * A three-way merger performing a content-merge if necessary
@@ -274,8 +284,16 @@ public enum MergeFailureReason {
 	protected MergeAlgorithm mergeAlgorithm;
 
 	/**
-	 * The size limit (bytes) which controls a file to be stored in {@code Heap} or
-	 * {@code LocalFile} during the merge.
+	 * The {@link WorkingTreeOptions} are needed to determine line endings for
+	 * merged files.
+	 *
+	 * @since 4.11
+	 */
+	protected WorkingTreeOptions workingTreeOptions;
+
+	/**
+	 * The size limit (bytes) which controls a file to be stored in {@code Heap}
+	 * or {@code LocalFile} during the merge.
 	 */
 	private int inCoreLimit;
 
@@ -296,8 +314,12 @@ private static int getInCoreLimit(Config config) {
 	}
 
 	/**
+	 * Constructor for ResolveMerger.
+	 *
 	 * @param local
+	 *            the {@link org.eclipse.jgit.lib.Repository}.
 	 * @param inCore
+	 *            a boolean.
 	 */
 	protected ResolveMerger(Repository local, boolean inCore) {
 		super(local);
@@ -312,19 +334,27 @@ protected ResolveMerger(Repository local, boolean inCore) {
 			dircache = DirCache.newInCore();
 		} else {
 			implicitDirCache = true;
+			workingTreeOptions = local.getConfig().get(WorkingTreeOptions.KEY);
 		}
 	}
 
 	/**
+	 * Constructor for ResolveMerger.
+	 *
 	 * @param local
+	 *            the {@link org.eclipse.jgit.lib.Repository}.
 	 */
 	protected ResolveMerger(Repository local) {
 		this(local, false);
 	}
 
 	/**
+	 * Constructor for ResolveMerger.
+	 *
 	 * @param inserter
+	 *            an {@link org.eclipse.jgit.lib.ObjectInserter} object.
 	 * @param config
+	 *            the repository configuration
 	 * @since 4.8
 	 */
 	protected ResolveMerger(ObjectInserter inserter, Config config) {
@@ -336,6 +366,7 @@ protected ResolveMerger(ObjectInserter inserter, Config config) {
 		dircache = DirCache.newInCore();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected boolean mergeImpl() throws IOException {
 		if (implicitDirCache)
@@ -365,8 +396,13 @@ private void checkout() throws NoWorkTreeException, IOException {
 		}
 		for (Map.Entry<String, DirCacheEntry> entry : toBeCheckedOut
 				.entrySet()) {
-			DirCacheCheckout.checkoutEntry(db, entry.getValue(), reader);
-			modifiedFiles.add(entry.getKey());
+			DirCacheEntry cacheEntry = entry.getValue();
+			if (cacheEntry.getFileMode() == FileMode.GITLINK) {
+				new File(nonNullRepo().getWorkTree(), entry.getKey()).mkdirs();
+			} else {
+				DirCacheCheckout.checkoutEntry(db, cacheEntry, reader);
+				modifiedFiles.add(entry.getKey());
+			}
 		}
 	}
 
@@ -376,9 +412,9 @@ private void checkout() throws NoWorkTreeException, IOException {
 	 * contained only stage 0. In case if inCore operation just clear the
 	 * history of modified files.
 	 *
-	 * @throws IOException
-	 * @throws CorruptObjectException
-	 * @throws NoWorkTreeException
+	 * @throws java.io.IOException
+	 * @throws org.eclipse.jgit.errors.CorruptObjectException
+	 * @throws org.eclipse.jgit.errors.NoWorkTreeException
 	 * @since 3.4
 	 */
 	protected void cleanUp() throws NoWorkTreeException,
@@ -479,72 +515,16 @@ private DirCacheEntry keep(DirCacheEntry e) {
 	 *            the file in the working tree
 	 * @param ignoreConflicts
 	 *            see
-	 *            {@link ResolveMerger#mergeTrees(AbstractTreeIterator, RevTree, RevTree, boolean)}
-	 * @return <code>false</code> if the merge will fail because the index entry
-	 *         didn't match ours or the working-dir file was dirty and a
-	 *         conflict occurred
-	 * @throws MissingObjectException
-	 * @throws IncorrectObjectTypeException
-	 * @throws CorruptObjectException
-	 * @throws IOException
-	 * @since 3.5
-	 * @deprecated
-	 */
-	@Deprecated
-	protected boolean processEntry(CanonicalTreeParser base,
-			CanonicalTreeParser ours, CanonicalTreeParser theirs,
-			DirCacheBuildIterator index, WorkingTreeIterator work,
-			boolean ignoreConflicts) throws MissingObjectException,
-			IncorrectObjectTypeException, CorruptObjectException, IOException {
-		return processEntry(base, ours, theirs, index, work, ignoreConflicts,
-				null);
-	}
-
-	/**
-	 * Processes one path and tries to merge taking git attributes in account.
-	 * This method will do all trivial (not content) merges and will also detect
-	 * if a merge will fail. The merge will fail when one of the following is
-	 * true
-	 * <ul>
-	 * <li>the index entry does not match the entry in ours. When merging one
-	 * branch into the current HEAD, ours will point to HEAD and theirs will
-	 * point to the other branch. It is assumed that the index matches the HEAD
-	 * because it will only not match HEAD if it was populated before the merge
-	 * operation. But the merge commit should not accidentally contain
-	 * modifications done before the merge. Check the <a href=
-	 * "http://www.kernel.org/pub/software/scm/git/docs/git-read-tree.html#_3_way_merge"
-	 * >git read-tree</a> documentation for further explanations.</li>
-	 * <li>A conflict was detected and the working-tree file is dirty. When a
-	 * conflict is detected the content-merge algorithm will try to write a
-	 * merged version into the working-tree. If the file is dirty we would
-	 * override unsaved data.</li>
-	 * </ul>
-	 *
-	 * @param base
-	 *            the common base for ours and theirs
-	 * @param ours
-	 *            the ours side of the merge. When merging a branch into the
-	 *            HEAD ours will point to HEAD
-	 * @param theirs
-	 *            the theirs side of the merge. When merging a branch into the
-	 *            current HEAD theirs will point to the branch which is merged
-	 *            into HEAD.
-	 * @param index
-	 *            the index entry
-	 * @param work
-	 *            the file in the working tree
-	 * @param ignoreConflicts
-	 *            see
-	 *            {@link ResolveMerger#mergeTrees(AbstractTreeIterator, RevTree, RevTree, boolean)}
+	 *            {@link org.eclipse.jgit.merge.ResolveMerger#mergeTrees(AbstractTreeIterator, RevTree, RevTree, boolean)}
 	 * @param attributes
 	 *            the attributes defined for this entry
 	 * @return <code>false</code> if the merge will fail because the index entry
 	 *         didn't match ours or the working-dir file was dirty and a
 	 *         conflict occurred
-	 * @throws MissingObjectException
-	 * @throws IncorrectObjectTypeException
-	 * @throws CorruptObjectException
-	 * @throws IOException
+	 * @throws org.eclipse.jgit.errors.MissingObjectException
+	 * @throws org.eclipse.jgit.errors.IncorrectObjectTypeException
+	 * @throws org.eclipse.jgit.errors.CorruptObjectException
+	 * @throws java.io.IOException
 	 * @since 4.9
 	 */
 	protected boolean processEntry(CanonicalTreeParser base,
@@ -698,24 +678,50 @@ protected boolean processEntry(CanonicalTreeParser base,
 
 		if (nonTree(modeO) && nonTree(modeT)) {
 			// Check worktree before modifying files
-			if (isWorktreeDirty(work, ourDce))
+			boolean worktreeDirty = isWorktreeDirty(work, ourDce);
+			if (!attributes.canBeContentMerged() && worktreeDirty) {
 				return false;
+			}
 
+			boolean gitlinkConflict = isGitLink(modeO) || isGitLink(modeT);
 			// Don't attempt to resolve submodule link conflicts
-			if (isGitLink(modeO) || isGitLink(modeT)
-					|| !attributes.canBeContentMerged()) {
+			if (gitlinkConflict || !attributes.canBeContentMerged()) {
 				add(tw.getRawPath(), base, DirCacheEntry.STAGE_1, 0, 0);
 				add(tw.getRawPath(), ours, DirCacheEntry.STAGE_2, 0, 0);
 				add(tw.getRawPath(), theirs, DirCacheEntry.STAGE_3, 0, 0);
-				unmergedPaths.add(tw.getPathString());
+
+				if (gitlinkConflict) {
+					MergeResult<SubmoduleConflict> result = new MergeResult<>(
+							Arrays.asList(
+									new SubmoduleConflict(base == null ? null
+											: base.getEntryObjectId()),
+									new SubmoduleConflict(ours == null ? null
+											: ours.getEntryObjectId()),
+									new SubmoduleConflict(theirs == null ? null
+											: theirs.getEntryObjectId())));
+					result.setContainsConflicts(true);
+					mergeResults.put(tw.getPathString(), result);
+					if (!ignoreConflicts) {
+						unmergedPaths.add(tw.getPathString());
+					}
+				} else {
+					// attribute merge issues are conflicts but not failures
+					unmergedPaths.add(tw.getPathString());
+				}
 				return true;
 			}
 
-			MergeResult<RawText> result = contentMerge(base, ours, theirs);
+			// Check worktree before modifying files
+			if (worktreeDirty) {
+				return false;
+			}
+
+			MergeResult<RawText> result = contentMerge(base, ours, theirs,
+					attributes);
 			if (ignoreConflicts) {
 				result.setContainsConflicts(false);
 			}
-			updateIndex(base, ours, theirs, result);
+			updateIndex(base, ours, theirs, result, attributes);
 			if (result.containsConflicts() && !ignoreConflicts)
 				unmergedPaths.add(tw.getPathString());
 			modifiedFiles.add(tw.getPathString());
@@ -723,6 +729,8 @@ protected boolean processEntry(CanonicalTreeParser base,
 			// OURS or THEIRS has been deleted
 			if (((modeO != 0 && !tw.idEqual(T_BASE, T_OURS)) || (modeT != 0 && !tw
 					.idEqual(T_BASE, T_THEIRS)))) {
+				MergeResult<RawText> result = contentMerge(base, ours, theirs,
+						attributes);
 
 				add(tw.getRawPath(), base, DirCacheEntry.STAGE_1, 0, 0);
 				add(tw.getRawPath(), ours, DirCacheEntry.STAGE_2, 0, 0);
@@ -743,8 +751,7 @@ protected boolean processEntry(CanonicalTreeParser base,
 				unmergedPaths.add(tw.getPathString());
 
 				// generate a MergeResult for the deleted file
-				mergeResults.put(tw.getPathString(),
-						contentMerge(base, ours, theirs));
+				mergeResults.put(tw.getPathString(), result);
 			}
 		}
 		return true;
@@ -758,19 +765,31 @@ protected boolean processEntry(CanonicalTreeParser base,
 	 * @param base
 	 * @param ours
 	 * @param theirs
+	 * @param attributes
 	 *
 	 * @return the result of the content merge
 	 * @throws IOException
 	 */
 	private MergeResult<RawText> contentMerge(CanonicalTreeParser base,
-			CanonicalTreeParser ours, CanonicalTreeParser theirs)
+			CanonicalTreeParser ours, CanonicalTreeParser theirs,
+			Attributes attributes)
 			throws IOException {
-		RawText baseText = base == null ? RawText.EMPTY_TEXT : getRawText(
-				base.getEntryObjectId(), reader);
-		RawText ourText = ours == null ? RawText.EMPTY_TEXT : getRawText(
-				ours.getEntryObjectId(), reader);
-		RawText theirsText = theirs == null ? RawText.EMPTY_TEXT : getRawText(
-				theirs.getEntryObjectId(), reader);
+		RawText baseText;
+		RawText ourText;
+		RawText theirsText;
+
+		try {
+			baseText = base == null ? RawText.EMPTY_TEXT : getRawText(
+							base.getEntryObjectId(), attributes);
+			ourText = ours == null ? RawText.EMPTY_TEXT : getRawText(
+							ours.getEntryObjectId(), attributes);
+			theirsText = theirs == null ? RawText.EMPTY_TEXT : getRawText(
+							theirs.getEntryObjectId(), attributes);
+		} catch (BinaryBlobException e) {
+			MergeResult<RawText> r = new MergeResult<>(Collections.<RawText>emptyList());
+			r.setContainsConflicts(true);
+			return r;
+		}
 		return (mergeAlgorithm.merge(RawTextComparator.DEFAULT, baseText,
 				ourText, theirsText));
 	}
@@ -829,80 +848,88 @@ private boolean isWorktreeDirty(WorkingTreeIterator work,
 	 * @param ours
 	 * @param theirs
 	 * @param result
+	 * @param attributes
 	 * @throws FileNotFoundException
 	 * @throws IOException
 	 */
 	private void updateIndex(CanonicalTreeParser base,
 			CanonicalTreeParser ours, CanonicalTreeParser theirs,
-			MergeResult<RawText> result) throws FileNotFoundException,
+			MergeResult<RawText> result, Attributes attributes)
+			throws FileNotFoundException,
 			IOException {
-		File mergedFile = !inCore ? writeMergedFile(result) : null;
-
-		if (result.containsConflicts()) {
-			// A conflict occurred, the file will contain conflict markers
-			// the index will be populated with the three stages and the
-			// workdir (if used) contains the halfway merged content.
-			add(tw.getRawPath(), base, DirCacheEntry.STAGE_1, 0, 0);
-			add(tw.getRawPath(), ours, DirCacheEntry.STAGE_2, 0, 0);
-			add(tw.getRawPath(), theirs, DirCacheEntry.STAGE_3, 0, 0);
-			mergeResults.put(tw.getPathString(), result);
-			return;
-		}
-
-		// No conflict occurred, the file will contain fully merged content.
-		// The index will be populated with the new merged version.
-		DirCacheEntry dce = new DirCacheEntry(tw.getPathString());
-
-		// Set the mode for the new content. Fall back to REGULAR_FILE if
-		// we can't merge modes of OURS and THEIRS.
-		int newMode = mergeFileModes(
-				tw.getRawMode(0),
-				tw.getRawMode(1),
-				tw.getRawMode(2));
-		dce.setFileMode(newMode == FileMode.MISSING.getBits()
-				? FileMode.REGULAR_FILE
-				: FileMode.fromBits(newMode));
-		if (mergedFile != null) {
-			long len = mergedFile.length();
-			dce.setLastModified(FS.DETECTED.lastModified(mergedFile));
-			dce.setLength((int) len);
-			InputStream is = new FileInputStream(mergedFile);
-			try {
-				dce.setObjectId(getObjectInserter().insert(OBJ_BLOB, len, is));
-			} finally {
-				is.close();
+		TemporaryBuffer rawMerged = null;
+		try {
+			rawMerged = doMerge(result);
+			File mergedFile = inCore ? null
+					: writeMergedFile(rawMerged, attributes);
+			if (result.containsConflicts()) {
+				// A conflict occurred, the file will contain conflict markers
+				// the index will be populated with the three stages and the
+				// workdir (if used) contains the halfway merged content.
+				add(tw.getRawPath(), base, DirCacheEntry.STAGE_1, 0, 0);
+				add(tw.getRawPath(), ours, DirCacheEntry.STAGE_2, 0, 0);
+				add(tw.getRawPath(), theirs, DirCacheEntry.STAGE_3, 0, 0);
+				mergeResults.put(tw.getPathString(), result);
+				return;
 			}
-		} else
-			dce.setObjectId(insertMergeResult(result));
-		builder.add(dce);
+
+			// No conflict occurred, the file will contain fully merged content.
+			// The index will be populated with the new merged version.
+			DirCacheEntry dce = new DirCacheEntry(tw.getPathString());
+
+			// Set the mode for the new content. Fall back to REGULAR_FILE if
+			// we can't merge modes of OURS and THEIRS.
+			int newMode = mergeFileModes(tw.getRawMode(0), tw.getRawMode(1),
+					tw.getRawMode(2));
+			dce.setFileMode(newMode == FileMode.MISSING.getBits()
+					? FileMode.REGULAR_FILE : FileMode.fromBits(newMode));
+			if (mergedFile != null) {
+				dce.setLastModified(
+						nonNullRepo().getFS().lastModified(mergedFile));
+				dce.setLength((int) mergedFile.length());
+			}
+			dce.setObjectId(insertMergeResult(rawMerged, attributes));
+			builder.add(dce);
+		} finally {
+			if (rawMerged != null) {
+				rawMerged.destroy();
+			}
+		}
 	}
 
 	/**
 	 * Writes merged file content to the working tree.
 	 *
-	 * @param result
-	 *            the result of the content merge
+	 * @param rawMerged
+	 *            the raw merged content
+	 * @param attributes
+	 *            the files .gitattributes entries
 	 * @return the working tree file to which the merged content was written.
 	 * @throws FileNotFoundException
 	 * @throws IOException
 	 */
-	private File writeMergedFile(MergeResult<RawText> result)
+	private File writeMergedFile(TemporaryBuffer rawMerged,
+			Attributes attributes)
 			throws FileNotFoundException, IOException {
 		File workTree = nonNullRepo().getWorkTree();
 		FS fs = nonNullRepo().getFS();
 		File of = new File(workTree, tw.getPathString());
 		File parentFolder = of.getParentFile();
-		if (!fs.exists(parentFolder))
+		if (!fs.exists(parentFolder)) {
 			parentFolder.mkdirs();
-		try (OutputStream os = new BufferedOutputStream(
-				new FileOutputStream(of))) {
-			new MergeFormatter().formatMerge(os, result,
-					Arrays.asList(commitNames), CHARACTER_ENCODING);
+		}
+		EolStreamType streamType = EolStreamTypeUtil.detectStreamType(
+				OperationType.CHECKOUT_OP, workingTreeOptions,
+				attributes);
+		try (OutputStream os = EolStreamTypeUtil.wrapOutputStream(
+				new BufferedOutputStream(new FileOutputStream(of)),
+				streamType)) {
+			rawMerged.writeTo(os, null);
 		}
 		return of;
 	}
 
-	private ObjectId insertMergeResult(MergeResult<RawText> result)
+	private TemporaryBuffer doMerge(MergeResult<RawText> result)
 			throws IOException {
 		TemporaryBuffer.LocalFile buf = new TemporaryBuffer.LocalFile(
 				db != null ? nonNullRepo().getDirectory() : null, inCoreLimit);
@@ -910,11 +937,20 @@ private ObjectId insertMergeResult(MergeResult<RawText> result)
 			new MergeFormatter().formatMerge(buf, result,
 					Arrays.asList(commitNames), CHARACTER_ENCODING);
 			buf.close();
-			try (InputStream in = buf.openInputStream()) {
-				return getObjectInserter().insert(OBJ_BLOB, buf.length(), in);
-			}
-		} finally {
+		} catch (IOException e) {
 			buf.destroy();
+			throw e;
+		}
+		return buf;
+	}
+
+	private ObjectId insertMergeResult(TemporaryBuffer buf,
+			Attributes attributes) throws IOException {
+		InputStream in = buf.openInputStream();
+		try (LfsInputStream is = LfsFactory.getInstance().applyCleanFilter(
+				getRepository(), in,
+				buf.length(), attributes.get(Constants.ATTR_MERGE))) {
+			return getObjectInserter().insert(OBJ_BLOB, is.getLength(), is);
 		}
 	}
 
@@ -946,27 +982,36 @@ private int mergeFileModes(int modeB, int modeO, int modeT) {
 		return FileMode.MISSING.getBits();
 	}
 
-	private static RawText getRawText(ObjectId id, ObjectReader reader)
-			throws IOException {
+	private RawText getRawText(ObjectId id,
+			Attributes attributes)
+			throws IOException, BinaryBlobException {
 		if (id.equals(ObjectId.zeroId()))
 			return new RawText(new byte[] {});
-		return new RawText(reader.open(id, OBJ_BLOB).getCachedBytes());
+
+		ObjectLoader loader = LfsFactory.getInstance().applySmudgeFilter(
+				getRepository(), reader.open(id, OBJ_BLOB),
+				attributes.get(Constants.ATTR_MERGE));
+		int threshold = PackConfig.DEFAULT_BIG_FILE_THRESHOLD;
+		return RawText.load(loader, threshold);
 	}
 
-	private static boolean nonTree(final int mode) {
+	private static boolean nonTree(int mode) {
 		return mode != 0 && !FileMode.TREE.equals(mode);
 	}
 
-	private static boolean isGitLink(final int mode) {
+	private static boolean isGitLink(int mode) {
 		return FileMode.GITLINK.equals(mode);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public ObjectId getResultTreeId() {
 		return (resultTree == null) ? null : resultTree.toObjectId();
 	}
 
 	/**
+	 * Set the names of the commits as they would appear in conflict markers
+	 *
 	 * @param commitNames
 	 *            the names of the commits as they would appear in conflict
 	 *            markers
@@ -976,6 +1021,8 @@ public void setCommitNames(String[] commitNames) {
 	}
 
 	/**
+	 * Get the names of the commits as they would appear in conflict markers.
+	 *
 	 * @return the names of the commits as they would appear in conflict
 	 *         markers.
 	 */
@@ -984,17 +1031,22 @@ public void setCommitNames(String[] commitNames) {
 	}
 
 	/**
-	 * @return the paths with conflicts. This is a subset of the files listed
-	 *         by {@link #getModifiedFiles()}
+	 * Get the paths with conflicts. This is a subset of the files listed by
+	 * {@link #getModifiedFiles()}
+	 *
+	 * @return the paths with conflicts. This is a subset of the files listed by
+	 *         {@link #getModifiedFiles()}
 	 */
 	public List<String> getUnmergedPaths() {
 		return unmergedPaths;
 	}
 
 	/**
-	 * @return the paths of files which have been modified by this merge. A
-	 *         file will be modified if a content-merge works on this path or if
-	 *         the merge algorithm decides to take the theirs-version. This is a
+	 * Get the paths of files which have been modified by this merge.
+	 *
+	 * @return the paths of files which have been modified by this merge. A file
+	 *         will be modified if a content-merge works on this path or if the
+	 *         merge algorithm decides to take the theirs-version. This is a
 	 *         superset of the files listed by {@link #getUnmergedPaths()}.
 	 */
 	public List<String> getModifiedFiles() {
@@ -1002,6 +1054,10 @@ public List<String> getModifiedFiles() {
 	}
 
 	/**
+	 * Get a map which maps the paths of files which have to be checked out
+	 * because the merge created new fully-merged content for this file into the
+	 * index.
+	 *
 	 * @return a map which maps the paths of files which have to be checked out
 	 *         because the merge created new fully-merged content for this file
 	 *         into the index. This means: the merge wrote a new stage 0 entry
@@ -1012,6 +1068,8 @@ public Map<String, DirCacheEntry> getToBeCheckedOut() {
 	}
 
 	/**
+	 * Get the mergeResults
+	 *
 	 * @return the mergeResults
 	 */
 	public Map<String, MergeResult<? extends Sequence>> getMergeResults() {
@@ -1019,6 +1077,9 @@ public Map<String, MergeResult<? extends Sequence>> getMergeResults() {
 	}
 
 	/**
+	 * Get list of paths causing this merge to fail (not stopped because of a
+	 * conflict).
+	 *
 	 * @return lists paths causing this merge to fail (not stopped because of a
 	 *         conflict). <code>null</code> is returned if this merge didn't
 	 *         fail.
@@ -1043,10 +1104,10 @@ public boolean failed() {
 	 * not set explicitly and if this merger doesn't work in-core, this merger
 	 * will implicitly get and lock a default DirCache. If the DirCache is
 	 * explicitly set the caller is responsible to lock it in advance. Finally
-	 * the merger will call {@link DirCache#commit()} which requires that the
-	 * DirCache is locked. If the {@link #mergeImpl()} returns without throwing
-	 * an exception the lock will be released. In case of exceptions the caller
-	 * is responsible to release the lock.
+	 * the merger will call {@link org.eclipse.jgit.dircache.DirCache#commit()}
+	 * which requires that the DirCache is locked. If the {@link #mergeImpl()}
+	 * returns without throwing an exception the lock will be released. In case
+	 * of exceptions the caller is responsible to release the lock.
 	 *
 	 * @param dc
 	 *            the DirCache to set
@@ -1076,8 +1137,12 @@ public void setWorkingTreeIterator(WorkingTreeIterator workingTreeIterator) {
 	 * The resolve conflict way of three way merging
 	 *
 	 * @param baseTree
+	 *            a {@link org.eclipse.jgit.treewalk.AbstractTreeIterator}
+	 *            object.
 	 * @param headTree
+	 *            a {@link org.eclipse.jgit.revwalk.RevTree} object.
 	 * @param mergeTree
+	 *            a {@link org.eclipse.jgit.revwalk.RevTree} object.
 	 * @param ignoreConflicts
 	 *            Controls what to do in case a content-merge is done and a
 	 *            conflict is detected. The default setting for this should be
@@ -1094,11 +1159,11 @@ public void setWorkingTreeIterator(WorkingTreeIterator workingTreeIterator) {
 	 *            other stages are filled. Means: there is no conflict on that
 	 *            path but the new content (including conflict markers) is
 	 *            stored as successful merge result. This is needed in the
-	 *            context of {@link RecursiveMerger} where when determining
-	 *            merge bases we don't want to deal with content-merge
-	 *            conflicts.
+	 *            context of {@link org.eclipse.jgit.merge.RecursiveMerger}
+	 *            where when determining merge bases we don't want to deal with
+	 *            content-merge conflicts.
 	 * @return whether the trees merged cleanly
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 * @since 3.5
 	 */
 	protected boolean mergeTrees(AbstractTreeIterator baseTree,
@@ -1161,9 +1226,9 @@ protected boolean mergeTrees(AbstractTreeIterator baseTree,
 	 *            The walk to iterate over.
 	 * @param ignoreConflicts
 	 *            see
-	 *            {@link ResolveMerger#mergeTrees(AbstractTreeIterator, RevTree, RevTree, boolean)}
+	 *            {@link org.eclipse.jgit.merge.ResolveMerger#mergeTrees(AbstractTreeIterator, RevTree, RevTree, boolean)}
 	 * @return Whether the trees merged cleanly.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 * @since 3.5
 	 */
 	protected boolean mergeTreeWalk(TreeWalk treeWalk, boolean ignoreConflicts)
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/merge/StrategyOneSided.java b/org.eclipse.jgit/src/org/eclipse/jgit/merge/StrategyOneSided.java
index 2224dbc..6e2e2aa 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/merge/StrategyOneSided.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/merge/StrategyOneSided.java
@@ -71,40 +71,44 @@ public class StrategyOneSided extends MergeStrategy {
 	 * @param index
 	 *            the position of the input tree to accept as the result.
 	 */
-	protected StrategyOneSided(final String name, final int index) {
+	protected StrategyOneSided(String name, int index) {
 		strategyName = name;
 		treeIndex = index;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public String getName() {
 		return strategyName;
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	public Merger newMerger(final Repository db) {
+	public Merger newMerger(Repository db) {
 		return new OneSide(db, treeIndex);
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	public Merger newMerger(final Repository db, boolean inCore) {
+	public Merger newMerger(Repository db, boolean inCore) {
 		return new OneSide(db, treeIndex);
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	public Merger newMerger(final ObjectInserter inserter, final Config config) {
+	public Merger newMerger(ObjectInserter inserter, Config config) {
 		return new OneSide(inserter, treeIndex);
 	}
 
 	static class OneSide extends Merger {
 		private final int treeIndex;
 
-		protected OneSide(final Repository local, final int index) {
+		protected OneSide(Repository local, int index) {
 			super(local);
 			treeIndex = index;
 		}
 
-		protected OneSide(final ObjectInserter inserter, final int index) {
+		protected OneSide(ObjectInserter inserter, int index) {
 			super(inserter);
 			treeIndex = index;
 		}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/merge/StrategyRecursive.java b/org.eclipse.jgit/src/org/eclipse/jgit/merge/StrategyRecursive.java
index 56128dd..716b136 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/merge/StrategyRecursive.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/merge/StrategyRecursive.java
@@ -54,21 +54,25 @@
  */
 public class StrategyRecursive extends StrategyResolve {
 
+	/** {@inheritDoc} */
 	@Override
 	public ThreeWayMerger newMerger(Repository db) {
 		return new RecursiveMerger(db, false);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public ThreeWayMerger newMerger(Repository db, boolean inCore) {
 		return new RecursiveMerger(db, inCore);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public ThreeWayMerger newMerger(ObjectInserter inserter, Config config) {
 		return new RecursiveMerger(inserter, config);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public String getName() {
 		return "recursive"; //$NON-NLS-1$
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/merge/StrategyResolve.java b/org.eclipse.jgit/src/org/eclipse/jgit/merge/StrategyResolve.java
index 17044b5..e836719 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/merge/StrategyResolve.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/merge/StrategyResolve.java
@@ -52,24 +52,25 @@
  */
 public class StrategyResolve extends ThreeWayMergeStrategy {
 
+	/** {@inheritDoc} */
 	@Override
 	public ThreeWayMerger newMerger(Repository db) {
 		return new ResolveMerger(db, false);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public ThreeWayMerger newMerger(Repository db, boolean inCore) {
 		return new ResolveMerger(db, inCore);
 	}
 
-	/**
-	 * @since 4.8
-	 */
+	/** {@inheritDoc} */
 	@Override
 	public ThreeWayMerger newMerger(ObjectInserter inserter, Config config) {
 		return new ResolveMerger(inserter, config);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public String getName() {
 		return "resolve"; //$NON-NLS-1$
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/merge/StrategySimpleTwoWayInCore.java b/org.eclipse.jgit/src/org/eclipse/jgit/merge/StrategySimpleTwoWayInCore.java
index cd427bd..4aeacf5 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/merge/StrategySimpleTwoWayInCore.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/merge/StrategySimpleTwoWayInCore.java
@@ -69,30 +69,33 @@
  * file contents.
  */
 public class StrategySimpleTwoWayInCore extends ThreeWayMergeStrategy {
-	/** Create a new instance of the strategy. */
+	/**
+	 * Create a new instance of the strategy.
+	 */
 	protected StrategySimpleTwoWayInCore() {
 		//
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public String getName() {
 		return "simple-two-way-in-core"; //$NON-NLS-1$
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	public ThreeWayMerger newMerger(final Repository db) {
+	public ThreeWayMerger newMerger(Repository db) {
 		return new InCoreMerger(db);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public ThreeWayMerger newMerger(Repository db, boolean inCore) {
 		// This class is always inCore, so ignore the parameter
 		return newMerger(db);
 	}
 
-	/**
-	 * @since 4.8
-	 */
+	/** {@inheritDoc} */
 	@Override
 	public ThreeWayMerger newMerger(ObjectInserter inserter, Config config) {
 		return new InCoreMerger(inserter);
@@ -113,13 +116,13 @@ private static class InCoreMerger extends ThreeWayMerger {
 
 		private ObjectId resultTree;
 
-		InCoreMerger(final Repository local) {
+		InCoreMerger(Repository local) {
 			super(local);
 			tw = new NameConflictTreeWalk(local, reader);
 			cache = DirCache.newInCore();
 		}
 
-		InCoreMerger(final ObjectInserter inserter) {
+		InCoreMerger(ObjectInserter inserter) {
 			super(inserter);
 			tw = new NameConflictTreeWalk(null, reader);
 			cache = DirCache.newInCore();
@@ -179,11 +182,11 @@ else if (modeB == modeT && tw.idEqual(T_BASE, T_THEIRS))
 			}
 		}
 
-		private static boolean nonTree(final int mode) {
+		private static boolean nonTree(int mode) {
 			return mode != 0 && !FileMode.TREE.equals(mode);
 		}
 
-		private void add(final int tree, final int stage) throws IOException {
+		private void add(int tree, int stage) throws IOException {
 			final AbstractTreeIterator i = getTree(tree);
 			if (i != null) {
 				if (FileMode.TREE.equals(tw.getRawMode(tree))) {
@@ -200,7 +203,7 @@ private void add(final int tree, final int stage) throws IOException {
 			}
 		}
 
-		private AbstractTreeIterator getTree(final int tree) {
+		private AbstractTreeIterator getTree(int tree) {
 			return tw.getTree(tree, AbstractTreeIterator.class);
 		}
 
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/merge/ThreeWayMergeStrategy.java b/org.eclipse.jgit/src/org/eclipse/jgit/merge/ThreeWayMergeStrategy.java
index c71590b..7d185ec 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/merge/ThreeWayMergeStrategy.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/merge/ThreeWayMergeStrategy.java
@@ -45,11 +45,15 @@
 
 import org.eclipse.jgit.lib.Repository;
 
-/** A merge strategy to merge 2 trees, using a common base ancestor tree. */
+/**
+ * A merge strategy to merge 2 trees, using a common base ancestor tree.
+ */
 public abstract class ThreeWayMergeStrategy extends MergeStrategy {
+	/** {@inheritDoc} */
 	@Override
 	public abstract ThreeWayMerger newMerger(Repository db);
 
+	/** {@inheritDoc} */
 	@Override
 	public abstract ThreeWayMerger newMerger(Repository db, boolean inCore);
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/merge/ThreeWayMerger.java b/org.eclipse.jgit/src/org/eclipse/jgit/merge/ThreeWayMerger.java
index b3ef0fb..2fc0f4f 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/merge/ThreeWayMerger.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/merge/ThreeWayMerger.java
@@ -57,7 +57,9 @@
 import org.eclipse.jgit.treewalk.AbstractTreeIterator;
 import org.eclipse.jgit.treewalk.EmptyTreeIterator;
 
-/** A merge of 2 trees, using a common base ancestor tree. */
+/**
+ * A merge of 2 trees, using a common base ancestor tree.
+ */
 public abstract class ThreeWayMerger extends Merger {
 	private RevTree baseTree;
 
@@ -69,7 +71,7 @@ public abstract class ThreeWayMerger extends Merger {
 	 * @param local
 	 *            the repository this merger will read and write data on.
 	 */
-	protected ThreeWayMerger(final Repository local) {
+	protected ThreeWayMerger(Repository local) {
 		super(local);
 	}
 
@@ -81,7 +83,7 @@ protected ThreeWayMerger(final Repository local) {
 	 * @param inCore
 	 *            perform the merge in core with no working folder involved
 	 */
-	protected ThreeWayMerger(final Repository local, boolean inCore) {
+	protected ThreeWayMerger(Repository local, boolean inCore) {
 		this(local);
 	}
 
@@ -103,14 +105,14 @@ protected ThreeWayMerger(ObjectInserter inserter) {
 	 *            common base treeish; null to automatically compute the common
 	 *            base from the input commits during
 	 *            {@link #merge(AnyObjectId...)}.
-	 * @throws IncorrectObjectTypeException
+	 * @throws org.eclipse.jgit.errors.IncorrectObjectTypeException
 	 *             the object is not a treeish.
-	 * @throws MissingObjectException
+	 * @throws org.eclipse.jgit.errors.MissingObjectException
 	 *             the object does not exist.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the object could not be read.
 	 */
-	public void setBase(final AnyObjectId id) throws MissingObjectException,
+	public void setBase(AnyObjectId id) throws MissingObjectException,
 			IncorrectObjectTypeException, IOException {
 		if (id != null) {
 			baseTree = walk.parseTree(id);
@@ -119,13 +121,15 @@ public void setBase(final AnyObjectId id) throws MissingObjectException,
 		}
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	public boolean merge(final AnyObjectId... tips) throws IOException {
+	public boolean merge(AnyObjectId... tips) throws IOException {
 		if (tips.length != 2)
 			return false;
 		return super.merge(tips);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public ObjectId getBaseCommitId() {
 		return baseCommitId;
@@ -136,7 +140,7 @@ public ObjectId getBaseCommitId() {
 	 *
 	 * @return an iterator over the caller-specified merge base, or the natural
 	 *         merge base of the two input commits.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 */
 	protected AbstractTreeIterator mergeBase() throws IOException {
 		if (baseTree != null)
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/nls/NLS.java b/org.eclipse.jgit/src/org/eclipse/jgit/nls/NLS.java
index 5e7beed..89a87af 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/nls/NLS.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/nls/NLS.java
@@ -68,15 +68,13 @@
  * </pre>
  */
 public class NLS {
-	/** The root locale constant. It is defined here because the Locale.ROOT is not defined in Java 5 */
+	/**
+	 * The root locale constant. It is defined here because the Locale.ROOT is
+	 * not defined in Java 5
+	 */
 	public static final Locale ROOT_LOCALE = new Locale("", "", ""); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
 
-	private static final InheritableThreadLocal<NLS> local = new InheritableThreadLocal<NLS>() {
-		@Override
-		protected NLS initialValue() {
-			return new NLS(Locale.getDefault());
-		}
-	};
+	private static final InheritableThreadLocal<NLS> local = new InheritableThreadLocal<>();
 
 	/**
 	 * Sets the locale for the calling thread.
@@ -96,27 +94,43 @@ public static void setLocale(Locale locale) {
 	/**
 	 * Sets the JVM default locale as the locale for the calling thread.
 	 * <p>
-	 * Semantically this is equivalent to <code>NLS.setLocale(Locale.getDefault())</code>.
+	 * Semantically this is equivalent to
+	 * <code>NLS.setLocale(Locale.getDefault())</code>.
 	 */
 	public static void useJVMDefaultLocale() {
-		local.set(new NLS(Locale.getDefault()));
+		useJVMDefaultInternal();
+	}
+
+	// TODO(ms): change signature of public useJVMDefaultLocale() in 5.0 to get
+	// rid of this internal method
+	private static NLS useJVMDefaultInternal() {
+		NLS b = new NLS(Locale.getDefault());
+		local.set(b);
+		return b;
 	}
 
 	/**
 	 * Returns an instance of the translation bundle of the required type. All
 	 * public String fields of the bundle instance will get their values
-	 * injected as described in the {@link TranslationBundle}.
+	 * injected as described in the
+	 * {@link org.eclipse.jgit.nls.TranslationBundle}.
 	 *
-	 * @param <T>
-	 *            required bundle type
 	 * @param type
 	 *            required bundle type
 	 * @return an instance of the required bundle type
-	 * @exception TranslationBundleLoadingException see {@link TranslationBundleLoadingException}
-	 * @exception TranslationStringMissingException see {@link TranslationStringMissingException}
+	 * @exception TranslationBundleLoadingException
+	 *                see
+	 *                {@link org.eclipse.jgit.errors.TranslationBundleLoadingException}
+	 * @exception TranslationStringMissingException
+	 *                see
+	 *                {@link org.eclipse.jgit.errors.TranslationStringMissingException}
 	 */
 	public static <T extends TranslationBundle> T getBundleFor(Class<T> type) {
-		return local.get().get(type);
+		NLS b = local.get();
+		if (b == null) {
+			b = useJVMDefaultInternal();
+		}
+		return b.get(type);
 	}
 
 	final private Locale locale;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/nls/TranslationBundle.java b/org.eclipse.jgit/src/org/eclipse/jgit/nls/TranslationBundle.java
index bde69c0..cdd7be2 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/nls/TranslationBundle.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/nls/TranslationBundle.java
@@ -92,21 +92,22 @@
  * </pre>
  *
  * The translated text is automatically injected into the public String fields
- * according to the locale set with {@link NLS#setLocale(Locale)}. However, the
- * {@link NLS#setLocale(Locale)} method defines only prefered locale which will
- * be honored only if it is supported by the provided resource bundle property
- * files. Basically, this class will use
- * {@link ResourceBundle#getBundle(String, Locale)} method to load a resource
- * bundle. See the documentation of this method for a detailed explanation of
- * resource bundle loading strategy. After a bundle is created the
- * {@link #effectiveLocale()} method can be used to determine whether the bundle
- * really corresponds to the requested locale or is a fallback.
+ * according to the locale set with
+ * {@link org.eclipse.jgit.nls.NLS#setLocale(Locale)}. However, the
+ * {@link org.eclipse.jgit.nls.NLS#setLocale(Locale)} method defines only
+ * prefered locale which will be honored only if it is supported by the provided
+ * resource bundle property files. Basically, this class will use
+ * {@link java.util.ResourceBundle#getBundle(String, Locale)} method to load a
+ * resource bundle. See the documentation of this method for a detailed
+ * explanation of resource bundle loading strategy. After a bundle is created
+ * the {@link #effectiveLocale()} method can be used to determine whether the
+ * bundle really corresponds to the requested locale or is a fallback.
  *
  * <p>
  * To load a String from a resource bundle property file this class uses the
- * {@link ResourceBundle#getString(String)}. This method can throw the
- * {@link MissingResourceException} and this class is not making any effort to
- * catch and/or translate this exception.
+ * {@link java.util.ResourceBundle#getString(String)}. This method can throw the
+ * {@link java.util.MissingResourceException} and this class is not making any
+ * effort to catch and/or translate this exception.
  *
  * <p>
  * To define a concrete translation bundle one has to:
@@ -125,15 +126,20 @@ public abstract class TranslationBundle {
 	private ResourceBundle resourceBundle;
 
 	/**
-	 * @return the locale locale used for loading the resource bundle from which
-	 *         the field values were taken
+	 * Get the locale used for loading the resource bundle from which the field
+	 * values were taken.
+	 *
+	 * @return the locale used for loading the resource bundle from which the
+	 *         field values were taken.
 	 */
 	public Locale effectiveLocale() {
 		return effectiveLocale;
 	}
 
 	/**
-	 * @return the resource bundle on which this translation bundle is based
+	 * Get the resource bundle on which this translation bundle is based.
+	 *
+	 * @return the resource bundle on which this translation bundle is based.
 	 */
 	public ResourceBundle resourceBundle() {
 		return resourceBundle;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/notes/DefaultNoteMerger.java b/org.eclipse.jgit/src/org/eclipse/jgit/notes/DefaultNoteMerger.java
index 2e7327c..54a2d89 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/notes/DefaultNoteMerger.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/notes/DefaultNoteMerger.java
@@ -53,7 +53,7 @@
 import org.eclipse.jgit.util.io.UnionInputStream;
 
 /**
- * Default implementation of the {@link NoteMerger}.
+ * Default implementation of the {@link org.eclipse.jgit.notes.NoteMerger}.
  * <p>
  * If ours and theirs are both non-null, which means they are either both edits
  * or both adds, then this merger will simply join the content of ours and
@@ -67,6 +67,7 @@
  */
 public class DefaultNoteMerger implements NoteMerger {
 
+	/** {@inheritDoc} */
 	@Override
 	public Note merge(Note base, Note ours, Note theirs, ObjectReader reader,
 			ObjectInserter inserter) throws IOException {
@@ -81,14 +82,11 @@ public Note merge(Note base, Note ours, Note theirs, ObjectReader reader,
 
 		ObjectLoader lo = reader.open(ours.getData());
 		ObjectLoader lt = reader.open(theirs.getData());
-		UnionInputStream union = new UnionInputStream(lo.openStream(),
-				lt.openStream());
-		try {
+		try (UnionInputStream union = new UnionInputStream(lo.openStream(),
+				lt.openStream())) {
 			ObjectId noteData = inserter.insert(Constants.OBJ_BLOB,
 					lo.getSize() + lt.getSize(), union);
 			return new Note(ours, noteData);
-		} finally {
-			union.close();
 		}
 	}
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/notes/LeafBucket.java b/org.eclipse.jgit/src/org/eclipse/jgit/notes/LeafBucket.java
index 1be5251..6723b63 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/notes/LeafBucket.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/notes/LeafBucket.java
@@ -218,7 +218,7 @@ private TreeFormatter build() {
 		return fmt;
 	}
 
-	private int treeSize(final int nameLen) {
+	private int treeSize(int nameLen) {
 		int sz = cnt * TreeFormatter.entrySize(REGULAR_FILE, nameLen);
 		for (NonNoteEntry e = nonNotes; e != null; e = e.next)
 			sz += e.treeEntrySize();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/notes/Note.java b/org.eclipse.jgit/src/org/eclipse/jgit/notes/Note.java
index 41e9bbe..7cf40dd 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/notes/Note.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/notes/Note.java
@@ -46,7 +46,9 @@
 import org.eclipse.jgit.lib.AnyObjectId;
 import org.eclipse.jgit.lib.ObjectId;
 
-/** In-memory representation of a single note attached to one object. */
+/**
+ * In-memory representation of a single note attached to one object.
+ */
 public class Note extends ObjectId {
 	private ObjectId data;
 
@@ -63,7 +65,11 @@ public Note(AnyObjectId noteOn, ObjectId noteData) {
 		data = noteData;
 	}
 
-	/** @return the note content */
+	/**
+	 * Get the note content.
+	 *
+	 * @return the note content.
+	 */
 	public ObjectId getData() {
 		return data;
 	}
@@ -72,6 +78,7 @@ void setData(ObjectId newData) {
 		data = newData;
 	}
 
+	/** {@inheritDoc} */
 	@SuppressWarnings("nls")
 	@Override
 	public String toString() {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/notes/NoteMap.java b/org.eclipse.jgit/src/org/eclipse/jgit/notes/NoteMap.java
index 44c5926..cbef613 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/notes/NoteMap.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/notes/NoteMap.java
@@ -63,10 +63,11 @@
 /**
  * Index of notes from a note branch.
  *
- * This class is not thread-safe, and relies on an {@link ObjectReader} that it
- * borrows/shares with the caller. The reader can be used during any call, and
- * is not released by this class. The caller should arrange for releasing the
- * shared {@code ObjectReader} at the proper times.
+ * This class is not thread-safe, and relies on an
+ * {@link org.eclipse.jgit.lib.ObjectReader} that it borrows/shares with the
+ * caller. The reader can be used during any call, and is not released by this
+ * class. The caller should arrange for releasing the shared
+ * {@code ObjectReader} at the proper times.
  */
 public class NoteMap implements Iterable<Note> {
 	/**
@@ -81,10 +82,11 @@ public static NoteMap newEmptyMap() {
 	}
 
 	/**
-	 * Shorten the note ref name by trimming off the {@link Constants#R_NOTES}
-	 * prefix if it exists.
+	 * Shorten the note ref name by trimming off the
+	 * {@link org.eclipse.jgit.lib.Constants#R_NOTES} prefix if it exists.
 	 *
 	 * @param noteRefName
+	 *            a {@link java.lang.String} object.
 	 * @return a more user friendly note name
 	 */
 	public static String shortenRefName(String noteRefName) {
@@ -103,13 +105,13 @@ public static String shortenRefName(String noteRefName) {
 	 * @param commit
 	 *            the revision of the note branch to read.
 	 * @return the note map read from the commit.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the repository cannot be accessed through the reader.
-	 * @throws CorruptObjectException
+	 * @throws org.eclipse.jgit.errors.CorruptObjectException
 	 *             a tree object is corrupt and cannot be read.
-	 * @throws IncorrectObjectTypeException
+	 * @throws org.eclipse.jgit.errors.IncorrectObjectTypeException
 	 *             a tree object wasn't actually a tree.
-	 * @throws MissingObjectException
+	 * @throws org.eclipse.jgit.errors.MissingObjectException
 	 *             a reference tree object doesn't exist.
 	 */
 	public static NoteMap read(ObjectReader reader, RevCommit commit)
@@ -128,13 +130,13 @@ public static NoteMap read(ObjectReader reader, RevCommit commit)
 	 * @param tree
 	 *            the note tree to read.
 	 * @return the note map read from the tree.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the repository cannot be accessed through the reader.
-	 * @throws CorruptObjectException
+	 * @throws org.eclipse.jgit.errors.CorruptObjectException
 	 *             a tree object is corrupt and cannot be read.
-	 * @throws IncorrectObjectTypeException
+	 * @throws org.eclipse.jgit.errors.IncorrectObjectTypeException
 	 *             a tree object wasn't actually a tree.
-	 * @throws MissingObjectException
+	 * @throws org.eclipse.jgit.errors.MissingObjectException
 	 *             a reference tree object doesn't exist.
 	 */
 	public static NoteMap read(ObjectReader reader, RevTree tree)
@@ -153,13 +155,13 @@ public static NoteMap read(ObjectReader reader, RevTree tree)
 	 * @param treeId
 	 *            the note tree to read.
 	 * @return the note map read from the tree.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the repository cannot be accessed through the reader.
-	 * @throws CorruptObjectException
+	 * @throws org.eclipse.jgit.errors.CorruptObjectException
 	 *             a tree object is corrupt and cannot be read.
-	 * @throws IncorrectObjectTypeException
+	 * @throws org.eclipse.jgit.errors.IncorrectObjectTypeException
 	 *             a tree object wasn't actually a tree.
-	 * @throws MissingObjectException
+	 * @throws org.eclipse.jgit.errors.MissingObjectException
 	 *             a reference tree object doesn't exist.
 	 */
 	public static NoteMap readTree(ObjectReader reader, ObjectId treeId)
@@ -197,10 +199,7 @@ private NoteMap(ObjectReader reader) {
 		this.reader = reader;
 	}
 
-	/**
-	 * @return an iterator that iterates over notes of this NoteMap. Non note
-	 *         entries are ignored by this iterator.
-	 */
+	/** {@inheritDoc} */
 	@Override
 	public Iterator<Note> iterator() {
 		try {
@@ -216,7 +215,7 @@ public Iterator<Note> iterator() {
 	 * @param id
 	 *            the object to look for.
 	 * @return the note's blob ObjectId, or null if no note exists.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             a portion of the note space is not accessible.
 	 */
 	public ObjectId get(AnyObjectId id) throws IOException {
@@ -230,7 +229,7 @@ public ObjectId get(AnyObjectId id) throws IOException {
 	 * @param id
 	 *            the object to look for.
 	 * @return the note for the given object id, or null if no note exists.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             a portion of the note space is not accessible.
 	 */
 	public Note getNote(AnyObjectId id) throws IOException {
@@ -243,7 +242,7 @@ public Note getNote(AnyObjectId id) throws IOException {
 	 * @param id
 	 *            the object to look for.
 	 * @return true if a note exists; false if there is no note.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             a portion of the note space is not accessible.
 	 */
 	public boolean contains(AnyObjectId id) throws IOException {
@@ -269,11 +268,11 @@ public boolean contains(AnyObjectId id) throws IOException {
 	 *            larger than this limit, LargeObjectException will be thrown.
 	 * @return if a note is defined for {@code id}, the note content. If no note
 	 *         is defined, null.
-	 * @throws LargeObjectException
+	 * @throws org.eclipse.jgit.errors.LargeObjectException
 	 *             the note data is larger than {@code sizeLimit}.
-	 * @throws MissingObjectException
+	 * @throws org.eclipse.jgit.errors.MissingObjectException
 	 *             the note's blob does not exist in the repository.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the note's blob cannot be read from the repository
 	 */
 	public byte[] getCachedBytes(AnyObjectId id, int sizeLimit)
@@ -306,7 +305,7 @@ public boolean contains(AnyObjectId id) throws IOException {
 	 *            data to associate with the note. This must be the ObjectId of
 	 *            a blob that already exists in the repository. If null the note
 	 *            will be deleted, if present.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             a portion of the note space is not accessible.
 	 */
 	public void set(AnyObjectId noteOn, ObjectId noteData) throws IOException {
@@ -337,7 +336,7 @@ public void set(AnyObjectId noteOn, ObjectId noteData) throws IOException {
 	 *            inserter to write the encoded {@code noteData} out as a blob.
 	 *            The caller must ensure the inserter is flushed before the
 	 *            updated note map is made available for reading.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the note data could not be stored in the repository.
 	 */
 	public void set(AnyObjectId noteOn, String noteData, ObjectInserter ins)
@@ -361,7 +360,7 @@ public void set(AnyObjectId noteOn, String noteData, ObjectInserter ins)
 	 *
 	 * @param noteOn
 	 *            the object to remove the note from.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             a portion of the note space is not accessible.
 	 */
 	public void remove(AnyObjectId noteOn) throws IOException {
@@ -376,7 +375,7 @@ public void remove(AnyObjectId noteOn) throws IOException {
 	 *            Caller is responsible for flushing the inserter before trying
 	 *            to read the objects, or exposing them through a reference.
 	 * @return the top level tree.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             a tree could not be written.
 	 */
 	public ObjectId writeTree(ObjectInserter inserter) throws IOException {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/notes/NoteMapMerger.java b/org.eclipse.jgit/src/org/eclipse/jgit/notes/NoteMapMerger.java
index 19ec1a1..325ff4f 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/notes/NoteMapMerger.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/notes/NoteMapMerger.java
@@ -56,14 +56,13 @@
 import org.eclipse.jgit.merge.MergeStrategy;
 import org.eclipse.jgit.merge.Merger;
 import org.eclipse.jgit.merge.ThreeWayMerger;
-import org.eclipse.jgit.treewalk.AbstractTreeIterator;
-import org.eclipse.jgit.treewalk.TreeWalk;
 
 /**
  * Three-way note tree merge.
  * <p>
- * Direct implementation of NoteMap merger without using {@link TreeWalk} and
- * {@link AbstractTreeIterator}
+ * Direct implementation of NoteMap merger without using
+ * {@link org.eclipse.jgit.treewalk.TreeWalk} and
+ * {@link org.eclipse.jgit.treewalk.AbstractTreeIterator}
  */
 public class NoteMapMerger {
 	private static final FanoutBucket EMPTY_FANOUT = new FanoutBucket(0);
@@ -83,8 +82,9 @@ public class NoteMapMerger {
 	private final MutableObjectId objectIdPrefix;
 
 	/**
-	 * Constructs a NoteMapMerger with custom {@link NoteMerger} and custom
-	 * {@link MergeStrategy}.
+	 * Constructs a NoteMapMerger with custom
+	 * {@link org.eclipse.jgit.notes.NoteMerger} and custom
+	 * {@link org.eclipse.jgit.merge.MergeStrategy}.
 	 *
 	 * @param db
 	 *            Git repository
@@ -104,9 +104,10 @@ public NoteMapMerger(Repository db, NoteMerger noteMerger,
 	}
 
 	/**
-	 * Constructs a NoteMapMerger with {@link DefaultNoteMerger} as the merger
-	 * for notes and the {@link MergeStrategy#RESOLVE} as the strategy for
-	 * resolving conflicts on non-notes
+	 * Constructs a NoteMapMerger with
+	 * {@link org.eclipse.jgit.notes.DefaultNoteMerger} as the merger for notes
+	 * and the {@link org.eclipse.jgit.merge.MergeStrategy#RESOLVE} as the
+	 * strategy for resolving conflicts on non-notes
 	 *
 	 * @param db
 	 *            Git repository
@@ -125,7 +126,7 @@ public NoteMapMerger(Repository db) {
 	 * @param theirs
 	 *            theirs version of the note tree
 	 * @return merge result as a new NoteMap
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 */
 	public NoteMap merge(NoteMap base, NoteMap ours, NoteMap theirs)
 			throws IOException {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/notes/NoteMerger.java b/org.eclipse.jgit/src/org/eclipse/jgit/notes/NoteMerger.java
index c70211d..8df4998 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/notes/NoteMerger.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/notes/NoteMerger.java
@@ -72,13 +72,13 @@ public interface NoteMerger {
 	 * @param inserter
 	 *            the object inserter that must be used to insert Git objects
 	 * @return the merge result
-	 * @throws NotesMergeConflictException
+	 * @throws org.eclipse.jgit.notes.NotesMergeConflictException
 	 *             in case there was a merge conflict which this note merger
 	 *             couldn't resolve
-	 * @throws IOException
-	 *             in case the reader or the inserter would throw an IOException
-	 *             the implementor will most likely want to propagate it as it
-	 *             can't do much to recover from it
+	 * @throws java.io.IOException
+	 *             in case the reader or the inserter would throw an
+	 *             java.io.IOException the implementor will most likely want to
+	 *             propagate it as it can't do much to recover from it
 	 */
 	Note merge(Note base, Note ours, Note their, ObjectReader reader,
 			ObjectInserter inserter) throws NotesMergeConflictException,
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/notes/NotesMergeConflictException.java b/org.eclipse.jgit/src/org/eclipse/jgit/notes/NotesMergeConflictException.java
index 94fba0f..796f1d1 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/notes/NotesMergeConflictException.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/notes/NotesMergeConflictException.java
@@ -49,8 +49,9 @@
 import org.eclipse.jgit.internal.JGitText;
 
 /**
- * This exception will be thrown from the {@link NoteMerger} when a conflict on
- * Notes content is found during merge.
+ * This exception will be thrown from the
+ * {@link org.eclipse.jgit.notes.NoteMerger} when a conflict on Notes content is
+ * found during merge.
  */
 public class NotesMergeConflictException extends IOException {
 	private static final long serialVersionUID = 1L;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/patch/BinaryHunk.java b/org.eclipse.jgit/src/org/eclipse/jgit/patch/BinaryHunk.java
index d0a6b1f..95391ec 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/patch/BinaryHunk.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/patch/BinaryHunk.java
@@ -49,7 +49,9 @@
 import static org.eclipse.jgit.util.RawParseUtils.nextLF;
 import static org.eclipse.jgit.util.RawParseUtils.parseBase10;
 
-/** Part of a "GIT binary patch" to describe the pre-image or post-image */
+/**
+ * Part of a "GIT binary patch" to describe the pre-image or post-image
+ */
 public class BinaryHunk {
 	private static final byte[] LITERAL = encodeASCII("literal "); //$NON-NLS-1$
 
@@ -78,42 +80,66 @@ public static enum Type {
 	/** Inflated length of the data. */
 	private int length;
 
-	BinaryHunk(final FileHeader fh, final int offset) {
+	BinaryHunk(FileHeader fh, int offset) {
 		file = fh;
 		startOffset = offset;
 	}
 
-	/** @return header for the file this hunk applies to */
+	/**
+	 * Get header for the file this hunk applies to.
+	 *
+	 * @return header for the file this hunk applies to.
+	 */
 	public FileHeader getFileHeader() {
 		return file;
 	}
 
-	/** @return the byte array holding this hunk's patch script. */
+	/**
+	 * Get the byte array holding this hunk's patch script.
+	 *
+	 * @return the byte array holding this hunk's patch script.
+	 */
 	public byte[] getBuffer() {
 		return file.buf;
 	}
 
-	/** @return offset the start of this hunk in {@link #getBuffer()}. */
+	/**
+	 * Get offset the start of this hunk in {@link #getBuffer()}.
+	 *
+	 * @return offset the start of this hunk in {@link #getBuffer()}.
+	 */
 	public int getStartOffset() {
 		return startOffset;
 	}
 
-	/** @return offset one past the end of the hunk in {@link #getBuffer()}. */
+	/**
+	 * Get offset one past the end of the hunk in {@link #getBuffer()}.
+	 *
+	 * @return offset one past the end of the hunk in {@link #getBuffer()}.
+	 */
 	public int getEndOffset() {
 		return endOffset;
 	}
 
-	/** @return type of this binary hunk */
+	/**
+	 * Get type of this binary hunk.
+	 *
+	 * @return type of this binary hunk.
+	 */
 	public Type getType() {
 		return type;
 	}
 
-	/** @return inflated size of this hunk's data */
+	/**
+	 * Get inflated size of this hunk's data.
+	 *
+	 * @return inflated size of this hunk's data.
+	 */
 	public int getSize() {
 		return length;
 	}
 
-	int parseHunk(int ptr, final int end) {
+	int parseHunk(int ptr, int end) {
 		final byte[] buf = file.buf;
 
 		if (match(buf, ptr, LITERAL) >= 0) {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/patch/CombinedFileHeader.java b/org.eclipse.jgit/src/org/eclipse/jgit/patch/CombinedFileHeader.java
index 2c8f34e..3407578 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/patch/CombinedFileHeader.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/patch/CombinedFileHeader.java
@@ -69,23 +69,33 @@ public class CombinedFileHeader extends FileHeader {
 
 	private FileMode[] oldModes;
 
-	CombinedFileHeader(final byte[] b, final int offset) {
+	CombinedFileHeader(byte[] b, int offset) {
 		super(b, offset);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	@SuppressWarnings("unchecked")
 	public List<? extends CombinedHunkHeader> getHunks() {
 		return (List<CombinedHunkHeader>) super.getHunks();
 	}
 
-	/** @return number of ancestor revisions mentioned in this diff. */
+	/**
+	 * {@inheritDoc}
+	 * <p>
+	 *
+	 * @return number of ancestor revisions mentioned in this diff.
+	 */
 	@Override
 	public int getParentCount() {
 		return oldIds.length;
 	}
 
-	/** @return get the file mode of the first parent. */
+	/**
+	 * {@inheritDoc}
+	 * <p>
+	 * @return get the file mode of the first parent.
+	 */
 	@Override
 	public FileMode getOldMode() {
 		return getOldMode(0);
@@ -98,11 +108,16 @@ public FileMode getOldMode() {
 	 *            the ancestor to get the mode of
 	 * @return the mode of the requested ancestor.
 	 */
-	public FileMode getOldMode(final int nthParent) {
+	public FileMode getOldMode(int nthParent) {
 		return oldModes[nthParent];
 	}
 
-	/** @return get the object id of the first parent. */
+	/**
+	 * {@inheritDoc}
+	 * <p>
+	 *
+	 * @return get the object id of the first parent.
+	 */
 	@Override
 	public AbbreviatedObjectId getOldId() {
 		return getOldId(0);
@@ -115,12 +130,13 @@ public AbbreviatedObjectId getOldId() {
 	 *            the ancestor to get the object id of
 	 * @return the id of the requested ancestor.
 	 */
-	public AbbreviatedObjectId getOldId(final int nthParent) {
+	public AbbreviatedObjectId getOldId(int nthParent) {
 		return oldIds[nthParent];
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	public String getScriptText(final Charset ocs, final Charset ncs) {
+	public String getScriptText(Charset ocs, Charset ncs) {
 		final Charset[] cs = new Charset[getParentCount() + 1];
 		Arrays.fill(cs, ocs);
 		cs[getParentCount()] = ncs;
@@ -128,23 +144,17 @@ public String getScriptText(final Charset ocs, final Charset ncs) {
 	}
 
 	/**
+	 * {@inheritDoc}
+	 * <p>
 	 * Convert the patch script for this file into a string.
-	 *
-	 * @param charsetGuess
-	 *            optional array to suggest the character set to use when
-	 *            decoding each file's line. If supplied the array must have a
-	 *            length of <code>{@link #getParentCount()} + 1</code>
-	 *            representing the old revision character sets and the new
-	 *            revision character set.
-	 * @return the patch script, as a Unicode string.
 	 */
 	@Override
-	public String getScriptText(final Charset[] charsetGuess) {
+	public String getScriptText(Charset[] charsetGuess) {
 		return super.getScriptText(charsetGuess);
 	}
 
 	@Override
-	int parseGitHeaders(int ptr, final int end) {
+	int parseGitHeaders(int ptr, int end) {
 		while (ptr < end) {
 			final int eol = nextLF(buf, ptr);
 			if (isHunkHdr(buf, ptr, end) >= 1) {
@@ -179,8 +189,9 @@ int parseGitHeaders(int ptr, final int end) {
 		return ptr;
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	protected void parseIndexLine(int ptr, final int eol) {
+	protected void parseIndexLine(int ptr, int eol) {
 		// "index $asha1,$bsha1..$csha1"
 		//
 		final List<AbbreviatedObjectId> ids = new ArrayList<>();
@@ -200,19 +211,20 @@ protected void parseIndexLine(int ptr, final int eol) {
 		oldModes = new FileMode[oldIds.length];
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	protected void parseNewFileMode(final int ptr, final int eol) {
+	protected void parseNewFileMode(int ptr, int eol) {
 		for (int i = 0; i < oldModes.length; i++)
 			oldModes[i] = FileMode.MISSING;
 		super.parseNewFileMode(ptr, eol);
 	}
 
 	@Override
-	HunkHeader newHunkHeader(final int offset) {
+	HunkHeader newHunkHeader(int offset) {
 		return new CombinedHunkHeader(this, offset);
 	}
 
-	private void parseModeLine(int ptr, final int eol) {
+	private void parseModeLine(int ptr, int eol) {
 		// "mode $amode,$bmode..$cmode"
 		//
 		int n = 0;
@@ -228,7 +240,7 @@ private void parseModeLine(int ptr, final int eol) {
 		newMode = parseFileMode(dot2 + 1, eol);
 	}
 
-	private void parseDeletedFileMode(int ptr, final int eol) {
+	private void parseDeletedFileMode(int ptr, int eol) {
 		// "deleted file mode $amode,$bmode"
 		//
 		changeType = ChangeType.DELETE;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/patch/CombinedHunkHeader.java b/org.eclipse.jgit/src/org/eclipse/jgit/patch/CombinedHunkHeader.java
index ed79787..d278132 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/patch/CombinedHunkHeader.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/patch/CombinedHunkHeader.java
@@ -54,7 +54,9 @@
 import org.eclipse.jgit.lib.AbbreviatedObjectId;
 import org.eclipse.jgit.util.MutableInteger;
 
-/** Hunk header for a hunk appearing in a "diff --cc" style patch. */
+/**
+ * Hunk header for a hunk appearing in a "diff --cc" style patch.
+ */
 public class CombinedHunkHeader extends HunkHeader {
 	private static abstract class CombinedOldImage extends OldImage {
 		int nContext;
@@ -62,7 +64,7 @@ private static abstract class CombinedOldImage extends OldImage {
 
 	private CombinedOldImage[] old;
 
-	CombinedHunkHeader(final CombinedFileHeader fh, final int offset) {
+	CombinedHunkHeader(CombinedFileHeader fh, int offset) {
 		super(fh, offset, null);
 		old = new CombinedOldImage[fh.getParentCount()];
 		for (int i = 0; i < old.length; i++) {
@@ -76,11 +78,13 @@ public AbbreviatedObjectId getId() {
 		}
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public CombinedFileHeader getFileHeader() {
 		return (CombinedFileHeader) super.getFileHeader();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public OldImage getOldImage() {
 		return getOldImage(0);
@@ -93,7 +97,7 @@ public OldImage getOldImage() {
 	 *            the ancestor to get the old image data of
 	 * @return image data of the requested ancestor.
 	 */
-	public OldImage getOldImage(final int nthParent) {
+	public OldImage getOldImage(int nthParent) {
 		return old[nthParent];
 	}
 
@@ -121,11 +125,11 @@ void parseHeader() {
 	}
 
 	@Override
-	int parseBody(final Patch script, final int end) {
+	int parseBody(Patch script, int end) {
 		final byte[] buf = file.buf;
 		int c = nextLF(buf, startOffset);
 
-		for (final CombinedOldImage o : old) {
+		for (CombinedOldImage o : old) {
 			o.nDeleted = 0;
 			o.nAdded = 0;
 			o.nContext = 0;
@@ -203,7 +207,7 @@ int parseBody(final Patch script, final int end) {
 	}
 
 	@Override
-	void extractFileLines(final OutputStream[] out) throws IOException {
+	void extractFileLines(OutputStream[] out) throws IOException {
 		final byte[] buf = file.buf;
 		int ptr = startOffset;
 		int eol = nextLF(buf, ptr);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/patch/FileHeader.java b/org.eclipse.jgit/src/org/eclipse/jgit/patch/FileHeader.java
index eb28a0e..d0a5216 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/patch/FileHeader.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/patch/FileHeader.java
@@ -69,7 +69,9 @@
 import org.eclipse.jgit.util.RawParseUtils;
 import org.eclipse.jgit.util.TemporaryBuffer;
 
-/** Patch header describing an action for a single file path. */
+/**
+ * Patch header describing an action for a single file path.
+ */
 public class FileHeader extends DiffEntry {
 	private static final byte[] OLD_MODE = encodeASCII("old mode "); //$NON-NLS-1$
 
@@ -144,7 +146,7 @@ public static enum PatchType {
 	 * @param type
 	 *            the type of patch used to modify this file
 	 */
-	public FileHeader(final byte[] headerLines, EditList edits, PatchType type) {
+	public FileHeader(byte[] headerLines, EditList edits, PatchType type) {
 		this(headerLines, 0);
 		endOffset = headerLines.length;
 		int ptr = parseGitFileName(Patch.DIFF_GIT.length, headerLines.length);
@@ -153,7 +155,7 @@ public FileHeader(final byte[] headerLines, EditList edits, PatchType type) {
 		addHunk(new HunkHeader(this, edits));
 	}
 
-	FileHeader(final byte[] b, final int offset) {
+	FileHeader(byte[] b, int offset) {
 		buf = b;
 		startOffset = offset;
 		changeType = ChangeType.MODIFY; // unless otherwise designated
@@ -164,17 +166,30 @@ int getParentCount() {
 		return 1;
 	}
 
-	/** @return the byte array holding this file's patch script. */
+	/**
+	 * Get the byte array holding this file's patch script.
+	 *
+	 * @return the byte array holding this file's patch script.
+	 */
 	public byte[] getBuffer() {
 		return buf;
 	}
 
-	/** @return offset the start of this file's script in {@link #getBuffer()}. */
+	/**
+	 * Get offset of the start of this file's script in {@link #getBuffer()}.
+	 *
+	 * @return offset of the start of this file's script in
+	 *         {@link #getBuffer()}.
+	 */
 	public int getStartOffset() {
 		return startOffset;
 	}
 
-	/** @return offset one past the end of the file script. */
+	/**
+	 * Get offset one past the end of the file script.
+	 *
+	 * @return offset one past the end of the file script.
+	 */
 	public int getEndOffset() {
 		return endOffset;
 	}
@@ -182,8 +197,9 @@ public int getEndOffset() {
 	/**
 	 * Convert the patch script for this file into a string.
 	 * <p>
-	 * The default character encoding ({@link Constants#CHARSET}) is assumed for
-	 * both the old and new files.
+	 * The default character encoding
+	 * ({@link org.eclipse.jgit.lib.Constants#CHARSET}) is assumed for both the
+	 * old and new files.
 	 *
 	 * @return the patch script, as a Unicode string.
 	 */
@@ -248,12 +264,12 @@ String getScriptText(Charset[] charsetGuess) {
 
 		final String[] files = extractFileLines(charsetGuess);
 		final int[] offsets = new int[files.length];
-		for (final HunkHeader h : getHunks())
+		for (HunkHeader h : getHunks())
 			h.extractFileLines(r, files, offsets);
 		return r.toString();
 	}
 
-	private static boolean trySimpleConversion(final Charset[] charsetGuess) {
+	private static boolean trySimpleConversion(Charset[] charsetGuess) {
 		if (charsetGuess == null)
 			return true;
 		for (int i = 1; i < charsetGuess.length; i++) {
@@ -263,12 +279,12 @@ private static boolean trySimpleConversion(final Charset[] charsetGuess) {
 		return true;
 	}
 
-	private String[] extractFileLines(final Charset[] csGuess) {
+	private String[] extractFileLines(Charset[] csGuess) {
 		final TemporaryBuffer[] tmp = new TemporaryBuffer[getParentCount() + 1];
 		try {
 			for (int i = 0; i < tmp.length; i++)
 				tmp[i] = new TemporaryBuffer.Heap(Integer.MAX_VALUE);
-			for (final HunkHeader h : getHunks())
+			for (HunkHeader h : getHunks())
 				h.extractFileLines(tmp);
 
 			final String[] r = new String[tmp.length];
@@ -284,24 +300,36 @@ private static boolean trySimpleConversion(final Charset[] charsetGuess) {
 		}
 	}
 
-	/** @return style of patch used to modify this file */
+	/**
+	 * Get style of patch used to modify this file.
+	 *
+	 * @return style of patch used to modify this file.
+	 */
 	public PatchType getPatchType() {
 		return patchType;
 	}
 
-	/** @return true if this patch modifies metadata about a file */
+	/**
+	 * Whether this patch modifies metadata about a file
+	 *
+	 * @return {@code true} if this patch modifies metadata about a file .
+	 */
 	public boolean hasMetaDataChanges() {
 		return changeType != ChangeType.MODIFY || newMode != oldMode;
 	}
 
-	/** @return hunks altering this file; in order of appearance in patch */
+	/**
+	 * Get hunks altering this file; in order of appearance in patch
+	 *
+	 * @return hunks altering this file; in order of appearance in patch.
+	 */
 	public List<? extends HunkHeader> getHunks() {
 		if (hunks == null)
 			return Collections.emptyList();
 		return hunks;
 	}
 
-	void addHunk(final HunkHeader h) {
+	void addHunk(HunkHeader h) {
 		if (h.getFileHeader() != this)
 			throw new IllegalArgumentException(JGitText.get().hunkBelongsToAnotherFile);
 		if (hunks == null)
@@ -309,24 +337,40 @@ void addHunk(final HunkHeader h) {
 		hunks.add(h);
 	}
 
-	HunkHeader newHunkHeader(final int offset) {
+	HunkHeader newHunkHeader(int offset) {
 		return new HunkHeader(this, offset);
 	}
 
-	/** @return if a {@link PatchType#GIT_BINARY}, the new-image delta/literal */
+	/**
+	 * Get the new-image delta/literal if this is a
+	 * {@link PatchType#GIT_BINARY}.
+	 *
+	 * @return the new-image delta/literal if this is a
+	 *         {@link PatchType#GIT_BINARY}.
+	 */
 	public BinaryHunk getForwardBinaryHunk() {
 		return forwardBinaryHunk;
 	}
 
-	/** @return if a {@link PatchType#GIT_BINARY}, the old-image delta/literal */
+	/**
+	 * Get the old-image delta/literal if this is a
+	 * {@link PatchType#GIT_BINARY}.
+	 *
+	 * @return the old-image delta/literal if this is a
+	 *         {@link PatchType#GIT_BINARY}.
+	 */
 	public BinaryHunk getReverseBinaryHunk() {
 		return reverseBinaryHunk;
 	}
 
-	/** @return a list describing the content edits performed on this file. */
+	/**
+	 * Convert to a list describing the content edits performed on this file.
+	 *
+	 * @return a list describing the content edits performed on this file.
+	 */
 	public EditList toEditList() {
 		final EditList r = new EditList();
-		for (final HunkHeader hunk : hunks)
+		for (HunkHeader hunk : hunks)
 			r.addAll(hunk.toEditList());
 		return r;
 	}
@@ -340,7 +384,7 @@ public EditList toEditList() {
 	 *            one past the last position to parse.
 	 * @return first character after the LF at the end of the line; -1 on error.
 	 */
-	int parseGitFileName(int ptr, final int end) {
+	int parseGitFileName(int ptr, int end) {
 		final int eol = nextLF(buf, ptr);
 		final int bol = ptr;
 		if (eol >= end) {
@@ -400,7 +444,7 @@ int parseGitFileName(int ptr, final int end) {
 		return eol;
 	}
 
-	int parseGitHeaders(int ptr, final int end) {
+	int parseGitHeaders(int ptr, int end) {
 		while (ptr < end) {
 			final int eol = nextLF(buf, ptr);
 			if (isHunkHdr(buf, ptr, eol) >= 1) {
@@ -470,25 +514,25 @@ int parseGitHeaders(int ptr, final int end) {
 		return ptr;
 	}
 
-	void parseOldName(int ptr, final int eol) {
+	void parseOldName(int ptr, int eol) {
 		oldPath = p1(parseName(oldPath, ptr + OLD_NAME.length, eol));
 		if (oldPath == DEV_NULL)
 			changeType = ChangeType.ADD;
 	}
 
-	void parseNewName(int ptr, final int eol) {
+	void parseNewName(int ptr, int eol) {
 		newPath = p1(parseName(newPath, ptr + NEW_NAME.length, eol));
 		if (newPath == DEV_NULL)
 			changeType = ChangeType.DELETE;
 	}
 
-	void parseNewFileMode(int ptr, final int eol) {
+	void parseNewFileMode(int ptr, int eol) {
 		oldMode = FileMode.MISSING;
 		newMode = parseFileMode(ptr + NEW_FILE_MODE.length, eol);
 		changeType = ChangeType.ADD;
 	}
 
-	int parseTraditionalHeaders(int ptr, final int end) {
+	int parseTraditionalHeaders(int ptr, int end) {
 		while (ptr < end) {
 			final int eol = nextLF(buf, ptr);
 			if (isHunkHdr(buf, ptr, eol) >= 1) {
@@ -511,7 +555,7 @@ int parseTraditionalHeaders(int ptr, final int end) {
 		return ptr;
 	}
 
-	private String parseName(final String expect, int ptr, final int end) {
+	private String parseName(String expect, int ptr, int end) {
 		if (ptr == end)
 			return expect;
 
@@ -541,7 +585,7 @@ private static String p1(final String r) {
 		return s > 0 ? r.substring(s + 1) : r;
 	}
 
-	FileMode parseFileMode(int ptr, final int end) {
+	FileMode parseFileMode(int ptr, int end) {
 		int tmp = 0;
 		while (ptr < end - 1) {
 			tmp <<= 3;
@@ -550,7 +594,7 @@ FileMode parseFileMode(int ptr, final int end) {
 		return FileMode.fromBits(tmp);
 	}
 
-	void parseIndexLine(int ptr, final int end) {
+	void parseIndexLine(int ptr, int end) {
 		// "index $asha1..$bsha1[ $mode]" where $asha1 and $bsha1
 		// can be unique abbreviations
 		//
@@ -592,7 +636,7 @@ private boolean eq(int aPtr, int aEnd, int bPtr, int bEnd) {
 	 *         for a 3 way-merge returns 3. If this is not a hunk header, 0 is
 	 *         returned instead.
 	 */
-	static int isHunkHdr(final byte[] buf, final int start, final int end) {
+	static int isHunkHdr(byte[] buf, int start, int end) {
 		int ptr = start;
 		while (ptr < end && buf[ptr] == '@')
 			ptr++;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/patch/FormatError.java b/org.eclipse.jgit/src/org/eclipse/jgit/patch/FormatError.java
index 767cb24..1dd24d7 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/patch/FormatError.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/patch/FormatError.java
@@ -48,7 +48,9 @@
 import org.eclipse.jgit.lib.Constants;
 import org.eclipse.jgit.util.RawParseUtils;
 
-/** An error in a patch script */
+/**
+ * An error in a patch script
+ */
 public class FormatError {
 	/** Classification of an error. */
 	public static enum Severity {
@@ -75,32 +77,53 @@ public static enum Severity {
 		message = msg;
 	}
 
-	/** @return the severity of the error. */
+	/**
+	 * Get the severity of the error.
+	 *
+	 * @return the severity of the error.
+	 */
 	public Severity getSeverity() {
 		return severity;
 	}
 
-	/** @return a message describing the error. */
+	/**
+	 * Get a message describing the error.
+	 *
+	 * @return a message describing the error.
+	 */
 	public String getMessage() {
 		return message;
 	}
 
-	/** @return the byte buffer holding the patch script. */
+	/**
+	 * Get the byte buffer holding the patch script.
+	 *
+	 * @return the byte buffer holding the patch script.
+	 */
 	public byte[] getBuffer() {
 		return buf;
 	}
 
-	/** @return byte offset within {@link #getBuffer()} where the error is */
+	/**
+	 * Get byte offset within {@link #getBuffer()} where the error is.
+	 *
+	 * @return byte offset within {@link #getBuffer()} where the error is.
+	 */
 	public int getOffset() {
 		return offset;
 	}
 
-	/** @return line of the patch script the error appears on. */
+	/**
+	 * Get line of the patch script the error appears on.
+	 *
+	 * @return line of the patch script the error appears on.
+	 */
 	public String getLineText() {
 		final int eol = RawParseUtils.nextLF(buf, offset);
 		return RawParseUtils.decode(Constants.CHARSET, buf, offset, eol);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public String toString() {
 		final StringBuilder r = new StringBuilder();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/patch/HunkHeader.java b/org.eclipse.jgit/src/org/eclipse/jgit/patch/HunkHeader.java
index d72b9bb..1458945 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/patch/HunkHeader.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/patch/HunkHeader.java
@@ -57,7 +57,9 @@
 import org.eclipse.jgit.lib.AbbreviatedObjectId;
 import org.eclipse.jgit.util.MutableInteger;
 
-/** Hunk header describing the layout of a single block of lines */
+/**
+ * Hunk header describing the layout of a single block of lines
+ */
 public class HunkHeader {
 	/** Details about an old image of the file. */
 	public abstract static class OldImage {
@@ -118,7 +120,7 @@ public int getLinesAdded() {
 
 	private EditList editList;
 
-	HunkHeader(final FileHeader fh, final int offset) {
+	HunkHeader(FileHeader fh, int offset) {
 		this(fh, offset, new OldImage() {
 			@Override
 			public AbbreviatedObjectId getId() {
@@ -127,13 +129,13 @@ public AbbreviatedObjectId getId() {
 		});
 	}
 
-	HunkHeader(final FileHeader fh, final int offset, final OldImage oi) {
+	HunkHeader(FileHeader fh, int offset, OldImage oi) {
 		file = fh;
 		startOffset = offset;
 		old = oi;
 	}
 
-	HunkHeader(final FileHeader fh, final EditList editList) {
+	HunkHeader(FileHeader fh, EditList editList) {
 		this(fh, fh.buf.length);
 		this.editList = editList;
 		endOffset = startOffset;
@@ -148,47 +150,83 @@ public AbbreviatedObjectId getId() {
 		}
 	}
 
-	/** @return header for the file this hunk applies to */
+	/**
+	 * Get header for the file this hunk applies to.
+	 *
+	 * @return header for the file this hunk applies to.
+	 */
 	public FileHeader getFileHeader() {
 		return file;
 	}
 
-	/** @return the byte array holding this hunk's patch script. */
+	/**
+	 * Get the byte array holding this hunk's patch script.
+	 *
+	 * @return the byte array holding this hunk's patch script.
+	 */
 	public byte[] getBuffer() {
 		return file.buf;
 	}
 
-	/** @return offset the start of this hunk in {@link #getBuffer()}. */
+	/**
+	 * Get offset of the start of this hunk in {@link #getBuffer()}.
+	 *
+	 * @return offset of the start of this hunk in {@link #getBuffer()}.
+	 */
 	public int getStartOffset() {
 		return startOffset;
 	}
 
-	/** @return offset one past the end of the hunk in {@link #getBuffer()}. */
+	/**
+	 * Get offset one past the end of the hunk in {@link #getBuffer()}.
+	 *
+	 * @return offset one past the end of the hunk in {@link #getBuffer()}.
+	 */
 	public int getEndOffset() {
 		return endOffset;
 	}
 
-	/** @return information about the old image mentioned in this hunk. */
+	/**
+	 * Get information about the old image mentioned in this hunk.
+	 *
+	 * @return information about the old image mentioned in this hunk.
+	 */
 	public OldImage getOldImage() {
 		return old;
 	}
 
-	/** @return first line number in the post-image file where the hunk starts */
+	/**
+	 * Get first line number in the post-image file where the hunk starts.
+	 *
+	 * @return first line number in the post-image file where the hunk starts.
+	 */
 	public int getNewStartLine() {
 		return newStartLine;
 	}
 
-	/** @return Total number of post-image lines this hunk covers */
+	/**
+	 * Get total number of post-image lines this hunk covers.
+	 *
+	 * @return total number of post-image lines this hunk covers.
+	 */
 	public int getNewLineCount() {
 		return newLineCount;
 	}
 
-	/** @return total number of lines of context appearing in this hunk */
+	/**
+	 * Get total number of lines of context appearing in this hunk.
+	 *
+	 * @return total number of lines of context appearing in this hunk.
+	 */
 	public int getLinesContext() {
 		return nContext;
 	}
 
-	/** @return a list describing the content edits performed within the hunk. */
+	/**
+	 * Convert to a list describing the content edits performed within the hunk.
+	 *
+	 * @return a list describing the content edits performed within the hunk.
+	 */
 	public EditList toEditList() {
 		if (editList == null) {
 			editList = new EditList();
@@ -255,7 +293,7 @@ void parseHeader() {
 			newLineCount = 1;
 	}
 
-	int parseBody(final Patch script, final int end) {
+	int parseBody(Patch script, int end) {
 		final byte[] buf = file.buf;
 		int c = nextLF(buf, startOffset), last = c;
 
@@ -321,7 +359,7 @@ && match(buf, last, Patch.SIG_FOOTER) >= 0) {
 		return c;
 	}
 
-	void extractFileLines(final OutputStream[] out) throws IOException {
+	void extractFileLines(OutputStream[] out) throws IOException {
 		final byte[] buf = file.buf;
 		int ptr = startOffset;
 		int eol = nextLF(buf, ptr);
@@ -404,6 +442,7 @@ void skipLine(final String[] text, final int[] offsets,
 		offsets[fileIdx] = end < 0 ? s.length() : end + 1;
 	}
 
+	/** {@inheritDoc} */
 	@SuppressWarnings("nls")
 	@Override
 	public String toString() {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/patch/Patch.java b/org.eclipse.jgit/src/org/eclipse/jgit/patch/Patch.java
index 10ac449d..052f2a7 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/patch/Patch.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/patch/Patch.java
@@ -58,7 +58,10 @@
 import org.eclipse.jgit.internal.JGitText;
 import org.eclipse.jgit.util.TemporaryBuffer;
 
-/** A parsed collection of {@link FileHeader}s from a unified diff patch file */
+/**
+ * A parsed collection of {@link org.eclipse.jgit.patch.FileHeader}s from a
+ * unified diff patch file
+ */
 public class Patch {
 	static final byte[] DIFF_GIT = encodeASCII("diff --git "); //$NON-NLS-1$
 
@@ -81,7 +84,9 @@ public class Patch {
 	/** Formatting errors, if any were identified. */
 	private final List<FormatError> errors;
 
-	/** Create an empty patch. */
+	/**
+	 * Create an empty patch.
+	 */
 	public Patch() {
 		files = new ArrayList<>();
 		errors = new ArrayList<>(0);
@@ -96,11 +101,15 @@ public Patch() {
 	 * @param fh
 	 *            the header of the file.
 	 */
-	public void addFile(final FileHeader fh) {
+	public void addFile(FileHeader fh) {
 		files.add(fh);
 	}
 
-	/** @return list of files described in the patch, in occurrence order. */
+	/**
+	 * Get list of files described in the patch, in occurrence order.
+	 *
+	 * @return list of files described in the patch, in occurrence order.
+	 */
 	public List<? extends FileHeader> getFiles() {
 		return files;
 	}
@@ -111,11 +120,15 @@ public List<? extends FileHeader> getFiles() {
 	 * @param err
 	 *            the error description.
 	 */
-	public void addError(final FormatError err) {
+	public void addError(FormatError err) {
 		errors.add(err);
 	}
 
-	/** @return collection of formatting errors, if any. */
+	/**
+	 * Get collection of formatting errors.
+	 *
+	 * @return collection of formatting errors, if any.
+	 */
 	public List<FormatError> getErrors() {
 		return errors;
 	}
@@ -130,19 +143,19 @@ public List<FormatError> getErrors() {
 	 * @param is
 	 *            the stream to read the patch data from. The stream is read
 	 *            until EOF is reached.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             there was an error reading from the input stream.
 	 */
-	public void parse(final InputStream is) throws IOException {
+	public void parse(InputStream is) throws IOException {
 		final byte[] buf = readFully(is);
 		parse(buf, 0, buf.length);
 	}
 
-	private static byte[] readFully(final InputStream is) throws IOException {
-		TemporaryBuffer b = new TemporaryBuffer.Heap(Integer.MAX_VALUE);
-		b.copy(is);
-		b.close();
-		return b.toByteArray();
+	private static byte[] readFully(InputStream is) throws IOException {
+		try (TemporaryBuffer b = new TemporaryBuffer.Heap(Integer.MAX_VALUE)) {
+			b.copy(is);
+			return b.toByteArray();
+		}
 	}
 
 	/**
@@ -160,12 +173,12 @@ public void parse(final InputStream is) throws IOException {
 	 *            1 past the last position to end parsing. The total length to
 	 *            be parsed is <code>end - ptr</code>.
 	 */
-	public void parse(final byte[] buf, int ptr, final int end) {
+	public void parse(byte[] buf, int ptr, int end) {
 		while (ptr < end)
 			ptr = parseFile(buf, ptr, end);
 	}
 
-	private int parseFile(final byte[] buf, int c, final int end) {
+	private int parseFile(byte[] buf, int c, int end) {
 		while (c < end) {
 			if (isHunkHdr(buf, c, end) >= 1) {
 				// If we find a disconnected hunk header we might
@@ -221,7 +234,7 @@ private int parseFile(final byte[] buf, int c, final int end) {
 		return c;
 	}
 
-	private int parseDiffGit(final byte[] buf, final int start, final int end) {
+	private int parseDiffGit(byte[] buf, int start, int end) {
 		final FileHeader fh = new FileHeader(buf, start);
 		int ptr = fh.parseGitFileName(start + DIFF_GIT.length, end);
 		if (ptr < 0)
@@ -258,14 +271,14 @@ private int parseTraditionalPatch(final byte[] buf, final int start,
 		return ptr;
 	}
 
-	private static int skipFile(final byte[] buf, int ptr) {
+	private static int skipFile(byte[] buf, int ptr) {
 		ptr = nextLF(buf, ptr);
 		if (match(buf, ptr, OLD_NAME) >= 0)
 			ptr = nextLF(buf, ptr);
 		return ptr;
 	}
 
-	private int parseHunks(final FileHeader fh, int c, final int end) {
+	private int parseHunks(FileHeader fh, int c, int end) {
 		final byte[] buf = fh.buf;
 		while (c < end) {
 			// If we see a file header at this point, we have all of the
@@ -336,7 +349,7 @@ && matchAny(buf, c, BIN_HEADERS)) {
 		return c;
 	}
 
-	private int parseGitBinary(final FileHeader fh, int c, final int end) {
+	private int parseGitBinary(FileHeader fh, int c, int end) {
 		final BinaryHunk postImage = new BinaryHunk(fh, c);
 		final int nEnd = postImage.parseHunk(c, end);
 		if (nEnd < 0) {
@@ -360,17 +373,17 @@ private int parseGitBinary(final FileHeader fh, int c, final int end) {
 		return c;
 	}
 
-	void warn(final byte[] buf, final int ptr, final String msg) {
+	void warn(byte[] buf, int ptr, String msg) {
 		addError(new FormatError(buf, ptr, FormatError.Severity.WARNING, msg));
 	}
 
-	void error(final byte[] buf, final int ptr, final String msg) {
+	void error(byte[] buf, int ptr, String msg) {
 		addError(new FormatError(buf, ptr, FormatError.Severity.ERROR, msg));
 	}
 
 	private static boolean matchAny(final byte[] buf, final int c,
 			final byte[][] srcs) {
-		for (final byte[] s : srcs) {
+		for (byte[] s : srcs) {
 			if (match(buf, c, s) >= 0)
 				return true;
 		}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revplot/AbstractPlotRenderer.java b/org.eclipse.jgit/src/org/eclipse/jgit/revplot/AbstractPlotRenderer.java
index f88b819..58e2106 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revplot/AbstractPlotRenderer.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revplot/AbstractPlotRenderer.java
@@ -92,14 +92,14 @@ public abstract class AbstractPlotRenderer<TLane extends PlotLane, TColor> {
 	 *            total height (in pixels) of this cell.
 	 */
 	@SuppressWarnings("unchecked")
-	protected void paintCommit(final PlotCommit<TLane> commit, final int h) {
+	protected void paintCommit(PlotCommit<TLane> commit, int h) {
 		final int dotSize = computeDotSize(h);
 		final TLane myLane = commit.getLane();
 		final int myLaneX = laneC(myLane);
 		final TColor myColor = laneColor(myLane);
 
 		int maxCenter = myLaneX;
-		for (final TLane passingLane : (TLane[]) commit.passingLanes) {
+		for (TLane passingLane : (TLane[]) commit.passingLanes) {
 			final int cx = laneC(passingLane);
 			final TColor c = laneColor(passingLane);
 			drawLine(c, cx, 0, cx, h, LINE_WIDTH);
@@ -190,7 +190,7 @@ protected void paintCommit(final PlotCommit<TLane> commit, final int h) {
 	 */
 	protected abstract int drawLabel(int x, int y, Ref ref);
 
-	private static int computeDotSize(final int h) {
+	private static int computeDotSize(int h) {
 		int d = (int) (Math.min(h, LANE_WIDTH) * 0.50f);
 		d += (d & 1);
 		return d;
@@ -282,12 +282,12 @@ protected abstract void drawLine(TColor color, int x1, int y1, int x2,
 	 */
 	protected abstract void drawText(String msg, int x, int y);
 
-	private static int laneX(final PlotLane myLane) {
+	private static int laneX(PlotLane myLane) {
 		final int p = myLane != null ? myLane.getPosition() : 0;
 		return LEFT_PAD + LANE_WIDTH * p;
 	}
 
-	private static int laneC(final PlotLane myLane) {
+	private static int laneC(PlotLane myLane) {
 		return laneX(myLane) + LANE_WIDTH / 2;
 	}
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revplot/PlotCommit.java b/org.eclipse.jgit/src/org/eclipse/jgit/revplot/PlotCommit.java
index 98bcd1a..9914b0c 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revplot/PlotCommit.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revplot/PlotCommit.java
@@ -79,7 +79,7 @@ public class PlotCommit<L extends PlotLane> extends RevCommit {
 	 * @param id
 	 *            the identity of this commit.
 	 */
-	protected PlotCommit(final AnyObjectId id) {
+	protected PlotCommit(AnyObjectId id) {
 		super(id);
 		forkingOffLanes = NO_LANES;
 		passingLanes = NO_LANES;
@@ -88,19 +88,19 @@ protected PlotCommit(final AnyObjectId id) {
 		refs = NO_REFS;
 	}
 
-	void addForkingOffLane(final PlotLane f) {
+	void addForkingOffLane(PlotLane f) {
 		forkingOffLanes = addLane(f, forkingOffLanes);
 	}
 
-	void addPassingLane(final PlotLane c) {
+	void addPassingLane(PlotLane c) {
 		passingLanes = addLane(c, passingLanes);
 	}
 
-	void addMergingLane(final PlotLane m) {
+	void addMergingLane(PlotLane m) {
 		mergingLanes = addLane(m, mergingLanes);
 	}
 
-	private static PlotLane[] addLane(final PlotLane l, PlotLane[] lanes) {
+	private static PlotLane[] addLane(PlotLane l, PlotLane[] lanes) {
 		final int cnt = lanes.length;
 		if (cnt == 0)
 			lanes = new PlotLane[] { l };
@@ -115,7 +115,7 @@ else if (cnt == 1)
 		return lanes;
 	}
 
-	void addChild(final PlotCommit c) {
+	void addChild(PlotCommit c) {
 		final int cnt = children.length;
 		if (cnt == 0)
 			children = new PlotCommit[] { c };
@@ -149,10 +149,10 @@ public final int getChildCount() {
 	 *            child index to obtain. Must be in the range 0 through
 	 *            {@link #getChildCount()}-1.
 	 * @return the specified child.
-	 * @throws ArrayIndexOutOfBoundsException
+	 * @throws java.lang.ArrayIndexOutOfBoundsException
 	 *             an invalid child index was specified.
 	 */
-	public final PlotCommit getChild(final int nth) {
+	public final PlotCommit getChild(int nth) {
 		return children[nth];
 	}
 
@@ -163,8 +163,8 @@ public final PlotCommit getChild(final int nth) {
 	 *            the commit to test.
 	 * @return true if the given commit built on top of this commit.
 	 */
-	public final boolean isChild(final PlotCommit c) {
-		for (final PlotCommit a : children)
+	public final boolean isChild(PlotCommit c) {
+		for (PlotCommit a : children)
 			if (a == c)
 				return true;
 		return false;
@@ -186,10 +186,10 @@ public final int getRefCount() {
 	 *            ref index to obtain. Must be in the range 0 through
 	 *            {@link #getRefCount()}-1.
 	 * @return the specified ref.
-	 * @throws ArrayIndexOutOfBoundsException
+	 * @throws java.lang.ArrayIndexOutOfBoundsException
 	 *             an invalid ref index was specified.
 	 */
-	public final Ref getRef(final int nth) {
+	public final Ref getRef(int nth) {
 		return refs[nth];
 	}
 
@@ -203,6 +203,7 @@ public final L getLane() {
 		return (L) lane;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void reset() {
 		forkingOffLanes = NO_LANES;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revplot/PlotCommitList.java b/org.eclipse.jgit/src/org/eclipse/jgit/revplot/PlotCommitList.java
index a8eb86e..5e15316 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revplot/PlotCommitList.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revplot/PlotCommitList.java
@@ -57,13 +57,13 @@
 import org.eclipse.jgit.revwalk.RevWalk;
 
 /**
- * An ordered list of {@link PlotCommit} subclasses.
+ * An ordered list of {@link org.eclipse.jgit.revplot.PlotCommit} subclasses.
  * <p>
  * Commits are allocated into lanes as they enter the list, based upon their
  * connections between descendant (child) commits and ancestor (parent) commits.
  * <p>
- * The source of the list must be a {@link PlotWalk} and {@link #fillTo(int)}
- * must be used to populate the list.
+ * The source of the list must be a {@link org.eclipse.jgit.revplot.PlotWalk}
+ * and {@link #fillTo(int)} must be used to populate the list.
  *
  * @param <L>
  *            type of lane used by the application.
@@ -82,6 +82,7 @@ public class PlotCommitList<L extends PlotLane> extends
 	private final HashMap<PlotLane, Integer> laneLength = new HashMap<>(
 			32);
 
+	/** {@inheritDoc} */
 	@Override
 	public void clear() {
 		super.clear();
@@ -91,8 +92,9 @@ public void clear() {
 		laneLength.clear();
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	public void source(final RevWalk w) {
+	public void source(RevWalk w) {
 		if (!(w instanceof PlotWalk))
 			throw new ClassCastException(MessageFormat.format(JGitText.get().classCastNotA, PlotWalk.class.getName()));
 		super.source(w);
@@ -118,12 +120,13 @@ public void source(final RevWalk w) {
 	@SuppressWarnings("unchecked")
 	public void findPassingThrough(final PlotCommit<L> currCommit,
 			final Collection<L> result) {
-		for (final PlotLane p : currCommit.passingLanes)
+		for (PlotLane p : currCommit.passingLanes)
 			result.add((L) p);
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	protected void enter(final int index, final PlotCommit<L> currCommit) {
+	protected void enter(int index, PlotCommit<L> currCommit) {
 		setupChildren(currCommit);
 
 		final int nChildren = currCommit.getChildCount();
@@ -199,7 +202,7 @@ protected void enter(final int index, final PlotCommit<L> currCommit) {
 			closeLane(currCommit.lane);
 	}
 
-	private void continueActiveLanes(final PlotCommit currCommit) {
+	private void continueActiveLanes(PlotCommit currCommit) {
 		for (PlotLane lane : activeLanes)
 			if (lane != currCommit.lane)
 				currCommit.addPassingLane(lane);
@@ -353,7 +356,7 @@ private void closeLane(PlotLane lane) {
 		}
 	}
 
-	private void setupChildren(final PlotCommit<L> currCommit) {
+	private void setupChildren(PlotCommit<L> currCommit) {
 		final int nParents = currCommit.getParentCount();
 		for (int i = 0; i < nParents; i++)
 			((PlotCommit) currCommit.getParent(i)).addChild(currCommit);
@@ -395,7 +398,11 @@ private int getFreePosition(BitSet blockedPositions) {
 	}
 
 	/**
-	 * @return a new Lane appropriate for this particular PlotList.
+	 * Create a new {@link PlotLane} appropriate for this particular
+	 * {@link PlotCommitList}.
+	 *
+	 * @return a new {@link PlotLane} appropriate for this particular
+	 *         {@link PlotCommitList}.
 	 */
 	@SuppressWarnings("unchecked")
 	protected L createLane() {
@@ -407,8 +414,9 @@ protected L createLane() {
 	 * is no longer needed.
 	 *
 	 * @param lane
+	 *            a lane
 	 */
-	protected void recycleLane(final L lane) {
+	protected void recycleLane(L lane) {
 		// Nothing.
 	}
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revplot/PlotWalk.java b/org.eclipse.jgit/src/org/eclipse/jgit/revplot/PlotWalk.java
index be1f07a..f27f356 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revplot/PlotWalk.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revplot/PlotWalk.java
@@ -70,11 +70,14 @@
 import org.eclipse.jgit.revwalk.RevTag;
 import org.eclipse.jgit.revwalk.RevWalk;
 
-/** Specialized RevWalk for visualization of a commit graph. */
+/**
+ * Specialized RevWalk for visualization of a commit graph.
+ */
 public class PlotWalk extends RevWalk {
 
 	private Map<AnyObjectId, Set<Ref>> reverseRefMap;
 
+	/** {@inheritDoc} */
 	@Override
 	public void dispose() {
 		super.dispose();
@@ -87,7 +90,7 @@ public void dispose() {
 	 * @param repo
 	 *            the repository the walker will obtain data from.
 	 */
-	public PlotWalk(final Repository repo) {
+	public PlotWalk(Repository repo) {
 		super(repo);
 		super.sort(RevSort.TOPO, true);
 		reverseRefMap = repo.getAllRefsByPeeledObjectId();
@@ -98,8 +101,7 @@ public PlotWalk(final Repository repo) {
 	 *
 	 * @param refs
 	 *            additional refs
-	 *
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 */
 	public void addAdditionalRefs(Iterable<Ref> refs) throws IOException {
 		for (Ref ref : refs) {
@@ -114,18 +116,21 @@ public void addAdditionalRefs(Iterable<Ref> refs) throws IOException {
 		}
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	public void sort(final RevSort s, final boolean use) {
+	public void sort(RevSort s, boolean use) {
 		if (s == RevSort.TOPO && !use)
 			throw new IllegalArgumentException(JGitText.get().topologicalSortRequired);
 		super.sort(s, use);
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	protected RevCommit createCommit(final AnyObjectId id) {
+	protected RevCommit createCommit(AnyObjectId id) {
 		return new PlotCommit(id);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public RevCommit next() throws MissingObjectException,
 			IncorrectObjectTypeException, IOException {
@@ -135,7 +140,7 @@ public RevCommit next() throws MissingObjectException,
 		return pc;
 	}
 
-	private Ref[] getRefs(final AnyObjectId commitId) {
+	private Ref[] getRefs(AnyObjectId commitId) {
 		Collection<Ref> list = reverseRefMap.get(commitId);
 		if (list == null)
 			return PlotCommit.NO_REFS;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/AbstractRevQueue.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/AbstractRevQueue.java
index 4923d0f..247a3bd 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/AbstractRevQueue.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/AbstractRevQueue.java
@@ -74,7 +74,7 @@ abstract class AbstractRevQueue extends Generator {
 	 * @param queueControl
 	 *            flag that controls admission to the queue.
 	 */
-	public final void add(final RevCommit c, final RevFlag queueControl) {
+	public final void add(RevCommit c, RevFlag queueControl) {
 		if (!c.has(queueControl)) {
 			c.add(queueControl);
 			add(c);
@@ -94,7 +94,7 @@ public final void add(final RevCommit c, final RevFlag queueControl) {
 	 * @param queueControl
 	 *            flag that controls admission to the queue.
 	 */
-	public final void addParents(final RevCommit c, final RevFlag queueControl) {
+	public final void addParents(RevCommit c, RevFlag queueControl) {
 		final RevCommit[] pList = c.parents;
 		if (pList == null)
 			return;
@@ -103,14 +103,16 @@ public final void addParents(final RevCommit c, final RevFlag queueControl) {
 	}
 
 	/**
+	 * {@inheritDoc}
+	 * <p>
 	 * Remove the first commit from the queue.
-	 *
-	 * @return the first commit of this queue.
 	 */
 	@Override
 	public abstract RevCommit next();
 
-	/** Remove all entries from this queue. */
+	/**
+	 * Remove all entries from this queue.
+	 */
 	public abstract void clear();
 
 	abstract boolean everbodyHasFlag(int f);
@@ -122,7 +124,15 @@ int outputType() {
 		return outputType;
 	}
 
-	protected static void describe(final StringBuilder s, final RevCommit c) {
+	/**
+	 * Describe this queue
+	 *
+	 * @param s
+	 *            a StringBuilder
+	 * @param c
+	 *            a {@link org.eclipse.jgit.revwalk.RevCommit}
+	 */
+	protected static void describe(StringBuilder s, RevCommit c) {
 		s.append(c.toString());
 		s.append('\n');
 	}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/AsyncRevObjectQueue.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/AsyncRevObjectQueue.java
index 1c0438a..d263184 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/AsyncRevObjectQueue.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/AsyncRevObjectQueue.java
@@ -59,11 +59,11 @@ public interface AsyncRevObjectQueue extends AsyncOperation {
 	 * Obtain the next object.
 	 *
 	 * @return the object; null if there are no more objects remaining.
-	 * @throws MissingObjectException
+	 * @throws org.eclipse.jgit.errors.MissingObjectException
 	 *             the object does not exist. There may be more objects
 	 *             remaining in the iteration, the application should call
 	 *             {@link #next()} again.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the object store cannot be accessed.
 	 */
 	public RevObject next() throws MissingObjectException, IOException;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackWriterBitmapWalker.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/BitmapWalker.java
similarity index 64%
rename from org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackWriterBitmapWalker.java
rename to org.eclipse.jgit/src/org/eclipse/jgit/revwalk/BitmapWalker.java
index a5c3b71..b07de5f 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackWriterBitmapWalker.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/BitmapWalker.java
@@ -41,29 +41,30 @@
  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-package org.eclipse.jgit.internal.storage.pack;
+package org.eclipse.jgit.revwalk;
 
 import java.io.IOException;
 import java.util.Arrays;
 
 import org.eclipse.jgit.errors.IncorrectObjectTypeException;
 import org.eclipse.jgit.errors.MissingObjectException;
+import org.eclipse.jgit.internal.revwalk.AddToBitmapFilter;
+import org.eclipse.jgit.internal.revwalk.AddUnseenToBitmapFilter;
+import org.eclipse.jgit.lib.AnyObjectId;
 import org.eclipse.jgit.lib.BitmapIndex;
 import org.eclipse.jgit.lib.BitmapIndex.Bitmap;
 import org.eclipse.jgit.lib.BitmapIndex.BitmapBuilder;
-import org.eclipse.jgit.lib.Constants;
 import org.eclipse.jgit.lib.NullProgressMonitor;
 import org.eclipse.jgit.lib.ObjectId;
 import org.eclipse.jgit.lib.ProgressMonitor;
-import org.eclipse.jgit.revwalk.ObjectWalk;
-import org.eclipse.jgit.revwalk.RevCommit;
-import org.eclipse.jgit.revwalk.RevFlag;
-import org.eclipse.jgit.revwalk.RevObject;
-import org.eclipse.jgit.revwalk.RevWalk;
-import org.eclipse.jgit.revwalk.filter.RevFilter;
+import org.eclipse.jgit.revwalk.filter.ObjectFilter;
 
-/** Helper class for PackWriter to do ObjectWalks with pack index bitmaps. */
-final class PackWriterBitmapWalker {
+/**
+ * Helper class to do ObjectWalks with pack index bitmaps.
+ *
+ * @since 4.10
+ */
+public final class BitmapWalker {
 
 	private final ObjectWalk walker;
 
@@ -73,18 +74,58 @@ final class PackWriterBitmapWalker {
 
 	private long countOfBitmapIndexMisses;
 
-	PackWriterBitmapWalker(
+	/**
+	 * Create a BitmapWalker.
+	 *
+	 * @param walker walker to use when traversing the object graph.
+	 * @param bitmapIndex index to obtain bitmaps from.
+	 * @param pm progress monitor to report progress on.
+	 */
+	public BitmapWalker(
 			ObjectWalk walker, BitmapIndex bitmapIndex, ProgressMonitor pm) {
 		this.walker = walker;
 		this.bitmapIndex = bitmapIndex;
 		this.pm = (pm == null) ? NullProgressMonitor.INSTANCE : pm;
 	}
 
-	long getCountOfBitmapIndexMisses() {
+	/**
+	 * Return the number of objects that had to be walked because they were not covered by a
+	 * bitmap.
+	 *
+	 * @return the number of objects that had to be walked because they were not covered by a
+	 *     bitmap.
+	 */
+	public long getCountOfBitmapIndexMisses() {
 		return countOfBitmapIndexMisses;
 	}
 
-	BitmapBuilder findObjects(Iterable<? extends ObjectId> start, BitmapBuilder seen,
+	/**
+	 * Return, as a bitmap, the objects reachable from the objects in start.
+	 *
+	 * @param start
+	 *            the objects to start the object traversal from.
+	 * @param seen
+	 *            the objects to skip if encountered during traversal.
+	 * @param ignoreMissing
+	 *            true to ignore missing objects, false otherwise.
+	 * @return as a bitmap, the objects reachable from the objects in start.
+	 * @throws org.eclipse.jgit.errors.MissingObjectException
+	 *             the object supplied is not available from the object
+	 *             database. This usually indicates the supplied object is
+	 *             invalid, but the reference was constructed during an earlier
+	 *             invocation to
+	 *             {@link org.eclipse.jgit.revwalk.RevWalk#lookupAny(AnyObjectId, int)}.
+	 * @throws org.eclipse.jgit.errors.IncorrectObjectTypeException
+	 *             the object was not parsed yet and it was discovered during
+	 *             parsing that it is not actually the type of the instance
+	 *             passed in. This usually indicates the caller used the wrong
+	 *             type in a
+	 *             {@link org.eclipse.jgit.revwalk.RevWalk#lookupAny(AnyObjectId, int)}
+	 *             call.
+	 * @throws java.io.IOException
+	 *             a pack file or loose object could not be read.
+	 */
+	public BitmapBuilder findObjects(Iterable<? extends ObjectId> start, BitmapBuilder seen,
 			boolean ignoreMissing)
 			throws MissingObjectException, IncorrectObjectTypeException,
 				   IOException {
@@ -167,6 +208,7 @@ private BitmapBuilder findObjectsWalk(Iterable<? extends ObjectId> start, Bitmap
 				walker.setRevFilter(
 						new AddUnseenToBitmapFilter(seen, bitmapResult));
 			}
+			walker.setObjectFilter(new BitmapObjectFilter(bitmapResult));
 
 			while (walker.next() != null) {
 				// Iterate through all of the commits. The BitmapRevFilter does
@@ -193,104 +235,20 @@ private BitmapBuilder findObjectsWalk(Iterable<? extends ObjectId> start, Bitmap
 	}
 
 	/**
-	 * A RevFilter that adds the visited commits to {@code bitmap} as a side
-	 * effect.
-	 * <p>
-	 * When the walk hits a commit that is part of {@code bitmap}'s
-	 * BitmapIndex, that entire bitmap is ORed into {@code bitmap} and the
-	 * commit and its parents are marked as SEEN so that the walk does not
-	 * have to visit its ancestors.  This ensures the walk is very short if
-	 * there is good bitmap coverage.
+	 * Filter that excludes objects already in the given bitmap.
 	 */
-	static class AddToBitmapFilter extends RevFilter {
+	static class BitmapObjectFilter extends ObjectFilter {
 		private final BitmapBuilder bitmap;
 
-		AddToBitmapFilter(BitmapBuilder bitmap) {
+		BitmapObjectFilter(BitmapBuilder bitmap) {
 			this.bitmap = bitmap;
 		}
 
 		@Override
-		public final boolean include(RevWalk walker, RevCommit cmit) {
-			Bitmap visitedBitmap;
-
-			if (bitmap.contains(cmit)) {
-				// already included
-			} else if ((visitedBitmap = bitmap.getBitmapIndex()
-					.getBitmap(cmit)) != null) {
-				bitmap.or(visitedBitmap);
-			} else {
-				bitmap.addObject(cmit, Constants.OBJ_COMMIT);
-				return true;
-			}
-
-			for (RevCommit p : cmit.getParents()) {
-				p.add(RevFlag.SEEN);
-			}
-			return false;
-		}
-
-		@Override
-		public final RevFilter clone() {
-			throw new UnsupportedOperationException();
-		}
-
-		@Override
-		public final boolean requiresCommitBody() {
-			return false;
-		}
-	}
-
-	/**
-	 * A RevFilter that adds the visited commits to {@code bitmap} as a side
-	 * effect.
-	 * <p>
-	 * When the walk hits a commit that is part of {@code bitmap}'s
-	 * BitmapIndex, that entire bitmap is ORed into {@code bitmap} and the
-	 * commit and its parents are marked as SEEN so that the walk does not
-	 * have to visit its ancestors.  This ensures the walk is very short if
-	 * there is good bitmap coverage.
-	 * <p>
-	 * Commits named in {@code seen} are considered already seen.  If one is
-	 * encountered, that commit and its parents will be marked with the SEEN
-	 * flag to prevent the walk from visiting its ancestors.
-	 */
-	static class AddUnseenToBitmapFilter extends RevFilter {
-		private final BitmapBuilder seen;
-		private final BitmapBuilder bitmap;
-
-		AddUnseenToBitmapFilter(BitmapBuilder seen, BitmapBuilder bitmapResult) {
-			this.seen = seen;
-			this.bitmap = bitmapResult;
-		}
-
-		@Override
-		public final boolean include(RevWalk walker, RevCommit cmit) {
-			Bitmap visitedBitmap;
-
-			if (seen.contains(cmit) || bitmap.contains(cmit)) {
-				// already seen or included
-			} else if ((visitedBitmap = bitmap.getBitmapIndex()
-					.getBitmap(cmit)) != null) {
-				bitmap.or(visitedBitmap);
-			} else {
-				bitmap.addObject(cmit, Constants.OBJ_COMMIT);
-				return true;
-			}
-
-			for (RevCommit p : cmit.getParents()) {
-				p.add(RevFlag.SEEN);
-			}
-			return false;
-		}
-
-		@Override
-		public final RevFilter clone() {
-			throw new UnsupportedOperationException();
-		}
-
-		@Override
-		public final boolean requiresCommitBody() {
-			return false;
+		public final boolean include(ObjectWalk walker, AnyObjectId objid)
+			throws MissingObjectException, IncorrectObjectTypeException,
+			       IOException {
+			return !bitmap.contains(objid);
 		}
 	}
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/BlockObjQueue.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/BlockObjQueue.java
index 371cd06..fcdf795 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/BlockObjQueue.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/BlockObjQueue.java
@@ -55,7 +55,7 @@ class BlockObjQueue {
 		free = new BlockFreeList();
 	}
 
-	void add(final RevObject c) {
+	void add(RevObject c) {
 		Block b = tail;
 		if (b == null) {
 			b = free.newBlock();
@@ -98,7 +98,7 @@ Block newBlock() {
 			return b;
 		}
 
-		void freeBlock(final Block b) {
+		void freeBlock(Block b) {
 			b.next = next;
 			next = b;
 		}
@@ -127,7 +127,7 @@ boolean isEmpty() {
 			return headIndex == tailIndex;
 		}
 
-		void add(final RevObject c) {
+		void add(RevObject c) {
 			objects[tailIndex++] = c;
 		}
 
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/BlockRevQueue.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/BlockRevQueue.java
index db5379e..79307b5 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/BlockRevQueue.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/BlockRevQueue.java
@@ -51,12 +51,14 @@
 abstract class BlockRevQueue extends AbstractRevQueue {
 	protected BlockFreeList free;
 
-	/** Create an empty revision queue. */
+	/**
+	 * Create an empty revision queue.
+	 */
 	protected BlockRevQueue() {
 		free = new BlockFreeList();
 	}
 
-	BlockRevQueue(final Generator s) throws MissingObjectException,
+	BlockRevQueue(Generator s) throws MissingObjectException,
 			IncorrectObjectTypeException, IOException {
 		free = new BlockFreeList();
 		outputType = s.outputType();
@@ -70,6 +72,8 @@ protected BlockRevQueue() {
 	}
 
 	/**
+	 * {@inheritDoc}
+	 * <p>
 	 * Reconfigure this queue to share the same free list as another.
 	 * <p>
 	 * Multiple revision queues can be connected to the same free list, making
@@ -79,12 +83,9 @@ protected BlockRevQueue() {
 	 * <p>
 	 * Free lists are not thread-safe. Applications must ensure that all queues
 	 * sharing the same free list are doing so from only a single thread.
-	 *
-	 * @param q
-	 *            the other queue we will steal entries from.
 	 */
 	@Override
-	public void shareFreeList(final BlockRevQueue q) {
+	public void shareFreeList(BlockRevQueue q) {
 		free = q.free;
 	}
 
@@ -100,7 +101,7 @@ Block newBlock() {
 			return b;
 		}
 
-		void freeBlock(final Block b) {
+		void freeBlock(Block b) {
 			b.next = next;
 			next = b;
 		}
@@ -137,11 +138,11 @@ boolean canUnpop() {
 			return headIndex > 0;
 		}
 
-		void add(final RevCommit c) {
+		void add(RevCommit c) {
 			commits[tailIndex++] = c;
 		}
 
-		void unpop(final RevCommit c) {
+		void unpop(RevCommit c) {
 			commits[--headIndex] = c;
 		}
 
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/BoundaryGenerator.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/BoundaryGenerator.java
index 6be0c85..0fd6621 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/BoundaryGenerator.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/BoundaryGenerator.java
@@ -54,7 +54,7 @@ class BoundaryGenerator extends Generator {
 
 	Generator g;
 
-	BoundaryGenerator(final RevWalk w, final Generator s) {
+	BoundaryGenerator(RevWalk w, Generator s) {
 		g = new InitialGenerator(w, s);
 	}
 
@@ -64,7 +64,7 @@ int outputType() {
 	}
 
 	@Override
-	void shareFreeList(final BlockRevQueue q) {
+	void shareFreeList(BlockRevQueue q) {
 		g.shareFreeList(q);
 	}
 
@@ -85,7 +85,7 @@ private class InitialGenerator extends Generator {
 
 		private final Generator source;
 
-		InitialGenerator(final RevWalk w, final Generator s) {
+		InitialGenerator(RevWalk w, Generator s) {
 			walk = w;
 			held = new FIFORevQueue();
 			source = s;
@@ -98,7 +98,7 @@ int outputType() {
 		}
 
 		@Override
-		void shareFreeList(final BlockRevQueue q) {
+		void shareFreeList(BlockRevQueue q) {
 			q.shareFreeList(held);
 		}
 
@@ -107,7 +107,7 @@ RevCommit next() throws MissingObjectException,
 				IncorrectObjectTypeException, IOException {
 			RevCommit c = source.next();
 			if (c != null) {
-				for (final RevCommit p : c.parents)
+				for (RevCommit p : c.parents)
 					if ((p.flags & UNINTERESTING) != 0)
 						held.add(p);
 				return c;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/DateRevQueue.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/DateRevQueue.java
index cd7c074..b86e876 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/DateRevQueue.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/DateRevQueue.java
@@ -49,7 +49,9 @@
 import org.eclipse.jgit.errors.IncorrectObjectTypeException;
 import org.eclipse.jgit.errors.MissingObjectException;
 
-/** A queue of commits sorted by commit time order. */
+/**
+ * A queue of commits sorted by commit time order.
+ */
 public class DateRevQueue extends AbstractRevQueue {
 	private static final int REBUILD_INDEX_COUNT = 1000;
 
@@ -67,12 +69,14 @@ public class DateRevQueue extends AbstractRevQueue {
 
 	private int last = -1;
 
-	/** Create an empty date queue. */
+	/**
+	 * Create an empty date queue.
+	 */
 	public DateRevQueue() {
 		super();
 	}
 
-	DateRevQueue(final Generator s) throws MissingObjectException,
+	DateRevQueue(Generator s) throws MissingObjectException,
 			IncorrectObjectTypeException, IOException {
 		for (;;) {
 			final RevCommit c = s.next();
@@ -82,8 +86,9 @@ public DateRevQueue() {
 		}
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	public void add(final RevCommit c) {
+	public void add(RevCommit c) {
 		sinceLastIndex++;
 		if (++inQueue > REBUILD_INDEX_COUNT
 				&& sinceLastIndex > REBUILD_INDEX_COUNT)
@@ -127,6 +132,7 @@ else if (t > when)
 		}
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public RevCommit next() {
 		final Entry q = head;
@@ -163,6 +169,7 @@ public RevCommit peek() {
 		return head != null ? head.commit : null;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void clear() {
 		head = null;
@@ -174,7 +181,7 @@ public void clear() {
 	}
 
 	@Override
-	boolean everbodyHasFlag(final int f) {
+	boolean everbodyHasFlag(int f) {
 		for (Entry q = head; q != null; q = q.next) {
 			if ((q.commit.flags & f) == 0)
 				return false;
@@ -183,7 +190,7 @@ boolean everbodyHasFlag(final int f) {
 	}
 
 	@Override
-	boolean anybodyHasFlag(final int f) {
+	boolean anybodyHasFlag(int f) {
 		for (Entry q = head; q != null; q = q.next) {
 			if ((q.commit.flags & f) != 0)
 				return true;
@@ -196,6 +203,7 @@ int outputType() {
 		return outputType | SORT_COMMIT_TIME_DESC;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public String toString() {
 		final StringBuilder s = new StringBuilder();
@@ -204,7 +212,7 @@ public String toString() {
 		return s.toString();
 	}
 
-	private Entry newEntry(final RevCommit c) {
+	private Entry newEntry(RevCommit c) {
 		Entry r = free;
 		if (r == null)
 			r = new Entry();
@@ -214,7 +222,7 @@ private Entry newEntry(final RevCommit c) {
 		return r;
 	}
 
-	private void freeEntry(final Entry e) {
+	private void freeEntry(Entry e) {
 		e.next = free;
 		free = e;
 	}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/DelayRevQueue.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/DelayRevQueue.java
index 4a0d19d..c397a01 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/DelayRevQueue.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/DelayRevQueue.java
@@ -69,7 +69,7 @@ final class DelayRevQueue extends Generator {
 
 	private int size;
 
-	DelayRevQueue(final Generator g) {
+	DelayRevQueue(Generator g) {
 		pending = g;
 		delay = new FIFORevQueue();
 	}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/DepthGenerator.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/DepthGenerator.java
index ad05186..eaec305 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/DepthGenerator.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/DepthGenerator.java
@@ -113,7 +113,7 @@ int outputType() {
 	}
 
 	@Override
-	void shareFreeList(final BlockRevQueue q) {
+	void shareFreeList(BlockRevQueue q) {
 		pending.shareFreeList(q);
 	}
 
@@ -134,7 +134,7 @@ RevCommit next() throws MissingObjectException,
 
 			int newDepth = c.depth + 1;
 
-			for (final RevCommit p : c.parents) {
+			for (RevCommit p : c.parents) {
 				DepthWalk.Commit dp = (DepthWalk.Commit) p;
 
 				// If no depth has been assigned to this commit, assign
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/DepthWalk.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/DepthWalk.java
index f932593..06a5272 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/DepthWalk.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/DepthWalk.java
@@ -52,15 +52,30 @@
 import org.eclipse.jgit.lib.ObjectReader;
 import org.eclipse.jgit.lib.Repository;
 
-/** Interface for revision walkers that perform depth filtering. */
+/**
+ * Interface for revision walkers that perform depth filtering.
+ */
 public interface DepthWalk {
-	/** @return Depth to filter to. */
+	/**
+	 * Get depth to filter to.
+	 *
+	 * @return Depth to filter to.
+	 */
 	public int getDepth();
 
 	/** @return flag marking commits that should become unshallow. */
+	/**
+	 * Get flag marking commits that should become unshallow.
+	 *
+	 * @return flag marking commits that should become unshallow.
+	 */
 	public RevFlag getUnshallowFlag();
 
-	/** @return flag marking commits that are interesting again. */
+	/**
+	 * Get flag marking commits that are interesting again.
+	 *
+	 * @return flag marking commits that are interesting again.
+	 */
 	public RevFlag getReinterestingFlag();
 
 	/** RevCommit with a depth (in commits) from a root. */
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/FIFORevQueue.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/FIFORevQueue.java
index 1415604..cdb084c 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/FIFORevQueue.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/FIFORevQueue.java
@@ -48,24 +48,29 @@
 import org.eclipse.jgit.errors.IncorrectObjectTypeException;
 import org.eclipse.jgit.errors.MissingObjectException;
 
-/** A queue of commits in FIFO order. */
+/**
+ * A queue of commits in FIFO order.
+ */
 public class FIFORevQueue extends BlockRevQueue {
 	private Block head;
 
 	private Block tail;
 
-	/** Create an empty FIFO queue. */
+	/**
+	 * Create an empty FIFO queue.
+	 */
 	public FIFORevQueue() {
 		super();
 	}
 
-	FIFORevQueue(final Generator s) throws MissingObjectException,
+	FIFORevQueue(Generator s) throws MissingObjectException,
 			IncorrectObjectTypeException, IOException {
 		super(s);
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	public void add(final RevCommit c) {
+	public void add(RevCommit c) {
 		Block b = tail;
 		if (b == null) {
 			b = free.newBlock();
@@ -87,7 +92,7 @@ public void add(final RevCommit c) {
 	 * @param c
 	 *            the commit to insert into the queue.
 	 */
-	public void unpop(final RevCommit c) {
+	public void unpop(RevCommit c) {
 		Block b = head;
 		if (b == null) {
 			b = free.newBlock();
@@ -108,6 +113,7 @@ public void unpop(final RevCommit c) {
 		head = b;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public RevCommit next() {
 		final Block b = head;
@@ -124,6 +130,7 @@ public RevCommit next() {
 		return c;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void clear() {
 		head = null;
@@ -132,7 +139,7 @@ public void clear() {
 	}
 
 	@Override
-	boolean everbodyHasFlag(final int f) {
+	boolean everbodyHasFlag(int f) {
 		for (Block b = head; b != null; b = b.next) {
 			for (int i = b.headIndex; i < b.tailIndex; i++)
 				if ((b.commits[i].flags & f) == 0)
@@ -142,7 +149,7 @@ boolean everbodyHasFlag(final int f) {
 	}
 
 	@Override
-	boolean anybodyHasFlag(final int f) {
+	boolean anybodyHasFlag(int f) {
 		for (Block b = head; b != null; b = b.next) {
 			for (int i = b.headIndex; i < b.tailIndex; i++)
 				if ((b.commits[i].flags & f) != 0)
@@ -151,7 +158,7 @@ boolean anybodyHasFlag(final int f) {
 		return false;
 	}
 
-	void removeFlag(final int f) {
+	void removeFlag(int f) {
 		final int not_f = ~f;
 		for (Block b = head; b != null; b = b.next) {
 			for (int i = b.headIndex; i < b.tailIndex; i++)
@@ -159,6 +166,7 @@ void removeFlag(final int f) {
 		}
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public String toString() {
 		final StringBuilder s = new StringBuilder();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/FixUninterestingGenerator.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/FixUninterestingGenerator.java
index 9d734a7..4e6d7e6 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/FixUninterestingGenerator.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/FixUninterestingGenerator.java
@@ -61,7 +61,7 @@
 final class FixUninterestingGenerator extends Generator {
 	private final Generator pending;
 
-	FixUninterestingGenerator(final Generator g) {
+	FixUninterestingGenerator(Generator g) {
 		pending = g;
 	}
 
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/FollowFilter.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/FollowFilter.java
index 9928286..dae3aac 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/FollowFilter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/FollowFilter.java
@@ -59,7 +59,8 @@
  * triggers rename detection so that the path node is updated to include a prior
  * file name as the RevWalk traverses history.
  *
- * The renames found will be reported to a {@link RenameCallback} if one is set.
+ * The renames found will be reported to a
+ * {@link org.eclipse.jgit.revwalk.RenameCallback} if one is set.
  * <p>
  * Results with this filter are unpredictable if the path being followed is a
  * subdirectory.
@@ -81,7 +82,7 @@ public class FollowFilter extends TreeFilter {
 	 * @param cfg
 	 *            diff config specifying rename detection options.
 	 * @return a new filter for the requested path.
-	 * @throws IllegalArgumentException
+	 * @throws java.lang.IllegalArgumentException
 	 *             the path supplied was the empty string.
 	 * @since 3.0
 	 */
@@ -94,33 +95,42 @@ public static FollowFilter create(String path, DiffConfig cfg) {
 
 	private RenameCallback renameCallback;
 
-	FollowFilter(final PathFilter path, final DiffConfig cfg) {
+	FollowFilter(PathFilter path, DiffConfig cfg) {
 		this.path = path;
 		this.cfg = cfg;
 	}
 
 	/** @return the path this filter matches. */
+	/**
+	 * Get the path this filter matches.
+	 *
+	 * @return the path this filter matches.
+	 */
 	public String getPath() {
 		return path.getPath();
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	public boolean include(final TreeWalk walker)
+	public boolean include(TreeWalk walker)
 			throws MissingObjectException, IncorrectObjectTypeException,
 			IOException {
 		return path.include(walker) && ANY_DIFF.include(walker);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public boolean shouldBeRecursive() {
 		return path.shouldBeRecursive() || ANY_DIFF.shouldBeRecursive();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public TreeFilter clone() {
 		return new FollowFilter(path.clone(), cfg);
 	}
 
+	/** {@inheritDoc} */
 	@SuppressWarnings("nls")
 	@Override
 	public String toString() {
@@ -130,6 +140,8 @@ public String toString() {
 	}
 
 	/**
+	 * Get the callback to which renames are reported.
+	 *
 	 * @return the callback to which renames are reported, or <code>null</code>
 	 *         if none
 	 */
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/FooterKey.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/FooterKey.java
index 36965f4..45d5f80 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/FooterKey.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/FooterKey.java
@@ -47,7 +47,9 @@
 
 import org.eclipse.jgit.lib.Constants;
 
-/** Case insensitive key for a {@link FooterLine}. */
+/**
+ * Case insensitive key for a {@link org.eclipse.jgit.revwalk.FooterLine}.
+ */
 public final class FooterKey {
 	/** Standard {@code Signed-off-by} */
 	public static final FooterKey SIGNED_OFF_BY = new FooterKey("Signed-off-by"); //$NON-NLS-1$
@@ -68,16 +70,21 @@ public final class FooterKey {
 	 * @param keyName
 	 *            name of the footer line.
 	 */
-	public FooterKey(final String keyName) {
+	public FooterKey(String keyName) {
 		name = keyName;
 		raw = Constants.encode(keyName.toLowerCase(Locale.ROOT));
 	}
 
-	/** @return name of this footer line. */
+	/**
+	 * Get name of this footer line.
+	 *
+	 * @return name of this footer line.
+	 */
 	public String getName() {
 		return name;
 	}
 
+	/** {@inheritDoc} */
 	@SuppressWarnings("nls")
 	@Override
 	public String toString() {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/FooterLine.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/FooterLine.java
index b061d6a..d6fed66 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/FooterLine.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/FooterLine.java
@@ -80,11 +80,13 @@ public final class FooterLine {
 	}
 
 	/**
+	 * Whether keys match
+	 *
 	 * @param key
 	 *            key to test this line's key name against.
 	 * @return true if {@code key.getName().equalsIgnorecase(getKey())}.
 	 */
-	public boolean matches(final FooterKey key) {
+	public boolean matches(FooterKey key) {
 		final byte[] kRaw = key.raw;
 		final int len = kRaw.length;
 		int bPtr = keyStart;
@@ -101,6 +103,8 @@ public boolean matches(final FooterKey key) {
 	}
 
 	/**
+	 * Get key name of this footer.
+	 *
 	 * @return key name of this footer; that is the text before the ":" on the
 	 *         line footer's line. The text is decoded according to the commit's
 	 *         specified (or assumed) character encoding.
@@ -110,6 +114,8 @@ public String getKey() {
 	}
 
 	/**
+	 * Get value of this footer.
+	 *
 	 * @return value of this footer; that is the text after the ":" and any
 	 *         leading whitespace has been skipped. May be the empty string if
 	 *         the footer has no value (line ended with ":"). The text is
@@ -144,6 +150,7 @@ public String getEmailAddress() {
 		return RawParseUtils.decode(enc, buffer, lt, gt - 1);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public String toString() {
 		return getKey() + ": " + getValue(); //$NON-NLS-1$
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/Generator.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/Generator.java
index a95303b..b2c92ea 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/Generator.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/Generator.java
@@ -81,7 +81,7 @@ abstract class Generator {
 	 * @param q
 	 *            another FIFO queue that wants to share our queue's free list.
 	 */
-	void shareFreeList(final BlockRevQueue q) {
+	void shareFreeList(BlockRevQueue q) {
 		// Do nothing by default.
 	}
 
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/LIFORevQueue.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/LIFORevQueue.java
index f9da5b1..846b8d9 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/LIFORevQueue.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/LIFORevQueue.java
@@ -49,22 +49,27 @@
 import org.eclipse.jgit.errors.IncorrectObjectTypeException;
 import org.eclipse.jgit.errors.MissingObjectException;
 
-/** A queue of commits in LIFO order. */
+/**
+ * A queue of commits in LIFO order.
+ */
 public class LIFORevQueue extends BlockRevQueue {
 	private Block head;
 
-	/** Create an empty LIFO queue. */
+	/**
+	 * Create an empty LIFO queue.
+	 */
 	public LIFORevQueue() {
 		super();
 	}
 
-	LIFORevQueue(final Generator s) throws MissingObjectException,
+	LIFORevQueue(Generator s) throws MissingObjectException,
 			IncorrectObjectTypeException, IOException {
 		super(s);
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	public void add(final RevCommit c) {
+	public void add(RevCommit c) {
 		Block b = head;
 		if (b == null || !b.canUnpop()) {
 			b = free.newBlock();
@@ -75,6 +80,7 @@ public void add(final RevCommit c) {
 		b.unpop(c);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public RevCommit next() {
 		final Block b = head;
@@ -89,6 +95,7 @@ public RevCommit next() {
 		return c;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void clear() {
 		head = null;
@@ -96,7 +103,7 @@ public void clear() {
 	}
 
 	@Override
-	boolean everbodyHasFlag(final int f) {
+	boolean everbodyHasFlag(int f) {
 		for (Block b = head; b != null; b = b.next) {
 			for (int i = b.headIndex; i < b.tailIndex; i++)
 				if ((b.commits[i].flags & f) == 0)
@@ -106,7 +113,7 @@ boolean everbodyHasFlag(final int f) {
 	}
 
 	@Override
-	boolean anybodyHasFlag(final int f) {
+	boolean anybodyHasFlag(int f) {
 		for (Block b = head; b != null; b = b.next) {
 			for (int i = b.headIndex; i < b.tailIndex; i++)
 				if ((b.commits[i].flags & f) != 0)
@@ -115,6 +122,7 @@ boolean anybodyHasFlag(final int f) {
 		return false;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public String toString() {
 		final StringBuilder s = new StringBuilder();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/MergeBaseGenerator.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/MergeBaseGenerator.java
index 73ce985..2fe9531 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/MergeBaseGenerator.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/MergeBaseGenerator.java
@@ -84,12 +84,12 @@ class MergeBaseGenerator extends Generator {
 
 	private CarryStack stack;
 
-	MergeBaseGenerator(final RevWalk w) {
+	MergeBaseGenerator(RevWalk w) {
 		walker = w;
 		pending = new DateRevQueue();
 	}
 
-	void init(final AbstractRevQueue p) throws IOException {
+	void init(AbstractRevQueue p) throws IOException {
 		try {
 			for (;;) {
 				final RevCommit c = p.next();
@@ -119,7 +119,7 @@ void init(final AbstractRevQueue p) throws IOException {
 		}
 	}
 
-	private void add(final RevCommit c) {
+	private void add(RevCommit c) {
 		final int flag = walker.allocFlag();
 		branchMask |= flag;
 		if ((c.flags & branchMask) != 0) {
@@ -146,7 +146,7 @@ private RevCommit _next() throws MissingObjectException,
 				return null;
 			}
 
-			for (final RevCommit p : c.parents) {
+			for (RevCommit p : c.parents) {
 				if ((p.flags & IN_PENDING) != 0)
 					continue;
 				if ((p.flags & PARSED) == 0)
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/ObjectWalk.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/ObjectWalk.java
index 5868998..e5903c9 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/ObjectWalk.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/ObjectWalk.java
@@ -76,8 +76,9 @@
  * scheduled for inclusion in the results of {@link #nextObject()}, returning
  * each object exactly once. Objects are sorted and returned according to the
  * the commits that reference them and the order they appear within a tree.
- * Ordering can be affected by changing the {@link RevSort} used to order the
- * commits that are returned first.
+ * Ordering can be affected by changing the
+ * {@link org.eclipse.jgit.revwalk.RevSort} used to order the commits that are
+ * returned first.
  */
 public class ObjectWalk extends RevWalk {
 	private static final int ID_SZ = 20;
@@ -118,7 +119,7 @@ public class ObjectWalk extends RevWalk {
 	 * @param repo
 	 *            the repository the walker will obtain data from.
 	 */
-	public ObjectWalk(final Repository repo) {
+	public ObjectWalk(Repository repo) {
 		this(repo.newObjectReader());
 	}
 
@@ -142,34 +143,39 @@ public ObjectWalk(ObjectReader or) {
 	/**
 	 * Mark an object or commit to start graph traversal from.
 	 * <p>
-	 * Callers are encouraged to use {@link RevWalk#parseAny(AnyObjectId)}
-	 * instead of {@link RevWalk#lookupAny(AnyObjectId, int)}, as this method
-	 * requires the object to be parsed before it can be added as a root for the
-	 * traversal.
+	 * Callers are encouraged to use
+	 * {@link org.eclipse.jgit.revwalk.RevWalk#parseAny(AnyObjectId)} instead of
+	 * {@link org.eclipse.jgit.revwalk.RevWalk#lookupAny(AnyObjectId, int)}, as
+	 * this method requires the object to be parsed before it can be added as a
+	 * root for the traversal.
 	 * <p>
 	 * The method will automatically parse an unparsed object, but error
 	 * handling may be more difficult for the application to explain why a
 	 * RevObject is not actually valid. The object pool of this walker would
 	 * also be 'poisoned' by the invalid RevObject.
 	 * <p>
-	 * This method will automatically call {@link RevWalk#markStart(RevCommit)}
-	 * if passed RevCommit instance, or a RevTag that directly (or indirectly)
-	 * references a RevCommit.
+	 * This method will automatically call
+	 * {@link org.eclipse.jgit.revwalk.RevWalk#markStart(RevCommit)} if passed
+	 * RevCommit instance, or a RevTag that directly (or indirectly) references
+	 * a RevCommit.
 	 *
 	 * @param o
 	 *            the object to start traversing from. The object passed must be
 	 *            from this same revision walker.
-	 * @throws MissingObjectException
+	 * @throws org.eclipse.jgit.errors.MissingObjectException
 	 *             the object supplied is not available from the object
 	 *             database. This usually indicates the supplied object is
 	 *             invalid, but the reference was constructed during an earlier
-	 *             invocation to {@link RevWalk#lookupAny(AnyObjectId, int)}.
-	 * @throws IncorrectObjectTypeException
+	 *             invocation to
+	 *             {@link org.eclipse.jgit.revwalk.RevWalk#lookupAny(AnyObjectId, int)}.
+	 * @throws org.eclipse.jgit.errors.IncorrectObjectTypeException
 	 *             the object was not parsed yet and it was discovered during
 	 *             parsing that it is not actually the type of the instance
 	 *             passed in. This usually indicates the caller used the wrong
-	 *             type in a {@link RevWalk#lookupAny(AnyObjectId, int)} call.
-	 * @throws IOException
+	 *             type in a
+	 *             {@link org.eclipse.jgit.revwalk.RevWalk#lookupAny(AnyObjectId, int)}
+	 *             call.
+	 * @throws java.io.IOException
 	 *             a pack file or loose object could not be read.
 	 */
 	public void markStart(RevObject o) throws MissingObjectException,
@@ -193,33 +199,38 @@ public void markStart(RevObject o) throws MissingObjectException,
 	 * reachable chain, back until the merge base of an uninteresting commit and
 	 * an otherwise interesting commit.
 	 * <p>
-	 * Callers are encouraged to use {@link RevWalk#parseAny(AnyObjectId)}
-	 * instead of {@link RevWalk#lookupAny(AnyObjectId, int)}, as this method
-	 * requires the object to be parsed before it can be added as a root for the
-	 * traversal.
+	 * Callers are encouraged to use
+	 * {@link org.eclipse.jgit.revwalk.RevWalk#parseAny(AnyObjectId)} instead of
+	 * {@link org.eclipse.jgit.revwalk.RevWalk#lookupAny(AnyObjectId, int)}, as
+	 * this method requires the object to be parsed before it can be added as a
+	 * root for the traversal.
 	 * <p>
 	 * The method will automatically parse an unparsed object, but error
 	 * handling may be more difficult for the application to explain why a
 	 * RevObject is not actually valid. The object pool of this walker would
 	 * also be 'poisoned' by the invalid RevObject.
 	 * <p>
-	 * This method will automatically call {@link RevWalk#markStart(RevCommit)}
-	 * if passed RevCommit instance, or a RevTag that directly (or indirectly)
-	 * references a RevCommit.
+	 * This method will automatically call
+	 * {@link org.eclipse.jgit.revwalk.RevWalk#markStart(RevCommit)} if passed
+	 * RevCommit instance, or a RevTag that directly (or indirectly) references
+	 * a RevCommit.
 	 *
 	 * @param o
 	 *            the object to start traversing from. The object passed must be
-	 * @throws MissingObjectException
+	 * @throws org.eclipse.jgit.errors.MissingObjectException
 	 *             the object supplied is not available from the object
 	 *             database. This usually indicates the supplied object is
 	 *             invalid, but the reference was constructed during an earlier
-	 *             invocation to {@link RevWalk#lookupAny(AnyObjectId, int)}.
-	 * @throws IncorrectObjectTypeException
+	 *             invocation to
+	 *             {@link org.eclipse.jgit.revwalk.RevWalk#lookupAny(AnyObjectId, int)}.
+	 * @throws org.eclipse.jgit.errors.IncorrectObjectTypeException
 	 *             the object was not parsed yet and it was discovered during
 	 *             parsing that it is not actually the type of the instance
 	 *             passed in. This usually indicates the caller used the wrong
-	 *             type in a {@link RevWalk#lookupAny(AnyObjectId, int)} call.
-	 * @throws IOException
+	 *             type in a
+	 *             {@link org.eclipse.jgit.revwalk.RevWalk#lookupAny(AnyObjectId, int)}
+	 *             call.
+	 * @throws java.io.IOException
 	 *             a pack file or loose object could not be read.
 	 */
 	public void markUninteresting(RevObject o) throws MissingObjectException,
@@ -243,12 +254,14 @@ else if (o instanceof RevTree)
 			addObject(o);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void sort(RevSort s) {
 		super.sort(s);
 		boundary = hasRevSort(RevSort.BOUNDARY);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void sort(RevSort s, boolean use) {
 		super.sort(s, use);
@@ -259,7 +272,6 @@ public void sort(RevSort s, boolean use) {
 	 * Get the currently configured object filter.
 	 *
 	 * @return the current filter. Never null as a filter is always needed.
-	 *
 	 * @since 4.0
 	 */
 	public ObjectFilter getObjectFilter() {
@@ -267,9 +279,9 @@ public ObjectFilter getObjectFilter() {
 	}
 
 	/**
-	 * Set the object filter for this walker.  This filter affects the objects
-	 * visited by {@link #nextObject()}.  It does not affect the commits
-	 * listed by {@link #next()}.
+	 * Set the object filter for this walker. This filter affects the objects
+	 * visited by {@link #nextObject()}. It does not affect the commits listed
+	 * by {@link #next()}.
 	 * <p>
 	 * If the filter returns false for an object, then that object is skipped
 	 * and objects reachable from it are not enqueued to be walked recursively.
@@ -277,9 +289,9 @@ public ObjectFilter getObjectFilter() {
 	 * are known to be uninteresting.
 	 *
 	 * @param newFilter
-	 *            the new filter. If null the special {@link ObjectFilter#ALL}
+	 *            the new filter. If null the special
+	 *            {@link org.eclipse.jgit.revwalk.filter.ObjectFilter#ALL}
 	 *            filter will be used instead, as it matches every object.
-	 *
 	 * @since 4.0
 	 */
 	public void setObjectFilter(ObjectFilter newFilter) {
@@ -287,6 +299,7 @@ public void setObjectFilter(ObjectFilter newFilter) {
 		objectFilter = newFilter != null ? newFilter : ObjectFilter.ALL;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public RevCommit next() throws MissingObjectException,
 			IncorrectObjectTypeException, IOException {
@@ -316,14 +329,14 @@ public RevCommit next() throws MissingObjectException,
 	 * Pop the next most recent object.
 	 *
 	 * @return next most recent object; null if traversal is over.
-	 * @throws MissingObjectException
+	 * @throws org.eclipse.jgit.errors.MissingObjectException
 	 *             one or or more of the next objects are not available from the
 	 *             object database, but were thought to be candidates for
 	 *             traversal. This usually indicates a broken link.
-	 * @throws IncorrectObjectTypeException
+	 * @throws org.eclipse.jgit.errors.IncorrectObjectTypeException
 	 *             one or or more of the objects in a tree do not match the type
 	 *             indicated.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             a pack file or loose object could not be read.
 	 */
 	public RevObject nextObject() throws MissingObjectException,
@@ -520,14 +533,14 @@ private static int parseMode(byte[] buf, int startPtr, int recEndPtr, TreeVisit
 	 * exception if there is a connectivity problem. The exception message
 	 * provides some detail about the connectivity failure.
 	 *
-	 * @throws MissingObjectException
+	 * @throws org.eclipse.jgit.errors.MissingObjectException
 	 *             one or or more of the next objects are not available from the
 	 *             object database, but were thought to be candidates for
 	 *             traversal. This usually indicates a broken link.
-	 * @throws IncorrectObjectTypeException
+	 * @throws org.eclipse.jgit.errors.IncorrectObjectTypeException
 	 *             one or or more of the objects in a tree do not match the type
 	 *             indicated.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             a pack file or loose object could not be read.
 	 */
 	public void checkConnectivity() throws MissingObjectException,
@@ -618,14 +631,22 @@ public int getPathHashCode() {
 		return hash;
 	}
 
-	/** @return the internal buffer holding the current path. */
+	/**
+	 * Get the internal buffer holding the current path.
+	 *
+	 * @return the internal buffer holding the current path.
+	 */
 	public byte[] getPathBuffer() {
 		if (pathLen == 0)
 			pathLen = updatePathBuf(currVisit);
 		return pathBuf;
 	}
 
-	/** @return length of the path in {@link #getPathBuffer()}. */
+	/**
+	 * Get length of the path in {@link #getPathBuffer()}.
+	 *
+	 * @return length of the path in {@link #getPathBuffer()}.
+	 */
 	public int getPathLength() {
 		if (pathLen == 0)
 			pathLen = updatePathBuf(currVisit);
@@ -667,6 +688,7 @@ private void growPathBuf(int ptr) {
 		pathBuf = newBuf;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void dispose() {
 		super.dispose();
@@ -675,8 +697,9 @@ public void dispose() {
 		freeVisit = null;
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	protected void reset(final int retainFlags) {
+	protected void reset(int retainFlags) {
 		super.reset(retainFlags);
 
 		for (RevObject obj : rootObjects)
@@ -688,7 +711,7 @@ protected void reset(final int retainFlags) {
 		freeVisit = null;
 	}
 
-	private void addObject(final RevObject o) {
+	private void addObject(RevObject o) {
 		if ((o.flags & IN_PENDING) == 0) {
 			o.flags |= IN_PENDING;
 			rootObjects.add(o);
@@ -696,7 +719,7 @@ private void addObject(final RevObject o) {
 		}
 	}
 
-	private void markTreeUninteresting(final RevTree tree)
+	private void markTreeUninteresting(RevTree tree)
 			throws MissingObjectException, IncorrectObjectTypeException,
 			IOException {
 		if ((tree.flags & UNINTERESTING) != 0)
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/PendingGenerator.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/PendingGenerator.java
index 94ae2c9..e607b7d 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/PendingGenerator.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/PendingGenerator.java
@@ -140,7 +140,7 @@ RevCommit next() throws MissingObjectException,
 					produce = filter.include(walker, c);
 				}
 
-				for (final RevCommit p : c.parents) {
+				for (RevCommit p : c.parents) {
 					if ((p.flags & SEEN) != 0)
 						continue;
 					if ((p.flags & PARSED) == 0)
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RenameCallback.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RenameCallback.java
index 3778355..7754f18 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RenameCallback.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RenameCallback.java
@@ -46,8 +46,9 @@
 
 /**
  * An instance of this class can be used in conjunction with a
- * {@link FollowFilter}. Whenever a rename has been detected during a revision
- * walk, it will be reported here.
+ * {@link org.eclipse.jgit.revwalk.FollowFilter}. Whenever a rename has been
+ * detected during a revision walk, it will be reported here.
+ *
  * @see FollowFilter#setRenameCallback(RenameCallback)
  */
 public abstract class RenameCallback {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevBlob.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevBlob.java
index 4245fca..cc5e3e4 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevBlob.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevBlob.java
@@ -52,7 +52,9 @@
 import org.eclipse.jgit.lib.AnyObjectId;
 import org.eclipse.jgit.lib.Constants;
 
-/** A binary file, or a symbolic link. */
+/**
+ * A binary file, or a symbolic link.
+ */
 public class RevBlob extends RevObject {
 	/**
 	 * Create a new blob reference.
@@ -60,10 +62,11 @@ public class RevBlob extends RevObject {
 	 * @param id
 	 *            object name for the blob.
 	 */
-	protected RevBlob(final AnyObjectId id) {
+	protected RevBlob(AnyObjectId id) {
 		super(id);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public final int getType() {
 		return Constants.OBJ_BLOB;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevCommit.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevCommit.java
index c641a13..b67f934 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevCommit.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevCommit.java
@@ -44,7 +44,7 @@
 
 package org.eclipse.jgit.revwalk;
 
-import static java.nio.charset.StandardCharsets.UTF_8;
+import static org.eclipse.jgit.lib.Constants.CHARSET;
 
 import java.io.IOException;
 import java.nio.charset.Charset;
@@ -66,7 +66,9 @@
 import org.eclipse.jgit.util.RawParseUtils;
 import org.eclipse.jgit.util.StringUtils;
 
-/** A commit reference to a commit in the DAG. */
+/**
+ * A commit reference to a commit in the DAG.
+ */
 public class RevCommit extends RevObject {
 	private static final int STACK_DEPTH = 500;
 
@@ -79,7 +81,8 @@ public class RevCommit extends RevObject {
 	 * will not have their headers loaded.
 	 *
 	 * Applications are discouraged from using this API. Callers usually need
-	 * more than one commit. Use {@link RevWalk#parseCommit(AnyObjectId)} to
+	 * more than one commit. Use
+	 * {@link org.eclipse.jgit.revwalk.RevWalk#parseCommit(AnyObjectId)} to
 	 * obtain a RevCommit from an existing repository.
 	 *
 	 * @param raw
@@ -115,7 +118,7 @@ public static RevCommit parse(byte[] raw) {
 	 *            modified by the caller.
 	 * @return the parsed commit, in an isolated revision pool that is not
 	 *         available to the caller.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             in case of RevWalk initialization fails
 	 */
 	public static RevCommit parse(RevWalk rw, byte[] raw) throws IOException {
@@ -145,18 +148,18 @@ public static RevCommit parse(RevWalk rw, byte[] raw) throws IOException {
 	 * @param id
 	 *            object name for the commit.
 	 */
-	protected RevCommit(final AnyObjectId id) {
+	protected RevCommit(AnyObjectId id) {
 		super(id);
 	}
 
 	@Override
-	void parseHeaders(final RevWalk walk) throws MissingObjectException,
+	void parseHeaders(RevWalk walk) throws MissingObjectException,
 			IncorrectObjectTypeException, IOException {
 		parseCanonical(walk, walk.getCachedBytes(this));
 	}
 
 	@Override
-	void parseBody(final RevWalk walk) throws MissingObjectException,
+	void parseBody(RevWalk walk) throws MissingObjectException,
 			IncorrectObjectTypeException, IOException {
 		if (buffer == null) {
 			buffer = walk.getCachedBytes(this);
@@ -165,7 +168,7 @@ void parseBody(final RevWalk walk) throws MissingObjectException,
 		}
 	}
 
-	void parseCanonical(final RevWalk walk, final byte[] raw)
+	void parseCanonical(RevWalk walk, byte[] raw)
 			throws IOException {
 		if (!walk.shallowCommitsInitialized)
 			walk.initializeShallowCommits();
@@ -220,6 +223,7 @@ else if (nParents == 1) {
 		flags |= PARSED;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public final int getType() {
 		return Constants.OBJ_COMMIT;
@@ -306,7 +310,7 @@ private static void carryOneStep(FIFORevQueue q, int carry, RevCommit c) {
 	 * @param flag
 	 *            the single flag value to carry back onto parents.
 	 */
-	public void carry(final RevFlag flag) {
+	public void carry(RevFlag flag) {
 		final int carry = flags & flag.mask;
 		if (carry != 0)
 			carryFlags(this, carry);
@@ -315,7 +319,7 @@ public void carry(final RevFlag flag) {
 	/**
 	 * Time from the "committer " line of the buffer.
 	 *
-	 * @return time, expressed as seconds since the epoch.
+	 * @return commit time
 	 */
 	public final int getCommitTime() {
 		return commitTime;
@@ -346,10 +350,10 @@ public final int getParentCount() {
 	 *            parent index to obtain. Must be in the range 0 through
 	 *            {@link #getParentCount()}-1.
 	 * @return the specified parent.
-	 * @throws ArrayIndexOutOfBoundsException
+	 * @throws java.lang.ArrayIndexOutOfBoundsException
 	 *             an invalid parent index was specified.
 	 */
-	public final RevCommit getParent(final int nth) {
+	public final RevCommit getParent(int nth) {
 		return parents[nth];
 	}
 
@@ -394,9 +398,10 @@ public final RevCommit getParent(final int nth) {
 	 * should cache the return value for as long as necessary to use all
 	 * information from it.
 	 * <p>
-	 * RevFilter implementations should try to use {@link RawParseUtils} to scan
-	 * the {@link #getRawBuffer()} instead, as this will allow faster evaluation
-	 * of commits.
+	 * RevFilter implementations should try to use
+	 * {@link org.eclipse.jgit.util.RawParseUtils} to scan the
+	 * {@link #getRawBuffer()} instead, as this will allow faster evaluation of
+	 * commits.
 	 *
 	 * @return identity of the author (name, email) and the time the commit was
 	 *         made by the author; null if no author line was found.
@@ -420,9 +425,10 @@ public final PersonIdent getAuthorIdent() {
 	 * should cache the return value for as long as necessary to use all
 	 * information from it.
 	 * <p>
-	 * RevFilter implementations should try to use {@link RawParseUtils} to scan
-	 * the {@link #getRawBuffer()} instead, as this will allow faster evaluation
-	 * of commits.
+	 * RevFilter implementations should try to use
+	 * {@link org.eclipse.jgit.util.RawParseUtils} to scan the
+	 * {@link #getRawBuffer()} instead, as this will allow faster evaluation of
+	 * commits.
 	 *
 	 * @return identity of the committer (name, email) and the time the commit
 	 *         was made by the committer; null if no committer line was found.
@@ -484,7 +490,7 @@ public final String getShortMessage() {
 		return str;
 	}
 
-	static boolean hasLF(final byte[] r, int b, final int e) {
+	static boolean hasLF(byte[] r, int b, int e) {
 		while (b < e)
 			if (r[b++] == '\n')
 				return true;
@@ -533,7 +539,7 @@ private Charset guessEncoding() {
 		try {
 			return getEncoding();
 		} catch (IllegalCharsetNameException | UnsupportedCharsetException e) {
-			return UTF_8;
+			return CHARSET;
 		}
 	}
 
@@ -609,7 +615,7 @@ public final List<FooterLine> getFooterLines() {
 	 *         with the specified key, or there are no footers at all.
 	 * @see #getFooterLines()
 	 */
-	public final List<String> getFooterLines(final String keyName) {
+	public final List<String> getFooterLines(String keyName) {
 		return getFooterLines(new FooterKey(keyName));
 	}
 
@@ -624,12 +630,12 @@ public final List<String> getFooterLines(final String keyName) {
 	 *         with the specified key, or there are no footers at all.
 	 * @see #getFooterLines()
 	 */
-	public final List<String> getFooterLines(final FooterKey keyName) {
+	public final List<String> getFooterLines(FooterKey keyName) {
 		final List<FooterLine> src = getFooterLines();
 		if (src.isEmpty())
 			return Collections.emptyList();
 		final ArrayList<String> r = new ArrayList<>(src.size());
-		for (final FooterLine f : src) {
+		for (FooterLine f : src) {
 			if (f.matches(keyName))
 				r.add(f.getValue());
 		}
@@ -654,7 +660,7 @@ public void reset() {
 	 * time in {@link #getCommitTime()}. Accessing other properties such as
 	 * {@link #getAuthorIdent()}, {@link #getCommitterIdent()} or either message
 	 * function requires reloading the buffer by invoking
-	 * {@link RevWalk#parseBody(RevObject)}.
+	 * {@link org.eclipse.jgit.revwalk.RevWalk#parseBody(RevObject)}.
 	 *
 	 * @since 4.0
 	 */
@@ -662,6 +668,7 @@ public final void disposeBody() {
 		buffer = null;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public String toString() {
 		final StringBuilder s = new StringBuilder();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevCommitList.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevCommitList.java
index 64f99bb..d2fda2f 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevCommitList.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevCommitList.java
@@ -50,7 +50,7 @@
 import org.eclipse.jgit.revwalk.filter.RevFilter;
 
 /**
- * An ordered list of {@link RevCommit} subclasses.
+ * An ordered list of {@link org.eclipse.jgit.revwalk.RevCommit} subclasses.
  *
  * @param <E>
  *            type of subclass of RevCommit the list is storing.
@@ -58,6 +58,7 @@
 public class RevCommitList<E extends RevCommit> extends RevObjectList<E> {
 	private RevWalk walker;
 
+	/** {@inheritDoc} */
 	@Override
 	public void clear() {
 		super.clear();
@@ -77,20 +78,20 @@ public void clear() {
 	 * @param flag
 	 *            the flag to apply (or remove). Applications are responsible
 	 *            for allocating this flag from the source RevWalk.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             revision filter needed to read additional objects, but an
 	 *             error occurred while reading the pack files or loose objects
 	 *             of the repository.
-	 * @throws IncorrectObjectTypeException
+	 * @throws org.eclipse.jgit.errors.IncorrectObjectTypeException
 	 *             revision filter needed to read additional objects, but an
 	 *             object was not of the correct type. Repository corruption may
 	 *             have occurred.
-	 * @throws MissingObjectException
+	 * @throws org.eclipse.jgit.errors.MissingObjectException
 	 *             revision filter needed to read additional objects, but an
 	 *             object that should be present was not found. Repository
 	 *             corruption may have occurred.
 	 */
-	public void applyFlag(final RevFilter matching, final RevFlag flag)
+	public void applyFlag(RevFilter matching, RevFlag flag)
 			throws MissingObjectException, IncorrectObjectTypeException,
 			IOException {
 		applyFlag(matching, flag, 0, size());
@@ -117,15 +118,15 @@ public void applyFlag(final RevFilter matching, final RevFlag flag)
 	 *            last commit within the list to end testing at, exclusive. If
 	 *            smaller than or equal to <code>rangeBegin</code> then no
 	 *            commits will be tested.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             revision filter needed to read additional objects, but an
 	 *             error occurred while reading the pack files or loose objects
 	 *             of the repository.
-	 * @throws IncorrectObjectTypeException
+	 * @throws org.eclipse.jgit.errors.IncorrectObjectTypeException
 	 *             revision filter needed to read additional objects, but an
 	 *             object was not of the correct type. Repository corruption may
 	 *             have occurred.
-	 * @throws MissingObjectException
+	 * @throws org.eclipse.jgit.errors.MissingObjectException
 	 *             revision filter needed to read additional objects, but an
 	 *             object that should be present was not found. Repository
 	 *             corruption may have occurred.
@@ -164,7 +165,7 @@ public void applyFlag(final RevFilter matching, final RevFlag flag,
 	 *            the flag to remove. Applications are responsible for
 	 *            allocating this flag from the source RevWalk.
 	 */
-	public void clearFlag(final RevFlag flag) {
+	public void clearFlag(RevFlag flag) {
 		clearFlag(flag, 0, size());
 	}
 
@@ -206,7 +207,7 @@ public void clearFlag(final RevFlag flag, final int rangeBegin,
 	 * @return index of the first commit at or after index <code>begin</code>
 	 *         that has the specified flag set on it; -1 if no match is found.
 	 */
-	public int indexOf(final RevFlag flag, int begin) {
+	public int indexOf(RevFlag flag, int begin) {
 		while (begin < size()) {
 			int index = begin;
 			Block s = contents;
@@ -237,7 +238,7 @@ public int indexOf(final RevFlag flag, int begin) {
 	 * @return index of the first commit at or before index <code>begin</code>
 	 *         that has the specified flag set on it; -1 if no match is found.
 	 */
-	public int lastIndexOf(final RevFlag flag, int begin) {
+	public int lastIndexOf(RevFlag flag, int begin) {
 		begin = Math.min(begin, size() - 1);
 		while (begin >= 0) {
 			int index = begin;
@@ -264,7 +265,7 @@ public int lastIndexOf(final RevFlag flag, int begin) {
 	 *            the walker to populate from.
 	 * @see #fillTo(int)
 	 */
-	public void source(final RevWalk w) {
+	public void source(RevWalk w) {
 		walker = w;
 	}
 
@@ -290,15 +291,15 @@ public boolean isPending() {
 	 * @param highMark
 	 *            number of commits the caller wants this list to contain when
 	 *            the fill operation is complete.
-	 * @throws IOException
-	 *             see {@link RevWalk#next()}
-	 * @throws IncorrectObjectTypeException
-	 *             see {@link RevWalk#next()}
-	 * @throws MissingObjectException
-	 *             see {@link RevWalk#next()}
+	 * @throws java.io.IOException
+	 *             see {@link org.eclipse.jgit.revwalk.RevWalk#next()}
+	 * @throws org.eclipse.jgit.errors.IncorrectObjectTypeException
+	 *             see {@link org.eclipse.jgit.revwalk.RevWalk#next()}
+	 * @throws org.eclipse.jgit.errors.MissingObjectException
+	 *             see {@link org.eclipse.jgit.revwalk.RevWalk#next()}
 	 */
 	@SuppressWarnings("unchecked")
-	public void fillTo(final int highMark) throws MissingObjectException,
+	public void fillTo(int highMark) throws MissingObjectException,
 			IncorrectObjectTypeException, IOException {
 		if (walker == null || size > highMark)
 			return;
@@ -355,15 +356,15 @@ public void fillTo(final int highMark) throws MissingObjectException,
 	 *            contain when the fill operation is complete. If highMark is 0
 	 *            the walk is pumped until the specified commit or the end of
 	 *            the walk is reached.
-	 * @throws IOException
-	 *             see {@link RevWalk#next()}
-	 * @throws IncorrectObjectTypeException
-	 *             see {@link RevWalk#next()}
-	 * @throws MissingObjectException
-	 *             see {@link RevWalk#next()}
+	 * @throws java.io.IOException
+	 *             see {@link org.eclipse.jgit.revwalk.RevWalk#next()}
+	 * @throws org.eclipse.jgit.errors.IncorrectObjectTypeException
+	 *             see {@link org.eclipse.jgit.revwalk.RevWalk#next()}
+	 * @throws org.eclipse.jgit.errors.MissingObjectException
+	 *             see {@link org.eclipse.jgit.revwalk.RevWalk#next()}
 	 */
 	@SuppressWarnings("unchecked")
-	public void fillTo(final RevCommit commitToLoad, int highMark)
+	public void fillTo(RevCommit commitToLoad, int highMark)
 			throws MissingObjectException, IncorrectObjectTypeException,
 			IOException {
 		if (walker == null || commitToLoad == null
@@ -418,7 +419,7 @@ public void fillTo(final RevCommit commitToLoad, int highMark)
 	 * @param e
 	 *            the object being added (or set) into the list.
 	 */
-	protected void enter(final int index, final E e) {
+	protected void enter(int index, E e) {
 		// Do nothing by default.
 	}
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevFlag.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevFlag.java
index dae52f8..413a552 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevFlag.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevFlag.java
@@ -48,9 +48,10 @@
 import org.eclipse.jgit.internal.JGitText;
 
 /**
- * Application level mark bit for {@link RevObject}s.
+ * Application level mark bit for {@link org.eclipse.jgit.revwalk.RevObject}s.
  * <p>
- * To create a flag use {@link RevWalk#newFlag(String)}.
+ * To create a flag use
+ * {@link org.eclipse.jgit.revwalk.RevWalk#newFlag(String)}.
  */
 public class RevFlag {
 	/**
@@ -84,7 +85,7 @@ public class RevFlag {
 
 	final int mask;
 
-	RevFlag(final RevWalk w, final String n, final int m) {
+	RevFlag(RevWalk w, String n, int m) {
 		walker = w;
 		name = n;
 		mask = m;
@@ -99,13 +100,14 @@ public RevWalk getRevWalk() {
 		return walker;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public String toString() {
 		return name;
 	}
 
 	static class StaticRevFlag extends RevFlag {
-		StaticRevFlag(final String n, final int m) {
+		StaticRevFlag(String n, int m) {
 			super(null, n, m);
 		}
 
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevFlagSet.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevFlagSet.java
index bb699e0..45a730c 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevFlagSet.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevFlagSet.java
@@ -50,7 +50,8 @@
 import java.util.List;
 
 /**
- * Multiple application level mark bits for {@link RevObject}s.
+ * Multiple application level mark bits for
+ * {@link org.eclipse.jgit.revwalk.RevObject}s.
  *
  * @see RevFlag
  */
@@ -59,7 +60,9 @@ public class RevFlagSet extends AbstractSet<RevFlag> {
 
 	private final List<RevFlag> active;
 
-	/** Create an empty set of flags. */
+	/**
+	 * Create an empty set of flags.
+	 */
 	public RevFlagSet() {
 		active = new ArrayList<>();
 	}
@@ -70,7 +73,7 @@ public RevFlagSet() {
 	 * @param s
 	 *            the set to copy flags from.
 	 */
-	public RevFlagSet(final RevFlagSet s) {
+	public RevFlagSet(RevFlagSet s) {
 		mask = s.mask;
 		active = new ArrayList<>(s.active);
 	}
@@ -81,20 +84,22 @@ public RevFlagSet(final RevFlagSet s) {
 	 * @param s
 	 *            the collection to copy flags from.
 	 */
-	public RevFlagSet(final Collection<RevFlag> s) {
+	public RevFlagSet(Collection<RevFlag> s) {
 		this();
 		addAll(s);
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	public boolean contains(final Object o) {
+	public boolean contains(Object o) {
 		if (o instanceof RevFlag)
 			return (mask & ((RevFlag) o).mask) != 0;
 		return false;
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	public boolean containsAll(final Collection<?> c) {
+	public boolean containsAll(Collection<?> c) {
 		if (c instanceof RevFlagSet) {
 			final int cMask = ((RevFlagSet) c).mask;
 			return (mask & cMask) == cMask;
@@ -102,8 +107,9 @@ public boolean containsAll(final Collection<?> c) {
 		return super.containsAll(c);
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	public boolean add(final RevFlag flag) {
+	public boolean add(RevFlag flag) {
 		if ((mask & flag.mask) != 0)
 			return false;
 		mask |= flag.mask;
@@ -114,8 +120,9 @@ public boolean add(final RevFlag flag) {
 		return true;
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	public boolean remove(final Object o) {
+	public boolean remove(Object o) {
 		final RevFlag flag = (RevFlag) o;
 		if ((mask & flag.mask) == 0)
 			return false;
@@ -126,6 +133,7 @@ public boolean remove(final Object o) {
 		return true;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public Iterator<RevFlag> iterator() {
 		final Iterator<RevFlag> i = active.iterator();
@@ -150,6 +158,7 @@ public void remove() {
 		};
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public int size() {
 		return active.size();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevObject.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevObject.java
index 7561927..eef9bf3 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevObject.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevObject.java
@@ -52,13 +52,15 @@
 import org.eclipse.jgit.lib.ObjectId;
 import org.eclipse.jgit.lib.ObjectIdOwnerMap;
 
-/** Base object type accessed during revision walking. */
+/**
+ * Base object type accessed during revision walking.
+ */
 public abstract class RevObject extends ObjectIdOwnerMap.Entry {
 	static final int PARSED = 1;
 
 	int flags;
 
-	RevObject(final AnyObjectId name) {
+	RevObject(AnyObjectId name) {
 		super(name);
 	}
 
@@ -69,7 +71,7 @@ abstract void parseBody(RevWalk walk) throws MissingObjectException,
 			IncorrectObjectTypeException, IOException;
 
 	/**
-	 * Get Git object type. See {@link Constants}.
+	 * Get Git object type. See {@link org.eclipse.jgit.lib.Constants}.
 	 *
 	 * @return object type
 	 */
@@ -91,7 +93,7 @@ public final ObjectId getId() {
 	 *            the flag to test.
 	 * @return true if the flag has been added to this object; false if not.
 	 */
-	public final boolean has(final RevFlag flag) {
+	public final boolean has(RevFlag flag) {
 		return (flags & flag.mask) != 0;
 	}
 
@@ -103,7 +105,7 @@ public final boolean has(final RevFlag flag) {
 	 * @return true if any flag in the set has been added to this object; false
 	 *         if not.
 	 */
-	public final boolean hasAny(final RevFlagSet set) {
+	public final boolean hasAny(RevFlagSet set) {
 		return (flags & set.mask) != 0;
 	}
 
@@ -115,7 +117,7 @@ public final boolean hasAny(final RevFlagSet set) {
 	 * @return true if all flags of the set have been added to this object;
 	 *         false if some or none have been added.
 	 */
-	public final boolean hasAll(final RevFlagSet set) {
+	public final boolean hasAll(RevFlagSet set) {
 		return (flags & set.mask) == set.mask;
 	}
 
@@ -127,7 +129,7 @@ public final boolean hasAll(final RevFlagSet set) {
 	 * @param flag
 	 *            the flag to mark on this object, for later testing.
 	 */
-	public final void add(final RevFlag flag) {
+	public final void add(RevFlag flag) {
 		flags |= flag.mask;
 	}
 
@@ -137,7 +139,7 @@ public final void add(final RevFlag flag) {
 	 * @param set
 	 *            the set of flags to mark on this object, for later testing.
 	 */
-	public final void add(final RevFlagSet set) {
+	public final void add(RevFlagSet set) {
 		flags |= set.mask;
 	}
 
@@ -149,7 +151,7 @@ public final void add(final RevFlagSet set) {
 	 * @param flag
 	 *            the flag to remove from this object.
 	 */
-	public final void remove(final RevFlag flag) {
+	public final void remove(RevFlag flag) {
 		flags &= ~flag.mask;
 	}
 
@@ -159,10 +161,11 @@ public final void remove(final RevFlag flag) {
 	 * @param set
 	 *            the flag to remove from this object.
 	 */
-	public final void remove(final RevFlagSet set) {
+	public final void remove(RevFlagSet set) {
 		flags &= ~set.mask;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public String toString() {
 		final StringBuilder s = new StringBuilder();
@@ -175,10 +178,12 @@ public String toString() {
 	}
 
 	/**
+	 * Append a debug description of core RevFlags to a buffer.
+	 *
 	 * @param s
 	 *            buffer to append a debug description of core RevFlags onto.
 	 */
-	protected void appendCoreFlags(final StringBuilder s) {
+	protected void appendCoreFlags(StringBuilder s) {
 		s.append((flags & RevWalk.TOPO_DELAY) != 0 ? 'o' : '-');
 		s.append((flags & RevWalk.TEMP_MARK) != 0 ? 't' : '-');
 		s.append((flags & RevWalk.REWRITE) != 0 ? 'r' : '-');
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevObjectList.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevObjectList.java
index 9598678..2f21e17 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevObjectList.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevObjectList.java
@@ -51,7 +51,7 @@
 import org.eclipse.jgit.internal.JGitText;
 
 /**
- * An ordered list of {@link RevObject} subclasses.
+ * An ordered list of {@link org.eclipse.jgit.revwalk.RevObject} subclasses.
  *
  * @param <E>
  *            type of subclass of RevObject the list is storing.
@@ -73,13 +73,16 @@ public class RevObjectList<E extends RevObject> extends AbstractList<E> {
 	/** Current number of elements in the list. */
 	protected int size = 0;
 
-	/** Create an empty object list. */
+	/**
+	 * Create an empty object list.
+	 */
 	public RevObjectList() {
 		// Initialized above.
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	public void add(final int index, final E element) {
+	public void add(int index, E element) {
 		if (index != size)
 			throw new UnsupportedOperationException(MessageFormat.format(
 					JGitText.get().unsupportedOperationNotAddAtEnd,
@@ -88,6 +91,7 @@ public void add(final int index, final E element) {
 		size++;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	@SuppressWarnings("unchecked")
 	public E set(int index, E element) {
@@ -109,6 +113,7 @@ public E set(int index, E element) {
 		return (E) old;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	@SuppressWarnings("unchecked")
 	public E get(int index) {
@@ -123,11 +128,13 @@ public E get(int index) {
 		return s != null ? (E) s.contents[index] : null;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public int size() {
 		return size;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void clear() {
 		contents = new Block(0);
@@ -140,7 +147,7 @@ protected static class Block {
 
 		final int shift;
 
-		Block(final int s) {
+		Block(int s) {
 			shift = s;
 		}
 	}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevSort.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevSort.java
index 238af12..a3b31a1 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevSort.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevSort.java
@@ -44,7 +44,10 @@
 
 package org.eclipse.jgit.revwalk;
 
-/** Sorting strategies supported by {@link RevWalk} and {@link ObjectWalk}. */
+/**
+ * Sorting strategies supported by {@link org.eclipse.jgit.revwalk.RevWalk} and
+ * {@link org.eclipse.jgit.revwalk.ObjectWalk}.
+ */
 public enum RevSort {
 	/**
 	 * No specific sorting is requested.
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevTag.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevTag.java
index 81a54bf..0050bac 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevTag.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevTag.java
@@ -45,7 +45,7 @@
 
 package org.eclipse.jgit.revwalk;
 
-import static java.nio.charset.StandardCharsets.UTF_8;
+import static org.eclipse.jgit.lib.Constants.CHARSET;
 
 import java.io.IOException;
 import java.nio.charset.Charset;
@@ -64,7 +64,9 @@
 import org.eclipse.jgit.util.RawParseUtils;
 import org.eclipse.jgit.util.StringUtils;
 
-/** An annotated tag. */
+/**
+ * An annotated tag.
+ */
 public class RevTag extends RevObject {
 	/**
 	 * Parse an annotated tag from its canonical format.
@@ -75,14 +77,15 @@ public class RevTag extends RevObject {
 	 * not have its headers loaded.
 	 *
 	 * Applications are discouraged from using this API. Callers usually need
-	 * more than one object. Use {@link RevWalk#parseTag(AnyObjectId)} to obtain
+	 * more than one object. Use
+	 * {@link org.eclipse.jgit.revwalk.RevWalk#parseTag(AnyObjectId)} to obtain
 	 * a RevTag from an existing repository.
 	 *
 	 * @param raw
 	 *            the canonical formatted tag to be parsed.
 	 * @return the parsed tag, in an isolated revision pool that is not
 	 *         available to the caller.
-	 * @throws CorruptObjectException
+	 * @throws org.eclipse.jgit.errors.CorruptObjectException
 	 *             the tag contains a malformed header that cannot be handled.
 	 */
 	public static RevTag parse(byte[] raw) throws CorruptObjectException {
@@ -109,7 +112,7 @@ public static RevTag parse(byte[] raw) throws CorruptObjectException {
 	 *            modified by the caller.
 	 * @return the parsed tag, in an isolated revision pool that is not
 	 *         available to the caller.
-	 * @throws CorruptObjectException
+	 * @throws org.eclipse.jgit.errors.CorruptObjectException
 	 *             the tag contains a malformed header that cannot be handled.
 	 */
 	public static RevTag parse(RevWalk rw, byte[] raw)
@@ -134,18 +137,18 @@ public static RevTag parse(RevWalk rw, byte[] raw)
 	 * @param id
 	 *            object name for the tag.
 	 */
-	protected RevTag(final AnyObjectId id) {
+	protected RevTag(AnyObjectId id) {
 		super(id);
 	}
 
 	@Override
-	void parseHeaders(final RevWalk walk) throws MissingObjectException,
+	void parseHeaders(RevWalk walk) throws MissingObjectException,
 			IncorrectObjectTypeException, IOException {
 		parseCanonical(walk, walk.getCachedBytes(this));
 	}
 
 	@Override
-	void parseBody(final RevWalk walk) throws MissingObjectException,
+	void parseBody(RevWalk walk) throws MissingObjectException,
 			IncorrectObjectTypeException, IOException {
 		if (buffer == null) {
 			buffer = walk.getCachedBytes(this);
@@ -154,7 +157,7 @@ void parseBody(final RevWalk walk) throws MissingObjectException,
 		}
 	}
 
-	void parseCanonical(final RevWalk walk, final byte[] rawTag)
+	void parseCanonical(RevWalk walk, byte[] rawTag)
 			throws CorruptObjectException {
 		final MutableInteger pos = new MutableInteger();
 		final int oType;
@@ -166,13 +169,14 @@ void parseCanonical(final RevWalk walk, final byte[] rawTag)
 
 		int p = pos.value += 4; // "tag "
 		final int nameEnd = RawParseUtils.nextLF(rawTag, p) - 1;
-		tagName = RawParseUtils.decode(UTF_8, rawTag, p, nameEnd);
+		tagName = RawParseUtils.decode(CHARSET, rawTag, p, nameEnd);
 
 		if (walk.isRetainBody())
 			buffer = rawTag;
 		flags |= PARSED;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public final int getType() {
 		return Constants.OBJ_TAG;
@@ -253,7 +257,7 @@ private Charset guessEncoding() {
 		try {
 			return RawParseUtils.parseEncoding(buffer);
 		} catch (IllegalCharsetNameException | UnsupportedCharsetException e) {
-			return UTF_8;
+			return CHARSET;
 		}
 	}
 
@@ -261,12 +265,15 @@ private Charset guessEncoding() {
 	 * Get a reference to the object this tag was placed on.
 	 * <p>
 	 * Note that the returned object has only been looked up (see
-	 * {@link RevWalk#lookupAny(AnyObjectId, int)}. To access the contents it
-	 * needs to be parsed, see {@link RevWalk#parseHeaders(RevObject)} and
-	 * {@link RevWalk#parseBody(RevObject)}.
+	 * {@link org.eclipse.jgit.revwalk.RevWalk#lookupAny(AnyObjectId, int)}. To
+	 * access the contents it needs to be parsed, see
+	 * {@link org.eclipse.jgit.revwalk.RevWalk#parseHeaders(RevObject)} and
+	 * {@link org.eclipse.jgit.revwalk.RevWalk#parseBody(RevObject)}.
 	 * <p>
-	 * As an alternative, use {@link RevWalk#peel(RevObject)} and pass this
-	 * {@link RevTag} to peel it until the first non-tag object.
+	 * As an alternative, use
+	 * {@link org.eclipse.jgit.revwalk.RevWalk#peel(RevObject)} and pass this
+	 * {@link org.eclipse.jgit.revwalk.RevTag} to peel it until the first
+	 * non-tag object.
 	 *
 	 * @return object this tag refers to (only looked up, not parsed)
 	 */
@@ -290,7 +297,7 @@ public final String getTagName() {
 	 * only the {@link #getObject()} pointer and {@link #getTagName()}.
 	 * Accessing other properties such as {@link #getTaggerIdent()} or either
 	 * message function requires reloading the buffer by invoking
-	 * {@link RevWalk#parseBody(RevObject)}.
+	 * {@link org.eclipse.jgit.revwalk.RevWalk#parseBody(RevObject)}.
 	 *
 	 * @since 4.0
 	 */
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevTree.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevTree.java
index d370409..e7de270 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevTree.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevTree.java
@@ -52,7 +52,9 @@
 import org.eclipse.jgit.lib.AnyObjectId;
 import org.eclipse.jgit.lib.Constants;
 
-/** A reference to a tree of subtrees/files. */
+/**
+ * A reference to a tree of subtrees/files.
+ */
 public class RevTree extends RevObject {
 	/**
 	 * Create a new tree reference.
@@ -60,10 +62,11 @@ public class RevTree extends RevObject {
 	 * @param id
 	 *            object name for the tree.
 	 */
-	protected RevTree(final AnyObjectId id) {
+	protected RevTree(AnyObjectId id) {
 		super(id);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public final int getType() {
 		return Constants.OBJ_TREE;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevWalk.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevWalk.java
index 320f05f..a986cfd 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevWalk.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevWalk.java
@@ -53,6 +53,7 @@
 import java.util.Iterator;
 import java.util.List;
 
+import org.eclipse.jgit.annotations.NonNull;
 import org.eclipse.jgit.errors.CorruptObjectException;
 import org.eclipse.jgit.errors.IncorrectObjectTypeException;
 import org.eclipse.jgit.errors.LargeObjectException;
@@ -84,10 +85,12 @@
  * usage of a RevWalk instance to a single thread, or implement their own
  * synchronization at a higher level.
  * <p>
- * Multiple simultaneous RevWalk instances per {@link Repository} are permitted,
- * even from concurrent threads. Equality of {@link RevCommit}s from two
- * different RevWalk instances is never true, even if their {@link ObjectId}s
- * are equal (and thus they describe the same commit).
+ * Multiple simultaneous RevWalk instances per
+ * {@link org.eclipse.jgit.lib.Repository} are permitted, even from concurrent
+ * threads. Equality of {@link org.eclipse.jgit.revwalk.RevCommit}s from two
+ * different RevWalk instances is never true, even if their
+ * {@link org.eclipse.jgit.lib.ObjectId}s are equal (and thus they describe the
+ * same commit).
  * <p>
  * The offered iterator is over the list of RevCommits described by the
  * configuration of this instance. Applications should restrict themselves to
@@ -206,7 +209,7 @@ public class RevWalk implements Iterable<RevCommit>, AutoCloseable {
 	 *            ObjectReader will be created by the walker, and will be closed
 	 *            when the walker is closed.
 	 */
-	public RevWalk(final Repository repo) {
+	public RevWalk(Repository repo) {
 		this(repo.newObjectReader(), true);
 	}
 
@@ -236,12 +239,18 @@ private RevWalk(ObjectReader or, boolean closeReader) {
 		this.closeReader = closeReader;
 	}
 
-	/** @return the reader this walker is using to load objects. */
+	/**
+	 * Get the reader this walker is using to load objects.
+	 *
+	 * @return the reader this walker is using to load objects.
+	 */
 	public ObjectReader getObjectReader() {
 		return reader;
 	}
 
 	/**
+	 * {@inheritDoc}
+	 * <p>
 	 * Release any resources used by this walker's reader.
 	 * <p>
 	 * A walker that has been released can be used again, but may need to be
@@ -272,20 +281,20 @@ public void close() {
 	 * @param c
 	 *            the commit to start traversing from. The commit passed must be
 	 *            from this same revision walker.
-	 * @throws MissingObjectException
+	 * @throws org.eclipse.jgit.errors.MissingObjectException
 	 *             the commit supplied is not available from the object
 	 *             database. This usually indicates the supplied commit is
 	 *             invalid, but the reference was constructed during an earlier
 	 *             invocation to {@link #lookupCommit(AnyObjectId)}.
-	 * @throws IncorrectObjectTypeException
+	 * @throws org.eclipse.jgit.errors.IncorrectObjectTypeException
 	 *             the object was not parsed yet and it was discovered during
 	 *             parsing that it is not actually a commit. This usually
 	 *             indicates the caller supplied a non-commit SHA-1 to
 	 *             {@link #lookupCommit(AnyObjectId)}.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             a pack file or loose object could not be read.
 	 */
-	public void markStart(final RevCommit c) throws MissingObjectException,
+	public void markStart(RevCommit c) throws MissingObjectException,
 			IncorrectObjectTypeException, IOException {
 		if ((c.flags & SEEN) != 0)
 			return;
@@ -302,23 +311,23 @@ public void markStart(final RevCommit c) throws MissingObjectException,
 	 * @param list
 	 *            commits to start traversing from. The commits passed must be
 	 *            from this same revision walker.
-	 * @throws MissingObjectException
+	 * @throws org.eclipse.jgit.errors.MissingObjectException
 	 *             one of the commits supplied is not available from the object
 	 *             database. This usually indicates the supplied commit is
 	 *             invalid, but the reference was constructed during an earlier
 	 *             invocation to {@link #lookupCommit(AnyObjectId)}.
-	 * @throws IncorrectObjectTypeException
+	 * @throws org.eclipse.jgit.errors.IncorrectObjectTypeException
 	 *             the object was not parsed yet and it was discovered during
 	 *             parsing that it is not actually a commit. This usually
 	 *             indicates the caller supplied a non-commit SHA-1 to
 	 *             {@link #lookupCommit(AnyObjectId)}.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             a pack file or loose object could not be read.
 	 */
-	public void markStart(final Collection<RevCommit> list)
+	public void markStart(Collection<RevCommit> list)
 			throws MissingObjectException, IncorrectObjectTypeException,
 			IOException {
-		for (final RevCommit c : list)
+		for (RevCommit c : list)
 			markStart(c);
 	}
 
@@ -342,20 +351,20 @@ public void markStart(final Collection<RevCommit> list)
 	 * @param c
 	 *            the commit to start traversing from. The commit passed must be
 	 *            from this same revision walker.
-	 * @throws MissingObjectException
+	 * @throws org.eclipse.jgit.errors.MissingObjectException
 	 *             the commit supplied is not available from the object
 	 *             database. This usually indicates the supplied commit is
 	 *             invalid, but the reference was constructed during an earlier
 	 *             invocation to {@link #lookupCommit(AnyObjectId)}.
-	 * @throws IncorrectObjectTypeException
+	 * @throws org.eclipse.jgit.errors.IncorrectObjectTypeException
 	 *             the object was not parsed yet and it was discovered during
 	 *             parsing that it is not actually a commit. This usually
 	 *             indicates the caller supplied a non-commit SHA-1 to
 	 *             {@link #lookupCommit(AnyObjectId)}.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             a pack file or loose object could not be read.
 	 */
-	public void markUninteresting(final RevCommit c)
+	public void markUninteresting(RevCommit c)
 			throws MissingObjectException, IncorrectObjectTypeException,
 			IOException {
 		c.flags |= UNINTERESTING;
@@ -383,17 +392,17 @@ public void markUninteresting(final RevCommit c)
 	 * @return true if there is a path directly from <code>tip</code> to
 	 *         <code>base</code> (and thus <code>base</code> is fully merged
 	 *         into <code>tip</code>); false otherwise.
-	 * @throws MissingObjectException
+	 * @throws org.eclipse.jgit.errors.MissingObjectException
 	 *             one or or more of the next commit's parents are not available
 	 *             from the object database, but were thought to be candidates
 	 *             for traversal. This usually indicates a broken link.
-	 * @throws IncorrectObjectTypeException
+	 * @throws org.eclipse.jgit.errors.IncorrectObjectTypeException
 	 *             one or or more of the next commit's parents are not actually
 	 *             commit objects.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             a pack file or loose object could not be read.
 	 */
-	public boolean isMergedInto(final RevCommit base, final RevCommit tip)
+	public boolean isMergedInto(RevCommit base, RevCommit tip)
 			throws MissingObjectException, IncorrectObjectTypeException,
 			IOException {
 		final RevFilter oldRF = filter;
@@ -420,14 +429,14 @@ public boolean isMergedInto(final RevCommit base, final RevCommit tip)
 	 * Pop the next most recent commit.
 	 *
 	 * @return next most recent commit; null if traversal is over.
-	 * @throws MissingObjectException
+	 * @throws org.eclipse.jgit.errors.MissingObjectException
 	 *             one or or more of the next commit's parents are not available
 	 *             from the object database, but were thought to be candidates
 	 *             for traversal. This usually indicates a broken link.
-	 * @throws IncorrectObjectTypeException
+	 * @throws org.eclipse.jgit.errors.IncorrectObjectTypeException
 	 *             one or or more of the next commit's parents are not actually
 	 *             commit objects.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             a pack file or loose object could not be read.
 	 */
 	public RevCommit next() throws MissingObjectException,
@@ -439,7 +448,8 @@ public RevCommit next() throws MissingObjectException,
 	 * Obtain the sort types applied to the commits returned.
 	 *
 	 * @return the sorting strategies employed. At least one strategy is always
-	 *         used, but that strategy may be {@link RevSort#NONE}.
+	 *         used, but that strategy may be
+	 *         {@link org.eclipse.jgit.revwalk.RevSort#NONE}.
 	 */
 	public EnumSet<RevSort> getRevSort() {
 		return sorting.clone();
@@ -465,7 +475,7 @@ public boolean hasRevSort(RevSort sort) {
 	 * @param s
 	 *            a sorting strategy to enable.
 	 */
-	public void sort(final RevSort s) {
+	public void sort(RevSort s) {
 		assertNotStarted();
 		sorting.clear();
 		sorting.add(s);
@@ -475,8 +485,9 @@ public void sort(final RevSort s) {
 	 * Add or remove a sorting strategy for the returned commits.
 	 * <p>
 	 * Multiple strategies can be applied at once, in which case some strategies
-	 * may take precedence over others. As an example, {@link RevSort#TOPO} must
-	 * take precedence over {@link RevSort#COMMIT_TIME_DESC}, otherwise it
+	 * may take precedence over others. As an example,
+	 * {@link org.eclipse.jgit.revwalk.RevSort#TOPO} must take precedence over
+	 * {@link org.eclipse.jgit.revwalk.RevSort#COMMIT_TIME_DESC}, otherwise it
 	 * cannot enforce its ordering.
 	 *
 	 * @param s
@@ -485,7 +496,7 @@ public void sort(final RevSort s) {
 	 *            true if this strategy should be used, false if it should be
 	 *            removed.
 	 */
-	public void sort(final RevSort s, final boolean use) {
+	public void sort(RevSort s, boolean use) {
 		assertNotStarted();
 		if (use)
 			sorting.add(s);
@@ -503,6 +514,7 @@ else if (sorting.size() == 0)
 	 *
 	 * @return the current filter. Never null as a filter is always needed.
 	 */
+	@NonNull
 	public RevFilter getRevFilter() {
 		return filter;
 	}
@@ -518,16 +530,18 @@ public RevFilter getRevFilter() {
 	 * Note that filters are not thread-safe and may not be shared by concurrent
 	 * RevWalk instances. Every RevWalk must be supplied its own unique filter,
 	 * unless the filter implementation specifically states it is (and always
-	 * will be) thread-safe. Callers may use {@link RevFilter#clone()} to create
-	 * a unique filter tree for this RevWalk instance.
+	 * will be) thread-safe. Callers may use
+	 * {@link org.eclipse.jgit.revwalk.filter.RevFilter#clone()} to create a
+	 * unique filter tree for this RevWalk instance.
 	 *
 	 * @param newFilter
-	 *            the new filter. If null the special {@link RevFilter#ALL}
-	 *            filter will be used instead, as it matches every commit.
+	 *            the new filter. If null the special
+	 *            {@link org.eclipse.jgit.revwalk.filter.RevFilter#ALL} filter
+	 *            will be used instead, as it matches every commit.
 	 * @see org.eclipse.jgit.revwalk.filter.AndRevFilter
 	 * @see org.eclipse.jgit.revwalk.filter.OrRevFilter
 	 */
-	public void setRevFilter(final RevFilter newFilter) {
+	public void setRevFilter(RevFilter newFilter) {
 		assertNotStarted();
 		filter = newFilter != null ? newFilter : RevFilter.ALL;
 	}
@@ -536,8 +550,11 @@ public void setRevFilter(final RevFilter newFilter) {
 	 * Get the tree filter used to simplify commits by modified paths.
 	 *
 	 * @return the current filter. Never null as a filter is always needed. If
-	 *         no filter is being applied {@link TreeFilter#ALL} is returned.
+	 *         no filter is being applied
+	 *         {@link org.eclipse.jgit.treewalk.filter.TreeFilter#ALL} is
+	 *         returned.
 	 */
+	@NonNull
 	public TreeFilter getTreeFilter() {
 		return treeFilter;
 	}
@@ -545,24 +562,27 @@ public TreeFilter getTreeFilter() {
 	/**
 	 * Set the tree filter used to simplify commits by modified paths.
 	 * <p>
-	 * If null or {@link TreeFilter#ALL} the path limiter is removed. Commits
-	 * will not be simplified.
+	 * If null or {@link org.eclipse.jgit.treewalk.filter.TreeFilter#ALL} the
+	 * path limiter is removed. Commits will not be simplified.
 	 * <p>
-	 * If non-null and not {@link TreeFilter#ALL} then the tree filter will be
-	 * installed. Commits will have their ancestry simplified to hide commits that
-	 * do not contain tree entries matched by the filter, unless
-	 * {@code setRewriteParents(false)} is called.
+	 * If non-null and not
+	 * {@link org.eclipse.jgit.treewalk.filter.TreeFilter#ALL} then the tree
+	 * filter will be installed. Commits will have their ancestry simplified to
+	 * hide commits that do not contain tree entries matched by the filter,
+	 * unless {@code setRewriteParents(false)} is called.
 	 * <p>
 	 * Usually callers should be inserting a filter graph including
-	 * {@link TreeFilter#ANY_DIFF} along with one or more
-	 * {@link org.eclipse.jgit.treewalk.filter.PathFilter} instances.
+	 * {@link org.eclipse.jgit.treewalk.filter.TreeFilter#ANY_DIFF} along with
+	 * one or more {@link org.eclipse.jgit.treewalk.filter.PathFilter}
+	 * instances.
 	 *
 	 * @param newFilter
-	 *            new filter. If null the special {@link TreeFilter#ALL} filter
+	 *            new filter. If null the special
+	 *            {@link org.eclipse.jgit.treewalk.filter.TreeFilter#ALL} filter
 	 *            will be used instead, as it matches everything.
 	 * @see org.eclipse.jgit.treewalk.filter.PathFilter
 	 */
-	public void setTreeFilter(final TreeFilter newFilter) {
+	public void setTreeFilter(TreeFilter newFilter) {
 		assertNotStarted();
 		treeFilter = newFilter != null ? newFilter : TreeFilter.ALL;
 	}
@@ -571,9 +591,9 @@ public void setTreeFilter(final TreeFilter newFilter) {
 	 * Set whether to rewrite parent pointers when filtering by modified paths.
 	 * <p>
 	 * By default, when {@link #setTreeFilter(TreeFilter)} is called with non-
-	 * null and non-{@link TreeFilter#ALL} filter, commits will have their
-	 * ancestry simplified and parents rewritten to hide commits that do not match
-	 * the filter.
+	 * null and non-{@link org.eclipse.jgit.treewalk.filter.TreeFilter#ALL}
+	 * filter, commits will have their ancestry simplified and parents rewritten
+	 * to hide commits that do not match the filter.
 	 * <p>
 	 * This behavior can be bypassed by passing false to this method.
 	 *
@@ -596,8 +616,8 @@ boolean getRewriteParents() {
 	 * care and would prefer to discard the body of a commit as early as
 	 * possible, to reduce memory usage.
 	 * <p>
-	 * True by default on {@link RevWalk} and false by default for
-	 * {@link ObjectWalk}.
+	 * True by default on {@link org.eclipse.jgit.revwalk.RevWalk} and false by
+	 * default for {@link org.eclipse.jgit.revwalk.ObjectWalk}.
 	 *
 	 * @return true if the body should be retained; false it is discarded.
 	 */
@@ -608,16 +628,17 @@ public boolean isRetainBody() {
 	/**
 	 * Set whether or not the body of a commit or tag is retained.
 	 * <p>
-	 * If a body of a commit or tag is not retained, the application must
-	 * call {@link #parseBody(RevObject)} before the body can be safely
-	 * accessed through the type specific access methods.
+	 * If a body of a commit or tag is not retained, the application must call
+	 * {@link #parseBody(RevObject)} before the body can be safely accessed
+	 * through the type specific access methods.
 	 * <p>
-	 * True by default on {@link RevWalk} and false by default for
-	 * {@link ObjectWalk}.
+	 * True by default on {@link org.eclipse.jgit.revwalk.RevWalk} and false by
+	 * default for {@link org.eclipse.jgit.revwalk.ObjectWalk}.
 	 *
-	 * @param retain true to retain bodies; false to discard them early.
+	 * @param retain
+	 *            true to retain bodies; false to discard them early.
 	 */
-	public void setRetainBody(final boolean retain) {
+	public void setRetainBody(boolean retain) {
 		retainBody = retain;
 	}
 
@@ -631,7 +652,8 @@ public void setRetainBody(final boolean retain) {
 	 *            name of the blob object.
 	 * @return reference to the blob object. Never null.
 	 */
-	public RevBlob lookupBlob(final AnyObjectId id) {
+	@NonNull
+	public RevBlob lookupBlob(AnyObjectId id) {
 		RevBlob c = (RevBlob) objects.get(id);
 		if (c == null) {
 			c = new RevBlob(id);
@@ -650,7 +672,8 @@ public RevBlob lookupBlob(final AnyObjectId id) {
 	 *            name of the tree object.
 	 * @return reference to the tree object. Never null.
 	 */
-	public RevTree lookupTree(final AnyObjectId id) {
+	@NonNull
+	public RevTree lookupTree(AnyObjectId id) {
 		RevTree c = (RevTree) objects.get(id);
 		if (c == null) {
 			c = new RevTree(id);
@@ -672,7 +695,8 @@ public RevTree lookupTree(final AnyObjectId id) {
 	 *            name of the commit object.
 	 * @return reference to the commit object. Never null.
 	 */
-	public RevCommit lookupCommit(final AnyObjectId id) {
+	@NonNull
+	public RevCommit lookupCommit(AnyObjectId id) {
 		RevCommit c = (RevCommit) objects.get(id);
 		if (c == null) {
 			c = createCommit(id);
@@ -691,7 +715,8 @@ public RevCommit lookupCommit(final AnyObjectId id) {
 	 *            name of the tag object.
 	 * @return reference to the tag object. Never null.
 	 */
-	public RevTag lookupTag(final AnyObjectId id) {
+	@NonNull
+	public RevTag lookupTag(AnyObjectId id) {
 		RevTag c = (RevTag) objects.get(id);
 		if (c == null) {
 			c = new RevTag(id);
@@ -712,7 +737,8 @@ public RevTag lookupTag(final AnyObjectId id) {
 	 *            type of the object. Must be a valid Git object type.
 	 * @return reference to the object. Never null.
 	 */
-	public RevObject lookupAny(final AnyObjectId id, final int type) {
+	@NonNull
+	public RevObject lookupAny(AnyObjectId id, int type) {
 		RevObject r = objects.get(id);
 		if (r == null) {
 			switch (type) {
@@ -759,14 +785,15 @@ public RevObject lookupOrNull(AnyObjectId id) {
 	 * @param id
 	 *            name of the commit object.
 	 * @return reference to the commit object. Never null.
-	 * @throws MissingObjectException
+	 * @throws org.eclipse.jgit.errors.MissingObjectException
 	 *             the supplied commit does not exist.
-	 * @throws IncorrectObjectTypeException
+	 * @throws org.eclipse.jgit.errors.IncorrectObjectTypeException
 	 *             the supplied id is not a commit or an annotated tag.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             a pack file or loose object could not be read.
 	 */
-	public RevCommit parseCommit(final AnyObjectId id)
+	@NonNull
+	public RevCommit parseCommit(AnyObjectId id)
 			throws MissingObjectException, IncorrectObjectTypeException,
 			IOException {
 		RevObject c = peel(parseAny(id));
@@ -786,14 +813,15 @@ public RevCommit parseCommit(final AnyObjectId id)
 	 *            name of the tree object, or a commit or annotated tag that may
 	 *            reference a tree.
 	 * @return reference to the tree object. Never null.
-	 * @throws MissingObjectException
+	 * @throws org.eclipse.jgit.errors.MissingObjectException
 	 *             the supplied tree does not exist.
-	 * @throws IncorrectObjectTypeException
+	 * @throws org.eclipse.jgit.errors.IncorrectObjectTypeException
 	 *             the supplied id is not a tree, a commit or an annotated tag.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             a pack file or loose object could not be read.
 	 */
-	public RevTree parseTree(final AnyObjectId id)
+	@NonNull
+	public RevTree parseTree(AnyObjectId id)
 			throws MissingObjectException, IncorrectObjectTypeException,
 			IOException {
 		RevObject c = peel(parseAny(id));
@@ -820,14 +848,15 @@ else if (!(c instanceof RevTree))
 	 * @param id
 	 *            name of the tag object.
 	 * @return reference to the tag object. Never null.
-	 * @throws MissingObjectException
+	 * @throws org.eclipse.jgit.errors.MissingObjectException
 	 *             the supplied tag does not exist.
-	 * @throws IncorrectObjectTypeException
+	 * @throws org.eclipse.jgit.errors.IncorrectObjectTypeException
 	 *             the supplied id is not a tag or an annotated tag.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             a pack file or loose object could not be read.
 	 */
-	public RevTag parseTag(final AnyObjectId id) throws MissingObjectException,
+	@NonNull
+	public RevTag parseTag(AnyObjectId id) throws MissingObjectException,
 			IncorrectObjectTypeException, IOException {
 		RevObject c = parseAny(id);
 		if (!(c instanceof RevTag))
@@ -847,12 +876,13 @@ public RevTag parseTag(final AnyObjectId id) throws MissingObjectException,
 	 * @param id
 	 *            name of the object.
 	 * @return reference to the object. Never null.
-	 * @throws MissingObjectException
+	 * @throws org.eclipse.jgit.errors.MissingObjectException
 	 *             the supplied does not exist.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             a pack file or loose object could not be read.
 	 */
-	public RevObject parseAny(final AnyObjectId id)
+	@NonNull
+	public RevObject parseAny(AnyObjectId id)
 			throws MissingObjectException, IOException {
 		RevObject r = objects.get(id);
 		if (r == null)
@@ -916,8 +946,6 @@ private RevObject parseNew(AnyObjectId id, ObjectLoader ldr)
 	/**
 	 * Asynchronous object parsing.
 	 *
-	 * @param <T>
-	 *            any ObjectId type.
 	 * @param objectIds
 	 *            objects to open from the object store. The supplied collection
 	 *            must not be modified until the queue has finished.
@@ -1007,12 +1035,12 @@ public void release() {
 	 *
 	 * @param obj
 	 *            the object the caller needs to be parsed.
-	 * @throws MissingObjectException
+	 * @throws org.eclipse.jgit.errors.MissingObjectException
 	 *             the supplied does not exist.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             a pack file or loose object could not be read.
 	 */
-	public void parseHeaders(final RevObject obj)
+	public void parseHeaders(RevObject obj)
 			throws MissingObjectException, IOException {
 		if ((obj.flags & PARSED) == 0)
 			obj.parseHeaders(this);
@@ -1026,12 +1054,12 @@ public void parseHeaders(final RevObject obj)
 	 *
 	 * @param obj
 	 *            the object the caller needs to be parsed.
-	 * @throws MissingObjectException
+	 * @throws org.eclipse.jgit.errors.MissingObjectException
 	 *             the supplied does not exist.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             a pack file or loose object could not be read.
 	 */
-	public void parseBody(final RevObject obj)
+	public void parseBody(RevObject obj)
 			throws MissingObjectException, IOException {
 		obj.parseBody(this);
 	}
@@ -1044,9 +1072,9 @@ public void parseBody(final RevObject obj)
 	 * @return If {@code obj} is not an annotated tag, {@code obj}. Otherwise
 	 *         the first non-tag object that {@code obj} references. The
 	 *         returned object's headers have been parsed.
-	 * @throws MissingObjectException
+	 * @throws org.eclipse.jgit.errors.MissingObjectException
 	 *             a referenced object cannot be found.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             a pack file or loose object could not be read.
 	 */
 	public RevObject peel(RevObject obj) throws MissingObjectException,
@@ -1069,10 +1097,10 @@ public RevObject peel(RevObject obj) throws MissingObjectException,
 	 * @param name
 	 *            description of the flag, primarily useful for debugging.
 	 * @return newly constructed flag instance.
-	 * @throws IllegalArgumentException
+	 * @throws java.lang.IllegalArgumentException
 	 *             too many flags have been reserved on this revision walker.
 	 */
-	public RevFlag newFlag(final String name) {
+	public RevFlag newFlag(String name) {
 		final int m = allocFlag();
 		return new RevFlag(this, name, m);
 	}
@@ -1096,7 +1124,7 @@ int allocFlag() {
 	 * @param flag
 	 *            the flag to carry onto parents, if set on a descendant.
 	 */
-	public void carry(final RevFlag flag) {
+	public void carry(RevFlag flag) {
 		if ((freeFlags & flag.mask) != 0)
 			throw new IllegalArgumentException(MessageFormat.format(JGitText.get().flagIsDisposed, flag.name));
 		if (flag.walker != this)
@@ -1113,8 +1141,8 @@ public void carry(final RevFlag flag) {
 	 * @param set
 	 *            the flags to carry onto parents, if set on a descendant.
 	 */
-	public void carry(final Collection<RevFlag> set) {
-		for (final RevFlag flag : set)
+	public void carry(Collection<RevFlag> set) {
+		for (RevFlag flag : set)
 			carry(flag);
 	}
 
@@ -1172,11 +1200,11 @@ public final void retainOnReset(Collection<RevFlag> flags) {
 	 * @param flag
 	 *            the to recycle.
 	 */
-	public void disposeFlag(final RevFlag flag) {
+	public void disposeFlag(RevFlag flag) {
 		freeFlag(flag.mask);
 	}
 
-	void freeFlag(final int mask) {
+	void freeFlag(int mask) {
 		retainOnReset &= ~mask;
 		if (isNotStarted()) {
 			freeFlags |= mask;
@@ -1216,7 +1244,7 @@ public final void reset() {
 	 *            application flags that should <b>not</b> be cleared from
 	 *            existing commit objects.
 	 */
-	public final void resetRetain(final RevFlagSet retainFlags) {
+	public final void resetRetain(RevFlagSet retainFlags) {
 		reset(retainFlags.mask);
 	}
 
@@ -1234,9 +1262,9 @@ public final void resetRetain(final RevFlagSet retainFlags) {
 	 *            application flags that should <b>not</b> be cleared from
 	 *            existing commit objects.
 	 */
-	public final void resetRetain(final RevFlag... retainFlags) {
+	public final void resetRetain(RevFlag... retainFlags) {
 		int mask = 0;
-		for (final RevFlag flag : retainFlags)
+		for (RevFlag flag : retainFlags)
 			mask |= flag.mask;
 		reset(mask);
 	}
@@ -1258,7 +1286,7 @@ protected void reset(int retainFlags) {
 		final int clearFlags = ~retainFlags;
 
 		final FIFORevQueue q = new FIFORevQueue();
-		for (final RevCommit c : roots) {
+		for (RevCommit c : roots) {
 			if ((c.flags & clearFlags) == 0)
 				continue;
 			c.flags &= retainFlags;
@@ -1272,7 +1300,7 @@ protected void reset(int retainFlags) {
 				break;
 			if (c.parents == null)
 				continue;
-			for (final RevCommit p : c.parents) {
+			for (RevCommit p : c.parents) {
 				if ((p.flags & clearFlags) == 0)
 					continue;
 				p.flags &= retainFlags;
@@ -1308,6 +1336,8 @@ public void dispose() {
 	}
 
 	/**
+	 * {@inheritDoc}
+	 * <p>
 	 * Returns an Iterator over the commits of this walker.
 	 * <p>
 	 * The returned iterator is only useful for one walk. If this RevWalk gets
@@ -1316,10 +1346,9 @@ public void dispose() {
 	 * Applications must not use both the Iterator and the {@link #next()} API
 	 * at the same time. Pick one API and use that for the entire walk.
 	 * <p>
-	 * If a checked exception is thrown during the walk (see {@link #next()})
-	 * it is rethrown from the Iterator as a {@link RevWalkException}.
+	 * If a checked exception is thrown during the walk (see {@link #next()}) it
+	 * is rethrown from the Iterator as a {@link RevWalkException}.
 	 *
-	 * @return an iterator over this walker's commits.
 	 * @see RevWalkException
 	 */
 	@Override
@@ -1365,7 +1394,9 @@ public void remove() {
 		};
 	}
 
-	/** Throws an exception if we have started producing output. */
+	/**
+	 * Throws an exception if we have started producing output.
+	 */
 	protected void assertNotStarted() {
 		if (isNotStarted())
 			return;
@@ -1377,7 +1408,8 @@ private boolean isNotStarted() {
 	}
 
 	/**
-	 * Create and return an {@link ObjectWalk} using the same objects.
+	 * Create and return an {@link org.eclipse.jgit.revwalk.ObjectWalk} using
+	 * the same objects.
 	 * <p>
 	 * Prior to using this method, the caller must reset this RevWalk to clean
 	 * any flags that were used during the last traversal.
@@ -1403,11 +1435,11 @@ public ObjectWalk toObjectWalkWithSameObjects() {
 	 *            the object this walker requires a commit reference for.
 	 * @return a new unparsed reference for the object.
 	 */
-	protected RevCommit createCommit(final AnyObjectId id) {
+	protected RevCommit createCommit(AnyObjectId id) {
 		return new RevCommit(id);
 	}
 
-	void carryFlagsImpl(final RevCommit c) {
+	void carryFlagsImpl(RevCommit c) {
 		final int carry = c.flags & carryFlags;
 		if (carry != 0)
 			RevCommit.carryFlags(c, carry);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevWalkUtils.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevWalkUtils.java
index e751d77..f1252a4 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevWalkUtils.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevWalkUtils.java
@@ -53,7 +53,7 @@
 import org.eclipse.jgit.lib.Ref;
 
 /**
- * Utility methods for {@link RevWalk}.
+ * Utility methods for {@link org.eclipse.jgit.revwalk.RevWalk}.
  */
 public final class RevWalkUtils {
 
@@ -67,9 +67,10 @@ private RevWalkUtils() {
 	 * other words, count the number of commits that are in <code>start</code>,
 	 * but not in <code>end</code>.
 	 * <p>
-	 * Note that this method calls {@link RevWalk#reset()} at the beginning.
-	 * Also note that the existing rev filter on the walk is left as-is, so be
-	 * sure to set the right rev filter before calling this method.
+	 * Note that this method calls
+	 * {@link org.eclipse.jgit.revwalk.RevWalk#reset()} at the beginning. Also
+	 * note that the existing rev filter on the walk is left as-is, so be sure
+	 * to set the right rev filter before calling this method.
 	 *
 	 * @param walk
 	 *            the rev walk to use
@@ -78,11 +79,10 @@ private RevWalkUtils() {
 	 * @param end
 	 *            the commit where counting should end, or null if counting
 	 *            should be done until there are no more commits
-	 *
 	 * @return the number of commits
-	 * @throws MissingObjectException
-	 * @throws IncorrectObjectTypeException
-	 * @throws IOException
+	 * @throws org.eclipse.jgit.errors.MissingObjectException
+	 * @throws org.eclipse.jgit.errors.IncorrectObjectTypeException
+	 * @throws java.io.IOException
 	 */
 	public static int count(final RevWalk walk, final RevCommit start,
 			final RevCommit end) throws MissingObjectException,
@@ -96,9 +96,10 @@ public static int count(final RevWalk walk, final RevCommit start,
 	 * Find of commits that are in <code>start</code>, but not in
 	 * <code>end</code>.
 	 * <p>
-	 * Note that this method calls {@link RevWalk#reset()} at the beginning.
-	 * Also note that the existing rev filter on the walk is left as-is, so be
-	 * sure to set the right rev filter before calling this method.
+	 * Note that this method calls
+	 * {@link org.eclipse.jgit.revwalk.RevWalk#reset()} at the beginning. Also
+	 * note that the existing rev filter on the walk is left as-is, so be sure
+	 * to set the right rev filter before calling this method.
 	 *
 	 * @param walk
 	 *            the rev walk to use
@@ -108,9 +109,9 @@ public static int count(final RevWalk walk, final RevCommit start,
 	 *            the commit where counting should end, or null if counting
 	 *            should be done until there are no more commits
 	 * @return the commits found
-	 * @throws MissingObjectException
-	 * @throws IncorrectObjectTypeException
-	 * @throws IOException
+	 * @throws org.eclipse.jgit.errors.MissingObjectException
+	 * @throws org.eclipse.jgit.errors.IncorrectObjectTypeException
+	 * @throws java.io.IOException
 	 */
 	public static List<RevCommit> find(final RevWalk walk,
 			final RevCommit start, final RevCommit end)
@@ -131,7 +132,8 @@ public static List<RevCommit> find(final RevWalk walk,
 	 * Find the list of branches a given commit is reachable from when following
 	 * parent.s
 	 * <p>
-	 * Note that this method calls {@link RevWalk#reset()} at the beginning.
+	 * Note that this method calls
+	 * {@link org.eclipse.jgit.revwalk.RevWalk#reset()} at the beginning.
 	 * <p>
 	 * In order to improve performance this method assumes clock skew among
 	 * committers is never larger than 24 hours.
@@ -143,9 +145,9 @@ public static List<RevCommit> find(final RevWalk walk,
 	 * @param refs
 	 *            the set of branches we want to see reachability from
 	 * @return the list of branches a given commit is reachable from
-	 * @throws MissingObjectException
-	 * @throws IncorrectObjectTypeException
-	 * @throws IOException
+	 * @throws org.eclipse.jgit.errors.MissingObjectException
+	 * @throws org.eclipse.jgit.errors.IncorrectObjectTypeException
+	 * @throws java.io.IOException
 	 */
 	public static List<Ref> findBranchesReachableFrom(RevCommit commit,
 			RevWalk revWalk, Collection<Ref> refs)
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RewriteGenerator.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RewriteGenerator.java
index 3ab96ca..1c868ff 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RewriteGenerator.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RewriteGenerator.java
@@ -76,12 +76,12 @@ class RewriteGenerator extends Generator {
 
 	private final Generator source;
 
-	RewriteGenerator(final Generator s) {
+	RewriteGenerator(Generator s) {
 		source = s;
 	}
 
 	@Override
-	void shareFreeList(final BlockRevQueue q) {
+	void shareFreeList(BlockRevQueue q) {
 		source.shareFreeList(q);
 	}
 
@@ -93,27 +93,25 @@ int outputType() {
 	@Override
 	RevCommit next() throws MissingObjectException,
 			IncorrectObjectTypeException, IOException {
-		for (;;) {
-			final RevCommit c = source.next();
-			if (c == null)
-				return null;
-
-			boolean rewrote = false;
-			final RevCommit[] pList = c.parents;
-			final int nParents = pList.length;
-			for (int i = 0; i < nParents; i++) {
-				final RevCommit oldp = pList[i];
-				final RevCommit newp = rewrite(oldp);
-				if (oldp != newp) {
-					pList[i] = newp;
-					rewrote = true;
-				}
-			}
-			if (rewrote)
-				c.parents = cleanup(pList);
-
-			return c;
+		final RevCommit c = source.next();
+		if (c == null) {
+			return null;
 		}
+		boolean rewrote = false;
+		final RevCommit[] pList = c.parents;
+		final int nParents = pList.length;
+		for (int i = 0; i < nParents; i++) {
+			final RevCommit oldp = pList[i];
+			final RevCommit newp = rewrite(oldp);
+			if (oldp != newp) {
+				pList[i] = newp;
+				rewrote = true;
+			}
+		}
+		if (rewrote) {
+			c.parents = cleanup(pList);
+		}
+		return c;
 	}
 
 	private RevCommit rewrite(RevCommit p) {
@@ -150,7 +148,7 @@ private RevCommit rewrite(RevCommit p) {
 		}
 	}
 
-	private RevCommit[] cleanup(final RevCommit[] oldList) {
+	private RevCommit[] cleanup(RevCommit[] oldList) {
 		// Remove any duplicate parents caused due to rewrites (e.g. a merge
 		// with two sides that both simplified back into the merge base).
 		// We also may have deleted a parent by marking it null.
@@ -169,14 +167,14 @@ private RevCommit rewrite(RevCommit p) {
 		}
 
 		if (newCnt == oldList.length) {
-			for (final RevCommit p : oldList)
+			for (RevCommit p : oldList)
 				p.flags &= ~DUPLICATE;
 			return oldList;
 		}
 
 		final RevCommit[] newList = new RevCommit[newCnt];
 		newCnt = 0;
-		for (final RevCommit p : oldList) {
+		for (RevCommit p : oldList) {
 			if (p != null) {
 				newList[newCnt++] = p;
 				p.flags &= ~DUPLICATE;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/StartGenerator.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/StartGenerator.java
index 1ec6290..eb129a2 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/StartGenerator.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/StartGenerator.java
@@ -66,7 +66,7 @@
 class StartGenerator extends Generator {
 	private final RevWalk walker;
 
-	StartGenerator(final RevWalk w) {
+	StartGenerator(RevWalk w) {
 		walker = w;
 	}
 
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/TopoSortGenerator.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/TopoSortGenerator.java
index 7b11d04..6450343 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/TopoSortGenerator.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/TopoSortGenerator.java
@@ -69,7 +69,7 @@ class TopoSortGenerator extends Generator {
 	 * @throws IncorrectObjectTypeException
 	 * @throws IOException
 	 */
-	TopoSortGenerator(final Generator s) throws MissingObjectException,
+	TopoSortGenerator(Generator s) throws MissingObjectException,
 			IncorrectObjectTypeException, IOException {
 		pending = new FIFORevQueue();
 		outputType = s.outputType() | SORT_TOPO;
@@ -78,7 +78,7 @@ class TopoSortGenerator extends Generator {
 			final RevCommit c = s.next();
 			if (c == null)
 				break;
-			for (final RevCommit p : c.parents)
+			for (RevCommit p : c.parents)
 				p.inDegree++;
 			pending.add(c);
 		}
@@ -90,7 +90,7 @@ int outputType() {
 	}
 
 	@Override
-	void shareFreeList(final BlockRevQueue q) {
+	void shareFreeList(BlockRevQueue q) {
 		q.shareFreeList(pending);
 	}
 
@@ -113,7 +113,7 @@ RevCommit next() throws MissingObjectException,
 			// All of our children have already produced,
 			// so it is OK for us to produce now as well.
 			//
-			for (final RevCommit p : c.parents) {
+			for (RevCommit p : c.parents) {
 				if (--p.inDegree == 0 && (p.flags & TOPO_DELAY) != 0) {
 					// This parent tried to come before us, but we are
 					// his last child. unpop the parent so it goes right
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/TreeRevFilter.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/TreeRevFilter.java
index b2c0fcd..1130153 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/TreeRevFilter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/TreeRevFilter.java
@@ -60,10 +60,12 @@
 import org.eclipse.jgit.treewalk.filter.TreeFilter;
 
 /**
- * Filter applying a {@link TreeFilter} against changed paths in each commit.
+ * Filter applying a {@link org.eclipse.jgit.treewalk.filter.TreeFilter} against
+ * changed paths in each commit.
  * <p>
  * Each commit is differenced concurrently against all of its parents to look
- * for tree entries that are interesting to the {@link TreeFilter}.
+ * for tree entries that are interesting to the
+ * {@link org.eclipse.jgit.treewalk.filter.TreeFilter}.
  *
  * @since 3.5
  */
@@ -76,17 +78,18 @@ public class TreeRevFilter extends RevFilter {
 	private final TreeWalk pathFilter;
 
 	/**
-	 * Create a {@link RevFilter} from a {@link TreeFilter}.
+	 * Create a {@link org.eclipse.jgit.revwalk.filter.RevFilter} from a
+	 * {@link org.eclipse.jgit.treewalk.filter.TreeFilter}.
 	 *
 	 * @param walker
 	 *            walker used for reading trees.
 	 * @param t
-	 *            filter to compare against any changed paths in each commit. If a
-	 *            {@link FollowFilter}, will be replaced with a new filter
-	 *            following new paths after a rename.
+	 *            filter to compare against any changed paths in each commit. If
+	 *            a {@link org.eclipse.jgit.revwalk.FollowFilter}, will be
+	 *            replaced with a new filter following new paths after a rename.
 	 * @since 3.5
 	 */
-	public TreeRevFilter(final RevWalk walker, final TreeFilter t) {
+	public TreeRevFilter(RevWalk walker, TreeFilter t) {
 		this(walker, t, 0);
 	}
 
@@ -121,13 +124,15 @@ public TreeRevFilter(final RevWalk walker, final TreeFilter t) {
 		this.rewriteFlag = rewriteFlag;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public RevFilter clone() {
 		throw new UnsupportedOperationException();
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	public boolean include(final RevWalk walker, final RevCommit c)
+	public boolean include(RevWalk walker, RevCommit c)
 			throws StopWalkException, MissingObjectException,
 			IncorrectObjectTypeException, IOException {
 		// Reset the tree filter to scan this commit and parents.
@@ -260,6 +265,7 @@ public boolean include(final RevWalk walker, final RevCommit c)
 		return false;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public boolean requiresCommitBody() {
 		return false;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/filter/AndRevFilter.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/filter/AndRevFilter.java
index 4a91493..dfb83b4 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/filter/AndRevFilter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/filter/AndRevFilter.java
@@ -57,9 +57,10 @@
  * Includes a commit only if all subfilters include the same commit.
  * <p>
  * Classic shortcut behavior is used, so evaluation of the
- * {@link RevFilter#include(RevWalk, RevCommit)} method stops as soon as a false
- * result is obtained. Applications can improve filtering performance by placing
- * faster filters that are more likely to reject a result earlier in the list.
+ * {@link org.eclipse.jgit.revwalk.filter.RevFilter#include(RevWalk, RevCommit)}
+ * method stops as soon as a false result is obtained. Applications can improve
+ * filtering performance by placing faster filters that are more likely to
+ * reject a result earlier in the list.
  */
 public abstract class AndRevFilter extends RevFilter {
 	/**
@@ -71,7 +72,7 @@ public abstract class AndRevFilter extends RevFilter {
 	 *            second filter to test.
 	 * @return a filter that must match both input filters.
 	 */
-	public static RevFilter create(final RevFilter a, final RevFilter b) {
+	public static RevFilter create(RevFilter a, RevFilter b) {
 		if (a == ALL)
 			return b;
 		if (b == ALL)
@@ -87,7 +88,7 @@ public static RevFilter create(final RevFilter a, final RevFilter b) {
 	 *            filters.
 	 * @return a filter that must match all input filters.
 	 */
-	public static RevFilter create(final RevFilter[] list) {
+	public static RevFilter create(RevFilter[] list) {
 		if (list.length == 2)
 			return create(list[0], list[1]);
 		if (list.length < 2)
@@ -105,7 +106,7 @@ public static RevFilter create(final RevFilter[] list) {
 	 *            filters.
 	 * @return a filter that must match all input filters.
 	 */
-	public static RevFilter create(final Collection<RevFilter> list) {
+	public static RevFilter create(Collection<RevFilter> list) {
 		if (list.size() < 2)
 			throw new IllegalArgumentException(JGitText.get().atLeastTwoFiltersNeeded);
 		final RevFilter[] subfilters = new RevFilter[list.size()];
@@ -122,7 +123,7 @@ private static class Binary extends AndRevFilter {
 
 		private final boolean requiresCommitBody;
 
-		Binary(final RevFilter one, final RevFilter two) {
+		Binary(RevFilter one, RevFilter two) {
 			a = one;
 			b = two;
 			requiresCommitBody = a.requiresCommitBody()
@@ -130,7 +131,7 @@ private static class Binary extends AndRevFilter {
 		}
 
 		@Override
-		public boolean include(final RevWalk walker, final RevCommit c)
+		public boolean include(RevWalk walker, RevCommit c)
 				throws MissingObjectException, IncorrectObjectTypeException,
 				IOException {
 			return a.include(walker, c) && b.include(walker, c);
@@ -158,7 +159,7 @@ private static class List extends AndRevFilter {
 
 		private final boolean requiresCommitBody;
 
-		List(final RevFilter[] list) {
+		List(RevFilter[] list) {
 			subfilters = list;
 
 			boolean rcb = false;
@@ -168,10 +169,10 @@ private static class List extends AndRevFilter {
 		}
 
 		@Override
-		public boolean include(final RevWalk walker, final RevCommit c)
+		public boolean include(RevWalk walker, RevCommit c)
 				throws MissingObjectException, IncorrectObjectTypeException,
 				IOException {
-			for (final RevFilter f : subfilters) {
+			for (RevFilter f : subfilters) {
 				if (!f.include(walker, c))
 					return false;
 			}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/filter/AuthorRevFilter.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/filter/AuthorRevFilter.java
index ef0064b..334d4f0 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/filter/AuthorRevFilter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/filter/AuthorRevFilter.java
@@ -50,7 +50,9 @@
 import org.eclipse.jgit.util.RawCharSequence;
 import org.eclipse.jgit.util.RawParseUtils;
 
-/** Matches only commits whose author name matches the pattern. */
+/**
+ * Matches only commits whose author name matches the pattern.
+ */
 public class AuthorRevFilter {
 	/**
 	 * Create a new author filter.
@@ -79,7 +81,7 @@ private AuthorRevFilter() {
 		// Don't permit us to be created.
 	}
 
-	static RawCharSequence textFor(final RevCommit cmit) {
+	static RawCharSequence textFor(RevCommit cmit) {
 		final byte[] raw = cmit.getRawBuffer();
 		final int b = RawParseUtils.author(raw, 0);
 		if (b < 0)
@@ -89,12 +91,12 @@ static RawCharSequence textFor(final RevCommit cmit) {
 	}
 
 	private static class PatternSearch extends PatternMatchRevFilter {
-		PatternSearch(final String patternText) {
+		PatternSearch(String patternText) {
 			super(patternText, true, true, Pattern.CASE_INSENSITIVE);
 		}
 
 		@Override
-		protected CharSequence text(final RevCommit cmit) {
+		protected CharSequence text(RevCommit cmit) {
 			return textFor(cmit);
 		}
 
@@ -105,12 +107,12 @@ public RevFilter clone() {
 	}
 
 	private static class SubStringSearch extends SubStringRevFilter {
-		SubStringSearch(final String patternText) {
+		SubStringSearch(String patternText) {
 			super(patternText);
 		}
 
 		@Override
-		protected RawCharSequence text(final RevCommit cmit) {
+		protected RawCharSequence text(RevCommit cmit) {
 			return textFor(cmit);
 		}
 	}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/filter/CommitTimeRevFilter.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/filter/CommitTimeRevFilter.java
index 5bf9366..3880515 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/filter/CommitTimeRevFilter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/filter/CommitTimeRevFilter.java
@@ -53,7 +53,9 @@
 import org.eclipse.jgit.revwalk.RevCommit;
 import org.eclipse.jgit.revwalk.RevWalk;
 
-/** Selects commits based upon the commit time field. */
+/**
+ * Selects commits based upon the commit time field.
+ */
 public abstract class CommitTimeRevFilter extends RevFilter {
 	/**
 	 * Create a new filter to select commits before a given date/time.
@@ -62,7 +64,7 @@ public abstract class CommitTimeRevFilter extends RevFilter {
 	 *            the point in time to cut on.
 	 * @return a new filter to select commits on or before <code>ts</code>.
 	 */
-	public static final RevFilter before(final Date ts) {
+	public static final RevFilter before(Date ts) {
 		return before(ts.getTime());
 	}
 
@@ -73,7 +75,7 @@ public static final RevFilter before(final Date ts) {
 	 *            the point in time to cut on, in milliseconds
 	 * @return a new filter to select commits on or before <code>ts</code>.
 	 */
-	public static final RevFilter before(final long ts) {
+	public static final RevFilter before(long ts) {
 		return new Before(ts);
 	}
 
@@ -84,7 +86,7 @@ public static final RevFilter before(final long ts) {
 	 *            the point in time to cut on.
 	 * @return a new filter to select commits on or after <code>ts</code>.
 	 */
-	public static final RevFilter after(final Date ts) {
+	public static final RevFilter after(Date ts) {
 		return after(ts.getTime());
 	}
 
@@ -95,7 +97,7 @@ public static final RevFilter after(final Date ts) {
 	 *            the point in time to cut on, in milliseconds.
 	 * @return a new filter to select commits on or after <code>ts</code>.
 	 */
-	public static final RevFilter after(final long ts) {
+	public static final RevFilter after(long ts) {
 		return new After(ts);
 	}
 
@@ -107,7 +109,7 @@ public static final RevFilter after(final long ts) {
 	 * @param until the point in time to cut off.
 	 * @return a new filter to select commits between the given date/times.
 	 */
-	public static final RevFilter between(final Date since, final Date until) {
+	public static final RevFilter between(Date since, Date until) {
 		return between(since.getTime(), until.getTime());
 	}
 
@@ -119,33 +121,35 @@ public static final RevFilter between(final Date since, final Date until) {
 	 * @param until the point in time to cut off, in millisconds.
 	 * @return a new filter to select commits between the given date/times.
 	 */
-	public static final RevFilter between(final long since, final long until) {
+	public static final RevFilter between(long since, long until) {
 		return new Between(since, until);
 	}
 
 	final int when;
 
-	CommitTimeRevFilter(final long ts) {
+	CommitTimeRevFilter(long ts) {
 		when = (int) (ts / 1000);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public RevFilter clone() {
 		return this;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public boolean requiresCommitBody() {
 		return false;
 	}
 
 	private static class Before extends CommitTimeRevFilter {
-		Before(final long ts) {
+		Before(long ts) {
 			super(ts);
 		}
 
 		@Override
-		public boolean include(final RevWalk walker, final RevCommit cmit)
+		public boolean include(RevWalk walker, RevCommit cmit)
 				throws StopWalkException, MissingObjectException,
 				IncorrectObjectTypeException, IOException {
 			return cmit.getCommitTime() <= when;
@@ -159,12 +163,12 @@ public String toString() {
 	}
 
 	private static class After extends CommitTimeRevFilter {
-		After(final long ts) {
+		After(long ts) {
 			super(ts);
 		}
 
 		@Override
-		public boolean include(final RevWalk walker, final RevCommit cmit)
+		public boolean include(RevWalk walker, RevCommit cmit)
 				throws StopWalkException, MissingObjectException,
 				IncorrectObjectTypeException, IOException {
 			// Since the walker sorts commits by commit time we can be
@@ -186,13 +190,13 @@ public String toString() {
 	private static class Between extends CommitTimeRevFilter {
 		private final int until;
 
-		Between(final long since, final long until) {
+		Between(long since, long until) {
 			super(since);
 			this.until = (int) (until / 1000);
 		}
 
 		@Override
-		public boolean include(final RevWalk walker, final RevCommit cmit)
+		public boolean include(RevWalk walker, RevCommit cmit)
 				throws StopWalkException, MissingObjectException,
 				IncorrectObjectTypeException, IOException {
 			return cmit.getCommitTime() <= until && cmit.getCommitTime() >= when;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/filter/CommitterRevFilter.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/filter/CommitterRevFilter.java
index eedfef2..37c840e 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/filter/CommitterRevFilter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/filter/CommitterRevFilter.java
@@ -50,7 +50,9 @@
 import org.eclipse.jgit.util.RawCharSequence;
 import org.eclipse.jgit.util.RawParseUtils;
 
-/** Matches only commits whose committer name matches the pattern. */
+/**
+ * Matches only commits whose committer name matches the pattern.
+ */
 public class CommitterRevFilter {
 	/**
 	 * Create a new committer filter.
@@ -79,7 +81,7 @@ private CommitterRevFilter() {
 		// Don't permit us to be created.
 	}
 
-	static RawCharSequence textFor(final RevCommit cmit) {
+	static RawCharSequence textFor(RevCommit cmit) {
 		final byte[] raw = cmit.getRawBuffer();
 		final int b = RawParseUtils.committer(raw, 0);
 		if (b < 0)
@@ -89,12 +91,12 @@ static RawCharSequence textFor(final RevCommit cmit) {
 	}
 
 	private static class PatternSearch extends PatternMatchRevFilter {
-		PatternSearch(final String patternText) {
+		PatternSearch(String patternText) {
 			super(patternText, true, true, Pattern.CASE_INSENSITIVE);
 		}
 
 		@Override
-		protected CharSequence text(final RevCommit cmit) {
+		protected CharSequence text(RevCommit cmit) {
 			return textFor(cmit);
 		}
 
@@ -105,12 +107,12 @@ public RevFilter clone() {
 	}
 
 	private static class SubStringSearch extends SubStringRevFilter {
-		SubStringSearch(final String patternText) {
+		SubStringSearch(String patternText) {
 			super(patternText);
 		}
 
 		@Override
-		protected RawCharSequence text(final RevCommit cmit) {
+		protected RawCharSequence text(RevCommit cmit) {
 			return textFor(cmit);
 		}
 	}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/filter/MaxCountRevFilter.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/filter/MaxCountRevFilter.java
index 38b0da5..02c6670 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/filter/MaxCountRevFilter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/filter/MaxCountRevFilter.java
@@ -79,6 +79,7 @@ private MaxCountRevFilter(int maxCount) {
 		this.maxCount = maxCount;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public boolean include(RevWalk walker, RevCommit cmit)
 			throws StopWalkException, MissingObjectException,
@@ -89,6 +90,7 @@ public boolean include(RevWalk walker, RevCommit cmit)
 		return true;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public RevFilter clone() {
 		return new MaxCountRevFilter(maxCount);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/filter/MessageRevFilter.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/filter/MessageRevFilter.java
index a7cc5bd..480aaa3 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/filter/MessageRevFilter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/filter/MessageRevFilter.java
@@ -50,7 +50,9 @@
 import org.eclipse.jgit.util.RawCharSequence;
 import org.eclipse.jgit.util.RawParseUtils;
 
-/** Matches only commits whose message matches the pattern. */
+/**
+ * Matches only commits whose message matches the pattern.
+ */
 public class MessageRevFilter {
 	/**
 	 * Create a message filter.
@@ -79,7 +81,7 @@ private MessageRevFilter() {
 		// Don't permit us to be created.
 	}
 
-	static RawCharSequence textFor(final RevCommit cmit) {
+	static RawCharSequence textFor(RevCommit cmit) {
 		final byte[] raw = cmit.getRawBuffer();
 		final int b = RawParseUtils.commitMessage(raw, 0);
 		if (b < 0)
@@ -88,13 +90,13 @@ static RawCharSequence textFor(final RevCommit cmit) {
 	}
 
 	private static class PatternSearch extends PatternMatchRevFilter {
-		PatternSearch(final String patternText) {
+		PatternSearch(String patternText) {
 			super(patternText, true, true, Pattern.CASE_INSENSITIVE
 					| Pattern.DOTALL);
 		}
 
 		@Override
-		protected CharSequence text(final RevCommit cmit) {
+		protected CharSequence text(RevCommit cmit) {
 			return textFor(cmit);
 		}
 
@@ -105,12 +107,12 @@ public RevFilter clone() {
 	}
 
 	private static class SubStringSearch extends SubStringRevFilter {
-		SubStringSearch(final String patternText) {
+		SubStringSearch(String patternText) {
 			super(patternText);
 		}
 
 		@Override
-		protected RawCharSequence text(final RevCommit cmit) {
+		protected RawCharSequence text(RevCommit cmit) {
 			return textFor(cmit);
 		}
 	}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/filter/NotRevFilter.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/filter/NotRevFilter.java
index d338802..69dec56 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/filter/NotRevFilter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/filter/NotRevFilter.java
@@ -50,7 +50,9 @@
 import org.eclipse.jgit.revwalk.RevCommit;
 import org.eclipse.jgit.revwalk.RevWalk;
 
-/** Includes a commit only if the subfilter does not include the commit. */
+/**
+ * Includes a commit only if the subfilter does not include the commit.
+ */
 public class NotRevFilter extends RevFilter {
 	/**
 	 * Create a filter that negates the result of another filter.
@@ -59,38 +61,43 @@ public class NotRevFilter extends RevFilter {
 	 *            filter to negate.
 	 * @return a filter that does the reverse of <code>a</code>.
 	 */
-	public static RevFilter create(final RevFilter a) {
+	public static RevFilter create(RevFilter a) {
 		return new NotRevFilter(a);
 	}
 
 	private final RevFilter a;
 
-	private NotRevFilter(final RevFilter one) {
+	private NotRevFilter(RevFilter one) {
 		a = one;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public RevFilter negate() {
 		return a;
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	public boolean include(final RevWalk walker, final RevCommit c)
+	public boolean include(RevWalk walker, RevCommit c)
 			throws MissingObjectException, IncorrectObjectTypeException,
 			IOException {
 		return !a.include(walker, c);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public boolean requiresCommitBody() {
 		return a.requiresCommitBody();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public RevFilter clone() {
 		return new NotRevFilter(a.clone());
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public String toString() {
 		return "NOT " + a.toString(); //$NON-NLS-1$
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/filter/ObjectFilter.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/filter/ObjectFilter.java
index 2ad273d..777e4e0 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/filter/ObjectFilter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/filter/ObjectFilter.java
@@ -54,7 +54,8 @@
  * Selects interesting objects when walking.
  * <p>
  * Applications should install the filter on an ObjectWalk by
- * {@link ObjectWalk#setObjectFilter(ObjectFilter)} prior to starting traversal.
+ * {@link org.eclipse.jgit.revwalk.ObjectWalk#setObjectFilter(ObjectFilter)}
+ * prior to starting traversal.
  *
  * @since 4.0
  */
@@ -77,13 +78,13 @@ public boolean include(ObjectWalk walker, AnyObjectId o) {
 	 * @param objid
 	 *            the object currently being tested.
 	 * @return {@code true} if the named object should be included in the walk.
-	 * @throws MissingObjectException
+	 * @throws org.eclipse.jgit.errors.MissingObjectException
 	 *             an object the filter needed to consult to determine its
 	 *             answer was missing
-	 * @throws IncorrectObjectTypeException
+	 * @throws org.eclipse.jgit.errors.IncorrectObjectTypeException
 	 *             an object the filter needed to consult to determine its
 	 *             answer was of the wrong type
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             an object the filter needed to consult to determine its
 	 *             answer could not be read.
 	 */
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/filter/OrRevFilter.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/filter/OrRevFilter.java
index 4c7b3bf..1cef12f 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/filter/OrRevFilter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/filter/OrRevFilter.java
@@ -57,9 +57,10 @@
  * Includes a commit if any subfilters include the same commit.
  * <p>
  * Classic shortcut behavior is used, so evaluation of the
- * {@link RevFilter#include(RevWalk, RevCommit)} method stops as soon as a true
- * result is obtained. Applications can improve filtering performance by placing
- * faster filters that are more likely to accept a result earlier in the list.
+ * {@link org.eclipse.jgit.revwalk.filter.RevFilter#include(RevWalk, RevCommit)}
+ * method stops as soon as a true result is obtained. Applications can improve
+ * filtering performance by placing faster filters that are more likely to
+ * accept a result earlier in the list.
  */
 public abstract class OrRevFilter extends RevFilter {
 	/**
@@ -71,7 +72,7 @@ public abstract class OrRevFilter extends RevFilter {
 	 *            second filter to test.
 	 * @return a filter that must match at least one input filter.
 	 */
-	public static RevFilter create(final RevFilter a, final RevFilter b) {
+	public static RevFilter create(RevFilter a, RevFilter b) {
 		if (a == ALL || b == ALL)
 			return ALL;
 		return new Binary(a, b);
@@ -85,7 +86,7 @@ public static RevFilter create(final RevFilter a, final RevFilter b) {
 	 *            filters.
 	 * @return a filter that must match at least one input filter.
 	 */
-	public static RevFilter create(final RevFilter[] list) {
+	public static RevFilter create(RevFilter[] list) {
 		if (list.length == 2)
 			return create(list[0], list[1]);
 		if (list.length < 2)
@@ -103,7 +104,7 @@ public static RevFilter create(final RevFilter[] list) {
 	 *            filters.
 	 * @return a filter that must match at least one input filter.
 	 */
-	public static RevFilter create(final Collection<RevFilter> list) {
+	public static RevFilter create(Collection<RevFilter> list) {
 		if (list.size() < 2)
 			throw new IllegalArgumentException(JGitText.get().atLeastTwoFiltersNeeded);
 		final RevFilter[] subfilters = new RevFilter[list.size()];
@@ -120,7 +121,7 @@ private static class Binary extends OrRevFilter {
 
 		private final boolean requiresCommitBody;
 
-		Binary(final RevFilter one, final RevFilter two) {
+		Binary(RevFilter one, RevFilter two) {
 			a = one;
 			b = two;
 			requiresCommitBody = a.requiresCommitBody()
@@ -128,7 +129,7 @@ private static class Binary extends OrRevFilter {
 		}
 
 		@Override
-		public boolean include(final RevWalk walker, final RevCommit c)
+		public boolean include(RevWalk walker, RevCommit c)
 				throws MissingObjectException, IncorrectObjectTypeException,
 				IOException {
 			return a.include(walker, c) || b.include(walker, c);
@@ -156,7 +157,7 @@ private static class List extends OrRevFilter {
 
 		private final boolean requiresCommitBody;
 
-		List(final RevFilter[] list) {
+		List(RevFilter[] list) {
 			subfilters = list;
 
 			boolean rcb = false;
@@ -166,10 +167,10 @@ private static class List extends OrRevFilter {
 		}
 
 		@Override
-		public boolean include(final RevWalk walker, final RevCommit c)
+		public boolean include(RevWalk walker, RevCommit c)
 				throws MissingObjectException, IncorrectObjectTypeException,
 				IOException {
-			for (final RevFilter f : subfilters) {
+			for (RevFilter f : subfilters) {
 				if (f.include(walker, c))
 					return true;
 			}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/filter/PatternMatchRevFilter.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/filter/PatternMatchRevFilter.java
index 1dd4555..4f41edf 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/filter/PatternMatchRevFilter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/filter/PatternMatchRevFilter.java
@@ -54,9 +54,10 @@
 import org.eclipse.jgit.lib.Constants;
 import org.eclipse.jgit.revwalk.RevCommit;
 import org.eclipse.jgit.revwalk.RevWalk;
-import org.eclipse.jgit.util.RawCharSequence;
 
-/** Abstract filter that searches text using extended regular expressions. */
+/**
+ * Abstract filter that searches text using extended regular expressions.
+ */
 public abstract class PatternMatchRevFilter extends RevFilter {
 	/**
 	 * Encode a string pattern for faster matching on byte arrays.
@@ -69,9 +70,9 @@ public abstract class PatternMatchRevFilter extends RevFilter {
 	 *            original pattern string supplied by the user or the
 	 *            application.
 	 * @return same pattern, but re-encoded to match our funny raw UTF-8
-	 *         character sequence {@link RawCharSequence}.
+	 *         character sequence {@link org.eclipse.jgit.util.RawCharSequence}.
 	 */
-	protected static final String forceToRaw(final String patternText) {
+	protected static final String forceToRaw(String patternText) {
 		final byte[] b = Constants.encode(patternText);
 		final StringBuilder needle = new StringBuilder(b.length);
 		for (int i = 0; i < b.length; i++)
@@ -97,7 +98,8 @@ protected static final String forceToRaw(final String patternText) {
 	 *            should {@link #forceToRaw(String)} be applied to the pattern
 	 *            before compiling it?
 	 * @param flags
-	 *            flags from {@link Pattern} to control how matching performs.
+	 *            flags from {@link java.util.regex.Pattern} to control how
+	 *            matching performs.
 	 */
 	protected PatternMatchRevFilter(String pattern, final boolean innerString,
 			final boolean rawEncoding, final int flags) {
@@ -124,13 +126,15 @@ public String pattern() {
 		return patternText;
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	public boolean include(final RevWalk walker, final RevCommit cmit)
+	public boolean include(RevWalk walker, RevCommit cmit)
 			throws MissingObjectException, IncorrectObjectTypeException,
 			IOException {
 		return compiledPattern.reset(text(cmit)).matches();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public boolean requiresCommitBody() {
 		return true;
@@ -145,6 +149,7 @@ public boolean requiresCommitBody() {
 	 */
 	protected abstract CharSequence text(RevCommit cmit);
 
+	/** {@inheritDoc} */
 	@SuppressWarnings("nls")
 	@Override
 	public String toString() {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/filter/RevFilter.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/filter/RevFilter.java
index 6b90d29..39f0d60 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/filter/RevFilter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/filter/RevFilter.java
@@ -61,7 +61,8 @@
  * <code>OrRevFilter</code> to create complex boolean expressions.
  * <p>
  * Applications should install the filter on a RevWalk by
- * {@link RevWalk#setRevFilter(RevFilter)} prior to starting traversal.
+ * {@link org.eclipse.jgit.revwalk.RevWalk#setRevFilter(RevFilter)} prior to
+ * starting traversal.
  * <p>
  * Unless specifically noted otherwise a RevFilter implementation is not thread
  * safe and may not be shared by different RevWalk instances at the same time.
@@ -73,9 +74,12 @@
  * <p>
  * <b>Message filters:</b>
  * <ul>
- * <li>Author name/email: {@link AuthorRevFilter}</li>
- * <li>Committer name/email: {@link CommitterRevFilter}</li>
- * <li>Message body: {@link MessageRevFilter}</li>
+ * <li>Author name/email:
+ * {@link org.eclipse.jgit.revwalk.filter.AuthorRevFilter}</li>
+ * <li>Committer name/email:
+ * {@link org.eclipse.jgit.revwalk.filter.CommitterRevFilter}</li>
+ * <li>Message body:
+ * {@link org.eclipse.jgit.revwalk.filter.MessageRevFilter}</li>
  * </ul>
  *
  * <p>
@@ -88,9 +92,9 @@
  * <p>
  * <b>Boolean modifiers:</b>
  * <ul>
- * <li>AND: {@link AndRevFilter}</li>
- * <li>OR: {@link OrRevFilter}</li>
- * <li>NOT: {@link NotRevFilter}</li>
+ * <li>AND: {@link org.eclipse.jgit.revwalk.filter.AndRevFilter}</li>
+ * <li>OR: {@link org.eclipse.jgit.revwalk.filter.OrRevFilter}</li>
+ * <li>NOT: {@link org.eclipse.jgit.revwalk.filter.NotRevFilter}</li>
  * </ul>
  */
 public abstract class RevFilter {
@@ -99,7 +103,7 @@ public abstract class RevFilter {
 
 	private static final class AllFilter extends RevFilter {
 		@Override
-		public boolean include(final RevWalk walker, final RevCommit c) {
+		public boolean include(RevWalk walker, RevCommit c) {
 			return true;
 		}
 
@@ -124,7 +128,7 @@ public String toString() {
 
 	private static final class NoneFilter extends RevFilter {
 		@Override
-		public boolean include(final RevWalk walker, final RevCommit c) {
+		public boolean include(RevWalk walker, RevCommit c) {
 			return false;
 		}
 
@@ -180,7 +184,7 @@ public String toString() {
 
 	private static final class NoMergesFilter extends RevFilter {
 		@Override
-		public boolean include(final RevWalk walker, final RevCommit c) {
+		public boolean include(RevWalk walker, RevCommit c) {
 			return c.getParentCount() < 2;
 		}
 
@@ -212,7 +216,7 @@ public String toString() {
 
 	private static final class MergeBaseFilter extends RevFilter {
 		@Override
-		public boolean include(final RevWalk walker, final RevCommit c) {
+		public boolean include(RevWalk walker, RevCommit c) {
 			throw new UnsupportedOperationException(JGitText.get().cannotBeCombined);
 		}
 
@@ -241,7 +245,11 @@ public RevFilter negate() {
 		return NotRevFilter.create(this);
 	}
 
-	/** @return true if the filter needs the commit body to be parsed. */
+	/**
+	 * Whether the filter needs the commit body to be parsed.
+	 *
+	 * @return true if the filter needs the commit body to be parsed.
+	 */
 	public boolean requiresCommitBody() {
 		// Assume true to be backward compatible with prior behavior.
 		return true;
@@ -258,19 +266,19 @@ public boolean requiresCommitBody() {
 	 *            returns true from {@link #requiresCommitBody()}.
 	 * @return true to include this commit in the results; false to have this
 	 *         commit be omitted entirely from the results.
-	 * @throws StopWalkException
+	 * @throws org.eclipse.jgit.errors.StopWalkException
 	 *             the filter knows for certain that no additional commits can
 	 *             ever match, and the current commit doesn't match either. The
 	 *             walk is halted and no more results are provided.
-	 * @throws MissingObjectException
+	 * @throws org.eclipse.jgit.errors.MissingObjectException
 	 *             an object the filter needs to consult to determine its answer
 	 *             does not exist in the Git repository the walker is operating
 	 *             on. Filtering this commit is impossible without the object.
-	 * @throws IncorrectObjectTypeException
+	 * @throws org.eclipse.jgit.errors.IncorrectObjectTypeException
 	 *             an object the filter needed to consult was not of the
 	 *             expected object type. This usually indicates a corrupt
 	 *             repository, as an object link is referencing the wrong type.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             a loose object or pack file could not be read to obtain data
 	 *             necessary for the filter to make its decision.
 	 */
@@ -279,16 +287,17 @@ public abstract boolean include(RevWalk walker, RevCommit cmit)
 			IncorrectObjectTypeException, IOException;
 
 	/**
+	 * {@inheritDoc}
+	 * <p>
 	 * Clone this revision filter, including its parameters.
 	 * <p>
 	 * This is a deep clone. If this filter embeds objects or other filters it
 	 * must also clone those, to ensure the instances do not share mutable data.
-	 *
-	 * @return another copy of this filter, suitable for another thread.
 	 */
 	@Override
 	public abstract RevFilter clone();
 
+	/** {@inheritDoc} */
 	@Override
 	public String toString() {
 		String n = getClass().getName();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/filter/RevFlagFilter.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/filter/RevFlagFilter.java
index 1fbf746..c67c44b 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/filter/RevFlagFilter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/filter/RevFlagFilter.java
@@ -52,7 +52,9 @@
 import org.eclipse.jgit.revwalk.RevFlagSet;
 import org.eclipse.jgit.revwalk.RevWalk;
 
-/** Matches only commits with some/all RevFlags already set. */
+/**
+ * Matches only commits with some/all RevFlags already set.
+ */
 public abstract class RevFlagFilter extends RevFilter {
 	/**
 	 * Create a new filter that tests for a single flag.
@@ -61,7 +63,7 @@ public abstract class RevFlagFilter extends RevFilter {
 	 *            the flag to test.
 	 * @return filter that selects only commits with flag <code>a</code>.
 	 */
-	public static RevFilter has(final RevFlag a) {
+	public static RevFilter has(RevFlag a) {
 		final RevFlagSet s = new RevFlagSet();
 		s.add(a);
 		return new HasAll(s);
@@ -74,9 +76,9 @@ public static RevFilter has(final RevFlag a) {
 	 *            set of flags to test.
 	 * @return filter that selects only commits with all flags in <code>a</code>.
 	 */
-	public static RevFilter hasAll(final RevFlag... a) {
+	public static RevFilter hasAll(RevFlag... a) {
 		final RevFlagSet set = new RevFlagSet();
-		for (final RevFlag flag : a)
+		for (RevFlag flag : a)
 			set.add(flag);
 		return new HasAll(set);
 	}
@@ -88,7 +90,7 @@ public static RevFilter hasAll(final RevFlag... a) {
 	 *            set of flags to test.
 	 * @return filter that selects only commits with all flags in <code>a</code>.
 	 */
-	public static RevFilter hasAll(final RevFlagSet a) {
+	public static RevFilter hasAll(RevFlagSet a) {
 		return new HasAll(new RevFlagSet(a));
 	}
 
@@ -99,9 +101,9 @@ public static RevFilter hasAll(final RevFlagSet a) {
 	 *            set of flags to test.
 	 * @return filter that selects only commits with any flag in <code>a</code>.
 	 */
-	public static RevFilter hasAny(final RevFlag... a) {
+	public static RevFilter hasAny(RevFlag... a) {
 		final RevFlagSet set = new RevFlagSet();
-		for (final RevFlag flag : a)
+		for (RevFlag flag : a)
 			set.add(flag);
 		return new HasAny(set);
 	}
@@ -113,33 +115,35 @@ public static RevFilter hasAny(final RevFlag... a) {
 	 *            set of flags to test.
 	 * @return filter that selects only commits with any flag in <code>a</code>.
 	 */
-	public static RevFilter hasAny(final RevFlagSet a) {
+	public static RevFilter hasAny(RevFlagSet a) {
 		return new HasAny(new RevFlagSet(a));
 	}
 
 	final RevFlagSet flags;
 
-	RevFlagFilter(final RevFlagSet m) {
+	RevFlagFilter(RevFlagSet m) {
 		flags = m;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public RevFilter clone() {
 		return this;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public String toString() {
 		return super.toString() + flags;
 	}
 
 	private static class HasAll extends RevFlagFilter {
-		HasAll(final RevFlagSet m) {
+		HasAll(RevFlagSet m) {
 			super(m);
 		}
 
 		@Override
-		public boolean include(final RevWalk walker, final RevCommit c)
+		public boolean include(RevWalk walker, RevCommit c)
 				throws MissingObjectException, IncorrectObjectTypeException,
 				IOException {
 			return c.hasAll(flags);
@@ -152,12 +156,12 @@ public boolean requiresCommitBody() {
 	}
 
 	private static class HasAny extends RevFlagFilter {
-		HasAny(final RevFlagSet m) {
+		HasAny(RevFlagSet m) {
 			super(m);
 		}
 
 		@Override
-		public boolean include(final RevWalk walker, final RevCommit c)
+		public boolean include(RevWalk walker, RevCommit c)
 				throws MissingObjectException, IncorrectObjectTypeException,
 				IOException {
 			return c.hasAny(flags);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/filter/SkipRevFilter.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/filter/SkipRevFilter.java
index 51dd2ed..79af5a3 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/filter/SkipRevFilter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/filter/SkipRevFilter.java
@@ -78,6 +78,7 @@ private SkipRevFilter(int skip) {
 		this.skip = skip;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public boolean include(RevWalk walker, RevCommit cmit)
 			throws StopWalkException, MissingObjectException,
@@ -87,6 +88,7 @@ public boolean include(RevWalk walker, RevCommit cmit)
 		return true;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public RevFilter clone() {
 		return new SkipRevFilter(skip);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/filter/SubStringRevFilter.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/filter/SubStringRevFilter.java
index ce3a022..54650da 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/filter/SubStringRevFilter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/filter/SubStringRevFilter.java
@@ -52,7 +52,9 @@
 import org.eclipse.jgit.util.RawCharSequence;
 import org.eclipse.jgit.util.RawSubStringPattern;
 
-/** Abstract filter that searches text using only substring search. */
+/**
+ * Abstract filter that searches text using only substring search.
+ */
 public abstract class SubStringRevFilter extends RevFilter {
 	/**
 	 * Can this string be safely handled by a substring filter?
@@ -60,9 +62,10 @@ public abstract class SubStringRevFilter extends RevFilter {
 	 * @param pattern
 	 *            the pattern text proposed by the user.
 	 * @return true if a substring filter can perform this pattern match; false
-	 *         if {@link PatternMatchRevFilter} must be used instead.
+	 *         if {@link org.eclipse.jgit.revwalk.filter.PatternMatchRevFilter}
+	 *         must be used instead.
 	 */
-	public static boolean safe(final String pattern) {
+	public static boolean safe(String pattern) {
 		for (int i = 0; i < pattern.length(); i++) {
 			final char c = pattern.charAt(i);
 			switch (c) {
@@ -93,17 +96,19 @@ public static boolean safe(final String pattern) {
 	 *            the {@link #safe(String)} as regular expression meta
 	 *            characters are treated as literals.
 	 */
-	protected SubStringRevFilter(final String patternText) {
+	protected SubStringRevFilter(String patternText) {
 		pattern = new RawSubStringPattern(patternText);
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	public boolean include(final RevWalk walker, final RevCommit cmit)
+	public boolean include(RevWalk walker, RevCommit cmit)
 			throws MissingObjectException, IncorrectObjectTypeException,
 			IOException {
 		return pattern.match(text(cmit)) >= 0;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public boolean requiresCommitBody() {
 		return true;
@@ -118,11 +123,13 @@ public boolean requiresCommitBody() {
 	 */
 	protected abstract RawCharSequence text(RevCommit cmit);
 
+	/** {@inheritDoc} */
 	@Override
 	public RevFilter clone() {
 		return this; // Typically we are actually thread-safe.
 	}
 
+	/** {@inheritDoc} */
 	@SuppressWarnings("nls")
 	@Override
 	public String toString() {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/storage/file/FileBasedConfig.java b/org.eclipse.jgit/src/org/eclipse/jgit/storage/file/FileBasedConfig.java
index b268979..4b272ba 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/storage/file/FileBasedConfig.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/storage/file/FileBasedConfig.java
@@ -49,12 +49,15 @@
 
 package org.eclipse.jgit.storage.file;
 
+import static org.eclipse.jgit.lib.Constants.CHARSET;
+
 import java.io.ByteArrayOutputStream;
 import java.io.File;
 import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.text.MessageFormat;
 
+import org.eclipse.jgit.annotations.Nullable;
 import org.eclipse.jgit.errors.ConfigInvalidException;
 import org.eclipse.jgit.errors.LockFailedException;
 import org.eclipse.jgit.internal.JGitText;
@@ -80,6 +83,8 @@ public class FileBasedConfig extends StoredConfig {
 
 	private final File configFile;
 
+	private final FS fs;
+
 	private boolean utf8Bom;
 
 	private volatile FileSnapshot snapshot;
@@ -113,31 +118,34 @@ public FileBasedConfig(File cfgLocation, FS fs) {
 	public FileBasedConfig(Config base, File cfgLocation, FS fs) {
 		super(base);
 		configFile = cfgLocation;
+		this.fs = fs;
 		this.snapshot = FileSnapshot.DIRTY;
 		this.hash = ObjectId.zeroId();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected boolean notifyUponTransientChanges() {
 		// we will notify listeners upon save()
 		return false;
 	}
 
-	/** @return location of the configuration file on disk */
+	/**
+	 * Get location of the configuration file on disk
+	 *
+	 * @return location of the configuration file on disk
+	 */
 	public final File getFile() {
 		return configFile;
 	}
 
 	/**
+	 * {@inheritDoc}
+	 * <p>
 	 * Load the configuration as a Git text style configuration file.
 	 * <p>
 	 * If the file does not exist, this configuration is cleared, and thus
 	 * behaves the same as though the file exists, but is empty.
-	 *
-	 * @throws IOException
-	 *             the file could not be read (but does exist).
-	 * @throws ConfigInvalidException
-	 *             the file is not a properly formatted configuration file.
 	 */
 	@Override
 	public void load() throws IOException, ConfigInvalidException {
@@ -158,8 +166,8 @@ public void load() throws IOException, ConfigInvalidException {
 				} else {
 					final String decoded;
 					if (isUtf8(in)) {
-						decoded = RawParseUtils.decode(
-								RawParseUtils.UTF8_CHARSET, in, 3, in.length);
+						decoded = RawParseUtils.decode(CHARSET,
+								in, 3, in.length);
 						utf8Bom = true;
 					} else {
 						decoded = RawParseUtils.decode(in);
@@ -197,6 +205,8 @@ public void load() throws IOException, ConfigInvalidException {
 	}
 
 	/**
+	 * {@inheritDoc}
+	 * <p>
 	 * Save the configuration as a Git text style configuration file.
 	 * <p>
 	 * <b>Warning:</b> Although this method uses the traditional Git file
@@ -204,9 +214,6 @@ public void load() throws IOException, ConfigInvalidException {
 	 * configuration file, it does not ensure that the file has not been
 	 * modified since the last read, which means updates performed by other
 	 * objects accessing the same backing file may be lost.
-	 *
-	 * @throws IOException
-	 *             the file could not be written.
 	 */
 	@Override
 	public void save() throws IOException {
@@ -217,7 +224,7 @@ public void save() throws IOException {
 			bos.write(0xEF);
 			bos.write(0xBB);
 			bos.write(0xBF);
-			bos.write(text.getBytes(RawParseUtils.UTF8_CHARSET.name()));
+			bos.write(text.getBytes(CHARSET));
 			out = bos.toByteArray();
 		} else {
 			out = Constants.encode(text);
@@ -240,16 +247,18 @@ public void save() throws IOException {
 		fireConfigChangedEvent();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void clear() {
 		hash = hash(new byte[0]);
 		super.clear();
 	}
 
-	private static ObjectId hash(final byte[] rawText) {
+	private static ObjectId hash(byte[] rawText) {
 		return ObjectId.fromRaw(Constants.newMessageDigest().digest(rawText));
 	}
 
+	/** {@inheritDoc} */
 	@SuppressWarnings("nls")
 	@Override
 	public String toString() {
@@ -257,10 +266,40 @@ public String toString() {
 	}
 
 	/**
+	 * Whether the currently loaded configuration file is outdated
+	 *
 	 * @return returns true if the currently loaded configuration file is older
-	 * than the file on disk
+	 *         than the file on disk
 	 */
 	public boolean isOutdated() {
 		return snapshot.isModified(getFile());
 	}
+
+	/**
+	 * {@inheritDoc}
+	 *
+	 * @since 4.10
+	 */
+	@Override
+	@Nullable
+	protected byte[] readIncludedConfig(String relPath)
+			throws ConfigInvalidException {
+		final File file;
+		if (relPath.startsWith("~/")) { //$NON-NLS-1$
+			file = fs.resolve(fs.userHome(), relPath.substring(2));
+		} else {
+			file = fs.resolve(configFile.getParentFile(), relPath);
+		}
+
+		if (!file.exists()) {
+			return null;
+		}
+
+		try {
+			return IO.readFully(file);
+		} catch (IOException ioe) {
+			throw new ConfigInvalidException(MessageFormat
+					.format(JGitText.get().cannotReadFile, relPath), ioe);
+		}
+	}
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/storage/file/FileRepositoryBuilder.java b/org.eclipse.jgit/src/org/eclipse/jgit/storage/file/FileRepositoryBuilder.java
index 944fb4f..3e45bd5 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/storage/file/FileRepositoryBuilder.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/storage/file/FileRepositoryBuilder.java
@@ -52,7 +52,7 @@
 import org.eclipse.jgit.lib.Repository;
 
 /**
- * Constructs a {@link FileRepository}.
+ * Constructs a {@link org.eclipse.jgit.internal.storage.file.FileRepository}.
  * <p>
  * Applications must set one of {@link #setGitDir(File)} or
  * {@link #setWorkTree(File)}, or use {@link #readEnvironment()} or
@@ -73,18 +73,14 @@
 public class FileRepositoryBuilder extends
 		BaseRepositoryBuilder<FileRepositoryBuilder, Repository> {
 	/**
+	 * {@inheritDoc}
+	 * <p>
 	 * Create a repository matching the configuration in this builder.
 	 * <p>
 	 * If an option was not set, the build method will try to default the option
 	 * based on other options. If insufficient information is available, an
 	 * exception is thrown to the caller.
 	 *
-	 * @return a repository matching this configuration.
-	 * @throws IllegalArgumentException
-	 *             insufficient parameters were set.
-	 * @throws IOException
-	 *             the repository could not be accessed to configure the rest of
-	 *             the builder's parameters.
 	 * @since 3.0
 	 */
 	@Override
@@ -96,12 +92,13 @@ public Repository build() throws IOException {
 	}
 
 	/**
-	 * Convenience factory method to construct a {@link FileRepository}.
+	 * Convenience factory method to construct a
+	 * {@link org.eclipse.jgit.internal.storage.file.FileRepository}.
 	 *
 	 * @param gitDir
 	 *            {@code GIT_DIR}, the repository meta directory.
 	 * @return a repository matching this configuration.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the repository could not be accessed to configure the rest of
 	 *             the builder's parameters.
 	 * @since 3.0
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/storage/file/WindowCacheConfig.java b/org.eclipse.jgit/src/org/eclipse/jgit/storage/file/WindowCacheConfig.java
index 4205fc4..c2e6a42 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/storage/file/WindowCacheConfig.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/storage/file/WindowCacheConfig.java
@@ -47,7 +47,9 @@
 import org.eclipse.jgit.lib.Config;
 import org.eclipse.jgit.storage.pack.PackConfig;
 
-/** Configuration parameters for JVM-wide buffer cache used by JGit. */
+/**
+ * Configuration parameters for JVM-wide buffer cache used by JGit.
+ */
 public class WindowCacheConfig {
 	/** 1024 (number of bytes in one kibibyte/kilobyte) */
 	public static final int KB = 1024;
@@ -67,7 +69,9 @@ public class WindowCacheConfig {
 
 	private int streamFileThreshold;
 
-	/** Create a default configuration. */
+	/**
+	 * Create a default configuration.
+	 */
 	public WindowCacheConfig() {
 		packedGitOpenFiles = 128;
 		packedGitLimit = 10 * MB;
@@ -78,6 +82,8 @@ public WindowCacheConfig() {
 	}
 
 	/**
+	 * Get maximum number of streams to open at a time.
+	 *
 	 * @return maximum number of streams to open at a time. Open packs count
 	 *         against the process limits. <b>Default is 128.</b>
 	 */
@@ -86,15 +92,20 @@ public int getPackedGitOpenFiles() {
 	}
 
 	/**
+	 * Set maximum number of streams to open at a time.
+	 *
 	 * @param fdLimit
 	 *            maximum number of streams to open at a time. Open packs count
 	 *            against the process limits
 	 */
-	public void setPackedGitOpenFiles(final int fdLimit) {
+	public void setPackedGitOpenFiles(int fdLimit) {
 		packedGitOpenFiles = fdLimit;
 	}
 
 	/**
+	 * Get maximum number bytes of heap memory to dedicate to caching pack file
+	 * data.
+	 *
 	 * @return maximum number bytes of heap memory to dedicate to caching pack
 	 *         file data. <b>Default is 10 MB.</b>
 	 */
@@ -103,15 +114,21 @@ public long getPackedGitLimit() {
 	}
 
 	/**
+	 * Set maximum number bytes of heap memory to dedicate to caching pack file
+	 * data.
+	 *
 	 * @param newLimit
 	 *            maximum number bytes of heap memory to dedicate to caching
 	 *            pack file data.
 	 */
-	public void setPackedGitLimit(final long newLimit) {
+	public void setPackedGitLimit(long newLimit) {
 		packedGitLimit = newLimit;
 	}
 
 	/**
+	 * Get size in bytes of a single window mapped or read in from the pack
+	 * file.
+	 *
 	 * @return size in bytes of a single window mapped or read in from the pack
 	 *         file. <b>Default is 8 KB.</b>
 	 */
@@ -120,33 +137,42 @@ public int getPackedGitWindowSize() {
 	}
 
 	/**
+	 * Set size in bytes of a single window read in from the pack file.
+	 *
 	 * @param newSize
 	 *            size in bytes of a single window read in from the pack file.
 	 */
-	public void setPackedGitWindowSize(final int newSize) {
+	public void setPackedGitWindowSize(int newSize) {
 		packedGitWindowSize = newSize;
 	}
 
 	/**
-	 * @return true enables use of Java NIO virtual memory mapping for windows;
-	 *         false reads entire window into a byte[] with standard read calls.
-	 *         <b>Default false.</b>
+	 * Whether to use Java NIO virtual memory mapping for windows
+	 *
+	 * @return {@code true} enables use of Java NIO virtual memory mapping for
+	 *         windows; false reads entire window into a byte[] with standard
+	 *         read calls. <b>Default false.</b>
 	 */
 	public boolean isPackedGitMMAP() {
 		return packedGitMMAP;
 	}
 
 	/**
+	 * Set whether to enable use of Java NIO virtual memory mapping for windows
+	 *
 	 * @param usemmap
-	 *            true enables use of Java NIO virtual memory mapping for
-	 *            windows; false reads entire window into a byte[] with standard
-	 *            read calls.
+	 *            {@code true} enables use of Java NIO virtual memory mapping
+	 *            for windows; false reads entire window into a byte[] with
+	 *            standard read calls.
 	 */
-	public void setPackedGitMMAP(final boolean usemmap) {
+	public void setPackedGitMMAP(boolean usemmap) {
 		packedGitMMAP = usemmap;
 	}
 
 	/**
+	 * Get maximum number of bytes to cache in delta base cache for inflated,
+	 * recently accessed objects, without delta chains.
+	 *
 	 * @return maximum number of bytes to cache in delta base cache for
 	 *         inflated, recently accessed objects, without delta chains.
 	 *         <b>Default 10 MB.</b>
@@ -156,27 +182,36 @@ public int getDeltaBaseCacheLimit() {
 	}
 
 	/**
+	 * Set maximum number of bytes to cache in delta base cache for inflated,
+	 * recently accessed objects, without delta chains.
+	 *
 	 * @param newLimit
 	 *            maximum number of bytes to cache in delta base cache for
 	 *            inflated, recently accessed objects, without delta chains.
 	 */
-	public void setDeltaBaseCacheLimit(final int newLimit) {
+	public void setDeltaBaseCacheLimit(int newLimit) {
 		deltaBaseCacheLimit = newLimit;
 	}
 
-	/** @return the size threshold beyond which objects must be streamed. */
+	/**
+	 * Get the size threshold beyond which objects must be streamed.
+	 *
+	 * @return the size threshold beyond which objects must be streamed.
+	 */
 	public int getStreamFileThreshold() {
 		return streamFileThreshold;
 	}
 
 	/**
+	 * Set new byte limit for objects that must be streamed.
+	 *
 	 * @param newLimit
 	 *            new byte limit for objects that must be streamed. Objects
 	 *            smaller than this size can be obtained as a contiguous byte
 	 *            array, while objects bigger than this size require using an
 	 *            {@link org.eclipse.jgit.lib.ObjectStream}.
 	 */
-	public void setStreamFileThreshold(final int newLimit) {
+	public void setStreamFileThreshold(int newLimit) {
 		streamFileThreshold = newLimit;
 	}
 
@@ -191,7 +226,7 @@ public void setStreamFileThreshold(final int newLimit) {
 	 * @return {@code this}.
 	 * @since 3.0
 	 */
-	public WindowCacheConfig fromConfig(final Config rc) {
+	public WindowCacheConfig fromConfig(Config rc) {
 		setPackedGitOpenFiles(rc.getInt(
 				"core", null, "packedgitopenfiles", getPackedGitOpenFiles())); //$NON-NLS-1$ //$NON-NLS-2$
 		setPackedGitLimit(rc.getLong(
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/SafeBufferedOutputStream.java b/org.eclipse.jgit/src/org/eclipse/jgit/storage/file/WindowCacheStats.java
similarity index 72%
copy from org.eclipse.jgit/src/org/eclipse/jgit/util/io/SafeBufferedOutputStream.java
copy to org.eclipse.jgit/src/org/eclipse/jgit/storage/file/WindowCacheStats.java
index 84c3398..3570733 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/SafeBufferedOutputStream.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/storage/file/WindowCacheStats.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011, Robin Rosenberg
+ * Copyright (C) 2018, David Pursehouse <david.pursehouse@gmail.com>
  * and other copyright owners as documented in the project's IP log.
  *
  * This program and the accompanying materials are made available
@@ -40,33 +40,29 @@
  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
-package org.eclipse.jgit.util.io;
 
-import java.io.BufferedOutputStream;
-import java.io.OutputStream;
+package org.eclipse.jgit.storage.file;
+
+import org.eclipse.jgit.internal.storage.file.WindowCache;
 
 /**
- * @deprecated use BufferedOutputStream in Java 8 and later.
+ * Accessor for stats about {@link WindowCache}.
+ *
+ * @since 4.11
+ *
  */
-@Deprecated
-public class SafeBufferedOutputStream extends BufferedOutputStream {
+public class WindowCacheStats {
 	/**
-	 * @see BufferedOutputStream#BufferedOutputStream(OutputStream)
-	 * @param out
-	 *            underlying output stream
+	 * @return the number of open files.
 	 */
-	public SafeBufferedOutputStream(OutputStream out) {
-		super(out);
+	public static int getOpenFiles() {
+		return WindowCache.getInstance().getOpenFiles();
 	}
 
 	/**
-	 * @see BufferedOutputStream#BufferedOutputStream(OutputStream, int)
-	 * @param out
-	 *            underlying output stream
-	 * @param size
-	 *            buffer size
+	 * @return the number of open bytes.
 	 */
-	public SafeBufferedOutputStream(OutputStream out, int size) {
-		super(out, size);
+	public static long getOpenBytes() {
+		return WindowCache.getInstance().getOpenBytes();
 	}
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/storage/pack/PackConfig.java b/org.eclipse.jgit/src/org/eclipse/jgit/storage/pack/PackConfig.java
index 4f2374f..256e41d 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/storage/pack/PackConfig.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/storage/pack/PackConfig.java
@@ -262,7 +262,9 @@ public class PackConfig {
 
 	private boolean singlePack;
 
-	/** Create a default configuration. */
+	/**
+	 * Create a default configuration.
+	 */
 	public PackConfig() {
 		// Fields are initialized to defaults.
 	}
@@ -280,7 +282,8 @@ public PackConfig(Repository db) {
 	}
 
 	/**
-	 * Create a configuration honoring settings in a {@link Config}.
+	 * Create a configuration honoring settings in a
+	 * {@link org.eclipse.jgit.lib.Config}.
 	 *
 	 * @param cfg
 	 *            the source to read settings from. The source is not retained
@@ -531,6 +534,9 @@ public void setMaxDeltaDepth(int maxDeltaDepth) {
 	}
 
 	/**
+	 * Whether existing delta chains should be cut at
+	 * {@link #getMaxDeltaDepth()}.
+	 *
 	 * @return true if existing delta chains should be cut at
 	 *         {@link #getMaxDeltaDepth()}. Default is false, allowing existing
 	 *         chains to be of any length.
@@ -558,9 +564,11 @@ public void setCutDeltaChains(boolean cut) {
 	}
 
 	/**
+	 * Whether all of refs/* should be packed in a single pack.
+	 *
 	 * @return true if all of refs/* should be packed in a single pack. Default
-	 *        is false, packing a separate GC_REST pack for references outside
-	 *        of refs/heads/* and refs/tags/*.
+	 *         is false, packing a separate GC_REST pack for references outside
+	 *         of refs/heads/* and refs/tags/*.
 	 * @since 4.9
 	 */
 	public boolean getSinglePack() {
@@ -785,7 +793,11 @@ public void setThreads(int threads) {
 		this.threads = threads;
 	}
 
-	/** @return the preferred thread pool to execute delta search on. */
+	/**
+	 * Get the preferred thread pool to execute delta search on.
+	 *
+	 * @return the preferred thread pool to execute delta search on.
+	 */
 	public Executor getExecutor() {
 		return executor;
 	}
@@ -1027,7 +1039,7 @@ public void setBitmapInactiveBranchAgeInDays(int ageInDays) {
 	 * @param rc
 	 *            configuration to read properties from.
 	 */
-	public void fromConfig(final Config rc) {
+	public void fromConfig(Config rc) {
 		setMaxDeltaDepth(rc.getInt("pack", "depth", getMaxDeltaDepth())); //$NON-NLS-1$ //$NON-NLS-2$
 		setDeltaSearchWindowSize(rc.getInt(
 				"pack", "window", getDeltaSearchWindowSize())); //$NON-NLS-1$ //$NON-NLS-2$
@@ -1073,6 +1085,7 @@ public void fromConfig(final Config rc) {
 						getBitmapInactiveBranchAgeInDays()));
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public String toString() {
 		final StringBuilder b = new StringBuilder();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/storage/pack/PackStatistics.java b/org.eclipse.jgit/src/org/eclipse/jgit/storage/pack/PackStatistics.java
index a811fe3..68878e5 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/storage/pack/PackStatistics.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/storage/pack/PackStatistics.java
@@ -166,6 +166,36 @@ public long getDeltaBytes() {
 	 * POJO for accumulating the statistics.
 	 */
 	public static class Accumulator {
+		/**
+		 * The count of references in the ref advertisement.
+		 *
+		 * @since 4.11
+		 */
+		public long advertised;
+
+		/**
+		 * The count of client wants.
+		 *
+		 * @since 4.11
+		 */
+		public long wants;
+
+		/**
+		 * The count of client haves.
+		 *
+		 * @since 4.11
+		 */
+		public long haves;
+
+		/**
+		 * Time in ms spent in the negotiation phase. For non-bidirectional
+		 * transports (e.g., HTTP), this is only for the final request that
+		 * sends back the pack file.
+		 *
+		 * @since 4.11
+		 */
+		public long timeNegotiating;
+
 		/** The set of objects to be included in the pack. */
 		public Set<ObjectId> interestingObjects;
 
@@ -254,7 +284,8 @@ public static class Accumulator {
 	private Accumulator statistics;
 
 	/**
-	 * Creates a new {@link PackStatistics} object from the accumulator.
+	 * Creates a new {@link org.eclipse.jgit.storage.pack.PackStatistics} object
+	 * from the accumulator.
 	 *
 	 * @param accumulator
 	 *            the accumulator of the statistics
@@ -270,6 +301,50 @@ public PackStatistics(Accumulator accumulator) {
 	}
 
 	/**
+	 * Get the count of references in the ref advertisement.
+	 *
+	 * @return count of refs in the ref advertisement.
+	 * @since 4.11
+	 */
+	public long getAdvertised() {
+		return statistics.advertised;
+	}
+
+	/**
+	 * Get the count of client wants.
+	 *
+	 * @return count of client wants.
+	 * @since 4.11
+	 */
+	public long getWants() {
+		return statistics.wants;
+	}
+
+	/**
+	 * Get the count of client haves.
+	 *
+	 * @return count of client haves.
+	 * @since 4.11
+	 */
+	public long getHaves() {
+		return statistics.haves;
+	}
+
+	/**
+	 * Time in ms spent in the negotiation phase. For non-bidirectional
+	 * transports (e.g., HTTP), this is only for the final request that sends
+	 * back the pack file.
+	 *
+	 * @return time for ref advertisement in ms.
+	 * @since 4.11
+	 */
+	public long getTimeNegotiating() {
+		return statistics.timeNegotiating;
+	}
+
+	/**
+	 * Get unmodifiable collection of objects to be included in the pack.
+	 *
 	 * @return unmodifiable collection of objects to be included in the pack.
 	 *         May be {@code null} if the pack was hand-crafted in a unit test.
 	 */
@@ -278,6 +353,9 @@ public Set<ObjectId> getInterestingObjects() {
 	}
 
 	/**
+	 * Get unmodifiable collection of objects that should be excluded from the
+	 * pack
+	 *
 	 * @return unmodifiable collection of objects that should be excluded from
 	 *         the pack, as the peer that will receive the pack already has
 	 *         these objects.
@@ -287,6 +365,9 @@ public Set<ObjectId> getUninterestingObjects() {
 	}
 
 	/**
+	 * Get unmodifiable collection of objects that were shallow commits on the
+	 * client.
+	 *
 	 * @return unmodifiable collection of objects that were shallow commits on
 	 *         the client.
 	 */
@@ -295,6 +376,8 @@ public Set<ObjectId> getClientShallowCommits() {
 	}
 
 	/**
+	 * Get unmodifiable list of the cached packs that were reused in the output
+	 *
 	 * @return unmodifiable list of the cached packs that were reused in the
 	 *         output, if any were selected for reuse.
 	 */
@@ -302,12 +385,19 @@ public List<CachedPack> getReusedPacks() {
 		return statistics.reusedPacks;
 	}
 
-	/** @return unmodifiable collection of the root commits of the history. */
+	/**
+	 * Get unmodifiable collection of the root commits of the history.
+	 *
+	 * @return unmodifiable collection of the root commits of the history.
+	 */
 	public Set<ObjectId> getRootCommits() {
 		return statistics.rootCommits;
 	}
 
 	/**
+	 * Get number of objects in the output pack that went through the delta
+	 * search process in order to find a potential delta base.
+	 *
 	 * @return number of objects in the output pack that went through the delta
 	 *         search process in order to find a potential delta base.
 	 */
@@ -316,6 +406,9 @@ public int getDeltaSearchNonEdgeObjects() {
 	}
 
 	/**
+	 * Get number of objects in the output pack that went through delta base
+	 * search and found a suitable base.
+	 *
 	 * @return number of objects in the output pack that went through delta base
 	 *         search and found a suitable base. This is a subset of
 	 *         {@link #getDeltaSearchNonEdgeObjects()}.
@@ -325,6 +418,8 @@ public int getDeltasFound() {
 	}
 
 	/**
+	 * Get total number of objects output.
+	 *
 	 * @return total number of objects output. This total includes the value of
 	 *         {@link #getTotalDeltas()}.
 	 */
@@ -333,6 +428,9 @@ public long getTotalObjects() {
 	}
 
 	/**
+	 * Get the count of objects that needed to be discovered through an object
+	 * walk because they were not found in bitmap indices.
+	 *
 	 * @return the count of objects that needed to be discovered through an
 	 *         object walk because they were not found in bitmap indices.
 	 *         Returns -1 if no bitmap indices were found.
@@ -342,6 +440,8 @@ public long getBitmapIndexMisses() {
 	}
 
 	/**
+	 * Get total number of deltas output.
+	 *
 	 * @return total number of deltas output. This may be lower than the actual
 	 *         number of deltas if a cached pack was reused.
 	 */
@@ -350,6 +450,9 @@ public long getTotalDeltas() {
 	}
 
 	/**
+	 * Get number of objects whose existing representation was reused in the
+	 * output.
+	 *
 	 * @return number of objects whose existing representation was reused in the
 	 *         output. This count includes {@link #getReusedDeltas()}.
 	 */
@@ -358,6 +461,9 @@ public long getReusedObjects() {
 	}
 
 	/**
+	 * Get number of deltas whose existing representation was reused in the
+	 * output.
+	 *
 	 * @return number of deltas whose existing representation was reused in the
 	 *         output, as their base object was also output or was assumed
 	 *         present for a thin pack. This may be lower than the actual number
@@ -368,6 +474,8 @@ public long getReusedDeltas() {
 	}
 
 	/**
+	 * Get total number of bytes written.
+	 *
 	 * @return total number of bytes written. This size includes the pack
 	 *         header, trailer, thin pack, and reused cached pack(s).
 	 */
@@ -376,6 +484,8 @@ public long getTotalBytes() {
 	}
 
 	/**
+	 * Get size of the thin pack in bytes.
+	 *
 	 * @return size of the thin pack in bytes, if a thin pack was generated. A
 	 *         thin pack is created when the client already has objects and some
 	 *         deltas are created against those objects, or if a cached pack is
@@ -387,6 +497,8 @@ public long getThinPackBytes() {
 	}
 
 	/**
+	 * Get information about this type of object in the pack.
+	 *
 	 * @param typeCode
 	 *            object type code, e.g. OBJ_COMMIT or OBJ_TREE.
 	 * @return information about this type of object in the pack.
@@ -395,17 +507,28 @@ public ObjectType byObjectType(int typeCode) {
 		return new ObjectType(statistics.objectTypes[typeCode]);
 	}
 
-	/** @return true if the resulting pack file was a shallow pack. */
+	/**
+	 * Whether the resulting pack file was a shallow pack.
+	 *
+	 * @return {@code true} if the resulting pack file was a shallow pack.
+	 */
 	public boolean isShallow() {
 		return statistics.depth > 0;
 	}
 
-	/** @return depth (in commits) the pack includes if shallow. */
+	/**
+	 * Get depth (in commits) the pack includes if shallow.
+	 *
+	 * @return depth (in commits) the pack includes if shallow.
+	 */
 	public int getDepth() {
 		return statistics.depth;
 	}
 
 	/**
+	 * Get time in milliseconds spent enumerating the objects that need to be
+	 * included in the output.
+	 *
 	 * @return time in milliseconds spent enumerating the objects that need to
 	 *         be included in the output. This time includes any restarts that
 	 *         occur when a cached pack is selected for reuse.
@@ -415,6 +538,9 @@ public long getTimeCounting() {
 	}
 
 	/**
+	 * Get time in milliseconds spent matching existing representations against
+	 * objects that will be transmitted.
+	 *
 	 * @return time in milliseconds spent matching existing representations
 	 *         against objects that will be transmitted, or that the client can
 	 *         be assumed to already have.
@@ -424,6 +550,9 @@ public long getTimeSearchingForReuse() {
 	}
 
 	/**
+	 * Get time in milliseconds spent finding the sizes of all objects that will
+	 * enter the delta compression search window.
+	 *
 	 * @return time in milliseconds spent finding the sizes of all objects that
 	 *         will enter the delta compression search window. The sizes need to
 	 *         be known to better match similar objects together and improve
@@ -434,6 +563,8 @@ public long getTimeSearchingForSizes() {
 	}
 
 	/**
+	 * Get time in milliseconds spent on delta compression.
+	 *
 	 * @return time in milliseconds spent on delta compression. This is observed
 	 *         wall-clock time and does not accurately track CPU time used when
 	 *         multiple threads were used to perform the delta compression.
@@ -443,6 +574,9 @@ public long getTimeCompressing() {
 	}
 
 	/**
+	 * Get time in milliseconds spent writing the pack output, from start of
+	 * header until end of trailer.
+	 *
 	 * @return time in milliseconds spent writing the pack output, from start of
 	 *         header until end of trailer. The transfer speed can be
 	 *         approximated by dividing {@link #getTotalBytes()} by this value.
@@ -451,7 +585,11 @@ public long getTimeWriting() {
 		return statistics.timeWriting;
 	}
 
-	/** @return total time spent processing this pack. */
+	/**
+	 * Get total time spent processing this pack.
+	 *
+	 * @return total time spent processing this pack.
+	 */
 	public long getTimeTotal() {
 		return statistics.timeCounting + statistics.timeSearchingForReuse
 				+ statistics.timeSearchingForSizes + statistics.timeCompressing
@@ -459,14 +597,20 @@ public long getTimeTotal() {
 	}
 
 	/**
-	 * @return get the average output speed in terms of bytes-per-second.
+	 * Get the average output speed in terms of bytes-per-second.
+	 *
+	 * @return the average output speed in terms of bytes-per-second.
 	 *         {@code getTotalBytes() / (getTimeWriting() / 1000.0)}.
 	 */
 	public double getTransferRate() {
 		return getTotalBytes() / (getTimeWriting() / 1000.0);
 	}
 
-	/** @return formatted message string for display to clients. */
+	/**
+	 * Get formatted message string for display to clients.
+	 *
+	 * @return formatted message string for display to clients.
+	 */
 	public String getMessage() {
 		return MessageFormat.format(JGitText.get().packWriterStatistics,
 				Long.valueOf(statistics.totalObjects),
@@ -475,7 +619,11 @@ public String getMessage() {
 				Long.valueOf(statistics.reusedDeltas));
 	}
 
-	/** @return a map containing ObjectType statistics. */
+	/**
+	 * Get a map containing ObjectType statistics.
+	 *
+	 * @return a map containing ObjectType statistics.
+	 */
 	public Map<Integer, ObjectType> getObjectTypes() {
 		HashMap<Integer, ObjectType> map = new HashMap<>();
 		map.put(Integer.valueOf(OBJ_BLOB), new ObjectType(
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/SafeBufferedOutputStream.java b/org.eclipse.jgit/src/org/eclipse/jgit/submodule/SubmoduleConflict.java
similarity index 69%
copy from org.eclipse.jgit/src/org/eclipse/jgit/util/io/SafeBufferedOutputStream.java
copy to org.eclipse.jgit/src/org/eclipse/jgit/submodule/SubmoduleConflict.java
index 84c3398..856eb72 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/SafeBufferedOutputStream.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/submodule/SubmoduleConflict.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011, Robin Rosenberg
+ * Copyright (C) 2017, Two Sigma Open Source
  * and other copyright owners as documented in the project's IP log.
  *
  * This program and the accompanying materials are made available
@@ -20,7 +20,7 @@
  *   copyright notice, this list of conditions and the following
  *   disclaimer in the documentation and/or other materials provided
  *   with the distribution.
- *
+*
  * - Neither the name of the Eclipse Foundation, Inc. nor the
  *   names of its contributors may be used to endorse or promote
  *   products derived from this software without specific prior
@@ -40,33 +40,38 @@
  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
-package org.eclipse.jgit.util.io;
+package org.eclipse.jgit.submodule;
 
-import java.io.BufferedOutputStream;
-import java.io.OutputStream;
+import org.eclipse.jgit.diff.Sequence;
+import org.eclipse.jgit.lib.ObjectId;
 
 /**
- * @deprecated use BufferedOutputStream in Java 8 and later.
+ * Merges expect that conflicts will consist of Sequences, but that doesn't
+ * really make sense for submodules. So this represents a submodule conflict.
+ *
+ * @since 4.11
  */
-@Deprecated
-public class SafeBufferedOutputStream extends BufferedOutputStream {
-	/**
-	 * @see BufferedOutputStream#BufferedOutputStream(OutputStream)
-	 * @param out
-	 *            underlying output stream
-	 */
-	public SafeBufferedOutputStream(OutputStream out) {
-		super(out);
-	}
+public class SubmoduleConflict extends Sequence {
+    private final ObjectId objectId;
 
-	/**
-	 * @see BufferedOutputStream#BufferedOutputStream(OutputStream, int)
-	 * @param out
-	 *            underlying output stream
-	 * @param size
-	 *            buffer size
-	 */
-	public SafeBufferedOutputStream(OutputStream out, int size) {
-		super(out, size);
-	}
+    /**
+     * Create a SubmoduleConflict for the given submodule object id
+     * @param objectId
+     */
+    public SubmoduleConflict(ObjectId objectId) {
+        super();
+        this.objectId = objectId;
+    }
+
+    @Override
+    public int size() {
+        return 1;
+    }
+
+    /**
+     * @return the object id for the conflicting submodule
+     */
+    public ObjectId getObjectId() {
+        return objectId;
+    }
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/submodule/SubmoduleStatus.java b/org.eclipse.jgit/src/org/eclipse/jgit/submodule/SubmoduleStatus.java
index 2298f4b..884f2ac 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/submodule/SubmoduleStatus.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/submodule/SubmoduleStatus.java
@@ -61,8 +61,12 @@ public class SubmoduleStatus {
 	 * Create submodule status
 	 *
 	 * @param type
+	 *            a {@link org.eclipse.jgit.submodule.SubmoduleStatusType}
+	 *            object.
 	 * @param path
+	 *            submodule path
 	 * @param indexId
+	 *            an {@link org.eclipse.jgit.lib.ObjectId} object.
 	 */
 	public SubmoduleStatus(final SubmoduleStatusType type, final String path,
 			final ObjectId indexId) {
@@ -73,9 +77,14 @@ public SubmoduleStatus(final SubmoduleStatusType type, final String path,
 	 * Create submodule status
 	 *
 	 * @param type
+	 *            a {@link org.eclipse.jgit.submodule.SubmoduleStatusType}
+	 *            object.
 	 * @param path
+	 *            submodule path
 	 * @param indexId
+	 *            index id
 	 * @param headId
+	 *            head id
 	 */
 	public SubmoduleStatus(final SubmoduleStatusType type, final String path,
 			final ObjectId indexId, final ObjectId headId) {
@@ -86,6 +95,8 @@ public SubmoduleStatus(final SubmoduleStatusType type, final String path,
 	}
 
 	/**
+	 * Get type
+	 *
 	 * @return type
 	 */
 	public SubmoduleStatusType getType() {
@@ -93,13 +104,17 @@ public SubmoduleStatusType getType() {
 	}
 
 	/**
-	 * @return path
+	 * Get submodule path
+	 *
+	 * @return path submodule path
 	 */
 	public String getPath() {
 		return path;
 	}
 
 	/**
+	 * Get index object id
+	 *
 	 * @return index object id
 	 */
 	public ObjectId getIndexId() {
@@ -107,6 +122,8 @@ public ObjectId getIndexId() {
 	}
 
 	/**
+	 * Get HEAD object id
+	 *
 	 * @return HEAD object id
 	 */
 	public ObjectId getHeadId() {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/submodule/SubmoduleWalk.java b/org.eclipse.jgit/src/org/eclipse/jgit/submodule/SubmoduleWalk.java
index 56784f7..ce8995a 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/submodule/SubmoduleWalk.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/submodule/SubmoduleWalk.java
@@ -81,7 +81,7 @@
 public class SubmoduleWalk implements AutoCloseable {
 
 	/**
-	 * The values for the config param submodule.<name>.ignore
+	 * The values for the config parameter submodule.&lt;name&gt;.ignore
 	 *
 	 * @since 3.6
 	 */
@@ -114,11 +114,14 @@ public enum IgnoreSubmoduleMode {
 	 * The {@code .gitmodules} file is read from the index.
 	 *
 	 * @param repository
-	 * @return generator over submodule index entries
-	 * @throws IOException
+	 *            a {@link org.eclipse.jgit.lib.Repository} object.
+	 * @return generator over submodule index entries. The caller is responsible
+	 *         for calling {@link #close()}.
+	 * @throws java.io.IOException
 	 */
 	public static SubmoduleWalk forIndex(Repository repository)
 			throws IOException {
+		@SuppressWarnings("resource") // The caller closes it
 		SubmoduleWalk generator = new SubmoduleWalk(repository);
 		try {
 			DirCache index = repository.readDirCache();
@@ -135,12 +138,14 @@ public static SubmoduleWalk forIndex(Repository repository)
 	 * path
 	 *
 	 * @param repository
+	 *            a {@link org.eclipse.jgit.lib.Repository} object.
 	 * @param treeId
-	 *            the root of a tree containing both a submodule at the given path
-	 *            and .gitmodules at the root.
+	 *            the root of a tree containing both a submodule at the given
+	 *            path and .gitmodules at the root.
 	 * @param path
+	 *            a {@link java.lang.String} object.
 	 * @return generator at given path, null if no submodule at given path
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 */
 	public static SubmoduleWalk forPath(Repository repository,
 			AnyObjectId treeId, String path) throws IOException {
@@ -166,12 +171,14 @@ public static SubmoduleWalk forPath(Repository repository,
 	 * path
 	 *
 	 * @param repository
+	 *            a {@link org.eclipse.jgit.lib.Repository} object.
 	 * @param iterator
-	 *            the root of a tree containing both a submodule at the given path
-	 *            and .gitmodules at the root.
+	 *            the root of a tree containing both a submodule at the given
+	 *            path and .gitmodules at the root.
 	 * @param path
+	 *            a {@link java.lang.String} object.
 	 * @return generator at given path, null if no submodule at given path
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 */
 	public static SubmoduleWalk forPath(Repository repository,
 			AbstractTreeIterator iterator, String path) throws IOException {
@@ -196,7 +203,9 @@ public static SubmoduleWalk forPath(Repository repository,
 	 * Get submodule directory
 	 *
 	 * @param parent
+	 *            the {@link org.eclipse.jgit.lib.Repository}.
 	 * @param path
+	 *            submodule path
 	 * @return directory
 	 */
 	public static File getSubmoduleDirectory(final Repository parent,
@@ -208,25 +217,47 @@ public static File getSubmoduleDirectory(final Repository parent,
 	 * Get submodule repository
 	 *
 	 * @param parent
+	 *            the {@link org.eclipse.jgit.lib.Repository}.
 	 * @param path
+	 *            submodule path
 	 * @return repository or null if repository doesn't exist
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 */
 	public static Repository getSubmoduleRepository(final Repository parent,
 			final String path) throws IOException {
-		return getSubmoduleRepository(parent.getWorkTree(), path);
+		return getSubmoduleRepository(parent.getWorkTree(), path,
+				parent.getFS());
 	}
 
 	/**
 	 * Get submodule repository at path
 	 *
 	 * @param parent
+	 *            the parent
 	 * @param path
+	 *            submodule path
 	 * @return repository or null if repository doesn't exist
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 */
 	public static Repository getSubmoduleRepository(final File parent,
 			final String path) throws IOException {
+		return getSubmoduleRepository(parent, path, FS.DETECTED);
+	}
+
+	/**
+	 * Get submodule repository at path, using the specified file system
+	 * abstraction
+	 *
+	 * @param parent
+	 * @param path
+	 * @param fs
+	 *            the file system abstraction to be used
+	 * @return repository or null if repository doesn't exist
+	 * @throws IOException
+	 * @since 4.10
+	 */
+	public static Repository getSubmoduleRepository(final File parent,
+			final String path, FS fs) throws IOException {
 		File subWorkTree = new File(parent, path);
 		if (!subWorkTree.isDirectory())
 			return null;
@@ -234,7 +265,7 @@ public static Repository getSubmoduleRepository(final File parent,
 		try {
 			return new RepositoryBuilder() //
 					.setMustExist(true) //
-					.setFS(FS.DETECTED) //
+					.setFS(fs) //
 					.setWorkTree(workTree) //
 					.build();
 		} catch (RepositoryNotFoundException e) {
@@ -257,7 +288,7 @@ public static Repository getSubmoduleRepository(final File parent,
 	 * @param url
 	 *            absolute or relative URL of the submodule repository
 	 * @return resolved URL
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 */
 	public static String getSubmoduleRemoteUrl(final Repository parent,
 			final String url) throws IOException {
@@ -337,9 +368,10 @@ else if (submoduleUrl.startsWith("../")) { //$NON-NLS-1$
 	 * Create submodule generator
 	 *
 	 * @param repository
-	 * @throws IOException
+	 *            the {@link org.eclipse.jgit.lib.Repository}.
+	 * @throws java.io.IOException
 	 */
-	public SubmoduleWalk(final Repository repository) throws IOException {
+	public SubmoduleWalk(Repository repository) throws IOException {
 		this.repository = repository;
 		repoConfig = repository.getConfig();
 		walk = new TreeWalk(repository);
@@ -356,7 +388,7 @@ public SubmoduleWalk(final Repository repository) throws IOException {
 	 *            .gitmodules config object
 	 * @return this generator
 	 */
-	public SubmoduleWalk setModulesConfig(final Config config) {
+	public SubmoduleWalk setModulesConfig(Config config) {
 		modulesConfig = config;
 		loadPathNames();
 		return this;
@@ -375,7 +407,7 @@ public SubmoduleWalk setModulesConfig(final Config config) {
 	 *            tree containing .gitmodules
 	 * @return this generator
 	 */
-	public SubmoduleWalk setRootTree(final AbstractTreeIterator tree) {
+	public SubmoduleWalk setRootTree(AbstractTreeIterator tree) {
 		rootTree = tree;
 		modulesConfig = null;
 		pathToName = null;
@@ -394,9 +426,9 @@ public SubmoduleWalk setRootTree(final AbstractTreeIterator tree) {
 	 * @param id
 	 *            ID of a tree containing .gitmodules
 	 * @return this generator
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 */
-	public SubmoduleWalk setRootTree(final AnyObjectId id) throws IOException {
+	public SubmoduleWalk setRootTree(AnyObjectId id) throws IOException {
 		final CanonicalTreeParser p = new CanonicalTreeParser();
 		p.reset(walk.getObjectReader(), id);
 		rootTree = p;
@@ -414,8 +446,9 @@ public SubmoduleWalk setRootTree(final AnyObjectId id) throws IOException {
 	 * If no submodule config is found, loads an empty config.
 	 *
 	 * @return this generator
-	 * @throws IOException if an error occurred, or if the repository is bare
-	 * @throws ConfigInvalidException
+	 * @throws java.io.IOException
+	 *             if an error occurred, or if the repository is bare
+	 * @throws org.eclipse.jgit.errors.ConfigInvalidException
 	 */
 	public SubmoduleWalk loadModulesConfig() throws IOException, ConfigInvalidException {
 		if (rootTree == null) {
@@ -483,8 +516,8 @@ private void loadPathNames() {
 	 * @return <code>true</code> if the working tree contains a .gitmodules file,
 	 *         <code>false</code> otherwise. Always returns <code>false</code>
 	 *         for bare repositories.
-	 * @throws IOException
-	 * @throws CorruptObjectException
+	 * @throws java.io.IOException
+	 * @throws CorruptObjectException if any.
 	 * @since 3.6
 	 */
 	public static boolean containsGitModulesFile(Repository repository)
@@ -512,6 +545,7 @@ private String getModuleName(String modulePath) {
 	 * Set tree filter
 	 *
 	 * @param filter
+	 *            a {@link org.eclipse.jgit.treewalk.filter.TreeFilter} object.
 	 * @return this generator
 	 */
 	public SubmoduleWalk setFilter(TreeFilter filter) {
@@ -523,10 +557,12 @@ public SubmoduleWalk setFilter(TreeFilter filter) {
 	 * Set the tree iterator used for finding submodule entries
 	 *
 	 * @param iterator
+	 *            an {@link org.eclipse.jgit.treewalk.AbstractTreeIterator}
+	 *            object.
 	 * @return this generator
-	 * @throws CorruptObjectException
+	 * @throws org.eclipse.jgit.errors.CorruptObjectException
 	 */
-	public SubmoduleWalk setTree(final AbstractTreeIterator iterator)
+	public SubmoduleWalk setTree(AbstractTreeIterator iterator)
 			throws CorruptObjectException {
 		walk.addTree(iterator);
 		return this;
@@ -536,12 +572,15 @@ public SubmoduleWalk setTree(final AbstractTreeIterator iterator)
 	 * Set the tree used for finding submodule entries
 	 *
 	 * @param treeId
+	 *            an {@link org.eclipse.jgit.lib.AnyObjectId} object.
 	 * @return this generator
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 * @throws IncorrectObjectTypeException
+	 *             if any.
 	 * @throws MissingObjectException
+	 *             if any.
 	 */
-	public SubmoduleWalk setTree(final AnyObjectId treeId) throws IOException {
+	public SubmoduleWalk setTree(AnyObjectId treeId) throws IOException {
 		walk.addTree(treeId);
 		return this;
 	}
@@ -575,7 +614,7 @@ public File getDirectory() {
 	 * {@link #getObjectId()} and {@link #getPath()}.
 	 *
 	 * @return true if entry found, false otherwise
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 */
 	public boolean next() throws IOException {
 		while (walk.next()) {
@@ -598,6 +637,15 @@ public String getPath() {
 	}
 
 	/**
+	 * The module name for the current submodule entry (used for the section name of .git/config)
+	 * @since 4.10
+	 * @return name
+	 */
+	public String getModuleName() {
+		return getModuleName(path);
+	}
+
+	/**
 	 * Get object id of current submodule entry
 	 *
 	 * @return object id
@@ -611,13 +659,13 @@ public ObjectId getObjectId() {
 	 * the .gitmodules file in the current repository's working tree.
 	 *
 	 * @return configured path
-	 * @throws ConfigInvalidException
-	 * @throws IOException
+	 * @throws org.eclipse.jgit.errors.ConfigInvalidException
+	 * @throws java.io.IOException
 	 */
 	public String getModulesPath() throws IOException, ConfigInvalidException {
 		lazyLoadModulesConfig();
 		return modulesConfig.getString(ConfigConstants.CONFIG_SUBMODULE_SECTION,
-				getModuleName(path), ConfigConstants.CONFIG_KEY_PATH);
+				getModuleName(), ConfigConstants.CONFIG_KEY_PATH);
 	}
 
 	/**
@@ -625,16 +673,12 @@ public String getModulesPath() throws IOException, ConfigInvalidException {
 	 * from the repository's config.
 	 *
 	 * @return configured URL
-	 * @throws ConfigInvalidException
-	 * @throws IOException
+	 * @throws org.eclipse.jgit.errors.ConfigInvalidException
+	 * @throws java.io.IOException
 	 */
 	public String getConfigUrl() throws IOException, ConfigInvalidException {
-		// SubmoduleInitCommand copies the submodules.*.url and
-		// submodules.*.update values from .gitmodules to the config, and
-		// does so using the path defined in .gitmodules as the subsection
-		// name. So no path-to-name translation is necessary here.
 		return repoConfig.getString(ConfigConstants.CONFIG_SUBMODULE_SECTION,
-				path, ConfigConstants.CONFIG_KEY_URL);
+				getModuleName(), ConfigConstants.CONFIG_KEY_URL);
 	}
 
 	/**
@@ -642,13 +686,13 @@ public String getConfigUrl() throws IOException, ConfigInvalidException {
 	 * from the .gitmodules file in the current repository's working tree.
 	 *
 	 * @return configured URL
-	 * @throws ConfigInvalidException
-	 * @throws IOException
+	 * @throws org.eclipse.jgit.errors.ConfigInvalidException
+	 * @throws java.io.IOException
 	 */
 	public String getModulesUrl() throws IOException, ConfigInvalidException {
 		lazyLoadModulesConfig();
 		return modulesConfig.getString(ConfigConstants.CONFIG_SUBMODULE_SECTION,
-				getModuleName(path), ConfigConstants.CONFIG_KEY_URL);
+				getModuleName(), ConfigConstants.CONFIG_KEY_URL);
 	}
 
 	/**
@@ -656,12 +700,12 @@ public String getModulesUrl() throws IOException, ConfigInvalidException {
 	 * from the repository's config.
 	 *
 	 * @return update value
-	 * @throws ConfigInvalidException
-	 * @throws IOException
+	 * @throws org.eclipse.jgit.errors.ConfigInvalidException
+	 * @throws java.io.IOException
 	 */
 	public String getConfigUpdate() throws IOException, ConfigInvalidException {
 		return repoConfig.getString(ConfigConstants.CONFIG_SUBMODULE_SECTION,
-				path, ConfigConstants.CONFIG_KEY_UPDATE);
+				getModuleName(), ConfigConstants.CONFIG_KEY_UPDATE);
 	}
 
 	/**
@@ -669,13 +713,13 @@ public String getConfigUpdate() throws IOException, ConfigInvalidException {
 	 * from the .gitmodules file in the current repository's working tree.
 	 *
 	 * @return update value
-	 * @throws ConfigInvalidException
-	 * @throws IOException
+	 * @throws org.eclipse.jgit.errors.ConfigInvalidException
+	 * @throws java.io.IOException
 	 */
 	public String getModulesUpdate() throws IOException, ConfigInvalidException {
 		lazyLoadModulesConfig();
 		return modulesConfig.getString(ConfigConstants.CONFIG_SUBMODULE_SECTION,
-				getModuleName(path), ConfigConstants.CONFIG_KEY_UPDATE);
+				getModuleName(), ConfigConstants.CONFIG_KEY_UPDATE);
 	}
 
 	/**
@@ -683,15 +727,15 @@ public String getModulesUpdate() throws IOException, ConfigInvalidException {
 	 * value from the .gitmodules file in the current repository's working tree.
 	 *
 	 * @return ignore value
-	 * @throws ConfigInvalidException
-	 * @throws IOException
+	 * @throws org.eclipse.jgit.errors.ConfigInvalidException
+	 * @throws java.io.IOException
 	 * @since 3.6
 	 */
 	public IgnoreSubmoduleMode getModulesIgnore() throws IOException,
 			ConfigInvalidException {
 		lazyLoadModulesConfig();
 		return modulesConfig.getEnum(IgnoreSubmoduleMode.values(),
-				ConfigConstants.CONFIG_SUBMODULE_SECTION, getModuleName(path),
+				ConfigConstants.CONFIG_SUBMODULE_SECTION, getModuleName(),
 				ConfigConstants.CONFIG_KEY_IGNORE, IgnoreSubmoduleMode.NONE);
 	}
 
@@ -699,7 +743,7 @@ ConfigConstants.CONFIG_SUBMODULE_SECTION, getModuleName(path),
 	 * Get repository for current submodule entry
 	 *
 	 * @return repository or null if non-existent
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 */
 	public Repository getRepository() throws IOException {
 		return getSubmoduleRepository(repository, path);
@@ -709,16 +753,14 @@ public Repository getRepository() throws IOException {
 	 * Get commit id that HEAD points to in the current submodule's repository
 	 *
 	 * @return object id of HEAD reference
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 */
 	public ObjectId getHead() throws IOException {
-		Repository subRepo = getRepository();
-		if (subRepo == null)
-			return null;
-		try {
+		try (Repository subRepo = getRepository()) {
+			if (subRepo == null) {
+				return null;
+			}
 			return subRepo.resolve(Constants.HEAD);
-		} finally {
-			subRepo.close();
 		}
 	}
 
@@ -726,17 +768,15 @@ public ObjectId getHead() throws IOException {
 	 * Get ref that HEAD points to in the current submodule's repository
 	 *
 	 * @return ref name, null on failures
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 */
 	public String getHeadRef() throws IOException {
-		Repository subRepo = getRepository();
-		if (subRepo == null)
-			return null;
-		try {
+		try (Repository subRepo = getRepository()) {
+			if (subRepo == null) {
+				return null;
+			}
 			Ref head = subRepo.exactRef(Constants.HEAD);
 			return head != null ? head.getLeaf().getName() : null;
-		} finally {
-			subRepo.close();
 		}
 	}
 
@@ -747,8 +787,8 @@ public String getHeadRef() throws IOException {
 	 * URL
 	 *
 	 * @return resolved remote URL
-	 * @throws IOException
-	 * @throws ConfigInvalidException
+	 * @throws java.io.IOException
+	 * @throws org.eclipse.jgit.errors.ConfigInvalidException
 	 */
 	public String getRemoteUrl() throws IOException, ConfigInvalidException {
 		String url = getModulesUrl();
@@ -756,6 +796,8 @@ public String getRemoteUrl() throws IOException, ConfigInvalidException {
 	}
 
 	/**
+	 * {@inheritDoc}
+	 * <p>
 	 * Release any resources used by this walker's reader.
 	 *
 	 * @since 4.0
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/AbstractAdvertiseRefsHook.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/AbstractAdvertiseRefsHook.java
index 6f13694..4bf0d26 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/AbstractAdvertiseRefsHook.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/AbstractAdvertiseRefsHook.java
@@ -51,12 +51,13 @@
 import org.eclipse.jgit.revwalk.RevWalk;
 
 /**
- * Implementation of {@link AdvertiseRefsHook} that advertises the same refs for
+ * Implementation of {@link org.eclipse.jgit.transport.AdvertiseRefsHook} that advertises the same refs for
  * upload-pack and receive-pack.
  *
  * @since 2.0
  */
 public abstract class AbstractAdvertiseRefsHook implements AdvertiseRefsHook {
+	/** {@inheritDoc} */
 	@Override
 	public void advertiseRefs(UploadPack uploadPack)
 			throws ServiceMayNotContinueException {
@@ -64,6 +65,7 @@ public void advertiseRefs(UploadPack uploadPack)
 				uploadPack.getRepository(), uploadPack.getRevWalk()));
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void advertiseRefs(BaseReceivePack receivePack)
 			throws ServiceMayNotContinueException {
@@ -82,7 +84,7 @@ public void advertiseRefs(BaseReceivePack receivePack)
 	 * @param revWalk
 	 *            open rev walk on the repository.
 	 * @return set of refs to advertise.
-	 * @throws ServiceMayNotContinueException
+	 * @throws org.eclipse.jgit.transport.ServiceMayNotContinueException
 	 *             abort; the message will be sent to the user.
 	 */
 	protected abstract Map<String, Ref> getAdvertisedRefs(
@@ -97,8 +99,8 @@ protected abstract Map<String, Ref> getAdvertisedRefs(
 	 * @param revWalk
 	 *            open rev walk on the repository.
 	 * @return set of additional haves; see
-	 *         {@link ReceivePack#getAdvertisedObjects()}.
-	 * @throws ServiceMayNotContinueException
+	 *         {@link org.eclipse.jgit.transport.ReceivePack#getAdvertisedObjects()}.
+	 * @throws org.eclipse.jgit.transport.ServiceMayNotContinueException
 	 *             abort; the message will be sent to the user.
 	 */
 	protected Set<ObjectId> getAdvertisedHaves(
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/AdvertiseRefsHook.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/AdvertiseRefsHook.java
index 96d7c24..ed05c73 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/AdvertiseRefsHook.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/AdvertiseRefsHook.java
@@ -70,10 +70,11 @@ public void advertiseRefs(BaseReceivePack receivePack) {
 	/**
 	 * Advertise refs for upload-pack.
 	 *
-	 * @param uploadPack instance on which to call
-	 *            {@link UploadPack#setAdvertisedRefs(java.util.Map)}
+	 * @param uploadPack
+	 *            instance on which to call
+	 *            {@link org.eclipse.jgit.transport.UploadPack#setAdvertisedRefs(java.util.Map)}
 	 *            if necessary.
-	 * @throws ServiceMayNotContinueException
+	 * @throws org.eclipse.jgit.transport.ServiceMayNotContinueException
 	 *             abort; the message will be sent to the user.
 	 */
 	public void advertiseRefs(UploadPack uploadPack)
@@ -82,10 +83,11 @@ public void advertiseRefs(UploadPack uploadPack)
 	/**
 	 * Advertise refs for receive-pack.
 	 *
-	 * @param receivePack instance on which to call
-	 *            {@link BaseReceivePack#setAdvertisedRefs(java.util.Map,java.util.Set)}
+	 * @param receivePack
+	 *            instance on which to call
+	 *            {@link org.eclipse.jgit.transport.BaseReceivePack#setAdvertisedRefs(java.util.Map,java.util.Set)}
 	 *            if necessary.
-	 * @throws ServiceMayNotContinueException
+	 * @throws org.eclipse.jgit.transport.ServiceMayNotContinueException
 	 *             abort; the message will be sent to the user.
 	 */
 	public void advertiseRefs(BaseReceivePack receivePack)
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/AdvertiseRefsHookChain.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/AdvertiseRefsHookChain.java
index 22ea5cb..4ef3e1a 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/AdvertiseRefsHookChain.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/AdvertiseRefsHookChain.java
@@ -46,13 +46,14 @@
 import java.util.List;
 
 /**
- * {@link AdvertiseRefsHook} that delegates to a list of other hooks.
+ * {@link org.eclipse.jgit.transport.AdvertiseRefsHook} that delegates to a list
+ * of other hooks.
  * <p>
  * Hooks are run in the order passed to the constructor. A hook may inspect or
  * modify the results of the previous hooks in the chain by calling
- * {@link UploadPack#getAdvertisedRefs()}, or
- * {@link BaseReceivePack#getAdvertisedRefs()} or
- * {@link BaseReceivePack#getAdvertisedObjects()}.
+ * {@link org.eclipse.jgit.transport.UploadPack#getAdvertisedRefs()}, or
+ * {@link org.eclipse.jgit.transport.BaseReceivePack#getAdvertisedRefs()} or
+ * {@link org.eclipse.jgit.transport.BaseReceivePack#getAdvertisedObjects()}.
  */
 public class AdvertiseRefsHookChain implements AdvertiseRefsHook {
 	private final AdvertiseRefsHook[] hooks;
@@ -79,6 +80,7 @@ else if (i == 1)
 			return new AdvertiseRefsHookChain(newHooks, i);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void advertiseRefs(BaseReceivePack rp)
 			throws ServiceMayNotContinueException {
@@ -86,6 +88,7 @@ public void advertiseRefs(BaseReceivePack rp)
 			hooks[i].advertiseRefs(rp);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void advertiseRefs(UploadPack rp)
 			throws ServiceMayNotContinueException {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/AmazonS3.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/AmazonS3.java
index 64cb4dd..a0fc57c 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/AmazonS3.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/AmazonS3.java
@@ -43,6 +43,8 @@
 
 package org.eclipse.jgit.transport;
 
+import static org.eclipse.jgit.lib.Constants.CHARSET;
+
 import java.io.ByteArrayOutputStream;
 import java.io.File;
 import java.io.FileInputStream;
@@ -126,14 +128,14 @@ public class AmazonS3 {
 		SIGNED_HEADERS.add("date"); //$NON-NLS-1$
 	}
 
-	private static boolean isSignedHeader(final String name) {
+	private static boolean isSignedHeader(String name) {
 		final String nameLC = StringUtils.toLowerCase(name);
 		return SIGNED_HEADERS.contains(nameLC) || nameLC.startsWith("x-amz-"); //$NON-NLS-1$
 	}
 
-	private static String toCleanString(final List<String> list) {
+	private static String toCleanString(List<String> list) {
 		final StringBuilder s = new StringBuilder();
-		for (final String v : list) {
+		for (String v : list) {
 			if (s.length() > 0)
 				s.append(',');
 			s.append(v.replaceAll("\n", "").trim()); //$NON-NLS-1$ //$NON-NLS-2$
@@ -141,7 +143,7 @@ private static String toCleanString(final List<String> list) {
 		return s.toString();
 	}
 
-	private static String remove(final Map<String, String> m, final String k) {
+	private static String remove(Map<String, String> m, String k) {
 		final String r = m.remove(k);
 		return r != null ? r : ""; //$NON-NLS-1$
 	}
@@ -229,7 +231,6 @@ interface Keys {
 	 *
 	 * @param props
 	 *            connection properties.
-	 *
 	 */
 	public AmazonS3(final Properties props) {
 		domain = props.getProperty(Keys.DOMAIN, "s3.amazonaws.com"); //$NON-NLS-1$
@@ -279,10 +280,10 @@ else if (StringUtils.equalsIgnoreCase("PUBLIC_READ", pacl)) //$NON-NLS-1$
 	 * @return connection to stream the content of the object. The request
 	 *         properties of the connection may not be modified by the caller as
 	 *         the request parameters have already been signed.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             sending the request was not possible.
 	 */
-	public URLConnection get(final String bucket, final String key)
+	public URLConnection get(String bucket, String key)
 			throws IOException {
 		for (int curAttempt = 0; curAttempt < maxAttempts; curAttempt++) {
 			final HttpURLConnection c = open("GET", bucket, key); //$NON-NLS-1$
@@ -308,10 +309,10 @@ public URLConnection get(final String bucket, final String key)
 	 * @param u
 	 *            connection previously created by {@link #get(String, String)}}.
 	 * @return stream to read plain text from.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             decryption could not be configured.
 	 */
-	public InputStream decrypt(final URLConnection u) throws IOException {
+	public InputStream decrypt(URLConnection u) throws IOException {
 		return encryption.decrypt(u.getInputStream());
 	}
 
@@ -331,11 +332,11 @@ public InputStream decrypt(final URLConnection u) throws IOException {
 	 * @return list of keys starting with <code>prefix</code>, after removing
 	 *         <code>prefix</code> (or <code>prefix + "/"</code>)from all
 	 *         of them.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             sending the request was not possible, or the response XML
 	 *             document could not be parsed properly.
 	 */
-	public List<String> list(final String bucket, String prefix)
+	public List<String> list(String bucket, String prefix)
 			throws IOException {
 		if (prefix.length() > 0 && !prefix.endsWith("/")) //$NON-NLS-1$
 			prefix += "/"; //$NON-NLS-1$
@@ -355,10 +356,10 @@ public List<String> list(final String bucket, String prefix)
 	 *            name of the bucket storing the object.
 	 * @param key
 	 *            key of the object within its bucket.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             deletion failed due to communications error.
 	 */
-	public void delete(final String bucket, final String key)
+	public void delete(String bucket, String key)
 			throws IOException {
 		for (int curAttempt = 0; curAttempt < maxAttempts; curAttempt++) {
 			final HttpURLConnection c = open("DELETE", bucket, key); //$NON-NLS-1$
@@ -392,18 +393,18 @@ public void delete(final String bucket, final String key)
 	 * @param data
 	 *            new data content for the object. Must not be null. Zero length
 	 *            array will create a zero length object.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             creation/updating failed due to communications error.
 	 */
-	public void put(final String bucket, final String key, final byte[] data)
+	public void put(String bucket, String key, byte[] data)
 			throws IOException {
 		if (encryption != WalkEncryption.NONE) {
 			// We have to copy to produce the cipher text anyway so use
 			// the large object code path as it supports that behavior.
 			//
-			final OutputStream os = beginPut(bucket, key, null, null);
-			os.write(data);
-			os.close();
+			try (OutputStream os = beginPut(bucket, key, null, null)) {
+				os.write(data);
+			}
 			return;
 		}
 
@@ -417,11 +418,8 @@ public void put(final String bucket, final String key, final byte[] data)
 			authorize(c);
 			c.setDoOutput(true);
 			c.setFixedLengthStreamingMode(data.length);
-			final OutputStream os = c.getOutputStream();
-			try {
+			try (OutputStream os = c.getOutputStream()) {
 				os.write(data);
-			} finally {
-				os.close();
 			}
 
 			switch (HttpSupport.response(c)) {
@@ -461,7 +459,7 @@ public void put(final String bucket, final String key, final byte[] data)
 	 * @param monitorTask
 	 *            (optional) task name to display during the close method.
 	 * @return a stream which accepts the new data, and transmits once closed.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             if encryption was enabled it could not be configured.
 	 */
 	public OutputStream beginPut(final String bucket, final String key,
@@ -502,12 +500,10 @@ void putImpl(final String bucket, final String key,
 			authorize(c);
 			c.setDoOutput(true);
 			monitor.beginTask(monitorTask, (int) (len / 1024));
-			final OutputStream os = c.getOutputStream();
-			try {
+			try (OutputStream os = c.getOutputStream()) {
 				buf.writeTo(os, monitor);
 			} finally {
 				monitor.endTask();
-				os.close();
 			}
 
 			switch (HttpSupport.response(c)) {
@@ -528,12 +524,11 @@ IOException error(final String action, final String key,
 				JGitText.get().amazonS3ActionFailed, action, key,
 				Integer.valueOf(HttpSupport.response(c)),
 				c.getResponseMessage()));
-		final InputStream errorStream = c.getErrorStream();
-		if (errorStream == null) {
+		if (c.getErrorStream() == null) {
 			return err;
 		}
 
-		try {
+		try (InputStream errorStream = c.getErrorStream()) {
 			final ByteArrayOutputStream b = new ByteArrayOutputStream();
 			byte[] buf = new byte[2048];
 			for (;;) {
@@ -549,13 +544,11 @@ IOException error(final String action, final String key,
 			if (buf.length > 0) {
 				err.initCause(new IOException("\n" + new String(buf))); //$NON-NLS-1$
 			}
-		} finally {
-			errorStream.close();
 		}
 		return err;
 	}
 
-	IOException maxAttempts(final String action, final String key) {
+	IOException maxAttempts(String action, String key) {
 		return new IOException(MessageFormat.format(
 				JGitText.get().amazonS3ActionFailedGivingUp, action, key,
 				Integer.valueOf(maxAttempts)));
@@ -604,10 +597,10 @@ HttpURLConnection open(final String method, final String bucket,
 		return c;
 	}
 
-	void authorize(final HttpURLConnection c) throws IOException {
+	void authorize(HttpURLConnection c) throws IOException {
 		final Map<String, List<String>> reqHdr = c.getRequestProperties();
 		final SortedMap<String, String> sigHdr = new TreeMap<>();
-		for (final Map.Entry<String, List<String>> entry : reqHdr.entrySet()) {
+		for (Map.Entry<String, List<String>> entry : reqHdr.entrySet()) {
 			final String hdr = entry.getKey();
 			if (isSignedHeader(hdr))
 				sigHdr.put(StringUtils.toLowerCase(hdr), toCleanString(entry.getValue()));
@@ -626,7 +619,7 @@ void authorize(final HttpURLConnection c) throws IOException {
 		s.append(remove(sigHdr, "date")); //$NON-NLS-1$
 		s.append('\n');
 
-		for (final Map.Entry<String, String> e : sigHdr.entrySet()) {
+		for (Map.Entry<String, String> e : sigHdr.entrySet()) {
 			s.append(e.getKey());
 			s.append(':');
 			s.append(e.getValue());
@@ -642,7 +635,7 @@ void authorize(final HttpURLConnection c) throws IOException {
 		try {
 			final Mac m = Mac.getInstance(HMAC);
 			m.init(privateKey);
-			sec = Base64.encodeBytes(m.doFinal(s.toString().getBytes("UTF-8"))); //$NON-NLS-1$
+			sec = Base64.encodeBytes(m.doFinal(s.toString().getBytes(CHARSET)));
 		} catch (NoSuchAlgorithmException e) {
 			throw new IOException(MessageFormat.format(JGitText.get().noHMACsupport, HMAC, e.getMessage()));
 		} catch (InvalidKeyException e) {
@@ -651,14 +644,11 @@ void authorize(final HttpURLConnection c) throws IOException {
 		c.setRequestProperty("Authorization", "AWS " + publicKey + ":" + sec); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
 	}
 
-	static Properties properties(final File authFile)
+	static Properties properties(File authFile)
 			throws FileNotFoundException, IOException {
 		final Properties p = new Properties();
-		final FileInputStream in = new FileInputStream(authFile);
-		try {
+		try (FileInputStream in = new FileInputStream(authFile)) {
 			p.load(in);
-		} finally {
-			in.close();
 		}
 		return p;
 	}
@@ -674,7 +664,7 @@ private final class ListParser extends DefaultHandler {
 
 		private StringBuilder data;
 
-		ListParser(final String bn, final String p) {
+		ListParser(String bn, String p) {
 			bucket = bn;
 			prefix = p;
 		}
@@ -701,16 +691,13 @@ void list() throws IOException {
 						throw new IOException(JGitText.get().noXMLParserAvailable);
 					}
 					xr.setContentHandler(this);
-					final InputStream in = c.getInputStream();
-					try {
+					try (InputStream in = c.getInputStream()) {
 						xr.parse(new InputSource(in));
 					} catch (SAXException parsingError) {
-						final IOException p;
-						p = new IOException(MessageFormat.format(JGitText.get().errorListing, prefix));
-						p.initCause(parsingError);
-						throw p;
-					} finally {
-						in.close();
+						throw new IOException(
+								MessageFormat.format(
+										JGitText.get().errorListing, prefix),
+								parsingError);
 					}
 					return;
 
@@ -740,7 +727,7 @@ public void ignorableWhitespace(final char[] ch, final int s,
 		}
 
 		@Override
-		public void characters(final char[] ch, final int s, final int n)
+		public void characters(char[] ch, int s, int n)
 				throws SAXException {
 			if (data != null)
 				data.append(ch, s, n);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BaseConnection.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BaseConnection.java
index 69028fa..f6045f6 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BaseConnection.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BaseConnection.java
@@ -71,31 +71,34 @@ public abstract class BaseConnection implements Connection {
 
 	private Writer messageWriter;
 
+	/** {@inheritDoc} */
 	@Override
 	public Map<String, Ref> getRefsMap() {
 		return advertisedRefs;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public final Collection<Ref> getRefs() {
 		return advertisedRefs.values();
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	public final Ref getRef(final String name) {
+	public final Ref getRef(String name) {
 		return advertisedRefs.get(name);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public String getMessages() {
 		return messageWriter != null ? messageWriter.toString() : ""; //$NON-NLS-1$
 	}
 
 	/**
-	 * User agent advertised by the remote server.
+	 * {@inheritDoc}
 	 *
-	 * @return agent (version of Git) running on the remote server. Null if the
-	 *         server does not advertise this version.
+	 * User agent advertised by the remote server.
 	 * @since 4.0
 	 */
 	@Override
@@ -114,6 +117,7 @@ protected void setPeerUserAgent(String agent) {
 		peerUserAgent = agent;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public abstract void close();
 
@@ -128,7 +132,7 @@ protected void setPeerUserAgent(String agent) {
 	 *            will be wrapped in an unmodifiable way to protect it, but it
 	 *            does not get copied.
 	 */
-	protected void available(final Map<String, Ref> all) {
+	protected void available(Map<String, Ref> all) {
 		advertisedRefs = Collections.unmodifiableMap(all);
 	}
 
@@ -136,7 +140,7 @@ protected void available(final Map<String, Ref> all) {
 	 * Helper method for ensuring one-operation per connection. Check whether
 	 * operation was already marked as started, and mark it as started.
 	 *
-	 * @throws TransportException
+	 * @throws org.eclipse.jgit.errors.TransportException
 	 *             if operation was already marked as started.
 	 */
 	protected void markStartedOperation() throws TransportException {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BaseFetchConnection.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BaseFetchConnection.java
index 41b8c2d..6f46025 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BaseFetchConnection.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BaseFetchConnection.java
@@ -64,6 +64,7 @@
  */
 abstract class BaseFetchConnection extends BaseConnection implements
 		FetchConnection {
+	/** {@inheritDoc} */
 	@Override
 	public final void fetch(final ProgressMonitor monitor,
 			final Collection<Ref> want, final Set<ObjectId> have)
@@ -71,6 +72,7 @@ public final void fetch(final ProgressMonitor monitor,
 		fetch(monitor, want, have, null);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public final void fetch(final ProgressMonitor monitor,
 			final Collection<Ref> want, final Set<ObjectId> have,
@@ -80,6 +82,8 @@ public final void fetch(final ProgressMonitor monitor,
 	}
 
 	/**
+	 * {@inheritDoc}
+	 *
 	 * Default implementation of {@link FetchConnection#didFetchIncludeTags()} -
 	 * returning false.
 	 */
@@ -98,7 +102,7 @@ public boolean didFetchIncludeTags() {
 	 *            as in {@link #fetch(ProgressMonitor, Collection, Set)}
 	 * @param have
 	 *            as in {@link #fetch(ProgressMonitor, Collection, Set)}
-	 * @throws TransportException
+	 * @throws org.eclipse.jgit.errors.TransportException
 	 *             as in {@link #fetch(ProgressMonitor, Collection, Set)}, but
 	 *             implementation doesn't have to care about multiple
 	 *             {@link #fetch(ProgressMonitor, Collection, Set)} calls, as it
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackConnection.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackConnection.java
index c695449..38eae1c 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackConnection.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackConnection.java
@@ -122,7 +122,7 @@ abstract class BasePackConnection extends BaseConnection {
 	/** Extra objects the remote has, but which aren't offered as refs. */
 	protected final Set<ObjectId> additionalHaves = new HashSet<>();
 
-	BasePackConnection(final PackTransport packTransport) {
+	BasePackConnection(PackTransport packTransport) {
 		transport = (Transport) packTransport;
 		local = transport.local;
 		uri = transport.uri;
@@ -170,9 +170,9 @@ protected final void init(InputStream myIn, OutputStream myOut) {
 	 * <p>
 	 * If any errors occur, this connection is automatically closed by invoking
 	 * {@link #close()} and the exception is wrapped (if necessary) and thrown
-	 * as a {@link TransportException}.
+	 * as a {@link org.eclipse.jgit.errors.TransportException}.
 	 *
-	 * @throws TransportException
+	 * @throws org.eclipse.jgit.errors.TransportException
 	 *             the reference list could not be scanned.
 	 */
 	protected void readAdvertisedRefs() throws TransportException {
@@ -267,11 +267,27 @@ protected TransportException noRepository() {
 		return new NoRemoteRepositoryException(uri, JGitText.get().notFound);
 	}
 
-	protected boolean isCapableOf(final String option) {
+	/**
+	 * Whether this option is supported
+	 *
+	 * @param option
+	 *            option string
+	 * @return whether this option is supported
+	 */
+	protected boolean isCapableOf(String option) {
 		return remoteCapablities.contains(option);
 	}
 
-	protected boolean wantCapability(final StringBuilder b, final String option) {
+	/**
+	 * Request capability
+	 *
+	 * @param b
+	 *            buffer
+	 * @param option
+	 *            option we want
+	 * @return {@code true} if the requested option is supported
+	 */
+	protected boolean wantCapability(StringBuilder b, String option) {
 		if (!isCapableOf(option))
 			return false;
 		b.append(' ');
@@ -279,6 +295,12 @@ protected boolean wantCapability(final StringBuilder b, final String option) {
 		return true;
 	}
 
+	/**
+	 * Add user agent capability
+	 *
+	 * @param b
+	 *            a {@link java.lang.StringBuilder} object.
+	 */
 	protected void addUserAgentCapability(StringBuilder b) {
 		String a = UserAgent.get();
 		if (a != null && UserAgent.hasAgent(remoteCapablities)) {
@@ -286,15 +308,17 @@ protected void addUserAgentCapability(StringBuilder b) {
 		}
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public String getPeerUserAgent() {
 		return UserAgent.getAgent(remoteCapablities, super.getPeerUserAgent());
 	}
 
-	private PackProtocolException duplicateAdvertisement(final String name) {
+	private PackProtocolException duplicateAdvertisement(String name) {
 		return new PackProtocolException(uri, MessageFormat.format(JGitText.get().duplicateAdvertisementsOf, name));
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void close() {
 		if (out != null) {
@@ -334,7 +358,9 @@ public void close() {
 		}
 	}
 
-	/** Tell the peer we are disconnecting, if it cares to know. */
+	/**
+	 * Tell the peer we are disconnecting, if it cares to know.
+	 */
 	protected void endOut() {
 		if (outNeedsEnd && out != null) {
 			try {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackFetchConnection.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackFetchConnection.java
index 61c4c4b..0dfcd87 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackFetchConnection.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackFetchConnection.java
@@ -45,8 +45,6 @@
 
 package org.eclipse.jgit.transport;
 
-import static org.eclipse.jgit.lib.RefDatabase.ALL;
-
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
@@ -54,7 +52,7 @@
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Date;
-import java.util.Map;
+import java.util.HashSet;
 import java.util.Set;
 
 import org.eclipse.jgit.errors.PackProtocolException;
@@ -94,10 +92,10 @@
  * easily wrapped up into a local process pipe, anonymous TCP socket, or a
  * command executed through an SSH tunnel.
  * <p>
- * If {@link BasePackConnection#statelessRPC} is {@code true}, this connection
- * can be tunneled over a request-response style RPC system like HTTP.  The RPC
- * call boundary is determined by this class switching from writing to the
- * OutputStream to reading from the InputStream.
+ * If {@link org.eclipse.jgit.transport.BasePackConnection#statelessRPC} is
+ * {@code true}, this connection can be tunneled over a request-response style
+ * RPC system like HTTP. The RPC call boundary is determined by this class
+ * switching from writing to the OutputStream to reading from the InputStream.
  * <p>
  * Concrete implementations should just call
  * {@link #init(java.io.InputStream, java.io.OutputStream)} and
@@ -199,6 +197,13 @@ public abstract class BasePackFetchConnection extends BasePackConnection
 	 */
 	public static final String OPTION_ALLOW_REACHABLE_SHA1_IN_WANT = GitProtocolConstants.OPTION_ALLOW_REACHABLE_SHA1_IN_WANT;
 
+	/**
+	 * The client specified a filter expression.
+	 *
+	 * @since 5.0
+	 */
+	public static final String OPTION_FILTER = GitProtocolConstants.OPTION_FILTER;
+
 	private final RevWalk walk;
 
 	/** All commits that are immediately reachable by a local ref. */
@@ -230,6 +235,8 @@ public abstract class BasePackFetchConnection extends BasePackConnection
 
 	private boolean noProgress;
 
+	private Set<AnyObjectId> minimalNegotiationSet;
+
 	private String lockMessage;
 
 	private PackLock packLock;
@@ -239,23 +246,30 @@ public abstract class BasePackFetchConnection extends BasePackConnection
 
 	private PacketLineOut pckState;
 
+	/** If not -1, the maximum blob size to be sent to the server. */
+	private final long filterBlobLimit;
+
 	/**
 	 * Create a new connection to fetch using the native git transport.
 	 *
 	 * @param packTransport
 	 *            the transport.
 	 */
-	public BasePackFetchConnection(final PackTransport packTransport) {
+	public BasePackFetchConnection(PackTransport packTransport) {
 		super(packTransport);
 
 		if (local != null) {
-			final FetchConfig cfg = local.getConfig().get(FetchConfig::new);
+			final FetchConfig cfg = getFetchConfig();
 			allowOfsDelta = cfg.allowOfsDelta;
+			if (cfg.minimalNegotiation) {
+				minimalNegotiationSet = new HashSet<>();
+			}
 		} else {
 			allowOfsDelta = true;
 		}
 		includeTags = transport.getTagOpt() != TagOpt.NO_TAGS;
 		thinPack = transport.isFetchThin();
+		filterBlobLimit = transport.getFilterBlobLimit();
 
 		if (local != null) {
 			walk = new RevWalk(local);
@@ -277,14 +291,24 @@ public BasePackFetchConnection(final PackTransport packTransport) {
 		}
 	}
 
-	private static class FetchConfig {
+	static class FetchConfig {
 		final boolean allowOfsDelta;
 
-		FetchConfig(final Config c) {
+		final boolean minimalNegotiation;
+
+		FetchConfig(Config c) {
 			allowOfsDelta = c.getBoolean("repack", "usedeltabaseoffset", true); //$NON-NLS-1$ //$NON-NLS-2$
+			minimalNegotiation = c.getBoolean("fetch", "useminimalnegotiation", //$NON-NLS-1$ //$NON-NLS-2$
+					false);
+		}
+
+		FetchConfig(boolean allowOfsDelta, boolean minimalNegotiation) {
+			this.allowOfsDelta = allowOfsDelta;
+			this.minimalNegotiation = minimalNegotiation;
 		}
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public final void fetch(final ProgressMonitor monitor,
 			final Collection<Ref> want, final Set<ObjectId> have)
@@ -292,9 +316,7 @@ public final void fetch(final ProgressMonitor monitor,
 		fetch(monitor, want, have, null);
 	}
 
-	/**
-	 * @since 3.0
-	 */
+	/** {@inheritDoc} */
 	@Override
 	public final void fetch(final ProgressMonitor monitor,
 			final Collection<Ref> want, final Set<ObjectId> have,
@@ -303,21 +325,25 @@ public final void fetch(final ProgressMonitor monitor,
 		doFetch(monitor, want, have, outputStream);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public boolean didFetchIncludeTags() {
 		return false;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public boolean didFetchTestConnectivity() {
 		return false;
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	public void setPackLockMessage(final String message) {
+	public void setPackLockMessage(String message) {
 		lockMessage = message;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public Collection<PackLock> getPackLocks() {
 		if (packLock != null)
@@ -330,7 +356,7 @@ public Collection<PackLock> getPackLocks() {
 	 *
 	 * @param monitor
 	 *            progress monitor to receive status updates. If the monitor is
-	 *            the {@link NullProgressMonitor#INSTANCE}, then the no-progress
+	 *            the {@link org.eclipse.jgit.lib.NullProgressMonitor#INSTANCE}, then the no-progress
 	 *            option enabled.
 	 * @param want
 	 *            the advertised remote references the caller wants to fetch.
@@ -340,7 +366,7 @@ public Collection<PackLock> getPackLocks() {
 	 *            destination repository's references.
 	 * @param outputStream
 	 *            ouputStream to write sideband messages to
-	 * @throws TransportException
+	 * @throws org.eclipse.jgit.errors.TransportException
 	 *             if any exception occurs.
 	 * @since 3.0
 	 */
@@ -380,6 +406,7 @@ protected void doFetch(final ProgressMonitor monitor,
 		}
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void close() {
 		if (walk != null)
@@ -387,9 +414,13 @@ public void close() {
 		super.close();
 	}
 
-	private int maxTimeWanted(final Collection<Ref> wants) {
+	FetchConfig getFetchConfig() {
+		return local.getConfig().get(FetchConfig::new);
+	}
+
+	private int maxTimeWanted(Collection<Ref> wants) {
 		int maxTime = 0;
-		for (final Ref r : wants) {
+		for (Ref r : wants) {
 			try {
 				final RevObject obj = walk.parseAny(r.getObjectId());
 				if (obj instanceof RevCommit) {
@@ -404,10 +435,9 @@ private int maxTimeWanted(final Collection<Ref> wants) {
 		return maxTime;
 	}
 
-	private void markReachable(final Set<ObjectId> have, final int maxTime)
+	private void markReachable(Set<ObjectId> have, int maxTime)
 			throws IOException {
-		Map<String, Ref> refs = local.getRefDatabase().getRefs(ALL);
-		for (final Ref r : refs.values()) {
+		for (Ref r : local.getRefDatabase().getRefs()) {
 			ObjectId id = r.getPeeledObjectId();
 			if (id == null)
 				id = r.getObjectId();
@@ -459,10 +489,10 @@ private void parseReachable(ObjectId id) {
 		}
 	}
 
-	private boolean sendWants(final Collection<Ref> want) throws IOException {
+	private boolean sendWants(Collection<Ref> want) throws IOException {
 		final PacketLineOut p = statelessRPC ? pckState : pckOut;
 		boolean first = true;
-		for (final Ref r : want) {
+		for (Ref r : want) {
 			ObjectId objectId = r.getObjectId();
 			if (objectId == null) {
 				continue;
@@ -488,9 +518,24 @@ private boolean sendWants(final Collection<Ref> want) throws IOException {
 			}
 			line.append('\n');
 			p.writeString(line.toString());
+			if (minimalNegotiationSet != null) {
+				Ref current = local.exactRef(r.getName());
+				if (current != null) {
+					ObjectId o = current.getObjectId();
+					if (o != null && !o.equals(ObjectId.zeroId())) {
+						minimalNegotiationSet.add(o);
+					}
+				}
+			}
 		}
-		if (first)
+		if (first) {
 			return false;
+		}
+		if (filterBlobLimit == 0) {
+			p.writeString(OPTION_FILTER + " blob:none"); //$NON-NLS-1$
+		} else if (filterBlobLimit > 0) {
+			p.writeString(OPTION_FILTER + " blob:limit=" + filterBlobLimit); //$NON-NLS-1$
+		}
 		p.end();
 		outNeedsEnd = false;
 		return true;
@@ -531,11 +576,16 @@ else if (wantCapability(line, OPTION_SIDE_BAND))
 					OPTION_MULTI_ACK_DETAILED));
 		}
 
+		if (filterBlobLimit >= 0 && !wantCapability(line, OPTION_FILTER)) {
+			throw new PackProtocolException(uri,
+					JGitText.get().filterRequiresCapability);
+		}
+
 		addUserAgentCapability(line);
 		return line.toString();
 	}
 
-	private void negotiate(final ProgressMonitor monitor) throws IOException,
+	private void negotiate(ProgressMonitor monitor) throws IOException,
 			CancelledException {
 		final MutableObjectId ackId = new MutableObjectId();
 		int resultsPending = 0;
@@ -545,18 +595,24 @@ private void negotiate(final ProgressMonitor monitor) throws IOException,
 		boolean receivedAck = false;
 		boolean receivedReady = false;
 
-		if (statelessRPC)
+		if (statelessRPC) {
 			state.writeTo(out, null);
+		}
 
 		negotiateBegin();
 		SEND_HAVES: for (;;) {
 			final RevCommit c = walk.next();
-			if (c == null)
+			if (c == null) {
 				break SEND_HAVES;
+			}
 
-			pckOut.writeString("have " + c.getId().name() + "\n"); //$NON-NLS-1$ //$NON-NLS-2$
+			ObjectId o = c.getId();
+			pckOut.writeString("have " + o.name() + "\n"); //$NON-NLS-1$ //$NON-NLS-2$
 			havesSent++;
 			havesSinceLastContinue++;
+			if (minimalNegotiationSet != null) {
+				minimalNegotiationSet.remove(o);
+			}
 
 			if ((31 & havesSent) != 0) {
 				// We group the have lines into blocks of 32, each marked
@@ -566,8 +622,9 @@ private void negotiate(final ProgressMonitor monitor) throws IOException,
 				continue;
 			}
 
-			if (monitor.isCancelled())
+			if (monitor.isCancelled()) {
 				throw new CancelledException();
+			}
 
 			pckOut.end();
 			resultsPending++; // Each end will cause a result to come back.
@@ -589,6 +646,16 @@ private void negotiate(final ProgressMonitor monitor) throws IOException,
 					// pack on the remote side. Keep doing that.
 					//
 					resultsPending--;
+					if (minimalNegotiationSet != null
+							&& minimalNegotiationSet.isEmpty()) {
+						// Minimal negotiation was requested and we sent out our
+						// current reference values for our wants, so terminate
+						// negotiation early.
+						if (statelessRPC) {
+							state.writeTo(out, null);
+						}
+						break SEND_HAVES;
+					}
 					break READ_RESULT;
 
 				case ACK:
@@ -599,8 +666,9 @@ private void negotiate(final ProgressMonitor monitor) throws IOException,
 					multiAck = MultiAck.OFF;
 					resultsPending = 0;
 					receivedAck = true;
-					if (statelessRPC)
+					if (statelessRPC) {
 						state.writeTo(out, null);
+					}
 					break SEND_HAVES;
 
 				case ACK_CONTINUE:
@@ -615,19 +683,31 @@ private void negotiate(final ProgressMonitor monitor) throws IOException,
 					receivedAck = true;
 					receivedContinue = true;
 					havesSinceLastContinue = 0;
-					if (anr == AckNackResult.ACK_READY)
+					if (anr == AckNackResult.ACK_READY) {
 						receivedReady = true;
+					}
+					if (minimalNegotiationSet != null && minimalNegotiationSet.isEmpty()) {
+						// Minimal negotiation was requested and we sent out our current reference
+						// values for our wants, so terminate negotiation early.
+						if (statelessRPC) {
+							state.writeTo(out, null);
+						}
+						break SEND_HAVES;
+					}
 					break;
 				}
 
-				if (monitor.isCancelled())
+				if (monitor.isCancelled()) {
 					throw new CancelledException();
+				}
 			}
 
-			if (noDone & receivedReady)
+			if (noDone & receivedReady) {
 				break SEND_HAVES;
-			if (statelessRPC)
+			}
+			if (statelessRPC) {
 				state.writeTo(out, null);
+			}
 
 			if (receivedContinue && havesSinceLastContinue > MAX_HAVES) {
 				// Our history must be really different from the remote's.
@@ -641,8 +721,9 @@ private void negotiate(final ProgressMonitor monitor) throws IOException,
 
 		// Tell the remote side we have run out of things to talk about.
 		//
-		if (monitor.isCancelled())
+		if (monitor.isCancelled()) {
 			throw new CancelledException();
+		}
 
 		if (!receivedReady || !noDone) {
 			// When statelessRPC is true we should always leave SEND_HAVES
@@ -687,8 +768,9 @@ private void negotiate(final ProgressMonitor monitor) throws IOException,
 				break;
 			}
 
-			if (monitor.isCancelled())
+			if (monitor.isCancelled()) {
 				throw new CancelledException();
+			}
 		}
 	}
 
@@ -703,7 +785,7 @@ public RevFilter clone() {
 			}
 
 			@Override
-			public boolean include(final RevWalk walker, final RevCommit c) {
+			public boolean include(RevWalk walker, RevCommit c) {
 				final boolean remoteKnowsIsCommon = c.has(COMMON);
 				if (c.has(ADVERTISED)) {
 					// Remote advertised this, and we have it, hence common.
@@ -724,14 +806,14 @@ public boolean requiresCommitBody() {
 	}
 
 	private void markRefsAdvertised() {
-		for (final Ref r : getRefs()) {
+		for (Ref r : getRefs()) {
 			markAdvertised(r.getObjectId());
 			if (r.getPeeledObjectId() != null)
 				markAdvertised(r.getPeeledObjectId());
 		}
 	}
 
-	private void markAdvertised(final AnyObjectId id) {
+	private void markAdvertised(AnyObjectId id) {
 		try {
 			walk.parseAny(id).add(ADVERTISED);
 		} catch (IOException readError) {
@@ -739,7 +821,7 @@ private void markAdvertised(final AnyObjectId id) {
 		}
 	}
 
-	private void markCommon(final RevObject obj, final AckNackResult anr)
+	private void markCommon(RevObject obj, AckNackResult anr)
 			throws IOException {
 		if (statelessRPC && anr == AckNackResult.ACK_COMMON && !obj.has(STATE)) {
 			StringBuilder s;
@@ -776,7 +858,7 @@ private void receivePack(final ProgressMonitor monitor,
 
 	/**
 	 * Notification event delivered just before the pack is received from the
-	 * network. This event can be used by RPC such as {@link TransportHttp} to
+	 * network. This event can be used by RPC such as {@link org.eclipse.jgit.transport.TransportHttp} to
 	 * disable its request magic and ensure the pack stream is read correctly.
 	 *
 	 * @since 2.0
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackPushConnection.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackPushConnection.java
index 679ea0c..69624ff 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackPushConnection.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackPushConnection.java
@@ -81,7 +81,8 @@
  * easily wrapped up into a local process pipe, anonymous TCP socket, or a
  * command executed through an SSH tunnel.
  * <p>
- * This implementation honors {@link Transport#isPushThin()} option.
+ * This implementation honors
+ * {@link org.eclipse.jgit.transport.Transport#isPushThin()} option.
  * <p>
  * Concrete implementations should just call
  * {@link #init(java.io.InputStream, java.io.OutputStream)} and
@@ -145,13 +146,14 @@ public abstract class BasePackPushConnection extends BasePackConnection implemen
 	 * @param packTransport
 	 *            the transport.
 	 */
-	public BasePackPushConnection(final PackTransport packTransport) {
+	public BasePackPushConnection(PackTransport packTransport) {
 		super(packTransport);
 		thinPack = transport.isPushThin();
 		atomic = transport.isPushAtomic();
 		pushOptions = transport.getPushOptions();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void push(final ProgressMonitor monitor,
 			final Map<String, RemoteRefUpdate> refUpdates)
@@ -159,9 +161,7 @@ public void push(final ProgressMonitor monitor,
 		push(monitor, refUpdates, null);
 	}
 
-	/**
-	 * @since 3.0
-	 */
+	/** {@inheritDoc} */
 	@Override
 	public void push(final ProgressMonitor monitor,
 			final Map<String, RemoteRefUpdate> refUpdates, OutputStream outputStream)
@@ -170,6 +170,7 @@ public void push(final ProgressMonitor monitor,
 		doPush(monitor, refUpdates, outputStream);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected TransportException noRepository() {
 		// Sadly we cannot tell the "invalid URI" case from "push not allowed".
@@ -202,7 +203,7 @@ protected TransportException noRepository() {
 	 *            update commands to be applied to the remote repository.
 	 * @param outputStream
 	 *            output stream to write sideband messages to
-	 * @throws TransportException
+	 * @throws org.eclipse.jgit.errors.TransportException
 	 *             if any exception occurs.
 	 * @since 3.0
 	 */
@@ -255,7 +256,7 @@ private void writeCommands(final Collection<RemoteRefUpdate> refUpdates,
 							pushOptions.toString()));
 		}
 
-		for (final RemoteRefUpdate rru : refUpdates) {
+		for (RemoteRefUpdate rru : refUpdates) {
 			if (!capableDeleteRefs && rru.isDelete()) {
 				rru.setStatus(Status.REJECTED_NODELETE);
 				continue;
@@ -293,7 +294,7 @@ private void writeCommands(final Collection<RemoteRefUpdate> refUpdates,
 	}
 
 	private void transmitOptions() throws IOException {
-		for (final String pushOption : pushOptions) {
+		for (String pushOption : pushOptions) {
 			pckOut.writeString(pushOption);
 		}
 
@@ -331,17 +332,17 @@ private void writePack(final Map<String, RemoteRefUpdate> refUpdates,
 		Set<ObjectId> remoteObjects = new HashSet<>();
 		Set<ObjectId> newObjects = new HashSet<>();
 
-		try (final PackWriter writer = new PackWriter(transport.getPackConfig(),
+		try (PackWriter writer = new PackWriter(transport.getPackConfig(),
 				local.newObjectReader())) {
 
-			for (final Ref r : getRefs()) {
+			for (Ref r : getRefs()) {
 				// only add objects that we actually have
 				ObjectId oid = r.getObjectId();
 				if (local.hasObject(oid))
 					remoteObjects.add(oid);
 			}
 			remoteObjects.addAll(additionalHaves);
-			for (final RemoteRefUpdate r : refUpdates.values()) {
+			for (RemoteRefUpdate r : refUpdates.values()) {
 				if (!ObjectId.zeroId().equals(r.getNewObjectId()))
 					newObjects.add(r.getNewObjectId());
 			}
@@ -364,7 +365,7 @@ private void writePack(final Map<String, RemoteRefUpdate> refUpdates,
 		}
 	}
 
-	private void readStatusReport(final Map<String, RemoteRefUpdate> refUpdates)
+	private void readStatusReport(Map<String, RemoteRefUpdate> refUpdates)
 			throws IOException {
 		final String unpackLine = readStringLongTimeout();
 		if (!unpackLine.startsWith("unpack ")) //$NON-NLS-1$
@@ -410,7 +411,7 @@ private void readStatusReport(final Map<String, RemoteRefUpdate> refUpdates)
 				rru.setMessage(message);
 			}
 		}
-		for (final RemoteRefUpdate rru : refUpdates.values()) {
+		for (RemoteRefUpdate rru : refUpdates.values()) {
 			if (rru.getStatus() == Status.AWAITING_REPORT)
 				throw new PackProtocolException(MessageFormat.format(
 						JGitText.get().expectedReportForRefNotReceived , uri, rru.getRemoteName()));
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BaseReceivePack.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BaseReceivePack.java
index 44abcd5..c426e3c 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BaseReceivePack.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BaseReceivePack.java
@@ -306,7 +306,7 @@ public void setPushCertificate(PushCertificate cert) {
 	 * @param into
 	 *            the destination repository.
 	 */
-	protected BaseReceivePack(final Repository into) {
+	protected BaseReceivePack(Repository into) {
 		db = into;
 		walk = new RevWalk(db);
 
@@ -340,7 +340,7 @@ protected static class ReceiveConfig {
 		final long maxDiscardBytes;
 		final SignedPushConfig signedPush;
 
-		ReceiveConfig(final Config config) {
+		ReceiveConfig(Config config) {
 			allowCreates = true;
 			allowDeletes = !config.getBoolean("receive", "denydeletes", false); //$NON-NLS-1$ //$NON-NLS-2$
 			allowNonFastForwards = !config.getBoolean("receive", //$NON-NLS-1$
@@ -405,15 +405,27 @@ public void flush() {
 		}
 	}
 
-	/** @return the process name used for pack lock messages. */
+	/**
+	 * Get the process name used for pack lock messages.
+	 *
+	 * @return the process name used for pack lock messages.
+	 */
 	protected abstract String getLockMessageProcessName();
 
-	/** @return the repository this receive completes into. */
+	/**
+	 * Get the repository this receive completes into.
+	 *
+	 * @return the repository this receive completes into.
+	 */
 	public final Repository getRepository() {
 		return db;
 	}
 
-	/** @return the RevWalk instance used by this connection. */
+	/**
+	 * Get the RevWalk instance used by this connection.
+	 *
+	 * @return the RevWalk instance used by this connection.
+	 */
 	public final RevWalk getRevWalk() {
 		return walk;
 	}
@@ -431,14 +443,15 @@ public final Map<String, Ref> getAdvertisedRefs() {
 	/**
 	 * Set the refs advertised by this ReceivePack.
 	 * <p>
-	 * Intended to be called from a {@link PreReceiveHook}.
+	 * Intended to be called from a
+	 * {@link org.eclipse.jgit.transport.PreReceiveHook}.
 	 *
 	 * @param allRefs
 	 *            explicit set of references to claim as advertised by this
-	 *            ReceivePack instance. This overrides any references that
-	 *            may exist in the source repository. The map is passed
-	 *            to the configured {@link #getRefFilter()}. If null, assumes
-	 *            all refs were advertised.
+	 *            ReceivePack instance. This overrides any references that may
+	 *            exist in the source repository. The map is passed to the
+	 *            configured {@link #getRefFilter()}. If null, assumes all refs
+	 *            were advertised.
 	 * @param additionalHaves
 	 *            explicit set of additional haves to claim as advertised. If
 	 *            null, assumes the default set of additional haves from the
@@ -475,6 +488,9 @@ public final Set<ObjectId> getAdvertisedObjects() {
 	}
 
 	/**
+	 * Whether this instance will validate all referenced, but not supplied by
+	 * the client, objects are reachable from another reference.
+	 *
 	 * @return true if this instance will validate all referenced, but not
 	 *         supplied by the client, objects are reachable from another
 	 *         reference.
@@ -493,8 +509,9 @@ public boolean isCheckReferencedObjectsAreReachable() {
 	 * This feature is useful when the application doesn't trust the client to
 	 * not provide a forged SHA-1 reference to an object, in an attempt to
 	 * access parts of the DAG that they aren't allowed to see and which have
-	 * been hidden from them via the configured {@link AdvertiseRefsHook} or
-	 * {@link RefFilter}.
+	 * been hidden from them via the configured
+	 * {@link org.eclipse.jgit.transport.AdvertiseRefsHook} or
+	 * {@link org.eclipse.jgit.transport.RefFilter}.
 	 * <p>
 	 * Enabling this feature may imply at least some, if not all, of the same
 	 * functionality performed by {@link #setCheckReceivedObjects(boolean)}.
@@ -508,6 +525,9 @@ public void setCheckReferencedObjectsAreReachable(boolean b) {
 	}
 
 	/**
+	 * Whether this class expects a bi-directional pipe opened between the
+	 * client and itself.
+	 *
 	 * @return true if this class expects a bi-directional pipe opened between
 	 *         the client and itself. The default is true.
 	 */
@@ -516,6 +536,10 @@ public boolean isBiDirectionalPipe() {
 	}
 
 	/**
+	 * Whether this class will assume the socket is a fully bidirectional pipe
+	 * between the two peers and takes advantage of that by first transmitting
+	 * the known refs, then waiting to read commands.
+	 *
 	 * @param twoWay
 	 *            if true, this class will assume the socket is a fully
 	 *            bidirectional pipe between the two peers and takes advantage
@@ -524,39 +548,51 @@ public boolean isBiDirectionalPipe() {
 	 *            commands before writing output and does not perform the
 	 *            initial advertising.
 	 */
-	public void setBiDirectionalPipe(final boolean twoWay) {
+	public void setBiDirectionalPipe(boolean twoWay) {
 		biDirectionalPipe = twoWay;
 	}
 
-	/** @return true if there is data expected after the pack footer. */
+	/**
+	 * Whether there is data expected after the pack footer.
+	 *
+	 * @return {@code true} if there is data expected after the pack footer.
+	 */
 	public boolean isExpectDataAfterPackFooter() {
 		return expectDataAfterPackFooter;
 	}
 
 	/**
+	 * Whether there is additional data in InputStream after pack.
+	 *
 	 * @param e
-	 *            true if there is additional data in InputStream after pack.
+	 *            {@code true} if there is additional data in InputStream after
+	 *            pack.
 	 */
 	public void setExpectDataAfterPackFooter(boolean e) {
 		expectDataAfterPackFooter = e;
 	}
 
 	/**
-	 * @return true if this instance will verify received objects are formatted
-	 *         correctly. Validating objects requires more CPU time on this side
-	 *         of the connection.
+	 * Whether this instance will verify received objects are formatted
+	 * correctly.
+	 *
+	 * @return {@code true} if this instance will verify received objects are
+	 *         formatted correctly. Validating objects requires more CPU time on
+	 *         this side of the connection.
 	 */
 	public boolean isCheckReceivedObjects() {
 		return objectChecker != null;
 	}
 
 	/**
+	 * Whether to enable checking received objects
+	 *
 	 * @param check
-	 *            true to enable checking received objects; false to assume all
-	 *            received objects are valid.
+	 *            {@code true} to enable checking received objects; false to
+	 *            assume all received objects are valid.
 	 * @see #setObjectChecker(ObjectChecker)
 	 */
-	public void setCheckReceivedObjects(final boolean check) {
+	public void setCheckReceivedObjects(boolean check) {
 		if (check && objectChecker == null)
 			setObjectChecker(new ObjectChecker());
 		else if (!check && objectChecker != null)
@@ -564,42 +600,59 @@ else if (!check && objectChecker != null)
 	}
 
 	/**
-	 * @param impl if non-null the object checking instance to verify each
-	 *        received object with; null to disable object checking.
+	 * Set the object checking instance to verify each received object with
+	 *
+	 * @param impl
+	 *            if non-null the object checking instance to verify each
+	 *            received object with; null to disable object checking.
 	 * @since 3.4
 	 */
 	public void setObjectChecker(ObjectChecker impl) {
 		objectChecker = impl;
 	}
 
-	/** @return true if the client can request refs to be created. */
+	/**
+	 * Whether the client can request refs to be created.
+	 *
+	 * @return {@code true} if the client can request refs to be created.
+	 */
 	public boolean isAllowCreates() {
 		return allowCreates;
 	}
 
 	/**
+	 * Whether to permit create ref commands to be processed.
+	 *
 	 * @param canCreate
-	 *            true to permit create ref commands to be processed.
+	 *            {@code true} to permit create ref commands to be processed.
 	 */
-	public void setAllowCreates(final boolean canCreate) {
+	public void setAllowCreates(boolean canCreate) {
 		allowCreates = canCreate;
 	}
 
-	/** @return true if the client can request refs to be deleted. */
+	/**
+	 * Whether the client can request refs to be deleted.
+	 *
+	 * @return {@code true} if the client can request refs to be deleted.
+	 */
 	public boolean isAllowDeletes() {
 		return allowAnyDeletes;
 	}
 
 	/**
+	 * Whether to permit delete ref commands to be processed.
+	 *
 	 * @param canDelete
-	 *            true to permit delete ref commands to be processed.
+	 *            {@code true} to permit delete ref commands to be processed.
 	 */
-	public void setAllowDeletes(final boolean canDelete) {
+	public void setAllowDeletes(boolean canDelete) {
 		allowAnyDeletes = canDelete;
 	}
 
 	/**
-	 * @return true if the client can delete from {@code refs/heads/}.
+	 * Whether the client can delete from {@code refs/heads/}.
+	 *
+	 * @return {@code true} if the client can delete from {@code refs/heads/}.
 	 * @since 3.6
 	 */
 	public boolean isAllowBranchDeletes() {
@@ -607,8 +660,11 @@ public boolean isAllowBranchDeletes() {
 	}
 
 	/**
+	 * Configure whether to permit deletion of branches from the
+	 * {@code refs/heads/} namespace.
+	 *
 	 * @param canDelete
-	 *            true to permit deletion of branches from the
+	 *            {@code true} to permit deletion of branches from the
 	 *            {@code refs/heads/} namespace.
 	 * @since 3.6
 	 */
@@ -617,25 +673,34 @@ public void setAllowBranchDeletes(boolean canDelete) {
 	}
 
 	/**
-	 * @return true if the client can request non-fast-forward updates of a ref,
-	 *         possibly making objects unreachable.
+	 * Whether the client can request non-fast-forward updates of a ref,
+	 * possibly making objects unreachable.
+	 *
+	 * @return {@code true} if the client can request non-fast-forward updates
+	 *         of a ref, possibly making objects unreachable.
 	 */
 	public boolean isAllowNonFastForwards() {
 		return allowNonFastForwards;
 	}
 
 	/**
+	 * Configure whether to permit the client to ask for non-fast-forward
+	 * updates of an existing ref.
+	 *
 	 * @param canRewind
-	 *            true to permit the client to ask for non-fast-forward updates
-	 *            of an existing ref.
+	 *            {@code true} to permit the client to ask for non-fast-forward
+	 *            updates of an existing ref.
 	 */
-	public void setAllowNonFastForwards(final boolean canRewind) {
+	public void setAllowNonFastForwards(boolean canRewind) {
 		allowNonFastForwards = canRewind;
 	}
 
 	/**
-	 * @return true if the client's commands should be performed as a single
-	 *         atomic transaction.
+	 * Whether the client's commands should be performed as a single atomic
+	 * transaction.
+	 *
+	 * @return {@code true} if the client's commands should be performed as a
+	 *         single atomic transaction.
 	 * @since 4.4
 	 */
 	public boolean isAtomic() {
@@ -643,16 +708,23 @@ public boolean isAtomic() {
 	}
 
 	/**
+	 * Configure whether to perform the client's commands as a single atomic
+	 * transaction.
+	 *
 	 * @param atomic
-	 *            true to perform the client's commands as a single atomic
-	 *            transaction.
+	 *            {@code true} to perform the client's commands as a single
+	 *            atomic transaction.
 	 * @since 4.4
 	 */
 	public void setAtomic(boolean atomic) {
 		this.atomic = atomic;
 	}
 
-	/** @return identity of the user making the changes in the reflog. */
+	/**
+	 * Get identity of the user making the changes in the reflog.
+	 *
+	 * @return identity of the user making the changes in the reflog.
+	 */
 	public PersonIdent getRefLogIdent() {
 		return refLogIdent;
 	}
@@ -669,16 +741,24 @@ public PersonIdent getRefLogIdent() {
 	 *            automatically determined based on the repository
 	 *            configuration.
 	 */
-	public void setRefLogIdent(final PersonIdent pi) {
+	public void setRefLogIdent(PersonIdent pi) {
 		refLogIdent = pi;
 	}
 
-	/** @return the hook used while advertising the refs to the client */
+	/**
+	 * Get the hook used while advertising the refs to the client
+	 *
+	 * @return the hook used while advertising the refs to the client
+	 */
 	public AdvertiseRefsHook getAdvertiseRefsHook() {
 		return advertiseRefsHook;
 	}
 
-	/** @return the filter used while advertising the refs to the client */
+	/**
+	 * Get the filter used while advertising the refs to the client
+	 *
+	 * @return the filter used while advertising the refs to the client
+	 */
 	public RefFilter getRefFilter() {
 		return refFilter;
 	}
@@ -686,17 +766,19 @@ public RefFilter getRefFilter() {
 	/**
 	 * Set the hook used while advertising the refs to the client.
 	 * <p>
-	 * If the {@link AdvertiseRefsHook} chooses to call
-	 * {@link #setAdvertisedRefs(Map,Set)}, only refs set by this hook
-	 * <em>and</em> selected by the {@link RefFilter} will be shown to the client.
-	 * Clients may still attempt to create or update a reference not advertised by
-	 * the configured {@link AdvertiseRefsHook}. These attempts should be rejected
-	 * by a matching {@link PreReceiveHook}.
+	 * If the {@link org.eclipse.jgit.transport.AdvertiseRefsHook} chooses to
+	 * call {@link #setAdvertisedRefs(Map,Set)}, only refs set by this hook
+	 * <em>and</em> selected by the {@link org.eclipse.jgit.transport.RefFilter}
+	 * will be shown to the client. Clients may still attempt to create or
+	 * update a reference not advertised by the configured
+	 * {@link org.eclipse.jgit.transport.AdvertiseRefsHook}. These attempts
+	 * should be rejected by a matching
+	 * {@link org.eclipse.jgit.transport.PreReceiveHook}.
 	 *
 	 * @param advertiseRefsHook
 	 *            the hook; may be null to show all refs.
 	 */
-	public void setAdvertiseRefsHook(final AdvertiseRefsHook advertiseRefsHook) {
+	public void setAdvertiseRefsHook(AdvertiseRefsHook advertiseRefsHook) {
 		if (advertiseRefsHook != null)
 			this.advertiseRefsHook = advertiseRefsHook;
 		else
@@ -706,18 +788,22 @@ public void setAdvertiseRefsHook(final AdvertiseRefsHook advertiseRefsHook) {
 	/**
 	 * Set the filter used while advertising the refs to the client.
 	 * <p>
-	 * Only refs allowed by this filter will be shown to the client.
-	 * The filter is run against the refs specified by the
-	 * {@link AdvertiseRefsHook} (if applicable).
+	 * Only refs allowed by this filter will be shown to the client. The filter
+	 * is run against the refs specified by the
+	 * {@link org.eclipse.jgit.transport.AdvertiseRefsHook} (if applicable).
 	 *
 	 * @param refFilter
 	 *            the filter; may be null to show all refs.
 	 */
-	public void setRefFilter(final RefFilter refFilter) {
+	public void setRefFilter(RefFilter refFilter) {
 		this.refFilter = refFilter != null ? refFilter : RefFilter.DEFAULT;
 	}
 
-	/** @return timeout (in seconds) before aborting an IO operation. */
+	/**
+	 * Get timeout (in seconds) before aborting an IO operation.
+	 *
+	 * @return timeout (in seconds) before aborting an IO operation.
+	 */
 	public int getTimeout() {
 		return timeout;
 	}
@@ -730,7 +816,7 @@ public int getTimeout() {
 	 *            before aborting an IO read or write operation with the
 	 *            connected client.
 	 */
-	public void setTimeout(final int seconds) {
+	public void setTimeout(int seconds) {
 		timeout = seconds;
 	}
 
@@ -775,7 +861,7 @@ public void setMaxCommandDiscardBytes(long limit) {
 	 * @param limit
 	 *            the Git object size limit. If zero then there is not limit.
 	 */
-	public void setMaxObjectSizeLimit(final long limit) {
+	public void setMaxObjectSizeLimit(long limit) {
 		maxObjectSizeLimit = limit;
 	}
 
@@ -786,10 +872,9 @@ public void setMaxObjectSizeLimit(final long limit) {
 	 *
 	 * @param limit
 	 *            the pack size limit, in bytes
-	 *
 	 * @since 3.3
 	 */
-	public void setMaxPackSizeLimit(final long limit) {
+	public void setMaxPackSizeLimit(long limit) {
 		if (limit < 0)
 			throw new IllegalArgumentException(MessageFormat.format(
 					JGitText.get().receivePackInvalidLimit, Long.valueOf(limit)));
@@ -801,7 +886,7 @@ public void setMaxPackSizeLimit(final long limit) {
 	 *
 	 * @return true if the client has advertised a side-band capability, false
 	 *     otherwise.
-	 * @throws RequestNotYetReadException
+	 * @throws org.eclipse.jgit.transport.RequestNotYetReadException
 	 *             if the client's request has not yet been read from the wire, so
 	 *             we do not know if they expect side-band. Note that the client
 	 *             may have already written the request, it just has not been
@@ -813,6 +898,8 @@ public boolean isSideBand() throws RequestNotYetReadException {
 	}
 
 	/**
+	 * Whether clients may request avoiding noisy progress messages.
+	 *
 	 * @return true if clients may request avoiding noisy progress messages.
 	 * @since 4.0
 	 */
@@ -835,6 +922,8 @@ public void setAllowQuiet(boolean allow) {
 	}
 
 	/**
+	 * Whether the server supports receiving push options.
+	 *
 	 * @return true if the server supports receiving push options.
 	 * @since 4.5
 	 */
@@ -857,7 +946,7 @@ public void setAllowPushOptions(boolean allow) {
 	 * True if the client wants less verbose output.
 	 *
 	 * @return true if the client has requested the server to be less verbose.
-	 * @throws RequestNotYetReadException
+	 * @throws org.eclipse.jgit.transport.RequestNotYetReadException
 	 *             if the client's request has not yet been read from the wire,
 	 *             so we do not know if they expect side-band. Note that the
 	 *             client may have already written the request, it just has not
@@ -908,7 +997,11 @@ public String getPeerUserAgent() {
 		return UserAgent.getAgent(enabledCapabilities, userAgent);
 	}
 
-	/** @return all of the command received by the current request. */
+	/**
+	 * Get all of the command received by the current request.
+	 *
+	 * @return all of the command received by the current request.
+	 */
 	public List<ReceiveCommand> getAllCommands() {
 		return Collections.unmodifiableList(commands);
 	}
@@ -926,17 +1019,19 @@ public List<ReceiveCommand> getAllCommands() {
 	 * message will be discarded, with no other indication to the caller or to
 	 * the client.
 	 * <p>
-	 * {@link PreReceiveHook}s should always try to use
-	 * {@link ReceiveCommand#setResult(Result, String)} with a result status of
-	 * {@link Result#REJECTED_OTHER_REASON} to indicate any reasons for
-	 * rejecting an update. Messages attached to a command are much more likely
-	 * to be returned to the client.
+	 * {@link org.eclipse.jgit.transport.PreReceiveHook}s should always try to
+	 * use
+	 * {@link org.eclipse.jgit.transport.ReceiveCommand#setResult(Result, String)}
+	 * with a result status of
+	 * {@link org.eclipse.jgit.transport.ReceiveCommand.Result#REJECTED_OTHER_REASON}
+	 * to indicate any reasons for rejecting an update. Messages attached to a
+	 * command are much more likely to be returned to the client.
 	 *
 	 * @param what
 	 *            string describing the problem identified by the hook. The
 	 *            string must not end with an LF, and must not contain an LF.
 	 */
-	public void sendError(final String what) {
+	public void sendError(String what) {
 		if (refs == null) {
 			if (advertiseError == null)
 				advertiseError = new StringBuilder();
@@ -969,11 +1064,15 @@ private void fatalError(String msg) {
 	 *            string describing the problem identified by the hook. The
 	 *            string must not end with an LF, and must not contain an LF.
 	 */
-	public void sendMessage(final String what) {
+	public void sendMessage(String what) {
 		msgOutWrapper.write(Constants.encode(what + "\n")); //$NON-NLS-1$
 	}
 
-	/** @return an underlying stream for sending messages to the client. */
+	/**
+	 * Get an underlying stream for sending messages to the client.
+	 *
+	 * @return an underlying stream for sending messages to the client.
+	 */
 	public OutputStream getMessageOutputStream() {
 		return msgOutWrapper;
 	}
@@ -984,7 +1083,7 @@ public OutputStream getMessageOutputStream() {
 	 * This can only be called if the pack is already received.
 	 *
 	 * @return the size of the received pack including index size
-	 * @throws IllegalStateException
+	 * @throws java.lang.IllegalStateException
 	 *             if called before the pack has been received
 	 * @since 3.3
 	 */
@@ -1006,12 +1105,20 @@ protected Set<ObjectId> getClientShallowCommits() {
 		return clientShallowCommits;
 	}
 
-	/** @return true if any commands to be executed have been read. */
+	/**
+	 * Whether any commands to be executed have been read.
+	 *
+	 * @return {@code true} if any commands to be executed have been read.
+	 */
 	protected boolean hasCommands() {
 		return !commands.isEmpty();
 	}
 
-	/** @return true if an error occurred that should be advertised. */
+	/**
+	 * Whether an error occurred that should be advertised.
+	 *
+	 * @return true if an error occurred that should be advertised.
+	 */
 	protected boolean hasError() {
 		return advertiseError != null;
 	}
@@ -1059,7 +1166,11 @@ protected void init(final InputStream input, final OutputStream output,
 		commands = new ArrayList<>();
 	}
 
-	/** @return advertised refs, or the default if not explicitly advertised. */
+	/**
+	 * Get advertised refs, or the default if not explicitly advertised.
+	 *
+	 * @return advertised refs, or the default if not explicitly advertised.
+	 */
 	protected Map<String, Ref> getAdvertisedOrDefaultRefs() {
 		if (refs == null)
 			setAdvertisedRefs(null, null);
@@ -1069,7 +1180,7 @@ protected Map<String, Ref> getAdvertisedOrDefaultRefs() {
 	/**
 	 * Receive a pack from the stream and check connectivity if necessary.
 	 *
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             an error occurred during unpacking or connectivity checking.
 	 */
 	protected void receivePackAndCheckConnectivity() throws IOException {
@@ -1082,7 +1193,7 @@ protected void receivePackAndCheckConnectivity() throws IOException {
 	/**
 	 * Unlock the pack written by this object.
 	 *
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the pack could not be unlocked.
 	 */
 	protected void unlockPack() throws IOException {
@@ -1097,12 +1208,12 @@ protected void unlockPack() throws IOException {
 	 *
 	 * @param adv
 	 *            the advertisement formatter.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the formatter failed to write an advertisement.
-	 * @throws ServiceMayNotContinueException
+	 * @throws org.eclipse.jgit.transport.ServiceMayNotContinueException
 	 *             the hook denied advertisement.
 	 */
-	public void sendAdvertisedRefs(final RefAdvertiser adv)
+	public void sendAdvertisedRefs(RefAdvertiser adv)
 			throws IOException, ServiceMayNotContinueException {
 		if (advertiseError != null) {
 			adv.writeOne("ERR " + advertiseError); //$NON-NLS-1$
@@ -1160,7 +1271,7 @@ public ReceivedPackStatistics getReceivedPackStatistics() {
 	/**
 	 * Receive a list of commands from the input.
 	 *
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 */
 	protected void recvCommands() throws IOException {
 		PacketLineIn pck = maxCommandBytes > 0
@@ -1289,7 +1400,9 @@ void readPostCommands(PacketLineIn in) throws IOException {
 		// Do nothing by default.
 	}
 
-	/** Enable capabilities based on a previously read capabilities line. */
+	/**
+	 * Enable capabilities based on a previously read capabilities line.
+	 */
 	protected void enableCapabilities() {
 		sideBand = isCapabilityEnabled(CAPABILITY_SIDE_BAND_64K);
 		quiet = allowQuiet && isCapabilityEnabled(CAPABILITY_QUIET);
@@ -1321,9 +1434,13 @@ void checkRequestWasRead() {
 			throw new RequestNotYetReadException();
 	}
 
-	/** @return true if a pack is expected based on the list of commands. */
+	/**
+	 * Whether a pack is expected based on the list of commands.
+	 *
+	 * @return {@code true} if a pack is expected based on the list of commands.
+	 */
 	protected boolean needPack() {
-		for (final ReceiveCommand cmd : commands) {
+		for (ReceiveCommand cmd : commands) {
 			if (cmd.getType() != ReceiveCommand.Type.DELETE)
 				return true;
 		}
@@ -1409,21 +1526,21 @@ private void checkConnectivity() throws IOException {
 		}
 		parser = null;
 
-		try (final ObjectWalk ow = new ObjectWalk(db)) {
+		try (ObjectWalk ow = new ObjectWalk(db)) {
 			if (baseObjects != null) {
 				ow.sort(RevSort.TOPO);
 				if (!baseObjects.isEmpty())
 					ow.sort(RevSort.BOUNDARY, true);
 			}
 
-			for (final ReceiveCommand cmd : commands) {
+			for (ReceiveCommand cmd : commands) {
 				if (cmd.getResult() != Result.NOT_ATTEMPTED)
 					continue;
 				if (cmd.getType() == ReceiveCommand.Type.DELETE)
 					continue;
 				ow.markStart(ow.parseAny(cmd.getNewId()));
 			}
-			for (final ObjectId have : advertisedHaves) {
+			for (ObjectId have : advertisedHaves) {
 				RevObject o = ow.parseAny(have);
 				ow.markUninteresting(o);
 
@@ -1475,9 +1592,11 @@ private void checkConnectivity() throws IOException {
 		}
 	}
 
-	/** Validate the command list. */
+	/**
+	 * Validate the command list.
+	 */
 	protected void validateCommands() {
-		for (final ReceiveCommand cmd : commands) {
+		for (ReceiveCommand cmd : commands) {
 			final Ref ref = cmd.getRef();
 			if (cmd.getResult() != Result.NOT_ATTEMPTED)
 				continue;
@@ -1612,6 +1731,8 @@ protected void validateCommands() {
 	}
 
 	/**
+	 * Whether any commands have been rejected so far.
+	 *
 	 * @return if any commands have been rejected so far.
 	 * @since 3.6
 	 */
@@ -1625,6 +1746,7 @@ protected boolean anyRejects() {
 
 	/**
 	 * Set the result to fail for any command that was not processed yet.
+	 *
 	 * @since 3.6
 	 */
 	protected void failPendingCommands() {
@@ -1639,11 +1761,13 @@ protected void failPendingCommands() {
 	 * @return a copy of the command list containing only those commands with the
 	 *         desired status.
 	 */
-	protected List<ReceiveCommand> filterCommands(final Result want) {
+	protected List<ReceiveCommand> filterCommands(Result want) {
 		return ReceiveCommand.filter(commands, want);
 	}
 
-	/** Execute commands to update references. */
+	/**
+	 * Execute commands to update references.
+	 */
 	protected void executeCommands() {
 		List<ReceiveCommand> toApply = filterCommands(Result.NOT_ATTEMPTED);
 		if (toApply.isEmpty())
@@ -1683,7 +1807,7 @@ protected void executeCommands() {
 	 *            an error that occurred during unpacking, or {@code null}
 	 * @param out
 	 *            the reporter for sending the status strings.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             an error occurred writing the status report.
 	 */
 	protected void sendStatusReport(final boolean forClient,
@@ -1691,7 +1815,7 @@ protected void sendStatusReport(final boolean forClient,
 		if (unpackError != null) {
 			out.sendString("unpack error " + unpackError.getMessage()); //$NON-NLS-1$
 			if (forClient) {
-				for (final ReceiveCommand cmd : commands) {
+				for (ReceiveCommand cmd : commands) {
 					out.sendString("ng " + cmd.getRefName() //$NON-NLS-1$
 							+ " n/a (unpacker error)"); //$NON-NLS-1$
 				}
@@ -1701,7 +1825,7 @@ protected void sendStatusReport(final boolean forClient,
 
 		if (forClient)
 			out.sendString("unpack ok"); //$NON-NLS-1$
-		for (final ReceiveCommand cmd : commands) {
+		for (ReceiveCommand cmd : commands) {
 			if (cmd.getResult() == Result.OK) {
 				if (forClient)
 					out.sendString("ok " + cmd.getRefName()); //$NON-NLS-1$
@@ -1770,7 +1894,7 @@ else if (cmd.getMessage().length() == Constants.OBJECT_ID_STRING_LENGTH) {
 	/**
 	 * Close and flush (if necessary) the underlying streams.
 	 *
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 */
 	protected void close() throws IOException {
 		if (sideBand) {
@@ -1802,7 +1926,7 @@ protected void close() throws IOException {
 	/**
 	 * Release any resources used by this object.
 	 *
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the pack could not be unlocked.
 	 */
 	protected void release() throws IOException {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BundleFetchConnection.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BundleFetchConnection.java
index f37ba01..449f529 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BundleFetchConnection.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BundleFetchConnection.java
@@ -47,8 +47,6 @@
 
 package org.eclipse.jgit.transport;
 
-import static org.eclipse.jgit.lib.RefDatabase.ALL;
-
 import java.io.BufferedInputStream;
 import java.io.IOException;
 import java.io.InputStream;
@@ -98,7 +96,7 @@ class BundleFetchConnection extends BaseFetchConnection {
 
 	private PackLock packLock;
 
-	BundleFetchConnection(Transport transportBundle, final InputStream src) throws TransportException {
+	BundleFetchConnection(Transport transportBundle, InputStream src) throws TransportException {
 		transport = transportBundle;
 		bin = new BufferedInputStream(src);
 		try {
@@ -155,12 +153,12 @@ private void readBundleV2() throws IOException {
 		available(avail);
 	}
 
-	private PackProtocolException duplicateAdvertisement(final String name) {
+	private PackProtocolException duplicateAdvertisement(String name) {
 		return new PackProtocolException(transport.uri,
 				MessageFormat.format(JGitText.get().duplicateAdvertisementsOf, name));
 	}
 
-	private String readLine(final byte[] hdrbuf) throws IOException {
+	private String readLine(byte[] hdrbuf) throws IOException {
 		StringBuilder line = new StringBuilder();
 		boolean done = false;
 		while (!done) {
@@ -180,11 +178,13 @@ private String readLine(final byte[] hdrbuf) throws IOException {
 		return line.toString();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public boolean didFetchTestConnectivity() {
 		return false;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected void doFetch(final ProgressMonitor monitor,
 			final Collection<Ref> want, final Set<ObjectId> have)
@@ -208,11 +208,13 @@ protected void doFetch(final ProgressMonitor monitor,
 		}
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	public void setPackLockMessage(final String message) {
+	public void setPackLockMessage(String message) {
 		lockMessage = message;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public Collection<PackLock> getPackLocks() {
 		if (packLock != null)
@@ -224,13 +226,13 @@ private void verifyPrerequisites() throws TransportException {
 		if (prereqs.isEmpty())
 			return;
 
-		try (final RevWalk rw = new RevWalk(transport.local)) {
+		try (RevWalk rw = new RevWalk(transport.local)) {
 			final RevFlag PREREQ = rw.newFlag("PREREQ"); //$NON-NLS-1$
 			final RevFlag SEEN = rw.newFlag("SEEN"); //$NON-NLS-1$
 
 			final Map<ObjectId, String> missing = new HashMap<>();
 			final List<RevObject> commits = new ArrayList<>();
-			for (final Map.Entry<ObjectId, String> e : prereqs.entrySet()) {
+			for (Map.Entry<ObjectId, String> e : prereqs.entrySet()) {
 				ObjectId p = e.getKey();
 				try {
 					final RevCommit c = rw.parseCommit(p);
@@ -250,13 +252,13 @@ private void verifyPrerequisites() throws TransportException {
 				throw new MissingBundlePrerequisiteException(transport.uri,
 						missing);
 
-			Map<String, Ref> localRefs;
+			List<Ref> localRefs;
 			try {
-				localRefs = transport.local.getRefDatabase().getRefs(ALL);
+				localRefs = transport.local.getRefDatabase().getRefs();
 			} catch (IOException e) {
 				throw new TransportException(transport.uri, e.getMessage(), e);
 			}
-			for (final Ref r : localRefs.values()) {
+			for (Ref r : localRefs) {
 				try {
 					rw.markStart(rw.parseCommit(r.getObjectId()));
 				} catch (IOException readError) {
@@ -280,7 +282,7 @@ private void verifyPrerequisites() throws TransportException {
 			}
 
 			if (remaining > 0) {
-				for (final RevObject o : commits) {
+				for (RevObject o : commits) {
 					if (!o.has(SEEN))
 						missing.put(o, prereqs.get(o));
 				}
@@ -290,6 +292,7 @@ private void verifyPrerequisites() throws TransportException {
 		}
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void close() {
 		if (bin != null) {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BundleWriter.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BundleWriter.java
index 0920f21..f2a261b 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BundleWriter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BundleWriter.java
@@ -70,7 +70,7 @@
  * <p>
  * Bundles generated by this class can be later read in from a file URI using
  * the bundle transport, or from an application controlled buffer by the more
- * generic {@link TransportBundleStream}.
+ * generic {@link org.eclipse.jgit.transport.TransportBundleStream}.
  * <p>
  * Applications creating bundles need to call one or more <code>include</code>
  * calls to reflect which objects should be available as refs in the bundle for
@@ -151,7 +151,7 @@ public void setPackConfig(PackConfig pc) {
 	 * @param id
 	 *            object to pack. Multiple refs may point to the same object.
 	 */
-	public void include(final String name, final AnyObjectId id) {
+	public void include(String name, AnyObjectId id) {
 		boolean validRefName = Repository.isValidRefName(name) || Constants.HEAD.equals(name);
 		if (!validRefName)
 			throw new IllegalArgumentException(MessageFormat.format(JGitText.get().invalidRefName, name));
@@ -169,7 +169,7 @@ public void include(final String name, final AnyObjectId id) {
 	 * @param r
 	 *            the ref to include.
 	 */
-	public void include(final Ref r) {
+	public void include(Ref r) {
 		include(r.getName(), r.getObjectId());
 
 		if (r.getPeeledObjectId() != null)
@@ -192,7 +192,7 @@ else if (r.getObjectId() != null
 	 *            parsed and not disposed in order to maximize the amount of
 	 *            debugging information available in the bundle stream.
 	 */
-	public void assume(final RevCommit c) {
+	public void assume(RevCommit c) {
 		if (c != null)
 			assume.add(c);
 	}
@@ -208,13 +208,10 @@ public void assume(final RevCommit c) {
 	 *            the stream the bundle is written to. The stream should be
 	 *            buffered by the caller. The caller is responsible for closing
 	 *            the stream.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             an error occurred reading a local object's data to include in
 	 *             the bundle, or writing compressed object data to the output
 	 *             stream.
-	 * @throws WriteAbortedException
-	 *             the write operation is aborted by
-	 *             {@link ObjectCountCallback}.
 	 */
 	public void writeBundle(ProgressMonitor monitor, OutputStream os)
 			throws IOException {
@@ -224,7 +221,7 @@ public void writeBundle(ProgressMonitor monitor, OutputStream os)
 			final HashSet<ObjectId> inc = new HashSet<>();
 			final HashSet<ObjectId> exc = new HashSet<>();
 			inc.addAll(include.values());
-			for (final RevCommit r : assume)
+			for (RevCommit r : assume)
 				exc.add(r.getId());
 			packWriter.setIndexDisabled(true);
 			packWriter.setDeltaBaseAsOffset(true);
@@ -239,7 +236,7 @@ public void writeBundle(ProgressMonitor monitor, OutputStream os)
 			w.write('\n');
 
 			final char[] tmp = new char[Constants.OBJECT_ID_STRING_LENGTH];
-			for (final RevCommit a : assume) {
+			for (RevCommit a : assume) {
 				w.write('-');
 				a.copyTo(tmp, w);
 				if (a.getRawBuffer() != null) {
@@ -248,7 +245,7 @@ public void writeBundle(ProgressMonitor monitor, OutputStream os)
 				}
 				w.write('\n');
 			}
-			for (final Map.Entry<String, ObjectId> e : include.entrySet()) {
+			for (Map.Entry<String, ObjectId> e : include.entrySet()) {
 				e.getValue().copyTo(tmp, w);
 				w.write(' ');
 				w.write(e.getKey());
@@ -270,17 +267,16 @@ private PackWriter newPackWriter() {
 	}
 
 	/**
-	 * Set the {@link ObjectCountCallback}.
+	 * Set the {@link org.eclipse.jgit.transport.ObjectCountCallback}.
 	 * <p>
 	 * It should be set before calling
 	 * {@link #writeBundle(ProgressMonitor, OutputStream)}.
 	 * <p>
 	 * This callback will be passed on to
-	 * {@link PackWriter#setObjectCountCallback}.
+	 * {@link org.eclipse.jgit.internal.storage.pack.PackWriter#setObjectCountCallback}.
 	 *
 	 * @param callback
 	 *            the callback to set
-	 *
 	 * @return this object for chaining.
 	 * @since 4.1
 	 */
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/ChainingCredentialsProvider.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/ChainingCredentialsProvider.java
index 8cb3d60..9f05d5a 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/ChainingCredentialsProvider.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/ChainingCredentialsProvider.java
@@ -72,11 +72,7 @@ public ChainingCredentialsProvider(CredentialsProvider... providers) {
 				Arrays.asList(providers));
 	}
 
-	/**
-	 * @return {@code true} if any of the credential providers in the list is
-	 *         interactive, otherwise {@code false}
-	 * @see org.eclipse.jgit.transport.CredentialsProvider#isInteractive()
-	 */
+	/** {@inheritDoc} */
 	@Override
 	public boolean isInteractive() {
 		for (CredentialsProvider p : credentialProviders)
@@ -85,11 +81,7 @@ public boolean isInteractive() {
 		return false;
 	}
 
-	/**
-	 * @return {@code true} if any of the credential providers in the list
-	 *         supports the requested items, otherwise {@code false}
-	 * @see org.eclipse.jgit.transport.CredentialsProvider#supports(org.eclipse.jgit.transport.CredentialItem[])
-	 */
+	/** {@inheritDoc} */
 	@Override
 	public boolean supports(CredentialItem... items) {
 		for (CredentialsProvider p : credentialProviders)
@@ -99,11 +91,11 @@ public boolean supports(CredentialItem... items) {
 	}
 
 	/**
+	 * {@inheritDoc}
+	 * <p>
 	 * Populates the credential items with the credentials provided by the first
 	 * credential provider in the list which populates them with non-null values
 	 *
-	 * @return {@code true} if any of the credential providers in the list
-	 *         supports the requested items, otherwise {@code false}
 	 * @see org.eclipse.jgit.transport.CredentialsProvider#supports(org.eclipse.jgit.transport.CredentialItem[])
 	 */
 	@Override
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/Connection.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/Connection.java
index 9a272a4..d4c514e 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/Connection.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/Connection.java
@@ -95,9 +95,11 @@ public interface Connection extends AutoCloseable {
 	 *            name of the ref to obtain.
 	 * @return the requested ref; null if the remote did not advertise this ref.
 	 */
-	public Ref getRef(final String name);
+	public Ref getRef(String name);
 
 	/**
+	 * {@inheritDoc}
+	 * <p>
 	 * Close any resources used by this connection.
 	 * <p>
 	 * If the remote repository is contacted by a network socket this method
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/CredentialItem.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/CredentialItem.java
index 88e075a..3a74f1d 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/CredentialItem.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/CredentialItem.java
@@ -48,14 +48,19 @@
 import org.eclipse.jgit.internal.JGitText;
 
 /**
- * A credential requested from a {@link CredentialsProvider}.
+ * A credential requested from a
+ * {@link org.eclipse.jgit.transport.CredentialsProvider}.
  *
  * Most users should work with the specialized subclasses:
  * <ul>
- * <li>{@link Username} for usernames</li>
- * <li>{@link Password} for passwords</li>
- * <li>{@link StringType} for other general string information</li>
- * <li>{@link CharArrayType} for other general secret information</li>
+ * <li>{@link org.eclipse.jgit.transport.CredentialItem.Username} for
+ * usernames</li>
+ * <li>{@link org.eclipse.jgit.transport.CredentialItem.Password} for
+ * passwords</li>
+ * <li>{@link org.eclipse.jgit.transport.CredentialItem.StringType} for other
+ * general string information</li>
+ * <li>{@link org.eclipse.jgit.transport.CredentialItem.CharArrayType} for other
+ * general secret information</li>
  * </ul>
  *
  * This class is not thread-safe. Applications should construct their own
@@ -83,17 +88,27 @@ public CredentialItem(String promptText, boolean maskValue) {
 		this.valueSecure = maskValue;
 	}
 
-	/** @return prompt to display to the user. */
+	/**
+	 * Get prompt to display to the user.
+	 *
+	 * @return prompt to display to the user.
+	 */
 	public String getPromptText() {
 		return promptText;
 	}
 
-	/** @return true if the value should be masked when entered. */
+	/**
+	 * Whether the value should be masked when entered.
+	 *
+	 * @return true if the value should be masked when entered.
+	 */
 	public boolean isValueSecure() {
 		return valueSecure;
 	}
 
-	/** Clear the stored value, destroying it as much as possible. */
+	/**
+	 * Clear the stored value, destroying it as much as possible.
+	 */
 	public abstract void clear();
 
 	/**
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/CredentialsProvider.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/CredentialsProvider.java
index 4800f68..8115946 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/CredentialsProvider.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/CredentialsProvider.java
@@ -52,9 +52,10 @@
  * Provide credentials for use in connecting to Git repositories.
  *
  * Implementors are strongly encouraged to support at least the minimal
- * {@link CredentialItem.Username} and {@link CredentialItem.Password} items.
- * More sophisticated implementors may implement additional types, such as
- * {@link CredentialItem.StringType}.
+ * {@link org.eclipse.jgit.transport.CredentialItem.Username} and
+ * {@link org.eclipse.jgit.transport.CredentialItem.Password} items. More
+ * sophisticated implementors may implement additional types, such as
+ * {@link org.eclipse.jgit.transport.CredentialItem.StringType}.
  *
  * CredentialItems are usually presented in bulk, allowing implementors to
  * combine them into a single UI widget and streamline the authentication
@@ -65,7 +66,11 @@
 public abstract class CredentialsProvider {
 	private static volatile CredentialsProvider defaultProvider;
 
-	/** @return the default credentials provider, or null. */
+	/**
+	 * Get the default credentials provider, or null.
+	 *
+	 * @return the default credentials provider, or null.
+	 */
 	public static CredentialsProvider getDefault() {
 		return defaultProvider;
 	}
@@ -81,6 +86,8 @@ public static void setDefault(CredentialsProvider p) {
 	}
 
 	/**
+	 * Whether any of the passed items is null
+	 *
 	 * @param items
 	 *            credential items to check
 	 * @return {@code true} if any of the passed items is null, {@code false}
@@ -106,12 +113,14 @@ protected static boolean isAnyNull(CredentialItem... items) {
 	public abstract boolean isInteractive();
 
 	/**
-	 * Check if the provider can supply the necessary {@link CredentialItem}s.
+	 * Check if the provider can supply the necessary
+	 * {@link org.eclipse.jgit.transport.CredentialItem}s.
 	 *
 	 * @param items
 	 *            the items the application requires to complete authentication.
-	 * @return {@code true} if this {@link CredentialsProvider} supports all of
-	 *         the items supplied.
+	 * @return {@code true} if this
+	 *         {@link org.eclipse.jgit.transport.CredentialsProvider} supports
+	 *         all of the items supplied.
 	 */
 	public abstract boolean supports(CredentialItem... items);
 
@@ -125,7 +134,7 @@ protected static boolean isAnyNull(CredentialItem... items) {
 	 * @return {@code true} if the request was successful and values were
 	 *         supplied; {@code false} if the user canceled the request and did
 	 *         not supply all requested values.
-	 * @throws UnsupportedCredentialItem
+	 * @throws org.eclipse.jgit.errors.UnsupportedCredentialItem
 	 *             if one of the items supplied is not supported.
 	 */
 	public abstract boolean get(URIish uri, CredentialItem... items)
@@ -141,7 +150,7 @@ public abstract boolean get(URIish uri, CredentialItem... items)
 	 * @return {@code true} if the request was successful and values were
 	 *         supplied; {@code false} if the user canceled the request and did
 	 *         not supply all requested values.
-	 * @throws UnsupportedCredentialItem
+	 * @throws org.eclipse.jgit.errors.UnsupportedCredentialItem
 	 *             if one of the items supplied is not supported.
 	 */
 	public boolean get(URIish uri, List<CredentialItem> items)
@@ -153,6 +162,7 @@ public boolean get(URIish uri, List<CredentialItem> items)
 	 * Reset the credentials provider for the given URI
 	 *
 	 * @param uri
+	 *            a {@link org.eclipse.jgit.transport.URIish} object.
 	 */
 	public void reset(URIish uri) {
 		// default does nothing
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/CredentialsProviderUserInfo.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/CredentialsProviderUserInfo.java
index 8358635..d901021 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/CredentialsProviderUserInfo.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/CredentialsProviderUserInfo.java
@@ -51,7 +51,10 @@
 import com.jcraft.jsch.UIKeyboardInteractive;
 import com.jcraft.jsch.UserInfo;
 
-/** A JSch {@link UserInfo} adapter for a {@link CredentialsProvider}. */
+/**
+ * A JSch {@link com.jcraft.jsch.UserInfo} adapter for a
+ * {@link org.eclipse.jgit.transport.CredentialsProvider}.
+ */
 public class CredentialsProviderUserInfo implements UserInfo,
 		UIKeyboardInteractive {
 	private final URIish uri;
@@ -85,16 +88,19 @@ private static URIish createURI(Session session) {
 		return uri;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public String getPassword() {
 		return password;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public String getPassphrase() {
 		return passphrase;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public boolean promptPassphrase(String msg) {
 		CredentialItem.StringType v = newPrompt(msg);
@@ -107,6 +113,7 @@ public boolean promptPassphrase(String msg) {
 		}
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public boolean promptPassword(String msg) {
 		CredentialItem.Password p = new CredentialItem.Password(msg);
@@ -123,17 +130,20 @@ private CredentialItem.StringType newPrompt(String msg) {
 		return new CredentialItem.StringType(msg, true);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public boolean promptYesNo(String msg) {
 		CredentialItem.YesNoType v = new CredentialItem.YesNoType(msg);
 		return provider.get(uri, v) && v.getValue();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void showMessage(String msg) {
 		provider.get(uri, new CredentialItem.InformationalMessage(msg));
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public String[] promptKeyboardInteractive(String destination, String name,
 			String instruction, String[] prompt, boolean[] echo) {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/Daemon.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/Daemon.java
index 896b10a..7289ce7 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/Daemon.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/Daemon.java
@@ -53,7 +53,9 @@
 import java.net.SocketAddress;
 import java.net.SocketException;
 import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.Collection;
 
+import org.eclipse.jgit.annotations.Nullable;
 import org.eclipse.jgit.errors.RepositoryNotFoundException;
 import org.eclipse.jgit.internal.JGitText;
 import org.eclipse.jgit.lib.PersonIdent;
@@ -65,7 +67,9 @@
 import org.eclipse.jgit.transport.resolver.ServiceNotEnabledException;
 import org.eclipse.jgit.transport.resolver.UploadPackFactory;
 
-/** Basic daemon for the anonymous <code>git://</code> transport protocol. */
+/**
+ * Basic daemon for the anonymous <code>git://</code> transport protocol.
+ */
 public class Daemon {
 	/** 9418: IANA assigned port number for Git. */
 	public static final int DEFAULT_PORT = 9418;
@@ -90,7 +94,9 @@ public class Daemon {
 
 	volatile ReceivePackFactory<DaemonClient> receivePackFactory;
 
-	/** Configure a daemon to listen on any available network port. */
+	/**
+	 * Configure a daemon to listen on any available network port.
+	 */
 	public Daemon() {
 		this(null);
 	}
@@ -103,7 +109,7 @@ public Daemon() {
 	 *            port will be chosen on all network interfaces.
 	 */
 	@SuppressWarnings("unchecked")
-	public Daemon(final InetSocketAddress addr) {
+	public Daemon(InetSocketAddress addr) {
 		myAddress = addr;
 		processors = new ThreadGroup("Git-Daemon"); //$NON-NLS-1$
 
@@ -149,12 +155,17 @@ public ReceivePack create(DaemonClient req, Repository db)
 
 					@Override
 					protected void execute(final DaemonClient dc,
-							final Repository db) throws IOException,
+							final Repository db,
+							@Nullable Collection<String> extraParameters)
+							throws IOException,
 							ServiceNotEnabledException,
 							ServiceNotAuthorizedException {
 						UploadPack up = uploadPackFactory.create(dc, db);
 						InputStream in = dc.getInputStream();
 						OutputStream out = dc.getOutputStream();
+						if (extraParameters != null) {
+							up.setExtraParameters(extraParameters);
+						}
 						up.upload(in, out, null);
 					}
 				}, new DaemonService("receive-pack", "receivepack") { //$NON-NLS-1$ //$NON-NLS-2$
@@ -164,7 +175,9 @@ protected void execute(final DaemonClient dc,
 
 					@Override
 					protected void execute(final DaemonClient dc,
-							final Repository db) throws IOException,
+							final Repository db,
+							@Nullable Collection<String> extraParameters)
+							throws IOException,
 							ServiceNotEnabledException,
 							ServiceNotAuthorizedException {
 						ReceivePack rp = receivePackFactory.create(dc, db);
@@ -175,7 +188,11 @@ protected void execute(final DaemonClient dc,
 				} };
 	}
 
-	/** @return the address connections are received on. */
+	/**
+	 * Get the address connections are received on.
+	 *
+	 * @return the address connections are received on.
+	 */
 	public synchronized InetSocketAddress getAddress() {
 		return myAddress;
 	}
@@ -192,14 +209,18 @@ public synchronized InetSocketAddress getAddress() {
 	public synchronized DaemonService getService(String name) {
 		if (!name.startsWith("git-")) //$NON-NLS-1$
 			name = "git-" + name; //$NON-NLS-1$
-		for (final DaemonService s : services) {
+		for (DaemonService s : services) {
 			if (s.getCommandName().equals(name))
 				return s;
 		}
 		return null;
 	}
 
-	/** @return timeout (in seconds) before aborting an IO operation. */
+	/**
+	 * Get timeout (in seconds) before aborting an IO operation.
+	 *
+	 * @return timeout (in seconds) before aborting an IO operation.
+	 */
 	public int getTimeout() {
 		return timeout;
 	}
@@ -212,11 +233,15 @@ public int getTimeout() {
 	 *            before aborting an IO read or write operation with the
 	 *            connected client.
 	 */
-	public void setTimeout(final int seconds) {
+	public void setTimeout(int seconds) {
 		timeout = seconds;
 	}
 
-	/** @return configuration controlling packing, may be null. */
+	/**
+	 * Get configuration controlling packing, may be null.
+	 *
+	 * @return configuration controlling packing, may be null.
+	 */
 	public PackConfig getPackConfig() {
 		return packConfig;
 	}
@@ -333,9 +358,9 @@ public void shutDown() {
 	/**
 	 * Start this daemon on a background thread.
 	 *
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the server socket could not be opened.
-	 * @throws IllegalStateException
+	 * @throws java.lang.IllegalStateException
 	 *             the daemon is already running.
 	 */
 	public synchronized void start() throws IOException {
@@ -359,7 +384,11 @@ private synchronized void clearThread() {
 		acceptThread = null;
 	}
 
-	/** @return true if this daemon is receiving connections. */
+	/**
+	 * Whether this daemon is receiving connections.
+	 *
+	 * @return {@code true} if this daemon is receiving connections.
+	 */
 	public synchronized boolean isRunning() {
 		return acceptThread != null && acceptThread.isRunning();
 	}
@@ -376,9 +405,8 @@ public synchronized void stop() {
 	/**
 	 * Stops this daemon and waits until it's acceptor thread has finished.
 	 *
-	 * @throws InterruptedException
+	 * @throws java.lang.InterruptedException
 	 *             if waiting for the acceptor thread is interrupted
-	 *
 	 * @since 4.9
 	 */
 	public void stopAndWait() throws InterruptedException {
@@ -392,7 +420,7 @@ public void stopAndWait() throws InterruptedException {
 		}
 	}
 
-	void startClient(final Socket s) {
+	void startClient(Socket s) {
 		final DaemonClient dc = new DaemonClient(this);
 
 		final SocketAddress peer = s.getRemoteSocketAddress();
@@ -426,8 +454,8 @@ public void run() {
 		}.start();
 	}
 
-	synchronized DaemonService matchService(final String cmd) {
-		for (final DaemonService d : services) {
+	synchronized DaemonService matchService(String cmd) {
+		for (DaemonService d : services) {
 			if (d.handles(cmd))
 				return d;
 		}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/DaemonClient.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/DaemonClient.java
index 23e3379..51c4918 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/DaemonClient.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/DaemonClient.java
@@ -50,11 +50,15 @@
 import java.io.OutputStream;
 import java.net.InetAddress;
 import java.net.Socket;
+import java.util.Arrays;
+import java.util.Collection;
 
 import org.eclipse.jgit.transport.resolver.ServiceNotAuthorizedException;
 import org.eclipse.jgit.transport.resolver.ServiceNotEnabledException;
 
-/** Active network client of {@link Daemon}. */
+/**
+ * Active network client of {@link org.eclipse.jgit.transport.Daemon}.
+ */
 public class DaemonClient {
 	private final Daemon daemon;
 
@@ -64,35 +68,51 @@ public class DaemonClient {
 
 	private OutputStream rawOut;
 
-	DaemonClient(final Daemon d) {
+	DaemonClient(Daemon d) {
 		daemon = d;
 	}
 
-	void setRemoteAddress(final InetAddress ia) {
+	void setRemoteAddress(InetAddress ia) {
 		peer = ia;
 	}
 
-	/** @return the daemon which spawned this client. */
+	/**
+	 * Get the daemon which spawned this client.
+	 *
+	 * @return the daemon which spawned this client.
+	 */
 	public Daemon getDaemon() {
 		return daemon;
 	}
 
-	/** @return Internet address of the remote client. */
+	/**
+	 * Get Internet address of the remote client.
+	 *
+	 * @return Internet address of the remote client.
+	 */
 	public InetAddress getRemoteAddress() {
 		return peer;
 	}
 
-	/** @return input stream to read from the connected client. */
+	/**
+	 * Get input stream to read from the connected client.
+	 *
+	 * @return input stream to read from the connected client.
+	 */
 	public InputStream getInputStream() {
 		return rawIn;
 	}
 
-	/** @return output stream to send data to the connected client. */
+	/**
+	 * Get output stream to send data to the connected client.
+	 *
+	 * @return output stream to send data to the connected client.
+	 */
 	public OutputStream getOutputStream() {
 		return rawOut;
 	}
 
-	void execute(final Socket sock) throws IOException,
+	void execute(Socket sock) throws IOException,
 			ServiceNotEnabledException, ServiceNotAuthorizedException {
 		rawIn = new BufferedInputStream(sock.getInputStream());
 		rawOut = new BufferedOutputStream(sock.getOutputStream());
@@ -100,6 +120,14 @@ void execute(final Socket sock) throws IOException,
 		if (0 < daemon.getTimeout())
 			sock.setSoTimeout(daemon.getTimeout() * 1000);
 		String cmd = new PacketLineIn(rawIn).readStringRaw();
+
+		Collection<String> extraParameters = null;
+
+		int nulnul = cmd.indexOf("\0\0"); //$NON-NLS-1$
+		if (nulnul != -1) {
+			extraParameters = Arrays.asList(cmd.substring(nulnul + 2).split("\0")); //$NON-NLS-1$
+		}
+
 		final int nul = cmd.indexOf('\0');
 		if (nul >= 0) {
 			// Newer clients hide a "host" header behind this byte.
@@ -113,6 +141,6 @@ void execute(final Socket sock) throws IOException,
 		if (srv == null)
 			return;
 		sock.setSoTimeout(0);
-		srv.execute(this, cmd);
+		srv.execute(this, cmd, extraParameters);
 	}
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/DaemonService.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/DaemonService.java
index 566153a..6d2bee8 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/DaemonService.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/DaemonService.java
@@ -45,14 +45,19 @@
 package org.eclipse.jgit.transport;
 
 import java.io.IOException;
+import java.util.Collection;
 
+import org.eclipse.jgit.annotations.Nullable;
 import org.eclipse.jgit.lib.Config;
 import org.eclipse.jgit.lib.Config.SectionParser;
 import org.eclipse.jgit.lib.Repository;
 import org.eclipse.jgit.transport.resolver.ServiceNotAuthorizedException;
 import org.eclipse.jgit.transport.resolver.ServiceNotEnabledException;
 
-/** A service exposed by {@link Daemon} over anonymous <code>git://</code>. */
+/**
+ * A service exposed by {@link org.eclipse.jgit.transport.Daemon} over anonymous
+ * <code>git://</code>.
+ */
 public abstract class DaemonService {
 	private final String command;
 
@@ -62,7 +67,7 @@ public abstract class DaemonService {
 
 	private boolean overridable;
 
-	DaemonService(final String cmdName, final String cfgName) {
+	DaemonService(String cmdName, String cfgName) {
 		command = cmdName.startsWith("git-") ? cmdName : "git-" + cmdName; //$NON-NLS-1$ //$NON-NLS-2$
 		configKey = cfg -> new ServiceConfig(DaemonService.this, cfg, cfgName);
 		overridable = true;
@@ -77,34 +82,55 @@ private static class ServiceConfig {
 		}
 	}
 
-	/** @return is this service enabled for invocation? */
+	/**
+	 * Whether this service is enabled for invocation.
+	 *
+	 * @return whether this service is enabled for invocation.
+	 */
 	public boolean isEnabled() {
 		return enabled;
 	}
 
 	/**
+	 * Set if it is allowed to use this service
+	 *
 	 * @param on
-	 *            true to allow this service to be used; false to deny it.
+	 *            {@code true} to allow this service to be used; {@code false}
+	 *            to deny it.
 	 */
-	public void setEnabled(final boolean on) {
+	public void setEnabled(boolean on) {
 		enabled = on;
 	}
 
 	/** @return can this service be configured in the repository config file? */
+	/**
+	 * Whether this service can be configured in the repository config file
+	 *
+	 * @return whether this service can be configured in the repository config
+	 *         file
+	 */
 	public boolean isOverridable() {
 		return overridable;
 	}
 
 	/**
+	 * Whether to permit repositories to override this service's enabled state
+	 * with the <code>daemon.servicename</code> config setting.
+	 *
 	 * @param on
-	 *            true to permit repositories to override this service's enabled
-	 *            state with the <code>daemon.servicename</code> config setting.
+	 *            {@code true} to permit repositories to override this service's
+	 *            enabled state with the <code>daemon.servicename</code> config
+	 *            setting.
 	 */
-	public void setOverridable(final boolean on) {
+	public void setOverridable(boolean on) {
 		overridable = on;
 	}
 
-	/** @return name of the command requested by clients. */
+	/**
+	 * Get name of the command requested by clients.
+	 *
+	 * @return name of the command requested by clients.
+	 */
 	public String getCommandName() {
 		return command;
 	}
@@ -116,43 +142,37 @@ public String getCommandName() {
 	 *            input line from the client.
 	 * @return true if this command can accept the given command line.
 	 */
-	public boolean handles(final String commandLine) {
+	public boolean handles(String commandLine) {
 		return command.length() + 1 < commandLine.length()
 				&& commandLine.charAt(command.length()) == ' '
 				&& commandLine.startsWith(command);
 	}
 
-	void execute(final DaemonClient client, final String commandLine)
+	void execute(DaemonClient client, String commandLine,
+			@Nullable Collection<String> extraParameters)
 			throws IOException, ServiceNotEnabledException,
 			ServiceNotAuthorizedException {
 		final String name = commandLine.substring(command.length() + 1);
-		Repository db;
-		try {
-			db = client.getDaemon().openRepository(client, name);
+		try (Repository db = client.getDaemon().openRepository(client, name)) {
+			if (isEnabledFor(db)) {
+				execute(client, db, extraParameters);
+			}
 		} catch (ServiceMayNotContinueException e) {
 			// An error when opening the repo means the client is expecting a ref
 			// advertisement, so use that style of error.
 			PacketLineOut pktOut = new PacketLineOut(client.getOutputStream());
 			pktOut.writeString("ERR " + e.getMessage() + "\n"); //$NON-NLS-1$ //$NON-NLS-2$
-			db = null;
-		}
-		if (db == null)
-			return;
-		try {
-			if (isEnabledFor(db))
-				execute(client, db);
-		} finally {
-			db.close();
 		}
 	}
 
-	private boolean isEnabledFor(final Repository db) {
+	private boolean isEnabledFor(Repository db) {
 		if (isOverridable())
 			return db.getConfig().get(configKey).enabled;
 		return isEnabled();
 	}
 
-	abstract void execute(DaemonClient client, Repository db)
+	abstract void execute(DaemonClient client, Repository db,
+			@Nullable Collection<String> extraParameters)
 			throws IOException, ServiceNotEnabledException,
 			ServiceNotAuthorizedException;
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/DefaultSshSessionFactory.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/DefaultSshSessionFactory.java
index 23fd7e3..5f74e72 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/DefaultSshSessionFactory.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/DefaultSshSessionFactory.java
@@ -59,8 +59,9 @@
  * connection will immediately fail.
  */
 class DefaultSshSessionFactory extends JschConfigSessionFactory {
+	/** {@inheritDoc} */
 	@Override
-	protected void configure(final OpenSshConfig.Host hc, final Session session) {
+	protected void configure(OpenSshConfig.Host hc, Session session) {
 		// No additional configuration required.
 	}
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/FetchConnection.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/FetchConnection.java
index 2d04240..f0c45d5 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/FetchConnection.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/FetchConnection.java
@@ -64,9 +64,9 @@
  * one-way object transfer service to copy objects from the remote repository
  * into this local repository.
  * <p>
- * Instances of a FetchConnection must be created by a {@link Transport} that
- * implements a specific object transfer protocol that both sides of the
- * connection understand.
+ * Instances of a FetchConnection must be created by a
+ * {@link org.eclipse.jgit.transport.Transport} that implements a specific
+ * object transfer protocol that both sides of the connection understand.
  * <p>
  * FetchConnection instances are not thread safe and may be accessed by only one
  * thread at a time.
@@ -78,7 +78,7 @@ public interface FetchConnection extends Connection {
 	 * Fetch objects we don't have but that are reachable from advertised refs.
 	 * <p>
 	 * Only one call per connection is allowed. Subsequent calls will result in
-	 * {@link TransportException}.
+	 * {@link org.eclipse.jgit.errors.TransportException}.
 	 * </p>
 	 * <p>
 	 * Implementations are free to use network connections as necessary to
@@ -87,7 +87,8 @@ public interface FetchConnection extends Connection {
 	 * avoid replacing/overwriting/duplicating an object already available in
 	 * the local destination repository. Locally available objects and packs
 	 * should always be preferred over remotely available objects and packs.
-	 * {@link Transport#isFetchThin()} should be honored if applicable.
+	 * {@link org.eclipse.jgit.transport.Transport#isFetchThin()} should be
+	 * honored if applicable.
 	 * </p>
 	 *
 	 * @param monitor
@@ -103,7 +104,7 @@ public interface FetchConnection extends Connection {
 	 *            repository, especially if they aren't yet reachable by the ref
 	 *            database. Connections should take this set as an addition to
 	 *            what is reachable through all Refs, not in replace of it.
-	 * @throws TransportException
+	 * @throws org.eclipse.jgit.errors.TransportException
 	 *             objects could not be copied due to a network failure,
 	 *             protocol error, or error on remote side, or connection was
 	 *             already used for fetch.
@@ -116,7 +117,7 @@ public void fetch(final ProgressMonitor monitor,
 	 * Fetch objects we don't have but that are reachable from advertised refs.
 	 * <p>
 	 * Only one call per connection is allowed. Subsequent calls will result in
-	 * {@link TransportException}.
+	 * {@link org.eclipse.jgit.errors.TransportException}.
 	 * </p>
 	 * <p>
 	 * Implementations are free to use network connections as necessary to
@@ -125,7 +126,8 @@ public void fetch(final ProgressMonitor monitor,
 	 * avoid replacing/overwriting/duplicating an object already available in
 	 * the local destination repository. Locally available objects and packs
 	 * should always be preferred over remotely available objects and packs.
-	 * {@link Transport#isFetchThin()} should be honored if applicable.
+	 * {@link org.eclipse.jgit.transport.Transport#isFetchThin()} should be
+	 * honored if applicable.
 	 * </p>
 	 *
 	 * @param monitor
@@ -143,7 +145,7 @@ public void fetch(final ProgressMonitor monitor,
 	 *            what is reachable through all Refs, not in replace of it.
 	 * @param out
 	 *            OutputStream to write sideband messages to
-	 * @throws TransportException
+	 * @throws org.eclipse.jgit.errors.TransportException
 	 *             objects could not be copied due to a network failure,
 	 *             protocol error, or error on remote side, or connection was
 	 *             already used for fetch.
@@ -157,11 +159,12 @@ public void fetch(final ProgressMonitor monitor,
 	 * Did the last {@link #fetch(ProgressMonitor, Collection, Set)} get tags?
 	 * <p>
 	 * Some Git aware transports are able to implicitly grab an annotated tag if
-	 * {@link TagOpt#AUTO_FOLLOW} or {@link TagOpt#FETCH_TAGS} was selected and
-	 * the object the tag peels to (references) was transferred as part of the
-	 * last {@link #fetch(ProgressMonitor, Collection, Set)} call. If it is
-	 * possible for such tags to have been included in the transfer this method
-	 * returns true, allowing the caller to attempt tag discovery.
+	 * {@link org.eclipse.jgit.transport.TagOpt#AUTO_FOLLOW} or
+	 * {@link org.eclipse.jgit.transport.TagOpt#FETCH_TAGS} was selected and the
+	 * object the tag peels to (references) was transferred as part of the last
+	 * {@link #fetch(ProgressMonitor, Collection, Set)} call. If it is possible
+	 * for such tags to have been included in the transfer this method returns
+	 * true, allowing the caller to attempt tag discovery.
 	 * <p>
 	 * By returning only true/false (and not the actual list of tags obtained)
 	 * the transport itself does not need to be aware of whether or not tags
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/FetchHeadRecord.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/FetchHeadRecord.java
index 421ef21..34ab361 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/FetchHeadRecord.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/FetchHeadRecord.java
@@ -63,7 +63,7 @@ class FetchHeadRecord {
 
 	URIish sourceURI;
 
-	void write(final Writer pw) throws IOException {
+	void write(Writer pw) throws IOException {
 		final String type;
 		final String name;
 		if (sourceName.startsWith(R_HEADS)) {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/FetchProcess.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/FetchProcess.java
index dd26fe5..ff183c8 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/FetchProcess.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/FetchProcess.java
@@ -106,12 +106,12 @@ class FetchProcess {
 
 	private Map<String, Ref> localRefs;
 
-	FetchProcess(final Transport t, final Collection<RefSpec> f) {
+	FetchProcess(Transport t, Collection<RefSpec> f) {
 		transport = t;
 		toFetch = f;
 	}
 
-	void execute(final ProgressMonitor monitor, final FetchResult result)
+	void execute(ProgressMonitor monitor, FetchResult result)
 			throws NotSupportedException, TransportException {
 		askFor.clear();
 		localUpdates.clear();
@@ -123,7 +123,7 @@ void execute(final ProgressMonitor monitor, final FetchResult result)
 			executeImp(monitor, result);
 		} finally {
 			try {
-			for (final PackLock lock : packLocks)
+			for (PackLock lock : packLocks)
 				lock.unlock();
 			} catch (IOException e) {
 				throw new TransportException(e.getMessage(), e);
@@ -139,7 +139,7 @@ private void executeImp(final ProgressMonitor monitor,
 			result.setAdvertisedRefs(transport.getURI(), conn.getRefsMap());
 			result.peerUserAgent = conn.getPeerUserAgent();
 			final Set<Ref> matched = new HashSet<>();
-			for (final RefSpec spec : toFetch) {
+			for (RefSpec spec : toFetch) {
 				if (spec.getSource() == null)
 					throw new TransportException(MessageFormat.format(
 							JGitText.get().sourceRefNotSpecifiedForRefspec, spec));
@@ -176,7 +176,7 @@ else if (tagopt == TagOpt.FETCH_TAGS)
 				//
 				have.addAll(askFor.keySet());
 				askFor.clear();
-				for (final Ref r : additionalTags) {
+				for (Ref r : additionalTags) {
 					ObjectId id = r.getPeeledObjectId();
 					if (id == null)
 						id = r.getObjectId();
@@ -198,7 +198,7 @@ else if (tagopt == TagOpt.FETCH_TAGS)
 				.newBatchUpdate()
 				.setAllowNonFastForwards(true)
 				.setRefLogMessage("fetch", true); //$NON-NLS-1$
-		try (final RevWalk walk = new RevWalk(transport.local)) {
+		try (RevWalk walk = new RevWalk(transport.local)) {
 			if (monitor instanceof BatchingProgressMonitor) {
 				((BatchingProgressMonitor) monitor).setDelayStart(
 						250, TimeUnit.MILLISECONDS);
@@ -239,7 +239,7 @@ else if (tagopt == TagOpt.FETCH_TAGS)
 		}
 	}
 
-	private void fetchObjects(final ProgressMonitor monitor)
+	private void fetchObjects(ProgressMonitor monitor)
 			throws TransportException {
 		try {
 			conn.setPackLockMessage("jgit fetch " + transport.uri); //$NON-NLS-1$
@@ -253,7 +253,7 @@ private void fetchObjects(final ProgressMonitor monitor)
 					JGitText.get().peerDidNotSupplyACompleteObjectGraph);
 	}
 
-	private void closeConnection(final FetchResult result) {
+	private void closeConnection(FetchResult result) {
 		if (conn != null) {
 			conn.close();
 			result.addMessages(conn.getMessages());
@@ -277,12 +277,12 @@ private void reopenConnection() throws NotSupportedException,
 		// new connection has offered to us.
 		//
 		final HashMap<ObjectId, Ref> avail = new HashMap<>();
-		for (final Ref r : conn.getRefs())
+		for (Ref r : conn.getRefs())
 			avail.put(r.getObjectId(), r);
 
 		final Collection<Ref> wants = new ArrayList<>(askFor.values());
 		askFor.clear();
-		for (final Ref want : wants) {
+		for (Ref want : wants) {
 			final Ref newRef = avail.get(want.getObjectId());
 			if (newRef != null) {
 				askFor.put(newRef.getObjectId(), newRef);
@@ -293,7 +293,7 @@ private void reopenConnection() throws NotSupportedException,
 		}
 	}
 
-	private void removeTrackingRefUpdate(final ObjectId want) {
+	private void removeTrackingRefUpdate(ObjectId want) {
 		final Iterator<TrackingRefUpdate> i = localUpdates.iterator();
 		while (i.hasNext()) {
 			final TrackingRefUpdate u = i.next();
@@ -302,7 +302,7 @@ private void removeTrackingRefUpdate(final ObjectId want) {
 		}
 	}
 
-	private void removeFetchHeadRecord(final ObjectId want) {
+	private void removeFetchHeadRecord(ObjectId want) {
 		final Iterator<FetchHeadRecord> i = fetchHeadUpdates.iterator();
 		while (i.hasNext()) {
 			final FetchHeadRecord fh = i.next();
@@ -311,21 +311,19 @@ private void removeFetchHeadRecord(final ObjectId want) {
 		}
 	}
 
-	private void updateFETCH_HEAD(final FetchResult result) throws IOException {
+	private void updateFETCH_HEAD(FetchResult result) throws IOException {
 		File meta = transport.local.getDirectory();
 		if (meta == null)
 			return;
 		final LockFile lock = new LockFile(new File(meta, "FETCH_HEAD")); //$NON-NLS-1$
 		try {
 			if (lock.lock()) {
-				final Writer w = new OutputStreamWriter(lock.getOutputStream());
-				try {
-					for (final FetchHeadRecord h : fetchHeadUpdates) {
+				try (Writer w = new OutputStreamWriter(
+						lock.getOutputStream())) {
+					for (FetchHeadRecord h : fetchHeadUpdates) {
 						h.write(w);
 						result.add(h);
 					}
-				} finally {
-					w.close();
 				}
 				lock.commit();
 			}
@@ -336,10 +334,10 @@ private void updateFETCH_HEAD(final FetchResult result) throws IOException {
 
 	private boolean askForIsComplete() throws TransportException {
 		try {
-			try (final ObjectWalk ow = new ObjectWalk(transport.local)) {
-				for (final ObjectId want : askFor.keySet())
+			try (ObjectWalk ow = new ObjectWalk(transport.local)) {
+				for (ObjectId want : askFor.keySet())
 					ow.markStart(ow.parseAny(want));
-				for (final Ref ref : localRefs().values())
+				for (Ref ref : localRefs().values())
 					ow.markUninteresting(ow.parseAny(ref.getObjectId()));
 				ow.checkConnectivity();
 			}
@@ -351,15 +349,15 @@ private boolean askForIsComplete() throws TransportException {
 		}
 	}
 
-	private void expandWildcard(final RefSpec spec, final Set<Ref> matched)
+	private void expandWildcard(RefSpec spec, Set<Ref> matched)
 			throws TransportException {
-		for (final Ref src : conn.getRefs()) {
+		for (Ref src : conn.getRefs()) {
 			if (spec.matchSource(src) && matched.add(src))
 				want(src, spec.expandFromSource(src));
 		}
 	}
 
-	private void expandSingle(final RefSpec spec, final Set<Ref> matched)
+	private void expandSingle(RefSpec spec, Set<Ref> matched)
 			throws TransportException {
 		String want = spec.getSource();
 		if (ObjectId.isId(want)) {
@@ -379,7 +377,7 @@ private void expandSingle(final RefSpec spec, final Set<Ref> matched)
 	private Collection<Ref> expandAutoFollowTags() throws TransportException {
 		final Collection<Ref> additionalTags = new ArrayList<>();
 		final Map<String, Ref> haveRefs = localRefs();
-		for (final Ref r : conn.getRefs()) {
+		for (Ref r : conn.getRefs()) {
 			if (!isTag(r))
 				continue;
 
@@ -403,7 +401,7 @@ private Collection<Ref> expandAutoFollowTags() throws TransportException {
 
 	private void expandFetchTags() throws TransportException {
 		final Map<String, Ref> haveRefs = localRefs();
-		for (final Ref r : conn.getRefs()) {
+		for (Ref r : conn.getRefs()) {
 			if (!isTag(r)) {
 				continue;
 			}
@@ -418,12 +416,12 @@ private void expandFetchTags() throws TransportException {
 		}
 	}
 
-	private void wantTag(final Ref r) throws TransportException {
+	private void wantTag(Ref r) throws TransportException {
 		want(r, new RefSpec().setSource(r.getName())
 				.setDestination(r.getName()).setForceUpdate(true));
 	}
 
-	private void want(final Ref src, final RefSpec spec)
+	private void want(Ref src, RefSpec spec)
 			throws TransportException {
 		final ObjectId newId = src.getObjectId();
 		if (newId == null) {
@@ -481,9 +479,12 @@ private Map<String, Ref> localRefs() throws TransportException {
 
 	private void deleteStaleTrackingRefs(FetchResult result,
 			BatchRefUpdate batch) throws IOException {
-		for (final Ref ref : localRefs().values()) {
+		for (Ref ref : localRefs().values()) {
+			if (ref.isSymbolic()) {
+				continue;
+			}
 			final String refname = ref.getName();
-			for (final RefSpec spec : toFetch) {
+			for (RefSpec spec : toFetch) {
 				if (spec.matchDestination(refname)) {
 					final RefSpec s = spec.expandFromDestination(refname);
 					if (result.getAdvertisedRef(s.getSource()) == null) {
@@ -508,11 +509,11 @@ private void deleteTrackingRef(final FetchResult result,
 		batch.addCommand(update.asReceiveCommand());
 	}
 
-	private static boolean isTag(final Ref r) {
+	private static boolean isTag(Ref r) {
 		return isTag(r.getName());
 	}
 
-	private static boolean isTag(final String name) {
+	private static boolean isTag(String name) {
 		return name.startsWith(Constants.R_TAGS);
 	}
 
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/FetchResult.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/FetchResult.java
index 2667ec3..ad4c5e9 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/FetchResult.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/FetchResult.java
@@ -68,7 +68,7 @@ public class FetchResult extends OperationResult {
 		submodules = new HashMap<>();
 	}
 
-	void add(final FetchHeadRecord r) {
+	void add(FetchHeadRecord r) {
 		if (!r.notForMerge)
 			forMerge.add(r);
 	}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/GitProtocolConstants.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/GitProtocolConstants.java
index 2031147..10cd775 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/GitProtocolConstants.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/GitProtocolConstants.java
@@ -108,6 +108,14 @@ public class GitProtocolConstants {
 	public static final String OPTION_SHALLOW = "shallow"; //$NON-NLS-1$
 
 	/**
+	 * The client wants the "deepen" command to be interpreted as relative to
+	 * the client's shallow commits.
+	 *
+	 * @since 5.0
+	 */
+	public static final String OPTION_DEEPEN_RELATIVE = "deepen-relative"; //$NON-NLS-1$
+
+	/**
 	 * The client does not want progress messages and will ignore them.
 	 *
 	 * @since 3.2
@@ -152,6 +160,13 @@ public class GitProtocolConstants {
 	public static final String OPTION_PUSH_CERT = "push-cert"; //$NON-NLS-1$
 
 	/**
+	 * The client specified a filter expression.
+	 *
+	 * @since 5.0
+	 */
+	public static final String OPTION_FILTER = "filter"; //$NON-NLS-1$
+
+	/**
 	 * The client supports atomic pushes. If this option is used, the server
 	 * will update all refs within one atomic transaction.
 	 *
@@ -215,6 +230,20 @@ public class GitProtocolConstants {
 	 */
 	public static final String CAPABILITY_PUSH_OPTIONS = "push-options"; //$NON-NLS-1$
 
+	/**
+	 * The server supports listing refs using protocol v2.
+	 *
+	 * @since 5.0
+	 */
+	public static final String COMMAND_LS_REFS = "ls-refs"; //$NON-NLS-1$
+
+	/**
+	 * The server supports fetch using protocol v2.
+	 *
+	 * @since 5.0
+	 */
+	public static final String COMMAND_FETCH = "fetch"; //$NON-NLS-1$
+
 	static enum MultiAck {
 		OFF, CONTINUE, DETAILED;
 	}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/HMACSHA1NonceGenerator.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/HMACSHA1NonceGenerator.java
index d43be89..1415334 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/HMACSHA1NonceGenerator.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/HMACSHA1NonceGenerator.java
@@ -42,8 +42,10 @@
  */
 package org.eclipse.jgit.transport;
 
+import static java.nio.charset.StandardCharsets.ISO_8859_1;
+import static org.eclipse.jgit.lib.Constants.CHARSET;
+
 import java.io.File;
-import java.io.UnsupportedEncodingException;
 import java.security.InvalidKeyException;
 import java.security.NoSuchAlgorithmException;
 
@@ -64,12 +66,15 @@ public class HMACSHA1NonceGenerator implements NonceGenerator {
 	private Mac mac;
 
 	/**
+	 * Constructor for HMACSHA1NonceGenerator.
+	 *
 	 * @param seed
-	 * @throws IllegalStateException
+	 *            seed the generator
+	 * @throws java.lang.IllegalStateException
 	 */
 	public HMACSHA1NonceGenerator(String seed) throws IllegalStateException {
 		try {
-			byte[] keyBytes = seed.getBytes("ISO-8859-1"); //$NON-NLS-1$
+			byte[] keyBytes = seed.getBytes(ISO_8859_1);
 			SecretKeySpec signingKey = new SecretKeySpec(keyBytes, "HmacSHA1"); //$NON-NLS-1$
 			mac = Mac.getInstance("HmacSHA1"); //$NON-NLS-1$
 			mac.init(signingKey);
@@ -77,11 +82,10 @@ public HMACSHA1NonceGenerator(String seed) throws IllegalStateException {
 			throw new IllegalStateException(e);
 		} catch (NoSuchAlgorithmException e) {
 			throw new IllegalStateException(e);
-		} catch (UnsupportedEncodingException e) {
-			throw new IllegalStateException(e);
 		}
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public synchronized String createNonce(Repository repo, long timestamp)
 			throws IllegalStateException {
@@ -98,15 +102,11 @@ public synchronized String createNonce(Repository repo, long timestamp)
 		}
 
 		String input = path + ":" + String.valueOf(timestamp); //$NON-NLS-1$
-		byte[] rawHmac;
-		try {
-			rawHmac = mac.doFinal(input.getBytes("UTF-8")); //$NON-NLS-1$
-		} catch (UnsupportedEncodingException e) {
-			throw new IllegalStateException(e);
-		}
+		byte[] rawHmac = mac.doFinal(input.getBytes(CHARSET));
 		return Long.toString(timestamp) + "-" + toHex(rawHmac); //$NON-NLS-1$
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public NonceStatus verify(String received, String sent,
 			Repository db, boolean allowSlop, int slop) {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/HttpAuthMethod.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/HttpAuthMethod.java
index c97daa9..fb03190 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/HttpAuthMethod.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/HttpAuthMethod.java
@@ -43,14 +43,15 @@
 
 package org.eclipse.jgit.transport;
 
+import static org.eclipse.jgit.lib.Constants.CHARSET;
 import static org.eclipse.jgit.util.HttpSupport.HDR_AUTHORIZATION;
 import static org.eclipse.jgit.util.HttpSupport.HDR_WWW_AUTHENTICATE;
 
 import java.io.IOException;
-import java.io.UnsupportedEncodingException;
 import java.net.URL;
 import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
@@ -59,7 +60,6 @@
 import java.util.Locale;
 import java.util.Map;
 import java.util.Map.Entry;
-import java.util.Random;
 
 import org.eclipse.jgit.transport.http.HttpConnection;
 import org.eclipse.jgit.util.Base64;
@@ -160,10 +160,10 @@ static HttpAuthMethod scanResponse(final HttpConnection conn,
 		final Map<String, List<String>> headers = conn.getHeaderFields();
 		HttpAuthMethod authentication = Type.NONE.method(EMPTY_STRING);
 
-		for (final Entry<String, List<String>> entry : headers.entrySet()) {
+		for (Entry<String, List<String>> entry : headers.entrySet()) {
 			if (HDR_WWW_AUTHENTICATE.equalsIgnoreCase(entry.getKey())) {
 				if (entry.getValue() != null) {
-					for (final String value : entry.getValue()) {
+					for (String value : entry.getValue()) {
 						if (value != null && value.length() != 0) {
 							final String[] valuePart = value.split(
 									SCHEMA_NAME_SEPARATOR, 2);
@@ -204,6 +204,12 @@ static HttpAuthMethod scanResponse(final HttpConnection conn,
 
 	protected final Type type;
 
+	/**
+	 * Constructor for HttpAuthMethod.
+	 *
+	 * @param type
+	 *            authentication method type
+	 */
 	protected HttpAuthMethod(Type type) {
 		this.type = type;
 	}
@@ -301,15 +307,15 @@ public Basic() {
 		}
 
 		@Override
-		void authorize(final String username, final String password) {
+		void authorize(String username, String password) {
 			this.user = username;
 			this.pass = password;
 		}
 
 		@Override
-		void configureRequest(final HttpConnection conn) throws IOException {
+		void configureRequest(HttpConnection conn) throws IOException {
 			String ident = user + ":" + pass; //$NON-NLS-1$
-			String enc = Base64.encodeBytes(ident.getBytes("UTF-8")); //$NON-NLS-1$
+			String enc = Base64.encodeBytes(ident.getBytes(CHARSET));
 			conn.setRequestProperty(HDR_AUTHORIZATION, type.getSchemeName()
 					+ " " + enc); //$NON-NLS-1$
 		}
@@ -317,7 +323,7 @@ void configureRequest(final HttpConnection conn) throws IOException {
 
 	/** Performs HTTP digest authentication. */
 	private static class Digest extends HttpAuthMethod {
-		private static final Random PRNG = new Random();
+		private static final SecureRandom PRNG = new SecureRandom();
 
 		private final Map<String, String> params;
 
@@ -340,14 +346,14 @@ private static class Digest extends HttpAuthMethod {
 		}
 
 		@Override
-		void authorize(final String username, final String password) {
+		void authorize(String username, String password) {
 			this.user = username;
 			this.pass = password;
 		}
 
 		@SuppressWarnings("boxing")
 		@Override
-		void configureRequest(final HttpConnection conn) throws IOException {
+		void configureRequest(HttpConnection conn) throws IOException {
 			final Map<String, String> r = new LinkedHashMap<>();
 
 			final String realm = params.get("realm"); //$NON-NLS-1$
@@ -423,25 +429,17 @@ private static String uri(URL u) {
 		}
 
 		private static String H(String data) {
-			try {
-				MessageDigest md = newMD5();
-				md.update(data.getBytes("UTF-8")); //$NON-NLS-1$
-				return LHEX(md.digest());
-			} catch (UnsupportedEncodingException e) {
-				throw new RuntimeException("UTF-8 encoding not available", e); //$NON-NLS-1$
-			}
+			MessageDigest md = newMD5();
+			md.update(data.getBytes(CHARSET));
+			return LHEX(md.digest());
 		}
 
 		private static String KD(String secret, String data) {
-			try {
-				MessageDigest md = newMD5();
-				md.update(secret.getBytes("UTF-8")); //$NON-NLS-1$
-				md.update((byte) ':');
-				md.update(data.getBytes("UTF-8")); //$NON-NLS-1$
-				return LHEX(md.digest());
-			} catch (UnsupportedEncodingException e) {
-				throw new RuntimeException("UTF-8 encoding not available", e); //$NON-NLS-1$
-			}
+			MessageDigest md = newMD5();
+			md.update(secret.getBytes(CHARSET));
+			md.update((byte) ':');
+			md.update(data.getBytes(CHARSET));
+			return LHEX(md.digest());
 		}
 
 		private static MessageDigest newMD5() {
@@ -557,9 +555,7 @@ void configureRequest(HttpConnection conn) throws IOException {
 				conn.setRequestProperty(HDR_AUTHORIZATION, getType().getSchemeName()
 						+ " " + Base64.encodeBytes(token)); //$NON-NLS-1$
 			} catch (GSSException e) {
-				IOException ioe = new IOException();
-				ioe.initCause(e);
-				throw ioe;
+				throw new IOException(e);
 			}
 		}
 	}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/HttpConfig.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/HttpConfig.java
index db59a54..101ce35 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/HttpConfig.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/HttpConfig.java
@@ -61,10 +61,10 @@
 import org.slf4j.LoggerFactory;
 
 /**
- * A representation of the "http.*" config values in a git {@link Config}. git
- * provides for setting values for specific URLs through "http.<url>.*
- * subsections. git always considers only the initial original URL for such
- * settings, not any redirected URL.
+ * A representation of the "http.*" config values in a git
+ * {@link org.eclipse.jgit.lib.Config}. git provides for setting values for
+ * specific URLs through "http.&lt;url&gt;.*" subsections. git always considers
+ * only the initial original URL for such settings, not any redirected URL.
  *
  * @since 4.9
  */
@@ -154,6 +154,8 @@ public boolean matchConfigValue(String s) {
 	private int maxRedirects;
 
 	/**
+	 * Get the "http.postBuffer" setting
+	 *
 	 * @return the value of the "http.postBuffer" setting
 	 */
 	public int getPostBuffer() {
@@ -161,6 +163,8 @@ public int getPostBuffer() {
 	}
 
 	/**
+	 * Get the "http.sslVerify" setting
+	 *
 	 * @return the value of the "http.sslVerify" setting
 	 */
 	public boolean isSslVerify() {
@@ -168,6 +172,8 @@ public boolean isSslVerify() {
 	}
 
 	/**
+	 * Get the "http.followRedirects" setting
+	 *
 	 * @return the value of the "http.followRedirects" setting
 	 */
 	public HttpRedirectMode getFollowRedirects() {
@@ -175,6 +181,8 @@ public HttpRedirectMode getFollowRedirects() {
 	}
 
 	/**
+	 * Get the "http.maxRedirects" setting
+	 *
 	 * @return the value of the "http.maxRedirects" setting
 	 */
 	public int getMaxRedirects() {
@@ -182,10 +190,11 @@ public int getMaxRedirects() {
 	}
 
 	/**
-	 * Creates a new {@link HttpConfig} tailored to the given {@link URIish}.
+	 * Creates a new {@link org.eclipse.jgit.transport.HttpConfig} tailored to
+	 * the given {@link org.eclipse.jgit.transport.URIish}.
 	 *
 	 * @param config
-	 *            to read the {@link HttpConfig} from
+	 *            to read the {@link org.eclipse.jgit.transport.HttpConfig} from
 	 * @param uri
 	 *            to get the configuration values for
 	 */
@@ -194,8 +203,8 @@ public HttpConfig(Config config, URIish uri) {
 	}
 
 	/**
-	 * Creates a {@link HttpConfig} that reads values solely from the user
-	 * config.
+	 * Creates a {@link org.eclipse.jgit.transport.HttpConfig} that reads values
+	 * solely from the user config.
 	 *
 	 * @param uri
 	 *            to get the configuration values for
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/HttpTransport.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/HttpTransport.java
index 006e846..d114186 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/HttpTransport.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/HttpTransport.java
@@ -62,7 +62,11 @@ public abstract class HttpTransport extends Transport {
 	protected static HttpConnectionFactory connectionFactory = new JDKHttpConnectionFactory();
 
 	/**
-	 * @return the {@link HttpConnectionFactory} used to create new connections
+	 * Get the {@link org.eclipse.jgit.transport.http.HttpConnectionFactory}
+	 * used to create new connections
+	 *
+	 * @return the {@link org.eclipse.jgit.transport.http.HttpConnectionFactory}
+	 *         used to create new connections
 	 * @since 3.3
 	 */
 	public static HttpConnectionFactory getConnectionFactory() {
@@ -70,10 +74,11 @@ public static HttpConnectionFactory getConnectionFactory() {
 	}
 
 	/**
-	 * Set the {@link HttpConnectionFactory} to be used to create new
-	 * connections
+	 * Set the {@link org.eclipse.jgit.transport.http.HttpConnectionFactory} to
+	 * be used to create new connections
 	 *
 	 * @param cf
+	 *            connection factory
 	 * @since 3.3
 	 */
 	public static void setConnectionFactory(HttpConnectionFactory cf) {
@@ -98,7 +103,7 @@ protected HttpTransport(Repository local, URIish uri) {
 	/**
 	 * Create a minimal HTTP transport instance not tied to a single repository.
 	 *
-	 * @param uri
+	 * @param uri a {@link org.eclipse.jgit.transport.URIish} object.
 	 */
 	protected HttpTransport(URIish uri) {
 		super(uri);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/InsecureCipherFactory.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/InsecureCipherFactory.java
index 73384a1..d494273 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/InsecureCipherFactory.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/InsecureCipherFactory.java
@@ -54,7 +54,7 @@
  * This is a hack for {@link WalkEncryption} to create any cipher configured by
  * the end-user. Using this class allows JGit to violate ErrorProne's security
  * recommendations (<a
- * href="http://errorprone.info/bugpattern/InsecureCryptoUsage"
+ * href="https://errorprone.info/bugpattern/InsecureCryptoUsage"
  * >InsecureCryptoUsage</a>), which is not secure.
  */
 class InsecureCipherFactory {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/InternalFetchConnection.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/InternalFetchConnection.java
index bea8d60..9fb9062 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/InternalFetchConnection.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/InternalFetchConnection.java
@@ -57,6 +57,21 @@
 class InternalFetchConnection<C> extends BasePackFetchConnection {
 	private Thread worker;
 
+	/**
+	 * Constructor for InternalFetchConnection.
+	 *
+	 * @param transport
+	 *            a {@link org.eclipse.jgit.transport.PackTransport}
+	 * @param uploadPackFactory
+	 *            a
+	 *            {@link org.eclipse.jgit.transport.resolver.UploadPackFactory}
+	 * @param req
+	 *            request
+	 * @param remote
+	 *            the remote {@link org.eclipse.jgit.lib.Repository}
+	 * @throws org.eclipse.jgit.errors.TransportException
+	 *             if any.
+	 */
 	public InternalFetchConnection(PackTransport transport,
 			final UploadPackFactory<C> uploadPackFactory,
 			final C req, final Repository remote) throws TransportException {
@@ -125,6 +140,7 @@ public void run() {
 		readAdvertisedRefs();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void close() {
 		super.close();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/InternalPushConnection.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/InternalPushConnection.java
index 8a1884e..732be63 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/InternalPushConnection.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/InternalPushConnection.java
@@ -57,6 +57,21 @@
 class InternalPushConnection<C> extends BasePackPushConnection {
 	private Thread worker;
 
+	/**
+	 * Constructor for InternalPushConnection.
+	 *
+	 * @param transport
+	 *            a {@link org.eclipse.jgit.transport.PackTransport}
+	 * @param receivePackFactory
+	 *            a
+	 *            {@link org.eclipse.jgit.transport.resolver.ReceivePackFactory}
+	 * @param req
+	 *            a request
+	 * @param remote
+	 *            the {@link org.eclipse.jgit.lib.Repository}
+	 * @throws org.eclipse.jgit.errors.TransportException
+	 *             if any.
+	 */
 	public InternalPushConnection(PackTransport transport,
 			final ReceivePackFactory<C> receivePackFactory,
 			final C req, final Repository remote) throws TransportException {
@@ -115,6 +130,7 @@ public void run() {
 		readAdvertisedRefs();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void close() {
 		super.close();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/JschConfigSessionFactory.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/JschConfigSessionFactory.java
index 0cc40f3..ea2f4b1 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/JschConfigSessionFactory.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/JschConfigSessionFactory.java
@@ -73,7 +73,6 @@
 import com.jcraft.jsch.JSch;
 import com.jcraft.jsch.JSchException;
 import com.jcraft.jsch.Session;
-import com.jcraft.jsch.UserInfo;
 
 /**
  * The base session factory that loads known hosts and private keys from
@@ -84,8 +83,8 @@
  * used by C Git.
  * <p>
  * The factory does not provide UI behavior. Override the method
- * {@link #configure(org.eclipse.jgit.transport.OpenSshConfig.Host, Session)}
- * to supply appropriate {@link UserInfo} to the session.
+ * {@link #configure(org.eclipse.jgit.transport.OpenSshConfig.Host, Session)} to
+ * supply appropriate {@link com.jcraft.jsch.UserInfo} to the session.
  */
 public abstract class JschConfigSessionFactory extends SshSessionFactory {
 
@@ -106,6 +105,7 @@ public abstract class JschConfigSessionFactory extends SshSessionFactory {
 
 	private OpenSshConfig config;
 
+	/** {@inheritDoc} */
 	@Override
 	public synchronized RemoteSession getSession(URIish uri,
 			CredentialsProvider credentialsProvider, FS fs, int tms)
@@ -263,7 +263,7 @@ private void setUserName(Session session, String userName) {
 	 *            the file system abstraction which will be necessary to
 	 *            perform certain file system operations.
 	 * @return new session instance, but otherwise unconfigured.
-	 * @throws JSchException
+	 * @throws com.jcraft.jsch.JSchException
 	 *             the session could not be created.
 	 */
 	protected Session createSession(final OpenSshConfig.Host hc,
@@ -287,7 +287,8 @@ protected void configureJSch(JSch jsch) {
 
 	/**
 	 * Provide additional configuration for the session based on the host
-	 * information. This method could be used to supply {@link UserInfo}.
+	 * information. This method could be used to supply
+	 * {@link com.jcraft.jsch.UserInfo}.
 	 *
 	 * @param hc
 	 *            host configuration
@@ -305,10 +306,10 @@ protected void configureJSch(JSch jsch) {
 	 *            the file system abstraction which will be necessary to
 	 *            perform certain file system operations.
 	 * @return the JSch instance to use.
-	 * @throws JSchException
+	 * @throws com.jcraft.jsch.JSchException
 	 *             the user configuration could not be created.
 	 */
-	protected JSch getJSch(final OpenSshConfig.Host hc, FS fs) throws JSchException {
+	protected JSch getJSch(OpenSshConfig.Host hc, FS fs) throws JSchException {
 		if (defaultJSch == null) {
 			defaultJSch = createDefaultJSch(fs);
 			if (defaultJSch.getConfigRepository() == null) {
@@ -339,11 +340,13 @@ protected JSch getJSch(final OpenSshConfig.Host hc, FS fs) throws JSchException
 	}
 
 	/**
+	 * Create default instance of jsch
+	 *
 	 * @param fs
-	 *            the file system abstraction which will be necessary to
-	 *            perform certain file system operations.
+	 *            the file system abstraction which will be necessary to perform
+	 *            certain file system operations.
 	 * @return the new default JSch implementation.
-	 * @throws JSchException
+	 * @throws com.jcraft.jsch.JSchException
 	 *             known host keys cannot be loaded.
 	 */
 	protected JSch createDefaultJSch(FS fs) throws JSchException {
@@ -354,18 +357,13 @@ protected JSch createDefaultJSch(FS fs) throws JSchException {
 		return jsch;
 	}
 
-	private static void knownHosts(final JSch sch, FS fs) throws JSchException {
+	private static void knownHosts(JSch sch, FS fs) throws JSchException {
 		final File home = fs.userHome();
 		if (home == null)
 			return;
 		final File known_hosts = new File(new File(home, ".ssh"), "known_hosts"); //$NON-NLS-1$ //$NON-NLS-2$
-		try {
-			final FileInputStream in = new FileInputStream(known_hosts);
-			try {
-				sch.setKnownHosts(in);
-			} finally {
-				in.close();
-			}
+		try (FileInputStream in = new FileInputStream(known_hosts)) {
+			sch.setKnownHosts(in);
 		} catch (FileNotFoundException none) {
 			// Oh well. They don't have a known hosts in home.
 		} catch (IOException err) {
@@ -373,7 +371,7 @@ private static void knownHosts(final JSch sch, FS fs) throws JSchException {
 		}
 	}
 
-	private static void identities(final JSch sch, FS fs) {
+	private static void identities(JSch sch, FS fs) {
 		final File home = fs.userHome();
 		if (home == null)
 			return;
@@ -385,7 +383,7 @@ private static void identities(final JSch sch, FS fs) {
 		}
 	}
 
-	private static void loadIdentity(final JSch sch, final File priv) {
+	private static void loadIdentity(JSch sch, File priv) {
 		if (priv.isFile()) {
 			try {
 				sch.addIdentity(priv.getAbsolutePath());
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/JschSession.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/JschSession.java
index a8cc032..e3ef832 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/JschSession.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/JschSession.java
@@ -66,8 +66,8 @@
  * Run remote commands using Jsch.
  * <p>
  * This class is the default session implementation using Jsch. Note that
- * {@link JschConfigSessionFactory} is used to create the actual session passed
- * to the constructor.
+ * {@link org.eclipse.jgit.transport.JschConfigSessionFactory} is used to create
+ * the actual session passed to the constructor.
  */
 public class JschSession implements RemoteSession {
 	final Session sock;
@@ -82,16 +82,18 @@ public class JschSession implements RemoteSession {
 	 * @param uri
 	 *            the URI information for the remote connection
 	 */
-	public JschSession(final Session session, URIish uri) {
+	public JschSession(Session session, URIish uri) {
 		sock = session;
 		this.uri = uri;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public Process exec(String command, int timeout) throws IOException {
 		return new JschProcess(command, timeout);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void disconnect() {
 		if (sock.isConnected())
@@ -99,12 +101,13 @@ public void disconnect() {
 	}
 
 	/**
-	 * A kludge to allow {@link TransportSftp} to get an Sftp channel from Jsch.
-	 * Ideally, this method would be generic, which would require implementing
-	 * generic Sftp channel operations in the RemoteSession class.
+	 * A kludge to allow {@link org.eclipse.jgit.transport.TransportSftp} to get
+	 * an Sftp channel from Jsch. Ideally, this method would be generic, which
+	 * would require implementing generic Sftp channel operations in the
+	 * RemoteSession class.
 	 *
 	 * @return a channel suitable for Sftp operations.
-	 * @throws JSchException
+	 * @throws com.jcraft.jsch.JSchException
 	 *             on problems getting the channel.
 	 */
 	public Channel getSftpChannel() throws JSchException {
@@ -142,7 +145,7 @@ private class JschProcess extends Process {
 		 * @throws IOException
 		 *             on problems opening streams
 		 */
-		JschProcess(final String commandName, int tms)
+		JschProcess(String commandName, int tms)
 				throws TransportException, IOException {
 			timeout = tms;
 			try {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/NetRC.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/NetRC.java
index 5727b03..e688f63 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/NetRC.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/NetRC.java
@@ -143,7 +143,9 @@ enum State {
 		COMMAND, MACHINE, LOGIN, PASSWORD, DEFAULT, ACCOUNT, MACDEF
 	}
 
-	/** */
+	/**
+	 * <p>Constructor for NetRC.</p>
+	 */
 	public NetRC() {
 		netrc = getDefaultFile();
 		if (netrc != null)
@@ -151,6 +153,8 @@ public NetRC() {
 	}
 
 	/**
+	 * <p>Constructor for NetRC.</p>
+	 *
 	 * @param netrc
 	 *            the .netrc file
 	 */
@@ -176,6 +180,7 @@ private static File getDefaultFile() {
 	 * Get entry by host name
 	 *
 	 * @param host
+	 *            the host name
 	 * @return entry associated with host name or null
 	 */
 	public NetRCEntry getEntry(String host) {
@@ -194,6 +199,8 @@ public NetRCEntry getEntry(String host) {
 	}
 
 	/**
+	 * Get all entries collected from .netrc file
+	 *
 	 * @return all entries collected from .netrc file
 	 */
 	public Collection<NetRCEntry> getEntries() {
@@ -204,9 +211,7 @@ private void parse() {
 		this.hosts.clear();
 		this.lastModified = this.netrc.lastModified();
 
-		BufferedReader r = null;
-		try {
-			r = new BufferedReader(new FileReader(netrc));
+		try (BufferedReader r = new BufferedReader(new FileReader(netrc))) {
 			String line = null;
 
 			NetRCEntry entry = new NetRCEntry();
@@ -308,13 +313,6 @@ private void parse() {
 				hosts.put(entry.machine, entry);
 		} catch (IOException e) {
 			throw new RuntimeException(e);
-		} finally {
-			try {
-				if (r != null)
-					r.close();
-			} catch (IOException e) {
-				throw new RuntimeException(e);
-			}
 		}
 	}
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/NetRCCredentialsProvider.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/NetRCCredentialsProvider.java
index 4037545..6531b17 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/NetRCCredentialsProvider.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/NetRCCredentialsProvider.java
@@ -54,7 +54,9 @@ public class NetRCCredentialsProvider extends CredentialsProvider {
 
 	NetRC netrc = new NetRC();
 
-	/** */
+	/**
+	 * <p>Constructor for NetRCCredentialsProvider.</p>
+	 */
 	public NetRCCredentialsProvider() {
 	}
 
@@ -65,6 +67,7 @@ public static void install() {
 		CredentialsProvider.setDefault(new NetRCCredentialsProvider());
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public boolean supports(CredentialItem... items) {
 		for (CredentialItem i : items) {
@@ -78,6 +81,7 @@ else if (i instanceof CredentialItem.Password)
 		return true;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public boolean get(URIish uri, CredentialItem... items)
 			throws UnsupportedCredentialItem {
@@ -108,6 +112,7 @@ public boolean get(URIish uri, CredentialItem... items)
 		return !isAnyNull(items);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public boolean isInteractive() {
 		return false;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/NonceGenerator.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/NonceGenerator.java
index d1ea089..51fe907 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/NonceGenerator.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/NonceGenerator.java
@@ -55,6 +55,8 @@
 public interface NonceGenerator {
 
 	/**
+	 * Create nonce to be signed by the pusher
+	 *
 	 * @param db
 	 *            The repository which should be used to obtain a unique String
 	 *            such that the pusher cannot forge nonces by pushing to another
@@ -62,12 +64,14 @@ public interface NonceGenerator {
 	 * @param timestamp
 	 *            The current time in seconds.
 	 * @return The nonce to be signed by the pusher
-	 * @throws IllegalStateException
+	 * @throws java.lang.IllegalStateException
 	 */
 	public String createNonce(Repository db, long timestamp)
 			throws IllegalStateException;
 
 	/**
+	 * Verify trustworthiness of the received nonce.
+	 *
 	 * @param received
 	 *            The nonce which was received from the server
 	 * @param sent
@@ -76,7 +80,6 @@ public String createNonce(Repository db, long timestamp)
 	 *            The repository which should be used to obtain a unique String
 	 *            such that the pusher cannot forge nonces by pushing to another
 	 *            repository at the same time as well and reusing the nonce.
-	 *
 	 * @param allowSlop
 	 *            If the receiving backend is is able to generate slop. This is
 	 *            the case for serving via http protocol using more than one
@@ -85,7 +88,6 @@ public String createNonce(Repository db, long timestamp)
 	 * @param slop
 	 *            If `allowSlop` is true, this specifies the number of seconds
 	 *            which we allow as slop.
-	 *
 	 * @return a NonceStatus indicating the trustworthiness of the received
 	 *         nonce.
 	 */
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/ObjectCountCallback.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/ObjectCountCallback.java
index cf81adb..3856bb2 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/ObjectCountCallback.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/ObjectCountCallback.java
@@ -45,7 +45,6 @@
 
 import java.io.OutputStream;
 
-import org.eclipse.jgit.internal.storage.pack.PackWriter;
 import org.eclipse.jgit.lib.ProgressMonitor;
 
 /**
@@ -55,19 +54,20 @@
  */
 public interface ObjectCountCallback {
 	/**
-	 * Invoked when the {@link PackWriter} has counted the objects to be
-	 * written to pack.
+	 * Invoked when the
+	 * {@link org.eclipse.jgit.internal.storage.pack.PackWriter} has counted the
+	 * objects to be written to pack.
 	 * <p>
-	 * An {@code ObjectCountCallback} can use this information to decide
-	 * whether the
-	 * {@link PackWriter#writePack(ProgressMonitor, ProgressMonitor, OutputStream)}
+	 * An {@code ObjectCountCallback} can use this information to decide whether
+	 * the
+	 * {@link org.eclipse.jgit.internal.storage.pack.PackWriter#writePack(ProgressMonitor, ProgressMonitor, OutputStream)}
 	 * operation should be aborted.
 	 * <p>
 	 * This callback will be called exactly once.
 	 *
 	 * @param objectCount
 	 *            the count of the objects.
-	 * @throws WriteAbortedException
+	 * @throws org.eclipse.jgit.transport.WriteAbortedException
 	 *             to indicate that the write operation should be aborted.
 	 */
 	void setObjectCount(long objectCount) throws WriteAbortedException;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/OpenSshConfig.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/OpenSshConfig.java
index b5d5099..f5ccdc8 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/OpenSshConfig.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/OpenSshConfig.java
@@ -84,9 +84,11 @@
  * </ul>
  * <p>
  * Therefore implement our own parser to read an OpenSSH configuration file. It
- * makes the critical options available to {@link SshSessionFactory} via
- * {@link Host} objects returned by {@link #lookup(String)}, and implements a
- * fully conforming {@link ConfigRepository} providing
+ * makes the critical options available to
+ * {@link org.eclipse.jgit.transport.SshSessionFactory} via
+ * {@link org.eclipse.jgit.transport.OpenSshConfig.Host} objects returned by
+ * {@link #lookup(String)}, and implements a fully conforming
+ * {@link com.jcraft.jsch.ConfigRepository} providing
  * {@link com.jcraft.jsch.ConfigRepository.Config}s via
  * {@link #getConfig(String)}.
  * </p>
@@ -103,7 +105,7 @@
  * ConfigRepository OTOH treats all option values as plain strings, so any
  * validation must happen in Jsch outside of the parser. Thus this parser does
  * not validate option values, except for a few options when constructing a
- * {@link Host} object.
+ * {@link org.eclipse.jgit.transport.OpenSshConfig.Host} object.
  * </p>
  * <p>
  * This config does %-substitutions for the following tokens:
@@ -184,7 +186,7 @@ public String toString() {
 	/** State read from the config file, plus {@link Host}s created from it. */
 	private State state;
 
-	OpenSshConfig(final File h, final File cfg) {
+	OpenSshConfig(File h, File cfg) {
 		home = h;
 		configFile = cfg;
 		state = new State();
@@ -199,7 +201,7 @@ public String toString() {
 	 *            configuration file.
 	 * @return r configuration for the requested name. Never null.
 	 */
-	public Host lookup(final String hostName) {
+	public Host lookup(String hostName) {
 		final State cache = refresh();
 		Host h = cache.hosts.get(hostName);
 		if (h != null) {
@@ -209,7 +211,7 @@ public Host lookup(final String hostName) {
 		// Initialize with default entries at the top of the file, before the
 		// first Host block.
 		fullConfig.merge(cache.entries.get(HostEntry.DEFAULT_NAME));
-		for (final Map.Entry<String, HostEntry> e : cache.entries.entrySet()) {
+		for (Map.Entry<String, HostEntry> e : cache.entries.entrySet()) {
 			String key = e.getKey();
 			if (isHostMatch(key, hostName)) {
 				fullConfig.merge(e.getValue());
@@ -236,7 +238,7 @@ private synchronized State refresh() {
 		return state;
 	}
 
-	private Map<String, HostEntry> parse(final InputStream in)
+	private Map<String, HostEntry> parse(InputStream in)
 			throws IOException {
 		final Map<String, HostEntry> m = new LinkedHashMap<>();
 		final BufferedReader br = new BufferedReader(new InputStreamReader(in));
@@ -330,14 +332,14 @@ private static boolean patternMatchesHost(final String pattern,
 		}
 	}
 
-	private static String dequote(final String value) {
+	private static String dequote(String value) {
 		if (value.startsWith("\"") && value.endsWith("\"") //$NON-NLS-1$ //$NON-NLS-2$
 				&& value.length() > 1)
 			return value.substring(1, value.length() - 1);
 		return value;
 	}
 
-	private static String nows(final String value) {
+	private static String nows(String value) {
 		final StringBuilder b = new StringBuilder();
 		for (int i = 0; i < value.length(); i++) {
 			if (!Character.isSpaceChar(value.charAt(i)))
@@ -346,7 +348,7 @@ private static String nows(final String value) {
 		return b.toString();
 	}
 
-	private static Boolean yesno(final String value) {
+	private static Boolean yesno(String value) {
 		if (StringUtils.equalsIgnoreCase("yes", value)) //$NON-NLS-1$
 			return Boolean.TRUE;
 		return Boolean.FALSE;
@@ -363,7 +365,7 @@ private static File toFile(String path, File home) {
 		return new File(home, path);
 	}
 
-	private static int positive(final String value) {
+	private static int positive(String value) {
 		if (value != null) {
 			try {
 				return Integer.parseUnsignedInt(value);
@@ -960,12 +962,11 @@ public String toString() {
 	}
 
 	/**
+	 * {@inheritDoc}
+	 * <p>
 	 * Retrieves the full {@link com.jcraft.jsch.ConfigRepository.Config Config}
 	 * for the given host name. Should be called only by Jsch and tests.
 	 *
-	 * @param hostName
-	 *            to get the config for
-	 * @return the configuration for the host
 	 * @since 4.9
 	 */
 	@Override
@@ -974,6 +975,7 @@ public Config getConfig(String hostName) {
 		return host.getConfig();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	@SuppressWarnings("nls")
 	public String toString() {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/OperationResult.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/OperationResult.java
index 4231798..08f7f0d 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/OperationResult.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/OperationResult.java
@@ -107,7 +107,7 @@ public Collection<Ref> getAdvertisedRefs() {
 	 *            name of the ref to obtain.
 	 * @return the requested ref; null if the remote did not advertise this ref.
 	 */
-	public final Ref getAdvertisedRef(final String name) {
+	public final Ref getAdvertisedRef(String name) {
 		return advertisedRefs.get(name);
 	}
 
@@ -129,16 +129,16 @@ public Collection<TrackingRefUpdate> getTrackingRefUpdates() {
 	 * @return status of the local ref; null if this local ref was not touched
 	 *         during this operation.
 	 */
-	public TrackingRefUpdate getTrackingRefUpdate(final String localName) {
+	public TrackingRefUpdate getTrackingRefUpdate(String localName) {
 		return updates.get(localName);
 	}
 
-	void setAdvertisedRefs(final URIish u, final Map<String, Ref> ar) {
+	void setAdvertisedRefs(URIish u, Map<String, Ref> ar) {
 		uri = u;
 		advertisedRefs = ar;
 	}
 
-	void add(final TrackingRefUpdate u) {
+	void add(TrackingRefUpdate u) {
 		updates.put(u.getLocalName(), u);
 	}
 
@@ -158,7 +158,7 @@ public String getMessages() {
 		return messageBuffer != null ? messageBuffer.toString() : ""; //$NON-NLS-1$
 	}
 
-	void addMessages(final String msg) {
+	void addMessages(String msg) {
 		if (msg != null && msg.length() > 0) {
 			if (messageBuffer == null)
 				messageBuffer = new StringBuilder();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PackParser.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PackParser.java
index 833d211..49acb4d 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PackParser.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PackParser.java
@@ -76,7 +76,6 @@
 import org.eclipse.jgit.lib.ObjectId;
 import org.eclipse.jgit.lib.ObjectIdOwnerMap;
 import org.eclipse.jgit.lib.ObjectIdSubclassMap;
-import org.eclipse.jgit.lib.ObjectInserter;
 import org.eclipse.jgit.lib.ObjectLoader;
 import org.eclipse.jgit.lib.ObjectReader;
 import org.eclipse.jgit.lib.ObjectStream;
@@ -88,14 +87,16 @@
 import org.eclipse.jgit.util.sha1.SHA1;
 
 /**
- * Parses a pack stream and imports it for an {@link ObjectInserter}.
+ * Parses a pack stream and imports it for an
+ * {@link org.eclipse.jgit.lib.ObjectInserter}.
  * <p>
  * Applications can acquire an instance of a parser from ObjectInserter's
- * {@link ObjectInserter#newPackParser(InputStream)} method.
+ * {@link org.eclipse.jgit.lib.ObjectInserter#newPackParser(InputStream)}
+ * method.
  * <p>
- * Implementations of {@link ObjectInserter} should subclass this type and
- * provide their own logic for the various {@code on*()} event methods declared
- * to be abstract.
+ * Implementations of {@link org.eclipse.jgit.lib.ObjectInserter} should
+ * subclass this type and provide their own logic for the various {@code on*()}
+ * event methods declared to be abstract.
  */
 public abstract class PackParser {
 	/** Size of the internal stream buffer. */
@@ -199,7 +200,7 @@ public static enum Source {
 	 * @param src
 	 *            the stream the parser will read.
 	 */
-	protected PackParser(final ObjectDatabase odb, final InputStream src) {
+	protected PackParser(ObjectDatabase odb, InputStream src) {
 		objectDatabase = odb.newCachedDatabase();
 		in = src;
 
@@ -213,7 +214,11 @@ protected PackParser(final ObjectDatabase odb, final InputStream src) {
 		checkObjectCollisions = true;
 	}
 
-	/** @return true if a thin pack (missing base objects) is permitted. */
+	/**
+	 * Whether a thin pack (missing base objects) is permitted.
+	 *
+	 * @return {@code true} if a thin pack (missing base objects) is permitted.
+	 */
 	public boolean isAllowThin() {
 		return allowThin;
 	}
@@ -227,11 +232,13 @@ public boolean isAllowThin() {
 	 * @param allow
 	 *            true to enable a thin pack.
 	 */
-	public void setAllowThin(final boolean allow) {
+	public void setAllowThin(boolean allow) {
 		allowThin = allow;
 	}
 
 	/**
+	 * Whether received objects are verified to prevent collisions.
+	 *
 	 * @return if true received objects are verified to prevent collisions.
 	 * @since 4.1
 	 */
@@ -300,7 +307,11 @@ public void setNeedBaseObjectIds(boolean b) {
 		this.needBaseObjectIds = b;
 	}
 
-	/** @return true if the EOF should be read from the input after the footer. */
+	/**
+	 * Whether the EOF should be read from the input after the footer.
+	 *
+	 * @return true if the EOF should be read from the input after the footer.
+	 */
 	public boolean isCheckEofAfterPackFooter() {
 		return checkEofAfterPackFooter;
 	}
@@ -315,12 +326,18 @@ public void setCheckEofAfterPackFooter(boolean b) {
 		checkEofAfterPackFooter = b;
 	}
 
-	/** @return true if there is data expected after the pack footer. */
+	/**
+	 * Whether there is data expected after the pack footer.
+	 *
+	 * @return true if there is data expected after the pack footer.
+	 */
 	public boolean isExpectDataAfterPackFooter() {
 		return expectDataAfterPackFooter;
 	}
 
 	/**
+	 * Set if there is additional data in InputStream after pack.
+	 *
 	 * @param e
 	 *            true if there is additional data in InputStream after pack.
 	 *            This requires the InputStream to support the mark and reset
@@ -330,14 +347,22 @@ public void setExpectDataAfterPackFooter(boolean e) {
 		expectDataAfterPackFooter = e;
 	}
 
-	/** @return the new objects that were sent by the user */
+	/**
+	 * Get the new objects that were sent by the user
+	 *
+	 * @return the new objects that were sent by the user
+	 */
 	public ObjectIdSubclassMap<ObjectId> getNewObjectIds() {
 		if (newObjectIds != null)
 			return newObjectIds;
 		return new ObjectIdSubclassMap<>();
 	}
 
-	/** @return set of objects the incoming pack assumed for delta purposes */
+	/**
+	 * Get set of objects the incoming pack assumed for delta purposes
+	 *
+	 * @return set of objects the incoming pack assumed for delta purposes
+	 */
 	public ObjectIdSubclassMap<ObjectId> getBaseObjectIds() {
 		if (baseObjectIds != null)
 			return baseObjectIds;
@@ -354,7 +379,7 @@ public ObjectIdSubclassMap<ObjectId> getBaseObjectIds() {
 	 * @param oc
 	 *            the checker instance; null to disable object checking.
 	 */
-	public void setObjectChecker(final ObjectChecker oc) {
+	public void setObjectChecker(ObjectChecker oc) {
 		objCheck = oc;
 	}
 
@@ -374,11 +399,15 @@ public void setObjectChecker(final ObjectChecker oc) {
 	 * @param on
 	 *            true to enable the default checker; false to disable it.
 	 */
-	public void setObjectChecking(final boolean on) {
+	public void setObjectChecking(boolean on) {
 		setObjectChecker(on ? new ObjectChecker() : null);
 	}
 
-	/** @return the message to record with the pack lock. */
+	/**
+	 * Get the message to record with the pack lock.
+	 *
+	 * @return the message to record with the pack lock.
+	 */
 	public String getLockMessage() {
 		return lockMessage;
 	}
@@ -420,7 +449,7 @@ public int getObjectCount() {
 		return entryCount;
 	}
 
-	/***
+	/**
 	 * Get the information about the requested object.
 	 * <p>
 	 * The object information is only available after
@@ -477,7 +506,7 @@ public long getPackSize() {
 	 * <p>
 	 * This should only be called after pack parsing is finished.
 	 *
-	 * @return {@link ReceivedPackStatistics}
+	 * @return {@link org.eclipse.jgit.transport.ReceivedPackStatistics}
 	 * @since 4.6
 	 */
 	public ReceivedPackStatistics getReceivedPackStatistics() {
@@ -489,10 +518,10 @@ public ReceivedPackStatistics getReceivedPackStatistics() {
 	 *
 	 * @param progress
 	 *            callback to provide progress feedback during parsing. If null,
-	 *            {@link NullProgressMonitor} will be used.
+	 *            {@link org.eclipse.jgit.lib.NullProgressMonitor} will be used.
 	 * @return the pack lock, if one was requested by setting
 	 *         {@link #setLockMessage(String)}.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the stream is malformed, or contains corrupt objects.
 	 * @since 3.0
 	 */
@@ -505,13 +534,13 @@ public final PackLock parse(ProgressMonitor progress) throws IOException {
 	 *
 	 * @param receiving
 	 *            receives progress feedback during the initial receiving
-	 *            objects phase. If null, {@link NullProgressMonitor} will be
-	 *            used.
+	 *            objects phase. If null,
+	 *            {@link org.eclipse.jgit.lib.NullProgressMonitor} will be used.
 	 * @param resolving
 	 *            receives progress feedback during the resolving objects phase.
 	 * @return the pack lock, if one was requested by setting
 	 *         {@link #setLockMessage(String)}.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the stream is malformed, or contains corrupt objects.
 	 * @since 3.0
 	 */
@@ -600,7 +629,7 @@ private void processDeltas(ProgressMonitor resolving) throws IOException {
 		resolving.endTask();
 	}
 
-	private void resolveDeltas(final ProgressMonitor progress)
+	private void resolveDeltas(ProgressMonitor progress)
 			throws IOException {
 		final int last = entryCount;
 		for (int i = 0; i < last; i++) {
@@ -701,7 +730,7 @@ private void resolveDeltas(DeltaVisit visit, final int type,
 
 	private final void checkIfTooLarge(int typeCode, long size)
 			throws IOException {
-		if (0 < maxObjectSizeLimit && maxObjectSizeLimit < size)
+		if (0 < maxObjectSizeLimit && maxObjectSizeLimit < size) {
 			switch (typeCode) {
 			case Constants.OBJ_COMMIT:
 			case Constants.OBJ_TREE:
@@ -711,13 +740,17 @@ private final void checkIfTooLarge(int typeCode, long size)
 
 			case Constants.OBJ_OFS_DELTA:
 			case Constants.OBJ_REF_DELTA:
-				throw new TooLargeObjectInPackException(maxObjectSizeLimit);
+				throw new TooLargeObjectInPackException(size, maxObjectSizeLimit);
 
 			default:
 				throw new IOException(MessageFormat.format(
 						JGitText.get().unknownObjectType,
 						Integer.valueOf(typeCode)));
 			}
+		}
+		if (size > Integer.MAX_VALUE - 8) {
+			throw new TooLargeObjectInPackException(size, Integer.MAX_VALUE - 8);
+		}
 	}
 
 	/**
@@ -733,7 +766,7 @@ private final void checkIfTooLarge(int typeCode, long size)
 	 * @param info
 	 *            the info object to populate.
 	 * @return {@code info}, after populating.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the size cannot be read.
 	 */
 	protected ObjectTypeAndSize readObjectHeader(ObjectTypeAndSize info)
@@ -786,7 +819,7 @@ protected ObjectTypeAndSize readObjectHeader(ObjectTypeAndSize info)
 		return info;
 	}
 
-	private UnresolvedDelta removeBaseById(final AnyObjectId id) {
+	private UnresolvedDelta removeBaseById(AnyObjectId id) {
 		final DeltaChain d = baseById.get(id);
 		return d != null ? d.remove() : null;
 	}
@@ -832,7 +865,7 @@ private UnresolvedDelta firstChildOf(PackedObjectInfo oe) {
 		return first;
 	}
 
-	private void resolveDeltasWithExternalBases(final ProgressMonitor progress)
+	private void resolveDeltasWithExternalBases(ProgressMonitor progress)
 			throws IOException {
 		growEntries(baseById.size());
 
@@ -840,7 +873,7 @@ private void resolveDeltasWithExternalBases(final ProgressMonitor progress)
 			baseObjectIds = new ObjectIdSubclassMap<>();
 
 		final List<DeltaChain> missing = new ArrayList<>(64);
-		for (final DeltaChain baseId : baseById) {
+		for (DeltaChain baseId : baseById) {
 			if (baseId.head == null)
 				continue;
 
@@ -872,7 +905,7 @@ private void resolveDeltasWithExternalBases(final ProgressMonitor progress)
 						JGitText.get().downloadCancelledDuringIndexing);
 		}
 
-		for (final DeltaChain base : missing) {
+		for (DeltaChain base : missing) {
 			if (base.head != null)
 				throw new MissingObjectException(base, "delta base"); //$NON-NLS-1$
 		}
@@ -1032,7 +1065,7 @@ private void indexOneObject() throws IOException {
 		}
 	}
 
-	private void whole(final long pos, final int type, final long sz)
+	private void whole(long pos, int type, long sz)
 			throws IOException {
 		SHA1 objectDigest = objectHasher.reset();
 		objectDigest.update(Constants.encodedTypeString(type));
@@ -1043,7 +1076,6 @@ private void whole(final long pos, final int type, final long sz)
 		final byte[] data;
 		if (type == Constants.OBJ_BLOB) {
 			byte[] readBuffer = buffer();
-			InputStream inf = inflate(Source.INPUT, sz);
 			BlobObjectChecker checker = null;
 			if (objCheck != null) {
 				checker = objCheck.newBlobObjectChecker();
@@ -1052,15 +1084,16 @@ private void whole(final long pos, final int type, final long sz)
 				checker = BlobObjectChecker.NULL_CHECKER;
 			}
 			long cnt = 0;
-			while (cnt < sz) {
-				int r = inf.read(readBuffer);
-				if (r <= 0)
-					break;
-				objectDigest.update(readBuffer, 0, r);
-				checker.update(readBuffer, 0, r);
-				cnt += r;
+			try (InputStream inf = inflate(Source.INPUT, sz)) {
+				while (cnt < sz) {
+					int r = inf.read(readBuffer);
+					if (r <= 0)
+						break;
+					objectDigest.update(readBuffer, 0, r);
+					checker.update(readBuffer, 0, r);
+					cnt += r;
+				}
 			}
-			inf.close();
 			objectDigest.digest(tempObjectId);
 			checker.endBlob(tempObjectId);
 			data = null;
@@ -1093,9 +1126,8 @@ private void whole(final long pos, final int type, final long sz)
 	 *            the type of the object.
 	 * @param data
 	 *            raw content of the object.
-	 * @throws CorruptObjectException
+	 * @throws org.eclipse.jgit.errors.CorruptObjectException
 	 * @since 4.9
-	 *
 	 */
 	protected void verifySafeObject(final AnyObjectId id, final int type,
 			final byte[] data) throws CorruptObjectException {
@@ -1130,33 +1162,29 @@ private void checkObjectCollision(PackedObjectInfo obj)
 		final byte[] readBuffer = buffer();
 		final byte[] curBuffer = new byte[readBuffer.length];
 		long sz = info.size;
-		InputStream pck = null;
 		try (ObjectStream cur = readCurs.open(obj, info.type).openStream()) {
 			if (cur.getSize() != sz) {
 				throw new IOException(MessageFormat.format(
 						JGitText.get().collisionOn, obj.name()));
 			}
-			pck = inflate(Source.DATABASE, sz);
-			while (0 < sz) {
-				int n = (int) Math.min(readBuffer.length, sz);
-				IO.readFully(cur, curBuffer, 0, n);
-				IO.readFully(pck, readBuffer, 0, n);
-				for (int i = 0; i < n; i++) {
-					if (curBuffer[i] != readBuffer[i]) {
-						throw new IOException(MessageFormat.format(JGitText
-								.get().collisionOn, obj.name()));
+			try (InputStream pck = inflate(Source.DATABASE, sz)) {
+				while (0 < sz) {
+					int n = (int) Math.min(readBuffer.length, sz);
+					IO.readFully(cur, curBuffer, 0, n);
+					IO.readFully(pck, readBuffer, 0, n);
+					for (int i = 0; i < n; i++) {
+						if (curBuffer[i] != readBuffer[i]) {
+							throw new IOException(MessageFormat.format(
+									JGitText.get().collisionOn, obj.name()));
+						}
 					}
+					sz -= n;
 				}
-				sz -= n;
 			}
 		} catch (MissingObjectException notLocal) {
 			// This is OK, we don't have a copy of the object locally
-			// but the API throws when we try to read it as usually its
+			// but the API throws when we try to read it as usually it's
 			// an error to read something that doesn't exist.
-		} finally {
-			if (pck != null) {
-				pck.close();
-			}
 		}
 	}
 
@@ -1196,7 +1224,7 @@ private ObjectTypeAndSize openDatabase(UnresolvedDelta delta,
 	}
 
 	// Consume exactly one byte from the buffer and return it.
-	private int readFrom(final Source src) throws IOException {
+	private int readFrom(Source src) throws IOException {
 		if (bAvail == 0)
 			fill(src, 1);
 		bAvail--;
@@ -1204,13 +1232,13 @@ private int readFrom(final Source src) throws IOException {
 	}
 
 	// Consume cnt bytes from the buffer.
-	void use(final int cnt) {
+	void use(int cnt) {
 		bOffset += cnt;
 		bAvail -= cnt;
 	}
 
 	// Ensure at least need bytes are available in in {@link #buf}.
-	int fill(final Source src, final int need) throws IOException {
+	int fill(Source src, int need) throws IOException {
 		while (bAvail < need) {
 			int next = bOffset + bAvail;
 			int free = buf.length - next;
@@ -1261,7 +1289,11 @@ private void sync() throws IOException {
 		bOffset = 0;
 	}
 
-	/** @return a temporary byte array for use by the caller. */
+	/**
+	 * Get a temporary byte array for use by the caller.
+	 *
+	 * @return a temporary byte array for use by the caller.
+	 */
 	protected byte[] buffer() {
 		return tempBuffer;
 	}
@@ -1298,7 +1330,7 @@ protected PackedObjectInfo newInfo(AnyObjectId id, UnresolvedDelta delta,
 	 * If external implementation wants to overwrite the expectedObjectCount,
 	 * they should call this method during {@link #onPackHeader(long)}.
 	 *
-	 * @param expectedObjectCount
+	 * @param expectedObjectCount a long.
 	 * @since 4.9
 	 */
 	protected void setExpectedObjectCount(long expectedObjectCount) {
@@ -1323,7 +1355,7 @@ protected void setExpectedObjectCount(long expectedObjectCount) {
 	 *            first offset within the buffer that is valid.
 	 * @param len
 	 *            number of bytes in the buffer that are valid.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the stream cannot be archived.
 	 */
 	protected abstract void onStoreStream(byte[] raw, int pos, int len)
@@ -1343,7 +1375,7 @@ protected abstract void onStoreStream(byte[] raw, int pos, int len)
 	 *            first offset within buffer that is valid.
 	 * @param len
 	 *            number of bytes in buffer that are valid.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the stream cannot be archived.
 	 */
 	protected abstract void onObjectHeader(Source src, byte[] raw, int pos,
@@ -1366,7 +1398,7 @@ protected abstract void onObjectHeader(Source src, byte[] raw, int pos,
 	 *            first offset within buffer that is valid.
 	 * @param len
 	 *            number of bytes in buffer that are valid.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the stream cannot be archived.
 	 */
 	protected abstract void onObjectData(Source src, byte[] raw, int pos,
@@ -1381,7 +1413,7 @@ protected abstract void onObjectData(Source src, byte[] raw, int pos,
 	 *            the type of the object.
 	 * @param data
 	 *            inflated data for the object.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the object cannot be archived.
 	 */
 	protected abstract void onInflatedObjectData(PackedObjectInfo obj,
@@ -1392,7 +1424,7 @@ protected abstract void onInflatedObjectData(PackedObjectInfo obj,
 	 *
 	 * @param objCnt
 	 *            number of objects expected in the stream.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the implementation refuses to work with this many objects.
 	 */
 	protected abstract void onPackHeader(long objCnt) throws IOException;
@@ -1403,7 +1435,7 @@ protected abstract void onInflatedObjectData(PackedObjectInfo obj,
 	 * @param hash
 	 *            the trailing 20 bytes of the pack, this is a SHA-1 checksum of
 	 *            all of the pack data.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the stream cannot be archived.
 	 */
 	protected abstract void onPackFooter(byte[] hash) throws IOException;
@@ -1426,7 +1458,7 @@ protected abstract void onInflatedObjectData(PackedObjectInfo obj,
 	 * @return true if the {@code info} should be included in the object list
 	 *         returned by {@link #getSortedObjectList(Comparator)}, false if it
 	 *         should not be included.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the base could not be included into the pack.
 	 */
 	protected abstract boolean onAppendBase(int typeCode, byte[] data,
@@ -1439,7 +1471,7 @@ protected abstract boolean onAppendBase(int typeCode, byte[] data,
 	 * external from the pack. The event is called after all of those deltas
 	 * have been resolved.
 	 *
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the pack cannot be archived.
 	 */
 	protected abstract void onEndThinPack() throws IOException;
@@ -1456,7 +1488,7 @@ protected abstract boolean onAppendBase(int typeCode, byte[] data,
 	 * @param info
 	 *            object to populate with type and size.
 	 * @return the {@code info} object.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the database cannot reposition to this location.
 	 */
 	protected abstract ObjectTypeAndSize seekDatabase(PackedObjectInfo obj,
@@ -1474,7 +1506,7 @@ protected abstract ObjectTypeAndSize seekDatabase(PackedObjectInfo obj,
 	 * @param info
 	 *            object to populate with type and size.
 	 * @return the {@code info} object.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the database cannot reposition to this location.
 	 */
 	protected abstract ObjectTypeAndSize seekDatabase(UnresolvedDelta delta,
@@ -1491,7 +1523,7 @@ protected abstract ObjectTypeAndSize seekDatabase(UnresolvedDelta delta,
 	 *            ideal target number of bytes to read. Actual read length may
 	 *            be shorter.
 	 * @return number of bytes stored.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the database cannot be accessed.
 	 */
 	protected abstract int readDatabase(byte[] dst, int pos, int cnt)
@@ -1521,13 +1553,15 @@ protected abstract int readDatabase(byte[] dst, int pos, int cnt)
 	 * @param streamPosition
 	 *            position of this object in the incoming stream.
 	 * @param type
-	 *            type of the object; one of {@link Constants#OBJ_COMMIT},
-	 *            {@link Constants#OBJ_TREE}, {@link Constants#OBJ_BLOB}, or
-	 *            {@link Constants#OBJ_TAG}.
+	 *            type of the object; one of
+	 *            {@link org.eclipse.jgit.lib.Constants#OBJ_COMMIT},
+	 *            {@link org.eclipse.jgit.lib.Constants#OBJ_TREE},
+	 *            {@link org.eclipse.jgit.lib.Constants#OBJ_BLOB}, or
+	 *            {@link org.eclipse.jgit.lib.Constants#OBJ_TAG}.
 	 * @param inflatedSize
 	 *            size of the object when fully inflated. The size stored within
 	 *            the pack may be larger or smaller, and is not yet known.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the object cannot be recorded.
 	 */
 	protected abstract void onBeginWholeObject(long streamPosition, int type,
@@ -1538,7 +1572,7 @@ protected abstract void onBeginWholeObject(long streamPosition, int type,
 	 *
 	 *@param info
 	 *            object information.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the object cannot be recorded.
 	 */
 	protected abstract void onEndWholeObject(PackedObjectInfo info)
@@ -1557,7 +1591,7 @@ protected abstract void onEndWholeObject(PackedObjectInfo info)
 	 * @param inflatedSize
 	 *            size of the delta when fully inflated. The size stored within
 	 *            the pack may be larger or smaller, and is not yet known.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the object cannot be recorded.
 	 */
 	protected abstract void onBeginOfsDelta(long deltaStreamPosition,
@@ -1575,7 +1609,7 @@ protected abstract void onBeginOfsDelta(long deltaStreamPosition,
 	 * @param inflatedSize
 	 *            size of the delta when fully inflated. The size stored within
 	 *            the pack may be larger or smaller, and is not yet known.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the object cannot be recorded.
 	 */
 	protected abstract void onBeginRefDelta(long deltaStreamPosition,
@@ -1586,7 +1620,7 @@ protected abstract void onBeginRefDelta(long deltaStreamPosition,
 	 *
 	 *@return object information that must be populated with at least the
 	 *         offset.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the object cannot be recorded.
 	 */
 	protected UnresolvedDelta onEndDelta() throws IOException {
@@ -1602,23 +1636,23 @@ public static class ObjectTypeAndSize {
 		public long size;
 	}
 
-	private void inflateAndSkip(final Source src, final long inflatedSize)
+	private void inflateAndSkip(Source src, long inflatedSize)
 			throws IOException {
-		final InputStream inf = inflate(src, inflatedSize);
-		IO.skipFully(inf, inflatedSize);
-		inf.close();
+		try (InputStream inf = inflate(src, inflatedSize)) {
+			IO.skipFully(inf, inflatedSize);
+		}
 	}
 
-	private byte[] inflateAndReturn(final Source src, final long inflatedSize)
+	private byte[] inflateAndReturn(Source src, long inflatedSize)
 			throws IOException {
 		final byte[] dst = new byte[(int) inflatedSize];
-		final InputStream inf = inflate(src, inflatedSize);
-		IO.readFully(inf, dst, 0, dst.length);
-		inf.close();
+		try (InputStream inf = inflate(src, inflatedSize)) {
+			IO.readFully(inf, dst, 0, dst.length);
+		}
 		return dst;
 	}
 
-	private InputStream inflate(final Source src, final long inflatedSize)
+	private InputStream inflate(Source src, long inflatedSize)
 			throws IOException {
 		inflater.open(src, inflatedSize);
 		return inflater;
@@ -1627,7 +1661,7 @@ private InputStream inflate(final Source src, final long inflatedSize)
 	private static class DeltaChain extends ObjectIdOwnerMap.Entry {
 		UnresolvedDelta head;
 
-		DeltaChain(final AnyObjectId id) {
+		DeltaChain(AnyObjectId id) {
 			super(id);
 		}
 
@@ -1638,7 +1672,7 @@ UnresolvedDelta remove() {
 			return r;
 		}
 
-		void add(final UnresolvedDelta d) {
+		void add(UnresolvedDelta d) {
 			d.next = head;
 			head = d;
 		}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PackedObjectInfo.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PackedObjectInfo.java
index 381c228..59d1b78 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PackedObjectInfo.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PackedObjectInfo.java
@@ -75,11 +75,13 @@ public class PackedObjectInfo extends ObjectIdOwnerMap.Entry {
 	 * @param id
 	 *            the identity of the object the new instance tracks.
 	 */
-	public PackedObjectInfo(final AnyObjectId id) {
+	public PackedObjectInfo(AnyObjectId id) {
 		super(id);
 	}
 
 	/**
+	 * Get offset in pack when object has been already written
+	 *
 	 * @return offset in pack when object has been already written, or 0 if it
 	 *         has not been written yet
 	 */
@@ -93,11 +95,13 @@ public long getOffset() {
 	 * @param offset
 	 *            offset where written object starts
 	 */
-	public void setOffset(final long offset) {
+	public void setOffset(long offset) {
 		this.offset = offset;
 	}
 
 	/**
+	 * Get the 32 bit CRC checksum for the packed data.
+	 *
 	 * @return the 32 bit CRC checksum for the packed data.
 	 */
 	public int getCRC() {
@@ -112,11 +116,13 @@ public int getCRC() {
 	 *            inflated length and delta base reference) as computed by
 	 *            {@link java.util.zip.CRC32}.
 	 */
-	public void setCRC(final int crc) {
+	public void setCRC(int crc) {
 		this.crc = crc;
 	}
 
 	/**
+	 * Get the object type.
+	 *
 	 * @return the object type. The default type is OBJ_BAD, which is considered
 	 *         as unknown or invalid type.
 	 * @since 4.9
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PacketLineIn.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PacketLineIn.java
index e709256..cc556f8 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PacketLineIn.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PacketLineIn.java
@@ -74,6 +74,13 @@ public class PacketLineIn {
 	/** Magic return from {@link #readString()} when a flush packet is found. */
 	public static final String END = new StringBuilder(0).toString(); 	/* must not string pool */
 
+	/**
+	 * Magic return from {@link #readString()} when a delim packet is found.
+	 *
+	 * @since 5.0
+	 */
+	public static final String DELIM = new StringBuilder(0).toString(); 	/* must not string pool */
+
 	static enum AckNackResult {
 		/** NAK */
 		NAK,
@@ -115,7 +122,7 @@ public PacketLineIn(InputStream in, long limit) {
 		this.limit = limit;
 	}
 
-	AckNackResult readACK(final MutableObjectId returnedId) throws IOException {
+	AckNackResult readACK(MutableObjectId returnedId) throws IOException {
 		final String line = readString();
 		if (line.length() == 0)
 			throw new PackProtocolException(JGitText.get().expectedACKNAKFoundEOF);
@@ -147,8 +154,9 @@ else if (arg.equals(" ready")) //$NON-NLS-1$
 	 * use {@link #readStringRaw()} instead.
 	 *
 	 * @return the string. {@link #END} if the string was the magic flush
+	 *         packet, {@link #DELIM} if the string was the magic DELIM
 	 *         packet.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the stream cannot be read.
 	 */
 	public String readString() throws IOException {
@@ -157,6 +165,10 @@ public String readString() throws IOException {
 			log.debug("git< 0000"); //$NON-NLS-1$
 			return END;
 		}
+		if (len == 1) {
+			log.debug("git< 0001"); //$NON-NLS-1$
+			return DELIM;
+		}
 
 		len -= 4; // length header (4 bytes)
 		if (len == 0) {
@@ -186,7 +198,7 @@ public String readString() throws IOException {
 	 *
 	 * @return the string. {@link #END} if the string was the magic flush
 	 *         packet.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the stream cannot be read.
 	 */
 	public String readStringRaw() throws IOException {
@@ -232,6 +244,8 @@ int readLength() throws IOException {
 
 		if (len == 0) {
 			return 0;
+		} else if (len == 1) {
+			return 1;
 		} else if (len < 4) {
 			throw invalidHeader();
 		}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PacketLineOut.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PacketLineOut.java
index a6bd342..a26d1d7 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PacketLineOut.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PacketLineOut.java
@@ -78,7 +78,7 @@ public class PacketLineOut {
 	 * @param outputStream
 	 *            stream.
 	 */
-	public PacketLineOut(final OutputStream outputStream) {
+	public PacketLineOut(OutputStream outputStream) {
 		out = outputStream;
 		lenbuffer = new byte[5];
 		flushOnEnd = true;
@@ -100,11 +100,11 @@ public void setFlushOnEnd(boolean flushOnEnd) {
 	 *
 	 * @param s
 	 *            string to write.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the packet could not be written, the stream is corrupted as
 	 *             the packet may have been only partially written.
 	 */
-	public void writeString(final String s) throws IOException {
+	public void writeString(String s) throws IOException {
 		writePacket(Constants.encode(s));
 	}
 
@@ -114,7 +114,7 @@ public void writeString(final String s) throws IOException {
 	 * @param packet
 	 *            the packet to write; the length of the packet is equal to the
 	 *            size of the byte array.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the packet could not be written, the stream is corrupted as
 	 *             the packet may have been only partially written.
 	 */
@@ -131,7 +131,7 @@ public void writePacket(byte[] packet) throws IOException {
 	 *            first index within {@code buf}.
 	 * @param len
 	 *            number of bytes to write.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the packet could not be written, the stream is corrupted as
 	 *             the packet may have been only partially written.
 	 * @since 4.5
@@ -147,6 +147,20 @@ public void writePacket(byte[] buf, int pos, int len) throws IOException {
 	}
 
 	/**
+	 * Write a packet delim marker (0001).
+	 *
+	 * @throws java.io.IOException
+	 *             the marker could not be written, the stream is corrupted
+	 *             as the marker may have been only partially written.
+	 * @since 5.0
+	 */
+	public void writeDelim() throws IOException {
+		formatLength(1);
+		out.write(lenbuffer, 0, 4);
+		log.debug("git> 0001"); //$NON-NLS-1$
+	}
+
+	/**
 	 * Write a packet end marker, sometimes referred to as a flush command.
 	 * <p>
 	 * Technically this is a magical packet type which can be detected
@@ -155,7 +169,7 @@ public void writePacket(byte[] buf, int pos, int len) throws IOException {
 	 * Implicitly performs a flush on the underlying OutputStream to ensure the
 	 * peer will receive all data written thus far.
 	 *
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the end marker could not be written, the stream is corrupted
 	 *             as the end marker may have been only partially written.
 	 */
@@ -173,7 +187,7 @@ public void end() throws IOException {
 	 * Performs a flush on the underlying OutputStream to ensure the peer will
 	 * receive all data written thus far.
 	 *
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the underlying stream failed to flush.
 	 */
 	public void flush() throws IOException {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PostReceiveHook.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PostReceiveHook.java
index 8e39501..5cbb6f5 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PostReceiveHook.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PostReceiveHook.java
@@ -46,11 +46,13 @@
 import java.util.Collection;
 
 /**
- * Hook invoked by {@link ReceivePack} after all updates are executed.
+ * Hook invoked by {@link org.eclipse.jgit.transport.ReceivePack} after all
+ * updates are executed.
  * <p>
  * The hook is called after all commands have been processed. Only commands with
- * a status of {@link ReceiveCommand.Result#OK} are passed into the hook. To get
- * all commands within the hook, see {@link ReceivePack#getAllCommands()}.
+ * a status of {@link org.eclipse.jgit.transport.ReceiveCommand.Result#OK} are
+ * passed into the hook. To get all commands within the hook, see
+ * {@link org.eclipse.jgit.transport.ReceivePack#getAllCommands()}.
  * <p>
  * Any post-receive hook implementation should not update the status of a
  * command, as the command has already completed or failed, and the status has
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PostReceiveHookChain.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PostReceiveHookChain.java
index 3bdcd68..0bdf7d4 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PostReceiveHookChain.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PostReceiveHookChain.java
@@ -47,7 +47,8 @@
 import java.util.List;
 
 /**
- * {@link PostReceiveHook} that delegates to a list of other hooks.
+ * {@link org.eclipse.jgit.transport.PostReceiveHook} that delegates to a list
+ * of other hooks.
  * <p>
  * Hooks are run in the order passed to the constructor.
  */
@@ -77,6 +78,7 @@ else if (i == 1)
 			return new PostReceiveHookChain(newHooks, i);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void onPostReceive(ReceivePack rp,
 			Collection<ReceiveCommand> commands) {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PostUploadHook.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PostUploadHook.java
index 5b37bcd..09667eb 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PostUploadHook.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PostUploadHook.java
@@ -42,11 +42,11 @@
 
 package org.eclipse.jgit.transport;
 
-import org.eclipse.jgit.internal.storage.pack.PackWriter;
 import org.eclipse.jgit.storage.pack.PackStatistics;
 
 /**
- * Hook invoked by {@link UploadPack} after the pack has been uploaded.
+ * Hook invoked by {@link org.eclipse.jgit.transport.UploadPack} after the pack
+ * has been uploaded.
  * <p>
  * Implementors of the interface are responsible for associating the current
  * thread to a particular connection, if they need to also include connection
@@ -68,8 +68,9 @@ public void onPostUpload(PackStatistics stats) {
 	 * Notifies the hook that a pack has been sent.
 	 *
 	 * @param stats
-	 *            the statistics gathered by {@link PackWriter} for the uploaded
-	 *            pack
+	 *            the statistics gathered by
+	 *            {@link org.eclipse.jgit.internal.storage.pack.PackWriter} for
+	 *            the uploaded pack
 	 */
 	public void onPostUpload(PackStatistics stats);
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PostUploadHookChain.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PostUploadHookChain.java
index 26323ba..542abe7 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PostUploadHookChain.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PostUploadHookChain.java
@@ -47,7 +47,8 @@
 import org.eclipse.jgit.storage.pack.PackStatistics;
 
 /**
- * {@link PostUploadHook} that delegates to a list of other hooks.
+ * {@link org.eclipse.jgit.transport.PostUploadHook} that delegates to a list of
+ * other hooks.
  * <p>
  * Hooks are run in the order passed to the constructor.
  *
@@ -78,6 +79,7 @@ else if (i == 1)
 			return new PostUploadHookChain(newHooks, i);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void onPostUpload(PackStatistics stats) {
 		for (int i = 0; i < count; i++)
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PreReceiveHook.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PreReceiveHook.java
index 27b2df0..77c1a8a 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PreReceiveHook.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PreReceiveHook.java
@@ -46,7 +46,8 @@
 import java.util.Collection;
 
 /**
- * Hook invoked by {@link ReceivePack} before any updates are executed.
+ * Hook invoked by {@link org.eclipse.jgit.transport.ReceivePack} before any
+ * updates are executed.
  * <p>
  * The hook is called with any commands that are deemed valid after parsing them
  * from the client and applying the standard receive configuration options to
@@ -57,23 +58,24 @@
  * </ul>
  * This means the hook will not receive a non-fast-forward update command if
  * denyNonFastForwards is set to true in the configuration file. To get all
- * commands within the hook, see {@link ReceivePack#getAllCommands()}.
+ * commands within the hook, see
+ * {@link org.eclipse.jgit.transport.ReceivePack#getAllCommands()}.
  * <p>
  * As the hook is invoked prior to the commands being executed, the hook may
  * choose to block any command by setting its result status with
- * {@link ReceiveCommand#setResult(ReceiveCommand.Result)}.
+ * {@link org.eclipse.jgit.transport.ReceiveCommand#setResult(ReceiveCommand.Result)}.
  * <p>
  * The hook may also choose to perform the command itself (or merely pretend
  * that it has performed the command), by setting the result status to
- * {@link ReceiveCommand.Result#OK}.
+ * {@link org.eclipse.jgit.transport.ReceiveCommand.Result#OK}.
  * <p>
  * Hooks should run quickly, as they block the caller thread and the client
  * process from completing.
  * <p>
  * Hooks may send optional messages back to the client via methods on
- * {@link ReceivePack}. Implementors should be aware that not all network
- * transports support this output, so some (or all) messages may simply be
- * discarded. These messages should be advisory only.
+ * {@link org.eclipse.jgit.transport.ReceivePack}. Implementors should be aware
+ * that not all network transports support this output, so some (or all)
+ * messages may simply be discarded. These messages should be advisory only.
  */
 public interface PreReceiveHook {
 	/** A simple no-op hook. */
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PreReceiveHookChain.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PreReceiveHookChain.java
index 7b1c8fb..47b94c6 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PreReceiveHookChain.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PreReceiveHookChain.java
@@ -47,7 +47,8 @@
 import java.util.List;
 
 /**
- * {@link PreReceiveHook} that delegates to a list of other hooks.
+ * {@link org.eclipse.jgit.transport.PreReceiveHook} that delegates to a list of
+ * other hooks.
  * <p>
  * Hooks are run in the order passed to the constructor.
  */
@@ -76,6 +77,7 @@ else if (i == 1)
 			return new PreReceiveHookChain(newHooks, i);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void onPreReceive(ReceivePack rp,
 			Collection<ReceiveCommand> commands) {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PreUploadHook.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PreUploadHook.java
index 7d9638c..2e1cd58 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PreUploadHook.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PreUploadHook.java
@@ -48,9 +48,11 @@
 import org.eclipse.jgit.lib.ObjectId;
 
 /**
- * Hook invoked by {@link UploadPack} before during critical phases.
+ * Hook invoked by {@link org.eclipse.jgit.transport.UploadPack} before during
+ * critical phases.
  * <p>
- * If any hook function throws {@link ServiceMayNotContinueException} then
+ * If any hook function throws
+ * {@link org.eclipse.jgit.transport.ServiceMayNotContinueException} then
  * processing stops immediately and the exception is thrown up the call stack.
  * Most phases of UploadPack will try to report the exception's message text to
  * the end-user over the client's protocol connection.
@@ -91,7 +93,7 @@ public void onSendPack(UploadPack up,
 	 *            the list of wanted objects.
 	 * @param cntOffered
 	 *            number of objects the client has offered.
-	 * @throws ServiceMayNotContinueException
+	 * @throws org.eclipse.jgit.transport.ServiceMayNotContinueException
 	 *             abort; the message will be sent to the user.
 	 */
 	public void onBeginNegotiateRound(UploadPack up,
@@ -115,7 +117,7 @@ public void onBeginNegotiateRound(UploadPack up,
 	 * @param ready
 	 *            true if a pack is ready to be sent (the commit graph was
 	 *            successfully cut).
-	 * @throws ServiceMayNotContinueException
+	 * @throws org.eclipse.jgit.transport.ServiceMayNotContinueException
 	 *             abort; the message will be sent to the user.
 	 */
 	public void onEndNegotiateRound(UploadPack up,
@@ -136,7 +138,7 @@ public void onEndNegotiateRound(UploadPack up,
 	 *            the list of common objects. Empty on an initial clone request.
 	 *            These may be RevObject or RevCommit if the processed parsed
 	 *            them. Implementors should not rely on the values being parsed.
-	 * @throws ServiceMayNotContinueException
+	 * @throws org.eclipse.jgit.transport.ServiceMayNotContinueException
 	 *             abort; the message will be sent to the user.
 	 */
 	public void onSendPack(UploadPack up, Collection<? extends ObjectId> wants,
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PreUploadHookChain.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PreUploadHookChain.java
index c9f88dd..bfd52af 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PreUploadHookChain.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PreUploadHookChain.java
@@ -49,7 +49,8 @@
 import org.eclipse.jgit.lib.ObjectId;
 
 /**
- * {@link PreUploadHook} that delegates to a list of other hooks.
+ * {@link org.eclipse.jgit.transport.PreUploadHook} that delegates to a list of
+ * other hooks.
  * <p>
  * Hooks are run in the order passed to the constructor. If running a method on
  * one hook throws an exception, execution of remaining hook methods is aborted.
@@ -79,6 +80,7 @@ else if (i == 1)
 			return new PreUploadHookChain(newHooks, i);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void onBeginNegotiateRound(UploadPack up,
 			Collection<? extends ObjectId> wants, int cntOffered)
@@ -87,6 +89,7 @@ public void onBeginNegotiateRound(UploadPack up,
 			hooks[i].onBeginNegotiateRound(up, wants, cntOffered);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void onEndNegotiateRound(UploadPack up,
 			Collection<? extends ObjectId> wants, int cntCommon,
@@ -96,6 +99,7 @@ public void onEndNegotiateRound(UploadPack up,
 			hooks[i].onEndNegotiateRound(up, wants, cntCommon, cntNotFound, ready);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void onSendPack(UploadPack up,
 			Collection<? extends ObjectId> wants,
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/ProgressSpinner.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/ProgressSpinner.java
index ac048a1..2364434 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/ProgressSpinner.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/ProgressSpinner.java
@@ -43,7 +43,7 @@
 
 package org.eclipse.jgit.transport;
 
-import static java.nio.charset.StandardCharsets.UTF_8;
+import static org.eclipse.jgit.lib.Constants.CHARSET;
 
 import java.io.IOException;
 import java.io.OutputStream;
@@ -104,7 +104,9 @@ public void beginTask(String title, long delay, TimeUnit delayUnits) {
 		}
 	}
 
-	/** Update the spinner if it is showing. */
+	/**
+	 * Update the spinner if it is showing.
+	 */
 	public void update() {
 		long now = System.currentTimeMillis();
 		if (now >= nextUpdateMillis) {
@@ -139,7 +141,7 @@ public void endTask(String result) {
 	private void write(String s) {
 		if (write) {
 			try {
-				out.write(s.getBytes(UTF_8));
+				out.write(s.getBytes(CHARSET));
 				out.flush();
 			} catch (IOException e) {
 				write = false;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PushCertificate.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PushCertificate.java
index e450345..a9397a5 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PushCertificate.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PushCertificate.java
@@ -132,6 +132,8 @@ public enum NonceStatus {
 	}
 
 	/**
+	 * Get the certificate version string.
+	 *
 	 * @return the certificate version string.
 	 * @since 4.1
 	 */
@@ -140,6 +142,8 @@ public String getVersion() {
 	}
 
 	/**
+	 * Get the raw line that signed the cert, as a string.
+	 *
 	 * @return the raw line that signed the cert, as a string.
 	 * @since 4.0
 	 */
@@ -148,6 +152,8 @@ public String getPusher() {
 	}
 
 	/**
+	 * Get identity of the pusher who signed the cert.
+	 *
 	 * @return identity of the pusher who signed the cert.
 	 * @since 4.1
 	 */
@@ -156,6 +162,8 @@ public PushCertificateIdent getPusherIdent() {
 	}
 
 	/**
+	 * Get URL of the repository the push was originally sent to.
+	 *
 	 * @return URL of the repository the push was originally sent to.
 	 * @since 4.0
 	 */
@@ -164,6 +172,8 @@ public String getPushee() {
 	}
 
 	/**
+	 * Get the raw nonce value that was presented by the pusher.
+	 *
 	 * @return the raw nonce value that was presented by the pusher.
 	 * @since 4.1
 	 */
@@ -172,6 +182,8 @@ public String getNonce() {
 	}
 
 	/**
+	 * Get verification status of the nonce embedded in the certificate.
+	 *
 	 * @return verification status of the nonce embedded in the certificate.
 	 * @since 4.0
 	 */
@@ -180,6 +192,9 @@ public NonceStatus getNonceStatus() {
 	}
 
 	/**
+	 * Get the list of commands as one string to be feed into the signature
+	 * verifier.
+	 *
 	 * @return the list of commands as one string to be feed into the signature
 	 *         verifier.
 	 * @since 4.1
@@ -189,9 +204,11 @@ public List<ReceiveCommand> getCommands() {
 	}
 
 	/**
+	 * Get the raw signature
+	 *
 	 * @return the raw signature, consisting of the lines received between the
-	 *     lines {@code "----BEGIN GPG SIGNATURE-----\n"} and
-	 *     {@code "----END GPG SIGNATURE-----\n}", inclusive.
+	 *         lines {@code "----BEGIN GPG SIGNATURE-----\n"} and
+	 *         {@code "----END GPG SIGNATURE-----\n}", inclusive.
 	 * @since 4.0
 	 */
 	public String getSignature() {
@@ -199,6 +216,8 @@ public String getSignature() {
 	}
 
 	/**
+	 * Get text payload of the certificate for the signature verifier.
+	 *
 	 * @return text payload of the certificate for the signature verifier.
 	 * @since 4.1
 	 */
@@ -207,8 +226,11 @@ public String toText() {
 	}
 
 	/**
+	 * Get original text payload plus signature
+	 *
 	 * @return original text payload plus signature; the final output will be
-	 *     valid as input to {@link PushCertificateParser#fromString(String)}.
+	 *         valid as input to
+	 *         {@link org.eclipse.jgit.transport.PushCertificateParser#fromString(String)}.
 	 * @since 4.1
 	 */
 	public String toTextWithSignature() {
@@ -233,11 +255,13 @@ private StringBuilder toStringBuilder() {
 		return sb;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public int hashCode() {
 		return signature.hashCode();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public boolean equals(Object o) {
 		if (!(o instanceof PushCertificate)) {
@@ -268,6 +292,7 @@ private static boolean commandsEqual(PushCertificate c1, PushCertificate c2) {
 		return true;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public String toString() {
 		return getClass().getSimpleName() + '['
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PushCertificateIdent.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PushCertificateIdent.java
index 4c8acd2..178c80d 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PushCertificateIdent.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PushCertificateIdent.java
@@ -43,7 +43,7 @@
 
 package org.eclipse.jgit.transport;
 
-import static java.nio.charset.StandardCharsets.UTF_8;
+import static org.eclipse.jgit.lib.Constants.CHARSET;
 import static org.eclipse.jgit.util.RawParseUtils.lastIndexOfTrim;
 
 import java.text.SimpleDateFormat;
@@ -58,18 +58,19 @@
 /**
  * Identity in a push certificate.
  * <p>
- * This is similar to a {@link PersonIdent} in that it contains a name,
- * timestamp, and timezone offset, but differs in the following ways:
+ * This is similar to a {@link org.eclipse.jgit.lib.PersonIdent} in that it
+ * contains a name, timestamp, and timezone offset, but differs in the following
+ * ways:
  * <ul>
  * <li>It is always parsed from a UTF-8 string, rather than a raw commit
- *   buffer.</li>
+ * buffer.</li>
  * <li>It is not guaranteed to contain a name and email portion, since any UTF-8
- *   string is a valid OpenPGP User ID (RFC4880 5.1.1). The raw User ID is
- *   always available as {@link #getUserId()}, but {@link #getEmailAddress()}
- *   may return null.</li>
- * <li>The raw text from which the identity was parsed is available with {@link
- *   #getRaw()}. This is necessary for losslessly reconstructing the signed push
- *   certificate payload.</li>
+ * string is a valid OpenPGP User ID (RFC4880 5.1.1). The raw User ID is always
+ * available as {@link #getUserId()}, but {@link #getEmailAddress()} may return
+ * null.</li>
+ * <li>The raw text from which the identity was parsed is available with
+ * {@link #getRaw()}. This is necessary for losslessly reconstructing the signed
+ * push certificate payload.</li>
  * <li>
  * </ul>
  *
@@ -79,22 +80,22 @@ public class PushCertificateIdent {
 	/**
 	 * Parse an identity from a string.
 	 * <p>
-	 * Spaces are trimmed when parsing the timestamp and timezone offset, with one
-	 * exception. The timestamp must be preceded by a single space, and the rest
-	 * of the string prior to that space (including any additional whitespace) is
-	 * treated as the OpenPGP User ID.
+	 * Spaces are trimmed when parsing the timestamp and timezone offset, with
+	 * one exception. The timestamp must be preceded by a single space, and the
+	 * rest of the string prior to that space (including any additional
+	 * whitespace) is treated as the OpenPGP User ID.
 	 * <p>
-	 * If either the timestamp or timezone offsets are missing, mimics {@link
-	 * RawParseUtils#parsePersonIdent(String)} behavior and sets them both to
-	 * zero.
+	 * If either the timestamp or timezone offsets are missing, mimics
+	 * {@link RawParseUtils#parsePersonIdent(String)} behavior and sets them
+	 * both to zero.
 	 *
 	 * @param str
 	 *            string to parse.
-	 * @return identity, never null.
+	 * @return a {@link org.eclipse.jgit.transport.PushCertificateIdent} object.
 	 */
 	public static PushCertificateIdent parse(String str) {
 		MutableInteger p = new MutableInteger();
-		byte[] raw = str.getBytes(UTF_8);
+		byte[] raw = str.getBytes(CHARSET);
 		int tzBegin = raw.length - 1;
 		tzBegin = lastIndexOfTrim(raw, ' ', tzBegin);
 		if (tzBegin < 0 || raw[tzBegin] != ' ') {
@@ -128,7 +129,7 @@ public static PushCertificateIdent parse(String str) {
 				idEnd = raw.length;
 			}
 		}
-		String id = new String(raw, 0, idEnd, UTF_8);
+		String id = new String(raw, 0, idEnd, CHARSET);
 
 		return new PushCertificateIdent(str, id, when * 1000L, tz);
 	}
@@ -181,15 +182,21 @@ public String getRaw() {
 		return raw;
 	}
 
-	/** @return the OpenPGP User ID, which may be any string. */
+	/**
+	 * Get the OpenPGP User ID, which may be any string.
+	 *
+	 * @return the OpenPGP User ID, which may be any string.
+	 */
 	public String getUserId() {
 		return userId;
 	}
 
 	/**
+	 * Get the name portion of the User ID.
+	 *
 	 * @return the name portion of the User ID. If no email address would be
-	 *         parsed by {@link #getEmailAddress()}, returns the full User ID with
-	 *         spaces trimmed.
+	 *         parsed by {@link #getEmailAddress()}, returns the full User ID
+	 *         with spaces trimmed.
 	 */
 	public String getName() {
 		int nameEnd = userId.indexOf('<');
@@ -208,6 +215,8 @@ public String getName() {
 	}
 
 	/**
+	 * Get the email portion of the User ID
+	 *
 	 * @return the email portion of the User ID, if one was successfully parsed
 	 *         from {@link #getUserId()}, or null.
 	 */
@@ -223,19 +232,28 @@ public String getEmailAddress() {
 		return userId.substring(emailBegin + 1, emailEnd);
 	}
 
-	/** @return the timestamp of the identity. */
+	/**
+	 * Get the timestamp of the identity.
+	 *
+	 * @return the timestamp of the identity.
+	 */
 	public Date getWhen() {
 		return new Date(when);
 	}
 
 	/**
-	 * @return this person's declared time zone; null if the timezone is unknown.
+	 * Get this person's declared time zone
+	 *
+	 * @return this person's declared time zone; null if the timezone is
+	 *         unknown.
 	 */
 	public TimeZone getTimeZone() {
 		return PersonIdent.getTimeZone(tzOffset);
 	}
 
 	/**
+	 * Get this person's declared time zone as minutes east of UTC.
+	 *
 	 * @return this person's declared time zone as minutes east of UTC. If the
 	 *         timezone is to the west of UTC it is negative.
 	 */
@@ -243,17 +261,20 @@ public int getTimeZoneOffset() {
 		return tzOffset;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public boolean equals(Object o) {
 		return (o instanceof PushCertificateIdent)
 			&& raw.equals(((PushCertificateIdent) o).raw);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public int hashCode() {
 		return raw.hashCode();
 	}
 
+	/** {@inheritDoc} */
 	@SuppressWarnings("nls")
 	@Override
 	public String toString() {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PushCertificateParser.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PushCertificateParser.java
index 5174f85..89c1a93 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PushCertificateParser.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PushCertificateParser.java
@@ -133,11 +133,12 @@ public String read() throws IOException {
 	/**
 	 * Parse a push certificate from a reader.
 	 * <p>
-	 * Differences from the {@link PacketLineIn} receiver methods:
+	 * Differences from the {@link org.eclipse.jgit.transport.PacketLineIn}
+	 * receiver methods:
 	 * <ul>
 	 * <li>Does not use pkt-line framing.</li>
 	 * <li>Reads an entire cert in one call rather than depending on a loop in
-	 *   the caller.</li>
+	 * the caller.</li>
 	 * <li>Does not assume a {@code "push-cert-end"} line.</li>
 	 * </ul>
 	 *
@@ -145,9 +146,9 @@ public String read() throws IOException {
 	 *            input reader; consumed only up until the end of the next
 	 *            signature in the input.
 	 * @return the parsed certificate, or null if the reader was at EOF.
-	 * @throws PackProtocolException
+	 * @throws org.eclipse.jgit.errors.PackProtocolException
 	 *             if the certificate is malformed.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             if there was an error reading from the input.
 	 * @since 4.1
 	 */
@@ -163,9 +164,9 @@ public static PushCertificate fromReader(Reader r)
 	 * @param str
 	 *            input string.
 	 * @return the parsed certificate.
-	 * @throws PackProtocolException
+	 * @throws org.eclipse.jgit.errors.PackProtocolException
 	 *             if the certificate is malformed.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             if there was an error reading from the input.
 	 * @since 4.1
 	 */
@@ -207,6 +208,8 @@ public static PushCertificate fromString(String str)
 	private final List<ReceiveCommand> commands = new ArrayList<>();
 
 	/**
+	 * <p>Constructor for PushCertificateParser.</p>
+	 *
 	 * @param into
 	 *            destination repository for the push.
 	 * @param cfg
@@ -240,9 +243,9 @@ private PushCertificateParser() {
 	 *            input reader; consumed only up until the end of the next
 	 *            signature in the input.
 	 * @return the parsed certificate, or null if the reader was at EOF.
-	 * @throws PackProtocolException
+	 * @throws org.eclipse.jgit.errors.PackProtocolException
 	 *             if the certificate is malformed.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             if there was an error reading from the input.
 	 * @since 4.1
 	 */
@@ -267,8 +270,11 @@ public PushCertificate parse(Reader r)
 	}
 
 	/**
-	 * @return the parsed certificate, or null if push certificates are disabled.
-	 * @throws IOException
+	 * Build the parsed certificate
+	 *
+	 * @return the parsed certificate, or null if push certificates are
+	 *         disabled.
+	 * @throws java.io.IOException
 	 *             if the push certificate has missing or invalid fields.
 	 * @since 4.1
 	 */
@@ -285,6 +291,9 @@ public PushCertificate build() throws IOException {
 	}
 
 	/**
+	 * Whether the repository is configured to use signed pushes in this
+	 * context.
+	 *
 	 * @return if the repository is configured to use signed pushes in this
 	 *         context.
 	 * @since 4.0
@@ -294,6 +303,9 @@ public boolean enabled() {
 	}
 
 	/**
+	 * Get the whole string for the nonce to be included into the capability
+	 * advertisement
+	 *
 	 * @return the whole string for the nonce to be included into the capability
 	 *         advertisement, or null if push certificates are disabled.
 	 * @since 4.0
@@ -348,7 +360,7 @@ private static String parseHeader(String s, String header)
 	 *            {@code NonceGenerator} will allow for some time skew caused by
 	 *            clients disconnected and reconnecting in the stateless smart
 	 *            HTTP protocol.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             if the certificate from the client is badly malformed or the
 	 *             client disconnects before sending the entire certificate.
 	 * @since 4.0
@@ -410,7 +422,7 @@ receivedNonce, sentNonce(), db, stateless, nonceSlopLimit)
 	 *
 	 * @param pckIn
 	 *            where we read the signature from.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             if the signature is invalid.
 	 * @since 4.0
 	 */
@@ -455,7 +467,7 @@ public void addCommand(ReceiveCommand cmd) {
 	 * @param line
 	 *            the line read from the wire that produced this
 	 *            command, with optional trailing newline already trimmed.
-	 * @throws PackProtocolException
+	 * @throws org.eclipse.jgit.errors.PackProtocolException
 	 *             if the raw line cannot be parsed to a command.
 	 * @since 4.0
 	 */
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PushCertificateStore.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PushCertificateStore.java
index 706e727..7f5a340 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PushCertificateStore.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PushCertificateStore.java
@@ -43,7 +43,7 @@
 
 package org.eclipse.jgit.transport;
 
-import static java.nio.charset.StandardCharsets.UTF_8;
+import static org.eclipse.jgit.lib.Constants.CHARSET;
 import static org.eclipse.jgit.lib.Constants.OBJ_BLOB;
 import static org.eclipse.jgit.lib.Constants.OBJ_COMMIT;
 import static org.eclipse.jgit.lib.FileMode.TYPE_FILE;
@@ -135,10 +135,12 @@ public PushCertificateStore(Repository db) {
 	}
 
 	/**
+	 * {@inheritDoc}
+	 * <p>
 	 * Close resources opened by this store.
 	 * <p>
-	 * If {@link #get(String)} was called, closes the cached object reader created
-	 * by that method. Does not close the underlying repository.
+	 * If {@link #get(String)} was called, closes the cached object reader
+	 * created by that method. Does not close the underlying repository.
 	 */
 	@Override
 	public void close() {
@@ -160,7 +162,7 @@ public void close() {
 	 *            the ref name to get the certificate for.
 	 * @return last certificate affecting the ref, or null if no cert was recorded
 	 *         for the last update to this ref.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             if a problem occurred reading the repository.
 	 */
 	public PushCertificate get(String refName) throws IOException {
@@ -190,7 +192,7 @@ public PushCertificate get(String refName) throws IOException {
 	 * @return iterable over certificates; must be fully iterated in order to
 	 *         close resources.
 	 */
-	public Iterable<PushCertificate> getAll(final String refName) {
+	public Iterable<PushCertificate> getAll(String refName) {
 		return new Iterable<PushCertificate>() {
 			@Override
 			public Iterator<PushCertificate> iterator() {
@@ -290,7 +292,7 @@ static PushCertificate read(TreeWalk tw) throws IOException {
 		ObjectLoader loader =
 				tw.getObjectReader().open(tw.getObjectId(0), OBJ_BLOB);
 		try (InputStream in = loader.openStream();
-				Reader r = new BufferedReader(new InputStreamReader(in, UTF_8))) {
+				Reader r = new BufferedReader(new InputStreamReader(in, CHARSET))) {
 			return PushCertificateParser.fromReader(r);
 		}
 	}
@@ -298,20 +300,20 @@ static PushCertificate read(TreeWalk tw) throws IOException {
 	/**
 	 * Put a certificate to be saved to the store.
 	 * <p>
-	 * Writes the contents of this certificate for each ref mentioned. It is up to
-	 * the caller to ensure this certificate accurately represents the state of
-	 * the ref.
+	 * Writes the contents of this certificate for each ref mentioned. It is up
+	 * to the caller to ensure this certificate accurately represents the state
+	 * of the ref.
 	 * <p>
-	 * Pending certificates added to this method are not returned by {@link
-	 * #get(String)} and {@link #getAll(String)} until after calling {@link
-	 * #save()}.
+	 * Pending certificates added to this method are not returned by
+	 * {@link #get(String)} and {@link #getAll(String)} until after calling
+	 * {@link #save()}.
 	 *
 	 * @param cert
 	 *            certificate to store.
 	 * @param ident
 	 *            identity for the commit that stores this certificate. Pending
-	 *            certificates are sorted by identity timestamp during {@link
-	 *            #save()}.
+	 *            certificates are sorted by identity timestamp during
+	 *            {@link #save()}.
 	 */
 	public void put(PushCertificate cert, PersonIdent ident) {
 		put(cert, ident, null);
@@ -325,16 +327,16 @@ public void put(PushCertificate cert, PersonIdent ident) {
 	 * list that exactly matches the old/new values mentioned in the push
 	 * certificate.
 	 * <p>
-	 * Pending certificates added to this method are not returned by {@link
-	 * #get(String)} and {@link #getAll(String)} until after calling {@link
-	 * #save()}.
+	 * Pending certificates added to this method are not returned by
+	 * {@link #get(String)} and {@link #getAll(String)} until after calling
+	 * {@link #save()}.
 	 *
 	 * @param cert
 	 *            certificate to store.
 	 * @param ident
 	 *            identity for the commit that stores this certificate. Pending
-	 *            certificates are sorted by identity timestamp during {@link
-	 *            #save()}.
+	 *            certificates are sorted by identity timestamp during
+	 *            {@link #save()}.
 	 * @param matching
 	 *            only store certs for the refs listed in this list whose values
 	 *            match the commands in the cert.
@@ -347,15 +349,15 @@ public void put(PushCertificate cert, PersonIdent ident,
 	/**
 	 * Save pending certificates to the store.
 	 * <p>
-	 * One commit is created per certificate added with {@link
-	 * #put(PushCertificate, PersonIdent)}, in order of identity timestamps, and
-	 * a single ref update is performed.
+	 * One commit is created per certificate added with
+	 * {@link #put(PushCertificate, PersonIdent)}, in order of identity
+	 * timestamps, and a single ref update is performed.
 	 * <p>
-	 * The pending list is cleared if and only the ref update fails, which allows
-	 * for easy retries in case of lock failure.
+	 * The pending list is cleared if and only the ref update fails, which
+	 * allows for easy retries in case of lock failure.
 	 *
 	 * @return the result of attempting to update the ref.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             if there was an error reading from or writing to the
 	 *             repository.
 	 */
@@ -384,18 +386,19 @@ public RefUpdate.Result save() throws IOException {
 	/**
 	 * Save pending certificates to the store in an existing batch ref update.
 	 * <p>
-	 * One commit is created per certificate added with {@link
-	 * #put(PushCertificate, PersonIdent)}, in order of identity timestamps, all
-	 * commits are flushed, and a single command is added to the batch.
+	 * One commit is created per certificate added with
+	 * {@link #put(PushCertificate, PersonIdent)}, in order of identity
+	 * timestamps, all commits are flushed, and a single command is added to the
+	 * batch.
 	 * <p>
-	 * The cached ref value and pending list are <em>not</em> cleared. If the ref
-	 * update succeeds, the caller is responsible for calling {@link #close()}
-	 * and/or {@link #clear()}.
+	 * The cached ref value and pending list are <em>not</em> cleared. If the
+	 * ref update succeeds, the caller is responsible for calling
+	 * {@link #close()} and/or {@link #clear()}.
 	 *
 	 * @param batch
 	 *            update to save to.
 	 * @return whether a command was added to the batch.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             if there was an error reading from or writing to the
 	 *             repository.
 	 */
@@ -470,7 +473,7 @@ private ObjectId saveCert(ObjectInserter inserter, DirCache dc,
 
 		DirCacheEditor editor = dc.editor();
 		String certText = pc.cert.toText() + pc.cert.getSignature();
-		final ObjectId certId = inserter.insert(OBJ_BLOB, certText.getBytes(UTF_8));
+		final ObjectId certId = inserter.insert(OBJ_BLOB, certText.getBytes(CHARSET));
 		boolean any = false;
 		for (ReceiveCommand cmd : pc.cert.getCommands()) {
 			if (byRef != null && !commandsEqual(cmd, byRef.get(cmd.getRefName()))) {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PushConnection.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PushConnection.java
index c2a885f..ff2939a 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PushConnection.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PushConnection.java
@@ -49,7 +49,6 @@
 
 import org.eclipse.jgit.errors.TransportException;
 import org.eclipse.jgit.lib.ProgressMonitor;
-import org.eclipse.jgit.transport.RemoteRefUpdate.Status;
 
 /**
  * Lists known refs from the remote and sends objects to the remote.
@@ -60,9 +59,9 @@
  * into the remote repository, as well as a way to modify the refs stored by the
  * remote repository.
  * <p>
- * Instances of a PushConnection must be created by a {@link Transport} that
- * implements a specific object transfer protocol that both sides of the
- * connection understand.
+ * Instances of a PushConnection must be created by a
+ * {@link org.eclipse.jgit.transport.Transport} that implements a specific
+ * object transfer protocol that both sides of the connection understand.
  * <p>
  * PushConnection instances are not thread safe and may be accessed by only one
  * thread at a time.
@@ -79,13 +78,14 @@ public interface PushConnection extends Connection {
 	 * <p>
 	 * <p>
 	 * Only one call per connection is allowed. Subsequent calls will result in
-	 * {@link TransportException}.
+	 * {@link org.eclipse.jgit.errors.TransportException}.
 	 * </p>
 	 * <p>
 	 * Implementation may use local repository to send a minimum set of objects
 	 * needed by remote repository in efficient way.
-	 * {@link Transport#isPushThin()} should be honored if applicable.
-	 * refUpdates should be filled with information about status of each update.
+	 * {@link org.eclipse.jgit.transport.Transport#isPushThin()} should be
+	 * honored if applicable. refUpdates should be filled with information about
+	 * status of each update.
 	 * </p>
 	 *
 	 * @param monitor
@@ -97,12 +97,16 @@ public interface PushConnection extends Connection {
 	 *            map of remote refnames to remote refs update
 	 *            specifications/statuses. Can't be empty. This indicate what
 	 *            refs caller want to update on remote side. Only refs updates
-	 *            with {@link Status#NOT_ATTEMPTED} should passed.
-	 *            Implementation must ensure that and appropriate status with
-	 *            optional message should be set during call. No refUpdate with
-	 *            {@link Status#AWAITING_REPORT} or {@link Status#NOT_ATTEMPTED}
+	 *            with
+	 *            {@link org.eclipse.jgit.transport.RemoteRefUpdate.Status#NOT_ATTEMPTED}
+	 *            should passed. Implementation must ensure that and appropriate
+	 *            status with optional message should be set during call. No
+	 *            refUpdate with
+	 *            {@link org.eclipse.jgit.transport.RemoteRefUpdate.Status#AWAITING_REPORT}
+	 *            or
+	 *            {@link org.eclipse.jgit.transport.RemoteRefUpdate.Status#NOT_ATTEMPTED}
 	 *            can be leaved by implementation after return from this call.
-	 * @throws TransportException
+	 * @throws org.eclipse.jgit.errors.TransportException
 	 *             objects could not be copied due to a network failure,
 	 *             critical protocol error, or error on remote side, or
 	 *             connection was already used for push - new connection must be
@@ -121,13 +125,14 @@ public void push(final ProgressMonitor monitor,
 	 * <p>
 	 * <p>
 	 * Only one call per connection is allowed. Subsequent calls will result in
-	 * {@link TransportException}.
+	 * {@link org.eclipse.jgit.errors.TransportException}.
 	 * </p>
 	 * <p>
 	 * Implementation may use local repository to send a minimum set of objects
 	 * needed by remote repository in efficient way.
-	 * {@link Transport#isPushThin()} should be honored if applicable.
-	 * refUpdates should be filled with information about status of each update.
+	 * {@link org.eclipse.jgit.transport.Transport#isPushThin()} should be
+	 * honored if applicable. refUpdates should be filled with information about
+	 * status of each update.
 	 * </p>
 	 *
 	 * @param monitor
@@ -139,14 +144,18 @@ public void push(final ProgressMonitor monitor,
 	 *            map of remote refnames to remote refs update
 	 *            specifications/statuses. Can't be empty. This indicate what
 	 *            refs caller want to update on remote side. Only refs updates
-	 *            with {@link Status#NOT_ATTEMPTED} should passed.
-	 *            Implementation must ensure that and appropriate status with
-	 *            optional message should be set during call. No refUpdate with
-	 *            {@link Status#AWAITING_REPORT} or {@link Status#NOT_ATTEMPTED}
+	 *            with
+	 *            {@link org.eclipse.jgit.transport.RemoteRefUpdate.Status#NOT_ATTEMPTED}
+	 *            should passed. Implementation must ensure that and appropriate
+	 *            status with optional message should be set during call. No
+	 *            refUpdate with
+	 *            {@link org.eclipse.jgit.transport.RemoteRefUpdate.Status#AWAITING_REPORT}
+	 *            or
+	 *            {@link org.eclipse.jgit.transport.RemoteRefUpdate.Status#NOT_ATTEMPTED}
 	 *            can be leaved by implementation after return from this call.
 	 * @param out
 	 *            output stream to write sideband messages to
-	 * @throws TransportException
+	 * @throws org.eclipse.jgit.errors.TransportException
 	 *             objects could not be copied due to a network failure,
 	 *             critical protocol error, or error on remote side, or
 	 *             connection was already used for push - new connection must be
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PushProcess.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PushProcess.java
index 3201732..470a3c0 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PushProcess.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PushProcess.java
@@ -48,7 +48,7 @@
 import java.text.MessageFormat;
 import java.util.Collection;
 import java.util.Collections;
-import java.util.HashMap;
+import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 
@@ -124,10 +124,10 @@ class PushProcess {
 			throws TransportException {
 		this.walker = new RevWalk(transport.local);
 		this.transport = transport;
-		this.toPush = new HashMap<>();
+		this.toPush = new LinkedHashMap<>();
 		this.out = out;
 		this.pushOptions = transport.getPushOptions();
-		for (final RemoteRefUpdate rru : toPush) {
+		for (RemoteRefUpdate rru : toPush) {
 			if (this.toPush.put(rru.getRemoteName(), rru) != null)
 				throw new TransportException(MessageFormat.format(
 						JGitText.get().duplicateRemoteRefUpdateIsIllegal, rru.getRemoteName()));
@@ -150,7 +150,7 @@ class PushProcess {
 	 *             when some error occurred during operation, like I/O, protocol
 	 *             error, or local database consistency error.
 	 */
-	PushResult execute(final ProgressMonitor monitor)
+	PushResult execute(ProgressMonitor monitor)
 			throws NotSupportedException, TransportException {
 		try {
 			monitor.beginTask(PROGRESS_OPENING_CONNECTION,
@@ -176,7 +176,7 @@ else if (!preprocessed.isEmpty())
 			}
 			if (!transport.isDryRun())
 				updateTrackingRefs();
-			for (final RemoteRefUpdate rru : toPush.values()) {
+			for (RemoteRefUpdate rru : toPush.values()) {
 				final TrackingRefUpdate tru = rru.getTrackingRefUpdate();
 				if (tru != null)
 					res.add(tru);
@@ -190,8 +190,8 @@ else if (!preprocessed.isEmpty())
 	private Map<String, RemoteRefUpdate> prepareRemoteUpdates()
 			throws TransportException {
 		boolean atomic = transport.isPushAtomic();
-		final Map<String, RemoteRefUpdate> result = new HashMap<>();
-		for (final RemoteRefUpdate rru : toPush.values()) {
+		final Map<String, RemoteRefUpdate> result = new LinkedHashMap<>();
+		for (RemoteRefUpdate rru : toPush.values()) {
 			final Ref advertisedRef = connection.getRef(rru.getRemoteName());
 			ObjectId advertisedOld = null;
 			if (advertisedRef != null) {
@@ -277,13 +277,13 @@ private Map<String, RemoteRefUpdate> rejectAll() {
 	}
 
 	private void modifyUpdatesForDryRun() {
-		for (final RemoteRefUpdate rru : toPush.values())
+		for (RemoteRefUpdate rru : toPush.values())
 			if (rru.getStatus() == Status.NOT_ATTEMPTED)
 				rru.setStatus(Status.OK);
 	}
 
 	private void updateTrackingRefs() {
-		for (final RemoteRefUpdate rru : toPush.values()) {
+		for (RemoteRefUpdate rru : toPush.values()) {
 			final Status status = rru.getStatus();
 			if (rru.hasTrackingRefUpdate()
 					&& (status == Status.UP_TO_DATE || status == Status.OK)) {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PushResult.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PushResult.java
index 41aa73c..5452704 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PushResult.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PushResult.java
@@ -51,7 +51,8 @@
 
 /**
  * Result of push operation to the remote repository. Holding information of
- * {@link OperationResult} and remote refs updates status.
+ * {@link org.eclipse.jgit.transport.OperationResult} and remote refs updates
+ * status.
  *
  * @see Transport#push(org.eclipse.jgit.lib.ProgressMonitor, Collection)
  */
@@ -81,7 +82,7 @@ public Collection<RemoteRefUpdate> getRemoteUpdates() {
 	 *            remote ref name
 	 * @return status of remote ref update
 	 */
-	public RemoteRefUpdate getRemoteUpdate(final String refName) {
+	public RemoteRefUpdate getRemoteUpdate(String refName) {
 		return remoteUpdates.get(refName);
 	}
 
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceiveCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceiveCommand.java
index e9681b3..d61aeb0 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceiveCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceiveCommand.java
@@ -52,6 +52,7 @@
 import java.util.Collection;
 import java.util.List;
 
+import org.eclipse.jgit.annotations.NonNull;
 import org.eclipse.jgit.annotations.Nullable;
 import org.eclipse.jgit.internal.JGitText;
 import org.eclipse.jgit.lib.AnyObjectId;
@@ -63,10 +64,11 @@
 import org.eclipse.jgit.revwalk.RevWalk;
 
 /**
- * A command being processed by {@link BaseReceivePack}.
+ * A command being processed by
+ * {@link org.eclipse.jgit.transport.BaseReceivePack}.
  * <p>
  * This command instance roughly translates to the server side representation of
- * the {@link RemoteRefUpdate} created by the client.
+ * the {@link org.eclipse.jgit.transport.RemoteRefUpdate} created by the client.
  */
 public class ReceiveCommand {
 	/** Type of operation requested. */
@@ -175,8 +177,10 @@ public static List<ReceiveCommand> filter(List<ReceiveCommand> commands,
 	/**
 	 * Set unprocessed commands as failed due to transaction aborted.
 	 * <p>
-	 * If a command is still {@link Result#NOT_ATTEMPTED} it will be set to
-	 * {@link Result#REJECTED_OTHER_REASON}.
+	 * If a command is still
+	 * {@link org.eclipse.jgit.transport.ReceiveCommand.Result#NOT_ATTEMPTED} it
+	 * will be set to
+	 * {@link org.eclipse.jgit.transport.ReceiveCommand.Result#REJECTED_OTHER_REASON}.
 	 *
 	 * @param commands
 	 *            commands to mark as failed.
@@ -196,8 +200,8 @@ public static void abort(Iterable<ReceiveCommand> commands) {
 	 *
 	 * @param cmd
 	 *            command.
-	 * @return whether the command failed due to transaction aborted, as in {@link
-	 *         #abort(Iterable)}.
+	 * @return whether the command failed due to transaction aborted, as in
+	 *         {@link #abort(Iterable)}.
 	 * @since 4.9
 	 */
 	public static boolean isTransactionAborted(ReceiveCommand cmd) {
@@ -205,14 +209,71 @@ public static boolean isTransactionAborted(ReceiveCommand cmd) {
 				&& cmd.getMessage().equals(JGitText.get().transactionAborted);
 	}
 
+	/**
+	 * Create a command to switch a reference from object to symbolic.
+	 *
+	 * @param oldId
+	 *            expected oldId. May be {@code zeroId} to create.
+	 * @param newTarget
+	 *            new target; must begin with {@code "refs/"}.
+	 * @param name
+	 *            name of the reference to make symbolic.
+	 * @return command instance.
+	 * @since 4.10
+	 */
+	public static ReceiveCommand link(@NonNull ObjectId oldId,
+			@NonNull String newTarget, @NonNull String name) {
+		return new ReceiveCommand(oldId, newTarget, name);
+	}
+
+	/**
+	 * Create a command to switch a symbolic reference's target.
+	 *
+	 * @param oldTarget
+	 *            expected old target. May be null to create.
+	 * @param newTarget
+	 *            new target; must begin with {@code "refs/"}.
+	 * @param name
+	 *            name of the reference to make symbolic.
+	 * @return command instance.
+	 * @since 4.10
+	 */
+	public static ReceiveCommand link(@Nullable String oldTarget,
+			@NonNull String newTarget, @NonNull String name) {
+		return new ReceiveCommand(oldTarget, newTarget, name);
+	}
+
+	/**
+	 * Create a command to switch a reference from symbolic to object.
+	 *
+	 * @param oldTarget
+	 *            expected old target.
+	 * @param newId
+	 *            new object identifier. May be {@code zeroId()} to delete.
+	 * @param name
+	 *            name of the reference to convert from symbolic.
+	 * @return command instance.
+	 * @since 4.10
+	 */
+	public static ReceiveCommand unlink(@NonNull String oldTarget,
+			@NonNull ObjectId newId, @NonNull String name) {
+		return new ReceiveCommand(oldTarget, newId, name);
+	}
+
 	private final ObjectId oldId;
 
+	private final String oldSymref;
+
 	private final ObjectId newId;
 
+	private final String newSymref;
+
 	private final String name;
 
 	private Type type;
 
+	private boolean typeIsCorrect;
+
 	private Ref ref;
 
 	private Result status = Result.NOT_ATTEMPTED;
@@ -227,30 +288,39 @@ public static boolean isTransactionAborted(ReceiveCommand cmd) {
 
 	private Boolean forceRefLog;
 
-	private boolean typeIsCorrect;
-
 	/**
-	 * Create a new command for {@link BaseReceivePack}.
+	 * Create a new command for
+	 * {@link org.eclipse.jgit.transport.BaseReceivePack}.
 	 *
 	 * @param oldId
 	 *            the expected old object id; must not be null. Use
-	 *            {@link ObjectId#zeroId()} to indicate a ref creation.
+	 *            {@link org.eclipse.jgit.lib.ObjectId#zeroId()} to indicate a
+	 *            ref creation.
 	 * @param newId
 	 *            the new object id; must not be null. Use
-	 *            {@link ObjectId#zeroId()} to indicate a ref deletion.
+	 *            {@link org.eclipse.jgit.lib.ObjectId#zeroId()} to indicate a
+	 *            ref deletion.
 	 * @param name
 	 *            name of the ref being affected.
 	 */
 	public ReceiveCommand(final ObjectId oldId, final ObjectId newId,
 			final String name) {
 		if (oldId == null) {
-			throw new IllegalArgumentException(JGitText.get().oldIdMustNotBeNull);
+			throw new IllegalArgumentException(
+					JGitText.get().oldIdMustNotBeNull);
 		}
 		if (newId == null) {
-			throw new IllegalArgumentException(JGitText.get().newIdMustNotBeNull);
+			throw new IllegalArgumentException(
+					JGitText.get().newIdMustNotBeNull);
+		}
+		if (name == null || name.isEmpty()) {
+			throw new IllegalArgumentException(
+					JGitText.get().nameMustNotBeNullOrEmpty);
 		}
 		this.oldId = oldId;
+		this.oldSymref = null;
 		this.newId = newId;
+		this.newSymref = null;
 		this.name = name;
 
 		type = Type.UPDATE;
@@ -263,31 +333,46 @@ public ReceiveCommand(final ObjectId oldId, final ObjectId newId,
 	}
 
 	/**
-	 * Create a new command for {@link BaseReceivePack}.
+	 * Create a new command for
+	 * {@link org.eclipse.jgit.transport.BaseReceivePack}.
 	 *
 	 * @param oldId
 	 *            the old object id; must not be null. Use
-	 *            {@link ObjectId#zeroId()} to indicate a ref creation.
+	 *            {@link org.eclipse.jgit.lib.ObjectId#zeroId()} to indicate a
+	 *            ref creation.
 	 * @param newId
 	 *            the new object id; must not be null. Use
-	 *            {@link ObjectId#zeroId()} to indicate a ref deletion.
+	 *            {@link org.eclipse.jgit.lib.ObjectId#zeroId()} to indicate a
+	 *            ref deletion.
 	 * @param name
 	 *            name of the ref being affected.
 	 * @param type
-	 *            type of the command. Must be {@link Type#CREATE} if {@code
-	 *            oldId} is zero, or {@link Type#DELETE} if {@code newId} is zero.
+	 *            type of the command. Must be
+	 *            {@link org.eclipse.jgit.transport.ReceiveCommand.Type#CREATE}
+	 *            if {@code
+	 *            oldId} is zero, or
+	 *            {@link org.eclipse.jgit.transport.ReceiveCommand.Type#DELETE}
+	 *            if {@code newId} is zero.
 	 * @since 2.0
 	 */
 	public ReceiveCommand(final ObjectId oldId, final ObjectId newId,
 			final String name, final Type type) {
 		if (oldId == null) {
-			throw new IllegalArgumentException(JGitText.get().oldIdMustNotBeNull);
+			throw new IllegalArgumentException(
+					JGitText.get().oldIdMustNotBeNull);
 		}
 		if (newId == null) {
-			throw new IllegalArgumentException(JGitText.get().newIdMustNotBeNull);
+			throw new IllegalArgumentException(
+					JGitText.get().newIdMustNotBeNull);
+		}
+		if (name == null || name.isEmpty()) {
+			throw new IllegalArgumentException(
+					JGitText.get().nameMustNotBeNullOrEmpty);
 		}
 		this.oldId = oldId;
+		this.oldSymref = null;
 		this.newId = newId;
+		this.newSymref = null;
 		this.name = name;
 		switch (type) {
 		case CREATE:
@@ -311,42 +396,203 @@ public ReceiveCommand(final ObjectId oldId, final ObjectId newId,
 			}
 			break;
 		default:
-			throw new IllegalStateException(JGitText.get().enumValueNotSupported0);
+			throw new IllegalStateException(
+					JGitText.get().enumValueNotSupported0);
 		}
 		this.type = type;
 	}
 
-	/** @return the old value the client thinks the ref has. */
+	/**
+	 * Create a command to switch a reference from object to symbolic.
+	 *
+	 * @param oldId
+	 *            the old object id; must not be null. Use
+	 *            {@link ObjectId#zeroId()} to indicate a ref creation.
+	 * @param newSymref
+	 *            new target, must begin with {@code "refs/"}. Use {@code null}
+	 *            to indicate a ref deletion.
+	 * @param name
+	 *            name of the reference to make symbolic.
+	 * @since 4.10
+	 */
+	private ReceiveCommand(ObjectId oldId, String newSymref, String name) {
+		if (oldId == null) {
+			throw new IllegalArgumentException(
+					JGitText.get().oldIdMustNotBeNull);
+		}
+		if (name == null || name.isEmpty()) {
+			throw new IllegalArgumentException(
+					JGitText.get().nameMustNotBeNullOrEmpty);
+		}
+		this.oldId = oldId;
+		this.oldSymref = null;
+		this.newId = ObjectId.zeroId();
+		this.newSymref = newSymref;
+		this.name = name;
+		if (AnyObjectId.equals(ObjectId.zeroId(), oldId)) {
+			type = Type.CREATE;
+		} else if (newSymref != null) {
+			type = Type.UPDATE;
+		} else {
+			type = Type.DELETE;
+		}
+		typeIsCorrect = true;
+	}
+
+	/**
+	 * Create a command to switch a reference from symbolic to object.
+	 *
+	 * @param oldSymref
+	 *            expected old target. Use {@code null} to indicate a ref
+	 *            creation.
+	 * @param newId
+	 *            the new object id; must not be null. Use
+	 *            {@link ObjectId#zeroId()} to indicate a ref deletion.
+	 * @param name
+	 *            name of the reference to convert from symbolic.
+	 * @since 4.10
+	 */
+	private ReceiveCommand(String oldSymref, ObjectId newId, String name) {
+		if (newId == null) {
+			throw new IllegalArgumentException(
+					JGitText.get().newIdMustNotBeNull);
+		}
+		if (name == null || name.isEmpty()) {
+			throw new IllegalArgumentException(
+					JGitText.get().nameMustNotBeNullOrEmpty);
+		}
+		this.oldId = ObjectId.zeroId();
+		this.oldSymref = oldSymref;
+		this.newId = newId;
+		this.newSymref = null;
+		this.name = name;
+		if (oldSymref == null) {
+			type = Type.CREATE;
+		} else if (!AnyObjectId.equals(ObjectId.zeroId(), newId)) {
+			type = Type.UPDATE;
+		} else {
+			type = Type.DELETE;
+		}
+		typeIsCorrect = true;
+	}
+
+	/**
+	 * Create a command to switch a symbolic reference's target.
+	 *
+	 * @param oldTarget
+	 *            expected old target. Use {@code null} to indicate a ref
+	 *            creation.
+	 * @param newTarget
+	 *            new target. Use {@code null} to indicate a ref deletion.
+	 * @param name
+	 *            name of the reference to make symbolic.
+	 * @since 4.10
+	 */
+	private ReceiveCommand(@Nullable String oldTarget, String newTarget, String name) {
+		if (name == null || name.isEmpty()) {
+			throw new IllegalArgumentException(
+					JGitText.get().nameMustNotBeNullOrEmpty);
+		}
+		this.oldId = ObjectId.zeroId();
+		this.oldSymref = oldTarget;
+		this.newId = ObjectId.zeroId();
+		this.newSymref = newTarget;
+		this.name = name;
+		if (oldTarget == null) {
+			if (newTarget == null) {
+				throw new IllegalArgumentException(
+						JGitText.get().bothRefTargetsMustNotBeNull);
+			}
+			type = Type.CREATE;
+		} else if (newTarget != null) {
+			type = Type.UPDATE;
+		} else {
+			type = Type.DELETE;
+		}
+		typeIsCorrect = true;
+	}
+
+	/**
+	 * Get the old value the client thinks the ref has.
+	 *
+	 * @return the old value the client thinks the ref has.
+	 */
 	public ObjectId getOldId() {
 		return oldId;
 	}
 
-	/** @return the requested new value for this ref. */
+	/**
+	 * Get expected old target for a symbolic reference.
+	 *
+	 * @return expected old target for a symbolic reference.
+	 * @since 4.10
+	 */
+	@Nullable
+	public String getOldSymref() {
+		return oldSymref;
+	}
+
+	/**
+	 * Get the requested new value for this ref.
+	 *
+	 * @return the requested new value for this ref.
+	 */
 	public ObjectId getNewId() {
 		return newId;
 	}
 
-	/** @return the name of the ref being updated. */
+	/**
+	 * Get requested new target for a symbolic reference.
+	 *
+	 * @return requested new target for a symbolic reference.
+	 * @since 4.10
+	 */
+	@Nullable
+	public String getNewSymref() {
+		return newSymref;
+	}
+
+	/**
+	 * Get the name of the ref being updated.
+	 *
+	 * @return the name of the ref being updated.
+	 */
 	public String getRefName() {
 		return name;
 	}
 
-	/** @return the type of this command; see {@link Type}. */
+	/**
+	 * Get the type of this command; see {@link Type}.
+	 *
+	 * @return the type of this command; see {@link Type}.
+	 */
 	public Type getType() {
 		return type;
 	}
 
-	/** @return the ref, if this was advertised by the connection. */
+	/**
+	 * Get the ref, if this was advertised by the connection.
+	 *
+	 * @return the ref, if this was advertised by the connection.
+	 */
 	public Ref getRef() {
 		return ref;
 	}
 
-	/** @return the current status code of this command. */
+	/**
+	 * Get the current status code of this command.
+	 *
+	 * @return the current status code of this command.
+	 */
 	public Result getResult() {
 		return status;
 	}
 
-	/** @return the message associated with a failure status. */
+	/**
+	 * Get the message associated with a failure status.
+	 *
+	 * @return the message associated with a failure status.
+	 */
 	public String getMessage() {
 		return message;
 	}
@@ -452,8 +698,8 @@ public boolean isRefLogIncludingResult() {
 	/**
 	 * Check whether the reflog should be written regardless of repo defaults.
 	 *
-	 * @return whether force writing is enabled; null if {@code
-	 * #setForceRefLog(boolean)} was never called.
+	 * @return whether force writing is enabled; {@code null} if
+	 *         {@code #setForceRefLog(boolean)} was never called.
 	 * @since 4.9
 	 */
 	@Nullable
@@ -467,7 +713,7 @@ public Boolean isForceRefLog() {
 	 * @param s
 	 *            the new status code for this command.
 	 */
-	public void setResult(final Result s) {
+	public void setResult(Result s) {
 		setResult(s, null);
 	}
 
@@ -479,7 +725,7 @@ public void setResult(final Result s) {
 	 * @param m
 	 *            optional message explaining the new status.
 	 */
-	public void setResult(final Result s, final String m) {
+	public void setResult(Result s, String m) {
 		status = s;
 		message = m;
 	}
@@ -490,12 +736,13 @@ public void setResult(final Result s, final String m) {
 	 * If the command's current type is UPDATE, a merge test will be performed
 	 * using the supplied RevWalk to determine if {@link #getOldId()} is fully
 	 * merged into {@link #getNewId()}. If some commits are not merged the
-	 * update type is changed to {@link Type#UPDATE_NONFASTFORWARD}.
+	 * update type is changed to
+	 * {@link org.eclipse.jgit.transport.ReceiveCommand.Type#UPDATE_NONFASTFORWARD}.
 	 *
 	 * @param walk
 	 *            an instance to perform the merge test with. The caller must
 	 *            allocate and release this object.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             either oldId or newId is not accessible in the repository
 	 *             used by the RevWalk. This usually indicates data corruption,
 	 *             and the command cannot be processed.
@@ -523,9 +770,20 @@ public void updateType(RevWalk walk) throws IOException {
 	 *            receive-pack session.
 	 * @since 2.0
 	 */
-	public void execute(final BaseReceivePack rp) {
+	public void execute(BaseReceivePack rp) {
 		try {
-			final RefUpdate ru = rp.getRepository().updateRef(getRefName());
+			String expTarget = getOldSymref();
+			boolean detach = getNewSymref() != null
+					|| (type == Type.DELETE && expTarget != null);
+			RefUpdate ru = rp.getRepository().updateRef(getRefName(), detach);
+			if (expTarget != null) {
+				if (!ru.getRef().isSymbolic() || !ru.getRef().getTarget()
+						.getName().equals(expTarget)) {
+					setResult(Result.LOCK_FAILURE);
+					return;
+				}
+			}
+
 			ru.setRefLogIdent(rp.getRefLogIdent());
 			ru.setRefLogMessage(refLogMessage, refLogIncludeResult);
 			switch (getType()) {
@@ -546,9 +804,13 @@ public void execute(final BaseReceivePack rp) {
 			case UPDATE_NONFASTFORWARD:
 				ru.setForceUpdate(rp.isAllowNonFastForwards());
 				ru.setExpectedOldObjectId(getOldId());
-				ru.setNewObjectId(getNewId());
 				ru.setRefLogMessage("push", true); //$NON-NLS-1$
-				setResult(ru.update(rp.getRevWalk()));
+				if (getNewSymref() != null) {
+					setResult(ru.link(getNewSymref()));
+				} else {
+					ru.setNewObjectId(getNewId());
+					setResult(ru.update(rp.getRevWalk()));
+				}
 				break;
 			}
 		} catch (IOException err) {
@@ -556,11 +818,11 @@ public void execute(final BaseReceivePack rp) {
 		}
 	}
 
-	void setRef(final Ref r) {
+	void setRef(Ref r) {
 		ref = r;
 	}
 
-	void setType(final Type t) {
+	void setType(Type t) {
 		type = t;
 	}
 
@@ -620,6 +882,7 @@ void reject(IOException err) {
 				JGitText.get().lockError, err.getMessage()));
 	}
 
+	/** {@inheritDoc} */
 	@SuppressWarnings("nls")
 	@Override
 	public String toString() {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceivePack.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceivePack.java
index 169df3b..35fb0b17 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceivePack.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceivePack.java
@@ -88,7 +88,7 @@ public class ReceivePack extends BaseReceivePack {
 	 * @param into
 	 *            the destination repository.
 	 */
-	public ReceivePack(final Repository into) {
+	public ReceivePack(Repository into) {
 		super(into);
 		preReceive = PreReceiveHook.NULL;
 		postReceive = PostReceiveHook.NULL;
@@ -130,7 +130,11 @@ public void setPushOptions(@Nullable List<String> options) {
 		pushOptions = options;
 	}
 
-	/** @return the hook invoked before updates occur. */
+	/**
+	 * Get the hook invoked before updates occur.
+	 *
+	 * @return the hook invoked before updates occur.
+	 */
 	public PreReceiveHook getPreReceiveHook() {
 		return preReceive;
 	}
@@ -141,7 +145,8 @@ public PreReceiveHook getPreReceiveHook() {
 	 * Only valid commands (those which have no obvious errors according to the
 	 * received input and this instance's configuration) are passed into the
 	 * hook. The hook may mark a command with a result of any value other than
-	 * {@link Result#NOT_ATTEMPTED} to block its execution.
+	 * {@link org.eclipse.jgit.transport.ReceiveCommand.Result#NOT_ATTEMPTED} to
+	 * block its execution.
 	 * <p>
 	 * The hook may be called with an empty command collection if the current
 	 * set is completely invalid.
@@ -149,11 +154,15 @@ public PreReceiveHook getPreReceiveHook() {
 	 * @param h
 	 *            the hook instance; may be null to disable the hook.
 	 */
-	public void setPreReceiveHook(final PreReceiveHook h) {
+	public void setPreReceiveHook(PreReceiveHook h) {
 		preReceive = h != null ? h : PreReceiveHook.NULL;
 	}
 
-	/** @return the hook invoked after updates occur. */
+	/**
+	 * Get the hook invoked after updates occur.
+	 *
+	 * @return the hook invoked after updates occur.
+	 */
 	public PostReceiveHook getPostReceiveHook() {
 		return postReceive;
 	}
@@ -161,18 +170,22 @@ public PostReceiveHook getPostReceiveHook() {
 	/**
 	 * Set the hook which is invoked after commands are executed.
 	 * <p>
-	 * Only successful commands (type is {@link Result#OK}) are passed into the
-	 * hook. The hook may be called with an empty command collection if the
-	 * current set all resulted in an error.
+	 * Only successful commands (type is
+	 * {@link org.eclipse.jgit.transport.ReceiveCommand.Result#OK}) are passed
+	 * into the hook. The hook may be called with an empty command collection if
+	 * the current set all resulted in an error.
 	 *
 	 * @param h
 	 *            the hook instance; may be null to disable the hook.
 	 */
-	public void setPostReceiveHook(final PostReceiveHook h) {
+	public void setPostReceiveHook(PostReceiveHook h) {
 		postReceive = h != null ? h : PostReceiveHook.NULL;
 	}
 
 	/**
+	 * Set whether this class will report command failures as warning messages
+	 * before sending the command results.
+	 *
 	 * @param echo
 	 *            if true this class will report command failures as warning
 	 *            messages before sending the command results. This is usually
@@ -199,7 +212,7 @@ public void setEchoCommandFailures(boolean echo) {
 	 *            through. When run over SSH this should be tied back to the
 	 *            standard error channel of the command execution. For most
 	 *            other network connections this should be null.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 */
 	public void receive(final InputStream input, final OutputStream output,
 			final OutputStream messages) throws IOException {
@@ -215,6 +228,7 @@ public void receive(final InputStream input, final OutputStream output,
 		}
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected void enableCapabilities() {
 		reportStatus = isCapabilityEnabled(CAPABILITY_REPORT_STATUS);
@@ -274,7 +288,7 @@ private void service() throws IOException {
 				if (echoCommandFailures && msgOut != null) {
 					sendStatusReport(false, unpackError, new Reporter() {
 						@Override
-						void sendString(final String s) throws IOException {
+						void sendString(String s) throws IOException {
 							msgOut.write(Constants.encode(s + "\n")); //$NON-NLS-1$
 						}
 					});
@@ -287,7 +301,7 @@ void sendString(final String s) throws IOException {
 				}
 				sendStatusReport(true, unpackError, new Reporter() {
 					@Override
-					void sendString(final String s) throws IOException {
+					void sendString(String s) throws IOException {
 						pckOut.writeString(s + "\n"); //$NON-NLS-1$
 					}
 				});
@@ -295,7 +309,7 @@ void sendString(final String s) throws IOException {
 			} else if (msgOut != null) {
 				sendStatusReport(false, unpackError, new Reporter() {
 					@Override
-					void sendString(final String s) throws IOException {
+					void sendString(String s) throws IOException {
 						msgOut.write(Constants.encode(s + "\n")); //$NON-NLS-1$
 					}
 				});
@@ -325,6 +339,7 @@ private void autoGc() {
 		repo.autoGC(NullProgressMonitor.INSTANCE);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected String getLockMessageProcessName() {
 		return "jgit receive-pack"; //$NON-NLS-1$
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceivedPackStatistics.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceivedPackStatistics.java
index 052d550..dec5289 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceivedPackStatistics.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceivedPackStatistics.java
@@ -46,7 +46,7 @@
 import org.eclipse.jgit.lib.Constants;
 
 /**
- * Statistics about {@link PackParser}.
+ * Statistics about {@link org.eclipse.jgit.transport.PackParser}.
  *
  * @since 4.6
  */
@@ -65,57 +65,101 @@ public class ReceivedPackStatistics {
 	private long numDeltaBlob;
 	private long numDeltaTag;
 
-	/** @return number of bytes read from the input stream */
+	/**
+	 * Get number of bytes read from the input stream
+	 *
+	 * @return number of bytes read from the input stream
+	 */
 	public long getNumBytesRead() {
 		return numBytesRead;
 	}
 
-	/** @return number of whole commit objects in the pack */
+	/**
+	 * Get number of whole commit objects in the pack
+	 *
+	 * @return number of whole commit objects in the pack
+	 */
 	public long getNumWholeCommit() {
 		return numWholeCommit;
 	}
 
-	/** @return number of whole tree objects in the pack */
+	/**
+	 * Get number of whole tree objects in the pack
+	 *
+	 * @return number of whole tree objects in the pack
+	 */
 	public long getNumWholeTree() {
 		return numWholeTree;
 	}
 
-	/** @return number of whole blob objects in the pack */
+	/**
+	 * Get number of whole blob objects in the pack
+	 *
+	 * @return number of whole blob objects in the pack
+	 */
 	public long getNumWholeBlob() {
 		return numWholeBlob;
 	}
 
-	/** @return number of whole tag objects in the pack */
+	/**
+	 * Get number of whole tag objects in the pack
+	 *
+	 * @return number of whole tag objects in the pack
+	 */
 	public long getNumWholeTag() {
 		return numWholeTag;
 	}
 
-	/** @return number of offset delta objects in the pack */
+	/**
+	 * Get number of offset delta objects in the pack
+	 *
+	 * @return number of offset delta objects in the pack
+	 */
 	public long getNumOfsDelta() {
 		return numOfsDelta;
 	}
 
-	/** @return number of ref delta objects in the pack */
+	/**
+	 * Get number of ref delta objects in the pack
+	 *
+	 * @return number of ref delta objects in the pack
+	 */
 	public long getNumRefDelta() {
 		return numRefDelta;
 	}
 
-	/** @return number of delta commit objects in the pack */
+	/**
+	 * Get number of delta commit objects in the pack
+	 *
+	 * @return number of delta commit objects in the pack
+	 */
 	public long getNumDeltaCommit() {
 		return numDeltaCommit;
 	}
 
-	/** @return number of delta tree objects in the pack */
+	/**
+	 * Get number of delta tree objects in the pack
+	 *
+	 * @return number of delta tree objects in the pack
+	 */
 	public long getNumDeltaTree() {
 		return numDeltaTree;
 	}
 
-	/** @return number of delta blob objects in the pack */
+	/**
+	 * Get number of delta blob objects in the pack
+	 *
+	 * @return number of delta blob objects in the pack
+	 */
 	public long getNumDeltaBlob() {
 		return numDeltaBlob;
 	}
 
-	/** @return number of delta tag objects in the pack */
+	/**
+	 * Get number of delta tag objects in the pack
+	 *
+	 * @return number of delta tag objects in the pack
+	 */
 	public long getNumDeltaTag() {
 		return numDeltaTag;
 	}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/RefAdvertiser.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/RefAdvertiser.java
index 745e813..dc1871b 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/RefAdvertiser.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/RefAdvertiser.java
@@ -43,7 +43,7 @@
 
 package org.eclipse.jgit.transport;
 
-import static java.nio.charset.StandardCharsets.UTF_8;
+import static org.eclipse.jgit.lib.Constants.CHARSET;
 import static org.eclipse.jgit.lib.Constants.OBJECT_ID_STRING_LENGTH;
 import static org.eclipse.jgit.transport.GitProtocolConstants.OPTION_SYMREF;
 
@@ -53,11 +53,12 @@
 import java.nio.charset.CharacterCodingException;
 import java.nio.charset.CharsetEncoder;
 import java.nio.charset.CoderResult;
+import java.util.Collection;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.LinkedHashSet;
 import java.util.Map;
 import java.util.Set;
-import java.util.SortedMap;
 
 import org.eclipse.jgit.lib.AnyObjectId;
 import org.eclipse.jgit.lib.Constants;
@@ -65,13 +66,15 @@
 import org.eclipse.jgit.lib.Ref;
 import org.eclipse.jgit.lib.RefComparator;
 import org.eclipse.jgit.lib.Repository;
-import org.eclipse.jgit.util.RefMap;
 
-/** Support for the start of {@link UploadPack} and {@link ReceivePack}. */
+/**
+ * Support for the start of {@link org.eclipse.jgit.transport.UploadPack} and
+ * {@link org.eclipse.jgit.transport.ReceivePack}.
+ */
 public abstract class RefAdvertiser {
 	/** Advertiser which frames lines in a {@link PacketLineOut} format. */
 	public static class PacketLineOutRefAdvertiser extends RefAdvertiser {
-		private final CharsetEncoder utf8 = UTF_8.newEncoder();
+		private final CharsetEncoder utf8 = CHARSET.newEncoder();
 		private final PacketLineOut pckOut;
 
 		private byte[] binArr = new byte[256];
@@ -149,7 +152,7 @@ private void grow() {
 		}
 
 		@Override
-		protected void writeOne(final CharSequence line) throws IOException {
+		protected void writeOne(CharSequence line) throws IOException {
 			pckOut.writeString(line.toString());
 		}
 
@@ -173,6 +176,11 @@ protected void end() throws IOException {
 
 	boolean first = true;
 
+	private boolean useProtocolV2;
+
+	/* only used in protocol v2 */
+	private final Map<String, String> symrefs = new HashMap<>();
+
 	/**
 	 * Initialize this advertiser with a repository for peeling tags.
 	 *
@@ -184,6 +192,16 @@ public void init(Repository src) {
 	}
 
 	/**
+	 * @param b
+	 *              true if this advertiser should advertise using the protocol
+	 *              v2 format, false otherwise
+	 * @since 5.0
+	 */
+	public void setUseProtocolV2(boolean b) {
+		useProtocolV2 = b;
+	}
+
+	/**
 	 * Toggle tag peeling.
 	 * <p>
 	 * <p>
@@ -196,7 +214,7 @@ public void init(Repository src) {
 	 *            true to show the dereferenced value of a tag as the special
 	 *            ref <code>$tag^{}</code> ; false to omit it from the output.
 	 */
-	public void setDerefTags(final boolean deref) {
+	public void setDerefTags(boolean deref) {
 		derefTags = deref;
 	}
 
@@ -247,11 +265,14 @@ public void advertiseCapability(String name, String value) {
 	 *            The symbolic ref, e.g. "HEAD"
 	 * @param to
 	 *            The real ref it points to, e.g. "refs/heads/master"
-	 *
 	 * @since 3.6
 	 */
 	public void addSymref(String from, String to) {
-		advertiseCapability(OPTION_SYMREF, from + ':' + to);
+		if (useProtocolV2) {
+			symrefs.put(from, to);
+		} else {
+			advertiseCapability(OPTION_SYMREF, from + ':' + to);
+		}
 	}
 
 	/**
@@ -262,16 +283,58 @@ public void addSymref(String from, String to) {
 	 *            sorted before display if necessary, and therefore may appear
 	 *            in any order.
 	 * @return set of ObjectIds that were advertised to the client.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the underlying output stream failed to write out an
 	 *             advertisement record.
+	 * @deprecated use {@link #send(Collection)} instead.
 	 */
+	@Deprecated
 	public Set<ObjectId> send(Map<String, Ref> refs) throws IOException {
-		for (Ref ref : getSortedRefs(refs)) {
-			if (ref.getObjectId() == null)
-				continue;
+		return send(refs.values());
+	}
 
-			advertiseAny(ref.getObjectId(), ref.getName());
+	/**
+	 * Format an advertisement for the supplied refs.
+	 *
+	 * @param refs
+	 *            zero or more refs to format for the client. The collection is
+	 *            sorted before display if necessary, and therefore may appear
+	 *            in any order.
+	 * @return set of ObjectIds that were advertised to the client.
+	 * @throws java.io.IOException
+	 *             the underlying output stream failed to write out an
+	 *             advertisement record.
+	 * @since 5.0
+	 */
+	public Set<ObjectId> send(Collection<Ref> refs) throws IOException {
+		for (Ref ref : RefComparator.sort(refs)) {
+			// TODO(jrn) revive the SortedMap optimization e.g. by introducing
+			// SortedList
+			ObjectId objectId = ref.getObjectId();
+			if (objectId == null) {
+				continue;
+			}
+
+			if (useProtocolV2) {
+				String symrefPart = symrefs.containsKey(ref.getName())
+						? (" symref-target:" + symrefs.get(ref.getName())) //$NON-NLS-1$
+						: ""; //$NON-NLS-1$
+				String peelPart = ""; //$NON-NLS-1$
+				if (derefTags) {
+					if (!ref.isPeeled() && repository != null) {
+						ref = repository.getRefDatabase().peel(ref);
+					}
+					ObjectId peeledObjectId = ref.getPeeledObjectId();
+					if (peeledObjectId != null) {
+						peelPart = " peeled:" + peeledObjectId.getName(); //$NON-NLS-1$
+					}
+				}
+				writeOne(objectId.getName() + " " + ref.getName() + symrefPart //$NON-NLS-1$
+						+ peelPart + "\n"); //$NON-NLS-1$
+				continue;
+			}
+
+			advertiseAny(objectId, ref.getName());
 
 			if (!derefTags)
 				continue;
@@ -279,7 +342,7 @@ public Set<ObjectId> send(Map<String, Ref> refs) throws IOException {
 			if (!ref.isPeeled()) {
 				if (repository == null)
 					continue;
-				ref = repository.peel(ref);
+				ref = repository.getRefDatabase().peel(ref);
 			}
 
 			if (ref.getPeeledObjectId() != null)
@@ -288,13 +351,6 @@ public Set<ObjectId> send(Map<String, Ref> refs) throws IOException {
 		return sent;
 	}
 
-	private Iterable<Ref> getSortedRefs(Map<String, Ref> all) {
-		if (all instanceof RefMap
-				|| (all instanceof SortedMap && ((SortedMap) all).comparator() == null))
-			return all.values();
-		return RefComparator.sort(all.values());
-	}
-
 	/**
 	 * Advertise one object is available using the magic {@code .have}.
 	 * <p>
@@ -305,7 +361,7 @@ private Iterable<Ref> getSortedRefs(Map<String, Ref> all) {
 	 *
 	 * @param id
 	 *            identity of the object that is assumed to exist.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the underlying output stream failed to write out an
 	 *             advertisement record.
 	 */
@@ -313,18 +369,22 @@ public void advertiseHave(AnyObjectId id) throws IOException {
 		advertiseAnyOnce(id, ".have"); //$NON-NLS-1$
 	}
 
-	/** @return true if no advertisements have been sent yet. */
+	/**
+	 * Whether no advertisements have been sent yet.
+	 *
+	 * @return true if no advertisements have been sent yet.
+	 */
 	public boolean isEmpty() {
 		return first;
 	}
 
-	private void advertiseAnyOnce(AnyObjectId obj, final String refName)
+	private void advertiseAnyOnce(AnyObjectId obj, String refName)
 			throws IOException {
 		if (!sent.contains(obj))
 			advertiseAny(obj, refName);
 	}
 
-	private void advertiseAny(AnyObjectId obj, final String refName)
+	private void advertiseAny(AnyObjectId obj, String refName)
 			throws IOException {
 		sent.add(obj.toObjectId());
 		advertiseId(obj, refName);
@@ -341,11 +401,11 @@ private void advertiseAny(AnyObjectId obj, final String refName)
 	 * @param refName
 	 *            name of the reference to advertise the object as, can be any
 	 *            string not including the NUL byte.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the underlying output stream failed to write out an
 	 *             advertisement record.
 	 */
-	public void advertiseId(final AnyObjectId id, final String refName)
+	public void advertiseId(AnyObjectId id, String refName)
 			throws IOException {
 		tmpLine.setLength(0);
 		id.copyTo(tmpId, tmpLine);
@@ -355,7 +415,7 @@ public void advertiseId(final AnyObjectId id, final String refName)
 			first = false;
 			if (!capablities.isEmpty()) {
 				tmpLine.append('\0');
-				for (final String capName : capablities) {
+				for (String capName : capablities) {
 					tmpLine.append(' ');
 					tmpLine.append(capName);
 				}
@@ -372,7 +432,7 @@ public void advertiseId(final AnyObjectId id, final String refName)
 	 * @param line
 	 *            the advertisement line to be written. The line always ends
 	 *            with LF. Never null or the empty string.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the underlying output stream failed to write out an
 	 *             advertisement record.
 	 */
@@ -381,7 +441,7 @@ public void advertiseId(final AnyObjectId id, final String refName)
 	/**
 	 * Mark the end of the advertisements.
 	 *
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the underlying output stream failed to write out an
 	 *             advertisement record.
 	 */
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/RefFilter.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/RefFilter.java
index d4f85f2..992ddc6 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/RefFilter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/RefFilter.java
@@ -50,17 +50,20 @@
 /**
  * Filters the list of refs that are advertised to the client.
  * <p>
- * The filter is called by {@link ReceivePack} and {@link UploadPack} to ensure
- * that the refs are filtered before they are advertised to the client.
+ * The filter is called by {@link org.eclipse.jgit.transport.ReceivePack} and
+ * {@link org.eclipse.jgit.transport.UploadPack} to ensure that the refs are
+ * filtered before they are advertised to the client.
  * <p>
  * This can be used by applications to control visibility of certain refs based
  * on a custom set of rules.
  */
 public interface RefFilter {
-	/** The default filter, allows all refs to be shown. */
+	/**
+	 * The default filter, allows all refs to be shown.
+	 */
 	public static final RefFilter DEFAULT = new RefFilter() {
 		@Override
-		public Map<String, Ref> filter (final Map<String, Ref> refs) {
+		public Map<String, Ref> filter (Map<String, Ref> refs) {
 			return refs;
 		}
 	};
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/RefLeaseSpec.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/RefLeaseSpec.java
index 734f523..ea0f84a 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/RefLeaseSpec.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/RefLeaseSpec.java
@@ -47,6 +47,7 @@
 
 /**
  * Describes the expected value for a ref being pushed.
+ *
  * @since 4.7
  */
 public class RefLeaseSpec implements Serializable {
@@ -59,6 +60,7 @@ public class RefLeaseSpec implements Serializable {
 	private final String expected;
 
 	/**
+	 * <p>Constructor for RefLeaseSpec.</p>
 	 *
 	 * @param ref
 	 *            ref being pushed
@@ -89,6 +91,7 @@ public String getExpected() {
 		return expected;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public String toString() {
 		final StringBuilder r = new StringBuilder();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/RefSpec.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/RefSpec.java
index 64f6c3f..afd3ada 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/RefSpec.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/RefSpec.java
@@ -72,7 +72,7 @@ public class RefSpec implements Serializable {
 	 *            ref spec component - string to test. Can be null.
 	 * @return true if provided string is a wildcard ref spec component.
 	 */
-	public static boolean isWildcard(final String s) {
+	public static boolean isWildcard(String s) {
 		return s != null && s.contains("*"); //$NON-NLS-1$
 	}
 
@@ -153,7 +153,7 @@ public RefSpec() {
 	 * @param mode
 	 *            whether to allow a wildcard on one side without a wildcard on
 	 *            the other.
-	 * @throws IllegalArgumentException
+	 * @throws java.lang.IllegalArgumentException
 	 *             the specification is invalid.
 	 * @since 4.5
 	 */
@@ -219,14 +219,14 @@ public RefSpec(String spec, WildcardMode mode) {
 	 *
 	 * @param spec
 	 *            string describing the specification.
-	 * @throws IllegalArgumentException
+	 * @throws java.lang.IllegalArgumentException
 	 *             the specification is invalid.
 	 */
-	public RefSpec(final String spec) {
+	public RefSpec(String spec) {
 		this(spec, WildcardMode.REQUIRE_MATCH);
 	}
 
-	private RefSpec(final RefSpec p) {
+	private RefSpec(RefSpec p) {
 		force = p.isForceUpdate();
 		wildcard = p.isWildcard();
 		srcName = p.getSource();
@@ -250,7 +250,7 @@ public boolean isForceUpdate() {
 	 *            new value for force update in the returned instance.
 	 * @return a new RefSpec with force update as specified.
 	 */
-	public RefSpec setForceUpdate(final boolean forceUpdate) {
+	public RefSpec setForceUpdate(boolean forceUpdate) {
 		final RefSpec r = new RefSpec(this);
 		r.force = forceUpdate;
 		return r;
@@ -288,12 +288,12 @@ public String getSource() {
 	 * @param source
 	 *            new value for source in the returned instance.
 	 * @return a new RefSpec with source as specified.
-	 * @throws IllegalStateException
+	 * @throws java.lang.IllegalStateException
 	 *             There is already a destination configured, and the wildcard
 	 *             status of the existing destination disagrees with the
 	 *             wildcard status of the new source.
 	 */
-	public RefSpec setSource(final String source) {
+	public RefSpec setSource(String source) {
 		final RefSpec r = new RefSpec(this);
 		r.srcName = checkValid(source);
 		if (isWildcard(r.srcName) && r.dstName == null)
@@ -327,12 +327,12 @@ public String getDestination() {
 	 * @param destination
 	 *            new value for destination in the returned instance.
 	 * @return a new RefSpec with destination as specified.
-	 * @throws IllegalStateException
+	 * @throws java.lang.IllegalStateException
 	 *             There is already a source configured, and the wildcard status
 	 *             of the existing source disagrees with the wildcard status of
 	 *             the new destination.
 	 */
-	public RefSpec setDestination(final String destination) {
+	public RefSpec setDestination(String destination) {
 		final RefSpec r = new RefSpec(this);
 		r.dstName = checkValid(destination);
 		if (isWildcard(r.dstName) && r.srcName == null)
@@ -350,7 +350,7 @@ public RefSpec setDestination(final String destination) {
 	 * @param destination
 	 *            new value for destination in the returned instance.
 	 * @return a new RefSpec with destination as specified.
-	 * @throws IllegalArgumentException
+	 * @throws java.lang.IllegalArgumentException
 	 *             The wildcard status of the new source disagrees with the
 	 *             wildcard status of the new destination.
 	 */
@@ -372,7 +372,7 @@ public RefSpec setSourceDestination(final String source,
 	 *            ref name that should be tested.
 	 * @return true if the names match; false otherwise.
 	 */
-	public boolean matchSource(final String r) {
+	public boolean matchSource(String r) {
 		return match(r, getSource());
 	}
 
@@ -383,7 +383,7 @@ public boolean matchSource(final String r) {
 	 *            ref whose name should be tested.
 	 * @return true if the names match; false otherwise.
 	 */
-	public boolean matchSource(final Ref r) {
+	public boolean matchSource(Ref r) {
 		return match(r.getName(), getSource());
 	}
 
@@ -394,7 +394,7 @@ public boolean matchSource(final Ref r) {
 	 *            ref name that should be tested.
 	 * @return true if the names match; false otherwise.
 	 */
-	public boolean matchDestination(final String r) {
+	public boolean matchDestination(String r) {
 		return match(r, getDestination());
 	}
 
@@ -405,7 +405,7 @@ public boolean matchDestination(final String r) {
 	 *            ref whose name should be tested.
 	 * @return true if the names match; false otherwise.
 	 */
-	public boolean matchDestination(final Ref r) {
+	public boolean matchDestination(Ref r) {
 		return match(r.getName(), getDestination());
 	}
 
@@ -421,11 +421,11 @@ public boolean matchDestination(final Ref r) {
 	 * @return a new specification expanded from provided ref name. Result
 	 *         specification is wildcard if and only if provided ref name is
 	 *         wildcard.
-	 * @throws IllegalStateException
+	 * @throws java.lang.IllegalStateException
 	 *             when the RefSpec was constructed with wildcard mode that
 	 *             doesn't require matching wildcards.
 	 */
-	public RefSpec expandFromSource(final String r) {
+	public RefSpec expandFromSource(String r) {
 		if (allowMismatchedWildcards != WildcardMode.REQUIRE_MATCH) {
 			throw new IllegalStateException(
 					JGitText.get().invalidExpandWildcard);
@@ -433,7 +433,7 @@ public RefSpec expandFromSource(final String r) {
 		return isWildcard() ? new RefSpec(this).expandFromSourceImp(r) : this;
 	}
 
-	private RefSpec expandFromSourceImp(final String name) {
+	private RefSpec expandFromSourceImp(String name) {
 		final String psrc = srcName, pdst = dstName;
 		wildcard = false;
 		srcName = name;
@@ -453,11 +453,11 @@ private RefSpec expandFromSourceImp(final String name) {
 	 * @return a new specification expanded from provided ref name. Result
 	 *         specification is wildcard if and only if provided ref name is
 	 *         wildcard.
-	 * @throws IllegalStateException
+	 * @throws java.lang.IllegalStateException
 	 *             when the RefSpec was constructed with wildcard mode that
 	 *             doesn't require matching wildcards.
 	 */
-	public RefSpec expandFromSource(final Ref r) {
+	public RefSpec expandFromSource(Ref r) {
 		return expandFromSource(r.getName());
 	}
 
@@ -473,11 +473,11 @@ public RefSpec expandFromSource(final Ref r) {
 	 * @return a new specification expanded from provided ref name. Result
 	 *         specification is wildcard if and only if provided ref name is
 	 *         wildcard.
-	 * @throws IllegalStateException
+	 * @throws java.lang.IllegalStateException
 	 *             when the RefSpec was constructed with wildcard mode that
 	 *             doesn't require matching wildcards.
 	 */
-	public RefSpec expandFromDestination(final String r) {
+	public RefSpec expandFromDestination(String r) {
 		if (allowMismatchedWildcards != WildcardMode.REQUIRE_MATCH) {
 			throw new IllegalStateException(
 					JGitText.get().invalidExpandWildcard);
@@ -485,7 +485,7 @@ public RefSpec expandFromDestination(final String r) {
 		return isWildcard() ? new RefSpec(this).expandFromDstImp(r) : this;
 	}
 
-	private RefSpec expandFromDstImp(final String name) {
+	private RefSpec expandFromDstImp(String name) {
 		final String psrc = srcName, pdst = dstName;
 		wildcard = false;
 		srcName = expandWildcard(name, pdst, psrc);
@@ -504,15 +504,15 @@ private RefSpec expandFromDstImp(final String name) {
 	 * @return a new specification expanded from provided ref name. Result
 	 *         specification is wildcard if and only if provided ref name is
 	 *         wildcard.
-	 * @throws IllegalStateException
+	 * @throws java.lang.IllegalStateException
 	 *             when the RefSpec was constructed with wildcard mode that
 	 *             doesn't require matching wildcards.
 	 */
-	public RefSpec expandFromDestination(final Ref r) {
+	public RefSpec expandFromDestination(Ref r) {
 		return expandFromDestination(r.getName());
 	}
 
-	private boolean match(final String name, final String s) {
+	private boolean match(String name, String s) {
 		if (s == null)
 			return false;
 		if (isWildcard(s)) {
@@ -541,7 +541,7 @@ private static String checkValid(String spec) {
 		return spec;
 	}
 
-	private static boolean isValid(final String s) {
+	private static boolean isValid(String s) {
 		if (s.startsWith("/")) //$NON-NLS-1$
 			return false;
 		if (s.contains("//")) //$NON-NLS-1$
@@ -556,6 +556,7 @@ private static boolean isValid(final String s) {
 		return true;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public int hashCode() {
 		int hc = 0;
@@ -566,8 +567,9 @@ public int hashCode() {
 		return hc;
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	public boolean equals(final Object obj) {
+	public boolean equals(Object obj) {
 		if (!(obj instanceof RefSpec))
 			return false;
 		final RefSpec b = (RefSpec) obj;
@@ -582,7 +584,7 @@ public boolean equals(final Object obj) {
 		return true;
 	}
 
-	private static boolean eq(final String a, final String b) {
+	private static boolean eq(String a, String b) {
 		if (a == b)
 			return true;
 		if (a == null || b == null)
@@ -590,6 +592,7 @@ private static boolean eq(final String a, final String b) {
 		return a.equals(b);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public String toString() {
 		final StringBuilder r = new StringBuilder();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/RemoteConfig.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/RemoteConfig.java
index c968ba3..0a621f1 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/RemoteConfig.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/RemoteConfig.java
@@ -109,10 +109,10 @@ public class RemoteConfig implements Serializable {
 	 * @return all remotes configurations existing in provided repository
 	 *         configuration. Returned configurations are ordered
 	 *         lexicographically by names.
-	 * @throws URISyntaxException
+	 * @throws java.net.URISyntaxException
 	 *             one of the URIs within the remote's configuration is invalid.
 	 */
-	public static List<RemoteConfig> getAllRemoteConfigs(final Config rc)
+	public static List<RemoteConfig> getAllRemoteConfigs(Config rc)
 			throws URISyntaxException {
 		final List<String> names = new ArrayList<>(rc
 				.getSubsections(SECTION));
@@ -120,7 +120,7 @@ public static List<RemoteConfig> getAllRemoteConfigs(final Config rc)
 
 		final List<RemoteConfig> result = new ArrayList<>(names
 				.size());
-		for (final String name : names)
+		for (String name : names)
 			result.add(new RemoteConfig(rc, name));
 		return result;
 	}
@@ -157,10 +157,10 @@ public static List<RemoteConfig> getAllRemoteConfigs(final Config rc)
 	 *            The configuration must already be loaded into memory.
 	 * @param remoteName
 	 *            subsection key indicating the name of this remote.
-	 * @throws URISyntaxException
+	 * @throws java.net.URISyntaxException
 	 *             one of the URIs within the remote's configuration is invalid.
 	 */
-	public RemoteConfig(final Config rc, final String remoteName)
+	public RemoteConfig(Config rc, String remoteName)
 			throws URISyntaxException {
 		name = remoteName;
 
@@ -170,12 +170,12 @@ public RemoteConfig(final Config rc, final String remoteName)
 		vlst = rc.getStringList(SECTION, name, KEY_URL);
 		Map<String, String> insteadOf = getReplacements(rc, KEY_INSTEADOF);
 		uris = new ArrayList<>(vlst.length);
-		for (final String s : vlst) {
+		for (String s : vlst) {
 			uris.add(new URIish(replaceUri(s, insteadOf)));
 		}
 		String[] plst = rc.getStringList(SECTION, name, KEY_PUSHURL);
 		pushURIs = new ArrayList<>(plst.length);
-		for (final String s : plst) {
+		for (String s : plst) {
 			pushURIs.add(new URIish(s));
 		}
 		if (pushURIs.isEmpty()) {
@@ -223,26 +223,26 @@ public RemoteConfig(final Config rc, final String remoteName)
 	 * @param rc
 	 *            the configuration file to store ourselves into.
 	 */
-	public void update(final Config rc) {
+	public void update(Config rc) {
 		final List<String> vlst = new ArrayList<>();
 
 		vlst.clear();
-		for (final URIish u : getURIs())
+		for (URIish u : getURIs())
 			vlst.add(u.toPrivateString());
 		rc.setStringList(SECTION, getName(), KEY_URL, vlst);
 
 		vlst.clear();
-		for (final URIish u : getPushURIs())
+		for (URIish u : getPushURIs())
 			vlst.add(u.toPrivateString());
 		rc.setStringList(SECTION, getName(), KEY_PUSHURL, vlst);
 
 		vlst.clear();
-		for (final RefSpec u : getFetchRefSpecs())
+		for (RefSpec u : getFetchRefSpecs())
 			vlst.add(u.toString());
 		rc.setStringList(SECTION, getName(), KEY_FETCH, vlst);
 
 		vlst.clear();
-		for (final RefSpec u : getPushRefSpecs())
+		for (RefSpec u : getPushRefSpecs())
 			vlst.add(u.toString());
 		rc.setStringList(SECTION, getName(), KEY_PUSH, vlst);
 
@@ -277,7 +277,7 @@ private void set(final Config rc, final String key, final int currentValue,
 			rc.setInt(SECTION, getName(), key, currentValue);
 	}
 
-	private void unset(final Config rc, final String key) {
+	private void unset(Config rc, String key) {
 		rc.unset(SECTION, getName(), key);
 	}
 
@@ -335,7 +335,7 @@ public List<URIish> getURIs() {
 	 *            the new URI to add to this remote.
 	 * @return true if the URI was added; false if it already exists.
 	 */
-	public boolean addURI(final URIish toAdd) {
+	public boolean addURI(URIish toAdd) {
 		if (uris.contains(toAdd))
 			return false;
 		return uris.add(toAdd);
@@ -348,7 +348,7 @@ public boolean addURI(final URIish toAdd) {
 	 *            the URI to remove from this remote.
 	 * @return true if the URI was added; false if it already exists.
 	 */
-	public boolean removeURI(final URIish toRemove) {
+	public boolean removeURI(URIish toRemove) {
 		return uris.remove(toRemove);
 	}
 
@@ -368,7 +368,7 @@ public List<URIish> getPushURIs() {
 	 *            the new URI to add to this remote.
 	 * @return true if the URI was added; false if it already exists.
 	 */
-	public boolean addPushURI(final URIish toAdd) {
+	public boolean addPushURI(URIish toAdd) {
 		if (pushURIs.contains(toAdd))
 			return false;
 		return pushURIs.add(toAdd);
@@ -381,7 +381,7 @@ public boolean addPushURI(final URIish toAdd) {
 	 *            the URI to remove from this remote.
 	 * @return true if the URI was added; false if it already exists.
 	 */
-	public boolean removePushURI(final URIish toRemove) {
+	public boolean removePushURI(URIish toRemove) {
 		return pushURIs.remove(toRemove);
 	}
 
@@ -401,7 +401,7 @@ public List<RefSpec> getFetchRefSpecs() {
 	 *            the new specification to add.
 	 * @return true if the specification was added; false if it already exists.
 	 */
-	public boolean addFetchRefSpec(final RefSpec s) {
+	public boolean addFetchRefSpec(RefSpec s) {
 		if (fetch.contains(s))
 			return false;
 		return fetch.add(s);
@@ -414,7 +414,7 @@ public boolean addFetchRefSpec(final RefSpec s) {
 	 *            list of fetch specifications to set. List is copied, it can be
 	 *            modified after this call.
 	 */
-	public void setFetchRefSpecs(final List<RefSpec> specs) {
+	public void setFetchRefSpecs(List<RefSpec> specs) {
 		fetch.clear();
 		fetch.addAll(specs);
 	}
@@ -426,7 +426,7 @@ public void setFetchRefSpecs(final List<RefSpec> specs) {
 	 *            list of push specifications to set. List is copied, it can be
 	 *            modified after this call.
 	 */
-	public void setPushRefSpecs(final List<RefSpec> specs) {
+	public void setPushRefSpecs(List<RefSpec> specs) {
 		push.clear();
 		push.addAll(specs);
 	}
@@ -438,7 +438,7 @@ public void setPushRefSpecs(final List<RefSpec> specs) {
 	 *            the specification to remove.
 	 * @return true if the specification existed and was removed.
 	 */
-	public boolean removeFetchRefSpec(final RefSpec s) {
+	public boolean removeFetchRefSpec(RefSpec s) {
 		return fetch.remove(s);
 	}
 
@@ -458,7 +458,7 @@ public List<RefSpec> getPushRefSpecs() {
 	 *            the new specification to add.
 	 * @return true if the specification was added; false if it already exists.
 	 */
-	public boolean addPushRefSpec(final RefSpec s) {
+	public boolean addPushRefSpec(RefSpec s) {
 		if (push.contains(s))
 			return false;
 		return push.add(s);
@@ -471,7 +471,7 @@ public boolean addPushRefSpec(final RefSpec s) {
 	 *            the specification to remove.
 	 * @return true if the specification existed and was removed.
 	 */
-	public boolean removePushRefSpec(final RefSpec s) {
+	public boolean removePushRefSpec(RefSpec s) {
 		return push.remove(s);
 	}
 
@@ -520,11 +520,14 @@ public TagOpt getTagOpt() {
 	 * @param option
 	 *            method to use when handling annotated tags.
 	 */
-	public void setTagOpt(final TagOpt option) {
+	public void setTagOpt(TagOpt option) {
 		tagopt = option != null ? option : TagOpt.AUTO_FOLLOW;
 	}
 
 	/**
+	 * Whether pushing to the remote automatically deletes remote refs which
+	 * don't exist on the source side.
+	 *
 	 * @return true if pushing to the remote automatically deletes remote refs
 	 *         which don't exist on the source side.
 	 */
@@ -538,11 +541,15 @@ public boolean isMirror() {
 	 * @param m
 	 *            true to automatically delete remote refs during push.
 	 */
-	public void setMirror(final boolean m) {
+	public void setMirror(boolean m) {
 		mirror = m;
 	}
 
-	/** @return timeout (in seconds) before aborting an IO operation. */
+	/**
+	 * Get timeout (in seconds) before aborting an IO operation.
+	 *
+	 * @return timeout (in seconds) before aborting an IO operation.
+	 */
 	public int getTimeout() {
 		return timeout;
 	}
@@ -555,7 +562,7 @@ public int getTimeout() {
 	 *            before aborting an IO read or write operation with this
 	 *            remote.  A timeout of 0 will block indefinitely.
 	 */
-	public void setTimeout(final int seconds) {
+	public void setTimeout(int seconds) {
 		timeout = seconds;
 	}
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/RemoteRefUpdate.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/RemoteRefUpdate.java
index 5c58346..931653f 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/RemoteRefUpdate.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/RemoteRefUpdate.java
@@ -55,17 +55,18 @@
 
 /**
  * Represent request and status of a remote ref update. Specification is
- * provided by client, while status is handled by {@link PushProcess} class,
- * being read-only for client.
+ * provided by client, while status is handled by
+ * {@link org.eclipse.jgit.transport.PushProcess} class, being read-only for
+ * client.
  * <p>
  * Client can create instances of this class directly, basing on user
- * specification and advertised refs ({@link Connection} or through
- * {@link Transport} helper methods. Apply this specification on remote
- * repository using
- * {@link Transport#push(org.eclipse.jgit.lib.ProgressMonitor, java.util.Collection)}
+ * specification and advertised refs
+ * ({@link org.eclipse.jgit.transport.Connection} or through
+ * {@link org.eclipse.jgit.transport.Transport} helper methods. Apply this
+ * specification on remote repository using
+ * {@link org.eclipse.jgit.transport.Transport#push(org.eclipse.jgit.lib.ProgressMonitor, java.util.Collection)}
  * method.
  * </p>
- *
  */
 public class RemoteRefUpdate {
 	/**
@@ -149,16 +150,19 @@ public static enum Status {
 
 	/**
 	 * Construct remote ref update request by providing an update specification.
-	 * Object is created with default {@link Status#NOT_ATTEMPTED} status and no
-	 * message.
+	 * Object is created with default
+	 * {@link org.eclipse.jgit.transport.RemoteRefUpdate.Status#NOT_ATTEMPTED}
+	 * status and no message.
 	 *
 	 * @param localDb
 	 *            local repository to push from.
 	 * @param srcRef
 	 *            source revision - any string resolvable by
-	 *            {@link Repository#resolve(String)}. This resolves to the new
-	 *            object that the caller want remote ref to be after update. Use
-	 *            null or {@link ObjectId#zeroId()} string for delete request.
+	 *            {@link org.eclipse.jgit.lib.Repository#resolve(String)}. This
+	 *            resolves to the new object that the caller want remote ref to
+	 *            be after update. Use null or
+	 *            {@link org.eclipse.jgit.lib.ObjectId#zeroId()} string for
+	 *            delete request.
 	 * @param remoteName
 	 *            full name of a remote ref to update, e.g. "refs/heads/master"
 	 *            (no wildcard, no short name).
@@ -176,13 +180,14 @@ public static enum Status {
 	 *            advertised by remote side before update; update will take
 	 *            place ONLY if remote side advertise exactly this expected id;
 	 *            null if caller doesn't care what object id remote side
-	 *            advertise. Use {@link ObjectId#zeroId()} when expecting no
-	 *            remote ref with this name.
-	 * @throws IOException
+	 *            advertise. Use {@link org.eclipse.jgit.lib.ObjectId#zeroId()}
+	 *            when expecting no remote ref with this name.
+	 * @throws java.io.IOException
 	 *             when I/O error occurred during creating
-	 *             {@link TrackingRefUpdate} for local tracking branch or srcRef
-	 *             can't be resolved to any object.
-	 * @throws IllegalArgumentException
+	 *             {@link org.eclipse.jgit.transport.TrackingRefUpdate} for
+	 *             local tracking branch or srcRef can't be resolved to any
+	 *             object.
+	 * @throws java.lang.IllegalArgumentException
 	 *             if some required parameter was null
 	 */
 	public RemoteRefUpdate(final Repository localDb, final String srcRef,
@@ -196,8 +201,9 @@ public RemoteRefUpdate(final Repository localDb, final String srcRef,
 
 	/**
 	 * Construct remote ref update request by providing an update specification.
-	 * Object is created with default {@link Status#NOT_ATTEMPTED} status and no
-	 * message.
+	 * Object is created with default
+	 * {@link org.eclipse.jgit.transport.RemoteRefUpdate.Status#NOT_ATTEMPTED}
+	 * status and no message.
 	 *
 	 * @param localDb
 	 *            local repository to push from.
@@ -220,13 +226,14 @@ public RemoteRefUpdate(final Repository localDb, final String srcRef,
 	 *            advertised by remote side before update; update will take
 	 *            place ONLY if remote side advertise exactly this expected id;
 	 *            null if caller doesn't care what object id remote side
-	 *            advertise. Use {@link ObjectId#zeroId()} when expecting no
-	 *            remote ref with this name.
-	 * @throws IOException
+	 *            advertise. Use {@link org.eclipse.jgit.lib.ObjectId#zeroId()}
+	 *            when expecting no remote ref with this name.
+	 * @throws java.io.IOException
 	 *             when I/O error occurred during creating
-	 *             {@link TrackingRefUpdate} for local tracking branch or srcRef
-	 *             can't be resolved to any object.
-	 * @throws IllegalArgumentException
+	 *             {@link org.eclipse.jgit.transport.TrackingRefUpdate} for
+	 *             local tracking branch or srcRef can't be resolved to any
+	 *             object.
+	 * @throws java.lang.IllegalArgumentException
 	 *             if some required parameter was null
 	 */
 	public RemoteRefUpdate(final Repository localDb, final Ref srcRef,
@@ -240,8 +247,9 @@ public RemoteRefUpdate(final Repository localDb, final Ref srcRef,
 
 	/**
 	 * Construct remote ref update request by providing an update specification.
-	 * Object is created with default {@link Status#NOT_ATTEMPTED} status and no
-	 * message.
+	 * Object is created with default
+	 * {@link org.eclipse.jgit.transport.RemoteRefUpdate.Status#NOT_ATTEMPTED}
+	 * status and no message.
 	 *
 	 * @param localDb
 	 *            local repository to push from.
@@ -250,7 +258,8 @@ public RemoteRefUpdate(final Repository localDb, final Ref srcRef,
 	 *            be used instead.
 	 * @param srcId
 	 *            The new object that the caller wants remote ref to be after
-	 *            update. Use null or {@link ObjectId#zeroId()} for delete
+	 *            update. Use null or
+	 *            {@link org.eclipse.jgit.lib.ObjectId#zeroId()} for delete
 	 *            request.
 	 * @param remoteName
 	 *            full name of a remote ref to update, e.g. "refs/heads/master"
@@ -269,13 +278,14 @@ public RemoteRefUpdate(final Repository localDb, final Ref srcRef,
 	 *            advertised by remote side before update; update will take
 	 *            place ONLY if remote side advertise exactly this expected id;
 	 *            null if caller doesn't care what object id remote side
-	 *            advertise. Use {@link ObjectId#zeroId()} when expecting no
-	 *            remote ref with this name.
-	 * @throws IOException
+	 *            advertise. Use {@link org.eclipse.jgit.lib.ObjectId#zeroId()}
+	 *            when expecting no remote ref with this name.
+	 * @throws java.io.IOException
 	 *             when I/O error occurred during creating
-	 *             {@link TrackingRefUpdate} for local tracking branch or srcRef
-	 *             can't be resolved to any object.
-	 * @throws IllegalArgumentException
+	 *             {@link org.eclipse.jgit.transport.TrackingRefUpdate} for
+	 *             local tracking branch or srcRef can't be resolved to any
+	 *             object.
+	 * @throws java.lang.IllegalArgumentException
 	 *             if some required parameter was null
 	 */
 	public RemoteRefUpdate(final Repository localDb, final String srcRef,
@@ -333,10 +343,11 @@ else if (srcId != null && !srcId.equals(ObjectId.zeroId()))
 	 *            configuration base.
 	 * @param newExpectedOldObjectId
 	 *            new expected object id value.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             when I/O error occurred during creating
-	 *             {@link TrackingRefUpdate} for local tracking branch or srcRef
-	 *             of base object no longer can be resolved to any object.
+	 *             {@link org.eclipse.jgit.transport.TrackingRefUpdate} for
+	 *             local tracking branch or srcRef of base object no longer can
+	 *             be resolved to any object.
 	 */
 	public RemoteRefUpdate(final RemoteRefUpdate base,
 			final ObjectId newExpectedOldObjectId) throws IOException {
@@ -346,6 +357,8 @@ public RemoteRefUpdate(final RemoteRefUpdate base,
 	}
 
 	/**
+	 * Get expected old object id
+	 *
 	 * @return expectedOldObjectId required to be advertised by remote side, as
 	 *         set in constructor; may be null.
 	 */
@@ -354,6 +367,9 @@ public ObjectId getExpectedOldObjectId() {
 	}
 
 	/**
+	 * Whether some object is required to be advertised by remote side, as set
+	 * in constructor
+	 *
 	 * @return true if some object is required to be advertised by remote side,
 	 *         as set in constructor; false otherwise.
 	 */
@@ -362,6 +378,8 @@ public boolean isExpectingOldObjectId() {
 	}
 
 	/**
+	 * Get new object id
+	 *
 	 * @return newObjectId for remote ref, as set in constructor.
 	 */
 	public ObjectId getNewObjectId() {
@@ -369,6 +387,8 @@ public ObjectId getNewObjectId() {
 	}
 
 	/**
+	 * Whether this update is a deleting update
+	 *
 	 * @return true if this update is deleting update; false otherwise.
 	 */
 	public boolean isDelete() {
@@ -376,6 +396,8 @@ public boolean isDelete() {
 	}
 
 	/**
+	 * Get name of remote ref to update
+	 *
 	 * @return name of remote ref to update, as set in constructor.
 	 */
 	public String getRemoteName() {
@@ -383,6 +405,8 @@ public String getRemoteName() {
 	}
 
 	/**
+	 * Get tracking branch update if localName was set in constructor.
+	 *
 	 * @return local tracking branch update if localName was set in constructor.
 	 */
 	public TrackingRefUpdate getTrackingRefUpdate() {
@@ -390,9 +414,12 @@ public TrackingRefUpdate getTrackingRefUpdate() {
 	}
 
 	/**
+	 * Get source revision as specified by user (in constructor)
+	 *
 	 * @return source revision as specified by user (in constructor), could be
-	 *         any string parseable by {@link Repository#resolve(String)}; can
-	 *         be null if specified that way in constructor - this stands for
+	 *         any string parseable by
+	 *         {@link org.eclipse.jgit.lib.Repository#resolve(String)}; can be
+	 *         null if specified that way in constructor - this stands for
 	 *         delete request.
 	 */
 	public String getSrcRef() {
@@ -400,6 +427,8 @@ public String getSrcRef() {
 	}
 
 	/**
+	 * Whether user specified a local tracking branch for remote update
+	 *
 	 * @return true if user specified a local tracking branch for remote update;
 	 *         false otherwise.
 	 */
@@ -408,6 +437,8 @@ public boolean hasTrackingRefUpdate() {
 	}
 
 	/**
+	 * Whether this update is forced regardless of old remote ref object
+	 *
 	 * @return true if this update is forced regardless of old remote ref
 	 *         object; false otherwise.
 	 */
@@ -416,6 +447,8 @@ public boolean isForceUpdate() {
 	}
 
 	/**
+	 * Get status of remote ref update operation.
+	 *
 	 * @return status of remote ref update operation.
 	 */
 	public Status getStatus() {
@@ -424,7 +457,8 @@ public Status getStatus() {
 
 	/**
 	 * Check whether update was fast-forward. Note that this result is
-	 * meaningful only after successful update (when status is {@link Status#OK}).
+	 * meaningful only after successful update (when status is
+	 * {@link org.eclipse.jgit.transport.RemoteRefUpdate.Status#OK}).
 	 *
 	 * @return true if update was fast-forward; false otherwise.
 	 */
@@ -433,6 +467,9 @@ public boolean isFastForward() {
 	}
 
 	/**
+	 * Get message describing reasons of status when needed/possible; may be
+	 * null.
+	 *
 	 * @return message describing reasons of status when needed/possible; may be
 	 *         null.
 	 */
@@ -444,7 +481,7 @@ void setExpectedOldObjectId(ObjectId id) {
 		expectedOldObjectId = id;
 	}
 
-	void setStatus(final Status status) {
+	void setStatus(Status status) {
 		this.status = status;
 	}
 
@@ -452,7 +489,7 @@ void setFastForward(boolean fastForward) {
 		this.fastForward = fastForward;
 	}
 
-	void setMessage(final String message) {
+	void setMessage(String message) {
 		this.message = message;
 	}
 
@@ -461,16 +498,17 @@ void setMessage(final String message) {
 	 *
 	 * @param walk
 	 *            walker used for checking update properties.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             when I/O error occurred during update
 	 */
-	protected void updateTrackingRef(final RevWalk walk) throws IOException {
+	protected void updateTrackingRef(RevWalk walk) throws IOException {
 		if (isDelete())
 			trackingRefUpdate.setResult(localUpdate.delete(walk));
 		else
 			trackingRefUpdate.setResult(localUpdate.update(walk));
 	}
 
+	/** {@inheritDoc} */
 	@SuppressWarnings("nls")
 	@Override
 	public String toString() {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/RemoteSession.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/RemoteSession.java
index d6a2fe6..525c895 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/RemoteSession.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/RemoteSession.java
@@ -65,17 +65,18 @@ public interface RemoteSession {
 	 * Generate a new remote process to execute the given command. This function
 	 * should also start execution and may need to create the streams prior to
 	 * execution.
+	 *
 	 * @param commandName
 	 *            command to execute
 	 * @param timeout
 	 *            timeout value, in seconds, for command execution
 	 * @return a new remote process
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             may be thrown in several cases. For example, on problems
 	 *             opening input or output streams or on problems connecting or
 	 *             communicating with the remote host. For the latter two cases,
 	 *             a TransportException may be thrown (a subclass of
-	 *             IOException).
+	 *             java.io.IOException).
 	 */
 	public Process exec(String commandName, int timeout) throws IOException;
 
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/RequestNotYetReadException.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/RequestNotYetReadException.java
index 8b45174..428af96 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/RequestNotYetReadException.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/RequestNotYetReadException.java
@@ -51,12 +51,16 @@
 public class RequestNotYetReadException extends IllegalStateException {
 	private static final long serialVersionUID = 1L;
 
-	/** Initialize with no message. */
+	/**
+	 * Initialize with no message.
+	 */
 	public RequestNotYetReadException() {
 		// Do not set a message.
 	}
 
 	/**
+	 * <p>Constructor for RequestNotYetReadException.</p>
+	 *
 	 * @param msg
 	 *            a message explaining the state. This message should not
 	 *            be shown to an end-user.
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/ServiceMayNotContinueException.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/ServiceMayNotContinueException.java
index 87c9a500..940d2e2 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/ServiceMayNotContinueException.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/ServiceMayNotContinueException.java
@@ -59,13 +59,17 @@ public class ServiceMayNotContinueException extends IOException {
 	private final int statusCode;
 	private boolean output;
 
-	/** Initialize with no message. */
+	/**
+	 * Initialize with no message.
+	 */
 	public ServiceMayNotContinueException() {
 		// Do not set a message.
 		statusCode = FORBIDDEN;
 	}
 
 	/**
+	 * <p>Constructor for ServiceMayNotContinueException.</p>
+	 *
 	 * @param msg
 	 *            a message explaining why it cannot continue. This message may
 	 *            be shown to an end-user.
@@ -76,6 +80,8 @@ public ServiceMayNotContinueException(String msg) {
 	}
 
 	/**
+	 * <p>Constructor for ServiceMayNotContinueException.</p>
+	 *
 	 * @param msg
 	 *            a message explaining why it cannot continue. This message may
 	 *            be shown to an end-user.
@@ -89,6 +95,8 @@ public ServiceMayNotContinueException(String msg, int statusCode) {
 	}
 
 	/**
+	 * <p>Constructor for ServiceMayNotContinueException.</p>
+	 *
 	 * @param msg
 	 *            a message explaining why it cannot continue. This message may
 	 *            be shown to an end-user.
@@ -102,6 +110,8 @@ public ServiceMayNotContinueException(String msg, Throwable cause) {
 	}
 
 	/**
+	 * <p>Constructor for ServiceMayNotContinueException.</p>
+	 *
 	 * @param msg
 	 *            a message explaining why it cannot continue. This message may
 	 *            be shown to an end-user.
@@ -128,17 +138,25 @@ public ServiceMayNotContinueException(Throwable cause) {
 		this(JGitText.get().internalServerError, cause);
 	}
 
-	/** @return true if the message was already output to the client. */
+	/**
+	 * Whether the message was already output to the client.
+	 *
+	 * @return {@code true} if the message was already output to the client.
+	 */
 	public boolean isOutput() {
 		return output;
 	}
 
-	/** Mark this message has being sent to the client. */
+	/**
+	 * Mark this message has being sent to the client.
+	 */
 	public void setOutput() {
 		output = true;
 	}
 
 	/**
+	 * Get status code
+	 *
 	 * @return true if the message was already output to the client.
 	 * @since 4.5
 	 */
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/SideBandInputStream.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/SideBandInputStream.java
index fe9f2a3..3100cb4 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/SideBandInputStream.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/SideBandInputStream.java
@@ -76,8 +76,9 @@
  * an unrecoverable error.
  *
  * @see SideBandOutputStream
+ * @since 4.11
  */
-class SideBandInputStream extends InputStream {
+public class SideBandInputStream extends InputStream {
 	static final int CH_DATA = 1;
 	static final int CH_PROGRESS = 2;
 	static final int CH_ERROR = 3;
@@ -120,6 +121,7 @@ class SideBandInputStream extends InputStream {
 		out = outputStream;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public int read() throws IOException {
 		needDataPacket();
@@ -129,8 +131,9 @@ public int read() throws IOException {
 		return rawIn.read();
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	public int read(final byte[] b, int off, int len) throws IOException {
+	public int read(byte[] b, int off, int len) throws IOException {
 		int r = 0;
 		while (len > 0) {
 			needDataPacket();
@@ -200,7 +203,7 @@ else if (0 <= cr)
 		progressBuffer = pkt;
 	}
 
-	private void doProgressLine(final String msg) throws IOException {
+	private void doProgressLine(String msg) throws IOException {
 		Matcher matcher;
 
 		matcher = P_BOUNDED.matcher(msg);
@@ -236,7 +239,7 @@ private void doProgressLine(final String msg) throws IOException {
 			out.write(msg.getBytes());
 	}
 
-	private void beginTask(final int totalWorkUnits) {
+	private void beginTask(int totalWorkUnits) {
 		monitor.beginTask(remote(currentTask), totalWorkUnits);
 	}
 
@@ -251,7 +254,7 @@ private static String remote(String msg) {
 		return r.toString();
 	}
 
-	private String readString(final int len) throws IOException {
+	private String readString(int len) throws IOException {
 		final byte[] raw = new byte[len];
 		IO.readFully(rawIn, raw, 0, len);
 		return RawParseUtils.decode(Constants.CHARSET, raw, 0, len);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/SideBandOutputStream.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/SideBandOutputStream.java
index 0303eed..b2cc1b6 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/SideBandOutputStream.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/SideBandOutputStream.java
@@ -102,7 +102,7 @@ public class SideBandOutputStream extends OutputStream {
 	 *            stream that the packets are written onto. This stream should
 	 *            be attached to a SideBandInputStream on the remote side.
 	 */
-	public SideBandOutputStream(final int chan, final int sz, final OutputStream os) {
+	public SideBandOutputStream(int chan, int sz, OutputStream os) {
 		if (chan <= 0 || chan > 255)
 			throw new IllegalArgumentException(MessageFormat.format(
 					JGitText.get().channelMustBeInRange1_255,
@@ -127,14 +127,16 @@ void flushBuffer() throws IOException {
 			writeBuffer();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void flush() throws IOException {
 		flushBuffer();
 		out.flush();
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	public void write(final byte[] b, int off, int len) throws IOException {
+	public void write(byte[] b, int off, int len) throws IOException {
 		while (0 < len) {
 			int capacity = buffer.length - cnt;
 			if (cnt == HDR_SIZE && capacity < len) {
@@ -159,8 +161,9 @@ public void write(final byte[] b, int off, int len) throws IOException {
 		}
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	public void write(final int b) throws IOException {
+	public void write(int b) throws IOException {
 		if (cnt == buffer.length)
 			writeBuffer();
 		buffer[cnt++] = (byte) b;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/SideBandProgressMonitor.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/SideBandProgressMonitor.java
index aa80065..8a3e4ef 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/SideBandProgressMonitor.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/SideBandProgressMonitor.java
@@ -55,11 +55,12 @@ class SideBandProgressMonitor extends BatchingProgressMonitor {
 
 	private boolean write;
 
-	SideBandProgressMonitor(final OutputStream os) {
+	SideBandProgressMonitor(OutputStream os) {
 		out = os;
 		write = true;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected void onUpdate(String taskName, int workCurr) {
 		StringBuilder s = new StringBuilder();
@@ -68,6 +69,7 @@ protected void onUpdate(String taskName, int workCurr) {
 		send(s);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected void onEndTask(String taskName, int workCurr) {
 		StringBuilder s = new StringBuilder();
@@ -82,6 +84,7 @@ private void format(StringBuilder s, String taskName, int workCurr) {
 		s.append(workCurr);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected void onUpdate(String taskName, int cmp, int totalWork, int pcnt) {
 		StringBuilder s = new StringBuilder();
@@ -90,6 +93,7 @@ protected void onUpdate(String taskName, int cmp, int totalWork, int pcnt) {
 		send(s);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected void onEndTask(String taskName, int cmp, int totalWork, int pcnt) {
 		StringBuilder s = new StringBuilder();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/SignedPushConfig.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/SignedPushConfig.java
index 1ecbed9..f404737 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/SignedPushConfig.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/SignedPushConfig.java
@@ -60,7 +60,9 @@ public class SignedPushConfig {
 	private int certNonceSlopLimit;
 	private NonceGenerator nonceGenerator;
 
-	/** Create a new config with default values disabling push verification. */
+	/**
+	 * Create a new config with default values disabling push verification.
+	 */
 	public SignedPushConfig() {
 	}
 
@@ -73,9 +75,10 @@ public SignedPushConfig() {
 	 * Set the seed used by the nonce verifier.
 	 * <p>
 	 * Setting this to a non-null value enables push certificate verification
-	 * using the default {@link HMACSHA1NonceGenerator} implementation, if a
-	 * different implementation was not set using {@link
-	 * #setNonceGenerator(NonceGenerator)}.
+	 * using the default
+	 * {@link org.eclipse.jgit.transport.HMACSHA1NonceGenerator} implementation,
+	 * if a different implementation was not set using
+	 * {@link #setNonceGenerator(NonceGenerator)}.
 	 *
 	 * @param seed
 	 *            new seed value.
@@ -84,7 +87,11 @@ public void setCertNonceSeed(String seed) {
 		certNonceSeed = seed;
 	}
 
-	/** @return the configured seed. */
+	/**
+	 * Get the configured seed.
+	 *
+	 * @return the configured seed.
+	 */
 	public String getCertNonceSeed() {
 		return certNonceSeed;
 	}
@@ -101,18 +108,23 @@ public void setCertNonceSlopLimit(int limit) {
 		certNonceSlopLimit = limit;
 	}
 
-	/** @return the configured nonce slop limit. */
+	/**
+	 * Get the configured nonce slop limit.
+	 *
+	 * @return the configured nonce slop limit.
+	 */
 	public int getCertNonceSlopLimit() {
 		return certNonceSlopLimit;
 	}
 
 	/**
-	 * Set the {@link NonceGenerator} used for signed pushes.
+	 * Set the {@link org.eclipse.jgit.transport.NonceGenerator} used for signed
+	 * pushes.
 	 * <p>
-	 * Setting this to a non-null value enables push certificate verification. If
-	 * this method is called, this implementation will be used instead of the
-	 * default {@link HMACSHA1NonceGenerator} even if {@link
-	 * #setCertNonceSeed(String)} was called.
+	 * Setting this to a non-null value enables push certificate verification.
+	 * If this method is called, this implementation will be used instead of the
+	 * default {@link org.eclipse.jgit.transport.HMACSHA1NonceGenerator} even if
+	 * {@link #setCertNonceSeed(String)} was called.
 	 *
 	 * @param generator
 	 *            new nonce generator.
@@ -122,12 +134,13 @@ public void setNonceGenerator(NonceGenerator generator) {
 	}
 
 	/**
-	 * Get the {@link NonceGenerator} used for signed pushes.
+	 * Get the {@link org.eclipse.jgit.transport.NonceGenerator} used for signed
+	 * pushes.
 	 * <p>
 	 * If {@link #setNonceGenerator(NonceGenerator)} was used to set a non-null
-	 * implementation, that will be returned. If no custom implementation was set
-	 * but {@link #setCertNonceSeed(String)} was called, returns a newly-created
-	 * {@link HMACSHA1NonceGenerator}.
+	 * implementation, that will be returned. If no custom implementation was
+	 * set but {@link #setCertNonceSeed(String)} was called, returns a
+	 * newly-created {@link org.eclipse.jgit.transport.HMACSHA1NonceGenerator}.
 	 *
 	 * @return the configured nonce generator.
 	 */
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/SshSessionFactory.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/SshSessionFactory.java
index 2d5029a..ae357df 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/SshSessionFactory.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/SshSessionFactory.java
@@ -54,9 +54,9 @@
  * communicating with the end-user as well as reading their personal SSH
  * configuration settings, such as known hosts and private keys.
  * <p>
- * A {@link RemoteSession} must be returned to the factory that created it.
- * Callers are encouraged to retain the SshSessionFactory for the duration of
- * the period they are using the Session.
+ * A {@link org.eclipse.jgit.transport.RemoteSession} must be returned to the
+ * factory that created it. Callers are encouraged to retain the
+ * SshSessionFactory for the duration of the period they are using the Session.
  */
 public abstract class SshSessionFactory {
 	private static SshSessionFactory INSTANCE = new DefaultSshSessionFactory();
@@ -80,7 +80,7 @@ public static SshSessionFactory getInstance() {
 	 *            factory for future sessions to be created through. If null the
 	 *            default factory will be restored.s
 	 */
-	public static void setInstance(final SshSessionFactory newFactory) {
+	public static void setInstance(SshSessionFactory newFactory) {
 		if (newFactory != null)
 			INSTANCE = newFactory;
 		else
@@ -106,7 +106,7 @@ public static void setInstance(final SshSessionFactory newFactory) {
 	 * @param tms
 	 *            Timeout value, in milliseconds.
 	 * @return a session that can contact the remote host.
-	 * @throws TransportException
+	 * @throws org.eclipse.jgit.errors.TransportException
 	 *             the session could not be created.
 	 */
 	public abstract RemoteSession getSession(URIish uri,
@@ -121,7 +121,7 @@ public abstract RemoteSession getSession(URIish uri,
 	 *            {@link #getSession(URIish, CredentialsProvider, FS, int)}
 	 *            method.
 	 */
-	public void releaseSession(final RemoteSession session) {
+	public void releaseSession(RemoteSession session) {
 		session.disconnect();
 	}
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/SshTransport.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/SshTransport.java
index 74865dc..62a6f0e 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/SshTransport.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/SshTransport.java
@@ -99,7 +99,7 @@ protected SshTransport(URIish uri) {
 	 *
 	 * @param factory
 	 *            a factory to set, must not be null
-	 * @throws IllegalStateException
+	 * @throws java.lang.IllegalStateException
 	 *             if session has been already created.
 	 */
 	public void setSshSessionFactory(SshSessionFactory factory) {
@@ -112,7 +112,10 @@ public void setSshSessionFactory(SshSessionFactory factory) {
 	}
 
 	/**
-	 * @return the SSH session factory that will be used for creating SSH sessions
+	 * Get the SSH session factory
+	 *
+	 * @return the SSH session factory that will be used for creating SSH
+	 *         sessions
 	 */
 	public SshSessionFactory getSshSessionFactory() {
 		return sch;
@@ -122,7 +125,7 @@ public SshSessionFactory getSshSessionFactory() {
 	 * Get the default SSH session
 	 *
 	 * @return a remote session
-	 * @throws TransportException
+	 * @throws org.eclipse.jgit.errors.TransportException
 	 *             in case of error with opening SSH session
 	 */
 	protected RemoteSession getSession() throws TransportException {
@@ -138,6 +141,7 @@ protected RemoteSession getSession() throws TransportException {
 		return sock;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void close() {
 		if (sock != null) {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TagOpt.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TagOpt.java
index 384e9fc..cd17913 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TagOpt.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TagOpt.java
@@ -48,7 +48,9 @@
 
 import org.eclipse.jgit.internal.JGitText;
 
-/** Specification of annotated tag behavior during fetch. */
+/**
+ * Specification of annotated tag behavior during fetch.
+ */
 public enum TagOpt {
 	/**
 	 * Automatically follow tags if we fetch the thing they point at.
@@ -82,7 +84,7 @@ public enum TagOpt {
 
 	private final String option;
 
-	private TagOpt(final String o) {
+	private TagOpt(String o) {
 		option = o;
 	}
 
@@ -102,10 +104,10 @@ public String option() {
 	 *            the configuration file text value.
 	 * @return the option that matches the passed parameter.
 	 */
-	public static TagOpt fromOption(final String o) {
+	public static TagOpt fromOption(String o) {
 		if (o == null || o.length() == 0)
 			return AUTO_FOLLOW;
-		for (final TagOpt tagopt : values()) {
+		for (TagOpt tagopt : values()) {
 			if (tagopt.option().equals(o))
 				return tagopt;
 		}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TestProtocol.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TestProtocol.java
index 8a28e3a..cdcd2a3 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TestProtocol.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TestProtocol.java
@@ -54,21 +54,23 @@
 import org.eclipse.jgit.errors.TransportException;
 import org.eclipse.jgit.internal.JGitText;
 import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.transport.BasePackFetchConnection.FetchConfig;
 import org.eclipse.jgit.transport.resolver.ReceivePackFactory;
 import org.eclipse.jgit.transport.resolver.UploadPackFactory;
 
 /**
  * Protocol for transport between manually-specified repositories in tests.
  * <p>
- * Remote repositories are registered using {@link #register(Object,
- * Repository)}, after which they can be accessed using the returned URI. As
- * this class provides both the client side (the protocol) and the server side,
- * the caller is responsible for setting up and passing the connection context,
- * whatever form that may take.
+ * Remote repositories are registered using
+ * {@link #register(Object, Repository)}, after which they can be accessed using
+ * the returned URI. As this class provides both the client side (the protocol)
+ * and the server side, the caller is responsible for setting up and passing the
+ * connection context, whatever form that may take.
  * <p>
  * Unlike the other built-in protocols, which are automatically-registered
  * singletons, callers are expected to register/unregister specific protocol
- * instances on demand with {@link Transport#register(TransportProtocol)}.
+ * instances on demand with
+ * {@link org.eclipse.jgit.transport.Transport#register(TransportProtocol)}.
  *
  * @param <C>
  *            the connection type
@@ -77,6 +79,8 @@
 public class TestProtocol<C> extends TransportProtocol {
 	private static final String SCHEME = "test"; //$NON-NLS-1$
 
+	private static FetchConfig fetchConfig;
+
 	private class Handle {
 		final C req;
 		final Repository remote;
@@ -92,12 +96,16 @@ private class Handle {
 	private final HashMap<URIish, Handle> handles;
 
 	/**
+	 * Constructor for TestProtocol.
+	 *
 	 * @param uploadPackFactory
-	 *            factory for creating {@link UploadPack} used by all connections
-	 *            from this protocol instance.
+	 *            factory for creating
+	 *            {@link org.eclipse.jgit.transport.UploadPack} used by all
+	 *            connections from this protocol instance.
 	 * @param receivePackFactory
-	 *            factory for creating {@link ReceivePack} used by all connections
-	 *            from this protocol instance.
+	 *            factory for creating
+	 *            {@link org.eclipse.jgit.transport.ReceivePack} used by all
+	 *            connections from this protocol instance.
 	 */
 	public TestProtocol(UploadPackFactory<C> uploadPackFactory,
 			ReceivePackFactory<C> receivePackFactory) {
@@ -106,16 +114,19 @@ public TestProtocol(UploadPackFactory<C> uploadPackFactory,
 		this.handles = new HashMap<>();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public String getName() {
 		return JGitText.get().transportProtoTest;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public Set<String> getSchemes() {
 		return Collections.singleton(SCHEME);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public Transport open(URIish uri, Repository local, String remoteName)
 			throws NotSupportedException, TransportException {
@@ -127,16 +138,22 @@ public Transport open(URIish uri, Repository local, String remoteName)
 		return new TransportInternal(local, uri, h);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public Set<URIishField> getRequiredFields() {
 		return EnumSet.of(URIishField.HOST, URIishField.PATH);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public Set<URIishField> getOptionalFields() {
 		return Collections.emptySet();
 	}
 
+	static void setFetchConfig(FetchConfig c) {
+		fetchConfig = c;
+	}
+
 	/**
 	 * Register a repository connection over the internal test protocol.
 	 *
@@ -174,8 +191,14 @@ private class TransportInternal extends Transport implements PackTransport {
 		public FetchConnection openFetch() throws NotSupportedException,
 				TransportException {
 			handle.remote.incrementOpen();
-			return new InternalFetchConnection<>(
-					this, uploadPackFactory, handle.req, handle.remote);
+			return new InternalFetchConnection<C>(this, uploadPackFactory,
+					handle.req, handle.remote) {
+				@Override
+				FetchConfig getFetchConfig() {
+					return fetchConfig != null ? fetchConfig
+							: super.getFetchConfig();
+				}
+			};
 		}
 
 		@Override
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TrackingRefUpdate.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TrackingRefUpdate.java
index 5aae5ea..ba2a673 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TrackingRefUpdate.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TrackingRefUpdate.java
@@ -49,7 +49,9 @@
 import org.eclipse.jgit.lib.ObjectId;
 import org.eclipse.jgit.lib.RefUpdate;
 
-/** Update of a locally stored tracking branch. */
+/**
+ * Update of a locally stored tracking branch.
+ */
 public class TrackingRefUpdate {
 	private final String remoteName;
 	final String localName;
@@ -132,6 +134,8 @@ void setResult(RefUpdate.Result result) {
 	}
 
 	/**
+	 * Get this update wrapped by a ReceiveCommand.
+	 *
 	 * @return this update wrapped by a ReceiveCommand.
 	 * @since 3.4
 	 */
@@ -201,6 +205,7 @@ private RefUpdate.Result decode(ReceiveCommand.Result status) {
 		}
 	}
 
+	/** {@inheritDoc} */
 	@SuppressWarnings("nls")
 	@Override
 	public String toString() {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransferConfig.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransferConfig.java
index 099629c..4ae1ccb 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransferConfig.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransferConfig.java
@@ -62,8 +62,8 @@
 import org.eclipse.jgit.util.SystemReader;
 
 /**
- * The standard "transfer", "fetch", "receive", and "uploadpack" configuration
- * parameters.
+ * The standard "transfer", "fetch", "protocol", "receive", and "uploadpack"
+ * configuration parameters.
  */
 public class TransferConfig {
 	private static final String FSCK = "fsck"; //$NON-NLS-1$
@@ -92,6 +92,33 @@ public enum FsckMode {
 		IGNORE;
 	}
 
+	/**
+	 * A git configuration variable for which versions of the Git protocol to prefer.
+	 * Used in protocol.version.
+	 */
+	enum ProtocolVersion {
+		V0("0"), //$NON-NLS-1$
+		V2("2"); //$NON-NLS-1$
+
+		final String name;
+
+		ProtocolVersion(String name) {
+			this.name = name;
+		}
+
+		static @Nullable ProtocolVersion parse(@Nullable String name) {
+			if (name == null) {
+				return null;
+			}
+			for (ProtocolVersion v : ProtocolVersion.values()) {
+				if (v.name.equals(name)) {
+					return v;
+				}
+			}
+			return null;
+		}
+	}
+
 	private final boolean fetchFsck;
 	private final boolean receiveFsck;
 	private final String fsckSkipList;
@@ -101,32 +128,36 @@ public enum FsckMode {
 	private final boolean safeForMacOS;
 	private final boolean allowTipSha1InWant;
 	private final boolean allowReachableSha1InWant;
+	private final boolean allowFilter;
+	final @Nullable ProtocolVersion protocolVersion;
 	final String[] hideRefs;
 
-	TransferConfig(final Repository db) {
+	TransferConfig(Repository db) {
 		this(db.getConfig());
 	}
 
-	TransferConfig(final Config rc) {
-		boolean fsck = rc.getBoolean("transfer", "fsckobjects", false); //$NON-NLS-1$ //$NON-NLS-2$
-		fetchFsck = rc.getBoolean("fetch", "fsckobjects", fsck); //$NON-NLS-1$ //$NON-NLS-2$
-		receiveFsck = rc.getBoolean("receive", "fsckobjects", fsck); //$NON-NLS-1$ //$NON-NLS-2$
-		fsckSkipList = rc.getString(FSCK, null, "skipList"); //$NON-NLS-1$
-		allowInvalidPersonIdent = rc.getBoolean(FSCK, "allowInvalidPersonIdent", false); //$NON-NLS-1$
-		safeForWindows = rc.getBoolean(FSCK, "safeForWindows", //$NON-NLS-1$
+	@SuppressWarnings("nls")
+	TransferConfig(Config rc) {
+		boolean fsck = rc.getBoolean("transfer", "fsckobjects", false);
+		fetchFsck = rc.getBoolean("fetch", "fsckobjects", fsck);
+		receiveFsck = rc.getBoolean("receive", "fsckobjects", fsck);
+		fsckSkipList = rc.getString(FSCK, null, "skipList");
+		allowInvalidPersonIdent = rc.getBoolean(FSCK, "allowInvalidPersonIdent",
+				false);
+		safeForWindows = rc.getBoolean(FSCK, "safeForWindows",
 						SystemReader.getInstance().isWindows());
-		safeForMacOS = rc.getBoolean(FSCK, "safeForMacOS", //$NON-NLS-1$
+		safeForMacOS = rc.getBoolean(FSCK, "safeForMacOS",
 						SystemReader.getInstance().isMacOS());
 
 		ignore = EnumSet.noneOf(ObjectChecker.ErrorType.class);
 		EnumSet<ObjectChecker.ErrorType> set = EnumSet
 				.noneOf(ObjectChecker.ErrorType.class);
 		for (String key : rc.getNames(FSCK)) {
-			if (equalsIgnoreCase(key, "skipList") //$NON-NLS-1$
-					|| equalsIgnoreCase(key, "allowLeadingZeroFileMode") //$NON-NLS-1$
-					|| equalsIgnoreCase(key, "allowInvalidPersonIdent") //$NON-NLS-1$
-					|| equalsIgnoreCase(key, "safeForWindows") //$NON-NLS-1$
-					|| equalsIgnoreCase(key, "safeForMacOS")) { //$NON-NLS-1$
+			if (equalsIgnoreCase(key, "skipList")
+					|| equalsIgnoreCase(key, "allowLeadingZeroFileMode")
+					|| equalsIgnoreCase(key, "allowInvalidPersonIdent")
+					|| equalsIgnoreCase(key, "safeForWindows")
+					|| equalsIgnoreCase(key, "safeForMacOS")) {
 				continue;
 			}
 
@@ -145,18 +176,23 @@ public enum FsckMode {
 			}
 		}
 		if (!set.contains(ObjectChecker.ErrorType.ZERO_PADDED_FILEMODE)
-				&& rc.getBoolean(FSCK, "allowLeadingZeroFileMode", false)) { //$NON-NLS-1$
+				&& rc.getBoolean(FSCK, "allowLeadingZeroFileMode", false)) {
 			ignore.add(ObjectChecker.ErrorType.ZERO_PADDED_FILEMODE);
 		}
 
 		allowTipSha1InWant = rc.getBoolean(
-				"uploadpack", "allowtipsha1inwant", false); //$NON-NLS-1$ //$NON-NLS-2$
+				"uploadpack", "allowtipsha1inwant", false);
 		allowReachableSha1InWant = rc.getBoolean(
-				"uploadpack", "allowreachablesha1inwant", false); //$NON-NLS-1$ //$NON-NLS-2$
-		hideRefs = rc.getStringList("uploadpack", null, "hiderefs"); //$NON-NLS-1$ //$NON-NLS-2$
+				"uploadpack", "allowreachablesha1inwant", false);
+		allowFilter = rc.getBoolean(
+				"uploadpack", "allowfilter", false);
+		protocolVersion = ProtocolVersion.parse(rc.getString("protocol", null, "version"));
+		hideRefs = rc.getStringList("uploadpack", null, "hiderefs");
 	}
 
 	/**
+	 * Create checker to verify fetched objects
+	 *
 	 * @return checker to verify fetched objects, or null if checking is not
 	 *         enabled in the repository configuration.
 	 * @since 3.6
@@ -167,6 +203,8 @@ public ObjectChecker newObjectChecker() {
 	}
 
 	/**
+	 * Create checker to verify objects pushed into this repository
+	 *
 	 * @return checker to verify objects pushed into this repository, or null if
 	 *         checking is not enabled in the repository configuration.
 	 * @since 4.2
@@ -196,6 +234,8 @@ private ObjectIdSet skipList() {
 	}
 
 	/**
+	 * Whether to allow clients to request non-advertised tip SHA-1s
+	 *
 	 * @return allow clients to request non-advertised tip SHA-1s?
 	 * @since 3.1
 	 */
@@ -204,6 +244,8 @@ public boolean isAllowTipSha1InWant() {
 	}
 
 	/**
+	 * Whether to allow clients to request non-tip SHA-1s
+	 *
 	 * @return allow clients to request non-tip SHA-1s?
 	 * @since 4.1
 	 */
@@ -212,7 +254,19 @@ public boolean isAllowReachableSha1InWant() {
 	}
 
 	/**
-	 * @return {@link RefFilter} respecting configured hidden refs.
+	 * @return true if clients are allowed to specify a "filter" line
+	 * @since 5.0
+	 */
+	public boolean isAllowFilter() {
+		return allowFilter;
+	}
+
+	/**
+	 * Get {@link org.eclipse.jgit.transport.RefFilter} respecting configured
+	 * hidden refs.
+	 *
+	 * @return {@link org.eclipse.jgit.transport.RefFilter} respecting
+	 *         configured hidden refs.
 	 * @since 3.1
 	 */
 	public RefFilter getRefFilter() {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/Transport.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/Transport.java
index 649e840..d342ef4 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/Transport.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/Transport.java
@@ -46,11 +46,10 @@
 
 package org.eclipse.jgit.transport;
 
-import static org.eclipse.jgit.lib.RefDatabase.ALL;
+import static org.eclipse.jgit.lib.Constants.CHARSET;
 
 import java.io.BufferedReader;
 import java.io.IOException;
-import java.io.InputStream;
 import java.io.InputStreamReader;
 import java.io.OutputStream;
 import java.io.PrintStream;
@@ -64,7 +63,7 @@
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Enumeration;
-import java.util.HashSet;
+import java.util.LinkedHashSet;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
@@ -78,7 +77,6 @@
 import org.eclipse.jgit.hooks.PrePushHook;
 import org.eclipse.jgit.internal.JGitText;
 import org.eclipse.jgit.lib.Constants;
-import org.eclipse.jgit.lib.NullProgressMonitor;
 import org.eclipse.jgit.lib.ObjectChecker;
 import org.eclipse.jgit.lib.ObjectId;
 import org.eclipse.jgit.lib.ProgressMonitor;
@@ -145,17 +143,8 @@ private static Enumeration<URL> catalogs(ClassLoader ldr) {
 	}
 
 	private static void scan(ClassLoader ldr, URL url) {
-		BufferedReader br;
-		try {
-			InputStream urlIn = url.openStream();
-			br = new BufferedReader(new InputStreamReader(urlIn, "UTF-8")); //$NON-NLS-1$
-		} catch (IOException err) {
-			// If we cannot read from the service list, go to the next.
-			//
-			return;
-		}
-
-		try {
+		try (BufferedReader br = new BufferedReader(
+				new InputStreamReader(url.openStream(), CHARSET))) {
 			String line;
 			while ((line = br.readLine()) != null) {
 				line = line.trim();
@@ -168,15 +157,8 @@ private static void scan(ClassLoader ldr, URL url) {
 					line = line.substring(0, comment).trim();
 				load(ldr, line);
 			}
-		} catch (IOException err) {
-			// If we failed during a read, ignore the error.
-			//
-		} finally {
-			try {
-				br.close();
-			} catch (IOException e) {
-				// Ignore the close error; we are only reading.
-			}
+		} catch (IOException e) {
+			// Ignore errors
 		}
 	}
 
@@ -215,7 +197,8 @@ private static void load(ClassLoader ldr, String cn) {
 	 * Protocol definitions are held by WeakReference, allowing them to be
 	 * garbage collected when the calling application drops all strongly held
 	 * references to the TransportProtocol. Therefore applications should use a
-	 * singleton pattern as described in {@link TransportProtocol}'s class
+	 * singleton pattern as described in
+	 * {@link org.eclipse.jgit.transport.TransportProtocol}'s class
 	 * documentation to ensure their protocol does not get disabled by garbage
 	 * collection earlier than expected.
 	 * <p>
@@ -270,7 +253,8 @@ public static List<TransportProtocol> getTransportProtocols() {
 	/**
 	 * Open a new transport instance to connect two repositories.
 	 * <p>
-	 * This method assumes {@link Operation#FETCH}.
+	 * This method assumes
+	 * {@link org.eclipse.jgit.transport.Transport.Operation#FETCH}.
 	 *
 	 * @param local
 	 *            existing local repository.
@@ -279,15 +263,15 @@ public static List<TransportProtocol> getTransportProtocols() {
 	 *            configuration name.
 	 * @return the new transport instance. Never null. In case of multiple URIs
 	 *         in remote configuration, only the first is chosen.
-	 * @throws URISyntaxException
+	 * @throws java.net.URISyntaxException
 	 *             the location is not a remote defined in the configuration
 	 *             file and is not a well-formed URL.
-	 * @throws NotSupportedException
+	 * @throws org.eclipse.jgit.errors.NotSupportedException
 	 *             the protocol specified is not supported.
-	 * @throws TransportException
+	 * @throws org.eclipse.jgit.errors.TransportException
 	 *             the transport cannot open this URI.
 	 */
-	public static Transport open(final Repository local, final String remote)
+	public static Transport open(Repository local, String remote)
 			throws NotSupportedException, URISyntaxException,
 			TransportException {
 		return open(local, remote, Operation.FETCH);
@@ -306,12 +290,12 @@ public static Transport open(final Repository local, final String remote)
 	 *            based on the type of connection desired.
 	 * @return the new transport instance. Never null. In case of multiple URIs
 	 *         in remote configuration, only the first is chosen.
-	 * @throws URISyntaxException
+	 * @throws java.net.URISyntaxException
 	 *             the location is not a remote defined in the configuration
 	 *             file and is not a well-formed URL.
-	 * @throws NotSupportedException
+	 * @throws org.eclipse.jgit.errors.NotSupportedException
 	 *             the protocol specified is not supported.
-	 * @throws TransportException
+	 * @throws org.eclipse.jgit.errors.TransportException
 	 *             the transport cannot open this URI.
 	 */
 	public static Transport open(final Repository local, final String remote,
@@ -330,7 +314,8 @@ public static Transport open(final Repository local, final String remote,
 	/**
 	 * Open new transport instances to connect two repositories.
 	 * <p>
-	 * This method assumes {@link Operation#FETCH}.
+	 * This method assumes
+	 * {@link org.eclipse.jgit.transport.Transport.Operation#FETCH}.
 	 *
 	 * @param local
 	 *            existing local repository.
@@ -339,12 +324,12 @@ public static Transport open(final Repository local, final String remote,
 	 *            configuration name.
 	 * @return the list of new transport instances for every URI in remote
 	 *         configuration.
-	 * @throws URISyntaxException
+	 * @throws java.net.URISyntaxException
 	 *             the location is not a remote defined in the configuration
 	 *             file and is not a well-formed URL.
-	 * @throws NotSupportedException
+	 * @throws org.eclipse.jgit.errors.NotSupportedException
 	 *             the protocol specified is not supported.
-	 * @throws TransportException
+	 * @throws org.eclipse.jgit.errors.TransportException
 	 *             the transport cannot open this URI.
 	 */
 	public static List<Transport> openAll(final Repository local,
@@ -366,12 +351,12 @@ public static List<Transport> openAll(final Repository local,
 	 *            based on the type of connection desired.
 	 * @return the list of new transport instances for every URI in remote
 	 *         configuration.
-	 * @throws URISyntaxException
+	 * @throws java.net.URISyntaxException
 	 *             the location is not a remote defined in the configuration
 	 *             file and is not a well-formed URL.
-	 * @throws NotSupportedException
+	 * @throws org.eclipse.jgit.errors.NotSupportedException
 	 *             the protocol specified is not supported.
-	 * @throws TransportException
+	 * @throws org.eclipse.jgit.errors.TransportException
 	 *             the transport cannot open this URI.
 	 */
 	public static List<Transport> openAll(final Repository local,
@@ -390,7 +375,8 @@ public static List<Transport> openAll(final Repository local,
 	/**
 	 * Open a new transport instance to connect two repositories.
 	 * <p>
-	 * This method assumes {@link Operation#FETCH}.
+	 * This method assumes
+	 * {@link org.eclipse.jgit.transport.Transport.Operation#FETCH}.
 	 *
 	 * @param local
 	 *            existing local repository.
@@ -399,15 +385,15 @@ public static List<Transport> openAll(final Repository local,
 	 *            repository.
 	 * @return the new transport instance. Never null. In case of multiple URIs
 	 *         in remote configuration, only the first is chosen.
-	 * @throws NotSupportedException
+	 * @throws org.eclipse.jgit.errors.NotSupportedException
 	 *             the protocol specified is not supported.
-	 * @throws TransportException
+	 * @throws org.eclipse.jgit.errors.TransportException
 	 *             the transport cannot open this URI.
-	 * @throws IllegalArgumentException
+	 * @throws java.lang.IllegalArgumentException
 	 *             if provided remote configuration doesn't have any URI
 	 *             associated.
 	 */
-	public static Transport open(final Repository local, final RemoteConfig cfg)
+	public static Transport open(Repository local, RemoteConfig cfg)
 			throws NotSupportedException, TransportException {
 		return open(local, cfg, Operation.FETCH);
 	}
@@ -425,11 +411,11 @@ public static Transport open(final Repository local, final RemoteConfig cfg)
 	 *            based on the type of connection desired.
 	 * @return the new transport instance. Never null. In case of multiple URIs
 	 *         in remote configuration, only the first is chosen.
-	 * @throws NotSupportedException
+	 * @throws org.eclipse.jgit.errors.NotSupportedException
 	 *             the protocol specified is not supported.
-	 * @throws TransportException
+	 * @throws org.eclipse.jgit.errors.TransportException
 	 *             the transport cannot open this URI.
-	 * @throws IllegalArgumentException
+	 * @throws java.lang.IllegalArgumentException
 	 *             if provided remote configuration doesn't have any URI
 	 *             associated.
 	 */
@@ -448,7 +434,8 @@ public static Transport open(final Repository local,
 	/**
 	 * Open new transport instances to connect two repositories.
 	 * <p>
-	 * This method assumes {@link Operation#FETCH}.
+	 * This method assumes
+	 * {@link org.eclipse.jgit.transport.Transport.Operation#FETCH}.
 	 *
 	 * @param local
 	 *            existing local repository.
@@ -457,9 +444,9 @@ public static Transport open(final Repository local,
 	 *            repository.
 	 * @return the list of new transport instances for every URI in remote
 	 *         configuration.
-	 * @throws NotSupportedException
+	 * @throws org.eclipse.jgit.errors.NotSupportedException
 	 *             the protocol specified is not supported.
-	 * @throws TransportException
+	 * @throws org.eclipse.jgit.errors.TransportException
 	 *             the transport cannot open this URI.
 	 */
 	public static List<Transport> openAll(final Repository local,
@@ -481,9 +468,9 @@ public static List<Transport> openAll(final Repository local,
 	 *            based on the type of connection desired.
 	 * @return the list of new transport instances for every URI in remote
 	 *         configuration.
-	 * @throws NotSupportedException
+	 * @throws org.eclipse.jgit.errors.NotSupportedException
 	 *             the protocol specified is not supported.
-	 * @throws TransportException
+	 * @throws org.eclipse.jgit.errors.TransportException
 	 *             the transport cannot open this URI.
 	 */
 	public static List<Transport> openAll(final Repository local,
@@ -491,7 +478,7 @@ public static List<Transport> openAll(final Repository local,
 			throws NotSupportedException, TransportException {
 		final List<URIish> uris = getURIs(cfg, op);
 		final List<Transport> transports = new ArrayList<>(uris.size());
-		for (final URIish uri : uris) {
+		for (URIish uri : uris) {
 			final Transport tn = open(local, uri, cfg.getName());
 			tn.applyConfig(cfg);
 			transports.add(tn);
@@ -515,7 +502,7 @@ private static List<URIish> getURIs(final RemoteConfig cfg,
 		}
 	}
 
-	private static boolean doesNotExist(final RemoteConfig cfg) {
+	private static boolean doesNotExist(RemoteConfig cfg) {
 		return cfg.getURIs().isEmpty() && cfg.getPushURIs().isEmpty();
 	}
 
@@ -527,12 +514,12 @@ private static boolean doesNotExist(final RemoteConfig cfg) {
 	 * @param uri
 	 *            location of the remote repository.
 	 * @return the new transport instance. Never null.
-	 * @throws NotSupportedException
+	 * @throws org.eclipse.jgit.errors.NotSupportedException
 	 *             the protocol specified is not supported.
-	 * @throws TransportException
+	 * @throws org.eclipse.jgit.errors.TransportException
 	 *             the transport cannot open this URI.
 	 */
-	public static Transport open(final Repository local, final URIish uri)
+	public static Transport open(Repository local, URIish uri)
 			throws NotSupportedException, TransportException {
 		return open(local, uri, null);
 	}
@@ -548,9 +535,9 @@ public static Transport open(final Repository local, final URIish uri)
 	 *            name of the remote, if the remote as configured in
 	 *            {@code local}; otherwise null.
 	 * @return the new transport instance. Never null.
-	 * @throws NotSupportedException
+	 * @throws org.eclipse.jgit.errors.NotSupportedException
 	 *             the protocol specified is not supported.
-	 * @throws TransportException
+	 * @throws org.eclipse.jgit.errors.TransportException
 	 *             the transport cannot open this URI.
 	 */
 	public static Transport open(Repository local, URIish uri, String remoteName)
@@ -580,10 +567,10 @@ public static Transport open(Repository local, URIish uri, String remoteName)
 	 * Note that the resulting transport instance can not be used for fetching
 	 * or pushing, but only for reading remote refs.
 	 *
-	 * @param uri
+	 * @param uri a {@link org.eclipse.jgit.transport.URIish} object.
 	 * @return new Transport instance
-	 * @throws NotSupportedException
-	 * @throws TransportException
+	 * @throws org.eclipse.jgit.errors.NotSupportedException
+	 * @throws org.eclipse.jgit.errors.TransportException
 	 */
 	public static Transport open(URIish uri) throws NotSupportedException, TransportException {
 		for (WeakReference<TransportProtocol> ref : protocols) {
@@ -601,12 +588,13 @@ public static Transport open(URIish uri) throws NotSupportedException, Transport
 	}
 
 	/**
-	 * Convert push remote refs update specification from {@link RefSpec} form
-	 * to {@link RemoteRefUpdate}. Conversion expands wildcards by matching
-	 * source part to local refs. expectedOldObjectId in RemoteRefUpdate is
-	 * set when specified in leases. Tracking branch is configured if RefSpec
-	 * destination matches source of any fetch ref spec for this transport
-	 * remote configuration.
+	 * Convert push remote refs update specification from
+	 * {@link org.eclipse.jgit.transport.RefSpec} form to
+	 * {@link org.eclipse.jgit.transport.RemoteRefUpdate}. Conversion expands
+	 * wildcards by matching source part to local refs. expectedOldObjectId in
+	 * RemoteRefUpdate is set when specified in leases. Tracking branch is
+	 * configured if RefSpec destination matches source of any fetch ref spec
+	 * for this transport remote configuration.
 	 *
 	 * @param db
 	 *            local database.
@@ -617,8 +605,9 @@ public static Transport open(URIish uri) throws NotSupportedException, Transport
 	 * @param fetchSpecs
 	 *            fetch specifications used for finding localtracking refs. May
 	 *            be null or empty collection.
-	 * @return collection of set up {@link RemoteRefUpdate}.
-	 * @throws IOException
+	 * @return collection of set up
+	 *         {@link org.eclipse.jgit.transport.RemoteRefUpdate}.
+	 * @throws java.io.IOException
 	 *             when problem occurred during conversion or specification set
 	 *             up: most probably, missing objects or refs.
 	 * @since 4.7
@@ -632,7 +621,7 @@ public static Collection<RemoteRefUpdate> findRemoteRefUpdatesFor(
 		final List<RemoteRefUpdate> result = new LinkedList<>();
 		final Collection<RefSpec> procRefs = expandPushWildcardsFor(db, specs);
 
-		for (final RefSpec spec : procRefs) {
+		for (RefSpec spec : procRefs) {
 			String srcSpec = spec.getSource();
 			final Ref srcRef = db.findRef(srcSpec);
 			if (srcRef != null)
@@ -668,12 +657,13 @@ public static Collection<RemoteRefUpdate> findRemoteRefUpdatesFor(
 	}
 
 	/**
-	 * Convert push remote refs update specification from {@link RefSpec} form
-	 * to {@link RemoteRefUpdate}. Conversion expands wildcards by matching
-	 * source part to local refs. expectedOldObjectId in RemoteRefUpdate is
-	 * always set as null. Tracking branch is configured if RefSpec destination
-	 * matches source of any fetch ref spec for this transport remote
-	 * configuration.
+	 * Convert push remote refs update specification from
+	 * {@link org.eclipse.jgit.transport.RefSpec} form to
+	 * {@link org.eclipse.jgit.transport.RemoteRefUpdate}. Conversion expands
+	 * wildcards by matching source part to local refs. expectedOldObjectId in
+	 * RemoteRefUpdate is always set as null. Tracking branch is configured if
+	 * RefSpec destination matches source of any fetch ref spec for this
+	 * transport remote configuration.
 	 *
 	 * @param db
 	 *            local database.
@@ -682,8 +672,9 @@ public static Collection<RemoteRefUpdate> findRemoteRefUpdatesFor(
 	 * @param fetchSpecs
 	 *            fetch specifications used for finding localtracking refs. May
 	 *            be null or empty collection.
-	 * @return collection of set up {@link RemoteRefUpdate}.
-	 * @throws IOException
+	 * @return collection of set up
+	 *         {@link org.eclipse.jgit.transport.RemoteRefUpdate}.
+	 * @throws java.io.IOException
 	 *             when problem occurred during conversion or specification set
 	 *             up: most probably, missing objects or refs.
 	 */
@@ -697,12 +688,12 @@ public static Collection<RemoteRefUpdate> findRemoteRefUpdatesFor(
 	private static Collection<RefSpec> expandPushWildcardsFor(
 			final Repository db, final Collection<RefSpec> specs)
 			throws IOException {
-		final Map<String, Ref> localRefs = db.getRefDatabase().getRefs(ALL);
-		final Collection<RefSpec> procRefs = new HashSet<>();
+		final List<Ref> localRefs = db.getRefDatabase().getRefs();
+		final Collection<RefSpec> procRefs = new LinkedHashSet<>();
 
-		for (final RefSpec spec : specs) {
+		for (RefSpec spec : specs) {
 			if (spec.isWildcard()) {
-				for (final Ref localRef : localRefs.values()) {
+				for (Ref localRef : localRefs) {
 					if (spec.matchSource(localRef))
 						procRefs.add(spec.expandFromSource(localRef));
 				}
@@ -716,7 +707,7 @@ private static Collection<RefSpec> expandPushWildcardsFor(
 	private static String findTrackingRefName(final String remoteName,
 			final Collection<RefSpec> fetchSpecs) {
 		// try to find matching tracking refs
-		for (final RefSpec fetchSpec : fetchSpecs) {
+		for (RefSpec fetchSpec : fetchSpecs) {
 			if (fetchSpec.matchSource(remoteName)) {
 				if (fetchSpec.isWildcard())
 					return fetchSpec.expandFromSource(remoteName)
@@ -799,6 +790,8 @@ private static String findTrackingRefName(final String remoteName,
 	/** Should refs no longer on the source be pruned from the destination? */
 	private boolean removeDeletedRefs;
 
+	private long filterBlobLimit = -1;
+
 	/** Timeout in seconds to wait before aborting an IO read or write. */
 	private int timeout;
 
@@ -825,7 +818,7 @@ private static String findTrackingRefName(final String remoteName,
 	 *            the URI used to access the remote repository. This must be the
 	 *            URI passed to {@link #open(Repository, URIish)}.
 	 */
-	protected Transport(final Repository local, final URIish uri) {
+	protected Transport(Repository local, URIish uri) {
 		final TransferConfig tc = local.getConfig().get(TransferConfig.KEY);
 		this.local = local;
 		this.uri = uri;
@@ -838,8 +831,9 @@ protected Transport(final Repository local, final URIish uri) {
 	 * Create a minimal transport instance not tied to a single repository.
 	 *
 	 * @param uri
+	 *            a {@link org.eclipse.jgit.transport.URIish} object.
 	 */
-	protected Transport(final URIish uri) {
+	protected Transport(URIish uri) {
 		this.uri = uri;
 		this.local = null;
 		this.objectChecker = new ObjectChecker();
@@ -872,7 +866,7 @@ public String getOptionUploadPack() {
 	 * @param where
 	 *            name of the executable.
 	 */
-	public void setOptionUploadPack(final String where) {
+	public void setOptionUploadPack(String where) {
 		if (where != null && where.length() > 0)
 			optionUploadPack = where;
 		else
@@ -894,7 +888,7 @@ public TagOpt getTagOpt() {
 	 * @param option
 	 *            method to use when handling annotated tags.
 	 */
-	public void setTagOpt(final TagOpt option) {
+	public void setTagOpt(TagOpt option) {
 		tagopt = option != null ? option : TagOpt.AUTO_FOLLOW;
 	}
 
@@ -918,11 +912,13 @@ public boolean isFetchThin() {
 	 *            when it shouldn't
 	 * @see PackTransport
 	 */
-	public void setFetchThin(final boolean fetchThin) {
+	public void setFetchThin(boolean fetchThin) {
 		this.fetchThin = fetchThin;
 	}
 
 	/**
+	 * Whether fetch will verify if received objects are formatted correctly.
+	 *
 	 * @return true if fetch will verify received objects are formatted
 	 *         correctly. Validating objects requires more CPU time on the
 	 *         client side of the connection.
@@ -932,12 +928,14 @@ public boolean isCheckFetchedObjects() {
 	}
 
 	/**
+	 * Configure if checking received objects is enabled
+	 *
 	 * @param check
 	 *            true to enable checking received objects; false to assume all
 	 *            received objects are valid.
 	 * @see #setObjectChecker(ObjectChecker)
 	 */
-	public void setCheckFetchedObjects(final boolean check) {
+	public void setCheckFetchedObjects(boolean check) {
 		if (check && objectChecker == null)
 			setObjectChecker(new ObjectChecker());
 		else if (!check && objectChecker != null)
@@ -945,6 +943,8 @@ else if (!check && objectChecker != null)
 	}
 
 	/**
+	 * Get configured object checker for received objects
+	 *
 	 * @return configured object checker for received objects, or null.
 	 * @since 3.6
 	 */
@@ -953,6 +953,8 @@ public ObjectChecker getObjectChecker() {
 	}
 
 	/**
+	 * Set the object checker to verify each received object with
+	 *
 	 * @param impl
 	 *            if non-null the object checking instance to verify each
 	 *            received object with; null to disable object checking.
@@ -963,7 +965,8 @@ public void setObjectChecker(ObjectChecker impl) {
 	}
 
 	/**
-	 * Default setting is: {@link RemoteConfig#DEFAULT_RECEIVE_PACK}
+	 * Default setting is:
+	 * {@link org.eclipse.jgit.transport.RemoteConfig#DEFAULT_RECEIVE_PACK}
 	 *
 	 * @return remote executable providing receive-pack service for pack
 	 *         transports.
@@ -975,7 +978,8 @@ public String getOptionReceivePack() {
 
 	/**
 	 * Set remote executable providing receive-pack service for pack transports.
-	 * Default setting is: {@link RemoteConfig#DEFAULT_RECEIVE_PACK}
+	 * Default setting is:
+	 * {@link org.eclipse.jgit.transport.RemoteConfig#DEFAULT_RECEIVE_PACK}
 	 *
 	 * @param optionReceivePack
 	 *            remote executable, if null or empty default one is set;
@@ -1006,7 +1010,7 @@ public boolean isPushThin() {
 	 *            false when it shouldn't
 	 * @see PackTransport
 	 */
-	public void setPushThin(final boolean pushThin) {
+	public void setPushThin(boolean pushThin) {
 		this.pushThin = pushThin;
 	}
 
@@ -1031,11 +1035,14 @@ public boolean isPushAtomic() {
 	 * @see PackTransport
 	 * @since 4.2
 	 */
-	public void setPushAtomic(final boolean atomic) {
+	public void setPushAtomic(boolean atomic) {
 		this.pushAtomic = atomic;
 	}
 
 	/**
+	 * Whether destination refs should be removed if they no longer exist at the
+	 * source repository.
+	 *
 	 * @return true if destination refs should be removed if they no longer
 	 *         exist at the source repository.
 	 */
@@ -1055,17 +1062,34 @@ public boolean isRemoveDeletedRefs() {
 	 *
 	 * @param remove true to remove refs that no longer exist.
 	 */
-	public void setRemoveDeletedRefs(final boolean remove) {
+	public void setRemoveDeletedRefs(boolean remove) {
 		removeDeletedRefs = remove;
 	}
 
 	/**
+	 * @return the last value passed to {@link #setFilterBlobLimit}, or -1 if
+	 *         it was never invoked.
+	 * @since 5.0
+	 */
+	public long getFilterBlobLimit() {
+		return filterBlobLimit;
+	}
+
+	/**
+	 * @param bytes exclude blobs of size greater than this
+	 * @since 5.0
+	 */
+	public void setFilterBlobLimit(long bytes) {
+		filterBlobLimit = bytes;
+	}
+
+	/**
 	 * Apply provided remote configuration on this transport.
 	 *
 	 * @param cfg
 	 *            configuration to apply on this transport.
 	 */
-	public void applyConfig(final RemoteConfig cfg) {
+	public void applyConfig(RemoteConfig cfg) {
 		setOptionUploadPack(cfg.getUploadPack());
 		setOptionReceivePack(cfg.getReceivePack());
 		setTagOpt(cfg.getTagOpt());
@@ -1075,6 +1099,9 @@ public void applyConfig(final RemoteConfig cfg) {
 	}
 
 	/**
+	 * Whether push operation should just check for possible result and not
+	 * really update remote refs
+	 *
 	 * @return true if push operation should just check for possible result and
 	 *         not really update remote refs, false otherwise - when push should
 	 *         act normally.
@@ -1091,11 +1118,15 @@ public boolean isDryRun() {
 	 *            and not really update remote refs, false otherwise - when push
 	 *            should act normally.
 	 */
-	public void setDryRun(final boolean dryRun) {
+	public void setDryRun(boolean dryRun) {
 		this.dryRun = dryRun;
 	}
 
-	/** @return timeout (in seconds) before aborting an IO operation. */
+	/**
+	 * Get timeout (in seconds) before aborting an IO operation.
+	 *
+	 * @return timeout (in seconds) before aborting an IO operation.
+	 */
 	public int getTimeout() {
 		return timeout;
 	}
@@ -1108,7 +1139,7 @@ public int getTimeout() {
 	 *            before aborting an IO read or write operation with this
 	 *            remote.
 	 */
-	public void setTimeout(final int seconds) {
+	public void setTimeout(int seconds) {
 		timeout = seconds;
 	}
 
@@ -1159,6 +1190,8 @@ public CredentialsProvider getCredentialsProvider() {
 	}
 
 	/**
+	 * Get the option strings associated with the push operation
+	 *
 	 * @return the option strings associated with the push operation
 	 * @since 4.5
 	 */
@@ -1173,7 +1206,7 @@ public List<String> getPushOptions() {
 	 *            null if push options are unsupported
 	 * @since 4.5
 	 */
-	public void setPushOptions(final List<String> pushOptions) {
+	public void setPushOptions(List<String> pushOptions) {
 		this.pushOptions = pushOptions;
 	}
 
@@ -1182,22 +1215,24 @@ public void setPushOptions(final List<String> pushOptions) {
 	 * <p>
 	 * This is a utility function providing standard fetch behavior. Local
 	 * tracking refs associated with the remote repository are automatically
-	 * updated if this transport was created from a {@link RemoteConfig} with
-	 * fetch RefSpecs defined.
+	 * updated if this transport was created from a
+	 * {@link org.eclipse.jgit.transport.RemoteConfig} with fetch RefSpecs
+	 * defined.
 	 *
 	 * @param monitor
 	 *            progress monitor to inform the user about our processing
-	 *            activity. Must not be null. Use {@link NullProgressMonitor} if
-	 *            progress updates are not interesting or necessary.
+	 *            activity. Must not be null. Use
+	 *            {@link org.eclipse.jgit.lib.NullProgressMonitor} if progress
+	 *            updates are not interesting or necessary.
 	 * @param toFetch
 	 *            specification of refs to fetch locally. May be null or the
 	 *            empty collection to use the specifications from the
 	 *            RemoteConfig. Source for each RefSpec can't be null.
 	 * @return information describing the tracking refs updated.
-	 * @throws NotSupportedException
+	 * @throws org.eclipse.jgit.errors.NotSupportedException
 	 *             this transport implementation does not support fetching
 	 *             objects.
-	 * @throws TransportException
+	 * @throws org.eclipse.jgit.errors.TransportException
 	 *             the remote connection could not be established or object
 	 *             copying (if necessary) failed or update specification was
 	 *             incorrect.
@@ -1218,9 +1253,9 @@ public FetchResult fetch(final ProgressMonitor monitor,
 			// object transfer overheads.
 			//
 			final Collection<RefSpec> tmp = new ArrayList<>(toFetch);
-			for (final RefSpec requested : toFetch) {
+			for (RefSpec requested : toFetch) {
 				final String reqSrc = requested.getSource();
-				for (final RefSpec configured : fetch) {
+				for (RefSpec configured : fetch) {
 					final String cfgSrc = configured.getSource();
 					final String cfgDst = configured.getDestination();
 					if (cfgSrc.equals(reqSrc) && cfgDst != null) {
@@ -1252,17 +1287,18 @@ public FetchResult fetch(final ProgressMonitor monitor,
 	 * For setting up remote ref update specification from ref spec, see helper
 	 * method {@link #findRemoteRefUpdatesFor(Collection)}, predefined refspecs
 	 * ({@link #REFSPEC_TAGS}, {@link #REFSPEC_PUSH_ALL}) or consider using
-	 * directly {@link RemoteRefUpdate} for more possibilities.
+	 * directly {@link org.eclipse.jgit.transport.RemoteRefUpdate} for more
+	 * possibilities.
 	 * <p>
 	 * When {@link #isDryRun()} is true, result of this operation is just
 	 * estimation of real operation result, no real action is performed.
 	 *
 	 * @see RemoteRefUpdate
-	 *
 	 * @param monitor
 	 *            progress monitor to inform the user about our processing
-	 *            activity. Must not be null. Use {@link NullProgressMonitor} if
-	 *            progress updates are not interesting or necessary.
+	 *            activity. Must not be null. Use
+	 *            {@link org.eclipse.jgit.lib.NullProgressMonitor} if progress
+	 *            updates are not interesting or necessary.
 	 * @param toPush
 	 *            specification of refs to push. May be null or the empty
 	 *            collection to use the specifications from the RemoteConfig
@@ -1273,10 +1309,10 @@ public FetchResult fetch(final ProgressMonitor monitor,
 	 *            output stream to write messages to
 	 * @return information about results of remote refs updates, tracking refs
 	 *         updates and refs advertised by remote repository.
-	 * @throws NotSupportedException
+	 * @throws org.eclipse.jgit.errors.NotSupportedException
 	 *             this transport implementation does not support pushing
 	 *             objects.
-	 * @throws TransportException
+	 * @throws org.eclipse.jgit.errors.TransportException
 	 *             the remote connection could not be established or object
 	 *             copying (if necessary) failed at I/O or protocol level or
 	 *             update specification was incorrect.
@@ -1322,30 +1358,30 @@ public PushResult push(final ProgressMonitor monitor,
 	 * For setting up remote ref update specification from ref spec, see helper
 	 * method {@link #findRemoteRefUpdatesFor(Collection)}, predefined refspecs
 	 * ({@link #REFSPEC_TAGS}, {@link #REFSPEC_PUSH_ALL}) or consider using
-	 * directly {@link RemoteRefUpdate} for more possibilities.
+	 * directly {@link org.eclipse.jgit.transport.RemoteRefUpdate} for more
+	 * possibilities.
 	 * <p>
 	 * When {@link #isDryRun()} is true, result of this operation is just
 	 * estimation of real operation result, no real action is performed.
 	 *
 	 * @see RemoteRefUpdate
-	 *
 	 * @param monitor
 	 *            progress monitor to inform the user about our processing
-	 *            activity. Must not be null. Use {@link NullProgressMonitor} if
-	 *            progress updates are not interesting or necessary.
+	 *            activity. Must not be null. Use
+	 *            {@link org.eclipse.jgit.lib.NullProgressMonitor} if progress
+	 *            updates are not interesting or necessary.
 	 * @param toPush
 	 *            specification of refs to push. May be null or the empty
 	 *            collection to use the specifications from the RemoteConfig
 	 *            converted by {@link #findRemoteRefUpdatesFor(Collection)}. No
 	 *            more than 1 RemoteRefUpdate with the same remoteName is
 	 *            allowed. These objects are modified during this call.
-	 *
 	 * @return information about results of remote refs updates, tracking refs
 	 *         updates and refs advertised by remote repository.
-	 * @throws NotSupportedException
+	 * @throws org.eclipse.jgit.errors.NotSupportedException
 	 *             this transport implementation does not support pushing
 	 *             objects.
-	 * @throws TransportException
+	 * @throws org.eclipse.jgit.errors.TransportException
 	 *             the remote connection could not be established or object
 	 *             copying (if necessary) failed at I/O or protocol level or
 	 *             update specification was incorrect.
@@ -1357,20 +1393,22 @@ public PushResult push(final ProgressMonitor monitor,
 	}
 
 	/**
-	 * Convert push remote refs update specification from {@link RefSpec} form
-	 * to {@link RemoteRefUpdate}. Conversion expands wildcards by matching
-	 * source part to local refs. expectedOldObjectId in RemoteRefUpdate is
-	 * always set as null. Tracking branch is configured if RefSpec destination
-	 * matches source of any fetch ref spec for this transport remote
-	 * configuration.
+	 * Convert push remote refs update specification from
+	 * {@link org.eclipse.jgit.transport.RefSpec} form to
+	 * {@link org.eclipse.jgit.transport.RemoteRefUpdate}. Conversion expands
+	 * wildcards by matching source part to local refs. expectedOldObjectId in
+	 * RemoteRefUpdate is always set as null. Tracking branch is configured if
+	 * RefSpec destination matches source of any fetch ref spec for this
+	 * transport remote configuration.
 	 * <p>
 	 * Conversion is performed for context of this transport (database, fetch
 	 * specifications).
 	 *
 	 * @param specs
 	 *            collection of RefSpec to convert.
-	 * @return collection of set up {@link RemoteRefUpdate}.
-	 * @throws IOException
+	 * @return collection of set up
+	 *         {@link org.eclipse.jgit.transport.RemoteRefUpdate}.
+	 * @throws java.io.IOException
 	 *             when problem occurred during conversion or specification set
 	 *             up: most probably, missing objects or refs.
 	 */
@@ -1381,12 +1419,13 @@ public Collection<RemoteRefUpdate> findRemoteRefUpdatesFor(
 	}
 
 	/**
-	 * Convert push remote refs update specification from {@link RefSpec} form
-	 * to {@link RemoteRefUpdate}. Conversion expands wildcards by matching
-	 * source part to local refs. expectedOldObjectId in RemoteRefUpdate is
-	 * set according to leases. Tracking branch is configured if RefSpec destination
-	 * matches source of any fetch ref spec for this transport remote
-	 * configuration.
+	 * Convert push remote refs update specification from
+	 * {@link org.eclipse.jgit.transport.RefSpec} form to
+	 * {@link org.eclipse.jgit.transport.RemoteRefUpdate}. Conversion expands
+	 * wildcards by matching source part to local refs. expectedOldObjectId in
+	 * RemoteRefUpdate is set according to leases. Tracking branch is configured
+	 * if RefSpec destination matches source of any fetch ref spec for this
+	 * transport remote configuration.
 	 * <p>
 	 * Conversion is performed for context of this transport (database, fetch
 	 * specifications).
@@ -1395,8 +1434,9 @@ public Collection<RemoteRefUpdate> findRemoteRefUpdatesFor(
 	 *            collection of RefSpec to convert.
 	 * @param leases
 	 *            map from ref to lease (containing expected old object id)
-	 * @return collection of set up {@link RemoteRefUpdate}.
-	 * @throws IOException
+	 * @return collection of set up
+	 *         {@link org.eclipse.jgit.transport.RemoteRefUpdate}.
+	 * @throws java.io.IOException
 	 *             when problem occurred during conversion or specification set
 	 *             up: most probably, missing objects or refs.
 	 * @since 4.7
@@ -1415,9 +1455,9 @@ public Collection<RemoteRefUpdate> findRemoteRefUpdatesFor(
 	 * be used for reading remote refs.
 	 *
 	 * @return a fresh connection to fetch from the remote repository.
-	 * @throws NotSupportedException
+	 * @throws org.eclipse.jgit.errors.NotSupportedException
 	 *             the implementation does not support fetching.
-	 * @throws TransportException
+	 * @throws org.eclipse.jgit.errors.TransportException
 	 *             the remote connection could not be established.
 	 */
 	public abstract FetchConnection openFetch() throws NotSupportedException,
@@ -1427,15 +1467,17 @@ public abstract FetchConnection openFetch() throws NotSupportedException,
 	 * Begins a new connection for pushing into the remote repository.
 	 *
 	 * @return a fresh connection to push into the remote repository.
-	 * @throws NotSupportedException
+	 * @throws org.eclipse.jgit.errors.NotSupportedException
 	 *             the implementation does not support pushing.
-	 * @throws TransportException
+	 * @throws org.eclipse.jgit.errors.TransportException
 	 *             the remote connection could not be established
 	 */
 	public abstract PushConnection openPush() throws NotSupportedException,
 			TransportException;
 
 	/**
+	 * {@inheritDoc}
+	 * <p>
 	 * Close any resources used by this transport.
 	 * <p>
 	 * If the remote repository is contacted by a network socket this method
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportAmazonS3.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportAmazonS3.java
index 6cd119b..6118cb8 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportAmazonS3.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportAmazonS3.java
@@ -86,8 +86,9 @@
  * extended HTTP/1.1 semantics. This make it possible to read or write Git data
  * from a remote repository that is stored on S3.
  * <p>
- * Unlike the HTTP variant (see {@link TransportHttp}) we rely upon being able
- * to list objects in a bucket, as the S3 API supports this function. By listing
+ * Unlike the HTTP variant (see
+ * {@link org.eclipse.jgit.transport.TransportHttp}) we rely upon being able to
+ * list objects in a bucket, as the S3 API supports this function. By listing
  * the bucket contents we can avoid relying on <code>objects/info/packs</code>
  * or <code>info/refs</code> in the remote repository.
  * <p>
@@ -201,6 +202,7 @@ private static Properties loadPropertiesFile(File propsFile)
 		}
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public FetchConnection openFetch() throws TransportException {
 		final DatabaseS3 c = new DatabaseS3(bucket, keyPrefix + "/objects"); //$NON-NLS-1$
@@ -209,6 +211,7 @@ public FetchConnection openFetch() throws TransportException {
 		return r;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public PushConnection openPush() throws TransportException {
 		final DatabaseS3 c = new DatabaseS3(bucket, keyPrefix + "/objects"); //$NON-NLS-1$
@@ -217,6 +220,7 @@ public PushConnection openPush() throws TransportException {
 		return r;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void close() {
 		// No explicit connections are maintained.
@@ -263,7 +267,7 @@ Collection<WalkRemoteObjectDatabase> getAlternates() throws IOException {
 		}
 
 		@Override
-		WalkRemoteObjectDatabase openAlternate(final String location)
+		WalkRemoteObjectDatabase openAlternate(String location)
 				throws IOException {
 			return new DatabaseS3(bucketName, resolveKey(location));
 		}
@@ -274,7 +278,7 @@ Collection<String> getPackNames() throws IOException {
 			have.addAll(s3.list(bucket, resolveKey("pack"))); //$NON-NLS-1$
 
 			final Collection<String> packs = new ArrayList<>();
-			for (final String n : have) {
+			for (String n : have) {
 				if (!n.startsWith("pack-") || !n.endsWith(".pack")) //$NON-NLS-1$ //$NON-NLS-2$
 					continue;
 
@@ -286,7 +290,7 @@ Collection<String> getPackNames() throws IOException {
 		}
 
 		@Override
-		FileStream open(final String path) throws IOException {
+		FileStream open(String path) throws IOException {
 			final URLConnection c = s3.get(bucket, resolveKey(path));
 			final InputStream raw = c.getInputStream();
 			final InputStream in = s3.decrypt(c);
@@ -295,7 +299,7 @@ FileStream open(final String path) throws IOException {
 		}
 
 		@Override
-		void deleteFile(final String path) throws IOException {
+		void deleteFile(String path) throws IOException {
 			s3.delete(bucket, resolveKey(path));
 		}
 
@@ -307,7 +311,7 @@ OutputStream writeFile(final String path,
 		}
 
 		@Override
-		void writeFile(final String path, final byte[] data) throws IOException {
+		void writeFile(String path, byte[] data) throws IOException {
 			s3.put(bucket, resolveKey(path), data);
 		}
 
@@ -319,7 +323,7 @@ Map<String, Ref> readAdvertisedRefs() throws TransportException {
 			return avail;
 		}
 
-		private void readLooseRefs(final TreeMap<String, Ref> avail)
+		private void readLooseRefs(TreeMap<String, Ref> avail)
 				throws TransportException {
 			try {
 				for (final String n : s3.list(bucket, resolveKey(ROOT_DIR
@@ -330,16 +334,13 @@ private void readLooseRefs(final TreeMap<String, Ref> avail)
 			}
 		}
 
-		private Ref readRef(final TreeMap<String, Ref> avail, final String rn)
+		private Ref readRef(TreeMap<String, Ref> avail, String rn)
 				throws TransportException {
 			final String s;
 			String ref = ROOT_DIR + rn;
 			try {
-				final BufferedReader br = openReader(ref);
-				try {
+				try (BufferedReader br = openReader(ref)) {
 					s = br.readLine();
-				} finally {
-					br.close();
 				}
 			} catch (FileNotFoundException noRef) {
 				return null;
@@ -373,7 +374,7 @@ private Ref readRef(final TreeMap<String, Ref> avail, final String rn)
 			throw new TransportException(getURI(), MessageFormat.format(JGitText.get().transportExceptionBadRef, rn, s));
 		}
 
-		private Storage loose(final Ref r) {
+		private Storage loose(Ref r) {
 			if (r != null && r.getStorage() == Storage.PACKED)
 				return Storage.LOOSE_PACKED;
 			return Storage.LOOSE;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportBundleFile.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportBundleFile.java
index f2ddc0d..58f021c 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportBundleFile.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportBundleFile.java
@@ -125,11 +125,20 @@ public Transport open(URIish uri) throws NotSupportedException,
 		bundle = bundlePath;
 	}
 
+	/**
+	 * Constructor for TransportBundleFile.
+	 *
+	 * @param uri
+	 *            a {@link org.eclipse.jgit.transport.URIish} object.
+	 * @param bundlePath
+	 *            transport bundle path
+	 */
 	public TransportBundleFile(URIish uri, File bundlePath) {
 		super(uri);
 		bundle = bundlePath;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public FetchConnection openFetch() throws NotSupportedException,
 			TransportException {
@@ -142,12 +151,14 @@ public FetchConnection openFetch() throws NotSupportedException,
 		return new BundleFetchConnection(this, src);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public PushConnection openPush() throws NotSupportedException {
 		throw new NotSupportedException(
 				JGitText.get().pushIsNotSupportedForBundleTransport);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void close() {
 		// Resources must be established per-connection.
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportBundleStream.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportBundleStream.java
index a9d881f..573367e 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportBundleStream.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportBundleStream.java
@@ -90,6 +90,7 @@ public TransportBundleStream(final Repository db, final URIish uri,
 		src = in;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public FetchConnection openFetch() throws TransportException {
 		if (src == null)
@@ -101,12 +102,14 @@ public FetchConnection openFetch() throws TransportException {
 		}
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public PushConnection openPush() throws NotSupportedException {
 		throw new NotSupportedException(
 				JGitText.get().pushIsNotSupportedForBundleTransport);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void close() {
 		if (src != null) {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportGitAnon.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportGitAnon.java
index 7bf5b94..1132503 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportGitAnon.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportGitAnon.java
@@ -113,24 +113,27 @@ public Transport open(URIish uri) throws NotSupportedException, TransportExcepti
 		}
 	};
 
-	TransportGitAnon(final Repository local, final URIish uri) {
+	TransportGitAnon(Repository local, URIish uri) {
 		super(local, uri);
 	}
 
-	TransportGitAnon(final URIish uri) {
+	TransportGitAnon(URIish uri) {
 		super(uri);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public FetchConnection openFetch() throws TransportException {
 		return new TcpFetchConnection();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public PushConnection openPush() throws TransportException {
 		return new TcpPushConnection();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void close() {
 		// Resources must be established per-connection.
@@ -139,6 +142,7 @@ public void close() {
 	Socket openConnection() throws TransportException {
 		final int tms = getTimeout() > 0 ? getTimeout() * 1000 : 0;
 		final int port = uri.getPort() > 0 ? uri.getPort() : GIT_PORT;
+		@SuppressWarnings("resource") // Closed by the caller
 		final Socket s = new Socket();
 		try {
 			final InetAddress host = InetAddress.getByName(uri.getHost());
@@ -159,7 +163,7 @@ Socket openConnection() throws TransportException {
 		return s;
 	}
 
-	void service(final String name, final PacketLineOut pckOut)
+	void service(String name, PacketLineOut pckOut)
 			throws IOException {
 		final StringBuilder cmd = new StringBuilder();
 		cmd.append(name);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportGitSsh.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportGitSsh.java
index b1b910e..d59fe33 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportGitSsh.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportGitSsh.java
@@ -141,12 +141,12 @@ public Transport open(URIish uri) throws NotSupportedException, TransportExcepti
 		}
 	};
 
-	TransportGitSsh(final Repository local, final URIish uri) {
+	TransportGitSsh(Repository local, URIish uri) {
 		super(local, uri);
 		initSshSessionFactory();
 	}
 
-	TransportGitSsh(final URIish uri) {
+	TransportGitSsh(URIish uri) {
 		super(uri);
 		initSshSessionFactory();
 	}
@@ -164,17 +164,19 @@ public RemoteSession getSession(URIish uri2,
 		}
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public FetchConnection openFetch() throws TransportException {
 		return new SshFetchConnection();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public PushConnection openPush() throws TransportException {
 		return new SshPushConnection();
 	}
 
-	String commandFor(final String exe) {
+	String commandFor(String exe) {
 		String path = uri.getPath();
 		if (uri.getScheme() != null && uri.getPath().startsWith("/~")) //$NON-NLS-1$
 			path = (uri.getPath().substring(1));
@@ -309,6 +311,9 @@ class SshFetchConnection extends BasePackFetchConnection {
 		public void close() {
 			endOut();
 
+			if (process != null) {
+				process.destroy();
+			}
 			if (errorThread != null) {
 				try {
 					errorThread.halt();
@@ -320,8 +325,6 @@ public void close() {
 			}
 
 			super.close();
-			if (process != null)
-				process.destroy();
 		}
 	}
 
@@ -375,6 +378,9 @@ class SshPushConnection extends BasePackPushConnection {
 		public void close() {
 			endOut();
 
+			if (process != null) {
+				process.destroy();
+			}
 			if (errorThread != null) {
 				try {
 					errorThread.halt();
@@ -386,8 +392,6 @@ public void close() {
 			}
 
 			super.close();
-			if (process != null)
-				process.destroy();
 		}
 	}
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportHttp.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportHttp.java
index 7c3f738..c08f400 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportHttp.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportHttp.java
@@ -273,7 +273,7 @@ public Transport open(URIish uri, Repository local, String remoteName)
 
 	private boolean sslFailure = false;
 
-	TransportHttp(final Repository local, final URIish uri)
+	TransportHttp(Repository local, URIish uri)
 			throws NotSupportedException {
 		super(local, uri);
 		setURI(uri);
@@ -291,11 +291,14 @@ private URL toURL(URIish urish) throws MalformedURLException {
 	}
 
 	/**
+	 * Set uri a {@link org.eclipse.jgit.transport.URIish} object.
+	 *
 	 * @param uri
-	 * @throws NotSupportedException
+	 *            a {@link org.eclipse.jgit.transport.URIish} object.
+	 * @throws org.eclipse.jgit.errors.NotSupportedException
 	 * @since 4.9
 	 */
-	protected void setURI(final URIish uri) throws NotSupportedException {
+	protected void setURI(URIish uri) throws NotSupportedException {
 		try {
 			currentUri = uri;
 			baseUrl = toURL(uri);
@@ -311,7 +314,7 @@ protected void setURI(final URIish uri) throws NotSupportedException {
 	 * @param uri
 	 * @throws NotSupportedException
 	 */
-	TransportHttp(final URIish uri) throws NotSupportedException {
+	TransportHttp(URIish uri) throws NotSupportedException {
 		super(uri);
 		setURI(uri);
 		http = new HttpConfig(uri);
@@ -329,31 +332,35 @@ protected void setURI(final URIish uri) throws NotSupportedException {
 	 * @param on
 	 *            if {@code true} (default), smart HTTP is enabled.
 	 */
-	public void setUseSmartHttp(final boolean on) {
+	public void setUseSmartHttp(boolean on) {
 		useSmartHttp = on;
 	}
 
+	@SuppressWarnings("resource") // Closed by caller
+	private FetchConnection getConnection(HttpConnection c, InputStream in,
+			String service) throws IOException {
+		BaseConnection f;
+		if (isSmartHttp(c, service)) {
+			readSmartHeaders(in, service);
+			f = new SmartHttpFetchConnection(in);
+		} else {
+			// Assume this server doesn't support smart HTTP fetch
+			// and fall back on dumb object walking.
+			f = newDumbConnection(in);
+		}
+		f.setPeerUserAgent(c.getHeaderField(HttpSupport.HDR_SERVER));
+		return (FetchConnection) f;
+	}
+
+	/** {@inheritDoc} */
 	@Override
 	public FetchConnection openFetch() throws TransportException,
 			NotSupportedException {
 		final String service = SVC_UPLOAD_PACK;
 		try {
 			final HttpConnection c = connect(service);
-			final InputStream in = openInputStream(c);
-			try {
-				BaseConnection f;
-				if (isSmartHttp(c, service)) {
-					readSmartHeaders(in, service);
-					f = new SmartHttpFetchConnection(in);
-				} else {
-					// Assume this server doesn't support smart HTTP fetch
-					// and fall back on dumb object walking.
-					f = newDumbConnection(in);
-				}
-				f.setPeerUserAgent(c.getHeaderField(HttpSupport.HDR_SERVER));
-				return (FetchConnection) f;
-			} finally {
-				in.close();
+			try (InputStream in = openInputStream(c)) {
+				return getConnection(c, in, service);
 			}
 		} catch (NotSupportedException err) {
 			throw err;
@@ -367,12 +374,9 @@ public FetchConnection openFetch() throws TransportException,
 	private WalkFetchConnection newDumbConnection(InputStream in)
 			throws IOException, PackProtocolException {
 		HttpObjectDB d = new HttpObjectDB(objectsUrl);
-		BufferedReader br = toBufferedReader(in);
 		Map<String, Ref> refs;
-		try {
+		try (BufferedReader br = toBufferedReader(in)) {
 			refs = d.readAdvertisedImpl(br);
-		} finally {
-			br.close();
 		}
 
 		if (!refs.containsKey(HEAD)) {
@@ -387,8 +391,8 @@ private WalkFetchConnection newDumbConnection(InputStream in)
 			int status = HttpSupport.response(conn);
 			switch (status) {
 			case HttpConnection.HTTP_OK: {
-				br = toBufferedReader(openInputStream(conn));
-				try {
+				try (BufferedReader br = toBufferedReader(
+						openInputStream(conn))) {
 					String line = br.readLine();
 					if (line != null && line.startsWith(RefDirectory.SYMREF)) {
 						String target = line.substring(RefDirectory.SYMREF.length());
@@ -402,8 +406,6 @@ private WalkFetchConnection newDumbConnection(InputStream in)
 								HEAD, ObjectId.fromString(line));
 						refs.put(r.getName(), r);
 					}
-				} finally {
-					br.close();
 				}
 				break;
 			}
@@ -427,14 +429,14 @@ private BufferedReader toBufferedReader(InputStream in) {
 		return new BufferedReader(new InputStreamReader(in, Constants.CHARSET));
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public PushConnection openPush() throws NotSupportedException,
 			TransportException {
 		final String service = SVC_RECEIVE_PACK;
 		try {
 			final HttpConnection c = connect(service);
-			final InputStream in = openInputStream(c);
-			try {
+			try (InputStream in = openInputStream(c)) {
 				if (isSmartHttp(c, service)) {
 					return smartPush(service, c, in);
 				} else if (!useSmartHttp) {
@@ -445,8 +447,6 @@ public PushConnection openPush() throws NotSupportedException,
 					final String msg = JGitText.get().remoteDoesNotSupportSmartHTTPPush;
 					throw new NotSupportedException(msg);
 				}
-			} finally {
-				in.close();
 			}
 		} catch (NotSupportedException err) {
 			throw err;
@@ -465,6 +465,7 @@ private PushConnection smartPush(String service, HttpConnection c,
 		return p;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void close() {
 		// No explicit connections are maintained.
@@ -482,7 +483,7 @@ public void setAdditionalHeaders(Map<String, String> headers) {
 		this.headers = headers;
 	}
 
-	private HttpConnection connect(final String service)
+	private HttpConnection connect(String service)
 			throws TransportException, NotSupportedException {
 		URL u = getServiceURL(service);
 		int authAttempts = 1;
@@ -774,7 +775,7 @@ private boolean isValidRedirect(URL current, String next, String checkFor) {
 		return true;
 	}
 
-	private URL getServiceURL(final String service)
+	private URL getServiceURL(String service)
 			throws NotSupportedException {
 		try {
 			final StringBuilder b = new StringBuilder();
@@ -798,28 +799,13 @@ private URL getServiceURL(final String service)
 	}
 
 	/**
-	 * Open an HTTP connection, setting the accept-encoding request header to gzip.
-	 *
-	 * @param method HTTP request method
-	 * @param u url of the HTTP connection
-	 * @return the HTTP connection
-	 * @throws IOException
-	 * @since 3.3
-	 * @deprecated use {@link #httpOpen(String, URL, AcceptEncoding)} instead.
-	 */
-	@Deprecated
-	protected HttpConnection httpOpen(String method, URL u) throws IOException {
-		return httpOpen(method, u, AcceptEncoding.GZIP);
-	}
-
-	/**
 	 * Open an HTTP connection.
 	 *
 	 * @param method HTTP request method
 	 * @param u url of the HTTP connection
 	 * @param acceptEncoding accept-encoding header option
 	 * @return the HTTP connection
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 * @since 4.6
 	 */
 	protected HttpConnection httpOpen(String method, URL u,
@@ -875,18 +861,18 @@ IOException wrongContentType(String expType, String actType) {
 		return new TransportException(uri, why);
 	}
 
-	private boolean isSmartHttp(final HttpConnection c, final String service) {
+	private boolean isSmartHttp(HttpConnection c, String service) {
 		final String expType = "application/x-" + service + "-advertisement"; //$NON-NLS-1$ //$NON-NLS-2$
 		final String actType = c.getContentType();
 		return expType.equals(actType);
 	}
 
-	private boolean isGzipContent(final HttpConnection c) {
+	private boolean isGzipContent(HttpConnection c) {
 		return ENCODING_GZIP.equals(c.getHeaderField(HDR_CONTENT_ENCODING))
 				|| ENCODING_X_GZIP.equals(c.getHeaderField(HDR_CONTENT_ENCODING));
 	}
 
-	private void readSmartHeaders(final InputStream in, final String service)
+	private void readSmartHeaders(InputStream in, String service)
 			throws IOException {
 		// A smart reply will have a '#' after the first 4 bytes, but
 		// a dumb reply cannot contain a '#' until after byte 41. Do a
@@ -917,7 +903,7 @@ private void readSmartHeaders(final InputStream in, final String service)
 	class HttpObjectDB extends WalkRemoteObjectDatabase {
 		private final URL httpObjectsUrl;
 
-		HttpObjectDB(final URL b) {
+		HttpObjectDB(URL b) {
 			httpObjectsUrl = b;
 		}
 
@@ -944,7 +930,7 @@ Collection<WalkRemoteObjectDatabase> getAlternates() throws IOException {
 		}
 
 		@Override
-		WalkRemoteObjectDatabase openAlternate(final String location)
+		WalkRemoteObjectDatabase openAlternate(String location)
 				throws IOException {
 			return new HttpObjectDB(new URL(httpObjectsUrl, location));
 		}
@@ -960,28 +946,23 @@ BufferedReader openReader(String path) throws IOException {
 		@Override
 		Collection<String> getPackNames() throws IOException {
 			final Collection<String> packs = new ArrayList<>();
-			try {
-				final BufferedReader br = openReader(INFO_PACKS);
-				try {
-					for (;;) {
-						final String s = br.readLine();
-						if (s == null || s.length() == 0)
-							break;
-						if (!s.startsWith("P pack-") || !s.endsWith(".pack")) //$NON-NLS-1$ //$NON-NLS-2$
-							throw invalidAdvertisement(s);
-						packs.add(s.substring(2));
-					}
-					return packs;
-				} finally {
-					br.close();
+			try (BufferedReader br = openReader(INFO_PACKS)) {
+				for (;;) {
+					final String s = br.readLine();
+					if (s == null || s.length() == 0)
+						break;
+					if (!s.startsWith("P pack-") || !s.endsWith(".pack")) //$NON-NLS-1$ //$NON-NLS-2$
+						throw invalidAdvertisement(s);
+					packs.add(s.substring(2));
 				}
+				return packs;
 			} catch (FileNotFoundException err) {
 				return packs;
 			}
 		}
 
 		@Override
-		FileStream open(final String path) throws IOException {
+		FileStream open(String path) throws IOException {
 			return open(path, AcceptEncoding.UNSPECIFIED);
 		}
 
@@ -1049,15 +1030,15 @@ Map<String, Ref> readAdvertisedImpl(final BufferedReader br)
 			return avail;
 		}
 
-		private PackProtocolException outOfOrderAdvertisement(final String n) {
+		private PackProtocolException outOfOrderAdvertisement(String n) {
 			return new PackProtocolException(MessageFormat.format(JGitText.get().advertisementOfCameBefore, n, n));
 		}
 
-		private PackProtocolException invalidAdvertisement(final String n) {
+		private PackProtocolException invalidAdvertisement(String n) {
 			return new PackProtocolException(MessageFormat.format(JGitText.get().invalidAdvertisementOf, n));
 		}
 
-		private PackProtocolException duplicateAdvertisement(final String n) {
+		private PackProtocolException duplicateAdvertisement(String n) {
 			return new PackProtocolException(MessageFormat.format(JGitText.get().duplicateAdvertisementsOf, n));
 		}
 
@@ -1070,7 +1051,7 @@ void close() {
 	class SmartHttpFetchConnection extends BasePackFetchConnection {
 		private MultiRequestService svc;
 
-		SmartHttpFetchConnection(final InputStream advertisement)
+		SmartHttpFetchConnection(InputStream advertisement)
 				throws TransportException {
 			super(TransportHttp.this);
 			statelessRPC = true;
@@ -1100,7 +1081,7 @@ protected void onReceivePack() {
 	}
 
 	class SmartHttpPushConnection extends BasePackPushConnection {
-		SmartHttpPushConnection(final InputStream advertisement)
+		SmartHttpPushConnection(InputStream advertisement)
 				throws TransportException {
 			super(TransportHttp.this);
 			statelessRPC = true;
@@ -1159,10 +1140,8 @@ void sendRequest() throws IOException {
 			// Try to compress the content, but only if that is smaller.
 			TemporaryBuffer buf = new TemporaryBuffer.Heap(
 					http.getPostBuffer());
-			try {
-				GZIPOutputStream gzip = new GZIPOutputStream(buf);
+			try (GZIPOutputStream gzip = new GZIPOutputStream(buf)) {
 				out.writeTo(gzip, null);
-				gzip.close();
 				if (out.length() < buf.length())
 					buf = out;
 			} catch (IOException err) {
@@ -1257,13 +1236,7 @@ void sendRequest() throws IOException {
 							}
 							authAttempts = 1;
 							// We only do the Kerberos part of SPNEGO, which
-							// requires only one attempt. We do *not* to the
-							// NTLM part of SPNEGO; it's a multi-round
-							// negotiation and among other problems it would
-							// be unclear when to stop if no HTTP_OK is
-							// forthcoming. In theory a malicious server
-							// could keep sending requests for another NTLM
-							// round, keeping a client stuck here.
+							// requires only one round.
 							break;
 						default:
 							// DIGEST or BASIC. Let's be sure we ignore
@@ -1305,6 +1278,27 @@ void sendRequest() throws IOException {
 				} catch (SSLHandshakeException e) {
 					handleSslFailure(e);
 					continue; // Re-try
+				} catch (IOException e) {
+					if (authenticator == null || authMethod
+							.getType() != HttpAuthMethod.Type.NONE) {
+						// Can happen for instance if the server advertises
+						// Negotiate, but the client isn't configured for
+						// Kerberos. The first time (authenticator == null) we
+						// must re-try even if the authMethod was NONE: this may
+						// occur if the server advertised NTLM on the GET
+						// and the HttpConnection managed to successfully
+						// authenticate under the hood with NTLM. We might not
+						// have picked this up on the GET's 200 response.
+						if (authMethod.getType() != HttpAuthMethod.Type.NONE) {
+							ignoreTypes.add(authMethod.getType());
+						}
+						// Start over with the remaining available methods.
+						authMethod = HttpAuthMethod.Type.NONE.method(null);
+						authenticator = authMethod;
+						authAttempts = 1;
+						continue;
+					}
+					throw e;
 				}
 			}
 		}
@@ -1390,7 +1384,7 @@ protected OutputStream overflow() throws IOException {
 	class MultiRequestService extends Service {
 		boolean finalRequest;
 
-		MultiRequestService(final String serviceName) {
+		MultiRequestService(String serviceName) {
 			super(serviceName);
 		}
 
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportLocal.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportLocal.java
index f483ec7..fbb2c44 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportLocal.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportLocal.java
@@ -162,22 +162,25 @@ public Transport open(URIish uri) throws NotSupportedException,
 		remoteGitDir = gitDir;
 	}
 
-	UploadPack createUploadPack(final Repository dst) {
+	UploadPack createUploadPack(Repository dst) {
 		return new UploadPack(dst);
 	}
 
-	ReceivePack createReceivePack(final Repository dst) {
+	ReceivePack createReceivePack(Repository dst) {
 		return new ReceivePack(dst);
 	}
 
 	private Repository openRepo() throws TransportException {
 		try {
-			return new RepositoryBuilder().setGitDir(remoteGitDir).build();
+			return new RepositoryBuilder()
+					.setFS(local != null ? local.getFS() : FS.DETECTED)
+					.setGitDir(remoteGitDir).build();
 		} catch (IOException err) {
 			throw new TransportException(uri, JGitText.get().notAGitDirectory);
 		}
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public FetchConnection openFetch() throws TransportException {
 		final String up = getOptionUploadPack();
@@ -194,6 +197,7 @@ public UploadPack create(Void req, Repository db) {
 		return new InternalFetchConnection<>(this, upf, null, openRepo());
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public PushConnection openPush() throws TransportException {
 		final String rp = getOptionReceivePack();
@@ -210,12 +214,22 @@ public ReceivePack create(Void req, Repository db) {
 		return new InternalPushConnection<>(this, rpf, null, openRepo());
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void close() {
 		// Resources must be established per-connection.
 	}
 
-	protected Process spawn(final String cmd)
+	/**
+	 * Spawn process
+	 *
+	 * @param cmd
+	 *            command
+	 * @return a {@link java.lang.Process} object.
+	 * @throws org.eclipse.jgit.errors.TransportException
+	 *             if any.
+	 */
+	protected Process spawn(String cmd)
 			throws TransportException {
 		try {
 			String[] args = { "." }; //$NON-NLS-1$
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportProtocol.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportProtocol.java
index e08efc4..de58aa9 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportProtocol.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportProtocol.java
@@ -72,11 +72,12 @@
  *
  * <p>
  * Applications may register additional protocols for use by JGit by calling
- * {@link Transport#register(TransportProtocol)}. Because that API holds onto
- * the protocol object by a WeakReference, applications must ensure their own
- * ClassLoader retains the TransportProtocol for the life of the application.
- * Using a static singleton pattern as above will ensure the protocol is valid
- * so long as the ClassLoader that defines it remains valid.
+ * {@link org.eclipse.jgit.transport.Transport#register(TransportProtocol)}.
+ * Because that API holds onto the protocol object by a WeakReference,
+ * applications must ensure their own ClassLoader retains the TransportProtocol
+ * for the life of the application. Using a static singleton pattern as above
+ * will ensure the protocol is valid so long as the ClassLoader that defines it
+ * remains valid.
  * <p>
  * Applications may automatically register additional protocols by filling in
  * the names of their TransportProtocol defining classes using the services file
@@ -102,25 +103,45 @@ public static enum URIishField {
 		PATH,
 	}
 
-	/** @return text name of the protocol suitable for display to a user. */
+	/**
+	 * Get text name of the protocol suitable for display to a user.
+	 *
+	 * @return text name of the protocol suitable for display to a user.
+	 */
 	public abstract String getName();
 
-	/** @return immutable set of schemes supported by this protocol. */
+	/**
+	 * Get immutable set of schemes supported by this protocol.
+	 *
+	 * @return immutable set of schemes supported by this protocol.
+	 */
 	public Set<String> getSchemes() {
 		return Collections.emptySet();
 	}
 
-	/** @return immutable set of URIishFields that must be filled in. */
+	/**
+	 * Get immutable set of URIishFields that must be filled in.
+	 *
+	 * @return immutable set of URIishFields that must be filled in.
+	 */
 	public Set<URIishField> getRequiredFields() {
 		return Collections.unmodifiableSet(EnumSet.of(URIishField.PATH));
 	}
 
-	/** @return immutable set of URIishFields that may be filled in. */
+	/**
+	 * Get immutable set of URIishFields that may be filled in.
+	 *
+	 * @return immutable set of URIishFields that may be filled in.
+	 */
 	public Set<URIishField> getOptionalFields() {
 		return Collections.emptySet();
 	}
 
-	/** @return if a port is supported, the default port, else -1. */
+	/**
+	 * Get the default port if the protocol supports a port, else -1.
+	 *
+	 * @return the default port if the protocol supports a port, else -1.
+	 */
 	public int getDefaultPort() {
 		return -1;
 	}
@@ -246,9 +267,9 @@ public boolean canHandle(URIish uri, Repository local, String remoteName) {
 	 *            name of the remote, if the remote as configured in
 	 *            {@code local}; otherwise null.
 	 * @return the transport.
-	 * @throws NotSupportedException
+	 * @throws org.eclipse.jgit.errors.NotSupportedException
 	 *             this protocol does not support the URI.
-	 * @throws TransportException
+	 * @throws org.eclipse.jgit.errors.TransportException
 	 *             the transport cannot open this URI.
 	 */
 	public abstract Transport open(URIish uri, Repository local,
@@ -260,9 +281,10 @@ public abstract Transport open(URIish uri, Repository local,
 	 * configuration instead of reading from configuration files.
 	 *
 	 * @param uri
+	 *            a {@link org.eclipse.jgit.transport.URIish} object.
 	 * @return new Transport
-	 * @throws NotSupportedException
-	 * @throws TransportException
+	 * @throws org.eclipse.jgit.errors.NotSupportedException
+	 * @throws org.eclipse.jgit.errors.TransportException
 	 */
 	public Transport open(URIish uri)
 			throws NotSupportedException, TransportException {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportSftp.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportSftp.java
index c46f94b..f129ba3 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportSftp.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportSftp.java
@@ -43,6 +43,8 @@
 
 package org.eclipse.jgit.transport;
 
+import static org.eclipse.jgit.lib.Constants.LOCK_SUFFIX;
+
 import java.io.BufferedReader;
 import java.io.FileNotFoundException;
 import java.io.IOException;
@@ -86,11 +88,12 @@
  * repository that is available over SSH, but whose remote host does not have
  * Git installed.
  * <p>
- * Unlike the HTTP variant (see {@link TransportHttp}) we rely upon being able
- * to list files in directories, as the SFTP protocol supports this function. By
+ * Unlike the HTTP variant (see
+ * {@link org.eclipse.jgit.transport.TransportHttp}) we rely upon being able to
+ * list files in directories, as the SFTP protocol supports this function. By
  * listing files through SFTP we can avoid needing to have current
- * <code>objects/info/packs</code> or <code>info/refs</code> files on the
- * remote repository and access the data directly, much as Git itself would.
+ * <code>objects/info/packs</code> or <code>info/refs</code> files on the remote
+ * repository and access the data directly, much as Git itself would.
  * <p>
  * Concurrent pushing over this transport is not supported. Multiple concurrent
  * push operations may cause confusion in the repository state.
@@ -133,10 +136,11 @@ public Transport open(URIish uri, Repository local, String remoteName)
 		}
 	};
 
-	TransportSftp(final Repository local, final URIish uri) {
+	TransportSftp(Repository local, URIish uri) {
 		super(local, uri);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public FetchConnection openFetch() throws TransportException {
 		final SftpObjectDB c = new SftpObjectDB(uri.getPath());
@@ -145,6 +149,7 @@ public FetchConnection openFetch() throws TransportException {
 		return r;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public PushConnection openPush() throws TransportException {
 		final SftpObjectDB c = new SftpObjectDB(uri.getPath());
@@ -192,7 +197,7 @@ class SftpObjectDB extends WalkRemoteObjectDatabase {
 			}
 		}
 
-		SftpObjectDB(final SftpObjectDB parent, final String p)
+		SftpObjectDB(SftpObjectDB parent, String p)
 				throws TransportException {
 			try {
 				ftp = newSftp();
@@ -224,7 +229,7 @@ Collection<WalkRemoteObjectDatabase> getAlternates() throws IOException {
 		}
 
 		@Override
-		WalkRemoteObjectDatabase openAlternate(final String location)
+		WalkRemoteObjectDatabase openAlternate(String location)
 				throws IOException {
 			return new SftpObjectDB(this, location);
 		}
@@ -241,9 +246,9 @@ Collection<String> getPackNames() throws IOException {
 				files = new HashMap<>();
 				mtimes = new HashMap<>();
 
-				for (final ChannelSftp.LsEntry ent : list)
+				for (ChannelSftp.LsEntry ent : list)
 					files.put(ent.getFilename(), ent);
-				for (final ChannelSftp.LsEntry ent : list) {
+				for (ChannelSftp.LsEntry ent : list) {
 					final String n = ent.getFilename();
 					if (!n.startsWith("pack-") || !n.endsWith(".pack")) //$NON-NLS-1$ //$NON-NLS-2$
 						continue;
@@ -258,7 +263,7 @@ Collection<String> getPackNames() throws IOException {
 
 				Collections.sort(packs, new Comparator<String>() {
 					@Override
-					public int compare(final String o1, final String o2) {
+					public int compare(String o1, String o2) {
 						return mtimes.get(o2).intValue()
 								- mtimes.get(o1).intValue();
 					}
@@ -273,7 +278,7 @@ public int compare(final String o1, final String o2) {
 		}
 
 		@Override
-		FileStream open(final String path) throws IOException {
+		FileStream open(String path) throws IOException {
 			try {
 				final SftpATTRS a = ftp.lstat(path);
 				return new FileStream(ftp.get(path), a.getSize());
@@ -287,7 +292,7 @@ FileStream open(final String path) throws IOException {
 		}
 
 		@Override
-		void deleteFile(final String path) throws IOException {
+		void deleteFile(String path) throws IOException {
 			try {
 				ftp.rm(path);
 			} catch (SftpException je) {
@@ -340,8 +345,8 @@ OutputStream writeFile(final String path,
 		}
 
 		@Override
-		void writeFile(final String path, final byte[] data) throws IOException {
-			final String lock = path + ".lock"; //$NON-NLS-1$
+		void writeFile(String path, byte[] data) throws IOException {
+			final String lock = path + LOCK_SUFFIX;
 			try {
 				super.writeFile(lock, data);
 				try {
@@ -408,7 +413,7 @@ private void readLooseRefs(final TreeMap<String, Ref> avail,
 						je.getMessage()), je);
 			}
 
-			for (final ChannelSftp.LsEntry ent : list) {
+			for (ChannelSftp.LsEntry ent : list) {
 				final String n = ent.getFilename();
 				if (".".equals(n) || "..".equals(n)) //$NON-NLS-1$ //$NON-NLS-2$
 					continue;
@@ -424,13 +429,8 @@ private void readLooseRefs(final TreeMap<String, Ref> avail,
 		private Ref readRef(final TreeMap<String, Ref> avail,
 				final String path, final String name) throws TransportException {
 			final String line;
-			try {
-				final BufferedReader br = openReader(path);
-				try {
-					line = br.readLine();
-				} finally {
-					br.close();
-				}
+			try (BufferedReader br = openReader(path)) {
+				line = br.readLine();
 			} catch (FileNotFoundException noRef) {
 				return null;
 			} catch (IOException err) {
@@ -466,7 +466,7 @@ private Ref readRef(final TreeMap<String, Ref> avail,
 					MessageFormat.format(JGitText.get().badRef, name, line));
 		}
 
-		private Storage loose(final Ref r) {
+		private Storage loose(Ref r) {
 			if (r != null && r.getStorage() == Storage.PACKED)
 				return Storage.LOOSE_PACKED;
 			return Storage.LOOSE;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/URIish.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/URIish.java
index ffd4d41..026fd81 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/URIish.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/URIish.java
@@ -95,7 +95,7 @@ public class URIish implements Serializable {
 	 * Part of a pattern which matches the optional port part of URIs. Defines
 	 * one capturing group containing the port without the preceding colon.
 	 */
-	private static final String OPT_PORT_P = "(?::(\\d+))?"; //$NON-NLS-1$
+	private static final String OPT_PORT_P = "(?::(\\d*))?"; //$NON-NLS-1$
 
 	/**
 	 * Part of a pattern which matches the ~username part (e.g. /~root in
@@ -200,10 +200,12 @@ public class URIish implements Serializable {
 	private String host;
 
 	/**
-	 * Parse and construct an {@link URIish} from a string
+	 * Parse and construct an {@link org.eclipse.jgit.transport.URIish} from a
+	 * string
 	 *
 	 * @param s
-	 * @throws URISyntaxException
+	 *            a {@link java.lang.String} object.
+	 * @throws java.net.URISyntaxException
 	 */
 	public URIish(String s) throws URISyntaxException {
 		if (StringUtils.isEmptyOrNull(s)) {
@@ -222,11 +224,23 @@ public URIish(String s) throws URISyntaxException {
 			scheme = matcher.group(1);
 			user = unescape(matcher.group(2));
 			pass = unescape(matcher.group(3));
-			host = unescape(matcher.group(4));
-			if (matcher.group(5) != null)
-				port = Integer.parseInt(matcher.group(5));
-			rawPath = cleanLeadingSlashes(
-					n2e(matcher.group(6)) + n2e(matcher.group(7)), scheme);
+			// empty ports are in general allowed, except for URLs like
+			// file://D:/path for which it is more desirable to parse with
+			// host=null and path=D:/path
+			String portString = matcher.group(5);
+			if ("file".equals(scheme) && "".equals(portString)) { //$NON-NLS-1$ //$NON-NLS-2$
+				rawPath = cleanLeadingSlashes(
+						n2e(matcher.group(4)) + ":" + portString //$NON-NLS-1$
+								+ n2e(matcher.group(6)) + n2e(matcher.group(7)),
+						scheme);
+			} else {
+				host = unescape(matcher.group(4));
+				if (portString != null && portString.length() > 0) {
+					port = Integer.parseInt(portString);
+				}
+				rawPath = cleanLeadingSlashes(
+						n2e(matcher.group(6)) + n2e(matcher.group(7)), scheme);
+			}
 			path = unescape(rawPath);
 			return;
 		}
@@ -373,7 +387,7 @@ else if (s != null && p.length() >= 2 && p.charAt(0) == '/'
 	 * @param u
 	 *            the source URL to convert from.
 	 */
-	public URIish(final URL u) {
+	public URIish(URL u) {
 		scheme = u.getProtocol();
 		path = u.getPath();
 		path = cleanLeadingSlashes(path, scheme);
@@ -395,12 +409,14 @@ public URIish(final URL u) {
 		host = u.getHost();
 	}
 
-	/** Create an empty, non-configured URI. */
+	/**
+	 * Create an empty, non-configured URI.
+	 */
 	public URIish() {
 		// Configure nothing.
 	}
 
-	private URIish(final URIish u) {
+	private URIish(URIish u) {
 		this.scheme = u.scheme;
 		this.rawPath = u.rawPath;
 		this.path = u.path;
@@ -411,6 +427,8 @@ private URIish(final URIish u) {
 	}
 
 	/**
+	 * Whether this URI references a repository on another system.
+	 *
 	 * @return true if this URI references a repository on another system.
 	 */
 	public boolean isRemote() {
@@ -418,6 +436,8 @@ public boolean isRemote() {
 	}
 
 	/**
+	 * Get host name part.
+	 *
 	 * @return host name part or null
 	 */
 	public String getHost() {
@@ -431,13 +451,15 @@ public String getHost() {
 	 *            the new value for host.
 	 * @return a new URI with the updated value.
 	 */
-	public URIish setHost(final String n) {
+	public URIish setHost(String n) {
 		final URIish r = new URIish(this);
 		r.host = n;
 		return r;
 	}
 
 	/**
+	 * Get protocol name
+	 *
 	 * @return protocol name or null for local references
 	 */
 	public String getScheme() {
@@ -451,13 +473,15 @@ public String getScheme() {
 	 *            the new value for scheme.
 	 * @return a new URI with the updated value.
 	 */
-	public URIish setScheme(final String n) {
+	public URIish setScheme(String n) {
 		final URIish r = new URIish(this);
 		r.scheme = n;
 		return r;
 	}
 
 	/**
+	 * Get path name component
+	 *
 	 * @return path name component
 	 */
 	public String getPath() {
@@ -465,6 +489,8 @@ public String getPath() {
 	}
 
 	/**
+	 * Get path name component
+	 *
 	 * @return path name component
 	 */
 	public String getRawPath() {
@@ -478,7 +504,7 @@ public String getRawPath() {
 	 *            the new value for path.
 	 * @return a new URI with the updated value.
 	 */
-	public URIish setPath(final String n) {
+	public URIish setPath(String n) {
 		final URIish r = new URIish(this);
 		r.path = n;
 		r.rawPath = n;
@@ -491,9 +517,9 @@ public URIish setPath(final String n) {
 	 * @param n
 	 *            the new value for path.
 	 * @return a new URI with the updated value.
-	 * @throws URISyntaxException
+	 * @throws java.net.URISyntaxException
 	 */
-	public URIish setRawPath(final String n) throws URISyntaxException {
+	public URIish setRawPath(String n) throws URISyntaxException {
 		final URIish r = new URIish(this);
 		r.path = unescape(n);
 		r.rawPath = n;
@@ -501,6 +527,8 @@ public URIish setRawPath(final String n) throws URISyntaxException {
 	}
 
 	/**
+	 * Get user name requested for transfer
+	 *
 	 * @return user name requested for transfer or null
 	 */
 	public String getUser() {
@@ -514,13 +542,15 @@ public String getUser() {
 	 *            the new value for user.
 	 * @return a new URI with the updated value.
 	 */
-	public URIish setUser(final String n) {
+	public URIish setUser(String n) {
 		final URIish r = new URIish(this);
 		r.user = n;
 		return r;
 	}
 
 	/**
+	 * Get password requested for transfer
+	 *
 	 * @return password requested for transfer or null
 	 */
 	public String getPass() {
@@ -534,13 +564,15 @@ public String getPass() {
 	 *            the new value for password.
 	 * @return a new URI with the updated value.
 	 */
-	public URIish setPass(final String n) {
+	public URIish setPass(String n) {
 		final URIish r = new URIish(this);
 		r.pass = n;
 		return r;
 	}
 
 	/**
+	 * Get port number requested for transfer or -1 if not explicit
+	 *
 	 * @return port number requested for transfer or -1 if not explicit
 	 */
 	public int getPort() {
@@ -554,12 +586,13 @@ public int getPort() {
 	 *            the new value for port.
 	 * @return a new URI with the updated value.
 	 */
-	public URIish setPort(final int n) {
+	public URIish setPort(int n) {
 		final URIish r = new URIish(this);
 		r.port = n > 0 ? n : -1;
 		return r;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public int hashCode() {
 		int hc = 0;
@@ -578,8 +611,9 @@ public int hashCode() {
 		return hc;
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	public boolean equals(final Object obj) {
+	public boolean equals(Object obj) {
 		if (!(obj instanceof URIish))
 			return false;
 		final URIish b = (URIish) obj;
@@ -598,7 +632,7 @@ public boolean equals(final Object obj) {
 		return true;
 	}
 
-	private static boolean eq(final String a, final String b) {
+	private static boolean eq(String a, String b) {
 		if (a == b)
 			return true;
 		if (StringUtils.isEmptyOrNull(a) && StringUtils.isEmptyOrNull(b))
@@ -617,12 +651,13 @@ public String toPrivateString() {
 		return format(true, false);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public String toString() {
 		return format(false, false);
 	}
 
-	private String format(final boolean includePassword, boolean escapeNonAscii) {
+	private String format(boolean includePassword, boolean escapeNonAscii) {
 		final StringBuilder r = new StringBuilder();
 		if (getScheme() != null) {
 			r.append(getScheme());
@@ -666,6 +701,8 @@ private String format(final boolean includePassword, boolean escapeNonAscii) {
 	}
 
 	/**
+	 * Get the URI as an ASCII string.
+	 *
 	 * @return the URI as an ASCII string. Password is not included.
 	 */
 	public String toASCIIString() {
@@ -673,6 +710,9 @@ public String toASCIIString() {
 	}
 
 	/**
+	 * Convert the URI including password, formatted with only ASCII characters
+	 * such that it will be valid for use over the network.
+	 *
 	 * @return the URI including password, formatted with only ASCII characters
 	 *         such that it will be valid for use over the network.
 	 */
@@ -713,7 +753,7 @@ public String toPrivateASCIIString() {
 	 *
 	 * @return the "humanish" part of the path. May be an empty string. Never
 	 *         {@code null}.
-	 * @throws IllegalArgumentException
+	 * @throws java.lang.IllegalArgumentException
 	 *             if it's impossible to determine a humanish part, or path is
 	 *             {@code null} or empty
 	 * @see #getPath
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java
index cf070c6..f70ead9 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java
@@ -43,10 +43,15 @@
 
 package org.eclipse.jgit.transport;
 
+import static org.eclipse.jgit.lib.Constants.R_TAGS;
 import static org.eclipse.jgit.lib.RefDatabase.ALL;
+import static org.eclipse.jgit.transport.GitProtocolConstants.COMMAND_FETCH;
+import static org.eclipse.jgit.transport.GitProtocolConstants.COMMAND_LS_REFS;
 import static org.eclipse.jgit.transport.GitProtocolConstants.OPTION_AGENT;
 import static org.eclipse.jgit.transport.GitProtocolConstants.OPTION_ALLOW_REACHABLE_SHA1_IN_WANT;
 import static org.eclipse.jgit.transport.GitProtocolConstants.OPTION_ALLOW_TIP_SHA1_IN_WANT;
+import static org.eclipse.jgit.transport.GitProtocolConstants.OPTION_DEEPEN_RELATIVE;
+import static org.eclipse.jgit.transport.GitProtocolConstants.OPTION_FILTER;
 import static org.eclipse.jgit.transport.GitProtocolConstants.OPTION_INCLUDE_TAG;
 import static org.eclipse.jgit.transport.GitProtocolConstants.OPTION_MULTI_ACK;
 import static org.eclipse.jgit.transport.GitProtocolConstants.OPTION_MULTI_ACK_DETAILED;
@@ -67,24 +72,30 @@
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+
+import org.eclipse.jgit.annotations.Nullable;
 import org.eclipse.jgit.errors.CorruptObjectException;
 import org.eclipse.jgit.errors.IncorrectObjectTypeException;
 import org.eclipse.jgit.errors.MissingObjectException;
 import org.eclipse.jgit.errors.PackProtocolException;
 import org.eclipse.jgit.internal.JGitText;
 import org.eclipse.jgit.internal.storage.pack.PackWriter;
+import org.eclipse.jgit.lib.BitmapIndex;
+import org.eclipse.jgit.lib.BitmapIndex.BitmapBuilder;
 import org.eclipse.jgit.lib.Constants;
 import org.eclipse.jgit.lib.NullProgressMonitor;
 import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.ObjectReader;
 import org.eclipse.jgit.lib.ProgressMonitor;
 import org.eclipse.jgit.lib.Ref;
-import org.eclipse.jgit.lib.RefDatabase;
 import org.eclipse.jgit.lib.Repository;
 import org.eclipse.jgit.revwalk.AsyncRevObjectQueue;
+import org.eclipse.jgit.revwalk.BitmapWalker;
 import org.eclipse.jgit.revwalk.DepthWalk;
 import org.eclipse.jgit.revwalk.ObjectWalk;
 import org.eclipse.jgit.revwalk.RevCommit;
@@ -98,6 +109,7 @@
 import org.eclipse.jgit.storage.pack.PackStatistics;
 import org.eclipse.jgit.transport.GitProtocolConstants.MultiAck;
 import org.eclipse.jgit.transport.RefAdvertiser.PacketLineOutRefAdvertiser;
+import org.eclipse.jgit.transport.TransferConfig.ProtocolVersion;
 import org.eclipse.jgit.util.io.InterruptTimer;
 import org.eclipse.jgit.util.io.NullOutputStream;
 import org.eclipse.jgit.util.io.TimeoutInputStream;
@@ -233,6 +245,12 @@ public Set<String> getOptions() {
 	/** Timer to manage {@link #timeout}. */
 	private InterruptTimer timer;
 
+	/**
+	 * Whether the client requested to use protocol V2 through a side
+	 * channel (such as the Git-Protocol HTTP header).
+	 */
+	private boolean clientRequestedV2;
+
 	private InputStream rawIn;
 
 	private ResponseBufferedOutputStream rawOut;
@@ -274,12 +292,22 @@ public Set<String> getOptions() {
 	/** Shallow commits the client already has. */
 	private final Set<ObjectId> clientShallowCommits = new HashSet<>();
 
-	/** Shallow commits on the client which are now becoming unshallow */
-	private final List<ObjectId> unshallowCommits = new ArrayList<>();
-
 	/** Desired depth from the client on a shallow request. */
 	private int depth;
 
+	/**
+	 * Commit time of the newest objects the client has asked us using
+	 * --shallow-since not to send. Cannot be nonzero if depth is nonzero.
+	 */
+	private int shallowSince;
+
+	/**
+	 * (Possibly short) ref names, ancestors of which the client has asked us
+	 * not to send using --shallow-exclude. Cannot be non-null if depth is
+	 * nonzero.
+	 */
+	private @Nullable List<String> shallowExcludeRefs;
+
 	/** Commit time of the oldest common commit, in seconds. */
 	private int oldestTime;
 
@@ -313,8 +341,7 @@ public Set<String> getOptions() {
 
 	private PackStatistics statistics;
 
-	@SuppressWarnings("deprecation")
-	private UploadPackLogger logger = UploadPackLogger.NULL;
+	private long filterBlobLimit = -1;
 
 	/**
 	 * Create a new pack upload for an open repository.
@@ -322,7 +349,7 @@ public Set<String> getOptions() {
 	 * @param copyFrom
 	 *            the source repository.
 	 */
-	public UploadPack(final Repository copyFrom) {
+	public UploadPack(Repository copyFrom) {
 		db = copyFrom;
 		walk = new RevWalk(db);
 		walk.setRetainBody(false);
@@ -342,12 +369,20 @@ public UploadPack(final Repository copyFrom) {
 		setTransferConfig(null);
 	}
 
-	/** @return the repository this upload is reading from. */
+	/**
+	 * Get the repository this upload is reading from.
+	 *
+	 * @return the repository this upload is reading from.
+	 */
 	public final Repository getRepository() {
 		return db;
 	}
 
-	/** @return the RevWalk instance used by this connection. */
+	/**
+	 * Get the RevWalk instance used by this connection.
+	 *
+	 * @return the RevWalk instance used by this connection.
+	 */
 	public final RevWalk getRevWalk() {
 		return walk;
 	}
@@ -365,14 +400,15 @@ public final Map<String, Ref> getAdvertisedRefs() {
 	/**
 	 * Set the refs advertised by this UploadPack.
 	 * <p>
-	 * Intended to be called from a {@link PreUploadHook}.
+	 * Intended to be called from a
+	 * {@link org.eclipse.jgit.transport.PreUploadHook}.
 	 *
 	 * @param allRefs
 	 *            explicit set of references to claim as advertised by this
-	 *            UploadPack instance. This overrides any references that
-	 *            may exist in the source repository. The map is passed
-	 *            to the configured {@link #getRefFilter()}. If null, assumes
-	 *            all refs were advertised.
+	 *            UploadPack instance. This overrides any references that may
+	 *            exist in the source repository. The map is passed to the
+	 *            configured {@link #getRefFilter()}. If null, assumes all refs
+	 *            were advertised.
 	 */
 	public void setAdvertisedRefs(Map<String, Ref> allRefs) {
 		if (allRefs != null)
@@ -385,7 +421,11 @@ public void setAdvertisedRefs(Map<String, Ref> allRefs) {
 			refs = refFilter.filter(refs);
 	}
 
-	/** @return timeout (in seconds) before aborting an IO operation. */
+	/**
+	 * Get timeout (in seconds) before aborting an IO operation.
+	 *
+	 * @return timeout (in seconds) before aborting an IO operation.
+	 */
 	public int getTimeout() {
 		return timeout;
 	}
@@ -398,11 +438,14 @@ public int getTimeout() {
 	 *            before aborting an IO read or write operation with the
 	 *            connected client.
 	 */
-	public void setTimeout(final int seconds) {
+	public void setTimeout(int seconds) {
 		timeout = seconds;
 	}
 
 	/**
+	 * Whether this class expects a bi-directional pipe opened between the
+	 * client and itself.
+	 *
 	 * @return true if this class expects a bi-directional pipe opened between
 	 *         the client and itself. The default is true.
 	 */
@@ -411,6 +454,9 @@ public boolean isBiDirectionalPipe() {
 	}
 
 	/**
+	 * Set whether this class will assume the socket is a fully bidirectional
+	 * pipe between the two peers
+	 *
 	 * @param twoWay
 	 *            if true, this class will assume the socket is a fully
 	 *            bidirectional pipe between the two peers and takes advantage
@@ -419,13 +465,15 @@ public boolean isBiDirectionalPipe() {
 	 *            commands before writing output and does not perform the
 	 *            initial advertising.
 	 */
-	public void setBiDirectionalPipe(final boolean twoWay) {
+	public void setBiDirectionalPipe(boolean twoWay) {
 		biDirectionalPipe = twoWay;
 	}
 
 	/**
-	 * @return policy used by the service to validate client requests, or null for
-	 *         a custom request validator.
+	 * Get policy used by the service to validate client requests
+	 *
+	 * @return policy used by the service to validate client requests, or null
+	 *         for a custom request validator.
 	 */
 	public RequestPolicy getRequestPolicy() {
 		if (requestValidator instanceof AdvertisedRequestValidator)
@@ -442,15 +490,21 @@ public RequestPolicy getRequestPolicy() {
 	}
 
 	/**
+	 * Set the policy used to enforce validation of a client's want list.
+	 *
 	 * @param policy
 	 *            the policy used to enforce validation of a client's want list.
-	 *            By default the policy is {@link RequestPolicy#ADVERTISED},
+	 *            By default the policy is
+	 *            {@link org.eclipse.jgit.transport.UploadPack.RequestPolicy#ADVERTISED},
 	 *            which is the Git default requiring clients to only ask for an
-	 *            object that a reference directly points to. This may be relaxed
-	 *            to {@link RequestPolicy#REACHABLE_COMMIT} or
-	 *            {@link RequestPolicy#REACHABLE_COMMIT_TIP} when callers have
-	 *            {@link #setBiDirectionalPipe(boolean)} set to false.
-	 *            Overrides any policy specified in a {@link TransferConfig}.
+	 *            object that a reference directly points to. This may be
+	 *            relaxed to
+	 *            {@link org.eclipse.jgit.transport.UploadPack.RequestPolicy#REACHABLE_COMMIT}
+	 *            or
+	 *            {@link org.eclipse.jgit.transport.UploadPack.RequestPolicy#REACHABLE_COMMIT_TIP}
+	 *            when callers have {@link #setBiDirectionalPipe(boolean)} set
+	 *            to false. Overrides any policy specified in a
+	 *            {@link org.eclipse.jgit.transport.TransferConfig}.
 	 */
 	public void setRequestPolicy(RequestPolicy policy) {
 		switch (policy) {
@@ -474,6 +528,8 @@ public void setRequestPolicy(RequestPolicy policy) {
 	}
 
 	/**
+	 * Set custom validator for client want list.
+	 *
 	 * @param validator
 	 *            custom validator for client want list.
 	 * @since 3.1
@@ -483,12 +539,20 @@ public void setRequestValidator(RequestValidator validator) {
 				: new AdvertisedRequestValidator();
 	}
 
-	/** @return the hook used while advertising the refs to the client */
+	/**
+	 * Get the hook used while advertising the refs to the client.
+	 *
+	 * @return the hook used while advertising the refs to the client.
+	 */
 	public AdvertiseRefsHook getAdvertiseRefsHook() {
 		return advertiseRefsHook;
 	}
 
-	/** @return the filter used while advertising the refs to the client */
+	/**
+	 * Get the filter used while advertising the refs to the client.
+	 *
+	 * @return the filter used while advertising the refs to the client.
+	 */
 	public RefFilter getRefFilter() {
 		return refFilter;
 	}
@@ -496,14 +560,15 @@ public RefFilter getRefFilter() {
 	/**
 	 * Set the hook used while advertising the refs to the client.
 	 * <p>
-	 * If the {@link AdvertiseRefsHook} chooses to call
-	 * {@link #setAdvertisedRefs(Map)}, only refs set by this hook <em>and</em>
-	 * selected by the {@link RefFilter} will be shown to the client.
+	 * If the {@link org.eclipse.jgit.transport.AdvertiseRefsHook} chooses to
+	 * call {@link #setAdvertisedRefs(Map)}, only refs set by this hook
+	 * <em>and</em> selected by the {@link org.eclipse.jgit.transport.RefFilter}
+	 * will be shown to the client.
 	 *
 	 * @param advertiseRefsHook
 	 *            the hook; may be null to show all refs.
 	 */
-	public void setAdvertiseRefsHook(final AdvertiseRefsHook advertiseRefsHook) {
+	public void setAdvertiseRefsHook(AdvertiseRefsHook advertiseRefsHook) {
 		if (advertiseRefsHook != null)
 			this.advertiseRefsHook = advertiseRefsHook;
 		else
@@ -513,19 +578,24 @@ public void setAdvertiseRefsHook(final AdvertiseRefsHook advertiseRefsHook) {
 	/**
 	 * Set the filter used while advertising the refs to the client.
 	 * <p>
-	 * Only refs allowed by this filter will be sent to the client.
-	 * The filter is run against the refs specified by the
-	 * {@link AdvertiseRefsHook} (if applicable). If null or not set, uses the
-	 * filter implied by the {@link TransferConfig}.
+	 * Only refs allowed by this filter will be sent to the client. The filter
+	 * is run against the refs specified by the
+	 * {@link org.eclipse.jgit.transport.AdvertiseRefsHook} (if applicable). If
+	 * null or not set, uses the filter implied by the
+	 * {@link org.eclipse.jgit.transport.TransferConfig}.
 	 *
 	 * @param refFilter
 	 *            the filter; may be null to show all refs.
 	 */
-	public void setRefFilter(final RefFilter refFilter) {
+	public void setRefFilter(RefFilter refFilter) {
 		this.refFilter = refFilter != null ? refFilter : RefFilter.DEFAULT;
 	}
 
-	/** @return the configured pre upload hook. */
+	/**
+	 * Get the configured pre upload hook.
+	 *
+	 * @return the configured pre upload hook.
+	 */
 	public PreUploadHook getPreUploadHook() {
 		return preUploadHook;
 	}
@@ -541,6 +611,8 @@ public void setPreUploadHook(PreUploadHook hook) {
 	}
 
 	/**
+	 * Get the configured post upload hook.
+	 *
 	 * @return the configured post upload hook.
 	 * @since 4.1
 	 */
@@ -571,6 +643,8 @@ public void setPackConfig(PackConfig pc) {
 	}
 
 	/**
+	 * Set configuration controlling transfer options.
+	 *
 	 * @param tc
 	 *            configuration controlling transfer options. If null the source
 	 *            repository's settings will be used.
@@ -588,33 +662,11 @@ public void setTransferConfig(TransferConfig tc) {
 	}
 
 	/**
-	 * @return the configured logger.
-	 *
-	 * @deprecated Use {@link #getPreUploadHook()}.
-	 */
-	@Deprecated
-	public UploadPackLogger getLogger() {
-		return logger;
-	}
-
-	/**
-	 * Set the logger.
-	 *
-	 * @param logger
-	 *            the logger instance. If null, no logging occurs.
-	 * @deprecated Use {@link #setPreUploadHook(PreUploadHook)}.
-	 */
-	@Deprecated
-	public void setLogger(UploadPackLogger logger) {
-		this.logger = logger;
-	}
-
-	/**
 	 * Check whether the client expects a side-band stream.
 	 *
 	 * @return true if the client has advertised a side-band capability, false
 	 *     otherwise.
-	 * @throws RequestNotYetReadException
+	 * @throws org.eclipse.jgit.transport.RequestNotYetReadException
 	 *             if the client's request has not yet been read from the wire, so
 	 *             we do not know if they expect side-band. Note that the client
 	 *             may have already written the request, it just has not been
@@ -628,8 +680,34 @@ public boolean isSideBand() throws RequestNotYetReadException {
 	}
 
 	/**
+	 * Set the Extra Parameters provided by the client.
+	 *
+	 * <p>These are parameters passed by the client through a side channel
+	 * such as the Git-Protocol HTTP header, to allow a client to request
+	 * a newer response format while remaining compatible with older servers
+	 * that do not understand different request formats.
+	 *
+	 * @param params
+	 *            parameters supplied by the client, split at colons or NUL
+	 *            bytes.
+	 * @since 5.0
+	 */
+	public void setExtraParameters(Collection<String> params) {
+		this.clientRequestedV2 = params.contains("version=2"); //$NON-NLS-1$
+	}
+
+	private boolean useProtocolV2() {
+		return ProtocolVersion.V2.equals(transferConfig.protocolVersion)
+				&& clientRequestedV2;
+	}
+
+	/**
 	 * Execute the upload task on the socket.
 	 *
+	 * <p>If the client passed extra parameters (e.g., "version=2") through a
+	 * side channel, the caller must call setExtraParameters first to supply
+	 * them.
+	 *
 	 * @param input
 	 *            raw input to read client commands from. Caller must ensure the
 	 *            input is buffered, otherwise read performance may suffer.
@@ -642,7 +720,7 @@ public boolean isSideBand() throws RequestNotYetReadException {
 	 *            through. When run over SSH this should be tied back to the
 	 *            standard error channel of the command execution. For most
 	 *            other network connections this should be null.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 */
 	public void upload(final InputStream input, OutputStream output,
 			final OutputStream messages) throws IOException {
@@ -670,7 +748,11 @@ public void upload(final InputStream input, OutputStream output,
 
 			pckIn = new PacketLineIn(rawIn);
 			pckOut = new PacketLineOut(rawOut);
-			service();
+			if (useProtocolV2()) {
+				serviceV2();
+			} else {
+				service();
+			}
 		} finally {
 			msgOut = NullOutputStream.INSTANCE;
 			walk.close();
@@ -690,21 +772,6 @@ public void upload(final InputStream input, OutputStream output,
 	 * @return statistics about pack output, if a pack was sent. Null if no pack
 	 *         was sent, such as during the negotiation phase of a smart HTTP
 	 *         connection, or if the client was already up-to-date.
-	 * @since 3.0
-	 * @deprecated Use {@link #getStatistics()}.
-	 */
-	@Deprecated
-	public PackWriter.Statistics getPackStatistics() {
-		return statistics == null ? null
-				: new PackWriter.Statistics(statistics);
-	}
-
-	/**
-	 * Get the PackWriter's statistics if a pack was sent to the client.
-	 *
-	 * @return statistics about pack output, if a pack was sent. Null if no pack
-	 *         was sent, such as during the negotiation phase of a smart HTTP
-	 *         connection, or if the client was already up-to-date.
 	 * @since 4.1
 	 */
 	public PackStatistics getStatistics() {
@@ -713,7 +780,7 @@ public PackStatistics getStatistics() {
 
 	private Map<String, Ref> getAdvertisedOrDefaultRefs() throws IOException {
 		if (refs == null)
-			setAdvertisedRefs(db.getRefDatabase().getRefs(RefDatabase.ALL));
+			setAdvertisedRefs(db.getRefDatabase().getRefs(ALL));
 		return refs;
 	}
 
@@ -721,6 +788,8 @@ private void service() throws IOException {
 		boolean sendPack = false;
 		// If it's a non-bidi request, we need to read the entire request before
 		// writing a response. Buffer the response until then.
+		PackStatistics.Accumulator accumulator = new PackStatistics.Accumulator();
+		List<ObjectId> unshallowCommits = new ArrayList<>();
 		try {
 			if (biDirectionalPipe)
 				sendAdvertisedRefs(new PacketLineOutRefAdvertiser(pckOut));
@@ -729,12 +798,15 @@ else if (requestValidator instanceof AnyRequestValidator)
 			else
 				advertised = refIdSet(getAdvertisedOrDefaultRefs().values());
 
+			long negotiateStart = System.currentTimeMillis();
+			accumulator.advertised = advertised.size();
 			recvWants();
 			if (wantIds.isEmpty()) {
 				preUploadHook.onBeginNegotiateRound(this, wantIds, 0);
 				preUploadHook.onEndNegotiateRound(this, wantIds, 0, 0, false);
 				return;
 			}
+			accumulator.wants = wantIds.size();
 
 			if (options.contains(OPTION_MULTI_ACK_DETAILED)) {
 				multiAck = MultiAck.DETAILED;
@@ -747,10 +819,13 @@ else if (requestValidator instanceof AnyRequestValidator)
 			if (!clientShallowCommits.isEmpty())
 				verifyClientShallow();
 			if (depth != 0)
-				processShallow();
+				processShallow(null, unshallowCommits, true);
 			if (!clientShallowCommits.isEmpty())
 				walk.assumeShallow(clientShallowCommits);
-			sendPack = negotiate();
+			sendPack = negotiate(accumulator);
+			accumulator.timeNegotiating += System.currentTimeMillis()
+					- negotiateStart;
+
 			if (sendPack && !biDirectionalPipe) {
 				// Ensure the request was fully consumed. Any remaining input must
 				// be a protocol error. If we aren't at EOF the implementation is broken.
@@ -796,8 +871,288 @@ else if (requestValidator instanceof AnyRequestValidator)
 			rawOut.stopBuffering();
 		}
 
-		if (sendPack)
-			sendPack();
+		if (sendPack) {
+			sendPack(accumulator, refs == null ? null : refs.values(), unshallowCommits);
+		}
+	}
+
+	private void lsRefsV2() throws IOException {
+		PacketLineOutRefAdvertiser adv = new PacketLineOutRefAdvertiser(pckOut);
+		String line;
+		ArrayList<String> refPrefixes = new ArrayList<>();
+		boolean needToFindSymrefs = false;
+
+		adv.setUseProtocolV2(true);
+
+		line = pckIn.readString();
+
+		// Currently, we do not support any capabilities, so the next
+		// line is DELIM if there are arguments or END if not.
+		if (line == PacketLineIn.DELIM) {
+			while ((line = pckIn.readString()) != PacketLineIn.END) {
+				if (line.equals("peel")) { //$NON-NLS-1$
+					adv.setDerefTags(true);
+				} else if (line.equals("symrefs")) { //$NON-NLS-1$
+					needToFindSymrefs = true;
+				} else if (line.startsWith("ref-prefix ")) { //$NON-NLS-1$
+					refPrefixes.add(line.substring("ref-prefix ".length())); //$NON-NLS-1$
+				} else {
+					throw new PackProtocolException(MessageFormat
+							.format(JGitText.get().unexpectedPacketLine, line));
+				}
+			}
+		} else if (line != PacketLineIn.END) {
+			throw new PackProtocolException(MessageFormat
+					.format(JGitText.get().unexpectedPacketLine, line));
+		}
+		rawOut.stopBuffering();
+
+		Map<String, Ref> refsToSend;
+		if (refPrefixes.isEmpty()) {
+			refsToSend = getAdvertisedOrDefaultRefs();
+		} else {
+			refsToSend = new HashMap<>();
+			for (String refPrefix : refPrefixes) {
+				for (Ref ref : db.getRefDatabase().getRefsByPrefix(refPrefix)) {
+					refsToSend.put(ref.getName(), ref);
+				}
+			}
+		}
+
+		if (needToFindSymrefs) {
+			findSymrefs(adv, refsToSend);
+		}
+
+		adv.send(refsToSend);
+		adv.end();
+	}
+
+	private void fetchV2() throws IOException {
+		options = new HashSet<>();
+
+		// Packs are always sent multiplexed and using full 64K
+		// lengths.
+		options.add(OPTION_SIDE_BAND_64K);
+
+		// Depending on the requestValidator, #processHaveLines may
+		// require that advertised be set. Set it only in the required
+		// circumstances (to avoid a full ref lookup in the case that
+		// we don't need it).
+		if (requestValidator instanceof TipRequestValidator ||
+				requestValidator instanceof ReachableCommitTipRequestValidator ||
+				requestValidator instanceof AnyRequestValidator) {
+			advertised = Collections.emptySet();
+		} else {
+			advertised = refIdSet(getAdvertisedOrDefaultRefs().values());
+		}
+
+		String line;
+		List<ObjectId> peerHas = new ArrayList<>();
+		boolean doneReceived = false;
+
+		// Currently, we do not support any capabilities, so the next
+		// line is DELIM.
+		if ((line = pckIn.readString()) != PacketLineIn.DELIM) {
+			throw new PackProtocolException(MessageFormat
+					.format(JGitText.get().unexpectedPacketLine, line));
+		}
+
+		boolean includeTag = false;
+		boolean filterReceived = false;
+		while ((line = pckIn.readString()) != PacketLineIn.END) {
+			if (line.startsWith("want ")) { //$NON-NLS-1$
+				wantIds.add(ObjectId.fromString(line.substring(5)));
+			} else if (line.startsWith("have ")) { //$NON-NLS-1$
+				peerHas.add(ObjectId.fromString(line.substring(5)));
+			} else if (line.equals("done")) { //$NON-NLS-1$
+				doneReceived = true;
+			} else if (line.equals(OPTION_THIN_PACK)) {
+				options.add(OPTION_THIN_PACK);
+			} else if (line.equals(OPTION_NO_PROGRESS)) {
+				options.add(OPTION_NO_PROGRESS);
+			} else if (line.equals(OPTION_INCLUDE_TAG)) {
+				options.add(OPTION_INCLUDE_TAG);
+				includeTag = true;
+			} else if (line.equals(OPTION_OFS_DELTA)) {
+				options.add(OPTION_OFS_DELTA);
+			} else if (line.startsWith("shallow ")) { //$NON-NLS-1$
+				clientShallowCommits.add(ObjectId.fromString(line.substring(8)));
+			} else if (line.startsWith("deepen ")) { //$NON-NLS-1$
+				depth = Integer.parseInt(line.substring(7));
+				if (depth <= 0) {
+					throw new PackProtocolException(
+							MessageFormat.format(JGitText.get().invalidDepth,
+									Integer.valueOf(depth)));
+				}
+				if (shallowSince != 0) {
+					throw new PackProtocolException(
+							JGitText.get().deepenSinceWithDeepen);
+				}
+				if (shallowExcludeRefs != null) {
+					throw new PackProtocolException(
+							JGitText.get().deepenNotWithDeepen);
+				}
+			} else if (line.startsWith("deepen-not ")) { //$NON-NLS-1$
+				List<String> exclude = shallowExcludeRefs;
+				if (exclude == null) {
+					exclude = shallowExcludeRefs = new ArrayList<>();
+				}
+				exclude.add(line.substring(11));
+				if (depth != 0) {
+					throw new PackProtocolException(
+							JGitText.get().deepenNotWithDeepen);
+				}
+			} else if (line.equals(OPTION_DEEPEN_RELATIVE)) {
+				options.add(OPTION_DEEPEN_RELATIVE);
+			} else if (line.startsWith("deepen-since ")) { //$NON-NLS-1$
+				shallowSince = Integer.parseInt(line.substring(13));
+				if (shallowSince <= 0) {
+					throw new PackProtocolException(
+							MessageFormat.format(
+									JGitText.get().invalidTimestamp, line));
+				}
+				if (depth !=  0) {
+					throw new PackProtocolException(
+							JGitText.get().deepenSinceWithDeepen);
+				}
+			} else if (transferConfig.isAllowFilter()
+					&& line.startsWith(OPTION_FILTER + ' ')) {
+				if (filterReceived) {
+					throw new PackProtocolException(JGitText.get().tooManyFilters);
+				}
+				filterReceived = true;
+				parseFilter(line.substring(OPTION_FILTER.length() + 1));
+			} else {
+				throw new PackProtocolException(MessageFormat
+						.format(JGitText.get().unexpectedPacketLine, line));
+			}
+		}
+		rawOut.stopBuffering();
+
+		boolean sectionSent = false;
+		@Nullable List<ObjectId> shallowCommits = null;
+		List<ObjectId> unshallowCommits = new ArrayList<>();
+
+		if (!clientShallowCommits.isEmpty()) {
+			verifyClientShallow();
+		}
+		if (depth != 0 || shallowSince != 0 || shallowExcludeRefs != null) {
+			shallowCommits = new ArrayList<ObjectId>();
+			processShallow(shallowCommits, unshallowCommits, false);
+		}
+		if (!clientShallowCommits.isEmpty())
+			walk.assumeShallow(clientShallowCommits);
+
+		if (doneReceived) {
+			processHaveLines(peerHas, ObjectId.zeroId(), new PacketLineOut(NullOutputStream.INSTANCE));
+		} else {
+			pckOut.writeString("acknowledgments\n"); //$NON-NLS-1$
+			for (ObjectId id : peerHas) {
+				if (walk.getObjectReader().has(id)) {
+					pckOut.writeString("ACK " + id.getName() + "\n"); //$NON-NLS-1$ //$NON-NLS-2$
+				}
+			}
+			processHaveLines(peerHas, ObjectId.zeroId(), new PacketLineOut(NullOutputStream.INSTANCE));
+			if (okToGiveUp()) {
+				pckOut.writeString("ready\n"); //$NON-NLS-1$
+			} else if (commonBase.isEmpty()) {
+				pckOut.writeString("NAK\n"); //$NON-NLS-1$
+			}
+			sectionSent = true;
+		}
+
+		if (doneReceived || okToGiveUp()) {
+			if (shallowCommits != null) {
+				if (sectionSent)
+					pckOut.writeDelim();
+				pckOut.writeString("shallow-info\n"); //$NON-NLS-1$
+				for (ObjectId o : shallowCommits) {
+					pckOut.writeString("shallow " + o.getName() + '\n'); //$NON-NLS-1$
+				}
+				for (ObjectId o : unshallowCommits) {
+					pckOut.writeString("unshallow " + o.getName() + '\n'); //$NON-NLS-1$
+				}
+				sectionSent = true;
+			}
+
+			if (sectionSent)
+				pckOut.writeDelim();
+			pckOut.writeString("packfile\n"); //$NON-NLS-1$
+			sendPack(new PackStatistics.Accumulator(),
+					includeTag
+						? db.getRefDatabase().getRefsByPrefix(R_TAGS)
+						: null,
+					new ArrayList<ObjectId>());
+		}
+		pckOut.end();
+	}
+
+	/*
+	 * Returns true if this is the last command and we should tear down the
+	 * connection.
+	 */
+	private boolean serveOneCommandV2() throws IOException {
+		String command;
+		try {
+			command = pckIn.readString();
+		} catch (EOFException eof) {
+			/* EOF when awaiting command is fine */
+			return true;
+		}
+		if (command == PacketLineIn.END) {
+			// A blank request is valid according
+			// to the protocol; do nothing in this
+			// case.
+			return true;
+		}
+		if (command.equals("command=" + COMMAND_LS_REFS)) { //$NON-NLS-1$
+			lsRefsV2();
+			return false;
+		}
+		if (command.equals("command=" + COMMAND_FETCH)) { //$NON-NLS-1$
+			fetchV2();
+			return false;
+		}
+		throw new PackProtocolException(MessageFormat
+				.format(JGitText.get().unknownTransportCommand, command));
+	}
+
+	private List<String> getV2CapabilityAdvertisement() {
+		ArrayList<String> caps = new ArrayList<>();
+		caps.add("version 2"); //$NON-NLS-1$
+		caps.add(COMMAND_LS_REFS);
+		caps.add(
+				COMMAND_FETCH + '=' +
+				(transferConfig.isAllowFilter() ? OPTION_FILTER + ' ' : "") + //$NON-NLS-1$
+				OPTION_SHALLOW);
+		return caps;
+	}
+
+	private void serviceV2() throws IOException {
+		if (biDirectionalPipe) {
+			// Just like in service(), the capability advertisement
+			// is sent only if this is a bidirectional pipe. (If
+			// not, the client is expected to call
+			// sendAdvertisedRefs() on its own.)
+			for (String s : getV2CapabilityAdvertisement()) {
+				pckOut.writeString(s + "\n"); //$NON-NLS-1$
+			}
+			pckOut.end();
+
+			while (!serveOneCommandV2()) {
+				// Repeat until an empty command or EOF.
+			}
+			return;
+		}
+
+		try {
+			serveOneCommandV2();
+		} finally {
+			while (0 < rawIn.skip(2048) || 0 <= rawIn.read()) {
+				// Discard until EOF.
+			}
+			rawOut.stopBuffering();
+		}
 	}
 
 	private static Set<ObjectId> refIdSet(Collection<Ref> refs) {
@@ -815,7 +1170,23 @@ private static Set<ObjectId> refIdSet(Collection<Ref> refs) {
 		return ids;
 	}
 
-	private void processShallow() throws IOException {
+	/*
+	 * Determines what "shallow" and "unshallow" lines to send to the user.
+	 * The information is written to shallowCommits (if not null) and
+	 * unshallowCommits, and also written to #pckOut (if writeToPckOut is
+	 * true).
+	 */
+	private void processShallow(@Nullable List<ObjectId> shallowCommits,
+			List<ObjectId> unshallowCommits,
+			boolean writeToPckOut) throws IOException {
+		if (options.contains(OPTION_DEEPEN_RELATIVE) ||
+				shallowSince != 0 ||
+				shallowExcludeRefs != null) {
+			// TODO(jonathantanmy): Implement deepen-relative, deepen-since,
+			// and deepen-not.
+			throw new UnsupportedOperationException();
+		}
+
 		int walkDepth = depth - 1;
 		try (DepthWalk.RevWalk depthWalk = new DepthWalk.RevWalk(
 				walk.getObjectReader(), walkDepth)) {
@@ -836,19 +1207,29 @@ private void processShallow() throws IOException {
 				// Commits at the boundary which aren't already shallow in
 				// the client need to be marked as such
 				if (c.getDepth() == walkDepth
-						&& !clientShallowCommits.contains(c))
-					pckOut.writeString("shallow " + o.name()); //$NON-NLS-1$
+						&& !clientShallowCommits.contains(c)) {
+					if (shallowCommits != null) {
+						shallowCommits.add(c.copy());
+					}
+					if (writeToPckOut) {
+						pckOut.writeString("shallow " + o.name()); //$NON-NLS-1$
+					}
+				}
 
 				// Commits not on the boundary which are shallow in the client
 				// need to become unshallowed
 				if (c.getDepth() < walkDepth
 						&& clientShallowCommits.remove(c)) {
 					unshallowCommits.add(c.copy());
-					pckOut.writeString("unshallow " + c.name()); //$NON-NLS-1$
+					if (writeToPckOut) {
+						pckOut.writeString("unshallow " + c.name()); //$NON-NLS-1$
+					}
 				}
 			}
 		}
-		pckOut.end();
+		if (writeToPckOut) {
+			pckOut.end();
+		}
 	}
 
 	private void verifyClientShallow()
@@ -885,13 +1266,45 @@ private void verifyClientShallow()
 	 *
 	 * @param adv
 	 *            the advertisement formatter.
-	 * @throws IOException
-	 *             the formatter failed to write an advertisement.
-	 * @throws ServiceMayNotContinueException
-	 *             the hook denied advertisement.
+	 * @throws java.io.IOException
+	 *            the formatter failed to write an advertisement.
+	 * @throws org.eclipse.jgit.transport.ServiceMayNotContinueException
+	 *            the hook denied advertisement.
 	 */
-	public void sendAdvertisedRefs(final RefAdvertiser adv) throws IOException,
+	public void sendAdvertisedRefs(RefAdvertiser adv) throws IOException,
 			ServiceMayNotContinueException {
+		sendAdvertisedRefs(adv, null);
+	}
+
+	/**
+	 * Generate an advertisement of available refs and capabilities.
+	 *
+	 * @param adv
+	 *            the advertisement formatter.
+	 * @param serviceName
+	 *            if not null, also output "# service=serviceName" followed by a
+	 *            flush packet before the advertisement. This is required
+	 *            in v0 of the HTTP protocol, described in Git's
+	 *            Documentation/technical/http-protocol.txt.
+	 * @throws java.io.IOException
+	 *            the formatter failed to write an advertisement.
+	 * @throws org.eclipse.jgit.transport.ServiceMayNotContinueException
+	 *            the hook denied advertisement.
+	 * @since 5.0
+	 */
+	public void sendAdvertisedRefs(RefAdvertiser adv,
+			@Nullable String serviceName) throws IOException,
+			ServiceMayNotContinueException {
+		if (useProtocolV2()) {
+			// The equivalent in v2 is only the capabilities
+			// advertisement.
+			for (String s : getV2CapabilityAdvertisement()) {
+				adv.writeOne(s);
+			}
+			adv.end();
+			return;
+		}
+
 		try {
 			advertiseRefsHook.advertiseRefs(this);
 		} catch (ServiceMayNotContinueException fail) {
@@ -902,6 +1315,10 @@ public void sendAdvertisedRefs(final RefAdvertiser adv) throws IOException,
 			throw fail;
 		}
 
+		if (serviceName != null) {
+			adv.writeOne("# service=" + serviceName + '\n'); //$NON-NLS-1$
+			adv.end();
+		}
 		adv.init(db);
 		adv.advertiseCapability(OPTION_INCLUDE_TAG);
 		adv.advertiseCapability(OPTION_MULTI_ACK_DETAILED);
@@ -924,6 +1341,9 @@ public void sendAdvertisedRefs(final RefAdvertiser adv) throws IOException,
 				|| policy == null)
 			adv.advertiseCapability(OPTION_ALLOW_REACHABLE_SHA1_IN_WANT);
 		adv.advertiseCapability(OPTION_AGENT, UserAgent.get());
+		if (transferConfig.isAllowFilter()) {
+			adv.advertiseCapability(OPTION_FILTER);
+		}
 		adv.setDerefTags(true);
 		Map<String, Ref> advertisedOrDefaultRefs = getAdvertisedOrDefaultRefs();
 		findSymrefs(adv, advertisedOrDefaultRefs);
@@ -953,6 +1373,8 @@ public void sendMessage(String what) {
 	}
 
 	/**
+	 * Get an underlying stream for sending messages to the client
+	 *
 	 * @return an underlying stream for sending messages to the client, or null.
 	 * @since 3.1
 	 */
@@ -960,8 +1382,36 @@ public OutputStream getMessageOutputStream() {
 		return msgOut;
 	}
 
+	private void parseFilter(String arg) throws PackProtocolException {
+		if (arg.equals("blob:none")) { //$NON-NLS-1$
+			filterBlobLimit = 0;
+		} else if (arg.startsWith("blob:limit=")) { //$NON-NLS-1$
+			try {
+				filterBlobLimit = Long.parseLong(
+						arg.substring("blob:limit=".length())); //$NON-NLS-1$
+			} catch (NumberFormatException e) {
+				throw new PackProtocolException(
+						MessageFormat.format(JGitText.get().invalidFilter,
+								arg));
+			}
+		}
+		/*
+		 * We must have (1) either "blob:none" or
+		 * "blob:limit=" set (because we only support
+		 * blob size limits for now), and (2) if the
+		 * latter, then it must be nonnegative. Throw
+		 * if (1) or (2) is not met.
+		 */
+		if (filterBlobLimit < 0) {
+			throw new PackProtocolException(
+					MessageFormat.format(JGitText.get().invalidFilter,
+							arg));
+		}
+	}
+
 	private void recvWants() throws IOException {
 		boolean isFirst = true;
+		boolean filterReceived = false;
 		for (;;) {
 			String line;
 			try {
@@ -990,6 +1440,19 @@ private void recvWants() throws IOException {
 				continue;
 			}
 
+			if (transferConfig.isAllowFilter()
+					&& line.startsWith(OPTION_FILTER + " ")) { //$NON-NLS-1$
+				String arg = line.substring(OPTION_FILTER.length() + 1);
+
+				if (filterReceived) {
+					throw new PackProtocolException(JGitText.get().tooManyFilters);
+				}
+				filterReceived = true;
+
+				parseFilter(arg);
+				continue;
+			}
+
 			if (!line.startsWith("want ") || line.length() < 45) //$NON-NLS-1$
 				throw new PackProtocolException(MessageFormat.format(JGitText.get().expectedGot, "want", line)); //$NON-NLS-1$
 
@@ -1039,7 +1502,8 @@ public String getPeerUserAgent() {
 		return UserAgent.getAgent(options, userAgent);
 	}
 
-	private boolean negotiate() throws IOException {
+	private boolean negotiate(PackStatistics.Accumulator accumulator)
+			throws IOException {
 		okToGiveUp = Boolean.FALSE;
 
 		ObjectId last = ObjectId.zeroId();
@@ -1060,7 +1524,7 @@ private boolean negotiate() throws IOException {
 			}
 
 			if (line == PacketLineIn.END) {
-				last = processHaveLines(peerHas, last);
+				last = processHaveLines(peerHas, last, pckOut);
 				if (commonBase.isEmpty() || multiAck != MultiAck.OFF)
 					pckOut.writeString("NAK\n"); //$NON-NLS-1$
 				if (noDone && sentReady) {
@@ -1073,9 +1537,9 @@ private boolean negotiate() throws IOException {
 
 			} else if (line.startsWith("have ") && line.length() == 45) { //$NON-NLS-1$
 				peerHas.add(ObjectId.fromString(line.substring(5)));
-
+				accumulator.haves++;
 			} else if (line.equals("done")) { //$NON-NLS-1$
-				last = processHaveLines(peerHas, last);
+				last = processHaveLines(peerHas, last, pckOut);
 
 				if (commonBase.isEmpty())
 					pckOut.writeString("NAK\n"); //$NON-NLS-1$
@@ -1091,7 +1555,7 @@ else if (multiAck != MultiAck.OFF)
 		}
 	}
 
-	private ObjectId processHaveLines(List<ObjectId> peerHas, ObjectId last)
+	private ObjectId processHaveLines(List<ObjectId> peerHas, ObjectId last, PacketLineOut out)
 			throws IOException {
 		preUploadHook.onBeginNegotiateRound(this, wantIds, peerHas.size());
 		if (wantAll.isEmpty() && !wantIds.isEmpty())
@@ -1136,13 +1600,13 @@ private ObjectId processHaveLines(List<ObjectId> peerHas, ObjectId last)
 				switch (multiAck) {
 				case OFF:
 					if (commonBase.size() == 1)
-						pckOut.writeString("ACK " + obj.name() + "\n"); //$NON-NLS-1$ //$NON-NLS-2$
+						out.writeString("ACK " + obj.name() + "\n"); //$NON-NLS-1$ //$NON-NLS-2$
 					break;
 				case CONTINUE:
-					pckOut.writeString("ACK " + obj.name() + " continue\n"); //$NON-NLS-1$ //$NON-NLS-2$
+					out.writeString("ACK " + obj.name() + " continue\n"); //$NON-NLS-1$ //$NON-NLS-2$
 					break;
 				case DETAILED:
-					pckOut.writeString("ACK " + obj.name() + " common\n"); //$NON-NLS-1$ //$NON-NLS-2$
+					out.writeString("ACK " + obj.name() + " common\n"); //$NON-NLS-1$ //$NON-NLS-2$
 					break;
 				}
 			}
@@ -1168,10 +1632,10 @@ private ObjectId processHaveLines(List<ObjectId> peerHas, ObjectId last)
 						case OFF:
 							break;
 						case CONTINUE:
-							pckOut.writeString("ACK " + id.name() + " continue\n"); //$NON-NLS-1$ //$NON-NLS-2$
+							out.writeString("ACK " + id.name() + " continue\n"); //$NON-NLS-1$ //$NON-NLS-2$
 							break;
 						case DETAILED:
-							pckOut.writeString("ACK " + id.name() + " ready\n"); //$NON-NLS-1$ //$NON-NLS-2$
+							out.writeString("ACK " + id.name() + " ready\n"); //$NON-NLS-1$ //$NON-NLS-2$
 							sentReady = true;
 							break;
 						}
@@ -1183,7 +1647,7 @@ private ObjectId processHaveLines(List<ObjectId> peerHas, ObjectId last)
 
 		if (multiAck == MultiAck.DETAILED && !didOkToGiveUp && okToGiveUp()) {
 			ObjectId id = peerHas.get(peerHas.size() - 1);
-			pckOut.writeString("ACK " + id.name() + " ready\n"); //$NON-NLS-1$ //$NON-NLS-2$
+			out.writeString("ACK " + id.name() + " ready\n"); //$NON-NLS-1$ //$NON-NLS-2$
 			sentReady = true;
 		}
 
@@ -1278,7 +1742,7 @@ public void checkWants(UploadPack up, List<ObjectId> wants)
 				new ReachableCommitTipRequestValidator().checkWants(up, wants);
 			else if (!wants.isEmpty()) {
 				Set<ObjectId> refIds =
-					refIdSet(up.getRepository().getRefDatabase().getRefs(ALL).values());
+						refIdSet(up.getRepository().getRefDatabase().getRefs());
 				for (ObjectId obj : wants) {
 					if (!refIds.contains(obj))
 						throw new WantNotValidException(obj);
@@ -1298,7 +1762,7 @@ public static final class ReachableCommitTipRequestValidator
 		public void checkWants(UploadPack up, List<ObjectId> wants)
 				throws PackProtocolException, IOException {
 			checkNotAdvertisedWants(up, wants,
-					refIdSet(up.getRepository().getRefDatabase().getRefs(ALL).values()));
+					refIdSet(up.getRepository().getRefDatabase().getRefs()));
 		}
 	}
 
@@ -1315,6 +1779,18 @@ public void checkWants(UploadPack up, List<ObjectId> wants)
 		}
 	}
 
+	private static void checkNotAdvertisedWantsUsingBitmap(ObjectReader reader,
+			BitmapIndex bitmapIndex, List<ObjectId> notAdvertisedWants,
+			Set<ObjectId> reachableFrom) throws IOException {
+		BitmapWalker bitmapWalker = new BitmapWalker(new ObjectWalk(reader), bitmapIndex, null);
+		BitmapBuilder reachables = bitmapWalker.findObjects(reachableFrom, null, false);
+		for (ObjectId oid : notAdvertisedWants) {
+			if (!reachables.contains(oid)) {
+				throw new WantNotValidException(oid);
+			}
+		}
+	}
+
 	private static void checkNotAdvertisedWants(UploadPack up,
 			List<ObjectId> notAdvertisedWants, Set<ObjectId> reachableFrom)
 			throws MissingObjectException, IncorrectObjectTypeException, IOException {
@@ -1324,13 +1800,28 @@ private static void checkNotAdvertisedWants(UploadPack up,
 		// into an advertised branch it will be marked UNINTERESTING and no commits
 		// return.
 
-		try (RevWalk walk = new RevWalk(up.getRevWalk().getObjectReader())) {
+		ObjectReader reader = up.getRevWalk().getObjectReader();
+		try (RevWalk walk = new RevWalk(reader)) {
 			AsyncRevObjectQueue q = walk.parseAny(notAdvertisedWants, true);
 			try {
 				RevObject obj;
 				while ((obj = q.next()) != null) {
-					if (!(obj instanceof RevCommit))
+					if (!(obj instanceof RevCommit)) {
+						// If unadvertized non-commits are requested, use
+						// bitmaps. If there are no bitmaps, instead of
+						// incurring the expense of a manual walk, reject
+						// the request.
+						BitmapIndex bitmapIndex = reader.getBitmapIndex();
+						if (bitmapIndex != null) {
+							checkNotAdvertisedWantsUsingBitmap(
+									reader,
+									bitmapIndex,
+									notAdvertisedWants,
+									reachableFrom);
+							return;
+						}
 						throw new WantNotValidException(obj);
+					}
 					walk.markStart((RevCommit) obj);
 				}
 			} catch (MissingObjectException notFound) {
@@ -1354,7 +1845,7 @@ private static void checkNotAdvertisedWants(UploadPack up,
 		}
 	}
 
-	private void addCommonBase(final RevObject o) {
+	private void addCommonBase(RevObject o) {
 		if (!o.has(COMMON)) {
 			o.add(COMMON);
 			commonBase.add(o);
@@ -1383,7 +1874,7 @@ private boolean okToGiveUpImp() throws PackProtocolException {
 		}
 	}
 
-	private boolean wantSatisfied(final RevObject want) throws IOException {
+	private boolean wantSatisfied(RevObject want) throws IOException {
 		if (want.has(SATISFIED))
 			return true;
 
@@ -1404,12 +1895,29 @@ private boolean wantSatisfied(final RevObject want) throws IOException {
 		return false;
 	}
 
-	private void sendPack() throws IOException {
+	/**
+	 * Send the requested objects to the client.
+	 *
+	 * @param accumulator
+	 *                where to write statistics about the content of the pack.
+	 * @param allTags
+	 *                refs to search for annotated tags to include in the pack
+	 *                if the {@link #OPTION_INCLUDE_TAG} capability was
+	 *                requested.
+	 * @param unshallowCommits
+	 *                shallow commits on the client that are now becoming
+	 *                unshallow
+	 * @throws IOException
+	 *                if an error occured while generating or writing the pack.
+	 */
+	private void sendPack(PackStatistics.Accumulator accumulator,
+			@Nullable Collection<Ref> allTags,
+			List<ObjectId> unshallowCommits) throws IOException {
 		final boolean sideband = options.contains(OPTION_SIDE_BAND)
 				|| options.contains(OPTION_SIDE_BAND_64K);
 		if (sideband) {
 			try {
-				sendPack(true);
+				sendPack(true, accumulator, allTags, unshallowCommits);
 			} catch (ServiceMayNotContinueException noPack) {
 				// This was already reported on (below).
 				throw noPack;
@@ -1430,7 +1938,7 @@ private void sendPack() throws IOException {
 					throw err;
 			}
 		} else {
-			sendPack(false);
+			sendPack(false, accumulator, allTags, unshallowCommits);
 		}
 	}
 
@@ -1450,8 +1958,28 @@ private boolean reportInternalServerErrorOverSideband() {
 		}
 	}
 
-	@SuppressWarnings("deprecation")
-	private void sendPack(final boolean sideband) throws IOException {
+	/**
+	 * Send the requested objects to the client.
+	 *
+	 * @param sideband
+	 *                whether to wrap the pack in side-band pkt-lines,
+	 *                interleaved with progress messages and errors.
+	 * @param accumulator
+	 *                where to write statistics about the content of the pack.
+	 * @param allTags
+	 *                refs to search for annotated tags to include in the pack
+	 *                if the {@link #OPTION_INCLUDE_TAG} capability was
+	 *                requested.
+	 * @param unshallowCommits
+	 *                shallow commits on the client that are now becoming
+	 *                unshallow
+	 * @throws IOException
+	 *                if an error occured while generating or writing the pack.
+	 */
+	private void sendPack(final boolean sideband,
+			PackStatistics.Accumulator accumulator,
+			@Nullable Collection<Ref> allTags,
+			List<ObjectId> unshallowCommits) throws IOException {
 		ProgressMonitor pm = NullProgressMonitor.INSTANCE;
 		OutputStream packOut = rawOut;
 
@@ -1492,10 +2020,18 @@ private void sendPack(final boolean sideband) throws IOException {
 		PackConfig cfg = packConfig;
 		if (cfg == null)
 			cfg = new PackConfig(db);
-		final PackWriter pw = new PackWriter(cfg, walk.getObjectReader());
+		@SuppressWarnings("resource") // PackWriter is referenced in the finally
+										// block, and is closed there
+		final PackWriter pw = new PackWriter(cfg, walk.getObjectReader(),
+				accumulator);
 		try {
 			pw.setIndexDisabled(true);
-			pw.setUseCachedPacks(true);
+			if (filterBlobLimit >= 0) {
+				pw.setFilterBlobLimit(filterBlobLimit);
+				pw.setUseCachedPacks(false);
+			} else {
+				pw.setUseCachedPacks(true);
+			}
 			pw.setUseBitmaps(depth == 0 && clientShallowCommits.isEmpty());
 			pw.setClientShallowCommits(clientShallowCommits);
 			pw.setReuseDeltaCommits(true);
@@ -1503,6 +2039,8 @@ private void sendPack(final boolean sideband) throws IOException {
 			pw.setThin(options.contains(OPTION_THIN_PACK));
 			pw.setReuseValidatingObjects(false);
 
+			// Objects named directly by references go at the beginning
+			// of the pack.
 			if (commonBase.isEmpty() && refs != null) {
 				Set<ObjectId> tagTargets = new HashSet<>();
 				for (Ref ref : refs.values()) {
@@ -1533,9 +2071,13 @@ else if (ref.getName().startsWith(Constants.R_HEADS))
 				rw = ow;
 			}
 
-			if (options.contains(OPTION_INCLUDE_TAG) && refs != null) {
-				for (Ref ref : refs.values()) {
+			if (options.contains(OPTION_INCLUDE_TAG) && allTags != null) {
+				for (Ref ref : allTags) {
 					ObjectId objectId = ref.getObjectId();
+					if (objectId == null) {
+						// skip unborn branch
+						continue;
+					}
 
 					// If the object was already requested, skip it.
 					if (wantAll.isEmpty()) {
@@ -1548,15 +2090,16 @@ else if (ref.getName().startsWith(Constants.R_HEADS))
 					}
 
 					if (!ref.isPeeled())
-						ref = db.peel(ref);
+						ref = db.getRefDatabase().peel(ref);
 
 					ObjectId peeledId = ref.getPeeledObjectId();
-					if (peeledId == null)
+					objectId = ref.getObjectId();
+					if (peeledId == null || objectId == null)
 						continue;
 
-					objectId = ref.getObjectId();
-					if (pw.willInclude(peeledId) && !pw.willInclude(objectId))
+					if (pw.willInclude(peeledId) && !pw.willInclude(objectId)) {
 						pw.addObject(rw.parseAny(objectId));
+					}
 				}
 			}
 
@@ -1572,7 +2115,6 @@ else if (ref.getName().startsWith(Constants.R_HEADS))
 			statistics = pw.getStatistics();
 			if (statistics != null) {
 				postUploadHook.onPostUpload(statistics);
-				logger.onPackStatistics(new PackWriter.Statistics(statistics));
 			}
 			pw.close();
 		}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPackInternalServerErrorException.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPackInternalServerErrorException.java
index acdfe04..1813521 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPackInternalServerErrorException.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPackInternalServerErrorException.java
@@ -45,7 +45,9 @@
 
 import java.io.IOException;
 
-/** UploadPack has already reported an error to the client.*/
+/**
+ * UploadPack has already reported an error to the client.
+ */
 public class UploadPackInternalServerErrorException extends IOException {
 	private static final long serialVersionUID = 1L;
 
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPackLogger.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPackLogger.java
deleted file mode 100644
index afc9965..0000000
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPackLogger.java
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright (C) 2011, Google Inc.
- * and other copyright owners as documented in the project's IP log.
- *
- * This program and the accompanying materials are made available
- * under the terms of the Eclipse Distribution License v1.0 which
- * accompanies this distribution, is reproduced below, and is
- * available at http://www.eclipse.org/org/documents/edl-v10.php
- *
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- * - Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- *
- * - Redistributions in binary form must reproduce the above
- *   copyright notice, this list of conditions and the following
- *   disclaimer in the documentation and/or other materials provided
- *   with the distribution.
- *
- * - Neither the name of the Eclipse Foundation, Inc. nor the
- *   names of its contributors may be used to endorse or promote
- *   products derived from this software without specific prior
- *   written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
- * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
- * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-package org.eclipse.jgit.transport;
-
-import org.eclipse.jgit.internal.storage.pack.PackWriter;
-
-/**
- * Logs activity that occurred within {@link UploadPack}.
- * <p>
- * Implementors of the interface are responsible for associating the current
- * thread to a particular connection, if they need to also include connection
- * information. One method is to use a {@link java.lang.ThreadLocal} to remember
- * the connection information before invoking UploadPack.
- *
- * @deprecated use {@link PostUploadHook} instead
- */
-@Deprecated
-public interface UploadPackLogger { // TODO remove in JGit 5.0
-	/** A simple no-op logger. */
-	public static final UploadPackLogger NULL = new UploadPackLogger() {
-		@Override
-		public void onPackStatistics(PackWriter.Statistics stats) {
-			// Do nothing.
-		}
-	};
-
-	/**
-	 * Notice to the logger after a pack has been sent.
-	 *
-	 * @param stats
-	 *            the statistics after sending a pack to the client.
-	 * @since 3.0
-	 */
-	public void onPackStatistics(PackWriter.Statistics stats);
-}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPackLoggerChain.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPackLoggerChain.java
deleted file mode 100644
index 9a8c12c..0000000
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPackLoggerChain.java
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright (C) 2011, Google Inc.
- * and other copyright owners as documented in the project's IP log.
- *
- * This program and the accompanying materials are made available
- * under the terms of the Eclipse Distribution License v1.0 which
- * accompanies this distribution, is reproduced below, and is
- * available at http://www.eclipse.org/org/documents/edl-v10.php
- *
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- * - Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- *
- * - Redistributions in binary form must reproduce the above
- *   copyright notice, this list of conditions and the following
- *   disclaimer in the documentation and/or other materials provided
- *   with the distribution.
- *
- * - Neither the name of the Eclipse Foundation, Inc. nor the
- *   names of its contributors may be used to endorse or promote
- *   products derived from this software without specific prior
- *   written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
- * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
- * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-package org.eclipse.jgit.transport;
-
-import java.util.List;
-
-import org.eclipse.jgit.internal.storage.pack.PackWriter;
-
-/**
- * UploadPackLogger that delegates to a list of other loggers.
- * <p>
- * loggers are run in the order passed to the constructor.
- *
- * @deprecated Use {@link PostUploadHookChain} instead.
- */
-@Deprecated
-public class UploadPackLoggerChain implements UploadPackLogger {
-	private final UploadPackLogger[] loggers;
-	private final int count;
-
-	/**
-	 * Create a new logger chaining the given loggers together.
-	 *
-	 * @param loggers
-	 *            loggers to execute, in order.
-	 * @return a new logger chain of the given loggers.
-	 */
-	public static UploadPackLogger newChain(
-			List<? extends UploadPackLogger> loggers) {
-		UploadPackLogger[] newLoggers = new UploadPackLogger[loggers.size()];
-		int i = 0;
-		for (UploadPackLogger logger : loggers)
-			if (logger != UploadPackLogger.NULL)
-				newLoggers[i++] = logger;
-		if (i == 0)
-			return UploadPackLogger.NULL;
-		else if (i == 1)
-			return newLoggers[0];
-		else
-			return new UploadPackLoggerChain(newLoggers, i);
-	}
-
-	/**
-	 * @since 3.0
-	 */
-	@Override
-	public void onPackStatistics(PackWriter.Statistics stats) {
-		for (int i = 0; i < count; i++)
-			loggers[i].onPackStatistics(stats);
-	}
-
-	private UploadPackLoggerChain(UploadPackLogger[] loggers, int count) {
-		this.loggers = loggers;
-		this.count = count;
-	}
-}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/UsernamePasswordCredentialsProvider.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/UsernamePasswordCredentialsProvider.java
index 6caa5aa..4445c3d 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/UsernamePasswordCredentialsProvider.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/UsernamePasswordCredentialsProvider.java
@@ -48,7 +48,8 @@
 import org.eclipse.jgit.errors.UnsupportedCredentialItem;
 
 /**
- * Simple {@link CredentialsProvider} that always uses the same information.
+ * Simple {@link org.eclipse.jgit.transport.CredentialsProvider} that always
+ * uses the same information.
  */
 public class UsernamePasswordCredentialsProvider extends CredentialsProvider {
 	private String username;
@@ -59,7 +60,9 @@ public class UsernamePasswordCredentialsProvider extends CredentialsProvider {
 	 * Initialize the provider with a single username and password.
 	 *
 	 * @param username
+	 *            user name
 	 * @param password
+	 *            password
 	 */
 	public UsernamePasswordCredentialsProvider(String username, String password) {
 		this(username, password.toCharArray());
@@ -69,18 +72,22 @@ public UsernamePasswordCredentialsProvider(String username, String password) {
 	 * Initialize the provider with a single username and password.
 	 *
 	 * @param username
+	 *            user name
 	 * @param password
+	 *            password
 	 */
 	public UsernamePasswordCredentialsProvider(String username, char[] password) {
 		this.username = username;
 		this.password = password;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public boolean isInteractive() {
 		return false;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public boolean supports(CredentialItem... items) {
 		for (CredentialItem i : items) {
@@ -96,6 +103,7 @@ else if (i instanceof CredentialItem.Password)
 		return true;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public boolean get(URIish uri, CredentialItem... items)
 			throws UnsupportedCredentialItem {
@@ -121,7 +129,9 @@ public boolean get(URIish uri, CredentialItem... items)
 		return true;
 	}
 
-	/** Destroy the saved username and password.. */
+	/**
+	 * Destroy the saved username and password..
+	 */
 	public void clear() {
 		username = null;
 
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/WalkEncryption.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/WalkEncryption.java
index 333e09d..b4248ee 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/WalkEncryption.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/WalkEncryption.java
@@ -95,6 +95,20 @@ abstract class WalkEncryption {
 	// consider permitting mixed ciphers to facilitate algorithm migration
 	// i.e. user keeps the password, but changes the algorithm
 	// then existing remote entries will still be readable
+	/**
+	 * Validate
+	 *
+	 * @param u
+	 *            a {@link java.net.HttpURLConnection} object.
+	 * @param prefix
+	 *            a {@link java.lang.String} object.
+	 * @param version
+	 *            a {@link java.lang.String} object.
+	 * @param name
+	 *            a {@link java.lang.String} object.
+	 * @throws java.io.IOException
+	 *             if any.
+	 */
 	protected void validateImpl(final HttpURLConnection u, final String prefix,
 			final String version, final String name) throws IOException {
 		String v;
@@ -114,11 +128,10 @@ protected void validateImpl(final HttpURLConnection u, final String prefix,
 			throw new IOException(MessageFormat.format(JGitText.get().unsupportedEncryptionAlgorithm, v));
 	}
 
-	IOException error(final Throwable why) {
-		final IOException e;
-		e = new IOException(MessageFormat.format(JGitText.get().encryptionError, why.getMessage()));
-		e.initCause(why);
-		return e;
+	IOException error(Throwable why) {
+		return new IOException(MessageFormat
+				.format(JGitText.get().encryptionError,
+				why.getMessage()), why);
 	}
 
 	private static class NoEncryption extends WalkEncryption {
@@ -128,7 +141,7 @@ void request(HttpURLConnection u, String prefix) {
 		}
 
 		@Override
-		void validate(final HttpURLConnection u, final String prefix)
+		void validate(HttpURLConnection u, String prefix)
 				throws IOException {
 			validateImpl(u, prefix, "", ""); //$NON-NLS-1$ //$NON-NLS-2$
 		}
@@ -227,19 +240,19 @@ static class JetS3tV2 extends WalkEncryption {
 		}
 
 		@Override
-		void request(final HttpURLConnection u, final String prefix) {
+		void request(HttpURLConnection u, String prefix) {
 			u.setRequestProperty(prefix + JETS3T_CRYPTO_VER, CRYPTO_VER);
 			u.setRequestProperty(prefix + JETS3T_CRYPTO_ALG, cryptoAlg);
 		}
 
 		@Override
-		void validate(final HttpURLConnection u, final String prefix)
+		void validate(HttpURLConnection u, String prefix)
 				throws IOException {
 			validateImpl(u, prefix, CRYPTO_VER, cryptoAlg);
 		}
 
 		@Override
-		OutputStream encrypt(final OutputStream os) throws IOException {
+		OutputStream encrypt(OutputStream os) throws IOException {
 			try {
 				final Cipher cipher = InsecureCipherFactory.create(cryptoAlg);
 				cipher.init(Cipher.ENCRYPT_MODE, secretKey, paramSpec);
@@ -250,7 +263,7 @@ OutputStream encrypt(final OutputStream os) throws IOException {
 		}
 
 		@Override
-		InputStream decrypt(final InputStream in) throws IOException {
+		InputStream decrypt(InputStream in) throws IOException {
 			try {
 				final Cipher cipher = InsecureCipherFactory.create(cryptoAlg);
 				cipher.init(Cipher.DECRYPT_MODE, secretKey, paramSpec);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/WalkFetchConnection.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/WalkFetchConnection.java
index 3d60aed..9307914 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/WalkFetchConnection.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/WalkFetchConnection.java
@@ -44,8 +44,6 @@
 
 package org.eclipse.jgit.transport;
 
-import static org.eclipse.jgit.lib.RefDatabase.ALL;
-
 import java.io.File;
 import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
@@ -58,7 +56,6 @@
 import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.List;
-import java.util.Map;
 import java.util.Set;
 
 import org.eclipse.jgit.errors.CompoundException;
@@ -190,7 +187,7 @@ class WalkFetchConnection extends BaseFetchConnection {
 	/** Inserter to read objects from {@link #local}. */
 	private final ObjectReader reader;
 
-	WalkFetchConnection(final WalkTransport t, final WalkRemoteObjectDatabase w) {
+	WalkFetchConnection(WalkTransport t, WalkRemoteObjectDatabase w) {
 		Transport wt = (Transport)t;
 		local = wt.local;
 		objCheck = wt.getObjectChecker();
@@ -223,11 +220,13 @@ class WalkFetchConnection extends BaseFetchConnection {
 		workQueue = new LinkedList<>();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public boolean didFetchTestConnectivity() {
 		return true;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected void doFetch(final ProgressMonitor monitor,
 			final Collection<Ref> want, final Set<ObjectId> have)
@@ -249,32 +248,35 @@ protected void doFetch(final ProgressMonitor monitor,
 		}
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public Collection<PackLock> getPackLocks() {
 		return packLocks;
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	public void setPackLockMessage(final String message) {
+	public void setPackLockMessage(String message) {
 		lockMessage = message;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void close() {
 		inserter.close();
 		reader.close();
-		for (final RemotePack p : unfetchedPacks) {
+		for (RemotePack p : unfetchedPacks) {
 			if (p.tmpIdx != null)
 				p.tmpIdx.delete();
 		}
-		for (final WalkRemoteObjectDatabase r : remotes)
+		for (WalkRemoteObjectDatabase r : remotes)
 			r.close();
 	}
 
-	private void queueWants(final Collection<Ref> want)
+	private void queueWants(Collection<Ref> want)
 			throws TransportException {
 		final HashSet<ObjectId> inWorkQueue = new HashSet<>();
-		for (final Ref r : want) {
+		for (Ref r : want) {
 			final ObjectId id = r.getObjectId();
 			if (id == null) {
 				throw new NullPointerException(MessageFormat.format(
@@ -297,7 +299,7 @@ private void queueWants(final Collection<Ref> want)
 		}
 	}
 
-	private void process(final ObjectId id) throws TransportException {
+	private void process(ObjectId id) throws TransportException {
 		final RevObject obj;
 		try {
 			if (id instanceof RevObject) {
@@ -337,7 +339,7 @@ private void process(final ObjectId id) throws TransportException {
 		fetchErrors.remove(id);
 	}
 
-	private void processBlob(final RevObject obj) throws TransportException {
+	private void processBlob(RevObject obj) throws TransportException {
 		try {
 			if (reader.has(obj, Constants.OBJ_BLOB))
 				obj.add(COMPLETE);
@@ -351,7 +353,7 @@ private void processBlob(final RevObject obj) throws TransportException {
 		}
 	}
 
-	private void processTree(final RevObject obj) throws TransportException {
+	private void processTree(RevObject obj) throws TransportException {
 		try {
 			treeWalk.reset(obj);
 			while (treeWalk.next()) {
@@ -379,22 +381,22 @@ private void processTree(final RevObject obj) throws TransportException {
 		obj.add(COMPLETE);
 	}
 
-	private void processCommit(final RevObject obj) throws TransportException {
+	private void processCommit(RevObject obj) throws TransportException {
 		final RevCommit commit = (RevCommit) obj;
 		markLocalCommitsComplete(commit.getCommitTime());
 		needs(commit.getTree());
-		for (final RevCommit p : commit.getParents())
+		for (RevCommit p : commit.getParents())
 			needs(p);
 		obj.add(COMPLETE);
 	}
 
-	private void processTag(final RevObject obj) {
+	private void processTag(RevObject obj) {
 		final RevTag tag = (RevTag) obj;
 		needs(tag.getObject());
 		obj.add(COMPLETE);
 	}
 
-	private void needs(final RevObject obj) {
+	private void needs(RevObject obj) {
 		if (obj.has(COMPLETE))
 			return;
 		if (!obj.has(IN_WORK_QUEUE)) {
@@ -403,7 +405,7 @@ private void needs(final RevObject obj) {
 		}
 	}
 
-	private void downloadObject(final ProgressMonitor pm, final AnyObjectId id)
+	private void downloadObject(ProgressMonitor pm, AnyObjectId id)
 			throws TransportException {
 		if (alreadyHave(id))
 			return;
@@ -457,7 +459,7 @@ private void downloadObject(final ProgressMonitor pm, final AnyObjectId id)
 
 				if (packNameList == null || packNameList.isEmpty())
 					continue;
-				for (final String packName : packNameList) {
+				for (String packName : packNameList) {
 					if (packsConsidered.add(packName))
 						unfetchedPacks.add(new RemotePack(wrr, packName));
 				}
@@ -469,7 +471,7 @@ private void downloadObject(final ProgressMonitor pm, final AnyObjectId id)
 			//
 			Collection<WalkRemoteObjectDatabase> al = expandOneAlternate(id, pm);
 			if (al != null && !al.isEmpty()) {
-				for (final WalkRemoteObjectDatabase alt : al) {
+				for (WalkRemoteObjectDatabase alt : al) {
 					remotes.add(alt);
 					noPacksYet.add(alt);
 					noAlternatesYet.add(alt);
@@ -493,7 +495,7 @@ private void downloadObject(final ProgressMonitor pm, final AnyObjectId id)
 		}
 	}
 
-	private boolean alreadyHave(final AnyObjectId id) throws TransportException {
+	private boolean alreadyHave(AnyObjectId id) throws TransportException {
 		try {
 			return reader.has(id);
 		} catch (IOException error) {
@@ -684,21 +686,21 @@ private Collection<WalkRemoteObjectDatabase> expandOneAlternate(
 		return null;
 	}
 
-	private void markLocalRefsComplete(final Set<ObjectId> have) throws TransportException {
-		Map<String, Ref> refs;
+	private void markLocalRefsComplete(Set<ObjectId> have) throws TransportException {
+		List<Ref> refs;
 		try {
-			refs = local.getRefDatabase().getRefs(ALL);
+			refs = local.getRefDatabase().getRefs();
 		} catch (IOException e) {
 			throw new TransportException(e.getMessage(), e);
 		}
-		for (final Ref r : refs.values()) {
+		for (Ref r : refs) {
 			try {
 				markLocalObjComplete(revWalk.parseAny(r.getObjectId()));
 			} catch (IOException readError) {
 				throw new TransportException(MessageFormat.format(JGitText.get().localRefIsMissingObjects, r.getName()), readError);
 			}
 		}
-		for (final ObjectId id : have) {
+		for (ObjectId id : have) {
 			try {
 				markLocalObjComplete(revWalk.parseAny(id));
 			} catch (IOException readError) {
@@ -727,7 +729,7 @@ private void markLocalObjComplete(RevObject obj) throws IOException {
 		}
 	}
 
-	private void markLocalCommitsComplete(final int until)
+	private void markLocalCommitsComplete(int until)
 			throws TransportException {
 		try {
 			for (;;) {
@@ -737,7 +739,7 @@ private void markLocalCommitsComplete(final int until)
 				localCommitQueue.next();
 
 				markTreeComplete(c.getTree());
-				for (final RevCommit p : c.getParents())
+				for (RevCommit p : c.getParents())
 					pushLocalCommit(p);
 			}
 		} catch (IOException err) {
@@ -745,7 +747,7 @@ private void markLocalCommitsComplete(final int until)
 		}
 	}
 
-	private void pushLocalCommit(final RevCommit p)
+	private void pushLocalCommit(RevCommit p)
 			throws MissingObjectException, IOException {
 		if (p.has(LOCALLY_SEEN))
 			return;
@@ -756,7 +758,7 @@ private void pushLocalCommit(final RevCommit p)
 		localCommitQueue.add(p);
 	}
 
-	private void markTreeComplete(final RevTree tree) throws IOException {
+	private void markTreeComplete(RevTree tree) throws IOException {
 		if (tree.has(COMPLETE))
 			return;
 		tree.add(COMPLETE);
@@ -790,7 +792,7 @@ private void markTreeComplete(final RevTree tree) throws IOException {
 		}
 	}
 
-	private void recordError(final AnyObjectId id, final Throwable what) {
+	private void recordError(AnyObjectId id, Throwable what) {
 		final ObjectId objId = id.copy();
 		List<Throwable> errors = fetchErrors.get(objId);
 		if (errors == null) {
@@ -811,7 +813,7 @@ private class RemotePack {
 
 		PackIndex index;
 
-		RemotePack(final WalkRemoteObjectDatabase c, final String pn) {
+		RemotePack(WalkRemoteObjectDatabase c, String pn) {
 			connection = c;
 			packName = pn;
 			idxName = packName.substring(0, packName.length() - 5) + ".idx"; //$NON-NLS-1$
@@ -829,7 +831,7 @@ private class RemotePack {
 			}
 		}
 
-		void openIndex(final ProgressMonitor pm) throws IOException {
+		void openIndex(ProgressMonitor pm) throws IOException {
 			if (index != null)
 				return;
 			if (tmpIdx == null)
@@ -848,17 +850,12 @@ else if (tmpIdx.isFile()) {
 			pm.beginTask("Get " + idxName.substring(0, 12) + "..idx", //$NON-NLS-1$ //$NON-NLS-2$
 					s.length < 0 ? ProgressMonitor.UNKNOWN
 							: (int) (s.length / 1024));
-			try {
-				final FileOutputStream fos = new FileOutputStream(tmpIdx);
-				try {
-					final byte[] buf = new byte[2048];
-					int cnt;
-					while (!pm.isCancelled() && (cnt = s.in.read(buf)) >= 0) {
-						fos.write(buf, 0, cnt);
-						pm.update(cnt / 1024);
-					}
-				} finally {
-					fos.close();
+			try (FileOutputStream fos = new FileOutputStream(tmpIdx)) {
+				final byte[] buf = new byte[2048];
+				int cnt;
+				while (!pm.isCancelled() && (cnt = s.in.read(buf)) >= 0) {
+					fos.write(buf, 0, cnt);
+					pm.update(cnt / 1024);
 				}
 			} catch (IOException err) {
 				FileUtils.delete(tmpIdx);
@@ -881,7 +878,7 @@ else if (tmpIdx.isFile()) {
 			}
 		}
 
-		void downloadPack(final ProgressMonitor monitor) throws IOException {
+		void downloadPack(ProgressMonitor monitor) throws IOException {
 			String name = "pack/" + packName; //$NON-NLS-1$
 			WalkRemoteObjectDatabase.FileStream s = connection.open(name);
 			try {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/WalkPushConnection.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/WalkPushConnection.java
index 5c4e14c..4c75425 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/WalkPushConnection.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/WalkPushConnection.java
@@ -134,6 +134,7 @@ class WalkPushConnection extends BaseConnection implements PushConnection {
 		dest = w;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void push(final ProgressMonitor monitor,
 			final Map<String, RemoteRefUpdate> refUpdates)
@@ -141,6 +142,7 @@ public void push(final ProgressMonitor monitor,
 		push(monitor, refUpdates, null);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void push(final ProgressMonitor monitor,
 			final Map<String, RemoteRefUpdate> refUpdates, OutputStream out)
@@ -155,7 +157,7 @@ public void push(final ProgressMonitor monitor,
 		// ref using the directory name being created.
 		//
 		final List<RemoteRefUpdate> updates = new ArrayList<>();
-		for (final RemoteRefUpdate u : refUpdates.values()) {
+		for (RemoteRefUpdate u : refUpdates.values()) {
 			final String n = u.getRemoteName();
 			if (!n.startsWith("refs/") || !Repository.isValidRefName(n)) { //$NON-NLS-1$
 				u.setStatus(Status.REJECTED_OTHER_REASON);
@@ -175,7 +177,7 @@ public void push(final ProgressMonitor monitor,
 		//
 		if (!updates.isEmpty())
 			sendpack(updates, monitor);
-		for (final RemoteRefUpdate u : updates)
+		for (RemoteRefUpdate u : updates)
 			updateCommand(u);
 
 		// Is this a new repository? If so we should create additional
@@ -194,10 +196,10 @@ protected void writeFile(String file, byte[] content)
 		if (!packedRefUpdates.isEmpty()) {
 			try {
 				refWriter.writePackedRefs();
-				for (final RemoteRefUpdate u : packedRefUpdates)
+				for (RemoteRefUpdate u : packedRefUpdates)
 					u.setStatus(Status.OK);
 			} catch (IOException err) {
-				for (final RemoteRefUpdate u : packedRefUpdates) {
+				for (RemoteRefUpdate u : packedRefUpdates) {
 					u.setStatus(Status.REJECTED_OTHER_REASON);
 					u.setMessage(err.getMessage());
 				}
@@ -212,6 +214,7 @@ protected void writeFile(String file, byte[] content)
 		}
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void close() {
 		dest.close();
@@ -222,14 +225,14 @@ private void sendpack(final List<RemoteRefUpdate> updates,
 		String pathPack = null;
 		String pathIdx = null;
 
-		try (final PackWriter writer = new PackWriter(transport.getPackConfig(),
+		try (PackWriter writer = new PackWriter(transport.getPackConfig(),
 				local.newObjectReader())) {
 
 			final Set<ObjectId> need = new HashSet<>();
 			final Set<ObjectId> have = new HashSet<>();
-			for (final RemoteRefUpdate r : updates)
+			for (RemoteRefUpdate r : updates)
 				need.add(r.getNewObjectId());
-			for (final Ref r : getRefs()) {
+			for (Ref r : getRefs()) {
 				have.add(r.getObjectId());
 				if (r.getPeeledObjectId() != null)
 					have.add(r.getPeeledObjectId());
@@ -244,7 +247,7 @@ private void sendpack(final List<RemoteRefUpdate> updates,
 				return;
 
 			packNames = new LinkedHashMap<>();
-			for (final String n : dest.getPackNames())
+			for (String n : dest.getPackNames())
 				packNames.put(n, n);
 
 			final String base = "pack-" + writer.computeName().name(); //$NON-NLS-1$
@@ -292,7 +295,7 @@ private void sendpack(final List<RemoteRefUpdate> updates,
 		}
 	}
 
-	private void safeDelete(final String path) {
+	private void safeDelete(String path) {
 		if (path != null) {
 			try {
 				dest.deleteFile(path);
@@ -304,7 +307,7 @@ private void safeDelete(final String path) {
 		}
 	}
 
-	private void deleteCommand(final RemoteRefUpdate u) {
+	private void deleteCommand(RemoteRefUpdate u) {
 		final Ref r = newRefs.remove(u.getRemoteName());
 		if (r == null) {
 			// Already gone.
@@ -334,7 +337,7 @@ private void deleteCommand(final RemoteRefUpdate u) {
 		}
 	}
 
-	private void updateCommand(final RemoteRefUpdate u) {
+	private void updateCommand(RemoteRefUpdate u) {
 		try {
 			dest.writeRef(u.getRemoteName(), u.getNewObjectId());
 			newRefs.put(u.getRemoteName(), new ObjectIdRef.Unpeeled(
@@ -351,7 +354,7 @@ private boolean isNewRepository() {
 				&& packNames.isEmpty();
 	}
 
-	private void createNewRepository(final List<RemoteRefUpdate> updates)
+	private void createNewRepository(List<RemoteRefUpdate> updates)
 			throws TransportException {
 		try {
 			final String ref = "ref: " + pickHEAD(updates) + "\n"; //$NON-NLS-1$ //$NON-NLS-2$
@@ -371,12 +374,12 @@ private void createNewRepository(final List<RemoteRefUpdate> updates)
 		}
 	}
 
-	private static String pickHEAD(final List<RemoteRefUpdate> updates) {
+	private static String pickHEAD(List<RemoteRefUpdate> updates) {
 		// Try to use master if the user is pushing that, it is the
 		// default branch and is likely what they want to remain as
 		// the default on the new remote.
 		//
-		for (final RemoteRefUpdate u : updates) {
+		for (RemoteRefUpdate u : updates) {
 			final String n = u.getRemoteName();
 			if (n.equals(Constants.R_HEADS + Constants.MASTER))
 				return n;
@@ -385,7 +388,7 @@ private static String pickHEAD(final List<RemoteRefUpdate> updates) {
 		// Pick any branch, under the assumption the user pushed only
 		// one to the remote side.
 		//
-		for (final RemoteRefUpdate u : updates) {
+		for (RemoteRefUpdate u : updates) {
 			final String n = u.getRemoteName();
 			if (n.startsWith(Constants.R_HEADS))
 				return n;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/WalkRemoteObjectDatabase.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/WalkRemoteObjectDatabase.java
index 17f8c3e..aa71c94 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/WalkRemoteObjectDatabase.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/WalkRemoteObjectDatabase.java
@@ -202,7 +202,7 @@ abstract WalkRemoteObjectDatabase openAlternate(String location)
 	 * @throws IOException
 	 *             deletion is not supported, or deletion failed.
 	 */
-	void deleteFile(final String path) throws IOException {
+	void deleteFile(String path) throws IOException {
 		throw new IOException(MessageFormat.format(JGitText.get().deletingNotSupported, path));
 	}
 
@@ -263,12 +263,9 @@ OutputStream writeFile(final String path, final ProgressMonitor monitor,
 	 *             writing is not supported, or attempting to write the file
 	 *             failed, possibly due to permissions or remote disk full, etc.
 	 */
-	void writeFile(final String path, final byte[] data) throws IOException {
-		final OutputStream os = writeFile(path, null, null);
-		try {
+	void writeFile(String path, byte[] data) throws IOException {
+		try (OutputStream os = writeFile(path, null, null)) {
 			os.write(data);
-		} finally {
-			os.close();
 		}
 	}
 
@@ -281,7 +278,7 @@ void writeFile(final String path, final byte[] data) throws IOException {
 	 * @throws IOException
 	 *             deletion is not supported, or deletion failed.
 	 */
-	void deleteRef(final String name) throws IOException {
+	void deleteRef(String name) throws IOException {
 		deleteFile(ROOT_DIR + name);
 	}
 
@@ -294,7 +291,7 @@ void deleteRef(final String name) throws IOException {
 	 * @throws IOException
 	 *             deletion is not supported, or deletion failed.
 	 */
-	void deleteRefLog(final String name) throws IOException {
+	void deleteRefLog(String name) throws IOException {
 		deleteFile(ROOT_DIR + Constants.LOGS + "/" + name); //$NON-NLS-1$
 	}
 
@@ -312,7 +309,7 @@ void deleteRefLog(final String name) throws IOException {
 	 *             writing is not supported, or attempting to write the file
 	 *             failed, possibly due to permissions or remote disk full, etc.
 	 */
-	void writeRef(final String name, final ObjectId value) throws IOException {
+	void writeRef(String name, ObjectId value) throws IOException {
 		final ByteArrayOutputStream b;
 
 		b = new ByteArrayOutputStream(Constants.OBJECT_ID_STRING_LENGTH + 1);
@@ -336,9 +333,9 @@ void writeRef(final String name, final ObjectId value) throws IOException {
 	 *             writing is not supported, or attempting to write the file
 	 *             failed, possibly due to permissions or remote disk full, etc.
 	 */
-	void writeInfoPacks(final Collection<String> packNames) throws IOException {
+	void writeInfoPacks(Collection<String> packNames) throws IOException {
 		final StringBuilder w = new StringBuilder();
-		for (final String n : packNames) {
+		for (String n : packNames) {
 			w.append("P "); //$NON-NLS-1$
 			w.append(n);
 			w.append('\n');
@@ -364,7 +361,7 @@ void writeInfoPacks(final Collection<String> packNames) throws IOException {
 	 *             exists, or after it was determined to exist but before the
 	 *             stream could be created.
 	 */
-	BufferedReader openReader(final String path) throws IOException {
+	BufferedReader openReader(String path) throws IOException {
 		final InputStream is = open(path).in;
 		return new BufferedReader(new InputStreamReader(is, Constants.CHARSET));
 	}
@@ -394,8 +391,7 @@ BufferedReader openReader(final String path) throws IOException {
 	 */
 	Collection<WalkRemoteObjectDatabase> readAlternates(final String listPath)
 			throws IOException {
-		final BufferedReader br = openReader(listPath);
-		try {
+		try (BufferedReader br = openReader(listPath)) {
 			final Collection<WalkRemoteObjectDatabase> alts = new ArrayList<>();
 			for (;;) {
 				String line = br.readLine();
@@ -406,8 +402,6 @@ Collection<WalkRemoteObjectDatabase> readAlternates(final String listPath)
 				alts.add(openAlternate(line));
 			}
 			return alts;
-		} finally {
-			br.close();
 		}
 	}
 
@@ -417,19 +411,13 @@ Collection<WalkRemoteObjectDatabase> readAlternates(final String listPath)
 	 * @param avail
 	 *            return collection of references. Any existing entries will be
 	 *            replaced if they are found in the packed-refs file.
-	 * @throws TransportException
+	 * @throws org.eclipse.jgit.errors.TransportException
 	 *             an error occurred reading from the packed refs file.
 	 */
-	protected void readPackedRefs(final Map<String, Ref> avail)
+	protected void readPackedRefs(Map<String, Ref> avail)
 			throws TransportException {
-		try {
-			final BufferedReader br = openReader(ROOT_DIR
-					+ Constants.PACKED_REFS);
-			try {
-				readPackedRefsImpl(avail, br);
-			} finally {
-				br.close();
-			}
+		try (BufferedReader br = openReader(ROOT_DIR + Constants.PACKED_REFS)) {
+			readPackedRefsImpl(avail, br);
 		} catch (FileNotFoundException notPacked) {
 			// Perhaps it wasn't worthwhile, or is just an older repository.
 		} catch (IOException e) {
@@ -487,7 +475,7 @@ static final class FileStream {
 		 *            stream containing the file data. This stream will be
 		 *            closed by the caller when reading is complete.
 		 */
-		FileStream(final InputStream i) {
+		FileStream(InputStream i) {
 			in = i;
 			length = -1;
 		}
@@ -502,7 +490,7 @@ static final class FileStream {
 		 *            total number of bytes available for reading through
 		 *            <code>i</code>.
 		 */
-		FileStream(final InputStream i, final long n) {
+		FileStream(InputStream i, long n) {
 			in = i;
 			length = n;
 		}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/WalkTransport.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/WalkTransport.java
index f1c4357..8262d00 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/WalkTransport.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/WalkTransport.java
@@ -53,8 +53,9 @@
  * from the loose objects directory, or entire packs if the source side does not
  * have the object as a loose object.
  * <p>
- * WalkTransports are not as efficient as {@link PackTransport} instances, but
- * can be useful in situations where a pack transport is not acceptable.
+ * WalkTransports are not as efficient as
+ * {@link org.eclipse.jgit.transport.PackTransport} instances, but can be useful
+ * in situations where a pack transport is not acceptable.
  *
  * @see WalkFetchConnection
  */
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/WantNotValidException.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/WantNotValidException.java
index f0f6434..601b0d0 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/WantNotValidException.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/WantNotValidException.java
@@ -54,7 +54,7 @@
  * <p>
  * Typically visible only inside of the server implementation; clients are
  * usually looking at the text message from the server in a generic
- * {@link PackProtocolException}.
+ * {@link org.eclipse.jgit.errors.PackProtocolException}.
  *
  * @since 4.3
  */
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/WriteAbortedException.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/WriteAbortedException.java
index 267bf7a..e3987ea 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/WriteAbortedException.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/WriteAbortedException.java
@@ -49,7 +49,7 @@
  * An exception to be thrown when the write operation is aborted.
  * <p>
  * That can be thrown inside
- * {@link ObjectCountCallback#setObjectCount(long)}.
+ * {@link org.eclipse.jgit.transport.ObjectCountCallback#setObjectCount(long)}.
  *
  * @since 4.1
  */
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/http/HttpConnection.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/http/HttpConnection.java
index 35a1ee1..d815bc3 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/http/HttpConnection.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/http/HttpConnection.java
@@ -56,13 +56,12 @@
 
 import javax.net.ssl.HostnameVerifier;
 import javax.net.ssl.KeyManager;
-import javax.net.ssl.SSLContext;
 import javax.net.ssl.TrustManager;
 
 /**
  * The interface of connections used during HTTP communication. This interface
- * is that subset of the interface exposed by {@link HttpURLConnection} which is
- * used by JGit
+ * is that subset of the interface exposed by {@link java.net.HttpURLConnection}
+ * which is used by JGit
  *
  * @since 3.3
  */
@@ -114,32 +113,42 @@ public interface HttpConnection {
 	public static final int HTTP_FORBIDDEN = java.net.HttpURLConnection.HTTP_FORBIDDEN;
 
 	/**
+	 * Get response code
+	 *
 	 * @see HttpURLConnection#getResponseCode()
 	 * @return the HTTP Status-Code, or -1
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 */
 	public int getResponseCode() throws IOException;
 
 	/**
+	 * Get URL
+	 *
 	 * @see HttpURLConnection#getURL()
 	 * @return the URL.
 	 */
 	public URL getURL();
 
 	/**
+	 * Get response message
+	 *
 	 * @see HttpURLConnection#getResponseMessage()
 	 * @return the HTTP response message, or <code>null</code>
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 */
 	public String getResponseMessage() throws IOException;
 
 	/**
+	 * Get list of header fields
+	 *
 	 * @see HttpURLConnection#getHeaderFields()
 	 * @return a Map of header fields
 	 */
 	public Map<String, List<String>> getHeaderFields();
 
 	/**
+	 * Set request property
+	 *
 	 * @see HttpURLConnection#setRequestProperty(String, String)
 	 * @param key
 	 *            the keyword by which the request is known (e.g., "
@@ -150,17 +159,23 @@ public interface HttpConnection {
 	public void setRequestProperty(String key, String value);
 
 	/**
+	 * Set request method
+	 *
 	 * @see HttpURLConnection#setRequestMethod(String)
 	 * @param method
 	 *            the HTTP method
 	 * @exception ProtocolException
 	 *                if the method cannot be reset or if the requested method
 	 *                isn't valid for HTTP.
+	 * @throws java.net.ProtocolException
+	 *             if any.
 	 */
 	public void setRequestMethod(String method)
 			throws ProtocolException;
 
 	/**
+	 * Set if to use caches
+	 *
 	 * @see HttpURLConnection#setUseCaches(boolean)
 	 * @param usecaches
 	 *            a <code>boolean</code> indicating whether or not to allow
@@ -169,6 +184,8 @@ public void setRequestMethod(String method)
 	public void setUseCaches(boolean usecaches);
 
 	/**
+	 * Set connect timeout
+	 *
 	 * @see HttpURLConnection#setConnectTimeout(int)
 	 * @param timeout
 	 *            an <code>int</code> that specifies the connect timeout value
@@ -177,6 +194,8 @@ public void setRequestMethod(String method)
 	public void setConnectTimeout(int timeout);
 
 	/**
+	 * Set read timeout
+	 *
 	 * @see HttpURLConnection#setReadTimeout(int)
 	 * @param timeout
 	 *            an <code>int</code> that specifies the timeout value to be
@@ -185,6 +204,8 @@ public void setRequestMethod(String method)
 	public void setReadTimeout(int timeout);
 
 	/**
+	 * Get content type
+	 *
 	 * @see HttpURLConnection#getContentType()
 	 * @return the content type of the resource that the URL references, or
 	 *         <code>null</code> if not known.
@@ -192,14 +213,20 @@ public void setRequestMethod(String method)
 	public String getContentType();
 
 	/**
+	 * Get input stream
+	 *
 	 * @see HttpURLConnection#getInputStream()
 	 * @return an input stream that reads from this open connection.
 	 * @exception IOException
 	 *                if an I/O error occurs while creating the input stream.
+	 * @throws java.io.IOException
+	 *             if any.
 	 */
 	public InputStream getInputStream() throws IOException;
 
 	/**
+	 * Get header field
+	 *
 	 * @see HttpURLConnection#getHeaderField(String)
 	 * @param name
 	 *            the name of a header field.
@@ -209,6 +236,8 @@ public void setRequestMethod(String method)
 	public String getHeaderField(String name);
 
 	/**
+	 * Get content length
+	 *
 	 * @see HttpURLConnection#getContentLength()
 	 * @return the content length of the resource that this connection's URL
 	 *         references, {@code -1} if the content length is not known, or if
@@ -217,6 +246,8 @@ public void setRequestMethod(String method)
 	public int getContentLength();
 
 	/**
+	 * Set whether or not to follow HTTP redirects.
+	 *
 	 * @see HttpURLConnection#setInstanceFollowRedirects(boolean)
 	 * @param followRedirects
 	 *            a <code>boolean</code> indicating whether or not to follow
@@ -225,27 +256,35 @@ public void setRequestMethod(String method)
 	public void setInstanceFollowRedirects(boolean followRedirects);
 
 	/**
+	 * Set if to do output
+	 *
 	 * @see HttpURLConnection#setDoOutput(boolean)
-     * @param   dooutput   the new value.
+	 * @param dooutput
+	 *            the new value.
 	 */
 	public void setDoOutput(boolean dooutput);
 
 	/**
+	 * Set fixed length streaming mode
+	 *
 	 * @see HttpURLConnection#setFixedLengthStreamingMode(int)
 	 * @param contentLength
 	 *            The number of bytes which will be written to the OutputStream.
-	 *
 	 */
 	public void setFixedLengthStreamingMode(int contentLength);
 
 	/**
+	 * Get output stream
+	 *
 	 * @see HttpURLConnection#getOutputStream()
 	 * @return an output stream that writes to this connection.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 */
 	public OutputStream getOutputStream() throws IOException;
 
 	/**
+	 * Set chunked streaming mode
+	 *
 	 * @see HttpURLConnection#setChunkedStreamingMode(int)
 	 * @param chunklen
 	 *            The number of bytes to write in each chunk. If chunklen is
@@ -254,20 +293,26 @@ public void setRequestMethod(String method)
 	public void setChunkedStreamingMode(int chunklen);
 
 	/**
+	 * Get request method
+	 *
 	 * @see HttpURLConnection#getRequestMethod()
 	 * @return the HTTP request method
 	 */
 	public String getRequestMethod();
 
 	/**
+	 * Whether we use a proxy
+	 *
 	 * @see HttpURLConnection#usingProxy()
 	 * @return a boolean indicating if the connection is using a proxy.
 	 */
 	public boolean usingProxy();
 
 	/**
+	 * Connect
+	 *
 	 * @see HttpURLConnection#connect()
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 */
 	public void connect() throws IOException;
 
@@ -283,21 +328,22 @@ public void setRequestMethod(String method)
 	 *            whether credentials presented by a peer should be accepted.
 	 * @param random
 	 *            the source of randomness for this generator or null. See
-	 *            {@link SSLContext#init(KeyManager[], TrustManager[], SecureRandom)}
-	 *
-	 * @throws NoSuchAlgorithmException
-	 * @throws KeyManagementException
+	 *            {@link javax.net.ssl.SSLContext#init(KeyManager[], TrustManager[], SecureRandom)}
+	 * @throws java.security.NoSuchAlgorithmException
+	 * @throws java.security.KeyManagementException
 	 */
 	public void configure(KeyManager[] km, TrustManager[] tm,
 			SecureRandom random) throws NoSuchAlgorithmException,
 			KeyManagementException;
 
 	/**
-	 * Set the {@link HostnameVerifier} used during https communication
+	 * Set the {@link javax.net.ssl.HostnameVerifier} used during https
+	 * communication
 	 *
 	 * @param hostnameverifier
-	 * @throws NoSuchAlgorithmException
-	 * @throws KeyManagementException
+	 *            a {@link javax.net.ssl.HostnameVerifier} object.
+	 * @throws java.security.NoSuchAlgorithmException
+	 * @throws java.security.KeyManagementException
 	 */
 	public void setHostnameVerifier(HostnameVerifier hostnameverifier)
 			throws NoSuchAlgorithmException, KeyManagementException;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/http/HttpConnectionFactory.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/http/HttpConnectionFactory.java
index 591353c..bd9d61f 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/http/HttpConnectionFactory.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/http/HttpConnectionFactory.java
@@ -47,30 +47,33 @@
 import java.net.URL;
 
 /**
- * The interface of a factory returning {@link HttpConnection}
+ * The interface of a factory returning
+ * {@link org.eclipse.jgit.transport.http.HttpConnection}
  *
  * @since 3.3
  */
 public interface HttpConnectionFactory {
 	/**
-	 * Creates a new connection to a destination defined by a {@link URL}
+	 * Creates a new connection to a destination defined by a
+	 * {@link java.net.URL}
 	 *
 	 * @param url
-	 * @return a {@link HttpConnection}
-	 * @throws IOException
+	 *            a {@link java.net.URL} object.
+	 * @return a {@link org.eclipse.jgit.transport.http.HttpConnection}
+	 * @throws java.io.IOException
 	 */
 	public HttpConnection create(URL url) throws IOException;
 
 	/**
-	 * Creates a new connection to a destination defined by a {@link URL} using
-	 * a proxy
+	 * Creates a new connection to a destination defined by a
+	 * {@link java.net.URL} using a proxy
 	 *
 	 * @param url
+	 *            a {@link java.net.URL} object.
 	 * @param proxy
 	 *            the proxy to be used
-	 * @return a {@link HttpConnection}
-	 *
-	 * @throws IOException
+	 * @return a {@link org.eclipse.jgit.transport.http.HttpConnection}
+	 * @throws java.io.IOException
 	 */
 	public HttpConnection create(URL url, Proxy proxy)
 			throws IOException;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/http/JDKHttpConnection.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/http/JDKHttpConnection.java
index 534e3d7..8241c59 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/http/JDKHttpConnection.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/http/JDKHttpConnection.java
@@ -63,8 +63,9 @@
 import javax.net.ssl.TrustManager;
 
 /**
- * A {@link HttpConnection} which simply delegates every call to a
- * {@link HttpURLConnection}. This is the default implementation used by JGit
+ * A {@link org.eclipse.jgit.transport.http.HttpConnection} which simply
+ * delegates every call to a {@link java.net.HttpURLConnection}. This is the
+ * default implementation used by JGit
  *
  * @since 3.3
  */
@@ -72,9 +73,12 @@ public class JDKHttpConnection implements HttpConnection {
 	HttpURLConnection wrappedUrlConnection;
 
 	/**
+	 * Constructor for JDKHttpConnection.
+	 *
 	 * @param url
-	 * @throws MalformedURLException
-	 * @throws IOException
+	 *            a {@link java.net.URL} object.
+	 * @throws java.net.MalformedURLException
+	 * @throws java.io.IOException
 	 */
 	protected JDKHttpConnection(URL url)
 			throws MalformedURLException,
@@ -83,10 +87,14 @@ protected JDKHttpConnection(URL url)
 	}
 
 	/**
+	 * Constructor for JDKHttpConnection.
+	 *
 	 * @param url
+	 *            a {@link java.net.URL} object.
 	 * @param proxy
-	 * @throws MalformedURLException
-	 * @throws IOException
+	 *            a {@link java.net.Proxy} object.
+	 * @throws java.net.MalformedURLException
+	 * @throws java.io.IOException
 	 */
 	protected JDKHttpConnection(URL url, Proxy proxy)
 			throws MalformedURLException, IOException {
@@ -94,117 +102,140 @@ protected JDKHttpConnection(URL url, Proxy proxy)
 				.openConnection(proxy);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public int getResponseCode() throws IOException {
 		return wrappedUrlConnection.getResponseCode();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public URL getURL() {
 		return wrappedUrlConnection.getURL();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public String getResponseMessage() throws IOException {
 		return wrappedUrlConnection.getResponseMessage();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public Map<String, List<String>> getHeaderFields() {
 		return wrappedUrlConnection.getHeaderFields();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void setRequestProperty(String key, String value) {
 		wrappedUrlConnection.setRequestProperty(key, value);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void setRequestMethod(String method) throws ProtocolException {
 		wrappedUrlConnection.setRequestMethod(method);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void setUseCaches(boolean usecaches) {
 		wrappedUrlConnection.setUseCaches(usecaches);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void setConnectTimeout(int timeout) {
 		wrappedUrlConnection.setConnectTimeout(timeout);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void setReadTimeout(int timeout) {
 		wrappedUrlConnection.setReadTimeout(timeout);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public String getContentType() {
 		return wrappedUrlConnection.getContentType();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public InputStream getInputStream() throws IOException {
 		return wrappedUrlConnection.getInputStream();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public String getHeaderField(String name) {
 		return wrappedUrlConnection.getHeaderField(name);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public int getContentLength() {
 		return wrappedUrlConnection.getContentLength();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void setInstanceFollowRedirects(boolean followRedirects) {
 		wrappedUrlConnection.setInstanceFollowRedirects(followRedirects);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void setDoOutput(boolean dooutput) {
 		wrappedUrlConnection.setDoOutput(dooutput);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void setFixedLengthStreamingMode(int contentLength) {
 		wrappedUrlConnection.setFixedLengthStreamingMode(contentLength);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public OutputStream getOutputStream() throws IOException {
 		return wrappedUrlConnection.getOutputStream();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void setChunkedStreamingMode(int chunklen) {
 		wrappedUrlConnection.setChunkedStreamingMode(chunklen);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public String getRequestMethod() {
 		return wrappedUrlConnection.getRequestMethod();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public boolean usingProxy() {
 		return wrappedUrlConnection.usingProxy();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void connect() throws IOException {
 		wrappedUrlConnection.connect();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void setHostnameVerifier(HostnameVerifier hostnameverifier) {
 		((HttpsURLConnection) wrappedUrlConnection)
 				.setHostnameVerifier(hostnameverifier);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void configure(KeyManager[] km, TrustManager[] tm,
 			SecureRandom random) throws NoSuchAlgorithmException,
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/http/JDKHttpConnectionFactory.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/http/JDKHttpConnectionFactory.java
index b9f009f..ef88947 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/http/JDKHttpConnectionFactory.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/http/JDKHttpConnectionFactory.java
@@ -47,16 +47,19 @@
 import java.net.URL;
 
 /**
- * A factory returning instances of {@link JDKHttpConnection}
+ * A factory returning instances of
+ * {@link org.eclipse.jgit.transport.http.JDKHttpConnection}
  *
  * @since 3.3
  */
 public class JDKHttpConnectionFactory implements HttpConnectionFactory {
+	/** {@inheritDoc} */
 	@Override
 	public HttpConnection create(URL url) throws IOException {
 		return new JDKHttpConnection(url);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public HttpConnection create(URL url, Proxy proxy)
 			throws IOException {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/resolver/FileResolver.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/resolver/FileResolver.java
index 8ab112e..60acd2f 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/resolver/FileResolver.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/resolver/FileResolver.java
@@ -70,7 +70,9 @@ public class FileResolver<C> implements RepositoryResolver<C> {
 
 	private final Collection<File> exportBase;
 
-	/** Initialize an empty file based resolver. */
+	/**
+	 * Initialize an empty file based resolver.
+	 */
 	public FileResolver() {
 		exports = new ConcurrentHashMap<>();
 		exportBase = new CopyOnWriteArrayList<>();
@@ -85,14 +87,15 @@ public FileResolver() {
 	 *            if true, exports all repositories, ignoring the check for the
 	 *            {@code git-daemon-export-ok} files.
 	 */
-	public FileResolver(final File basePath, final boolean exportAll) {
+	public FileResolver(File basePath, boolean exportAll) {
 		this();
 		exportDirectory(basePath);
 		setExportAll(exportAll);
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	public Repository open(final C req, final String name)
+	public Repository open(C req, String name)
 			throws RepositoryNotFoundException, ServiceNotEnabledException {
 		if (isUnreasonableName(name))
 			throw new RepositoryNotFoundException(name);
@@ -148,6 +151,9 @@ public Repository open(final C req, final String name)
 	}
 
 	/**
+	 * Whether <code>git-daemon-export-ok</code> is required to export a
+	 * repository
+	 *
 	 * @return false if <code>git-daemon-export-ok</code> is required to export
 	 *         a repository; true if <code>git-daemon-export-ok</code> is
 	 *         ignored.
@@ -167,9 +173,9 @@ public boolean isExportAll() {
 	 * If true, all repositories are available through the daemon, whether or
 	 * not <code>git-daemon-export-ok</code> exists.
 	 *
-	 * @param export
+	 * @param export a boolean.
 	 */
-	public void setExportAll(final boolean export) {
+	public void setExportAll(boolean export) {
 		exportAll = export;
 	}
 
@@ -196,7 +202,7 @@ public void exportRepository(String name, Repository db) {
 	 *            git repository, but any directory below it which has a file
 	 *            named <code>git-daemon-export-ok</code> will be published.
 	 */
-	public void exportDirectory(final File dir) {
+	public void exportDirectory(File dir) {
 		exportBase.add(dir);
 	}
 
@@ -214,7 +220,7 @@ public void exportDirectory(final File dir) {
 	 * @param db
 	 *            the opened repository instance.
 	 * @return true if the repository is accessible; false if not.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the repository could not be accessed, the caller will claim
 	 *             the repository does not exist.
 	 */
@@ -234,7 +240,7 @@ private static String nameWithDotGit(String name) {
 		return name + Constants.DOT_GIT_EXT;
 	}
 
-	private static boolean isUnreasonableName(final String name) {
+	private static boolean isUnreasonableName(String name) {
 		if (name.length() == 0)
 			return true; // no empty paths
 
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/resolver/ReceivePackFactory.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/resolver/ReceivePackFactory.java
index 73c2ed8..4967169 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/resolver/ReceivePackFactory.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/resolver/ReceivePackFactory.java
@@ -47,13 +47,16 @@
 import org.eclipse.jgit.transport.ReceivePack;
 
 /**
- * Create and configure {@link ReceivePack} service instance.
+ * Create and configure {@link org.eclipse.jgit.transport.ReceivePack} service
+ * instance.
  *
  * @param <C>
  *            type of connection
  */
 public interface ReceivePackFactory<C> {
-	/** A factory disabling the ReceivePack service for all repositories */
+	/**
+	 * A factory disabling the ReceivePack service for all repositories
+	 */
 	public static final ReceivePackFactory<?> DISABLED = new ReceivePackFactory<Object>() {
 		@Override
 		public ReceivePack create(Object req, Repository db)
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/resolver/RepositoryResolver.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/resolver/RepositoryResolver.java
index 80211e5..a305e4c 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/resolver/RepositoryResolver.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/resolver/RepositoryResolver.java
@@ -48,13 +48,15 @@
 import org.eclipse.jgit.transport.ServiceMayNotContinueException;
 
 /**
- * Locate a Git {@link Repository} by name from the URL.
+ * Locate a Git {@link org.eclipse.jgit.lib.Repository} by name from the URL.
  *
  * @param <C>
  *            type of connection.
  */
 public interface RepositoryResolver<C> {
-	/** Resolver configured to open nothing. */
+	/**
+	 * Resolver configured to open nothing.
+	 */
 	public static final RepositoryResolver<?> NONE = new RepositoryResolver<Object>() {
 		@Override
 		public Repository open(Object req, String name)
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/resolver/ServiceNotAuthorizedException.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/resolver/ServiceNotAuthorizedException.java
index 57a6192..d2d1b99 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/resolver/ServiceNotAuthorizedException.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/resolver/ServiceNotAuthorizedException.java
@@ -56,8 +56,12 @@ public class ServiceNotAuthorizedException extends Exception {
 	private static final long serialVersionUID = 1L;
 
 	/**
+	 * Constructor for ServiceNotAuthorizedException.
+	 *
 	 * @param message
+	 *            error message
 	 * @param cause
+	 *            a {@link java.lang.Throwable} object.
 	 * @since 4.1
 	 */
 	public ServiceNotAuthorizedException(String message, Throwable cause) {
@@ -65,14 +69,19 @@ public ServiceNotAuthorizedException(String message, Throwable cause) {
 	}
 
 	/**
+	 * Constructor for ServiceNotAuthorizedException.
+	 *
 	 * @param message
+	 *            error message
 	 * @since 4.1
 	 */
 	public ServiceNotAuthorizedException(String message) {
 		super(message);
 	}
 
-	/** Indicates that the requested service requires authentication. */
+	/**
+	 * Indicates that the requested service requires authentication.
+	 */
 	public ServiceNotAuthorizedException() {
 		super(JGitText.get().unauthorized);
 	}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/resolver/ServiceNotEnabledException.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/resolver/ServiceNotEnabledException.java
index 78ae303..4473452 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/resolver/ServiceNotEnabledException.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/resolver/ServiceNotEnabledException.java
@@ -45,13 +45,19 @@
 
 import org.eclipse.jgit.internal.JGitText;
 
-/** Indicates the request service is not enabled on a repository. */
+/**
+ * Indicates the request service is not enabled on a repository.
+ */
 public class ServiceNotEnabledException extends Exception {
 	private static final long serialVersionUID = 1L;
 
 	/**
+	 * Constructor for ServiceNotEnabledException.
+	 *
 	 * @param message
+	 *            error message
 	 * @param cause
+	 *            a {@link java.lang.Throwable} object.
 	 * @since 4.1
 	 */
 	public ServiceNotEnabledException(String message, Throwable cause) {
@@ -59,14 +65,19 @@ public ServiceNotEnabledException(String message, Throwable cause) {
 	}
 
 	/**
+	 * Constructor for ServiceNotEnabledException.
+	 *
 	 * @param message
+	 *            error message
 	 * @since 4.1
 	 */
 	public ServiceNotEnabledException(String message) {
 		super(message);
 	}
 
-	/** Indicates the request service is not available. */
+	/**
+	 * Indicates the request service is not available.
+	 */
 	public ServiceNotEnabledException() {
 		super(JGitText.get().serviceNotEnabledNoName);
 	}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/resolver/UploadPackFactory.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/resolver/UploadPackFactory.java
index d7ed0f6..40d1ffd 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/resolver/UploadPackFactory.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/resolver/UploadPackFactory.java
@@ -47,13 +47,16 @@
 import org.eclipse.jgit.transport.UploadPack;
 
 /**
- * Create and configure {@link UploadPack} service instance.
+ * Create and configure {@link org.eclipse.jgit.transport.UploadPack} service
+ * instance.
  *
  * @param <C>
  *            the connection type
  */
 public interface UploadPackFactory<C> {
-	/** A factory disabling the UploadPack service for all repositories. */
+	/**
+	 * A factory disabling the UploadPack service for all repositories.
+	 */
 	public static final UploadPackFactory<?> DISABLED = new UploadPackFactory<Object>() {
 		@Override
 		public UploadPack create(Object req, Repository db)
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/AbstractTreeIterator.java b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/AbstractTreeIterator.java
index 6d4c342..470ed02 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/AbstractTreeIterator.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/AbstractTreeIterator.java
@@ -51,7 +51,6 @@
 
 import org.eclipse.jgit.attributes.AttributesHandler;
 import org.eclipse.jgit.attributes.AttributesNode;
-import org.eclipse.jgit.dircache.DirCacheCheckout;
 import org.eclipse.jgit.errors.CorruptObjectException;
 import org.eclipse.jgit.errors.IncorrectObjectTypeException;
 import org.eclipse.jgit.lib.Constants;
@@ -59,7 +58,6 @@
 import org.eclipse.jgit.lib.MutableObjectId;
 import org.eclipse.jgit.lib.ObjectId;
 import org.eclipse.jgit.lib.ObjectReader;
-import org.eclipse.jgit.treewalk.filter.TreeFilter;
 import org.eclipse.jgit.util.Paths;
 
 /**
@@ -154,7 +152,9 @@ public abstract class AbstractTreeIterator {
 	 */
 	protected int pathLen;
 
-	/** Create a new iterator with no parent. */
+	/**
+	 * Create a new iterator with no parent.
+	 */
 	protected AbstractTreeIterator() {
 		parent = null;
 		path = new byte[DEFAULT_PATH_SIZE];
@@ -176,7 +176,7 @@ protected AbstractTreeIterator() {
 	 *            root of the repository. A trailing slash ('/') is
 	 *            automatically appended if the prefix does not end in '/'.
 	 */
-	protected AbstractTreeIterator(final String prefix) {
+	protected AbstractTreeIterator(String prefix) {
 		parent = null;
 
 		if (prefix != null && prefix.length() > 0) {
@@ -210,7 +210,7 @@ protected AbstractTreeIterator(final String prefix) {
 	 *            root of the repository. A trailing slash ('/') is
 	 *            automatically appended if the prefix does not end in '/'.
 	 */
-	protected AbstractTreeIterator(final byte[] prefix) {
+	protected AbstractTreeIterator(byte[] prefix) {
 		parent = null;
 
 		if (prefix != null && prefix.length > 0) {
@@ -232,7 +232,7 @@ protected AbstractTreeIterator(final byte[] prefix) {
 	 * @param p
 	 *            parent tree iterator.
 	 */
-	protected AbstractTreeIterator(final AbstractTreeIterator p) {
+	protected AbstractTreeIterator(AbstractTreeIterator p) {
 		parent = p;
 		path = p.path;
 		pathOffset = p.pathLen + 1;
@@ -275,7 +275,7 @@ protected AbstractTreeIterator(final AbstractTreeIterator p,
 	 *            number of live bytes in the path buffer. This many bytes will
 	 *            be moved into the larger buffer.
 	 */
-	protected void growPath(final int len) {
+	protected void growPath(int len) {
 		setPathCapacity(path.length << 1, len);
 	}
 
@@ -287,7 +287,7 @@ protected void growPath(final int len) {
 	 * @param len
 	 *            the amount of live bytes in path buffer
 	 */
-	protected void ensurePathCapacity(final int capacity, final int len) {
+	protected void ensurePathCapacity(int capacity, int len) {
 		if (path.length >= capacity)
 			return;
 		final byte[] o = path;
@@ -322,11 +322,11 @@ private void setPathCapacity(int capacity, int len) {
 	 * @return -1 if this entry sorts first; 0 if the entries are equal; 1 if
 	 *         p's entry sorts first.
 	 */
-	public int pathCompare(final AbstractTreeIterator p) {
+	public int pathCompare(AbstractTreeIterator p) {
 		return pathCompare(p, p.mode);
 	}
 
-	int pathCompare(final AbstractTreeIterator p, final int pMode) {
+	int pathCompare(AbstractTreeIterator p, int pMode) {
 		// Its common when we are a subtree for both parents to match;
 		// when this happens everything in path[0..cPos] is known to
 		// be equal and does not require evaluation again.
@@ -341,7 +341,7 @@ int pathCompare(final AbstractTreeIterator p, final int pMode) {
 	 * @param name
 	 *            file name to find (will not find a directory).
 	 * @return true if the file exists in this tree; false otherwise.
-	 * @throws CorruptObjectException
+	 * @throws org.eclipse.jgit.errors.CorruptObjectException
 	 *             tree is invalid.
 	 * @since 4.2
 	 */
@@ -355,7 +355,7 @@ public boolean findFile(String name) throws CorruptObjectException {
 	 * @param name
 	 *            file name to find (will not find a directory).
 	 * @return true if the file exists in this tree; false otherwise.
-	 * @throws CorruptObjectException
+	 * @throws org.eclipse.jgit.errors.CorruptObjectException
 	 *             tree is invalid.
 	 * @since 4.2
 	 */
@@ -420,12 +420,16 @@ private static int alreadyMatch(AbstractTreeIterator a,
 	 *            the other iterator to test against.
 	 * @return true if both iterators have the same object id; false otherwise.
 	 */
-	public boolean idEqual(final AbstractTreeIterator otherIterator) {
+	public boolean idEqual(AbstractTreeIterator otherIterator) {
 		return ObjectId.equals(idBuffer(), idOffset(),
 				otherIterator.idBuffer(), otherIterator.idOffset());
 	}
 
-	/** @return true if the entry has a valid ObjectId. */
+	/**
+	 * Whether the entry has a valid ObjectId.
+	 *
+	 * @return {@code true} if the entry has a valid ObjectId.
+	 */
 	public abstract boolean hasId();
 
 	/**
@@ -443,21 +447,33 @@ public ObjectId getEntryObjectId() {
 	 * @param out
 	 *            buffer to copy the object id into.
 	 */
-	public void getEntryObjectId(final MutableObjectId out) {
+	public void getEntryObjectId(MutableObjectId out) {
 		out.fromRaw(idBuffer(), idOffset());
 	}
 
-	/** @return the file mode of the current entry. */
+	/**
+	 * Get the file mode of the current entry.
+	 *
+	 * @return the file mode of the current entry.
+	 */
 	public FileMode getEntryFileMode() {
 		return FileMode.fromBits(mode);
 	}
 
-	/** @return the file mode of the current entry as bits */
+	/**
+	 * Get the file mode of the current entry as bits.
+	 *
+	 * @return the file mode of the current entry as bits.
+	 */
 	public int getEntryRawMode() {
 		return mode;
 	}
 
-	/** @return path of the current entry, as a string. */
+	/**
+	 * Get path of the current entry, as a string.
+	 *
+	 * @return path of the current entry, as a string.
+	 */
 	public String getEntryPathString() {
 		return TreeWalk.pathOf(this);
 	}
@@ -474,7 +490,11 @@ public String getEntryPathString() {
 		return path;
 	}
 
-	/** @return length of the path in {@link #getEntryPathBuffer()}. */
+	/**
+	 * Get length of the path in {@link #getEntryPathBuffer()}.
+	 *
+	 * @return length of the path in {@link #getEntryPathBuffer()}.
+	 */
 	public int getEntryPathLength() {
 		return pathLen;
 	}
@@ -529,10 +549,10 @@ public int getEntryPathHashCode() {
 	 * @param reader
 	 *            reader to load the tree data from.
 	 * @return a new parser that walks over the current subtree.
-	 * @throws IncorrectObjectTypeException
+	 * @throws org.eclipse.jgit.errors.IncorrectObjectTypeException
 	 *             the current entry is not actually a tree and cannot be parsed
 	 *             as though it were a tree.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             a loose object or pack file could not be read.
 	 */
 	public abstract AbstractTreeIterator createSubtreeIterator(
@@ -560,10 +580,10 @@ public EmptyTreeIterator createEmptyTreeIterator() {
 	 * @param idBuffer
 	 *            temporary ObjectId buffer for use by this method.
 	 * @return a new parser that walks over the current subtree.
-	 * @throws IncorrectObjectTypeException
+	 * @throws org.eclipse.jgit.errors.IncorrectObjectTypeException
 	 *             the current entry is not actually a tree and cannot be parsed
 	 *             as though it were a tree.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             a loose object or pack file could not be read.
 	 */
 	public AbstractTreeIterator createSubtreeIterator(
@@ -580,7 +600,7 @@ public AbstractTreeIterator createSubtreeIterator(
 	 * method of repositioning the iterator to its first entry, so subclasses
 	 * are strongly encouraged to override the method.
 	 *
-	 * @throws CorruptObjectException
+	 * @throws org.eclipse.jgit.errors.CorruptObjectException
 	 *             the tree is invalid.
 	 */
 	public void reset() throws CorruptObjectException {
@@ -629,7 +649,7 @@ public void reset() throws CorruptObjectException {
 	 * @param delta
 	 *            number of entries to move the iterator by. Must be a positive,
 	 *            non-zero integer.
-	 * @throws CorruptObjectException
+	 * @throws org.eclipse.jgit.errors.CorruptObjectException
 	 *             the tree is invalid.
 	 */
 	public abstract void next(int delta) throws CorruptObjectException;
@@ -653,7 +673,7 @@ public void reset() throws CorruptObjectException {
 	 * @param delta
 	 *            number of entries to move the iterator by. Must be a positive,
 	 *            non-zero integer.
-	 * @throws CorruptObjectException
+	 * @throws org.eclipse.jgit.errors.CorruptObjectException
 	 *             the tree is invalid.
 	 */
 	public abstract void back(int delta) throws CorruptObjectException;
@@ -662,11 +682,12 @@ public void reset() throws CorruptObjectException {
 	 * Advance to the next tree entry, populating this iterator with its data.
 	 * <p>
 	 * This method behaves like <code>seek(1)</code> but is called by
-	 * {@link TreeWalk} only if a {@link TreeFilter} was used and ruled out the
-	 * current entry from the results. In such cases this tree iterator may
-	 * perform special behavior.
+	 * {@link org.eclipse.jgit.treewalk.TreeWalk} only if a
+	 * {@link org.eclipse.jgit.treewalk.filter.TreeFilter} was used and ruled
+	 * out the current entry from the results. In such cases this tree iterator
+	 * may perform special behavior.
 	 *
-	 * @throws CorruptObjectException
+	 * @throws org.eclipse.jgit.errors.CorruptObjectException
 	 *             the tree is invalid.
 	 */
 	public void skip() throws CorruptObjectException {
@@ -685,7 +706,9 @@ public void stopWalk() {
 	}
 
 	/**
-	 * @return true if the iterator implements {@link #stopWalk()}.
+	 * Whether the iterator implements {@link #stopWalk()}.
+	 *
+	 * @return {@code true} if the iterator implements {@link #stopWalk()}.
 	 * @since 4.2
 	 */
 	protected boolean needsStopWalk() {
@@ -693,14 +716,18 @@ protected boolean needsStopWalk() {
 	}
 
 	/**
-	 * @return the length of the name component of the path for the current entry
+	 * Get the length of the name component of the path for the current entry.
+	 *
+	 * @return the length of the name component of the path for the current
+	 *         entry.
 	 */
 	public int getNameLength() {
 		return pathLen - pathOffset;
 	}
 
 	/**
-	 * JGit internal API for use by {@link DirCacheCheckout}
+	 * JGit internal API for use by
+	 * {@link org.eclipse.jgit.dircache.DirCacheCheckout}
 	 *
 	 * @return start of name component part within {@link #getEntryPathBuffer()}
 	 * @since 2.0
@@ -724,6 +751,7 @@ public void getName(byte[] buffer, int offset) {
 		System.arraycopy(path, pathOffset, buffer, offset, pathLen - pathOffset);
 	}
 
+	/** {@inheritDoc} */
 	@SuppressWarnings("nls")
 	@Override
 	public String toString() {
@@ -731,8 +759,10 @@ public String toString() {
 	}
 
 	/**
-	 * @return whether or not this Iterator is iterating through the Work Tree
+	 * Whether or not this Iterator is iterating through the working tree.
 	 *
+	 * @return whether or not this Iterator is iterating through the working
+	 *         tree
 	 * @since 4.3
 	 */
 	public boolean isWorkTree() {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/CanonicalTreeParser.java b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/CanonicalTreeParser.java
index 2d6abd1..0199688 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/CanonicalTreeParser.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/CanonicalTreeParser.java
@@ -66,7 +66,9 @@
 import org.eclipse.jgit.lib.ObjectId;
 import org.eclipse.jgit.lib.ObjectReader;
 
-/** Parses raw Git trees from the canonical semi-text/semi-binary format. */
+/**
+ * Parses raw Git trees from the canonical semi-text/semi-binary format.
+ */
 public class CanonicalTreeParser extends AbstractTreeIterator {
 	private static final byte[] EMPTY = {};
 	private static final byte[] ATTRS = encode(DOT_GIT_ATTRIBUTES);
@@ -82,7 +84,9 @@ public class CanonicalTreeParser extends AbstractTreeIterator {
 	/** Offset one past the current entry (first byte of next entry). */
 	private int nextPtr;
 
-	/** Create a new parser. */
+	/**
+	 * Create a new parser.
+	 */
 	public CanonicalTreeParser() {
 		reset(EMPTY);
 	}
@@ -102,10 +106,10 @@ public CanonicalTreeParser() {
 	 *            messages if data corruption is found.
 	 * @throws MissingObjectException
 	 *             the object supplied is not available from the repository.
-	 * @throws IncorrectObjectTypeException
+	 * @throws org.eclipse.jgit.errors.IncorrectObjectTypeException
 	 *             the object supplied as an argument is not actually a tree and
 	 *             cannot be parsed as though it were a tree.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             a loose object or pack file could not be read.
 	 */
 	public CanonicalTreeParser(final byte[] prefix, final ObjectReader reader,
@@ -115,12 +119,14 @@ public CanonicalTreeParser(final byte[] prefix, final ObjectReader reader,
 		reset(reader, treeId);
 	}
 
-	private CanonicalTreeParser(final CanonicalTreeParser p) {
+	private CanonicalTreeParser(CanonicalTreeParser p) {
 		super(p);
 	}
 
 	/**
-	 * @return the parent of this tree parser
+	 * Get the parent of this tree parser.
+	 *
+	 * @return the parent of this tree parser.
 	 * @deprecated internal use only
 	 */
 	@Deprecated
@@ -134,7 +140,7 @@ public CanonicalTreeParser getParent() {
 	 * @param treeData
 	 *            the raw tree content.
 	 */
-	public void reset(final byte[] treeData) {
+	public void reset(byte[] treeData) {
 		attributesNode = null;
 		raw = treeData;
 		prevPtr = -1;
@@ -156,10 +162,10 @@ public void reset(final byte[] treeData) {
 	 * @return the root level parser.
 	 * @throws MissingObjectException
 	 *             the object supplied is not available from the repository.
-	 * @throws IncorrectObjectTypeException
+	 * @throws org.eclipse.jgit.errors.IncorrectObjectTypeException
 	 *             the object supplied as an argument is not actually a tree and
 	 *             cannot be parsed as though it were a tree.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             a loose object or pack file could not be read.
 	 */
 	public CanonicalTreeParser resetRoot(final ObjectReader reader,
@@ -172,7 +178,11 @@ public CanonicalTreeParser resetRoot(final ObjectReader reader,
 		return p;
 	}
 
-	/** @return this iterator, or its parent, if the tree is at eof. */
+	/**
+	 * Get this iterator, or its parent, if the tree is at eof.
+	 *
+	 * @return this iterator, or its parent, if the tree is at eof.
+	 */
 	public CanonicalTreeParser next() {
 		CanonicalTreeParser p = this;
 		for (;;) {
@@ -203,17 +213,18 @@ public CanonicalTreeParser next() {
 	 *            messages if data corruption is found.
 	 * @throws MissingObjectException
 	 *             the object supplied is not available from the repository.
-	 * @throws IncorrectObjectTypeException
+	 * @throws org.eclipse.jgit.errors.IncorrectObjectTypeException
 	 *             the object supplied as an argument is not actually a tree and
 	 *             cannot be parsed as though it were a tree.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             a loose object or pack file could not be read.
 	 */
-	public void reset(final ObjectReader reader, final AnyObjectId id)
+	public void reset(ObjectReader reader, AnyObjectId id)
 			throws IncorrectObjectTypeException, IOException {
 		reset(reader.open(id, OBJ_TREE).getCachedBytes());
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public CanonicalTreeParser createSubtreeIterator(final ObjectReader reader,
 			final MutableObjectId idBuffer)
@@ -238,7 +249,7 @@ public CanonicalTreeParser createSubtreeIterator(final ObjectReader reader,
 	 * @param id
 	 *            ObjectId of the tree to open.
 	 * @return a new parser that walks over the current subtree.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             a loose object or pack file could not be read.
 	 */
 	public final CanonicalTreeParser createSubtreeIterator0(
@@ -249,43 +260,51 @@ public final CanonicalTreeParser createSubtreeIterator0(
 		return p;
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	public CanonicalTreeParser createSubtreeIterator(final ObjectReader reader)
+	public CanonicalTreeParser createSubtreeIterator(ObjectReader reader)
 			throws IncorrectObjectTypeException, IOException {
 		return createSubtreeIterator(reader, new MutableObjectId());
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public boolean hasId() {
 		return true;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public byte[] idBuffer() {
 		return raw;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public int idOffset() {
 		return nextPtr - OBJECT_ID_LENGTH;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void reset() {
 		if (!first())
 			reset(raw);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public boolean first() {
 		return currPtr == 0;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public boolean eof() {
 		return currPtr == raw.length;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void next(int delta) {
 		if (delta == 1) {
@@ -315,6 +334,7 @@ public void next(int delta) {
 			parseEntry();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void back(int delta) {
 		if (delta == 1 && 0 <= prevPtr) {
@@ -381,12 +401,15 @@ private void parseEntry() {
 	}
 
 	/**
-	 * Retrieve the {@link AttributesNode} for the current entry.
+	 * Retrieve the {@link org.eclipse.jgit.attributes.AttributesNode} for the
+	 * current entry.
 	 *
 	 * @param reader
-	 *            {@link ObjectReader} used to parse the .gitattributes entry.
-	 * @return {@link AttributesNode} for the current entry.
-	 * @throws IOException
+	 *            {@link org.eclipse.jgit.lib.ObjectReader} used to parse the
+	 *            .gitattributes entry.
+	 * @return {@link org.eclipse.jgit.attributes.AttributesNode} for the
+	 *         current entry.
+	 * @throws java.io.IOException
 	 * @since 4.2
 	 */
 	public AttributesNode getEntryAttributesNode(ObjectReader reader)
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/EmptyTreeIterator.java b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/EmptyTreeIterator.java
index ec4a84e..f5d45c7 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/EmptyTreeIterator.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/EmptyTreeIterator.java
@@ -52,14 +52,18 @@
 import org.eclipse.jgit.lib.ObjectId;
 import org.eclipse.jgit.lib.ObjectReader;
 
-/** Iterator over an empty tree (a directory with no files). */
+/**
+ * Iterator over an empty tree (a directory with no files).
+ */
 public class EmptyTreeIterator extends AbstractTreeIterator {
-	/** Create a new iterator with no parent. */
+	/**
+	 * Create a new iterator with no parent.
+	 */
 	public EmptyTreeIterator() {
 		// Create a root empty tree.
 	}
 
-	EmptyTreeIterator(final AbstractTreeIterator p) {
+	EmptyTreeIterator(AbstractTreeIterator p) {
 		super(p);
 		pathLen = pathOffset;
 	}
@@ -86,63 +90,75 @@ public EmptyTreeIterator(final AbstractTreeIterator p,
 		pathLen = childPathOffset - 1;
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	public AbstractTreeIterator createSubtreeIterator(final ObjectReader reader)
+	public AbstractTreeIterator createSubtreeIterator(ObjectReader reader)
 			throws IncorrectObjectTypeException, IOException {
 		return new EmptyTreeIterator(this);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public boolean hasId() {
 		return false;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public ObjectId getEntryObjectId() {
 		return ObjectId.zeroId();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public byte[] idBuffer() {
 		return zeroid;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public int idOffset() {
 		return 0;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void reset() {
 		// Do nothing.
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public boolean first() {
 		return true;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public boolean eof() {
 		return true;
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	public void next(final int delta) throws CorruptObjectException {
+	public void next(int delta) throws CorruptObjectException {
 		// Do nothing.
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	public void back(final int delta) throws CorruptObjectException {
+	public void back(int delta) throws CorruptObjectException {
 		// Do nothing.
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void stopWalk() {
 		if (parent != null)
 			parent.stopWalk();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected boolean needsStopWalk() {
 		return parent != null && parent.needsStopWalk();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/FileTreeIterator.java b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/FileTreeIterator.java
index afa2ed9..24b9ac0 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/FileTreeIterator.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/FileTreeIterator.java
@@ -52,6 +52,7 @@
 import java.io.IOException;
 import java.io.InputStream;
 
+import org.eclipse.jgit.dircache.DirCacheIterator;
 import org.eclipse.jgit.errors.IncorrectObjectTypeException;
 import org.eclipse.jgit.lib.Constants;
 import org.eclipse.jgit.lib.FileMode;
@@ -63,9 +64,11 @@
  * Working directory iterator for standard Java IO.
  * <p>
  * This iterator uses the standard <code>java.io</code> package to read the
- * specified working directory as part of a {@link TreeWalk}.
+ * specified working directory as part of a
+ * {@link org.eclipse.jgit.treewalk.TreeWalk}.
  */
 public class FileTreeIterator extends WorkingTreeIterator {
+
 	/**
 	 * the starting directory of this Iterator. All entries are located directly
 	 * in this directory.
@@ -108,7 +111,6 @@ public FileTreeIterator(Repository repo) {
 	 * @param fileModeStrategy
 	 *            the strategy to use to determine the FileMode for a FileEntry;
 	 *            controls gitlinks etc.
-	 *
 	 * @since 4.3
 	 */
 	public FileTreeIterator(Repository repo, FileModeStrategy fileModeStrategy) {
@@ -130,7 +132,7 @@ public FileTreeIterator(Repository repo, FileModeStrategy fileModeStrategy) {
 	 * @param options
 	 *            working tree options to be used
 	 */
-	public FileTreeIterator(final File root, FS fs, WorkingTreeOptions options) {
+	public FileTreeIterator(File root, FS fs, WorkingTreeOptions options) {
 		this(root, fs, options, DefaultFileModeStrategy.INSTANCE);
 	}
 
@@ -148,7 +150,6 @@ public FileTreeIterator(final File root, FS fs, WorkingTreeOptions options) {
 	 * @param fileModeStrategy
 	 *            the strategy to use to determine the FileMode for a FileEntry;
 	 *            controls gitlinks etc.
-	 *
 	 * @since 4.3
 	 */
 	public FileTreeIterator(final File root, FS fs, WorkingTreeOptions options,
@@ -172,28 +173,6 @@ public FileTreeIterator(final File root, FS fs, WorkingTreeOptions options,
 	 *            the file system abstraction which will be necessary to perform
 	 *            certain file system operations.
 	 * @since 4.3
-	 * @deprecated use {@link #FileTreeIterator(FileTreeIterator, File, FS)}
-	 *             instead.
-	 */
-	@Deprecated
-	protected FileTreeIterator(final WorkingTreeIterator p, final File root,
-			FS fs) {
-		this(p, root, fs, DefaultFileModeStrategy.INSTANCE);
-	}
-
-	/**
-	 * Create a new iterator to traverse a subdirectory.
-	 *
-	 * @param p
-	 *            the parent iterator we were created from.
-	 * @param root
-	 *            the subdirectory. This should be a directory contained within
-	 *            the parent directory.
-	 * @param fs
-	 *            the file system abstraction which will be necessary to perform
-	 *            certain file system operations.
-	 *
-	 * @since 4.3
 	 */
 	protected FileTreeIterator(final FileTreeIterator p, final File root,
 			FS fs) {
@@ -215,7 +194,6 @@ protected FileTreeIterator(final FileTreeIterator p, final File root,
 	 * @param fileModeStrategy
 	 *            the strategy to use to determine the FileMode for a given
 	 *            FileEntry.
-	 *
 	 * @since 4.3
 	 */
 	protected FileTreeIterator(final WorkingTreeIterator p, final File root,
@@ -227,20 +205,41 @@ protected FileTreeIterator(final WorkingTreeIterator p, final File root,
 		init(entries());
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	public AbstractTreeIterator createSubtreeIterator(final ObjectReader reader)
+	public AbstractTreeIterator createSubtreeIterator(ObjectReader reader)
 			throws IncorrectObjectTypeException, IOException {
-		return new FileTreeIterator(this, ((FileEntry) current()).getFile(), fs, fileModeStrategy);
+		if (!walksIgnoredDirectories() && isEntryIgnored()) {
+			DirCacheIterator iterator = getDirCacheIterator();
+			if (iterator == null) {
+				return new EmptyTreeIterator(this);
+			}
+			// Only enter if we have an associated DirCacheIterator that is
+			// at the same entry (which indicates there is some already
+			// tracked file underneath this directory). Otherwise the
+			// directory is indeed ignored and can be skipped entirely.
+		}
+		return enterSubtree();
+	}
+
+
+	/**
+	 * Create a new iterator for the current entry's subtree.
+	 * <p>
+	 * The parent reference of the iterator must be <code>this</code>, otherwise
+	 * the caller would not be able to exit out of the subtree iterator
+	 * correctly and return to continue walking <code>this</code>.
+	 *
+	 * @return a new iterator that walks over the current subtree.
+	 * @since 5.0
+	 */
+	protected AbstractTreeIterator enterSubtree() {
+		return new FileTreeIterator(this, ((FileEntry) current()).getFile(), fs,
+				fileModeStrategy);
 	}
 
 	private Entry[] entries() {
-		final File[] all = directory.listFiles();
-		if (all == null)
-			return EOF;
-		final Entry[] r = new Entry[all.length];
-		for (int i = 0; i < r.length; i++)
-			r[i] = new FileEntry(all[i], fs, fileModeStrategy);
-		return r;
+		return fs.list(directory, fileModeStrategy);
 	}
 
 	/**
@@ -269,7 +268,7 @@ public interface FileModeStrategy {
 	 *
 	 * @since 4.3
 	 */
-	static public class DefaultFileModeStrategy implements FileModeStrategy {
+	public static class DefaultFileModeStrategy implements FileModeStrategy {
 		/**
 		 * a singleton instance of the default FileModeStrategy
 		 */
@@ -302,7 +301,7 @@ public FileMode getMode(File f, FS.Attributes attributes) {
 	 *
 	 * @since 4.3
 	 */
-	static public class NoGitlinksStrategy implements FileModeStrategy {
+	public static class NoGitlinksStrategy implements FileModeStrategy {
 
 		/**
 		 * a singleton instance of the default FileModeStrategy
@@ -327,7 +326,7 @@ public FileMode getMode(File f, FS.Attributes attributes) {
 	/**
 	 * Wrapper for a standard Java IO file
 	 */
-	static public class FileEntry extends Entry {
+	public static class FileEntry extends Entry {
 		private final FileMode mode;
 
 		private FS.Attributes attributes;
@@ -366,6 +365,29 @@ public FileEntry(File f, FS fs, FileModeStrategy fileModeStrategy) {
 			mode = fileModeStrategy.getMode(f, attributes);
 		}
 
+		/**
+		 * Create a new file entry given the specified FileModeStrategy
+		 *
+		 * @param f
+		 *            file
+		 * @param fs
+		 *            file system
+		 * @param attributes
+		 *            of the file
+		 * @param fileModeStrategy
+		 *            the strategy to use when determining the FileMode of a
+		 *            file; controls gitlinks etc.
+		 *
+		 * @since 5.0
+		 */
+		public FileEntry(File f, FS fs, FS.Attributes attributes,
+				FileModeStrategy fileModeStrategy) {
+			this.fs = fs;
+			this.attributes = attributes;
+			f = fs.normalize(f);
+			mode = fileModeStrategy.getMode(f, attributes);
+		}
+
 		@Override
 		public FileMode getMode() {
 			return mode;
@@ -388,12 +410,12 @@ public long getLastModified() {
 
 		@Override
 		public InputStream openInputStream() throws IOException {
-			if (fs.isSymLink(getFile()))
+			if (attributes.isSymbolicLink()) {
 				return new ByteArrayInputStream(fs.readSymLink(getFile())
-						.getBytes(
-						Constants.CHARACTER_ENCODING));
-			else
+						.getBytes(Constants.CHARACTER_ENCODING));
+			} else {
 				return new FileInputStream(getFile());
+			}
 		}
 
 		/**
@@ -407,6 +429,8 @@ public File getFile() {
 	}
 
 	/**
+	 * <p>Getter for the field <code>directory</code>.</p>
+	 *
 	 * @return The root directory of this iterator
 	 */
 	public File getDirectory() {
@@ -414,6 +438,8 @@ public File getDirectory() {
 	}
 
 	/**
+	 * Get the location of the working file.
+	 *
 	 * @return The location of the working file. This is the same as {@code new
 	 *         File(getDirectory(), getEntryPath())} but may be faster by
 	 *         reusing an internal File instance.
@@ -422,11 +448,13 @@ public File getEntryFile() {
 		return ((FileEntry) current()).getFile();
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	protected byte[] idSubmodule(final Entry e) {
+	protected byte[] idSubmodule(Entry e) {
 		return idSubmodule(getDirectory(), e);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected String readSymlinkTarget(Entry entry) throws IOException {
 		return fs.readSymLink(getEntryFile());
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/NameConflictTreeWalk.java b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/NameConflictTreeWalk.java
index 59cf798..61b130f 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/NameConflictTreeWalk.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/NameConflictTreeWalk.java
@@ -46,7 +46,6 @@
 import java.io.IOException;
 
 import org.eclipse.jgit.annotations.Nullable;
-import org.eclipse.jgit.dircache.DirCacheBuilder;
 import org.eclipse.jgit.errors.CorruptObjectException;
 import org.eclipse.jgit.lib.FileMode;
 import org.eclipse.jgit.lib.ObjectReader;
@@ -55,24 +54,26 @@
 /**
  * Specialized TreeWalk to detect directory-file (D/F) name conflicts.
  * <p>
- * Due to the way a Git tree is organized the standard {@link TreeWalk} won't
- * easily find a D/F conflict when merging two or more trees together. In the
- * standard TreeWalk the file will be returned first, and then much later the
- * directory will be returned. This makes it impossible for the application to
- * efficiently detect and handle the conflict.
+ * Due to the way a Git tree is organized the standard
+ * {@link org.eclipse.jgit.treewalk.TreeWalk} won't easily find a D/F conflict
+ * when merging two or more trees together. In the standard TreeWalk the file
+ * will be returned first, and then much later the directory will be returned.
+ * This makes it impossible for the application to efficiently detect and handle
+ * the conflict.
  * <p>
  * Using this walk implementation causes the directory to report earlier than
  * usual, at the same time as the non-directory entry. This permits the
  * application to handle the D/F conflict in a single step. The directory is
  * returned only once, so it does not get returned later in the iteration.
  * <p>
- * When a D/F conflict is detected {@link TreeWalk#isSubtree()} will return true
- * and {@link TreeWalk#enterSubtree()} will recurse into the subtree, no matter
- * which iterator originally supplied the subtree.
+ * When a D/F conflict is detected
+ * {@link org.eclipse.jgit.treewalk.TreeWalk#isSubtree()} will return true and
+ * {@link org.eclipse.jgit.treewalk.TreeWalk#enterSubtree()} will recurse into
+ * the subtree, no matter which iterator originally supplied the subtree.
  * <p>
  * Because conflicted directories report early, using this walk implementation
- * to populate a {@link DirCacheBuilder} may cause the automatic resorting to
- * run and fix the entry ordering.
+ * to populate a {@link org.eclipse.jgit.dircache.DirCacheBuilder} may cause the
+ * automatic resorting to run and fix the entry ordering.
  * <p>
  * This walk implementation requires more CPU to implement a look-ahead and a
  * look-behind to merge a D/F pair together, or to skip a previously reported
@@ -98,7 +99,7 @@ public class NameConflictTreeWalk extends TreeWalk {
 	 * @param repo
 	 *            the repository the walker will obtain data from.
 	 */
-	public NameConflictTreeWalk(final Repository repo) {
+	public NameConflictTreeWalk(Repository repo) {
 		super(repo);
 	}
 
@@ -111,7 +112,7 @@ public NameConflictTreeWalk(final Repository repo) {
 	 *            the reader the walker will obtain tree data from.
 	 * @since 4.3
 	 */
-	public NameConflictTreeWalk(@Nullable Repository repo, final ObjectReader or) {
+	public NameConflictTreeWalk(@Nullable Repository repo, ObjectReader or) {
 		super(repo, or);
 	}
 
@@ -121,7 +122,7 @@ public NameConflictTreeWalk(@Nullable Repository repo, final ObjectReader or) {
 	 * @param or
 	 *            the reader the walker will obtain tree data from.
 	 */
-	public NameConflictTreeWalk(final ObjectReader or) {
+	public NameConflictTreeWalk(ObjectReader or) {
 		super(or);
 	}
 
@@ -134,7 +135,7 @@ AbstractTreeIterator min() throws CorruptObjectException {
 
 			if (isTree(minRef)) {
 				if (skipEntry(minRef)) {
-					for (final AbstractTreeIterator t : trees) {
+					for (AbstractTreeIterator t : trees) {
 						if (t.matches == minRef) {
 							t.next(1);
 							t.matches = null;
@@ -186,7 +187,7 @@ && nameEqual(minRef, t)) {
 				//
 				t.matches = minRef;
 			} else if (fastMinHasMatch && isTree(t) && !isTree(minRef)
-					&& nameEqual(t, minRef)) {
+					&& !isGitlink(minRef) && nameEqual(t, minRef)) {
 				// The minimum is a file (non-tree) but the next entry
 				// of this iterator is a tree whose name matches our file.
 				// This is a classic D/F conflict and commonly occurs like
@@ -217,16 +218,20 @@ private static boolean nameEqual(final AbstractTreeIterator a,
 		return a.pathCompare(b, TREE_MODE) == 0;
 	}
 
-	private static boolean isTree(final AbstractTreeIterator p) {
+	private boolean isGitlink(AbstractTreeIterator p) {
+		return FileMode.GITLINK.equals(p.mode);
+	}
+
+	private static boolean isTree(AbstractTreeIterator p) {
 		return FileMode.TREE.equals(p.mode);
 	}
 
-	private boolean skipEntry(final AbstractTreeIterator minRef)
+	private boolean skipEntry(AbstractTreeIterator minRef)
 			throws CorruptObjectException {
 		// A tree D/F may have been handled earlier. We need to
 		// not report this path if it has already been reported.
 		//
-		for (final AbstractTreeIterator t : trees) {
+		for (AbstractTreeIterator t : trees) {
 			if (t.matches == minRef || t.first())
 				continue;
 
@@ -255,14 +260,14 @@ private boolean skipEntry(final AbstractTreeIterator minRef)
 		return false;
 	}
 
-	private AbstractTreeIterator combineDF(final AbstractTreeIterator minRef)
+	private AbstractTreeIterator combineDF(AbstractTreeIterator minRef)
 			throws CorruptObjectException {
 		// Look for a possible D/F conflict forward in the tree(s)
 		// as there may be a "$path/" which matches "$path". Make
 		// such entries match this entry.
 		//
 		AbstractTreeIterator treeMatch = null;
-		for (final AbstractTreeIterator t : trees) {
+		for (AbstractTreeIterator t : trees) {
 			if (t.matches == minRef || t.eof())
 				continue;
 
@@ -301,12 +306,13 @@ private AbstractTreeIterator combineDF(final AbstractTreeIterator minRef)
 			// matching iterators instead of the file iterator.
 			// This way isSubtree is true and isRecursive works.
 			//
-			for (final AbstractTreeIterator t : trees)
+			for (AbstractTreeIterator t : trees)
 				if (t.matches == minRef)
 					t.matches = treeMatch;
 
-			if (dfConflict == null)
+			if (dfConflict == null && !isGitlink(minRef)) {
 				dfConflict = treeMatch;
+			}
 
 			return treeMatch;
 		}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/TreeWalk.java b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/TreeWalk.java
index c54e148..d500aae 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/TreeWalk.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/TreeWalk.java
@@ -81,7 +81,8 @@
 import org.eclipse.jgit.util.io.EolStreamTypeUtil;
 
 /**
- * Walks one or more {@link AbstractTreeIterator}s in parallel.
+ * Walks one or more {@link org.eclipse.jgit.treewalk.AbstractTreeIterator}s in
+ * parallel.
  * <p>
  * This class can perform n-way differences across as many trees as necessary.
  * <p>
@@ -97,8 +98,9 @@
  * usage of a TreeWalk instance to a single thread, or implement their own
  * synchronization at a higher level.
  * <p>
- * Multiple simultaneous TreeWalk instances per {@link Repository} are
- * permitted, even from concurrent threads.
+ * Multiple simultaneous TreeWalk instances per
+ * {@link org.eclipse.jgit.lib.Repository} are permitted, even from concurrent
+ * threads.
  */
 public class TreeWalk implements AutoCloseable, AttributesProvider {
 	private static final AbstractTreeIterator[] NO_TREES = {};
@@ -131,7 +133,11 @@ public static enum OperationType {
 	private Map<String, String> filterCommandsByNameDotType = new HashMap<>();
 
 	/**
+	 * Set the operation type of this walk
+	 *
 	 * @param operationType
+	 *            a {@link org.eclipse.jgit.treewalk.TreeWalk.OperationType}
+	 *            object.
 	 * @since 4.2
 	 */
 	public void setOperationType(OperationType operationType) {
@@ -153,14 +159,14 @@ public void setOperationType(OperationType operationType) {
 	 *            one or more trees to walk through, all with the same root.
 	 * @return a new tree walk configured for exactly this one path; null if no
 	 *         path was found in any of the trees.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             reading a pack file or loose object failed.
-	 * @throws CorruptObjectException
+	 * @throws org.eclipse.jgit.errors.CorruptObjectException
 	 *             an tree object could not be read as its data stream did not
 	 *             appear to be a tree, or could not be inflated.
-	 * @throws IncorrectObjectTypeException
+	 * @throws org.eclipse.jgit.errors.IncorrectObjectTypeException
 	 *             an object we expected to be a tree was not a tree.
-	 * @throws MissingObjectException
+	 * @throws org.eclipse.jgit.errors.MissingObjectException
 	 *             a tree object was not found.
 	 */
 	public static TreeWalk forPath(final ObjectReader reader, final String path,
@@ -178,7 +184,8 @@ public static TreeWalk forPath(final ObjectReader reader, final String path,
 	 *
 	 * @param repo
 	 *            repository to read config data and
-	 *            {@link AttributesNodeProvider} from.
+	 *            {@link org.eclipse.jgit.attributes.AttributesNodeProvider}
+	 *            from.
 	 * @param reader
 	 *            the reader the walker will obtain tree data from.
 	 * @param path
@@ -187,14 +194,14 @@ public static TreeWalk forPath(final ObjectReader reader, final String path,
 	 *            one or more trees to walk through, all with the same root.
 	 * @return a new tree walk configured for exactly this one path; null if no
 	 *         path was found in any of the trees.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             reading a pack file or loose object failed.
-	 * @throws CorruptObjectException
+	 * @throws org.eclipse.jgit.errors.CorruptObjectException
 	 *             an tree object could not be read as its data stream did not
 	 *             appear to be a tree, or could not be inflated.
-	 * @throws IncorrectObjectTypeException
+	 * @throws org.eclipse.jgit.errors.IncorrectObjectTypeException
 	 *             an object we expected to be a tree was not a tree.
-	 * @throws MissingObjectException
+	 * @throws org.eclipse.jgit.errors.MissingObjectException
 	 *             a tree object was not found.
 	 * @since 4.3
 	 */
@@ -234,14 +241,14 @@ public static TreeWalk forPath(final @Nullable Repository repo,
 	 *            one or more trees to walk through, all with the same root.
 	 * @return a new tree walk configured for exactly this one path; null if no
 	 *         path was found in any of the trees.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             reading a pack file or loose object failed.
-	 * @throws CorruptObjectException
+	 * @throws org.eclipse.jgit.errors.CorruptObjectException
 	 *             an tree object could not be read as its data stream did not
 	 *             appear to be a tree, or could not be inflated.
-	 * @throws IncorrectObjectTypeException
+	 * @throws org.eclipse.jgit.errors.IncorrectObjectTypeException
 	 *             an object we expected to be a tree was not a tree.
-	 * @throws MissingObjectException
+	 * @throws org.eclipse.jgit.errors.MissingObjectException
 	 *             a tree object was not found.
 	 */
 	public static TreeWalk forPath(final Repository db, final String path,
@@ -267,14 +274,14 @@ public static TreeWalk forPath(final Repository db, final String path,
 	 *            the single tree to walk through.
 	 * @return a new tree walk configured for exactly this one path; null if no
 	 *         path was found in any of the trees.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             reading a pack file or loose object failed.
-	 * @throws CorruptObjectException
+	 * @throws org.eclipse.jgit.errors.CorruptObjectException
 	 *             an tree object could not be read as its data stream did not
 	 *             appear to be a tree, or could not be inflated.
-	 * @throws IncorrectObjectTypeException
+	 * @throws org.eclipse.jgit.errors.IncorrectObjectTypeException
 	 *             an object we expected to be a tree was not a tree.
-	 * @throws MissingObjectException
+	 * @throws org.eclipse.jgit.errors.MissingObjectException
 	 *             a tree object was not found.
 	 */
 	public static TreeWalk forPath(final Repository db, final String path,
@@ -325,7 +332,7 @@ public static TreeWalk forPath(final Repository db, final String path,
 	 *            ObjectReader will be created by the walker, and will be closed
 	 *            when the walker is closed.
 	 */
-	public TreeWalk(final Repository repo) {
+	public TreeWalk(Repository repo) {
 		this(repo, repo.newObjectReader(), true);
 	}
 
@@ -341,7 +348,7 @@ public TreeWalk(final Repository repo) {
 	 *            is not closed when the walker is closed.
 	 * @since 4.3
 	 */
-	public TreeWalk(final @Nullable Repository repo, final ObjectReader or) {
+	public TreeWalk(@Nullable Repository repo, ObjectReader or) {
 		this(repo, or, false);
 	}
 
@@ -352,7 +359,7 @@ public TreeWalk(final @Nullable Repository repo, final ObjectReader or) {
 	 *            the reader the walker will obtain tree data from. The reader
 	 *            is not closed when the walker is closed.
 	 */
-	public TreeWalk(final ObjectReader or) {
+	public TreeWalk(ObjectReader or) {
 		this(null, or, false);
 	}
 
@@ -373,13 +380,19 @@ private TreeWalk(final @Nullable Repository repo, final ObjectReader or,
 		this.closeReader = closeReader;
 	}
 
-	/** @return the reader this walker is using to load objects. */
+	/**
+	 * Get the reader this walker is using to load objects.
+	 *
+	 * @return the reader this walker is using to load objects.
+	 */
 	public ObjectReader getObjectReader() {
 		return reader;
 	}
 
 	/**
-	 * @return the {@link OperationType}
+	 * Get the operation type
+	 *
+	 * @return the {@link org.eclipse.jgit.treewalk.TreeWalk.OperationType}
 	 * @since 4.3
 	 */
 	public OperationType getOperationType() {
@@ -387,6 +400,8 @@ public OperationType getOperationType() {
 	}
 
 	/**
+	 * {@inheritDoc}
+	 * <p>
 	 * Release any resources used by this walker's reader.
 	 * <p>
 	 * A walker that has been released can be used again, but may need to be
@@ -421,16 +436,18 @@ public TreeFilter getFilter() {
 	 * Note that filters are not thread-safe and may not be shared by concurrent
 	 * TreeWalk instances. Every TreeWalk must be supplied its own unique
 	 * filter, unless the filter implementation specifically states it is (and
-	 * always will be) thread-safe. Callers may use {@link TreeFilter#clone()}
-	 * to create a unique filter tree for this TreeWalk instance.
+	 * always will be) thread-safe. Callers may use
+	 * {@link org.eclipse.jgit.treewalk.filter.TreeFilter#clone()} to create a
+	 * unique filter tree for this TreeWalk instance.
 	 *
 	 * @param newFilter
-	 *            the new filter. If null the special {@link TreeFilter#ALL}
-	 *            filter will be used instead, as it matches every entry.
+	 *            the new filter. If null the special
+	 *            {@link org.eclipse.jgit.treewalk.filter.TreeFilter#ALL} filter
+	 *            will be used instead, as it matches every entry.
 	 * @see org.eclipse.jgit.treewalk.filter.AndTreeFilter
 	 * @see org.eclipse.jgit.treewalk.filter.OrTreeFilter
 	 */
-	public void setFilter(final TreeFilter newFilter) {
+	public void setFilter(TreeFilter newFilter) {
 		filter = newFilter != null ? newFilter : TreeFilter.ALL;
 	}
 
@@ -458,7 +475,7 @@ public boolean isRecursive() {
 	 * @param b
 	 *            true to skip subtree nodes and only obtain files nodes.
 	 */
-	public void setRecursive(final boolean b) {
+	public void setRecursive(boolean b) {
 		recursive = b;
 	}
 
@@ -488,24 +505,28 @@ public boolean isPostOrderTraversal() {
 	 *            true to get trees after their children.
 	 * @see #isPostOrderTraversal()
 	 */
-	public void setPostOrderTraversal(final boolean b) {
+	public void setPostOrderTraversal(boolean b) {
 		postOrderTraversal = b;
 	}
 
 	/**
-	 * Sets the {@link AttributesNodeProvider} for this {@link TreeWalk}.
+	 * Sets the {@link org.eclipse.jgit.attributes.AttributesNodeProvider} for
+	 * this {@link org.eclipse.jgit.treewalk.TreeWalk}.
 	 * <p>
-	 * This is a requirement for a correct computation of the git attributes.
-	 * If this {@link TreeWalk} has been built using
+	 * This is a requirement for a correct computation of the git attributes. If
+	 * this {@link org.eclipse.jgit.treewalk.TreeWalk} has been built using
 	 * {@link #TreeWalk(Repository)} constructor, the
-	 * {@link AttributesNodeProvider} has already been set. Indeed,the
-	 * {@link Repository} can provide an {@link AttributesNodeProvider} using
-	 * {@link Repository#createAttributesNodeProvider()} method. Otherwise you
-	 * should provide one.
+	 * {@link org.eclipse.jgit.attributes.AttributesNodeProvider} has already
+	 * been set. Indeed,the {@link org.eclipse.jgit.lib.Repository} can provide
+	 * an {@link org.eclipse.jgit.attributes.AttributesNodeProvider} using
+	 * {@link org.eclipse.jgit.lib.Repository#createAttributesNodeProvider()}
+	 * method. Otherwise you should provide one.
 	 * </p>
 	 *
 	 * @see Repository#createAttributesNodeProvider()
 	 * @param provider
+	 *            a {@link org.eclipse.jgit.attributes.AttributesNodeProvider}
+	 *            object.
 	 * @since 4.2
 	 */
 	public void setAttributesNodeProvider(AttributesNodeProvider provider) {
@@ -513,7 +534,10 @@ public void setAttributesNodeProvider(AttributesNodeProvider provider) {
 	}
 
 	/**
-	 * @return the {@link AttributesNodeProvider} for this {@link TreeWalk}.
+	 * Get the attributes node provider
+	 *
+	 * @return the {@link org.eclipse.jgit.attributes.AttributesNodeProvider}
+	 *         for this {@link org.eclipse.jgit.treewalk.TreeWalk}.
 	 * @since 4.3
 	 */
 	public AttributesNodeProvider getAttributesNodeProvider() {
@@ -521,9 +545,11 @@ public AttributesNodeProvider getAttributesNodeProvider() {
 	}
 
 	/**
+	 * {@inheritDoc}
+	 * <p>
 	 * Retrieve the git attributes for the current entry.
 	 *
-	 * <h4>Git attribute computation</h4>
+	 * <h3>Git attribute computation</h3>
 	 *
 	 * <ul>
 	 * <li>Get the attributes matching the current path entry from the info file
@@ -542,7 +568,7 @@ public AttributesNodeProvider getAttributesNodeProvider() {
 	 * </ul>
 	 *
 	 *
-	 * <h4>Iterator constraints</h4>
+	 * <h3>Iterator constraints</h3>
 	 *
 	 * <p>
 	 * In order to have a correct list of attributes for the current entry, this
@@ -556,7 +582,6 @@ public AttributesNodeProvider getAttributesNodeProvider() {
 	 * provided it will fallback on the {@link DirCacheIterator}.
 	 * </p>
 	 *
-	 * @return a {@link Set} of {@link Attribute}s that match the current entry.
 	 * @since 4.2
 	 */
 	@Override
@@ -587,33 +612,29 @@ public Attributes getAttributes() {
 	}
 
 	/**
+	 * Get the EOL stream type of the current entry using the config and
+	 * {@link #getAttributes()}.
+	 *
 	 * @param opType
 	 *            the operationtype (checkin/checkout) which should be used
 	 * @return the EOL stream type of the current entry using the config and
-	 *         {@link #getAttributes()} Note that this method may return null if
-	 *         the {@link TreeWalk} is not based on a working tree
+	 *         {@link #getAttributes()}. Note that this method may return null
+	 *         if the {@link org.eclipse.jgit.treewalk.TreeWalk} is not based on
+	 *         a working tree
+	 * @since 4.10
 	 */
-	// TODO(msohn) make this method public in 4.4
 	@Nullable
-	EolStreamType getEolStreamType(OperationType opType) {
-			if (attributesNodeProvider == null || config == null)
-				return null;
-		return EolStreamTypeUtil.detectStreamType(opType,
+	public EolStreamType getEolStreamType(OperationType opType) {
+		if (attributesNodeProvider == null || config == null)
+			return null;
+		return EolStreamTypeUtil.detectStreamType(
+				opType != null ? opType : operationType,
 					config.get(WorkingTreeOptions.KEY), getAttributes());
 	}
 
 	/**
-	 * @return the EOL stream type of the current entry using the config and
-	 *         {@link #getAttributes()} Note that this method may return null if
-	 *         the {@link TreeWalk} is not based on a working tree
-	 * @since 4.3
+	 * Reset this walker so new tree iterators can be added to it.
 	 */
-	// TODO(msohn) deprecate this method in 4.4
-	public @Nullable EolStreamType getEolStreamType() {
-		return (getEolStreamType(operationType));
-	}
-
-	/** Reset this walker so new tree iterators can be added to it. */
 	public void reset() {
 		attrs = null;
 		attributesHandler = null;
@@ -628,19 +649,19 @@ public void reset() {
 	 * @param id
 	 *            the tree we need to parse. The walker will execute over this
 	 *            single tree if the reset is successful.
-	 * @throws MissingObjectException
+	 * @throws org.eclipse.jgit.errors.MissingObjectException
 	 *             the given tree object does not exist in this repository.
-	 * @throws IncorrectObjectTypeException
+	 * @throws org.eclipse.jgit.errors.IncorrectObjectTypeException
 	 *             the given object id does not denote a tree, but instead names
 	 *             some other non-tree type of object. Note that commits are not
 	 *             trees, even if they are sometimes called a "tree-ish".
-	 * @throws CorruptObjectException
+	 * @throws org.eclipse.jgit.errors.CorruptObjectException
 	 *             the object claimed to be a tree, but its contents did not
 	 *             appear to be a tree. The repository may have data corruption.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             a loose object or pack file could not be read.
 	 */
-	public void reset(final AnyObjectId id) throws MissingObjectException,
+	public void reset(AnyObjectId id) throws MissingObjectException,
 			IncorrectObjectTypeException, CorruptObjectException, IOException {
 		if (trees.length == 1) {
 			AbstractTreeIterator o = trees[0];
@@ -669,19 +690,19 @@ public void reset(final AnyObjectId id) throws MissingObjectException,
 	 * @param ids
 	 *            the trees we need to parse. The walker will execute over this
 	 *            many parallel trees if the reset is successful.
-	 * @throws MissingObjectException
+	 * @throws org.eclipse.jgit.errors.MissingObjectException
 	 *             the given tree object does not exist in this repository.
-	 * @throws IncorrectObjectTypeException
+	 * @throws org.eclipse.jgit.errors.IncorrectObjectTypeException
 	 *             the given object id does not denote a tree, but instead names
 	 *             some other non-tree type of object. Note that commits are not
 	 *             trees, even if they are sometimes called a "tree-ish".
-	 * @throws CorruptObjectException
+	 * @throws org.eclipse.jgit.errors.CorruptObjectException
 	 *             the object claimed to be a tree, but its contents did not
 	 *             appear to be a tree. The repository may have data corruption.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             a loose object or pack file could not be read.
 	 */
-	public void reset(final AnyObjectId... ids) throws MissingObjectException,
+	public void reset(AnyObjectId... ids) throws MissingObjectException,
 			IncorrectObjectTypeException, CorruptObjectException, IOException {
 		final int oldLen = trees.length;
 		final int newLen = ids.length;
@@ -724,19 +745,19 @@ public void reset(final AnyObjectId... ids) throws MissingObjectException,
 	 * @param id
 	 *            identity of the tree object the caller wants walked.
 	 * @return position of this tree within the walker.
-	 * @throws MissingObjectException
+	 * @throws org.eclipse.jgit.errors.MissingObjectException
 	 *             the given tree object does not exist in this repository.
-	 * @throws IncorrectObjectTypeException
+	 * @throws org.eclipse.jgit.errors.IncorrectObjectTypeException
 	 *             the given object id does not denote a tree, but instead names
 	 *             some other non-tree type of object. Note that commits are not
 	 *             trees, even if they are sometimes called a "tree-ish".
-	 * @throws CorruptObjectException
+	 * @throws org.eclipse.jgit.errors.CorruptObjectException
 	 *             the object claimed to be a tree, but its contents did not
 	 *             appear to be a tree. The repository may have data corruption.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             a loose object or pack file could not be read.
 	 */
-	public int addTree(final AnyObjectId id) throws MissingObjectException,
+	public int addTree(AnyObjectId id) throws MissingObjectException,
 			IncorrectObjectTypeException, CorruptObjectException, IOException {
 		return addTree(parserFor(id));
 	}
@@ -784,19 +805,19 @@ public int getTreeCount() {
 	 *
 	 * @return true if there is an entry available; false if all entries have
 	 *         been walked and the walk of this set of tree iterators is over.
-	 * @throws MissingObjectException
+	 * @throws org.eclipse.jgit.errors.MissingObjectException
 	 *             {@link #isRecursive()} was enabled, a subtree was found, but
 	 *             the subtree object does not exist in this repository. The
 	 *             repository may be missing objects.
-	 * @throws IncorrectObjectTypeException
+	 * @throws org.eclipse.jgit.errors.IncorrectObjectTypeException
 	 *             {@link #isRecursive()} was enabled, a subtree was found, and
 	 *             the subtree id does not denote a tree, but instead names some
 	 *             other non-tree type of object. The repository may have data
 	 *             corruption.
-	 * @throws CorruptObjectException
+	 * @throws org.eclipse.jgit.errors.CorruptObjectException
 	 *             the contents of a tree did not appear to be a tree. The
 	 *             repository may have data corruption.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             a loose object or pack file could not be read.
 	 */
 	public boolean next() throws MissingObjectException,
@@ -871,8 +892,6 @@ void stopWalk() throws IOException {
 	 * iterators to manage only one list of items, with the diving handled by
 	 * recursive trees.
 	 *
-	 * @param <T>
-	 *            type of the tree iterator expected by the caller.
 	 * @param nth
 	 *            tree to obtain the current iterator of.
 	 * @param clazz
@@ -888,38 +907,42 @@ public <T extends AbstractTreeIterator> T getTree(final int nth,
 	}
 
 	/**
-	 * Obtain the raw {@link FileMode} bits for the current entry.
+	 * Obtain the raw {@link org.eclipse.jgit.lib.FileMode} bits for the current
+	 * entry.
 	 * <p>
 	 * Every added tree supplies mode bits, even if the tree does not contain
-	 * the current entry. In the latter case {@link FileMode#MISSING}'s mode
-	 * bits (0) are returned.
+	 * the current entry. In the latter case
+	 * {@link org.eclipse.jgit.lib.FileMode#MISSING}'s mode bits (0) are
+	 * returned.
 	 *
 	 * @param nth
 	 *            tree to obtain the mode bits from.
 	 * @return mode bits for the current entry of the nth tree.
 	 * @see FileMode#fromBits(int)
 	 */
-	public int getRawMode(final int nth) {
+	public int getRawMode(int nth) {
 		final AbstractTreeIterator t = trees[nth];
 		return t.matches == currentHead ? t.mode : 0;
 	}
 
 	/**
-	 * Obtain the {@link FileMode} for the current entry.
+	 * Obtain the {@link org.eclipse.jgit.lib.FileMode} for the current entry.
 	 * <p>
 	 * Every added tree supplies a mode, even if the tree does not contain the
-	 * current entry. In the latter case {@link FileMode#MISSING} is returned.
+	 * current entry. In the latter case
+	 * {@link org.eclipse.jgit.lib.FileMode#MISSING} is returned.
 	 *
 	 * @param nth
 	 *            tree to obtain the mode from.
 	 * @return mode for the current entry of the nth tree.
 	 */
-	public FileMode getFileMode(final int nth) {
+	public FileMode getFileMode(int nth) {
 		return FileMode.fromBits(getRawMode(nth));
 	}
 
 	/**
-	 * Obtain the {@link FileMode} for the current entry on the currentHead tree
+	 * Obtain the {@link org.eclipse.jgit.lib.FileMode} for the current entry on
+	 * the currentHead tree
 	 *
 	 * @return mode for the current entry of the currentHead tree.
 	 * @since 4.3
@@ -937,15 +960,18 @@ public FileMode getFileMode() {
 	 * whenever possible.
 	 * <p>
 	 * Every tree supplies an object id, even if the tree does not contain the
-	 * current entry. In the latter case {@link ObjectId#zeroId()} is returned.
+	 * current entry. In the latter case
+	 * {@link org.eclipse.jgit.lib.ObjectId#zeroId()} is returned.
 	 *
 	 * @param nth
 	 *            tree to obtain the object identifier from.
 	 * @return object identifier for the current tree entry.
 	 * @see #getObjectId(MutableObjectId, int)
 	 * @see #idEqual(int, int)
+	 * @see #getObjectId(MutableObjectId, int)
+	 * @see #idEqual(int, int)
 	 */
-	public ObjectId getObjectId(final int nth) {
+	public ObjectId getObjectId(int nth) {
 		final AbstractTreeIterator t = trees[nth];
 		return t.matches == currentHead ? t.getEntryObjectId() : ObjectId
 				.zeroId();
@@ -955,7 +981,8 @@ public ObjectId getObjectId(final int nth) {
 	 * Obtain the ObjectId for the current entry.
 	 * <p>
 	 * Every tree supplies an object id, even if the tree does not contain the
-	 * current entry. In the latter case {@link ObjectId#zeroId()} is supplied.
+	 * current entry. In the latter case
+	 * {@link org.eclipse.jgit.lib.ObjectId#zeroId()} is supplied.
 	 * <p>
 	 * Applications should try to use {@link #idEqual(int, int)} when possible
 	 * as it avoids conversion overheads.
@@ -966,7 +993,7 @@ public ObjectId getObjectId(final int nth) {
 	 *            tree to obtain the object identifier from.
 	 * @see #idEqual(int, int)
 	 */
-	public void getObjectId(final MutableObjectId out, final int nth) {
+	public void getObjectId(MutableObjectId out, int nth) {
 		final AbstractTreeIterator t = trees[nth];
 		if (t.matches == currentHead)
 			t.getEntryObjectId(out);
@@ -985,7 +1012,7 @@ public void getObjectId(final MutableObjectId out, final int nth) {
 	 *         <code>getObjectId(nthA).equals(getObjectId(nthB))</code>.
 	 * @see #getObjectId(int)
 	 */
-	public boolean idEqual(final int nthA, final int nthB) {
+	public boolean idEqual(int nthA, int nthB) {
 		final AbstractTreeIterator ch = currentHead;
 		final AbstractTreeIterator a = trees[nthA];
 		final AbstractTreeIterator b = trees[nthB];
@@ -1053,6 +1080,8 @@ public String getPathString() {
 	}
 
 	/**
+	 * Get the path length of the current entry.
+	 *
 	 * @return The path length of the current entry.
 	 */
 	public int getPathLength() {
@@ -1081,7 +1110,7 @@ public int getPathLength() {
 	 *         again on this tree walk.
 	 * @since 4.7
 	 */
-	public int isPathMatch(final byte[] p, final int pLen) {
+	public int isPathMatch(byte[] p, int pLen) {
 		final AbstractTreeIterator t = currentHead;
 		final byte[] c = t.path;
 		final int cLen = t.pathLen;
@@ -1134,7 +1163,7 @@ public int isPathMatch(final byte[] p, final int pLen) {
 	 *         path; 1 if the current path is past p and p will never match
 	 *         again on this tree walk.
 	 */
-	public int isPathPrefix(final byte[] p, final int pLen) {
+	public int isPathPrefix(byte[] p, int pLen) {
 		final AbstractTreeIterator t = currentHead;
 		final byte[] c = t.path;
 		final int cLen = t.pathLen;
@@ -1184,7 +1213,7 @@ public int isPathPrefix(final byte[] p, final int pLen) {
 	 * @return true if p is suffix of the current path;
 	 *         false if otherwise
 	 */
-	public boolean isPathSuffix(final byte[] p, final int pLen) {
+	public boolean isPathSuffix(byte[] p, int pLen) {
 		final AbstractTreeIterator t = currentHead;
 		final byte[] c = t.path;
 		final int cLen = t.pathLen;
@@ -1241,17 +1270,17 @@ public boolean isPostChildren() {
 	 * If the current entry is a subtree this method arranges for its children
 	 * to be returned before the next sibling following the subtree is returned.
 	 *
-	 * @throws MissingObjectException
+	 * @throws org.eclipse.jgit.errors.MissingObjectException
 	 *             a subtree was found, but the subtree object does not exist in
 	 *             this repository. The repository may be missing objects.
-	 * @throws IncorrectObjectTypeException
+	 * @throws org.eclipse.jgit.errors.IncorrectObjectTypeException
 	 *             a subtree was found, and the subtree id does not denote a
 	 *             tree, but instead names some other non-tree type of object.
 	 *             The repository may have data corruption.
-	 * @throws CorruptObjectException
+	 * @throws org.eclipse.jgit.errors.CorruptObjectException
 	 *             the contents of a tree did not appear to be a tree. The
 	 *             repository may have data corruption.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             a loose object or pack file could not be read.
 	 */
 	public void enterSubtree() throws MissingObjectException,
@@ -1332,7 +1361,7 @@ void exitSubtree() {
 			trees[i] = trees[i].parent;
 
 		AbstractTreeIterator minRef = null;
-		for (final AbstractTreeIterator t : trees) {
+		for (AbstractTreeIterator t : trees) {
 			if (t.matches != t)
 				continue;
 			if (minRef == null || t.pathCompare(minRef) < 0)
@@ -1341,26 +1370,30 @@ void exitSubtree() {
 		currentHead = minRef;
 	}
 
-	private CanonicalTreeParser parserFor(final AnyObjectId id)
+	private CanonicalTreeParser parserFor(AnyObjectId id)
 			throws IncorrectObjectTypeException, IOException {
 		final CanonicalTreeParser p = new CanonicalTreeParser();
 		p.reset(reader, id);
 		return p;
 	}
 
-	static String pathOf(final AbstractTreeIterator t) {
+	static String pathOf(AbstractTreeIterator t) {
 		return RawParseUtils.decode(Constants.CHARSET, t.path, 0, t.pathLen);
 	}
 
-	static String pathOf(final byte[] buf, int pos, int end) {
+	static String pathOf(byte[] buf, int pos, int end) {
 		return RawParseUtils.decode(Constants.CHARSET, buf, pos, end);
 	}
 
 	/**
+	 * Get the tree of that type.
+	 *
 	 * @param type
 	 *            of the tree to be queried
-	 * @return the tree of that type or null if none is present
+	 * @return the tree of that type or null if none is present.
 	 * @since 4.3
+	 * @param <T>
+	 *            a tree type.
 	 */
 	public <T extends AbstractTreeIterator> T getTree(
 			Class<T> type) {
@@ -1375,13 +1408,13 @@ public <T extends AbstractTreeIterator> T getTree(
 
 	/**
 	 * Inspect config and attributes to return a filtercommand applicable for
-	 * the current path
+	 * the current path, but without expanding %f occurences
 	 *
 	 * @param filterCommandType
 	 *            which type of filterCommand should be executed. E.g. "clean",
 	 *            "smudge"
 	 * @return a filter command
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 * @since 4.2
 	 */
 	public String getFilterCommand(String filterCommandType)
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeIterator.java b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeIterator.java
index b1b146c..179fd46 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeIterator.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeIterator.java
@@ -60,6 +60,8 @@
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.Comparator;
+import java.util.HashMap;
+import java.util.Map;
 
 import org.eclipse.jgit.api.errors.FilterFailedException;
 import org.eclipse.jgit.attributes.AttributesNode;
@@ -67,7 +69,6 @@
 import org.eclipse.jgit.attributes.FilterCommand;
 import org.eclipse.jgit.attributes.FilterCommandRegistry;
 import org.eclipse.jgit.diff.RawText;
-import org.eclipse.jgit.dircache.DirCache;
 import org.eclipse.jgit.dircache.DirCacheEntry;
 import org.eclipse.jgit.dircache.DirCacheIterator;
 import org.eclipse.jgit.errors.CorruptObjectException;
@@ -101,13 +102,15 @@
 import org.eclipse.jgit.util.sha1.SHA1;
 
 /**
- * Walks a working directory tree as part of a {@link TreeWalk}.
+ * Walks a working directory tree as part of a
+ * {@link org.eclipse.jgit.treewalk.TreeWalk}.
  * <p>
  * Most applications will want to use the standard implementation of this
- * iterator, {@link FileTreeIterator}, as that does all IO through the standard
- * <code>java.io</code> package. Plugins for a Java based IDE may however wish
- * to create their own implementations of this class to allow traversal of the
- * IDE's project space, as well as benefit from any caching the IDE may have.
+ * iterator, {@link org.eclipse.jgit.treewalk.FileTreeIterator}, as that does
+ * all IO through the standard <code>java.io</code> package. Plugins for a Java
+ * based IDE may however wish to create their own implementations of this class
+ * to allow traversal of the IDE's project space, as well as benefit from any
+ * caching the IDE may have.
  *
  * @see FileTreeIterator
  */
@@ -208,7 +211,7 @@ protected WorkingTreeIterator(final String prefix,
 	 * @param p
 	 *            parent tree iterator.
 	 */
-	protected WorkingTreeIterator(final WorkingTreeIterator p) {
+	protected WorkingTreeIterator(WorkingTreeIterator p) {
 		super(p);
 		state = p.state;
 		repository = p.repository;
@@ -234,7 +237,8 @@ protected void initRootIterator(Repository repo) {
 	}
 
 	/**
-	 * Define the matching {@link DirCacheIterator}, to optimize ObjectIds.
+	 * Define the matching {@link org.eclipse.jgit.dircache.DirCacheIterator},
+	 * to optimize ObjectIds.
 	 *
 	 * Once the DirCacheIterator has been set this iterator must only be
 	 * advanced by the TreeWalk that is supplied, as it assumes that itself and
@@ -244,13 +248,54 @@ protected void initRootIterator(Repository repo) {
 	 * @param walk
 	 *            the walk that will be advancing this iterator.
 	 * @param treeId
-	 *            index of the matching {@link DirCacheIterator}.
+	 *            index of the matching
+	 *            {@link org.eclipse.jgit.dircache.DirCacheIterator}.
 	 */
 	public void setDirCacheIterator(TreeWalk walk, int treeId) {
 		state.walk = walk;
 		state.dirCacheTree = treeId;
 	}
 
+	/**
+	 * Retrieves the {@link DirCacheIterator} at the current entry if
+	 * {@link #setDirCacheIterator(TreeWalk, int)} was called.
+	 *
+	 * @return the DirCacheIterator, or {@code null} if not set or not at the
+	 *         current entry
+	 * @since 5.0
+	 */
+	protected DirCacheIterator getDirCacheIterator() {
+		if (state.dirCacheTree >= 0 && state.walk != null) {
+			return state.walk.getTree(state.dirCacheTree,
+					DirCacheIterator.class);
+		}
+		return null;
+	}
+
+	/**
+	 * Defines whether this {@link WorkingTreeIterator} walks ignored
+	 * directories.
+	 *
+	 * @param includeIgnored
+	 *            {@code false} to skip ignored directories, if possible;
+	 *            {@code true} to always include them in the walk
+	 * @since 5.0
+	 */
+	public void setWalkIgnoredDirectories(boolean includeIgnored) {
+		state.walkIgnored = includeIgnored;
+	}
+
+	/**
+	 * Tells whether this {@link WorkingTreeIterator} walks ignored directories.
+	 *
+	 * @return {@code true} if it does, {@code false} otherwise
+	 * @since 5.0
+	 */
+	public boolean walksIgnoredDirectories() {
+		return state.walkIgnored;
+	}
+
+	/** {@inheritDoc} */
 	@Override
 	public boolean hasId() {
 		if (contentIdFromPtr == ptr)
@@ -258,6 +303,7 @@ public boolean hasId() {
 		return (mode & FileMode.TYPE_MASK) == FileMode.TYPE_FILE;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public byte[] idBuffer() {
 		if (contentIdFromPtr == ptr)
@@ -295,6 +341,7 @@ public boolean hasId() {
 		return zeroid;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public boolean isWorkTree() {
 		return true;
@@ -304,6 +351,8 @@ public boolean isWorkTree() {
 	 * Get submodule id for given entry.
 	 *
 	 * @param e
+	 *            a {@link org.eclipse.jgit.treewalk.WorkingTreeIterator.Entry}
+	 *            object.
 	 * @return non-null submodule id
 	 */
 	protected byte[] idSubmodule(Entry e) {
@@ -323,33 +372,29 @@ public boolean isWorkTree() {
 	 * relative to the directory.
 	 *
 	 * @param directory
+	 *            a {@link java.io.File} object.
 	 * @param e
+	 *            a {@link org.eclipse.jgit.treewalk.WorkingTreeIterator.Entry}
+	 *            object.
 	 * @return non-null submodule id
 	 */
 	protected byte[] idSubmodule(File directory, Entry e) {
-		final Repository submoduleRepo;
-		try {
-			submoduleRepo = SubmoduleWalk.getSubmoduleRepository(directory,
-					e.getName());
+		try (Repository submoduleRepo = SubmoduleWalk.getSubmoduleRepository(
+				directory, e.getName(),
+				repository != null ? repository.getFS() : FS.DETECTED)) {
+			if (submoduleRepo == null) {
+				return zeroid;
+			}
+			ObjectId head = submoduleRepo.resolve(Constants.HEAD);
+			if (head == null) {
+				return zeroid;
+			}
+			byte[] id = new byte[Constants.OBJECT_ID_LENGTH];
+			head.copyRawTo(id, 0);
+			return id;
 		} catch (IOException exception) {
 			return zeroid;
 		}
-		if (submoduleRepo == null)
-			return zeroid;
-
-		final ObjectId head;
-		try {
-			head = submoduleRepo.resolve(Constants.HEAD);
-		} catch (IOException exception) {
-			return zeroid;
-		} finally {
-			submoduleRepo.close();
-		}
-		if (head == null)
-			return zeroid;
-		final byte[] id = new byte[Constants.OBJECT_ID_LENGTH];
-		head.copyRawTo(id, 0);
-		return id;
 	}
 
 	private static final byte[] digits = { '0', '1', '2', '3', '4', '5', '6',
@@ -358,7 +403,7 @@ public boolean isWorkTree() {
 	private static final byte[] hblob = Constants
 			.encodedTypeString(Constants.OBJ_BLOB);
 
-	private byte[] idBufferBlob(final Entry e) {
+	private byte[] idBufferBlob(Entry e) {
 		try {
 			final InputStream is = e.openInputStream();
 			if (is == null)
@@ -416,7 +461,7 @@ && getEolStreamType(opType) == EolStreamType.DIRECT) {
 		return filterClean(is, opType);
 	}
 
-	private static void safeClose(final InputStream in) {
+	private static void safeClose(InputStream in) {
 		try {
 			in.close();
 		} catch (IOException err2) {
@@ -462,7 +507,7 @@ private InputStream filterClean(InputStream in, OperationType opType)
 				while (command.run() != -1) {
 					// loop as long as command.run() tells there is work to do
 				}
-				return buffer.openInputStream();
+				return buffer.openInputStreamWithAutoDestroy();
 			}
 			FS fs = repository.getFS();
 			ProcessBuilder filterProcessBuilder = fs.runInShell(filterCommand,
@@ -485,7 +530,7 @@ filterCommand, getEntryPathString(),
 						RawParseUtils.decode(result.getStderr()
 								.toByteArray(MAX_EXCEPTION_TEXT_SIZE))));
 			}
-			return result.getStdout().openInputStream();
+			return result.getStdout().openInputStreamWithAutoDestroy();
 		}
 		return in;
 	}
@@ -504,11 +549,13 @@ public WorkingTreeOptions getOptions() {
 		return state.options;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public int idOffset() {
 		return contentIdOffset;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void reset() {
 		if (!first()) {
@@ -518,26 +565,30 @@ public void reset() {
 		}
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public boolean first() {
 		return ptr == 0;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public boolean eof() {
 		return ptr == entryCnt;
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	public void next(final int delta) throws CorruptObjectException {
+	public void next(int delta) throws CorruptObjectException {
 		ptr += delta;
 		if (!eof()) {
 			parseEntry();
 		}
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	public void back(final int delta) throws CorruptObjectException {
+	public void back(int delta) throws CorruptObjectException {
 		ptr -= delta;
 		parseEntry();
 	}
@@ -568,7 +619,7 @@ public long getEntryLength() {
 	 * Get the filtered input length of this entry
 	 *
 	 * @return size of the content, in bytes
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 */
 	public long getEntryContentLength() throws IOException {
 		if (canonLen == -1) {
@@ -610,7 +661,7 @@ public long getEntryLastModified() {
 	 * The caller will close the stream once complete.
 	 *
 	 * @return a stream to read from the file.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the file could not be opened for reading.
 	 */
 	public InputStream openEntryStream() throws IOException {
@@ -626,7 +677,7 @@ && getEolStreamType() == EolStreamType.DIRECT)
 	 * Determine if the current entry path is ignored by an ignore rule.
 	 *
 	 * @return true if the entry was ignored by an ignore rule file.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             a relevant ignore rule file exists but cannot be read.
 	 */
 	public boolean isEntryIgnored() throws IOException {
@@ -639,58 +690,64 @@ public boolean isEntryIgnored() throws IOException {
 	 * @param pLen
 	 *            the length of the path in the path buffer.
 	 * @return true if the entry is ignored by an ignore rule.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             a relevant ignore rule file exists but cannot be read.
 	 */
-	protected boolean isEntryIgnored(final int pLen) throws IOException {
-		return isEntryIgnored(pLen, mode, false);
+	protected boolean isEntryIgnored(int pLen) throws IOException {
+		return isEntryIgnored(pLen, mode);
 	}
 
 	/**
-	 * Determine if the entry path is ignored by an ignore rule. Consider
-	 * possible rule negation from child iterator.
+	 * Determine if the entry path is ignored by an ignore rule.
 	 *
 	 * @param pLen
 	 *            the length of the path in the path buffer.
 	 * @param fileMode
 	 *            the original iterator file mode
-	 * @param negatePrevious
-	 *            true if the previous matching iterator rule was negation
 	 * @return true if the entry is ignored by an ignore rule.
 	 * @throws IOException
 	 *             a relevant ignore rule file exists but cannot be read.
 	 */
-	private boolean isEntryIgnored(final int pLen, int fileMode,
-			boolean negatePrevious)
+	private boolean isEntryIgnored(int pLen, int fileMode)
 			throws IOException {
-		IgnoreNode rules = getIgnoreNode();
-		if (rules != null) {
-			// The ignore code wants path to start with a '/' if possible.
-			// If we have the '/' in our path buffer because we are inside
-			// a subdirectory include it in the range we convert to string.
-			//
-			int pOff = pathOffset;
-			if (0 < pOff)
-				pOff--;
-			String p = TreeWalk.pathOf(path, pOff, pLen);
-			switch (rules.isIgnored(p, FileMode.TREE.equals(fileMode),
-					negatePrevious)) {
-			case IGNORED:
-				return true;
-			case NOT_IGNORED:
-				return false;
-			case CHECK_PARENT:
-				negatePrevious = false;
-				break;
-			case CHECK_PARENT_NEGATE_FIRST_MATCH:
-				negatePrevious = true;
-				break;
-			}
+		// The ignore code wants path to start with a '/' if possible.
+		// If we have the '/' in our path buffer because we are inside
+		// a sub-directory include it in the range we convert to string.
+		//
+		final int pOff = 0 < pathOffset ? pathOffset - 1 : pathOffset;
+		String pathRel = TreeWalk.pathOf(this.path, pOff, pLen);
+		String parentRel = getParentPath(pathRel);
+
+		// CGit is processing .gitignore files by starting at the root of the
+		// repository and then recursing into subdirectories. With this
+		// approach, top-level ignored directories will be processed first which
+		// allows to skip entire subtrees and further .gitignore-file processing
+		// within these subtrees.
+		//
+		// We will follow the same approach by marking directories as "ignored"
+		// here. This allows to have a simplified FastIgnore.checkIgnore()
+		// implementation (both in terms of code and computational complexity):
+		//
+		// Without the "ignored" flag, we would have to apply the ignore-check
+		// to a path and all of its parents always(!), to determine whether a
+		// path is ignored directly or by one of its parent directories; with
+		// the "ignored" flag, we know at this point that the parent directory
+		// is definitely not ignored, thus the path can only become ignored if
+		// there is a rule matching the path itself.
+		if (isDirectoryIgnored(parentRel)) {
+			return true;
 		}
-		if (parent instanceof WorkingTreeIterator)
-			return ((WorkingTreeIterator) parent).isEntryIgnored(pLen, fileMode,
-					negatePrevious);
-		return false;
+
+		IgnoreNode rules = getIgnoreNode();
+		final Boolean ignored = rules != null
+				? rules.checkIgnored(pathRel, FileMode.TREE.equals(fileMode))
+				: null;
+		if (ignored != null) {
+			return ignored.booleanValue();
+		}
+		return parent instanceof WorkingTreeIterator
+				&& ((WorkingTreeIterator) parent).isEntryIgnored(pLen,
+						fileMode);
 	}
 
 	private IgnoreNode getIgnoreNode() throws IOException {
@@ -700,12 +757,12 @@ private IgnoreNode getIgnoreNode() throws IOException {
 	}
 
 	/**
-	 * Retrieves the {@link AttributesNode} for the current entry.
+	 * Retrieves the {@link org.eclipse.jgit.attributes.AttributesNode} for the
+	 * current entry.
 	 *
-	 * @return {@link AttributesNode} for the current entry.
+	 * @return the {@link org.eclipse.jgit.attributes.AttributesNode} for the
+	 *         current entry.
 	 * @throws IOException
-	 *             if an error is raised while parsing the .gitattributes file
-	 * @since 3.7
 	 */
 	public AttributesNode getEntryAttributesNode() throws IOException {
 		if (attributesNode instanceof PerDirectoryAttributesNode)
@@ -730,7 +787,7 @@ public int compare(Entry a, Entry b) {
 	 *            files in the subtree of the work tree this iterator operates
 	 *            on
 	 */
-	protected void init(final Entry[] list) {
+	protected void init(Entry[] list) {
 		// Filter out nulls, . and .. as these are not valid tree entries,
 		// also cache the encoded forms of the path names for efficient use
 		// later on during sorting and iteration.
@@ -809,9 +866,10 @@ public enum MetadataDiff {
 	 * Is the file mode of the current entry different than the given raw mode?
 	 *
 	 * @param rawMode
+	 *            an int.
 	 * @return true if different, false otherwise
 	 */
-	public boolean isModeDifferent(final int rawMode) {
+	public boolean isModeDifferent(int rawMode) {
 		// Determine difference in mode-bits of file and index-entry. In the
 		// bitwise presentation of modeDiff we'll have a '1' when the two modes
 		// differ at this position.
@@ -835,12 +893,14 @@ public boolean isModeDifferent(final int rawMode) {
 
 	/**
 	 * Compare the metadata (mode, length, modification-timestamp) of the
-	 * current entry and a {@link DirCacheEntry}
+	 * current entry and a {@link org.eclipse.jgit.dircache.DirCacheEntry}
 	 *
 	 * @param entry
-	 *            the {@link DirCacheEntry} to compare with
-	 * @return a {@link MetadataDiff} which tells whether and how the entries
-	 *         metadata differ
+	 *            the {@link org.eclipse.jgit.dircache.DirCacheEntry} to compare
+	 *            with
+	 * @return a
+	 *         {@link org.eclipse.jgit.treewalk.WorkingTreeIterator.MetadataDiff}
+	 *         which tells whether and how the entries metadata differ
 	 */
 	public MetadataDiff compareMetadata(DirCacheEntry entry) {
 		if (entry.isAssumeValid())
@@ -890,7 +950,7 @@ else if (!entry.isSmudged())
 
 	/**
 	 * Checks whether this entry differs from a given entry from the
-	 * {@link DirCache}.
+	 * {@link org.eclipse.jgit.dircache.DirCache}.
 	 *
 	 * File status information is used and if status is same we consider the
 	 * file identical to the state in the working directory. Native git uses
@@ -904,7 +964,7 @@ else if (!entry.isSmudged())
 	 * @param reader
 	 *            access to repository objects if necessary. Should not be null.
 	 * @return true if content is most likely different.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 * @since 3.3
 	 */
 	public boolean isModified(DirCacheEntry entry, boolean forceContentCheck,
@@ -931,7 +991,19 @@ public boolean isModified(DirCacheEntry entry, boolean forceContentCheck,
 			}
 			return false;
 		case DIFFER_BY_METADATA:
-			if (mode == FileMode.SYMLINK.getBits())
+			if (mode == FileMode.TREE.getBits()
+					&& entry.getFileMode().equals(FileMode.GITLINK)) {
+				byte[] idBuffer = idBuffer();
+				int idOffset = idOffset();
+				if (entry.getObjectId().compareTo(idBuffer, idOffset) == 0) {
+					return true;
+				} else if (ObjectId.zeroId().compareTo(idBuffer,
+						idOffset) == 0) {
+					return new File(repository.getWorkTree(),
+							entry.getPathString()).list().length > 0;
+				}
+				return false;
+			} else if (mode == FileMode.SYMLINK.getBits())
 				return contentCheck(entry, reader);
 			return true;
 		default:
@@ -945,12 +1017,13 @@ public boolean isModified(DirCacheEntry entry, boolean forceContentCheck,
 	 * in the index.
 	 *
 	 * @param indexIter
-	 *            {@link DirCacheIterator} positioned at the same entry as this
-	 *            iterator or null if no {@link DirCacheIterator} is available
-	 *            at this iterator's current entry
+	 *            {@link org.eclipse.jgit.dircache.DirCacheIterator} positioned
+	 *            at the same entry as this iterator or null if no
+	 *            {@link org.eclipse.jgit.dircache.DirCacheIterator} is
+	 *            available at this iterator's current entry
 	 * @return index file mode
 	 */
-	public FileMode getIndexFileMode(final DirCacheIterator indexIter) {
+	public FileMode getIndexFileMode(DirCacheIterator indexIter) {
 		final FileMode wtMode = getEntryFileMode();
 		if (indexIter == null) {
 			return wtMode;
@@ -1067,7 +1140,7 @@ private static String readContentAsNormalizedString(DirCacheEntry entry,
 	 * @param entry
 	 *            to read
 	 * @return the entry's content as a normalized string
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             if the entry cannot be read or does not denote a symlink
 	 * @since 4.6
 	 */
@@ -1131,13 +1204,17 @@ private static long computeLength(InputStream in) throws IOException {
 		return contentDigest.digest();
 	}
 
-	/** A single entry within a working directory tree. */
-	protected static abstract class Entry {
+	/**
+	 * A single entry within a working directory tree.
+	 *
+	 * @since 5.0
+	 */
+	public static abstract class Entry {
 		byte[] encodedName;
 
 		int encodedNameLen;
 
-		void encodeName(final CharsetEncoder enc) {
+		void encodeName(CharsetEncoder enc) {
 			final ByteBuffer b;
 			try {
 				b = enc.encode(CharBuffer.wrap(getName()));
@@ -1238,11 +1315,8 @@ private static class PerDirectoryIgnoreNode extends IgnoreNode {
 
 		IgnoreNode load() throws IOException {
 			IgnoreNode r = new IgnoreNode();
-			InputStream in = entry.openInputStream();
-			try {
+			try (InputStream in = entry.openInputStream()) {
 				r.parse(in);
-			} finally {
-				in.close();
 			}
 			return r.getRules().isEmpty() ? null : r;
 		}
@@ -1290,11 +1364,8 @@ IgnoreNode load() throws IOException {
 		private static void loadRulesFromFile(IgnoreNode r, File exclude)
 				throws FileNotFoundException, IOException {
 			if (FS.DETECTED.exists(exclude)) {
-				FileInputStream in = new FileInputStream(exclude);
-				try {
+				try (FileInputStream in = new FileInputStream(exclude)) {
 					r.parse(in);
-				} finally {
-					in.close();
 				}
 			}
 		}
@@ -1311,11 +1382,8 @@ private static class PerDirectoryAttributesNode extends AttributesNode {
 
 		AttributesNode load() throws IOException {
 			AttributesNode r = new AttributesNode();
-			InputStream in = entry.openInputStream();
-			try {
+			try (InputStream in = entry.openInputStream()) {
 				r.parse(in);
-			} finally {
-				in.close();
 			}
 			return r.getRules().isEmpty() ? null : r;
 		}
@@ -1336,7 +1404,12 @@ private static final class IteratorState {
 		TreeWalk walk;
 
 		/** Position of the matching {@link DirCacheIterator}. */
-		int dirCacheTree;
+		int dirCacheTree = -1;
+
+		/** Whether the iterator shall walk ignored directories. */
+		boolean walkIgnored = false;
+
+		final Map<String, Boolean> directoryToIgnored = new HashMap<>();
 
 		IteratorState(WorkingTreeOptions options) {
 			this.options = options;
@@ -1351,9 +1424,11 @@ void initializeReadBuffer() {
 	}
 
 	/**
+	 * Get the clean filter command for the current entry.
+	 *
 	 * @return the clean filter command for the current entry or
 	 *         <code>null</code> if no such command is defined
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 * @since 4.2
 	 */
 	public String getCleanFilterCommand() throws IOException {
@@ -1369,11 +1444,13 @@ public String getCleanFilterCommand() throws IOException {
 	}
 
 	/**
+	 * Get the eol stream type for the current entry.
+	 *
 	 * @return the eol stream type for the current entry or <code>null</code> if
 	 *         it cannot be determined. When state or state.walk is null or the
-	 *         {@link TreeWalk} is not based on a {@link Repository} then null
-	 *         is returned.
-	 * @throws IOException
+	 *         {@link org.eclipse.jgit.treewalk.TreeWalk} is not based on a
+	 *         {@link org.eclipse.jgit.lib.Repository} then null is returned.
+	 * @throws java.io.IOException
 	 * @since 4.3
 	 */
 	public EolStreamType getEolStreamType() throws IOException {
@@ -1394,11 +1471,7 @@ private EolStreamType getEolStreamType(OperationType opType)
 		if (eolStreamTypeHolder == null) {
 			EolStreamType type=null;
 			if (state.walk != null) {
-				if (opType != null) {
-					type = state.walk.getEolStreamType(opType);
-				} else {
-					type=state.walk.getEolStreamType();
-				}
+				type = state.walk.getEolStreamType(opType);
 			} else {
 				switch (getOptions().getAutoCRLF()) {
 				case FALSE:
@@ -1414,4 +1487,67 @@ private EolStreamType getEolStreamType(OperationType opType)
 		}
 		return eolStreamTypeHolder.get();
 	}
+
+	private boolean isDirectoryIgnored(String pathRel) throws IOException {
+		final int pOff = 0 < pathOffset ? pathOffset - 1 : pathOffset;
+		final String base = TreeWalk.pathOf(this.path, 0, pOff);
+		final String pathAbs = concatPath(base, pathRel);
+		return isDirectoryIgnored(pathRel, pathAbs);
+	}
+
+	private boolean isDirectoryIgnored(String pathRel, String pathAbs)
+			throws IOException {
+		assert pathRel.length() == 0 || (pathRel.charAt(0) != '/'
+				&& pathRel.charAt(pathRel.length() - 1) != '/');
+		assert pathAbs.length() == 0 || (pathAbs.charAt(0) != '/'
+				&& pathAbs.charAt(pathAbs.length() - 1) != '/');
+		assert pathAbs.endsWith(pathRel);
+
+		Boolean ignored = state.directoryToIgnored.get(pathAbs);
+		if (ignored != null) {
+			return ignored.booleanValue();
+		}
+
+		final String parentRel = getParentPath(pathRel);
+		if (parentRel != null && isDirectoryIgnored(parentRel)) {
+			state.directoryToIgnored.put(pathAbs, Boolean.TRUE);
+			return true;
+		}
+
+		final IgnoreNode node = getIgnoreNode();
+		for (String p = pathRel; node != null
+				&& !"".equals(p); p = getParentPath(p)) { //$NON-NLS-1$
+			ignored = node.checkIgnored(p, true);
+			if (ignored != null) {
+				state.directoryToIgnored.put(pathAbs, ignored);
+				return ignored.booleanValue();
+			}
+		}
+
+		if (!(this.parent instanceof WorkingTreeIterator)) {
+			state.directoryToIgnored.put(pathAbs, Boolean.FALSE);
+			return false;
+		}
+
+		final WorkingTreeIterator wtParent = (WorkingTreeIterator) this.parent;
+		final String parentRelPath = concatPath(
+				TreeWalk.pathOf(this.path, wtParent.pathOffset, pathOffset - 1),
+				pathRel);
+		assert concatPath(TreeWalk.pathOf(wtParent.path, 0,
+				Math.max(0, wtParent.pathOffset - 1)), parentRelPath)
+						.equals(pathAbs);
+		return wtParent.isDirectoryIgnored(parentRelPath, pathAbs);
+	}
+
+	private static String getParentPath(String path) {
+		final int slashIndex = path.lastIndexOf('/', path.length() - 2);
+		if (slashIndex > 0) {
+			return path.substring(path.charAt(0) == '/' ? 1 : 0, slashIndex);
+		}
+		return path.length() > 0 ? "" : null; //$NON-NLS-1$
+	}
+
+	private static String concatPath(String p1, String p2) {
+		return p1 + (p1.length() > 0 && p2.length() > 0 ? "/" : "") + p2; //$NON-NLS-1$ //$NON-NLS-2$
+	}
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeOptions.java b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeOptions.java
index 2b18904..846fb6e 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeOptions.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeOptions.java
@@ -52,7 +52,9 @@
 import org.eclipse.jgit.lib.CoreConfig.HideDotFiles;
 import org.eclipse.jgit.lib.CoreConfig.SymLinks;
 
-/** Options used by the {@link WorkingTreeIterator}. */
+/**
+ * Options used by the {@link org.eclipse.jgit.treewalk.WorkingTreeIterator}.
+ */
 public class WorkingTreeOptions {
 	/** Key for {@link Config#get(SectionParser)}. */
 	public static final Config.SectionParser<WorkingTreeOptions> KEY =
@@ -72,7 +74,7 @@ public class WorkingTreeOptions {
 
 	private final boolean dirNoGitLinks;
 
-	private WorkingTreeOptions(final Config rc) {
+	private WorkingTreeOptions(Config rc) {
 		fileMode = rc.getBoolean(ConfigConstants.CONFIG_CORE_SECTION,
 				ConfigConstants.CONFIG_KEY_FILEMODE, true);
 		autoCRLF = rc.getEnum(ConfigConstants.CONFIG_CORE_SECTION, null,
@@ -92,18 +94,29 @@ private WorkingTreeOptions(final Config rc) {
 	}
 
 	/** @return true if the execute bit on working files should be trusted. */
+	/**
+	 * Whether the execute bit on working files should be trusted.
+	 *
+	 * @return {@code true} if the execute bit on working files should be
+	 *         trusted.
+	 */
 	public boolean isFileMode() {
 		return fileMode;
 	}
 
-	/** @return how automatic CRLF conversion has been configured. */
+	/**
+	 * Get automatic CRLF conversion configuration.
+	 *
+	 * @return how automatic CRLF conversion has been configured.
+	 */
 	public AutoCRLF getAutoCRLF() {
 		return autoCRLF;
 	}
 
 	/**
-	 * @return how text line endings should be normalized.
+	 * Get how text line endings should be normalized.
 	 *
+	 * @return how text line endings should be normalized.
 	 * @since 4.3
 	 */
 	public EOL getEOL() {
@@ -111,7 +124,9 @@ public EOL getEOL() {
 	}
 
 	/**
-	 * @return how stat data is compared
+	 * Get how stat data is compared.
+	 *
+	 * @return how stat data is compared.
 	 * @since 3.0
 	 */
 	public CheckStat getCheckStat() {
@@ -119,6 +134,8 @@ public CheckStat getCheckStat() {
 	}
 
 	/**
+	 * Get how we handle symbolic links
+	 *
 	 * @return how we handle symbolic links
 	 * @since 3.3
 	 */
@@ -127,6 +144,8 @@ public SymLinks getSymLinks() {
 	}
 
 	/**
+	 * Get how we create '.'-files (on Windows)
+	 *
 	 * @return how we create '.'-files (on Windows)
 	 * @since 3.5
 	 */
@@ -135,9 +154,10 @@ public HideDotFiles getHideDotFiles() {
 	}
 
 	/**
-	 * @return whether or not we treat nested repos as directories.
-	 * 		   If true, folders containing .git entries will not be
-	 * 		   treated as gitlinks.
+	 * Whether or not we treat nested repos as directories.
+	 *
+	 * @return whether or not we treat nested repos as directories. If true,
+	 *         folders containing .git entries will not be treated as gitlinks.
 	 * @since 4.3
 	 */
 	public boolean isDirNoGitLinks() { return dirNoGitLinks; }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/filter/AndTreeFilter.java b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/filter/AndTreeFilter.java
index 9658166..a960bd7 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/filter/AndTreeFilter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/filter/AndTreeFilter.java
@@ -56,9 +56,10 @@
  * Includes a tree entry only if all subfilters include the same tree entry.
  * <p>
  * Classic shortcut behavior is used, so evaluation of the
- * {@link TreeFilter#include(TreeWalk)} method stops as soon as a false result
- * is obtained. Applications can improve filtering performance by placing faster
- * filters that are more likely to reject a result earlier in the list.
+ * {@link org.eclipse.jgit.treewalk.filter.TreeFilter#include(TreeWalk)} method
+ * stops as soon as a false result is obtained. Applications can improve
+ * filtering performance by placing faster filters that are more likely to
+ * reject a result earlier in the list.
  */
 public abstract class AndTreeFilter extends TreeFilter {
 	/**
@@ -70,7 +71,7 @@ public abstract class AndTreeFilter extends TreeFilter {
 	 *            second filter to test.
 	 * @return a filter that must match both input filters.
 	 */
-	public static TreeFilter create(final TreeFilter a, final TreeFilter b) {
+	public static TreeFilter create(TreeFilter a, TreeFilter b) {
 		if (a == ALL)
 			return b;
 		if (b == ALL)
@@ -86,7 +87,7 @@ public static TreeFilter create(final TreeFilter a, final TreeFilter b) {
 	 *            filters.
 	 * @return a filter that must match all input filters.
 	 */
-	public static TreeFilter create(final TreeFilter[] list) {
+	public static TreeFilter create(TreeFilter[] list) {
 		if (list.length == 2)
 			return create(list[0], list[1]);
 		if (list.length < 2)
@@ -104,7 +105,7 @@ public static TreeFilter create(final TreeFilter[] list) {
 	 *            filters.
 	 * @return a filter that must match all input filters.
 	 */
-	public static TreeFilter create(final Collection<TreeFilter> list) {
+	public static TreeFilter create(Collection<TreeFilter> list) {
 		if (list.size() < 2)
 			throw new IllegalArgumentException(JGitText.get().atLeastTwoFiltersNeeded);
 		final TreeFilter[] subfilters = new TreeFilter[list.size()];
@@ -119,13 +120,13 @@ private static class Binary extends AndTreeFilter {
 
 		private final TreeFilter b;
 
-		Binary(final TreeFilter one, final TreeFilter two) {
+		Binary(TreeFilter one, TreeFilter two) {
 			a = one;
 			b = two;
 		}
 
 		@Override
-		public boolean include(final TreeWalk walker)
+		public boolean include(TreeWalk walker)
 				throws MissingObjectException, IncorrectObjectTypeException,
 				IOException {
 			return matchFilter(walker) <= 0;
@@ -169,12 +170,12 @@ public String toString() {
 	private static class List extends AndTreeFilter {
 		private final TreeFilter[] subfilters;
 
-		List(final TreeFilter[] list) {
+		List(TreeFilter[] list) {
 			subfilters = list;
 		}
 
 		@Override
-		public boolean include(final TreeWalk walker)
+		public boolean include(TreeWalk walker)
 				throws MissingObjectException, IncorrectObjectTypeException,
 				IOException {
 			return matchFilter(walker) <= 0;
@@ -185,7 +186,7 @@ public int matchFilter(TreeWalk walker)
 				throws MissingObjectException, IncorrectObjectTypeException,
 				IOException {
 			int m = 0;
-			for (final TreeFilter f : subfilters) {
+			for (TreeFilter f : subfilters) {
 				int r = f.matchFilter(walker);
 				if (r == 1) {
 					return 1;
@@ -199,7 +200,7 @@ public int matchFilter(TreeWalk walker)
 
 		@Override
 		public boolean shouldBeRecursive() {
-			for (final TreeFilter f : subfilters)
+			for (TreeFilter f : subfilters)
 				if (f.shouldBeRecursive())
 					return true;
 			return false;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/filter/ByteArraySet.java b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/filter/ByteArraySet.java
index 91251e4..995561e 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/filter/ByteArraySet.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/filter/ByteArraySet.java
@@ -77,7 +77,7 @@ class ByteArraySet {
 		initTable(1 << Integer.highestOneBit((capacity * 2) - 1));
 	}
 
-	private byte[] get(final byte[] toFind, int length, int hash) {
+	private byte[] get(byte[] toFind, int length, int hash) {
 		final int msk = mask;
 		int i = hash & msk;
 		final byte[][] tbl = table;
@@ -112,7 +112,7 @@ private static boolean equals(byte[] storedObj, byte[] toFind, int length) {
 	 *            pre-computed hash of toFind
 	 * @return true if the mapping exists for this byte array; false otherwise.
 	 */
-	boolean contains(final byte[] toFind, int length, int hash) {
+	boolean contains(byte[] toFind, int length, int hash) {
 		return get(toFind, length, hash) != null;
 	}
 
@@ -180,7 +180,7 @@ boolean isEmpty() {
 		return size == 0;
 	}
 
-	private void insert(final byte[] newValue, int hash) {
+	private void insert(byte[] newValue, int hash) {
 		final int msk = mask;
 		int j = hash & msk;
 		final byte[][] tbl = table;
@@ -213,6 +213,7 @@ private void initTable(int sz) {
 		table = new byte[sz][];
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public String toString() {
 		StringBuilder sb = new StringBuilder();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/filter/IndexDiffFilter.java b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/filter/IndexDiffFilter.java
index b821a16..6cca582 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/filter/IndexDiffFilter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/filter/IndexDiffFilter.java
@@ -58,26 +58,33 @@
 import org.eclipse.jgit.treewalk.WorkingTreeIterator;
 
 /**
- * A performance optimized variant of {@link TreeFilter#ANY_DIFF} which should
- * be used when among the walked trees there is a {@link DirCacheIterator} and a
- * {@link WorkingTreeIterator}. Please see the documentation of
- * {@link TreeFilter#ANY_DIFF} for a basic description of the semantics.
+ * A performance optimized variant of
+ * {@link org.eclipse.jgit.treewalk.filter.TreeFilter#ANY_DIFF} which should be
+ * used when among the walked trees there is a
+ * {@link org.eclipse.jgit.dircache.DirCacheIterator} and a
+ * {@link org.eclipse.jgit.treewalk.WorkingTreeIterator}. Please see the
+ * documentation of {@link org.eclipse.jgit.treewalk.filter.TreeFilter#ANY_DIFF}
+ * for a basic description of the semantics.
  * <p>
  * This filter tries to avoid computing content ids of the files in the
- * working-tree. In contrast to {@link TreeFilter#ANY_DIFF} this filter takes
- * care to first compare the entry from the {@link DirCacheIterator} with the
- * entries from all other iterators besides the {@link WorkingTreeIterator}.
- * Since all those entries have fast access to content ids that is very fast. If
- * a difference is detected in this step this filter decides to include that
- * path before even looking at the working-tree entry.
+ * working-tree. In contrast to
+ * {@link org.eclipse.jgit.treewalk.filter.TreeFilter#ANY_DIFF} this filter
+ * takes care to first compare the entry from the
+ * {@link org.eclipse.jgit.dircache.DirCacheIterator} with the entries from all
+ * other iterators besides the
+ * {@link org.eclipse.jgit.treewalk.WorkingTreeIterator}. Since all those
+ * entries have fast access to content ids that is very fast. If a difference is
+ * detected in this step this filter decides to include that path before even
+ * looking at the working-tree entry.
  * <p>
  * If no difference is found then we have to compare index and working-tree as
  * the last step. By making use of
- * {@link WorkingTreeIterator#isModified(org.eclipse.jgit.dircache.DirCacheEntry, boolean, ObjectReader)}
+ * {@link org.eclipse.jgit.treewalk.WorkingTreeIterator#isModified(org.eclipse.jgit.dircache.DirCacheEntry, boolean, ObjectReader)}
  * we can avoid the computation of the content id if the file is not dirty.
  * <p>
- * Instances of this filter should not be used for multiple {@link TreeWalk}s.
- * Always construct a new instance of this filter for each TreeWalk.
+ * Instances of this filter should not be used for multiple
+ * {@link org.eclipse.jgit.treewalk.TreeWalk}s. Always construct a new instance
+ * of this filter for each TreeWalk.
  */
 public class IndexDiffFilter extends TreeFilter {
 	private final int dirCache;
@@ -97,11 +104,13 @@ public class IndexDiffFilter extends TreeFilter {
 	 * filter in multiple treewalks.
 	 *
 	 * @param dirCacheIndex
-	 *            the index of the {@link DirCacheIterator} in the associated
-	 *            treewalk
+	 *            the index of the
+	 *            {@link org.eclipse.jgit.dircache.DirCacheIterator} in the
+	 *            associated treewalk
 	 * @param workingTreeIndex
-	 *            the index of the {@link WorkingTreeIterator} in the associated
-	 *            treewalk
+	 *            the index of the
+	 *            {@link org.eclipse.jgit.treewalk.WorkingTreeIterator} in the
+	 *            associated treewalk
 	 */
 	public IndexDiffFilter(int dirCacheIndex, int workingTreeIndex) {
 		this(dirCacheIndex, workingTreeIndex, true /* honor ignores */);
@@ -112,14 +121,16 @@ public IndexDiffFilter(int dirCacheIndex, int workingTreeIndex) {
 	 * filter in multiple treewalks.
 	 *
 	 * @param dirCacheIndex
-	 *            the index of the {@link DirCacheIterator} in the associated
-	 *            treewalk
+	 *            the index of the
+	 *            {@link org.eclipse.jgit.dircache.DirCacheIterator} in the
+	 *            associated treewalk
 	 * @param workingTreeIndex
-	 *            the index of the {@link WorkingTreeIterator} in the associated
-	 *            treewalk
+	 *            the index of the
+	 *            {@link org.eclipse.jgit.treewalk.WorkingTreeIterator} in the
+	 *            associated treewalk
 	 * @param honorIgnores
 	 *            true if the filter should skip working tree files that are
-	 *            declared as ignored by the standard exclude mechanisms..
+	 *            declared as ignored by the standard exclude mechanisms.
 	 */
 	public IndexDiffFilter(int dirCacheIndex, int workingTreeIndex,
 			boolean honorIgnores) {
@@ -128,6 +139,7 @@ public IndexDiffFilter(int dirCacheIndex, int workingTreeIndex,
 		this.honorIgnores = honorIgnores;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public boolean include(TreeWalk tw) throws MissingObjectException,
 			IncorrectObjectTypeException, IOException {
@@ -255,6 +267,7 @@ private WorkingTreeIterator workingTree(TreeWalk tw) {
 		return tw.getTree(workingTree, WorkingTreeIterator.class);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public boolean shouldBeRecursive() {
 		// We cannot compare subtrees in the working tree, so encourage
@@ -262,11 +275,13 @@ public boolean shouldBeRecursive() {
 		return true;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public TreeFilter clone() {
 		return this;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public String toString() {
 		return "INDEX_DIFF_FILTER"; //$NON-NLS-1$
@@ -286,9 +301,11 @@ public Set<String> getIgnoredPaths() {
 	}
 
 	/**
+	 * <p>Getter for the field <code>untrackedFolders</code>.</p>
+	 *
 	 * @return all paths of folders which contain only untracked files/folders.
 	 *         If on the associated treewalk postorder traversal was turned on
-	 *         (see {@link TreeWalk#setPostOrderTraversal(boolean)}) then an
+	 *         (see {@link org.eclipse.jgit.treewalk.TreeWalk#setPostOrderTraversal(boolean)}) then an
 	 *         empty list will be returned.
 	 */
 	public List<String> getUntrackedFolders() {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/filter/InterIndexDiffFilter.java b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/filter/InterIndexDiffFilter.java
index 2ea8228..338ee2b 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/filter/InterIndexDiffFilter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/filter/InterIndexDiffFilter.java
@@ -49,8 +49,9 @@
 
 /**
  * A filter for extracting changes between two versions of the dircache. In
- * addition to what {@link TreeFilter#ANY_DIFF} would do, it also detects
- * changes that will affect decorations and show up in an attempt to commit.
+ * addition to what {@link org.eclipse.jgit.treewalk.filter.TreeFilter#ANY_DIFF}
+ * would do, it also detects changes that will affect decorations and show up in
+ * an attempt to commit.
  */
 public final class InterIndexDiffFilter extends TreeFilter {
 	private static final int baseTree = 0;
@@ -60,8 +61,9 @@ public final class InterIndexDiffFilter extends TreeFilter {
 	 */
 	public static final TreeFilter INSTANCE = new InterIndexDiffFilter();
 
+	/** {@inheritDoc} */
 	@Override
-	public boolean include(final TreeWalk walker) {
+	public boolean include(TreeWalk walker) {
 		final int n = walker.getTreeCount();
 		if (n == 1) // Assume they meant difference to empty tree.
 			return true;
@@ -88,16 +90,19 @@ public boolean include(final TreeWalk walker) {
 		return false;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public boolean shouldBeRecursive() {
 		return false;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public TreeFilter clone() {
 		return this;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public String toString() {
 		return "INTERINDEX_DIFF"; //$NON-NLS-1$
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/filter/NotIgnoredFilter.java b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/filter/NotIgnoredFilter.java
index 7f30cc7..6090508 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/filter/NotIgnoredFilter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/filter/NotIgnoredFilter.java
@@ -50,7 +50,8 @@
 import org.eclipse.jgit.treewalk.WorkingTreeIterator;
 
 /**
- * Skip {@link WorkingTreeIterator} entries that appear in gitignore files.
+ * Skip {@link org.eclipse.jgit.treewalk.WorkingTreeIterator} entries that
+ * appear in gitignore files.
  */
 public class NotIgnoredFilter extends TreeFilter {
 	private final int index;
@@ -61,10 +62,11 @@ public class NotIgnoredFilter extends TreeFilter {
 	 * @param workdirTreeIndex
 	 *            index of the workdir tree in the tree walk
 	 */
-	public NotIgnoredFilter(final int workdirTreeIndex) {
+	public NotIgnoredFilter(int workdirTreeIndex) {
 		this.index = workdirTreeIndex;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public boolean include(TreeWalk tw) throws MissingObjectException,
 			IncorrectObjectTypeException, IOException {
@@ -72,17 +74,20 @@ public boolean include(TreeWalk tw) throws MissingObjectException,
 		return i == null || !i.isEntryIgnored();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public boolean shouldBeRecursive() {
 		return false;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public TreeFilter clone() {
 		// immutable
 		return this;
 	}
 
+	/** {@inheritDoc} */
 	@SuppressWarnings("nls")
 	@Override
 	public String toString() {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/filter/NotTreeFilter.java b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/filter/NotTreeFilter.java
index 80c0b87..d315526 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/filter/NotTreeFilter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/filter/NotTreeFilter.java
@@ -50,7 +50,9 @@
 import org.eclipse.jgit.errors.MissingObjectException;
 import org.eclipse.jgit.treewalk.TreeWalk;
 
-/** Includes an entry only if the subfilter does not include the entry. */
+/**
+ * Includes an entry only if the subfilter does not include the entry.
+ */
 public class NotTreeFilter extends TreeFilter {
 	/**
 	 * Create a filter that negates the result of another filter.
@@ -59,28 +61,31 @@ public class NotTreeFilter extends TreeFilter {
 	 *            filter to negate.
 	 * @return a filter that does the reverse of <code>a</code>.
 	 */
-	public static TreeFilter create(final TreeFilter a) {
+	public static TreeFilter create(TreeFilter a) {
 		return new NotTreeFilter(a);
 	}
 
 	private final TreeFilter a;
 
-	private NotTreeFilter(final TreeFilter one) {
+	private NotTreeFilter(TreeFilter one) {
 		a = one;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public TreeFilter negate() {
 		return a;
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	public boolean include(final TreeWalk walker)
+	public boolean include(TreeWalk walker)
 			throws MissingObjectException, IncorrectObjectTypeException,
 			IOException {
 		return matchFilter(walker) == 0;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public int matchFilter(TreeWalk walker)
 			throws MissingObjectException, IncorrectObjectTypeException,
@@ -97,17 +102,20 @@ public int matchFilter(TreeWalk walker)
 		return -1;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public boolean shouldBeRecursive() {
 		return a.shouldBeRecursive();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public TreeFilter clone() {
 		final TreeFilter n = a.clone();
 		return n == a ? this : new NotTreeFilter(n);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public String toString() {
 		return "NOT " + a.toString(); //$NON-NLS-1$
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/filter/OrTreeFilter.java b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/filter/OrTreeFilter.java
index 2c1a9d4..308ff0c 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/filter/OrTreeFilter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/filter/OrTreeFilter.java
@@ -56,9 +56,10 @@
  * Includes a tree entry if any subfilters include the same tree entry.
  * <p>
  * Classic shortcut behavior is used, so evaluation of the
- * {@link TreeFilter#include(TreeWalk)} method stops as soon as a true result is
- * obtained. Applications can improve filtering performance by placing faster
- * filters that are more likely to accept a result earlier in the list.
+ * {@link org.eclipse.jgit.treewalk.filter.TreeFilter#include(TreeWalk)} method
+ * stops as soon as a true result is obtained. Applications can improve
+ * filtering performance by placing faster filters that are more likely to
+ * accept a result earlier in the list.
  */
 public abstract class OrTreeFilter extends TreeFilter {
 	/**
@@ -70,7 +71,7 @@ public abstract class OrTreeFilter extends TreeFilter {
 	 *            second filter to test.
 	 * @return a filter that must match at least one input filter.
 	 */
-	public static TreeFilter create(final TreeFilter a, final TreeFilter b) {
+	public static TreeFilter create(TreeFilter a, TreeFilter b) {
 		if (a == ALL || b == ALL)
 			return ALL;
 		return new Binary(a, b);
@@ -84,7 +85,7 @@ public static TreeFilter create(final TreeFilter a, final TreeFilter b) {
 	 *            filters.
 	 * @return a filter that must match at least one input filter.
 	 */
-	public static TreeFilter create(final TreeFilter[] list) {
+	public static TreeFilter create(TreeFilter[] list) {
 		if (list.length == 2)
 			return create(list[0], list[1]);
 		if (list.length < 2)
@@ -102,7 +103,7 @@ public static TreeFilter create(final TreeFilter[] list) {
 	 *            filters.
 	 * @return a filter that must match at least one input filter.
 	 */
-	public static TreeFilter create(final Collection<TreeFilter> list) {
+	public static TreeFilter create(Collection<TreeFilter> list) {
 		if (list.size() < 2)
 			throw new IllegalArgumentException(JGitText.get().atLeastTwoFiltersNeeded);
 		final TreeFilter[] subfilters = new TreeFilter[list.size()];
@@ -117,13 +118,13 @@ private static class Binary extends OrTreeFilter {
 
 		private final TreeFilter b;
 
-		Binary(final TreeFilter one, final TreeFilter two) {
+		Binary(TreeFilter one, TreeFilter two) {
 			a = one;
 			b = two;
 		}
 
 		@Override
-		public boolean include(final TreeWalk walker)
+		public boolean include(TreeWalk walker)
 				throws MissingObjectException, IncorrectObjectTypeException,
 				IOException {
 			return matchFilter(walker) <= 0;
@@ -167,12 +168,12 @@ public String toString() {
 	private static class List extends OrTreeFilter {
 		private final TreeFilter[] subfilters;
 
-		List(final TreeFilter[] list) {
+		List(TreeFilter[] list) {
 			subfilters = list;
 		}
 
 		@Override
-		public boolean include(final TreeWalk walker)
+		public boolean include(TreeWalk walker)
 				throws MissingObjectException, IncorrectObjectTypeException,
 				IOException {
 			return matchFilter(walker) <= 0;
@@ -183,7 +184,7 @@ public int matchFilter(TreeWalk walker)
 				throws MissingObjectException, IncorrectObjectTypeException,
 				IOException {
 			int m = 1;
-			for (final TreeFilter f : subfilters) {
+			for (TreeFilter f : subfilters) {
 				int r = f.matchFilter(walker);
 				if (r == 0) {
 					return 0;
@@ -197,7 +198,7 @@ public int matchFilter(TreeWalk walker)
 
 		@Override
 		public boolean shouldBeRecursive() {
-			for (final TreeFilter f : subfilters)
+			for (TreeFilter f : subfilters)
 				if (f.shouldBeRecursive())
 					return true;
 			return false;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/filter/PathFilter.java b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/filter/PathFilter.java
index 445ba15..9267fb6 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/filter/PathFilter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/filter/PathFilter.java
@@ -51,9 +51,10 @@
 /**
  * Includes tree entries only if they match the configured path.
  * <p>
- * Applications should use {@link PathFilterGroup} to connect these into a tree
- * filter graph, as the group supports breaking out of traversal once it is
- * known the path can never match.
+ * Applications should use
+ * {@link org.eclipse.jgit.treewalk.filter.PathFilterGroup} to connect these
+ * into a tree filter graph, as the group supports breaking out of traversal
+ * once it is known the path can never match.
  */
 public class PathFilter extends TreeFilter {
 	/**
@@ -70,7 +71,7 @@ public class PathFilter extends TreeFilter {
 	 *            trailing '/' characters will be trimmed before string's length
 	 *            is checked or is used as part of the constructed filter.
 	 * @return a new filter for the requested path.
-	 * @throws IllegalArgumentException
+	 * @throws java.lang.IllegalArgumentException
 	 *             the path supplied was the empty string.
 	 */
 	public static PathFilter create(String path) {
@@ -85,39 +86,48 @@ public static PathFilter create(String path) {
 
 	final byte[] pathRaw;
 
-	private PathFilter(final String s) {
+	private PathFilter(String s) {
 		pathStr = s;
 		pathRaw = Constants.encode(pathStr);
 	}
 
-	/** @return the path this filter matches. */
+	/**
+	 * Get the path this filter matches.
+	 *
+	 * @return the path this filter matches.
+	 */
 	public String getPath() {
 		return pathStr;
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	public boolean include(final TreeWalk walker) {
+	public boolean include(TreeWalk walker) {
 		return matchFilter(walker) <= 0;
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	public int matchFilter(final TreeWalk walker) {
+	public int matchFilter(TreeWalk walker) {
 		return walker.isPathMatch(pathRaw, pathRaw.length);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public boolean shouldBeRecursive() {
-		for (final byte b : pathRaw)
+		for (byte b : pathRaw)
 			if (b == '/')
 				return true;
 		return false;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public PathFilter clone() {
 		return this;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	@SuppressWarnings("nls")
 	public String toString() {
@@ -125,12 +135,15 @@ public String toString() {
 	}
 
 	/**
+	 * Whether the path length of this filter matches the length of the current
+	 * path of the supplied TreeWalk.
+	 *
 	 * @param walker
 	 *            The walk to check against.
 	 * @return {@code true} if the path length of this filter matches the length
 	 *         of the current path of the supplied TreeWalk.
 	 */
-	public boolean isDone(final TreeWalk walker) {
+	public boolean isDone(TreeWalk walker) {
 		return pathRaw.length == walker.getPathLength();
 	}
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/filter/PathFilterGroup.java b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/filter/PathFilterGroup.java
index 174a4f5..5cf5750 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/filter/PathFilterGroup.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/filter/PathFilterGroup.java
@@ -55,10 +55,11 @@
 /**
  * Includes tree entries only if they match one or more configured paths.
  * <p>
- * Operates like {@link PathFilter} but causes the walk to abort as soon as the
- * tree can no longer match any of the paths within the group. This may bypass
- * the boolean logic of a higher level AND or OR group, but does improve
- * performance for the common case of examining one or more modified paths.
+ * Operates like {@link org.eclipse.jgit.treewalk.filter.PathFilter} but causes
+ * the walk to abort as soon as the tree can no longer match any of the paths
+ * within the group. This may bypass the boolean logic of a higher level AND or
+ * OR group, but does improve performance for the common case of examining one
+ * or more modified paths.
  * <p>
  * This filter is effectively an OR group around paths, with the early abort
  * feature described above.
@@ -81,13 +82,13 @@ public class PathFilterGroup {
 	 *            the paths to test against. Must have at least one entry.
 	 * @return a new filter for the list of paths supplied.
 	 */
-	public static TreeFilter createFromStrings(final Collection<String> paths) {
+	public static TreeFilter createFromStrings(Collection<String> paths) {
 		if (paths.isEmpty())
 			throw new IllegalArgumentException(
 					JGitText.get().atLeastOnePathIsRequired);
 		final PathFilter[] p = new PathFilter[paths.size()];
 		int i = 0;
-		for (final String s : paths)
+		for (String s : paths)
 			p[i++] = PathFilter.create(s);
 		return create(p);
 	}
@@ -108,7 +109,7 @@ public static TreeFilter createFromStrings(final Collection<String> paths) {
 	 *            the paths to test against. Must have at least one entry.
 	 * @return a new filter for the paths supplied.
 	 */
-	public static TreeFilter createFromStrings(final String... paths) {
+	public static TreeFilter createFromStrings(String... paths) {
 		if (paths.length == 0)
 			throw new IllegalArgumentException(
 					JGitText.get().atLeastOnePathIsRequired);
@@ -130,7 +131,7 @@ public static TreeFilter createFromStrings(final String... paths) {
 	 *            the paths to test against. Must have at least one entry.
 	 * @return a new filter for the list of paths supplied.
 	 */
-	public static TreeFilter create(final Collection<PathFilter> paths) {
+	public static TreeFilter create(Collection<PathFilter> paths) {
 		if (paths.isEmpty())
 			throw new IllegalArgumentException(
 					JGitText.get().atLeastOnePathIsRequired);
@@ -139,7 +140,7 @@ public static TreeFilter create(final Collection<PathFilter> paths) {
 		return create(p);
 	}
 
-	private static TreeFilter create(final PathFilter[] p) {
+	private static TreeFilter create(PathFilter[] p) {
 		if (p.length == 1)
 			return new Single(p[0]);
 		return new Group(p);
@@ -150,13 +151,13 @@ static class Single extends TreeFilter {
 
 		private final byte[] raw;
 
-		private Single(final PathFilter p) {
+		private Single(PathFilter p) {
 			path = p;
 			raw = path.pathRaw;
 		}
 
 		@Override
-		public boolean include(final TreeWalk walker) {
+		public boolean include(TreeWalk walker) {
 			final int cmp = walker.isPathPrefix(raw, raw.length);
 			if (cmp > 0)
 				throw StopWalkException.INSTANCE;
@@ -187,7 +188,7 @@ static class Group extends TreeFilter {
 
 		private byte[] max;
 
-		private Group(final PathFilter[] pathFilters) {
+		private Group(PathFilter[] pathFilters) {
 			fullpaths = new ByteArraySet(pathFilters.length);
 			prefixes = new ByteArraySet(pathFilters.length / 5);
 			// 5 is an empirically derived ratio of #paths/#prefixes from:
@@ -238,7 +239,7 @@ private static int compare(byte[] a, byte[] b) {
 		}
 
 		@Override
-		public boolean include(final TreeWalk walker) {
+		public boolean include(TreeWalk walker) {
 
 			byte[] rp = walker.getRawPath();
 			Hasher hasher = new Hasher(rp, walker.getPathLength());
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/filter/PathSuffixFilter.java b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/filter/PathSuffixFilter.java
index f54cbea..3d9f875 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/filter/PathSuffixFilter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/filter/PathSuffixFilter.java
@@ -59,8 +59,8 @@
  * paths ending in <code>.txt</code>.
  * <p>
  * Using this filter is recommended instead of filtering the entries using
- * {@link TreeWalk#getPathString()} and <code>endsWith</code> or some other type
- * of string match function.
+ * {@link org.eclipse.jgit.treewalk.TreeWalk#getPathString()} and
+ * <code>endsWith</code> or some other type of string match function.
  */
 public class PathSuffixFilter extends TreeFilter {
 
@@ -72,7 +72,7 @@ public class PathSuffixFilter extends TreeFilter {
 	 * @param path
 	 *            the path suffix to filter on. Must not be the empty string.
 	 * @return a new filter for the requested path.
-	 * @throws IllegalArgumentException
+	 * @throws java.lang.IllegalArgumentException
 	 *             the path supplied was the empty string.
 	 */
 	public static PathSuffixFilter create(String path) {
@@ -84,16 +84,18 @@ public static PathSuffixFilter create(String path) {
 	final String pathStr;
 	final byte[] pathRaw;
 
-	private PathSuffixFilter(final String s) {
+	private PathSuffixFilter(String s) {
 		pathStr = s;
 		pathRaw = Constants.encode(pathStr);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public TreeFilter clone() {
 		return this;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public boolean include(TreeWalk walker) throws MissingObjectException,
 			IncorrectObjectTypeException, IOException {
@@ -104,6 +106,7 @@ public boolean include(TreeWalk walker) throws MissingObjectException,
 
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public boolean shouldBeRecursive() {
 		return true;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/filter/SkipWorkTreeFilter.java b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/filter/SkipWorkTreeFilter.java
index e6bedfd..b52d2bd 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/filter/SkipWorkTreeFilter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/filter/SkipWorkTreeFilter.java
@@ -69,6 +69,7 @@ public SkipWorkTreeFilter(int treeIdx) {
 		this.treeIdx = treeIdx;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public boolean include(TreeWalk walker) {
 		DirCacheIterator i = walker.getTree(treeIdx, DirCacheIterator.class);
@@ -79,16 +80,19 @@ public boolean include(TreeWalk walker) {
 		return e == null || !e.isSkipWorkTree();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public boolean shouldBeRecursive() {
 		return false;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public TreeFilter clone() {
 		return this;
 	}
 
+	/** {@inheritDoc} */
 	@SuppressWarnings("nls")
 	@Override
 	public String toString() {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/filter/TreeFilter.java b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/filter/TreeFilter.java
index 2c2fb47..11ad465 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/filter/TreeFilter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/filter/TreeFilter.java
@@ -67,7 +67,8 @@
  * <p>
  * <b>Path filters:</b>
  * <ul>
- * <li>Matching pathname: {@link PathFilter}</li>
+ * <li>Matching pathname:
+ * {@link org.eclipse.jgit.treewalk.filter.PathFilter}</li>
  * </ul>
  *
  * <p>
@@ -79,9 +80,9 @@
  * <p>
  * <b>Boolean modifiers:</b>
  * <ul>
- * <li>AND: {@link AndTreeFilter}</li>
- * <li>OR: {@link OrTreeFilter}</li>
- * <li>NOT: {@link NotTreeFilter}</li>
+ * <li>AND: {@link org.eclipse.jgit.treewalk.filter.AndTreeFilter}</li>
+ * <li>OR: {@link org.eclipse.jgit.treewalk.filter.OrTreeFilter}</li>
+ * <li>NOT: {@link org.eclipse.jgit.treewalk.filter.NotTreeFilter}</li>
  * </ul>
  */
 public abstract class TreeFilter {
@@ -90,7 +91,7 @@ public abstract class TreeFilter {
 
 	private static final class AllFilter extends TreeFilter {
 		@Override
-		public boolean include(final TreeWalk walker) {
+		public boolean include(TreeWalk walker) {
 			return true;
 		}
 
@@ -132,7 +133,7 @@ private static final class AnyDiffFilter extends TreeFilter {
 		private static final int baseTree = 0;
 
 		@Override
-		public boolean include(final TreeWalk walker) {
+		public boolean include(TreeWalk walker) {
 			final int n = walker.getTreeCount();
 			if (n == 1) // Assume they meant difference to empty tree.
 				return true;
@@ -173,24 +174,25 @@ public TreeFilter negate() {
 	 * Determine if the current entry is interesting to report.
 	 * <p>
 	 * This method is consulted for subtree entries even if
-	 * {@link TreeWalk#isRecursive()} is enabled. The consultation allows the
-	 * filter to bypass subtree recursion on a case-by-case basis, even when
-	 * recursion is enabled at the application level.
+	 * {@link org.eclipse.jgit.treewalk.TreeWalk#isRecursive()} is enabled. The
+	 * consultation allows the filter to bypass subtree recursion on a
+	 * case-by-case basis, even when recursion is enabled at the application
+	 * level.
 	 *
 	 * @param walker
 	 *            the walker the filter needs to examine.
 	 * @return true if the current entry should be seen by the application;
 	 *         false to hide the entry.
-	 * @throws MissingObjectException
+	 * @throws org.eclipse.jgit.errors.MissingObjectException
 	 *             an object the filter needs to consult to determine its answer
 	 *             does not exist in the Git repository the walker is operating
 	 *             on. Filtering this current walker entry is impossible without
 	 *             the object.
-	 * @throws IncorrectObjectTypeException
+	 * @throws org.eclipse.jgit.errors.IncorrectObjectTypeException
 	 *             an object the filter needed to consult was not of the
 	 *             expected object type. This usually indicates a corrupt
 	 *             repository, as an object link is referencing the wrong type.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             a loose object or pack file could not be read to obtain data
 	 *             necessary for the filter to make its decision.
 	 */
@@ -203,23 +205,23 @@ public abstract boolean include(TreeWalk walker)
 	 * <p>
 	 * This method extends the result returned by {@link #include(TreeWalk)}
 	 * with a third option (-1), splitting the value true. This gives the
-	 * application a possibility to distinguish between an exact match
-	 * and the case when a subtree to the current entry might be a match.
+	 * application a possibility to distinguish between an exact match and the
+	 * case when a subtree to the current entry might be a match.
 	 *
 	 * @param walker
 	 *            the walker the filter needs to examine.
-	 * @return -1 if the current entry is a parent of the filter but no
-	 *         exact match has been made; 0 if the current entry should
-	 *         be seen by the application; 1 if it should be hidden.
-	 * @throws MissingObjectException
+	 * @return -1 if the current entry is a parent of the filter but no exact
+	 *         match has been made; 0 if the current entry should be seen by the
+	 *         application; 1 if it should be hidden.
+	 * @throws org.eclipse.jgit.errors.MissingObjectException
 	 *             as thrown by {@link #include(TreeWalk)}
-	 * @throws IncorrectObjectTypeException
+	 * @throws org.eclipse.jgit.errors.IncorrectObjectTypeException
 	 *             as thrown by {@link #include(TreeWalk)}
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             as thrown by {@link #include(TreeWalk)}
 	 * @since 4.7
 	 */
-	public int matchFilter(final TreeWalk walker)
+	public int matchFilter(TreeWalk walker)
 			throws MissingObjectException, IncorrectObjectTypeException,
 			IOException
 	{
@@ -241,16 +243,17 @@ public int matchFilter(final TreeWalk walker)
 	public abstract boolean shouldBeRecursive();
 
 	/**
+	 * {@inheritDoc}
+	 *
 	 * Clone this tree filter, including its parameters.
 	 * <p>
 	 * This is a deep clone. If this filter embeds objects or other filters it
 	 * must also clone those, to ensure the instances do not share mutable data.
-	 *
-	 * @return another copy of this filter, suitable for another thread.
 	 */
 	@Override
 	public abstract TreeFilter clone();
 
+	/** {@inheritDoc} */
 	@Override
 	public String toString() {
 		String n = getClass().getName();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/filter/TreeFilterMarker.java b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/filter/TreeFilterMarker.java
index 59515dc..738ccbd 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/filter/TreeFilterMarker.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/filter/TreeFilterMarker.java
@@ -53,8 +53,9 @@
 import org.eclipse.jgit.treewalk.TreeWalk;
 
 /**
- * For testing an array of {@link TreeFilter} during a {@link TreeWalk} for each
- * entry and returning the result as a bitmask.
+ * For testing an array of {@link org.eclipse.jgit.treewalk.filter.TreeFilter}
+ * during a {@link org.eclipse.jgit.treewalk.TreeWalk} for each entry and
+ * returning the result as a bitmask.
  *
  * @since 2.3
  */
@@ -68,8 +69,8 @@ public class TreeFilterMarker {
 	 *
 	 * @param markTreeFilters
 	 *            the filters to use for marking, must not have more elements
-	 *            than {@link Integer#SIZE}.
-	 * @throws IllegalArgumentException
+	 *            than {@link java.lang.Integer#SIZE}.
+	 * @throws java.lang.IllegalArgumentException
 	 *             if more tree filters are passed than possible
 	 */
 	public TreeFilterMarker(TreeFilter[] markTreeFilters) {
@@ -85,19 +86,23 @@ public TreeFilterMarker(TreeFilter[] markTreeFilters) {
 
 	/**
 	 * Test the filters against the walk. Returns a bitmask where each bit
-	 * represents the result of a call to {@link TreeFilter#include(TreeWalk)},
+	 * represents the result of a call to
+	 * {@link org.eclipse.jgit.treewalk.filter.TreeFilter#include(TreeWalk)},
 	 * ordered by the index for which the tree filters were passed in the
 	 * constructor.
 	 *
 	 * @param walk
 	 *            the walk from which to test the current entry
 	 * @return the marks bitmask
-	 * @throws MissingObjectException
-	 *             as thrown by {@link TreeFilter#include(TreeWalk)}
-	 * @throws IncorrectObjectTypeException
-	 *             as thrown by {@link TreeFilter#include(TreeWalk)}
-	 * @throws IOException
-	 *             as thrown by {@link TreeFilter#include(TreeWalk)}
+	 * @throws org.eclipse.jgit.errors.MissingObjectException
+	 *             as thrown by
+	 *             {@link org.eclipse.jgit.treewalk.filter.TreeFilter#include(TreeWalk)}
+	 * @throws org.eclipse.jgit.errors.IncorrectObjectTypeException
+	 *             as thrown by
+	 *             {@link org.eclipse.jgit.treewalk.filter.TreeFilter#include(TreeWalk)}
+	 * @throws java.io.IOException
+	 *             as thrown by
+	 *             {@link org.eclipse.jgit.treewalk.filter.TreeFilter#include(TreeWalk)}
 	 */
 	public int getMarks(TreeWalk walk) throws MissingObjectException,
 			IncorrectObjectTypeException, IOException {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/Base64.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/Base64.java
index c05570b..442f079 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/Base64.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/Base64.java
@@ -6,8 +6,8 @@
 
 package org.eclipse.jgit.util;
 
-import java.io.UnsupportedEncodingException;
-import java.nio.charset.StandardCharsets;
+import static org.eclipse.jgit.lib.Constants.CHARSET;
+
 import java.text.MessageFormat;
 import java.util.Arrays;
 
@@ -18,14 +18,13 @@
  * <p>
  * I am placing this code in the Public Domain. Do with it as you will. This
  * software comes with no guarantees or warranties but with plenty of
- * well-wishing instead! Please visit <a
- * href="http://iharder.net/base64">http://iharder.net/base64</a> periodically
- * to check for updates or to contribute improvements.
+ * well-wishing instead! Please visit
+ * <a href="http://iharder.net/base64">http://iharder.net/base64</a>
+ * periodically to check for updates or to contribute improvements.
  * </p>
  *
  * @author Robert Harder
  * @author rob@iharder.net
- * @version 2.1, stripped to minimum feature set used by JGit.
  */
 public class Base64 {
 	/** The equals sign (=) as a byte. */
@@ -40,9 +39,6 @@ public class Base64 {
 	/** Indicates an invalid byte during decoding. */
 	private final static byte INVALID_DEC = -3;
 
-	/** Preferred encoding. */
-	private final static String UTF_8 = "UTF-8"; //$NON-NLS-1$
-
 	/** The 64 valid Base64 values. */
 	private final static byte[] ENC;
 
@@ -54,15 +50,11 @@ public class Base64 {
 	private final static byte[] DEC;
 
 	static {
-		try {
-			ENC = ("ABCDEFGHIJKLMNOPQRSTUVWXYZ" // //$NON-NLS-1$
-					+ "abcdefghijklmnopqrstuvwxyz" // //$NON-NLS-1$
-					+ "0123456789" // //$NON-NLS-1$
-					+ "+/" // //$NON-NLS-1$
-			).getBytes(UTF_8);
-		} catch (UnsupportedEncodingException uee) {
-			throw new RuntimeException(uee.getMessage(), uee);
-		}
+		ENC = ("ABCDEFGHIJKLMNOPQRSTUVWXYZ" // //$NON-NLS-1$
+				+ "abcdefghijklmnopqrstuvwxyz" // //$NON-NLS-1$
+				+ "0123456789" // //$NON-NLS-1$
+				+ "+/" // //$NON-NLS-1$
+		).getBytes(CHARSET);
 
 		DEC = new byte[128];
 		Arrays.fill(DEC, INVALID_DEC);
@@ -185,7 +177,7 @@ public static String encodeBytes(byte[] source, int off, int len) {
 			e += 4;
 		}
 
-		return new String(outBuff, 0, e, StandardCharsets.UTF_8);
+		return new String(outBuff, 0, e, CHARSET);
 	}
 
 	/**
@@ -254,7 +246,7 @@ else if (source[srcOffset + 3] == EQUALS_SIGN) {
 	 * @param len
 	 *            The length of characters to decode
 	 * @return decoded data
-	 * @throws IllegalArgumentException
+	 * @throws java.lang.IllegalArgumentException
 	 *             the input is not a valid Base64 sequence.
 	 */
 	public static byte[] decode(byte[] source, int off, int len) {
@@ -301,7 +293,7 @@ else if (source[srcOffset + 3] == EQUALS_SIGN) {
 	 * @return the decoded data
 	 */
 	public static byte[] decode(String s) {
-		byte[] bytes = s.getBytes(StandardCharsets.UTF_8);
+		byte[] bytes = s.getBytes(CHARSET);
 		return decode(bytes, 0, bytes.length);
 	}
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/BlockList.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/BlockList.java
index c86c588..c3d4747 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/BlockList.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/BlockList.java
@@ -84,7 +84,9 @@ public class BlockList<T> extends AbstractList<T> {
 
 	private T[] tailBlock;
 
-	/** Initialize an empty list. */
+	/**
+	 * Initialize an empty list.
+	 */
 	public BlockList() {
 		directory = BlockList.<T> newDirectory(256);
 		directory[0] = BlockList.<T> newBlock();
@@ -106,11 +108,13 @@ public BlockList(int capacity) {
 		tailBlock = directory[0];
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public int size() {
 		return size;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void clear() {
 		for (T[] block : directory) {
@@ -123,6 +127,7 @@ public void clear() {
 		tailBlock = directory[0];
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public T get(int index) {
 		if (index < 0 || size <= index)
@@ -130,6 +135,7 @@ public T get(int index) {
 		return directory[toDirectoryIndex(index)][toBlockIndex(index)];
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public T set(int index, T element) {
 		if (index < 0 || size <= index)
@@ -187,6 +193,7 @@ public void addAll(T[] src, int srcIdx, int srcCnt) {
 		}
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public boolean add(T element) {
 		int i = tailBlkIdx;
@@ -217,6 +224,7 @@ public boolean add(T element) {
 		return true;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void add(int index, T element) {
 		if (index == size) {
@@ -238,6 +246,7 @@ public void add(int index, T element) {
 		}
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public T remove(int index) {
 		if (index == size - 1) {
@@ -277,6 +286,7 @@ private void resetTailBlock() {
 		tailBlock = directory[tailDirIdx];
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public Iterator<T> iterator() {
 		return new MyIterator();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/CachedAuthenticator.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/CachedAuthenticator.java
index 8677c69..6b58790 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/CachedAuthenticator.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/CachedAuthenticator.java
@@ -49,7 +49,9 @@
 import java.util.Collection;
 import java.util.concurrent.CopyOnWriteArrayList;
 
-/** Abstract authenticator which remembers prior authentications. */
+/**
+ * Abstract authenticator which remembers prior authentications.
+ */
 public abstract class CachedAuthenticator extends Authenticator {
 	private static final Collection<CachedAuthentication> cached = new CopyOnWriteArrayList<>();
 
@@ -59,15 +61,16 @@ public abstract class CachedAuthenticator extends Authenticator {
 	 * @param ca
 	 *            the information we should remember.
 	 */
-	public static void add(final CachedAuthentication ca) {
+	public static void add(CachedAuthentication ca) {
 		cached.add(ca);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected final PasswordAuthentication getPasswordAuthentication() {
 		final String host = getRequestingHost();
 		final int port = getRequestingPort();
-		for (final CachedAuthentication ca : cached) {
+		for (CachedAuthentication ca : cached) {
 			if (ca.host.equals(host) && ca.port == port)
 				return ca.toPasswordAuthentication();
 		}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/ChangeIdUtil.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/ChangeIdUtil.java
index f1f6053..c8e6645 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/ChangeIdUtil.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/ChangeIdUtil.java
@@ -82,9 +82,11 @@ static String clean(String msg) {
 	 * @param firstParentId
 	 *            parent id of previous commit or null
 	 * @param author
-	 *            the {@link PersonIdent} for the presumed author and time
+	 *            the {@link org.eclipse.jgit.lib.PersonIdent} for the presumed
+	 *            author and time
 	 * @param committer
-	 *            the {@link PersonIdent} for the presumed committer and time
+	 *            the {@link org.eclipse.jgit.lib.PersonIdent} for the presumed
+	 *            committer and time
 	 * @param message
 	 *            The commit message
 	 * @return the change id SHA1 string (without the 'I') or null if the
@@ -138,7 +140,9 @@ public static ObjectId computeChangeId(final ObjectId treeId,
 	 * line.
 	 *
 	 * @param message
+	 *            a message.
 	 * @param changeId
+	 *            a Change-Id.
 	 * @return a commit message with an inserted Change-Id line
 	 */
 	public static String insertId(String message, ObjectId changeId) {
@@ -148,18 +152,21 @@ public static String insertId(String message, ObjectId changeId) {
 	/**
 	 * Find the right place to insert a Change-Id and return it.
 	 * <p>
-	 * If no Change-Id is found the Change-Id is inserted before
-	 * the first footer line but after a Bug line.
+	 * If no Change-Id is found the Change-Id is inserted before the first
+	 * footer line but after a Bug line.
 	 *
-	 * If Change-Id is found and replaceExisting is set to false,
-	 * the message is unchanged.
+	 * If Change-Id is found and replaceExisting is set to false, the message is
+	 * unchanged.
 	 *
-	 * If Change-Id is found and replaceExisting is set to true,
-	 * the Change-Id is replaced with {@code changeId}.
+	 * If Change-Id is found and replaceExisting is set to true, the Change-Id
+	 * is replaced with {@code changeId}.
 	 *
 	 * @param message
+	 *            a message.
 	 * @param changeId
+	 *            a Change-Id.
 	 * @param replaceExisting
+	 *            a boolean.
 	 * @return a commit message with an inserted Change-Id line
 	 */
 	public static String insertId(String message, ObjectId changeId,
@@ -219,6 +226,7 @@ public static String insertId(String message, ObjectId changeId,
 	 * only lines matching {@code footerPattern}.
 	 *
 	 * @param message
+	 *            a message.
 	 * @param delimiter
 	 *            the line delimiter, like "\n" or "\r\n", needed to find the
 	 *            footer
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/FS.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/FS.java
index a8720ef..3372bbe 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/FS.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/FS.java
@@ -71,12 +71,27 @@
 import org.eclipse.jgit.internal.JGitText;
 import org.eclipse.jgit.lib.Constants;
 import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.treewalk.FileTreeIterator.FileEntry;
+import org.eclipse.jgit.treewalk.FileTreeIterator.FileModeStrategy;
+import org.eclipse.jgit.treewalk.WorkingTreeIterator.Entry;
 import org.eclipse.jgit.util.ProcessResult.Status;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-/** Abstraction to support various file system operations not in Java. */
+/**
+ * Abstraction to support various file system operations not in Java.
+ */
 public abstract class FS {
+	private static final Logger LOG = LoggerFactory.getLogger(FS.class);
+
+	/**
+	 * An empty array of entries, suitable as a return value for
+	 * {@link #list(File, FileModeStrategy)}.
+	 *
+	 * @since 5.0
+	 */
+	protected static final Entry[] NO_ENTRIES = {};
+
 	/**
 	 * This class creates FS instances. It will be overridden by a Java7 variant
 	 * if such can be detected in {@link #detect(Boolean)}.
@@ -158,8 +173,6 @@ public int getRc() {
 		}
 	}
 
-	private final static Logger LOG = LoggerFactory.getLogger(FS.class);
-
 	/** The auto-detected implementation selected for this operating system and JRE. */
 	public static final FS DETECTED = detect();
 
@@ -192,7 +205,6 @@ public static FS detect() {
 	 *            </ul>
 	 *
 	 *            Note: this parameter is only relevant on Windows.
-	 *
 	 * @return detected file system abstraction
 	 */
 	public static FS detect(Boolean cygwinUsed) {
@@ -224,7 +236,11 @@ protected FS(FS src) {
 		gitSystemConfig = src.gitSystemConfig;
 	}
 
-	/** @return a new instance of the same type of FS. */
+	/**
+	 * Create a new instance of the same type of FS.
+	 *
+	 * @return a new instance of the same type of FS.
+	 */
 	public abstract FS newInstance();
 
 	/**
@@ -242,8 +258,8 @@ protected FS(FS src) {
 	 * parallel only one will succeed. In such cases both clients may think they
 	 * created a new file.
 	 *
-	 * @return true if this implementation support atomic creation of new
-	 *         Files by {@link File#createNewFile()}
+	 * @return true if this implementation support atomic creation of new Files
+	 *         by {@link java.io.File#createNewFile()}
 	 * @since 4.5
 	 */
 	public boolean supportsAtomicCreateNewFile() {
@@ -305,8 +321,9 @@ public boolean supportsSymlinks() {
 	 * than that of the link target.
 	 *
 	 * @param f
+	 *            a {@link java.io.File} object.
 	 * @return last modified time of f
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 * @since 3.0
 	 */
 	public long lastModified(File f) throws IOException {
@@ -318,8 +335,10 @@ public long lastModified(File f) throws IOException {
 	 * symbolic links, the link is modified, not the target,
 	 *
 	 * @param f
+	 *            a {@link java.io.File} object.
 	 * @param time
-	 * @throws IOException
+	 *            last modified time
+	 * @throws java.io.IOException
 	 * @since 3.0
 	 */
 	public void setLastModified(File f, long time) throws IOException {
@@ -331,8 +350,9 @@ public void setLastModified(File f, long time) throws IOException {
 	 * it's the length of the link, else the length of the target.
 	 *
 	 * @param path
+	 *            a {@link java.io.File} object.
 	 * @return length of a file
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 * @since 3.0
 	 */
 	public long length(File path) throws IOException {
@@ -343,7 +363,8 @@ public long length(File path) throws IOException {
 	 * Delete a file. Throws an exception if delete fails.
 	 *
 	 * @param f
-	 * @throws IOException
+	 *            a {@link java.io.File} object.
+	 * @throws java.io.IOException
 	 *             this may be a Java7 subclass with detailed information
 	 * @since 3.3
 	 */
@@ -369,7 +390,7 @@ public void delete(File f) throws IOException {
 	 * @return the translated path. <code>new File(dir,name)</code> if this
 	 *         platform does not require path name translation.
 	 */
-	public File resolve(final File dir, final String name) {
+	public File resolve(File dir, String name) {
 		final File abspn = new File(name);
 		if (abspn.isAbsolute())
 			return abspn;
@@ -444,12 +465,12 @@ public String run() {
 	 *            Files to search for in the given path
 	 * @return the first match found, or null
 	 * @since 3.0
-	 **/
-	protected static File searchPath(final String path, final String... lookFor) {
+	 */
+	protected static File searchPath(String path, String... lookFor) {
 		if (path == null)
 			return null;
 
-		for (final String p : path.split(File.pathSeparator)) {
+		for (String p : path.split(File.pathSeparator)) {
 			for (String command : lookFor) {
 				final File e = new File(p, command);
 				if (e.isFile())
@@ -470,7 +491,7 @@ protected static File searchPath(final String path, final String... lookFor) {
 	 *            to be used to parse the command's output
 	 * @return the one-line output of the command or {@code null} if there is
 	 *         none
-	 * @throws CommandFailedException
+	 * @throws org.eclipse.jgit.errors.CommandFailedException
 	 *             thrown when the command failed (return code was non-zero)
 	 */
 	@Nullable
@@ -493,7 +514,7 @@ protected static String readPipe(File dir, String[] command,
 	 *            current process
 	 * @return the one-line output of the command or {@code null} if there is
 	 *         none
-	 * @throws CommandFailedException
+	 * @throws org.eclipse.jgit.errors.CommandFailedException
 	 *             thrown when the command failed (return code was non-zero)
 	 * @since 4.0
 	 */
@@ -632,6 +653,8 @@ private void setError(IOException e, String message, int exitCode) {
 	}
 
 	/**
+	 * Discover the path to the Git executable.
+	 *
 	 * @return the path to the Git executable or {@code null} if it cannot be
 	 *         determined.
 	 * @since 4.0
@@ -639,6 +662,8 @@ private void setError(IOException e, String message, int exitCode) {
 	protected abstract File discoverGitExe();
 
 	/**
+	 * Discover the path to the system-wide Git configuration file
+	 *
 	 * @return the path to the system-wide Git configuration file or
 	 *         {@code null} if it cannot be determined.
 	 * @since 4.0
@@ -686,8 +711,10 @@ protected File discoverGitSystemConfig() {
 	}
 
 	/**
-	 * @return the currently used path to the system-wide Git configuration
-	 *         file or {@code null} if none has been set.
+	 * Get the currently used path to the system-wide Git configuration file.
+	 *
+	 * @return the currently used path to the system-wide Git configuration file
+	 *         or {@code null} if none has been set.
 	 * @since 4.0
 	 */
 	public File getGitSystemConfig() {
@@ -711,7 +738,10 @@ public FS setGitSystemConfig(File configFile) {
 	}
 
 	/**
+	 * Get the parent directory of this file's parent directory
+	 *
 	 * @param grandchild
+	 *            a {@link java.io.File} object.
 	 * @return the parent directory of this file's parent directory or
 	 *         {@code null} in case there's no grandparent directory
 	 * @since 4.0
@@ -729,8 +759,9 @@ protected static File resolveGrandparentFile(File grandchild) {
 	 * Check if a file is a symbolic link and read it
 	 *
 	 * @param path
+	 *            a {@link java.io.File} object.
 	 * @return target of link or null
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 * @since 3.0
 	 */
 	public String readSymLink(File path) throws IOException {
@@ -738,9 +769,12 @@ public String readSymLink(File path) throws IOException {
 	}
 
 	/**
+	 * Whether the path is a symbolic link (and we support these).
+	 *
 	 * @param path
+	 *            a {@link java.io.File} object.
 	 * @return true if the path is a symbolic link (and we support these)
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 * @since 3.0
 	 */
 	public boolean isSymLink(File path) throws IOException {
@@ -752,6 +786,7 @@ public boolean isSymLink(File path) throws IOException {
 	 * target does not exist
 	 *
 	 * @param path
+	 *            a {@link java.io.File} object.
 	 * @return true if path exists
 	 * @since 3.0
 	 */
@@ -764,6 +799,7 @@ public boolean exists(File path) {
 	 * path is a symbolic link to a directory, this method returns false.
 	 *
 	 * @param path
+	 *            a {@link java.io.File} object.
 	 * @return true if file is a directory,
 	 * @since 3.0
 	 */
@@ -776,6 +812,7 @@ public boolean isDirectory(File path) {
 	 * symbolic links the test returns false if path represents a symbolic link.
 	 *
 	 * @param path
+	 *            a {@link java.io.File} object.
 	 * @return true if path represents a regular file
 	 * @since 3.0
 	 */
@@ -784,10 +821,14 @@ public boolean isFile(File path) {
 	}
 
 	/**
+	 * Whether path is hidden, either starts with . on unix or has the hidden
+	 * attribute in windows
+	 *
 	 * @param path
+	 *            a {@link java.io.File} object.
 	 * @return true if path is hidden, either starts with . on unix or has the
 	 *         hidden attribute in windows
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 * @since 3.0
 	 */
 	public boolean isHidden(File path) throws IOException {
@@ -798,8 +839,10 @@ public boolean isHidden(File path) throws IOException {
 	 * Set the hidden attribute for file whose name starts with a period.
 	 *
 	 * @param path
+	 *            a {@link java.io.File} object.
 	 * @param hidden
-	 * @throws IOException
+	 *            whether to set the file hidden
+	 * @throws java.io.IOException
 	 * @since 3.0
 	 */
 	public void setHidden(File path, boolean hidden) throws IOException {
@@ -810,8 +853,10 @@ public void setHidden(File path, boolean hidden) throws IOException {
 	 * Create a symbolic link
 	 *
 	 * @param path
+	 *            a {@link java.io.File} object.
 	 * @param target
-	 * @throws IOException
+	 *            target path of the symlink
+	 * @throws java.io.IOException
 	 * @since 3.0
 	 */
 	public void createSymLink(File path, String target) throws IOException {
@@ -819,15 +864,15 @@ public void createSymLink(File path, String target) throws IOException {
 	}
 
 	/**
-	 * Create a new file. See {@link File#createNewFile()}. Subclasses of this
-	 * class may take care to provide a safe implementation for this even if
-	 * {@link #supportsAtomicCreateNewFile()} is <code>false</code>
+	 * Create a new file. See {@link java.io.File#createNewFile()}. Subclasses
+	 * of this class may take care to provide a safe implementation for this
+	 * even if {@link #supportsAtomicCreateNewFile()} is <code>false</code>
 	 *
 	 * @param path
 	 *            the file to be created
 	 * @return <code>true</code> if the file was created, <code>false</code> if
 	 *         the file already existed
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 * @since 4.5
 	 */
 	public boolean createNewFile(File path) throws IOException {
@@ -835,7 +880,8 @@ public boolean createNewFile(File path) throws IOException {
 	}
 
 	/**
-	 * See {@link FileUtils#relativizePath(String, String, String, boolean)}.
+	 * See
+	 * {@link org.eclipse.jgit.util.FileUtils#relativizePath(String, String, String, boolean)}.
 	 *
 	 * @param base
 	 *            The path against which <code>other</code> should be
@@ -852,6 +898,29 @@ public String relativize(String base, String other) {
 	}
 
 	/**
+	 * Enumerates children of a directory.
+	 *
+	 * @param directory
+	 *            to get the children of
+	 * @param fileModeStrategy
+	 *            to use to calculate the git mode of a child
+	 * @return an array of entries for the children
+	 *
+	 * @since 5.0
+	 */
+	public Entry[] list(File directory, FileModeStrategy fileModeStrategy) {
+		final File[] all = directory.listFiles();
+		if (all == null) {
+			return NO_ENTRIES;
+		}
+		final Entry[] result = new Entry[all.length];
+		for (int i = 0; i < result.length; i++) {
+			result[i] = new FileEntry(all[i], this, fileModeStrategy);
+		}
+		return result;
+	}
+
+	/**
 	 * Checks whether the given hook is defined for the given repository, then
 	 * runs it with the given arguments.
 	 * <p>
@@ -868,7 +937,7 @@ public String relativize(String base, String other) {
 	 *            Arguments to pass to this hook. Cannot be <code>null</code>,
 	 *            but can be an empty array.
 	 * @return The ProcessResult describing this hook's execution.
-	 * @throws JGitInternalException
+	 * @throws org.eclipse.jgit.api.errors.JGitInternalException
 	 *             if we fail to run the hook somehow. Causes may include an
 	 *             interrupted process or I/O errors.
 	 * @since 4.0
@@ -903,7 +972,7 @@ public ProcessResult runHookIfPresent(Repository repository,
 	 *            A string to pass on to the standard input of the hook. May be
 	 *            <code>null</code>.
 	 * @return The ProcessResult describing this hook's execution.
-	 * @throws JGitInternalException
+	 * @throws org.eclipse.jgit.api.errors.JGitInternalException
 	 *             if we fail to run the hook somehow. Causes may include an
 	 *             interrupted process or I/O errors.
 	 * @since 4.0
@@ -939,7 +1008,7 @@ public ProcessResult runHookIfPresent(Repository repository,
 	 *            A string to pass on to the standard input of the hook. May be
 	 *            <code>null</code>.
 	 * @return The ProcessResult describing this hook's execution.
-	 * @throws JGitInternalException
+	 * @throws org.eclipse.jgit.api.errors.JGitInternalException
 	 *             if we fail to run the hook somehow. Causes may include an
 	 *             interrupted process or I/O errors.
 	 * @since 4.0
@@ -984,11 +1053,11 @@ protected ProcessResult internalRunHookIfPresent(Repository repository,
 	 *            The repository within which to find a hook.
 	 * @param hookName
 	 *            The name of the hook we're trying to find.
-	 * @return The {@link File} containing this particular hook if it exists in
-	 *         the given repository, <code>null</code> otherwise.
+	 * @return The {@link java.io.File} containing this particular hook if it
+	 *         exists in the given repository, <code>null</code> otherwise.
 	 * @since 4.0
 	 */
-	public File findHook(Repository repository, final String hookName) {
+	public File findHook(Repository repository, String hookName) {
 		File gitDir = repository.getDirectory();
 		if (gitDir == null)
 			return null;
@@ -1015,9 +1084,9 @@ public File findHook(Repository repository, final String hookName) {
 	 *            A string to pass on to the standard input of the hook. Can be
 	 *            <code>null</code>.
 	 * @return the exit value of this process.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             if an I/O error occurs while executing this process.
-	 * @throws InterruptedException
+	 * @throws java.lang.InterruptedException
 	 *             if the current thread is interrupted while waiting for the
 	 *             process to end.
 	 * @since 4.2
@@ -1051,9 +1120,9 @@ public int runProcess(ProcessBuilder processBuilder,
 	 *            will be consumed by the process. The method will close the
 	 *            inputstream after all bytes are read.
 	 * @return the return code of this process.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             if an I/O error occurs while executing this process.
-	 * @throws InterruptedException
+	 * @throws java.lang.InterruptedException
 	 *             if the current thread is interrupted while waiting for the
 	 *             process to end.
 	 * @since 4.2
@@ -1073,19 +1142,23 @@ public int runProcess(ProcessBuilder processBuilder,
 					new StreamGobbler(process.getErrorStream(), errRedirect));
 			executor.execute(
 					new StreamGobbler(process.getInputStream(), outRedirect));
+			@SuppressWarnings("resource") // Closed in the finally block
 			OutputStream outputStream = process.getOutputStream();
-			if (inRedirect != null) {
-				new StreamGobbler(inRedirect, outputStream).copy();
-			}
 			try {
-				outputStream.close();
-			} catch (IOException e) {
-				// When the process exits before consuming the input, the OutputStream
-				// is replaced with the null output stream. This null output stream
-				// throws IOException for all write calls. When StreamGobbler fails to
-				// flush the buffer because of this, this close call tries to flush it
-				// again. This causes another IOException. Since we ignore the
-				// IOException in StreamGobbler, we also ignore the exception here.
+				if (inRedirect != null) {
+					new StreamGobbler(inRedirect, outputStream).copy();
+				}
+			} finally {
+				try {
+					outputStream.close();
+				} catch (IOException e) {
+					// When the process exits before consuming the input, the OutputStream
+					// is replaced with the null output stream. This null output stream
+					// throws IOException for all write calls. When StreamGobbler fails to
+					// flush the buffer because of this, this close call tries to flush it
+					// again. This causes another IOException. Since we ignore the
+					// IOException in StreamGobbler, we also ignore the exception here.
+				}
 			}
 			return process.waitFor();
 		} catch (IOException e) {
@@ -1179,27 +1252,24 @@ private static boolean shutdownAndAwaitTermination(ExecutorService pool) {
 	public abstract ProcessBuilder runInShell(String cmd, String[] args);
 
 	/**
-	 * Execute a command defined by a {@link ProcessBuilder}.
+	 * Execute a command defined by a {@link java.lang.ProcessBuilder}.
 	 *
 	 * @param pb
 	 *            The command to be executed
 	 * @param in
 	 *            The standard input stream passed to the process
 	 * @return The result of the executed command
-	 * @throws InterruptedException
-	 * @throws IOException
+	 * @throws java.lang.InterruptedException
+	 * @throws java.io.IOException
 	 * @since 4.2
 	 */
 	public ExecutionResult execute(ProcessBuilder pb, InputStream in)
 			throws IOException, InterruptedException {
-		TemporaryBuffer stdout = new TemporaryBuffer.LocalFile(null);
-		TemporaryBuffer stderr = new TemporaryBuffer.Heap(1024, 1024 * 1024);
-		try {
+		try (TemporaryBuffer stdout = new TemporaryBuffer.LocalFile(null);
+				TemporaryBuffer stderr = new TemporaryBuffer.Heap(1024,
+						1024 * 1024)) {
 			int rc = runProcess(pb, stdout, stderr, in);
 			return new ExecutionResult(stdout, stderr, rc);
-		} finally {
-			stdout.close();
-			stderr.close();
 		}
 	}
 
@@ -1340,8 +1410,11 @@ boolean exists() {
 	}
 
 	/**
+	 * Get the file attributes we care for.
+	 *
 	 * @param path
-	 * @return the file attributes we care for
+	 *            a {@link java.io.File} object.
+	 * @return the file attributes we care for.
 	 * @since 3.3
 	 */
 	public Attributes getAttributes(File path) {
@@ -1361,6 +1434,7 @@ public Attributes getAttributes(File path) {
 	 * Normalize the unicode path to composed form.
 	 *
 	 * @param file
+	 *            a {@link java.io.File} object.
 	 * @return NFC-format File
 	 * @since 3.3
 	 */
@@ -1372,6 +1446,7 @@ public File normalize(File file) {
 	 * Normalize the unicode path to composed form.
 	 *
 	 * @param name
+	 *            path name
 	 * @return NFC-format string
 	 * @since 3.3
 	 */
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_POSIX.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_POSIX.java
index da3b057..a2923db 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_POSIX.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_POSIX.java
@@ -80,9 +80,15 @@ public class FS_POSIX extends FS {
 
 	private volatile boolean supportsUnixNLink = true;
 
-	private volatile Boolean supportsAtomicCreateNewFile;
+	private volatile AtomicFileCreation supportsAtomicCreateNewFile = AtomicFileCreation.UNDEFINED;
 
-	/** Default constructor. */
+	private enum AtomicFileCreation {
+		SUPPORTED, NOT_SUPPORTED, UNDEFINED
+	}
+
+	/**
+	 * Default constructor.
+	 */
 	protected FS_POSIX() {
 	}
 
@@ -99,34 +105,38 @@ protected FS_POSIX(FS src) {
 		}
 	}
 
-	@SuppressWarnings("boxing")
 	private void determineAtomicFileCreationSupport() {
 		// @TODO: enhance SystemReader to support this without copying code
-		Boolean ret = getAtomicFileCreationSupportOption(
+		AtomicFileCreation ret = getAtomicFileCreationSupportOption(
 				SystemReader.getInstance().openUserConfig(null, this));
-		if (ret == null && StringUtils.isEmptyOrNull(SystemReader.getInstance()
-				.getenv(Constants.GIT_CONFIG_NOSYSTEM_KEY))) {
+		if (ret == AtomicFileCreation.UNDEFINED
+				&& StringUtils.isEmptyOrNull(SystemReader.getInstance()
+						.getenv(Constants.GIT_CONFIG_NOSYSTEM_KEY))) {
 			ret = getAtomicFileCreationSupportOption(
 					SystemReader.getInstance().openSystemConfig(null, this));
 		}
-		supportsAtomicCreateNewFile = (ret == null) || ret;
+		supportsAtomicCreateNewFile = ret;
 	}
 
-	private Boolean getAtomicFileCreationSupportOption(FileBasedConfig config) {
+	private AtomicFileCreation getAtomicFileCreationSupportOption(
+			FileBasedConfig config) {
 		try {
 			config.load();
 			String value = config.getString(ConfigConstants.CONFIG_CORE_SECTION,
 					null,
 					ConfigConstants.CONFIG_KEY_SUPPORTSATOMICFILECREATION);
 			if (value == null) {
-				return null;
+				return AtomicFileCreation.UNDEFINED;
 			}
-			return Boolean.valueOf(StringUtils.toBoolean(value));
+			return StringUtils.toBoolean(value)
+					? AtomicFileCreation.SUPPORTED
+					: AtomicFileCreation.NOT_SUPPORTED;
 		} catch (IOException | ConfigInvalidException e) {
-			return Boolean.TRUE;
+			return AtomicFileCreation.SUPPORTED;
 		}
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public FS newInstance() {
 		return new FS_POSIX(this);
@@ -174,6 +184,7 @@ private static int readUmask() {
 		}
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected File discoverGitExe() {
 		String path = SystemReader.getInstance().getenv("PATH"); //$NON-NLS-1$
@@ -204,21 +215,25 @@ protected File discoverGitExe() {
 		return gitExe;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public boolean isCaseSensitive() {
 		return !SystemReader.getInstance().isMacOS();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public boolean supportsExecute() {
 		return true;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public boolean canExecute(File f) {
 		return FileUtils.canExecute(f);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public boolean setExecute(File f, boolean canExecute) {
 		if (!isFile(f))
@@ -227,7 +242,7 @@ public boolean setExecute(File f, boolean canExecute) {
 			return f.setExecutable(false, false);
 
 		try {
-			Path path = f.toPath();
+			Path path = FileUtils.toPath(f);
 			Set<PosixFilePermission> pset = Files.getPosixFilePermissions(path);
 
 			// owner (user) is always allowed to execute.
@@ -259,6 +274,7 @@ private static void apply(Set<PosixFilePermission> set,
 		}
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public ProcessBuilder runInShell(String cmd, String[] args) {
 		List<String> argv = new ArrayList<>(4 + args.length);
@@ -272,9 +288,7 @@ public ProcessBuilder runInShell(String cmd, String[] args) {
 		return proc;
 	}
 
-	/**
-	 * @since 4.0
-	 */
+	/** {@inheritDoc} */
 	@Override
 	public ProcessResult runHookIfPresent(Repository repository, String hookName,
 			String[] args, PrintStream outRedirect, PrintStream errRedirect,
@@ -283,48 +297,43 @@ public ProcessResult runHookIfPresent(Repository repository, String hookName,
 				errRedirect, stdinArgs);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public boolean retryFailedLockFileCommit() {
 		return false;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public boolean supportsSymlinks() {
 		return true;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void setHidden(File path, boolean hidden) throws IOException {
 		// no action on POSIX
 	}
 
-	/**
-	 * @since 3.3
-	 */
+	/** {@inheritDoc} */
 	@Override
 	public Attributes getAttributes(File path) {
 		return FileUtils.getFileAttributesPosix(this, path);
 	}
 
-	/**
-	 * @since 3.3
-	 */
+	/** {@inheritDoc} */
 	@Override
 	public File normalize(File file) {
 		return FileUtils.normalize(file);
 	}
 
-	/**
-	 * @since 3.3
-	 */
+	/** {@inheritDoc} */
 	@Override
 	public String normalize(String name) {
 		return FileUtils.normalize(name);
 	}
 
-	/**
-	 * @since 3.7
-	 */
+	/** {@inheritDoc} */
 	@Override
 	public File findHook(Repository repository, String hookName) {
 		final File gitdir = repository.getDirectory();
@@ -338,24 +347,27 @@ public File findHook(Repository repository, String hookName) {
 		return null;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public boolean supportsAtomicCreateNewFile() {
-		if (supportsAtomicCreateNewFile == null) {
+		if (supportsAtomicCreateNewFile == AtomicFileCreation.UNDEFINED) {
 			determineAtomicFileCreationSupport();
 		}
-		return supportsAtomicCreateNewFile.booleanValue();
+		return supportsAtomicCreateNewFile == AtomicFileCreation.SUPPORTED;
 	}
 
 	@Override
 	@SuppressWarnings("boxing")
 	/**
+	 * {@inheritDoc}
+	 * <p>
 	 * An implementation of the File#createNewFile() semantics which works also
 	 * on NFS. If the config option
 	 * {@code core.supportsAtomicCreateNewFile = true} (which is the default)
 	 * then simply File#createNewFile() is called.
 	 *
 	 * But if {@code core.supportsAtomicCreateNewFile = false} then after
-	 * successful creation of the lock file a hardlink to that lock file is
+	 * successful creation of the lock file a hard link to that lock file is
 	 * created and the attribute nlink of the lock file is checked to be 2. If
 	 * multiple clients manage to create the same lock file nlink would be
 	 * greater than 2 showing the error.
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_Win32.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_Win32.java
index 0602921..9f99e28 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_Win32.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_Win32.java
@@ -47,11 +47,21 @@
 import java.io.File;
 import java.io.IOException;
 import java.nio.charset.Charset;
+import java.nio.file.FileVisitOption;
+import java.nio.file.FileVisitResult;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.SimpleFileVisitor;
+import java.nio.file.attribute.BasicFileAttributes;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.EnumSet;
 import java.util.List;
 
 import org.eclipse.jgit.errors.CommandFailedException;
+import org.eclipse.jgit.treewalk.FileTreeIterator.FileEntry;
+import org.eclipse.jgit.treewalk.FileTreeIterator.FileModeStrategy;
+import org.eclipse.jgit.treewalk.WorkingTreeIterator.Entry;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -83,36 +93,86 @@ protected FS_Win32(FS src) {
 		super(src);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public FS newInstance() {
 		return new FS_Win32(this);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public boolean supportsExecute() {
 		return false;
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	public boolean canExecute(final File f) {
+	public boolean canExecute(File f) {
 		return false;
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	public boolean setExecute(final File f, final boolean canExec) {
+	public boolean setExecute(File f, boolean canExec) {
 		return false;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public boolean isCaseSensitive() {
 		return false;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public boolean retryFailedLockFileCommit() {
 		return true;
 	}
 
+	/** {@inheritDoc} */
+	@Override
+	public Entry[] list(File directory, FileModeStrategy fileModeStrategy) {
+		List<Entry> result = new ArrayList<>();
+		FS fs = this;
+		boolean checkExecutable = fs.supportsExecute();
+		try {
+			Files.walkFileTree(directory.toPath(),
+					EnumSet.noneOf(FileVisitOption.class), 1,
+					new SimpleFileVisitor<Path>() {
+						@Override
+						public FileVisitResult visitFile(Path file,
+								BasicFileAttributes attrs) throws IOException {
+							File f = file.toFile();
+							FS.Attributes attributes = new FS.Attributes(fs, f,
+									true, attrs.isDirectory(),
+									checkExecutable && f.canExecute(),
+									attrs.isSymbolicLink(),
+									attrs.isRegularFile(),
+									attrs.creationTime().toMillis(),
+									attrs.lastModifiedTime().toMillis(),
+									attrs.size());
+							result.add(new FileEntry(f, fs, attributes,
+									fileModeStrategy));
+							return FileVisitResult.CONTINUE;
+						}
+
+						@Override
+						public FileVisitResult visitFileFailed(Path file,
+								IOException exc) throws IOException {
+							// Just ignore it
+							return FileVisitResult.CONTINUE;
+						}
+					});
+		} catch (IOException e) {
+			// Ignore
+		}
+		if (result.isEmpty()) {
+			return NO_ENTRIES;
+		}
+		return result.toArray(new Entry[result.size()]);
+	}
+
+	/** {@inheritDoc} */
 	@Override
 	protected File discoverGitExe() {
 		String path = SystemReader.getInstance().getenv("PATH"); //$NON-NLS-1$
@@ -141,6 +201,7 @@ protected File discoverGitExe() {
 		return gitExe;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected File userHomeImpl() {
 		String home = SystemReader.getInstance().getenv("HOME"); //$NON-NLS-1$
@@ -160,6 +221,7 @@ protected File userHomeImpl() {
 		return super.userHomeImpl();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public ProcessBuilder runInShell(String cmd, String[] args) {
 		List<String> argv = new ArrayList<>(3 + args.length);
@@ -172,6 +234,7 @@ public ProcessBuilder runInShell(String cmd, String[] args) {
 		return proc;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public boolean supportsSymlinks() {
 		if (supportSymlinks == null)
@@ -200,9 +263,7 @@ private void detectSymlinkSupport() {
 		}
 	}
 
-	/**
-	 * @since 3.3
-	 */
+	/** {@inheritDoc} */
 	@Override
 	public Attributes getAttributes(File path) {
 		return FileUtils.getFileAttributesBasic(this, path);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_Win32_Cygwin.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_Win32_Cygwin.java
index 545cc01..3393fbf 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_Win32_Cygwin.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_Win32_Cygwin.java
@@ -43,6 +43,8 @@
 
 package org.eclipse.jgit.util;
 
+import static org.eclipse.jgit.lib.Constants.CHARSET;
+
 import java.io.File;
 import java.io.PrintStream;
 import java.nio.file.Files;
@@ -72,6 +74,8 @@ public class FS_Win32_Cygwin extends FS_Win32 {
 	private static String cygpath;
 
 	/**
+	 * Whether cygwin is found
+	 *
 	 * @return true if cygwin is found
 	 */
 	public static boolean isCygwin() {
@@ -107,20 +111,22 @@ protected FS_Win32_Cygwin(FS src) {
 		super(src);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public FS newInstance() {
 		return new FS_Win32_Cygwin(this);
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	public File resolve(final File dir, final String pn) {
+	public File resolve(File dir, String pn) {
 		String useCygPath = System.getProperty("jgit.usecygpath"); //$NON-NLS-1$
 		if (useCygPath != null && useCygPath.equals("true")) { //$NON-NLS-1$
 			String w;
 			try {
 				w = readPipe(dir, //
 					new String[] { cygpath, "--windows", "--absolute", pn }, // //$NON-NLS-1$ //$NON-NLS-2$
-					"UTF-8"); //$NON-NLS-1$
+					CHARSET.name());
 			} catch (CommandFailedException e) {
 				LOG.warn(e.getMessage());
 				return null;
@@ -132,6 +138,7 @@ public File resolve(final File dir, final String pn) {
 		return super.resolve(dir, pn);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	protected File userHomeImpl() {
 		final String home = AccessController
@@ -146,6 +153,7 @@ public String run() {
 		return resolve(new File("."), home); //$NON-NLS-1$
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public ProcessBuilder runInShell(String cmd, String[] args) {
 		List<String> argv = new ArrayList<>(4 + args.length);
@@ -159,18 +167,14 @@ public ProcessBuilder runInShell(String cmd, String[] args) {
 		return proc;
 	}
 
-	/**
-	 * @since 3.7
-	 */
+	/** {@inheritDoc} */
 	@Override
 	public String relativize(String base, String other) {
 		final String relativized = super.relativize(base, other);
 		return relativized.replace(File.separatorChar, '/');
 	}
 
-	/**
-	 * @since 4.0
-	 */
+	/** {@inheritDoc} */
 	@Override
 	public ProcessResult runHookIfPresent(Repository repository, String hookName,
 			String[] args, PrintStream outRedirect, PrintStream errRedirect,
@@ -179,9 +183,7 @@ public ProcessResult runHookIfPresent(Repository repository, String hookName,
 				errRedirect, stdinArgs);
 	}
 
-	/**
-	 * @since 3.7
-	 */
+	/** {@inheritDoc} */
 	@Override
 	public File findHook(Repository repository, String hookName) {
 		final File gitdir = repository.getDirectory();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/FileUtil.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/FileUtil.java
deleted file mode 100644
index b87b9a4..0000000
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/FileUtil.java
+++ /dev/null
@@ -1,239 +0,0 @@
-/*
- * Copyright (C) 2012, Robin Rosenberg <robin.rosenberg@dewire.com>
- * and other copyright owners as documented in the project's IP log.
- *
- * This program and the accompanying materials are made available
- * under the terms of the Eclipse Distribution License v1.0 which
- * accompanies this distribution, is reproduced below, and is
- * available at http://www.eclipse.org/org/documents/edl-v10.php
- *
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- * - Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- *
- * - Redistributions in binary form must reproduce the above
- *   copyright notice, this list of conditions and the following
- *   disclaimer in the documentation and/or other materials provided
- *   with the distribution.
- *
- * - Neither the name of the Eclipse Foundation, Inc. nor the
- *   names of its contributors may be used to endorse or promote
- *   products derived from this software without specific prior
- *   written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
- * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
- * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-package org.eclipse.jgit.util;
-
-import java.io.File;
-import java.io.IOException;
-import java.nio.file.Files;
-
-import org.eclipse.jgit.util.FS.Attributes;
-
-/**
- * File utilities using Java 7 NIO2
- */
-@Deprecated
-public class FileUtil {
-
-	/**
-	 * @param path
-	 * @return target path of the symlink
-	 * @throws IOException
-	 * @deprecated use {@link FileUtils#readSymLink(File)} instead
-	 */
-	@Deprecated
-	public static String readSymlink(File path) throws IOException {
-		return FileUtils.readSymLink(path);
-	}
-
-	/**
-	 * @param path
-	 *            path of the symlink to be created
-	 * @param target
-	 *            target of the symlink to be created
-	 * @throws IOException
-	 * @deprecated use {@link FileUtils#createSymLink(File, String)} instead
-	 */
-	@Deprecated
-	public static void createSymLink(File path, String target)
-			throws IOException {
-		FileUtils.createSymLink(path, target);
-	}
-
-	/**
-	 * @param path
-	 * @return {@code true} if the passed path is a symlink
-	 * @deprecated Use {@link Files#isSymbolicLink(java.nio.file.Path)} instead
-	 */
-	@Deprecated
-	public static boolean isSymlink(File path) {
-		return FileUtils.isSymlink(path);
-	}
-
-	/**
-	 * @param path
-	 * @return lastModified attribute for given path
-	 * @throws IOException
-	 * @deprecated Use
-	 *             {@link Files#getLastModifiedTime(java.nio.file.Path, java.nio.file.LinkOption...)}
-	 *             instead
-	 */
-	@Deprecated
-	public static long lastModified(File path) throws IOException {
-		return FileUtils.lastModified(path);
-	}
-
-	/**
-	 * @param path
-	 * @param time
-	 * @throws IOException
-	 * @deprecated Use
-	 *             {@link Files#setLastModifiedTime(java.nio.file.Path, java.nio.file.attribute.FileTime)}
-	 *             instead
-	 */
-	@Deprecated
-	public static void setLastModified(File path, long time) throws IOException {
-		FileUtils.setLastModified(path, time);
-	}
-
-	/**
-	 * @param path
-	 * @return {@code true} if the given path exists
-	 * @deprecated Use
-	 *             {@link Files#exists(java.nio.file.Path, java.nio.file.LinkOption...)}
-	 *             instead
-	 */
-	@Deprecated
-	public static boolean exists(File path) {
-		return FileUtils.exists(path);
-	}
-
-	/**
-	 * @param path
-	 * @return {@code true} if the given path is hidden
-	 * @throws IOException
-	 * @deprecated Use {@link Files#isHidden(java.nio.file.Path)} instead
-	 */
-	@Deprecated
-	public static boolean isHidden(File path) throws IOException {
-		return FileUtils.isHidden(path);
-	}
-
-	/**
-	 * @param path
-	 * @param hidden
-	 * @throws IOException
-	 * @deprecated Use {@link FileUtils#setHidden(File,boolean)} instead
-	 */
-	@Deprecated
-	public static void setHidden(File path, boolean hidden) throws IOException {
-		FileUtils.setHidden(path, hidden);
-	}
-
-	/**
-	 * @param path
-	 * @return length of the given file
-	 * @throws IOException
-	 * @deprecated Use {@link FileUtils#getLength(File)} instead
-	 */
-	@Deprecated
-	public static long getLength(File path) throws IOException {
-		return FileUtils.getLength(path);
-	}
-
-	/**
-	 * @param path
-	 * @return {@code true} if the given file a directory
-	 * @deprecated Use
-	 *             {@link Files#isDirectory(java.nio.file.Path, java.nio.file.LinkOption...)}
-	 *             instead
-	 */
-	@Deprecated
-	public static boolean isDirectory(File path) {
-		return FileUtils.isDirectory(path);
-	}
-
-	/**
-	 * @param path
-	 * @return {@code true} if the given file is a file
-	 * @deprecated Use
-	 *             {@link Files#isRegularFile(java.nio.file.Path, java.nio.file.LinkOption...)}
-	 *             instead
-	 */
-	@Deprecated
-	public static boolean isFile(File path) {
-		return FileUtils.isFile(path);
-	}
-
-	/**
-	 * @param path
-	 * @return {@code true} if the given file can be executed
-	 * @deprecated Use {@link FileUtils#canExecute(File)} instead
-	 */
-	@Deprecated
-	public static boolean canExecute(File path) {
-		return FileUtils.canExecute(path);
-	}
-
-	/**
-	 * @param path
-	 * @throws IOException
-	 * @deprecated use {@link FileUtils#delete(File)}
-	 */
-	@Deprecated
-	public static void delete(File path) throws IOException {
-		FileUtils.delete(path);
-	}
-
-	/**
-	 * @param fs
-	 * @param path
-	 * @return file system attributes for the given file
-	 * @deprecated Use {@link FileUtils#getFileAttributesPosix(FS,File)} instead
-	 */
-	@Deprecated
-	public static Attributes getFileAttributesPosix(FS fs, File path) {
-		return FileUtils.getFileAttributesPosix(fs, path);
-	}
-
-	/**
-	 * @param file
-	 * @return on Mac: NFC normalized {@link File}, otherwise the passed file
-	 * @deprecated Use {@link FileUtils#normalize(File)} instead
-	 */
-	@Deprecated
-	public static File normalize(File file) {
-		return FileUtils.normalize(file);
-	}
-
-	/**
-	 * @param name
-	 * @return on Mac: NFC normalized form of given name
-	 * @deprecated Use {@link FileUtils#normalize(String)} instead
-	 */
-	@Deprecated
-	public static String normalize(String name) {
-		return FileUtils.normalize(name);
-	}
-
-}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/FileUtils.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/FileUtils.java
index 76dbb87..2f547c1 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/FileUtils.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/FileUtils.java
@@ -47,10 +47,10 @@
 
 import java.io.File;
 import java.io.IOException;
-import java.nio.channels.FileLock;
 import java.nio.file.AtomicMoveNotSupportedException;
 import java.nio.file.CopyOption;
 import java.nio.file.Files;
+import java.nio.file.InvalidPathException;
 import java.nio.file.LinkOption;
 import java.nio.file.Path;
 import java.nio.file.StandardCopyOption;
@@ -112,17 +112,36 @@ public class FileUtils {
 	public static final int EMPTY_DIRECTORIES_ONLY = 16;
 
 	/**
+	 * Safe conversion from {@link java.io.File} to {@link java.nio.file.Path}.
+	 *
+	 * @param f
+	 *            {@code File} to be converted to {@code Path}
+	 * @return the path represented by the file
+	 * @throws java.io.IOException
+	 *             in case the path represented by the file is not valid (
+	 *             {@link java.nio.file.InvalidPathException})
+	 * @since 4.10
+	 */
+	public static Path toPath(File f) throws IOException {
+		try {
+			return f.toPath();
+		} catch (InvalidPathException ex) {
+			throw new IOException(ex);
+		}
+	}
+
+	/**
 	 * Delete file or empty folder
 	 *
 	 * @param f
 	 *            {@code File} to be deleted
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             if deletion of {@code f} fails. This may occur if {@code f}
 	 *             didn't exist when the method was called. This can therefore
-	 *             cause IOExceptions during race conditions when multiple
-	 *             concurrent threads all try to delete the same file.
+	 *             cause java.io.IOExceptions during race conditions when
+	 *             multiple concurrent threads all try to delete the same file.
 	 */
-	public static void delete(final File f) throws IOException {
+	public static void delete(File f) throws IOException {
 		delete(f, NONE);
 	}
 
@@ -136,14 +155,14 @@ public static void delete(final File f) throws IOException {
 	 *            a subtree, {@code RETRY} to retry when deletion failed.
 	 *            Retrying may help if the underlying file system doesn't allow
 	 *            deletion of files being read by another thread.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             if deletion of {@code f} fails. This may occur if {@code f}
 	 *             didn't exist when the method was called. This can therefore
-	 *             cause IOExceptions during race conditions when multiple
-	 *             concurrent threads all try to delete the same file. This
-	 *             exception is not thrown when IGNORE_ERRORS is set.
+	 *             cause java.io.IOExceptions during race conditions when
+	 *             multiple concurrent threads all try to delete the same file.
+	 *             This exception is not thrown when IGNORE_ERRORS is set.
 	 */
-	public static void delete(final File f, int options) throws IOException {
+	public static void delete(File f, int options) throws IOException {
 		FS fs = FS.DETECTED;
 		if ((options & SKIP_MISSING) != 0 && !fs.exists(f))
 			return;
@@ -218,28 +237,30 @@ public static void delete(final File f, int options) throws IOException {
 	 *            the old {@code File}
 	 * @param dst
 	 *            the new {@code File}
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             if the rename has failed
 	 * @since 3.0
 	 */
-	public static void rename(final File src, final File dst)
+	public static void rename(File src, File dst)
 			throws IOException {
 		rename(src, dst, StandardCopyOption.REPLACE_EXISTING);
 	}
 
 	/**
-	 * Rename a file or folder using the passed {@link CopyOption}s. If the
-	 * rename fails and if we are running on a filesystem where it makes sense
-	 * to repeat a failing rename then repeat the rename operation up to 9 times
-	 * with 100ms sleep time between two calls. Furthermore if the destination
-	 * exists and is a directory hierarchy with only directories in it, the
-	 * whole directory hierarchy will be deleted. If the target represents a
-	 * non-empty directory structure, empty subdirectories within that structure
-	 * may or may not be deleted even if the method fails. Furthermore if the
-	 * destination exists and is a file then the file will be replaced if
-	 * {@link StandardCopyOption#REPLACE_EXISTING} has been set. If
-	 * {@link StandardCopyOption#ATOMIC_MOVE} has been set the rename will be
-	 * done atomically or fail with an {@link AtomicMoveNotSupportedException}
+	 * Rename a file or folder using the passed
+	 * {@link java.nio.file.CopyOption}s. If the rename fails and if we are
+	 * running on a filesystem where it makes sense to repeat a failing rename
+	 * then repeat the rename operation up to 9 times with 100ms sleep time
+	 * between two calls. Furthermore if the destination exists and is a
+	 * directory hierarchy with only directories in it, the whole directory
+	 * hierarchy will be deleted. If the target represents a non-empty directory
+	 * structure, empty subdirectories within that structure may or may not be
+	 * deleted even if the method fails. Furthermore if the destination exists
+	 * and is a file then the file will be replaced if
+	 * {@link java.nio.file.StandardCopyOption#REPLACE_EXISTING} has been set.
+	 * If {@link java.nio.file.StandardCopyOption#ATOMIC_MOVE} has been set the
+	 * rename will be done atomically or fail with an
+	 * {@link java.nio.file.AtomicMoveNotSupportedException}
 	 *
 	 * @param src
 	 *            the old file
@@ -247,10 +268,10 @@ public static void rename(final File src, final File dst)
 	 *            the new file
 	 * @param options
 	 *            options to pass to
-	 *            {@link Files#move(java.nio.file.Path, java.nio.file.Path, CopyOption...)}
-	 * @throws AtomicMoveNotSupportedException
+	 *            {@link java.nio.file.Files#move(java.nio.file.Path, java.nio.file.Path, CopyOption...)}
+	 * @throws java.nio.file.AtomicMoveNotSupportedException
 	 *             if file cannot be moved as an atomic file system operation
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 * @since 4.1
 	 */
 	public static void rename(final File src, final File dst,
@@ -259,7 +280,7 @@ public static void rename(final File src, final File dst,
 		int attempts = FS.DETECTED.retryFailedLockFileCommit() ? 10 : 1;
 		while (--attempts >= 0) {
 			try {
-				Files.move(src.toPath(), dst.toPath(), options);
+				Files.move(toPath(src), toPath(dst), options);
 				return;
 			} catch (AtomicMoveNotSupportedException e) {
 				throw e;
@@ -269,7 +290,7 @@ public static void rename(final File src, final File dst,
 						delete(dst, EMPTY_DIRECTORIES_ONLY | RECURSIVE);
 					}
 					// On *nix there is no try, you do or do not
-					Files.move(src.toPath(), dst.toPath(), options);
+					Files.move(toPath(src), toPath(dst), options);
 					return;
 				} catch (IOException e2) {
 					// ignore and continue retry
@@ -293,13 +314,14 @@ public static void rename(final File src, final File dst,
 	 *
 	 * @param d
 	 *            directory to be created
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             if creation of {@code d} fails. This may occur if {@code d}
 	 *             did exist when the method was called. This can therefore
-	 *             cause IOExceptions during race conditions when multiple
-	 *             concurrent threads all try to create the same directory.
+	 *             cause java.io.IOExceptions during race conditions when
+	 *             multiple concurrent threads all try to create the same
+	 *             directory.
 	 */
-	public static void mkdir(final File d)
+	public static void mkdir(File d)
 			throws IOException {
 		mkdir(d, false);
 	}
@@ -312,13 +334,14 @@ public static void mkdir(final File d)
 	 * @param skipExisting
 	 *            if {@code true} skip creation of the given directory if it
 	 *            already exists in the file system
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             if creation of {@code d} fails. This may occur if {@code d}
 	 *             did exist when the method was called. This can therefore
-	 *             cause IOExceptions during race conditions when multiple
-	 *             concurrent threads all try to create the same directory.
+	 *             cause java.io.IOExceptions during race conditions when
+	 *             multiple concurrent threads all try to create the same
+	 *             directory.
 	 */
-	public static void mkdir(final File d, boolean skipExisting)
+	public static void mkdir(File d, boolean skipExisting)
 			throws IOException {
 		if (!d.mkdir()) {
 			if (skipExisting && d.isDirectory())
@@ -336,13 +359,14 @@ public static void mkdir(final File d, boolean skipExisting)
 	 *
 	 * @param d
 	 *            directory to be created
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             if creation of {@code d} fails. This may occur if {@code d}
 	 *             did exist when the method was called. This can therefore
-	 *             cause IOExceptions during race conditions when multiple
-	 *             concurrent threads all try to create the same directory.
+	 *             cause java.io.IOExceptions during race conditions when
+	 *             multiple concurrent threads all try to create the same
+	 *             directory.
 	 */
-	public static void mkdirs(final File d) throws IOException {
+	public static void mkdirs(File d) throws IOException {
 		mkdirs(d, false);
 	}
 
@@ -357,13 +381,14 @@ public static void mkdirs(final File d) throws IOException {
 	 * @param skipExisting
 	 *            if {@code true} skip creation of the given directory if it
 	 *            already exists in the file system
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             if creation of {@code d} fails. This may occur if {@code d}
 	 *             did exist when the method was called. This can therefore
-	 *             cause IOExceptions during race conditions when multiple
-	 *             concurrent threads all try to create the same directory.
+	 *             cause java.io.IOExceptions during race conditions when
+	 *             multiple concurrent threads all try to create the same
+	 *             directory.
 	 */
-	public static void mkdirs(final File d, boolean skipExisting)
+	public static void mkdirs(File d, boolean skipExisting)
 			throws IOException {
 		if (!d.mkdirs()) {
 			if (skipExisting && d.isDirectory())
@@ -381,12 +406,12 @@ public static void mkdirs(final File d, boolean skipExisting)
 	 * filesystem activities that might affect the file.
 	 * <p>
 	 * Note: this method should not be used for file-locking, as the resulting
-	 * protocol cannot be made to work reliably. The {@link FileLock} facility
-	 * should be used instead.
+	 * protocol cannot be made to work reliably. The
+	 * {@link java.nio.channels.FileLock} facility should be used instead.
 	 *
 	 * @param f
 	 *            the file to be created
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             if the named file already exists or if an I/O error occurred
 	 */
 	public static void createNewFile(File f) throws IOException {
@@ -403,12 +428,12 @@ public static void createNewFile(File f) throws IOException {
 	 * @param target
 	 *            the target of the symbolic link
 	 * @return the path to the symbolic link
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 * @since 4.2
 	 */
 	public static Path createSymLink(File path, String target)
 			throws IOException {
-		Path nioPath = path.toPath();
+		Path nioPath = toPath(path);
 		if (Files.exists(nioPath, LinkOption.NOFOLLOW_LINKS)) {
 			BasicFileAttributes attrs = Files.readAttributes(nioPath,
 					BasicFileAttributes.class, LinkOption.NOFOLLOW_LINKS);
@@ -421,18 +446,21 @@ public static Path createSymLink(File path, String target)
 		if (SystemReader.getInstance().isWindows()) {
 			target = target.replace('/', '\\');
 		}
-		Path nioTarget = new File(target).toPath();
+		Path nioTarget = toPath(new File(target));
 		return Files.createSymbolicLink(nioPath, nioTarget);
 	}
 
 	/**
+	 * Read target path of the symlink.
+	 *
 	 * @param path
+	 *            a {@link java.io.File} object.
 	 * @return target path of the symlink, or null if it is not a symbolic link
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 * @since 3.0
 	 */
 	public static String readSymLink(File path) throws IOException {
-		Path nioPath = path.toPath();
+		Path nioPath = toPath(path);
 		Path target = Files.readSymbolicLink(nioPath);
 		String targetString = target.toString();
 		if (SystemReader.getInstance().isWindows()) {
@@ -447,11 +475,13 @@ public static String readSymLink(File path) throws IOException {
 	 * Create a temporary directory.
 	 *
 	 * @param prefix
+	 *            prefix string
 	 * @param suffix
+	 *            suffix string
 	 * @param dir
 	 *            The parent dir, can be null to use system default temp dir.
 	 * @return the temp dir created.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 * @since 3.4
 	 */
 	public static File createTempDir(String prefix, String suffix, File dir)
@@ -468,43 +498,19 @@ public static File createTempDir(String prefix, String suffix, File dir)
 		throw new IOException(JGitText.get().cannotCreateTempDir);
 	}
 
-
 	/**
-	 * @deprecated Use the more-clearly-named
-	 *             {@link FileUtils#relativizeNativePath(String, String)}
-	 *             instead, or directly call
-	 *             {@link FileUtils#relativizePath(String, String, String, boolean)}
+	 * Expresses <code>other</code> as a relative file path from
+	 * <code>base</code>. File-separator and case sensitivity are based on the
+	 * current file system.
 	 *
-	 *             Expresses <code>other</code> as a relative file path from
-	 *             <code>base</code>. File-separator and case sensitivity are
-	 *             based on the current file system.
-	 *
-	 *             See also
-	 *             {@link FileUtils#relativizePath(String, String, String, boolean)}.
+	 * See also
+	 * {@link org.eclipse.jgit.util.FileUtils#relativizePath(String, String, String, boolean)}.
 	 *
 	 * @param base
 	 *            Base path
 	 * @param other
 	 *            Destination path
 	 * @return Relative path from <code>base</code> to <code>other</code>
-	 * @since 3.7
-	 */
-	@Deprecated
-	public static String relativize(String base, String other) {
-		return relativizeNativePath(base, other);
-	}
-
-	/**
-	 * Expresses <code>other</code> as a relative file path from <code>base</code>.
-	 * File-separator and case sensitivity are based on the current file system.
-	 *
-	 * See also {@link FileUtils#relativizePath(String, String, String, boolean)}.
-	 *
-	 * @param base
-	 *            Base path
-	 * @param other
-	 *             Destination path
-	 * @return Relative path from <code>base</code> to <code>other</code>
 	 * @since 4.8
 	 */
 	public static String relativizeNativePath(String base, String other) {
@@ -512,15 +518,17 @@ public static String relativizeNativePath(String base, String other) {
 	}
 
 	/**
-	 * Expresses <code>other</code> as a relative file path from <code>base</code>.
-	 * File-separator and case sensitivity are based on Git's internal representation of files (which matches Unix).
+	 * Expresses <code>other</code> as a relative file path from
+	 * <code>base</code>. File-separator and case sensitivity are based on Git's
+	 * internal representation of files (which matches Unix).
 	 *
-	 * See also {@link FileUtils#relativizePath(String, String, String, boolean)}.
+	 * See also
+	 * {@link org.eclipse.jgit.util.FileUtils#relativizePath(String, String, String, boolean)}.
 	 *
 	 * @param base
 	 *            Base path
 	 * @param other
-	 *             Destination path
+	 *            Destination path
 	 * @return Relative path from <code>base</code> to <code>other</code>
 	 * @since 4.8
 	 */
@@ -540,7 +548,6 @@ public static String relativizeGitPath(String base, String other) {
 	 * </pre>
 	 *
 	 * This will return "..\\another_project\\pom.xml".
-	 * </p>
 	 *
 	 * <p>
 	 * <b>Note</b> that this will return the empty String if <code>base</code>
@@ -599,6 +606,7 @@ else if (!caseSensitive
 	 * Determine if an IOException is a Stale NFS File Handle
 	 *
 	 * @param ioe
+	 *            an {@link java.io.IOException} object.
 	 * @return a boolean true if the IOException is a Stale NFS FIle Handle
 	 * @since 4.1
 	 */
@@ -614,6 +622,7 @@ public static boolean isStaleFileHandle(IOException ioe) {
 	 * File Handle
 	 *
 	 * @param throwable
+	 *            a {@link java.lang.Throwable} object.
 	 * @return a boolean true if the throwable or a cause in its causal chain is
 	 *         a Stale NFS File Handle
 	 * @since 4.7
@@ -644,7 +653,7 @@ static boolean isSymlink(File file) {
 	 * @throws IOException
 	 */
 	static long lastModified(File file) throws IOException {
-		return Files.getLastModifiedTime(file.toPath(), LinkOption.NOFOLLOW_LINKS)
+		return Files.getLastModifiedTime(toPath(file), LinkOption.NOFOLLOW_LINKS)
 				.toMillis();
 	}
 
@@ -654,7 +663,7 @@ static long lastModified(File file) throws IOException {
 	 * @throws IOException
 	 */
 	static void setLastModified(File file, long time) throws IOException {
-		Files.setLastModifiedTime(file.toPath(), FileTime.fromMillis(time));
+		Files.setLastModifiedTime(toPath(file), FileTime.fromMillis(time));
 	}
 
 	/**
@@ -672,28 +681,35 @@ static boolean exists(File file) {
 	 * @throws IOException
 	 */
 	static boolean isHidden(File file) throws IOException {
-		return Files.isHidden(file.toPath());
+		return Files.isHidden(toPath(file));
 	}
 
 	/**
+	 * Set a file hidden (on Windows)
+	 *
 	 * @param file
+	 *            a {@link java.io.File} object.
 	 * @param hidden
-	 * @throws IOException
+	 *            a boolean.
+	 * @throws java.io.IOException
 	 * @since 4.1
 	 */
 	public static void setHidden(File file, boolean hidden) throws IOException {
-		Files.setAttribute(file.toPath(), "dos:hidden", Boolean.valueOf(hidden), //$NON-NLS-1$
+		Files.setAttribute(toPath(file), "dos:hidden", Boolean.valueOf(hidden), //$NON-NLS-1$
 				LinkOption.NOFOLLOW_LINKS);
 	}
 
 	/**
+	 * Get file length
+	 *
 	 * @param file
+	 *            a {@link java.io.File}.
 	 * @return length of the given file
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 * @since 4.1
 	 */
 	public static long getLength(File file) throws IOException {
-		Path nioPath = file.toPath();
+		Path nioPath = toPath(file);
 		if (Files.isSymbolicLink(nioPath))
 			return Files.readSymbolicLink(nioPath).toString()
 					.getBytes(Constants.CHARSET).length;
@@ -719,8 +735,11 @@ static boolean isFile(File file) {
 	}
 
 	/**
+	 * Whether the given file can be executed.
+	 *
 	 * @param file
-	 * @return {@code true} if the given file can be executed
+	 *            a {@link java.io.File} object.
+	 * @return {@code true} if the given file can be executed.
 	 * @since 4.1
 	 */
 	public static boolean canExecute(File file) {
@@ -737,7 +756,7 @@ public static boolean canExecute(File file) {
 	 */
 	static Attributes getFileAttributesBasic(FS fs, File file) {
 		try {
-			Path nioPath = file.toPath();
+			Path nioPath = toPath(file);
 			BasicFileAttributes readAttributes = nioPath
 					.getFileSystem()
 					.provider()
@@ -762,14 +781,18 @@ static Attributes getFileAttributesBasic(FS fs, File file) {
 	}
 
 	/**
+	 * Get file system attributes for the given file.
+	 *
 	 * @param fs
+	 *            a {@link org.eclipse.jgit.util.FS} object.
 	 * @param file
-	 * @return file system attributes for the given file
+	 *            a {@link java.io.File}.
+	 * @return file system attributes for the given file.
 	 * @since 4.1
 	 */
 	public static Attributes getFileAttributesPosix(FS fs, File file) {
 		try {
-			Path nioPath = file.toPath();
+			Path nioPath = toPath(file);
 			PosixFileAttributes readAttributes = nioPath
 					.getFileSystem()
 					.provider()
@@ -795,8 +818,12 @@ public static Attributes getFileAttributesPosix(FS fs, File file) {
 	}
 
 	/**
+	 * NFC normalize a file (on Mac), otherwise do nothing
+	 *
 	 * @param file
-	 * @return on Mac: NFC normalized {@link File}, otherwise the passed file
+	 *            a {@link java.io.File}.
+	 * @return on Mac: NFC normalized {@link java.io.File}, otherwise the passed
+	 *         file
 	 * @since 4.1
 	 */
 	public static File normalize(File file) {
@@ -811,7 +838,10 @@ public static File normalize(File file) {
 	}
 
 	/**
+	 * On Mac: get NFC normalized form of given name, otherwise the given name.
+	 *
 	 * @param name
+	 *            a {@link java.lang.String} object.
 	 * @return on Mac: NFC normalized form of given name
 	 * @since 4.1
 	 */
@@ -825,16 +855,16 @@ public static String normalize(String name) {
 	}
 
 	/**
-	 * Best-effort variation of {@link File#getCanonicalFile()} returning the
-	 * input file if the file cannot be canonicalized instead of throwing
-	 * {@link IOException}.
+	 * Best-effort variation of {@link java.io.File#getCanonicalFile()}
+	 * returning the input file if the file cannot be canonicalized instead of
+	 * throwing {@link java.io.IOException}.
 	 *
 	 * @param file
 	 *            to be canonicalized; may be {@code null}
 	 * @return canonicalized file, or the unchanged input file if
 	 *         canonicalization failed or if {@code file == null}
-	 * @throws SecurityException
-	 *             if {@link File#getCanonicalFile()} throws one
+	 * @throws java.lang.SecurityException
+	 *             if {@link java.io.File#getCanonicalFile()} throws one
 	 * @since 4.2
 	 */
 	public static File canonicalize(File file) {
@@ -848,4 +878,19 @@ public static File canonicalize(File file) {
 		}
 	}
 
+	/**
+	 * Convert a path to String, replacing separators as necessary.
+	 *
+	 * @param file
+	 *            a {@link java.io.File}.
+	 * @return file's path as a String
+	 * @since 4.10
+	 */
+	public static String pathToString(File file) {
+		final String path = file.getPath();
+		if (SystemReader.getInstance().isWindows()) {
+			return path.replace('\\', '/');
+		}
+		return path;
+	}
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/GitDateFormatter.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/GitDateFormatter.java
index d7ab5f8..e461902 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/GitDateFormatter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/GitDateFormatter.java
@@ -54,7 +54,8 @@
  * A utility for formatting dates according to the Git log.date formats plus
  * extensions.
  * <p>
- * The enum {@link Format} defines the available types.
+ * The enum {@link org.eclipse.jgit.util.GitDateFormatter.Format} defines the
+ * available types.
  */
 public class GitDateFormatter {
 
@@ -119,6 +120,8 @@ static public enum Format {
 	 * Create a new Git oriented date formatter
 	 *
 	 * @param format
+	 *            a {@link org.eclipse.jgit.util.GitDateFormatter.Format}
+	 *            object.
 	 */
 	public GitDateFormatter(Format format) {
 		this.format = format;
@@ -159,6 +162,7 @@ public GitDateFormatter(Format format) {
 	 * specification.
 	 *
 	 * @param ident
+	 *            a {@link org.eclipse.jgit.lib.PersonIdent} object.
 	 * @return formatted version of date, time and time zone
 	 */
 	@SuppressWarnings("boxing")
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/GitDateParser.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/GitDateParser.java
index da78008..a339b9a 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/GitDateParser.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/GitDateParser.java
@@ -55,7 +55,7 @@
 import org.eclipse.jgit.internal.JGitText;
 
 /**
- * Parses strings with time and date specifications into {@link Date}.
+ * Parses strings with time and date specifications into {@link java.util.Date}.
  *
  * When git needs to parse strings specified by the user this parser can be
  * used. One example is the parsing of the config parameter gc.pruneexpire. The
@@ -134,16 +134,17 @@ private ParseableSimpleDateFormat(String formatStr) {
 	}
 
 	/**
-	 * Parses a string into a {@link Date} using the default locale. Since this
-	 * parser also supports relative formats (e.g. "yesterday") the caller can
-	 * specify the reference date. These types of strings can be parsed:
+	 * Parses a string into a {@link java.util.Date} using the default locale.
+	 * Since this parser also supports relative formats (e.g. "yesterday") the
+	 * caller can specify the reference date. These types of strings can be
+	 * parsed:
 	 * <ul>
 	 * <li>"never"</li>
 	 * <li>"now"</li>
 	 * <li>"yesterday"</li>
 	 * <li>"(x) years|months|weeks|days|hours|minutes|seconds ago"<br>
-	 * Multiple specs can be combined like in "2 weeks 3 days ago". Instead of
-	 * ' ' one can use '.' to seperate the words</li>
+	 * Multiple specs can be combined like in "2 weeks 3 days ago". Instead of '
+	 * ' one can use '.' to seperate the words</li>
 	 * <li>"yyyy-MM-dd HH:mm:ss Z" (ISO)</li>
 	 * <li>"EEE, dd MMM yyyy HH:mm:ss Z" (RFC)</li>
 	 * <li>"yyyy-MM-dd"</li>
@@ -161,11 +162,12 @@ private ParseableSimpleDateFormat(String formatStr) {
 	 *            formats. E.g. if baseDate is "25.8.2012" then parsing of the
 	 *            string "1 week ago" would result in a date corresponding to
 	 *            "18.8.2012". This is used when a JGit command calls this
-	 *            parser often but wants a consistent starting point for calls.<br>
+	 *            parser often but wants a consistent starting point for
+	 *            calls.<br>
 	 *            If set to <code>null</code> then the current time will be used
 	 *            instead.
-	 * @return the parsed {@link Date}
-	 * @throws ParseException
+	 * @return the parsed {@link java.util.Date}
+	 * @throws java.text.ParseException
 	 *             if the given dateStr was not recognized
 	 */
 	public static Date parse(String dateStr, Calendar now)
@@ -174,16 +176,17 @@ public static Date parse(String dateStr, Calendar now)
 	}
 
 	/**
-	 * Parses a string into a {@link Date} using the given locale. Since this
-	 * parser also supports relative formats (e.g. "yesterday") the caller can
-	 * specify the reference date. These types of strings can be parsed:
+	 * Parses a string into a {@link java.util.Date} using the given locale.
+	 * Since this parser also supports relative formats (e.g. "yesterday") the
+	 * caller can specify the reference date. These types of strings can be
+	 * parsed:
 	 * <ul>
 	 * <li>"never"</li>
 	 * <li>"now"</li>
 	 * <li>"yesterday"</li>
 	 * <li>"(x) years|months|weeks|days|hours|minutes|seconds ago"<br>
-	 * Multiple specs can be combined like in "2 weeks 3 days ago". Instead of
-	 * ' ' one can use '.' to seperate the words</li>
+	 * Multiple specs can be combined like in "2 weeks 3 days ago". Instead of '
+	 * ' one can use '.' to seperate the words</li>
 	 * <li>"yyyy-MM-dd HH:mm:ss Z" (ISO)</li>
 	 * <li>"EEE, dd MMM yyyy HH:mm:ss Z" (RFC)</li>
 	 * <li>"yyyy-MM-dd"</li>
@@ -201,13 +204,14 @@ public static Date parse(String dateStr, Calendar now)
 	 *            formats. E.g. if baseDate is "25.8.2012" then parsing of the
 	 *            string "1 week ago" would result in a date corresponding to
 	 *            "18.8.2012". This is used when a JGit command calls this
-	 *            parser often but wants a consistent starting point for calls.<br>
+	 *            parser often but wants a consistent starting point for
+	 *            calls.<br>
 	 *            If set to <code>null</code> then the current time will be used
 	 *            instead.
 	 * @param locale
 	 *            locale to be used to parse the date string
-	 * @return the parsed {@link Date}
-	 * @throws ParseException
+	 * @return the parsed {@link java.util.Date}
+	 * @throws java.text.ParseException
 	 *             if the given dateStr was not recognized
 	 * @since 3.2
 	 */
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/Holder.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/Holder.java
index 3563e1b..b4cc6ca 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/Holder.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/Holder.java
@@ -45,14 +45,15 @@
  * Holder of an object.
  *
  * @param <T>
- *            the type of value held by this {@link Holder}
- *
+ *            the type of value held by this {@link org.eclipse.jgit.util.Holder}
  * @since 4.3
  */
 public class Holder<T> {
 	private T value;
 
 	/**
+	 * <p>Constructor for Holder.</p>
+	 *
 	 * @param value
 	 *            is the initial value that is {@link #set(Object)}
 	 */
@@ -61,15 +62,20 @@ public Holder(T value) {
 	}
 
 	/**
-	 * @return the value held by this {@link Holder}
+	 * Get the value held by this {@link org.eclipse.jgit.util.Holder}
+	 *
+	 * @return the value held by this {@link org.eclipse.jgit.util.Holder}
 	 */
 	public T get() {
 		return value;
 	}
 
 	/**
+	 * Set a new value held by this {@link org.eclipse.jgit.util.Holder}
+	 *
 	 * @param value
-	 *            to be set as new value held by this {@link Holder}
+	 *            to be set as new value held by this
+	 *            {@link org.eclipse.jgit.util.Holder}
 	 */
 	public void set(T value) {
 		this.value = value;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/HttpSupport.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/HttpSupport.java
index 13e61a7..6f92b37 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/HttpSupport.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/HttpSupport.java
@@ -44,6 +44,8 @@
 
 package org.eclipse.jgit.util;
 
+import static org.eclipse.jgit.lib.Constants.CHARACTER_ENCODING;
+
 import java.io.IOException;
 import java.io.UnsupportedEncodingException;
 import java.net.ConnectException;
@@ -65,7 +67,9 @@
 import org.eclipse.jgit.internal.JGitText;
 import org.eclipse.jgit.transport.http.HttpConnection;
 
-/** Extra utilities to support usage of HTTP. */
+/**
+ * Extra utilities to support usage of HTTP.
+ */
 public class HttpSupport {
 	/** The {@code GET} HTTP method. */
 	public static final String METHOD_GET = "GET"; //$NON-NLS-1$
@@ -173,11 +177,11 @@ public class HttpSupport {
 	 * @param key
 	 *            value which must be encoded to protected special characters.
 	 */
-	public static void encode(final StringBuilder urlstr, final String key) {
+	public static void encode(StringBuilder urlstr, String key) {
 		if (key == null || key.length() == 0)
 			return;
 		try {
-			urlstr.append(URLEncoder.encode(key, "UTF-8")); //$NON-NLS-1$
+			urlstr.append(URLEncoder.encode(key, CHARACTER_ENCODING));
 		} catch (UnsupportedEncodingException e) {
 			throw new RuntimeException(JGitText.get().couldNotURLEncodeToUTF8, e);
 		}
@@ -192,12 +196,13 @@ public static void encode(final StringBuilder urlstr, final String key) {
 	 * @param c
 	 *            connection the code should be obtained from.
 	 * @return r HTTP status code, usually 200 to indicate success. See
-	 *         {@link HttpConnection} for other defined constants.
-	 * @throws IOException
+	 *         {@link org.eclipse.jgit.transport.http.HttpConnection} for other
+	 *         defined constants.
+	 * @throws java.io.IOException
 	 *             communications error prevented obtaining the response code.
 	 * @since 3.3
 	 */
-	public static int response(final HttpConnection c) throws IOException {
+	public static int response(HttpConnection c) throws IOException {
 		try {
 			return c.getResponseCode();
 		} catch (ConnectException ce) {
@@ -220,11 +225,12 @@ public static int response(final HttpConnection c) throws IOException {
 	 * @param c
 	 *            connection the code should be obtained from.
 	 * @return r HTTP status code, usually 200 to indicate success. See
-	 *         {@link HttpConnection} for other defined constants.
-	 * @throws IOException
+	 *         {@link org.eclipse.jgit.transport.http.HttpConnection} for other
+	 *         defined constants.
+	 * @throws java.io.IOException
 	 *             communications error prevented obtaining the response code.
 	 */
-	public static int response(final java.net.HttpURLConnection c)
+	public static int response(java.net.HttpURLConnection c)
 			throws IOException {
 		try {
 			return c.getResponseCode();
@@ -248,7 +254,7 @@ public static int response(final java.net.HttpURLConnection c)
 	 * @param headerName
 	 *            the header name
 	 * @return the header value
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             communications error prevented obtaining the header.
 	 * @since 4.7
 	 */
@@ -265,11 +271,11 @@ public static String responseHeader(final HttpConnection c,
 	 * @param u
 	 *            location of the server caller wants to talk to.
 	 * @return proxy to communicate with the supplied URL.
-	 * @throws ConnectException
+	 * @throws java.net.ConnectException
 	 *             the proxy could not be computed as the supplied URL could not
 	 *             be read. This failure should never occur.
 	 */
-	public static Proxy proxyFor(final ProxySelector proxySelector, final URL u)
+	public static Proxy proxyFor(ProxySelector proxySelector, URL u)
 			throws ConnectException {
 		try {
 			return proxySelector.select(u.toURI()).get(0);
@@ -285,7 +291,9 @@ public static Proxy proxyFor(final ProxySelector proxySelector, final URL u)
 	 * Disable SSL and hostname verification for given HTTP connection
 	 *
 	 * @param conn
-	 * @throws IOException
+	 *            a {@link org.eclipse.jgit.transport.http.HttpConnection}
+	 *            object.
+	 * @throws java.io.IOException
 	 * @since 4.3
 	 */
 	public static void disableSslVerify(HttpConnection conn)
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/IO.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/IO.java
index 6cff76c..e88e7a3 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/IO.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/IO.java
@@ -47,7 +47,6 @@
 
 import java.io.EOFException;
 import java.io.File;
-import java.io.FileInputStream;
 import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.InputStream;
@@ -59,6 +58,7 @@
 import java.util.List;
 
 import org.eclipse.jgit.internal.JGitText;
+import org.eclipse.jgit.util.io.SilentFileInputStream;
 
 /**
  * Input/Output utilities
@@ -71,12 +71,12 @@ public class IO {
 	 * @param path
 	 *            location of the file to read.
 	 * @return complete contents of the requested local file.
-	 * @throws FileNotFoundException
+	 * @throws java.io.FileNotFoundException
 	 *             the file does not exist.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the file exists, but its contents cannot be read.
 	 */
-	public static final byte[] readFully(final File path)
+	public static final byte[] readFully(File path)
 			throws FileNotFoundException, IOException {
 		return IO.readFully(path, Integer.MAX_VALUE);
 	}
@@ -91,15 +91,14 @@ public class IO {
 	 *            only the first limit number of bytes are returned
 	 * @return complete contents of the requested local file. If the contents
 	 *         exceeds the limit, then only the limit is returned.
-	 * @throws FileNotFoundException
+	 * @throws java.io.FileNotFoundException
 	 *             the file does not exist.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the file exists, but its contents cannot be read.
 	 */
-	public static final byte[] readSome(final File path, final int limit)
+	public static final byte[] readSome(File path, int limit)
 			throws FileNotFoundException, IOException {
-		FileInputStream in = new FileInputStream(path);
-		try {
+		try (SilentFileInputStream in = new SilentFileInputStream(path)) {
 			byte[] buf = new byte[limit];
 			int cnt = 0;
 			for (;;) {
@@ -113,12 +112,6 @@ public class IO {
 			byte[] res = new byte[cnt];
 			System.arraycopy(buf, 0, res, 0, cnt);
 			return res;
-		} finally {
-			try {
-				in.close();
-			} catch (IOException ignored) {
-				// do nothing
-			}
 		}
 	}
 
@@ -131,15 +124,14 @@ public class IO {
 	 *            maximum number of bytes to read, if the file is larger than
 	 *            this limit an IOException is thrown.
 	 * @return complete contents of the requested local file.
-	 * @throws FileNotFoundException
+	 * @throws java.io.FileNotFoundException
 	 *             the file does not exist.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the file exists, but its contents cannot be read.
 	 */
-	public static final byte[] readFully(final File path, final int max)
+	public static final byte[] readFully(File path, int max)
 			throws FileNotFoundException, IOException {
-		final FileInputStream in = new FileInputStream(path);
-		try {
+		try (SilentFileInputStream in = new SilentFileInputStream(path)) {
 			long sz = Math.max(path.length(), 1);
 			if (sz > max)
 				throw new IOException(MessageFormat.format(
@@ -173,12 +165,6 @@ public class IO {
 				buf = nb;
 			}
 			return buf;
-		} finally {
-			try {
-				in.close();
-			} catch (IOException ignored) {
-				// ignore any close errors, this was a read only stream
-			}
 		}
 	}
 
@@ -199,7 +185,7 @@ public class IO {
 	 *         on obtaining the underlying array for efficient data access. If
 	 *         {@code sizeHint} was too large, the array may be over-allocated,
 	 *         resulting in {@code limit() < array().length}.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             there was an error reading from the stream.
 	 */
 	public static ByteBuffer readWholeStream(InputStream in, int sizeHint)
@@ -238,7 +224,7 @@ public static ByteBuffer readWholeStream(InputStream in, int sizeHint)
 	 *            number of bytes that must be read.
 	 * @throws EOFException
 	 *             the stream ended before dst was fully populated.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             there was an error reading from the stream.
 	 */
 	public static void readFully(final InputStream fd, final byte[] dst,
@@ -264,7 +250,7 @@ public static void readFully(final InputStream fd, final byte[] dst,
 	 * @param len
 	 *            number of bytes that should be read.
 	 * @return number of bytes actually read.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             there was an error reading from the channel.
 	 */
 	public static int read(ReadableByteChannel channel, byte[] dst, int off,
@@ -293,7 +279,7 @@ public static int read(ReadableByteChannel channel, byte[] dst, int off,
 	 * @param off
 	 *            position within the buffer to start writing to.
 	 * @return number of bytes in buffer or stream, whichever is shortest
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             there was an error reading from the stream.
 	 */
 	public static int readFully(InputStream fd, byte[] dst, int off)
@@ -322,10 +308,10 @@ public static int readFully(InputStream fd, byte[] dst, int off)
 	 * @throws EOFException
 	 *             the stream ended before the requested number of bytes were
 	 *             skipped.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             there was an error reading from the stream.
 	 */
-	public static void skipFully(final InputStream fd, long toSkip)
+	public static void skipFully(InputStream fd, long toSkip)
 			throws IOException {
 		while (toSkip > 0) {
 			final long r = fd.skip(toSkip);
@@ -343,7 +329,7 @@ public static void skipFully(final InputStream fd, long toSkip)
 	 * @return the string divided into lines
 	 * @since 2.0
 	 */
-	public static List<String> readLines(final String s) {
+	public static List<String> readLines(String s) {
 		List<String> l = new ArrayList<>();
 		StringBuilder sb = new StringBuilder();
 		for (int i = 0; i < s.length(); i++) {
@@ -384,7 +370,7 @@ public static List<String> readLines(final String s) {
 	 *            hint for buffer sizing; 0 or negative for default.
 	 * @return the next line from the input, always ending in {@code \n} unless
 	 *         EOF was reached.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             there was an error reading from the stream.
 	 * @since 4.1
 	 */
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/IntList.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/IntList.java
index 0a3c846..7441d50 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/IntList.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/IntList.java
@@ -44,13 +44,17 @@
 
 package org.eclipse.jgit.util;
 
-/** A more efficient List&lt;Integer&gt; using a primitive integer array. */
+/**
+ * A more efficient List&lt;Integer&gt; using a primitive integer array.
+ */
 public class IntList {
 	private int[] entries;
 
 	private int count;
 
-	/** Create an empty list with a default capacity. */
+	/**
+	 * Create an empty list with a default capacity.
+	 */
 	public IntList() {
 		this(10);
 	}
@@ -61,11 +65,15 @@ public IntList() {
 	 * @param capacity
 	 *            number of entries the list can initially hold.
 	 */
-	public IntList(final int capacity) {
+	public IntList(int capacity) {
 		entries = new int[capacity];
 	}
 
-	/** @return number of entries in this list */
+	/**
+	 * Get number of entries in this list.
+	 *
+	 * @return number of entries in this list.
+	 */
 	public int size() {
 		return count;
 	}
@@ -86,19 +94,23 @@ public boolean contains(int value) {
 	}
 
 	/**
+	 * Get the value at the specified index
+	 *
 	 * @param i
 	 *            index to read, must be in the range [0, {@link #size()}).
 	 * @return the number at the specified index
-	 * @throws ArrayIndexOutOfBoundsException
+	 * @throws java.lang.ArrayIndexOutOfBoundsException
 	 *             the index outside the valid range
 	 */
-	public int get(final int i) {
+	public int get(int i) {
 		if (count <= i)
 			throw new ArrayIndexOutOfBoundsException(i);
 		return entries[i];
 	}
 
-	/** Empty this list */
+	/**
+	 * Empty this list
+	 */
 	public void clear() {
 		count = 0;
 	}
@@ -109,7 +121,7 @@ public void clear() {
 	 * @param n
 	 *            the number to add.
 	 */
-	public void add(final int n) {
+	public void add(int n) {
 		if (count == entries.length)
 			grow();
 		entries[count++] = n;
@@ -123,7 +135,7 @@ public void add(final int n) {
 	 * @param n
 	 *            value to store at the position.
 	 */
-	public void set(final int index, final int n) {
+	public void set(int index, int n) {
 		if (count < index)
 			throw new ArrayIndexOutOfBoundsException(index);
 		else if (count == index)
@@ -142,7 +154,7 @@ else if (count == index)
 	 * @param val
 	 *            value to insert into padded positions.
 	 */
-	public void fillTo(int toIndex, final int val) {
+	public void fillTo(int toIndex, int val) {
 		while (count < toIndex)
 			add(val);
 	}
@@ -153,6 +165,7 @@ private void grow() {
 		entries = n;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public String toString() {
 		final StringBuilder r = new StringBuilder();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/LfsFactory.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/LfsFactory.java
new file mode 100644
index 0000000..6d60ef3
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/LfsFactory.java
@@ -0,0 +1,318 @@
+/*
+ * Copyright (C) 2018, Markus Duft <markus.duft@ssi-schaefer.com>
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ *   copyright notice, this list of conditions and the following
+ *   disclaimer in the documentation and/or other materials provided
+ *   with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ *   names of its contributors may be used to endorse or promote
+ *   products derived from this software without specific prior
+ *   written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.eclipse.jgit.util;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PrintStream;
+import java.text.MessageFormat;
+import java.util.concurrent.Callable;
+
+import org.eclipse.jgit.annotations.Nullable;
+import org.eclipse.jgit.attributes.Attribute;
+import org.eclipse.jgit.attributes.Attributes;
+import org.eclipse.jgit.hooks.PrePushHook;
+import org.eclipse.jgit.internal.JGitText;
+import org.eclipse.jgit.lib.ObjectLoader;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.revwalk.RevCommit;
+import org.eclipse.jgit.treewalk.FileTreeIterator;
+import org.eclipse.jgit.treewalk.TreeWalk;
+import org.eclipse.jgit.treewalk.filter.PathFilter;
+
+/**
+ * Represents an optionally present LFS support implementation
+ *
+ * @since 4.11
+ */
+public class LfsFactory {
+
+	private static LfsFactory instance = new LfsFactory();
+
+	/**
+	 * Constructor
+	 */
+	protected LfsFactory() {
+	}
+
+	/**
+	 * @return the current LFS implementation
+	 */
+	public static LfsFactory getInstance() {
+		return instance;
+	}
+
+	/**
+	 * @param instance
+	 *            register a {@link LfsFactory} instance as the
+	 *            {@link LfsFactory} implementation to use.
+	 */
+	public static void setInstance(LfsFactory instance) {
+		LfsFactory.instance = instance;
+	}
+
+	/**
+	 * @return whether LFS support is available
+	 */
+	public boolean isAvailable() {
+		return false;
+	}
+
+	/**
+	 * Apply clean filtering to the given stream, writing the file content to
+	 * the LFS storage if required and returning a stream to the LFS pointer
+	 * instead.
+	 *
+	 * @param db
+	 *            the repository
+	 * @param input
+	 *            the original input
+	 * @param length
+	 *            the expected input stream length
+	 * @param attribute
+	 *            the attribute used to check for LFS enablement (i.e. "merge",
+	 *            "diff", "filter" from .gitattributes).
+	 * @return a stream to the content that should be written to the object
+	 *         store along with the expected length of the stream. the original
+	 *         stream is not applicable.
+	 * @throws IOException
+	 *             in case of an error
+	 */
+	public LfsInputStream applyCleanFilter(Repository db,
+			InputStream input, long length, Attribute attribute)
+			throws IOException {
+		return new LfsInputStream(input, length);
+	}
+
+	/**
+	 * Apply smudge filtering to a given loader, potentially redirecting it to a
+	 * LFS blob which is downloaded on demand.
+	 *
+	 * @param db
+	 *            the repository
+	 * @param loader
+	 *            the loader for the blob
+	 * @param attribute
+	 *            the attribute used to check for LFS enablement (i.e. "merge",
+	 *            "diff", "filter" from .gitattributes).
+	 * @return a loader for the actual data of a blob, or the original loader in
+	 *         case LFS is not applicable.
+	 * @throws IOException
+	 */
+	public ObjectLoader applySmudgeFilter(Repository db,
+			ObjectLoader loader, Attribute attribute) throws IOException {
+		return loader;
+	}
+
+	/**
+	 * Retrieve a pre-push hook to be applied.
+	 *
+	 * @param repo
+	 *            the {@link Repository} the hook is applied to.
+	 * @param outputStream
+	 * @return a {@link PrePushHook} implementation or <code>null</code>
+	 */
+	public @Nullable PrePushHook getPrePushHook(Repository repo,
+			PrintStream outputStream) {
+		return null;
+	}
+
+	/**
+	 * Retrieve an {@link LfsInstallCommand} which can be used to enable LFS
+	 * support (if available) either per repository or for the user.
+	 *
+	 * @return a command to install LFS support.
+	 */
+	public @Nullable LfsInstallCommand getInstallCommand() {
+		return null;
+	}
+
+	/**
+	 * @param db
+	 *            the repository to check
+	 * @return whether LFS is enabled for the given repository locally or
+	 *         globally.
+	 */
+	public boolean isEnabled(Repository db) {
+		return false;
+	}
+
+	/**
+	 * @param db
+	 *            the repository
+	 * @param path
+	 *            the path to find attributes for
+	 * @return the {@link Attributes} for the given path.
+	 * @throws IOException
+	 *             in case of an error
+	 */
+	public static Attributes getAttributesForPath(Repository db, String path)
+			throws IOException {
+		try (TreeWalk walk = new TreeWalk(db)) {
+			walk.addTree(new FileTreeIterator(db));
+			PathFilter f = PathFilter.create(path);
+			walk.setFilter(f);
+			walk.setRecursive(false);
+			Attributes attr = null;
+			while (walk.next()) {
+				if (f.isDone(walk)) {
+					attr = walk.getAttributes();
+					break;
+				} else if (walk.isSubtree()) {
+					walk.enterSubtree();
+				}
+			}
+			if (attr == null) {
+				throw new IOException(MessageFormat
+						.format(JGitText.get().noPathAttributesFound, path));
+			}
+
+			return attr;
+		}
+	}
+
+	/**
+	 * Get attributes for given path and commit
+	 *
+	 * @param db
+	 *            the repository
+	 * @param path
+	 *            the path to find attributes for
+	 * @param commit
+	 *            the commit to inspect.
+	 * @return the {@link Attributes} for the given path.
+	 * @throws IOException
+	 *             in case of an error
+	 */
+	public static Attributes getAttributesForPath(Repository db, String path,
+			RevCommit commit) throws IOException {
+		if (commit == null) {
+			return getAttributesForPath(db, path);
+		}
+
+		try (TreeWalk walk = TreeWalk.forPath(db, path, commit.getTree())) {
+			Attributes attr = walk == null ? null : walk.getAttributes();
+			if (attr == null) {
+				throw new IOException(MessageFormat
+						.format(JGitText.get().noPathAttributesFound, path));
+			}
+
+			return attr;
+		}
+	}
+
+	/**
+	 * Encapsulate a potentially exchanged {@link InputStream} along with the
+	 * expected stream content length.
+	 */
+	public static final class LfsInputStream extends InputStream {
+		/**
+		 * The actual stream.
+		 */
+		private InputStream stream;
+
+		/**
+		 * The expected stream content length.
+		 */
+		private long length;
+
+		/**
+		 * Create a new wrapper around a certain stream
+		 *
+		 * @param stream
+		 *            the stream to wrap. the stream will be closed on
+		 *            {@link #close()}.
+		 * @param length
+		 *            the expected length of the stream
+		 */
+		public LfsInputStream(InputStream stream, long length) {
+			this.stream = stream;
+			this.length = length;
+		}
+
+		/**
+		 * Create a new wrapper around a temporary buffer.
+		 *
+		 * @param buffer
+		 *            the buffer to initialize stream and length from. The
+		 *            buffer will be destroyed on {@link #close()}
+		 * @throws IOException
+		 *             in case of an error opening the stream to the buffer.
+		 */
+		public LfsInputStream(TemporaryBuffer buffer) throws IOException {
+			this.stream = buffer.openInputStreamWithAutoDestroy();
+			this.length = buffer.length();
+		}
+
+		@Override
+		public void close() throws IOException {
+			stream.close();
+		}
+
+		@Override
+		public int read() throws IOException {
+			return stream.read();
+		}
+
+		/**
+		 * @return the length of the stream
+		 */
+		public long getLength() {
+			return length;
+		}
+	}
+
+	/**
+	 * A command to enable LFS. Optionally set a {@link Repository} to enable
+	 * locally on the repository only.
+	 */
+	public interface LfsInstallCommand extends Callable<Void> {
+		/**
+		 * @param repo
+		 *            the repository to enable support for.
+		 * @return The {@link LfsInstallCommand} for chaining.
+		 */
+		public LfsInstallCommand setRepository(Repository repo);
+	}
+
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/LongList.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/LongList.java
index e3639f5..3bd6e18 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/LongList.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/LongList.java
@@ -46,13 +46,17 @@
 
 import java.util.Arrays;
 
-/** A more efficient List&lt;Long&gt; using a primitive long array. */
+/**
+ * A more efficient List&lt;Long&gt; using a primitive long array.
+ */
 public class LongList {
 	private long[] entries;
 
 	private int count;
 
-	/** Create an empty list with a default capacity. */
+	/**
+	 * Create an empty list with a default capacity.
+	 */
 	public LongList() {
 		this(10);
 	}
@@ -63,23 +67,29 @@ public LongList() {
 	 * @param capacity
 	 *            number of entries the list can initially hold.
 	 */
-	public LongList(final int capacity) {
+	public LongList(int capacity) {
 		entries = new long[capacity];
 	}
 
-	/** @return number of entries in this list */
+	/**
+	 * Get number of entries in this list
+	 *
+	 * @return number of entries in this list
+	 */
 	public int size() {
 		return count;
 	}
 
 	/**
+	 * Get the value at the specified index
+	 *
 	 * @param i
 	 *            index to read, must be in the range [0, {@link #size()}).
 	 * @return the number at the specified index
-	 * @throws ArrayIndexOutOfBoundsException
+	 * @throws java.lang.ArrayIndexOutOfBoundsException
 	 *             the index outside the valid range
 	 */
-	public long get(final int i) {
+	public long get(int i) {
 		if (count <= i)
 			throw new ArrayIndexOutOfBoundsException(i);
 		return entries[i];
@@ -92,14 +102,16 @@ public long get(final int i) {
 	 *            the value to search for.
 	 * @return true of {@code value} appears in this list.
 	 */
-	public boolean contains(final long value) {
+	public boolean contains(long value) {
 		for (int i = 0; i < count; i++)
 			if (entries[i] == value)
 				return true;
 		return false;
 	}
 
-	/** Empty this list */
+	/**
+	 * Clear this list
+	 */
 	public void clear() {
 		count = 0;
 	}
@@ -110,7 +122,7 @@ public void clear() {
 	 * @param n
 	 *            the number to add.
 	 */
-	public void add(final long n) {
+	public void add(long n) {
 		if (count == entries.length)
 			grow();
 		entries[count++] = n;
@@ -124,7 +136,7 @@ public void add(final long n) {
 	 * @param n
 	 *            value to store at the position.
 	 */
-	public void set(final int index, final long n) {
+	public void set(int index, long n) {
 		if (count < index)
 			throw new ArrayIndexOutOfBoundsException(index);
 		else if (count == index)
@@ -143,12 +155,14 @@ else if (count == index)
 	 * @param val
 	 *            value to insert into padded positions.
 	 */
-	public void fillTo(int toIndex, final long val) {
+	public void fillTo(int toIndex, long val) {
 		while (count < toIndex)
 			add(val);
 	}
 
-	/** Sort the list of longs according to their natural ordering. */
+	/**
+	 * Sort the list of longs according to their natural ordering.
+	 */
 	public void sort() {
 		Arrays.sort(entries, 0, count);
 	}
@@ -159,6 +173,7 @@ private void grow() {
 		entries = n;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public String toString() {
 		final StringBuilder r = new StringBuilder();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/LongMap.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/LongMap.java
index 7b0b0c7..8c7f672 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/LongMap.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/LongMap.java
@@ -44,7 +44,7 @@
 package org.eclipse.jgit.util;
 
 /**
- * Simple Map<long,Object>.
+ * Simple Map&lt;long, Object&gt;.
  *
  * @param <V>
  *            type of the value instance.
@@ -61,13 +61,17 @@ public class LongMap<V> {
 	/** Next {@link #size} to trigger a {@link #grow()}. */
 	private int growAt;
 
-	/** Initialize an empty LongMap. */
+	/**
+	 * Initialize an empty LongMap.
+	 */
 	public LongMap() {
 		table = createArray(64);
 		growAt = (int) (table.length * LOAD_FACTOR);
 	}
 
 	/**
+	 * Whether {@code key} is present in the map.
+	 *
 	 * @param key
 	 *            the key to find.
 	 * @return {@code true} if {@code key} is present in the map.
@@ -77,9 +81,11 @@ public boolean containsKey(long key) {
 	}
 
 	/**
+	 * Get value for this {@code key}
+	 *
 	 * @param key
 	 *            the key to find.
-	 * @return stored value of the key, or {@code null}.
+	 * @return stored value for this key, or {@code null}.
 	 */
 	public V get(long key) {
 		for (Node<V> n = table[index(key)]; n != null; n = n.next) {
@@ -90,6 +96,8 @@ public V get(long key) {
 	}
 
 	/**
+	 * Remove an entry from the map
+	 *
 	 * @param key
 	 *            key to remove from the map.
 	 * @return old value of the key, or {@code null}.
@@ -113,6 +121,8 @@ public V remove(long key) {
 	}
 
 	/**
+	 * Put a new entry into the map
+	 *
 	 * @param key
 	 *            key to store {@code value} under.
 	 * @param value
@@ -134,7 +144,7 @@ public V put(long key, V value) {
 		return null;
 	}
 
-	private void insert(final Node<V> n) {
+	private void insert(Node<V> n) {
 		final int idx = index(n.key);
 		n.next = table[idx];
 		table[idx] = n;
@@ -156,14 +166,14 @@ private void grow() {
 		}
 	}
 
-	private final int index(final long key) {
+	private final int index(long key) {
 		int h = ((int) key) >>> 1;
 		h ^= (h >>> 20) ^ (h >>> 12);
 		return h & (table.length - 1);
 	}
 
 	@SuppressWarnings("unchecked")
-	private static final <V> Node<V>[] createArray(final int sz) {
+	private static final <V> Node<V>[] createArray(int sz) {
 		return new Node[sz];
 	}
 
@@ -172,7 +182,7 @@ private static class Node<V> {
 		V value;
 		Node<V> next;
 
-		Node(final long k, final V v) {
+		Node(long k, V v) {
 			key = k;
 			value = v;
 		}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/MutableInteger.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/MutableInteger.java
index cbe3210..8cee9f9 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/MutableInteger.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/MutableInteger.java
@@ -43,7 +43,9 @@
 
 package org.eclipse.jgit.util;
 
-/** A boxed integer that can be modified. */
+/**
+ * A boxed integer that can be modified.
+ */
 public final class MutableInteger {
 	/** Current value of this boxed value. */
 	public int value;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/NB.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/NB.java
index 471a499..8ad6aa0 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/NB.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/NB.java
@@ -43,7 +43,9 @@
 
 package org.eclipse.jgit.util;
 
-/** Conversion utilities for network byte order handling. */
+/**
+ * Conversion utilities for network byte order handling.
+ */
 public final class NB {
 	/**
 	 * Compare a 32 bit unsigned integer stored in a 32 bit signed integer.
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/ProcessResult.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/ProcessResult.java
index 77c9608..9267a32 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/ProcessResult.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/ProcessResult.java
@@ -86,6 +86,8 @@ public ProcessResult(Status status) {
 	}
 
 	/**
+	 * <p>Constructor for ProcessResult.</p>
+	 *
 	 * @param exitCode
 	 *            Exit code of the process.
 	 * @param status
@@ -97,6 +99,8 @@ public ProcessResult(int exitCode, Status status) {
 	}
 
 	/**
+	 * Get exit code of the process.
+	 *
 	 * @return The exit code of the process.
 	 */
 	public int getExitCode() {
@@ -104,6 +108,8 @@ public int getExitCode() {
 	}
 
 	/**
+	 * Get the status of the process' execution.
+	 *
 	 * @return The status of the process' execution.
 	 */
 	public Status getStatus() {
@@ -111,6 +117,8 @@ public Status getStatus() {
 	}
 
 	/**
+	 * Whether the execution occurred and resulted in an error
+	 *
 	 * @return <code>true</code> if the execution occurred and resulted in a
 	 *         return code different from 0, <code>false</code> otherwise.
 	 * @since 4.0
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/QuotedString.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/QuotedString.java
index 57dfb85..4d58d06 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/QuotedString.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/QuotedString.java
@@ -47,7 +47,9 @@
 
 import org.eclipse.jgit.lib.Constants;
 
-/** Utility functions related to quoted string handling. */
+/**
+ * Utility functions related to quoted string handling.
+ */
 public abstract class QuotedString {
 	/** Quoting style that obeys the rules Git applies to file names */
 	public static final GitPathStyle GIT_PATH = new GitPathStyle();
@@ -97,7 +99,7 @@ public abstract class QuotedString {
 	 * @return the cleaned string.
 	 * @see #dequote(byte[], int, int)
 	 */
-	public String dequote(final String in) {
+	public String dequote(String in) {
 		final byte[] b = Constants.encode(in);
 		return dequote(b, 0, b.length);
 	}
@@ -135,7 +137,7 @@ public String dequote(final String in) {
 	 */
 	public static class BourneStyle extends QuotedString {
 		@Override
-		public String quote(final String in) {
+		public String quote(String in) {
 			final StringBuilder r = new StringBuilder();
 			r.append('\'');
 			int start = 0, i = 0;
@@ -158,7 +160,7 @@ public String quote(final String in) {
 		}
 
 		@Override
-		public String dequote(final byte[] in, int ip, final int ie) {
+		public String dequote(byte[] in, int ip, int ie) {
 			boolean inquote = false;
 			final byte[] r = new byte[ie - ip];
 			int rPtr = 0;
@@ -186,7 +188,7 @@ public String dequote(final byte[] in, int ip, final int ie) {
 	/** Bourne style, but permits <code>~user</code> at the start of the string. */
 	public static class BourneUserPathStyle extends BourneStyle {
 		@Override
-		public String quote(final String in) {
+		public String quote(String in) {
 			if (in.matches("^~[A-Za-z0-9_-]+$")) { //$NON-NLS-1$
 				// If the string is just "~user" we can assume they
 				// mean "~user/".
@@ -253,7 +255,7 @@ public static final class GitPathStyle extends QuotedString {
 		}
 
 		@Override
-		public String quote(final String instr) {
+		public String quote(String instr) {
 			if (instr.length() == 0)
 				return "\"\""; //$NON-NLS-1$
 			boolean reuse = true;
@@ -289,13 +291,13 @@ public String quote(final String instr) {
 		}
 
 		@Override
-		public String dequote(final byte[] in, final int inPtr, final int inEnd) {
+		public String dequote(byte[] in, int inPtr, int inEnd) {
 			if (2 <= inEnd - inPtr && in[inPtr] == '"' && in[inEnd - 1] == '"')
 				return dq(in, inPtr + 1, inEnd - 1);
 			return RawParseUtils.decode(Constants.CHARSET, in, inPtr, inEnd);
 		}
 
-		private static String dq(final byte[] in, int inPtr, final int inEnd) {
+		private static String dq(byte[] in, int inPtr, int inEnd) {
 			final byte[] r = new byte[inEnd - inPtr];
 			int rPtr = 0;
 			while (inPtr < inEnd) {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/RawCharSequence.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/RawCharSequence.java
index e85bd65..42060c6 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/RawCharSequence.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/RawCharSequence.java
@@ -68,27 +68,31 @@ public final class RawCharSequence implements CharSequence {
 	 * @param end
 	 *            ending position for the sequence.
 	 */
-	public RawCharSequence(final byte[] buf, final int start, final int end) {
+	public RawCharSequence(byte[] buf, int start, int end) {
 		buffer = buf;
 		startPtr = start;
 		endPtr = end;
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	public char charAt(final int index) {
+	public char charAt(int index) {
 		return (char) (buffer[startPtr + index] & 0xff);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public int length() {
 		return endPtr - startPtr;
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	public CharSequence subSequence(final int start, final int end) {
+	public CharSequence subSequence(int start, int end) {
 		return new RawCharSequence(buffer, startPtr + start, startPtr + end);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public String toString() {
 		final int n = length();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/RawParseUtils.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/RawParseUtils.java
index ad138bb..c22c8de 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/RawParseUtils.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/RawParseUtils.java
@@ -63,10 +63,13 @@
 import java.util.Map;
 
 import org.eclipse.jgit.annotations.Nullable;
+import org.eclipse.jgit.errors.BinaryBlobException;
 import org.eclipse.jgit.lib.Constants;
 import org.eclipse.jgit.lib.PersonIdent;
 
-/** Handy utility functions to parse raw object contents. */
+/**
+ * Handy utility functions to parse raw object contents.
+ */
 public final class RawParseUtils {
 	/**
 	 * UTF-8 charset constant.
@@ -123,7 +126,7 @@ public final class RawParseUtils {
 	 *            the buffer to test for equality with b.
 	 * @return ptr + src.length if b[ptr..src.length] == src; else -1.
 	 */
-	public static final int match(final byte[] b, int ptr, final byte[] src) {
+	public static final int match(byte[] b, int ptr, byte[] src) {
 		if (ptr + src.length > b.length)
 			return -1;
 		for (int i = 0; i < src.length; i++, ptr++)
@@ -306,7 +309,7 @@ public static final long parseLongBase10(final byte[] b, int ptr,
 	 * @param p
 	 *            first position within the buffer to parse.
 	 * @return the integer value.
-	 * @throws ArrayIndexOutOfBoundsException
+	 * @throws java.lang.ArrayIndexOutOfBoundsException
 	 *             if the string is not hex formatted.
 	 */
 	public static final int parseHexInt16(final byte[] bs, final int p) {
@@ -336,7 +339,7 @@ public static final int parseHexInt16(final byte[] bs, final int p) {
 	 * @param p
 	 *            first position within the buffer to parse.
 	 * @return the integer value.
-	 * @throws ArrayIndexOutOfBoundsException
+	 * @throws java.lang.ArrayIndexOutOfBoundsException
 	 *             if the string is not hex formatted.
 	 */
 	public static final int parseHexInt32(final byte[] bs, final int p) {
@@ -377,7 +380,7 @@ public static final int parseHexInt32(final byte[] bs, final int p) {
 	 * @param p
 	 *            first position within the buffer to parse.
 	 * @return the integer value.
-	 * @throws ArrayIndexOutOfBoundsException
+	 * @throws java.lang.ArrayIndexOutOfBoundsException
 	 *             if the string is not hex formatted.
 	 * @since 4.3
 	 */
@@ -437,7 +440,7 @@ public static final long parseHexInt64(final byte[] bs, final int p) {
 	 * @param digit
 	 *            hex character to parse.
 	 * @return numeric value, in the range 0-15.
-	 * @throws ArrayIndexOutOfBoundsException
+	 * @throws java.lang.ArrayIndexOutOfBoundsException
 	 *             if the input digit is not a valid hex digit.
 	 */
 	public static final int parseHexInt4(final byte digit) {
@@ -459,7 +462,7 @@ public static final int parseHexInt4(final byte digit) {
 	 *            position within buffer to start parsing digits at.
 	 * @return the timezone at this location, expressed in minutes.
 	 */
-	public static final int parseTimeZoneOffset(final byte[] b, int ptr) {
+	public static final int parseTimeZoneOffset(byte[] b, int ptr) {
 		return parseTimeZoneOffset(b, ptr, null);
 	}
 
@@ -498,7 +501,7 @@ public static final int parseTimeZoneOffset(final byte[] b, int ptr,
 	 *            character to find.
 	 * @return new position just after chrA.
 	 */
-	public static final int next(final byte[] b, int ptr, final char chrA) {
+	public static final int next(byte[] b, int ptr, char chrA) {
 		final int sz = b.length;
 		while (ptr < sz) {
 			if (b[ptr++] == chrA)
@@ -518,7 +521,7 @@ public static final int next(final byte[] b, int ptr, final char chrA) {
 	 *            position within buffer to start looking for LF at.
 	 * @return new position just after the first LF found.
 	 */
-	public static final int nextLF(final byte[] b, int ptr) {
+	public static final int nextLF(byte[] b, int ptr) {
 		return next(b, ptr, '\n');
 	}
 
@@ -535,7 +538,7 @@ public static final int nextLF(final byte[] b, int ptr) {
 	 *            character to find.
 	 * @return new position just after the first chrA or LF to be found.
 	 */
-	public static final int nextLF(final byte[] b, int ptr, final char chrA) {
+	public static final int nextLF(byte[] b, int ptr, char chrA) {
 		final int sz = b.length;
 		while (ptr < sz) {
 			final byte c = b[ptr++];
@@ -556,7 +559,7 @@ public static final int nextLF(final byte[] b, int ptr, final char chrA) {
 	 *            character to find.
 	 * @return new position just before chrA, -1 for not found
 	 */
-	public static final int prev(final byte[] b, int ptr, final char chrA) {
+	public static final int prev(byte[] b, int ptr, char chrA) {
 		if (ptr == b.length)
 			--ptr;
 		while (ptr >= 0) {
@@ -577,7 +580,7 @@ public static final int prev(final byte[] b, int ptr, final char chrA) {
 	 *            position within buffer to start looking for LF at.
 	 * @return new position just before the first LF found, -1 for not found
 	 */
-	public static final int prevLF(final byte[] b, int ptr) {
+	public static final int prevLF(byte[] b, int ptr) {
 		return prev(b, ptr, '\n');
 	}
 
@@ -595,7 +598,7 @@ public static final int prevLF(final byte[] b, int ptr) {
 	 * @return new position just before the first chrA or LF to be found, -1 for
 	 *         not found
 	 */
-	public static final int prevLF(final byte[] b, int ptr, final char chrA) {
+	public static final int prevLF(byte[] b, int ptr, char chrA) {
 		if (ptr == b.length)
 			--ptr;
 		while (ptr >= 0) {
@@ -610,7 +613,7 @@ public static final int prevLF(final byte[] b, int ptr, final char chrA) {
 	 * Index the region between <code>[ptr, end)</code> to find line starts.
 	 * <p>
 	 * The returned list is 1 indexed. Index 0 contains
-	 * {@link Integer#MIN_VALUE} to pad the list out.
+	 * {@link java.lang.Integer#MIN_VALUE} to pad the list out.
 	 * <p>
 	 * Using a 1 indexed list means that line numbers can be directly accessed
 	 * from the list, so <code>list.get(1)</code> (aka get line 1) returns
@@ -619,8 +622,8 @@ public static final int prevLF(final byte[] b, int ptr, final char chrA) {
 	 * The last element (index <code>map.size()-1</code>) always contains
 	 * <code>end</code>.
 	 * <p>
-	 * If the data contains a '\0' anywhere, the whole region is considered binary
-	 * and a LineMap corresponding to a single line is returned.
+	 * If the data contains a '\0' anywhere, the whole region is considered
+	 * binary and a LineMap corresponding to a single line is returned.
 	 * </p>
 	 *
 	 * @param buf
@@ -630,11 +633,47 @@ public static final int prevLF(final byte[] b, int ptr, final char chrA) {
 	 *            line 1.
 	 * @param end
 	 *            1 past the end of the content within <code>buf</code>.
-	 * @return a line map indexing the start position of each line.
+	 * @return a line map indicating the starting position of each line, or a
+	 *         map representing the entire buffer as a single line if
+	 *         <code>buf</code> contains a NUL byte.
 	 */
-	public static final IntList lineMap(final byte[] buf, int ptr, int end) {
-		int start = ptr;
+	public static final IntList lineMap(byte[] buf, int ptr, int end) {
+		IntList map = lineMapOrNull(buf, ptr, end);
+		if (map == null) {
+			map = new IntList(3);
+			map.add(Integer.MIN_VALUE);
+			map.add(ptr);
+			map.add(end);
+		}
+		return map;
+	}
 
+	/**
+	 * Like {@link #lineMap(byte[], int, int)} but throw
+	 * {@link BinaryBlobException} if a NUL byte is encountered.
+	 *
+	 * @param buf
+	 *            buffer to scan.
+	 * @param ptr
+	 *            position within the buffer corresponding to the first byte of
+	 *            line 1.
+	 * @param end
+	 *            1 past the end of the content within <code>buf</code>.
+	 * @return a line map indicating the starting position of each line.
+	 * @throws BinaryBlobException
+	 *            if a NUL byte is found.
+	 * @since 5.0
+	 */
+	public static final IntList lineMapOrBinary(byte[] buf, int ptr, int end)
+			throws BinaryBlobException {
+		IntList map = lineMapOrNull(buf, ptr, end);
+		if (map == null) {
+			throw new BinaryBlobException();
+		}
+		return map;
+	}
+
+	private static @Nullable IntList lineMapOrNull(byte[] buf, int ptr, int end) {
 		// Experimentally derived from multiple source repositories
 		// the average number of bytes/line is 36. Its a rough guess
 		// to initially size our map close to the target.
@@ -647,11 +686,7 @@ public static final IntList lineMap(final byte[] buf, int ptr, int end) {
 			}
 
 			if (buf[ptr] == '\0') {
-				// binary data.
-				map = new IntList(3);
-				map.add(Integer.MIN_VALUE);
-				map.add(start);
-				break;
+				return null;
 			}
 
 			foundLF = (buf[ptr] == '\n');
@@ -673,7 +708,7 @@ public static final IntList lineMap(final byte[] buf, int ptr, int end) {
 	 *         character of the author's name. If no author header can be
 	 *         located -1 is returned.
 	 */
-	public static final int author(final byte[] b, int ptr) {
+	public static final int author(byte[] b, int ptr) {
 		final int sz = b.length;
 		if (ptr == 0)
 			ptr += 46; // skip the "tree ..." line.
@@ -695,7 +730,7 @@ public static final int author(final byte[] b, int ptr) {
 	 *         character of the committer's name. If no committer header can be
 	 *         located -1 is returned.
 	 */
-	public static final int committer(final byte[] b, int ptr) {
+	public static final int committer(byte[] b, int ptr) {
 		final int sz = b.length;
 		if (ptr == 0)
 			ptr += 46; // skip the "tree ..." line.
@@ -719,7 +754,7 @@ public static final int committer(final byte[] b, int ptr) {
 	 *         character of the tagger's name. If no tagger header can be
 	 *         located -1 is returned.
 	 */
-	public static final int tagger(final byte[] b, int ptr) {
+	public static final int tagger(byte[] b, int ptr) {
 		final int sz = b.length;
 		if (ptr == 0)
 			ptr += 48; // skip the "object ..." line.
@@ -747,7 +782,7 @@ public static final int tagger(final byte[] b, int ptr) {
 	 *         character of the encoding's name. If no encoding header can be
 	 *         located -1 is returned (and UTF-8 should be assumed).
 	 */
-	public static final int encoding(final byte[] b, int ptr) {
+	public static final int encoding(byte[] b, int ptr) {
 		final int sz = b.length;
 		while (ptr < sz) {
 			if (b[ptr] == '\n')
@@ -771,7 +806,7 @@ public static final int encoding(final byte[] b, int ptr) {
 	 * @since 4.2
 	 */
 	@Nullable
-	public static String parseEncodingName(final byte[] b) {
+	public static String parseEncodingName(byte[] b) {
 		int enc = encoding(b, 0);
 		if (enc < 0) {
 			return null;
@@ -799,7 +834,7 @@ public static String parseEncodingName(final byte[] b) {
 	 *             if the JRE does not support the character set requested by
 	 *             the encoding header.
 	 */
-	public static Charset parseEncoding(final byte[] b) {
+	public static Charset parseEncoding(byte[] b) {
 		String enc = parseEncodingName(b);
 		if (enc == null) {
 			return UTF_8;
@@ -829,7 +864,7 @@ public static Charset parseEncoding(final byte[] b) {
 	 * @return the parsed identity or null in case the identity could not be
 	 *         parsed.
 	 */
-	public static PersonIdent parsePersonIdent(final String in) {
+	public static PersonIdent parsePersonIdent(String in) {
 		return parsePersonIdent(Constants.encode(in), 0);
 	}
 
@@ -851,7 +886,7 @@ public static PersonIdent parsePersonIdent(final String in) {
 	 * @return the parsed identity or null in case the identity could not be
 	 *         parsed.
 	 */
-	public static PersonIdent parsePersonIdent(final byte[] raw, final int nameB) {
+	public static PersonIdent parsePersonIdent(byte[] raw, int nameB) {
 		Charset cs;
 		try {
 			cs = parseEncoding(raw);
@@ -959,7 +994,7 @@ public static PersonIdent parsePersonIdentOnly(final byte[] raw,
 	 * @return position of the ':' which terminates the footer line key if this
 	 *         is otherwise a valid footer line key; otherwise -1.
 	 */
-	public static int endOfFooterLineKey(final byte[] raw, int ptr) {
+	public static int endOfFooterLineKey(byte[] raw, int ptr) {
 		try {
 			for (;;) {
 				final byte c = raw[ptr];
@@ -986,7 +1021,7 @@ public static int endOfFooterLineKey(final byte[] raw, int ptr) {
 	 * @return a string representation of the range <code>[start,end)</code>,
 	 *         after decoding the region through the specified character set.
 	 */
-	public static String decode(final byte[] buffer) {
+	public static String decode(byte[] buffer) {
 		return decode(buffer, 0, buffer.length);
 	}
 
@@ -1024,7 +1059,7 @@ public static String decode(final byte[] buffer, final int start,
 	 * @return a string representation of the range <code>[start,end)</code>,
 	 *         after decoding the region through the specified character set.
 	 */
-	public static String decode(final Charset cs, final byte[] buffer) {
+	public static String decode(Charset cs, byte[] buffer) {
 		return decode(cs, buffer, 0, buffer.length);
 	}
 
@@ -1076,7 +1111,7 @@ public static String decode(final Charset cs, final byte[] buffer,
 	 *            data from.
 	 * @return a string representation of the range <code>[start,end)</code>,
 	 *         after decoding the region through the specified character set.
-	 * @throws CharacterCodingException
+	 * @throws java.nio.charset.CharacterCodingException
 	 *             the input is not in any of the tested character sets.
 	 */
 	public static String decodeNoFallback(final Charset cs,
@@ -1141,7 +1176,7 @@ public static String extractBinaryString(final byte[] buffer,
 		return r.toString();
 	}
 
-	private static String decode(final ByteBuffer b, final Charset charset)
+	private static String decode(ByteBuffer b, Charset charset)
 			throws CharacterCodingException {
 		final CharsetDecoder d = charset.newDecoder();
 		d.onMalformedInput(CodingErrorAction.REPORT);
@@ -1160,7 +1195,7 @@ private static String decode(final ByteBuffer b, final Charset charset)
 	 *            commit buffer.
 	 * @return position of the user's message buffer.
 	 */
-	public static final int commitMessage(final byte[] b, int ptr) {
+	public static final int commitMessage(byte[] b, int ptr) {
 		final int sz = b.length;
 		if (ptr == 0)
 			ptr += 46; // skip the "tree ..." line.
@@ -1184,7 +1219,7 @@ public static final int commitMessage(final byte[] b, int ptr) {
 	 *            buffer.
 	 * @return position of the user's message buffer.
 	 */
-	public static final int tagMessage(final byte[] b, int ptr) {
+	public static final int tagMessage(byte[] b, int ptr) {
 		final int sz = b.length;
 		if (ptr == 0)
 			ptr += 48; // skip the "object ..." line.
@@ -1209,7 +1244,7 @@ public static final int tagMessage(final byte[] b, int ptr) {
 	 * @return position of the LF at the end of the paragraph;
 	 *         <code>b.length</code> if no paragraph end could be located.
 	 */
-	public static final int endOfParagraph(final byte[] b, final int start) {
+	public static final int endOfParagraph(byte[] b, int start) {
 		int ptr = start;
 		final int sz = b.length;
 		while (ptr < sz && (b[ptr] != '\n' && b[ptr] != '\r'))
@@ -1222,13 +1257,15 @@ public static final int endOfParagraph(final byte[] b, final int start) {
 	}
 
 	/**
+	 * Get last index of {@code ch} in raw, trimming spaces.
+	 *
 	 * @param raw
 	 *            buffer to scan.
 	 * @param ch
 	 *            character to find.
 	 * @param pos
 	 *            starting position.
-	 * @return last index of ch in raw, trimming spaces.
+	 * @return last index of {@code ch} in raw, trimming spaces.
 	 * @since 4.1
 	 */
 	public static int lastIndexOfTrim(byte[] raw, char ch, int pos) {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/RawSubStringPattern.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/RawSubStringPattern.java
index bc101bd..040b5cb 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/RawSubStringPattern.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/RawSubStringPattern.java
@@ -66,7 +66,7 @@ public class RawSubStringPattern {
 	 *            meta-characters are supported by this implementation. The
 	 *            string may not be the empty string.
 	 */
-	public RawSubStringPattern(final String patternText) {
+	public RawSubStringPattern(String patternText) {
 		if (patternText.length() == 0)
 			throw new IllegalArgumentException(JGitText.get().cannotMatchOnEmptyString);
 		needleString = patternText;
@@ -87,7 +87,7 @@ public RawSubStringPattern(final String patternText) {
 	 *         pattern; -1 if this pattern does not appear at any position of
 	 *         <code>rcs</code>.
 	 */
-	public int match(final RawCharSequence rcs) {
+	public int match(RawCharSequence rcs) {
 		final int needleLen = needle.length;
 		final byte first = needle[0];
 
@@ -114,11 +114,11 @@ public int match(final RawCharSequence rcs) {
 		return -1;
 	}
 
-	private static final boolean neq(final byte a, final byte b) {
+	private static final boolean neq(byte a, byte b) {
 		return a != b && a != lc(b);
 	}
 
-	private static final byte lc(final byte q) {
+	private static final byte lc(byte q) {
 		return (byte) StringUtils.toLowerCase((char) (q & 0xff));
 	}
 
@@ -131,6 +131,7 @@ public String pattern() {
 		return needleString;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public String toString() {
 		return pattern();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/RefList.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/RefList.java
index ce4b7c7..639c353 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/RefList.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/RefList.java
@@ -71,9 +71,9 @@ public class RefList<T extends Ref> implements Iterable<Ref> {
 	private static final RefList<Ref> EMPTY = new RefList<>(new Ref[0], 0);
 
 	/**
+	 * Create an empty unmodifiable reference list.
+	 *
 	 * @return an empty unmodifiable reference list.
-	 * @param <T>
-	 *            the type of reference being stored in the collection.
 	 */
 	@SuppressWarnings("unchecked")
 	public static <T extends Ref> RefList<T> emptyList() {
@@ -100,6 +100,7 @@ protected RefList(RefList<T> src) {
 		this.cnt = src.cnt;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public Iterator<Ref> iterator() {
 		return new Iterator<Ref>() {
@@ -124,18 +125,30 @@ public void remove() {
 		};
 	}
 
-	/** @return this cast as an immutable, standard {@link java.util.List}. */
+	/**
+	 * Cast {@code this} as an immutable, standard {@link java.util.List}.
+	 *
+	 * @return {@code this} as an immutable, standard {@link java.util.List}.
+	 */
 	public final List<Ref> asList() {
 		final List<Ref> r = Arrays.asList(list).subList(0, cnt);
 		return Collections.unmodifiableList(r);
 	}
 
-	/** @return number of items in this list. */
+	/**
+	 * Get number of items in this list.
+	 *
+	 * @return number of items in this list.
+	 */
 	public final int size() {
 		return cnt;
 	}
 
-	/** @return true if the size of this list is 0. */
+	/**
+	 * Get if this list is empty.
+	 *
+	 * @return true if the size of this list is 0.
+	 */
 	public final boolean isEmpty() {
 		return cnt == 0;
 	}
@@ -303,6 +316,7 @@ public final RefList<T> put(T ref) {
 		return add(idx, ref);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public String toString() {
 		StringBuilder r = new StringBuilder();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/RefMap.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/RefMap.java
index 510e818..a3f9730 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/RefMap.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/RefMap.java
@@ -59,17 +59,19 @@
  * Specialized Map to present a {@code RefDatabase} namespace.
  * <p>
  * Although not declared as a {@link java.util.SortedMap}, iterators from this
- * map's projections always return references in {@link RefComparator} ordering.
- * The map's internal representation is a sorted array of {@link Ref} objects,
+ * map's projections always return references in
+ * {@link org.eclipse.jgit.lib.RefComparator} ordering. The map's internal
+ * representation is a sorted array of {@link org.eclipse.jgit.lib.Ref} objects,
  * which means lookup and replacement is O(log N), while insertion and removal
  * can be as expensive as O(N + log N) while the list expands or contracts.
  * Since this is not a general map implementation, all entries must be keyed by
  * the reference name.
  * <p>
  * This class is really intended as a helper for {@code RefDatabase}, which
- * needs to perform a merge-join of three sorted {@link RefList}s in order to
- * present the unified namespace of the packed-refs file, the loose refs/
- * directory tree, and the resolved form of any symbolic references.
+ * needs to perform a merge-join of three sorted
+ * {@link org.eclipse.jgit.util.RefList}s in order to present the unified
+ * namespace of the packed-refs file, the loose refs/ directory tree, and the
+ * resolved form of any symbolic references.
  */
 public class RefMap extends AbstractMap<String, Ref> {
 	/**
@@ -109,7 +111,9 @@ public class RefMap extends AbstractMap<String, Ref> {
 
 	private Set<Entry<String, Ref>> entrySet;
 
-	/** Construct an empty map with a small initial capacity. */
+	/**
+	 * Construct an empty map with a small initial capacity.
+	 */
 	public RefMap() {
 		prefix = ""; //$NON-NLS-1$
 		packed = RefList.emptyList();
@@ -145,11 +149,13 @@ public RefMap(String prefix, RefList<? extends Ref> packed,
 		this.resolved = (RefList<Ref>) resolved;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public boolean containsKey(Object name) {
 		return get(name) != null;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public Ref get(Object key) {
 		String name = toRefName((String) key);
@@ -161,8 +167,9 @@ public Ref get(Object key) {
 		return ref;
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	public Ref put(final String keyName, Ref value) {
+	public Ref put(String keyName, Ref value) {
 		String name = toRefName(keyName);
 
 		if (!name.equals(value.getName()))
@@ -189,6 +196,7 @@ public Ref put(final String keyName, Ref value) {
 		}
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public Ref remove(Object key) {
 		String name = toRefName((String) key);
@@ -212,11 +220,13 @@ public Ref remove(Object key) {
 		return res;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public boolean isEmpty() {
 		return entrySet().isEmpty();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public Set<Entry<String, Ref>> entrySet() {
 		if (entrySet == null) {
@@ -258,6 +268,7 @@ public void clear() {
 		return entrySet;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public String toString() {
 		StringBuilder r = new StringBuilder();
@@ -344,7 +355,7 @@ public Entry<String, Ref> peek() {
 			return null;
 		}
 
-		private Ref resolveLoose(final Ref l) {
+		private Ref resolveLoose(Ref l) {
 			if (resolvedIdx < resolved.size()) {
 				Ref r = resolved.get(resolvedIdx);
 				int cmp = RefComparator.compareTo(l, r);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/RelativeDateFormatter.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/RelativeDateFormatter.java
index a5df66e..83c60c6 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/RelativeDateFormatter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/RelativeDateFormatter.java
@@ -67,10 +67,14 @@ public class RelativeDateFormatter {
 	final static long YEAR_IN_MILLIS = 365 * DAY_IN_MILLIS;
 
 	/**
+	 * Get age of given {@link java.util.Date} compared to now formatted in the
+	 * same relative format as returned by {@code git log --relative-date}
+	 *
 	 * @param when
-	 *            {@link Date} to format
-	 * @return age of given {@link Date} compared to now formatted in the same
-	 *         relative format as returned by {@code git log --relative-date}
+	 *            {@link java.util.Date} to format
+	 * @return age of given {@link java.util.Date} compared to now formatted in
+	 *         the same relative format as returned by
+	 *         {@code git log --relative-date}
 	 */
 	@SuppressWarnings("boxing")
 	public static String format(Date when) {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/SshSupport.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/SshSupport.java
new file mode 100644
index 0000000..96123ea
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/SshSupport.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2018, Markus Duft <markus.duft@ssi-schaefer.com>
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ *   copyright notice, this list of conditions and the following
+ *   disclaimer in the documentation and/or other materials provided
+ *   with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ *   names of its contributors may be used to endorse or promote
+ *   products derived from this software without specific prior
+ *   written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.eclipse.jgit.util;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+
+import org.eclipse.jgit.annotations.Nullable;
+import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.transport.CredentialsProvider;
+import org.eclipse.jgit.transport.RemoteSession;
+import org.eclipse.jgit.transport.SshSessionFactory;
+import org.eclipse.jgit.transport.URIish;
+import org.eclipse.jgit.util.io.MessageWriter;
+import org.eclipse.jgit.util.io.StreamCopyThread;
+
+/**
+ * Extra utilities to support usage of SSH.
+ *
+ * @since 5.0
+ */
+public class SshSupport {
+
+	/**
+	 * Utility to execute a remote SSH command and read the first line of
+	 * output.
+	 *
+	 * @param sshUri
+	 *            the SSH remote URI
+	 * @param provider
+	 *            the {@link CredentialsProvider} or <code>null</code>.
+	 * @param fs
+	 *            the {@link FS} implementation passed to
+	 *            {@link SshSessionFactory}
+	 * @param command
+	 *            the remote command to execute.
+	 * @param timeout
+	 *            a timeout in seconds.
+	 * @return The first line of output read from stdout. Stderr is discarded.
+	 * @throws IOException
+	 */
+	public static String runSshCommand(URIish sshUri,
+			@Nullable CredentialsProvider provider, FS fs, String command,
+			int timeout) throws IOException {
+		RemoteSession session = null;
+		Process process = null;
+		StreamCopyThread errorThread = null;
+		try (MessageWriter stderr = new MessageWriter()) {
+			session = SshSessionFactory.getInstance().getSession(sshUri,
+					provider, fs, 1000 * timeout);
+			process = session.exec(command, 0);
+			errorThread = new StreamCopyThread(process.getErrorStream(),
+					stderr.getRawStream());
+			errorThread.start();
+			try (BufferedReader reader = new BufferedReader(
+					new InputStreamReader(process.getInputStream(),
+							Constants.CHARSET))) {
+				return reader.readLine();
+			}
+		} finally {
+			if (errorThread != null) {
+				try {
+					errorThread.halt();
+				} catch (InterruptedException e) {
+					// Stop waiting and return anyway.
+				} finally {
+					errorThread = null;
+				}
+			}
+			if (process != null) {
+				process.destroy();
+			}
+			if (session != null) {
+				SshSessionFactory.getInstance().releaseSession(session);
+			}
+		}
+	}
+
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/StringUtils.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/StringUtils.java
index 2bfeaf1..3868e56 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/StringUtils.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/StringUtils.java
@@ -48,7 +48,9 @@
 
 import org.eclipse.jgit.internal.JGitText;
 
-/** Miscellaneous string comparison utility methods. */
+/**
+ * Miscellaneous string comparison utility methods.
+ */
 public final class StringUtils {
 	private static final char[] LC;
 
@@ -72,7 +74,7 @@ public final class StringUtils {
 	 *            the input character.
 	 * @return lowercase version of the input.
 	 */
-	public static char toLowerCase(final char c) {
+	public static char toLowerCase(char c) {
 		return c <= 'Z' ? LC[c] : c;
 	}
 
@@ -89,7 +91,7 @@ public static char toLowerCase(final char c) {
 	 * @return a copy of the input string, after converting characters in the
 	 *         range 'A'..'Z' to 'a'..'z'.
 	 */
-	public static String toLowerCase(final String in) {
+	public static String toLowerCase(String in) {
 		final StringBuilder r = new StringBuilder(in.length());
 		for (int i = 0; i < in.length(); i++)
 			r.append(toLowerCase(in.charAt(i)));
@@ -102,10 +104,12 @@ public static String toLowerCase(final String in) {
 	 *
 	 * <p>
 	 * Capitalizes a String changing the first letter to title case as per
-	 * {@link Character#toTitleCase(char)}. No other letters are changed.
+	 * {@link java.lang.Character#toTitleCase(char)}. No other letters are
+	 * changed.
 	 * </p>
-	 *
-	 * A <code>null</code> input String returns <code>null</code>.</p>
+	 * <p>
+	 * A <code>null</code> input String returns <code>null</code>.
+	 * </p>
 	 *
 	 * @param str
 	 *            the String to capitalize, may be null
@@ -134,7 +138,7 @@ public static String capitalize(String str) {
 	 *            second string to compare.
 	 * @return true if a equals b
 	 */
-	public static boolean equalsIgnoreCase(final String a, final String b) {
+	public static boolean equalsIgnoreCase(String a, String b) {
 		if (a == b)
 			return true;
 		if (a.length() != b.length())
@@ -156,9 +160,8 @@ public static boolean equalsIgnoreCase(final String a, final String b) {
 	 *            first string to compare.
 	 * @param b
 	 *            second string to compare.
-	 * @return negative, zero or positive if a sorts before, is equal to, or
-	 *         sorts after b.
 	 * @since 2.0
+	 * @return an int.
 	 */
 	public static int compareIgnoreCase(String a, String b) {
 		for (int i = 0; i < a.length() && i < b.length(); i++) {
@@ -179,9 +182,8 @@ public static int compareIgnoreCase(String a, String b) {
 	 *            first string to compare.
 	 * @param b
 	 *            second string to compare.
-	 * @return negative, zero or positive if a sorts before, is equal to, or
-	 *         sorts after b.
 	 * @since 2.0
+	 * @return an int.
 	 */
 	public static int compareWithCase(String a, String b) {
 		for (int i = 0; i < a.length() && i < b.length(); i++) {
@@ -199,11 +201,11 @@ public static int compareWithCase(String a, String b) {
 	 * @param stringValue
 	 *            the string to parse.
 	 * @return the boolean interpretation of {@code value}.
-	 * @throws IllegalArgumentException
+	 * @throws java.lang.IllegalArgumentException
 	 *             if {@code value} is not recognized as one of the standard
 	 *             boolean names.
 	 */
-	public static boolean toBoolean(final String stringValue) {
+	public static boolean toBoolean(String stringValue) {
 		if (stringValue == null)
 			throw new NullPointerException(JGitText.get().expectedBooleanStringValue);
 
@@ -230,7 +232,7 @@ public static boolean toBoolean(final String stringValue) {
 	 * @return the boolean interpretation of {@code value} or null in case the
 	 *         string does not represent a boolean value
 	 */
-	public static Boolean toBooleanOrNull(final String stringValue) {
+	public static Boolean toBooleanOrNull(String stringValue) {
 		if (stringValue == null)
 			return null;
 
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/SystemReader.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/SystemReader.java
index 2cd8035..96a796c 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/SystemReader.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/SystemReader.java
@@ -151,12 +151,18 @@ public int getTimezone(long when) {
 
 	private static SystemReader INSTANCE = DEFAULT;
 
-	/** @return the live instance to read system properties. */
+	/**
+	 * Get time since epoch, with up to millisecond resolution.
+	 *
+	 * @return time since epoch, with up to millisecond resolution.
+	 */
 	public static SystemReader getInstance() {
 		return INSTANCE;
 	}
 
 	/**
+	 * Set the new instance to use when accessing properties.
+	 *
 	 * @param newReader
 	 *            the new instance to use when accessing properties, or null for
 	 *            the default instance.
@@ -201,18 +207,26 @@ protected final void setPlatformChecker() {
 	public abstract String getHostname();
 
 	/**
-	 * @param variable system variable to read
+	 * Get value of the system variable
+	 *
+	 * @param variable
+	 *            system variable to read
 	 * @return value of the system variable
 	 */
 	public abstract String getenv(String variable);
 
 	/**
-	 * @param key of the system property to read
+	 * Get value of the system property
+	 *
+	 * @param key
+	 *            of the system property to read
 	 * @return value of the system property
 	 */
 	public abstract String getProperty(String key);
 
 	/**
+	 * Open the git configuration found in the user home
+	 *
 	 * @param parent
 	 *            a config with values not found directly in the returned config
 	 * @param fs
@@ -223,6 +237,8 @@ protected final void setPlatformChecker() {
 	public abstract FileBasedConfig openUserConfig(Config parent, FS fs);
 
 	/**
+	 * Open the gitonfig configuration found in the system-wide "etc" directory
+	 *
 	 * @param parent
 	 *            a config with values not found directly in the returned
 	 *            config. Null is a reasonable value here.
@@ -235,11 +251,15 @@ protected final void setPlatformChecker() {
 	public abstract FileBasedConfig openSystemConfig(Config parent, FS fs);
 
 	/**
+	 * Get the current system time
+	 *
 	 * @return the current system time
 	 */
 	public abstract long getCurrentTime();
 
 	/**
+	 * Get clock instance preferred by this system.
+	 *
 	 * @return clock instance preferred by this system.
 	 * @since 4.6
 	 */
@@ -248,12 +268,17 @@ public MonotonicClock getClock() {
 	}
 
 	/**
-	 * @param when TODO
+	 * Get the local time zone
+	 *
+	 * @param when
+	 *            a system timestamp
 	 * @return the local time zone
 	 */
 	public abstract int getTimezone(long when);
 
 	/**
+	 * Get system time zone, possibly mocked for testing
+	 *
 	 * @return system time zone, possibly mocked for testing
 	 * @since 1.2
 	 */
@@ -262,6 +287,8 @@ public TimeZone getTimeZone() {
 	}
 
 	/**
+	 * Get the locale to use
+	 *
 	 * @return the locale to use
 	 * @since 1.2
 	 */
@@ -274,7 +301,7 @@ public Locale getLocale() {
 	 *
 	 * @param pattern
 	 *            the pattern as defined in
-	 *            {@link SimpleDateFormat#SimpleDateFormat(String)}
+	 *            {@link java.text.SimpleDateFormat#SimpleDateFormat(String)}
 	 * @return the simple date format
 	 * @since 2.0
 	 */
@@ -287,7 +314,7 @@ public SimpleDateFormat getSimpleDateFormat(String pattern) {
 	 *
 	 * @param pattern
 	 *            the pattern as defined in
-	 *            {@link SimpleDateFormat#SimpleDateFormat(String)}
+	 *            {@link java.text.SimpleDateFormat#SimpleDateFormat(String)}
 	 * @param locale
 	 *            locale to be used for the {@code SimpleDateFormat}
 	 * @return the simple date format
@@ -302,10 +329,10 @@ public SimpleDateFormat getSimpleDateFormat(String pattern, Locale locale) {
 	 *
 	 * @param dateStyle
 	 *            the date style as specified in
-	 *            {@link DateFormat#getDateTimeInstance(int, int)}
+	 *            {@link java.text.DateFormat#getDateTimeInstance(int, int)}
 	 * @param timeStyle
 	 *            the time style as specified in
-	 *            {@link DateFormat#getDateTimeInstance(int, int)}
+	 *            {@link java.text.DateFormat#getDateTimeInstance(int, int)}
 	 * @return the date format
 	 * @since 2.0
 	 */
@@ -314,7 +341,9 @@ public DateFormat getDateTimeInstance(int dateStyle, int timeStyle) {
 	}
 
 	/**
-	 * @return true if we are running on a Windows.
+	 * Whether we are running on Windows.
+	 *
+	 * @return true if we are running on Windows.
 	 */
 	public boolean isWindows() {
 		if (isWindows == null) {
@@ -325,6 +354,8 @@ public boolean isWindows() {
 	}
 
 	/**
+	 * Whether we are running on Mac OS X
+	 *
 	 * @return true if we are running on Mac OS X
 	 */
 	public boolean isMacOS() {
@@ -351,7 +382,7 @@ public String run() {
 	 * Scans a multi-directory path string such as {@code "src/main.c"}.
 	 *
 	 * @param path path string to scan.
-	 * @throws CorruptObjectException path is invalid.
+	 * @throws org.eclipse.jgit.errors.CorruptObjectException path is invalid.
 	 * @since 3.6
 	 */
 	public void checkPath(String path) throws CorruptObjectException {
@@ -365,7 +396,7 @@ public void checkPath(String path) throws CorruptObjectException {
 	 *
 	 * @param path
 	 *            path string to scan.
-	 * @throws CorruptObjectException
+	 * @throws org.eclipse.jgit.errors.CorruptObjectException
 	 *             path is invalid.
 	 * @since 4.2
 	 */
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/TemporaryBuffer.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/TemporaryBuffer.java
index e3f1916..3ed7aeb 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/TemporaryBuffer.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/TemporaryBuffer.java
@@ -91,7 +91,7 @@ public abstract class TemporaryBuffer extends OutputStream {
 	 *            maximum number of bytes to store in memory before entering the
 	 *            overflow output path; also used as the estimated size.
 	 */
-	protected TemporaryBuffer(final int limit) {
+	protected TemporaryBuffer(int limit) {
 		this(limit, limit);
 	}
 
@@ -106,7 +106,7 @@ protected TemporaryBuffer(final int limit) {
 	 *            overflow output path.
 	 * @since 4.0
 	 */
-	protected TemporaryBuffer(final int estimatedSize, final int limit) {
+	protected TemporaryBuffer(int estimatedSize, int limit) {
 		if (estimatedSize > limit)
 			throw new IllegalArgumentException();
 		this.inCoreLimit = limit;
@@ -114,8 +114,9 @@ protected TemporaryBuffer(final int estimatedSize, final int limit) {
 		reset();
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	public void write(final int b) throws IOException {
+	public void write(int b) throws IOException {
 		if (overflow != null) {
 			overflow.write(b);
 			return;
@@ -134,8 +135,9 @@ public void write(final int b) throws IOException {
 		s.buffer[s.count++] = (byte) b;
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	public void write(final byte[] b, int off, int len) throws IOException {
+	public void write(byte[] b, int off, int len) throws IOException {
 		if (overflow == null) {
 			while (len > 0) {
 				Block s = last();
@@ -162,7 +164,7 @@ public void write(final byte[] b, int off, int len) throws IOException {
 	/**
 	 * Dumps the entire buffer into the overflow stream, and flushes it.
 	 *
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the overflow stream cannot be started, or the buffer contents
 	 *             cannot be written to it, or it failed to flush.
 	 */
@@ -177,11 +179,11 @@ protected void doFlush() throws IOException {
 	 *
 	 * @param in
 	 *            the stream to read from, until EOF is reached.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             an error occurred reading from the input stream, or while
 	 *             writing to a local temporary file.
 	 */
-	public void copy(final InputStream in) throws IOException {
+	public void copy(InputStream in) throws IOException {
 		if (blocks != null) {
 			for (;;) {
 				Block s = last();
@@ -227,10 +229,8 @@ private long inCoreLength() {
 	 * The buffer is only complete after {@link #close()} has been invoked.
 	 *
 	 * @return the complete byte array; length matches {@link #length()}.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             an error occurred reading from a local temporary file
-	 * @throws OutOfMemoryError
-	 *             the buffer cannot fit in memory
 	 */
 	public byte[] toByteArray() throws IOException {
 		final long len = length();
@@ -238,7 +238,7 @@ private long inCoreLength() {
 			throw new OutOfMemoryError(JGitText.get().lengthExceedsMaximumArraySize);
 		final byte[] out = new byte[(int) len];
 		int outPtr = 0;
-		for (final Block b : blocks) {
+		for (Block b : blocks) {
 			System.arraycopy(b.buffer, 0, out, outPtr, b.count);
 			outPtr += b.count;
 		}
@@ -253,13 +253,9 @@ private long inCoreLength() {
 	 *
 	 * @param limit
 	 *            the maximum number of bytes to be returned
-	 *
 	 * @return the byte array limited to {@code limit} bytes.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             an error occurred reading from a local temporary file
-	 * @throws OutOfMemoryError
-	 *             the buffer cannot fit in memory
-	 *
 	 * @since 4.2
 	 */
 	public byte[] toByteArray(int limit) throws IOException {
@@ -269,7 +265,7 @@ private long inCoreLength() {
 					JGitText.get().lengthExceedsMaximumArraySize);
 		final byte[] out = new byte[(int) len];
 		int outPtr = 0;
-		for (final Block b : blocks) {
+		for (Block b : blocks) {
 			System.arraycopy(b.buffer, 0, out, outPtr, b.count);
 			outPtr += b.count;
 		}
@@ -288,15 +284,15 @@ private long inCoreLength() {
 	 *            if not null progress updates are sent here. Caller should
 	 *            initialize the task and the number of work units to <code>
 	 *            {@link #length()}/1024</code>.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             an error occurred reading from a temporary file on the local
 	 *             system, or writing to the output stream.
 	 */
-	public void writeTo(final OutputStream os, ProgressMonitor pm)
+	public void writeTo(OutputStream os, ProgressMonitor pm)
 			throws IOException {
 		if (pm == null)
 			pm = NullProgressMonitor.INSTANCE;
-		for (final Block b : blocks) {
+		for (Block b : blocks) {
 			os.write(b.buffer, 0, b.count);
 			pm.update(b.count / 1024);
 		}
@@ -310,14 +306,36 @@ public void writeTo(final OutputStream os, ProgressMonitor pm)
 	 *
 	 * @return a stream to read from the buffer. The caller must close the
 	 *         stream when it is no longer useful.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             an error occurred opening the temporary file.
 	 */
 	public InputStream openInputStream() throws IOException {
 		return new BlockInputStream();
 	}
 
-	/** Reset this buffer for reuse, purging all buffered content. */
+	/**
+	 * Same as {@link #openInputStream()} but handling destruction of any
+	 * associated resources automatically when closing the returned stream.
+	 *
+	 * @return an InputStream which will automatically destroy any associated
+	 *         temporary file on {@link #close()}
+	 * @throws IOException
+	 *             in case of an error.
+	 * @since 4.11
+	 */
+	public InputStream openInputStreamWithAutoDestroy() throws IOException {
+		return new BlockInputStream() {
+			@Override
+			public void close() throws IOException {
+				super.close();
+				destroy();
+			}
+		};
+	}
+
+	/**
+	 * Reset this buffer for reuse, purging all buffered content.
+	 */
 	public void reset() {
 		if (overflow != null) {
 			destroy();
@@ -334,7 +352,7 @@ public void reset() {
 	 *
 	 * @return the output stream to receive the buffered content, followed by
 	 *         the remaining output.
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 *             the buffer cannot create the overflow stream.
 	 */
 	protected abstract OutputStream overflow() throws IOException;
@@ -355,7 +373,7 @@ private void switchToOverflow() throws IOException {
 		overflow = overflow();
 
 		final Block last = blocks.remove(blocks.size() - 1);
-		for (final Block b : blocks)
+		for (Block b : blocks)
 			overflow.write(b.buffer, 0, b.count);
 		blocks = null;
 
@@ -363,6 +381,7 @@ private void switchToOverflow() throws IOException {
 		overflow.write(last.buffer, 0, last.count);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void close() throws IOException {
 		if (overflow != null) {
@@ -374,7 +393,9 @@ public void close() throws IOException {
 		}
 	}
 
-	/** Clear this buffer so it has no data, and cannot be used again. */
+	/**
+	 * Clear this buffer so it has no data, and cannot be used again.
+	 */
 	public void destroy() {
 		blocks = null;
 
@@ -421,7 +442,7 @@ public static class LocalFile extends TemporaryBuffer {
 		 *            system default temporary directory (for example /tmp) will
 		 *            be used instead.
 		 */
-		public LocalFile(final File directory) {
+		public LocalFile(File directory) {
 			this(directory, DEFAULT_IN_CORE_LIMIT);
 		}
 
@@ -437,7 +458,7 @@ public LocalFile(final File directory) {
 		 *            maximum number of bytes to store in memory. Storage beyond
 		 *            this limit will use the local file.
 		 */
-		public LocalFile(final File directory, final int inCoreLimit) {
+		public LocalFile(File directory, int inCoreLimit) {
 			super(inCoreLimit);
 			this.directory = directory;
 		}
@@ -466,17 +487,14 @@ public long length() {
 			if (Integer.MAX_VALUE < len)
 				throw new OutOfMemoryError(JGitText.get().lengthExceedsMaximumArraySize);
 			final byte[] out = new byte[(int) len];
-			final FileInputStream in = new FileInputStream(onDiskFile);
-			try {
+			try (FileInputStream in = new FileInputStream(onDiskFile)) {
 				IO.readFully(in, out, 0, (int) len);
-			} finally {
-				in.close();
 			}
 			return out;
 		}
 
 		@Override
-		public void writeTo(final OutputStream os, ProgressMonitor pm)
+		public void writeTo(OutputStream os, ProgressMonitor pm)
 				throws IOException {
 			if (onDiskFile == null) {
 				super.writeTo(os, pm);
@@ -484,16 +502,13 @@ public void writeTo(final OutputStream os, ProgressMonitor pm)
 			}
 			if (pm == null)
 				pm = NullProgressMonitor.INSTANCE;
-			final FileInputStream in = new FileInputStream(onDiskFile);
-			try {
+			try (FileInputStream in = new FileInputStream(onDiskFile)) {
 				int cnt;
 				final byte[] buf = new byte[Block.SZ];
 				while ((cnt = in.read(buf)) >= 0) {
 					os.write(buf, 0, cnt);
 					pm.update(cnt / 1024);
 				}
-			} finally {
-				in.close();
 			}
 		}
 
@@ -505,6 +520,20 @@ public InputStream openInputStream() throws IOException {
 		}
 
 		@Override
+		public InputStream openInputStreamWithAutoDestroy() throws IOException {
+			if (onDiskFile == null) {
+				return super.openInputStreamWithAutoDestroy();
+			}
+			return new FileInputStream(onDiskFile) {
+				@Override
+				public void close() throws IOException {
+					super.close();
+					destroy();
+				}
+			};
+		}
+
+		@Override
 		public void destroy() {
 			super.destroy();
 
@@ -534,7 +563,7 @@ public static class Heap extends TemporaryBuffer {
 		 *            also used as the estimated size. Storing beyond this many
 		 *            will cause an IOException to be thrown during write.
 		 */
-		public Heap(final int limit) {
+		public Heap(int limit) {
 			super(limit);
 		}
 
@@ -550,7 +579,7 @@ public Heap(final int limit) {
 		 *            thrown during write.
 		 * @since 4.0
 		 */
-		public Heap(final int estimatedSize, final int limit) {
+		public Heap(int estimatedSize, int limit) {
 			super(estimatedSize, limit);
 		}
 
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/AutoCRLFInputStream.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/AutoCRLFInputStream.java
index 30f9ce9..08377e6 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/AutoCRLFInputStream.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/AutoCRLFInputStream.java
@@ -91,14 +91,16 @@ public AutoCRLFInputStream(InputStream in, boolean detectBinary) {
 		this.detectBinary = detectBinary;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public int read() throws IOException {
 		final int read = read(single, 0, 1);
 		return read == 1 ? single[0] & 0xff : -1;
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	public int read(byte[] bs, final int off, final int len) throws IOException {
+	public int read(byte[] bs, int off, int len) throws IOException {
 		if (len == 0)
 			return 0;
 
@@ -135,6 +137,7 @@ public int read(byte[] bs, final int off, final int len) throws IOException {
 		return n;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void close() throws IOException {
 		in.close();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/AutoCRLFOutputStream.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/AutoCRLFOutputStream.java
index 3a72f7e..d8cfee7 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/AutoCRLFOutputStream.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/AutoCRLFOutputStream.java
@@ -75,14 +75,18 @@ public class AutoCRLFOutputStream extends OutputStream {
 	private boolean isBinary;
 
 	/**
-	 * @param out
+	 * <p>Constructor for AutoCRLFOutputStream.</p>
+	 *
+	 * @param out a {@link java.io.OutputStream} object.
 	 */
 	public AutoCRLFOutputStream(OutputStream out) {
 		this(out, true);
 	}
 
 	/**
-	 * @param out
+	 * <p>Constructor for AutoCRLFOutputStream.</p>
+	 *
+	 * @param out a {@link java.io.OutputStream} object.
 	 * @param detectBinary
 	 *            whether binaries should be detected
 	 * @since 4.3
@@ -92,12 +96,14 @@ public AutoCRLFOutputStream(OutputStream out, boolean detectBinary) {
 		this.detectBinary = detectBinary;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void write(int b) throws IOException {
 		onebytebuf[0] = (byte) b;
 		write(onebytebuf, 0, 1);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void write(byte[] b) throws IOException {
 		int overflow = buffer(b, 0, b.length);
@@ -105,8 +111,9 @@ public void write(byte[] b) throws IOException {
 			write(b, b.length - overflow, overflow);
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	public void write(byte[] b, final int startOff, final int startLen)
+	public void write(byte[] b, int startOff, int startLen)
 			throws IOException {
 		final int overflow = buffer(b, startOff, startLen);
 		if (overflow < 0)
@@ -166,6 +173,7 @@ private void decideMode() throws IOException {
 		write(binbuf, 0, cachedLen);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void flush() throws IOException {
 		if (binbufcnt <= binbuf.length)
@@ -174,6 +182,7 @@ public void flush() throws IOException {
 		out.flush();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void close() throws IOException {
 		flush();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/AutoLFInputStream.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/AutoLFInputStream.java
index 6e33f99..ff28161 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/AutoLFInputStream.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/AutoLFInputStream.java
@@ -125,14 +125,16 @@ public AutoLFInputStream(InputStream in, boolean detectBinary,
 		this.abortIfBinary = abortIfBinary;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public int read() throws IOException {
 		final int read = read(single, 0, 1);
 		return read == 1 ? single[0] & 0xff : -1;
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	public int read(byte[] bs, final int off, final int len)
+	public int read(byte[] bs, int off, int len)
 			throws IOException {
 		if (len == 0)
 			return 0;
@@ -171,13 +173,16 @@ public int read(byte[] bs, final int off, final int len)
 	}
 
 	/**
-	 * @return true if the stream has detected as a binary so far
+	 * Whether the stream has detected as a binary so far.
+	 *
+	 * @return true if the stream has detected as a binary so far.
 	 * @since 3.3
 	 */
 	public boolean isBinary() {
 		return isBinary;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void close() throws IOException {
 		in.close();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/AutoLFOutputStream.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/AutoLFOutputStream.java
index c932b00..908d0a0 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/AutoLFOutputStream.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/AutoLFOutputStream.java
@@ -76,14 +76,24 @@ public class AutoLFOutputStream extends OutputStream {
 	private boolean isBinary;
 
 	/**
+	 * <p>
+	 * Constructor for AutoLFOutputStream.
+	 * </p>
+	 *
 	 * @param out
+	 *            an {@link java.io.OutputStream} object.
 	 */
 	public AutoLFOutputStream(OutputStream out) {
 		this(out, true);
 	}
 
 	/**
+	 * <p>
+	 * Constructor for AutoLFOutputStream.
+	 * </p>
+	 *
 	 * @param out
+	 *            an {@link java.io.OutputStream} object.
 	 * @param detectBinary
 	 *            whether binaries should be detected
 	 */
@@ -92,12 +102,14 @@ public AutoLFOutputStream(OutputStream out, boolean detectBinary) {
 		this.detectBinary = detectBinary;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void write(int b) throws IOException {
 		onebytebuf[0] = (byte) b;
 		write(onebytebuf, 0, 1);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void write(byte[] b) throws IOException {
 		int overflow = buffer(b, 0, b.length);
@@ -106,8 +118,9 @@ public void write(byte[] b) throws IOException {
 		}
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	public void write(byte[] b, final int startOff, final int startLen)
+	public void write(byte[] b, int startOff, int startLen)
 			throws IOException {
 		final int overflow = buffer(b, startOff, startLen);
 		if (overflow < 0) {
@@ -180,6 +193,7 @@ private void decideMode() throws IOException {
 		write(binbuf, 0, cachedLen);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void flush() throws IOException {
 		if (binbufcnt <= binbuf.length) {
@@ -188,6 +202,7 @@ public void flush() throws IOException {
 		out.flush();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void close() throws IOException {
 		flush();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/CountingOutputStream.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/CountingOutputStream.java
index ad6f1de..6fb1e6d 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/CountingOutputStream.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/CountingOutputStream.java
@@ -46,7 +46,9 @@
 import java.io.IOException;
 import java.io.OutputStream;
 
-/** Counts the number of bytes written. */
+/**
+ * Counts the number of bytes written.
+ */
 public class CountingOutputStream extends OutputStream {
 	private final OutputStream out;
 	private long cnt;
@@ -61,28 +63,36 @@ public CountingOutputStream(OutputStream out) {
 		this.out = out;
 	}
 
-	/** @return current number of bytes written. */
+	/**
+	 * Get current number of bytes written.
+	 *
+	 * @return current number of bytes written.
+	 */
 	public long getCount() {
 		return cnt;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void write(int val) throws IOException {
 		out.write(val);
 		cnt++;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void write(byte[] buf, int off, int len) throws IOException {
 		out.write(buf, off, len);
 		cnt += len;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void flush() throws IOException {
 		out.flush();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void close() throws IOException {
 		out.close();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/DisabledOutputStream.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/DisabledOutputStream.java
index 9ddf9b3..ec36495 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/DisabledOutputStream.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/DisabledOutputStream.java
@@ -48,7 +48,9 @@
 
 import org.eclipse.jgit.internal.JGitText;
 
-/** An OutputStream which always throws IllegalStateExeption during write. */
+/**
+ * An OutputStream which always throws IllegalStateExeption during write.
+ */
 public final class DisabledOutputStream extends OutputStream {
 	/** The canonical instance which always throws IllegalStateException. */
 	public static final DisabledOutputStream INSTANCE = new DisabledOutputStream();
@@ -58,6 +60,7 @@ private DisabledOutputStream() {
 		// more than one instance from being created.
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void write(int b) throws IOException {
 		// We shouldn't be writing output at this stage, there
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/EolCanonicalizingInputStream.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/EolCanonicalizingInputStream.java
deleted file mode 100644
index ee729e8..0000000
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/EolCanonicalizingInputStream.java
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright (C) 2010, 2013 Marc Strapetz <marc.strapetz@syntevo.com>
- * and other copyright owners as documented in the project's IP log.
- *
- * This program and the accompanying materials are made available
- * under the terms of the Eclipse Distribution License v1.0 which
- * accompanies this distribution, is reproduced below, and is
- * available at http://www.eclipse.org/org/documents/edl-v10.php
- *
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- * - Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- *
- * - Redistributions in binary form must reproduce the above
- *   copyright notice, this list of conditions and the following
- *   disclaimer in the documentation and/or other materials provided
- *   with the distribution.
- *
- * - Neither the name of the Eclipse Foundation, Inc. nor the
- *   names of its contributors may be used to endorse or promote
- *   products derived from this software without specific prior
- *   written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
- * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
- * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-package org.eclipse.jgit.util.io;
-
-import java.io.IOException;
-import java.io.InputStream;
-
-/**
- * An input stream which canonicalizes EOLs bytes on the fly to '\n'.
- *
- * Optionally, a binary check on the first 8000 bytes is performed and in case
- * of binary files, canonicalization is turned off (for the complete file).
- *
- * @deprecated use {@link AutoLFInputStream} instead
- */
-@Deprecated
-public class EolCanonicalizingInputStream extends AutoLFInputStream {
-
-	/**
-	 * Creates a new InputStream, wrapping the specified stream
-	 *
-	 * @param in
-	 *            raw input stream
-	 * @param detectBinary
-	 *            whether binaries should be detected
-	 */
-	public EolCanonicalizingInputStream(InputStream in, boolean detectBinary) {
-		super(in, detectBinary);
-	}
-
-	/**
-	 * Creates a new InputStream, wrapping the specified stream
-	 *
-	 * @param in
-	 *            raw input stream
-	 * @param detectBinary
-	 *            whether binaries should be detected
-	 * @param abortIfBinary
-	 *            throw an IOException if the file is binary
-	 */
-	public EolCanonicalizingInputStream(InputStream in, boolean detectBinary,
-			boolean abortIfBinary) {
-		super(in, detectBinary, abortIfBinary);
-	}
-
-	/**
-	 * A special exception thrown when {@link AutoLFInputStream} is told to
-	 * throw an exception when attempting to read a binary file. The exception
-	 * may be thrown at any stage during reading.
-	 *
-	 * @since 3.3
-	 */
-	public static class IsBinaryException extends IOException {
-		private static final long serialVersionUID = 1L;
-
-		IsBinaryException() {
-			super();
-		}
-	}
-
-}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/EolStreamTypeUtil.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/EolStreamTypeUtil.java
index 727c1f4..822961f 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/EolStreamTypeUtil.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/EolStreamTypeUtil.java
@@ -46,14 +46,13 @@
 import java.io.OutputStream;
 
 import org.eclipse.jgit.attributes.Attributes;
-import org.eclipse.jgit.lib.Config;
 import org.eclipse.jgit.lib.CoreConfig.EolStreamType;
 import org.eclipse.jgit.treewalk.TreeWalk.OperationType;
 import org.eclipse.jgit.treewalk.WorkingTreeOptions;
 
 /**
  * Utility used to create input and output stream wrappers for
- * {@link EolStreamType}
+ * {@link org.eclipse.jgit.lib.CoreConfig.EolStreamType}
  *
  * @since 4.3
  */
@@ -71,18 +70,24 @@ private EolStreamTypeUtil() {
 	 * <li>global attributes</li>
 	 * <li>info attributes</li>
 	 * <li>working tree .gitattributes</li>
+	 * </ul>
 	 *
 	 * @param op
-	 *            is the {@link OperationType} of the current traversal
+	 *            is the
+	 *            {@link org.eclipse.jgit.treewalk.TreeWalk.OperationType} of
+	 *            the current traversal
 	 * @param options
-	 *            are the {@link Config} options with key
-	 *            {@link WorkingTreeOptions#KEY}
+	 *            are the {@link org.eclipse.jgit.lib.Config} options with key
+	 *            {@link org.eclipse.jgit.treewalk.WorkingTreeOptions#KEY}
 	 * @param attrs
-	 *            are the {@link Attributes} of the file for which the
-	 *            {@link EolStreamType} is to be detected
-	 *
-	 * @return the stream conversion {@link EolStreamType} to be performed for
-	 *         the selected {@link OperationType}
+	 *            are the {@link org.eclipse.jgit.attributes.Attributes} of the
+	 *            file for which the
+	 *            {@link org.eclipse.jgit.lib.CoreConfig.EolStreamType} is to be
+	 *            detected
+	 * @return the stream conversion
+	 *         {@link org.eclipse.jgit.lib.CoreConfig.EolStreamType} to be
+	 *         performed for the selected
+	 *         {@link org.eclipse.jgit.treewalk.TreeWalk.OperationType}
 	 */
 	public static EolStreamType detectStreamType(OperationType op,
 			WorkingTreeOptions options, Attributes attrs) {
@@ -97,11 +102,15 @@ public static EolStreamType detectStreamType(OperationType op,
 	}
 
 	/**
+	 * Wrap the input stream depending on
+	 * {@link org.eclipse.jgit.lib.CoreConfig.EolStreamType}
+	 *
 	 * @param in
 	 *            original stream
 	 * @param conversion
 	 *            to be performed
-	 * @return the converted stream depending on {@link EolStreamType}
+	 * @return the converted stream depending on
+	 *         {@link org.eclipse.jgit.lib.CoreConfig.EolStreamType}
 	 */
 	public static InputStream wrapInputStream(InputStream in,
 			EolStreamType conversion) {
@@ -120,11 +129,15 @@ public static InputStream wrapInputStream(InputStream in,
 	}
 
 	/**
+	 * Wrap the output stream depending on
+	 * {@link org.eclipse.jgit.lib.CoreConfig.EolStreamType}
+	 *
 	 * @param out
 	 *            original stream
 	 * @param conversion
 	 *            to be performed
-	 * @return the converted stream depending on {@link EolStreamType}
+	 * @return the converted stream depending on
+	 *         {@link org.eclipse.jgit.lib.CoreConfig.EolStreamType}
 	 */
 	public static OutputStream wrapOutputStream(OutputStream out,
 			EolStreamType conversion) {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/InterruptTimer.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/InterruptTimer.java
index 0c5edb0..b7feddd 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/InterruptTimer.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/InterruptTimer.java
@@ -88,7 +88,9 @@ public final class InterruptTimer {
 
 	final AutoKiller autoKiller;
 
-	/** Create a new timer with a default thread name. */
+	/**
+	 * Create a new timer with a default thread name.
+	 */
 	public InterruptTimer() {
 		this("JGit-InterruptTimer"); //$NON-NLS-1$
 	}
@@ -101,7 +103,7 @@ public InterruptTimer() {
 	 * @param threadName
 	 *            name of the timer thread.
 	 */
-	public InterruptTimer(final String threadName) {
+	public InterruptTimer(String threadName) {
 		state = new AlarmState();
 		autoKiller = new AutoKiller(state);
 		thread = new AlarmThread(threadName, state);
@@ -115,7 +117,7 @@ public InterruptTimer(final String threadName) {
 	 *            number of milliseconds before the interrupt should trigger.
 	 *            Must be &gt; 0.
 	 */
-	public void begin(final int timeout) {
+	public void begin(int timeout) {
 		if (timeout <= 0)
 			throw new IllegalArgumentException(MessageFormat.format(
 					JGitText.get().invalidTimeout, Integer.valueOf(timeout)));
@@ -123,12 +125,16 @@ public void begin(final int timeout) {
 		state.begin(timeout);
 	}
 
-	/** Disable the interrupt timer, as the operation is complete. */
+	/**
+	 * Disable the interrupt timer, as the operation is complete.
+	 */
 	public void end() {
 		state.end();
 	}
 
-	/** Shutdown the timer thread, and wait for it to terminate. */
+	/**
+	 * Shutdown the timer thread, and wait for it to terminate.
+	 */
 	public void terminate() {
 		state.terminate();
 		try {
@@ -139,7 +145,7 @@ public void terminate() {
 	}
 
 	static final class AlarmThread extends Thread {
-		AlarmThread(final String name, final AlarmState q) {
+		AlarmThread(String name, AlarmState q) {
 			super(q);
 			setName(name);
 			setDaemon(true);
@@ -155,7 +161,7 @@ static final class AlarmThread extends Thread {
 	private static final class AutoKiller {
 		private final AlarmState state;
 
-		AutoKiller(final AlarmState s) {
+		AutoKiller(AlarmState s) {
 			state = s;
 		}
 
@@ -197,7 +203,7 @@ public synchronized void run() {
 			}
 		}
 
-		synchronized void begin(final int timeout) {
+		synchronized void begin(int timeout) {
 			if (terminated)
 				throw new IllegalStateException(JGitText.get().timerAlreadyTerminated);
 			callingThread = Thread.currentThread();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/IsolatedOutputStream.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/IsolatedOutputStream.java
index 3598a7b..65470d4 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/IsolatedOutputStream.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/IsolatedOutputStream.java
@@ -91,13 +91,15 @@ public IsolatedOutputStream(OutputStream out) {
 				new ArrayBlockingQueue<Runnable>(1), new NamedThreadFactory());
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void write(int ch) throws IOException {
 		write(new byte[] { (byte) ch }, 0, 1);
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	public void write(final byte[] buf, final int pos, final int cnt)
+	public void write(byte[] buf, int pos, int cnt)
 			throws IOException {
 		checkClosed();
 		execute(new Callable<Void>() {
@@ -109,6 +111,7 @@ public Void call() throws IOException {
 		});
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void flush() throws IOException {
 		checkClosed();
@@ -121,6 +124,7 @@ public Void call() throws IOException {
 		});
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void close() throws IOException {
 		if (!copier.isShutdown()) {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/LimitedInputStream.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/LimitedInputStream.java
index d74532f..9ab2caa 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/LimitedInputStream.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/LimitedInputStream.java
@@ -51,13 +51,13 @@
 import org.eclipse.jgit.internal.JGitText;
 
 /**
- * Wraps a {@link InputStream}, limiting the number of bytes which can be
- * read.
+ * Wraps a {@link java.io.InputStream}, limiting the number of bytes which can
+ * be read.
  *
- * This class was copied and modifed from the Google Guava 16.0. Differently from
- * the original Guava code, when a caller tries to read from this stream past
- * the given limit and the wrapped stream hasn't yet reached its EOF this class
- * will call the limitExceeded method instead of returning EOF.
+ * This class was copied and modifed from the Google Guava 16.0. Differently
+ * from the original Guava code, when a caller tries to read from this stream
+ * past the given limit and the wrapped stream hasn't yet reached its EOF this
+ * class will call the limitExceeded method instead of returning EOF.
  *
  * @since 3.3
  */
@@ -80,18 +80,21 @@ protected LimitedInputStream(InputStream in, long limit) {
 		this.limit = limit;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public int available() throws IOException {
 		return (int) Math.min(in.available(), left);
 	}
 
 	// it's okay to mark even if mark isn't supported, as reset won't work
+	/** {@inheritDoc} */
 	@Override
 	public synchronized void mark(int readLimit) {
 		in.mark(readLimit);
 		mark = left;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public int read() throws IOException {
 		if (left == 0) {
@@ -107,6 +110,7 @@ public int read() throws IOException {
 		return result;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public int read(byte[] b, int off, int len) throws IOException {
 		if (left == 0) {
@@ -123,6 +127,7 @@ public int read(byte[] b, int off, int len) throws IOException {
 		return result;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public synchronized void reset() throws IOException {
 		if (!in.markSupported())
@@ -135,6 +140,7 @@ public synchronized void reset() throws IOException {
 		left = mark;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public long skip(long n) throws IOException {
 		n = Math.min(n, left);
@@ -147,10 +153,11 @@ public long skip(long n) throws IOException {
 	 * Called when trying to read past the given {@link #limit} and the wrapped
 	 * InputStream {@link #in} hasn't yet reached its EOF
 	 *
-	 * @throws IOException
-	 *            subclasses can throw an IOException when the limit is exceeded.
-	 *            The throws IOException will be forwarded back to the caller of
-	 *            the read method which read the stream past the limit.
+	 * @throws java.io.IOException
+	 *             subclasses can throw an {@link java.io.IOException} when the
+	 *             limit is exceeded. The throws java.io.IOException will be
+	 *             forwarded back to the caller of the read method which read
+	 *             the stream past the limit.
 	 */
 	protected abstract void limitExceeded() throws IOException;
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/MessageWriter.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/MessageWriter.java
index a675360..94e5ef3 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/MessageWriter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/MessageWriter.java
@@ -66,20 +66,24 @@
  * {@link #toString()} returns all written data, after converting it to a String
  * under the assumption of UTF-8 encoding.
  * <p>
- * Internally {@link RawParseUtils#decode(byte[])} is used by {@code toString()}
- * tries to work out a reasonably correct character set for the raw data.
+ * Internally {@link org.eclipse.jgit.util.RawParseUtils#decode(byte[])} is used
+ * by {@code toString()} tries to work out a reasonably correct character set
+ * for the raw data.
  */
 public class MessageWriter extends Writer {
 	private final ByteArrayOutputStream buf;
 
 	private final OutputStreamWriter enc;
 
-	/** Create an empty writer. */
+	/**
+	 * Create an empty writer.
+	 */
 	public MessageWriter() {
 		buf = new ByteArrayOutputStream();
 		enc = new OutputStreamWriter(getRawStream(), Constants.CHARSET);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void write(char[] cbuf, int off, int len) throws IOException {
 		synchronized (buf) {
@@ -89,6 +93,9 @@ public void write(char[] cbuf, int off, int len) throws IOException {
 	}
 
 	/**
+	 * Get the underlying byte stream that character writes to this writer drop
+	 * into.
+	 *
 	 * @return the underlying byte stream that character writes to this writer
 	 *         drop into. Writes to this stream should should be in UTF-8.
 	 */
@@ -96,17 +103,20 @@ public OutputStream getRawStream() {
 		return buf;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void close() throws IOException {
 		// Do nothing, we are buffered with no resources.
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void flush() throws IOException {
 		// Do nothing, we are buffered with no resources.
 	}
 
 	/** @return string version of all buffered data. */
+	/** {@inheritDoc} */
 	@Override
 	public String toString() {
 		return RawParseUtils.decode(buf.toByteArray());
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/NullOutputStream.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/NullOutputStream.java
index 7b1e932..f90f7e4 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/NullOutputStream.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/NullOutputStream.java
@@ -57,16 +57,19 @@ private NullOutputStream() {
 		// more than one instance from being created.
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void write(int b) {
 		// Discard.
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void write(byte[] buf) {
 		// Discard.
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void write(byte[] buf, int pos, int cnt) {
 		// Discard.
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/SafeBufferedOutputStream.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/SilentFileInputStream.java
similarity index 73%
rename from org.eclipse.jgit/src/org/eclipse/jgit/util/io/SafeBufferedOutputStream.java
rename to org.eclipse.jgit/src/org/eclipse/jgit/util/io/SilentFileInputStream.java
index 84c3398..e58803b 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/SafeBufferedOutputStream.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/SilentFileInputStream.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011, Robin Rosenberg
+ * Copyright (C) 2018, David Pursehouse <david.pursehouse@gmail.com>
  * and other copyright owners as documented in the project's IP log.
  *
  * This program and the accompanying materials are made available
@@ -40,33 +40,36 @@
  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
+
 package org.eclipse.jgit.util.io;
 
-import java.io.BufferedOutputStream;
-import java.io.OutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
 
 /**
- * @deprecated use BufferedOutputStream in Java 8 and later.
+ * An implementation of FileInputStream that ignores any exceptions on close().
+ *
+ * @since 5.0
  */
-@Deprecated
-public class SafeBufferedOutputStream extends BufferedOutputStream {
+public class SilentFileInputStream extends FileInputStream {
 	/**
-	 * @see BufferedOutputStream#BufferedOutputStream(OutputStream)
-	 * @param out
-	 *            underlying output stream
+	 * @param file
+	 *            the file
+	 * @throws FileNotFoundException
+	 *             the file was not found
 	 */
-	public SafeBufferedOutputStream(OutputStream out) {
-		super(out);
+	public SilentFileInputStream(File file) throws FileNotFoundException {
+		super(file);
 	}
 
-	/**
-	 * @see BufferedOutputStream#BufferedOutputStream(OutputStream, int)
-	 * @param out
-	 *            underlying output stream
-	 * @param size
-	 *            buffer size
-	 */
-	public SafeBufferedOutputStream(OutputStream out, int size) {
-		super(out, size);
+	@Override
+	public void close() {
+		try {
+			super.close();
+		} catch (IOException e) {
+			// Ignore
+		}
 	}
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/StreamCopyThread.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/StreamCopyThread.java
index 7aba0a5..a9989a1 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/StreamCopyThread.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/StreamCopyThread.java
@@ -48,7 +48,9 @@
 import java.io.InterruptedIOException;
 import java.io.OutputStream;
 
-/** Thread to copy from an input stream to an output stream. */
+/**
+ * Thread to copy from an input stream to an output stream.
+ */
 public class StreamCopyThread extends Thread {
 	private static final int BUFFER_SIZE = 1024;
 
@@ -71,7 +73,7 @@ public class StreamCopyThread extends Thread {
 	 *            stream to copy into. The destination stream is automatically
 	 *            closed when the thread terminates.
 	 */
-	public StreamCopyThread(final InputStream i, final OutputStream o) {
+	public StreamCopyThread(InputStream i, OutputStream o) {
 		setName(Thread.currentThread().getName() + "-StreamCopy"); //$NON-NLS-1$
 		src = i;
 		dst = o;
@@ -79,26 +81,12 @@ public StreamCopyThread(final InputStream i, final OutputStream o) {
 	}
 
 	/**
-	 * Request the thread to flush the output stream as soon as possible.
-	 * <p>
-	 * This is an asynchronous request to the thread. The actual flush will
-	 * happen at some future point in time, when the thread wakes up to process
-	 * the request.
-	 */
-	@Deprecated
-	public void flush() {
-		synchronized (writeLock) {
-			interrupt();
-		}
-	}
-
-	/**
 	 * Request that the thread terminate, and wait for it.
 	 * <p>
 	 * This method signals to the copy thread that it should stop as soon as
 	 * there is no more IO occurring.
 	 *
-	 * @throws InterruptedException
+	 * @throws java.lang.InterruptedException
 	 *             the calling thread was interrupted.
 	 */
 	public void halt() throws InterruptedException {
@@ -112,6 +100,7 @@ public void halt() throws InterruptedException {
 		}
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void run() {
 		try {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/TeeInputStream.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/TeeInputStream.java
index a7a0347..e40a5a4 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/TeeInputStream.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/TeeInputStream.java
@@ -47,15 +47,13 @@
 import java.io.InputStream;
 import java.io.OutputStream;
 
-import org.eclipse.jgit.util.TemporaryBuffer;
-
 /**
  * Input stream that copies data read to another output stream.
  *
- * This stream is primarily useful with a {@link TemporaryBuffer}, where any
- * data read or skipped by the caller is also duplicated into the temporary
- * buffer. Later the temporary buffer can then be used instead of the original
- * source stream.
+ * This stream is primarily useful with a
+ * {@link org.eclipse.jgit.util.TemporaryBuffer}, where any data read or skipped
+ * by the caller is also duplicated into the temporary buffer. Later the
+ * temporary buffer can then be used instead of the original source stream.
  *
  * During close this stream copies any remaining data from the source stream
  * into the destination stream.
@@ -74,13 +72,14 @@ public class TeeInputStream extends InputStream {
 	 *            source stream to consume.
 	 * @param dst
 	 *            destination to copy the source to as it is consumed. Typically
-	 *            this is a {@link TemporaryBuffer}.
+	 *            this is a {@link org.eclipse.jgit.util.TemporaryBuffer}.
 	 */
 	public TeeInputStream(InputStream src, OutputStream dst) {
 		this.src = src;
 		this.dst = dst;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public int read() throws IOException {
 		byte[] b = skipBuffer();
@@ -88,8 +87,9 @@ public int read() throws IOException {
 		return n == 1 ? b[0] & 0xff : -1;
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	public long skip(final long count) throws IOException {
+	public long skip(long count) throws IOException {
 		long skipped = 0;
 		long cnt = count;
 		final byte[] b = skipBuffer();
@@ -104,6 +104,7 @@ public long skip(final long count) throws IOException {
 		return skipped;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public int read(byte[] b, int off, int len) throws IOException {
 		if (len == 0)
@@ -115,6 +116,7 @@ public int read(byte[] b, int off, int len) throws IOException {
 		return n;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void close() throws IOException {
 		byte[] b = skipBuffer();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/ThrowingPrintWriter.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/ThrowingPrintWriter.java
index 5eca0d9..caabcef 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/ThrowingPrintWriter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/ThrowingPrintWriter.java
@@ -64,7 +64,7 @@ public class ThrowingPrintWriter extends Writer {
 	 * Construct a JGitPrintWriter
 	 *
 	 * @param out
-	 *            the underlying {@link Writer}
+	 *            the underlying {@link java.io.Writer}
 	 */
 	public ThrowingPrintWriter(Writer out) {
 		this.out = out;
@@ -76,16 +76,19 @@ public String run() {
 		});
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void write(char[] cbuf, int off, int len) throws IOException {
 		out.write(cbuf, off, len);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void flush() throws IOException {
 		out.flush();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void close() throws IOException {
 		out.close();
@@ -94,8 +97,8 @@ public void close() throws IOException {
 	/**
 	 * Print a string and terminate with a line feed.
 	 *
-	 * @param s
-	 * @throws IOException
+	 * @param s a {@link java.lang.String} object.
+	 * @throws java.io.IOException
 	 */
 	public void println(String s) throws IOException {
 		print(s + LF);
@@ -104,7 +107,7 @@ public void println(String s) throws IOException {
 	/**
 	 * Print a platform dependent new line
 	 *
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 */
 	public void println() throws IOException {
 		print(LF);
@@ -113,8 +116,8 @@ public void println() throws IOException {
 	/**
 	 * Print a char
 	 *
-	 * @param value
-	 * @throws IOException
+	 * @param value a char.
+	 * @throws java.io.IOException
 	 */
 	public void print(char value) throws IOException {
 		print(String.valueOf(value));
@@ -124,7 +127,8 @@ public void print(char value) throws IOException {
 	 * Print an int as string
 	 *
 	 * @param value
-	 * @throws IOException
+	 *            an int.
+	 * @throws java.io.IOException
 	 */
 	public void print(int value) throws IOException {
 		print(String.valueOf(value));
@@ -133,8 +137,8 @@ public void print(int value) throws IOException {
 	/**
 	 * Print a long as string
 	 *
-	 * @param value
-	 * @throws IOException
+	 * @param value a long.
+	 * @throws java.io.IOException
 	 */
 	public void print(long value) throws IOException {
 		print(String.valueOf(value));
@@ -143,8 +147,8 @@ public void print(long value) throws IOException {
 	/**
 	 * Print a short as string
 	 *
-	 * @param value
-	 * @throws IOException
+	 * @param value a short.
+	 * @throws java.io.IOException
 	 */
 	public void print(short value) throws IOException {
 		print(String.valueOf(value));
@@ -152,11 +156,13 @@ public void print(short value) throws IOException {
 
 	/**
 	 * Print a formatted message according to
-	 * {@link String#format(String, Object...)}.
+	 * {@link java.lang.String#format(String, Object...)}.
 	 *
 	 * @param fmt
+	 *            a {@link java.lang.String} object.
 	 * @param args
-	 * @throws IOException
+	 *            objects.
+	 * @throws java.io.IOException
 	 */
 	public void format(String fmt, Object... args) throws IOException {
 		print(String.format(fmt, args));
@@ -166,7 +172,8 @@ public void format(String fmt, Object... args) throws IOException {
 	 * Print an object's toString representations
 	 *
 	 * @param any
-	 * @throws IOException
+	 *            an object.
+	 * @throws java.io.IOException
 	 */
 	public void print(Object any) throws IOException {
 		out.write(String.valueOf(any));
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/TimeoutInputStream.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/TimeoutInputStream.java
index 1148895..2392b8a 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/TimeoutInputStream.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/TimeoutInputStream.java
@@ -51,7 +51,9 @@
 
 import org.eclipse.jgit.internal.JGitText;
 
-/** InputStream with a configurable timeout. */
+/**
+ * InputStream with a configurable timeout.
+ */
 public class TimeoutInputStream extends FilterInputStream {
 	private final InterruptTimer myTimer;
 
@@ -72,22 +74,29 @@ public TimeoutInputStream(final InputStream src,
 		myTimer = timer;
 	}
 
-	/** @return number of milliseconds before aborting a read. */
+	/**
+	 * Get number of milliseconds before aborting a read.
+	 *
+	 * @return number of milliseconds before aborting a read.
+	 */
 	public int getTimeout() {
 		return timeout;
 	}
 
 	/**
+	 * Set number of milliseconds before aborting a read.
+	 *
 	 * @param millis
 	 *            number of milliseconds before aborting a read. Must be &gt; 0.
 	 */
-	public void setTimeout(final int millis) {
+	public void setTimeout(int millis) {
 		if (millis < 0)
 			throw new IllegalArgumentException(MessageFormat.format(
 					JGitText.get().invalidTimeout, Integer.valueOf(millis)));
 		timeout = millis;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public int read() throws IOException {
 		try {
@@ -100,11 +109,13 @@ public int read() throws IOException {
 		}
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public int read(byte[] buf) throws IOException {
 		return read(buf, 0, buf.length);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public int read(byte[] buf, int off, int cnt) throws IOException {
 		try {
@@ -117,6 +128,7 @@ public int read(byte[] buf, int off, int cnt) throws IOException {
 		}
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public long skip(long cnt) throws IOException {
 		try {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/TimeoutOutputStream.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/TimeoutOutputStream.java
index 9236d0e..27f1874 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/TimeoutOutputStream.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/TimeoutOutputStream.java
@@ -50,7 +50,9 @@
 
 import org.eclipse.jgit.internal.JGitText;
 
-/** OutputStream with a configurable timeout. */
+/**
+ * OutputStream with a configurable timeout.
+ */
 public class TimeoutOutputStream extends OutputStream {
 	private final OutputStream dst;
 
@@ -73,22 +75,30 @@ public TimeoutOutputStream(final OutputStream destination,
 		myTimer = timer;
 	}
 
-	/** @return number of milliseconds before aborting a write. */
+	/**
+	 * Get number of milliseconds before aborting a write.
+	 *
+	 * @return number of milliseconds before aborting a write.
+	 */
 	public int getTimeout() {
 		return timeout;
 	}
 
 	/**
+	 * Set number of milliseconds before aborting a write.
+	 *
 	 * @param millis
-	 *            number of milliseconds before aborting a write. Must be &gt; 0.
+	 *            number of milliseconds before aborting a write. Must be &gt;
+	 *            0.
 	 */
-	public void setTimeout(final int millis) {
+	public void setTimeout(int millis) {
 		if (millis < 0)
 			throw new IllegalArgumentException(MessageFormat.format(
 					JGitText.get().invalidTimeout, Integer.valueOf(millis)));
 		timeout = millis;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void write(int b) throws IOException {
 		try {
@@ -101,11 +111,13 @@ public void write(int b) throws IOException {
 		}
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void write(byte[] buf) throws IOException {
 		write(buf, 0, buf.length);
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void write(byte[] buf, int off, int len) throws IOException {
 		try {
@@ -118,6 +130,7 @@ public void write(byte[] buf, int off, int len) throws IOException {
 		}
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void flush() throws IOException {
 		try {
@@ -130,6 +143,7 @@ public void flush() throws IOException {
 		}
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void close() throws IOException {
 		try {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/UnionInputStream.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/UnionInputStream.java
index 1c46310..e14eb2b 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/UnionInputStream.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/UnionInputStream.java
@@ -58,7 +58,7 @@
  * Currently this stream does not support the mark/reset APIs. If mark and later
  * reset functionality is needed the caller should wrap this stream with a
  * {@link java.io.BufferedInputStream}.
- * */
+ */
 public class UnionInputStream extends InputStream {
 	private static final InputStream EOF = new InputStream() {
 		@Override
@@ -69,7 +69,9 @@ public int read() throws IOException {
 
 	private final LinkedList<InputStream> streams = new LinkedList<>();
 
-	/** Create an empty InputStream that is currently at EOF state. */
+	/**
+	 * Create an empty InputStream that is currently at EOF state.
+	 */
 	public UnionInputStream() {
 		// Do nothing.
 	}
@@ -105,7 +107,7 @@ private void pop() throws IOException {
 	 * @param in
 	 *            the stream to add; must not be null.
 	 */
-	public void add(final InputStream in) {
+	public void add(InputStream in) {
 		streams.add(in);
 	}
 
@@ -122,6 +124,7 @@ public boolean isEmpty() {
 		return streams.isEmpty();
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public int read() throws IOException {
 		for (;;) {
@@ -136,6 +139,7 @@ else if (in == EOF)
 		}
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public int read(byte[] b, int off, int len) throws IOException {
 		if (len == 0)
@@ -152,13 +156,15 @@ else if (in == EOF)
 		}
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public int available() throws IOException {
 		return head().available();
 	}
 
+	/** {@inheritDoc} */
 	@Override
-	public long skip(final long count) throws IOException {
+	public long skip(long count) throws IOException {
 		long skipped = 0;
 		long cnt = count;
 		while (0 < cnt) {
@@ -190,6 +196,7 @@ public long skip(final long count) throws IOException {
 		return skipped;
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public void close() throws IOException {
 		IOException err = null;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/sha1/SHA1.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/sha1/SHA1.java
index 5449711..9fe01f1 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/sha1/SHA1.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/sha1/SHA1.java
@@ -70,8 +70,8 @@
  * sha1collisiondetection</a> for more information.
  * <p>
  * When detectCollision is true (default), this implementation throws
- * {@link Sha1CollisionException} from any digest method if a potential
- * collision was detected.
+ * {@link org.eclipse.jgit.util.sha1.Sha1CollisionException} from any digest
+ * method if a potential collision was detected.
  *
  * @since 4.7
  */
@@ -85,7 +85,11 @@ public class SHA1 {
 		DETECT_COLLISIONS = v != null ? Boolean.parseBoolean(v) : true;
 	}
 
-	/** @return a new context to compute a SHA-1 hash of data. */
+	/**
+	 * Create a new context to compute a SHA-1 hash of data.
+	 *
+	 * @return a new context to compute a SHA-1 hash of data.
+	 */
 	public static SHA1 newInstance() {
 		return new SHA1();
 	}
@@ -121,6 +125,7 @@ private SHA1() {
 	 * {@code -Dorg.eclipse.jgit.util.sha1.detectCollision=true}.
 	 *
 	 * @param detect
+	 *            a boolean.
 	 * @return {@code this}
 	 */
 	public SHA1 setDetectCollision(boolean detect) {
@@ -131,7 +136,7 @@ public SHA1 setDetectCollision(boolean detect) {
 	/**
 	 * Update the digest computation by adding a byte.
 	 *
-	 * @param b
+	 * @param b a byte.
 	 */
 	public void update(byte b) {
 		int bufferLen = (int) (length & 63);
@@ -503,7 +508,7 @@ private void finish() {
 	 * Once {@code digest()} is called, this instance should be discarded.
 	 *
 	 * @return the bytes for the resulting hash.
-	 * @throws Sha1CollisionException
+	 * @throws org.eclipse.jgit.util.sha1.Sha1CollisionException
 	 *             if a collision was detected and safeHash is false.
 	 */
 	public byte[] digest() throws Sha1CollisionException {
@@ -524,7 +529,7 @@ private void finish() {
 	 * Once {@code digest()} is called, this instance should be discarded.
 	 *
 	 * @return the ObjectId for the resulting hash.
-	 * @throws Sha1CollisionException
+	 * @throws org.eclipse.jgit.util.sha1.Sha1CollisionException
 	 *             if a collision was detected and safeHash is false.
 	 */
 	public ObjectId toObjectId() throws Sha1CollisionException {
@@ -539,7 +544,7 @@ public ObjectId toObjectId() throws Sha1CollisionException {
 	 *
 	 * @param id
 	 *            destination to copy the digest to.
-	 * @throws Sha1CollisionException
+	 * @throws org.eclipse.jgit.util.sha1.Sha1CollisionException
 	 *             if a collision was detected and safeHash is false.
 	 */
 	public void digest(MutableObjectId id) throws Sha1CollisionException {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/sha1/Sha1CollisionException.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/sha1/Sha1CollisionException.java
index be126a5..dcefe95 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/sha1/Sha1CollisionException.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/sha1/Sha1CollisionException.java
@@ -49,7 +49,8 @@
 import org.eclipse.jgit.lib.ObjectId;
 
 /**
- * Thrown by {@link SHA1} if it detects a likely hash collision.
+ * Thrown by {@link org.eclipse.jgit.util.sha1.SHA1} if it detects a likely hash
+ * collision.
  *
  * @since 4.7
  */
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/time/MonotonicClock.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/time/MonotonicClock.java
index 794d851..c7c874d 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/time/MonotonicClock.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/time/MonotonicClock.java
@@ -44,7 +44,6 @@
 package org.eclipse.jgit.util.time;
 
 import java.time.Duration;
-import java.util.concurrent.TimeUnit;
 
 /**
  * A provider of time.
@@ -53,7 +52,9 @@
  * source, such as the local system clock.
  * <p>
  * MonotonicClocks provide the following behavior, with the assertion always
- * being true if {@link ProposedTimestamp#blockUntil(Duration)} is used:
+ * being true if
+ * {@link org.eclipse.jgit.util.time.ProposedTimestamp#blockUntil(Duration)} is
+ * used:
  *
  * <pre>
  *   MonotonicClock clk = ...;
@@ -64,7 +65,7 @@
  *   }
  *
  *   try (ProposedTimestamp t2 = clk.propose()) {
- *   	assert t2.millis() > r1;
+ *   	assert t2.millis() &gt; r1;
  *   }
  * </pre>
  *
@@ -83,14 +84,11 @@ public interface MonotonicClock {
 	 * by NTP) and return that proposal, concurrently sending network messages
 	 * to closely collaborating peers in the same cluster to also ensure their
 	 * system clocks are ahead of this time. In such an implementation the
-	 * {@link ProposedTimestamp#blockUntil(Duration)} method would wait for
-	 * replies from the peers indicating their own system clocks have moved past
-	 * the proposed time.
+	 * {@link org.eclipse.jgit.util.time.ProposedTimestamp#blockUntil(Duration)}
+	 * method would wait for replies from the peers indicating their own system
+	 * clocks have moved past the proposed time.
 	 *
-	 * @return "now". The value can be immediately accessed by
-	 *         {@link ProposedTimestamp#read(TimeUnit)} and friends, but the
-	 *         caller must use {@link ProposedTimestamp#blockUntil(Duration)} to
-	 *         ensure ordering holds.
+	 * @return a {@link org.eclipse.jgit.util.time.ProposedTimestamp} object.
 	 */
 	ProposedTimestamp propose();
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/time/MonotonicSystemClock.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/time/MonotonicSystemClock.java
index a9f4830..cce1e11 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/time/MonotonicSystemClock.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/time/MonotonicSystemClock.java
@@ -51,7 +51,8 @@
 import java.util.concurrent.atomic.AtomicLong;
 
 /**
- * A {@link MonotonicClock} based on {@code System.currentTimeMillis}.
+ * A {@link org.eclipse.jgit.util.time.MonotonicClock} based on
+ * {@code System.currentTimeMillis}.
  *
  * @since 4.6
  */
@@ -69,6 +70,7 @@ private static long nowMicros() {
 		}
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public ProposedTimestamp propose() {
 		final long u = nowMicros();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/time/ProposedTimestamp.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/time/ProposedTimestamp.java
index c09ab32..789950e 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/time/ProposedTimestamp.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/time/ProposedTimestamp.java
@@ -55,7 +55,8 @@
 import java.util.concurrent.TimeoutException;
 
 /**
- * A timestamp generated by {@link MonotonicClock#propose()}.
+ * A timestamp generated by
+ * {@link org.eclipse.jgit.util.time.MonotonicClock#propose()}.
  * <p>
  * ProposedTimestamp implements AutoCloseable so that implementations can
  * release resources associated with obtaining certainty about time elapsing.
@@ -73,10 +74,10 @@ public abstract class ProposedTimestamp implements AutoCloseable {
 	 *            timestamps to wait on.
 	 * @param maxWait
 	 *            how long to wait for the timestamps.
-	 * @throws InterruptedException
+	 * @throws java.lang.InterruptedException
 	 *             current thread was interrupted before the waiting process
 	 *             completed normally.
-	 * @throws TimeoutException
+	 * @throws java.util.concurrent.TimeoutException
 	 *             the timeout was reached without the proposed timestamp become
 	 *             certainly in the past.
 	 */
@@ -121,31 +122,44 @@ public static void blockUntil(Iterable<ProposedTimestamp> times,
 	 * <p>
 	 * This method forces the caller to wait up to {@code timeout} for
 	 * {@code this} to pass sufficiently into the past such that the creating
-	 * {@link MonotonicClock} instance will not create an earlier timestamp.
+	 * {@link org.eclipse.jgit.util.time.MonotonicClock} instance will not
+	 * create an earlier timestamp.
 	 *
 	 * @param maxWait
 	 *            how long the implementation may block the caller.
-	 * @throws InterruptedException
+	 * @throws java.lang.InterruptedException
 	 *             current thread was interrupted before the waiting process
 	 *             completed normally.
-	 * @throws TimeoutException
+	 * @throws java.util.concurrent.TimeoutException
 	 *             the timeout was reached without the proposed timestamp
 	 *             becoming certainly in the past.
 	 */
 	public abstract void blockUntil(Duration maxWait)
 			throws InterruptedException, TimeoutException;
 
-	/** @return milliseconds since epoch; {@code read(MILLISECONDS}). */
+	/**
+	 * Get milliseconds since epoch; {@code read(MILLISECONDS}).
+	 *
+	 * @return milliseconds since epoch; {@code read(MILLISECONDS}).
+	 */
 	public long millis() {
 		return read(MILLISECONDS);
 	}
 
-	/** @return microseconds since epoch; {@code read(MICROSECONDS}). */
+	/**
+	 * Get microseconds since epoch; {@code read(MICROSECONDS}).
+	 *
+	 * @return microseconds since epoch; {@code read(MICROSECONDS}).
+	 */
 	public long micros() {
 		return read(MICROSECONDS);
 	}
 
-	/** @return time since epoch, with up to microsecond resolution. */
+	/**
+	 * Get time since epoch, with up to microsecond resolution.
+	 *
+	 * @return time since epoch, with up to microsecond resolution.
+	 */
 	public Instant instant() {
 		long usec = micros();
 		long secs = usec / 1000000L;
@@ -153,22 +167,35 @@ public Instant instant() {
 		return Instant.ofEpochSecond(secs, nanos);
 	}
 
-	/** @return time since epoch, with up to microsecond resolution. */
+	/**
+	 * Get time since epoch, with up to microsecond resolution.
+	 *
+	 * @return time since epoch, with up to microsecond resolution.
+	 */
 	public Timestamp timestamp() {
 		return Timestamp.from(instant());
 	}
 
-	/** @return time since epoch, with up to millisecond resolution. */
+	/**
+	 * Get time since epoch, with up to millisecond resolution.
+	 *
+	 * @return time since epoch, with up to millisecond resolution.
+	 */
 	public Date date() {
 		return new Date(millis());
 	}
 
-	/** Release resources allocated by this timestamp. */
+	/**
+	 * {@inheritDoc}
+	 * <p>
+	 * Release resources allocated by this timestamp.
+	 */
 	@Override
 	public void close() {
 		// Do nothing by default.
 	}
 
+	/** {@inheritDoc} */
 	@Override
 	public String toString() {
 		return instant().toString();
diff --git a/pom.xml b/pom.xml
index 74cd61d..042b21e 100644
--- a/pom.xml
+++ b/pom.xml
@@ -51,7 +51,7 @@
   <groupId>org.eclipse.jgit</groupId>
   <artifactId>org.eclipse.jgit-parent</artifactId>
   <packaging>pom</packaging>
-  <version>4.9.3-SNAPSHOT</version>
+  <version>5.0.0-SNAPSHOT</version>
 
   <name>JGit - Parent</name>
   <url>${jgit-url}</url>
@@ -70,10 +70,6 @@
     <connection>scm:git:https://git.eclipse.org/r/jgit/jgit</connection>
   </scm>
 
-  <prerequisites>
-    <maven>3.3.1</maven>
-  </prerequisites>
-
   <ciManagement>
     <system>hudson</system>
     <url>https://hudson.eclipse.org/jgit/</url>
@@ -93,6 +89,9 @@
       <name>Dave Borowitz</name>
     </developer>
     <developer>
+      <name>David Pursehouse</name>
+    </developer>
+    <developer>
       <name>Gunnar Wagenknecht</name>
     </developer>
     <developer>
@@ -122,6 +121,9 @@
     <developer>
       <name>Stefan Lay</name>
     </developer>
+    <developer>
+      <name>Thomas Wolf</name>
+    </developer>
   </developers>
 
   <mailingLists>
@@ -195,25 +197,27 @@
     <maven.build.timestamp.format>yyyyMMddHHmm</maven.build.timestamp.format>
     <bundle-manifest>${project.build.directory}/META-INF/MANIFEST.MF</bundle-manifest>
 
-    <jgit-last-release-version>4.7.0.201704051617-r</jgit-last-release-version>
+    <jgit-last-release-version>4.11.0.201803080745-r</jgit-last-release-version>
     <jsch-version>0.1.54</jsch-version>
+    <jzlib-version>1.1.1</jzlib-version>
     <javaewah-version>1.1.6</javaewah-version>
     <junit-version>4.12</junit-version>
     <test-fork-count>1C</test-fork-count>
     <args4j-version>2.33</args4j-version>
-    <commons-compress-version>1.6</commons-compress-version>
+    <commons-compress-version>1.15</commons-compress-version>
     <osgi-core-version>4.3.1</osgi-core-version>
     <servlet-api-version>3.1.0</servlet-api-version>
-    <jetty-version>9.4.5.v20170502</jetty-version>
-    <japicmp-version>0.10.0</japicmp-version>
-    <httpclient-version>4.3.6</httpclient-version>
+    <jetty-version>9.4.8.v20171121</jetty-version>
+    <japicmp-version>0.11.0</japicmp-version>
+    <httpclient-version>4.5.2</httpclient-version>
+    <httpcore-version>4.4.6</httpcore-version>
     <slf4j-version>1.7.2</slf4j-version>
     <log4j-version>1.2.15</log4j-version>
-    <maven-javadoc-plugin-version>2.10.4</maven-javadoc-plugin-version>
-    <tycho-extras-version>1.0.0</tycho-extras-version>
-    <gson-version>2.2.4</gson-version>
-    <spotbugs-maven-plugin-version>3.0.6</spotbugs-maven-plugin-version>
-    <maven-surefire-report-plugin-version>2.20</maven-surefire-report-plugin-version>
+    <maven-javadoc-plugin-version>3.0.1</maven-javadoc-plugin-version>
+    <tycho-extras-version>1.1.0</tycho-extras-version>
+    <gson-version>2.8.2</gson-version>
+    <spotbugs-maven-plugin-version>3.1.2</spotbugs-maven-plugin-version>
+    <maven-surefire-report-plugin-version>2.20.1</maven-surefire-report-plugin-version>
 
     <!-- Properties to enable jacoco code coverage analysis -->
     <sonar.core.codeCoveragePlugin>jacoco</sonar.core.codeCoveragePlugin>
@@ -263,63 +267,6 @@
         </plugin>
 
         <plugin>
-          <artifactId>maven-compiler-plugin</artifactId>
-          <version>3.6.2</version>
-          <configuration>
-            <encoding>UTF-8</encoding>
-            <source>1.8</source>
-            <target>1.8</target>
-          </configuration>
-          <executions>
-            <execution>
-              <id>default-compile</id>
-              <phase>compile</phase>
-              <goals>
-                <goal>compile</goal>
-              </goals>
-              <configuration>
-                <includes>
-                  <include>org/eclipse/jgit/transport/InsecureCipherFactory.java</include>
-                </includes>
-              </configuration>
-            </execution>
-            <execution>
-              <id>compile-with-errorprone</id>
-              <phase>compile</phase>
-              <goals>
-                <goal>compile</goal>
-              </goals>
-              <configuration>
-                <compilerId>javac-with-errorprone</compilerId>
-                <forceJavacCompilerUse>true</forceJavacCompilerUse>
-                <excludes>
-                  <exclude>org/eclipse/jgit/transport/InsecureCipherFactory.java</exclude>
-                </excludes>
-              </configuration>
-            </execution>
-          </executions>
-          <dependencies>
-            <dependency>
-              <groupId>org.codehaus.plexus</groupId>
-              <artifactId>plexus-compiler-javac</artifactId>
-              <version>2.8.2</version>
-            </dependency>
-            <dependency>
-              <groupId>org.codehaus.plexus</groupId>
-              <artifactId>plexus-compiler-javac-errorprone</artifactId>
-              <version>2.8.2</version>
-            </dependency>
-            <!-- override plexus-compiler-javac-errorprone's dependency on
-                 Error Prone with the latest version -->
-            <dependency>
-              <groupId>com.google.errorprone</groupId>
-              <artifactId>error_prone_core</artifactId>
-              <version>2.1.1</version>
-            </dependency>
-          </dependencies>
-        </plugin>
-
-        <plugin>
           <artifactId>maven-clean-plugin</artifactId>
           <version>3.0.0</version>
         </plugin>
@@ -327,7 +274,7 @@
         <plugin>
           <groupId>org.apache.maven.plugins</groupId>
           <artifactId>maven-shade-plugin</artifactId>
-          <version>3.0.0</version>
+          <version>3.1.0</version>
         </plugin>
 
         <plugin>
@@ -339,7 +286,7 @@
         <plugin>
           <groupId>org.apache.maven.plugins</groupId>
           <artifactId>maven-dependency-plugin</artifactId>
-          <version>3.0.0</version>
+          <version>3.1.1</version>
         </plugin>
 
         <plugin>
@@ -357,7 +304,7 @@
         <plugin>
           <groupId>org.apache.maven.plugins</groupId>
           <artifactId>maven-surefire-plugin</artifactId>
-          <version>2.20</version>
+          <version>2.20.1</version>
           <configuration>
             <forkCount>${test-fork-count}</forkCount>
             <reuseForks>true</reuseForks>
@@ -371,7 +318,7 @@
         </plugin>
 
         <plugin>
-          <groupId>com.github.hazendaz.spotbugs</groupId>
+          <groupId>com.github.spotbugs</groupId>
           <artifactId>spotbugs-maven-plugin</artifactId>
           <version>${spotbugs-maven-plugin-version}</version>
           <configuration>
@@ -462,6 +409,27 @@
 
     <plugins>
       <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-enforcer-plugin</artifactId>
+        <version>3.0.0-M1</version>
+        <executions>
+          <execution>
+            <id>enforce-maven</id>
+            <goals>
+              <goal>enforce</goal>
+            </goals>
+            <configuration>
+              <rules>
+                <requireMavenVersion>
+                  <version>3.5.2</version>
+                </requireMavenVersion>
+              </rules>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+
+      <plugin>
         <artifactId>maven-compiler-plugin</artifactId>
       </plugin>
 
@@ -506,6 +474,7 @@
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-javadoc-plugin</artifactId>
         <configuration>
+          <additionalparam>-Xdoclint:-missing</additionalparam>
           <encoding>${project.build.sourceEncoding}</encoding>
           <quiet>true</quiet>
           <excludePackageNames>org.eclipse.jgit.http.test</excludePackageNames>
@@ -570,8 +539,6 @@
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-javadoc-plugin</artifactId>
         <version>${maven-javadoc-plugin-version}</version>
-        <configuration>
-        </configuration>
       </plugin>
       <plugin>
         <groupId>org.apache.maven.plugins</groupId>
@@ -579,7 +546,7 @@
         <version>2.5</version>
       </plugin>
       <plugin>
-        <groupId>com.github.hazendaz.spotbugs</groupId>
+        <groupId>com.github.spotbugs</groupId>
         <artifactId>spotbugs-maven-plugin</artifactId>
         <version>${spotbugs-maven-plugin-version}</version>
       </plugin>
@@ -607,6 +574,12 @@
       </dependency>
 
       <dependency>
+        <groupId>com.jcraft</groupId>
+        <artifactId>jzlib</artifactId>
+        <version>${jzlib-version}</version>
+      </dependency>
+
+      <dependency>
         <groupId>com.googlecode.javaewah</groupId>
         <artifactId>JavaEWAH</artifactId>
         <version>${javaewah-version}</version>
@@ -637,6 +610,13 @@
       </dependency>
 
       <dependency>
+        <groupId>org.tukaani</groupId>
+        <artifactId>xz</artifactId>
+        <version>1.6</version>
+        <optional>true</optional>
+      </dependency>
+
+      <dependency>
         <groupId>org.eclipse.jetty</groupId>
         <artifactId>jetty-servlet</artifactId>
         <version>${jetty-version}</version>
@@ -655,6 +635,12 @@
       </dependency>
 
       <dependency>
+        <groupId>org.apache.httpcomponents</groupId>
+        <artifactId>httpcore</artifactId>
+        <version>${httpcore-version}</version>
+      </dependency>
+
+      <dependency>
         <groupId>org.slf4j</groupId>
         <artifactId>slf4j-api</artifactId>
         <version>${slf4j-version}</version>
@@ -719,39 +705,112 @@
 
   <profiles>
     <profile>
-      <id>jgit.java8</id>
+      <id>javac</id>
+      <build>
+        <plugins>
+          <plugin>
+            <artifactId>maven-compiler-plugin</artifactId>
+            <version>3.7.0</version>
+            <configuration>
+              <encoding>UTF-8</encoding>
+              <source>1.8</source>
+              <target>1.8</target>
+            </configuration>
+            <executions>
+              <execution>
+                <id>default-compile</id>
+                <phase>compile</phase>
+                <goals>
+                  <goal>compile</goal>
+                </goals>
+                <configuration>
+                  <includes>
+                    <include>org/eclipse/jgit/transport/InsecureCipherFactory.java</include>
+                  </includes>
+                </configuration>
+              </execution>
+              <execution>
+                <id>compile-with-errorprone</id>
+                <phase>compile</phase>
+                <goals>
+                  <goal>compile</goal>
+                </goals>
+                <configuration>
+                  <compilerId>javac-with-errorprone</compilerId>
+                  <forceJavacCompilerUse>true</forceJavacCompilerUse>
+                  <excludes>
+                    <exclude>org/eclipse/jgit/transport/InsecureCipherFactory.java</exclude>
+                  </excludes>
+                </configuration>
+              </execution>
+            </executions>
+            <dependencies>
+              <dependency>
+                <groupId>org.codehaus.plexus</groupId>
+                <artifactId>plexus-compiler-javac</artifactId>
+                <version>2.8.2</version>
+              </dependency>
+              <dependency>
+                <groupId>org.codehaus.plexus</groupId>
+                <artifactId>plexus-compiler-javac-errorprone</artifactId>
+                <version>2.8.4</version>
+              </dependency>
+              <!-- override plexus-compiler-javac-errorprone's dependency on
+                  Error Prone with the latest version -->
+              <dependency>
+                <groupId>com.google.errorprone</groupId>
+                <artifactId>error_prone_core</artifactId>
+                <version>2.3.1</version>
+              </dependency>
+            </dependencies>
+          </plugin>
+        </plugins>
+      </build>
+    </profile>
+    <profile>
+      <id>ecj</id>
       <activation>
-        <jdk>[1.8,)</jdk>
+        <activeByDefault>true</activeByDefault>
       </activation>
       <build>
         <plugins>
           <plugin>
-            <groupId>org.apache.maven.plugins</groupId>
-            <artifactId>maven-javadoc-plugin</artifactId>
+            <artifactId>maven-compiler-plugin</artifactId>
+            <version>3.7.0</version>
             <configuration>
-              <additionalparam>-Xdoclint:-missing</additionalparam>
+              <compilerId>eclipse</compilerId>
+              <encoding>UTF-8</encoding>
+              <source>1.8</source>
+              <target>1.8</target>
+              <!-- Passing arguments is a trainwreck, see https://issues.apache.org/jira/browse/MCOMPILER-123 -->
+              <compilerArguments>
+                <properties>${project.basedir}/.settings/org.eclipse.jdt.core.prefs</properties>
+              </compilerArguments>
+              <showWarnings>true</showWarnings>
+              <showDeprecation>true</showDeprecation>
             </configuration>
+            <dependencies>
+              <dependency>
+                <groupId>org.codehaus.plexus</groupId>
+                <artifactId>plexus-compiler-eclipse</artifactId>
+                <version>2.8.4</version>
+              </dependency>
+              <dependency>
+                <groupId>org.eclipse.jdt</groupId>
+                <artifactId>ecj</artifactId>
+                <version>3.13.102</version>
+              </dependency>
+            </dependencies>
           </plugin>
         </plugins>
       </build>
-      <reporting>
-        <plugins>
-          <plugin>
-            <groupId>org.apache.maven.plugins</groupId>
-            <artifactId>maven-javadoc-plugin</artifactId>
-            <configuration>
-              <additionalparam>-Xdoclint:-missing</additionalparam>
-            </configuration>
-          </plugin>
-        </plugins>
-      </reporting>
     </profile>
     <profile>
       <id>static-checks</id>
       <build>
         <plugins>
           <plugin>
-            <groupId>com.github.hazendaz.spotbugs</groupId>
+            <groupId>com.github.spotbugs</groupId>
             <artifactId>spotbugs-maven-plugin</artifactId>
           </plugin>
           <plugin>