Merge branch 'stable-4.11' into stable-5.0

* stable-4.11:
  Prepare 4.11.8-SNAPSHOT builds
  JGit v4.11.7.201903122105-r
  Prepare 4.9.10-SNAPSHOT builds
  JGit v4.9.9.201903122025-r
  Prepare 4.7.9-SNAPSHOT builds
  JGit v4.7.8.201903121755-r
  Prepare 4.5.7-SNAPSHOT builds
  JGit v4.5.6.201903121547-r
  Check for packfile validity and fd before reading
  Move throw of PackInvalidException outside the catch
  Use FileSnapshot to get lastModified on PackFile
  Include size when comparing FileSnapshot
  Do not reuse packfiles when changed on filesystem
  Silence API warnings for new API introduced for fixes

Change-Id: I04c70f66c6f1e53bdc199fb5b24c9136c9a8e4f7
Signed-off-by: Matthias Sohn <matthias.sohn@sap.com>
diff --git a/org.eclipse.jgit.ant.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.ant.test/META-INF/MANIFEST.MF
index c64401a..268baee 100644
--- a/org.eclipse.jgit.ant.test/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.ant.test/META-INF/MANIFEST.MF
@@ -4,13 +4,13 @@
 Bundle-Name: %plugin_name
 Automatic-Module-Name: org.eclipse.jgit.ant.test
 Bundle-SymbolicName: org.eclipse.jgit.ant.test
-Bundle-Version: 4.11.8.qualifier
+Bundle-Version: 5.0.4.qualifier
 Bundle-ActivationPolicy: lazy
 Bundle-RequiredExecutionEnvironment: JavaSE-1.8
 Import-Package: org.apache.tools.ant,
- org.eclipse.jgit.ant.tasks;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.junit;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.lib;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.util;version="[4.11.8,4.12.0)",
+ org.eclipse.jgit.ant.tasks;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.junit;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.lib;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.util;version="[5.0.4,5.1.0)",
  org.hamcrest.core;version="[1.1.0,2.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 64b8f81..4bfbc9e 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.11.8-SNAPSHOT</version>
+    <version>5.0.4-SNAPSHOT</version>
   </parent>
 
   <artifactId>org.eclipse.jgit.ant.test</artifactId>
diff --git a/org.eclipse.jgit.ant/META-INF/MANIFEST.MF b/org.eclipse.jgit.ant/META-INF/MANIFEST.MF
index 00400bc..6df3091 100644
--- a/org.eclipse.jgit.ant/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.ant/META-INF/MANIFEST.MF
@@ -3,11 +3,11 @@
 Bundle-Name: %Bundle-Name
 Automatic-Module-Name: org.eclipse.jgit.ant
 Bundle-SymbolicName: org.eclipse.jgit.ant
-Bundle-Version: 4.11.8.qualifier
+Bundle-Version: 5.0.4.qualifier
 Bundle-RequiredExecutionEnvironment: JavaSE-1.8
 Import-Package: org.apache.tools.ant,
-  org.eclipse.jgit.storage.file;version="[4.11.8,4.12.0)"
+  org.eclipse.jgit.storage.file;version="[5.0.4,5.1.0)"
 Bundle-Localization: plugin
 Bundle-Vendor: %Provider-Name
-Export-Package: org.eclipse.jgit.ant.tasks;version="4.11.8";
+Export-Package: org.eclipse.jgit.ant.tasks;version="5.0.4";
  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 7d86718..a288360 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.11.8-SNAPSHOT</version>
+		<version>5.0.4-SNAPSHOT</version>
 	</parent>
 
 	<artifactId>org.eclipse.jgit.ant</artifactId>
diff --git a/org.eclipse.jgit.archive/META-INF/MANIFEST.MF b/org.eclipse.jgit.archive/META-INF/MANIFEST.MF
index 05d16ab..3285ee4 100644
--- a/org.eclipse.jgit.archive/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.archive/META-INF/MANIFEST.MF
@@ -3,7 +3,7 @@
 Bundle-Name: %plugin_name
 Automatic-Module-Name: org.eclipse.jgit.archive
 Bundle-SymbolicName: org.eclipse.jgit.archive
-Bundle-Version: 4.11.8.qualifier
+Bundle-Version: 5.0.4.qualifier
 Bundle-Vendor: %provider_name
 Bundle-Localization: plugin
 Bundle-RequiredExecutionEnvironment: JavaSE-1.8
@@ -13,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.11.8,4.12.0)",
- org.eclipse.jgit.lib;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.nls;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.revwalk;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.util;version="[4.11.8,4.12.0)",
+ org.eclipse.jgit.api;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.lib;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.nls;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.revwalk;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.util;version="[5.0.4,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.11.8";
+Export-Package: org.eclipse.jgit.archive;version="5.0.4";
   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 500c9c9..f85551e 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.11.8.qualifier
-Eclipse-SourceBundle: org.eclipse.jgit.archive;version="4.11.8.qualifier";roots="."
+Bundle-Version: 5.0.4.qualifier
+Eclipse-SourceBundle: org.eclipse.jgit.archive;version="5.0.4.qualifier";roots="."
diff --git a/org.eclipse.jgit.archive/pom.xml b/org.eclipse.jgit.archive/pom.xml
index 4b8b7ed..4bfa176 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.11.8-SNAPSHOT</version>
+    <version>5.0.4-SNAPSHOT</version>
   </parent>
 
   <artifactId>org.eclipse.jgit.archive</artifactId>
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 7559ada..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;
@@ -82,22 +84,14 @@
 	@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);
 	}
 
 	/** {@inheritDoc} */
-	@Deprecated
-	@Override
-	public void putEntry(ArchiveOutputStream out,
-			String path, FileMode mode, ObjectLoader loader)
-			throws IOException {
-		putEntry(out, null, path, mode,loader);
-	}
-
-	/** {@inheritDoc} */
 	@Override
 	public void putEntry(ArchiveOutputStream out,
 			ObjectId tree, String path, FileMode mode, ObjectLoader loader)
@@ -106,7 +100,7 @@
 			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;
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 2f95f6d..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
@@ -83,15 +83,6 @@
 	}
 
 	/** {@inheritDoc} */
-	@Deprecated
-	@Override
-	public void putEntry(ArchiveOutputStream out,
-			String path, FileMode mode, ObjectLoader loader)
-			throws IOException {
-		putEntry(out, null, path, mode,loader);
-	}
-
-	/** {@inheritDoc} */
 	@Override
 	public void putEntry(ArchiveOutputStream out,
 			ObjectId tree, String path, FileMode mode, ObjectLoader loader)
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 b22a62d..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
@@ -83,15 +83,6 @@
 	}
 
 	/** {@inheritDoc} */
-	@Deprecated
-	@Override
-	public void putEntry(ArchiveOutputStream out,
-			String path, FileMode mode, ObjectLoader loader)
-			throws IOException {
-		putEntry(out, null, path, mode,loader);
-	}
-
-	/** {@inheritDoc} */
 	@Override
 	public void putEntry(ArchiveOutputStream out,
 			ObjectId tree, String path, FileMode mode, ObjectLoader loader)
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 d23d2b6..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
@@ -83,15 +83,6 @@
 	}
 
 	/** {@inheritDoc} */
-	@Deprecated
-	@Override
-	public void putEntry(ArchiveOutputStream out,
-			String path, FileMode mode, ObjectLoader loader)
-			throws IOException {
-		putEntry(out, null, path, mode,loader);
-	}
-
-	/** {@inheritDoc} */
 	@Override
 	public void putEntry(ArchiveOutputStream out,
 			ObjectId tree, String path, FileMode mode, ObjectLoader loader)
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 dc8fb44..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
@@ -84,15 +84,6 @@
 	}
 
 	/** {@inheritDoc} */
-	@Deprecated
-	@Override
-	public void putEntry(ArchiveOutputStream out,
-			String path, FileMode mode, ObjectLoader loader)
-			throws IOException {
-		putEntry(out, null, path, mode,loader);
-	}
-
-	/** {@inheritDoc} */
 	@Override
 	public void putEntry(ArchiveOutputStream out,
 			ObjectId tree, String path, FileMode mode, ObjectLoader loader)
diff --git a/org.eclipse.jgit.http.apache/META-INF/MANIFEST.MF b/org.eclipse.jgit.http.apache/META-INF/MANIFEST.MF
index 675a272..69fb47c 100644
--- a/org.eclipse.jgit.http.apache/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.http.apache/META-INF/MANIFEST.MF
@@ -3,7 +3,7 @@
 Bundle-Name: %Bundle-Name
 Automatic-Module-Name: org.eclipse.jgit.http.apache
 Bundle-SymbolicName: org.eclipse.jgit.http.apache
-Bundle-Version: 4.11.8.qualifier
+Bundle-Version: 5.0.4.qualifier
 Bundle-RequiredExecutionEnvironment: JavaSE-1.8
 Bundle-Localization: plugin
 Bundle-Vendor: %Provider-Name
@@ -23,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.11.8,4.12.0)",
- org.eclipse.jgit.transport.http;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.util;version="[4.11.8,4.12.0)"
-Export-Package: org.eclipse.jgit.transport.http.apache;version="4.11.8";
+ org.eclipse.jgit.nls;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.transport.http;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.util;version="[5.0.4,5.1.0)"
+Export-Package: org.eclipse.jgit.transport.http.apache;version="5.0.4";
   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 2767627..bc71faa 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.11.8-SNAPSHOT</version>
+		<version>5.0.4-SNAPSHOT</version>
 	</parent>
 
 	<artifactId>org.eclipse.jgit.http.apache</artifactId>
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 2819300..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
@@ -421,7 +421,7 @@
 
 	/** {@inheritDoc} */
 	@Override
-	public void setHostnameVerifier(final HostnameVerifier hostnameverifier) {
+	public void setHostnameVerifier(HostnameVerifier hostnameverifier) {
 		this.hostnameverifier = hostnameverifier;
 	}
 
diff --git a/org.eclipse.jgit.http.server/META-INF/MANIFEST.MF b/org.eclipse.jgit.http.server/META-INF/MANIFEST.MF
index 6888183..c97b927 100644
--- a/org.eclipse.jgit.http.server/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.http.server/META-INF/MANIFEST.MF
@@ -3,13 +3,13 @@
 Bundle-Name: %plugin_name
 Automatic-Module-Name: org.eclipse.jgit.http.server
 Bundle-SymbolicName: org.eclipse.jgit.http.server
-Bundle-Version: 4.11.8.qualifier
+Bundle-Version: 5.0.4.qualifier
 Bundle-Localization: plugin
 Bundle-Vendor: %provider_name
-Export-Package: org.eclipse.jgit.http.server;version="4.11.8",
- org.eclipse.jgit.http.server.glue;version="4.11.8";
+Export-Package: org.eclipse.jgit.http.server;version="5.0.4",
+ org.eclipse.jgit.http.server.glue;version="5.0.4";
   uses:="javax.servlet,javax.servlet.http",
- org.eclipse.jgit.http.server.resolver;version="4.11.8";
+ org.eclipse.jgit.http.server.resolver;version="5.0.4";
   uses:="org.eclipse.jgit.transport.resolver,
    org.eclipse.jgit.lib,
    org.eclipse.jgit.transport,
@@ -18,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.11.8,4.12.0)",
- org.eclipse.jgit.internal.storage.dfs;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.internal.storage.file;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.lib;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.nls;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.revwalk;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.transport;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.transport.resolver;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.util;version="[4.11.8,4.12.0)"
+ org.eclipse.jgit.errors;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.internal.storage.dfs;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.internal.storage.file;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.lib;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.nls;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.revwalk;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.transport;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.transport.resolver;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.util;version="[5.0.4,5.1.0)"
diff --git a/org.eclipse.jgit.http.server/pom.xml b/org.eclipse.jgit.http.server/pom.xml
index 3a2257d..6f70081 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.11.8-SNAPSHOT</version>
+    <version>5.0.4-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 7f826d4..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,7 +66,7 @@
 class AsIsFileFilter implements Filter {
 	private final AsIsFileService asIs;
 
-	AsIsFileFilter(final AsIsFileService getAnyFile) {
+	AsIsFileFilter(AsIsFileService getAnyFile) {
 		this.asIs = getAnyFile;
 	}
 
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 0d935fc..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 @@
 
 	private long end;
 
-	FileSender(final File path) throws FileNotFoundException {
+	FileSender(File path) throws FileNotFoundException {
 		this.path = path;
 		this.source = new RandomAccessFile(path, "r");
 
@@ -217,7 +217,7 @@
 		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/GitServlet.java b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/GitServlet.java
index ee23677..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
@@ -183,7 +183,7 @@
 
 	/** {@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/InfoPacksServlet.java b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/InfoPacksServlet.java
index 830e061..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
@@ -67,7 +67,7 @@
 		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 4f70cf7..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;
@@ -79,7 +76,7 @@
 				Constants.CHARSET)) {
 			final RefAdvertiser adv = new RefAdvertiser() {
 				@Override
-				protected void writeOne(final CharSequence line)
+				protected void writeOne(CharSequence line)
 						throws IOException {
 					// Whoever decided that info/refs should use a different
 					// delimiter than the native git:// protocol shouldn't
@@ -94,10 +91,7 @@
 			};
 			adv.init(db);
 			adv.setDerefTags(true);
-
-			Map<String, Ref> refs = db.getRefDatabase().getRefs(ALL);
-			refs.remove(Constants.HEAD);
-			adv.send(refs);
+			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 b0b831f..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
@@ -88,7 +88,7 @@
 			((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/ObjectFileServlet.java b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/ObjectFileServlet.java
index 50dc68f..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 @@
 		}
 
 		@Override
-		String etag(final FileSender sender) throws IOException {
+		String etag(FileSender sender) throws IOException {
 			return Long.toHexString(sender.getLastModified());
 		}
 	}
@@ -88,7 +88,7 @@
 		}
 
 		@Override
-		String etag(final FileSender sender) throws IOException {
+		String etag(FileSender sender) throws IOException {
 			return sender.getTailChecksum();
 		}
 	}
@@ -111,7 +111,7 @@
 
 	private final String contentType;
 
-	ObjectFileServlet(final String contentType) {
+	ObjectFileServlet(String contentType) {
 		this.contentType = contentType;
 	}
 
@@ -170,7 +170,7 @@
 		}
 	}
 
-	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/RepositoryFilter.java b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/RepositoryFilter.java
index c89a5d7..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
@@ -100,13 +100,13 @@
 	 *            {@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();
 	}
 
@@ -140,9 +140,9 @@
 			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;
@@ -155,13 +155,8 @@
 		} 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 f1ff547..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
@@ -90,7 +90,7 @@
 	 *             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);
@@ -110,7 +110,7 @@
 	 * @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);
@@ -220,12 +220,9 @@
 	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();
 		}
 	}
 
@@ -241,7 +238,7 @@
 		return content;
 	}
 
-	static boolean acceptsGzipEncoding(final HttpServletRequest req) {
+	static boolean acceptsGzipEncoding(HttpServletRequest req) {
 		return acceptsGzipEncoding(req.getHeader(HDR_ACCEPT_ENCODING));
 	}
 
@@ -261,7 +258,7 @@
 		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);
@@ -271,7 +268,7 @@
 		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 4eb94a3..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
@@ -110,11 +110,8 @@
 			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;
@@ -131,12 +128,9 @@
 			// 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 6417877..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,7 +75,7 @@
 
 	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()]);
 	}
@@ -133,9 +133,7 @@
 			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());
@@ -178,6 +176,37 @@
 			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 00851cf..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,7 +64,7 @@
 
 	private final String fileName;
 
-	TextFileServlet(final String name) {
+	TextFileServlet(String name) {
 		this.fileName = name;
 	}
 
@@ -80,7 +80,7 @@
 		}
 	}
 
-	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 3e9c1fe..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 @@
 				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();
 			}
 		}
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 57fddda..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
@@ -64,7 +64,7 @@
 	 * @param status
 	 *            the HTTP status code to always send.
 	 */
-	public ErrorServlet(final int status) {
+	public ErrorServlet(int status) {
 		this.status = status;
 	}
 
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 a3dc6c3..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
@@ -75,7 +75,7 @@
 	 * @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)));
@@ -108,7 +108,7 @@
 					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 bf2d6db..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 @@
 	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 @@
 	}
 
 	@Override
-	boolean match(final HttpServletRequest req) {
+	boolean match(HttpServletRequest req) {
 		final String pathInfo = req.getPathInfo();
 		return pathInfo != null && pattern.matcher(pathInfo).matches();
 	}
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 6742c9f..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 @@
 	static class Binder extends ServletBinderImpl {
 		private final String suffix;
 
-		Binder(final String suffix) {
+		Binder(String suffix) {
 			this.suffix = suffix;
 		}
 
@@ -89,7 +89,7 @@
 	}
 
 	@Override
-	boolean match(final HttpServletRequest req) {
+	boolean match(HttpServletRequest req) {
 		final String pathInfo = req.getPathInfo();
 		return pathInfo != null && pathInfo.endsWith(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 @@
 	/** 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 @@
 	 * @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 @@
 	 *            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 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/resolver/AsIsFileService.java b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/resolver/AsIsFileService.java
index 11ad5e0..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
@@ -73,7 +73,7 @@
 	private static class ServiceConfig {
 		final boolean enabled;
 
-		ServiceConfig(final Config cfg) {
+		ServiceConfig(Config cfg) {
 			enabled = cfg.getBoolean("http", "getanyfile", true);
 		}
 	}
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 95eb8d5..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
@@ -74,7 +74,7 @@
 
 		final boolean enabled;
 
-		ServiceConfig(final Config cfg) {
+		ServiceConfig(Config cfg) {
 			set = cfg.getString("http", null, "receivepack") != null;
 			enabled = cfg.getBoolean("http", "receivepack", false);
 		}
@@ -82,7 +82,7 @@
 
 	/** {@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 f5afa1e..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;
@@ -64,18 +66,25 @@
 	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/META-INF/MANIFEST.MF b/org.eclipse.jgit.http.test/META-INF/MANIFEST.MF
index f338607..fed632d 100644
--- a/org.eclipse.jgit.http.test/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.http.test/META-INF/MANIFEST.MF
@@ -3,7 +3,7 @@
 Bundle-Name: %plugin_name
 Automatic-Module-Name: org.eclipse.jgit.http.test
 Bundle-SymbolicName: org.eclipse.jgit.http.test
-Bundle-Version: 4.11.8.qualifier
+Bundle-Version: 5.0.4.qualifier
 Bundle-Vendor: %provider_name
 Bundle-Localization: plugin
 Bundle-RequiredExecutionEnvironment: JavaSE-1.8
@@ -25,25 +25,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.errors;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.http.server;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.http.server.glue;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.http.server.resolver;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.internal;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.internal.storage.dfs;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.internal.storage.file;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.internal.storage.reftable;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.junit;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.junit.http;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.lib;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.nls;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.revwalk;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.storage.file;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.transport;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.transport.http;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.transport.http.apache;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.transport.resolver;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.util;version="[4.11.8,4.12.0)",
+ org.eclipse.jgit.errors;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.http.server;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.http.server.glue;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.http.server.resolver;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.internal;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.internal.storage.dfs;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.internal.storage.file;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.internal.storage.reftable;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.junit;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.junit.http;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.lib;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.nls;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.revwalk;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.storage.file;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.transport;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.transport.http;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.transport.http.apache;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.transport.resolver;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.util;version="[5.0.4,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.12,5.0.0)",
  org.junit.rules;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 422398c..87e2f4c 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.11.8-SNAPSHOT</version>
+    <version>5.0.4-SNAPSHOT</version>
   </parent>
 
   <artifactId>org.eclipse.jgit.http.test</artifactId>
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 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 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 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/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 @@
 		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 @@
 		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 @@
 		return ctx;
 	}
 
-	private static String nameOf(final Repository db) {
+	private static String nameOf(Repository db) {
 		return db.getDirectory().getName();
 	}
 
@@ -345,4 +354,82 @@
 			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/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 @@
 			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 @@
 				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 @@
 
 		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 @@
 			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 31832e7..65210d1 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,7 +43,7 @@
 
 package org.eclipse.jgit.http.test;
 
-import static java.nio.charset.StandardCharsets.UTF_8;
+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;
@@ -298,10 +298,10 @@
 					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
@@ -429,11 +429,8 @@
 			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();
 			}
 		}
 
@@ -1166,7 +1163,7 @@
 	public void testInvalidWant() throws Exception {
 		@SuppressWarnings("resource")
 		ObjectId id = new ObjectInserter.Formatter().idFor(Constants.OBJ_BLOB,
-				"testInvalidWant".getBytes(UTF_8));
+				"testInvalidWant".getBytes(CHARSET));
 
 		Repository dst = createBareRepository();
 		try (Transport t = Transport.open(dst, remoteURI);
diff --git a/org.eclipse.jgit.junit.http/META-INF/MANIFEST.MF b/org.eclipse.jgit.junit.http/META-INF/MANIFEST.MF
index d7920fa..a68d152 100644
--- a/org.eclipse.jgit.junit.http/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.junit.http/META-INF/MANIFEST.MF
@@ -3,7 +3,7 @@
 Bundle-Name: %plugin_name
 Automatic-Module-Name: org.eclipse.jgit.junit.http
 Bundle-SymbolicName: org.eclipse.jgit.junit.http
-Bundle-Version: 4.11.8.qualifier
+Bundle-Version: 5.0.4.qualifier
 Bundle-Localization: plugin
 Bundle-Vendor: %provider_name
 Bundle-ActivationPolicy: lazy
@@ -22,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.11.8,4.12.0)",
- org.eclipse.jgit.http.server;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.internal.storage.file;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.junit;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.lib;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.revwalk;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.transport;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.transport.resolver;version="[4.11.8,4.12.0)",
+ org.eclipse.jgit.errors;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.http.server;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.internal.storage.file;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.junit;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.lib;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.revwalk;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.transport;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.transport.resolver;version="[5.0.4,5.1.0)",
  org.junit;version="[4.12,5.0.0)"
-Export-Package: org.eclipse.jgit.junit.http;version="4.11.8";
+Export-Package: org.eclipse.jgit.junit.http;version="5.0.4";
   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 5d92a1a..eb7d02f 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.11.8-SNAPSHOT</version>
+    <version>5.0.4-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 01c4360..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
@@ -67,7 +67,7 @@
 
 	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);
@@ -77,7 +77,7 @@
 		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()) {
@@ -89,7 +89,7 @@
 		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()) {
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 fed063a..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
@@ -107,7 +107,7 @@
 	 *
 	 * @param name
 	 */
-	public RecordingLogger(final String name) {
+	public RecordingLogger(String name) {
 		this.name = name;
 	}
 
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 c5576f9..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
@@ -134,7 +134,7 @@
 		return secureUri;
 	}
 
-	private ServletContextHandler smart(final String path) {
+	private ServletContextHandler smart(String path) {
 		GitServlet gs = new GitServlet();
 		gs.setRepositoryResolver(new RepositoryResolver<HttpServletRequest>() {
 			@Override
@@ -154,7 +154,7 @@
 		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/.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/META-INF/MANIFEST.MF b/org.eclipse.jgit.junit/META-INF/MANIFEST.MF
index f9e12d5..749f8fe 100644
--- a/org.eclipse.jgit.junit/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.junit/META-INF/MANIFEST.MF
@@ -3,31 +3,31 @@
 Bundle-Name: %plugin_name
 Automatic-Module-Name: org.eclipse.jgit.junit
 Bundle-SymbolicName: org.eclipse.jgit.junit
-Bundle-Version: 4.11.8.qualifier
+Bundle-Version: 5.0.4.qualifier
 Bundle-Localization: plugin
 Bundle-Vendor: %provider_name
 Bundle-ActivationPolicy: lazy
 Bundle-RequiredExecutionEnvironment: JavaSE-1.8
-Import-Package: org.eclipse.jgit.api;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.api.errors;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.dircache;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.errors;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.internal.storage.file;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.internal.storage.pack;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.lib;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.merge;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.revwalk;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.storage.file;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.treewalk;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.treewalk.filter;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.util;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.util.io;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.util.time;version="[4.11.8,4.12.0)",
+Import-Package: org.eclipse.jgit.api;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.api.errors;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.dircache;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.errors;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.internal.storage.file;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.internal.storage.pack;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.lib;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.merge;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.revwalk;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.storage.file;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.treewalk;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.treewalk.filter;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.util;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.util.io;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.util.time;version="[5.0.4,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="4.11.8";
+Export-Package: org.eclipse.jgit.junit;version="5.0.4";
   uses:="org.eclipse.jgit.dircache,
    org.eclipse.jgit.lib,
    org.eclipse.jgit.revwalk,
@@ -36,4 +36,4 @@
    org.eclipse.jgit.util,
    org.eclipse.jgit.storage.file,
    org.eclipse.jgit.api",
- org.eclipse.jgit.junit.time;version="4.11.8"
+ org.eclipse.jgit.junit.time;version="5.0.4"
diff --git a/org.eclipse.jgit.junit/pom.xml b/org.eclipse.jgit.junit/pom.xml
index d251b97..30ce0b3 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.11.8-SNAPSHOT</version>
+    <version>5.0.4-SNAPSHOT</version>
   </parent>
 
   <artifactId>org.eclipse.jgit.junit</artifactId>
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 cef81a0..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,7 +45,7 @@
 
 package org.eclipse.jgit.junit;
 
-import static java.nio.charset.StandardCharsets.UTF_8;
+import static org.eclipse.jgit.lib.Constants.CHARSET;
 
 import java.io.File;
 import java.io.FileNotFoundException;
@@ -142,7 +142,7 @@
 	 * @param fileName
 	 * @return the test resource file
 	 */
-	public static File getTestResourceFile(final String fileName) {
+	public static File getTestResourceFile(String fileName) {
 		if (fileName == null || fileName.length() <= 0) {
 			return null;
 		}
@@ -242,11 +242,11 @@
 	 * @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);
 		try (Writer w = new OutputStreamWriter(new FileOutputStream(f),
-				UTF_8)) {
+				CHARSET)) {
 			w.write(body);
 		}
 	}
@@ -261,9 +261,9 @@
 	 * @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);
 	}
 
 	/**
@@ -274,7 +274,7 @@
 	 * @return the content of the file
 	 * @throws IOException
 	 */
-	public static String read(final Repository db, final String name)
+	public static String read(Repository db, String name)
 			throws IOException {
 		File file = new File(db.getWorkTree(), name);
 		return read(file);
@@ -288,7 +288,7 @@
 	 *            name of the file
 	 * @return {@code true} if the file exists
 	 */
-	public static boolean check(final Repository db, final String name) {
+	public static boolean check(Repository db, String name) {
 		File file = new File(db.getWorkTree(), name);
 		return file.exists();
 	}
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 568bc3b..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,7 +45,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.assertFalse;
 import static org.junit.Assert.fail;
 
@@ -225,7 +225,7 @@
 	 * @param dir
 	 *            the recursively directory to delete, if present.
 	 */
-	protected void recursiveDelete(final File dir) {
+	protected void recursiveDelete(File dir) {
 		recursiveDelete(dir, false, true);
 	}
 
@@ -352,7 +352,7 @@
 			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:"
@@ -540,7 +540,7 @@
 	 * @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);
@@ -571,7 +571,7 @@
 	 * @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);
 	}
 
@@ -583,11 +583,11 @@
 	 * @return the content of the file
 	 * @throws IOException
 	 */
-	protected String read(final File f) 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 05d1522..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
@@ -109,7 +109,7 @@
 		setCurrentPlatform();
 	}
 
-	private void init(final String n) {
+	private void init(String n) {
 		setProperty(n, n);
 	}
 
@@ -197,7 +197,7 @@
 	 *            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;
 	}
 
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 afc2c44..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,7 +46,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 java.io.File;
@@ -92,22 +92,15 @@
 	 * @param dst
 	 * @throws IOException
 	 */
-	protected static void copyFile(final File src, final File dst)
+	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();
 		}
 	}
 
@@ -119,7 +112,7 @@
 	 * @return the trash file
 	 * @throws IOException
 	 */
-	protected File writeTrashFile(final String name, final String data)
+	protected File writeTrashFile(String name, String data)
 			throws IOException {
 		return JGitTestUtil.writeTrashFile(db, name, data);
 	}
@@ -135,7 +128,7 @@
 	 * @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);
 	}
@@ -162,7 +155,7 @@
 	 * @return the file's content
 	 * @throws IOException
 	 */
-	protected String read(final String name) throws IOException {
+	protected String read(String name) throws IOException {
 		return JGitTestUtil.read(db, name);
 	}
 
@@ -173,7 +166,7 @@
 	 *            file name
 	 * @return if the file exists
 	 */
-	protected boolean check(final String name) {
+	protected boolean check(String name) {
 		return JGitTestUtil.check(db, name);
 	}
 
@@ -184,7 +177,7 @@
 	 *            file name
 	 * @throws IOException
 	 */
-	protected void deleteTrashFile(final String name) throws IOException {
+	protected void deleteTrashFile(String name) throws IOException {
 		JGitTestUtil.deleteTrashFile(db, name);
 	}
 
@@ -196,10 +189,10 @@
 	 *            expected content
 	 * @throws IOException
 	 */
-	protected static void checkFile(File f, final String checkData)
+	protected static void checkFile(File f, String checkData)
 			throws IOException {
 		try (Reader r = new InputStreamReader(new FileInputStream(f),
-				UTF_8)) {
+				CHARSET)) {
 			if (checkData.length() > 0) {
 				char[] data = new char[checkData.length()];
 				assertEquals(data.length, r.read(data));
@@ -293,10 +286,11 @@
 				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);
 			}
@@ -380,8 +374,9 @@
 			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;
@@ -505,7 +500,7 @@
 	 * @param mode
 	 * @return the DirCacheEntry
 	 */
-	protected DirCacheEntry createEntry(final String path, final FileMode mode) {
+	protected DirCacheEntry createEntry(String path, FileMode mode) {
 		return createEntry(path, mode, DirCacheEntry.STAGE_0, path);
 	}
 
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 41634e7..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,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.fail;
 
@@ -244,7 +244,7 @@
 	 * @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);
 	}
 
@@ -267,8 +267,8 @@
 	 * @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));
 	}
 
 	/**
@@ -279,7 +279,7 @@
 	 * @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);
@@ -298,7 +298,7 @@
 	 * @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);
@@ -315,10 +315,10 @@
 	 * @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;
@@ -339,7 +339,7 @@
 	 * @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
@@ -370,7 +370,7 @@
 	 * @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);
 	}
 
@@ -386,7 +386,7 @@
 	 * @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);
 	}
@@ -404,7 +404,7 @@
 	 * @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);
 	}
@@ -470,7 +470,7 @@
 	 * @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);
@@ -759,7 +759,7 @@
 			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);
@@ -791,7 +791,7 @@
 	 * @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;
 	}
@@ -944,7 +944,7 @@
 		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())
@@ -962,7 +962,7 @@
 	public class BranchBuilder {
 		private final String ref;
 
-		BranchBuilder(final String ref) {
+		BranchBuilder(String ref) {
 			this.ref = ref;
 		}
 
@@ -1093,7 +1093,7 @@
 			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 54c81f2..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
@@ -55,7 +55,7 @@
 	 * @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);
@@ -68,7 +68,7 @@
 	 *            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();
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 454bd1d..c805f75 100644
--- a/org.eclipse.jgit.lfs.server.test/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.lfs.server.test/META-INF/MANIFEST.MF
@@ -3,7 +3,7 @@
 Bundle-Name: %plugin_name
 Automatic-Module-Name: org.eclipse.jgit.lfs.server.test
 Bundle-SymbolicName: org.eclipse.jgit.lfs.server.test
-Bundle-Version: 4.11.8.qualifier
+Bundle-Version: 5.0.4.qualifier
 Bundle-Vendor: %provider_name
 Bundle-Localization: plugin
 Bundle-RequiredExecutionEnvironment: JavaSE-1.8
@@ -28,24 +28,24 @@
  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.11.8,4.12.0)",
- org.eclipse.jgit.api.errors;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.internal.storage.file;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.junit;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.junit.http;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.lfs;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.lfs.errors;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.lfs.lib;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.lfs.server;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.lfs.server.fs;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.lfs.test;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.lib;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.revwalk;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.storage.file;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.transport;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.treewalk;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.treewalk.filter;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.util;version="[4.11.8,4.12.0)",
+ org.eclipse.jgit.api;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.api.errors;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.internal.storage.file;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.junit;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.junit.http;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.lfs;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.lfs.errors;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.lfs.lib;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.lfs.server;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.lfs.server.fs;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.lfs.test;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.lib;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.revwalk;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.storage.file;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.transport;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.treewalk;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.treewalk.filter;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.util;version="[5.0.4,5.1.0)",
  org.hamcrest.core;version="[1.1.0,2.0.0)",
  org.junit;version="[4.12,5.0.0)",
  org.junit.rules;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 c08bf6b..dee3199 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.11.8-SNAPSHOT</version>
+    <version>5.0.4-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/LfsServerTest.java b/org.eclipse.jgit.lfs.server.test/tst/org/eclipse/jgit/lfs/server/fs/LfsServerTest.java
index 90fe116..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;
@@ -131,12 +131,6 @@
 
 			@Override
 			protected LargeFileRepository getLargeFileRepository(
-					LfsRequest request, String path) {
-				return repository;
-			}
-
-			@Override
-			protected LargeFileRepository getLargeFileRepository(
 					LfsRequest request, String path, String auth)
 					throws LfsException {
 				return repository;
@@ -217,11 +211,11 @@
 				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/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 @@
 
 		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/META-INF/MANIFEST.MF b/org.eclipse.jgit.lfs.server/META-INF/MANIFEST.MF
index 68555b8..14d3ab8 100644
--- a/org.eclipse.jgit.lfs.server/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.lfs.server/META-INF/MANIFEST.MF
@@ -3,19 +3,19 @@
 Bundle-Name: %plugin_name
 Automatic-Module-Name: org.eclipse.jgit.lfs.server
 Bundle-SymbolicName: org.eclipse.jgit.lfs.server
-Bundle-Version: 4.11.8.qualifier
+Bundle-Version: 5.0.4.qualifier
 Bundle-Localization: plugin
 Bundle-Vendor: %provider_name
-Export-Package: org.eclipse.jgit.lfs.server;version="4.11.8";
+Export-Package: org.eclipse.jgit.lfs.server;version="5.0.4";
   uses:="javax.servlet.http,
    org.eclipse.jgit.lfs.lib",
- org.eclipse.jgit.lfs.server.fs;version="4.11.8";
+ org.eclipse.jgit.lfs.server.fs;version="5.0.4";
   uses:="javax.servlet,
    javax.servlet.http,
    org.eclipse.jgit.lfs.server,
    org.eclipse.jgit.lfs.lib",
- org.eclipse.jgit.lfs.server.internal;version="4.11.8";x-internal:=true,
- org.eclipse.jgit.lfs.server.s3;version="4.11.8";
+ org.eclipse.jgit.lfs.server.internal;version="5.0.4";x-internal:=true,
+ org.eclipse.jgit.lfs.server.s3;version="5.0.4";
   uses:="org.eclipse.jgit.lfs.server,
    org.eclipse.jgit.lfs.lib"
 Bundle-RequiredExecutionEnvironment: JavaSE-1.8
@@ -25,14 +25,15 @@
  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.11.8,4.12.0)",
- org.eclipse.jgit.internal;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.internal.storage.file;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.lfs.errors;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.lfs.internal;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.lfs.lib;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.nls;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.transport.http;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.transport.http.apache;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.util;version="[4.11.8,4.12.0)",
+ org.eclipse.jgit.annotations;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.internal;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.internal.storage.file;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.lfs.errors;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.lfs.internal;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.lfs.lib;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.lib;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.nls;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.transport.http;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.transport.http.apache;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.util;version="[5.0.4,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 e73ad2f..7c81c1a 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.11.8-SNAPSHOT</version>
+    <version>5.0.4-SNAPSHOT</version>
   </parent>
 
   <artifactId>org.eclipse.jgit.lfs.server</artifactId>
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 6968d75..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;
@@ -112,48 +112,6 @@
 	 *            the request
 	 * @param path
 	 *            the path
-	 * @return the large file repository storing large files.
-	 * @throws org.eclipse.jgit.lfs.errors.LfsException
-	 *             implementations should throw more specific exceptions to
-	 *             signal which type of error occurred:
-	 *             <dl>
-	 *             <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 org.eclipse.jgit.lfs.errors.LfsRepositoryNotFound}</dt>
-	 *             <dd>when the repository does not exist for the user</dd>
-	 *             <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 org.eclipse.jgit.lfs.errors.LfsRateLimitExceeded}</dt>
-	 *             <dd>when the user has hit a rate limit with the server</dd>
-	 *             <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 org.eclipse.jgit.lfs.errors.LfsInsufficientStorage}</dt>
-	 *             <dd>when there is insufficient storage on the server</dd>
-	 *             <dt>{@link org.eclipse.jgit.lfs.errors.LfsUnavailable}</dt>
-	 *             <dd>when LFS is not available</dd>
-	 *             <dt>{@link org.eclipse.jgit.lfs.errors.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.
-	 *
-	 * @param request
-	 *            the request
-	 * @param path
-	 *            the path
 	 * @param auth
 	 *            the Authorization HTTP header
 	 * @return the large file repository storing large files.
@@ -244,10 +202,10 @@
 	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));
+				new InputStreamReader(req.getInputStream(), CHARSET));
 		LfsRequest request = LfsGson.fromJson(r, LfsRequest.class);
 		String path = req.getPathInfo();
 
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 688aef2..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
@@ -170,7 +170,7 @@
 	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];
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 b21c94e..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,7 +43,7 @@
  */
 package org.eclipse.jgit.lfs.server.s3;
 
-import static java.nio.charset.StandardCharsets.UTF_8;
+import static org.eclipse.jgit.lib.Constants.CHARSET;
 import static org.eclipse.jgit.util.HttpSupport.HDR_AUTHORIZATION;
 
 import java.io.UnsupportedEncodingException;
@@ -359,13 +359,13 @@
 
 	private static byte[] hash(String s) {
 		MessageDigest md = Constants.newMessageDigest();
-		md.update(s.getBytes(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);
+			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 urlEncode(String url, boolean keepPathSlash) {
 		String encoded;
 		try {
-			encoded = URLEncoder.encode(url, 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/META-INF/MANIFEST.MF b/org.eclipse.jgit.lfs.test/META-INF/MANIFEST.MF
index d64e2e2..d8376ce 100644
--- a/org.eclipse.jgit.lfs.test/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.lfs.test/META-INF/MANIFEST.MF
@@ -3,23 +3,23 @@
 Bundle-Name: %plugin_name
 Automatic-Module-Name: org.eclipse.jgit.lfs.test
 Bundle-SymbolicName: org.eclipse.jgit.lfs.test
-Bundle-Version: 4.11.8.qualifier
+Bundle-Version: 5.0.4.qualifier
 Bundle-Vendor: %provider_name
 Bundle-Localization: plugin
 Bundle-RequiredExecutionEnvironment: JavaSE-1.8
-Import-Package: org.eclipse.jgit.internal.storage.dfs;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.junit;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.lfs;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.lfs.errors;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.lfs.lib;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.lib;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.revwalk;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.treewalk;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.treewalk.filter;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.util;version="[4.11.8,4.12.0)",
+Import-Package: org.eclipse.jgit.internal.storage.dfs;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.junit;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.lfs;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.lfs.errors;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.lfs.lib;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.lib;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.revwalk;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.treewalk;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.treewalk.filter;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.util;version="[5.0.4,5.1.0)",
  org.hamcrest.core;version="[1.1.0,2.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)"
-Export-Package: org.eclipse.jgit.lfs.test;version="4.11.8";x-friends:="org.eclipse.jgit.lfs.server.test"
+Export-Package: org.eclipse.jgit.lfs.test;version="5.0.4";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 0b7300e..a55cecd 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.11.8-SNAPSHOT</version>
+    <version>5.0.4-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 c3c3859..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,7 +42,7 @@
  */
 package org.eclipse.jgit.lfs.test;
 
-import static java.nio.charset.StandardCharsets.UTF_8;
+import static org.eclipse.jgit.lib.Constants.CHARSET;
 
 import java.io.BufferedInputStream;
 import java.io.FileNotFoundException;
@@ -66,7 +66,7 @@
 	 */
 	public static LongObjectId hash(String s) {
 		MessageDigest md = Constants.newMessageDigest();
-		md.update(s.getBytes(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/LFSPointerTest.java b/org.eclipse.jgit.lfs.test/tst/org/eclipse/jgit/lfs/lib/LFSPointerTest.java
index 146a25e..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,7 +43,7 @@
 
 package org.eclipse.jgit.lfs.lib;
 
-import static java.nio.charset.StandardCharsets.UTF_8;
+import static org.eclipse.jgit.lib.Constants.CHARACTER_ENCODING;
 import static org.junit.Assert.assertEquals;
 
 import java.io.ByteArrayOutputStream;
@@ -66,7 +66,7 @@
 			assertEquals(
 					"version https://git-lfs.github.com/spec/v1\noid sha256:"
 							+ s + "\nsize 4\n",
-					baos.toString(UTF_8.name()));
+					baos.toString(CHARACTER_ENCODING));
 		}
 	}
 }
diff --git a/org.eclipse.jgit.lfs/META-INF/MANIFEST.MF b/org.eclipse.jgit.lfs/META-INF/MANIFEST.MF
index 44ac856..3e1e221 100644
--- a/org.eclipse.jgit.lfs/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.lfs/META-INF/MANIFEST.MF
@@ -3,33 +3,34 @@
 Bundle-Name: %plugin_name
 Automatic-Module-Name: org.eclipse.jgit.lfs
 Bundle-SymbolicName: org.eclipse.jgit.lfs
-Bundle-Version: 4.11.8.qualifier
+Bundle-Version: 5.0.4.qualifier
 Bundle-Localization: plugin
 Bundle-Vendor: %provider_name
-Export-Package: org.eclipse.jgit.lfs;version="4.11.8",
- org.eclipse.jgit.lfs.errors;version="4.11.8",
- org.eclipse.jgit.lfs.internal;version="4.11.8";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.11.8"
+Export-Package: org.eclipse.jgit.lfs;version="5.0.4",
+ org.eclipse.jgit.lfs.errors;version="5.0.4",
+ org.eclipse.jgit.lfs.internal;version="5.0.4";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.4"
 Bundle-RequiredExecutionEnvironment: JavaSE-1.8
 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="[4.11.8,4.12.0)";resolution:=optional,
- org.eclipse.jgit.api.errors;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.attributes;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.diff;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.errors;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.hooks;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.internal.storage.file;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.lib;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.nls;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.revwalk;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.storage.file;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.storage.pack;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.transport;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.transport.http;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.treewalk;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.treewalk.filter;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.util;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.util.io;version="[4.11.8,4.12.0)"
+ org.eclipse.jgit.annotations;version="[5.0.4,5.1.0)";resolution:=optional,
+ org.eclipse.jgit.api.errors;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.attributes;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.diff;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.errors;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.hooks;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.internal.storage.file;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.lib;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.nls;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.revwalk;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.storage.file;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.storage.pack;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.transport;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.transport.http;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.treewalk;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.treewalk.filter;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.util;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.util.io;version="[5.0.4,5.1.0)",
+ org.slf4j;version="[1.7.0,2.0.0)"
diff --git a/org.eclipse.jgit.lfs/pom.xml b/org.eclipse.jgit.lfs/pom.xml
index bec09ee..c231692 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.11.8-SNAPSHOT</version>
+    <version>5.0.4-SNAPSHOT</version>
   </parent>
 
   <artifactId>org.eclipse.jgit.lfs</artifactId>
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 40d8342..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
@@ -65,19 +65,6 @@
 	/**
 	 * Constructor for Lfs.
 	 *
-	 * @param root
-	 *            the path to the LFS media directory. Will be
-	 *            {@code "<repo>/.git/lfs"}
-	 * @deprecated use {@link #Lfs(Repository)} instead.
-	 */
-	@Deprecated
-	public Lfs(Path root) {
-		this.root = root;
-	}
-
-	/**
-	 * Constructor for Lfs.
-	 *
 	 * @param db
 	 *            the associated repo
 	 *
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 0e3830c..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,7 +42,7 @@
  */
 package org.eclipse.jgit.lfs;
 
-import static java.nio.charset.StandardCharsets.UTF_8;
+import static org.eclipse.jgit.lib.Constants.CHARSET;
 
 import java.io.BufferedReader;
 import java.io.IOException;
@@ -134,7 +134,7 @@
 	 */
 	public void encode(OutputStream out) {
 		try (PrintStream ps = new PrintStream(out, false,
-				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$
@@ -143,7 +143,7 @@
 			ps.print(size + "\n"); //$NON-NLS-1$
 		} catch (UnsupportedEncodingException e) {
 			// should not happen, we are using a standard charset
-			throw new UnsupportedCharsetException(UTF_8.name());
+			throw new UnsupportedCharsetException(CHARSET.name());
 		}
 	}
 
@@ -165,7 +165,7 @@
 		long sz = -1;
 
 		try (BufferedReader br = new BufferedReader(
-				new InputStreamReader(in, UTF_8))) {
+				new InputStreamReader(in, CHARSET))) {
 			for (String s = br.readLine(); s != null; s = br.readLine()) {
 				if (s.startsWith("#") || s.length() == 0) { //$NON-NLS-1$
 					continue;
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
index 6115e39..de4449f 100644
--- a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/LfsPrePushHook.java
+++ b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/LfsPrePushHook.java
@@ -42,7 +42,7 @@
  */
 package org.eclipse.jgit.lfs;
 
-import static java.nio.charset.StandardCharsets.UTF_8;
+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;
@@ -174,8 +174,8 @@
 
 	private void excludeRemoteRefs(ObjectWalk walk) throws IOException {
 		RefDatabase refDatabase = getRepository().getRefDatabase();
-		Map<String, Ref> remoteRefs = refDatabase.getRefs(remote());
-		for (Ref r : remoteRefs.values()) {
+		List<Ref> remoteRefs = refDatabase.getRefsByPrefix(remote());
+		for (Ref r : remoteRefs) {
 			ObjectId oid = r.getPeeledObjectId();
 			if (oid == null) {
 				oid = r.getObjectId();
@@ -208,7 +208,7 @@
 		}
 		Gson gson = Protocol.gson();
 		api.getOutputStream().write(
-				gson.toJson(toRequest(OPERATION_UPLOAD, res)).getBytes(UTF_8));
+				gson.toJson(toRequest(OPERATION_UPLOAD, res)).getBytes(CHARSET));
 		int responseCode = api.getResponseCode();
 		if (responseCode != HTTP_OK) {
 			throw new IOException(
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 e2ab309..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,11 +42,12 @@
  */
 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.charset.StandardCharsets;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.text.MessageFormat;
@@ -169,7 +170,7 @@
 				.write(gson
 						.toJson(LfsConnectionFactory
 								.toRequest(Protocol.OPERATION_DOWNLOAD, res))
-						.getBytes(StandardCharsets.UTF_8));
+						.getBytes(CHARSET));
 		int responseCode = lfsServerConn.getResponseCode();
 		if (responseCode != HttpConnection.HTTP_OK) {
 			throw new IOException(
diff --git a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/errors/LfsConfigInvalidException.java b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/errors/LfsConfigInvalidException.java
index 5320af0..f90a003 100644
--- a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/errors/LfsConfigInvalidException.java
+++ b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/errors/LfsConfigInvalidException.java
@@ -63,4 +63,17 @@
 		super(msg);
 	}
 
+	/**
+	 * Constructor for LfsConfigInvalidException.
+	 *
+	 * @param msg
+	 *            the error description
+	 * @param e
+	 *            cause of this exception
+	 * @since 5.0
+	 */
+	public LfsConfigInvalidException(String msg, Exception e) {
+		super(msg, e);
+	}
+
 }
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
index 5d8268b..955eca0 100644
--- 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
@@ -47,10 +47,9 @@
 import static org.eclipse.jgit.util.HttpSupport.HDR_ACCEPT_ENCODING;
 import static org.eclipse.jgit.util.HttpSupport.HDR_CONTENT_TYPE;
 
-import java.io.BufferedReader;
 import java.io.IOException;
-import java.io.InputStreamReader;
 import java.net.ProxySelector;
+import java.net.URISyntaxException;
 import java.net.URL;
 import java.text.SimpleDateFormat;
 import java.util.LinkedList;
@@ -58,6 +57,7 @@
 import java.util.TreeMap;
 
 import org.eclipse.jgit.annotations.NonNull;
+import org.eclipse.jgit.errors.CommandFailedException;
 import org.eclipse.jgit.lfs.LfsPointer;
 import org.eclipse.jgit.lfs.Protocol;
 import org.eclipse.jgit.lfs.errors.LfsConfigInvalidException;
@@ -66,20 +66,17 @@
 import org.eclipse.jgit.lib.StoredConfig;
 import org.eclipse.jgit.transport.HttpConfig;
 import org.eclipse.jgit.transport.HttpTransport;
-import org.eclipse.jgit.transport.RemoteSession;
-import org.eclipse.jgit.transport.SshSessionFactory;
 import org.eclipse.jgit.transport.URIish;
 import org.eclipse.jgit.transport.http.HttpConnection;
-import org.eclipse.jgit.util.FS;
 import org.eclipse.jgit.util.HttpSupport;
-import org.eclipse.jgit.util.io.MessageWriter;
-import org.eclipse.jgit.util.io.StreamCopyThread;
+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 = 30;
 	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<>();
@@ -133,6 +130,7 @@
 		String lfsUrl = config.getString(ConfigConstants.CONFIG_SECTION_LFS,
 				null,
 				ConfigConstants.CONFIG_KEY_URL);
+		Exception ex = null;
 		if (lfsUrl == null) {
 			String remoteUrl = null;
 			for (String remote : db.getRemoteNames()) {
@@ -151,38 +149,44 @@
 				break;
 			}
 			if (lfsUrl == null && remoteUrl != null) {
-				lfsUrl = discoverLfsUrl(db, purpose, additionalHeaders,
-						remoteUrl);
+				try {
+					lfsUrl = discoverLfsUrl(db, purpose, additionalHeaders,
+							remoteUrl);
+				} catch (URISyntaxException | IOException
+						| CommandFailedException e) {
+					ex = e;
+				}
 			} else {
 				lfsUrl = lfsUrl + Protocol.INFO_LFS_ENDPOINT;
 			}
 		}
 		if (lfsUrl == null) {
+			if (ex != null) {
+				throw new LfsConfigInvalidException(
+						LfsText.get().lfsNoDownloadUrl, ex);
+			}
 			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
+			Map<String, String> additionalHeaders, String remoteUrl)
+			throws URISyntaxException, IOException, CommandFailedException {
+		URIish u = new URIish(remoteUrl);
+		if (u.getScheme() == null || 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;
 		}
 	}
 
 	private static Protocol.ExpiringAction getSshAuthentication(
 			Repository db, String purpose, String remoteUrl, URIish u)
-			throws IOException {
+			throws IOException, CommandFailedException {
 		AuthCache cached = sshAuthCache.get(remoteUrl);
 		Protocol.ExpiringAction action = null;
 		if (cached != null && cached.validUntil > System.currentTimeMillis()) {
@@ -193,10 +197,11 @@
 			// discover and authenticate; git-lfs does "ssh
 			// -p <port> -- <host> git-lfs-authenticate
 			// <project> <upload/download>"
-			String json = runSshCommand(u.setPath(""), //$NON-NLS-1$
-					db.getFS(),
+			String json = SshSupport.runSshCommand(u.setPath(""), //$NON-NLS-1$
+					null, db.getFS(),
 					"git-lfs-authenticate " + extractProjectName(u) + " " //$NON-NLS-1$//$NON-NLS-2$
-							+ purpose);
+							+ purpose,
+					SSH_AUTH_TIMEOUT_SECONDS);
 
 			action = Protocol.gson().fromJson(json,
 					Protocol.ExpiringAction.class);
@@ -230,8 +235,10 @@
 				.create(contentUrl, HttpSupport
 						.proxyFor(ProxySelector.getDefault(), contentUrl));
 		contentServerConn.setRequestMethod(method);
-		action.header
-				.forEach((k, v) -> contentServerConn.setRequestProperty(k, v));
+		if (action.header != null) {
+			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)) {
@@ -245,7 +252,13 @@
 	}
 
 	private static String extractProjectName(URIish u) {
-		String path = u.getPath().substring(1);
+		String path = u.getPath();
+
+		// begins with a slash if the url contains a port (gerrit vs. github).
+		if (path.startsWith("/")) { //$NON-NLS-1$
+			path = path.substring(1);
+		}
+
 		if (path.endsWith(org.eclipse.jgit.lib.Constants.DOT_GIT)) {
 			return path.substring(0, path.length() - 4);
 		} else {
@@ -253,42 +266,6 @@
 		}
 	}
 
-	private static String runSshCommand(URIish sshUri, FS fs, String command)
-			throws IOException {
-		RemoteSession session = null;
-		Process process = null;
-		StreamCopyThread errorThread = null;
-		try (MessageWriter stderr = new MessageWriter()) {
-			session = SshSessionFactory.getInstance().getSession(sshUri, null,
-					fs, 5_000);
-			process = session.exec(command, 0);
-			errorThread = new StreamCopyThread(process.getErrorStream(),
-					stderr.getRawStream());
-			errorThread.start();
-			try (BufferedReader reader = new BufferedReader(
-					new InputStreamReader(process.getInputStream(),
-							org.eclipse.jgit.lib.Constants.CHARSET))) {
-				return reader.readLine();
-			}
-		} finally {
-			if (process != null) {
-				process.destroy();
-			}
-			if (errorThread != null) {
-				try {
-					errorThread.halt();
-				} catch (InterruptedException e) {
-					// Stop waiting and return anyway.
-				} finally {
-					errorThread = null;
-				}
-			}
-			if (session != null) {
-				SshSessionFactory.getInstance().releaseSession(session);
-			}
-		}
-	}
-
 	/**
 	 * @param operation
 	 *            the operation to perform, e.g. Protocol.OPERATION_DOWNLOAD
@@ -313,7 +290,7 @@
 	}
 
 	private static final class AuthCache {
-		private static final long AUTH_CACHE_EAGER_TIMEOUT = 100;
+		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$
@@ -330,8 +307,9 @@
 			this.cachedAction = action;
 			try {
 				if (action.expiresIn != null && !action.expiresIn.isEmpty()) {
-					this.validUntil = System.currentTimeMillis()
-							+ Long.parseLong(action.expiresIn);
+					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)
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 4529a25..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
@@ -78,7 +78,7 @@
 	 *            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;
@@ -138,7 +138,7 @@
 	 *            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));
@@ -173,7 +173,7 @@
 		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.
@@ -249,7 +249,7 @@
 	 *         &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));
@@ -281,7 +281,7 @@
 	 *         &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)));
@@ -313,7 +313,7 @@
 	 *         &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]));
@@ -340,7 +340,7 @@
 		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);
 	}
 
@@ -352,7 +352,7 @@
 
 	/** {@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
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 96d6938..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
@@ -170,7 +170,7 @@
 	 * 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;
 
@@ -202,7 +202,7 @@
 	 * @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));
@@ -231,7 +231,7 @@
 	 * @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]);
@@ -257,7 +257,7 @@
 	 * @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;
 	}
 
@@ -274,13 +274,13 @@
 	 *            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 @@
 	 * @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 @@
 	 * @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 @@
 	 * @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;
@@ -338,14 +338,14 @@
 	 * @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));
@@ -365,7 +365,7 @@
 	 * @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 @@
 	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)];
@@ -424,7 +424,7 @@
 	 * @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());
 	}
 
@@ -440,7 +440,7 @@
 	 * @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 @@
 	 * @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 @@
 		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 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)];
@@ -524,7 +524,7 @@
 	 *            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);
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 ec1e179..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
@@ -90,7 +90,7 @@
 	 *            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 {
@@ -110,7 +110,7 @@
 	 *            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;
 	}
 
@@ -173,7 +173,7 @@
 	 *            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);
 	}
 
@@ -187,7 +187,7 @@
 	 *            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);
@@ -203,7 +203,7 @@
 	 *            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);
 	}
 
@@ -217,7 +217,7 @@
 	 *            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]);
 	}
 
@@ -231,7 +231,7 @@
 	 *            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);
 	}
 
@@ -242,14 +242,14 @@
 	 *            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);
@@ -280,7 +280,7 @@
 	 * @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;
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 7b0c494..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
@@ -167,7 +167,7 @@
 	 *            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);
 	}
 
@@ -180,7 +180,7 @@
 	 * @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);
@@ -194,7 +194,7 @@
 	 *            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);
 	}
 
@@ -207,7 +207,7 @@
 	 * @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];
@@ -223,7 +223,7 @@
 	 * @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);
 	}
 
@@ -233,14 +233,14 @@
 	 * @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);
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 c5e3141..d09852b 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.11.8.qualifier"
+      version="5.0.4.qualifier"
       provider-name="%providerName">
 
    <description url="http://www.eclipse.org/jgit/">
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 1cc6ceb..a9a58af 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.11.8-SNAPSHOT</version>
+    <version>5.0.4-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 0edae1e..485fd6b 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.11.8.qualifier"
+      version="5.0.4.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 88cc0dd..d148ac3 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.11.8-SNAPSHOT</version>
+    <version>5.0.4-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 c8e1a42..6551330 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.11.8.qualifier"
+      version="5.0.4.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 7586570..f65326e 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.11.8-SNAPSHOT</version>
+    <version>5.0.4-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 78a2e89..72e15da 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.11.8.qualifier"
+      version="5.0.4.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 5c9bcc6..35a4fda 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.11.8-SNAPSHOT</version>
+    <version>5.0.4-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 f2780a4..18a7d1a 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.11.8.qualifier"
+      version="5.0.4.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.11.8" match="equivalent"/>
-      <import feature="org.eclipse.jgit.lfs" version="4.11.8" match="equivalent"/>
+      <import feature="org.eclipse.jgit" version="5.0.4" match="equivalent"/>
+      <import feature="org.eclipse.jgit.lfs" version="5.0.4" 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 44793f8..73a7d3f 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.11.8-SNAPSHOT</version>
+    <version>5.0.4-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 97a6a17..810d018 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.11.8.qualifier"
+      version="5.0.4.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 bc89eeb..88b8ce9 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.11.8-SNAPSHOT</version>
+    <version>5.0.4-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 ca7416f..c8c3b51 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.11.8-SNAPSHOT</version>
+    <version>5.0.4-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 f3c7e93..12d6fe3 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.11.8.qualifier"
+      version="5.0.4.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 8ac8974..7c83241 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.11.8-SNAPSHOT</version>
+    <version>5.0.4-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 0746920..fc7dfa6 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.11.8.qualifier
+Bundle-Version: 5.0.4.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 0c1d5bb..dfb5a8f 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,7 +1,7 @@
 <?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="1535176347">
+<target name="jgit-4.5" sequenceNumber="1535179254">
   <locations>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
       <unit id="org.eclipse.jetty.client" version="9.4.8.v20171121"/>
@@ -39,6 +39,7 @@
       <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" 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"/>
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 e05c410..dbfd694 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,7 +1,7 @@
 <?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="1535176335">
+<target name="jgit-4.6" sequenceNumber="1535179241">
   <locations>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
       <unit id="org.eclipse.jetty.client" version="9.4.8.v20171121"/>
@@ -39,6 +39,7 @@
       <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" 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"/>
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 20b0a29..be7719d 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,7 +1,7 @@
 <?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="1535176314">
+<target name="jgit-4.7" sequenceNumber="1535179221">
   <locations>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
       <unit id="org.eclipse.jetty.client" version="9.4.8.v20171121"/>
@@ -39,6 +39,7 @@
       <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" 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"/>
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 b84fc20..3de172b 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,7 +1,7 @@
 <?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="1535176301">
+<target name="jgit-4.8" sequenceNumber="1535179205">
   <locations>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
       <unit id="org.eclipse.jetty.client" version="9.4.8.v20171121"/>
@@ -39,6 +39,7 @@
       <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" 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"/>
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
index f4ec50d..ecec41d 100644
--- 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
@@ -18,6 +18,7 @@
 	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]
@@ -44,4 +45,4 @@
 	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/pom.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/pom.xml
index 24c48ed..3c60a83 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.11.8-SNAPSHOT</version>
+    <version>5.0.4-SNAPSHOT</version>
   </parent>
 
   <artifactId>org.eclipse.jgit.target</artifactId>
diff --git a/org.eclipse.jgit.packaging/pom.xml b/org.eclipse.jgit.packaging/pom.xml
index d3d85c3..3cb21c1 100644
--- a/org.eclipse.jgit.packaging/pom.xml
+++ b/org.eclipse.jgit.packaging/pom.xml
@@ -53,7 +53,7 @@
 
   <groupId>org.eclipse.jgit</groupId>
   <artifactId>jgit.tycho.parent</artifactId>
-  <version>4.11.8-SNAPSHOT</version>
+  <version>5.0.4-SNAPSHOT</version>
   <packaging>pom</packaging>
 
   <name>JGit Tycho Parent</name>
diff --git a/org.eclipse.jgit.pgm.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.pgm.test/META-INF/MANIFEST.MF
index 2830651..39910ce 100644
--- a/org.eclipse.jgit.pgm.test/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.pgm.test/META-INF/MANIFEST.MF
@@ -3,28 +3,28 @@
 Bundle-Name: %plugin_name
 Automatic-Module-Name: org.eclipse.jgit.pgm.test
 Bundle-SymbolicName: org.eclipse.jgit.pgm.test
-Bundle-Version: 4.11.8.qualifier
+Bundle-Version: 5.0.4.qualifier
 Bundle-Vendor: %provider_name
 Bundle-Localization: plugin
 Bundle-ActivationPolicy: lazy
 Bundle-RequiredExecutionEnvironment: JavaSE-1.8
-Import-Package: org.eclipse.jgit.api;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.api.errors;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.diff;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.dircache;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.internal.storage.file;version="4.11.8",
- org.eclipse.jgit.junit;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.lib;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.merge;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.pgm;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.pgm.internal;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.pgm.opt;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.revwalk;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.storage.file;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.transport;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.treewalk;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.util;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.util.io;version="[4.11.8,4.12.0)",
+Import-Package: org.eclipse.jgit.api;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.api.errors;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.diff;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.dircache;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.internal.storage.file;version="5.0.4",
+ org.eclipse.jgit.junit;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.lib;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.merge;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.pgm;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.pgm.internal;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.pgm.opt;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.revwalk;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.storage.file;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.transport;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.treewalk;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.util;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.util.io;version="[5.0.4,5.1.0)",
  org.hamcrest.core;bundle-version="[1.1.0,2.0.0)",
  org.junit;version="[4.12,5.0.0)",
  org.junit.rules;version="[4.12,5.0.0)",
diff --git a/org.eclipse.jgit.pgm.test/pom.xml b/org.eclipse.jgit.pgm.test/pom.xml
index e9b777f..30c32ed 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.11.8-SNAPSHOT</version>
+    <version>5.0.4-SNAPSHOT</version>
   </parent>
 
   <artifactId>org.eclipse.jgit.pgm.test</artifactId>
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 @@
 		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 @@
 	}
 
 	@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 e5c85eb..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,7 @@
  */
 package org.eclipse.jgit.pgm;
 
-import static java.nio.charset.StandardCharsets.UTF_8;
+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;
@@ -612,7 +612,7 @@
 
 	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)
@@ -700,7 +700,7 @@
 		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>() {
@@ -750,7 +750,7 @@
 			// 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);
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 @@
 	}
 
 	@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 @@
 			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 @@
 	@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/BUILD b/org.eclipse.jgit.pgm/BUILD
index 0792268..ddc84be 100644
--- a/org.eclipse.jgit.pgm/BUILD
+++ b/org.eclipse.jgit.pgm/BUILD
@@ -25,6 +25,12 @@
     ],
 )
 
+java_binary(
+    name = "jgit",
+    main_class = "org.eclipse.jgit.pgm.Main",
+    runtime_deps = [":pgm"],
+)
+
 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 5e2def1..f8aa095 100644
--- a/org.eclipse.jgit.pgm/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.pgm/META-INF/MANIFEST.MF
@@ -3,7 +3,7 @@
 Bundle-Name: %plugin_name
 Automatic-Module-Name: org.eclipse.jgit.pgm
 Bundle-SymbolicName: org.eclipse.jgit.pgm
-Bundle-Version: 4.11.8.qualifier
+Bundle-Version: 5.0.4.qualifier
 Bundle-Vendor: %provider_name
 Bundle-ActivationPolicy: lazy
 Bundle-Localization: plugin
@@ -28,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.11.8,4.12.0)",
- org.eclipse.jgit.api.errors;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.archive;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.awtui;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.blame;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.diff;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.dircache;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.errors;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.gitrepo;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.internal.ketch;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.internal.storage.dfs;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.internal.storage.file;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.internal.storage.io;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.internal.storage.pack;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.internal.storage.reftable;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.internal.storage.reftree;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.lfs;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.lfs.lib;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.lfs.server;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.lfs.server.fs;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.lfs.server.s3;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.lib;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.merge;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.nls;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.notes;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.revplot;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.revwalk;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.revwalk.filter;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.storage.file;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.storage.pack;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.transport;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.transport.http.apache;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.transport.resolver;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.treewalk;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.treewalk.filter;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.util;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.util.io;version="[4.11.8,4.12.0)",
+ org.eclipse.jgit.api;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.api.errors;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.archive;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.awtui;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.blame;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.diff;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.dircache;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.errors;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.gitrepo;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.internal.ketch;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.internal.storage.dfs;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.internal.storage.file;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.internal.storage.io;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.internal.storage.pack;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.internal.storage.reftable;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.internal.storage.reftree;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.lfs;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.lfs.lib;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.lfs.server;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.lfs.server.fs;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.lfs.server.s3;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.lib;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.merge;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.nls;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.notes;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.revplot;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.revwalk;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.revwalk.filter;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.storage.file;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.storage.pack;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.transport;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.transport.http.apache;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.transport.resolver;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.treewalk;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.treewalk.filter;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.util;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.util.io;version="[5.0.4,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.11.8";
+Export-Package: org.eclipse.jgit.console;version="5.0.4";
   uses:="org.eclipse.jgit.transport,
    org.eclipse.jgit.util",
- org.eclipse.jgit.pgm;version="4.11.8";
+ org.eclipse.jgit.pgm;version="5.0.4";
   uses:="org.eclipse.jgit.revwalk,
    org.eclipse.jgit.treewalk.filter,
    org.eclipse.jgit.pgm.opt,
@@ -81,11 +81,11 @@
    org.eclipse.jgit.treewalk,
    javax.swing,
    org.eclipse.jgit.transport",
- org.eclipse.jgit.pgm.debug;version="4.11.8";
+ org.eclipse.jgit.pgm.debug;version="5.0.4";
   uses:="org.eclipse.jgit.util.io,
    org.eclipse.jgit.pgm",
- org.eclipse.jgit.pgm.internal;version="4.11.8";x-friends:="org.eclipse.jgit.pgm.test,org.eclipse.jgit.test",
- org.eclipse.jgit.pgm.opt;version="4.11.8";
+ org.eclipse.jgit.pgm.internal;version="5.0.4";x-friends:="org.eclipse.jgit.pgm.test,org.eclipse.jgit.test",
+ org.eclipse.jgit.pgm.opt;version="5.0.4";
   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 edc945c..1d4575e 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.11.8.qualifier
-Eclipse-SourceBundle: org.eclipse.jgit.pgm;version="4.11.8.qualifier";roots="."
+Bundle-Version: 5.0.4.qualifier
+Eclipse-SourceBundle: org.eclipse.jgit.pgm;version="5.0.4.qualifier";roots="."
diff --git a/org.eclipse.jgit.pgm/pom.xml b/org.eclipse.jgit.pgm/pom.xml
index 7d2184f..db6745e 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.11.8-SNAPSHOT</version>
+    <version>5.0.4-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/pgm/AbstractFetchCommand.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/AbstractFetchCommand.java
index f0754b1..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
@@ -74,10 +74,10 @@
 	 * @throws java.io.IOException
 	 *             if any.
 	 */
-	protected void showFetchResult(final FetchResult r) throws IOException {
+	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;
 
@@ -181,7 +181,7 @@
 		}
 	}
 
-	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/AmazonS3Client.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/AmazonS3Client.java
index cce889b..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
@@ -105,7 +105,7 @@
 			}
 
 		} 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$
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 e6685c2..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
@@ -292,7 +292,7 @@
 				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);
@@ -302,15 +302,15 @@
 		}
 	}
 
-	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/CommandCatalog.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/CommandCatalog.java
index 81aeef8..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,11 +43,10 @@
 
 package org.eclipse.jgit.pgm;
 
-import static java.nio.charset.StandardCharsets.UTF_8;
+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;
@@ -88,7 +87,7 @@
 	 *            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);
 	}
 
@@ -108,17 +107,17 @@
 	 */
 	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());
 			}
 		});
@@ -147,36 +146,20 @@
 		}
 	}
 
-	private void scan(final URL cUrl) {
-		final BufferedReader cIn;
-		try {
-			final InputStream in = cUrl.openStream();
-			cIn = new BufferedReader(new InputStreamReader(in, UTF_8));
-		} 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 2c9bc0d..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
@@ -66,29 +66,29 @@
 
 	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('-');
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 d0ada67..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
@@ -142,7 +142,7 @@
 			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);
 		}
@@ -157,14 +157,14 @@
 		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/Die.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Die.java
index 59de80c..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
@@ -63,7 +63,7 @@
 	 * @param why
 	 *            the message to show to the end-user.
 	 */
-	public Die(final String why) {
+	public Die(String why) {
 		super(why);
 	}
 
@@ -75,7 +75,7 @@
 	 * @param cause
 	 *            why the command has failed.
 	 */
-	public Die(final String why, final Throwable cause) {
+	public Die(String why, Throwable cause) {
 		super(why, cause);
 	}
 
@@ -100,7 +100,7 @@
 	 *            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 ed6f7b4..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
@@ -170,7 +170,7 @@
 
 	/** {@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));
 	}
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 5104063..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
@@ -75,9 +75,9 @@
 	/** {@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 bc76372..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 @@
 		tags = Boolean.FALSE;
 	}
 
+	@Option(name = "--force", usage = "usage_forcedFetch", aliases = { "-f" })
+	private Boolean force;
+
 	private FetchRecurseSubmodulesMode recurseSubmodules;
 
 	@Option(name = "--recurse-submodules", usage = "usage_recurseSubmodules")
@@ -155,6 +158,9 @@
 			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()
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 a081b78..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 @@
 		frame = new JFrame();
 		frame.addWindowListener(new WindowAdapter() {
 			@Override
-			public void windowClosing(final WindowEvent e) {
+			public void windowClosing(WindowEvent e) {
 				frame.dispose();
 			}
 		});
@@ -116,7 +116,7 @@
 
 	/** {@inheritDoc} */
 	@Override
-	protected void show(final RevCommit c) throws Exception {
+	protected void show(RevCommit c) throws Exception {
 		throw new UnsupportedOperationException();
 	}
 
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 75542d4..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
@@ -186,7 +186,7 @@
 
 	/** {@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));
 	}
@@ -241,7 +241,7 @@
 
 	/** {@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);
@@ -266,7 +266,7 @@
 
 		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 9013ff6..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
@@ -83,7 +83,7 @@
 			}
 		});
 		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$
@@ -96,7 +96,7 @@
 		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 c57f9f2..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
@@ -73,7 +73,7 @@
 	/** {@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 a376bc0..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;
@@ -71,6 +71,7 @@
 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;
@@ -105,10 +106,19 @@
 
 	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());
 		BuiltinLFS.register();
 		gcExecutor = Executors.newSingleThreadExecutor(new ThreadFactory() {
@@ -131,7 +141,7 @@
 	 *            arguments.
 	 * @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();
 
@@ -155,7 +165,7 @@
 	 *            arguments.
 	 * @throws java.lang.Exception
 	 */
-	protected void run(final String[] argv) throws Exception {
+	protected void run(String[] argv) throws Exception {
 		writer = createErrorWriter();
 		try {
 			if (!installConsole()) {
@@ -217,10 +227,10 @@
 	}
 
 	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 {
@@ -246,12 +256,12 @@
 				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++) {
@@ -286,7 +296,7 @@
 		}
 	}
 
-	void init(final TextBuiltin cmd) throws IOException {
+	void init(TextBuiltin cmd) throws IOException {
 		if (cmd.requiresRepository()) {
 			cmd.init(openGitDir(gitdir), null);
 		} else {
@@ -350,7 +360,7 @@
 		}
 	}
 
-	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/MergeBase.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/MergeBase.java
index 62a88ae..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
@@ -68,7 +68,7 @@
 	/** {@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 309dca2..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
@@ -149,7 +149,7 @@
 		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);
@@ -157,13 +157,13 @@
 				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/Remote.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Remote.java
index 948cbc5..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
@@ -146,7 +146,7 @@
 
 	/** {@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/RevList.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/RevList.java
index 8c88a5c..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
@@ -53,7 +53,7 @@
 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);
@@ -67,7 +67,7 @@
 
 	/** {@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 21adf73..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;
@@ -74,8 +71,7 @@
 	@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.
@@ -91,7 +87,7 @@
 						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 3fc9101..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 @@
 
 	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 @@
 	}
 
 	@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,17 +130,17 @@
 	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));
 	}
 
@@ -153,7 +151,7 @@
 	@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) {
@@ -171,9 +169,7 @@
 			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();
@@ -191,7 +187,7 @@
 				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);
@@ -237,7 +233,7 @@
 	 */
 	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);
@@ -264,7 +260,7 @@
 	 *            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.
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 de04045..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
@@ -167,7 +167,7 @@
 
 	/** {@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));
 	}
@@ -248,7 +248,7 @@
 
 		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();
@@ -259,7 +259,7 @@
 
 	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);
 
@@ -273,7 +273,7 @@
 		}
 	}
 
-	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);
@@ -292,7 +292,7 @@
 
 		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 7b59d43..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,23 +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$
@@ -69,14 +65,13 @@
 	}
 
 	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/TextBuiltin.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/TextBuiltin.java
index bc3755d..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,7 +129,7 @@
 	/** 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;
 	}
 
@@ -176,7 +176,7 @@
 	 *            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$
@@ -239,7 +239,7 @@
 	 *            the arguments supplied on the command line, if any.
 	 * @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 {
@@ -267,7 +267,7 @@
 	 *            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$
 	}
 
@@ -280,7 +280,7 @@
 	 *            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);
 	}
@@ -295,7 +295,7 @@
 	 * @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$
@@ -361,7 +361,7 @@
 		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));
@@ -375,7 +375,7 @@
 	 *            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);
 	}
 
@@ -388,7 +388,7 @@
 	 *            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);
 	}
 
@@ -416,7 +416,7 @@
 	 * @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);
 	}
 
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 5efc03b..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
@@ -96,14 +96,9 @@
 	}
 
 	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 248eaac..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;
@@ -154,7 +154,7 @@
 			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/MakeCacheTree.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/MakeCacheTree.java
index 127e541..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
@@ -65,7 +65,7 @@
 		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/RebuildCommitGraph.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/RebuildCommitGraph.java
index 2e41eec..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;
@@ -117,7 +115,7 @@
 	/** {@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();
@@ -224,7 +222,7 @@
 
 		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;
@@ -247,8 +245,7 @@
 
 	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());
@@ -261,7 +258,7 @@
 		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 3172483..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
@@ -154,14 +154,14 @@
 					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 20fa4a3..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
@@ -67,7 +67,7 @@
 		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 a960ec6..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
@@ -65,11 +65,11 @@
 		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(' ');
 
@@ -87,7 +87,7 @@
 		/** */
 		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));
@@ -97,7 +97,7 @@
 		/** */
 		CLASSES {
 			@Override
-			void print(ThrowingPrintWriter err, final CommandRef c) throws IOException {
+			void print(ThrowingPrintWriter err, CommandRef c) throws IOException {
 				err.print(c.getImplementationClassName());
 			}
 		},
@@ -105,7 +105,7 @@
 		/** */
 		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/ShowPackDelta.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/ShowPackDelta.java
index bbc1b0f..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
@@ -125,12 +125,13 @@
 			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 83b7bce..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
@@ -288,11 +288,8 @@
 			else
 				rb.findGitDir(dir);
 
-			Repository repo = rb.build();
-			try {
+			try (Repository repo = rb.build()) {
 				run(repo);
-			} finally {
-				repo.close();
 			}
 		}
 	}
@@ -502,7 +499,7 @@
 		}
 	}
 
-	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/WriteReftable.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/WriteReftable.java
index 6cbc1b0..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;
@@ -192,7 +192,7 @@
 	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));
@@ -227,7 +227,7 @@
 
 		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/opt/AbstractTreeIteratorHandler.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/AbstractTreeIteratorHandler.java
index 6fe7927..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
@@ -98,7 +98,7 @@
 
 	/** {@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()) {
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 e071bdf..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
@@ -111,7 +111,7 @@
 	 *             if the option bean class is using args4j annotations
 	 *             incorrectly.
 	 */
-	public CmdLineParser(final Object bean) {
+	public CmdLineParser(Object bean) {
 		this(bean, null);
 	}
 
@@ -130,7 +130,7 @@
 	 *             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;
@@ -143,7 +143,7 @@
 
 	/** {@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];
@@ -232,7 +232,7 @@
 	 * @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);
 	}
 
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 0e5b0f5..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
@@ -84,7 +84,7 @@
 
 	/** {@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 {
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 33d669c..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
@@ -84,7 +84,7 @@
 
 	/** {@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;
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 dd8520a..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
@@ -78,7 +78,7 @@
 
 	/** {@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;
 	}
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 d2fa764..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
@@ -88,7 +88,7 @@
 
 	/** {@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;
@@ -115,7 +115,7 @@
 		return 1;
 	}
 
-	private void addOne(final String name, final boolean interesting)
+	private void addOne(String name, boolean interesting)
 			throws CmdLineException {
 		final ObjectId id;
 		try {
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 9444363..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
@@ -87,7 +87,7 @@
 
 	/** {@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 {
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 d60071f..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
@@ -84,7 +84,7 @@
 
 	/** {@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)
diff --git a/org.eclipse.jgit.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.test/META-INF/MANIFEST.MF
index 855cda5..4b83fb0 100644
--- a/org.eclipse.jgit.test/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.test/META-INF/MANIFEST.MF
@@ -3,58 +3,58 @@
 Bundle-Name: %plugin_name
 Automatic-Module-Name: org.eclipse.jgit.test
 Bundle-SymbolicName: org.eclipse.jgit.test
-Bundle-Version: 4.11.8.qualifier
+Bundle-Version: 5.0.4.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.11.8,4.12.0)",
- org.eclipse.jgit.api.errors;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.attributes;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.awtui;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.blame;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.diff;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.dircache;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.errors;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.events;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.fnmatch;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.gitrepo;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.hooks;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.ignore;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.ignore.internal;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.internal;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.internal.fsck;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.internal.storage.dfs;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.internal.storage.file;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.internal.storage.io;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.internal.storage.pack;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.internal.storage.reftable;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.internal.storage.reftree;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.junit;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.lfs;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.lib;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.merge;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.nls;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.notes;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.patch;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.pgm;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.pgm.internal;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.revplot;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.revwalk;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.revwalk.filter;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.storage.file;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.storage.pack;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.submodule;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.transport;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.transport.http;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.transport.resolver;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.treewalk;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.treewalk.filter;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.util;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.util.io;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.util.sha1;version="[4.11.8,4.12.0)",
+ org.eclipse.jgit.api;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.api.errors;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.attributes;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.awtui;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.blame;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.diff;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.dircache;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.errors;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.events;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.fnmatch;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.gitrepo;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.hooks;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.ignore;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.ignore.internal;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.internal;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.internal.fsck;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.internal.storage.dfs;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.internal.storage.file;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.internal.storage.io;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.internal.storage.pack;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.internal.storage.reftable;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.internal.storage.reftree;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.junit;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.lfs;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.lib;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.merge;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.nls;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.notes;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.patch;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.pgm;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.pgm.internal;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.revplot;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.revwalk;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.revwalk.filter;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.storage.file;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.storage.pack;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.submodule;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.transport;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.transport.http;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.transport.resolver;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.treewalk;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.treewalk.filter;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.util;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.util.io;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.util.sha1;version="[5.0.4,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)",
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 438d2d6..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,7 +42,7 @@
  */
 package org.eclipse.jgit.ignore;
 
-import static java.nio.charset.StandardCharsets.UTF_8;
+import static org.eclipse.jgit.lib.Constants.CHARSET;
 
 import java.io.BufferedReader;
 import java.io.File;
@@ -158,7 +158,7 @@
 			this.gitDir = gitDir;
 			this.pattern = pattern;
 			Files.write(FileUtils.toPath(new File(gitDir, ".gitignore")),
-					(pattern + "\n").getBytes(UTF_8), StandardOpenOption.CREATE,
+					(pattern + "\n").getBytes(CHARSET), StandardOpenOption.CREATE,
 					StandardOpenOption.TRUNCATE_EXISTING,
 					StandardOpenOption.WRITE);
 		}
@@ -188,7 +188,7 @@
 			Process proc = Runtime.getRuntime().exec(command, new String[0],
 					gitDir);
 			try (OutputStream out = proc.getOutputStream()) {
-				out.write((path + "\n").getBytes(UTF_8));
+				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 3f9ef12..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
@@ -85,7 +85,7 @@
 
 		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;
@@ -103,7 +103,7 @@
 			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());
 				}
@@ -111,7 +111,7 @@
 				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();
@@ -121,7 +121,7 @@
 				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();
 				}
@@ -147,7 +147,7 @@
 			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");
@@ -188,7 +188,7 @@
 	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";
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 43f4037..e6c7128 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.11.8-SNAPSHOT</version>
+    <version>5.0.4-SNAPSHOT</version>
   </parent>
 
   <artifactId>org.eclipse.jgit.test</artifactId>
@@ -62,6 +62,10 @@
     JUnit tests for the core library.
   </description>
 
+  <properties>
+    <maven.javadoc.skip>true</maven.javadoc.skip>
+  </properties>
+
   <dependencies>
     <dependency>
       <groupId>junit</groupId>
diff --git a/org.eclipse.jgit.test/tests.bzl b/org.eclipse.jgit.test/tests.bzl
index c75ab76..f368000 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/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 @@
 
 	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 @@
 		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 @@
 		}
 	}
 
-	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 @@
 		}
 
 		@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 @@
 		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 @@
 				- 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/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 @@
 		}
 	}
 
-	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/CommitCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitCommandTest.java
index 0dd3749..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;
@@ -553,8 +553,8 @@
 				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 cc21b47..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
@@ -1289,7 +1289,7 @@
 		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 be67893..f2093e3 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
@@ -55,7 +55,6 @@
 
 import org.eclipse.jgit.api.errors.GitAPIException;
 import org.eclipse.jgit.api.errors.RefNotFoundException;
-import org.eclipse.jgit.errors.InvalidPatternException;
 import org.eclipse.jgit.junit.RepositoryTestCase;
 import org.eclipse.jgit.lib.ObjectId;
 import org.junit.Test;
@@ -69,13 +68,18 @@
 
 	private Git git;
 
-	@Parameter
+	@Parameter(0)
 	public boolean useAnnotatedTags;
 
-	@Parameters
+	@Parameter(1)
+	public boolean describeUseAllTags;
+
+	@Parameters(name = "git tag -a {0}?-a: with git describe {1}?--tags:")
 	public static Collection<Boolean[]> getUseAnnotatedTagsValues() {
-		return Arrays.asList(new Boolean[][] { { Boolean.TRUE },
-				{ Boolean.FALSE } });
+		return Arrays.asList(new Boolean[][] { { Boolean.TRUE, Boolean.FALSE },
+				{ Boolean.FALSE, Boolean.FALSE },
+				{ Boolean.TRUE, Boolean.TRUE },
+				{ Boolean.FALSE, Boolean.TRUE } });
 	}
 
 	@Override
@@ -100,35 +104,52 @@
 		tag("bob-t2");
 
 		ObjectId c4 = modify("ddd");
+		assertNameStartsWith(c4, "3e563c5");
 
 		assertNull(describe(c1));
 		assertNull(describe(c1, true));
 		assertNull(describe(c1, "a*", "b*", "c*"));
-
-		assertEquals("alice-t1", describe(c2));
-		assertEquals("alice-t1", describe(c2, "alice*"));
 		assertNull(describe(c2, "bob*"));
 		assertNull(describe(c2, "?ob*"));
-		assertEquals("alice-t1", describe(c2, "a*", "b*", "c*"));
 
-		assertEquals("bob-t2", describe(c3));
-		assertEquals("bob-t2-0-g44579eb", describe(c3, true));
-		assertEquals("alice-t1-1-g44579eb", describe(c3, "alice*"));
-		assertEquals("alice-t1-1-g44579eb", describe(c3, "a??c?-t*"));
-		assertEquals("bob-t2", describe(c3, "bob*"));
-		assertEquals("bob-t2", describe(c3, "?ob*"));
-		assertEquals("bob-t2", describe(c3, "a*", "b*", "c*"));
+		if (useAnnotatedTags || describeUseAllTags) {
+			assertEquals("alice-t1", describe(c2));
+			assertEquals("alice-t1", describe(c2, "alice*"));
+			assertEquals("alice-t1", describe(c2, "a*", "b*", "c*"));
 
-		assertNameStartsWith(c4, "3e563c5");
-		// the value verified with git-describe(1)
-		assertEquals("bob-t2-1-g3e563c5", describe(c4));
-		assertEquals("bob-t2-1-g3e563c5", describe(c4, true));
-		assertEquals("alice-t1-2-g3e563c5", describe(c4, "alice*"));
-		assertEquals("bob-t2-1-g3e563c5", describe(c4, "bob*"));
-		assertEquals("bob-t2-1-g3e563c5", describe(c4, "a*", "b*", "c*"));
+			assertEquals("bob-t2", describe(c3));
+			assertEquals("bob-t2-0-g44579eb", describe(c3, true));
+			assertEquals("alice-t1-1-g44579eb", describe(c3, "alice*"));
+			assertEquals("alice-t1-1-g44579eb", describe(c3, "a??c?-t*"));
+			assertEquals("bob-t2", describe(c3, "bob*"));
+			assertEquals("bob-t2", describe(c3, "?ob*"));
+			assertEquals("bob-t2", describe(c3, "a*", "b*", "c*"));
+
+			// the value verified with git-describe(1)
+			assertEquals("bob-t2-1-g3e563c5", describe(c4));
+			assertEquals("bob-t2-1-g3e563c5", describe(c4, true));
+			assertEquals("alice-t1-2-g3e563c5", describe(c4, "alice*"));
+			assertEquals("bob-t2-1-g3e563c5", describe(c4, "bob*"));
+			assertEquals("bob-t2-1-g3e563c5", describe(c4, "a*", "b*", "c*"));
+		} else {
+			assertEquals(null, describe(c2));
+			assertEquals(null, describe(c3));
+			assertEquals(null, describe(c4));
+		}
 
 		// test default target
-		assertEquals("bob-t2-1-g3e563c5", git.describe().call());
+		if (useAnnotatedTags) {
+			assertEquals("bob-t2-1-g3e563c5", git.describe().call());
+			assertEquals("bob-t2-1-g3e563c5",
+					git.describe().setTags(false).call());
+			assertEquals("bob-t2-1-g3e563c5",
+					git.describe().setTags(true).call());
+		} else {
+			assertEquals(null, git.describe().call());
+			assertEquals(null, git.describe().setTags(false).call());
+			assertEquals("bob-t2-1-g3e563c5",
+					git.describe().setTags(true).call());
+		}
 	}
 
 	@Test
@@ -143,12 +164,17 @@
 		tag("v1.1.1");
 		ObjectId c2 = modify("bbb");
 
+		if (!useAnnotatedTags && !describeUseAllTags) {
+			assertEquals(null, describe(c1));
+			assertEquals(null, describe(c2));
+			return;
+		}
+
 		// Ensure that if we're interested in any tags, we get the most recent tag
 		// as per Git behaviour since 1.7.1.1
 		if (useAnnotatedTags) {
 			assertEquals("v1.1.1", describe(c1));
 			assertEquals("v1.1.1-1-gb89dead", describe(c2));
-
 			// Ensure that if we're only interested in one of multiple tags, we get the right match
 			assertEquals("v1.0.1", describe(c1, "v1.0*"));
 			assertEquals("v1.1.1", describe(c1, "v1.1*"));
@@ -204,7 +230,11 @@
 		ObjectId c4 = merge(c2);
 
 		assertNameStartsWith(c4, "119892b");
-		assertEquals("t-2-g119892b", describe(c4)); // 2 commits: c4 and c3
+		if (useAnnotatedTags || describeUseAllTags) {
+			assertEquals("2 commits: c4 and c3", "t-2-g119892b", describe(c4));
+		} else {
+			assertEquals(null, describe(c4));
+		}
 		assertNull(describe(c3));
 		assertNull(describe(c3, true));
 	}
@@ -236,14 +266,76 @@
 		branch("b", c1);
 
 		ObjectId c3 = modify("ccc");
+		assertNameStartsWith(c3, "0244e7f");
 
 		ObjectId c4 = merge(c2);
 
 		assertNameStartsWith(c4, "119892b");
-		assertEquals("t2-2-g119892b", describe(c4)); // 2 commits: c4 and c3
+
+		if (useAnnotatedTags || describeUseAllTags) {
+			assertEquals("t2-2-g119892b", describe(c4)); // 2 commits: c4 and c3
+			assertEquals("t1-1-g0244e7f", describe(c3));
+		} else {
+			assertEquals(null, describe(c4));
+			assertEquals(null, describe(c3));
+		}
+	}
+
+	/**
+	 * When t1 annotated dominates t2 lightweight tag
+	 *
+	 * <pre>
+	 * t1 -+-> t2  -
+	 *     |       |
+	 *     +-> c3 -+-> c4
+	 * </pre>
+	 *
+	 * @throws Exception
+	 */
+	@Test
+	public void t1AnnotatedDominatesT2lightweight() throws Exception {
+		ObjectId c1 = modify("aaa");
+		tag("t1", useAnnotatedTags);
+
+		ObjectId c2 = modify("bbb");
+		tag("t2", false);
+
+		assertNameStartsWith(c2, "3747db3");
+		if (useAnnotatedTags && !describeUseAllTags) {
+			assertEquals(
+					"only annotated tag t1 expected to be used for describe",
+					"t1-1-g3747db3", describe(c2)); // 1 commits: t2 overridden
+													// by t1
+		} else if (!useAnnotatedTags && !describeUseAllTags) {
+			assertEquals("no commits to describe expected", null, describe(c2));
+		} else {
+			assertEquals("lightweight tag t2 expected in describe", "t2",
+					describe(c2));
+		}
+
+		branch("b", c1);
+
+		ObjectId c3 = modify("ccc");
 
 		assertNameStartsWith(c3, "0244e7f");
-		assertEquals("t1-1-g0244e7f", describe(c3));
+		if (useAnnotatedTags || describeUseAllTags) {
+			assertEquals("t1-1-g0244e7f", describe(c3));
+		}
+
+		ObjectId c4 = merge(c2);
+
+		assertNameStartsWith(c4, "119892b");
+		if (describeUseAllTags) {
+			assertEquals(
+					"2 commits for describe commit increment expected since lightweight tag: c4 and c3",
+					"t2-2-g119892b", describe(c4)); // 2 commits: c4 and c3
+		} else if (!useAnnotatedTags && !describeUseAllTags) {
+			assertEquals("no matching commits expected", null, describe(c4));
+		} else {
+			assertEquals(
+					"3 commits for describe commit increment expected since annotated tag: c4 and c3 and c2",
+					"t1-3-g119892b", describe(c4)); //
+		}
 	}
 
 	/**
@@ -271,7 +363,11 @@
 		ObjectId c4 = merge(t1);
 
 		assertNameStartsWith(c4, "bb389a4");
-		assertEquals("t1-3-gbb389a4", describe(c4));
+		if (useAnnotatedTags || describeUseAllTags) {
+			assertEquals("t1-3-gbb389a4", describe(c4));
+		} else {
+			assertEquals(null, describe(c4));
+		}
 	}
 
 	/**
@@ -300,7 +396,11 @@
 		ObjectId c4 = merge(c2);
 
 		assertNameStartsWith(c4, "bb389a4");
-		assertEquals("t2-4-gbb389a4", describe(c4));
+		if (useAnnotatedTags || describeUseAllTags) {
+			assertEquals("t2-4-gbb389a4", describe(c4));
+		} else {
+			assertEquals(null, describe(c4));
+		}
 	}
 
 	private ObjectId merge(ObjectId c2) throws GitAPIException {
@@ -314,10 +414,15 @@
 	}
 
 	private void tag(String tag) throws GitAPIException {
+		tag(tag, this.useAnnotatedTags);
+	}
+
+	private void tag(String tag, boolean annotatedTag) throws GitAPIException {
 		TagCommand tagCommand = git.tag().setName(tag)
-				.setAnnotated(useAnnotatedTags);
-		if (useAnnotatedTags)
+				.setAnnotated(annotatedTag);
+		if (annotatedTag) {
 			tagCommand.setMessage(tag);
+		}
 		tagCommand.call();
 	}
 
@@ -329,15 +434,17 @@
 
 	private String describe(ObjectId c1, boolean longDesc)
 			throws GitAPIException, IOException {
-		return git.describe().setTarget(c1).setLong(longDesc).call();
+		return git.describe().setTarget(c1).setTags(describeUseAllTags)
+				.setLong(longDesc).call();
 	}
 
 	private String describe(ObjectId c1) throws GitAPIException, IOException {
 		return describe(c1, false);
 	}
 
-	private String describe(ObjectId c1, String... patterns) throws GitAPIException, IOException, InvalidPatternException {
-		return git.describe().setTarget(c1).setMatch(patterns).call();
+	private String describe(ObjectId c1, String... patterns) throws Exception {
+		return git.describe().setTarget(c1).setTags(describeUseAllTags)
+				.setMatch(patterns).call();
 	}
 
 	private static void assertNameStartsWith(ObjectId c4, String prefix) {
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 1e3a39a..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,7 +42,7 @@
 
 package org.eclipse.jgit.api;
 
-import static java.nio.charset.StandardCharsets.UTF_8;
+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;
@@ -150,8 +150,8 @@
 			EolStreamType streamTypeWithBinaryCheck, String output,
 			String expectedConversion) throws Exception {
 		ByteArrayOutputStream b;
-		byte[] outputBytes = output.getBytes(UTF_8);
-		byte[] expectedConversionBytes = expectedConversion.getBytes(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();
@@ -277,8 +277,8 @@
 	private void testCheckin(EolStreamType streamTypeText,
 			EolStreamType streamTypeWithBinaryCheck, String input,
 			String expectedConversion) throws Exception {
-		byte[] inputBytes = input.getBytes(UTF_8);
-		byte[] expectedConversionBytes = expectedConversion.getBytes(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 530fb1b..adc4d98 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,12 +43,17 @@
 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.ArrayList;
 import java.util.Collection;
 import java.util.List;
 
+import org.eclipse.jgit.junit.JGitTestUtil;
 import org.eclipse.jgit.junit.RepositoryTestCase;
 import org.eclipse.jgit.lib.Constants;
 import org.eclipse.jgit.lib.ObjectId;
@@ -105,6 +110,25 @@
 	}
 
 	@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 fetchAddsBranches() throws Exception {
 		final String branch1 = "b1";
 		final String branch2 = "b2";
@@ -275,6 +299,45 @@
 	}
 
 	@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"));
+	}
+
+	@Test
 	public void fetchAddRefsWithDuplicateRefspec() throws Exception {
 		final String branchName = "branch";
 		final String remoteBranchName = "test/" + branchName;
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 @@
 		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 @@
 		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 @@
 	}
 
 	@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 @@
 				.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 6e06e95..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,7 +42,7 @@
  */
 package org.eclipse.jgit.api;
 
-import static java.nio.charset.StandardCharsets.UTF_8;
+import static org.eclipse.jgit.lib.Constants.CHARSET;
 import static org.junit.Assert.assertEquals;
 
 import java.util.List;
@@ -88,7 +88,7 @@
 		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 9461c42..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,7 +42,7 @@
  */
 package org.eclipse.jgit.api;
 
-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.assertNotNull;
@@ -592,7 +592,7 @@
 	private static void writeToFile(File actFile, String string)
 			throws IOException {
 		try (FileOutputStream fos = new FileOutputStream(actFile)) {
-			fos.write(string.getBytes(UTF_8));
+			fos.write(string.getBytes(CHARSET));
 		}
 	}
 
@@ -606,7 +606,7 @@
 				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);
 		}
 	}
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 913b4ac..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,7 +42,7 @@
  */
 package org.eclipse.jgit.api;
 
-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.assertNotNull;
@@ -396,7 +396,7 @@
 	private static void writeToFile(File actFile, String string)
 			throws IOException {
 		try (FileOutputStream fos = new FileOutputStream(actFile)) {
-			fos.write(string.getBytes(UTF_8));
+			fos.write(string.getBytes(CHARSET));
 		}
 	}
 
@@ -410,7 +410,7 @@
 				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);
 		}
 	}
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 @@
 		}
 	}
 
-	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 2bf91ae..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,7 +42,7 @@
  */
 package org.eclipse.jgit.api;
 
-import static java.nio.charset.StandardCharsets.UTF_8;
+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;
@@ -1464,7 +1464,7 @@
 		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
@@ -1481,7 +1481,7 @@
 		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());
@@ -2104,7 +2104,7 @@
 		int count = 0;
 		File todoFile = getTodoFile();
 		try (BufferedReader br = new BufferedReader(new InputStreamReader(
-				new FileInputStream(todoFile), UTF_8))) {
+				new FileInputStream(todoFile), CHARSET))) {
 			String line = br.readLine();
 			while (line != null) {
 				int firstBlank = line.indexOf(' ');
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 @@
 		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 @@
 		}
 	}
 
-	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 @@
 		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 @@
 		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> 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> 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 @@
 				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 @@
 		}
 	}
 
+	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 @@
 		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/diff/AbstractDiffTestCase.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/AbstractDiffTestCase.java
index 0f13a68..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,7 +43,7 @@
 
 package org.eclipse.jgit.diff;
 
-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.assertTrue;
 
@@ -240,6 +240,6 @@
 			r.append(text.charAt(i));
 			r.append('\n');
 		}
-		return new RawText(r.toString().getBytes(UTF_8));
+		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 49e5d1b..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 @@
 		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 @@
 		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,7 +180,7 @@
 		}
 	}
 
-	private Patch parseTestPatchFile(final String patchFile) throws IOException {
+	private Patch parseTestPatchFile(String patchFile) throws IOException {
 		try (InputStream in = getClass().getResourceAsStream(patchFile)) {
 			if (in == null) {
 				fail("No " + patchFile + " test vector");
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 6ad59b9..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,7 +44,8 @@
 
 package org.eclipse.jgit.diff;
 
-import static java.nio.charset.StandardCharsets.UTF_8;
+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;
@@ -65,6 +66,16 @@
 	}
 
 	@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"));
@@ -136,8 +147,8 @@
 		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);
@@ -149,14 +160,14 @@
 		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);
@@ -167,8 +178,8 @@
 		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);
@@ -179,8 +190,8 @@
 		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);
@@ -239,6 +250,6 @@
 			r.append(text.charAt(i));
 			r.append('\n');
 		}
-		return new RawText(r.toString().getBytes(UTF_8));
+		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 f168e83..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,7 +43,7 @@
 
 package org.eclipse.jgit.diff;
 
-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.assertTrue;
 
@@ -82,7 +82,7 @@
 				+ "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());
@@ -130,12 +130,12 @@
 				+ "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 @@
 
 		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 dec1762..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,7 +43,7 @@
 
 package org.eclipse.jgit.dircache;
 
-import static java.nio.charset.StandardCharsets.UTF_8;
+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;
@@ -99,7 +99,7 @@
 		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()) {
@@ -180,7 +180,7 @@
 		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);
 		}
@@ -229,14 +229,14 @@
 		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<>();
 		try (BufferedReader br = new BufferedReader(new InputStreamReader(
-				new FileInputStream(pathOf("gitgit.lsfiles")), UTF_8))) {
+				new FileInputStream(pathOf("gitgit.lsfiles")), CHARSET))) {
 			String line;
 			while ((line = br.readLine()) != null) {
 				final CGitIndexRecord cr = new CGitIndexRecord(line);
@@ -249,7 +249,7 @@
 	private static Map<String, CGitLsTreeRecord> readLsTree() throws Exception {
 		final LinkedHashMap<String, CGitLsTreeRecord> r = new LinkedHashMap<>();
 		try (BufferedReader br = new BufferedReader(new InputStreamReader(
-				new FileInputStream(pathOf("gitgit.lstree")), UTF_8))) {
+				new FileInputStream(pathOf("gitgit.lstree")), CHARSET))) {
 			String line;
 			while ((line = br.readLine()) != null) {
 				final CGitLsTreeRecord cr = new CGitLsTreeRecord(line);
@@ -268,7 +268,7 @@
 
 		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);
@@ -286,7 +286,7 @@
 
 		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 @@
 		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 @@
 		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 @@
 		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 @@
 		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 @@
 		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 @@
 			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 @@
 			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 @@
 		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 @@
 		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 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 @@
 
 		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 @@
 				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 @@
 					.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 2253a04..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,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.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNull;
@@ -160,7 +160,7 @@
 				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,108 +185,93 @@
 		}
 	}
 
+	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 {
-		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();
 
-		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(UTF_8)))
-			.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(UTF_8)))
-			.setRemoteReader(repos)
-			.setURI("platform/")
-			.setTargetURI("platform/superproject")
-			.setRecordRemoteBranch(true)
-			.setRecordSubmoduleLabels(true)
-			.call();
-		String idStr = commit.getId().name() + ":" + ".gitmodules";
-		assertEquals(firstIdStr, idStr);
-		child.close();
-		dest.close();
+			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();
 
-		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);
+			String idStr = commit.getId().name() + ":" + ".gitmodules";
+			ObjectId modId = dest.resolve(idStr);
 
-		IndexedRepos repos = new IndexedRepos();
-		repos.put("platform/base", child);
-
-		RevCommit commit = cmd
-			.setInputStream(new ByteArrayInputStream(xmlContent.toString().getBytes(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);
-
-		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, "../base");
+			}
 		}
-
-		child.close();
-		dest.close();
 	}
 
 	@Test
@@ -299,200 +284,174 @@
 			.append("<project path=\"base\" name=\"platform/base\" />")
 			.append("</manifest>");
 
-		Repository dest = Git.cloneRepository()
-				.setURI(db.getDirectory().toURI().toString())
-				.setDirectory(createUniqueTestGitDir(true)).setBare(true).call()
-				.getRepository();
+		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();
 
-		assertTrue(dest.isBare());
+			String idStr = commit.getId().name() + ":" + ".gitmodules";
+			ObjectId modId = dest.resolve(idStr);
 
-		RevCommit commit = new RepoCommand(dest)
-			.setInputStream(new ByteArrayInputStream(
-				xmlContent.toString().getBytes(UTF_8)))
-			.setRemoteReader(new IndexedRepos())
-			.setURI("platform/")
-			.setTargetURI("platform/superproject")
-			.setRecordRemoteBranch(true)
-			.setIgnoreRemoteFailures(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, "https://host.com/platform/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");
+			}
 		}
-
-		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(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(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 {
-		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(UTF_8)))
-					.setRemoteReader(repos)
-					.setURI(baseUrl)
-					.setTargetURI(abs + "/superproject")
-					.setRecordRemoteBranch(true)
-					.setRecordSubmoduleLabels(true)
-					.call();
+					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);
+					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);
-		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("../chromium/src", subUrl);
+					}
+					fetchSlash = !fetchSlash;
+				} while (fetchSlash);
+				baseSlash = !baseSlash;
+			} while (baseSlash);
+		}
 	}
 
 	@Test
@@ -513,11 +472,12 @@
 			.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
@@ -603,19 +563,21 @@
 		// 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
@@ -638,24 +600,27 @@
 				.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
@@ -677,11 +642,12 @@
 			.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
@@ -703,11 +669,12 @@
 			.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
@@ -729,11 +696,12 @@
 			.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
@@ -757,14 +725,14 @@
 				.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
@@ -790,22 +758,24 @@
 				.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
@@ -841,36 +811,38 @@
 				.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
@@ -896,34 +868,37 @@
 				.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
@@ -959,11 +934,12 @@
 			.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 testRemoteAlias() throws Exception {
@@ -1165,11 +1141,12 @@
 			.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
@@ -1191,11 +1168,12 @@
 			.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() {
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 3b11616..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
@@ -141,7 +141,9 @@
 		// Do a tree walk that does descend into ignored directories and return
 		// a list of all ignored files
 		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()) {
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 ccc64fb..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,7 +42,7 @@
  */
 package org.eclipse.jgit.ignore;
 
-import static java.nio.charset.StandardCharsets.UTF_8;
+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;
@@ -56,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;
@@ -546,19 +545,6 @@
 		endWalk();
 	}
 
-	@SuppressWarnings("deprecation")
-	@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));
-	}
-
 	@Test
 	public void testEmptyIgnoreRules() throws IOException {
 		IgnoreNode node = new IgnoreNode();
@@ -746,7 +732,9 @@
 
 	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 {
@@ -779,6 +767,6 @@
 		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 d5d3857..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,7 +41,7 @@
  */
 package org.eclipse.jgit.indexdiff;
 
-import static java.nio.charset.StandardCharsets.UTF_8;
+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;
@@ -128,7 +128,7 @@
 		File restoreScript = new File(testDir, name + ".sh");
 		try (OutputStream out = new BufferedOutputStream(
 				new FileOutputStream(restoreScript));
-				Writer writer = new OutputStreamWriter(out, 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/file/ConcurrentRepackTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/ConcurrentRepackTest.java
index 4813d28..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 @@
 		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 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 @@
 		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 File fullPackFileName(final ObjectId name, final String suffix) {
+	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/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 @@
 		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 @@
 					.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 @@
 			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 @@
 			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 @@
 		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 @@
 		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/PackWriterTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackWriterTest.java
index 379432d..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
@@ -368,7 +368,7 @@
 				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 @@
 
 		// 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);
@@ -715,14 +712,14 @@
 			String id = pw.computeName().getName();
 			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 @@
 		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 @@
 		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 @@
 		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 @@
 					@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 @@
 						}
 					}
 				});
-		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 d8d45a8..e1adeed 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,8 @@
 
 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;
@@ -62,6 +62,7 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
+import java.util.Optional;
 
 import org.eclipse.jgit.lib.AnyObjectId;
 import org.eclipse.jgit.lib.Constants;
@@ -94,13 +95,13 @@
 		}
 	}
 
-	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);
 	}
@@ -110,11 +111,21 @@
 		delete(db, ref, expected, exists, removed);
 	}
 
-	private void delete(Repository repo, final RefUpdate ref, final Result expected,
-			final boolean exists, final boolean removed) throws IOException {
-		assertEquals(exists, repo.getAllRefs().containsKey(ref.getName()));
+	private void delete(Repository repo, final RefUpdate ref,
+			final Result expected, final boolean exists, final boolean removed)
+			throws IOException {
+		assertEquals(exists, getRef(repo, ref.getName()).isPresent());
 		assertEquals(expected, ref.delete());
-		assertEquals(!removed, repo.getAllRefs().containsKey(ref.getName()));
+		assertEquals(!removed, getRef(repo, ref.getName()).isPresent());
+	}
+
+	private Optional<Ref> getRef(Repository repo, String name)
+			throws IOException {
+		return getRef(repo.getRefDatabase().getRefs(), name);
+	}
+
+	private Optional<Ref> getRef(List<Ref> refs, String name) {
+		return refs.stream().filter(r -> r.getName().equals(name)).findAny();
 	}
 
 	@Test
@@ -125,8 +136,7 @@
 		ru.setNewObjectId(newid);
 		Result update = ru.update();
 		assertEquals(Result.NEW, update);
-		final Ref r = db.getAllRefs().get(newRef);
-		assertNotNull(r);
+		final Ref r = getRef(db, newRef).get();
 		assertEquals(newRef, r.getName());
 		assertNotNull(r.getObjectId());
 		assertNotSame(newid, r.getObjectId());
@@ -253,7 +263,7 @@
 
 		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();
 		}
 
@@ -378,10 +388,10 @@
 
 	@Test
 	public void testRefKeySameAsName() {
+		@SuppressWarnings("deprecation")
 		Map<String, Ref> allRefs = db.getAllRefs();
 		for (Entry<String, Ref> e : allRefs.entrySet()) {
 			assertEquals(e.getKey(), e.getValue().getName());
-
 		}
 	}
 
@@ -520,8 +530,8 @@
 	 */
 	@Test
 	public void testRefsCacheAfterUpdate() throws Exception {
-		// Do not use the defalt repo for this case.
-		Map<String, Ref> allRefs = db.getAllRefs();
+		// Do not use the default repo for this case.
+		List<Ref> allRefs = db.getRefDatabase().getRefs();
 		ObjectId oldValue = db.resolve("HEAD");
 		ObjectId newValue = db.resolve("HEAD^");
 		// first make HEAD refer to loose ref
@@ -537,9 +547,9 @@
 		update = updateRef.update();
 		assertEquals(Result.FAST_FORWARD, update);
 
-		allRefs = db.getAllRefs();
-		Ref master = allRefs.get("refs/heads/master");
-		Ref head = allRefs.get("HEAD");
+		allRefs = db.getRefDatabase().getRefs();
+		Ref master = getRef(allRefs, "refs/heads/master").get();
+		Ref head = getRef(allRefs, "HEAD").get();
 		assertEquals("refs/heads/master", master.getName());
 		assertEquals("HEAD", head.getName());
 		assertTrue("is symbolic reference", head.isSymbolic());
@@ -557,8 +567,8 @@
 	 */
 	@Test
 	public void testRefsCacheAfterUpdateLooseOnly() throws Exception {
-		// Do not use the defalt repo for this case.
-		Map<String, Ref> allRefs = db.getAllRefs();
+		// Do not use the default repo for this case.
+		List<Ref> allRefs = db.getRefDatabase().getRefs();
 		ObjectId oldValue = db.resolve("HEAD");
 		writeSymref(Constants.HEAD, "refs/heads/newref");
 		RefUpdate updateRef = db.updateRef(Constants.HEAD);
@@ -567,9 +577,9 @@
 		Result update = updateRef.update();
 		assertEquals(Result.NEW, update);
 
-		allRefs = db.getAllRefs();
-		Ref head = allRefs.get("HEAD");
-		Ref newref = allRefs.get("refs/heads/newref");
+		allRefs = db.getRefDatabase().getRefs();
+		Ref head = getRef(allRefs, "HEAD").get();
+		Ref newref = getRef(allRefs, "refs/heads/newref").get();
 		assertEquals("refs/heads/newref", newref.getName());
 		assertEquals("HEAD", head.getName());
 		assertTrue("is symbolic reference", head.isSymbolic());
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 d7505af..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
@@ -47,7 +47,7 @@
 package org.eclipse.jgit.internal.storage.file;
 
 import static java.nio.charset.StandardCharsets.ISO_8859_1;
-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.assertNotNull;
@@ -137,10 +137,10 @@
 	@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()
@@ -162,10 +162,10 @@
 	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()
@@ -187,10 +187,10 @@
 	@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()
@@ -213,13 +213,13 @@
 		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()
@@ -242,13 +242,13 @@
 		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()
@@ -273,26 +273,24 @@
 		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)
@@ -307,7 +305,7 @@
 		// 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());
@@ -375,7 +373,7 @@
 
 	@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());
@@ -417,14 +415,11 @@
 		// 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.
@@ -522,7 +517,7 @@
 				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());
@@ -562,7 +557,7 @@
 	@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()));
@@ -752,7 +747,7 @@
 		}
 	}
 
-	private ObjectId insertCommit(final CommitBuilder builder)
+	private ObjectId insertCommit(CommitBuilder builder)
 			throws IOException, UnsupportedEncodingException {
 		try (ObjectInserter oi = db.newObjectInserter()) {
 			ObjectId id = oi.insert(builder);
@@ -769,7 +764,7 @@
 		}
 	}
 
-	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 @@
 		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 @@
 
 		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 @@
 					.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 @@
 		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 @@
 		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 @@
 		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 @@
 		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 @@
 		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 @@
 					.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 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 @@
 		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 @@
 				// parts[4] is the offset in the pack
 				toLoad.add(o);
 			}
-		} finally {
-			br.close();
 		}
 		assertEquals(96, toLoad.size());
 	}
@@ -127,7 +124,7 @@
 		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 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 @@
 
 		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 @@
 		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/reftree/RefTreeDatabaseTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/reftree/RefTreeDatabaseTest.java
index 1684afa..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 @@
 				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 @@
 		});
 	}
 
-	private void update(final String name, final ObjectId id)
+	private void update(String name, ObjectId id)
 			throws IOException {
 		commit(new Function() {
 			@Override
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 @@
 		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 @@
 		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 7862005..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
@@ -914,12 +914,12 @@
 		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);
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 0412242..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;
@@ -1904,6 +1906,117 @@
 		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 {
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 @@
 	}
 
 	/**
-	 * 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 @@
 			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/ObjectCheckerTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ObjectCheckerTest.java
index f6879b9..1ab36f0 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,7 +45,7 @@
 package org.eclipse.jgit.lib;
 
 import static java.lang.Integer.valueOf;
-import static java.nio.charset.StandardCharsets.UTF_8;
+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;
@@ -1560,7 +1560,7 @@
 		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);
@@ -1574,7 +1574,7 @@
 		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);
@@ -1588,7 +1588,7 @@
 		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);
@@ -1602,7 +1602,7 @@
 		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
@@ -1762,7 +1762,7 @@
 		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/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 @@
 
 	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 @@
 			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 @@
 		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 @@
 
 	@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 @@
 	@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 @@
 	@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 @@
 	@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 @@
 	@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 @@
 	@Test
 	public void testRepositoryUnregisteringWhenExpiredAndUsageCountNegative()
 			throws Exception {
+		@SuppressWarnings("resource") // We are testing the close() method
 		Repository repoA = createBareRepository();
 		RepositoryCache.register(repoA);
 
@@ -234,7 +240,9 @@
 
 	@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 @@
 
 	@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 @@
 		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 @@
 		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 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 @@
 		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 99%
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 190224a..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 @@
 		}
 	}
 
-	private void setIndex(final ObjectId id, String path)
+	private void setIndex(ObjectId id, String path)
 			throws MissingObjectException, IOException {
 		DirCache lockedDircache;
 		DirCacheEditor dcedit;
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 97%
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 9322a47..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,7 +42,7 @@
  */
 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;
@@ -91,19 +91,17 @@
 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(
@@ -756,7 +754,7 @@
 		}
 		binary[50] = '\0';
 
-		writeTrashFile("file", new String(binary, UTF_8));
+		writeTrashFile("file", new String(binary, CHARSET));
 		git.add().addFilepattern("file").call();
 		RevCommit first = git.commit().setMessage("added file").call();
 
@@ -764,7 +762,7 @@
 		int idx = LINELEN * 1200 + 1;
 		byte save = binary[idx];
 		binary[idx] = '@';
-		writeTrashFile("file", new String(binary, UTF_8));
+		writeTrashFile("file", new String(binary, CHARSET));
 
 		binary[idx] = save;
 		git.add().addFilepattern("file").call();
@@ -773,7 +771,7 @@
 
 		git.checkout().setCreateBranch(true).setStartPoint(first).setName("side").call();
 		binary[LINELEN * 1500 + 1] = '!';
-		writeTrashFile("file", new String(binary, UTF_8));
+		writeTrashFile("file", new String(binary, CHARSET));
 		git.add().addFilepattern("file").call();
 		RevCommit sideCommit = git.commit().setAll(true)
 			.setMessage("modified file l 1500").call();
@@ -935,7 +933,7 @@
 			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"
@@ -943,7 +941,7 @@
 						+ ">>>>>>> THEIRS\n"
 						+ "2\n"
 						+ "3";
-				assertEquals(expected, new String(out.toByteArray(), UTF_8));
+				assertEquals(expected, new String(out.toByteArray(), CHARSET));
 			}
 		}
 	}
@@ -1033,19 +1031,21 @@
 		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
@@ -1328,6 +1328,6 @@
 		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 @@
 		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 6027aff..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,7 +89,7 @@
 		assertEquals(new Edit(23 - 1, 25 - 1, 22 - 1, 28 - 1), e.get(2));
 	}
 
-	private Patch parseTestPatchFile(final String patchFile) throws IOException {
+	private Patch parseTestPatchFile(String patchFile) throws IOException {
 		try (InputStream in = getClass().getResourceAsStream(patchFile)) {
 			if (in == null) {
 				fail("No " + patchFile + " test vector");
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 @@
 		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 65375c7..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
@@ -44,7 +44,7 @@
 package org.eclipse.jgit.patch;
 
 import static java.nio.charset.StandardCharsets.ISO_8859_1;
-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.assertTrue;
 import static org.junit.Assert.fail;
@@ -83,7 +83,7 @@
 	@Test
 	public void testGetText_Convert() throws IOException {
 		final Charset csOld = ISO_8859_1;
-		final Charset csNew = UTF_8;
+		final Charset csNew = CHARSET;
 		final Patch p = parseTestPatchFile();
 		assertTrue(p.getErrors().isEmpty());
 		assertEquals(1, p.getFiles().size());
@@ -103,7 +103,7 @@
 	@Test
 	public void testGetText_DiffCc() throws IOException {
 		final Charset csOld = ISO_8859_1;
-		final Charset csNew = UTF_8;
+		final Charset csNew = CHARSET;
 		final Patch p = parseTestPatchFile();
 		assertTrue(p.getErrors().isEmpty());
 		assertEquals(1, p.getFiles().size());
@@ -134,7 +134,7 @@
 		}
 	}
 
-	private String readTestPatchFile(final Charset cs) throws IOException {
+	private String readTestPatchFile(Charset cs) throws IOException {
 		final String patchFile = JGitTestUtil.getName() + ".patch";
 		try (InputStream in = getClass().getResourceAsStream(patchFile)) {
 			if (in == null) {
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 @@
 
 	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 @@
 
 	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 @@
 
 	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 @@
 
 	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 @@
 		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 88f240b..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
@@ -44,7 +44,7 @@
 package org.eclipse.jgit.revwalk;
 
 import static java.nio.charset.StandardCharsets.ISO_8859_1;
-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.assertNotNull;
 import static org.junit.Assert.assertNull;
@@ -114,7 +114,7 @@
 		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());
@@ -138,7 +138,7 @@
 		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");
@@ -148,7 +148,7 @@
 
 		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;
 	}
 
@@ -161,7 +161,7 @@
 
 		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());
@@ -176,7 +176,7 @@
 
 		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());
@@ -185,13 +185,13 @@
 	@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());
@@ -205,13 +205,13 @@
 	@Test
 	public void testParse_implicit_mixed_encoded() throws Exception {
 		final ByteArrayOutputStream b = new ByteArrayOutputStream();
-		b.write("tree 9788669ad918b6fcce64af8882fc9a81cb6aba67\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(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("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());
@@ -260,14 +260,14 @@
 	@Test
 	public void testParse_explicit_bad_encoded() throws Exception {
 		final ByteArrayOutputStream b = new ByteArrayOutputStream();
-		b.write("tree 9788669ad918b6fcce64af8882fc9a81cb6aba67\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(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("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());
@@ -291,14 +291,14 @@
 	@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());
@@ -313,13 +313,13 @@
 	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"));
@@ -338,12 +338,12 @@
 	@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"));
@@ -365,12 +365,12 @@
 	@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"));
@@ -483,7 +483,7 @@
 		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 122a397..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
@@ -76,7 +76,7 @@
 
 		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 38bd371..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
@@ -44,7 +44,7 @@
 package org.eclipse.jgit.revwalk;
 
 import static java.nio.charset.StandardCharsets.ISO_8859_1;
-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.assertNotNull;
 import static org.junit.Assert.assertNull;
@@ -82,7 +82,7 @@
 		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");
@@ -98,7 +98,7 @@
 		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());
@@ -141,7 +141,7 @@
 		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());
@@ -189,7 +189,7 @@
 		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());
@@ -202,7 +202,7 @@
 		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");
@@ -213,7 +213,7 @@
 
 		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;
 	}
 
@@ -221,17 +221,17 @@
 	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());
@@ -246,15 +246,15 @@
 	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));
+				.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(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("\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_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));
+		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_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 @@
 	@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 @@
 	@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 @@
 		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 ab2705c..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 @@
 		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);
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 @@
 		}
 	}
 
-	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 @@
 		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 @@
 		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 @@
 		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 @@
 		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 @@
 		}
 	}
 
-	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 7f0d602..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,7 +42,7 @@
  */
 package org.eclipse.jgit.storage.file;
 
-import static java.nio.charset.StandardCharsets.UTF_8;
+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;
@@ -105,7 +105,7 @@
 
 	@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));
@@ -121,7 +121,7 @@
 		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);
@@ -135,7 +135,7 @@
 		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));
 	}
 
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 93f4709..5780973 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 @@
 			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 @@
 			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));
@@ -240,16 +241,14 @@
 				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/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 @@
 		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 @@
 		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 @@
 
 		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/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 @@
 			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 @@
 		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 @@
 		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 5d9bdbd..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
@@ -93,8 +93,7 @@
 	@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();
@@ -107,8 +106,6 @@
 			assertTrue(file.hasObject(ObjectId.fromString("902d5476fa249b7abc9d84c611577a81381f0327")));
 			assertTrue(file.hasObject(ObjectId.fromString("aabf2ffaec9b497f0950352b3e582d73035c2035")));
 			assertTrue(file.hasObject(ObjectId.fromString("c59759f143fb1fe21c197981df75a7ee00290799")));
-		} finally {
-			is.close();
 		}
 	}
 
@@ -121,8 +118,7 @@
 	@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();
@@ -140,8 +136,6 @@
 			assertTrue(file.hasObject(ObjectId.fromString("20a8ade77639491ea0bd667bf95de8abf3a434c8")));
 			assertTrue(file.hasObject(ObjectId.fromString("2675188fd86978d5bc4d7211698b2118ae3bf658")));
 			// and lots more...
-		} finally {
-			is.close();
 		}
 	}
 
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 @@
 	}
 
 	@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 @@
 		assertEOF();
 	}
 
+	@Test
+	public void testReadString_Delim() throws IOException {
+		init("0001");
+		assertSame(PacketLineIn.DELIM, in.readString());
+		assertEOF();
+	}
+
 	// readStringNoLF
 
 	@Test
@@ -330,7 +326,7 @@
 
 	// 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 @@
 		assertEquals(1, flushCnt[0]);
 	}
 
+	@Test
+	public void testWriteDelim() throws IOException {
+		out.writeDelim();
+		assertBuffer("0001");
+	}
+
 	// writePacket
 
 	@Test
@@ -167,7 +173,7 @@
 		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 c16c1b2..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 @@
 	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 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 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);
@@ -196,4 +213,45 @@
 			}
 		}
 	}
+
+	@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 @@
 			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,
 				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 3836b7d..0ffbe65 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 @@
 		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 @@
 		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 @@
 
 		// 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 @@
 				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 @@
 		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 @@
 		}
 	}
 
-	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/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 @@
 		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 @@
 		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 @@
 		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/UploadPackTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/UploadPackTest.java
index a8127ab..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,22 +1,41 @@
 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;
@@ -170,4 +189,899 @@
 					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 cb04f83..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 java.nio.charset.StandardCharsets.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;
@@ -360,7 +360,7 @@
 		 * @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);
 		}
 
 		/**
@@ -371,7 +371,7 @@
 		 * @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)
@@ -419,12 +419,9 @@
 				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"
@@ -654,9 +651,9 @@
 			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.");
+			}
 		}
 
 		/**
@@ -668,9 +665,9 @@
 		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.");
+			}
 		}
 
 		/**
@@ -741,7 +738,7 @@
 			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);
 		}
 
@@ -836,10 +833,10 @@
 			{
 				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();
 			}
 			{
@@ -1074,10 +1071,10 @@
 				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());
@@ -1089,11 +1086,11 @@
 				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.
@@ -1111,11 +1108,11 @@
 				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();
+				}
 
 			}
 
@@ -1124,9 +1121,9 @@
 				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 @@
 				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 @@
 		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 717a2f3..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
@@ -93,7 +93,7 @@
 	}
 
 	@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 @@
 
 	@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 @@
 		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 @@
 		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 @@
 		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 @@
 		}
 	}
 
-	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 @@
 	}
 
 	@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 @@
 		}
 	}
 
-	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 @@
 		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,
 			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 @@
 
 	@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 @@
 
 	@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 @@
 				"\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 @@
 		}
 	}
 
-	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 @@
 		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 @@
 			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 @@
 		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 a6f3345..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
@@ -54,14 +54,14 @@
 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) {
+	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/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 @@
 		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 0243798..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
@@ -47,18 +47,25 @@
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertNotNull;
 
+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));
 	}
@@ -85,6 +92,13 @@
 	}
 
 	@Test
+	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);
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 e8566d2..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,7 +42,7 @@
  */
 package org.eclipse.jgit.util;
 
-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.assertNotNull;
 
@@ -93,7 +93,7 @@
 	}
 
 	private static RawCharSequence raw(String text) {
-		byte[] bytes = text.getBytes(UTF_8);
+		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 @@
 		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 @@
 
 	@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 @@
 				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 @@
 
 	@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 @@
 				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 @@
 
 	@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 @@
 				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 @@
 
 	@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 @@
 				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 @@
 
 	@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 @@
 				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 @@
 
 	@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 @@
 				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 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 @@
 				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 @@
 
 	@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 @@
 				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 @@
 
 	@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 @@
 				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 @@
 
 	@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 @@
 
 	@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 @@
 				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/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 @@
 		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 38199d8..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,7 +44,7 @@
 
 package org.eclipse.jgit.util.io;
 
-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.ByteArrayInputStream;
@@ -97,38 +97,41 @@
 
 	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) {
-		return in.getBytes(UTF_8);
+		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 @@
 
 	@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 @@
 
 	@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 e6045a9..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,7 +43,7 @@
 
 package org.eclipse.jgit.util.sha1;
 
-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.assertTrue;
 import static org.junit.Assert.fail;
@@ -95,15 +95,15 @@
 				.fromString("a9993e364706816aba3e25717850c26c9cd0d89d");
 
 		MessageDigest m = MessageDigest.getInstance("SHA-1");
-		m.update(TEST1.getBytes(UTF_8));
+		m.update(TEST1.getBytes(CHARSET));
 		ObjectId m1 = ObjectId.fromRaw(m.digest());
 
 		SHA1 s = SHA1.newInstance();
-		s.update(TEST1.getBytes(UTF_8));
+		s.update(TEST1.getBytes(CHARSET));
 		ObjectId s1 = ObjectId.fromRaw(s.digest());
 
 		s.reset();
-		s.update(TEST1.getBytes(UTF_8));
+		s.update(TEST1.getBytes(CHARSET));
 		ObjectId s2 = s.toObjectId();
 
 		assertEquals(m1, s1);
@@ -117,15 +117,15 @@
 				.fromString("84983e441c3bd26ebaae4aa1f95129e5e54670f1");
 
 		MessageDigest m = MessageDigest.getInstance("SHA-1");
-		m.update(TEST2.getBytes(UTF_8));
+		m.update(TEST2.getBytes(CHARSET));
 		ObjectId m1 = ObjectId.fromRaw(m.digest());
 
 		SHA1 s = SHA1.newInstance();
-		s.update(TEST2.getBytes(UTF_8));
+		s.update(TEST2.getBytes(CHARSET));
 		ObjectId s1 = ObjectId.fromRaw(s.digest());
 
 		s.reset();
-		s.update(TEST2.getBytes(UTF_8));
+		s.update(TEST2.getBytes(CHARSET));
 		ObjectId s2 = s.toObjectId();
 
 		assertEquals(m1, s1);
diff --git a/org.eclipse.jgit.ui/META-INF/MANIFEST.MF b/org.eclipse.jgit.ui/META-INF/MANIFEST.MF
index 54a26b9..7667af4 100644
--- a/org.eclipse.jgit.ui/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.ui/META-INF/MANIFEST.MF
@@ -4,14 +4,14 @@
 Bundle-Name: %plugin_name
 Automatic-Module-Name: org.eclipse.jgit.ui
 Bundle-SymbolicName: org.eclipse.jgit.ui
-Bundle-Version: 4.11.8.qualifier
+Bundle-Version: 5.0.4.qualifier
 Bundle-Vendor: %provider_name
 Bundle-RequiredExecutionEnvironment: JavaSE-1.8
-Export-Package: org.eclipse.jgit.awtui;version="4.11.8"
-Import-Package: org.eclipse.jgit.errors;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.lib;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.nls;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.revplot;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.revwalk;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.transport;version="[4.11.8,4.12.0)",
- org.eclipse.jgit.util;version="[4.11.8,4.12.0)"
+Export-Package: org.eclipse.jgit.awtui;version="5.0.4"
+Import-Package: org.eclipse.jgit.errors;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.lib;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.nls;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.revplot;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.revwalk;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.transport;version="[5.0.4,5.1.0)",
+ org.eclipse.jgit.util;version="[5.0.4,5.1.0)"
diff --git a/org.eclipse.jgit.ui/pom.xml b/org.eclipse.jgit.ui/pom.xml
index a072778..7d10c09 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.11.8-SNAPSHOT</version>
+    <version>5.0.4-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 bccf0c0..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 @@
 
 	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();
@@ -125,7 +125,7 @@
 
 	/** {@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());
@@ -134,11 +134,11 @@
 
 	/** {@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;
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 d122a77..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
@@ -114,7 +114,7 @@
 
 	/** {@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);
@@ -161,7 +161,7 @@
 		}
 
 		@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:
@@ -175,7 +175,7 @@
 			}
 		}
 
-		PersonIdent authorFor(final PlotCommit<SwingLane> c) {
+		PersonIdent authorFor(PlotCommit<SwingLane> c) {
 			if (c != lastCommit) {
 				lastCommit = c;
 				lastAuthor = c.getAuthorIdent();
@@ -244,7 +244,7 @@
 		}
 
 		@Override
-		protected void paintComponent(final Graphics inputGraphics) {
+		protected void paintComponent(Graphics inputGraphics) {
 			if (inputGraphics == null)
 				return;
 			renderer.paint(inputGraphics, commit);
@@ -259,7 +259,7 @@
 			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 743eb78..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
@@ -79,7 +79,7 @@
 
 	/** {@inheritDoc} */
 	@Override
-	protected void recycleLane(final SwingLane lane) {
+	protected void recycleLane(SwingLane lane) {
 		colors.add(lane.color);
 	}
 
diff --git a/org.eclipse.jgit/.settings/.api_filters b/org.eclipse.jgit/.settings/.api_filters
index cc0d70d..e6a698d 100644
--- a/org.eclipse.jgit/.settings/.api_filters
+++ b/org.eclipse.jgit/.settings/.api_filters
@@ -3,17 +3,8 @@
     <resource path="META-INF/MANIFEST.MF">
         <filter id="924844039">
             <message_arguments>
-                <message_argument value="4.11.7"/>
-                <message_argument value="4.11.0"/>
-            </message_arguments>
-        </filter>
-    </resource>
-    <resource path="src/org/eclipse/jgit/lib/Constants.java" type="org.eclipse.jgit.lib.Constants">
-        <filter id="1141899266">
-            <message_arguments>
-                <message_argument value="4.7"/>
-                <message_argument value="4.11"/>
-                <message_argument value="LOCK_SUFFIX"/>
+                <message_argument value="5.0.4"/>
+                <message_argument value="5.0.0"/>
             </message_arguments>
         </filter>
     </resource>
@@ -37,7 +28,7 @@
         <filter id="1141899266">
             <message_arguments>
                 <message_argument value="4.7"/>
-                <message_argument value="4.11"/>
+                <message_argument value="5.0"/>
                 <message_argument value="createNewFileAtomic(File)"/>
             </message_arguments>
         </filter>
@@ -52,7 +43,7 @@
         <filter id="1141899266">
             <message_arguments>
                 <message_argument value="4.7"/>
-                <message_argument value="4.11"/>
+                <message_argument value="5.0"/>
                 <message_argument value="LockToken"/>
             </message_arguments>
         </filter>
diff --git a/org.eclipse.jgit/META-INF/MANIFEST.MF b/org.eclipse.jgit/META-INF/MANIFEST.MF
index 2a55d8a..a8114d9 100644
--- a/org.eclipse.jgit/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit/META-INF/MANIFEST.MF
@@ -3,12 +3,12 @@
 Bundle-Name: %plugin_name
 Automatic-Module-Name: org.eclipse.jgit
 Bundle-SymbolicName: org.eclipse.jgit
-Bundle-Version: 4.11.8.qualifier
+Bundle-Version: 5.0.4.qualifier
 Bundle-Localization: plugin
 Bundle-Vendor: %provider_name
 Bundle-ActivationPolicy: lazy
-Export-Package: org.eclipse.jgit.annotations;version="4.11.8",
- org.eclipse.jgit.api;version="4.11.8";
+Export-Package: org.eclipse.jgit.annotations;version="5.0.4",
+ org.eclipse.jgit.api;version="5.0.4";
   uses:="org.eclipse.jgit.revwalk,
    org.eclipse.jgit.treewalk.filter,
    org.eclipse.jgit.diff,
@@ -22,52 +22,52 @@
    org.eclipse.jgit.submodule,
    org.eclipse.jgit.transport,
    org.eclipse.jgit.merge",
- org.eclipse.jgit.api.errors;version="4.11.8";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.errors",
- org.eclipse.jgit.attributes;version="4.11.8",
- org.eclipse.jgit.blame;version="4.11.8";
+ org.eclipse.jgit.api.errors;version="5.0.4";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.errors",
+ org.eclipse.jgit.attributes;version="5.0.4",
+ org.eclipse.jgit.blame;version="5.0.4";
   uses:="org.eclipse.jgit.lib,
    org.eclipse.jgit.revwalk,
    org.eclipse.jgit.treewalk.filter,
    org.eclipse.jgit.diff",
- org.eclipse.jgit.diff;version="4.11.8";
+ org.eclipse.jgit.diff;version="5.0.4";
   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.11.8";
+ org.eclipse.jgit.dircache;version="5.0.4";
   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.11.8";
+ org.eclipse.jgit.errors;version="5.0.4";
   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.11.8";uses:="org.eclipse.jgit.lib",
- org.eclipse.jgit.fnmatch;version="4.11.8",
- org.eclipse.jgit.gitrepo;version="4.11.8";
+ org.eclipse.jgit.events;version="5.0.4";uses:="org.eclipse.jgit.lib",
+ org.eclipse.jgit.fnmatch;version="5.0.4",
+ org.eclipse.jgit.gitrepo;version="5.0.4";
   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.11.8";x-internal:=true,
- org.eclipse.jgit.hooks;version="4.11.8";uses:="org.eclipse.jgit.lib",
- org.eclipse.jgit.ignore;version="4.11.8",
- org.eclipse.jgit.ignore.internal;version="4.11.8";x-friends:="org.eclipse.jgit.test",
- org.eclipse.jgit.internal;version="4.11.8";x-friends:="org.eclipse.jgit.test,org.eclipse.jgit.http.test",
- org.eclipse.jgit.internal.fsck;version="4.11.8";x-friends:="org.eclipse.jgit.test",
- org.eclipse.jgit.internal.ketch;version="4.11.8";x-friends:="org.eclipse.jgit.junit,org.eclipse.jgit.test,org.eclipse.jgit.pgm",
- org.eclipse.jgit.internal.storage.dfs;version="4.11.8";
+ org.eclipse.jgit.gitrepo.internal;version="5.0.4";x-internal:=true,
+ org.eclipse.jgit.hooks;version="5.0.4";uses:="org.eclipse.jgit.lib",
+ org.eclipse.jgit.ignore;version="5.0.4",
+ org.eclipse.jgit.ignore.internal;version="5.0.4";x-friends:="org.eclipse.jgit.test",
+ org.eclipse.jgit.internal;version="5.0.4";x-friends:="org.eclipse.jgit.test,org.eclipse.jgit.http.test",
+ org.eclipse.jgit.internal.fsck;version="5.0.4";x-friends:="org.eclipse.jgit.test",
+ org.eclipse.jgit.internal.ketch;version="5.0.4";x-friends:="org.eclipse.jgit.junit,org.eclipse.jgit.test,org.eclipse.jgit.pgm",
+ org.eclipse.jgit.internal.storage.dfs;version="5.0.4";
   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.11.8";
+ org.eclipse.jgit.internal.storage.file;version="5.0.4";
   x-friends:="org.eclipse.jgit.test,
    org.eclipse.jgit.junit,
    org.eclipse.jgit.junit.http,
@@ -75,12 +75,12 @@
    org.eclipse.jgit.lfs,
    org.eclipse.jgit.pgm,
    org.eclipse.jgit.pgm.test",
- org.eclipse.jgit.internal.storage.io;version="4.11.8";x-friends:="org.eclipse.jgit.junit,org.eclipse.jgit.test,org.eclipse.jgit.pgm",
- org.eclipse.jgit.internal.storage.pack;version="4.11.8";x-friends:="org.eclipse.jgit.junit,org.eclipse.jgit.test,org.eclipse.jgit.pgm",
- org.eclipse.jgit.internal.storage.reftable;version="4.11.8";
+ org.eclipse.jgit.internal.storage.io;version="5.0.4";x-friends:="org.eclipse.jgit.junit,org.eclipse.jgit.test,org.eclipse.jgit.pgm",
+ org.eclipse.jgit.internal.storage.pack;version="5.0.4";x-friends:="org.eclipse.jgit.junit,org.eclipse.jgit.test,org.eclipse.jgit.pgm",
+ org.eclipse.jgit.internal.storage.reftable;version="5.0.4";
   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="4.11.8";x-friends:="org.eclipse.jgit.junit,org.eclipse.jgit.test,org.eclipse.jgit.pgm",
- org.eclipse.jgit.lib;version="4.11.8";
+ org.eclipse.jgit.internal.storage.reftree;version="5.0.4";x-friends:="org.eclipse.jgit.junit,org.eclipse.jgit.test,org.eclipse.jgit.pgm",
+ org.eclipse.jgit.lib;version="5.0.4";
   uses:="org.eclipse.jgit.revwalk,
    org.eclipse.jgit.treewalk.filter,
    org.eclipse.jgit.util,
@@ -90,33 +90,33 @@
    org.eclipse.jgit.treewalk,
    org.eclipse.jgit.transport,
    org.eclipse.jgit.submodule",
- org.eclipse.jgit.lib.internal;version="4.11.8";x-internal:=true,
- org.eclipse.jgit.merge;version="4.11.8";
+ org.eclipse.jgit.lib.internal;version="5.0.4";x-internal:=true,
+ org.eclipse.jgit.merge;version="5.0.4";
   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.11.8",
- org.eclipse.jgit.notes;version="4.11.8";
+ org.eclipse.jgit.nls;version="5.0.4",
+ org.eclipse.jgit.notes;version="5.0.4";
   uses:="org.eclipse.jgit.lib,
    org.eclipse.jgit.treewalk,
    org.eclipse.jgit.revwalk,
    org.eclipse.jgit.merge",
- org.eclipse.jgit.patch;version="4.11.8";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.diff",
- org.eclipse.jgit.revplot;version="4.11.8";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.revwalk",
- org.eclipse.jgit.revwalk;version="4.11.8";
+ org.eclipse.jgit.patch;version="5.0.4";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.diff",
+ org.eclipse.jgit.revplot;version="5.0.4";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.revwalk",
+ org.eclipse.jgit.revwalk;version="5.0.4";
   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.11.8";uses:="org.eclipse.jgit.revwalk,org.eclipse.jgit.lib,org.eclipse.jgit.util",
- org.eclipse.jgit.storage.file;version="4.11.8";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.util",
- org.eclipse.jgit.storage.pack;version="4.11.8";uses:="org.eclipse.jgit.lib",
- org.eclipse.jgit.submodule;version="4.11.8";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.treewalk.filter,org.eclipse.jgit.treewalk",
- org.eclipse.jgit.transport;version="4.11.8";
+ org.eclipse.jgit.revwalk.filter;version="5.0.4";uses:="org.eclipse.jgit.revwalk,org.eclipse.jgit.lib,org.eclipse.jgit.util",
+ org.eclipse.jgit.storage.file;version="5.0.4";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.util",
+ org.eclipse.jgit.storage.pack;version="5.0.4";uses:="org.eclipse.jgit.lib",
+ org.eclipse.jgit.submodule;version="5.0.4";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.treewalk.filter,org.eclipse.jgit.treewalk",
+ org.eclipse.jgit.transport;version="5.0.4";
   uses:="org.eclipse.jgit.transport.resolver,
    org.eclipse.jgit.revwalk,
    org.eclipse.jgit.internal.storage.pack,
@@ -128,24 +128,24 @@
    org.eclipse.jgit.transport.http,
    org.eclipse.jgit.errors,
    org.eclipse.jgit.storage.pack",
- org.eclipse.jgit.transport.http;version="4.11.8";uses:="javax.net.ssl",
- org.eclipse.jgit.transport.resolver;version="4.11.8";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.transport",
- org.eclipse.jgit.treewalk;version="4.11.8";
+ org.eclipse.jgit.transport.http;version="5.0.4";uses:="javax.net.ssl",
+ org.eclipse.jgit.transport.resolver;version="5.0.4";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.transport",
+ org.eclipse.jgit.treewalk;version="5.0.4";
   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.11.8";uses:="org.eclipse.jgit.treewalk",
- org.eclipse.jgit.util;version="4.11.8";
+ org.eclipse.jgit.treewalk.filter;version="5.0.4";uses:="org.eclipse.jgit.treewalk",
+ org.eclipse.jgit.util;version="5.0.4";
   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.11.8",
- org.eclipse.jgit.util.sha1;version="4.11.8",
- org.eclipse.jgit.util.time;version="4.11.8"
+ org.eclipse.jgit.util.io;version="5.0.4",
+ org.eclipse.jgit.util.sha1;version="5.0.4",
+ org.eclipse.jgit.util.time;version="5.0.4"
 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 46a73f8..b2d694a 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.11.8.qualifier
-Eclipse-SourceBundle: org.eclipse.jgit;version="4.11.8.qualifier";roots="."
+Bundle-Version: 5.0.4.qualifier
+Eclipse-SourceBundle: org.eclipse.jgit;version="5.0.4.qualifier";roots="."
diff --git a/org.eclipse.jgit/pom.xml b/org.eclipse.jgit/pom.xml
index f457c38..2b56d0a 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.11.8-SNAPSHOT</version>
+    <version>5.0.4-SNAPSHOT</version>
   </parent>
 
   <artifactId>org.eclipse.jgit</artifactId>
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 815c672..017662d 100644
--- a/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties
+++ b/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties
@@ -226,6 +226,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
@@ -311,6 +313,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.
@@ -362,6 +365,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}''
 invalidGitModules=Invalid .gitmodules file
 invalidGitType=invalid git type: {0}
@@ -398,6 +402,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
@@ -629,6 +634,7 @@
 sourceRefDoesntResolveToAnyObject=Source ref {0} doesn''t resolve to any object.
 sourceRefNotSpecifiedForRefspec=Source ref not specified for refspec: {0}
 squashCommitNotUpdatingHEAD=Squash commit -- not updating HEAD
+sshCommandFailed=Execution of ssh command ''{0}'' failed with error ''{1}''
 sshUserNameError=Jsch error: failed to set SSH user name correctly to ''{0}''; using ''{1}'' picked up from SSH config file.
 sslFailureExceptionMessage=Secure connection to {0} could not be stablished because of SSL problems
 sslFailureInfo=A secure connection to {0}\ncould not be established because the server''s certificate could not be validated.
@@ -673,6 +679,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
@@ -716,6 +723,7 @@
 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}
@@ -730,6 +738,7 @@
 unknownObjectType2=unknown
 unknownRepositoryFormat=Unknown repository format
 unknownRepositoryFormat2=Unknown repository format "{0}"; expected "0".
+unknownTransportCommand=unknown command {0}
 unknownZlibError=Unknown zlib error.
 unlockLockFileFailed=Unlocking LockFile ''{0}'' failed
 unmergedPath=Unmerged path: {0}
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 10397f8..27bb5a9 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/ArchiveCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/ArchiveCommand.java
@@ -157,30 +157,6 @@
 		 *
 		 * @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
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 f45e39e..65b72f7 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/CherryPickCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/CherryPickCommand.java
@@ -288,7 +288,7 @@
 	 * @return {@code this}
 	 * @since 3.1
 	 */
-	public CherryPickCommand setReflogPrefix(final String prefix) {
+	public CherryPickCommand setReflogPrefix(String prefix) {
 		this.reflogPrefix = prefix;
 		return this;
 	}
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 79b0efb..5c06bac 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/CloneCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/CloneCommand.java
@@ -191,12 +191,12 @@
 			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) {
@@ -306,7 +306,7 @@
 		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$
@@ -315,7 +315,7 @@
 			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));
 		}
@@ -386,12 +386,9 @@
 		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();
 					}
 				}
 			}
@@ -413,7 +410,7 @@
 		}
 
 		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;
@@ -443,11 +440,11 @@
 		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;
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 f257283..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;
@@ -238,7 +238,7 @@
 					RevCommit headCommit = rw.parseCommit(headId);
 					headCommit.getTree();
 					if (indexTreeId.equals(headCommit.getTree())) {
-						throw new EmtpyCommitException(
+						throw new EmptyCommitException(
 								JGitText.get().emptyCommit);
 					}
 				}
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 29baf4c..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 @@
 
 	private SetupUpstreamMode upstreamMode;
 
-	private String startPoint = Constants.HEAD;
+	private String startPoint = HEAD;
 
 	private RevCommit startCommit;
 
@@ -121,7 +124,7 @@
 		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));
@@ -153,7 +156,7 @@
 				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)
@@ -171,7 +174,7 @@
 							+ 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;
@@ -279,17 +282,34 @@
 	}
 
 	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
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 5bd932d..a484742 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/DescribeCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/DescribeCommand.java
@@ -107,6 +107,11 @@
 	private List<IMatcher> matchers = new ArrayList<>();
 
 	/**
+	 * Whether to use all tags (incl. lightweight) or not
+	 */
+	private boolean useTags = false;
+
+	/**
 	 * Constructor for DescribeCommand.
 	 *
 	 * @param repo
@@ -176,6 +181,22 @@
 		return this;
 	}
 
+	/**
+	 * Instead of using only the annotated tags, use any tag found in refs/tags
+	 * namespace. This option enables matching lightweight (non-annotated) tags
+	 * or not.
+	 *
+	 * @param tags
+	 *            <code>true</code> enables matching lightweight (non-annotated)
+	 *            tags like setting option --tags in c git
+	 * @return {@code this}
+	 * @since 5.0
+	 */
+	public DescribeCommand setTags(boolean tags) {
+		this.useTags = tags;
+		return this;
+	}
+
 	private String longDescription(Ref tag, int depth, ObjectId tip)
 			throws IOException {
 		return String.format(
@@ -243,12 +264,16 @@
 		}
 	}
 
-	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;
 	}
 
 	/**
@@ -261,12 +286,14 @@
 	public String call() throws GitAPIException {
 		try {
 			checkCallable();
-
-			if (target == null)
+			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()
+					.filter(this::filterLightweightTags)
 					.collect(Collectors.groupingBy(this::getObjectIdFromRef));
 
 			// combined flags of all the candidate instances
@@ -390,4 +417,22 @@
 			w.close();
 		}
 	}
+
+	/**
+	 * Whether we use lightweight tags or not for describe Candidates
+	 *
+	 * @param ref
+	 *            reference under inspection
+	 * @return true if it should be used for describe or not regarding
+	 *         {@link org.eclipse.jgit.api.DescribeCommand#useTags}
+	 */
+	@SuppressWarnings("null")
+	private boolean filterLightweightTags(Ref ref) {
+		ObjectId id = ref.getObjectId();
+		try {
+			return this.useTags || (id != null && (w.parseTag(id) != null));
+		} catch (IOException e) {
+			return false;
+		}
+	}
 }
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 5d178bc..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 @@
 
 	private Callback callback;
 
+	private boolean isForceUpdate;
+
 	/**
 	 * Callback for status of fetch operation.
 	 *
@@ -198,7 +200,8 @@
 								.setTagOpt(tagOption)
 								.setCheckFetchedObjects(checkFetchedObjects)
 								.setRemoveDeletedRefs(isRemoveDeletedRefs())
-								.setThin(thin).setRefSpecs(refSpecs)
+								.setThin(thin)
+								.setRefSpecs(applyOptions(refSpecs))
 								.setDryRun(dryRun)
 								.setRecurseSubmodules(recurseMode);
 						configure(f);
@@ -237,8 +240,8 @@
 				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);
 			}
@@ -261,6 +264,17 @@
 
 	}
 
+	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.
 	 *
@@ -517,4 +531,27 @@
 		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/ListBranchCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/ListBranchCommand.java
index cdae782..28a27a9 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/ListBranchCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/ListBranchCommand.java
@@ -187,6 +187,6 @@
 	}
 
 	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/ListTagCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/ListTagCommand.java
index 9161211..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;
@@ -78,11 +77,11 @@
 	@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 fd6c1fa..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;
@@ -275,10 +272,9 @@
 	 *             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)
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 cd50cae..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 @@
 
 	private String message;
 
+	private boolean insertChangeId;
+
 	private ProgressMonitor monitor = NullProgressMonitor.INSTANCE;
 
 	/**
@@ -253,7 +255,7 @@
 			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();
@@ -392,6 +394,7 @@
 						try (Git git = new Git(getRepository())) {
 							newHeadId = git.commit()
 									.setReflogComment(refLogMessage.toString())
+									.setInsertChangeId(insertChangeId)
 									.call().getId();
 						}
 						mergeStatus = MergeStatus.MERGED;
@@ -619,6 +622,23 @@
 	}
 
 	/**
+	 * 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>
 	 *
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 a9d9759..a2b2007 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/NameRevCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/NameRevCommand.java
@@ -251,8 +251,7 @@
 	 * prefix added by {@link #addPrefix(String)}.
 	 *
 	 * @param prefix
-	 *            prefix to add; see
-	 *            {@link org.eclipse.jgit.lib.RefDatabase#getRefs(String)}
+	 *            prefix to add; the prefix must end with a slash
 	 * @return {@code this}
 	 */
 	public NameRevCommand addPrefix(String prefix) {
@@ -279,7 +278,8 @@
 		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);
@@ -325,7 +325,7 @@
 
 	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/PushCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/PushCommand.java
index 19bdd35..459451f 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/PushCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/PushCommand.java
@@ -153,7 +153,8 @@
 
 			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)
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 da1ff06..98c16b8 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/RebaseCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/RebaseCommand.java
@@ -1734,23 +1734,17 @@
 				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/RemoteAddCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/RemoteAddCommand.java
index c43c5c6..a8fdcd2 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/RemoteAddCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/RemoteAddCommand.java
@@ -86,9 +86,12 @@
 	 *
 	 * @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;
 	}
 
 	/**
@@ -96,9 +99,12 @@
 	 *
 	 * @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;
 	}
 
 	/**
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 be446f9..13ce4e7 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/ResetCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/ResetCommand.java
@@ -245,7 +245,7 @@
 		}
 	}
 
-	private RevCommit parseCommit(final ObjectId commitId) {
+	private RevCommit parseCommit(ObjectId commitId) {
 		try (RevWalk rw = new RevWalk(repo)) {
 			return rw.parseCommit(commitId);
 		} catch (IOException e) {
@@ -360,7 +360,7 @@
 
 	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();
 
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 088aa15..d2f4be8 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/RmCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/RmCommand.java
@@ -154,7 +154,7 @@
 		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/StashApplyCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/StashApplyCommand.java
index 5f7928d..01d070c 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/StashApplyCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/StashApplyCommand.java
@@ -111,7 +111,7 @@
 	 *            the {@link org.eclipse.jgit.lib.Repository} to apply the stash
 	 *            to
 	 */
-	public StashApplyCommand(final Repository repo) {
+	public StashApplyCommand(Repository repo) {
 		super(repo);
 	}
 
@@ -125,7 +125,7 @@
 	 *            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;
 	}
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 3495ff8..c32890d 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/StashCreateCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/StashCreateCommand.java
@@ -195,7 +195,7 @@
 
 	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);
 		}
 	}
@@ -303,12 +303,9 @@
 						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 cd8f8e6..7f02aab 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/StashDropCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/StashDropCommand.java
@@ -107,7 +107,7 @@
 	 *            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();
 
@@ -124,7 +124,7 @@
 	 *            {@link #setStashRef(int)}
 	 * @return {@code this}
 	 */
-	public StashDropCommand setAll(final boolean all) {
+	public StashDropCommand setAll(boolean all) {
 		this.all = all;
 		return this;
 	}
@@ -138,7 +138,7 @@
 		}
 	}
 
-	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());
@@ -146,7 +146,7 @@
 		return update;
 	}
 
-	private void deleteRef(final Ref stashRef) {
+	private void deleteRef(Ref stashRef) {
 		try {
 			Result result = createRefUpdate(stashRef).delete();
 			if (Result.FORCED != result)
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 6451b70..f316b23 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/StashListCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/StashListCommand.java
@@ -72,7 +72,7 @@
 	 *
 	 * @param repo a {@link org.eclipse.jgit.lib.Repository} object.
 	 */
-	public StashListCommand(final Repository repo) {
+	public StashListCommand(Repository repo) {
 		super(repo);
 	}
 
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 81ea350..9d9626f 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleAddCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleAddCommand.java
@@ -89,7 +89,7 @@
 	 * @param repo
 	 *            a {@link org.eclipse.jgit.lib.Repository} object.
 	 */
-	public SubmoduleAddCommand(final Repository repo) {
+	public SubmoduleAddCommand(Repository repo) {
 		super(repo);
 	}
 
@@ -100,7 +100,7 @@
 	 *            (with <code>/</code> as separator)
 	 * @return this command
 	 */
-	public SubmoduleAddCommand setPath(final String path) {
+	public SubmoduleAddCommand setPath(String path) {
 		this.path = path;
 		return this;
 	}
@@ -112,7 +112,7 @@
 	 *            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;
 	}
@@ -126,7 +126,7 @@
 	 *            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;
 	}
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 6af27d7..2db12b8 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleInitCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleInitCommand.java
@@ -77,7 +77,7 @@
 	 * @param repo
 	 *            a {@link org.eclipse.jgit.lib.Repository} object.
 	 */
-	public SubmoduleInitCommand(final Repository repo) {
+	public SubmoduleInitCommand(Repository repo) {
 		super(repo);
 		paths = new ArrayList<>();
 	}
@@ -89,7 +89,7 @@
 	 *            (with <code>/</code> as separator)
 	 * @return this command
 	 */
-	public SubmoduleInitCommand addPath(final String path) {
+	public SubmoduleInitCommand addPath(String path) {
 		paths.add(path);
 		return this;
 	}
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 97ae668..0606c5b 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleStatusCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleStatusCommand.java
@@ -77,7 +77,7 @@
 	 * @param repo
 	 *            a {@link org.eclipse.jgit.lib.Repository} object.
 	 */
-	public SubmoduleStatusCommand(final Repository repo) {
+	public SubmoduleStatusCommand(Repository repo) {
 		super(repo);
 		paths = new ArrayList<>();
 	}
@@ -89,7 +89,7 @@
 	 *            (with <code>/</code> as separator)
 	 * @return this command
 	 */
-	public SubmoduleStatusCommand addPath(final String path) {
+	public SubmoduleStatusCommand addPath(String path) {
 		paths.add(path);
 		return this;
 	}
@@ -130,16 +130,14 @@
 					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 d22d820..7cf4b73 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleSyncCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleSyncCommand.java
@@ -79,7 +79,7 @@
 	 * @param repo
 	 *            a {@link org.eclipse.jgit.lib.Repository} object.
 	 */
-	public SubmoduleSyncCommand(final Repository repo) {
+	public SubmoduleSyncCommand(Repository repo) {
 		super(repo);
 		paths = new ArrayList<>();
 	}
@@ -91,7 +91,7 @@
 	 *            (with <code>/</code> as separator)
 	 * @return this command
 	 */
-	public SubmoduleSyncCommand addPath(final String path) {
+	public SubmoduleSyncCommand addPath(String path) {
 		paths.add(path);
 		return this;
 	}
@@ -104,7 +104,7 @@
 	 * @return shortened branch name, null on failures
 	 * @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());
@@ -132,30 +132,31 @@
 						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 3362d46..398f21e 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleUpdateCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleUpdateCommand.java
@@ -103,7 +103,7 @@
 	 * @param repo
 	 *            a {@link org.eclipse.jgit.lib.Repository} object.
 	 */
-	public SubmoduleUpdateCommand(final Repository repo) {
+	public SubmoduleUpdateCommand(Repository repo) {
 		super(repo);
 		paths = new ArrayList<>();
 	}
@@ -132,7 +132,7 @@
 	 * @return this command
 	 * @since 4.9
 	 */
-	public SubmoduleUpdateCommand setFetch(final boolean fetch) {
+	public SubmoduleUpdateCommand setFetch(boolean fetch) {
 		this.fetch = fetch;
 		return this;
 	}
@@ -144,11 +144,43 @@
 	 *            (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;
+	}
+
 	/**
 	 * {@inheritDoc}
 	 *
@@ -175,34 +207,8 @@
 				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());
 
@@ -237,8 +243,6 @@
 									generator.getPath());
 						}
 					}
-				} finally {
-					submoduleRepo.close();
 				}
 				updated.add(generator.getPath());
 			}
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 9c91537..d34bb5d 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/TransportCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/TransportCommand.java
@@ -80,7 +80,7 @@
 	 *
 	 * @param repo a {@link org.eclipse.jgit.lib.Repository} object.
 	 */
-	protected TransportCommand(final Repository repo) {
+	protected TransportCommand(Repository repo) {
 		super(repo);
 		setCredentialsProvider(CredentialsProvider.getDefault());
 	}
@@ -147,7 +147,7 @@
 	 *            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);
@@ -164,7 +164,7 @@
 	 *            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/errors/AbortedByHookException.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/AbortedByHookException.java
old mode 100755
new mode 100644
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 88%
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 ea0e718..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,30 +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 { // TODO: Correct spelling of this class name in 5.0
+public class EmptyCommitException extends GitAPIException {
 	private static final long serialVersionUID = 1L;
 
 	/**
-	 * Constructor for EmtpyCommitException
+	 * 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 EmtpyCommitException.
+	 * 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/StashApplyFailureException.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/StashApplyFailureException.java
index 517b512..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
@@ -26,7 +26,7 @@
 	 * @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/blame/ReverseWalk.java b/org.eclipse.jgit/src/org/eclipse/jgit/blame/ReverseWalk.java
index 2eb313f..1067378 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/blame/ReverseWalk.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/blame/ReverseWalk.java
@@ -108,7 +108,7 @@
 			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/DiffConfig.java b/org.eclipse.jgit/src/org/eclipse/jgit/diff/DiffConfig.java
index 063ceff..21dca6b 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/diff/DiffConfig.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/diff/DiffConfig.java
@@ -76,7 +76,7 @@
 
 	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(
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 2e29b81..7aaa500 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/diff/DiffFormatter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/diff/DiffFormatter.java
@@ -222,7 +222,7 @@
 	 *            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);
@@ -235,7 +235,7 @@
 	 * @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);
@@ -742,7 +742,7 @@
 	 * @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
@@ -768,7 +768,7 @@
 	 *            the text B which was compared
 	 * @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);
@@ -816,12 +816,12 @@
 	 *            the line number within text
 	 * @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();
 	}
 
@@ -834,7 +834,7 @@
 	 *            the line number within text
 	 * @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);
 	}
@@ -848,7 +848,7 @@
 	 *            the line number within text
 	 * @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);
 	}
@@ -878,7 +878,7 @@
 		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);
@@ -1213,7 +1213,7 @@
 		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)))
@@ -1221,15 +1221,15 @@
 		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 775d11a..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 @@
 	 * @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 @@
 	 * @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;
 
@@ -279,7 +279,7 @@
 
 	/** {@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
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 @@
 		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 @@
 		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/MyersDiff.java b/org.eclipse.jgit/src/org/eclipse/jgit/diff/MyersDiff.java
index 646f264..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 @@
 			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 @@
 			}
 
 			@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 @@
 			}
 
 			@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;
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 ec88ce4..bd41d90 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/diff/RawText.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/diff/RawText.java
@@ -88,12 +88,29 @@
 	 * 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;
 	}
 
 	/**
@@ -147,7 +164,7 @@
 	 * @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);
@@ -221,11 +238,11 @@
 		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);
 	}
 
@@ -325,7 +342,8 @@
 	 * @throws java.io.IOException
 	 *             if the input could not be read.
 	 */
-	public static RawText load(ObjectLoader ldr, int threshold) throws IOException, BinaryBlobException {
+	public static RawText load(ObjectLoader ldr, int threshold)
+			throws IOException, BinaryBlobException {
 		long sz = ldr.getSize();
 
 		if (sz > threshold) {
@@ -369,7 +387,7 @@
 
 			System.arraycopy(head, 0, data, 0, head.length);
 			IO.readFully(stream, data, off, (int) (sz-off));
-			return new RawText(data);
+			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 ed2eebb..1e68c2f 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/diff/RawTextComparator.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/diff/RawTextComparator.java
@@ -77,7 +77,7 @@
 		}
 
 		@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);
@@ -164,7 +164,7 @@
 		}
 
 		@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++)
@@ -199,7 +199,7 @@
 		}
 
 		@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++)
@@ -244,7 +244,7 @@
 		}
 
 		@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) {
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 8b4d2ec..5897ffb 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/diff/SimilarityIndex.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/diff/SimilarityIndex.java
@@ -147,23 +147,17 @@
 
 	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/dircache/BaseDirCacheEditor.java b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/BaseDirCacheEditor.java
index 0228f4d..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,7 +85,7 @@
 	 *            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];
 	}
@@ -111,7 +111,7 @@
 	 * @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);
@@ -140,7 +140,7 @@
 	 * @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;
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 cc431db..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 @@
 
 	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 @@
 		}
 	};
 
-	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);
 	}
 
@@ -188,7 +189,7 @@
 	 *             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;
@@ -215,7 +216,7 @@
 	 *             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();
@@ -244,7 +245,7 @@
 	 *             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())
@@ -372,7 +373,7 @@
 	 *            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();
 	}
@@ -403,7 +404,7 @@
 		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;
@@ -429,18 +430,10 @@
 		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
@@ -480,7 +473,7 @@
 		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();
@@ -588,12 +581,11 @@
 		}
 	}
 
-	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++)
@@ -656,7 +648,7 @@
 		}
 	}
 
-	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);
 
@@ -710,6 +702,8 @@
 		}
 
 		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);
@@ -743,16 +737,18 @@
 		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)
@@ -783,7 +779,7 @@
 	 *         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);
 	}
@@ -839,7 +835,7 @@
 	 *            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) {
@@ -852,7 +848,7 @@
 		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))
@@ -886,7 +882,7 @@
 	 *            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];
 	}
 
@@ -897,7 +893,7 @@
 	 *            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];
 	}
@@ -946,7 +942,7 @@
 	 * @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();
@@ -972,7 +968,7 @@
 	 * @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 6e3682a..e80544e 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheBuildIterator.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheBuildIterator.java
@@ -96,7 +96,7 @@
 	 *            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;
 	}
@@ -109,7 +109,7 @@
 
 	/** {@inheritDoc} */
 	@Override
-	public AbstractTreeIterator createSubtreeIterator(final ObjectReader reader)
+	public AbstractTreeIterator createSubtreeIterator(ObjectReader reader)
 			throws IncorrectObjectTypeException, IOException {
 		if (currentSubtree == null)
 			throw new IncorrectObjectTypeException(getEntryObjectId(),
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 2ff7bb9..c5ff9ac 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheBuilder.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheBuilder.java
@@ -83,7 +83,7 @@
 	 *            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);
 	}
 
@@ -102,7 +102,7 @@
 	 * @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,
@@ -131,7 +131,7 @@
 	 * @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);
 	}
@@ -227,7 +227,7 @@
 		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/DirCacheEditor.java b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheEditor.java
index 30e3a3c..74ba97f 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheEditor.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheEditor.java
@@ -77,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);
@@ -96,7 +96,7 @@
 	 *            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<>();
 	}
@@ -111,7 +111,7 @@
 	 * @param edit
 	 *            another edit command.
 	 */
-	public void add(final PathEdit edit) {
+	public void add(PathEdit edit) {
 		edits.add(edit);
 	}
 
@@ -304,7 +304,7 @@
 		 * @param entryPath
 		 *            path of the file within the repository.
 		 */
-		public PathEdit(final String entryPath) {
+		public PathEdit(String entryPath) {
 			path = Constants.encode(entryPath);
 		}
 
@@ -319,7 +319,7 @@
 		 *            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;
 		}
 
@@ -374,7 +374,7 @@
 		 * @param entryPath
 		 *            path of the file within the repository.
 		 */
-		public DeletePath(final String entryPath) {
+		public DeletePath(String entryPath) {
 			super(entryPath);
 		}
 
@@ -385,12 +385,12 @@
 		 *            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);
 		}
 	}
@@ -440,7 +440,7 @@
 		}
 
 		@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 7c03c64..fee9f51 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheEntry.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheEntry.java
@@ -227,7 +227,7 @@
 	 *             "\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);
 	}
 
@@ -244,7 +244,7 @@
 	 *             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);
 	}
 
@@ -258,7 +258,7 @@
 	 *             "\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);
 	}
 
@@ -276,7 +276,7 @@
 	 *             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(
@@ -312,7 +312,7 @@
 		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);
@@ -343,7 +343,7 @@
 	 *            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
@@ -420,7 +420,7 @@
 	 *            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
@@ -518,7 +518,7 @@
 	 *             {@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:
@@ -548,7 +548,7 @@
 	 * @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);
 	}
 
@@ -572,7 +572,7 @@
 	 * @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);
 	}
 
@@ -604,7 +604,7 @@
 	 *            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);
 	}
 
@@ -614,7 +614,7 @@
 	 * @param sz
 	 *            new cached size of the file, as bytes.
 	 */
-	public void setLength(final long sz) {
+	public void setLength(long sz) {
 		setLength((int) sz);
 	}
 
@@ -638,7 +638,7 @@
 	 *            {@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());
 	}
 
@@ -651,7 +651,7 @@
 	 * @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);
 	}
@@ -704,7 +704,7 @@
 	 * @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);
 	}
 
@@ -719,7 +719,7 @@
 	 * @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);
@@ -741,14 +741,14 @@
 		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);
@@ -771,7 +771,7 @@
 		}
 	}
 
-	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 d768216..19c916f 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheIterator.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheIterator.java
@@ -114,7 +114,7 @@
 	 * @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;
@@ -124,7 +124,7 @@
 			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;
@@ -137,7 +137,7 @@
 
 	/** {@inheritDoc} */
 	@Override
-	public AbstractTreeIterator createSubtreeIterator(final ObjectReader reader)
+	public AbstractTreeIterator createSubtreeIterator(ObjectReader reader)
 			throws IncorrectObjectTypeException, IOException {
 		if (currentSubtree == null)
 			throw new IncorrectObjectTypeException(getEntryObjectId(),
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 dc825d4..b605f3c 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheTree.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheTree.java
@@ -82,7 +82,7 @@
 
 	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;
@@ -185,7 +185,7 @@
 		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);
@@ -248,7 +248,7 @@
 	 *            index of the child to obtain.
 	 * @return the child tree.
 	 */
-	public DirCacheTree getChild(final int i) {
+	public DirCacheTree getChild(int i) {
 		return children[i];
 	}
 
@@ -389,7 +389,7 @@
 		return size;
 	}
 
-	private void appendName(final StringBuilder r) {
+	private void appendName(StringBuilder r) {
 		if (parent != null) {
 			parent.appendName(r);
 			r.append(getNameString());
@@ -404,7 +404,7 @@
 		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++)
@@ -503,7 +503,7 @@
 			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)
@@ -524,14 +524,14 @@
 		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--)
@@ -540,7 +540,7 @@
 		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;
@@ -557,7 +557,7 @@
 		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] == '/')
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 62ff990..1df70e3 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/errors/CompoundException.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/errors/CompoundException.java
@@ -56,10 +56,10 @@
 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$
@@ -75,7 +75,7 @@
 	 * @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 a7e1d02..24f43cf 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/errors/ConfigInvalidException.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/errors/ConfigInvalidException.java
@@ -55,7 +55,7 @@
 	 * @param message
 	 *            why the configuration is invalid.
 	 */
-	public ConfigInvalidException(final String message) {
+	public ConfigInvalidException(String message) {
 		super(message);
 	}
 
@@ -67,7 +67,7 @@
 	 * @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/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 @@
 	 *
 	 * @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 a647121..785cb95 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/errors/IllegalTodoFileModification.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/errors/IllegalTodoFileModification.java
@@ -56,7 +56,7 @@
 	 * @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 @@
 	 * @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 @@
 	 * @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 @@
 	 * @param s
 	 *            message
 	 */
-	public IndexReadException(final String s) {
+	public IndexReadException(String s) {
 		super(s);
 	}
 
@@ -75,7 +75,7 @@
 	 * @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 @@
 	 *
 	 * @param s message
 	 */
-	public IndexWriteException(final String s) {
+	public IndexWriteException(String s) {
 		super(s);
 	}
 
@@ -70,7 +70,7 @@
 	 * @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/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 f6aa092..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 @@
 	 * @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 @@
 	 * @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,7 +94,7 @@
 	 * @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;
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 @@
 	 * @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 @@
 	 * @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/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 @@
 	 *
 	 * @param s message describing the issue
 	 */
-	public NotSupportedException(final String s) {
+	public NotSupportedException(String s) {
 		super(s);
 	}
 
@@ -70,7 +70,7 @@
 	 * @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 @@
 	 *
 	 * @param s message
 	 */
-	public ObjectWritingException(final String s) {
+	public ObjectWritingException(String s) {
 		super(s);
 	}
 
@@ -68,7 +68,7 @@
 	 * @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 9886e15..a83de06 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/errors/PackInvalidException.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/errors/PackInvalidException.java
@@ -61,7 +61,7 @@
 	 * @param path
 	 *            path of the invalid pack file.
 	 */
-	public PackInvalidException(final File path) {
+	public PackInvalidException(File path) {
 		this(path.getAbsolutePath());
 	}
 
@@ -71,7 +71,7 @@
 	 * @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 5b9a4b9..ea1e65b 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/errors/PackMismatchException.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/errors/PackMismatchException.java
@@ -57,7 +57,7 @@
 	 * @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 @@
 	 * @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 @@
 	 * @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 @@
 	 * @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 aabb46a..04fd8ea 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/errors/RepositoryNotFoundException.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/errors/RepositoryNotFoundException.java
@@ -60,7 +60,7 @@
 	 * @param location
 	 *            description of the repository not found, usually file path.
 	 */
-	public RepositoryNotFoundException(final File location) {
+	public RepositoryNotFoundException(File location) {
 		this(location.getPath());
 	}
 
@@ -72,7 +72,7 @@
 	 * @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);
 	}
 
@@ -82,7 +82,7 @@
 	 * @param location
 	 *            description of the repository not found, usually file path.
 	 */
-	public RepositoryNotFoundException(final String location) {
+	public RepositoryNotFoundException(String location) {
 		super(message(location));
 	}
 
@@ -98,7 +98,7 @@
 		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 82654e8..f6852b5 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/errors/RevWalkException.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/errors/RevWalkException.java
@@ -65,7 +65,7 @@
 	 * @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/StoredObjectRepresentationNotAvailableException.java b/org.eclipse.jgit/src/org/eclipse/jgit/errors/StoredObjectRepresentationNotAvailableException.java
index 8fa14c7..611fd66 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/errors/StoredObjectRepresentationNotAvailableException.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/errors/StoredObjectRepresentationNotAvailableException.java
@@ -56,21 +56,6 @@
 	 *
 	 * @param otp
 	 *            the object whose current representation is no longer present.
-	 * @deprecated use
-	 *             {@link #StoredObjectRepresentationNotAvailableException(ObjectToPack, Throwable)}
-	 *             instead.
-	 * @since 3.0
-	 */
-	@Deprecated
-	public StoredObjectRepresentationNotAvailableException(ObjectToPack otp) {
-		// Do nothing.
-	}
-
-	/**
-	 * Construct an error for an object.
-	 *
-	 * @param otp
-	 *            the object whose current representation is no longer present.
 	 * @param cause
 	 *            cause
 	 * @since 4.10
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 @@
 	 *
 	 * @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/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 @@
 	 * @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 @@
 	 * @param s
 	 *            message
 	 */
-	public TransportException(final String s) {
+	public TransportException(String s) {
 		super(s);
 	}
 
@@ -102,7 +102,7 @@
 	 * @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 4fc534b..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,7 +63,7 @@
 	 * @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;
 	}
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 88c2ef6..9bab687 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/errors/UnsupportedCredentialItem.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/errors/UnsupportedCredentialItem.java
@@ -62,7 +62,7 @@
 	 * @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 @@
 	 * @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 @@
 	 * @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/IndexChangedEvent.java b/org.eclipse.jgit/src/org/eclipse/jgit/events/IndexChangedEvent.java
index 647ec8a..dcce86a 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/events/IndexChangedEvent.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/events/IndexChangedEvent.java
@@ -47,6 +47,28 @@
  * 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() {
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 98aee0e..7039c3d 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/fnmatch/CharacterHead.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/fnmatch/CharacterHead.java
@@ -53,14 +53,14 @@
 	 * @param expectedCharacter
 	 *            expected {@code char}
 	 */
-	protected CharacterHead(final char expectedCharacter) {
+	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;
 	}
 
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 5663039..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 @@
 	 * @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);
 	}
 
@@ -315,7 +315,7 @@
 	 * @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;
@@ -357,7 +357,7 @@
 	 *            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))
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 965d900..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 @@
 
 	private final boolean inverse;
 
-	GroupHead(String pattern, final String wholePattern)
+	GroupHead(String pattern, String wholePattern)
 			throws InvalidPatternException {
 		super(false);
 		this.characterClasses = new ArrayList<>();
@@ -132,7 +132,7 @@
 
 	/** {@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;
@@ -214,7 +214,7 @@
 	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/RestrictedWildCardHead.java b/org.eclipse.jgit/src/org/eclipse/jgit/fnmatch/RestrictedWildCardHead.java
index c132e28..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,14 +47,14 @@
 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;
 	}
 
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 c806e23..07362aa 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/fnmatch/WildCardHead.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/fnmatch/WildCardHead.java
@@ -51,7 +51,7 @@
 
 	/** {@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/RepoCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoCommand.java
index 8b8df87..80fd3cf 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoCommand.java
@@ -413,7 +413,7 @@
 	 *            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;
 	}
@@ -448,7 +448,7 @@
 	 *            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;
 	}
@@ -463,7 +463,7 @@
 	 *            object.
 	 * @return this command
 	 */
-	public RepoCommand setRemoteReader(final RemoteReader callback) {
+	public RepoCommand setRemoteReader(RemoteReader callback) {
 		this.callback = callback;
 		return this;
 	}
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 e827612..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 @@
 			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());
 			}
 		}
 	}
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 ad43e2c..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;
@@ -158,7 +158,7 @@
 		PrintStream hookErrRedirect = null;
 		try {
 			hookErrRedirect = new PrintStream(errorByteArray, false,
-					UTF_8.name());
+					CHARSET.name());
 		} catch (UnsupportedEncodingException e) {
 			// UTF-8 is guaranteed to be available
 		}
@@ -167,7 +167,7 @@
 				hookErrRedirect, getStdinArgs());
 		if (result.isExecutedWithError()) {
 			throw new AbortedByHookException(
-					new String(errorByteArray.toByteArray(), UTF_8),
+					new String(errorByteArray.toByteArray(), CHARSET),
 					getHookName(), result.getExitCode());
 		}
 	}
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 79395ed..b801d68 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/hooks/Hooks.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/hooks/Hooks.java
@@ -115,7 +115,11 @@
 					outputStream);
 			if (hook != null) {
 				if (hook.isNativeHookPresent()) {
-					throw new IllegalStateException(MessageFormat
+					PrintStream ps = outputStream;
+					if (ps == null) {
+						ps = System.out;
+					}
+					ps.println(MessageFormat
 							.format(JGitText.get().lfsHookConflict, repo));
 				}
 				return hook;
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 1224df4..d570fde 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/ignore/IgnoreNode.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/ignore/IgnoreNode.java
@@ -163,35 +163,6 @@
 	 *            (uses '/' and not '\').
 	 * @param isDirectory
 	 *            true if the target item is a directory.
-	 * @param negateFirstMatch
-	 *            true if the first match should be negated
-	 * @deprecated negateFirstMatch is not honored anymore
-	 * @return status of the path.
-	 * @since 3.6
-	 */
-	@Deprecated
-	public MatchResult isIgnored(String entryPath, boolean isDirectory,
-			boolean negateFirstMatch) {
-		final Boolean result = checkIgnored(entryPath, isDirectory);
-		if (result == null) {
-			return negateFirstMatch
-					? MatchResult.CHECK_PARENT_NEGATE_FIRST_MATCH
-					: MatchResult.CHECK_PARENT;
-		}
-
-		return result.booleanValue() ? MatchResult.IGNORED
-				: MatchResult.NOT_IGNORED;
-	}
-
-	/**
-	 * Determine if an entry path matches an ignore rule.
-	 *
-	 * @param entryPath
-	 *            the path to test. The path must be relative to this ignore
-	 *            node's own repository path, and in repository path format
-	 *            (uses '/' and not '\').
-	 * @param isDirectory
-	 *            true if the target item is a directory.
 	 * @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
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 120d6ad..d2f6232 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java
@@ -287,6 +287,8 @@
 	/***/ public String credentialUsername;
 	/***/ public String daemonAlreadyRunning;
 	/***/ public String daysAgo;
+	/***/ public String deepenNotWithDeepen;
+	/***/ public String deepenSinceWithDeepen;
 	/***/ public String deleteBranchUnexpectedResult;
 	/***/ public String deleteFileFailed;
 	/***/ public String deleteRequiresZeroNewId;
@@ -372,6 +374,7 @@
 	/***/ public String fileModeNotSetForPath;
 	/***/ public String filterExecutionFailed;
 	/***/ public String filterExecutionFailedRc;
+	/***/ public String filterRequiresCapability;
 	/***/ public String findingGarbage;
 	/***/ public String flagIsDisposed;
 	/***/ public String flagNotFromThis;
@@ -423,6 +426,7 @@
 	/***/ public String invalidDepth;
 	/***/ public String invalidEncryption;
 	/***/ public String invalidExpandWildcard;
+	/***/ public String invalidFilter;
 	/***/ public String invalidGitdirRef;
 	/***/ public String invalidGitModules;
 	/***/ public String invalidGitType;
@@ -458,6 +462,7 @@
 	/***/ public String invalidSystemProperty;
 	/***/ public String invalidTagOption;
 	/***/ public String invalidTimeout;
+	/***/ public String invalidTimestamp;
 	/***/ public String invalidTimeUnitValue2;
 	/***/ public String invalidTimeUnitValue3;
 	/***/ public String invalidTreeZeroLengthName;
@@ -690,6 +695,7 @@
 	/***/ public String sourceRefDoesntResolveToAnyObject;
 	/***/ public String sourceRefNotSpecifiedForRefspec;
 	/***/ public String squashCommitNotUpdatingHEAD;
+	/***/ public String sshCommandFailed;
 	/***/ public String sshUserNameError;
 	/***/ public String sslFailureExceptionMessage;
 	/***/ public String sslFailureInfo;
@@ -735,6 +741,7 @@
 	/***/ public String timeIsUncertain;
 	/***/ public String timerAlreadyTerminated;
 	/***/ public String tooManyCommands;
+	/***/ public String tooManyFilters;
 	/***/ public String tooManyIncludeRecursions;
 	/***/ public String topologicalSortRequired;
 	/***/ public String transportExceptionBadRef;
@@ -777,6 +784,7 @@
 	/***/ public String unexpectedEofInPack;
 	/***/ public String unexpectedHunkTrailer;
 	/***/ public String unexpectedOddResult;
+	/***/ public String unexpectedPacketLine;
 	/***/ public String unexpectedRefReport;
 	/***/ public String unexpectedReportLine;
 	/***/ public String unexpectedReportLine2;
@@ -791,6 +799,7 @@
 	/***/ public String unknownObjectType2;
 	/***/ public String unknownRepositoryFormat;
 	/***/ public String unknownRepositoryFormat2;
+	/***/ public String unknownTransportCommand;
 	/***/ public String unknownZlibError;
 	/***/ public String unlockLockFileFailed;
 	/***/ public String unmergedPath;
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 1908d6c..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
@@ -260,7 +260,7 @@
 	 * @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
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 9c37a90..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
@@ -122,7 +122,7 @@
 
 	/** {@inheritDoc} */
 	@Override
-	protected void startPush(final ReplicaPushRequest req) {
+	protected void startPush(ReplicaPushRequest req) {
 		getSystem().getExecutor().execute(new Runnable() {
 			@Override
 			public void run() {
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 674da1f..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
@@ -138,7 +138,7 @@
 
 	/** {@inheritDoc} */
 	@Override
-	protected void startPush(final ReplicaPushRequest req) {
+	protected void startPush(ReplicaPushRequest req) {
 		getSystem().getExecutor().execute(new Runnable() {
 			@Override
 			public void run() {
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 14dc80f..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
@@ -181,7 +181,7 @@
 	private Ref clockHand;
 
 	@SuppressWarnings("unchecked")
-	private DfsBlockCache(final DfsBlockCacheConfig cfg) {
+	private DfsBlockCache(DfsBlockCacheConfig cfg) {
 		tableSize = tableSize(cfg);
 		if (tableSize < 1)
 			throw new IllegalArgumentException(JGitText.get().tSizeMustBeGreaterOrEqual1);
@@ -330,7 +330,7 @@
 		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)
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 cd7901b..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
@@ -106,7 +106,7 @@
 	 *            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,
@@ -135,7 +135,7 @@
 	 *            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(
@@ -206,7 +206,7 @@
 	 *            configuration to read properties from.
 	 * @return {@code this}
 	 */
-	public DfsBlockCacheConfig fromConfig(final Config rc) {
+	public DfsBlockCacheConfig fromConfig(Config rc) {
 		long cfgBlockLimit = rc.getLong(
 				CONFIG_CORE_SECTION,
 				CONFIG_DFS_SECTION,
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 69989a4..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
@@ -403,7 +403,7 @@
 	}
 
 	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());
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 eb0a527..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;
@@ -309,6 +310,15 @@
 		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);
@@ -317,27 +327,20 @@
 		// 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;
 	}
@@ -403,7 +406,7 @@
 		}
 
 		@Override
-		public void write(final int b) throws IOException {
+		public void write(int b) throws IOException {
 			hdrBuf[0] = (byte) b;
 			write(hdrBuf, 0, 1);
 		}
@@ -666,6 +669,7 @@
 
 		@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 42b1a47..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
@@ -497,7 +497,7 @@
 		} while (!packList.compareAndSet(o, n));
 	}
 
-	PackList scanPacks(final PackList original) throws IOException {
+	PackList scanPacks(PackList original) throws IOException {
 		PackList o, n;
 		synchronized (packList) {
 			do {
@@ -546,7 +546,7 @@
 			}
 		}
 
-		if (newPacks.isEmpty())
+		if (newPacks.isEmpty() && newReftables.isEmpty())
 			return new PackListImpl(NO_PACKS.packs, NO_PACKS.reftables);
 		if (!foundNew) {
 			old.clearDirty();
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 3a04d70..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 @@
 	/** Length of the data section of the object. */
 	long length;
 
-	DfsObjectToPack(AnyObjectId src, final int type) {
+	DfsObjectToPack(AnyObjectId src, int type) {
 		super(src, type);
 	}
 
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 ab76332..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
@@ -268,8 +268,7 @@
 		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);
 
@@ -285,8 +284,6 @@
 				writeIndex(objdb, outDesc, pw);
 
 				PackStatistics stats = pw.getStatistics();
-				pw.close();
-				pw = null;
 
 				outDesc.setPackStats(stats);
 				newStats = stats;
@@ -296,10 +293,6 @@
 					objdb.rollbackPack(Collections.singletonList(outDesc));
 				}
 			}
-		} finally {
-			if (pw != null) {
-				pw.close();
-			}
 		}
 	}
 
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 7e36042..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
@@ -209,8 +209,7 @@
 			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();
@@ -221,7 +220,6 @@
 					idx = PackIndex.read(new BufferedInputStream(in, bs));
 					ctx.stats.readIdxBytes += rc.position();
 				} finally {
-					rc.close();
 					ctx.stats.readIdxMicros += elapsedMicros(start);
 				}
 			} catch (EOFException e) {
@@ -276,10 +274,9 @@
 
 			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;
@@ -293,7 +290,6 @@
 							in, idx(ctx), getReverseIdx(ctx));
 				} finally {
 					size = rc.position();
-					rc.close();
 					ctx.stats.readIdxBytes += size;
 					ctx.stats.readIdxMicros += elapsedMicros(start);
 				}
@@ -443,6 +439,7 @@
 
 	private void copyPackThroughCache(PackOutputStream out, DfsReader ctx)
 			throws IOException {
+		@SuppressWarnings("resource") // Explicitly closed in finally block
 		ReadableChannel rc = null;
 		try {
 			long position = 12;
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 bf14d18..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
@@ -115,7 +115,7 @@
 	 *            {@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;
 	}
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 1976816..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
@@ -133,7 +133,7 @@
 
 	/** {@inheritDoc} */
 	@Override
-	public void notifyIndexChanged() {
+	public void notifyIndexChanged(boolean internal) {
 		// Do not send notifications.
 		// There is no index, as there is no working tree.
 	}
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 8793d83..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,7 +43,7 @@
 
 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;
 
@@ -67,7 +67,7 @@
 	 */
 	public static DfsStreamKey of(DfsRepositoryDescription repo, String name,
 			@Nullable PackExt ext) {
-		return new ByteArrayDfsStreamKey(repo, name.getBytes(UTF_8), ext);
+		return new ByteArrayDfsStreamKey(repo, name.getBytes(CHARSET), ext);
 	}
 
 	final int hash;
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 fa2c529..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
@@ -104,31 +104,34 @@
 	/** {@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 d88011c..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;
 
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 6ade438..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
@@ -213,22 +213,6 @@
 		}
 
 		@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 338df4a..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,14 +58,14 @@
 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;
@@ -73,7 +73,7 @@
 
 	/** {@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 4dcf133..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,14 +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);
@@ -92,7 +92,7 @@
 
 	/** {@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 7963cea..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
@@ -76,7 +76,7 @@
 	 * @param n
 	 *            size of the byte window
 	 */
-	protected ByteWindow(final PackFile p, final long s, final int n) {
+	protected ByteWindow(PackFile p, long s, int n) {
 		pack = p;
 		start = s;
 		end = start + n;
@@ -86,7 +86,7 @@
 		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;
 	}
 
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 e810ae0..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
@@ -181,11 +181,11 @@
 
 	/** {@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;
@@ -205,7 +205,7 @@
 	}
 
 	@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/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 @@
 
 	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 @@
 		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 moveToHead(final Slot e) {
+	private void moveToHead(Slot e) {
 		unlink(e);
 		e.lruPrev = null;
 		e.lruNext = lruHead;
@@ -147,7 +147,7 @@
 		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 @@
 			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 @@
 
 		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/FileRepository.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileRepository.java
index 9b82210..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;
@@ -125,6 +123,10 @@
 	private final FileBasedConfig repoConfig;
 	private final RefDatabase refs;
 	private final ObjectDirectory objectDatabase;
+
+	private final Object snapshotLock = new Object();
+
+	// protected by snapshotLock
 	private FileSnapshot snapshot;
 
 	/**
@@ -147,7 +149,7 @@
 	 *             accessed.
 	 * @see FileRepositoryBuilder
 	 */
-	public FileRepository(final File gitDir) throws IOException {
+	public FileRepository(File gitDir) throws IOException {
 		this(new FileRepositoryBuilder().setGitDir(gitDir).setup());
 	}
 
@@ -161,7 +163,7 @@
 	 *             accessed.
 	 * @see FileRepositoryBuilder
 	 */
-	public FileRepository(final String gitDir) throws IOException {
+	public FileRepository(String gitDir) throws IOException {
 		this(new File(gitDir));
 	}
 
@@ -174,7 +176,7 @@
 	 *             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,8 +242,9 @@
 						Long.valueOf(repositoryFormatVersion)));
 		}
 
-		if (!isBare())
+		if (!isBare()) {
 			snapshot = FileSnapshot.save(getIndexFile());
+		}
 	}
 
 	private void loadSystemConfig() throws IOException {
@@ -531,34 +534,43 @@
 	 *             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));
 	}
 
 	/** {@inheritDoc} */
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 b5485c4..f26eba3 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
@@ -268,7 +268,7 @@
 				+ ", 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.
@@ -276,7 +276,7 @@
 		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 0598ddd..859db48 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
@@ -769,7 +769,8 @@
 	 * @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 {
@@ -835,7 +836,7 @@
 		}
 
 		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());
@@ -998,6 +999,9 @@
 	private void deleteTempPacksIdx() {
 		Path packDir = repo.getObjectDatabase().getPackDirectory().toPath();
 		Instant threshold = Instant.now().minus(1, ChronoUnit.DAYS);
+		if (!Files.exists(packDir)) {
+			return;
+		}
 		try (DirectoryStream<Path> stream =
 				Files.newDirectoryStream(packDir, "gc_*_tmp")) { //$NON-NLS-1$
 			stream.forEach(t -> {
@@ -1059,7 +1063,7 @@
 	 */
 	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());
@@ -1367,7 +1371,7 @@
 		}
 
 		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++;
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 82458c1..0e587ce 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.File;
 import java.io.IOException;
@@ -171,6 +171,6 @@
 		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/LazyObjectIdSetFile.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/LazyObjectIdSetFile.java
index 3d0e9c7..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;
@@ -86,7 +86,7 @@
 	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/LocalObjectToPack.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/LocalObjectToPack.java
index 55eeb95..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,7 +58,7 @@
 	/** Length of the data section of the object. */
 	long length;
 
-	LocalObjectToPack(AnyObjectId src, final int type) {
+	LocalObjectToPack(AnyObjectId src, int type) {
 		super(src, type);
 	}
 
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 9befe2a..b80c58c 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
@@ -93,7 +93,7 @@
 	 *            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 {
@@ -144,26 +144,8 @@
 	 *
 	 * @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 org.eclipse.jgit.internal.storage.file.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);
 	}
@@ -282,7 +264,7 @@
 	 *             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';
@@ -303,7 +285,7 @@
 	 *             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) {
@@ -349,18 +331,18 @@
 
 		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);
 			}
 
@@ -400,7 +382,7 @@
 	 * @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);
 	}
 
@@ -411,7 +393,7 @@
 	 * @param on
 	 *            true if the commit method must remember the FileSnapshot.
 	 */
-	public void setNeedSnapshot(final boolean on) {
+	public void setNeedSnapshot(boolean on) {
 		needSnapshot = on;
 	}
 
@@ -421,7 +403,7 @@
 	 * @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;
 	}
 
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 881e38f..2b6d230 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
@@ -257,7 +257,7 @@
 		// 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();
 		}
 	}
@@ -278,7 +278,7 @@
 	 * Add a single existing pack to the list of available pack files.
 	 */
 	@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$
@@ -622,7 +622,7 @@
 			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();
@@ -819,7 +819,7 @@
 		return shallowCommitsIds;
 	}
 
-	private void insertPack(final PackFile pf) {
+	private void insertPack(PackFile pf) {
 		PackList o, n;
 		do {
 			o = packList.get();
@@ -842,7 +842,7 @@
 		} while (!packList.compareAndSet(o, n));
 	}
 
-	private void removePack(final PackFile deadPack) {
+	private void removePack(PackFile deadPack) {
 		PackList o, n;
 		do {
 			o = packList.get();
@@ -860,7 +860,7 @@
 		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;
@@ -868,7 +868,7 @@
 		return -1;
 	}
 
-	private PackList scanPacks(final PackList original) {
+	private PackList scanPacks(PackList original) {
 		synchronized (packList) {
 			PackList o, n;
 			do {
@@ -887,13 +887,13 @@
 		}
 	}
 
-	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$
@@ -936,7 +936,7 @@
 			return old;
 		}
 
-		for (final PackFile p : forReuse.values()) {
+		for (PackFile p : forReuse.values()) {
 			p.close();
 		}
 
@@ -948,9 +948,9 @@
 		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.
@@ -979,7 +979,7 @@
 		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);
 		}
@@ -1038,12 +1038,12 @@
 		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);
@@ -1081,7 +1081,7 @@
 		/** 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;
 		}
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 e06f721..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,7 +78,7 @@
 
 	private Deflater deflate;
 
-	ObjectDirectoryInserter(final FileObjectDatabase dest, final Config cfg) {
+	ObjectDirectoryInserter(FileObjectDatabase dest, Config cfg) {
 		db = dest;
 		config = cfg.get(WriteConfig.KEY);
 	}
@@ -117,7 +117,7 @@
 
 	/** {@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);
 	}
@@ -267,7 +267,7 @@
 		}
 	}
 
-	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) ' ');
@@ -279,7 +279,7 @@
 		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 5dcba60..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
@@ -153,7 +153,7 @@
 	 * @param empty
 	 *            true to enable keeping an empty pack.
 	 */
-	public void setKeepEmpty(final boolean empty) {
+	public void setKeepEmpty(boolean empty) {
 		keepEmpty = empty;
 	}
 
@@ -429,8 +429,7 @@
 
 	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);
@@ -438,12 +437,10 @@
 				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 21a1c7f..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,6 +52,7 @@
 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;
 
@@ -93,19 +93,15 @@
 	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) {
-			throw new IOException(MessageFormat
-					.format(JGitText.get().unreadablePackIndex,
-							idxFile.getAbsolutePath()),
-					ioe);
-		} 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);
 			}
 		}
 	}
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 341157f..ee3c0a8 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 @@
 	/** 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;
 		}
 	};
@@ -164,7 +164,7 @@
 	 * @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.fileSnapshot = FileSnapshot.save(packFile);
 		this.packLastModified = (int) (fileSnapshot.lastModified() >> 10);
@@ -265,7 +265,7 @@
 	 * @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);
 	}
@@ -293,7 +293,7 @@
 	 * @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;
@@ -358,7 +358,7 @@
 	 * @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);
 	}
 
@@ -717,7 +717,7 @@
 		}
 	}
 
-	ByteArrayWindow read(final long pos, int size) throws IOException {
+	ByteArrayWindow read(long pos, int size) throws IOException {
 		synchronized (readLock) {
 			if (invalid || fd == null) {
 				// Due to concurrency between a read and another packfile invalidation thread
@@ -736,7 +736,7 @@
 		}
 	}
 
-	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);
@@ -793,7 +793,7 @@
 		}
 	}
 
-	ObjectLoader load(final WindowCursor curs, long pos)
+	ObjectLoader load(WindowCursor curs, long pos)
 			throws IOException, LargeObjectException {
 		try {
 			final byte[] ib = curs.tempId;
@@ -982,7 +982,7 @@
 		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);
@@ -1029,13 +1029,13 @@
 		}
 	}
 
-	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);
@@ -1133,7 +1133,7 @@
 		}
 	}
 
-	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 acfd9c4..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,6 +63,7 @@
 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 org.eclipse.jgit.lib.ObjectId} in a
@@ -94,21 +94,15 @@
 	 *             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) {
-			throw new IOException(MessageFormat
-					.format(JGitText.get().unreadablePackIndex,
+			throw new IOException(
+					MessageFormat.format(JGitText.get().unreadablePackIndex,
 							idxFile.getAbsolutePath()),
 					ioe);
-		} finally {
-			try {
-				fd.close();
-			} catch (IOException err2) {
-				// ignore
-			}
 		}
 	}
 
@@ -145,7 +139,7 @@
 		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,7 +157,7 @@
 	 *            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;
 	}
 
@@ -247,7 +241,7 @@
 	 *            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;
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 8ea31e4..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
@@ -113,14 +113,14 @@
 	@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
@@ -137,14 +137,14 @@
 		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);
@@ -161,7 +161,7 @@
 
 	/** {@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)
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 9f6201f..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
@@ -176,7 +176,7 @@
 		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
@@ -193,14 +193,14 @@
 		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;
@@ -209,7 +209,7 @@
 
 	/** {@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);
@@ -217,7 +217,7 @@
 
 	/** {@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)
@@ -225,7 +225,7 @@
 		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)));
@@ -290,7 +290,7 @@
 		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 b92f7b2..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
@@ -123,7 +123,7 @@
 	 */
 	public static int oldestPossibleFormat(
 			final List<? extends PackedObjectInfo> objs) {
-		for (final PackedObjectInfo oe : objs) {
+		for (PackedObjectInfo oe : objs) {
 			if (!PackIndexWriterV1.canStore(oe))
 				return 2;
 		}
@@ -180,7 +180,7 @@
 	 *            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());
@@ -250,7 +250,7 @@
 	 * @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);
@@ -269,11 +269,11 @@
 	 */
 	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);
 		}
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 f220e7a..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;
@@ -73,7 +73,7 @@
 	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 a18ccaf..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
@@ -76,12 +76,12 @@
 	}
 
 	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);
 		}
@@ -89,7 +89,7 @@
 
 	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);
@@ -100,7 +100,7 @@
 	}
 
 	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/PackInserter.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackInserter.java
index 7ff2696..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
@@ -438,7 +438,7 @@
 		}
 
 		@Override
-		public void write(final int b) throws IOException {
+		public void write(int b) throws IOException {
 			hdrBuf[0] = (byte) b;
 			write(hdrBuf, 0, 1);
 		}
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 82f0da1..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
@@ -65,7 +65,7 @@
 	 * @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$
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 944af26..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 @@
 	 * @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 @@
 
 		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 @@
 	 *            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;
@@ -177,7 +177,7 @@
 	 * @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 @@
 		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/RefDirectory.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/RefDirectory.java
index 106c84b..6a18df8 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
@@ -209,7 +209,7 @@
 
 	private List<Integer> retrySleepMs = RETRY_SLEEP_MS;
 
-	RefDirectory(final FileRepository db) {
+	RefDirectory(FileRepository db) {
 		final FS fs = db.getFS();
 		parent = db;
 		gitDir = db.getDirectory();
@@ -346,7 +346,7 @@
 
 	/** {@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) {
@@ -435,7 +435,7 @@
 
 		RefList.Builder<LooseRef> newLoose;
 
-		LooseScanner(final RefList<LooseRef> curLoose) {
+		LooseScanner(RefList<LooseRef> curLoose) {
 			this.curLoose = curLoose;
 		}
 
@@ -546,7 +546,7 @@
 
 	/** {@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;
@@ -568,7 +568,7 @@
 		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());
@@ -582,7 +582,7 @@
 		}
 	}
 
-	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);
@@ -972,7 +972,7 @@
 		}
 	}
 
-	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;
@@ -1024,7 +1024,7 @@
 		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();
@@ -1190,7 +1190,7 @@
 		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' //
@@ -1263,18 +1263,18 @@
 		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 202e51f..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
@@ -104,7 +104,7 @@
 		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 4d6b245..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,7 +60,7 @@
 	private boolean shouldDeref;
 	private LockFile lock;
 
-	RefDirectoryUpdate(final RefDirectory r, final Ref ref) {
+	RefDirectoryUpdate(RefDirectory r, Ref ref) {
 		super(ref);
 		database = r;
 	}
@@ -106,7 +106,7 @@
 
 	/** {@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);
 
@@ -148,7 +148,7 @@
 
 	/** {@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;
@@ -156,7 +156,7 @@
 
 	/** {@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/ReflogWriter.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ReflogWriter.java
index fd6b427..131f716 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
@@ -220,6 +220,22 @@
 		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
@@ -229,29 +245,17 @@
 			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/UnpackedObject.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/UnpackedObject.java
index adb05e4..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
@@ -266,7 +266,7 @@
 		}
 	}
 
-	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 e71284f..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
@@ -157,7 +157,7 @@
 	 *             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)
@@ -178,7 +178,7 @@
 		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));
@@ -193,7 +193,7 @@
 		return r;
 	}
 
-	static final void purge(final PackFile pack) {
+	static final void purge(PackFile pack) {
 		cache.removeAll(pack);
 	}
 
@@ -232,7 +232,7 @@
 
 	private final AtomicLong openBytes;
 
-	private WindowCache(final WindowCacheConfig cfg) {
+	private WindowCache(WindowCacheConfig cfg) {
 		tableSize = tableSize(cfg);
 		final int lockCount = lockCount(cfg);
 		if (tableSize < 1)
@@ -286,11 +286,11 @@
 		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();
@@ -310,18 +310,18 @@
 		}
 	}
 
-	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();
 	}
@@ -330,11 +330,11 @@
 		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)
@@ -344,7 +344,7 @@
 		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);
 	}
 
@@ -360,7 +360,7 @@
 	 *             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);
@@ -399,7 +399,7 @@
 		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) {
@@ -415,7 +415,7 @@
 		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.
@@ -487,7 +487,7 @@
 	 * @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;
@@ -521,11 +521,11 @@
 		}
 	}
 
-	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];
 	}
 
@@ -556,7 +556,7 @@
 		 */
 		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 569bfe8..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
@@ -347,7 +347,7 @@
 			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)) {
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 @@
 
 	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/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 @@
 	 *            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 @@
 	 *            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 @@
 	 *            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/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 @@
 		}
 	}
 
-	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 @@
 		} 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/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 @@
 		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/ObjectToPack.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/ObjectToPack.java
index e8c7510..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
@@ -103,7 +103,7 @@
 	 * @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;
 	}
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 fd9c1a0..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
@@ -107,7 +107,7 @@
 
 	/** {@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);
@@ -115,7 +115,7 @@
 
 	/** {@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);
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 42df1a6..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
@@ -303,6 +303,8 @@
 
 	private ObjectCountCallback callback;
 
+	private long filterBlobLimit = -1;
+
 	/**
 	 * Create writer for specified repository.
 	 * <p>
@@ -312,7 +314,7 @@
 	 * @param repo
 	 *            repository where objects are stored.
 	 */
-	public PackWriter(final Repository repo) {
+	public PackWriter(Repository repo) {
 		this(repo, repo.newObjectReader());
 	}
 
@@ -325,7 +327,7 @@
 	 * @param reader
 	 *            reader to read from the repository with.
 	 */
-	public PackWriter(final ObjectReader reader) {
+	public PackWriter(ObjectReader reader) {
 		this(new PackConfig(), reader);
 	}
 
@@ -340,7 +342,7 @@
 	 * @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);
 	}
 
@@ -355,7 +357,7 @@
 	 * @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);
 	}
 
@@ -510,7 +512,7 @@
 	 *            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;
 	}
 
@@ -601,7 +603,7 @@
 	 *            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;
 	}
 
@@ -639,6 +641,14 @@
 	}
 
 	/**
+	 * @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.
@@ -914,7 +924,7 @@
 	 * @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();
 	}
@@ -981,7 +991,7 @@
 	 * @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);
 
@@ -1003,7 +1013,7 @@
 	 * @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);
@@ -1516,7 +1526,7 @@
 			// 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() {
@@ -1723,7 +1733,7 @@
 		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);
@@ -1960,7 +1970,7 @@
 				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 {
@@ -1970,7 +1980,7 @@
 					continue;
 				if (exclude(o))
 					continue;
-				addObject(o, walker.getPathHashCode());
+				filterAndAddObject(o, o.getType(), walker.getPathHashCode());
 				countingMonitor.update(1);
 			}
 		}
@@ -2003,7 +2013,7 @@
 				needBitmap.remove(objectId);
 				continue;
 			}
-			addObject(objectId, obj.getType(), 0);
+			filterAndAddObject(objectId, obj.getType(), 0);
 		}
 
 		if (thin)
@@ -2040,13 +2050,13 @@
 	 * @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);
 	}
 
@@ -2062,6 +2072,21 @@
 		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;
@@ -2223,290 +2248,6 @@
 		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/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 @@
 		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 @@
 	}
 
 	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 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/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 @@
 		}
 
 		private static byte[] nameUtf8(Ref ref) {
-			return ref.getName().getBytes(UTF_8);
+			return ref.getName().getBytes(CHARSET);
 		}
 	}
 
@@ -559,13 +559,13 @@
 			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/ReftableOutputStream.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/ReftableOutputStream.java
index 1fc43c9..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;
@@ -160,7 +160,7 @@
 	}
 
 	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 7487719..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;
@@ -182,7 +182,7 @@
 	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);
@@ -223,7 +223,7 @@
 		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;
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 e9aa110..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
@@ -279,7 +279,7 @@
 		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();
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 183468f..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
@@ -282,7 +282,7 @@
 	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) {
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 425f7f6..d105d0d 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/AbbreviatedObjectId.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/AbbreviatedObjectId.java
@@ -74,7 +74,7 @@
 	 *            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 {
@@ -131,7 +131,7 @@
 	 *            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);
@@ -165,7 +165,7 @@
 		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.
@@ -244,7 +244,7 @@
 	 *         &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));
@@ -280,7 +280,7 @@
 	 *         &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)));
@@ -316,7 +316,7 @@
 	 *         &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]));
@@ -347,7 +347,7 @@
 		return w1 >>> 24;
 	}
 
-	private int mask(final int word, final int v) {
+	private int mask(int word, int v) {
 		return mask(nibbles, word, v);
 	}
 
@@ -359,7 +359,7 @@
 
 	/** {@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
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 5847765..978dd3a 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/AnyObjectId.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/AnyObjectId.java
@@ -73,17 +73,19 @@
 		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;
@@ -159,7 +161,7 @@
 	 * Compare this ObjectId to another and obtain a sort ordering.
 	 */
 	@Override
-	public final int compareTo(final AnyObjectId other) {
+	public final int compareTo(AnyObjectId other) {
 		if (this == other)
 			return 0;
 
@@ -195,7 +197,7 @@
 	 * @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));
@@ -228,7 +230,7 @@
 	 * @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]);
@@ -257,7 +259,7 @@
 	 *            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;
 	}
 
@@ -274,13 +276,13 @@
 	 *            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
@@ -293,7 +295,7 @@
 	 * @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);
@@ -309,7 +311,7 @@
 	 * @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);
@@ -325,7 +327,7 @@
 	 * @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;
@@ -341,7 +343,7 @@
 	 * @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);
@@ -349,7 +351,7 @@
 		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);
@@ -365,7 +367,7 @@
 	 * @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());
 	}
 
@@ -408,7 +410,7 @@
 	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];
@@ -426,7 +428,7 @@
 	 * @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());
 	}
 
@@ -442,7 +444,7 @@
 	 * @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);
 	}
@@ -457,7 +459,7 @@
 	 * @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);
 	}
@@ -468,7 +470,7 @@
 		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);
@@ -479,7 +481,7 @@
 	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];
@@ -527,7 +529,7 @@
 	 *            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);
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 6919f7e..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;
@@ -179,7 +180,7 @@
 	 *            configuration.
 	 * @return {@code this}.
 	 */
-	public BatchRefUpdate setRefLogIdent(final PersonIdent pi) {
+	public BatchRefUpdate setRefLogIdent(PersonIdent pi) {
 		refLogIdent = pi;
 		return this;
 	}
@@ -528,8 +529,9 @@
 		}
 		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
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 fc354db..9f64f35 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/BitmapIndex.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/BitmapIndex.java
@@ -121,19 +121,6 @@
 	 * 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/BlobBasedConfig.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/BlobBasedConfig.java
index 3ff92dc..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;
@@ -76,13 +78,12 @@
 	 * @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);
 		}
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 596da03..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,7 +107,7 @@
 	 * @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;
 	}
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 2217fde..59a13f6 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/CommitBuilder.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/CommitBuilder.java
@@ -243,7 +243,7 @@
 	 * @param newMessage
 	 *            the commit message. Should not be null.
 	 */
-	public void setMessage(final String newMessage) {
+	public void setMessage(String newMessage) {
 		message = newMessage;
 	}
 
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 4d558c9..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;
@@ -374,7 +376,7 @@
 	}
 
 	@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) {
@@ -513,7 +515,7 @@
 	 *         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);
 	}
 
@@ -599,7 +601,7 @@
 	 * @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) {
@@ -619,7 +621,7 @@
 	 *            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);
 	}
 
@@ -1008,7 +1010,7 @@
 	 */
 	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) {
@@ -1057,11 +1059,11 @@
 	 *             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(
@@ -1166,8 +1168,7 @@
 
 		String decoded;
 		if (isUtf8(bytes)) {
-			decoded = RawParseUtils.decode(RawParseUtils.UTF8_CHARSET, bytes, 3,
-					bytes.length);
+			decoded = RawParseUtils.decode(CHARSET, bytes, 3, bytes.length);
 		} else {
 			decoded = RawParseUtils.decode(bytes);
 		}
@@ -1184,7 +1185,7 @@
 				getBaseState());
 	}
 
-	private ConfigSnapshot newState(final List<ConfigLine> entries) {
+	private ConfigSnapshot newState(List<ConfigLine> entries) {
 		return new ConfigSnapshot(Collections.unmodifiableList(entries),
 				getBaseState());
 	}
@@ -1209,7 +1210,7 @@
 				&& 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 (;;) {
@@ -1248,7 +1249,7 @@
 		return name.toString();
 	}
 
-	private static String readKeyName(final StringReader in)
+	private static String readKeyName(StringReader in)
 			throws ConfigInvalidException {
 		final StringBuilder name = new StringBuilder();
 		for (;;) {
@@ -1335,7 +1336,7 @@
 		return r.toString();
 	}
 
-	private static String readValue(final StringReader in)
+	private static String readValue(StringReader in)
 			throws ConfigInvalidException {
 		StringBuilder value = new StringBuilder();
 		StringBuilder trailingSpaces = null;
@@ -1451,7 +1452,7 @@
 
 		private int pos;
 
-		StringReader(final String in) {
+		StringReader(String in) {
 			buf = in.toCharArray();
 		}
 
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 d5f1d8f..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 @@
 	/** 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 @@
 				&& 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 @@
 		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)
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 10abd9e..9023bd8 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;
@@ -226,10 +228,10 @@
 	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";
@@ -475,7 +477,7 @@
 	 * @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;
@@ -500,7 +502,7 @@
 	 * @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;
@@ -599,7 +601,7 @@
 	 * @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));
 	}
 
@@ -615,7 +617,7 @@
 	 *             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);
@@ -635,7 +637,7 @@
 	 *         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) {
@@ -652,7 +654,8 @@
 	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 */
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 32a894f..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 @@
 		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,
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 68f881d..891c7f2 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/DefaultTypedConfigGetter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/DefaultTypedConfigGetter.java
@@ -270,8 +270,8 @@
 		}
 	}
 
-	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;
 			}
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 7852371..d4c4d5b 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/FileMode.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/FileMode.java
@@ -88,7 +88,7 @@
 	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;
 		}
 	};
@@ -97,7 +97,7 @@
 	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;
 		}
 	};
@@ -106,7 +106,7 @@
 	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;
 		}
 	};
@@ -115,7 +115,7 @@
 	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;
 		}
 	};
@@ -124,7 +124,7 @@
 	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;
 		}
 	};
@@ -133,7 +133,7 @@
 	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;
 		}
 	};
@@ -145,7 +145,7 @@
 	 *            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)
@@ -165,7 +165,7 @@
 
 		return new FileMode(bits, Constants.OBJ_BAD) {
 			@Override
-			public boolean equals(final int a) {
+			public boolean equals(int a) {
 				return bits == a;
 			}
 		};
@@ -177,7 +177,7 @@
 
 	private final int objectType;
 
-	private FileMode(int mode, final int expType) {
+	private FileMode(int mode, int expType) {
 		modeBits = mode;
 		objectType = expType;
 		if (mode != 0) {
@@ -206,7 +206,7 @@
 	 *            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.
@@ -222,7 +222,7 @@
 	 * @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);
 	}
 
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 87086cb..94b9ddc 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/IndexDiff.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/IndexDiff.java
@@ -542,10 +542,9 @@
 							JGitText.get().invalidIgnoreParamSubmodule,
 							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())) {
@@ -574,8 +573,6 @@
 								recordFileMode(subRepoPath, FileMode.GITLINK);
 							}
 						}
-					} finally {
-						subRepo.close();
 					}
 				}
 			}
@@ -745,7 +742,7 @@
 	 * @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;
 	}
@@ -759,7 +756,7 @@
 	 *         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 a97721c..dd0f18e 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/InflaterCache.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/InflaterCache.java
@@ -89,7 +89,7 @@
 	 *            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))
@@ -97,7 +97,7 @@
 		}
 	}
 
-	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 e492af9..8cf0fd0 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/MutableObjectId.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/MutableObjectId.java
@@ -162,7 +162,7 @@
 	 *            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);
 	}
 
@@ -175,7 +175,7 @@
 	 * @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);
@@ -190,7 +190,7 @@
 	 *            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);
 	}
 
@@ -203,7 +203,7 @@
 	 * @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];
@@ -243,7 +243,7 @@
 	 * @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);
 	}
 
@@ -253,14 +253,14 @@
 	 * @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);
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 5c14754..d37fb21 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectChecker.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectChecker.java
@@ -1230,7 +1230,7 @@
 	 * @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 bbef51d..93add5c 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectDatabase.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectDatabase.java
@@ -121,8 +121,8 @@
 	 * @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);
 		}
 	}
@@ -141,7 +141,7 @@
 	 * @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);
 	}
@@ -172,7 +172,7 @@
 	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 0e85545..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 @@
 	 *            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 @@
 	 *            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 @@
 	 *            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 @@
 	 *            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 @@
 	 *            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 @@
 	 *            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 @@
 	 *            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 @@
 	 *            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);
@@ -281,7 +281,7 @@
 	 * @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;
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 03a430c..9df5933 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectIdOwnerMap.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectIdOwnerMap.java
@@ -134,7 +134,7 @@
 	 * @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)
@@ -149,7 +149,7 @@
 	 * Returns true if this map contains the specified object.
 	 */
 	@Override
-	public boolean contains(final AnyObjectId toFind) {
+	public boolean contains(AnyObjectId toFind) {
 		return get(toFind) != null;
 	}
 
@@ -163,7 +163,7 @@
 	 * @param newValue
 	 *            the object to store.
 	 */
-	public <Q extends V> void add(final Q newValue) {
+	public <Q extends V> void add(Q newValue) {
 		if (++size == grow)
 			grow();
 
@@ -194,7 +194,7 @@
 	 *         {@code get(newValue)} first.
 	 */
 	@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;
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 001aa9c..cd57bda 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectIdSubclassMap.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectIdSubclassMap.java
@@ -96,7 +96,7 @@
 	 *            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;
@@ -116,7 +116,7 @@
 	 * Returns true if this map contains the specified object.
 	 */
 	@Override
-	public boolean contains(final AnyObjectId toFind) {
+	public boolean contains(AnyObjectId toFind) {
 		return get(toFind) != null;
 	}
 
@@ -131,7 +131,7 @@
 	 * @param newValue
 	 *            the object 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);
@@ -155,7 +155,7 @@
 	 *         that would have been returned had the caller used
 	 *         {@code get(newValue)} first.
 	 */
-	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;
@@ -226,7 +226,7 @@
 		};
 	}
 
-	private void insert(final V newValue) {
+	private void insert(V newValue) {
 		final int msk = mask;
 		int j = newValue.w1 & msk;
 		final V[] tbl = table;
@@ -254,7 +254,7 @@
 	}
 
 	@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 40522ba..77fa1b2 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectInserter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectInserter.java
@@ -361,7 +361,7 @@
 	 * @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);
 	}
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 432f5a6..2e52f03 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectLoader.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectLoader.java
@@ -194,8 +194,7 @@
 		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);
@@ -212,8 +211,6 @@
 
 			IO.readFully(in, buf, 0, buf.length);
 			return buf;
-		} finally {
-			in.close();
 		}
 	}
 
@@ -255,8 +252,7 @@
 	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;
@@ -269,15 +265,13 @@
 				}
 				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;
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 18a11f0..c16a2b6 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/PersonIdent.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/PersonIdent.java
@@ -167,7 +167,7 @@
 	 *
 	 * @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));
 	}
 
@@ -177,7 +177,7 @@
 	 * @param pi
 	 *            Original {@link org.eclipse.jgit.lib.PersonIdent}
 	 */
-	public PersonIdent(final PersonIdent pi) {
+	public PersonIdent(PersonIdent pi) {
 		this(pi.getName(), pi.getEmailAddress());
 	}
 
@@ -190,7 +190,7 @@
 	 * @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());
 	}
 
@@ -221,7 +221,7 @@
 	 * @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);
 	}
 
@@ -234,7 +234,7 @@
 	 * @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);
 	}
 
@@ -264,7 +264,7 @@
 	 * @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);
 	}
 
@@ -274,7 +274,7 @@
 				.getTimezone(when));
 	}
 
-	private PersonIdent(final UserConfig config) {
+	private PersonIdent(UserConfig config) {
 		this(config.getCommitterName(), config.getCommitterEmail());
 	}
 
@@ -370,7 +370,7 @@
 
 	/** {@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())
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 06b4b22..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;
@@ -183,7 +183,7 @@
 			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)
@@ -192,7 +192,7 @@
 			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;
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 395bb32..b000558 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Ref.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Ref.java
@@ -105,7 +105,7 @@
 
 		private final boolean packed;
 
-		private Storage(final boolean l, final boolean p) {
+		private Storage(boolean l, boolean p) {
 			loose = l;
 			packed = p;
 		}
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 43d2f37..8bcac00 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefComparator.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefComparator.java
@@ -62,7 +62,7 @@
 
 	/** {@inheritDoc} */
 	@Override
-	public int compare(final Ref o1, final Ref o2) {
+	public int compare(Ref o1, Ref o2) {
 		return compareTo(o1, o2);
 	}
 
@@ -73,7 +73,7 @@
 	 *            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;
@@ -101,7 +101,7 @@
 	 *            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 557bdb9..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;
@@ -89,7 +91,10 @@
 	 */
 	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$
 
 	/**
@@ -332,6 +337,29 @@
 	}
 
 	/**
+	 * 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
@@ -343,16 +371,73 @@
 	 *         of each key. The map can be an unsorted map.
 	 * @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
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 3d22bb0..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 @@
 	 * @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;
 
@@ -107,7 +107,7 @@
 	 *            automatically determined based on the repository
 	 *            configuration.
 	 */
-	public void setRefLogIdent(final PersonIdent pi) {
+	public void setRefLogIdent(PersonIdent pi) {
 		destination.setRefLogIdent(pi);
 	}
 
@@ -127,7 +127,7 @@
 	 * @param msg
 	 *            the message to describe this change.
 	 */
-	public void setRefLogMessage(final String msg) {
+	public void setRefLogMessage(String msg) {
 		if (msg == null)
 			disableRefLog();
 		else
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 06a7576..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,7 +227,7 @@
 	 * @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$
@@ -350,7 +350,7 @@
 	 * @param id
 	 *            the new value.
 	 */
-	public void setNewObjectId(final AnyObjectId id) {
+	public void setNewObjectId(AnyObjectId id) {
 		newValue = id.copy();
 	}
 
@@ -377,7 +377,7 @@
 	 *            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;
 	}
 
@@ -396,7 +396,7 @@
 	 * @param b
 	 *            true if this update should ignore merge tests.
 	 */
-	public void setForceUpdate(final boolean b) {
+	public void setForceUpdate(boolean b) {
 		force = b;
 	}
 
@@ -421,7 +421,7 @@
 	 *            automatically determined based on the repository
 	 *            configuration.
 	 */
-	public void setRefLogIdent(final PersonIdent pi) {
+	public void setRefLogIdent(PersonIdent pi) {
 		refLogIdent = pi;
 	}
 
@@ -461,7 +461,7 @@
 	 *            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) {
@@ -615,7 +615,7 @@
 	 * @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() {
@@ -659,7 +659,7 @@
 	 * @return the result status of the delete.
 	 * @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();
@@ -731,7 +731,7 @@
 		}
 	}
 
-	private Result updateImpl(final RevWalk walk, final Store store)
+	private Result updateImpl(RevWalk walk, Store store)
 			throws IOException {
 		RevObject newObj;
 		RevObject oldObj;
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 90a0350..71ee963 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefWriter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefWriter.java
@@ -116,7 +116,7 @@
 	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
@@ -161,7 +161,7 @@
 	 */
 	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;
@@ -177,7 +177,7 @@
 		}
 
 		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;
 
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 db5cad0..29cc19c 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Repository.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Repository.java
@@ -164,7 +164,7 @@
 	 * @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();
@@ -344,7 +344,7 @@
 	 *             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);
 	}
@@ -392,7 +392,7 @@
 	 *             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);
 	}
 
@@ -411,7 +411,7 @@
 	 *             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);
 	}
 
@@ -427,7 +427,7 @@
 	 *             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);
 	}
 
@@ -482,13 +482,13 @@
 	 *             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;
@@ -509,7 +509,7 @@
 	 * @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);
@@ -523,7 +523,7 @@
 	}
 
 	@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;
@@ -688,6 +688,8 @@
 			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;
@@ -711,7 +713,7 @@
 									.format(JGitText.get().invalidRefName,
 											name),
 									revstr);
-						Ref ref = getRef(name);
+						Ref ref = findRef(name);
 						name = null;
 						if (ref == null)
 							return null;
@@ -764,7 +766,7 @@
 									.format(JGitText.get().invalidRefName,
 											name),
 									revstr);
-						Ref ref = getRef(name);
+						Ref ref = findRef(name);
 						name = null;
 						if (ref == null)
 							return null;
@@ -815,7 +817,7 @@
 			throw new RevisionSyntaxException(
 					MessageFormat.format(JGitText.get().invalidRefName, name),
 					revstr);
-		if (getRef(name) != null)
+		if (findRef(name) != null)
 			return name;
 		return resolveSimple(name);
 	}
@@ -841,7 +843,7 @@
 	}
 
 	@Nullable
-	private ObjectId resolveSimple(final String revstr) throws IOException {
+	private ObjectId resolveSimple(String revstr) throws IOException {
 		if (ObjectId.isId(revstr))
 			return ObjectId.fromString(revstr);
 
@@ -911,7 +913,7 @@
 	}
 
 	@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()) {
@@ -1059,24 +1061,6 @@
 	 * 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 java.io.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".
@@ -1085,7 +1069,7 @@
 	 * @since 4.2
 	 */
 	@Nullable
-	public Ref exactRef(String name) throws IOException {
+	public final Ref exactRef(String name) throws IOException {
 		return getRefDatabase().exactRef(name);
 	}
 
@@ -1101,7 +1085,7 @@
 	 * @since 4.2
 	 */
 	@Nullable
-	public Ref findRef(String name) throws IOException {
+	public final Ref findRef(String name) throws IOException {
 		return getRefDatabase().getRef(name);
 	}
 
@@ -1126,7 +1110,9 @@
 	 * @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 {
@@ -1149,9 +1135,11 @@
 	 *         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) {
@@ -1285,7 +1273,7 @@
 		IndexChangedListener l = new IndexChangedListener() {
 			@Override
 			public void onIndexChanged(IndexChangedEvent event) {
-				notifyIndexChanged();
+				notifyIndexChanged(true);
 			}
 		};
 		return DirCache.lock(this, l);
@@ -1378,7 +1366,7 @@
 	 * @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) {
 			return false;
@@ -1580,16 +1568,22 @@
 	}
 
 	/**
-	 * Force a scan for changed refs.
+	 * Force a scan for changed refs. Fires an IndexChangedEvent(false) if
+	 * changes are detected.
 	 *
 	 * @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);
 
 	/**
 	 * Get a shortened more user friendly ref name
@@ -1968,11 +1962,8 @@
 
 	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);
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 ce7ce8c..400342b1 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/RepositoryCache.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/RepositoryCache.java
@@ -88,7 +88,7 @@
 	 * @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);
 	}
@@ -115,7 +115,7 @@
 	 *             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);
 	}
@@ -135,7 +135,7 @@
 	 * @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);
@@ -151,7 +151,7 @@
 	 * @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);
@@ -170,7 +170,7 @@
 	 *            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()));
 		}
@@ -287,13 +287,13 @@
 		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);
 	}
 
@@ -302,7 +302,7 @@
 			&& (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) {
@@ -329,7 +329,7 @@
 		}
 	}
 
-	private Lock lockFor(final Key location) {
+	private Lock lockFor(Key location) {
 		return openLocks[(location.hashCode() >>> 1) % openLocks.length];
 	}
 
@@ -383,7 +383,7 @@
 		 * @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);
 		}
 
@@ -406,7 +406,7 @@
 		 * @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);
 		}
@@ -421,12 +421,12 @@
 		 *            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) {
@@ -440,7 +440,7 @@
 		}
 
 		@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);
@@ -452,7 +452,7 @@
 		}
 
 		@Override
-		public boolean equals(final Object o) {
+		public boolean equals(Object o) {
 			return o instanceof FileKey && path.equals(((FileKey) o).path);
 		}
 
@@ -476,19 +476,19 @@
 		 *         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;
@@ -521,7 +521,7 @@
 		 * @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/TagBuilder.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/TagBuilder.java
index 32ef504..bd03165 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/TagBuilder.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/TagBuilder.java
@@ -168,7 +168,7 @@
 	 * @param newMessage
 	 *            the tag's message.
 	 */
-	public void setMessage(final String newMessage) {
+	public void setMessage(String newMessage) {
 		message = newMessage;
 	}
 
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 936ce3d..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,7 +44,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.IOException;
 import java.io.OutputStreamWriter;
@@ -63,7 +63,7 @@
 	 * Initialize a new progress monitor.
 	 */
 	public TextProgressMonitor() {
-		this(new PrintWriter(new OutputStreamWriter(System.err, UTF_8)));
+		this(new PrintWriter(new OutputStreamWriter(System.err, CHARSET)));
 	}
 
 	/**
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 1a3c6f6..bfb5e2f 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/UserConfig.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/UserConfig.java
@@ -71,7 +71,7 @@
 
 	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();
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 520ea6e..98a706c 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeStrategy.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeStrategy.java
@@ -100,7 +100,7 @@
 	 * @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);
 	}
 
@@ -129,7 +129,7 @@
 	 *            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);
 	}
 
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 cd19d69..25eb1af 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/merge/Merger.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/merge/Merger.java
@@ -113,7 +113,7 @@
 	 * @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);
 		}
@@ -215,7 +215,7 @@
 	 *             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);
 	}
 
@@ -243,7 +243,7 @@
 	 *             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++)
@@ -328,7 +328,7 @@
 	 * @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);
 	}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java b/org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java
old mode 100755
new mode 100644
index 6f7a702..da6a3da
--- a/org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java
@@ -516,61 +516,6 @@
 	 * @param ignoreConflicts
 	 *            see
 	 *            {@link org.eclipse.jgit.merge.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 org.eclipse.jgit.errors.MissingObjectException
-	 * @throws org.eclipse.jgit.errors.IncorrectObjectTypeException
-	 * @throws org.eclipse.jgit.errors.CorruptObjectException
-	 * @throws java.io.IOException
-	 * @since 3.5
-	 */
-	@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 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
@@ -1050,11 +995,11 @@
 		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);
 	}
 
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 979685c..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,7 +71,7 @@
 	 * @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;
 	}
@@ -84,31 +84,31 @@
 
 	/** {@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/StrategySimpleTwoWayInCore.java b/org.eclipse.jgit/src/org/eclipse/jgit/merge/StrategySimpleTwoWayInCore.java
index 5739d58..4aeacf5 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/merge/StrategySimpleTwoWayInCore.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/merge/StrategySimpleTwoWayInCore.java
@@ -84,7 +84,7 @@
 
 	/** {@inheritDoc} */
 	@Override
-	public ThreeWayMerger newMerger(final Repository db) {
+	public ThreeWayMerger newMerger(Repository db) {
 		return new InCoreMerger(db);
 	}
 
@@ -116,13 +116,13 @@
 
 		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();
@@ -182,11 +182,11 @@
 			}
 		}
 
-		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))) {
@@ -203,7 +203,7 @@
 			}
 		}
 
-		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/ThreeWayMerger.java b/org.eclipse.jgit/src/org/eclipse/jgit/merge/ThreeWayMerger.java
index 3f28820..2fc0f4f 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/merge/ThreeWayMerger.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/merge/ThreeWayMerger.java
@@ -71,7 +71,7 @@
 	 * @param local
 	 *            the repository this merger will read and write data on.
 	 */
-	protected ThreeWayMerger(final Repository local) {
+	protected ThreeWayMerger(Repository local) {
 		super(local);
 	}
 
@@ -83,7 +83,7 @@
 	 * @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);
 	}
 
@@ -112,7 +112,7 @@
 	 * @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);
@@ -123,7 +123,7 @@
 
 	/** {@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);
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 @@
 		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/patch/BinaryHunk.java b/org.eclipse.jgit/src/org/eclipse/jgit/patch/BinaryHunk.java
index 079d6f6..95391ec 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/patch/BinaryHunk.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/patch/BinaryHunk.java
@@ -80,7 +80,7 @@
 	/** Inflated length of the data. */
 	private int length;
 
-	BinaryHunk(final FileHeader fh, final int offset) {
+	BinaryHunk(FileHeader fh, int offset) {
 		file = fh;
 		startOffset = offset;
 	}
@@ -139,7 +139,7 @@
 		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 1afb53d..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,7 +69,7 @@
 
 	private FileMode[] oldModes;
 
-	CombinedFileHeader(final byte[] b, final int offset) {
+	CombinedFileHeader(byte[] b, int offset) {
 		super(b, offset);
 	}
 
@@ -108,7 +108,7 @@
 	 *            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];
 	}
 
@@ -130,13 +130,13 @@
 	 *            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;
@@ -149,12 +149,12 @@
 	 * Convert the patch script for this file into a 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) {
@@ -191,7 +191,7 @@
 
 	/** {@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<>();
@@ -213,18 +213,18 @@
 
 	/** {@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;
@@ -240,7 +240,7 @@
 		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 bbf8023..d278132 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/patch/CombinedHunkHeader.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/patch/CombinedHunkHeader.java
@@ -64,7 +64,7 @@
 
 	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++) {
@@ -97,7 +97,7 @@
 	 *            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];
 	}
 
@@ -125,11 +125,11 @@
 	}
 
 	@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;
@@ -207,7 +207,7 @@
 	}
 
 	@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 5cfbbb2..d0a5216 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/patch/FileHeader.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/patch/FileHeader.java
@@ -146,7 +146,7 @@
 	 * @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);
@@ -155,7 +155,7 @@
 		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
@@ -264,12 +264,12 @@
 
 		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++) {
@@ -279,12 +279,12 @@
 		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];
@@ -329,7 +329,7 @@
 		return hunks;
 	}
 
-	void addHunk(final HunkHeader h) {
+	void addHunk(HunkHeader h) {
 		if (h.getFileHeader() != this)
 			throw new IllegalArgumentException(JGitText.get().hunkBelongsToAnotherFile);
 		if (hunks == null)
@@ -337,7 +337,7 @@
 		hunks.add(h);
 	}
 
-	HunkHeader newHunkHeader(final int offset) {
+	HunkHeader newHunkHeader(int offset) {
 		return new HunkHeader(this, offset);
 	}
 
@@ -370,7 +370,7 @@
 	 */
 	public EditList toEditList() {
 		final EditList r = new EditList();
-		for (final HunkHeader hunk : hunks)
+		for (HunkHeader hunk : hunks)
 			r.addAll(hunk.toEditList());
 		return r;
 	}
@@ -384,7 +384,7 @@
 	 *            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) {
@@ -444,7 +444,7 @@
 		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) {
@@ -514,25 +514,25 @@
 		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) {
@@ -555,7 +555,7 @@
 		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;
 
@@ -585,7 +585,7 @@
 		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;
@@ -594,7 +594,7 @@
 		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
 		//
@@ -636,7 +636,7 @@
 	 *         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/HunkHeader.java b/org.eclipse.jgit/src/org/eclipse/jgit/patch/HunkHeader.java
index d022d47..1458945 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/patch/HunkHeader.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/patch/HunkHeader.java
@@ -120,7 +120,7 @@
 
 	private EditList editList;
 
-	HunkHeader(final FileHeader fh, final int offset) {
+	HunkHeader(FileHeader fh, int offset) {
 		this(fh, offset, new OldImage() {
 			@Override
 			public AbbreviatedObjectId getId() {
@@ -129,13 +129,13 @@
 		});
 	}
 
-	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;
@@ -293,7 +293,7 @@
 			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;
 
@@ -359,7 +359,7 @@
 		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);
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 da123a7..052f2a7 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/patch/Patch.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/patch/Patch.java
@@ -101,7 +101,7 @@
 	 * @param fh
 	 *            the header of the file.
 	 */
-	public void addFile(final FileHeader fh) {
+	public void addFile(FileHeader fh) {
 		files.add(fh);
 	}
 
@@ -120,7 +120,7 @@
 	 * @param err
 	 *            the error description.
 	 */
-	public void addError(final FormatError err) {
+	public void addError(FormatError err) {
 		errors.add(err);
 	}
 
@@ -146,12 +146,12 @@
 	 * @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 {
+	private static byte[] readFully(InputStream is) throws IOException {
 		try (TemporaryBuffer b = new TemporaryBuffer.Heap(Integer.MAX_VALUE)) {
 			b.copy(is);
 			return b.toByteArray();
@@ -173,12 +173,12 @@
 	 *            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
@@ -234,7 +234,7 @@
 		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)
@@ -271,14 +271,14 @@
 		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
@@ -349,7 +349,7 @@
 		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) {
@@ -373,17 +373,17 @@
 		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 @@
 	 *            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 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 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 091bf68..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 @@
 	 * @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 @@
 		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 @@
 		return lanes;
 	}
 
-	void addChild(final PlotCommit c) {
+	void addChild(PlotCommit c) {
 		final int cnt = children.length;
 		if (cnt == 0)
 			children = new PlotCommit[] { c };
@@ -152,7 +152,7 @@
 	 * @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 @@
 	 *            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;
@@ -189,7 +189,7 @@
 	 * @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];
 	}
 
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 6a0ba66..5e15316 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revplot/PlotCommitList.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revplot/PlotCommitList.java
@@ -94,7 +94,7 @@
 
 	/** {@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);
@@ -120,13 +120,13 @@
 	@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();
@@ -202,7 +202,7 @@
 			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);
@@ -356,7 +356,7 @@
 		}
 	}
 
-	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);
@@ -416,7 +416,7 @@
 	 * @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 8ba8d6e..f27f356 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revplot/PlotWalk.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revplot/PlotWalk.java
@@ -90,7 +90,7 @@
 	 * @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();
@@ -118,7 +118,7 @@
 
 	/** {@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);
@@ -126,7 +126,7 @@
 
 	/** {@inheritDoc} */
 	@Override
-	protected RevCommit createCommit(final AnyObjectId id) {
+	protected RevCommit createCommit(AnyObjectId id) {
 		return new PlotCommit(id);
 	}
 
@@ -140,7 +140,7 @@
 		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 b948adb..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 @@
 	 * @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 @@
 	 * @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;
@@ -132,7 +132,7 @@
 	 * @param c
 	 *            a {@link org.eclipse.jgit.revwalk.RevCommit}
 	 */
-	protected static void describe(final StringBuilder s, final RevCommit c) {
+	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/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 @@
 		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 @@
 			return b;
 		}
 
-		void freeBlock(final Block b) {
+		void freeBlock(Block b) {
 			b.next = next;
 			next = b;
 		}
@@ -127,7 +127,7 @@
 			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 74a3511..79307b5 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/BlockRevQueue.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/BlockRevQueue.java
@@ -58,7 +58,7 @@
 		free = new BlockFreeList();
 	}
 
-	BlockRevQueue(final Generator s) throws MissingObjectException,
+	BlockRevQueue(Generator s) throws MissingObjectException,
 			IncorrectObjectTypeException, IOException {
 		free = new BlockFreeList();
 		outputType = s.outputType();
@@ -85,7 +85,7 @@
 	 * sharing the same free list are doing so from only a single thread.
 	 */
 	@Override
-	public void shareFreeList(final BlockRevQueue q) {
+	public void shareFreeList(BlockRevQueue q) {
 		free = q.free;
 	}
 
@@ -101,7 +101,7 @@
 			return b;
 		}
 
-		void freeBlock(final Block b) {
+		void freeBlock(Block b) {
 			b.next = next;
 			next = b;
 		}
@@ -138,11 +138,11 @@
 			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 @@
 
 	Generator g;
 
-	BoundaryGenerator(final RevWalk w, final Generator s) {
+	BoundaryGenerator(RevWalk w, Generator s) {
 		g = new InitialGenerator(w, s);
 	}
 
@@ -64,7 +64,7 @@
 	}
 
 	@Override
-	void shareFreeList(final BlockRevQueue q) {
+	void shareFreeList(BlockRevQueue q) {
 		g.shareFreeList(q);
 	}
 
@@ -85,7 +85,7 @@
 
 		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 @@
 		}
 
 		@Override
-		void shareFreeList(final BlockRevQueue q) {
+		void shareFreeList(BlockRevQueue q) {
 			q.shareFreeList(held);
 		}
 
@@ -107,7 +107,7 @@
 				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 c993fe5..b86e876 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/DateRevQueue.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/DateRevQueue.java
@@ -76,7 +76,7 @@
 		super();
 	}
 
-	DateRevQueue(final Generator s) throws MissingObjectException,
+	DateRevQueue(Generator s) throws MissingObjectException,
 			IncorrectObjectTypeException, IOException {
 		for (;;) {
 			final RevCommit c = s.next();
@@ -88,7 +88,7 @@
 
 	/** {@inheritDoc} */
 	@Override
-	public void add(final RevCommit c) {
+	public void add(RevCommit c) {
 		sinceLastIndex++;
 		if (++inQueue > REBUILD_INDEX_COUNT
 				&& sinceLastIndex > REBUILD_INDEX_COUNT)
@@ -181,7 +181,7 @@
 	}
 
 	@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;
@@ -190,7 +190,7 @@
 	}
 
 	@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;
@@ -212,7 +212,7 @@
 		return s.toString();
 	}
 
-	private Entry newEntry(final RevCommit c) {
+	private Entry newEntry(RevCommit c) {
 		Entry r = free;
 		if (r == null)
 			r = new Entry();
@@ -222,7 +222,7 @@
 		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 @@
 
 	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 @@
 	}
 
 	@Override
-	void shareFreeList(final BlockRevQueue q) {
+	void shareFreeList(BlockRevQueue q) {
 		pending.shareFreeList(q);
 	}
 
@@ -134,7 +134,7 @@
 
 			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/FIFORevQueue.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/FIFORevQueue.java
index 63b7990..cdb084c 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/FIFORevQueue.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/FIFORevQueue.java
@@ -63,14 +63,14 @@
 		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();
@@ -92,7 +92,7 @@
 	 * @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();
@@ -139,7 +139,7 @@
 	}
 
 	@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)
@@ -149,7 +149,7 @@
 	}
 
 	@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)
@@ -158,7 +158,7 @@
 		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++)
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 2da97c8..dae3aac 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/FollowFilter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/FollowFilter.java
@@ -95,7 +95,7 @@
 
 	private RenameCallback renameCallback;
 
-	FollowFilter(final PathFilter path, final DiffConfig cfg) {
+	FollowFilter(PathFilter path, DiffConfig cfg) {
 		this.path = path;
 		this.cfg = cfg;
 	}
@@ -112,7 +112,7 @@
 
 	/** {@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);
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 360be29..45d5f80 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/FooterKey.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/FooterKey.java
@@ -70,7 +70,7 @@
 	 * @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));
 	}
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 074ce82..d6fed66 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/FooterLine.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/FooterLine.java
@@ -86,7 +86,7 @@
 	 *            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;
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 @@
 	 * @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 f734b69..846b8d9 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/LIFORevQueue.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/LIFORevQueue.java
@@ -62,14 +62,14 @@
 		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();
@@ -103,7 +103,7 @@
 	}
 
 	@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)
@@ -113,7 +113,7 @@
 	}
 
 	@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)
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 @@
 
 	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 @@
 		}
 	}
 
-	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 @@
 				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 25c3e12..e5903c9 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/ObjectWalk.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/ObjectWalk.java
@@ -119,7 +119,7 @@
 	 * @param repo
 	 *            the repository the walker will obtain data from.
 	 */
-	public ObjectWalk(final Repository repo) {
+	public ObjectWalk(Repository repo) {
 		this(repo.newObjectReader());
 	}
 
@@ -699,7 +699,7 @@
 
 	/** {@inheritDoc} */
 	@Override
-	protected void reset(final int retainFlags) {
+	protected void reset(int retainFlags) {
 		super.reset(retainFlags);
 
 		for (RevObject obj : rootObjects)
@@ -711,7 +711,7 @@
 		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);
@@ -719,7 +719,7 @@
 		}
 	}
 
-	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 @@
 					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/RevBlob.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevBlob.java
index d352929..cc5e3e4 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevBlob.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevBlob.java
@@ -62,7 +62,7 @@
 	 * @param id
 	 *            object name for the blob.
 	 */
-	protected RevBlob(final AnyObjectId id) {
+	protected RevBlob(AnyObjectId id) {
 		super(id);
 	}
 
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 9db1467..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;
@@ -148,18 +148,18 @@
 	 * @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);
@@ -168,7 +168,7 @@
 		}
 	}
 
-	void parseCanonical(final RevWalk walk, final byte[] raw)
+	void parseCanonical(RevWalk walk, byte[] raw)
 			throws IOException {
 		if (!walk.shallowCommitsInitialized)
 			walk.initializeShallowCommits();
@@ -310,7 +310,7 @@
 	 * @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);
@@ -353,7 +353,7 @@
 	 * @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];
 	}
 
@@ -490,7 +490,7 @@
 		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;
@@ -539,7 +539,7 @@
 		try {
 			return getEncoding();
 		} catch (IllegalCharsetNameException | UnsupportedCharsetException e) {
-			return UTF_8;
+			return CHARSET;
 		}
 	}
 
@@ -615,7 +615,7 @@
 	 *         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));
 	}
 
@@ -630,12 +630,12 @@
 	 *         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());
 		}
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 38cf3f5..d2fda2f 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevCommitList.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevCommitList.java
@@ -91,7 +91,7 @@
 	 *             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());
@@ -165,7 +165,7 @@
 	 *            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());
 	}
 
@@ -207,7 +207,7 @@
 	 * @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;
@@ -238,7 +238,7 @@
 	 * @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;
@@ -265,7 +265,7 @@
 	 *            the walker to populate from.
 	 * @see #fillTo(int)
 	 */
-	public void source(final RevWalk w) {
+	public void source(RevWalk w) {
 		walker = w;
 	}
 
@@ -299,7 +299,7 @@
 	 *             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;
@@ -364,7 +364,7 @@
 	 *             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
@@ -419,7 +419,7 @@
 	 * @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 1e79867..413a552 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevFlag.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevFlag.java
@@ -85,7 +85,7 @@
 
 	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;
@@ -107,7 +107,7 @@
 	}
 
 	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 9740d14..45a730c 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevFlagSet.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevFlagSet.java
@@ -73,7 +73,7 @@
 	 * @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);
 	}
@@ -84,14 +84,14 @@
 	 * @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;
@@ -99,7 +99,7 @@
 
 	/** {@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;
@@ -109,7 +109,7 @@
 
 	/** {@inheritDoc} */
 	@Override
-	public boolean add(final RevFlag flag) {
+	public boolean add(RevFlag flag) {
 		if ((mask & flag.mask) != 0)
 			return false;
 		mask |= flag.mask;
@@ -122,7 +122,7 @@
 
 	/** {@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;
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 4a88105..eef9bf3 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevObject.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevObject.java
@@ -60,7 +60,7 @@
 
 	int flags;
 
-	RevObject(final AnyObjectId name) {
+	RevObject(AnyObjectId name) {
 		super(name);
 	}
 
@@ -93,7 +93,7 @@
 	 *            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;
 	}
 
@@ -105,7 +105,7 @@
 	 * @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;
 	}
 
@@ -117,7 +117,7 @@
 	 * @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;
 	}
 
@@ -129,7 +129,7 @@
 	 * @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;
 	}
 
@@ -139,7 +139,7 @@
 	 * @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;
 	}
 
@@ -151,7 +151,7 @@
 	 * @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;
 	}
 
@@ -161,7 +161,7 @@
 	 * @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;
 	}
 
@@ -183,7 +183,7 @@
 	 * @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 2bb4427..2f21e17 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevObjectList.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevObjectList.java
@@ -82,7 +82,7 @@
 
 	/** {@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,
@@ -147,7 +147,7 @@
 
 		final int shift;
 
-		Block(final int s) {
+		Block(int s) {
 			shift = s;
 		}
 	}
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 d74837e..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;
@@ -137,18 +137,18 @@
 	 * @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);
@@ -157,7 +157,7 @@
 		}
 	}
 
-	void parseCanonical(final RevWalk walk, final byte[] rawTag)
+	void parseCanonical(RevWalk walk, byte[] rawTag)
 			throws CorruptObjectException {
 		final MutableInteger pos = new MutableInteger();
 		final int oType;
@@ -169,7 +169,7 @@
 
 		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;
@@ -257,7 +257,7 @@
 		try {
 			return RawParseUtils.parseEncoding(buffer);
 		} catch (IllegalCharsetNameException | UnsupportedCharsetException e) {
-			return UTF_8;
+			return CHARSET;
 		}
 	}
 
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 92b81a1..e7de270 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevTree.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevTree.java
@@ -62,7 +62,7 @@
 	 * @param id
 	 *            object name for the tree.
 	 */
-	protected RevTree(final AnyObjectId id) {
+	protected RevTree(AnyObjectId id) {
 		super(id);
 	}
 
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 91c15a1..a986cfd 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevWalk.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevWalk.java
@@ -209,7 +209,7 @@
 	 *            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);
 	}
 
@@ -294,7 +294,7 @@
 	 * @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;
@@ -324,10 +324,10 @@
 	 * @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);
 	}
 
@@ -364,7 +364,7 @@
 	 * @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;
@@ -402,7 +402,7 @@
 	 * @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;
@@ -475,7 +475,7 @@
 	 * @param s
 	 *            a sorting strategy to enable.
 	 */
-	public void sort(final RevSort s) {
+	public void sort(RevSort s) {
 		assertNotStarted();
 		sorting.clear();
 		sorting.add(s);
@@ -496,7 +496,7 @@
 	 *            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);
@@ -541,7 +541,7 @@
 	 * @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;
 	}
@@ -582,7 +582,7 @@
 	 *            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;
 	}
@@ -638,7 +638,7 @@
 	 * @param retain
 	 *            true to retain bodies; false to discard them early.
 	 */
-	public void setRetainBody(final boolean retain) {
+	public void setRetainBody(boolean retain) {
 		retainBody = retain;
 	}
 
@@ -653,7 +653,7 @@
 	 * @return reference to the blob object. Never null.
 	 */
 	@NonNull
-	public RevBlob lookupBlob(final AnyObjectId id) {
+	public RevBlob lookupBlob(AnyObjectId id) {
 		RevBlob c = (RevBlob) objects.get(id);
 		if (c == null) {
 			c = new RevBlob(id);
@@ -673,7 +673,7 @@
 	 * @return reference to the tree object. Never null.
 	 */
 	@NonNull
-	public RevTree lookupTree(final AnyObjectId id) {
+	public RevTree lookupTree(AnyObjectId id) {
 		RevTree c = (RevTree) objects.get(id);
 		if (c == null) {
 			c = new RevTree(id);
@@ -696,7 +696,7 @@
 	 * @return reference to the commit object. Never null.
 	 */
 	@NonNull
-	public RevCommit lookupCommit(final AnyObjectId id) {
+	public RevCommit lookupCommit(AnyObjectId id) {
 		RevCommit c = (RevCommit) objects.get(id);
 		if (c == null) {
 			c = createCommit(id);
@@ -716,7 +716,7 @@
 	 * @return reference to the tag object. Never null.
 	 */
 	@NonNull
-	public RevTag lookupTag(final AnyObjectId id) {
+	public RevTag lookupTag(AnyObjectId id) {
 		RevTag c = (RevTag) objects.get(id);
 		if (c == null) {
 			c = new RevTag(id);
@@ -738,7 +738,7 @@
 	 * @return reference to the object. Never null.
 	 */
 	@NonNull
-	public RevObject lookupAny(final AnyObjectId id, final int type) {
+	public RevObject lookupAny(AnyObjectId id, int type) {
 		RevObject r = objects.get(id);
 		if (r == null) {
 			switch (type) {
@@ -793,7 +793,7 @@
 	 *             a pack file or loose object could not be read.
 	 */
 	@NonNull
-	public RevCommit parseCommit(final AnyObjectId id)
+	public RevCommit parseCommit(AnyObjectId id)
 			throws MissingObjectException, IncorrectObjectTypeException,
 			IOException {
 		RevObject c = peel(parseAny(id));
@@ -821,7 +821,7 @@
 	 *             a pack file or loose object could not be read.
 	 */
 	@NonNull
-	public RevTree parseTree(final AnyObjectId id)
+	public RevTree parseTree(AnyObjectId id)
 			throws MissingObjectException, IncorrectObjectTypeException,
 			IOException {
 		RevObject c = peel(parseAny(id));
@@ -856,7 +856,7 @@
 	 *             a pack file or loose object could not be read.
 	 */
 	@NonNull
-	public RevTag parseTag(final AnyObjectId id) throws MissingObjectException,
+	public RevTag parseTag(AnyObjectId id) throws MissingObjectException,
 			IncorrectObjectTypeException, IOException {
 		RevObject c = parseAny(id);
 		if (!(c instanceof RevTag))
@@ -882,7 +882,7 @@
 	 *             a pack file or loose object could not be read.
 	 */
 	@NonNull
-	public RevObject parseAny(final AnyObjectId id)
+	public RevObject parseAny(AnyObjectId id)
 			throws MissingObjectException, IOException {
 		RevObject r = objects.get(id);
 		if (r == null)
@@ -1040,7 +1040,7 @@
 	 * @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);
@@ -1059,7 +1059,7 @@
 	 * @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);
 	}
@@ -1100,7 +1100,7 @@
 	 * @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);
 	}
@@ -1124,7 +1124,7 @@
 	 * @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)
@@ -1141,8 +1141,8 @@
 	 * @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);
 	}
 
@@ -1200,11 +1200,11 @@
 	 * @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;
@@ -1244,7 +1244,7 @@
 	 *            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);
 	}
 
@@ -1262,9 +1262,9 @@
 	 *            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);
 	}
@@ -1286,7 +1286,7 @@
 		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;
@@ -1300,7 +1300,7 @@
 				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;
@@ -1435,11 +1435,11 @@
 	 *            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/RewriteGenerator.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RewriteGenerator.java
index f82301a..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 @@
 
 	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);
 	}
 
@@ -148,7 +148,7 @@
 		}
 	}
 
-	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.
@@ -167,14 +167,14 @@
 		}
 
 		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 @@
 	 * @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 @@
 			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 @@
 	}
 
 	@Override
-	void shareFreeList(final BlockRevQueue q) {
+	void shareFreeList(BlockRevQueue q) {
 		q.shareFreeList(pending);
 	}
 
@@ -113,7 +113,7 @@
 			// 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 99c5d59..1130153 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/TreeRevFilter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/TreeRevFilter.java
@@ -89,7 +89,7 @@
 	 *            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);
 	}
 
@@ -132,7 +132,7 @@
 
 	/** {@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.
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 0019e0c..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
@@ -72,7 +72,7 @@
 	 *            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)
@@ -88,7 +88,7 @@
 	 *            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)
@@ -106,7 +106,7 @@
 	 *            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()];
@@ -123,7 +123,7 @@
 
 		private final boolean requiresCommitBody;
 
-		Binary(final RevFilter one, final RevFilter two) {
+		Binary(RevFilter one, RevFilter two) {
 			a = one;
 			b = two;
 			requiresCommitBody = a.requiresCommitBody()
@@ -131,7 +131,7 @@
 		}
 
 		@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);
@@ -159,7 +159,7 @@
 
 		private final boolean requiresCommitBody;
 
-		List(final RevFilter[] list) {
+		List(RevFilter[] list) {
 			subfilters = list;
 
 			boolean rcb = false;
@@ -169,10 +169,10 @@
 		}
 
 		@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 e00feaf..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
@@ -81,7 +81,7 @@
 		// 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)
@@ -91,12 +91,12 @@
 	}
 
 	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);
 		}
 
@@ -107,12 +107,12 @@
 	}
 
 	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 9f4f10f..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
@@ -64,7 +64,7 @@
 	 *            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());
 	}
 
@@ -75,7 +75,7 @@
 	 *            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);
 	}
 
@@ -86,7 +86,7 @@
 	 *            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());
 	}
 
@@ -97,7 +97,7 @@
 	 *            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);
 	}
 
@@ -109,7 +109,7 @@
 	 * @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());
 	}
 
@@ -121,13 +121,13 @@
 	 * @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);
 	}
 
@@ -144,12 +144,12 @@
 	}
 
 	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;
@@ -163,12 +163,12 @@
 	}
 
 	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
@@ -190,13 +190,13 @@
 	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 4a1b3a6..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
@@ -81,7 +81,7 @@
 		// 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)
@@ -91,12 +91,12 @@
 	}
 
 	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);
 		}
 
@@ -107,12 +107,12 @@
 	}
 
 	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/MessageRevFilter.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/filter/MessageRevFilter.java
index f1f4065..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
@@ -81,7 +81,7 @@
 		// 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)
@@ -90,13 +90,13 @@
 	}
 
 	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);
 		}
 
@@ -107,12 +107,12 @@
 	}
 
 	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 84b7f6b..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
@@ -61,13 +61,13 @@
 	 *            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;
 	}
 
@@ -79,7 +79,7 @@
 
 	/** {@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);
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 a14764a..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
@@ -72,7 +72,7 @@
 	 *            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);
@@ -86,7 +86,7 @@
 	 *            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)
@@ -104,7 +104,7 @@
 	 *            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()];
@@ -121,7 +121,7 @@
 
 		private final boolean requiresCommitBody;
 
-		Binary(final RevFilter one, final RevFilter two) {
+		Binary(RevFilter one, RevFilter two) {
 			a = one;
 			b = two;
 			requiresCommitBody = a.requiresCommitBody()
@@ -129,7 +129,7 @@
 		}
 
 		@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);
@@ -157,7 +157,7 @@
 
 		private final boolean requiresCommitBody;
 
-		List(final RevFilter[] list) {
+		List(RevFilter[] list) {
 			subfilters = list;
 
 			boolean rcb = false;
@@ -167,10 +167,10 @@
 		}
 
 		@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 edce224..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
@@ -72,7 +72,7 @@
 	 * @return same pattern, but re-encoded to match our funny raw UTF-8
 	 *         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++)
@@ -128,7 +128,7 @@
 
 	/** {@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();
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 9068c57..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
@@ -103,7 +103,7 @@
 
 	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;
 		}
 
@@ -128,7 +128,7 @@
 
 	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;
 		}
 
@@ -184,7 +184,7 @@
 
 	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;
 		}
 
@@ -216,7 +216,7 @@
 
 	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);
 		}
 
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 8225e4d..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
@@ -63,7 +63,7 @@
 	 *            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);
@@ -76,9 +76,9 @@
 	 *            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);
 	}
@@ -90,7 +90,7 @@
 	 *            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));
 	}
 
@@ -101,9 +101,9 @@
 	 *            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);
 	}
@@ -115,13 +115,13 @@
 	 *            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;
 	}
 
@@ -138,12 +138,12 @@
 	}
 
 	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);
@@ -156,12 +156,12 @@
 	}
 
 	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/SubStringRevFilter.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/filter/SubStringRevFilter.java
index 3e6b148..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
@@ -65,7 +65,7 @@
 	 *         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) {
@@ -96,13 +96,13 @@
 	 *            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;
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 3f064e3..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,6 +49,8 @@
 
 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;
@@ -164,8 +166,8 @@
 				} 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);
@@ -222,7 +224,7 @@
 			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);
@@ -252,7 +254,7 @@
 		super.clear();
 	}
 
-	private static ObjectId hash(final byte[] rawText) {
+	private static ObjectId hash(byte[] rawText) {
 		return ObjectId.fromRaw(Constants.newMessageDigest().digest(rawText));
 	}
 
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 19fc63e..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
@@ -98,7 +98,7 @@
 	 *            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;
 	}
 
@@ -121,7 +121,7 @@
 	 *            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;
 	}
 
@@ -142,7 +142,7 @@
 	 * @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;
 	}
 
@@ -165,7 +165,7 @@
 	 *            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;
 	}
 
@@ -189,7 +189,7 @@
 	 *            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;
 	}
 
@@ -211,7 +211,7 @@
 	 *            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;
 	}
 
@@ -226,7 +226,7 @@
 	 * @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/storage/pack/PackConfig.java b/org.eclipse.jgit/src/org/eclipse/jgit/storage/pack/PackConfig.java
index 484cde2..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
@@ -1039,7 +1039,7 @@
 	 * @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$
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 2314cf1..ce8995a 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/submodule/SubmoduleWalk.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/submodule/SubmoduleWalk.java
@@ -115,11 +115,13 @@
 	 *
 	 * @param repository
 	 *            a {@link org.eclipse.jgit.lib.Repository} object.
-	 * @return generator over submodule index entries
+	 * @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();
@@ -369,7 +371,7 @@
 	 *            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);
@@ -386,7 +388,7 @@
 	 *            .gitmodules config object
 	 * @return this generator
 	 */
-	public SubmoduleWalk setModulesConfig(final Config config) {
+	public SubmoduleWalk setModulesConfig(Config config) {
 		modulesConfig = config;
 		loadPathNames();
 		return this;
@@ -405,7 +407,7 @@
 	 *            tree containing .gitmodules
 	 * @return this generator
 	 */
-	public SubmoduleWalk setRootTree(final AbstractTreeIterator tree) {
+	public SubmoduleWalk setRootTree(AbstractTreeIterator tree) {
 		rootTree = tree;
 		modulesConfig = null;
 		pathToName = null;
@@ -426,7 +428,7 @@
 	 * @return this generator
 	 * @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;
@@ -560,7 +562,7 @@
 	 * @return this generator
 	 * @throws org.eclipse.jgit.errors.CorruptObjectException
 	 */
-	public SubmoduleWalk setTree(final AbstractTreeIterator iterator)
+	public SubmoduleWalk setTree(AbstractTreeIterator iterator)
 			throws CorruptObjectException {
 		walk.addTree(iterator);
 		return this;
@@ -578,7 +580,7 @@
 	 * @throws MissingObjectException
 	 *             if any.
 	 */
-	public SubmoduleWalk setTree(final AnyObjectId treeId) throws IOException {
+	public SubmoduleWalk setTree(AnyObjectId treeId) throws IOException {
 		walk.addTree(treeId);
 		return this;
 	}
@@ -754,13 +756,11 @@
 	 * @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();
 		}
 	}
 
@@ -771,14 +771,12 @@
 	 * @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();
 		}
 	}
 
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 d7c5b9d..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,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.ByteArrayOutputStream;
 import java.io.File;
@@ -128,14 +128,14 @@
 		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$
@@ -143,7 +143,7 @@
 		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$
 	}
@@ -283,7 +283,7 @@
 	 * @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$
@@ -312,7 +312,7 @@
 	 * @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());
 	}
 
@@ -336,7 +336,7 @@
 	 *             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$
@@ -359,7 +359,7 @@
 	 * @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$
@@ -396,7 +396,7 @@
 	 * @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
@@ -524,12 +524,11 @@
 				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 (;;) {
@@ -545,13 +544,11 @@
 			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)));
@@ -600,10 +597,10 @@
 		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()));
@@ -622,7 +619,7 @@
 		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());
@@ -638,7 +635,7 @@
 		try {
 			final Mac m = Mac.getInstance(HMAC);
 			m.init(privateKey);
-			sec = Base64.encodeBytes(m.doFinal(s.toString().getBytes(UTF_8)));
+			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) {
@@ -647,7 +644,7 @@
 		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();
 		try (FileInputStream in = new FileInputStream(authFile)) {
@@ -667,7 +664,7 @@
 
 		private StringBuilder data;
 
-		ListParser(final String bn, final String p) {
+		ListParser(String bn, String p) {
 			bucket = bn;
 			prefix = p;
 		}
@@ -730,7 +727,7 @@
 		}
 
 		@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 c8d1d22..f6045f6 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BaseConnection.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BaseConnection.java
@@ -85,7 +85,7 @@
 
 	/** {@inheritDoc} */
 	@Override
-	public final Ref getRef(final String name) {
+	public final Ref getRef(String name) {
 		return advertisedRefs.get(name);
 	}
 
@@ -132,7 +132,7 @@
 	 *            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);
 	}
 
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 e9227e3..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 @@
 	/** 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;
@@ -274,7 +274,7 @@
 	 *            option string
 	 * @return whether this option is supported
 	 */
-	protected boolean isCapableOf(final String option) {
+	protected boolean isCapableOf(String option) {
 		return remoteCapablities.contains(option);
 	}
 
@@ -287,7 +287,7 @@
 	 *            option we want
 	 * @return {@code true} if the requested option is supported
 	 */
-	protected boolean wantCapability(final StringBuilder b, final String option) {
+	protected boolean wantCapability(StringBuilder b, String option) {
 		if (!isCapableOf(option))
 			return false;
 		b.append(' ');
@@ -314,7 +314,7 @@
 		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));
 	}
 
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 1383045..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;
@@ -55,7 +53,6 @@
 import java.util.Collections;
 import java.util.Date;
 import java.util.HashSet;
-import java.util.Map;
 import java.util.Set;
 
 import org.eclipse.jgit.errors.PackProtocolException;
@@ -200,6 +197,13 @@
 	 */
 	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. */
@@ -242,13 +246,16 @@
 
 	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) {
@@ -262,6 +269,7 @@
 		}
 		includeTags = transport.getTagOpt() != TagOpt.NO_TAGS;
 		thinPack = transport.isFetchThin();
+		filterBlobLimit = transport.getFilterBlobLimit();
 
 		if (local != null) {
 			walk = new RevWalk(local);
@@ -288,7 +296,7 @@
 
 		final boolean minimalNegotiation;
 
-		FetchConfig(final Config c) {
+		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);
@@ -331,7 +339,7 @@
 
 	/** {@inheritDoc} */
 	@Override
-	public void setPackLockMessage(final String message) {
+	public void setPackLockMessage(String message) {
 		lockMessage = message;
 	}
 
@@ -410,9 +418,9 @@
 		return local.getConfig().get(FetchConfig::new);
 	}
 
-	private int maxTimeWanted(final Collection<Ref> wants) {
+	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) {
@@ -427,10 +435,9 @@
 		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();
@@ -482,10 +489,10 @@
 		}
 	}
 
-	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;
@@ -524,6 +531,11 @@
 		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;
@@ -564,11 +576,16 @@
 					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;
@@ -768,7 +785,7 @@
 			}
 
 			@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.
@@ -789,14 +806,14 @@
 	}
 
 	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) {
@@ -804,7 +821,7 @@
 		}
 	}
 
-	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;
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 ee6f29e..69624ff 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackPushConnection.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackPushConnection.java
@@ -146,7 +146,7 @@
 	 * @param packTransport
 	 *            the transport.
 	 */
-	public BasePackPushConnection(final PackTransport packTransport) {
+	public BasePackPushConnection(PackTransport packTransport) {
 		super(packTransport);
 		thinPack = transport.isPushThin();
 		atomic = transport.isPushAtomic();
@@ -256,7 +256,7 @@
 							pushOptions.toString()));
 		}
 
-		for (final RemoteRefUpdate rru : refUpdates) {
+		for (RemoteRefUpdate rru : refUpdates) {
 			if (!capableDeleteRefs && rru.isDelete()) {
 				rru.setStatus(Status.REJECTED_NODELETE);
 				continue;
@@ -294,7 +294,7 @@
 	}
 
 	private void transmitOptions() throws IOException {
-		for (final String pushOption : pushOptions) {
+		for (String pushOption : pushOptions) {
 			pckOut.writeString(pushOption);
 		}
 
@@ -332,17 +332,17 @@
 		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());
 			}
@@ -365,7 +365,7 @@
 		}
 	}
 
-	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$
@@ -411,7 +411,7 @@
 				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 8f365fc..d3419bc 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BaseReceivePack.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BaseReceivePack.java
@@ -312,7 +312,7 @@
 	 * @param into
 	 *            the destination repository.
 	 */
-	protected BaseReceivePack(final Repository into) {
+	protected BaseReceivePack(Repository into) {
 		db = into;
 		walk = new RevWalk(db);
 
@@ -346,7 +346,7 @@
 		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$
@@ -554,7 +554,7 @@
 	 *            commands before writing output and does not perform the
 	 *            initial advertising.
 	 */
-	public void setBiDirectionalPipe(final boolean twoWay) {
+	public void setBiDirectionalPipe(boolean twoWay) {
 		biDirectionalPipe = twoWay;
 	}
 
@@ -598,7 +598,7 @@
 	 *            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)
@@ -632,7 +632,7 @@
 	 * @param canCreate
 	 *            {@code true} to permit create ref commands to be processed.
 	 */
-	public void setAllowCreates(final boolean canCreate) {
+	public void setAllowCreates(boolean canCreate) {
 		allowCreates = canCreate;
 	}
 
@@ -651,7 +651,7 @@
 	 * @param canDelete
 	 *            {@code true} to permit delete ref commands to be processed.
 	 */
-	public void setAllowDeletes(final boolean canDelete) {
+	public void setAllowDeletes(boolean canDelete) {
 		allowAnyDeletes = canDelete;
 	}
 
@@ -697,7 +697,7 @@
 	 *            {@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;
 	}
 
@@ -747,7 +747,7 @@
 	 *            automatically determined based on the repository
 	 *            configuration.
 	 */
-	public void setRefLogIdent(final PersonIdent pi) {
+	public void setRefLogIdent(PersonIdent pi) {
 		refLogIdent = pi;
 	}
 
@@ -784,7 +784,7 @@
 	 * @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
@@ -801,7 +801,7 @@
 	 * @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;
 	}
 
@@ -822,7 +822,7 @@
 	 *            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;
 	}
 
@@ -867,7 +867,7 @@
 	 * @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;
 	}
 
@@ -880,7 +880,7 @@
 	 *            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)));
@@ -1037,7 +1037,7 @@
 	 *            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();
@@ -1070,7 +1070,7 @@
 	 *            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$
 	}
 
@@ -1221,7 +1221,7 @@
 	 * @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$
@@ -1448,7 +1448,7 @@
 	 * @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;
 		}
@@ -1549,21 +1549,21 @@
 		}
 		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);
 
@@ -1619,7 +1619,7 @@
 	 * 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;
@@ -1784,7 +1784,7 @@
 	 * @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);
 	}
 
@@ -1838,7 +1838,7 @@
 		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$
 				}
@@ -1848,7 +1848,7 @@
 
 		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$
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 39efabf..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 @@
 
 	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 @@
 		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) {
@@ -212,7 +210,7 @@
 
 	/** {@inheritDoc} */
 	@Override
-	public void setPackLockMessage(final String message) {
+	public void setPackLockMessage(String message) {
 		lockMessage = message;
 	}
 
@@ -228,13 +226,13 @@
 		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);
@@ -254,13 +252,13 @@
 				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) {
@@ -284,7 +282,7 @@
 			}
 
 			if (remaining > 0) {
-				for (final RevObject o : commits) {
+				for (RevObject o : commits) {
 					if (!o.has(SEEN))
 						missing.put(o, prereqs.get(o));
 				}
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 35ac779..f2a261b 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BundleWriter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BundleWriter.java
@@ -151,7 +151,7 @@
 	 * @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 @@
 	 * @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 @@
 	 *            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);
 	}
@@ -221,7 +221,7 @@
 			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);
@@ -236,7 +236,7 @@
 			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) {
@@ -245,7 +245,7 @@
 				}
 				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());
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 bcc5110..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,7 +95,7 @@
 	 *            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}
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 2fc5eb2..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;
@@ -107,7 +109,7 @@
 	 *            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$
 
@@ -153,12 +155,17 @@
 
 					@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$
@@ -168,7 +175,9 @@
 
 					@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);
@@ -200,7 +209,7 @@
 	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;
 		}
@@ -224,7 +233,7 @@
 	 *            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;
 	}
 
@@ -411,7 +420,7 @@
 		}
 	}
 
-	void startClient(final Socket s) {
+	void startClient(Socket s) {
 		final DaemonClient dc = new DaemonClient(this);
 
 		final SocketAddress peer = s.getRemoteSocketAddress();
@@ -445,8 +454,8 @@
 		}.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 a9731ac..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,6 +50,8 @@
 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;
@@ -66,11 +68,11 @@
 
 	private OutputStream rawOut;
 
-	DaemonClient(final Daemon d) {
+	DaemonClient(Daemon d) {
 		daemon = d;
 	}
 
-	void setRemoteAddress(final InetAddress ia) {
+	void setRemoteAddress(InetAddress ia) {
 		peer = ia;
 	}
 
@@ -110,7 +112,7 @@
 		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());
@@ -118,6 +120,14 @@
 		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.
@@ -131,6 +141,6 @@
 		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 712eb22..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,7 +45,9 @@
 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;
@@ -65,7 +67,7 @@
 
 	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;
@@ -96,7 +98,7 @@
 	 *            {@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;
 	}
 
@@ -120,7 +122,7 @@
 	 *            enabled state with the <code>daemon.servicename</code> config
 	 *            setting.
 	 */
-	public void setOverridable(final boolean on) {
+	public void setOverridable(boolean on) {
 		overridable = on;
 	}
 
@@ -140,19 +142,20 @@
 	 *            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);
 		try (Repository db = client.getDaemon().openRepository(client, name)) {
 			if (isEnabledFor(db)) {
-				execute(client, db);
+				execute(client, db, extraParameters);
 			}
 		} catch (ServiceMayNotContinueException e) {
 			// An error when opening the repo means the client is expecting a ref
@@ -162,13 +165,14 @@
 		}
 	}
 
-	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 a749fbc..5f74e72 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/DefaultSshSessionFactory.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/DefaultSshSessionFactory.java
@@ -61,7 +61,7 @@
 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/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 @@
 
 	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 117e844..c43ab18 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 @@
 
 	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 @@
 			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 @@
 			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 @@
 				//
 				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 @@
 				.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);
@@ -257,7 +257,7 @@
 		}
 	}
 
-	private void fetchObjects(final ProgressMonitor monitor)
+	private void fetchObjects(ProgressMonitor monitor)
 			throws TransportException {
 		try {
 			conn.setPackLockMessage("jgit fetch " + transport.uri); //$NON-NLS-1$
@@ -271,7 +271,7 @@
 					JGitText.get().peerDidNotSupplyACompleteObjectGraph);
 	}
 
-	private void closeConnection(final FetchResult result) {
+	private void closeConnection(FetchResult result) {
 		if (conn != null) {
 			conn.close();
 			result.addMessages(conn.getMessages());
@@ -295,12 +295,12 @@
 		// 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);
@@ -311,7 +311,7 @@
 		}
 	}
 
-	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();
@@ -320,7 +320,7 @@
 		}
 	}
 
-	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();
@@ -329,7 +329,7 @@
 		}
 	}
 
-	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;
@@ -338,7 +338,7 @@
 			if (lock.lock()) {
 				try (Writer w = new OutputStreamWriter(
 						lock.getOutputStream())) {
-					for (final FetchHeadRecord h : fetchHeadUpdates) {
+					for (FetchHeadRecord h : fetchHeadUpdates) {
 						h.write(w);
 						result.add(h);
 					}
@@ -352,10 +352,10 @@
 
 	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();
 			}
@@ -367,15 +367,15 @@
 		}
 	}
 
-	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)) {
@@ -395,7 +395,7 @@
 	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;
 
@@ -419,7 +419,7 @@
 
 	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;
 			}
@@ -434,12 +434,12 @@
 		}
 	}
 
-	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) {
@@ -497,12 +497,15 @@
 
 	private void deleteStaleTrackingRefs(FetchResult result,
 			BatchRefUpdate batch) throws IOException {
-		final Set<Ref> processed = new HashSet<>();
-		for (final Ref ref : localRefs().values()) {
-			final String refname = ref.getName();
-			for (final RefSpec spec : toFetch) {
+		Set<Ref> processed = new HashSet<>();
+		for (Ref ref : localRefs().values()) {
+			if (ref.isSymbolic()) {
+				continue;
+			}
+			String refname = ref.getName();
+			for (RefSpec spec : toFetch) {
 				if (spec.matchDestination(refname)) {
-					final RefSpec s = spec.expandFromDestination(refname);
+					RefSpec s = spec.expandFromDestination(refname);
 					if (result.getAdvertisedRef(s.getSource()) == null
 							&& processed.add(ref)) {
 						deleteTrackingRef(result, batch, s, ref);
@@ -526,11 +529,11 @@
 		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 @@
 		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 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 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 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 6c26b70..1415334 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/HMACSHA1NonceGenerator.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/HMACSHA1NonceGenerator.java
@@ -43,7 +43,7 @@
 package org.eclipse.jgit.transport;
 
 import static java.nio.charset.StandardCharsets.ISO_8859_1;
-import static java.nio.charset.StandardCharsets.UTF_8;
+import static org.eclipse.jgit.lib.Constants.CHARSET;
 
 import java.io.File;
 import java.security.InvalidKeyException;
@@ -102,7 +102,7 @@
 		}
 
 		String input = path + ":" + String.valueOf(timestamp); //$NON-NLS-1$
-		byte[] rawHmac = mac.doFinal(input.getBytes(UTF_8));
+		byte[] rawHmac = mac.doFinal(input.getBytes(CHARSET));
 		return Long.toString(timestamp) + "-" + toHex(rawHmac); //$NON-NLS-1$
 	}
 
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 c40d963..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,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.HttpSupport.HDR_AUTHORIZATION;
 import static org.eclipse.jgit.util.HttpSupport.HDR_WWW_AUTHENTICATE;
 
@@ -51,6 +51,7 @@
 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 @@
 		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);
@@ -307,15 +307,15 @@
 		}
 
 		@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));
+			String enc = Base64.encodeBytes(ident.getBytes(CHARSET));
 			conn.setRequestProperty(HDR_AUTHORIZATION, type.getSchemeName()
 					+ " " + enc); //$NON-NLS-1$
 		}
@@ -323,7 +323,7 @@
 
 	/** 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;
 
@@ -346,14 +346,14 @@
 		}
 
 		@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$
@@ -430,15 +430,15 @@
 
 		private static String H(String data) {
 			MessageDigest md = newMD5();
-			md.update(data.getBytes(UTF_8));
+			md.update(data.getBytes(CHARSET));
 			return LHEX(md.digest());
 		}
 
 		private static String KD(String secret, String data) {
 			MessageDigest md = newMD5();
-			md.update(secret.getBytes(UTF_8));
+			md.update(secret.getBytes(CHARSET));
 			md.update((byte) ':');
-			md.update(data.getBytes(UTF_8));
+			md.update(data.getBytes(CHARSET));
 			return LHEX(md.digest());
 		}
 
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/JschConfigSessionFactory.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/JschConfigSessionFactory.java
index 2a222fb..eab3b3c 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/JschConfigSessionFactory.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/JschConfigSessionFactory.java
@@ -70,6 +70,7 @@
 import org.slf4j.LoggerFactory;
 
 import com.jcraft.jsch.ConfigRepository;
+import com.jcraft.jsch.ConfigRepository.Config;
 import com.jcraft.jsch.JSch;
 import com.jcraft.jsch.JSchException;
 import com.jcraft.jsch.Session;
@@ -222,10 +223,30 @@
 			session.setUserInfo(new CredentialsProviderUserInfo(session,
 					credentialsProvider));
 		}
+		safeConfig(session, hc.getConfig());
 		configure(hc, session);
 		return session;
 	}
 
+	private void safeConfig(Session session, Config cfg) {
+		// Ensure that Jsch checks all configured algorithms, not just its
+		// built-in ones. Otherwise it may propose an algorithm for which it
+		// doesn't have an implementation, and then run into an NPE if that
+		// algorithm ends up being chosen.
+		copyConfigValueToSession(session, cfg, "Ciphers", "CheckCiphers"); //$NON-NLS-1$ //$NON-NLS-2$
+		copyConfigValueToSession(session, cfg, "KexAlgorithms", "CheckKexes"); //$NON-NLS-1$ //$NON-NLS-2$
+		copyConfigValueToSession(session, cfg, "HostKeyAlgorithms", //$NON-NLS-1$
+				"CheckSignatures"); //$NON-NLS-1$
+	}
+
+	private void copyConfigValueToSession(Session session, Config cfg,
+			String from, String to) {
+		String value = cfg.getValue(from);
+		if (value != null) {
+			session.setConfig(to, value);
+		}
+	}
+
 	private void setUserName(Session session, String userName) {
 		// Jsch 0.1.54 picks up the user name from the ssh config, even if an
 		// explicit user name was given! We must correct that if ~/.ssh/config
@@ -309,7 +330,7 @@
 	 * @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) {
@@ -351,13 +372,15 @@
 	 */
 	protected JSch createDefaultJSch(FS fs) throws JSchException {
 		final JSch jsch = new JSch();
+		JSch.setConfig("ssh-rsa", JSch.getConfig("signature.rsa")); //$NON-NLS-1$ //$NON-NLS-2$
+		JSch.setConfig("ssh-dss", JSch.getConfig("signature.dss")); //$NON-NLS-1$ //$NON-NLS-2$
 		configureJSch(jsch);
 		knownHosts(jsch, fs);
 		identities(jsch, fs);
 		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;
@@ -371,7 +394,7 @@
 		}
 	}
 
-	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;
@@ -383,7 +406,7 @@
 		}
 	}
 
-	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 081d057..e3ef832 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/JschSession.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/JschSession.java
@@ -82,7 +82,7 @@
 	 * @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;
 	}
@@ -145,7 +145,7 @@
 		 * @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 e3f287b..e688f63 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/NetRC.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/NetRC.java
@@ -211,9 +211,7 @@
 		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();
@@ -315,13 +313,6 @@
 				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/OpenSshConfig.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/OpenSshConfig.java
index 4660c40..f5ccdc8 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/OpenSshConfig.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/OpenSshConfig.java
@@ -186,7 +186,7 @@
 	/** 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();
@@ -201,7 +201,7 @@
 	 *            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) {
@@ -211,7 +211,7 @@
 		// 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());
@@ -238,7 +238,7 @@
 		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));
@@ -332,14 +332,14 @@
 		}
 	}
 
-	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)))
@@ -348,7 +348,7 @@
 		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;
@@ -365,7 +365,7 @@
 		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);
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 @@
 	 *            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 @@
 	 * @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 @@
 		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 af5a0b7..49acb4d 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PackParser.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PackParser.java
@@ -200,7 +200,7 @@
 	 * @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;
 
@@ -232,7 +232,7 @@
 	 * @param allow
 	 *            true to enable a thin pack.
 	 */
-	public void setAllowThin(final boolean allow) {
+	public void setAllowThin(boolean allow) {
 		allowThin = allow;
 	}
 
@@ -379,7 +379,7 @@
 	 * @param oc
 	 *            the checker instance; null to disable object checking.
 	 */
-	public void setObjectChecker(final ObjectChecker oc) {
+	public void setObjectChecker(ObjectChecker oc) {
 		objCheck = oc;
 	}
 
@@ -399,7 +399,7 @@
 	 * @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);
 	}
 
@@ -629,7 +629,7 @@
 		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++) {
@@ -819,7 +819,7 @@
 		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;
 	}
@@ -865,7 +865,7 @@
 		return first;
 	}
 
-	private void resolveDeltasWithExternalBases(final ProgressMonitor progress)
+	private void resolveDeltasWithExternalBases(ProgressMonitor progress)
 			throws IOException {
 		growEntries(baseById.size());
 
@@ -873,7 +873,7 @@
 			baseObjectIds = new ObjectIdSubclassMap<>();
 
 		final List<DeltaChain> missing = new ArrayList<>(64);
-		for (final DeltaChain baseId : baseById) {
+		for (DeltaChain baseId : baseById) {
 			if (baseId.head == null)
 				continue;
 
@@ -905,7 +905,7 @@
 						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$
 		}
@@ -1065,7 +1065,7 @@
 		}
 	}
 
-	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));
@@ -1076,7 +1076,6 @@
 		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();
@@ -1085,15 +1084,16 @@
 				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;
@@ -1162,33 +1162,29 @@
 		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();
-			}
 		}
 	}
 
@@ -1228,7 +1224,7 @@
 	}
 
 	// 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--;
@@ -1236,13 +1232,13 @@
 	}
 
 	// 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;
@@ -1640,23 +1636,23 @@
 		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;
@@ -1665,7 +1661,7 @@
 	private static class DeltaChain extends ObjectIdOwnerMap.Entry {
 		UnresolvedDelta head;
 
-		DeltaChain(final AnyObjectId id) {
+		DeltaChain(AnyObjectId id) {
 			super(id);
 		}
 
@@ -1676,7 +1672,7 @@
 			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 80fc0b4..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,7 +75,7 @@
 	 * @param id
 	 *            the identity of the object the new instance tracks.
 	 */
-	public PackedObjectInfo(final AnyObjectId id) {
+	public PackedObjectInfo(AnyObjectId id) {
 		super(id);
 	}
 
@@ -95,7 +95,7 @@
 	 * @param offset
 	 *            offset where written object starts
 	 */
-	public void setOffset(final long offset) {
+	public void setOffset(long offset) {
 		this.offset = offset;
 	}
 
@@ -116,7 +116,7 @@
 	 *            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;
 	}
 
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 87064e1..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 @@
 	/** 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 @@
 		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,6 +154,7 @@
 	 * 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 java.io.IOException
 	 *             the stream cannot be read.
@@ -157,6 +165,10 @@
 			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) {
@@ -232,6 +244,8 @@
 
 		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 48bdd01..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 @@
 	 * @param outputStream
 	 *            stream.
 	 */
-	public PacketLineOut(final OutputStream outputStream) {
+	public PacketLineOut(OutputStream outputStream) {
 		out = outputStream;
 		lenbuffer = new byte[5];
 		flushOnEnd = true;
@@ -104,7 +104,7 @@
 	 *             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));
 	}
 
@@ -147,6 +147,20 @@
 	}
 
 	/**
+	 * 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
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 41af807..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;
@@ -141,7 +141,7 @@
 	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/PushCertificateIdent.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PushCertificateIdent.java
index f9fddbe..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;
@@ -95,7 +95,7 @@
 	 */
 	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] != ' ') {
@@ -129,7 +129,7 @@
 				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);
 	}
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 ab58a33..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;
@@ -192,7 +192,7 @@
 	 * @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() {
@@ -292,7 +292,7 @@
 		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);
 		}
 	}
@@ -473,7 +473,7 @@
 
 		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/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 @@
 			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 @@
 	 *             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 @@
 			}
 			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 @@
 	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 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 8bae5a5..5452704 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PushResult.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PushResult.java
@@ -82,7 +82,7 @@
 	 *            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 e14d18f..d61aeb0 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceiveCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceiveCommand.java
@@ -713,7 +713,7 @@
 	 * @param s
 	 *            the new status code for this command.
 	 */
-	public void setResult(final Result s) {
+	public void setResult(Result s) {
 		setResult(s, null);
 	}
 
@@ -725,7 +725,7 @@
 	 * @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;
 	}
@@ -770,7 +770,7 @@
 	 *            receive-pack session.
 	 * @since 2.0
 	 */
-	public void execute(final BaseReceivePack rp) {
+	public void execute(BaseReceivePack rp) {
 		try {
 			String expTarget = getOldSymref();
 			boolean detach = getNewSymref() != null
@@ -818,11 +818,11 @@
 		}
 	}
 
-	void setRef(final Ref r) {
+	void setRef(Ref r) {
 		ref = r;
 	}
 
-	void setType(final Type t) {
+	void setType(Type t) {
 		type = t;
 	}
 
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 7c5f32a..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 @@
 	 * @param into
 	 *            the destination repository.
 	 */
-	public ReceivePack(final Repository into) {
+	public ReceivePack(Repository into) {
 		super(into);
 		preReceive = PreReceiveHook.NULL;
 		postReceive = PostReceiveHook.NULL;
@@ -154,7 +154,7 @@
 	 * @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;
 	}
 
@@ -178,7 +178,7 @@
 	 * @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;
 	}
 
@@ -288,7 +288,7 @@
 				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$
 						}
 					});
@@ -301,7 +301,7 @@
 				}
 				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$
 					}
 				});
@@ -309,7 +309,7 @@
 			} 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$
 					}
 				});
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 5eb1661..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,7 +66,6 @@
 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 org.eclipse.jgit.transport.UploadPack} and
@@ -74,7 +74,7 @@
 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];
@@ -152,7 +152,7 @@
 		}
 
 		@Override
-		protected void writeOne(final CharSequence line) throws IOException {
+		protected void writeOne(CharSequence line) throws IOException {
 			pckOut.writeString(line.toString());
 		}
 
@@ -176,6 +176,11 @@
 
 	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.
 	 *
@@ -187,6 +192,16 @@
 	}
 
 	/**
+	 * @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>
@@ -199,7 +214,7 @@
 	 *            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;
 	}
 
@@ -253,7 +268,11 @@
 	 * @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);
+		}
 	}
 
 	/**
@@ -267,13 +286,55 @@
 	 * @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;
@@ -281,7 +342,7 @@
 			if (!ref.isPeeled()) {
 				if (repository == null)
 					continue;
-				ref = repository.peel(ref);
+				ref = repository.getRefDatabase().peel(ref);
 			}
 
 			if (ref.getPeeledObjectId() != null)
@@ -290,13 +351,6 @@
 		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>
@@ -324,13 +378,13 @@
 		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);
@@ -351,7 +405,7 @@
 	 *             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);
@@ -361,7 +415,7 @@
 			first = false;
 			if (!capablities.isEmpty()) {
 				tmpLine.append('\0');
-				for (final String capName : capablities) {
+				for (String capName : capablities) {
 					tmpLine.append(' ');
 					tmpLine.append(capName);
 				}
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 bbe4f84..992ddc6 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/RefFilter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/RefFilter.java
@@ -63,7 +63,7 @@
 	 */
 	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/RefSpec.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/RefSpec.java
index e1b306e..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 @@
 	 *            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$
 	}
 
@@ -222,11 +222,11 @@
 	 * @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 @@
 	 *            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;
@@ -293,7 +293,7 @@
 	 *             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)
@@ -332,7 +332,7 @@
 	 *             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)
@@ -372,7 +372,7 @@
 	 *            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 @@
 	 *            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 @@
 	 *            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 @@
 	 *            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());
 	}
 
@@ -425,7 +425,7 @@
 	 *             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 @@
 		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;
@@ -457,7 +457,7 @@
 	 *             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());
 	}
 
@@ -477,7 +477,7 @@
 	 *             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 @@
 		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);
@@ -508,11 +508,11 @@
 	 *             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 @@
 		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$
@@ -569,7 +569,7 @@
 
 	/** {@inheritDoc} */
 	@Override
-	public boolean equals(final Object obj) {
+	public boolean equals(Object obj) {
 		if (!(obj instanceof RefSpec))
 			return false;
 		final RefSpec b = (RefSpec) obj;
@@ -584,7 +584,7 @@
 		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)
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 7b882ec..0a621f1 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/RemoteConfig.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/RemoteConfig.java
@@ -112,7 +112,7 @@
 	 * @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 @@
 
 		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;
 	}
@@ -160,7 +160,7 @@
 	 * @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 @@
 		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 @@
 	 * @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 @@
 			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 @@
 	 *            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 @@
 	 *            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 @@
 	 *            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 @@
 	 *            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 @@
 	 *            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 @@
 	 *            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 @@
 	 *            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 @@
 	 *            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 @@
 	 *            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 @@
 	 *            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,7 +520,7 @@
 	 * @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;
 	}
 
@@ -541,7 +541,7 @@
 	 * @param m
 	 *            true to automatically delete remote refs during push.
 	 */
-	public void setMirror(final boolean m) {
+	public void setMirror(boolean m) {
 		mirror = m;
 	}
 
@@ -562,7 +562,7 @@
 	 *            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 3e9b16e..931653f 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/RemoteRefUpdate.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/RemoteRefUpdate.java
@@ -481,7 +481,7 @@
 		expectedOldObjectId = id;
 	}
 
-	void setStatus(final Status status) {
+	void setStatus(Status status) {
 		this.status = status;
 	}
 
@@ -489,7 +489,7 @@
 		this.fastForward = fastForward;
 	}
 
-	void setMessage(final String message) {
+	void setMessage(String message) {
 		this.message = message;
 	}
 
@@ -501,7 +501,7 @@
 	 * @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
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 15338a3..3100cb4 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/SideBandInputStream.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/SideBandInputStream.java
@@ -133,7 +133,7 @@
 
 	/** {@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();
@@ -203,7 +203,7 @@
 		progressBuffer = pkt;
 	}
 
-	private void doProgressLine(final String msg) throws IOException {
+	private void doProgressLine(String msg) throws IOException {
 		Matcher matcher;
 
 		matcher = P_BOUNDED.matcher(msg);
@@ -239,7 +239,7 @@
 			out.write(msg.getBytes());
 	}
 
-	private void beginTask(final int totalWorkUnits) {
+	private void beginTask(int totalWorkUnits) {
 		monitor.beginTask(remote(currentTask), totalWorkUnits);
 	}
 
@@ -254,7 +254,7 @@
 		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 af65827..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 @@
 	 *            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,
@@ -136,7 +136,7 @@
 
 	/** {@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) {
@@ -163,7 +163,7 @@
 
 	/** {@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 365545a..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,7 +55,7 @@
 
 	private boolean write;
 
-	SideBandProgressMonitor(final OutputStream os) {
+	SideBandProgressMonitor(OutputStream os) {
 		out = os;
 		write = true;
 	}
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 e002233..ae357df 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/SshSessionFactory.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/SshSessionFactory.java
@@ -80,7 +80,7 @@
 	 *            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
@@ -121,7 +121,7 @@
 	 *            {@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/TagOpt.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TagOpt.java
index e1134e8..cd17913 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TagOpt.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TagOpt.java
@@ -84,7 +84,7 @@
 
 	private final String option;
 
-	private TagOpt(final String o) {
+	private TagOpt(String o) {
 		option = o;
 	}
 
@@ -104,10 +104,10 @@
 	 *            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/TransferConfig.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransferConfig.java
index 4c70725..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 @@
 		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 @@
 	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,15 +176,18 @@
 			}
 		}
 		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");
 	}
 
 	/**
@@ -220,6 +254,14 @@
 	}
 
 	/**
+	 * @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.
 	 *
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 8db796a..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;
@@ -144,17 +143,8 @@
 	}
 
 	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();
@@ -167,15 +157,8 @@
 					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
 		}
 	}
 
@@ -288,7 +271,7 @@
 	 * @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);
@@ -410,7 +393,7 @@
 	 *             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);
 	}
@@ -495,7 +478,7 @@
 			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);
@@ -519,7 +502,7 @@
 		}
 	}
 
-	private static boolean doesNotExist(final RemoteConfig cfg) {
+	private static boolean doesNotExist(RemoteConfig cfg) {
 		return cfg.getURIs().isEmpty() && cfg.getPushURIs().isEmpty();
 	}
 
@@ -536,7 +519,7 @@
 	 * @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);
 	}
@@ -638,7 +621,7 @@
 		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)
@@ -705,12 +688,12 @@
 	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));
 				}
@@ -724,7 +707,7 @@
 	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)
@@ -807,6 +790,8 @@
 	/** 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;
 
@@ -833,7 +818,7 @@
 	 *            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;
@@ -848,7 +833,7 @@
 	 * @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();
@@ -881,7 +866,7 @@
 	 * @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
@@ -903,7 +888,7 @@
 	 * @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;
 	}
 
@@ -927,7 +912,7 @@
 	 *            when it shouldn't
 	 * @see PackTransport
 	 */
-	public void setFetchThin(final boolean fetchThin) {
+	public void setFetchThin(boolean fetchThin) {
 		this.fetchThin = fetchThin;
 	}
 
@@ -950,7 +935,7 @@
 	 *            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)
@@ -1025,7 +1010,7 @@
 	 *            false when it shouldn't
 	 * @see PackTransport
 	 */
-	public void setPushThin(final boolean pushThin) {
+	public void setPushThin(boolean pushThin) {
 		this.pushThin = pushThin;
 	}
 
@@ -1050,7 +1035,7 @@
 	 * @see PackTransport
 	 * @since 4.2
 	 */
-	public void setPushAtomic(final boolean atomic) {
+	public void setPushAtomic(boolean atomic) {
 		this.pushAtomic = atomic;
 	}
 
@@ -1077,17 +1062,34 @@
 	 *
 	 * @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());
@@ -1116,7 +1118,7 @@
 	 *            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;
 	}
 
@@ -1137,7 +1139,7 @@
 	 *            before aborting an IO read or write operation with this
 	 *            remote.
 	 */
-	public void setTimeout(final int seconds) {
+	public void setTimeout(int seconds) {
 		timeout = seconds;
 	}
 
@@ -1204,7 +1206,7 @@
 	 *            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;
 	}
 
@@ -1251,9 +1253,9 @@
 			// 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) {
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 c6191ec..6118cb8 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportAmazonS3.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportAmazonS3.java
@@ -267,7 +267,7 @@
 		}
 
 		@Override
-		WalkRemoteObjectDatabase openAlternate(final String location)
+		WalkRemoteObjectDatabase openAlternate(String location)
 				throws IOException {
 			return new DatabaseS3(bucketName, resolveKey(location));
 		}
@@ -278,7 +278,7 @@
 			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;
 
@@ -290,7 +290,7 @@
 		}
 
 		@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);
@@ -299,7 +299,7 @@
 		}
 
 		@Override
-		void deleteFile(final String path) throws IOException {
+		void deleteFile(String path) throws IOException {
 			s3.delete(bucket, resolveKey(path));
 		}
 
@@ -311,7 +311,7 @@
 		}
 
 		@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);
 		}
 
@@ -323,7 +323,7 @@
 			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
@@ -334,16 +334,13 @@
 			}
 		}
 
-		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;
@@ -377,7 +374,7 @@
 			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/TransportGitAnon.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportGitAnon.java
index 816187e..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,11 +113,11 @@
 		}
 	};
 
-	TransportGitAnon(final Repository local, final URIish uri) {
+	TransportGitAnon(Repository local, URIish uri) {
 		super(local, uri);
 	}
 
-	TransportGitAnon(final URIish uri) {
+	TransportGitAnon(URIish uri) {
 		super(uri);
 	}
 
@@ -142,6 +142,7 @@
 	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());
@@ -162,7 +163,7 @@
 		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 bc85e6f..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 @@
 		}
 	};
 
-	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();
 	}
@@ -176,7 +176,7 @@
 		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));
@@ -311,6 +311,9 @@
 		public void close() {
 			endOut();
 
+			if (process != null) {
+				process.destroy();
+			}
 			if (errorThread != null) {
 				try {
 					errorThread.halt();
@@ -322,8 +325,6 @@
 			}
 
 			super.close();
-			if (process != null)
-				process.destroy();
 		}
 	}
 
@@ -377,6 +378,9 @@
 		public void close() {
 			endOut();
 
+			if (process != null) {
+				process.destroy();
+			}
 			if (errorThread != null) {
 				try {
 					errorThread.halt();
@@ -388,8 +392,6 @@
 			}
 
 			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 a182623..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 @@
 
 	private boolean sslFailure = false;
 
-	TransportHttp(final Repository local, final URIish uri)
+	TransportHttp(Repository local, URIish uri)
 			throws NotSupportedException {
 		super(local, uri);
 		setURI(uri);
@@ -298,7 +298,7 @@
 	 * @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);
@@ -314,7 +314,7 @@
 	 * @param uri
 	 * @throws NotSupportedException
 	 */
-	TransportHttp(final URIish uri) throws NotSupportedException {
+	TransportHttp(URIish uri) throws NotSupportedException {
 		super(uri);
 		setURI(uri);
 		http = new HttpConfig(uri);
@@ -332,10 +332,26 @@
 	 * @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,
@@ -343,21 +359,8 @@
 		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;
@@ -480,7 +483,7 @@
 		this.headers = headers;
 	}
 
-	private HttpConnection connect(final String service)
+	private HttpConnection connect(String service)
 			throws TransportException, NotSupportedException {
 		URL u = getServiceURL(service);
 		int authAttempts = 1;
@@ -772,7 +775,7 @@
 		return true;
 	}
 
-	private URL getServiceURL(final String service)
+	private URL getServiceURL(String service)
 			throws NotSupportedException {
 		try {
 			final StringBuilder b = new StringBuilder();
@@ -796,21 +799,6 @@
 	}
 
 	/**
-	 * 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 java.io.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
@@ -873,18 +861,18 @@
 		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
@@ -915,7 +903,7 @@
 	class HttpObjectDB extends WalkRemoteObjectDatabase {
 		private final URL httpObjectsUrl;
 
-		HttpObjectDB(final URL b) {
+		HttpObjectDB(URL b) {
 			httpObjectsUrl = b;
 		}
 
@@ -942,7 +930,7 @@
 		}
 
 		@Override
-		WalkRemoteObjectDatabase openAlternate(final String location)
+		WalkRemoteObjectDatabase openAlternate(String location)
 				throws IOException {
 			return new HttpObjectDB(new URL(httpObjectsUrl, location));
 		}
@@ -974,7 +962,7 @@
 		}
 
 		@Override
-		FileStream open(final String path) throws IOException {
+		FileStream open(String path) throws IOException {
 			return open(path, AcceptEncoding.UNSPECIFIED);
 		}
 
@@ -1042,15 +1030,15 @@
 			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));
 		}
 
@@ -1063,7 +1051,7 @@
 	class SmartHttpFetchConnection extends BasePackFetchConnection {
 		private MultiRequestService svc;
 
-		SmartHttpFetchConnection(final InputStream advertisement)
+		SmartHttpFetchConnection(InputStream advertisement)
 				throws TransportException {
 			super(TransportHttp.this);
 			statelessRPC = true;
@@ -1093,7 +1081,7 @@
 	}
 
 	class SmartHttpPushConnection extends BasePackPushConnection {
-		SmartHttpPushConnection(final InputStream advertisement)
+		SmartHttpPushConnection(InputStream advertisement)
 				throws TransportException {
 			super(TransportHttp.this);
 			statelessRPC = true;
@@ -1396,7 +1384,7 @@
 	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 4f1880b..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,11 +162,11 @@
 		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);
 	}
 
@@ -229,7 +229,7 @@
 	 * @throws org.eclipse.jgit.errors.TransportException
 	 *             if any.
 	 */
-	protected Process spawn(final String cmd)
+	protected Process spawn(String cmd)
 			throws TransportException {
 		try {
 			String[] args = { "." }; //$NON-NLS-1$
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 39f9897..f129ba3 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportSftp.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportSftp.java
@@ -136,7 +136,7 @@
 		}
 	};
 
-	TransportSftp(final Repository local, final URIish uri) {
+	TransportSftp(Repository local, URIish uri) {
 		super(local, uri);
 	}
 
@@ -197,7 +197,7 @@
 			}
 		}
 
-		SftpObjectDB(final SftpObjectDB parent, final String p)
+		SftpObjectDB(SftpObjectDB parent, String p)
 				throws TransportException {
 			try {
 				ftp = newSftp();
@@ -229,7 +229,7 @@
 		}
 
 		@Override
-		WalkRemoteObjectDatabase openAlternate(final String location)
+		WalkRemoteObjectDatabase openAlternate(String location)
 				throws IOException {
 			return new SftpObjectDB(this, location);
 		}
@@ -246,9 +246,9 @@
 				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;
@@ -263,7 +263,7 @@
 
 				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();
 					}
@@ -278,7 +278,7 @@
 		}
 
 		@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());
@@ -292,7 +292,7 @@
 		}
 
 		@Override
-		void deleteFile(final String path) throws IOException {
+		void deleteFile(String path) throws IOException {
 			try {
 				ftp.rm(path);
 			} catch (SftpException je) {
@@ -345,7 +345,7 @@
 		}
 
 		@Override
-		void writeFile(final String path, final byte[] data) throws IOException {
+		void writeFile(String path, byte[] data) throws IOException {
 			final String lock = path + LOCK_SUFFIX;
 			try {
 				super.writeFile(lock, data);
@@ -413,7 +413,7 @@
 						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;
@@ -466,7 +466,7 @@
 					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 a048fe3..026fd81 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/URIish.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/URIish.java
@@ -387,7 +387,7 @@
 	 * @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);
@@ -416,7 +416,7 @@
 		// Configure nothing.
 	}
 
-	private URIish(final URIish u) {
+	private URIish(URIish u) {
 		this.scheme = u.scheme;
 		this.rawPath = u.rawPath;
 		this.path = u.path;
@@ -451,7 +451,7 @@
 	 *            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;
@@ -473,7 +473,7 @@
 	 *            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;
@@ -504,7 +504,7 @@
 	 *            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;
@@ -519,7 +519,7 @@
 	 * @return a new URI with the updated value.
 	 * @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;
@@ -542,7 +542,7 @@
 	 *            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;
@@ -564,7 +564,7 @@
 	 *            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;
@@ -586,7 +586,7 @@
 	 *            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;
@@ -613,7 +613,7 @@
 
 	/** {@inheritDoc} */
 	@Override
-	public boolean equals(final Object obj) {
+	public boolean equals(Object obj) {
 		if (!(obj instanceof URIish))
 			return false;
 		final URIish b = (URIish) obj;
@@ -632,7 +632,7 @@
 		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))
@@ -657,7 +657,7 @@
 		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());
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 8f75bba..6a3d9a1 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,16 @@
 
 package org.eclipse.jgit.transport;
 
-import static org.eclipse.jgit.lib.RefDatabase.ALL;
+import static java.util.function.Function.identity;
+import static java.util.stream.Collectors.toMap;
+import static org.eclipse.jgit.lib.Constants.R_TAGS;
+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,10 +73,13 @@
 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;
@@ -101,6 +110,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;
@@ -236,6 +246,12 @@
 	/** 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;
@@ -246,12 +262,18 @@
 
 	private OutputStream msgOut = NullOutputStream.INSTANCE;
 
-	/** The refs we advertised as existing at the start of the connection. */
+	/**
+	 * Refs eligible for advertising to the client, set using
+	 * {@link #setAdvertisedRefs}.
+	 */
 	private Map<String, Ref> refs;
 
 	/** Hook used while advertising the refs to the client. */
 	private AdvertiseRefsHook advertiseRefsHook = AdvertiseRefsHook.DEFAULT;
 
+	/** Whether the {@link #advertiseRefsHook} has been invoked. */
+	private boolean advertiseRefsHookCalled;
+
 	/** Filter used while advertising the refs to the client. */
 	private RefFilter refFilter = RefFilter.DEFAULT;
 
@@ -277,12 +299,22 @@
 	/** 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;
 
@@ -316,8 +348,7 @@
 
 	private PackStatistics statistics;
 
-	@SuppressWarnings("deprecation")
-	private UploadPackLogger logger = UploadPackLogger.NULL;
+	private long filterBlobLimit = -1;
 
 	/**
 	 * Create a new pack upload for an open repository.
@@ -325,7 +356,7 @@
 	 * @param copyFrom
 	 *            the source repository.
 	 */
-	public UploadPack(final Repository copyFrom) {
+	public UploadPack(Repository copyFrom) {
 		db = copyFrom;
 		walk = new RevWalk(db);
 		walk.setRetainBody(false);
@@ -414,7 +445,7 @@
 	 *            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;
 	}
 
@@ -441,7 +472,7 @@
 	 *            commands before writing output and does not perform the
 	 *            initial advertising.
 	 */
-	public void setBiDirectionalPipe(final boolean twoWay) {
+	public void setBiDirectionalPipe(boolean twoWay) {
 		biDirectionalPipe = twoWay;
 	}
 
@@ -544,7 +575,7 @@
 	 * @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
@@ -563,7 +594,7 @@
 	 * @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;
 	}
 
@@ -638,29 +669,6 @@
 	}
 
 	/**
-	 * Get the configured logger.
-	 *
-	 * @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
@@ -679,8 +687,34 @@
 	}
 
 	/**
+	 * 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.
@@ -721,7 +755,11 @@
 
 			pckIn = new PacketLineIn(rawIn);
 			pckOut = new PacketLineOut(rawOut);
-			service();
+			if (useProtocolV2()) {
+				serviceV2();
+			} else {
+				service();
+			}
 		} finally {
 			msgOut = NullOutputStream.INSTANCE;
 			walk.close();
@@ -741,21 +779,6 @@
 	 * @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() {
@@ -767,18 +790,56 @@
 			return refs;
 		}
 
-		advertiseRefsHook.advertiseRefs(this);
+		if (!advertiseRefsHookCalled) {
+			advertiseRefsHook.advertiseRefs(this);
+			advertiseRefsHookCalled = true;
+		}
 		if (refs == null) {
-			setAdvertisedRefs(db.getRefDatabase().getRefs(ALL));
+			// Fall back to all refs.
+			setAdvertisedRefs(
+					db.getRefDatabase().getRefs().stream()
+						.collect(toMap(Ref::getName, identity())));
 		}
 		return refs;
 	}
 
+	private Map<String, Ref> getFilteredRefs(Collection<String> refPrefixes)
+					throws IOException {
+		if (refPrefixes.isEmpty()) {
+			return getAdvertisedOrDefaultRefs();
+		}
+		if (refs == null && !advertiseRefsHookCalled) {
+			advertiseRefsHook.advertiseRefs(this);
+			advertiseRefsHookCalled = true;
+		}
+		if (refs == null) {
+			// Fast path: the advertised refs hook did not set advertised refs.
+			Map<String, Ref> rs = new HashMap<>();
+			for (String p : refPrefixes) {
+				for (Ref r : db.getRefDatabase().getRefsByPrefix(p)) {
+					rs.put(r.getName(), r);
+				}
+			}
+			if (refFilter != RefFilter.DEFAULT) {
+				return refFilter.filter(rs);
+			}
+			return transferConfig.getRefFilter().filter(rs);
+		}
+
+		// Slow path: filter the refs provided by the advertised refs hook.
+		// refFilter has already been applied to refs.
+		return refs.values().stream()
+				.filter(ref -> refPrefixes.stream()
+						.anyMatch(ref.getName()::startsWith))
+				.collect(toMap(Ref::getName, identity()));
+	}
+
 	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));
@@ -808,7 +869,7 @@
 			if (!clientShallowCommits.isEmpty())
 				verifyClientShallow();
 			if (depth != 0)
-				processShallow();
+				processShallow(null, unshallowCommits, true);
 			if (!clientShallowCommits.isEmpty())
 				walk.assumeShallow(clientShallowCommits);
 			sendPack = negotiate(accumulator);
@@ -860,8 +921,278 @@
 			rawOut.stopBuffering();
 		}
 
-		if (sendPack)
-			sendPack(accumulator);
+		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 = getFilteredRefs(refPrefixes);
+
+		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,
+					unshallowCommits);
+		}
+		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) {
@@ -879,7 +1210,23 @@
 		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)) {
@@ -900,19 +1247,29 @@
 				// 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()
@@ -950,14 +1307,50 @@
 	 * @param adv
 	 *            the advertisement formatter.
 	 * @throws java.io.IOException
-	 *             the formatter failed to write an advertisement.
+	 *            the formatter failed to write an advertisement.
 	 * @throws org.eclipse.jgit.transport.ServiceMayNotContinueException
-	 *             the hook denied advertisement.
+	 *            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;
+		}
+
 		Map<String, Ref> advertisedOrDefaultRefs = getAdvertisedOrDefaultRefs();
 
+		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);
@@ -980,6 +1373,9 @@
 				|| 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);
 		findSymrefs(adv, advertisedOrDefaultRefs);
 		advertised = adv.send(advertisedOrDefaultRefs);
@@ -1017,8 +1413,36 @@
 		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 {
@@ -1047,6 +1471,19 @@
 				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$
 
@@ -1118,7 +1555,7 @@
 			}
 
 			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) {
@@ -1133,7 +1570,7 @@
 				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$
@@ -1149,7 +1586,7 @@
 		}
 	}
 
-	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())
@@ -1194,13 +1631,13 @@
 				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;
 				}
 			}
@@ -1226,10 +1663,10 @@
 						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;
 						}
@@ -1241,7 +1678,7 @@
 
 		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;
 		}
 
@@ -1336,7 +1773,7 @@
 				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);
@@ -1356,7 +1793,7 @@
 		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()));
 		}
 	}
 
@@ -1439,7 +1876,7 @@
 		}
 	}
 
-	private void addCommonBase(final RevObject o) {
+	private void addCommonBase(RevObject o) {
 		if (!o.has(COMMON)) {
 			o.add(COMMON);
 			commonBase.add(o);
@@ -1468,7 +1905,7 @@
 		}
 	}
 
-	private boolean wantSatisfied(final RevObject want) throws IOException {
+	private boolean wantSatisfied(RevObject want) throws IOException {
 		if (want.has(SATISFIED))
 			return true;
 
@@ -1489,13 +1926,29 @@
 		return false;
 	}
 
-	private void sendPack(PackStatistics.Accumulator accumulator)
-			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, accumulator);
+				sendPack(true, accumulator, allTags, unshallowCommits);
 			} catch (ServiceMayNotContinueException noPack) {
 				// This was already reported on (below).
 				throw noPack;
@@ -1516,7 +1969,7 @@
 					throw err;
 			}
 		} else {
-			sendPack(false, accumulator);
+			sendPack(false, accumulator, allTags, unshallowCommits);
 		}
 	}
 
@@ -1536,9 +1989,28 @@
 		}
 	}
 
-	@SuppressWarnings("deprecation")
+	/**
+	 * 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) throws IOException {
+			PackStatistics.Accumulator accumulator,
+			@Nullable Collection<Ref> allTags,
+			List<ObjectId> unshallowCommits) throws IOException {
 		ProgressMonitor pm = NullProgressMonitor.INSTANCE;
 		OutputStream packOut = rawOut;
 
@@ -1579,11 +2051,18 @@
 		PackConfig cfg = packConfig;
 		if (cfg == null)
 			cfg = new PackConfig(db);
+		@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);
@@ -1591,6 +2070,8 @@
 			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()) {
@@ -1621,8 +2102,8 @@
 				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
@@ -1640,7 +2121,7 @@
 					}
 
 					if (!ref.isPeeled())
-						ref = db.peel(ref);
+						ref = db.getRefDatabase().peel(ref);
 
 					ObjectId peeledId = ref.getPeeledObjectId();
 					objectId = ref.getObjectId();
@@ -1665,7 +2146,6 @@
 			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/UploadPackLogger.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPackLogger.java
deleted file mode 100644
index 611418d..0000000
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPackLogger.java
+++ /dev/null
@@ -1,77 +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 org.eclipse.jgit.transport.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 org.eclipse.jgit.transport.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 9e14672..0000000
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPackLoggerChain.java
+++ /dev/null
@@ -1,96 +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 org.eclipse.jgit.transport.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);
-	}
-
-	/** {@inheritDoc} */
-	@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/WalkEncryption.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/WalkEncryption.java
index 615e46b..b4248ee 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/WalkEncryption.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/WalkEncryption.java
@@ -128,7 +128,7 @@
 			throw new IOException(MessageFormat.format(JGitText.get().unsupportedEncryptionAlgorithm, v));
 	}
 
-	IOException error(final Throwable why) {
+	IOException error(Throwable why) {
 		return new IOException(MessageFormat
 				.format(JGitText.get().encryptionError,
 				why.getMessage()), why);
@@ -141,7 +141,7 @@
 		}
 
 		@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$
 		}
@@ -240,19 +240,19 @@
 		}
 
 		@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);
@@ -263,7 +263,7 @@
 		}
 
 		@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 6708964..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 @@
 	/** 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();
@@ -259,7 +256,7 @@
 
 	/** {@inheritDoc} */
 	@Override
-	public void setPackLockMessage(final String message) {
+	public void setPackLockMessage(String message) {
 		lockMessage = message;
 	}
 
@@ -268,18 +265,18 @@
 	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(
@@ -302,7 +299,7 @@
 		}
 	}
 
-	private void process(final ObjectId id) throws TransportException {
+	private void process(ObjectId id) throws TransportException {
 		final RevObject obj;
 		try {
 			if (id instanceof RevObject) {
@@ -342,7 +339,7 @@
 		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);
@@ -356,7 +353,7 @@
 		}
 	}
 
-	private void processTree(final RevObject obj) throws TransportException {
+	private void processTree(RevObject obj) throws TransportException {
 		try {
 			treeWalk.reset(obj);
 			while (treeWalk.next()) {
@@ -384,22 +381,22 @@
 		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)) {
@@ -408,7 +405,7 @@
 		}
 	}
 
-	private void downloadObject(final ProgressMonitor pm, final AnyObjectId id)
+	private void downloadObject(ProgressMonitor pm, AnyObjectId id)
 			throws TransportException {
 		if (alreadyHave(id))
 			return;
@@ -462,7 +459,7 @@
 
 				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));
 				}
@@ -474,7 +471,7 @@
 			//
 			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);
@@ -498,7 +495,7 @@
 		}
 	}
 
-	private boolean alreadyHave(final AnyObjectId id) throws TransportException {
+	private boolean alreadyHave(AnyObjectId id) throws TransportException {
 		try {
 			return reader.has(id);
 		} catch (IOException error) {
@@ -689,21 +686,21 @@
 		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) {
@@ -732,7 +729,7 @@
 		}
 	}
 
-	private void markLocalCommitsComplete(final int until)
+	private void markLocalCommitsComplete(int until)
 			throws TransportException {
 		try {
 			for (;;) {
@@ -742,7 +739,7 @@
 				localCommitQueue.next();
 
 				markTreeComplete(c.getTree());
-				for (final RevCommit p : c.getParents())
+				for (RevCommit p : c.getParents())
 					pushLocalCommit(p);
 			}
 		} catch (IOException err) {
@@ -750,7 +747,7 @@
 		}
 	}
 
-	private void pushLocalCommit(final RevCommit p)
+	private void pushLocalCommit(RevCommit p)
 			throws MissingObjectException, IOException {
 		if (p.has(LOCALLY_SEEN))
 			return;
@@ -761,7 +758,7 @@
 		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);
@@ -795,7 +792,7 @@
 		}
 	}
 
-	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) {
@@ -816,7 +813,7 @@
 
 		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$
@@ -834,7 +831,7 @@
 			}
 		}
 
-		void openIndex(final ProgressMonitor pm) throws IOException {
+		void openIndex(ProgressMonitor pm) throws IOException {
 			if (index != null)
 				return;
 			if (tmpIdx == null)
@@ -853,17 +850,12 @@
 			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);
@@ -886,7 +878,7 @@
 			}
 		}
 
-		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 cf50c51..4c75425 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/WalkPushConnection.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/WalkPushConnection.java
@@ -157,7 +157,7 @@
 		// 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);
@@ -177,7 +177,7 @@
 		//
 		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
@@ -196,10 +196,10 @@
 		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());
 				}
@@ -225,14 +225,14 @@
 		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());
@@ -247,7 +247,7 @@
 				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$
@@ -295,7 +295,7 @@
 		}
 	}
 
-	private void safeDelete(final String path) {
+	private void safeDelete(String path) {
 		if (path != null) {
 			try {
 				dest.deleteFile(path);
@@ -307,7 +307,7 @@
 		}
 	}
 
-	private void deleteCommand(final RemoteRefUpdate u) {
+	private void deleteCommand(RemoteRefUpdate u) {
 		final Ref r = newRefs.remove(u.getRemoteName());
 		if (r == null) {
 			// Already gone.
@@ -337,7 +337,7 @@
 		}
 	}
 
-	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(
@@ -354,7 +354,7 @@
 				&& 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$
@@ -374,12 +374,12 @@
 		}
 	}
 
-	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;
@@ -388,7 +388,7 @@
 		// 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 965be50..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 @@
 	 * @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,7 +263,7 @@
 	 *             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 {
+	void writeFile(String path, byte[] data) throws IOException {
 		try (OutputStream os = writeFile(path, null, null)) {
 			os.write(data);
 		}
@@ -278,7 +278,7 @@
 	 * @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);
 	}
 
@@ -291,7 +291,7 @@
 	 * @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$
 	}
 
@@ -309,7 +309,7 @@
 	 *             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);
@@ -333,9 +333,9 @@
 	 *             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');
@@ -361,7 +361,7 @@
 	 *             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));
 	}
@@ -414,7 +414,7 @@
 	 * @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 (BufferedReader br = openReader(ROOT_DIR + Constants.PACKED_REFS)) {
 			readPackedRefsImpl(avail, br);
@@ -475,7 +475,7 @@
 		 *            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;
 		}
@@ -490,7 +490,7 @@
 		 *            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/resolver/FileResolver.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/resolver/FileResolver.java
index 16a6f4a..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
@@ -87,7 +87,7 @@
 	 *            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);
@@ -95,7 +95,7 @@
 
 	/** {@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);
@@ -175,7 +175,7 @@
 	 *
 	 * @param export a boolean.
 	 */
-	public void setExportAll(final boolean export) {
+	public void setExportAll(boolean export) {
 		exportAll = export;
 	}
 
@@ -202,7 +202,7 @@
 	 *            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);
 	}
 
@@ -240,7 +240,7 @@
 		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/treewalk/AbstractTreeIterator.java b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/AbstractTreeIterator.java
index a7900f0..470ed02 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/AbstractTreeIterator.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/AbstractTreeIterator.java
@@ -176,7 +176,7 @@
 	 *            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 @@
 	 *            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 @@
 	 * @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 @@
 	 *            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 @@
 	 * @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 @@
 	 * @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.
@@ -420,7 +420,7 @@
 	 *            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());
 	}
@@ -447,7 +447,7 @@
 	 * @param out
 	 *            buffer to copy the object id into.
 	 */
-	public void getEntryObjectId(final MutableObjectId out) {
+	public void getEntryObjectId(MutableObjectId out) {
 		out.fromRaw(idBuffer(), idOffset());
 	}
 
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 71113a6..0199688 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/CanonicalTreeParser.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/CanonicalTreeParser.java
@@ -119,7 +119,7 @@
 		reset(reader, treeId);
 	}
 
-	private CanonicalTreeParser(final CanonicalTreeParser p) {
+	private CanonicalTreeParser(CanonicalTreeParser p) {
 		super(p);
 	}
 
@@ -140,7 +140,7 @@
 	 * @param treeData
 	 *            the raw tree content.
 	 */
-	public void reset(final byte[] treeData) {
+	public void reset(byte[] treeData) {
 		attributesNode = null;
 		raw = treeData;
 		prevPtr = -1;
@@ -219,7 +219,7 @@
 	 * @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());
 	}
@@ -262,7 +262,7 @@
 
 	/** {@inheritDoc} */
 	@Override
-	public CanonicalTreeParser createSubtreeIterator(final ObjectReader reader)
+	public CanonicalTreeParser createSubtreeIterator(ObjectReader reader)
 			throws IncorrectObjectTypeException, IOException {
 		return createSubtreeIterator(reader, new MutableObjectId());
 	}
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 596d3d0..f5d45c7 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/EmptyTreeIterator.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/EmptyTreeIterator.java
@@ -63,7 +63,7 @@
 		// Create a root empty tree.
 	}
 
-	EmptyTreeIterator(final AbstractTreeIterator p) {
+	EmptyTreeIterator(AbstractTreeIterator p) {
 		super(p);
 		pathLen = pathOffset;
 	}
@@ -92,7 +92,7 @@
 
 	/** {@inheritDoc} */
 	@Override
-	public AbstractTreeIterator createSubtreeIterator(final ObjectReader reader)
+	public AbstractTreeIterator createSubtreeIterator(ObjectReader reader)
 			throws IncorrectObjectTypeException, IOException {
 		return new EmptyTreeIterator(this);
 	}
@@ -141,13 +141,13 @@
 
 	/** {@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.
 	}
 
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 8df764d..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;
@@ -67,6 +68,7 @@
  * {@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.
@@ -130,7 +132,7 @@
 	 * @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);
 	}
 
@@ -171,27 +173,6 @@
 	 *            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) {
@@ -226,19 +207,39 @@
 
 	/** {@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);
 	}
 
 	/**
@@ -267,7 +268,7 @@
 	 *
 	 * @since 4.3
 	 */
-	static public class DefaultFileModeStrategy implements FileModeStrategy {
+	public static class DefaultFileModeStrategy implements FileModeStrategy {
 		/**
 		 * a singleton instance of the default FileModeStrategy
 		 */
@@ -300,7 +301,7 @@
 	 *
 	 * @since 4.3
 	 */
-	static public class NoGitlinksStrategy implements FileModeStrategy {
+	public static class NoGitlinksStrategy implements FileModeStrategy {
 
 		/**
 		 * a singleton instance of the default FileModeStrategy
@@ -325,7 +326,7 @@
 	/**
 	 * 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;
@@ -364,6 +365,29 @@
 			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;
@@ -386,12 +410,12 @@
 
 		@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());
+			}
 		}
 
 		/**
@@ -426,7 +450,7 @@
 
 	/** {@inheritDoc} */
 	@Override
-	protected byte[] idSubmodule(final Entry e) {
+	protected byte[] idSubmodule(Entry e) {
 		return idSubmodule(getDirectory(), e);
 	}
 
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 5560f77..61b130f 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/NameConflictTreeWalk.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/NameConflictTreeWalk.java
@@ -99,7 +99,7 @@
 	 * @param repo
 	 *            the repository the walker will obtain data from.
 	 */
-	public NameConflictTreeWalk(final Repository repo) {
+	public NameConflictTreeWalk(Repository repo) {
 		super(repo);
 	}
 
@@ -112,7 +112,7 @@
 	 *            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);
 	}
 
@@ -122,7 +122,7 @@
 	 * @param or
 	 *            the reader the walker will obtain tree data from.
 	 */
-	public NameConflictTreeWalk(final ObjectReader or) {
+	public NameConflictTreeWalk(ObjectReader or) {
 		super(or);
 	}
 
@@ -135,7 +135,7 @@
 
 			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;
@@ -222,16 +222,16 @@
 		return FileMode.GITLINK.equals(p.mode);
 	}
 
-	private static boolean isTree(final AbstractTreeIterator p) {
+	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;
 
@@ -260,14 +260,14 @@
 		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;
 
@@ -306,7 +306,7 @@
 			// 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;
 
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 8872689..d500aae 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/TreeWalk.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/TreeWalk.java
@@ -332,7 +332,7 @@
 	 *            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);
 	}
 
@@ -348,7 +348,7 @@
 	 *            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);
 	}
 
@@ -359,7 +359,7 @@
 	 *            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);
 	}
 
@@ -447,7 +447,7 @@
 	 * @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;
 	}
 
@@ -475,7 +475,7 @@
 	 * @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;
 	}
 
@@ -505,7 +505,7 @@
 	 *            true to get trees after their children.
 	 * @see #isPostOrderTraversal()
 	 */
-	public void setPostOrderTraversal(final boolean b) {
+	public void setPostOrderTraversal(boolean b) {
 		postOrderTraversal = b;
 	}
 
@@ -633,22 +633,6 @@
 	}
 
 	/**
-	 * Get the EOL stream type of the current entry using the config and
-	 * {@link #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 org.eclipse.jgit.treewalk.TreeWalk} is not based on
-	 *         a working tree
-	 * @since 4.3
-	 * @deprecated use {@link #getEolStreamType(OperationType)} instead.
-	 */
-	@Deprecated
-	public @Nullable EolStreamType getEolStreamType() {
-		return (getEolStreamType(operationType));
-	}
-
-	/**
 	 * Reset this walker so new tree iterators can be added to it.
 	 */
 	public void reset() {
@@ -677,7 +661,7 @@
 	 * @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];
@@ -718,7 +702,7 @@
 	 * @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;
@@ -773,7 +757,7 @@
 	 * @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));
 	}
@@ -936,7 +920,7 @@
 	 * @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;
 	}
@@ -952,7 +936,7 @@
 	 *            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));
 	}
 
@@ -987,7 +971,7 @@
 	 * @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();
@@ -1009,7 +993,7 @@
 	 *            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);
@@ -1028,7 +1012,7 @@
 	 *         <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];
@@ -1126,7 +1110,7 @@
 	 *         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;
@@ -1179,7 +1163,7 @@
 	 *         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;
@@ -1229,7 +1213,7 @@
 	 * @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;
@@ -1377,7 +1361,7 @@
 			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)
@@ -1386,18 +1370,18 @@
 		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);
 	}
 
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 68cc7cb..179fd46 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeIterator.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeIterator.java
@@ -211,7 +211,7 @@
 	 * @param p
 	 *            parent tree iterator.
 	 */
-	protected WorkingTreeIterator(final WorkingTreeIterator p) {
+	protected WorkingTreeIterator(WorkingTreeIterator p) {
 		super(p);
 		state = p.state;
 		repository = p.repository;
@@ -256,6 +256,45 @@
 		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() {
@@ -340,30 +379,22 @@
 	 * @return non-null submodule id
 	 */
 	protected byte[] idSubmodule(File directory, Entry e) {
-		final Repository submoduleRepo;
-		try {
-			submoduleRepo = SubmoduleWalk.getSubmoduleRepository(directory,
-					e.getName(),
-					repository != null ? repository.getFS() : FS.DETECTED);
+		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',
@@ -372,7 +403,7 @@
 	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)
@@ -430,7 +461,7 @@
 		return filterClean(is, opType);
 	}
 
-	private static void safeClose(final InputStream in) {
+	private static void safeClose(InputStream in) {
 		try {
 			in.close();
 		} catch (IOException err2) {
@@ -548,7 +579,7 @@
 
 	/** {@inheritDoc} */
 	@Override
-	public void next(final int delta) throws CorruptObjectException {
+	public void next(int delta) throws CorruptObjectException {
 		ptr += delta;
 		if (!eof()) {
 			parseEntry();
@@ -557,7 +588,7 @@
 
 	/** {@inheritDoc} */
 	@Override
-	public void back(final int delta) throws CorruptObjectException {
+	public void back(int delta) throws CorruptObjectException {
 		ptr -= delta;
 		parseEntry();
 	}
@@ -662,7 +693,7 @@
 	 * @throws java.io.IOException
 	 *             a relevant ignore rule file exists but cannot be read.
 	 */
-	protected boolean isEntryIgnored(final int pLen) throws IOException {
+	protected boolean isEntryIgnored(int pLen) throws IOException {
 		return isEntryIgnored(pLen, mode);
 	}
 
@@ -677,7 +708,7 @@
 	 * @throws IOException
 	 *             a relevant ignore rule file exists but cannot be read.
 	 */
-	private boolean isEntryIgnored(final int pLen, int fileMode)
+	private boolean isEntryIgnored(int pLen, int fileMode)
 			throws IOException {
 		// The ignore code wants path to start with a '/' if possible.
 		// If we have the '/' in our path buffer because we are inside
@@ -756,7 +787,7 @@
 	 *            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.
@@ -838,7 +869,7 @@
 	 *            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.
@@ -992,7 +1023,7 @@
 	 *            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;
@@ -1173,13 +1204,17 @@
 		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()));
@@ -1280,11 +1315,8 @@
 
 		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;
 		}
@@ -1332,11 +1364,8 @@
 		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();
 				}
 			}
 		}
@@ -1353,11 +1382,8 @@
 
 		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;
 		}
@@ -1378,7 +1404,10 @@
 		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<>();
 
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 2dfb203..846fb6e 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeOptions.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeOptions.java
@@ -74,7 +74,7 @@
 
 	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,
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 6d40a4e..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
@@ -71,7 +71,7 @@
 	 *            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)
@@ -87,7 +87,7 @@
 	 *            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)
@@ -105,7 +105,7 @@
 	 *            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()];
@@ -120,13 +120,13 @@
 
 		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;
@@ -170,12 +170,12 @@
 	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;
@@ -186,7 +186,7 @@
 				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;
@@ -200,7 +200,7 @@
 
 		@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 653786b..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 @@
 		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 @@
 	 *            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 @@
 		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;
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 81b8e6d..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
@@ -63,7 +63,7 @@
 
 	/** {@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;
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 3403c78..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
@@ -62,7 +62,7 @@
 	 * @param workdirTreeIndex
 	 *            index of the workdir tree in the tree walk
 	 */
-	public NotIgnoredFilter(final int workdirTreeIndex) {
+	public NotIgnoredFilter(int workdirTreeIndex) {
 		this.index = workdirTreeIndex;
 	}
 
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 2e023d0..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
@@ -61,13 +61,13 @@
 	 *            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;
 	}
 
@@ -79,7 +79,7 @@
 
 	/** {@inheritDoc} */
 	@Override
-	public boolean include(final TreeWalk walker)
+	public boolean include(TreeWalk walker)
 			throws MissingObjectException, IncorrectObjectTypeException,
 			IOException {
 		return matchFilter(walker) == 0;
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 dbb062b..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
@@ -71,7 +71,7 @@
 	 *            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);
@@ -85,7 +85,7 @@
 	 *            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)
@@ -103,7 +103,7 @@
 	 *            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()];
@@ -118,13 +118,13 @@
 
 		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;
@@ -168,12 +168,12 @@
 	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;
@@ -184,7 +184,7 @@
 				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;
@@ -198,7 +198,7 @@
 
 		@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 2f7f5cd..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
@@ -86,7 +86,7 @@
 
 	final byte[] pathRaw;
 
-	private PathFilter(final String s) {
+	private PathFilter(String s) {
 		pathStr = s;
 		pathRaw = Constants.encode(pathStr);
 	}
@@ -102,20 +102,20 @@
 
 	/** {@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;
@@ -143,7 +143,7 @@
 	 * @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 0652288..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
@@ -82,13 +82,13 @@
 	 *            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);
 	}
@@ -109,7 +109,7 @@
 	 *            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);
@@ -131,7 +131,7 @@
 	 *            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);
@@ -140,7 +140,7 @@
 		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);
@@ -151,13 +151,13 @@
 
 		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;
@@ -188,7 +188,7 @@
 
 		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:
@@ -239,7 +239,7 @@
 		}
 
 		@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 553e6bd..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
@@ -84,7 +84,7 @@
 	final String pathStr;
 	final byte[] pathRaw;
 
-	private PathSuffixFilter(final String s) {
+	private PathSuffixFilter(String s) {
 		pathStr = s;
 		pathRaw = Constants.encode(pathStr);
 	}
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 f0a7632..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
@@ -91,7 +91,7 @@
 
 	private static final class AllFilter extends TreeFilter {
 		@Override
-		public boolean include(final TreeWalk walker) {
+		public boolean include(TreeWalk walker) {
 			return true;
 		}
 
@@ -133,7 +133,7 @@
 		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;
@@ -221,7 +221,7 @@
 	 *             as thrown by {@link #include(TreeWalk)}
 	 * @since 4.7
 	 */
-	public int matchFilter(final TreeWalk walker)
+	public int matchFilter(TreeWalk walker)
 			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 0c27ced..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,9 +6,8 @@
 
 package org.eclipse.jgit.util;
 
-import static java.nio.charset.StandardCharsets.UTF_8;
+import static org.eclipse.jgit.lib.Constants.CHARSET;
 
-import java.nio.charset.StandardCharsets;
 import java.text.MessageFormat;
 import java.util.Arrays;
 
@@ -55,7 +54,7 @@
 				+ "abcdefghijklmnopqrstuvwxyz" // //$NON-NLS-1$
 				+ "0123456789" // //$NON-NLS-1$
 				+ "+/" // //$NON-NLS-1$
-		).getBytes(UTF_8);
+		).getBytes(CHARSET);
 
 		DEC = new byte[128];
 		Arrays.fill(DEC, INVALID_DEC);
@@ -178,7 +177,7 @@
 			e += 4;
 		}
 
-		return new String(outBuff, 0, e, StandardCharsets.UTF_8);
+		return new String(outBuff, 0, e, CHARSET);
 	}
 
 	/**
@@ -294,7 +293,7 @@
 	 * @return the decoded data
 	 */
 	public static byte[] decode(String s) {
-		byte[] bytes = s.getBytes(UTF_8);
+		byte[] bytes = s.getBytes(CHARSET);
 		return decode(bytes, 0, bytes.length);
 	}
 }
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 9915bdf..6b58790 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/CachedAuthenticator.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/CachedAuthenticator.java
@@ -61,7 +61,7 @@
 	 * @param ca
 	 *            the information we should remember.
 	 */
-	public static void add(final CachedAuthentication ca) {
+	public static void add(CachedAuthentication ca) {
 		cached.add(ca);
 	}
 
@@ -70,7 +70,7 @@
 	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/FS.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/FS.java
index cffcb55..d093818 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/FS.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/FS.java
@@ -76,6 +76,9 @@
 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;
@@ -87,6 +90,14 @@
 	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)}.
 	 *
@@ -384,7 +395,7 @@
 	 * @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;
@@ -473,11 +484,11 @@
 	 * @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())
@@ -975,6 +986,29 @@
 	}
 
 	/**
+	 * 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>
@@ -1111,7 +1145,7 @@
 	 *         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;
@@ -1196,19 +1230,23 @@
 					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) {
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 45237c4..8795329 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
@@ -399,7 +399,7 @@
 			Integer nlink = (Integer) (Files.getAttribute(lockPath,
 					"unix:nlink")); //$NON-NLS-1$
 			if (nlink > 2) {
-				LOG.warn("nlink of link to lock file {0} was not 2 but {1}", //$NON-NLS-1$
+				LOG.warn("nlink of link to lock file {} was not 2 but {}", //$NON-NLS-1$
 						lock.getPath(), nlink);
 				return false;
 			} else if (nlink < 2) {
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 29fe5dc..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;
 
@@ -97,13 +107,13 @@
 
 	/** {@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;
 	}
 
@@ -121,6 +131,49 @@
 
 	/** {@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$
 		File gitExe = searchPath(path, "git.exe", "git.cmd"); //$NON-NLS-1$ //$NON-NLS-2$
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 64cdcc3..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;
@@ -117,14 +119,14 @@
 
 	/** {@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;
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 96f2175..0000000
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/FileUtil.java
+++ /dev/null
@@ -1,303 +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 org.eclipse.jgit.util.FS.Attributes;
-
-/**
- * File utilities using Java 7 NIO2
- */
-@Deprecated
-public class FileUtil {
-
-	/**
-	 * Read target path of a symlink.
-	 *
-	 * @param path
-	 *            a {@link java.io.File}.
-	 * @return target path of the symlink.
-	 * @throws java.io.IOException
-	 * @deprecated use {@link org.eclipse.jgit.util.FileUtils#readSymLink(File)}
-	 *             instead
-	 */
-	@Deprecated
-	public static String readSymlink(File path) throws IOException {
-		return FileUtils.readSymLink(path);
-	}
-
-	/**
-	 * Create a symlink
-	 *
-	 * @param path
-	 *            path of the symlink to be created
-	 * @param target
-	 *            target of the symlink to be created
-	 * @throws java.io.IOException
-	 * @deprecated use
-	 *             {@link org.eclipse.jgit.util.FileUtils#createSymLink(File, String)}
-	 *             instead
-	 */
-	@Deprecated
-	public static void createSymLink(File path, String target)
-			throws IOException {
-		FileUtils.createSymLink(path, target);
-	}
-
-	/**
-	 * Whether the passed file is a symlink
-	 *
-	 * @param path
-	 *            a {@link java.io.File} object.
-	 * @return {@code true} if the passed path is a symlink
-	 * @deprecated Use
-	 *             {@link java.nio.file.Files#isSymbolicLink(java.nio.file.Path)}
-	 *             instead
-	 */
-	@Deprecated
-	public static boolean isSymlink(File path) {
-		return FileUtils.isSymlink(path);
-	}
-
-	/**
-	 * Get lastModified attribute for given path
-	 *
-	 * @param path
-	 *            a {@link java.io.File}.
-	 * @return lastModified attribute for given path
-	 * @throws java.io.IOException
-	 * @deprecated Use
-	 *             {@link java.nio.file.Files#getLastModifiedTime(java.nio.file.Path, java.nio.file.LinkOption...)}
-	 *             instead
-	 */
-	@Deprecated
-	public static long lastModified(File path) throws IOException {
-		return FileUtils.lastModified(path);
-	}
-
-	/**
-	 * Set lastModified attribute for given path
-	 *
-	 * @param path
-	 *            a {@link java.io.File}.
-	 * @param time
-	 *            a long.
-	 * @throws java.io.IOException
-	 * @deprecated Use
-	 *             {@link java.nio.file.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);
-	}
-
-	/**
-	 * Whether this file exists
-	 *
-	 * @param path
-	 *            a {@link java.io.File}.
-	 * @return {@code true} if the given path exists
-	 * @deprecated Use
-	 *             {@link java.nio.file.Files#exists(java.nio.file.Path, java.nio.file.LinkOption...)}
-	 *             instead
-	 */
-	@Deprecated
-	public static boolean exists(File path) {
-		return FileUtils.exists(path);
-	}
-
-	/**
-	 * Whether this file is hidden
-	 *
-	 * @param path
-	 *            a {@link java.io.File}.
-	 * @return {@code true} if the given path is hidden
-	 * @throws java.io.IOException
-	 * @deprecated Use {@link java.nio.file.Files#isHidden(java.nio.file.Path)}
-	 *             instead
-	 */
-	@Deprecated
-	public static boolean isHidden(File path) throws IOException {
-		return FileUtils.isHidden(path);
-	}
-
-	/**
-	 * Set this file hidden
-	 *
-	 * @param path
-	 *            a {@link java.io.File}.
-	 * @param hidden
-	 *            a boolean.
-	 * @throws java.io.IOException
-	 * @deprecated Use
-	 *             {@link org.eclipse.jgit.util.FileUtils#setHidden(File,boolean)}
-	 *             instead
-	 */
-	@Deprecated
-	public static void setHidden(File path, boolean hidden) throws IOException {
-		FileUtils.setHidden(path, hidden);
-	}
-
-	/**
-	 * Get file length
-	 *
-	 * @param path
-	 *            a {@link java.io.File}.
-	 * @return length of the given file
-	 * @throws java.io.IOException
-	 * @deprecated Use {@link org.eclipse.jgit.util.FileUtils#getLength(File)}
-	 *             instead
-	 */
-	@Deprecated
-	public static long getLength(File path) throws IOException {
-		return FileUtils.getLength(path);
-	}
-
-	/**
-	 * Whether the given File is a directory
-	 *
-	 * @param path
-	 *            a {@link java.io.File} object.
-	 * @return {@code true} if the given file is a directory
-	 * @deprecated Use
-	 *             {@link java.nio.file.Files#isDirectory(java.nio.file.Path, java.nio.file.LinkOption...)}
-	 *             instead
-	 */
-	@Deprecated
-	public static boolean isDirectory(File path) {
-		return FileUtils.isDirectory(path);
-	}
-
-	/**
-	 * Whether the given File is a file
-	 *
-	 * @param path
-	 *            a {@link java.io.File} object.
-	 * @return {@code true} if the given file is a file
-	 * @deprecated Use
-	 *             {@link java.nio.file.Files#isRegularFile(java.nio.file.Path, java.nio.file.LinkOption...)}
-	 *             instead
-	 */
-	@Deprecated
-	public static boolean isFile(File path) {
-		return FileUtils.isFile(path);
-	}
-
-	/**
-	 * Whether the given file can be executed
-	 *
-	 * @param path
-	 *            a {@link java.io.File} object.
-	 * @return {@code true} if the given file can be executed
-	 * @deprecated Use {@link org.eclipse.jgit.util.FileUtils#canExecute(File)}
-	 *             instead
-	 */
-	@Deprecated
-	public static boolean canExecute(File path) {
-		return FileUtils.canExecute(path);
-	}
-
-	/**
-	 * Delete the given file
-	 *
-	 * @param path
-	 *            a {@link java.io.File} object.
-	 * @throws java.io.IOException
-	 * @deprecated use {@link org.eclipse.jgit.util.FileUtils#delete(File)}
-	 */
-	@Deprecated
-	public static void delete(File path) throws IOException {
-		FileUtils.delete(path);
-	}
-
-	/**
-	 * Get file system attributes for the given file
-	 *
-	 * @param fs
-	 *            a {@link org.eclipse.jgit.util.FS} object.
-	 * @param path
-	 *            a {@link java.io.File} object.
-	 * @return file system attributes for the given file
-	 * @deprecated Use
-	 *             {@link org.eclipse.jgit.util.FileUtils#getFileAttributesPosix(FS,File)}
-	 *             instead
-	 */
-	@Deprecated
-	public static Attributes getFileAttributesPosix(FS fs, File path) {
-		return FileUtils.getFileAttributesPosix(fs, path);
-	}
-
-	/**
-	 * NFC normalize File (on Mac), otherwise do nothing
-	 *
-	 * @param file
-	 *            a {@link java.io.File}.
-	 * @return on Mac: NFC normalized {@link java.io.File}, otherwise the passed
-	 *         file
-	 * @deprecated Use {@link org.eclipse.jgit.util.FileUtils#normalize(File)}
-	 *             instead
-	 */
-	@Deprecated
-	public static File normalize(File file) {
-		return FileUtils.normalize(file);
-	}
-
-	/**
-	 * NFC normalize file name (on Mac), otherwise do nothing
-	 *
-	 * @param name
-	 *            a {@link java.lang.String} object.
-	 * @return on Mac: NFC normalized form of given name
-	 * @deprecated Use {@link org.eclipse.jgit.util.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 76a7eb6..f1e05e5 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/FileUtils.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/FileUtils.java
@@ -122,7 +122,7 @@
 	 *             {@link java.nio.file.InvalidPathException})
 	 * @since 4.10
 	 */
-	public static Path toPath(final File f) throws IOException {
+	public static Path toPath(File f) throws IOException {
 		try {
 			return f.toPath();
 		} catch (InvalidPathException ex) {
@@ -141,7 +141,7 @@
 	 *             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);
 	}
 
@@ -162,7 +162,7 @@
 	 *             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;
@@ -241,7 +241,7 @@
 	 *             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);
 	}
@@ -321,7 +321,7 @@
 	 *             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);
 	}
@@ -341,7 +341,7 @@
 	 *             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())
@@ -366,7 +366,7 @@
 	 *             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);
 	}
 
@@ -388,7 +388,7 @@
 	 *             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())
@@ -498,33 +498,6 @@
 		throw new IOException(JGitText.get().cannotCreateTempDir);
 	}
 
-
-	/**
-	 * Relativize a path
-	 *
-	 * @deprecated Use the more-clearly-named
-	 *             {@link org.eclipse.jgit.util.FileUtils#relativizeNativePath(String, String)}
-	 *             instead, or directly call
-	 *             {@link org.eclipse.jgit.util.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.
-	 *
-	 *             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
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 a5a858f..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;
@@ -175,11 +177,11 @@
 	 * @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);
 		}
@@ -200,7 +202,7 @@
 	 *             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) {
@@ -228,7 +230,7 @@
 	 * @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();
@@ -273,7 +275,7 @@
 	 *             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);
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 f39d217..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
@@ -76,7 +76,7 @@
 	 * @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);
 	}
@@ -96,10 +96,9 @@
 	 * @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 @@
 			byte[] res = new byte[cnt];
 			System.arraycopy(buf, 0, res, 0, cnt);
 			return res;
-		} finally {
-			try {
-				in.close();
-			} catch (IOException ignored) {
-				// do nothing
-			}
 		}
 	}
 
@@ -136,10 +129,9 @@
 	 * @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 @@
 				buf = nb;
 			}
 			return buf;
-		} finally {
-			try {
-				in.close();
-			} catch (IOException ignored) {
-				// ignore any close errors, this was a read only stream
-			}
 		}
 	}
 
@@ -325,7 +311,7 @@
 	 * @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 @@
 	 * @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++) {
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 24038f0..7441d50 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/IntList.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/IntList.java
@@ -65,7 +65,7 @@
 	 * @param capacity
 	 *            number of entries the list can initially hold.
 	 */
-	public IntList(final int capacity) {
+	public IntList(int capacity) {
 		entries = new int[capacity];
 	}
 
@@ -102,7 +102,7 @@
 	 * @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];
@@ -121,7 +121,7 @@
 	 * @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;
@@ -135,7 +135,7 @@
 	 * @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)
@@ -154,7 +154,7 @@
 	 * @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);
 	}
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 404594c..3bd6e18 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/LongList.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/LongList.java
@@ -67,7 +67,7 @@
 	 * @param capacity
 	 *            number of entries the list can initially hold.
 	 */
-	public LongList(final int capacity) {
+	public LongList(int capacity) {
 		entries = new long[capacity];
 	}
 
@@ -89,7 +89,7 @@
 	 * @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];
@@ -102,7 +102,7 @@
 	 *            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;
@@ -122,7 +122,7 @@
 	 * @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;
@@ -136,7 +136,7 @@
 	 * @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)
@@ -155,7 +155,7 @@
 	 * @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);
 	}
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 09eee42..8c7f672 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/LongMap.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/LongMap.java
@@ -144,7 +144,7 @@
 		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;
@@ -166,14 +166,14 @@
 		}
 	}
 
-	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];
 	}
 
@@ -182,7 +182,7 @@
 		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/QuotedString.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/QuotedString.java
index 77bc249..4d58d06 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/QuotedString.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/QuotedString.java
@@ -99,7 +99,7 @@
 	 * @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);
 	}
@@ -137,7 +137,7 @@
 	 */
 	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;
@@ -160,7 +160,7 @@
 		}
 
 		@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;
@@ -188,7 +188,7 @@
 	/** 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/".
@@ -255,7 +255,7 @@
 		}
 
 		@Override
-		public String quote(final String instr) {
+		public String quote(String instr) {
 			if (instr.length() == 0)
 				return "\"\""; //$NON-NLS-1$
 			boolean reuse = true;
@@ -291,13 +291,13 @@
 		}
 
 		@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 23ee9d0..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,7 +68,7 @@
 	 * @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;
@@ -76,7 +76,7 @@
 
 	/** {@inheritDoc} */
 	@Override
-	public char charAt(final int index) {
+	public char charAt(int index) {
 		return (char) (buffer[startPtr + index] & 0xff);
 	}
 
@@ -88,7 +88,7 @@
 
 	/** {@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);
 	}
 
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 014c772..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,6 +63,7 @@
 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;
 
@@ -125,7 +126,7 @@
 	 *            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++)
@@ -461,7 +462,7 @@
 	 *            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);
 	}
 
@@ -500,7 +501,7 @@
 	 *            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)
@@ -520,7 +521,7 @@
 	 *            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');
 	}
 
@@ -537,7 +538,7 @@
 	 *            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++];
@@ -558,7 +559,7 @@
 	 *            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) {
@@ -579,7 +580,7 @@
 	 *            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');
 	}
 
@@ -597,7 +598,7 @@
 	 * @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) {
@@ -632,11 +633,47 @@
 	 *            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.
@@ -649,11 +686,7 @@
 			}
 
 			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');
@@ -675,7 +708,7 @@
 	 *         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.
@@ -697,7 +730,7 @@
 	 *         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.
@@ -721,7 +754,7 @@
 	 *         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.
@@ -749,7 +782,7 @@
 	 *         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')
@@ -773,7 +806,7 @@
 	 * @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;
@@ -801,7 +834,7 @@
 	 *             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;
@@ -831,7 +864,7 @@
 	 * @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);
 	}
 
@@ -853,7 +886,7 @@
 	 * @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);
@@ -961,7 +994,7 @@
 	 * @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];
@@ -988,7 +1021,7 @@
 	 * @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);
 	}
 
@@ -1026,7 +1059,7 @@
 	 * @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);
 	}
 
@@ -1143,7 +1176,7 @@
 		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);
@@ -1162,7 +1195,7 @@
 	 *            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.
@@ -1186,7 +1219,7 @@
 	 *            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.
@@ -1211,7 +1244,7 @@
 	 * @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'))
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 a8f9bc7..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 @@
 	 *            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 @@
 	 *         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 @@
 		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));
 	}
 
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 c1aaecf..a3f9730 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/RefMap.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/RefMap.java
@@ -169,7 +169,7 @@
 
 	/** {@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()))
@@ -355,7 +355,7 @@
 			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/SshSupport.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/SshSupport.java
new file mode 100644
index 0000000..913aa72
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/SshSupport.java
@@ -0,0 +1,156 @@
+/*
+ * 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.text.MessageFormat;
+
+import org.eclipse.jgit.annotations.Nullable;
+import org.eclipse.jgit.errors.CommandFailedException;
+import org.eclipse.jgit.internal.JGitText;
+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. The timeout may be exceeded in corner
+	 *            cases.
+	 * @return The entire output read from stdout.
+	 * @throws IOException
+	 * @throws CommandFailedException
+	 *             if the ssh command execution failed, error message contains
+	 *             the content of stderr.
+	 */
+	public static String runSshCommand(URIish sshUri,
+			@Nullable CredentialsProvider provider, FS fs, String command,
+			int timeout) throws IOException, CommandFailedException {
+		RemoteSession session = null;
+		Process process = null;
+		StreamCopyThread errorThread = null;
+		StreamCopyThread outThread = null;
+		CommandFailedException failure = null;
+		@SuppressWarnings("resource")
+		MessageWriter stderr = new MessageWriter();
+		try (MessageWriter stdout = 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();
+			outThread = new StreamCopyThread(process.getInputStream(),
+					stdout.getRawStream());
+			outThread.start();
+			try {
+				// waitFor with timeout has a bug - JSch' exitValue() throws the
+				// wrong exception type :(
+				if (process.waitFor() == 0) {
+					return stdout.toString();
+				} else {
+					return null; // still running after timeout
+				}
+			} catch (InterruptedException e) {
+				return null; // error
+			}
+		} finally {
+			if (errorThread != null) {
+				try {
+					errorThread.halt();
+				} catch (InterruptedException e) {
+					// Stop waiting and return anyway.
+				} finally {
+					errorThread = null;
+				}
+			}
+			if (outThread != null) {
+				try {
+					outThread.halt();
+				} catch (InterruptedException e) {
+					// Stop waiting and return anyway.
+				} finally {
+					outThread = null;
+				}
+			}
+			if (process != null) {
+				if (process.exitValue() != 0) {
+					failure = new CommandFailedException(process.exitValue(),
+							MessageFormat.format(
+							JGitText.get().sshCommandFailed, command,
+							stderr.toString()));
+				}
+				process.destroy();
+			}
+			stderr.close();
+			if (session != null) {
+				SshSessionFactory.getInstance().releaseSession(session);
+			}
+			if (failure != null) {
+				throw failure;
+			}
+		}
+	}
+
+}
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 b4736d3..3868e56 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/StringUtils.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/StringUtils.java
@@ -74,7 +74,7 @@
 	 *            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;
 	}
 
@@ -91,7 +91,7 @@
 	 * @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)));
@@ -138,7 +138,7 @@
 	 *            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())
@@ -205,7 +205,7 @@
 	 *             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);
 
@@ -232,7 +232,7 @@
 	 * @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 96a796c..953c976 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/SystemReader.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/SystemReader.java
@@ -237,7 +237,7 @@
 	public abstract FileBasedConfig openUserConfig(Config parent, FS fs);
 
 	/**
-	 * Open the gitonfig configuration found in the system-wide "etc" directory
+	 * Open the gitconfig configuration found in the system-wide "etc" directory
 	 *
 	 * @param parent
 	 *            a config with values not found directly in the returned
@@ -245,7 +245,7 @@
 	 * @param fs
 	 *            the file system abstraction which will be necessary to perform
 	 *            certain file system operations.
-	 * @return the gitonfig configuration found in the system-wide "etc"
+	 * @return the gitconfig configuration found in the system-wide "etc"
 	 *         directory
 	 */
 	public abstract FileBasedConfig openSystemConfig(Config parent, FS fs);
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 dd933a0..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 @@
 	 *            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 @@
 	 *            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;
@@ -116,7 +116,7 @@
 
 	/** {@inheritDoc} */
 	@Override
-	public void write(final int b) throws IOException {
+	public void write(int b) throws IOException {
 		if (overflow != null) {
 			overflow.write(b);
 			return;
@@ -137,7 +137,7 @@
 
 	/** {@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();
@@ -183,7 +183,7 @@
 	 *             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();
@@ -238,7 +238,7 @@
 			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;
 		}
@@ -265,7 +265,7 @@
 					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,11 +288,11 @@
 	 *             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);
 		}
@@ -373,7 +373,7 @@
 		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;
 
@@ -442,7 +442,7 @@
 		 *            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);
 		}
 
@@ -458,7 +458,7 @@
 		 *            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;
 		}
@@ -487,17 +487,14 @@
 			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);
@@ -505,16 +502,13 @@
 			}
 			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();
 			}
 		}
 
@@ -569,7 +563,7 @@
 		 *            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);
 		}
 
@@ -585,7 +579,7 @@
 		 *            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 4566825..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
@@ -100,7 +100,7 @@
 
 	/** {@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;
 
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 e764389..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
@@ -113,7 +113,7 @@
 
 	/** {@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)
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 06f83f3..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
@@ -134,7 +134,7 @@
 
 	/** {@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;
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 32226c4..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
@@ -120,7 +120,7 @@
 
 	/** {@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) {
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 dd9a953..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 org.eclipse.jgit.util.io.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/InterruptTimer.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/InterruptTimer.java
index f400e50..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
@@ -103,7 +103,7 @@
 	 * @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);
@@ -117,7 +117,7 @@
 	 *            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)));
@@ -145,7 +145,7 @@
 	}
 
 	static final class AlarmThread extends Thread {
-		AlarmThread(final String name, final AlarmState q) {
+		AlarmThread(String name, AlarmState q) {
 			super(q);
 			setName(name);
 			setDaemon(true);
@@ -161,7 +161,7 @@
 	private static final class AutoKiller {
 		private final AlarmState state;
 
-		AutoKiller(final AlarmState s) {
+		AutoKiller(AlarmState s) {
 			state = s;
 		}
 
@@ -203,7 +203,7 @@
 			}
 		}
 
-		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 5e50995..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
@@ -99,7 +99,7 @@
 
 	/** {@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>() {
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 69%
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 68b417e..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,39 +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;
 
 /**
- * <p>SafeBufferedOutputStream class.</p>
+ * An implementation of FileInputStream that ignores any exceptions on close().
  *
- * @deprecated use BufferedOutputStream in Java 8 and later.
+ * @since 5.0
  */
-@Deprecated
-public class SafeBufferedOutputStream extends BufferedOutputStream {
+public class SilentFileInputStream extends FileInputStream {
 	/**
-	 * <p>Constructor for SafeBufferedOutputStream.</p>
-	 *
-	 * @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);
 	}
 
-	/**
-	 * <p>Constructor for SafeBufferedOutputStream.</p>
-	 *
-	 * @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 5c1af9ef..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
@@ -73,7 +73,7 @@
 	 *            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;
@@ -81,20 +81,6 @@
 	}
 
 	/**
-	 * 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
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 dee4fe9..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
@@ -89,7 +89,7 @@
 
 	/** {@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();
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 01b2519..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
@@ -89,7 +89,7 @@
 	 * @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)));
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 ea40133..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
@@ -91,7 +91,7 @@
 	 *            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)));
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 51d3106..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
@@ -107,7 +107,7 @@
 	 * @param in
 	 *            the stream to add; must not be null.
 	 */
-	public void add(final InputStream in) {
+	public void add(InputStream in) {
 		streams.add(in);
 	}
 
@@ -164,7 +164,7 @@
 
 	/** {@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) {
diff --git a/pom.xml b/pom.xml
index 162b6d8..3347847 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.11.8-SNAPSHOT</version>
+  <version>5.0.4-SNAPSHOT</version>
 
   <name>JGit - Parent</name>
   <url>${jgit-url}</url>
@@ -213,7 +213,7 @@
     <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>3.0.0</maven-javadoc-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>
@@ -267,63 +267,6 @@
         </plugin>
 
         <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.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.2.0</version>
-            </dependency>
-          </dependencies>
-        </plugin>
-
-        <plugin>
           <artifactId>maven-clean-plugin</artifactId>
           <version>3.0.0</version>
         </plugin>
@@ -343,7 +286,7 @@
         <plugin>
           <groupId>org.apache.maven.plugins</groupId>
           <artifactId>maven-dependency-plugin</artifactId>
-          <version>3.0.2</version>
+          <version>3.1.1</version>
         </plugin>
 
         <plugin>
@@ -541,7 +484,6 @@
         </configuration>
         <executions>
           <execution>
-            <id>attach-javadocs</id>
             <goals>
               <goal>jar</goal>
             </goals>
@@ -596,6 +538,23 @@
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-javadoc-plugin</artifactId>
         <version>${maven-javadoc-plugin-version}</version>
+        <reportSets>
+          <reportSet>
+            <reports>
+              <report>javadoc</report>
+            </reports>
+          </reportSet>
+          <reportSet>
+            <id>aggregate</id>
+            <inherited>false</inherited>
+            <reports>
+              <report>aggregate</report>
+            </reports>
+          </reportSet>
+        </reportSets>
+        <configuration>
+          <additionalJOption>-Xdoclint:-missing</additionalJOption>
+        </configuration>
       </plugin>
       <plugin>
         <groupId>org.apache.maven.plugins</groupId>
@@ -619,6 +578,24 @@
           </reportsDirectories>
         </configuration>
       </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-project-info-reports-plugin</artifactId>
+        <version>2.9</version>
+        <reportSets>
+          <reportSet>
+            <reports>
+              <report>dependencies</report>
+              <report>project-team</report>
+              <report>mailing-list</report>
+              <report>cim</report>
+              <report>issue-tracking</report>
+              <report>license</report>
+              <report>scm</report>
+            </reports>
+          </reportSet>
+        </reportSets>
+      </plugin>
     </plugins>
   </reporting>
 
@@ -762,6 +739,107 @@
 
   <profiles>
     <profile>
+      <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>
+        <activeByDefault>true</activeByDefault>
+      </activation>
+      <build>
+        <plugins>
+          <plugin>
+            <artifactId>maven-compiler-plugin</artifactId>
+            <version>3.7.0</version>
+            <configuration>
+              <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>
+    </profile>
+    <profile>
       <id>static-checks</id>
       <build>
         <plugins>