Merge branch 'stable-5.2' into stable-5.3

* stable-5.2:
  Fix API problem filters
  Fix unclosed resource warning in SmartOutputStream
  JschConfigSessionFactory: fix boxing warning
  SshSupport#runSshCommand: don't throw exception in finally block
  Don't override already managed maven-compiler-plugin version
  Remove unused import from CreateFileSnapshotBenchmark
  Remove duplicate ignore_optional_problems entry in .classpath
  Update maven-site-plugin used by benchmark module to 3.8.2
  Add dependency to enable site generation for benchmark module
  Ignore warnings for generated source code in
org.eclipse.jgit.benchmark
  Fix MBean registration
  Enhance WindowCache statistics

Change-Id: I67a07d92718188bdf7f8a13b83e9f538ecf4b22f
Signed-off-by: Matthias Sohn <matthias.sohn@sap.com>
diff --git a/.bazelrc b/.bazelrc
new file mode 100644
index 0000000..3a61f8c
--- /dev/null
+++ b/.bazelrc
@@ -0,0 +1,9 @@
+build --repository_cache=~/.gerritcodereview/bazel-cache/repository
+build --experimental_strict_action_env
+build --action_env=PATH
+build --disk_cache=~/.gerritcodereview/bazel-cache/cas
+build --java_toolchain //tools:error_prone_warnings_toolchain
+
+test --build_tests_only
+test --test_output=errors
+
diff --git a/README.md b/README.md
index 54133e1..091accd 100644
--- a/README.md
+++ b/README.md
@@ -1,15 +1,16 @@
-Java Git
-========
+# Java Git
 
 An implementation of the Git version control system in pure Java.
 
-This package is licensed under the EDL (Eclipse Distribution
+This project is licensed under the __EDL__ (Eclipse Distribution
 License).
 
-JGit can be imported straight into Eclipse, built and tested from
-there, but the automated builds use Maven.
+JGit can be imported straight into Eclipse and built and tested from
+there. It can be built from the command line using
+[Maven](https://maven.apache.org/) or [Bazel](https://bazel.build/).
+The CI builds use Maven and run on [Jenkins](https://ci.eclipse.org/jgit/).
 
-- org.eclipse.jgit
+- __org.eclipse.jgit__
 
     A pure Java library capable of being run standalone, with no
     additional support libraries. It provides classes to read and
@@ -18,63 +19,73 @@
     All portions of JGit are covered by the EDL. Absolutely no GPL,
     LGPL or EPL contributions are accepted within this package.
 
-- org.eclipse.jgit.ant
+- __org.eclipse.jgit.ant__
 
     Ant tasks based on JGit.
 
-- org.eclipse.jgit.archive
+- __org.eclipse.jgit.archive__
 
     Support for exporting to various archive formats (zip etc).
 
-- org.eclipse.jgit.http.apache
+- __org.eclipse.jgit.http.apache__
 
-    Apache httpclient support
+    [Apache httpclient](https://hc.apache.org/httpcomponents-client-ga/) support.
 
-- org.eclipse.jgit.http.server
+- __org.eclipse.jgit.http.server__
 
-    Server for the smart and dumb Git HTTP protocol.
+    Server for the smart and dumb
+    [Git HTTP protocol](https://github.com/git/git/blob/master/Documentation/technical/http-protocol.txt).
 
-- org.eclipse.jgit.pgm
+- __org.eclipse.jgit.lfs__
 
-    Command-line interface Git commands implemented using JGit
-    ("pgm" stands for program).
+    Support for [LFS](https://git-lfs.github.com/) (Large File Storage).
 
-- org.eclipse.jgit.packaging
+- __org.eclipse.jgit.lfs.server__
+
+    Basic LFS server support.
+
+- __org.eclipse.jgit.packaging__
 
     Production of Eclipse features and p2 repository for JGit. See the JGit
     Wiki on why and how to use this module.
 
-Tests
------
+- __org.eclipse.jgit.pgm__
 
-- org.eclipse.jgit.junit
+    Command-line interface Git commands implemented using JGit
+    ("pgm" stands for program).
 
-    Helpers for unit testing
+- __org.eclipse.jgit.ssh.apache__
 
-- org.eclipse.jgit.test
+    Client support for the ssh protocol based on
+    [Apache Mina sshd](https://mina.apache.org/sshd-project/).
 
-    Unit tests for org.eclipse.jgit
+- __org.eclipse.jgit.ui__
 
-- org.eclipse.jgit.ant.test
-- org.eclipse.jgit.pgm.test
-- org.eclipse.jgit.http.test
-- org.eclipse.jgit.junit.test
+    Simple UI for displaying git log.
 
-    No further description needed
+## Tests
 
-Warnings/Caveats
-----------------
+- __org.eclipse.jgit.junit__, __org.eclipse.jgit.junit.http__,
+__org.eclipse.jgit.junit.ssh__: Helpers for unit testing
+- __org.eclipse.jgit.ant.test__: Unit tests for org.eclipse.jgit.ant
+- __org.eclipse.jgit.http.test__: Unit tests for org.eclipse.jgit.http.server
+- __org.eclipse.jgit.lfs.server.test__: Unit tests for org.eclipse.jgit.lfs.server
+- __org.eclipse.jgit.lfs.test__: Unit tests for org.eclipse.jgit.lfs
+- __org.eclipse.jgit.pgm.test__: Unit tests for org.eclipse.jgit.pgm
+- __org.eclipse.jgit.ssh.apache.test__: Unit tests for org.eclipse.jgit.ssh.apache
+- __org.eclipse.jgit.test__: Unit tests for org.eclipse.jgit
 
-- Native smbolic links are supported, provided the file system supports
-  them. For Windows you must have Windows Vista/Windows 2008 or newer,
-  use a non-administrator account and have the SeCreateSymbolicLinkPrivilege.
+## Warnings/Caveats
 
-- Only the timestamp of the index is used by jgit if the index is
+- Native symbolic links are supported, provided the file system supports
+  them. For Windows you must use a non-administrator account and have the SeCreateSymbolicLinkPrivilege.
+
+- Only the timestamp of the index is used by JGit if the index is
   dirty.
 
 - JGit requires at least a Java 8 JDK.
 
-- CRLF conversion is performed depending on the core.autocrlf setting,
+- CRLF conversion is performed depending on the `core.autocrlf` setting,
   however Git for Windows by default stores that setting during
   installation in the "system wide" configuration file. If Git is not
   installed, use the global or repository configuration for the
@@ -88,102 +99,69 @@
   is installed. Modifying PATH is the recommended option if C Git is
   installed.
 
-- We try to use the same notation of $HOME as C Git does. On Windows
-  this is often not the same value as the user.home system property.
+- We try to use the same notation of `$HOME` as C Git does. On Windows
+  this is often not the same value as the `user.home` system property.
 
+## Features
 
-Package Features
-----------------
-
-- org.eclipse.jgit/
-
-    * Read loose and packed commits, trees, blobs, including
-      deltafied objects.
-
-    * Read objects from shared repositories
-
-    * Write loose commits, trees, blobs.
-
-    * Write blobs from local files or Java InputStreams.
-
-    * Read blobs as Java InputStreams.
-
-    * Copy trees to local directory, or local directory to a tree.
-
-    * Lazily loads objects as necessary.
-
-    * Read and write .git/config files.
-
-    * Create a new repository.
-
-    * Read and write refs, including walking through symrefs.
-
-    * Read, update and write the Git index.
-
-    * Checkout in dirty working directory if trivial.
-
-    * Walk the history from a given set of commits looking for commits
+- __org.eclipse.jgit__
+  - Read loose and packed commits, trees, blobs, including
+    deltafied objects.
+  - Read objects from shared repositories
+  - Write loose commits, trees, blobs.
+  - Write blobs from local files or Java InputStreams.
+  - Read blobs as Java InputStreams.
+  - Copy trees to local directory, or local directory to a tree.
+  - Lazily loads objects as necessary.
+  - Read and write .git/config files.
+  - Create a new repository.
+  - Read and write refs, including walking through symrefs.
+  - Read, update and write the Git index.
+  - Checkout in dirty working directory if trivial.
+  - Walk the history from a given set of commits looking for commits
       introducing changes in files under a specified path.
+  - Object transport
 
-    * Object transport
       Fetch via ssh, git, http, Amazon S3 and bundles.
       Push via ssh, git and Amazon S3. JGit does not yet deltify
       the pushed packs so they may be a lot larger than C Git packs.
 
-    * Garbage collection
+  - Garbage collection
+  - Merge
+  - Rebase
+  - And much more
 
-    * Merge
-
-    * Rebase
-
-    * And much more
-
-- org.eclipse.jgit.pgm/
-
-    * Assorted set of command line utilities. Mostly for ad-hoc testing of jgit
+- __org.eclipse.jgit.pgm__
+  - Assorted set of command line utilities. Mostly for ad-hoc testing of jgit
       log, glog, fetch etc.
+- __org.eclipse.jgit.ant__
+  - Ant tasks
+- __org.eclipse.jgit.archive__
+  - Support for Zip/Tar and other formats
+- __org.eclipse.http__
+  - HTTP client and server support
 
-- org.eclipse.jgit.ant/
-
-    * Ant tasks
-
-- org.eclipse.jgit.archive/
-
-    * Support for Zip/Tar and other formats
-
-- org.eclipse.http.*/
-
-    * HTTP client and server support
-
-Missing Features
-----------------
+## Missing Features
 
 There are some missing features:
 
-- gitattributes support
+- verifying signed commits
+- signing tags
+- signing push
 
+## Support
 
-Support
--------
+Post questions, comments or discussions to the jgit-dev@eclipse.org mailing list.
+You need to be [subscribed](https://dev.eclipse.org/mailman/listinfo/jgit-dev)
+to post. File bugs and enhancement requests in
+[Bugzilla](https://wiki.eclipse.org/EGit/Contributor_Guide#Filing_Bugs).
 
-Post question, comments or patches to the jgit-dev@eclipse.org mailing list.
-You need to be subscribed to post, see here:
+## Contributing
 
-https://dev.eclipse.org/mailman/listinfo/jgit-dev
+See the [EGit Contributor Guide](http://wiki.eclipse.org/EGit/Contributor_Guide).
 
-
-Contributing
-------------
-
-See the EGit Contributor Guide:
-
-http://wiki.eclipse.org/EGit/Contributor_Guide
-
-
-About Git
----------
+## About Git
 
 More information about Git, its repository format, and the canonical
-C based implementation can be obtained from the Git website:
-
-http://git-scm.com/
+C based implementation can be obtained from the
+[Git website](http://git-scm.com/).
diff --git a/WORKSPACE b/WORKSPACE
index 81f9ecc..dc89a6c 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -138,8 +138,8 @@
 
 maven_jar(
     name = "tukaani-xz",
-    artifact = "org.tukaani:xz:1.6",
-    sha1 = "05b6f921f1810bdf90e25471968f741f87168b64",
+    artifact = "org.tukaani:xz:1.8",
+    sha1 = "c4f7d054303948eb6a4066194253886c8af07128",
 )
 
 maven_jar(
@@ -198,46 +198,69 @@
     sha1 = "3edcfe49d2c6053a70a2a47e4e1c2f94998a49cf",
 )
 
-JETTY_VER = "9.4.11.v20180605"
+JETTY_VER = "9.4.14.v20181114"
 
 maven_jar(
     name = "jetty-servlet",
     artifact = "org.eclipse.jetty:jetty-servlet:" + JETTY_VER,
-    sha1 = "66d31900fcfc70e3666f0b3335b6660635154f98",
-    src_sha1 = "930c50de49b9c258d5f0329426cbcac4d3143497",
+    sha1 = "96f501462af425190ff7b63e387692c1aa3af2c8",
+    src_sha1 = "204b8a84adf3ce354138509c42638b5b2d223d1f",
 )
 
 maven_jar(
     name = "jetty-security",
     artifact = "org.eclipse.jetty:jetty-security:" + JETTY_VER,
-    sha1 = "926def86d31ee07ca4b4658833dc6ee6918b8e86",
-    src_sha1 = "019bc7c2a366cbb201950f24dd64d9d9a49b6840",
+    sha1 = "6cbeb2fe9b3cc4f88a7ea040b8a0c4f703cd72ce",
+    src_sha1 = "33555125c5988fca12273f60a0aa545d848de54a",
 )
 
 maven_jar(
     name = "jetty-server",
     artifact = "org.eclipse.jetty:jetty-server:" + JETTY_VER,
-    sha1 = "58353c2f27515b007fc83ae22002feb34fc24714",
-    src_sha1 = "e7d832d74df616137755996b41bc28bb82b3bc42",
+    sha1 = "b36a3d52d78a1df6406f6fa236a6eeff48cbfef6",
+    src_sha1 = "55db20ea68c9c1b0ed264d80e7d75b4988da87a6",
 )
 
 maven_jar(
     name = "jetty-http",
     artifact = "org.eclipse.jetty:jetty-http:" + JETTY_VER,
-    sha1 = "20c35f5336befe35b0bd5c4a63e07170fe7872d7",
-    src_sha1 = "5bc30d1f7e8c4456c22cc85999b8cafd3741bdff",
+    sha1 = "6d0c8ac42e9894ae7b5032438eb4579c2a47f4fe",
+    src_sha1 = "3c4f8a942909cabe6d029f835c185207eb91af75",
 )
 
 maven_jar(
     name = "jetty-io",
     artifact = "org.eclipse.jetty:jetty-io:" + JETTY_VER,
-    sha1 = "d164de1dac18c4ca80a1b783d879c97449909c3b",
-    src_sha1 = "02c0caba292b1cb74cec1d36c6f91dc863c89b5a",
+    sha1 = "a8c6a705ddb9f83a75777d89b0be59fcef3f7637",
+    src_sha1 = "06132108ccabbe181707af911e5a68fd8e8806ff",
 )
 
 maven_jar(
     name = "jetty-util",
     artifact = "org.eclipse.jetty:jetty-util:" + JETTY_VER,
-    sha1 = "f0f25aa2f27d618a04bc7356fa247ae4a05245b3",
-    src_sha1 = "4e5c4c483cfd9804c2fc5d5751866243bbb9d740",
+    sha1 = "5bb3d7a38f7ea54138336591d89dd5867b806c02",
+    src_sha1 = "94e89a8c9f82e38555e95b9f7f58344a247e862c",
+)
+
+BOUNCYCASTLE_VER = "1.60"
+
+maven_jar(
+    name = "bcpg-jdk15on",
+    artifact = "org.bouncycastle:bcpg-jdk15on:" + BOUNCYCASTLE_VER,
+    sha1 = "13c7a199c484127daad298996e95818478431a2c",
+    src_sha1 = "edcd9e86d95e39b4da39bb295efd93bc4f56266e",
+)
+
+maven_jar(
+    name = "bcprov-jdk15on",
+    artifact = "org.bouncycastle:bcprov-jdk15on:" + BOUNCYCASTLE_VER,
+    sha1 = "bd47ad3bd14b8e82595c7adaa143501e60842a84",
+    src_sha1 = "7c57a4d13fe53d9abb967bba600dd0b293dafd6a",
+)
+
+maven_jar(
+    name = "bcpkix-jdk15on",
+    artifact = "org.bouncycastle:bcpkix-jdk15on:" + BOUNCYCASTLE_VER,
+    sha1 = "d0c46320fbc07be3a24eb13a56cee4e3d38e0c75",
+    src_sha1 = "a25f041293f401af08efba63ff4bbdce98134a03",
 )
diff --git a/lib/BUILD b/lib/BUILD
index 7403ce2..47125ed 100644
--- a/lib/BUILD
+++ b/lib/BUILD
@@ -151,6 +151,33 @@
 )
 
 java_library(
+    name = "bcpg",
+    visibility = [
+        "//org.eclipse.jgit:__pkg__",
+        "//org.eclipse.jgit.test:__pkg__",
+    ],
+    exports = ["@bcpg-jdk15on//jar"],
+)
+
+java_library(
+    name = "bcprov",
+    visibility = [
+        "//org.eclipse.jgit:__pkg__",
+        "//org.eclipse.jgit.test:__pkg__",
+    ],
+    exports = ["@bcprov-jdk15on//jar"],
+)
+
+java_library(
+    name = "bcpkix",
+    visibility = [
+        "//org.eclipse.jgit:__pkg__",
+        "//org.eclipse.jgit.test:__pkg__",
+    ],
+    exports = ["@bcpkix-jdk15on//jar"],
+)
+
+java_library(
     name = "jzlib",
     visibility = [
         "//org.eclipse.jgit:__pkg__",
diff --git a/org.eclipse.jgit.ant.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.ant.test/META-INF/MANIFEST.MF
index ad64078..4a03b57 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: 5.2.3.qualifier
+Bundle-Version: 5.3.7.qualifier
 Bundle-ActivationPolicy: lazy
 Bundle-RequiredExecutionEnvironment: JavaSE-1.8
 Import-Package: org.apache.tools.ant,
- org.eclipse.jgit.ant.tasks;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.junit;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.lib;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.util;version="[5.2.3,5.3.0)",
+ org.eclipse.jgit.ant.tasks;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.junit;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.lib;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.util;version="[5.3.7,5.4.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 d75acdb..99c58ca 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>5.2.3-SNAPSHOT</version>
+    <version>5.3.7-SNAPSHOT</version>
   </parent>
 
   <artifactId>org.eclipse.jgit.ant.test</artifactId>
@@ -105,7 +105,7 @@
       <plugin>
         <artifactId>maven-surefire-plugin</artifactId>
         <configuration>
-          <argLine>-Xmx256m -Dfile.encoding=UTF-8 -Djava.io.tmpdir=${project.build.directory}</argLine>
+          <argLine>@{argLine} -Xmx256m -Dfile.encoding=UTF-8 -Djava.io.tmpdir=${project.build.directory}</argLine>
         </configuration>
       </plugin>
     </plugins>
diff --git a/org.eclipse.jgit.ant/META-INF/MANIFEST.MF b/org.eclipse.jgit.ant/META-INF/MANIFEST.MF
index f0bbb7e..d7386e6 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: 5.2.3.qualifier
+Bundle-Version: 5.3.7.qualifier
 Bundle-RequiredExecutionEnvironment: JavaSE-1.8
 Import-Package: org.apache.tools.ant,
-  org.eclipse.jgit.storage.file;version="[5.2.3,5.3.0)"
+  org.eclipse.jgit.storage.file;version="[5.3.7,5.4.0)"
 Bundle-Localization: plugin
 Bundle-Vendor: %Provider-Name
-Export-Package: org.eclipse.jgit.ant.tasks;version="5.2.3";
+Export-Package: org.eclipse.jgit.ant.tasks;version="5.3.7";
  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 f68a015..7f5da47 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>5.2.3-SNAPSHOT</version>
+		<version>5.3.7-SNAPSHOT</version>
 	</parent>
 
 	<artifactId>org.eclipse.jgit.ant</artifactId>
diff --git a/org.eclipse.jgit.ant/src/org/eclipse/jgit/ant/tasks/GitCheckoutTask.java b/org.eclipse.jgit.ant/src/org/eclipse/jgit/ant/tasks/GitCheckoutTask.java
index 0b27cc2..5f80d00 100644
--- a/org.eclipse.jgit.ant/src/org/eclipse/jgit/ant/tasks/GitCheckoutTask.java
+++ b/org.eclipse.jgit.ant/src/org/eclipse/jgit/ant/tasks/GitCheckoutTask.java
@@ -123,7 +123,7 @@ public void execute() throws BuildException {
 		}
 
 		try {
-			checkout.setCreateBranch(createBranch).setForce(force)
+			checkout.setCreateBranch(createBranch).setForceRefUpdate(force)
 					.setName(branch);
 			checkout.call();
 		} catch (Exception e) {
diff --git a/org.eclipse.jgit.archive/META-INF/MANIFEST.MF b/org.eclipse.jgit.archive/META-INF/MANIFEST.MF
index 8c854b8..a3499c5 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: 5.2.3.qualifier
+Bundle-Version: 5.3.7.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="[5.2.3,5.3.0)",
- org.eclipse.jgit.lib;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.nls;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.revwalk;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.util;version="[5.2.3,5.3.0)",
+ org.eclipse.jgit.api;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.lib;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.nls;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.revwalk;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.util;version="[5.3.7,5.4.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="5.2.3";
+Export-Package: org.eclipse.jgit.archive;version="5.3.7";
   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 aab58a6..74c9065 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: 5.2.3.qualifier
-Eclipse-SourceBundle: org.eclipse.jgit.archive;version="5.2.3.qualifier";roots="."
+Bundle-Version: 5.3.7.qualifier
+Eclipse-SourceBundle: org.eclipse.jgit.archive;version="5.3.7.qualifier";roots="."
diff --git a/org.eclipse.jgit.archive/pom.xml b/org.eclipse.jgit.archive/pom.xml
index f36a3a6..3c47f15 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>5.2.3-SNAPSHOT</version>
+    <version>5.3.7-SNAPSHOT</version>
   </parent>
 
   <artifactId>org.eclipse.jgit.archive</artifactId>
diff --git a/org.eclipse.jgit.benchmarks/pom.xml b/org.eclipse.jgit.benchmarks/pom.xml
index 67bedc9..b91a141 100644
--- a/org.eclipse.jgit.benchmarks/pom.xml
+++ b/org.eclipse.jgit.benchmarks/pom.xml
@@ -47,7 +47,7 @@
   <modelVersion>4.0.0</modelVersion>
 
   <groupId>org.eclipse.jgit</groupId>
-  <version>5.2.3-SNAPSHOT</version>
+  <version>5.3.7-SNAPSHOT</version>
   <artifactId>org.eclipse.jgit.benchmarks</artifactId>
   <packaging>jar</packaging>
 
diff --git a/org.eclipse.jgit.coverage/.classpath b/org.eclipse.jgit.coverage/.classpath
new file mode 100644
index 0000000..248406b
--- /dev/null
+++ b/org.eclipse.jgit.coverage/.classpath
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8">
+		<attributes>
+			<attribute name="maven.pomderived" value="true"/>
+		</attributes>
+	</classpathentry>
+	<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
+		<attributes>
+			<attribute name="maven.pomderived" value="true"/>
+		</attributes>
+	</classpathentry>
+	<classpathentry kind="output" path="target/classes"/>
+</classpath>
diff --git a/org.eclipse.jgit.coverage/.gitignore b/org.eclipse.jgit.coverage/.gitignore
new file mode 100644
index 0000000..b83d222
--- /dev/null
+++ b/org.eclipse.jgit.coverage/.gitignore
@@ -0,0 +1 @@
+/target/
diff --git a/org.eclipse.jgit.coverage/.project b/org.eclipse.jgit.coverage/.project
new file mode 100644
index 0000000..6306b5c
--- /dev/null
+++ b/org.eclipse.jgit.coverage/.project
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>org.eclipse.jgit.coverage</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.m2e.core.maven2Builder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.m2e.core.maven2Nature</nature>
+	</natures>
+</projectDescription>
diff --git a/org.eclipse.jgit.coverage/.settings/org.eclipse.core.resources.prefs b/org.eclipse.jgit.coverage/.settings/org.eclipse.core.resources.prefs
new file mode 100644
index 0000000..99f26c0
--- /dev/null
+++ b/org.eclipse.jgit.coverage/.settings/org.eclipse.core.resources.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+encoding/<project>=UTF-8
diff --git a/org.eclipse.jgit.coverage/.settings/org.eclipse.m2e.core.prefs b/org.eclipse.jgit.coverage/.settings/org.eclipse.m2e.core.prefs
new file mode 100644
index 0000000..f897a7f
--- /dev/null
+++ b/org.eclipse.jgit.coverage/.settings/org.eclipse.m2e.core.prefs
@@ -0,0 +1,4 @@
+activeProfiles=
+eclipse.preferences.version=1
+resolveWorkspaceProjects=true
+version=1
diff --git a/org.eclipse.jgit.coverage/pom.xml b/org.eclipse.jgit.coverage/pom.xml
new file mode 100644
index 0000000..bd78a25
--- /dev/null
+++ b/org.eclipse.jgit.coverage/pom.xml
@@ -0,0 +1,143 @@
+<?xml version="1.0"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <parent>
+    <groupId>org.eclipse.jgit</groupId>
+    <artifactId>org.eclipse.jgit-parent</artifactId>
+    <version>5.3.7-SNAPSHOT</version>
+  </parent>
+  <modelVersion>4.0.0</modelVersion>
+
+  <artifactId>org.eclipse.jgit.coverage</artifactId>
+  <packaging>pom</packaging>
+
+  <name>JGit - Test Coverage</name>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.eclipse.jgit</groupId>
+      <artifactId>org.eclipse.jgit</artifactId>
+      <version>5.3.7-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.jgit</groupId>
+      <artifactId>org.eclipse.jgit.ant</artifactId>
+      <version>5.3.7-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.jgit</groupId>
+      <artifactId>org.eclipse.jgit.archive</artifactId>
+      <version>5.3.7-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.jgit</groupId>
+      <artifactId>org.eclipse.jgit.http.apache</artifactId>
+      <version>5.3.7-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.jgit</groupId>
+      <artifactId>org.eclipse.jgit.http.server</artifactId>
+      <version>5.3.7-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.jgit</groupId>
+      <artifactId>org.eclipse.jgit.lfs</artifactId>
+      <version>5.3.7-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.jgit</groupId>
+      <artifactId>org.eclipse.jgit.lfs.server</artifactId>
+      <version>5.3.7-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.jgit</groupId>
+      <artifactId>org.eclipse.jgit.pgm</artifactId>
+      <version>5.3.7-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.jgit</groupId>
+      <artifactId>org.eclipse.jgit.ui</artifactId>
+      <version>5.3.7-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.jgit</groupId>
+      <artifactId>org.eclipse.jgit.ssh.apache</artifactId>
+      <version>5.3.7-SNAPSHOT</version>
+    </dependency>
+
+    <dependency>
+      <groupId>org.eclipse.jgit</groupId>
+      <artifactId>org.eclipse.jgit.test</artifactId>
+      <version>5.3.7-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.jgit</groupId>
+      <artifactId>org.eclipse.jgit.ant.test</artifactId>
+      <version>5.3.7-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.jgit</groupId>
+      <artifactId>org.eclipse.jgit.http.test</artifactId>
+      <version>5.3.7-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.jgit</groupId>
+      <artifactId>org.eclipse.jgit.pgm.test</artifactId>
+      <version>5.3.7-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.jgit</groupId>
+      <artifactId>org.eclipse.jgit.lfs.test</artifactId>
+      <version>5.3.7-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.jgit</groupId>
+      <artifactId>org.eclipse.jgit.lfs.server.test</artifactId>
+      <version>5.3.7-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.jgit</groupId>
+      <artifactId>org.eclipse.jgit.ssh.apache.test</artifactId>
+      <version>5.3.7-SNAPSHOT</version>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.jacoco</groupId>
+        <artifactId>jacoco-maven-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>aggregate-reports-all</id>
+            <phase>verify</phase>
+            <goals>
+              <goal>report-aggregate</goal>
+            </goals>
+            <configuration>
+              <title>JGit Test Coverage </title>
+              <outputDirectory>${project.reporting.outputDirectory}/jacoco-aggregate</outputDirectory>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
+  </build>
+  <reporting>
+    <plugins>
+      <plugin>
+        <groupId>org.jacoco</groupId>
+        <artifactId>jacoco-maven-plugin</artifactId>
+        <reportSets>
+          <reportSet>
+            <id>aggregate</id>
+            <reports>
+              <report>report-aggregate</report>
+            </reports>
+          </reportSet>
+        </reportSets>
+      </plugin>
+    </plugins>
+  </reporting>
+</project>
diff --git a/org.eclipse.jgit.http.apache/META-INF/MANIFEST.MF b/org.eclipse.jgit.http.apache/META-INF/MANIFEST.MF
index fb3dec7..3ea2f90 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: 5.2.3.qualifier
+Bundle-Version: 5.3.7.qualifier
 Bundle-RequiredExecutionEnvironment: JavaSE-1.8
 Bundle-Localization: plugin
 Bundle-Vendor: %Provider-Name
@@ -23,11 +23,11 @@
  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.annotations;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.nls;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.transport.http;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.util;version="[5.2.3,5.3.0)"
-Export-Package: org.eclipse.jgit.transport.http.apache;version="5.2.3";
+ org.eclipse.jgit.annotations;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.nls;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.transport.http;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.util;version="[5.3.7,5.4.0)"
+Export-Package: org.eclipse.jgit.transport.http.apache;version="5.3.7";
   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 a1cb74c..ab56aea 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>5.2.3-SNAPSHOT</version>
+		<version>5.3.7-SNAPSHOT</version>
 	</parent>
 
 	<artifactId>org.eclipse.jgit.http.apache</artifactId>
diff --git a/org.eclipse.jgit.http.server/META-INF/MANIFEST.MF b/org.eclipse.jgit.http.server/META-INF/MANIFEST.MF
index b65ee84..b42ac1d 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: 5.2.3.qualifier
+Bundle-Version: 5.3.7.qualifier
 Bundle-Localization: plugin
 Bundle-Vendor: %provider_name
-Export-Package: org.eclipse.jgit.http.server;version="5.2.3",
- org.eclipse.jgit.http.server.glue;version="5.2.3";
+Export-Package: org.eclipse.jgit.http.server;version="5.3.7",
+ org.eclipse.jgit.http.server.glue;version="5.3.7";
   uses:="javax.servlet,javax.servlet.http",
- org.eclipse.jgit.http.server.resolver;version="5.2.3";
+ org.eclipse.jgit.http.server.resolver;version="5.3.7";
   uses:="org.eclipse.jgit.transport.resolver,
    org.eclipse.jgit.lib,
    org.eclipse.jgit.transport,
@@ -18,13 +18,13 @@
 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="[5.2.3,5.3.0)",
- org.eclipse.jgit.internal.storage.dfs;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.internal.storage.file;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.internal.transport.parser;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.lib;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.nls;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.revwalk;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.transport;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.transport.resolver;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.util;version="[5.2.3,5.3.0)"
+ org.eclipse.jgit.errors;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.internal.storage.dfs;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.internal.storage.file;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.internal.transport.parser;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.lib;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.nls;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.revwalk;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.transport;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.transport.resolver;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.util;version="[5.3.7,5.4.0)"
diff --git a/org.eclipse.jgit.http.server/pom.xml b/org.eclipse.jgit.http.server/pom.xml
index 78191ef..843139d 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>5.2.3-SNAPSHOT</version>
+    <version>5.3.7-SNAPSHOT</version>
   </parent>
 
   <artifactId>org.eclipse.jgit.http.server</artifactId>
diff --git a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/GitSmartHttpTools.java b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/GitSmartHttpTools.java
index ee4b32e..5e09d01 100644
--- a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/GitSmartHttpTools.java
+++ b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/GitSmartHttpTools.java
@@ -63,6 +63,7 @@
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
+import org.eclipse.jgit.internal.transport.parser.FirstCommand;
 import org.eclipse.jgit.internal.transport.parser.FirstWant;
 import org.eclipse.jgit.lib.Constants;
 import org.eclipse.jgit.transport.PacketLineIn;
@@ -287,7 +288,7 @@ private static boolean isReceivePackSideBand(HttpServletRequest req) {
 			// not have a ReceivePack, or it might not have read any of the request.
 			// So, cheat and read the first line.
 			String line = new PacketLineIn(req.getInputStream()).readString();
-			ReceivePack.FirstLine parsed = new ReceivePack.FirstLine(line);
+			FirstCommand parsed = FirstCommand.fromLine(line);
 			return parsed.getCapabilities().contains(CAPABILITY_SIDE_BAND_64K);
 		} catch (IOException e) {
 			// Probably the connection is closed and a subsequent write will fail, but
@@ -298,10 +299,11 @@ private static boolean isReceivePackSideBand(HttpServletRequest req) {
 
 	private static void writeSideBand(OutputStream out, String textForGit)
 			throws IOException {
-		@SuppressWarnings("resource" /* java 7 */)
-		OutputStream msg = new SideBandOutputStream(CH_ERROR, SMALL_BUF, out);
-		msg.write(Constants.encode("error: " + textForGit));
-		msg.flush();
+		try (OutputStream msg = new SideBandOutputStream(CH_ERROR, SMALL_BUF,
+				out)) {
+			msg.write(Constants.encode("error: " + textForGit));
+			msg.flush();
+		}
 	}
 
 	private static void writePacket(PacketLineOut pckOut, String textForGit)
diff --git a/org.eclipse.jgit.http.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.http.test/META-INF/MANIFEST.MF
index 495d36d..9bbeb1a 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: 5.2.3.qualifier
+Bundle-Version: 5.3.7.qualifier
 Bundle-Vendor: %provider_name
 Bundle-Localization: plugin
 Bundle-RequiredExecutionEnvironment: JavaSE-1.8
@@ -28,25 +28,25 @@
  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="[5.2.3,5.3.0)",
- org.eclipse.jgit.http.server;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.http.server.glue;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.http.server.resolver;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.internal;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.internal.storage.dfs;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.internal.storage.file;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.internal.storage.reftable;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.junit;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.junit.http;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.lib;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.nls;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.revwalk;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.storage.file;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.transport;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.transport.http;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.transport.http.apache;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.transport.resolver;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.util;version="[5.2.3,5.3.0)",
+ org.eclipse.jgit.errors;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.http.server;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.http.server.glue;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.http.server.resolver;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.internal;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.internal.storage.dfs;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.internal.storage.file;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.internal.storage.reftable;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.junit;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.junit.http;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.lib;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.nls;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.revwalk;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.storage.file;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.transport;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.transport.http;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.transport.http.apache;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.transport.resolver;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.util;version="[5.3.7,5.4.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)",
diff --git a/org.eclipse.jgit.http.test/pom.xml b/org.eclipse.jgit.http.test/pom.xml
index e8e697e..e87dcbb 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>5.2.3-SNAPSHOT</version>
+    <version>5.3.7-SNAPSHOT</version>
   </parent>
 
   <artifactId>org.eclipse.jgit.http.test</artifactId>
@@ -71,13 +71,6 @@
     </dependency>
 
     <dependency>
-      <groupId>org.hamcrest</groupId>
-      <artifactId>hamcrest-library</artifactId>
-      <scope>test</scope>
-      <version>[1.1.0,2.0.0)</version>
-    </dependency>
-
-    <dependency>
       <groupId>org.eclipse.jgit</groupId>
       <artifactId>org.eclipse.jgit</artifactId>
       <version>${project.version}</version>
@@ -91,6 +84,13 @@
     </dependency>
 
     <dependency>
+      <groupId>org.hamcrest</groupId>
+      <artifactId>hamcrest-library</artifactId>
+      <scope>test</scope>
+      <version>[1.1.0,2.0.0)</version>
+    </dependency>
+
+    <dependency>
       <groupId>org.eclipse.jgit</groupId>
       <artifactId>org.eclipse.jgit.junit.http</artifactId>
       <version>${project.version}</version>
@@ -139,7 +139,7 @@
       <plugin>
         <artifactId>maven-surefire-plugin</artifactId>
         <configuration>
-          <argLine>-Djava.io.tmpdir=${project.build.directory}  -Xmx300m</argLine>
+          <argLine>@{argLine} -Djava.io.tmpdir=${project.build.directory}  -Xmx300m</argLine>
           <includes>
             <include>**/*Test.java</include>
             <include>**/*Tests.java</include>
diff --git a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/DumbClientDumbServerTest.java b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/DumbClientDumbServerTest.java
index ab6dc35..c1e55cb 100644
--- a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/DumbClientDumbServerTest.java
+++ b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/DumbClientDumbServerTest.java
@@ -194,13 +194,13 @@ public void testListRemote() throws IOException {
 	@Test
 	public void testInitialClone_Loose() throws Exception {
 		Repository dst = createBareRepository();
-		assertFalse(dst.hasObject(A_txt));
+		assertFalse(dst.getObjectDatabase().has(A_txt));
 
 		try (Transport t = Transport.open(dst, remoteURI)) {
 			t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
 		}
 
-		assertTrue(dst.hasObject(A_txt));
+		assertTrue(dst.getObjectDatabase().has(A_txt));
 		assertEquals(B, dst.exactRef(master).getObjectId());
 		fsck(dst, B);
 
@@ -213,16 +213,19 @@ public void testInitialClone_Loose() throws Exception {
 
 	@Test
 	public void testInitialClone_Packed() throws Exception {
-		new TestRepository<>(remoteRepository).packAndPrune();
+		try (TestRepository<Repository> tr = new TestRepository<>(
+				remoteRepository)) {
+			tr.packAndPrune();
+		}
 
 		Repository dst = createBareRepository();
-		assertFalse(dst.hasObject(A_txt));
+		assertFalse(dst.getObjectDatabase().has(A_txt));
 
 		try (Transport t = Transport.open(dst, remoteURI)) {
 			t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
 		}
 
-		assertTrue(dst.hasObject(A_txt));
+		assertTrue(dst.getObjectDatabase().has(A_txt));
 		assertEquals(B, dst.exactRef(master).getObjectId());
 		fsck(dst, B);
 
diff --git a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/DumbClientSmartServerTest.java b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/DumbClientSmartServerTest.java
index 4ff81c5..2d22baf 100644
--- a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/DumbClientSmartServerTest.java
+++ b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/DumbClientSmartServerTest.java
@@ -193,14 +193,14 @@ public void testListRemote() throws IOException {
 	@Test
 	public void testInitialClone_Small() throws Exception {
 		Repository dst = createBareRepository();
-		assertFalse(dst.hasObject(A_txt));
+		assertFalse(dst.getObjectDatabase().has(A_txt));
 
 		try (Transport t = Transport.open(dst, remoteURI)) {
 		((TransportHttp) t).setUseSmartHttp(false);
 			t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
 		}
 
-		assertTrue(dst.hasObject(A_txt));
+		assertTrue(dst.getObjectDatabase().has(A_txt));
 		assertEquals(B, dst.exactRef(master).getObjectId());
 		fsck(dst, B);
 
@@ -215,17 +215,20 @@ public void testInitialClone_Small() throws Exception {
 
 	@Test
 	public void testInitialClone_Packed() throws Exception {
-		new TestRepository<>(remoteRepository).packAndPrune();
+		try (TestRepository<Repository> tr = new TestRepository<>(
+				remoteRepository)) {
+			tr.packAndPrune();
+		}
 
 		Repository dst = createBareRepository();
-		assertFalse(dst.hasObject(A_txt));
+		assertFalse(dst.getObjectDatabase().has(A_txt));
 
 		try (Transport t = Transport.open(dst, remoteURI)) {
 			((TransportHttp) t).setUseSmartHttp(false);
 			t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
 		}
 
-		assertTrue(dst.hasObject(A_txt));
+		assertTrue(dst.getObjectDatabase().has(A_txt));
 		assertEquals(B, dst.exactRef(master).getObjectId());
 		fsck(dst, B);
 
diff --git a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/HookMessageTest.java b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/HookMessageTest.java
index 7795658..5a5ff1a 100644
--- a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/HookMessageTest.java
+++ b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/HookMessageTest.java
@@ -163,7 +163,7 @@ public void testPush_CreateBranch() throws Exception {
 					.singleton(update));
 		}
 
-		assertTrue(remoteRepository.hasObject(Q_txt));
+		assertTrue(remoteRepository.getObjectDatabase().has(Q_txt));
 		assertNotNull("has " + dstName, remoteRepository.exactRef(dstName));
 		assertEquals(Q, remoteRepository.exactRef(dstName).getObjectId());
 		fsck(remoteRepository, Q);
diff --git a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/SmartClientSmartServerSslTest.java b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/SmartClientSmartServerSslTest.java
index 7deb0d8..30501df 100644
--- a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/SmartClientSmartServerSslTest.java
+++ b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/SmartClientSmartServerSslTest.java
@@ -275,13 +275,13 @@ public void destroy() {
 	@Test
 	public void testInitialClone_ViaHttps() throws Exception {
 		Repository dst = createBareRepository();
-		assertFalse(dst.hasObject(A_txt));
+		assertFalse(dst.getObjectDatabase().has(A_txt));
 
 		try (Transport t = Transport.open(dst, secureURI)) {
 			t.setCredentialsProvider(testCredentials);
 			t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
 		}
-		assertTrue(dst.hasObject(A_txt));
+		assertTrue(dst.getObjectDatabase().has(A_txt));
 		assertEquals(B, dst.exactRef(master).getObjectId());
 		fsck(dst, B);
 
@@ -292,14 +292,14 @@ public void testInitialClone_ViaHttps() throws Exception {
 	@Test
 	public void testInitialClone_RedirectToHttps() throws Exception {
 		Repository dst = createBareRepository();
-		assertFalse(dst.hasObject(A_txt));
+		assertFalse(dst.getObjectDatabase().has(A_txt));
 
 		URIish cloneFrom = extendPath(remoteURI, "/https");
 		try (Transport t = Transport.open(dst, cloneFrom)) {
 			t.setCredentialsProvider(testCredentials);
 			t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
 		}
-		assertTrue(dst.hasObject(A_txt));
+		assertTrue(dst.getObjectDatabase().has(A_txt));
 		assertEquals(B, dst.exactRef(master).getObjectId());
 		fsck(dst, B);
 
@@ -310,7 +310,7 @@ public void testInitialClone_RedirectToHttps() throws Exception {
 	@Test
 	public void testInitialClone_RedirectBackToHttp() throws Exception {
 		Repository dst = createBareRepository();
-		assertFalse(dst.hasObject(A_txt));
+		assertFalse(dst.getObjectDatabase().has(A_txt));
 
 		URIish cloneFrom = extendPath(secureURI, "/back");
 		try (Transport t = Transport.open(dst, cloneFrom)) {
@@ -325,7 +325,7 @@ public void testInitialClone_RedirectBackToHttp() throws Exception {
 	@Test
 	public void testInitialClone_SslFailure() throws Exception {
 		Repository dst = createBareRepository();
-		assertFalse(dst.hasObject(A_txt));
+		assertFalse(dst.getObjectDatabase().has(A_txt));
 
 		try (Transport t = Transport.open(dst, secureURI)) {
 			// Set a credentials provider that doesn't handle questions
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 78bf778..017e2c7 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
@@ -206,7 +206,7 @@ public UploadPack create(HttpServletRequest req, Repository db)
 
 		ServletContextHandler app = addNormalContext(gs, src, srcName);
 
-		ServletContextHandler broken = addBrokenContext(gs, src, srcName);
+		ServletContextHandler broken = addBrokenContext(gs, srcName);
 
 		ServletContextHandler redirect = addRedirectContext(gs);
 
@@ -285,8 +285,8 @@ public void destroy() {
 		return app;
 	}
 
-	@SuppressWarnings("unused")
-	private ServletContextHandler addBrokenContext(GitServlet gs, TestRepository<Repository> src, String srcName) {
+	private ServletContextHandler addBrokenContext(GitServlet gs,
+			String srcName) {
 		ServletContextHandler broken = server.addContext("/bad");
 		broken.addFilter(new FilterHolder(new Filter() {
 
@@ -414,12 +414,11 @@ public void destroy() {
 
 	@Test
 	public void testListRemote() throws IOException {
-		Repository dst = createBareRepository();
-
 		assertEquals("http", remoteURI.getScheme());
 
 		Map<String, Ref> map;
-		try (Transport t = Transport.open(dst, remoteURI)) {
+		try (Repository dst = createBareRepository();
+				Transport t = Transport.open(dst, remoteURI)) {
 			// I didn't make up these public interface names, I just
 			// approved them for inclusion into the code base. Sorry.
 			// --spearce
@@ -457,9 +456,9 @@ public void testListRemote() throws IOException {
 
 	@Test
 	public void testListRemote_BadName() throws IOException, URISyntaxException {
-		Repository dst = createBareRepository();
 		URIish uri = new URIish(this.remoteURI.toString() + ".invalid");
-		try (Transport t = Transport.open(dst, uri)) {
+		try (Repository dst = createBareRepository();
+				Transport t = Transport.open(dst, uri)) {
 			try {
 				t.openFetch();
 				fail("fetch connection opened");
@@ -484,23 +483,20 @@ public void testListRemote_BadName() throws IOException, URISyntaxException {
 
 	@Test
 	public void testFetchBySHA1() throws Exception {
-		Repository dst = createBareRepository();
-		assertFalse(dst.hasObject(A_txt));
-
-		try (Transport t = Transport.open(dst, remoteURI)) {
+		try (Repository dst = createBareRepository();
+				Transport t = Transport.open(dst, remoteURI)) {
+			assertFalse(dst.getObjectDatabase().has(A_txt));
 			t.fetch(NullProgressMonitor.INSTANCE,
 					Collections.singletonList(new RefSpec(B.name())));
+			assertTrue(dst.getObjectDatabase().has(A_txt));
 		}
-
-		assertTrue(dst.hasObject(A_txt));
 	}
 
 	@Test
 	public void testFetchBySHA1Unreachable() throws Exception {
-		Repository dst = createBareRepository();
-		assertFalse(dst.hasObject(A_txt));
-
-		try (Transport t = Transport.open(dst, remoteURI)) {
+		try (Repository dst = createBareRepository();
+				Transport t = Transport.open(dst, remoteURI)) {
+			assertFalse(dst.getObjectDatabase().has(A_txt));
 			thrown.expect(TransportException.class);
 			thrown.expectMessage(Matchers.containsString(
 					"want " + unreachableCommit.name() + " not valid"));
@@ -512,9 +508,6 @@ public void testFetchBySHA1Unreachable() throws Exception {
 	@Test
 	public void testFetchBySHA1UnreachableByAdvertiseRefsHook()
 			throws Exception {
-		Repository dst = createBareRepository();
-		assertFalse(dst.hasObject(A_txt));
-
 		advertiseRefsHook = new AbstractAdvertiseRefsHook() {
 			@Override
 			protected Map<String, Ref> getAdvertisedRefs(Repository repository,
@@ -523,7 +516,9 @@ protected Map<String, Ref> getAdvertisedRefs(Repository repository,
 			}
 		};
 
-		try (Transport t = Transport.open(dst, remoteURI)) {
+		try (Repository dst = createBareRepository();
+				Transport t = Transport.open(dst, remoteURI)) {
+			assertFalse(dst.getObjectDatabase().has(A_txt));
 			thrown.expect(TransportException.class);
 			thrown.expectMessage(Matchers.containsString(
 					"want " + A.name() + " not valid"));
@@ -534,17 +529,15 @@ protected Map<String, Ref> getAdvertisedRefs(Repository repository,
 
 	@Test
 	public void testInitialClone_Small() throws Exception {
-		Repository dst = createBareRepository();
-		assertFalse(dst.hasObject(A_txt));
-
-		try (Transport t = Transport.open(dst, remoteURI)) {
+		try (Repository dst = createBareRepository();
+				Transport t = Transport.open(dst, remoteURI)) {
+			assertFalse(dst.getObjectDatabase().has(A_txt));
 			t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
+			assertTrue(dst.getObjectDatabase().has(A_txt));
+			assertEquals(B, dst.exactRef(master).getObjectId());
+			fsck(dst, B);
 		}
 
-		assertTrue(dst.hasObject(A_txt));
-		assertEquals(B, dst.exactRef(master).getObjectId());
-		fsck(dst, B);
-
 		List<AccessEvent> requests = getRequests();
 		assertEquals(2, requests.size());
 
@@ -574,21 +567,20 @@ public void testInitialClone_Small() throws Exception {
 
 	private void initialClone_Redirect(int nofRedirects, int code)
 			throws Exception {
-		Repository dst = createBareRepository();
-		assertFalse(dst.hasObject(A_txt));
-
 		URIish cloneFrom = redirectURI;
 		if (code != 301 || nofRedirects > 1) {
 			cloneFrom = extendPath(cloneFrom,
 					"/response/" + nofRedirects + "/" + code);
 		}
-		try (Transport t = Transport.open(dst, cloneFrom)) {
-			t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
-		}
 
-		assertTrue(dst.hasObject(A_txt));
-		assertEquals(B, dst.exactRef(master).getObjectId());
-		fsck(dst, B);
+		try (Repository dst = createBareRepository();
+				Transport t = Transport.open(dst, cloneFrom)) {
+			assertFalse(dst.getObjectDatabase().has(A_txt));
+			t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
+			assertTrue(dst.getObjectDatabase().has(A_txt));
+			assertEquals(B, dst.exactRef(master).getObjectId());
+			fsck(dst, B);
+		}
 
 		List<AccessEvent> requests = getRequests();
 		assertEquals(2 + nofRedirects, requests.size());
@@ -663,12 +655,12 @@ public void testInitialClone_RedirectTooOften() throws Exception {
 				.getUserConfig();
 		userConfig.setInt("http", null, "maxRedirects", 3);
 		userConfig.save();
-		Repository dst = createBareRepository();
-		assertFalse(dst.hasObject(A_txt));
 
 		URIish cloneFrom = extendPath(redirectURI, "/response/4/302");
 		String remoteUri = cloneFrom.toString();
-		try (Transport t = Transport.open(dst, cloneFrom)) {
+		try (Repository dst = createBareRepository();
+				Transport t = Transport.open(dst, cloneFrom)) {
+			assertFalse(dst.getObjectDatabase().has(A_txt));
 			t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
 			fail("Should have failed (too many redirects)");
 		} catch (TransportException e) {
@@ -685,11 +677,10 @@ public void testInitialClone_RedirectTooOften() throws Exception {
 
 	@Test
 	public void testInitialClone_RedirectLoop() throws Exception {
-		Repository dst = createBareRepository();
-		assertFalse(dst.hasObject(A_txt));
-
 		URIish cloneFrom = extendPath(redirectURI, "/loop");
-		try (Transport t = Transport.open(dst, cloneFrom)) {
+		try (Repository dst = createBareRepository();
+				Transport t = Transport.open(dst, cloneFrom)) {
+			assertFalse(dst.getObjectDatabase().has(A_txt));
 			t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
 			fail("Should have failed (redirect loop)");
 		} catch (TransportException e) {
@@ -703,18 +694,17 @@ public void testInitialClone_RedirectOnPostAllowed() throws Exception {
 				.getUserConfig();
 		userConfig.setString("http", null, "followRedirects", "true");
 		userConfig.save();
-		Repository dst = createBareRepository();
-		assertFalse(dst.hasObject(A_txt));
 
 		URIish cloneFrom = extendPath(remoteURI, "/post");
-		try (Transport t = Transport.open(dst, cloneFrom)) {
+		try (Repository dst = createBareRepository();
+				Transport t = Transport.open(dst, cloneFrom)) {
+			assertFalse(dst.getObjectDatabase().has(A_txt));
 			t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
+			assertTrue(dst.getObjectDatabase().has(A_txt));
+			assertEquals(B, dst.exactRef(master).getObjectId());
+			fsck(dst, B);
 		}
 
-		assertTrue(dst.hasObject(A_txt));
-		assertEquals(B, dst.exactRef(master).getObjectId());
-		fsck(dst, B);
-
 		List<AccessEvent> requests = getRequests();
 		assertEquals(3, requests.size());
 
@@ -748,11 +738,10 @@ public void testInitialClone_RedirectOnPostAllowed() throws Exception {
 
 	@Test
 	public void testInitialClone_RedirectOnPostForbidden() throws Exception {
-		Repository dst = createBareRepository();
-		assertFalse(dst.hasObject(A_txt));
-
 		URIish cloneFrom = extendPath(remoteURI, "/post");
-		try (Transport t = Transport.open(dst, cloneFrom)) {
+		try (Repository dst = createBareRepository();
+				Transport t = Transport.open(dst, cloneFrom)) {
+			assertFalse(dst.getObjectDatabase().has(A_txt));
 			t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
 			fail("Should have failed (redirect on POST)");
 		} catch (TransportException e) {
@@ -767,10 +756,9 @@ public void testInitialClone_RedirectForbidden() throws Exception {
 		userConfig.setString("http", null, "followRedirects", "false");
 		userConfig.save();
 
-		Repository dst = createBareRepository();
-		assertFalse(dst.hasObject(A_txt));
-
-		try (Transport t = Transport.open(dst, redirectURI)) {
+		try (Repository dst = createBareRepository();
+				Transport t = Transport.open(dst, redirectURI)) {
+			assertFalse(dst.getObjectDatabase().has(A_txt));
 			t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
 			fail("Should have failed (redirects forbidden)");
 		} catch (TransportException e) {
@@ -781,18 +769,16 @@ public void testInitialClone_RedirectForbidden() throws Exception {
 
 	@Test
 	public void testInitialClone_WithAuthentication() throws Exception {
-		Repository dst = createBareRepository();
-		assertFalse(dst.hasObject(A_txt));
-
-		try (Transport t = Transport.open(dst, authURI)) {
+		try (Repository dst = createBareRepository();
+				Transport t = Transport.open(dst, authURI)) {
+			assertFalse(dst.getObjectDatabase().has(A_txt));
 			t.setCredentialsProvider(testCredentials);
 			t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
+			assertTrue(dst.getObjectDatabase().has(A_txt));
+			assertEquals(B, dst.exactRef(master).getObjectId());
+			fsck(dst, B);
 		}
 
-		assertTrue(dst.hasObject(A_txt));
-		assertEquals(B, dst.exactRef(master).getObjectId());
-		fsck(dst, B);
-
 		List<AccessEvent> requests = getRequests();
 		assertEquals(3, requests.size());
 
@@ -827,10 +813,9 @@ public void testInitialClone_WithAuthentication() throws Exception {
 	@Test
 	public void testInitialClone_WithAuthenticationNoCredentials()
 			throws Exception {
-		Repository dst = createBareRepository();
-		assertFalse(dst.hasObject(A_txt));
-
-		try (Transport t = Transport.open(dst, authURI)) {
+		try (Repository dst = createBareRepository();
+				Transport t = Transport.open(dst, authURI)) {
+			assertFalse(dst.getObjectDatabase().has(A_txt));
 			t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
 			fail("Should not have succeeded -- no authentication");
 		} catch (TransportException e) {
@@ -849,10 +834,9 @@ public void testInitialClone_WithAuthenticationNoCredentials()
 	@Test
 	public void testInitialClone_WithAuthenticationWrongCredentials()
 			throws Exception {
-		Repository dst = createBareRepository();
-		assertFalse(dst.hasObject(A_txt));
-
-		try (Transport t = Transport.open(dst, authURI)) {
+		try (Repository dst = createBareRepository();
+				Transport t = Transport.open(dst, authURI)) {
+			assertFalse(dst.getObjectDatabase().has(A_txt));
 			t.setCredentialsProvider(new UsernamePasswordCredentialsProvider(
 					AppServer.username, "wrongpassword"));
 			t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
@@ -875,9 +859,6 @@ public void testInitialClone_WithAuthenticationWrongCredentials()
 	@Test
 	public void testInitialClone_WithAuthenticationAfterRedirect()
 			throws Exception {
-		Repository dst = createBareRepository();
-		assertFalse(dst.hasObject(A_txt));
-
 		URIish cloneFrom = extendPath(redirectURI, "/target/auth");
 		CredentialsProvider uriSpecificCredentialsProvider = new UsernamePasswordCredentialsProvider(
 				"unknown", "none") {
@@ -895,15 +876,16 @@ public boolean get(URIish uri, CredentialItem... items)
 				return super.get(uri, items);
 			}
 		};
-		try (Transport t = Transport.open(dst, cloneFrom)) {
+		try (Repository dst = createBareRepository();
+				Transport t = Transport.open(dst, cloneFrom)) {
+			assertFalse(dst.getObjectDatabase().has(A_txt));
 			t.setCredentialsProvider(uriSpecificCredentialsProvider);
 			t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
+			assertTrue(dst.getObjectDatabase().has(A_txt));
+			assertEquals(B, dst.exactRef(master).getObjectId());
+			fsck(dst, B);
 		}
 
-		assertTrue(dst.hasObject(A_txt));
-		assertEquals(B, dst.exactRef(master).getObjectId());
-		fsck(dst, B);
-
 		List<AccessEvent> requests = getRequests();
 		assertEquals(4, requests.size());
 
@@ -944,18 +926,16 @@ public boolean get(URIish uri, CredentialItem... items)
 	@Test
 	public void testInitialClone_WithAuthenticationOnPostOnly()
 			throws Exception {
-		Repository dst = createBareRepository();
-		assertFalse(dst.hasObject(A_txt));
-
-		try (Transport t = Transport.open(dst, authOnPostURI)) {
+		try (Repository dst = createBareRepository();
+				Transport t = Transport.open(dst, authOnPostURI)) {
+			assertFalse(dst.getObjectDatabase().has(A_txt));
 			t.setCredentialsProvider(testCredentials);
 			t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
+			assertTrue(dst.getObjectDatabase().has(A_txt));
+			assertEquals(B, dst.exactRef(master).getObjectId());
+			fsck(dst, B);
 		}
 
-		assertTrue(dst.hasObject(A_txt));
-		assertEquals(B, dst.exactRef(master).getObjectId());
-		fsck(dst, B);
-
 		List<AccessEvent> requests = getRequests();
 		assertEquals(3, requests.size());
 
@@ -1006,8 +986,12 @@ public void testFetch_FewLocalCommits() throws Exception {
 
 		// Create a new commit on the remote.
 		//
-		b = new TestRepository<>(remoteRepository).branch(master);
-		RevCommit Z = b.commit().message("Z").create();
+		RevCommit Z;
+		try (TestRepository<Repository> tr = new TestRepository<>(
+				remoteRepository)) {
+			b = tr.branch(master);
+			Z = b.commit().message("Z").create();
+		}
 
 		// Now incrementally update.
 		//
@@ -1066,8 +1050,12 @@ public void testFetch_TooManyLocalCommits() throws Exception {
 
 		// Create a new commit on the remote.
 		//
-		b = new TestRepository<>(remoteRepository).branch(master);
-		RevCommit Z = b.commit().message("Z").create();
+		RevCommit Z;
+		try (TestRepository<Repository> tr = new TestRepository<>(
+				remoteRepository)) {
+			b = tr.branch(master);
+			Z = b.commit().message("Z").create();
+		}
 
 		// Now incrementally update.
 		//
@@ -1121,10 +1109,9 @@ public void testFetch_TooManyLocalCommits() throws Exception {
 
 	@Test
 	public void testInitialClone_BrokenServer() throws Exception {
-		Repository dst = createBareRepository();
-		assertFalse(dst.hasObject(A_txt));
-
-		try (Transport t = Transport.open(dst, brokenURI)) {
+		try (Repository dst = createBareRepository();
+				Transport t = Transport.open(dst, brokenURI)) {
+			assertFalse(dst.getObjectDatabase().has(A_txt));
 			try {
 				t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
 				fail("fetch completed despite upload-pack being broken");
@@ -1159,12 +1146,14 @@ public void testInitialClone_BrokenServer() throws Exception {
 
 	@Test
 	public void testInvalidWant() throws Exception {
-		@SuppressWarnings("resource")
-		ObjectId id = new ObjectInserter.Formatter().idFor(Constants.OBJ_BLOB,
-				"testInvalidWant".getBytes(UTF_8));
+		ObjectId id;
+		try (ObjectInserter.Formatter formatter = new ObjectInserter.Formatter()) {
+			id = formatter.idFor(Constants.OBJ_BLOB,
+					"testInvalidWant".getBytes(UTF_8));
+		}
 
-		Repository dst = createBareRepository();
-		try (Transport t = Transport.open(dst, remoteURI);
+		try (Repository dst = createBareRepository();
+				Transport t = Transport.open(dst, remoteURI);
 				FetchConnection c = t.openFetch()) {
 			Ref want = new ObjectIdRef.Unpeeled(Ref.Storage.NETWORK, id.name(),
 					id);
@@ -1201,8 +1190,8 @@ public void testFetch_RefsUnreadableOnUpload() throws Exception {
 			URIish badRefsURI = new URIish(noRefServer.getURI()
 					.resolve(app.getContextPath() + "/" + repoName).toString());
 
-			Repository dst = createBareRepository();
-			try (Transport t = Transport.open(dst, badRefsURI);
+			try (Repository dst = createBareRepository();
+					Transport t = Transport.open(dst, badRefsURI);
 					FetchConnection c = t.openFetch()) {
 				// We start failing here to exercise the post-advertisement
 				// upload pack handler.
@@ -1281,7 +1270,7 @@ public void testPush_CreateBranch() throws Exception {
 			t.push(NullProgressMonitor.INSTANCE, Collections.singleton(u));
 		}
 
-		assertTrue(remoteRepository.hasObject(Q_txt));
+		assertTrue(remoteRepository.getObjectDatabase().has(Q_txt));
 		assertNotNull("has " + dstName, remoteRepository.exactRef(dstName));
 		assertEquals(Q, remoteRepository.exactRef(dstName).getObjectId());
 		fsck(remoteRepository, Q);
@@ -1355,7 +1344,7 @@ public void testPush_ChunkedEncoding() throws Exception {
 			t.push(NullProgressMonitor.INSTANCE, Collections.singleton(u));
 		}
 
-		assertTrue(remoteRepository.hasObject(Q_bin));
+		assertTrue(remoteRepository.getObjectDatabase().has(Q_bin));
 		assertNotNull("has " + dstName, remoteRepository.exactRef(dstName));
 		assertEquals(Q, remoteRepository.exactRef(dstName).getObjectId());
 		fsck(remoteRepository, Q);
diff --git a/org.eclipse.jgit.junit.http/META-INF/MANIFEST.MF b/org.eclipse.jgit.junit.http/META-INF/MANIFEST.MF
index 8432c45..fa4fc2c 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: 5.2.3.qualifier
+Bundle-Version: 5.3.7.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="[5.2.3,5.3.0)",
- org.eclipse.jgit.http.server;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.internal.storage.file;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.junit;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.lib;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.revwalk;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.transport;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.transport.resolver;version="[5.2.3,5.3.0)",
+ org.eclipse.jgit.errors;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.http.server;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.internal.storage.file;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.junit;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.lib;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.revwalk;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.transport;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.transport.resolver;version="[5.3.7,5.4.0)",
  org.junit;version="[4.12,5.0.0)"
-Export-Package: org.eclipse.jgit.junit.http;version="5.2.3";
+Export-Package: org.eclipse.jgit.junit.http;version="5.3.7";
   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 b766974..0296e9d 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>5.2.3-SNAPSHOT</version>
+    <version>5.3.7-SNAPSHOT</version>
   </parent>
 
   <artifactId>org.eclipse.jgit.junit.http</artifactId>
diff --git a/org.eclipse.jgit.junit.http/src/org/eclipse/jgit/junit/http/HttpTestCase.java b/org.eclipse.jgit.junit.http/src/org/eclipse/jgit/junit/http/HttpTestCase.java
index a133ca6..41bc97d 100644
--- a/org.eclipse.jgit.junit.http/src/org/eclipse/jgit/junit/http/HttpTestCase.java
+++ b/org.eclipse.jgit.junit.http/src/org/eclipse/jgit/junit/http/HttpTestCase.java
@@ -186,9 +186,10 @@ protected List<AccessEvent> getRequests(String path) {
 	 */
 	protected static void fsck(Repository db, RevObject... tips)
 			throws Exception {
-		TestRepository<? extends Repository> tr =
-				new TestRepository<>(db);
-		tr.fsck(tips);
+		try (TestRepository<? extends Repository> tr =
+				new TestRepository<>(db)) {
+			tr.fsck(tips);
+		}
 	}
 
 	/**
diff --git a/org.eclipse.jgit.junit.ssh/META-INF/MANIFEST.MF b/org.eclipse.jgit.junit.ssh/META-INF/MANIFEST.MF
index 1467499..4e1d38a 100644
--- a/org.eclipse.jgit.junit.ssh/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.junit.ssh/META-INF/MANIFEST.MF
@@ -3,7 +3,7 @@
 Bundle-Name: %plugin_name
 Automatic-Module-Name: org.eclipse.jgit.junit.ssh
 Bundle-SymbolicName: org.eclipse.jgit.junit.ssh
-Bundle-Version: 5.2.3.qualifier
+Bundle-Version: 5.3.7.qualifier
 Bundle-Localization: plugin
 Bundle-Vendor: %provider_name
 Bundle-ActivationPolicy: lazy
@@ -29,8 +29,8 @@
  org.apache.sshd.server.shell;version="[2.0.0,2.1.0)",
  org.apache.sshd.server.subsystem;version="[2.0.0,2.1.0)",
  org.apache.sshd.server.subsystem.sftp;version="[2.0.0,2.1.0)",
- org.eclipse.jgit.annotations;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.lib;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.transport;version="[5.2.3,5.3.0)",
+ org.eclipse.jgit.annotations;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.lib;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.transport;version="[5.3.7,5.4.0)",
  org.slf4j;version="[1.7.0,2.0.0)"
-Export-Package: org.eclipse.jgit.junit.ssh;version="5.2.3"
+Export-Package: org.eclipse.jgit.junit.ssh;version="5.3.7"
diff --git a/org.eclipse.jgit.junit.ssh/pom.xml b/org.eclipse.jgit.junit.ssh/pom.xml
index 4cd68eb..97b70dc 100644
--- a/org.eclipse.jgit.junit.ssh/pom.xml
+++ b/org.eclipse.jgit.junit.ssh/pom.xml
@@ -50,7 +50,7 @@
   <parent>
     <groupId>org.eclipse.jgit</groupId>
     <artifactId>org.eclipse.jgit-parent</artifactId>
-    <version>5.2.3-SNAPSHOT</version>
+    <version>5.3.7-SNAPSHOT</version>
   </parent>
 
   <artifactId>org.eclipse.jgit.junit.ssh</artifactId>
diff --git a/org.eclipse.jgit.junit/META-INF/MANIFEST.MF b/org.eclipse.jgit.junit/META-INF/MANIFEST.MF
index a416ae7..1e24fe3 100644
--- a/org.eclipse.jgit.junit/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.junit/META-INF/MANIFEST.MF
@@ -3,34 +3,34 @@
 Bundle-Name: %plugin_name
 Automatic-Module-Name: org.eclipse.jgit.junit
 Bundle-SymbolicName: org.eclipse.jgit.junit
-Bundle-Version: 5.2.3.qualifier
+Bundle-Version: 5.3.7.qualifier
 Bundle-Localization: plugin
 Bundle-Vendor: %provider_name
 Bundle-ActivationPolicy: lazy
 Bundle-RequiredExecutionEnvironment: JavaSE-1.8
-Import-Package: org.eclipse.jgit.annotations;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.api;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.api.errors;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.dircache;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.errors;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.internal.storage.file;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.internal.storage.pack;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.lib;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.merge;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.revwalk;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.storage.file;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.transport;version="5.2.3",
- org.eclipse.jgit.treewalk;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.treewalk.filter;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.util;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.util.io;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.util.time;version="[5.2.3,5.3.0)",
+Import-Package: org.eclipse.jgit.annotations;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.api;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.api.errors;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.dircache;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.errors;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.internal.storage.file;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.internal.storage.pack;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.lib;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.merge;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.revwalk;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.storage.file;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.transport;version="5.3.7",
+ org.eclipse.jgit.treewalk;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.treewalk.filter;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.util;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.util.io;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.util.time;version="[5.3.7,5.4.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)",
  org.slf4j;version="[1.7.0,2.0.0)"
-Export-Package: org.eclipse.jgit.junit;version="5.2.3";
+Export-Package: org.eclipse.jgit.junit;version="5.3.7";
   uses:="org.eclipse.jgit.dircache,
    org.eclipse.jgit.lib,
    org.eclipse.jgit.revwalk,
@@ -43,4 +43,4 @@
    org.junit.runners.model,
    org.junit.runner,
    org.eclipse.jgit.util.time",
- org.eclipse.jgit.junit.time;version="5.2.3";uses:="org.eclipse.jgit.util.time"
+ org.eclipse.jgit.junit.time;version="5.3.7";uses:="org.eclipse.jgit.util.time"
diff --git a/org.eclipse.jgit.junit/pom.xml b/org.eclipse.jgit.junit/pom.xml
index e198193..69f1275 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>5.2.3-SNAPSHOT</version>
+    <version>5.3.7-SNAPSHOT</version>
   </parent>
 
   <artifactId>org.eclipse.jgit.junit</artifactId>
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 29579d0..3b7cdde 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
@@ -401,10 +401,11 @@ protected FileRepository createWorkRepository() throws IOException {
 	 * @return the newly created repository, opened for access
 	 * @throws IOException
 	 *             the repository could not be created in the temporary area
+	 * @since 5.3
 	 */
-	private FileRepository createRepository(boolean bare)
+	protected FileRepository createRepository(boolean bare)
 			throws IOException {
-		return createRepository(bare, true /* auto close */);
+		return createRepository(bare, false /* auto close */);
 	}
 
 	/**
@@ -414,11 +415,13 @@ private FileRepository createRepository(boolean bare)
 	 *            true to create a bare repository; false to make a repository
 	 *            within its working directory
 	 * @param autoClose
-	 *            auto close the repository in #tearDown
+	 *            auto close the repository in {@link #tearDown()}
 	 * @return the newly created repository, opened for access
 	 * @throws IOException
 	 *             the repository could not be created in the temporary area
+	 * @deprecated use {@link #createRepository(boolean)} instead
 	 */
+	@Deprecated
 	public FileRepository createRepository(boolean bare, boolean autoClose)
 			throws IOException {
 		File gitdir = createUniqueTestGitDir(bare);
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 49a2b20..02ffe4f 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
@@ -112,7 +112,7 @@
  * @param <R>
  *            type of Repository the test data is stored on.
  */
-public class TestRepository<R extends Repository> {
+public class TestRepository<R extends Repository> implements AutoCloseable {
 
 	/** Constant <code>AUTHOR="J. Author"</code> */
 	public static final String AUTHOR = "J. Author";
@@ -933,6 +933,23 @@ public void packAndPrune() throws Exception {
 		}
 	}
 
+	/**
+	 * Closes the underlying {@link Repository} object and any other internal
+	 * resources.
+	 * <p>
+	 * {@link AutoCloseable} resources that may escape this object, such as
+	 * those returned by the {@link #git} and {@link #getRevWalk()} methods are
+	 * not closed.
+	 */
+	@Override
+	public void close() {
+		try {
+			inserter.close();
+		} finally {
+			db.close();
+		}
+	}
+
 	private static void prunePacked(ObjectDirectory odb) throws IOException {
 		for (PackFile p : odb.getPacks()) {
 			for (MutableEntry e : p)
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 32bdf98..55ed767 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: 5.2.3.qualifier
+Bundle-Version: 5.3.7.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="[5.2.3,5.3.0)",
- org.eclipse.jgit.api.errors;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.internal.storage.file;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.junit;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.junit.http;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.lfs;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.lfs.errors;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.lfs.lib;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.lfs.server;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.lfs.server.fs;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.lfs.test;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.lib;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.revwalk;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.storage.file;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.transport;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.treewalk;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.treewalk.filter;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.util;version="[5.2.3,5.3.0)",
+ org.eclipse.jgit.api;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.api.errors;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.internal.storage.file;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.junit;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.junit.http;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.lfs;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.lfs.errors;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.lfs.lib;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.lfs.server;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.lfs.server.fs;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.lfs.test;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.lib;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.revwalk;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.storage.file;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.transport;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.treewalk;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.treewalk.filter;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.util;version="[5.3.7,5.4.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 1e26b0a..77c1c24 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>5.2.3-SNAPSHOT</version>
+    <version>5.3.7-SNAPSHOT</version>
   </parent>
 
   <artifactId>org.eclipse.jgit.lfs.server.test</artifactId>
@@ -137,7 +137,7 @@
       <plugin>
         <artifactId>maven-surefire-plugin</artifactId>
         <configuration>
-          <argLine>-Djava.io.tmpdir=${project.build.directory}  -Xmx300m</argLine>
+          <argLine>@{argLine} -Djava.io.tmpdir=${project.build.directory}  -Xmx300m</argLine>
         </configuration>
       </plugin>
     </plugins>
diff --git a/org.eclipse.jgit.lfs.server/META-INF/MANIFEST.MF b/org.eclipse.jgit.lfs.server/META-INF/MANIFEST.MF
index 7bed133..15ef303 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: 5.2.3.qualifier
+Bundle-Version: 5.3.7.qualifier
 Bundle-Localization: plugin
 Bundle-Vendor: %provider_name
-Export-Package: org.eclipse.jgit.lfs.server;version="5.2.3";
+Export-Package: org.eclipse.jgit.lfs.server;version="5.3.7";
   uses:="javax.servlet.http,
    org.eclipse.jgit.lfs.lib",
- org.eclipse.jgit.lfs.server.fs;version="5.2.3";
+ org.eclipse.jgit.lfs.server.fs;version="5.3.7";
   uses:="javax.servlet,
    javax.servlet.http,
    org.eclipse.jgit.lfs.server,
    org.eclipse.jgit.lfs.lib",
- org.eclipse.jgit.lfs.server.internal;version="5.2.3";x-internal:=true,
- org.eclipse.jgit.lfs.server.s3;version="5.2.3";
+ org.eclipse.jgit.lfs.server.internal;version="5.3.7";x-internal:=true,
+ org.eclipse.jgit.lfs.server.s3;version="5.3.7";
   uses:="org.eclipse.jgit.lfs.server,
    org.eclipse.jgit.lfs.lib"
 Bundle-RequiredExecutionEnvironment: JavaSE-1.8
@@ -25,15 +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="[5.2.3,5.3.0)",
- org.eclipse.jgit.internal;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.internal.storage.file;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.lfs.errors;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.lfs.internal;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.lfs.lib;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.lib;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.nls;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.transport.http;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.transport.http.apache;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.util;version="[5.2.3,5.3.0)",
+ org.eclipse.jgit.annotations;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.internal;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.internal.storage.file;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.lfs.errors;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.lfs.internal;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.lfs.lib;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.lib;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.nls;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.transport.http;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.transport.http.apache;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.util;version="[5.3.7,5.4.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 4a2b38a..af0b397 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>5.2.3-SNAPSHOT</version>
+    <version>5.3.7-SNAPSHOT</version>
   </parent>
 
   <artifactId>org.eclipse.jgit.lfs.server</artifactId>
diff --git a/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/internal/LfsGson.java b/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/internal/LfsGson.java
index 7974b24..3f6b780 100644
--- a/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/internal/LfsGson.java
+++ b/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/internal/LfsGson.java
@@ -53,8 +53,6 @@
 
 /**
  * Wrapper for {@link com.google.gson.Gson} used by LFS servlets.
- *
- * @since 4.10.0
  */
 public class LfsGson {
 	private static final Gson gson = new GsonBuilder()
diff --git a/org.eclipse.jgit.lfs.test/BUILD b/org.eclipse.jgit.lfs.test/BUILD
index 504e2df..ee2402a 100644
--- a/org.eclipse.jgit.lfs.test/BUILD
+++ b/org.eclipse.jgit.lfs.test/BUILD
@@ -1,11 +1,10 @@
-load("@rules_java//java:defs.bzl", "java_library")
-
-package(default_visibility = ["//visibility:public"])
-
 load(
     "@com_googlesource_gerrit_bazlets//tools:junit.bzl",
     "junit_tests",
 )
+load("@rules_java//java:defs.bzl", "java_library")
+
+package(default_visibility = ["//visibility:public"])
 
 junit_tests(
     name = "lfs",
diff --git a/org.eclipse.jgit.lfs.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.lfs.test/META-INF/MANIFEST.MF
index 2863967..4ec19ec 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: 5.2.3.qualifier
+Bundle-Version: 5.3.7.qualifier
 Bundle-Vendor: %provider_name
 Bundle-Localization: plugin
 Bundle-RequiredExecutionEnvironment: JavaSE-1.8
-Import-Package: org.eclipse.jgit.internal.storage.dfs;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.junit;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.lfs;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.lfs.errors;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.lfs.lib;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.lib;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.revwalk;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.treewalk;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.treewalk.filter;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.util;version="[5.2.3,5.3.0)",
+Import-Package: org.eclipse.jgit.internal.storage.dfs;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.junit;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.lfs;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.lfs.errors;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.lfs.lib;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.lib;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.revwalk;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.treewalk;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.treewalk.filter;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.util;version="[5.3.7,5.4.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="5.2.3";x-friends:="org.eclipse.jgit.lfs.server.test"
+Export-Package: org.eclipse.jgit.lfs.test;version="5.3.7";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 37d11f9..e9f392e 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>5.2.3-SNAPSHOT</version>
+    <version>5.3.7-SNAPSHOT</version>
   </parent>
 
   <artifactId>org.eclipse.jgit.lfs.test</artifactId>
@@ -111,7 +111,7 @@
       <plugin>
         <artifactId>maven-surefire-plugin</artifactId>
         <configuration>
-          <argLine>-Djava.io.tmpdir=${project.build.directory}  -Xmx300m</argLine>
+          <argLine>@{argLine} -Djava.io.tmpdir=${project.build.directory}  -Xmx300m</argLine>
         </configuration>
       </plugin>
     </plugins>
diff --git a/org.eclipse.jgit.lfs/META-INF/MANIFEST.MF b/org.eclipse.jgit.lfs/META-INF/MANIFEST.MF
index 209b2b2..9837dd9 100644
--- a/org.eclipse.jgit.lfs/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.lfs/META-INF/MANIFEST.MF
@@ -3,33 +3,33 @@
 Bundle-Name: %plugin_name
 Automatic-Module-Name: org.eclipse.jgit.lfs
 Bundle-SymbolicName: org.eclipse.jgit.lfs
-Bundle-Version: 5.2.3.qualifier
+Bundle-Version: 5.3.7.qualifier
 Bundle-Localization: plugin
 Bundle-Vendor: %provider_name
-Export-Package: org.eclipse.jgit.lfs;version="5.2.3",
- org.eclipse.jgit.lfs.errors;version="5.2.3",
- org.eclipse.jgit.lfs.internal;version="5.2.3";x-friends:="org.eclipse.jgit.lfs.test,org.eclipse.jgit.lfs.server.fs,org.eclipse.jgit.lfs.server",
- org.eclipse.jgit.lfs.lib;version="5.2.3"
+Export-Package: org.eclipse.jgit.lfs;version="5.3.7",
+ org.eclipse.jgit.lfs.errors;version="5.3.7",
+ org.eclipse.jgit.lfs.internal;version="5.3.7";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.3.7"
 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="[5.2.3,5.3.0)";resolution:=optional,
- org.eclipse.jgit.api.errors;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.attributes;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.diff;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.errors;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.hooks;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.internal.storage.file;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.lib;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.nls;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.revwalk;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.storage.file;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.storage.pack;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.transport;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.transport.http;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.treewalk;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.treewalk.filter;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.util;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.util.io;version="[5.2.3,5.3.0)"
+ org.eclipse.jgit.annotations;version="[5.3.7,5.4.0)";resolution:=optional,
+ org.eclipse.jgit.api.errors;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.attributes;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.diff;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.errors;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.hooks;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.internal.storage.file;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.lib;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.nls;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.revwalk;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.storage.file;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.storage.pack;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.transport;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.transport.http;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.treewalk;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.treewalk.filter;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.util;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.util.io;version="[5.3.7,5.4.0)"
diff --git a/org.eclipse.jgit.lfs/pom.xml b/org.eclipse.jgit.lfs/pom.xml
index f7cad33..92b86be 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>5.2.3-SNAPSHOT</version>
+    <version>5.3.7-SNAPSHOT</version>
   </parent>
 
   <artifactId>org.eclipse.jgit.lfs</artifactId>
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 ad4da8c..7172b23 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="5.2.3.qualifier"
+      version="5.3.7.qualifier"
       provider-name="%providerName">
 
    <description url="http://www.eclipse.org/jgit/">
@@ -86,4 +86,25 @@
          version="0.0.0"
          unpack="false"/>
 
+   <plugin
+         id="org.bouncycastle.bcpg"
+         download-size="0"
+         install-size="0"
+         version="0.0.0"
+         unpack="false"/>
+
+   <plugin
+         id="org.bouncycastle.bcpkix"
+         download-size="0"
+         install-size="0"
+         version="0.0.0"
+         unpack="false"/>
+
+   <plugin
+         id="org.bouncycastle.bcprov"
+         download-size="0"
+         install-size="0"
+         version="0.0.0"
+         unpack="false"/>
+
 </feature>
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 576756b..1df0290 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>5.2.3-SNAPSHOT</version>
+    <version>5.3.7-SNAPSHOT</version>
   </parent>
 
   <groupId>org.eclipse.jgit.feature</groupId>
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 e721ddc..9fc034b 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="5.2.3.qualifier"
+      version="5.3.7.qualifier"
       provider-name="%providerName">
 
    <description url="http://www.eclipse.org/jgit/">
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 c356b34..94f61f2 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>5.2.3-SNAPSHOT</version>
+    <version>5.3.7-SNAPSHOT</version>
   </parent>
 
   <groupId>org.eclipse.jgit.feature</groupId>
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 0abc1ac..a850c33 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="5.2.3.qualifier"
+      version="5.3.7.qualifier"
       provider-name="%providerName">
 
    <description url="http://www.eclipse.org/jgit/">
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 da11f32..04583ab 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>5.2.3-SNAPSHOT</version>
+    <version>5.3.7-SNAPSHOT</version>
   </parent>
 
   <groupId>org.eclipse.jgit.feature</groupId>
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 d287505..e7799a9 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="5.2.3.qualifier"
+      version="5.3.7.qualifier"
       provider-name="%providerName">
 
    <description url="http://www.eclipse.org/jgit/">
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 7957600..ac5cfc4 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>5.2.3-SNAPSHOT</version>
+    <version>5.3.7-SNAPSHOT</version>
   </parent>
 
   <groupId>org.eclipse.jgit.feature</groupId>
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 c74326e..343d1e7 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="5.2.3.qualifier"
+      version="5.3.7.qualifier"
       provider-name="%providerName">
 
    <description url="http://www.eclipse.org/jgit/">
@@ -31,9 +31,9 @@
          version="0.0.0"/>
 
    <requires>
-      <import feature="org.eclipse.jgit" version="5.2.3" match="equivalent"/>
-      <import feature="org.eclipse.jgit.lfs" version="5.2.3" match="equivalent"/>
-      <import feature="org.eclipse.jgit.ssh.apache" version="5.2.3" match="equivalent"/>
+      <import feature="org.eclipse.jgit" version="5.3.7" match="equivalent"/>
+      <import feature="org.eclipse.jgit.lfs" version="5.3.7" match="equivalent"/>
+      <import feature="org.eclipse.jgit.ssh.apache" version="5.3.7" match="equivalent"/>
    </requires>
 
    <plugin
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 e45d79d..1eefe17 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>5.2.3-SNAPSHOT</version>
+    <version>5.3.7-SNAPSHOT</version>
   </parent>
 
   <groupId>org.eclipse.jgit.feature</groupId>
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 2179699..b52ed9c 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="5.2.3.qualifier"
+      version="5.3.7.qualifier"
       provider-name="%providerName">
 
    <description url="http://www.eclipse.org/jgit/">
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 221f031..9bb8cf8 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>5.2.3-SNAPSHOT</version>
+    <version>5.3.7-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 e258eb2..86071e1 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>5.2.3-SNAPSHOT</version>
+    <version>5.3.7-SNAPSHOT</version>
   </parent>
 
   <artifactId>org.eclipse.jgit.repository</artifactId>
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 cee8946..02fe61b 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="5.2.3.qualifier"
+      version="5.3.7.qualifier"
       provider-name="%providerName">
 
    <description url="http://www.eclipse.org/jgit/">
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 60b2c5e..cbb12d6 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>5.2.3-SNAPSHOT</version>
+    <version>5.3.7-SNAPSHOT</version>
   </parent>
 
   <groupId>org.eclipse.jgit.feature</groupId>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.ssh.apache.feature/feature.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.ssh.apache.feature/feature.xml
index 2ce712c..ebcd542 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.ssh.apache.feature/feature.xml
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.ssh.apache.feature/feature.xml
@@ -2,7 +2,7 @@
 <feature
       id="org.eclipse.jgit.ssh.apache"
       label="%featureName"
-      version="5.2.3.qualifier"
+      version="5.3.7.qualifier"
       provider-name="%providerName">
 
    <description url="http://www.eclipse.org/jgit/">
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.ssh.apache.feature/pom.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.ssh.apache.feature/pom.xml
index 869fb17..c5798f7 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.ssh.apache.feature/pom.xml
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.ssh.apache.feature/pom.xml
@@ -50,7 +50,7 @@
   <parent>
     <groupId>org.eclipse.jgit</groupId>
     <artifactId>jgit.tycho.parent</artifactId>
-    <version>5.2.3-SNAPSHOT</version>
+    <version>5.3.7-SNAPSHOT</version>
   </parent>
 
   <groupId>org.eclipse.jgit.feature</groupId>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.ssh.apache.source.feature/feature.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.ssh.apache.source.feature/feature.xml
index 0877744..0153921 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.ssh.apache.source.feature/feature.xml
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.ssh.apache.source.feature/feature.xml
@@ -2,7 +2,7 @@
 <feature
       id="org.eclipse.jgit.ssh.apache.source"
       label="%featureName"
-      version="5.2.3.qualifier"
+      version="5.3.7.qualifier"
       provider-name="%providerName">
 
    <description url="http://www.eclipse.org/jgit/">
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.ssh.apache.source.feature/pom.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.ssh.apache.source.feature/pom.xml
index 6fd255a..3a28a5a 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.ssh.apache.source.feature/pom.xml
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.ssh.apache.source.feature/pom.xml
@@ -50,7 +50,7 @@
   <parent>
     <groupId>org.eclipse.jgit</groupId>
     <artifactId>jgit.tycho.parent</artifactId>
-    <version>5.2.3-SNAPSHOT</version>
+    <version>5.3.7-SNAPSHOT</version>
   </parent>
 
   <groupId>org.eclipse.jgit.feature</groupId>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/.project b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/.project
index 18caf2c..48c2bd1 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/.project
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/.project
@@ -6,6 +6,11 @@
 	</projects>
 	<buildSpec>
 		<buildCommand>
+			<name>org.eclipse.xtext.ui.shared.xtextBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
 			<name>org.eclipse.pde.ManifestBuilder</name>
 			<arguments>
 			</arguments>
@@ -13,5 +18,6 @@
 	</buildSpec>
 	<natures>
 		<nature>org.eclipse.pde.PluginNature</nature>
+		<nature>org.eclipse.xtext.ui.shared.xtextNature</nature>
 	</natures>
 </projectDescription>
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 b869d8d..c70489f 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: 5.2.3.qualifier
+Bundle-Version: 5.3.7.qualifier
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.10-staging.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.10-staging.tpd
deleted file mode 100644
index 98bbc2d..0000000
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.10-staging.tpd
+++ /dev/null
@@ -1,8 +0,0 @@
-target "jgit-4.9-staging" with source configurePhase
-
-include "projects/jetty-9.4.11.tpd"
-include "orbit/R20190602212107-2019-06.tpd"
-
-location "http://download.eclipse.org/staging/2018-12/" {
-	org.eclipse.osgi lazy
-}
\ No newline at end of file
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.10.target
similarity index 72%
rename from org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.5.target
rename to org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.10.target
index 7820a13..86653be 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.10.target
@@ -1,26 +1,26 @@
 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
 <?pde?>
 <!-- generated with https://github.com/eclipse-cbi/targetplatform-dsl -->
-<target name="jgit-4.5" sequenceNumber="1566229356">
+<target name="jgit-4.10" sequenceNumber="1566244557">
   <locations>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
-      <unit id="org.eclipse.jetty.client" version="9.4.11.v20180605"/>
-      <unit id="org.eclipse.jetty.client.source" version="9.4.11.v20180605"/>
-      <unit id="org.eclipse.jetty.continuation" version="9.4.11.v20180605"/>
-      <unit id="org.eclipse.jetty.continuation.source" version="9.4.11.v20180605"/>
-      <unit id="org.eclipse.jetty.http" version="9.4.11.v20180605"/>
-      <unit id="org.eclipse.jetty.http.source" version="9.4.11.v20180605"/>
-      <unit id="org.eclipse.jetty.io" version="9.4.11.v20180605"/>
-      <unit id="org.eclipse.jetty.io.source" version="9.4.11.v20180605"/>
-      <unit id="org.eclipse.jetty.security" version="9.4.11.v20180605"/>
-      <unit id="org.eclipse.jetty.security.source" version="9.4.11.v20180605"/>
-      <unit id="org.eclipse.jetty.server" version="9.4.11.v20180605"/>
-      <unit id="org.eclipse.jetty.server.source" version="9.4.11.v20180605"/>
-      <unit id="org.eclipse.jetty.servlet" version="9.4.11.v20180605"/>
-      <unit id="org.eclipse.jetty.servlet.source" version="9.4.11.v20180605"/>
-      <unit id="org.eclipse.jetty.util" version="9.4.11.v20180605"/>
-      <unit id="org.eclipse.jetty.util.source" version="9.4.11.v20180605"/>
-      <repository id="jetty-9.4.11" location="http://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.4.11.v20180605"/>
+      <unit id="org.eclipse.jetty.client" version="9.4.14.v20181114"/>
+      <unit id="org.eclipse.jetty.client.source" version="9.4.14.v20181114"/>
+      <unit id="org.eclipse.jetty.continuation" version="9.4.14.v20181114"/>
+      <unit id="org.eclipse.jetty.continuation.source" version="9.4.14.v20181114"/>
+      <unit id="org.eclipse.jetty.http" version="9.4.14.v20181114"/>
+      <unit id="org.eclipse.jetty.http.source" version="9.4.14.v20181114"/>
+      <unit id="org.eclipse.jetty.io" version="9.4.14.v20181114"/>
+      <unit id="org.eclipse.jetty.io.source" version="9.4.14.v20181114"/>
+      <unit id="org.eclipse.jetty.security" version="9.4.14.v20181114"/>
+      <unit id="org.eclipse.jetty.security.source" version="9.4.14.v20181114"/>
+      <unit id="org.eclipse.jetty.server" version="9.4.14.v20181114"/>
+      <unit id="org.eclipse.jetty.server.source" version="9.4.14.v20181114"/>
+      <unit id="org.eclipse.jetty.servlet" version="9.4.14.v20181114"/>
+      <unit id="org.eclipse.jetty.servlet.source" version="9.4.14.v20181114"/>
+      <unit id="org.eclipse.jetty.util" version="9.4.14.v20181114"/>
+      <unit id="org.eclipse.jetty.util.source" version="9.4.14.v20181114"/>
+      <repository id="jetty-9.4.14" location="http://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.4.14.v20181114"/>
     </location>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
       <unit id="org.apache.ant" version="1.10.5.v20190526-1402"/>
@@ -37,6 +37,12 @@
       <unit id="org.apache.httpcomponents.httpcore.source" version="4.4.10.v20190123-2214"/>
       <unit id="org.apache.log4j" version="1.2.15.v201012070815"/>
       <unit id="org.apache.log4j.source" version="1.2.15.v201012070815"/>
+      <unit id="org.bouncycastle.bcpg" version="1.60.0.v20181210-2057"/>
+      <unit id="org.bouncycastle.bcpg.source" version="1.60.0.v20181210-2057"/>
+      <unit id="org.bouncycastle.bcpkix" version="1.60.0.v20181210-2057"/>
+      <unit id="org.bouncycastle.bcpkix.source" version="1.60.0.v20181210-2057"/>
+      <unit id="org.bouncycastle.bcprov" version="1.60.0.v20181210-2057"/>
+      <unit id="org.bouncycastle.bcprov.source" version="1.60.0.v20181210-2057"/>
       <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"/>
@@ -62,8 +68,8 @@
       <unit id="org.junit.source" version="4.12.0.v201504281640"/>
       <unit id="javax.servlet" version="3.1.0.v201410161800"/>
       <unit id="javax.servlet.source" version="3.1.0.v201410161800"/>
-      <unit id="org.tukaani.xz" version="1.6.0.v20170629-1752"/>
-      <unit id="org.tukaani.xz.source" version="1.6.0.v20170629-1752"/>
+      <unit id="org.tukaani.xz" version="1.8.0.v20180207-1613"/>
+      <unit id="org.tukaani.xz.source" version="1.8.0.v20180207-1613"/>
       <unit id="org.slf4j.api" version="1.7.2.v20121108-1250"/>
       <unit id="org.slf4j.api.source" version="1.7.2.v20121108-1250"/>
       <unit id="org.slf4j.impl.log4j12" version="1.7.2.v20131105-2200"/>
@@ -80,7 +86,7 @@
     </location>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
       <unit id="org.eclipse.osgi" version="0.0.0"/>
-      <repository location="http://download.eclipse.org/releases/mars/"/>
+      <repository location="http://download.eclipse.org/releases/2018-12/"/>
     </location>
   </locations>
 </target>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.10.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.10.tpd
new file mode 100644
index 0000000..6beb42e
--- /dev/null
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.10.tpd
@@ -0,0 +1,8 @@
+target "jgit-4.10" with source configurePhase
+
+include "projects/jetty-9.4.14.tpd"
+include "orbit/R20190602212107-2019-06.tpd"
+
+location "http://download.eclipse.org/releases/2018-12/" {
+	org.eclipse.osgi lazy
+}
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.10-staging.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.11-staging.target
similarity index 72%
rename from org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.10-staging.target
rename to org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.11-staging.target
index 55e44b8..0857af3 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.10-staging.target
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.11-staging.target
@@ -1,26 +1,26 @@
 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
 <?pde?>
 <!-- generated with https://github.com/eclipse-cbi/targetplatform-dsl -->
-<target name="jgit-4.9-staging" sequenceNumber="1566229361">
+<target name="jgit-4.11-staging" sequenceNumber="1566244434">
   <locations>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
-      <unit id="org.eclipse.jetty.client" version="9.4.11.v20180605"/>
-      <unit id="org.eclipse.jetty.client.source" version="9.4.11.v20180605"/>
-      <unit id="org.eclipse.jetty.continuation" version="9.4.11.v20180605"/>
-      <unit id="org.eclipse.jetty.continuation.source" version="9.4.11.v20180605"/>
-      <unit id="org.eclipse.jetty.http" version="9.4.11.v20180605"/>
-      <unit id="org.eclipse.jetty.http.source" version="9.4.11.v20180605"/>
-      <unit id="org.eclipse.jetty.io" version="9.4.11.v20180605"/>
-      <unit id="org.eclipse.jetty.io.source" version="9.4.11.v20180605"/>
-      <unit id="org.eclipse.jetty.security" version="9.4.11.v20180605"/>
-      <unit id="org.eclipse.jetty.security.source" version="9.4.11.v20180605"/>
-      <unit id="org.eclipse.jetty.server" version="9.4.11.v20180605"/>
-      <unit id="org.eclipse.jetty.server.source" version="9.4.11.v20180605"/>
-      <unit id="org.eclipse.jetty.servlet" version="9.4.11.v20180605"/>
-      <unit id="org.eclipse.jetty.servlet.source" version="9.4.11.v20180605"/>
-      <unit id="org.eclipse.jetty.util" version="9.4.11.v20180605"/>
-      <unit id="org.eclipse.jetty.util.source" version="9.4.11.v20180605"/>
-      <repository id="jetty-9.4.11" location="http://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.4.11.v20180605"/>
+      <unit id="org.eclipse.jetty.client" version="9.4.14.v20181114"/>
+      <unit id="org.eclipse.jetty.client.source" version="9.4.14.v20181114"/>
+      <unit id="org.eclipse.jetty.continuation" version="9.4.14.v20181114"/>
+      <unit id="org.eclipse.jetty.continuation.source" version="9.4.14.v20181114"/>
+      <unit id="org.eclipse.jetty.http" version="9.4.14.v20181114"/>
+      <unit id="org.eclipse.jetty.http.source" version="9.4.14.v20181114"/>
+      <unit id="org.eclipse.jetty.io" version="9.4.14.v20181114"/>
+      <unit id="org.eclipse.jetty.io.source" version="9.4.14.v20181114"/>
+      <unit id="org.eclipse.jetty.security" version="9.4.14.v20181114"/>
+      <unit id="org.eclipse.jetty.security.source" version="9.4.14.v20181114"/>
+      <unit id="org.eclipse.jetty.server" version="9.4.14.v20181114"/>
+      <unit id="org.eclipse.jetty.server.source" version="9.4.14.v20181114"/>
+      <unit id="org.eclipse.jetty.servlet" version="9.4.14.v20181114"/>
+      <unit id="org.eclipse.jetty.servlet.source" version="9.4.14.v20181114"/>
+      <unit id="org.eclipse.jetty.util" version="9.4.14.v20181114"/>
+      <unit id="org.eclipse.jetty.util.source" version="9.4.14.v20181114"/>
+      <repository id="jetty-9.4.14" location="http://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.4.14.v20181114"/>
     </location>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
       <unit id="org.apache.ant" version="1.10.5.v20190526-1402"/>
@@ -37,6 +37,12 @@
       <unit id="org.apache.httpcomponents.httpcore.source" version="4.4.10.v20190123-2214"/>
       <unit id="org.apache.log4j" version="1.2.15.v201012070815"/>
       <unit id="org.apache.log4j.source" version="1.2.15.v201012070815"/>
+      <unit id="org.bouncycastle.bcpg" version="1.60.0.v20181210-2057"/>
+      <unit id="org.bouncycastle.bcpg.source" version="1.60.0.v20181210-2057"/>
+      <unit id="org.bouncycastle.bcpkix" version="1.60.0.v20181210-2057"/>
+      <unit id="org.bouncycastle.bcpkix.source" version="1.60.0.v20181210-2057"/>
+      <unit id="org.bouncycastle.bcprov" version="1.60.0.v20181210-2057"/>
+      <unit id="org.bouncycastle.bcprov.source" version="1.60.0.v20181210-2057"/>
       <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"/>
@@ -62,8 +68,8 @@
       <unit id="org.junit.source" version="4.12.0.v201504281640"/>
       <unit id="javax.servlet" version="3.1.0.v201410161800"/>
       <unit id="javax.servlet.source" version="3.1.0.v201410161800"/>
-      <unit id="org.tukaani.xz" version="1.6.0.v20170629-1752"/>
-      <unit id="org.tukaani.xz.source" version="1.6.0.v20170629-1752"/>
+      <unit id="org.tukaani.xz" version="1.8.0.v20180207-1613"/>
+      <unit id="org.tukaani.xz.source" version="1.8.0.v20180207-1613"/>
       <unit id="org.slf4j.api" version="1.7.2.v20121108-1250"/>
       <unit id="org.slf4j.api.source" version="1.7.2.v20121108-1250"/>
       <unit id="org.slf4j.impl.log4j12" version="1.7.2.v20131105-2200"/>
@@ -80,7 +86,7 @@
     </location>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
       <unit id="org.eclipse.osgi" version="0.0.0"/>
-      <repository location="http://download.eclipse.org/staging/2018-12/"/>
+      <repository location="http://download.eclipse.org/staging/2019-03/"/>
     </location>
   </locations>
 </target>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.11-staging.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.11-staging.tpd
new file mode 100644
index 0000000..4fc23ed
--- /dev/null
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.11-staging.tpd
@@ -0,0 +1,8 @@
+target "jgit-4.11-staging" with source configurePhase
+
+include "projects/jetty-9.4.14.tpd"
+include "orbit/R20190602212107-2019-06.tpd"
+
+location "http://download.eclipse.org/staging/2019-03/" {
+	org.eclipse.osgi lazy
+}
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.5.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.5.tpd
deleted file mode 100644
index 7a5feb0..0000000
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.5.tpd
+++ /dev/null
@@ -1,8 +0,0 @@
-target "jgit-4.5" with source configurePhase
-
-include "projects/jetty-9.4.11.tpd"
-include "orbit/R20190602212107-2019-06.tpd"
-
-location "http://download.eclipse.org/releases/mars/" {
-	org.eclipse.osgi lazy
-}
\ No newline at end of file
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 997d9c9..05488b9 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,26 +1,26 @@
 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
 <?pde?>
 <!-- generated with https://github.com/eclipse-cbi/targetplatform-dsl -->
-<target name="jgit-4.6" sequenceNumber="1566229352">
+<target name="jgit-4.6" sequenceNumber="1566244561">
   <locations>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
-      <unit id="org.eclipse.jetty.client" version="9.4.11.v20180605"/>
-      <unit id="org.eclipse.jetty.client.source" version="9.4.11.v20180605"/>
-      <unit id="org.eclipse.jetty.continuation" version="9.4.11.v20180605"/>
-      <unit id="org.eclipse.jetty.continuation.source" version="9.4.11.v20180605"/>
-      <unit id="org.eclipse.jetty.http" version="9.4.11.v20180605"/>
-      <unit id="org.eclipse.jetty.http.source" version="9.4.11.v20180605"/>
-      <unit id="org.eclipse.jetty.io" version="9.4.11.v20180605"/>
-      <unit id="org.eclipse.jetty.io.source" version="9.4.11.v20180605"/>
-      <unit id="org.eclipse.jetty.security" version="9.4.11.v20180605"/>
-      <unit id="org.eclipse.jetty.security.source" version="9.4.11.v20180605"/>
-      <unit id="org.eclipse.jetty.server" version="9.4.11.v20180605"/>
-      <unit id="org.eclipse.jetty.server.source" version="9.4.11.v20180605"/>
-      <unit id="org.eclipse.jetty.servlet" version="9.4.11.v20180605"/>
-      <unit id="org.eclipse.jetty.servlet.source" version="9.4.11.v20180605"/>
-      <unit id="org.eclipse.jetty.util" version="9.4.11.v20180605"/>
-      <unit id="org.eclipse.jetty.util.source" version="9.4.11.v20180605"/>
-      <repository id="jetty-9.4.11" location="http://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.4.11.v20180605"/>
+      <unit id="org.eclipse.jetty.client" version="9.4.14.v20181114"/>
+      <unit id="org.eclipse.jetty.client.source" version="9.4.14.v20181114"/>
+      <unit id="org.eclipse.jetty.continuation" version="9.4.14.v20181114"/>
+      <unit id="org.eclipse.jetty.continuation.source" version="9.4.14.v20181114"/>
+      <unit id="org.eclipse.jetty.http" version="9.4.14.v20181114"/>
+      <unit id="org.eclipse.jetty.http.source" version="9.4.14.v20181114"/>
+      <unit id="org.eclipse.jetty.io" version="9.4.14.v20181114"/>
+      <unit id="org.eclipse.jetty.io.source" version="9.4.14.v20181114"/>
+      <unit id="org.eclipse.jetty.security" version="9.4.14.v20181114"/>
+      <unit id="org.eclipse.jetty.security.source" version="9.4.14.v20181114"/>
+      <unit id="org.eclipse.jetty.server" version="9.4.14.v20181114"/>
+      <unit id="org.eclipse.jetty.server.source" version="9.4.14.v20181114"/>
+      <unit id="org.eclipse.jetty.servlet" version="9.4.14.v20181114"/>
+      <unit id="org.eclipse.jetty.servlet.source" version="9.4.14.v20181114"/>
+      <unit id="org.eclipse.jetty.util" version="9.4.14.v20181114"/>
+      <unit id="org.eclipse.jetty.util.source" version="9.4.14.v20181114"/>
+      <repository id="jetty-9.4.14" location="http://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.4.14.v20181114"/>
     </location>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
       <unit id="org.apache.ant" version="1.10.5.v20190526-1402"/>
@@ -37,6 +37,12 @@
       <unit id="org.apache.httpcomponents.httpcore.source" version="4.4.10.v20190123-2214"/>
       <unit id="org.apache.log4j" version="1.2.15.v201012070815"/>
       <unit id="org.apache.log4j.source" version="1.2.15.v201012070815"/>
+      <unit id="org.bouncycastle.bcpg" version="1.60.0.v20181210-2057"/>
+      <unit id="org.bouncycastle.bcpg.source" version="1.60.0.v20181210-2057"/>
+      <unit id="org.bouncycastle.bcpkix" version="1.60.0.v20181210-2057"/>
+      <unit id="org.bouncycastle.bcpkix.source" version="1.60.0.v20181210-2057"/>
+      <unit id="org.bouncycastle.bcprov" version="1.60.0.v20181210-2057"/>
+      <unit id="org.bouncycastle.bcprov.source" version="1.60.0.v20181210-2057"/>
       <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"/>
@@ -62,8 +68,8 @@
       <unit id="org.junit.source" version="4.12.0.v201504281640"/>
       <unit id="javax.servlet" version="3.1.0.v201410161800"/>
       <unit id="javax.servlet.source" version="3.1.0.v201410161800"/>
-      <unit id="org.tukaani.xz" version="1.6.0.v20170629-1752"/>
-      <unit id="org.tukaani.xz.source" version="1.6.0.v20170629-1752"/>
+      <unit id="org.tukaani.xz" version="1.8.0.v20180207-1613"/>
+      <unit id="org.tukaani.xz.source" version="1.8.0.v20180207-1613"/>
       <unit id="org.slf4j.api" version="1.7.2.v20121108-1250"/>
       <unit id="org.slf4j.api.source" version="1.7.2.v20121108-1250"/>
       <unit id="org.slf4j.impl.log4j12" version="1.7.2.v20131105-2200"/>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.6.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.6.tpd
index 8b3dd0b..1a2c9a3 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.6.tpd
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.6.tpd
@@ -1,6 +1,6 @@
 target "jgit-4.6" with source configurePhase
 
-include "projects/jetty-9.4.11.tpd"
+include "projects/jetty-9.4.14.tpd"
 include "orbit/R20190602212107-2019-06.tpd"
 
 location "http://download.eclipse.org/releases/neon/" {
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 03c9a8b..e82222a 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,26 +1,26 @@
 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
 <?pde?>
 <!-- generated with https://github.com/eclipse-cbi/targetplatform-dsl -->
-<target name="jgit-4.7" sequenceNumber="1566229348">
+<target name="jgit-4.7" sequenceNumber="1566244564">
   <locations>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
-      <unit id="org.eclipse.jetty.client" version="9.4.11.v20180605"/>
-      <unit id="org.eclipse.jetty.client.source" version="9.4.11.v20180605"/>
-      <unit id="org.eclipse.jetty.continuation" version="9.4.11.v20180605"/>
-      <unit id="org.eclipse.jetty.continuation.source" version="9.4.11.v20180605"/>
-      <unit id="org.eclipse.jetty.http" version="9.4.11.v20180605"/>
-      <unit id="org.eclipse.jetty.http.source" version="9.4.11.v20180605"/>
-      <unit id="org.eclipse.jetty.io" version="9.4.11.v20180605"/>
-      <unit id="org.eclipse.jetty.io.source" version="9.4.11.v20180605"/>
-      <unit id="org.eclipse.jetty.security" version="9.4.11.v20180605"/>
-      <unit id="org.eclipse.jetty.security.source" version="9.4.11.v20180605"/>
-      <unit id="org.eclipse.jetty.server" version="9.4.11.v20180605"/>
-      <unit id="org.eclipse.jetty.server.source" version="9.4.11.v20180605"/>
-      <unit id="org.eclipse.jetty.servlet" version="9.4.11.v20180605"/>
-      <unit id="org.eclipse.jetty.servlet.source" version="9.4.11.v20180605"/>
-      <unit id="org.eclipse.jetty.util" version="9.4.11.v20180605"/>
-      <unit id="org.eclipse.jetty.util.source" version="9.4.11.v20180605"/>
-      <repository id="jetty-9.4.11" location="http://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.4.11.v20180605"/>
+      <unit id="org.eclipse.jetty.client" version="9.4.14.v20181114"/>
+      <unit id="org.eclipse.jetty.client.source" version="9.4.14.v20181114"/>
+      <unit id="org.eclipse.jetty.continuation" version="9.4.14.v20181114"/>
+      <unit id="org.eclipse.jetty.continuation.source" version="9.4.14.v20181114"/>
+      <unit id="org.eclipse.jetty.http" version="9.4.14.v20181114"/>
+      <unit id="org.eclipse.jetty.http.source" version="9.4.14.v20181114"/>
+      <unit id="org.eclipse.jetty.io" version="9.4.14.v20181114"/>
+      <unit id="org.eclipse.jetty.io.source" version="9.4.14.v20181114"/>
+      <unit id="org.eclipse.jetty.security" version="9.4.14.v20181114"/>
+      <unit id="org.eclipse.jetty.security.source" version="9.4.14.v20181114"/>
+      <unit id="org.eclipse.jetty.server" version="9.4.14.v20181114"/>
+      <unit id="org.eclipse.jetty.server.source" version="9.4.14.v20181114"/>
+      <unit id="org.eclipse.jetty.servlet" version="9.4.14.v20181114"/>
+      <unit id="org.eclipse.jetty.servlet.source" version="9.4.14.v20181114"/>
+      <unit id="org.eclipse.jetty.util" version="9.4.14.v20181114"/>
+      <unit id="org.eclipse.jetty.util.source" version="9.4.14.v20181114"/>
+      <repository id="jetty-9.4.14" location="http://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.4.14.v20181114"/>
     </location>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
       <unit id="org.apache.ant" version="1.10.5.v20190526-1402"/>
@@ -37,6 +37,12 @@
       <unit id="org.apache.httpcomponents.httpcore.source" version="4.4.10.v20190123-2214"/>
       <unit id="org.apache.log4j" version="1.2.15.v201012070815"/>
       <unit id="org.apache.log4j.source" version="1.2.15.v201012070815"/>
+      <unit id="org.bouncycastle.bcpg" version="1.60.0.v20181210-2057"/>
+      <unit id="org.bouncycastle.bcpg.source" version="1.60.0.v20181210-2057"/>
+      <unit id="org.bouncycastle.bcpkix" version="1.60.0.v20181210-2057"/>
+      <unit id="org.bouncycastle.bcpkix.source" version="1.60.0.v20181210-2057"/>
+      <unit id="org.bouncycastle.bcprov" version="1.60.0.v20181210-2057"/>
+      <unit id="org.bouncycastle.bcprov.source" version="1.60.0.v20181210-2057"/>
       <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"/>
@@ -62,8 +68,8 @@
       <unit id="org.junit.source" version="4.12.0.v201504281640"/>
       <unit id="javax.servlet" version="3.1.0.v201410161800"/>
       <unit id="javax.servlet.source" version="3.1.0.v201410161800"/>
-      <unit id="org.tukaani.xz" version="1.6.0.v20170629-1752"/>
-      <unit id="org.tukaani.xz.source" version="1.6.0.v20170629-1752"/>
+      <unit id="org.tukaani.xz" version="1.8.0.v20180207-1613"/>
+      <unit id="org.tukaani.xz.source" version="1.8.0.v20180207-1613"/>
       <unit id="org.slf4j.api" version="1.7.2.v20121108-1250"/>
       <unit id="org.slf4j.api.source" version="1.7.2.v20121108-1250"/>
       <unit id="org.slf4j.impl.log4j12" version="1.7.2.v20131105-2200"/>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.7.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.7.tpd
index e93fc46..fc1b046 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.7.tpd
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.7.tpd
@@ -1,6 +1,6 @@
 target "jgit-4.7" with source configurePhase
 
-include "projects/jetty-9.4.11.tpd"
+include "projects/jetty-9.4.14.tpd"
 include "orbit/R20190602212107-2019-06.tpd"
 
 location "http://download.eclipse.org/releases/oxygen/" {
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 e29620c..0b353db 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,26 +1,26 @@
 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
 <?pde?>
 <!-- generated with https://github.com/eclipse-cbi/targetplatform-dsl -->
-<target name="jgit-4.8" sequenceNumber="1566229344">
+<target name="jgit-4.8" sequenceNumber="1566244569">
   <locations>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
-      <unit id="org.eclipse.jetty.client" version="9.4.11.v20180605"/>
-      <unit id="org.eclipse.jetty.client.source" version="9.4.11.v20180605"/>
-      <unit id="org.eclipse.jetty.continuation" version="9.4.11.v20180605"/>
-      <unit id="org.eclipse.jetty.continuation.source" version="9.4.11.v20180605"/>
-      <unit id="org.eclipse.jetty.http" version="9.4.11.v20180605"/>
-      <unit id="org.eclipse.jetty.http.source" version="9.4.11.v20180605"/>
-      <unit id="org.eclipse.jetty.io" version="9.4.11.v20180605"/>
-      <unit id="org.eclipse.jetty.io.source" version="9.4.11.v20180605"/>
-      <unit id="org.eclipse.jetty.security" version="9.4.11.v20180605"/>
-      <unit id="org.eclipse.jetty.security.source" version="9.4.11.v20180605"/>
-      <unit id="org.eclipse.jetty.server" version="9.4.11.v20180605"/>
-      <unit id="org.eclipse.jetty.server.source" version="9.4.11.v20180605"/>
-      <unit id="org.eclipse.jetty.servlet" version="9.4.11.v20180605"/>
-      <unit id="org.eclipse.jetty.servlet.source" version="9.4.11.v20180605"/>
-      <unit id="org.eclipse.jetty.util" version="9.4.11.v20180605"/>
-      <unit id="org.eclipse.jetty.util.source" version="9.4.11.v20180605"/>
-      <repository id="jetty-9.4.11" location="http://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.4.11.v20180605"/>
+      <unit id="org.eclipse.jetty.client" version="9.4.14.v20181114"/>
+      <unit id="org.eclipse.jetty.client.source" version="9.4.14.v20181114"/>
+      <unit id="org.eclipse.jetty.continuation" version="9.4.14.v20181114"/>
+      <unit id="org.eclipse.jetty.continuation.source" version="9.4.14.v20181114"/>
+      <unit id="org.eclipse.jetty.http" version="9.4.14.v20181114"/>
+      <unit id="org.eclipse.jetty.http.source" version="9.4.14.v20181114"/>
+      <unit id="org.eclipse.jetty.io" version="9.4.14.v20181114"/>
+      <unit id="org.eclipse.jetty.io.source" version="9.4.14.v20181114"/>
+      <unit id="org.eclipse.jetty.security" version="9.4.14.v20181114"/>
+      <unit id="org.eclipse.jetty.security.source" version="9.4.14.v20181114"/>
+      <unit id="org.eclipse.jetty.server" version="9.4.14.v20181114"/>
+      <unit id="org.eclipse.jetty.server.source" version="9.4.14.v20181114"/>
+      <unit id="org.eclipse.jetty.servlet" version="9.4.14.v20181114"/>
+      <unit id="org.eclipse.jetty.servlet.source" version="9.4.14.v20181114"/>
+      <unit id="org.eclipse.jetty.util" version="9.4.14.v20181114"/>
+      <unit id="org.eclipse.jetty.util.source" version="9.4.14.v20181114"/>
+      <repository id="jetty-9.4.14" location="http://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.4.14.v20181114"/>
     </location>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
       <unit id="org.apache.ant" version="1.10.5.v20190526-1402"/>
@@ -37,6 +37,12 @@
       <unit id="org.apache.httpcomponents.httpcore.source" version="4.4.10.v20190123-2214"/>
       <unit id="org.apache.log4j" version="1.2.15.v201012070815"/>
       <unit id="org.apache.log4j.source" version="1.2.15.v201012070815"/>
+      <unit id="org.bouncycastle.bcpg" version="1.60.0.v20181210-2057"/>
+      <unit id="org.bouncycastle.bcpg.source" version="1.60.0.v20181210-2057"/>
+      <unit id="org.bouncycastle.bcpkix" version="1.60.0.v20181210-2057"/>
+      <unit id="org.bouncycastle.bcpkix.source" version="1.60.0.v20181210-2057"/>
+      <unit id="org.bouncycastle.bcprov" version="1.60.0.v20181210-2057"/>
+      <unit id="org.bouncycastle.bcprov.source" version="1.60.0.v20181210-2057"/>
       <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"/>
@@ -62,8 +68,8 @@
       <unit id="org.junit.source" version="4.12.0.v201504281640"/>
       <unit id="javax.servlet" version="3.1.0.v201410161800"/>
       <unit id="javax.servlet.source" version="3.1.0.v201410161800"/>
-      <unit id="org.tukaani.xz" version="1.6.0.v20170629-1752"/>
-      <unit id="org.tukaani.xz.source" version="1.6.0.v20170629-1752"/>
+      <unit id="org.tukaani.xz" version="1.8.0.v20180207-1613"/>
+      <unit id="org.tukaani.xz.source" version="1.8.0.v20180207-1613"/>
       <unit id="org.slf4j.api" version="1.7.2.v20121108-1250"/>
       <unit id="org.slf4j.api.source" version="1.7.2.v20121108-1250"/>
       <unit id="org.slf4j.impl.log4j12" version="1.7.2.v20131105-2200"/>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.8.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.8.tpd
index ba6337d..a8f837e 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.8.tpd
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.8.tpd
@@ -1,6 +1,6 @@
 target "jgit-4.8" with source configurePhase
 
-include "projects/jetty-9.4.11.tpd"
+include "projects/jetty-9.4.14.tpd"
 include "orbit/R20190602212107-2019-06.tpd"
 
 location "http://download.eclipse.org/releases/photon/" {
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.9.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.9.target
index 82a64ce..94a752c 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.9.target
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.9.target
@@ -1,26 +1,26 @@
 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
 <?pde?>
 <!-- generated with https://github.com/eclipse-cbi/targetplatform-dsl -->
-<target name="jgit-4.9" sequenceNumber="1566229339">
+<target name="jgit-4.9" sequenceNumber="1566244572">
   <locations>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
-      <unit id="org.eclipse.jetty.client" version="9.4.11.v20180605"/>
-      <unit id="org.eclipse.jetty.client.source" version="9.4.11.v20180605"/>
-      <unit id="org.eclipse.jetty.continuation" version="9.4.11.v20180605"/>
-      <unit id="org.eclipse.jetty.continuation.source" version="9.4.11.v20180605"/>
-      <unit id="org.eclipse.jetty.http" version="9.4.11.v20180605"/>
-      <unit id="org.eclipse.jetty.http.source" version="9.4.11.v20180605"/>
-      <unit id="org.eclipse.jetty.io" version="9.4.11.v20180605"/>
-      <unit id="org.eclipse.jetty.io.source" version="9.4.11.v20180605"/>
-      <unit id="org.eclipse.jetty.security" version="9.4.11.v20180605"/>
-      <unit id="org.eclipse.jetty.security.source" version="9.4.11.v20180605"/>
-      <unit id="org.eclipse.jetty.server" version="9.4.11.v20180605"/>
-      <unit id="org.eclipse.jetty.server.source" version="9.4.11.v20180605"/>
-      <unit id="org.eclipse.jetty.servlet" version="9.4.11.v20180605"/>
-      <unit id="org.eclipse.jetty.servlet.source" version="9.4.11.v20180605"/>
-      <unit id="org.eclipse.jetty.util" version="9.4.11.v20180605"/>
-      <unit id="org.eclipse.jetty.util.source" version="9.4.11.v20180605"/>
-      <repository id="jetty-9.4.11" location="http://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.4.11.v20180605"/>
+      <unit id="org.eclipse.jetty.client" version="9.4.14.v20181114"/>
+      <unit id="org.eclipse.jetty.client.source" version="9.4.14.v20181114"/>
+      <unit id="org.eclipse.jetty.continuation" version="9.4.14.v20181114"/>
+      <unit id="org.eclipse.jetty.continuation.source" version="9.4.14.v20181114"/>
+      <unit id="org.eclipse.jetty.http" version="9.4.14.v20181114"/>
+      <unit id="org.eclipse.jetty.http.source" version="9.4.14.v20181114"/>
+      <unit id="org.eclipse.jetty.io" version="9.4.14.v20181114"/>
+      <unit id="org.eclipse.jetty.io.source" version="9.4.14.v20181114"/>
+      <unit id="org.eclipse.jetty.security" version="9.4.14.v20181114"/>
+      <unit id="org.eclipse.jetty.security.source" version="9.4.14.v20181114"/>
+      <unit id="org.eclipse.jetty.server" version="9.4.14.v20181114"/>
+      <unit id="org.eclipse.jetty.server.source" version="9.4.14.v20181114"/>
+      <unit id="org.eclipse.jetty.servlet" version="9.4.14.v20181114"/>
+      <unit id="org.eclipse.jetty.servlet.source" version="9.4.14.v20181114"/>
+      <unit id="org.eclipse.jetty.util" version="9.4.14.v20181114"/>
+      <unit id="org.eclipse.jetty.util.source" version="9.4.14.v20181114"/>
+      <repository id="jetty-9.4.14" location="http://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.4.14.v20181114"/>
     </location>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
       <unit id="org.apache.ant" version="1.10.5.v20190526-1402"/>
@@ -37,6 +37,12 @@
       <unit id="org.apache.httpcomponents.httpcore.source" version="4.4.10.v20190123-2214"/>
       <unit id="org.apache.log4j" version="1.2.15.v201012070815"/>
       <unit id="org.apache.log4j.source" version="1.2.15.v201012070815"/>
+      <unit id="org.bouncycastle.bcpg" version="1.60.0.v20181210-2057"/>
+      <unit id="org.bouncycastle.bcpg.source" version="1.60.0.v20181210-2057"/>
+      <unit id="org.bouncycastle.bcpkix" version="1.60.0.v20181210-2057"/>
+      <unit id="org.bouncycastle.bcpkix.source" version="1.60.0.v20181210-2057"/>
+      <unit id="org.bouncycastle.bcprov" version="1.60.0.v20181210-2057"/>
+      <unit id="org.bouncycastle.bcprov.source" version="1.60.0.v20181210-2057"/>
       <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"/>
@@ -62,8 +68,8 @@
       <unit id="org.junit.source" version="4.12.0.v201504281640"/>
       <unit id="javax.servlet" version="3.1.0.v201410161800"/>
       <unit id="javax.servlet.source" version="3.1.0.v201410161800"/>
-      <unit id="org.tukaani.xz" version="1.6.0.v20170629-1752"/>
-      <unit id="org.tukaani.xz.source" version="1.6.0.v20170629-1752"/>
+      <unit id="org.tukaani.xz" version="1.8.0.v20180207-1613"/>
+      <unit id="org.tukaani.xz.source" version="1.8.0.v20180207-1613"/>
       <unit id="org.slf4j.api" version="1.7.2.v20121108-1250"/>
       <unit id="org.slf4j.api.source" version="1.7.2.v20121108-1250"/>
       <unit id="org.slf4j.impl.log4j12" version="1.7.2.v20131105-2200"/>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.9.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.9.tpd
index d5beea3..f91f53e 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.9.tpd
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.9.tpd
@@ -1,6 +1,6 @@
 target "jgit-4.9" with source configurePhase
 
-include "projects/jetty-9.4.11.tpd"
+include "projects/jetty-9.4.14.tpd"
 include "orbit/R20190602212107-2019-06.tpd"
 
 location "http://download.eclipse.org/releases/2018-09/" {
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/R20181128170323-2018-12.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/R20181128170323-2018-12.tpd
index d5a257d..fd69da2 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/R20181128170323-2018-12.tpd
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/R20181128170323-2018-12.tpd
@@ -16,6 +16,12 @@
 	org.apache.httpcomponents.httpcore.source [4.4.9.v20180409-1525,4.4.9.v20180409-1525]
 	org.apache.log4j [1.2.15.v201012070815,1.2.15.v201012070815]
 	org.apache.log4j.source [1.2.15.v201012070815,1.2.15.v201012070815]
+	org.bouncycastle.bcpg [1.60.0.v20181107-1520,1.60.0.v20181107-1520]
+	org.bouncycastle.bcpg.source [1.60.0.v20181107-1520,1.60.0.v20181107-1520]
+	org.bouncycastle.bcpkix [1.60.0.v20181107-1520,1.60.0.v20181107-1520]
+	org.bouncycastle.bcpkix.source [1.60.0.v20181107-1520,1.60.0.v20181107-1520]
+	org.bouncycastle.bcprov [1.60.0.v20181107-1520,1.60.0.v20181107-1520]
+	org.bouncycastle.bcprov.source [1.60.0.v20181107-1520,1.60.0.v20181107-1520]
 	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]
@@ -41,8 +47,8 @@
 	org.junit.source [4.12.0.v201504281640,4.12.0.v201504281640]
 	javax.servlet [3.1.0.v201410161800,3.1.0.v201410161800]
 	javax.servlet.source [3.1.0.v201410161800,3.1.0.v201410161800]
-	org.tukaani.xz [1.6.0.v20170629-1752,1.6.0.v20170629-1752]
-	org.tukaani.xz.source [1.6.0.v20170629-1752,1.6.0.v20170629-1752]
+	org.tukaani.xz [1.8.0.v20180207-1613,1.8.0.v20180207-1613]
+	org.tukaani.xz.source [1.8.0.v20180207-1613,1.8.0.v20180207-1613]
 	org.slf4j.api [1.7.2.v20121108-1250,1.7.2.v20121108-1250]
 	org.slf4j.api.source [1.7.2.v20121108-1250,1.7.2.v20121108-1250]
 	org.slf4j.impl.log4j12 [1.7.2.v20131105-2200,1.7.2.v20131105-2200]
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/R20190226160451-2019-03.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/R20190226160451-2019-03.tpd
new file mode 100644
index 0000000..32aba68
--- /dev/null
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/R20190226160451-2019-03.tpd
@@ -0,0 +1,64 @@
+target "R20190226160451-2019-03" with source configurePhase
+// see http://download.eclipse.org/tools/orbit/downloads/
+
+location "http://download.eclipse.org/tools/orbit/downloads/drops/R20190226160451/repository" {
+	org.apache.ant [1.10.5.v20180808-0324,1.10.5.v20180808-0324]
+	org.apache.ant.source [1.10.5.v20180808-0324,1.10.5.v20180808-0324]
+	org.apache.commons.codec [1.10.0.v20180409-1845,1.10.0.v20180409-1845]
+	org.apache.commons.codec.source [1.10.0.v20180409-1845,1.10.0.v20180409-1845]
+	org.apache.commons.compress [1.18.0.v20181121-2221,1.18.0.v20181121-2221]
+	org.apache.commons.compress.source [1.18.0.v20181121-2221,1.18.0.v20181121-2221]
+	org.apache.commons.logging [1.2.0.v20180409-1502,1.2.0.v20180409-1502]
+	org.apache.commons.logging.source [1.2.0.v20180409-1502,1.2.0.v20180409-1502]
+	org.apache.httpcomponents.httpclient [4.5.6.v20190213-1430,4.5.6.v20190213-1430]
+	org.apache.httpcomponents.httpclient.source [4.5.6.v20190213-1430,4.5.6.v20190213-1430]
+	org.apache.httpcomponents.httpcore [4.4.10.v20190123-2214,4.4.10.v20190123-2214]
+	org.apache.httpcomponents.httpcore.source [4.4.10.v20190123-2214,4.4.10.v20190123-2214]
+	org.apache.log4j [1.2.15.v201012070815,1.2.15.v201012070815]
+	org.apache.log4j.source [1.2.15.v201012070815,1.2.15.v201012070815]
+	org.bouncycastle.bcpg [1.60.0.v20181210-2057,1.60.0.v20181210-2057]
+	org.bouncycastle.bcpg.source [1.60.0.v20181210-2057,1.60.0.v20181210-2057]
+	org.bouncycastle.bcpkix [1.60.0.v20181210-2057,1.60.0.v20181210-2057]
+	org.bouncycastle.bcpkix.source [1.60.0.v20181210-2057,1.60.0.v20181210-2057]
+	org.bouncycastle.bcprov [1.60.0.v20181210-2057,1.60.0.v20181210-2057]
+	org.bouncycastle.bcprov.source [1.60.0.v20181210-2057,1.60.0.v20181210-2057]
+	org.kohsuke.args4j [2.33.0.v20160323-2218,2.33.0.v20160323-2218]
+	org.kohsuke.args4j.source [2.33.0.v20160323-2218,2.33.0.v20160323-2218]
+	org.hamcrest [1.1.0.v20090501071000,1.1.0.v20090501071000]
+	org.hamcrest.core [1.3.0.v20180420-1519,1.3.0.v20180420-1519]
+	org.hamcrest.core.source [1.3.0.v20180420-1519,1.3.0.v20180420-1519]
+	org.hamcrest.library [1.3.0.v20180524-2246,1.3.0.v20180524-2246]
+	org.hamcrest.library.source [1.3.0.v20180524-2246,1.3.0.v20180524-2246]
+	javaewah [1.1.6.v20160919-1400,1.1.6.v20160919-1400]
+	javaewah.source [1.1.6.v20160919-1400,1.1.6.v20160919-1400]
+	org.objenesis [2.6.0.v20180420-1519,2.6.0.v20180420-1519]
+	org.objenesis.source [2.6.0.v20180420-1519,2.6.0.v20180420-1519]
+	org.mockito [2.13.0.v20180426-1843,2.13.0.v20180426-1843]
+	org.mockito.source [2.13.0.v20180426-1843,2.13.0.v20180426-1843]
+	net.bytebuddy.byte-buddy [1.7.9.v20180420-1519,1.7.9.v20180420-1519]
+	net.bytebuddy.byte-buddy.source [1.7.9.v20180420-1519,1.7.9.v20180420-1519]
+	net.bytebuddy.byte-buddy-agent [1.7.9.v20180420-1519,1.7.9.v20180420-1519]
+	net.bytebuddy.byte-buddy-agent.source [1.7.9.v20180420-1519,1.7.9.v20180420-1519]
+	com.google.gson [2.8.2.v20180104-1110,2.8.2.v20180104-1110]
+	com.google.gson.source [2.8.2.v20180104-1110,2.8.2.v20180104-1110]
+	com.jcraft.jsch [0.1.54.v20170116-1932,0.1.54.v20170116-1932]
+	com.jcraft.jsch.source [0.1.54.v20170116-1932,0.1.54.v20170116-1932]
+	org.junit [4.12.0.v201504281640,4.12.0.v201504281640]
+	org.junit.source [4.12.0.v201504281640,4.12.0.v201504281640]
+	javax.servlet [3.1.0.v201410161800,3.1.0.v201410161800]
+	javax.servlet.source [3.1.0.v201410161800,3.1.0.v201410161800]
+	org.tukaani.xz [1.8.0.v20180207-1613,1.8.0.v20180207-1613]
+	org.tukaani.xz.source [1.8.0.v20180207-1613,1.8.0.v20180207-1613]
+	org.slf4j.api [1.7.2.v20121108-1250,1.7.2.v20121108-1250]
+	org.slf4j.api.source [1.7.2.v20121108-1250,1.7.2.v20121108-1250]
+	org.slf4j.impl.log4j12 [1.7.2.v20131105-2200,1.7.2.v20131105-2200]
+	org.slf4j.impl.log4j12.source [1.7.2.v20131105-2200,1.7.2.v20131105-2200]
+	com.jcraft.jzlib [1.1.1.v201205102305,1.1.1.v201205102305]
+	com.jcraft.jzlib.source [1.1.1.v201205102305,1.1.1.v201205102305]
+	net.i2p.crypto.eddsa [0.3.0.v20181102-1323,0.3.0.v20181102-1323]
+	net.i2p.crypto.eddsa.source [0.3.0.v20181102-1323,0.3.0.v20181102-1323]
+	org.apache.sshd.core [2.0.0.v20181102-1323,2.0.0.v20181102-1323]
+	org.apache.sshd.core.source [2.0.0.v20181102-1323,2.0.0.v20181102-1323]
+	org.apache.sshd.sftp [2.0.0.v20181102-1323,2.0.0.v20181102-1323]
+	org.apache.sshd.sftp.source [2.0.0.v20181102-1323,2.0.0.v20181102-1323]
+}
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/R20190602212107-2019-06.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/R20190602212107-2019-06.tpd
index b503092..65d5c9f 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/R20190602212107-2019-06.tpd
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/R20190602212107-2019-06.tpd
@@ -16,6 +16,12 @@
 	org.apache.httpcomponents.httpcore.source [4.4.10.v20190123-2214,4.4.10.v20190123-2214]
 	org.apache.log4j [1.2.15.v201012070815,1.2.15.v201012070815]
 	org.apache.log4j.source [1.2.15.v201012070815,1.2.15.v201012070815]
+	org.bouncycastle.bcpg [1.60.0.v20181210-2057,1.60.0.v20181210-2057]
+	org.bouncycastle.bcpg.source [1.60.0.v20181210-2057,1.60.0.v20181210-2057]
+	org.bouncycastle.bcpkix [1.60.0.v20181210-2057,1.60.0.v20181210-2057]
+	org.bouncycastle.bcpkix.source [1.60.0.v20181210-2057,1.60.0.v20181210-2057]
+	org.bouncycastle.bcprov [1.60.0.v20181210-2057,1.60.0.v20181210-2057]
+	org.bouncycastle.bcprov.source [1.60.0.v20181210-2057,1.60.0.v20181210-2057]
 	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]
@@ -41,8 +47,8 @@
 	org.junit.source [4.12.0.v201504281640,4.12.0.v201504281640]
 	javax.servlet [3.1.0.v201410161800,3.1.0.v201410161800]
 	javax.servlet.source [3.1.0.v201410161800,3.1.0.v201410161800]
-	org.tukaani.xz [1.6.0.v20170629-1752,1.6.0.v20170629-1752]
-	org.tukaani.xz.source [1.6.0.v20170629-1752,1.6.0.v20170629-1752]
+	org.tukaani.xz [1.8.0.v20180207-1613,1.8.0.v20180207-1613]
+	org.tukaani.xz.source [1.8.0.v20180207-1613,1.8.0.v20180207-1613]
 	org.slf4j.api [1.7.2.v20121108-1250,1.7.2.v20121108-1250]
 	org.slf4j.api.source [1.7.2.v20121108-1250,1.7.2.v20121108-1250]
 	org.slf4j.impl.log4j12 [1.7.2.v20131105-2200,1.7.2.v20131105-2200]
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 dba70d3..03c338e 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>5.2.3-SNAPSHOT</version>
+    <version>5.3.7-SNAPSHOT</version>
   </parent>
 
   <artifactId>org.eclipse.jgit.target</artifactId>
@@ -82,4 +82,4 @@
       </plugin>
     </plugins>
   </build>
-</project>
+</project>
\ No newline at end of file
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/projects/jetty-9.4.11.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/projects/jetty-9.4.11.tpd
deleted file mode 100644
index d2fd901..0000000
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/projects/jetty-9.4.11.tpd
+++ /dev/null
@@ -1,20 +0,0 @@
-target "jetty-9.4.11" with source configurePhase
-
-location jetty-9.4.11 "http://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.4.11.v20180605" {
-	org.eclipse.jetty.client [9.4.11.v20180605,9.4.11.v20180605]
-	org.eclipse.jetty.client.source [9.4.11.v20180605,9.4.11.v20180605]
-	org.eclipse.jetty.continuation [9.4.11.v20180605,9.4.11.v20180605]
-	org.eclipse.jetty.continuation.source [9.4.11.v20180605,9.4.11.v20180605]
-	org.eclipse.jetty.http [9.4.11.v20180605,9.4.11.v20180605]
-	org.eclipse.jetty.http.source [9.4.11.v20180605,9.4.11.v20180605]
-	org.eclipse.jetty.io [9.4.11.v20180605,9.4.11.v20180605]
-	org.eclipse.jetty.io.source [9.4.11.v20180605,9.4.11.v20180605]
-	org.eclipse.jetty.security [9.4.11.v20180605,9.4.11.v20180605]
-	org.eclipse.jetty.security.source [9.4.11.v20180605,9.4.11.v20180605]
-	org.eclipse.jetty.server [9.4.11.v20180605,9.4.11.v20180605]
-	org.eclipse.jetty.server.source [9.4.11.v20180605,9.4.11.v20180605]
-	org.eclipse.jetty.servlet [9.4.11.v20180605,9.4.11.v20180605]
-	org.eclipse.jetty.servlet.source [9.4.11.v20180605,9.4.11.v20180605]
-	org.eclipse.jetty.util [9.4.11.v20180605,9.4.11.v20180605]
-	org.eclipse.jetty.util.source [9.4.11.v20180605,9.4.11.v20180605]
-}
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/projects/jetty-9.4.14.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/projects/jetty-9.4.14.tpd
new file mode 100644
index 0000000..5372e77
--- /dev/null
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/projects/jetty-9.4.14.tpd
@@ -0,0 +1,20 @@
+target "jetty-9.4.14" with source configurePhase
+
+location jetty-9.4.14 "http://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.4.14.v20181114" {
+	org.eclipse.jetty.client [9.4.14.v20181114,9.4.14.v20181114]
+	org.eclipse.jetty.client.source [9.4.14.v20181114,9.4.14.v20181114]
+	org.eclipse.jetty.continuation [9.4.14.v20181114,9.4.14.v20181114]
+	org.eclipse.jetty.continuation.source [9.4.14.v20181114,9.4.14.v20181114]
+	org.eclipse.jetty.http [9.4.14.v20181114,9.4.14.v20181114]
+	org.eclipse.jetty.http.source [9.4.14.v20181114,9.4.14.v20181114]
+	org.eclipse.jetty.io [9.4.14.v20181114,9.4.14.v20181114]
+	org.eclipse.jetty.io.source [9.4.14.v20181114,9.4.14.v20181114]
+	org.eclipse.jetty.security [9.4.14.v20181114,9.4.14.v20181114]
+	org.eclipse.jetty.security.source [9.4.14.v20181114,9.4.14.v20181114]
+	org.eclipse.jetty.server [9.4.14.v20181114,9.4.14.v20181114]
+	org.eclipse.jetty.server.source [9.4.14.v20181114,9.4.14.v20181114]
+	org.eclipse.jetty.servlet [9.4.14.v20181114,9.4.14.v20181114]
+	org.eclipse.jetty.servlet.source [9.4.14.v20181114,9.4.14.v20181114]
+	org.eclipse.jetty.util [9.4.14.v20181114,9.4.14.v20181114]
+	org.eclipse.jetty.util.source [9.4.14.v20181114,9.4.14.v20181114]
+}
diff --git a/org.eclipse.jgit.packaging/pom.xml b/org.eclipse.jgit.packaging/pom.xml
index d8d061e..fa57f7d 100644
--- a/org.eclipse.jgit.packaging/pom.xml
+++ b/org.eclipse.jgit.packaging/pom.xml
@@ -49,7 +49,7 @@
 
   <groupId>org.eclipse.jgit</groupId>
   <artifactId>jgit.tycho.parent</artifactId>
-  <version>5.2.3-SNAPSHOT</version>
+  <version>5.3.7-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 90398a9..0d786fc 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: 5.2.3.qualifier
+Bundle-Version: 5.3.7.qualifier
 Bundle-Vendor: %provider_name
 Bundle-Localization: plugin
 Bundle-ActivationPolicy: lazy
 Bundle-RequiredExecutionEnvironment: JavaSE-1.8
-Import-Package: org.eclipse.jgit.api;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.api.errors;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.diff;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.dircache;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.internal.storage.file;version="5.2.3",
- org.eclipse.jgit.junit;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.lib;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.merge;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.pgm;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.pgm.internal;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.pgm.opt;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.revwalk;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.storage.file;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.transport;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.treewalk;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.util;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.util.io;version="[5.2.3,5.3.0)",
+Import-Package: org.eclipse.jgit.api;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.api.errors;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.diff;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.dircache;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.internal.storage.file;version="5.3.7",
+ org.eclipse.jgit.junit;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.lib;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.merge;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.pgm;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.pgm.internal;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.pgm.opt;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.revwalk;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.storage.file;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.transport;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.treewalk;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.util;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.util.io;version="[5.3.7,5.4.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 ced7168..2525f3a 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>5.2.3-SNAPSHOT</version>
+    <version>5.3.7-SNAPSHOT</version>
   </parent>
 
   <artifactId>org.eclipse.jgit.pgm.test</artifactId>
@@ -109,7 +109,7 @@
       <plugin>
         <artifactId>maven-surefire-plugin</artifactId>
         <configuration>
-          <argLine>-Djava.io.tmpdir=${project.build.directory}</argLine>
+          <argLine>@{argLine} -Djava.io.tmpdir=${project.build.directory}</argLine>
         </configuration>
       </plugin>
     </plugins>
diff --git a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/CheckoutTest.java b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/CheckoutTest.java
index b2115a4..f0e2b38 100644
--- a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/CheckoutTest.java
+++ b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/CheckoutTest.java
@@ -58,6 +58,7 @@
 import org.eclipse.jgit.api.Git;
 import org.eclipse.jgit.api.errors.CheckoutConflictException;
 import org.eclipse.jgit.diff.DiffEntry;
+import org.eclipse.jgit.junit.LocalDiskRepositoryTestCase;
 import org.eclipse.jgit.lib.CLIRepositoryTestCase;
 import org.eclipse.jgit.lib.FileMode;
 import org.eclipse.jgit.lib.Ref;
@@ -684,4 +685,19 @@ public void testCheckoutLink() throws Exception {
 			assertTrue(Files.isSymbolicLink(path));
 		}
 	}
+
+	@Test
+	public void testCheckoutForce_Bug530771() throws Exception {
+		try (Git git = new Git(db)) {
+			File f = writeTrashFile("a", "Hello world");
+			git.add().addFilepattern("a").call();
+			git.commit().setMessage("create a").call();
+			writeTrashFile("a", "Goodbye world");
+			assertEquals("[]",
+					Arrays.toString(execute("git checkout -f HEAD")));
+			assertEquals("Hello world", read(f));
+			assertEquals("[a, mode:100644, content:Hello world]",
+					indexState(db, LocalDiskRepositoryTestCase.CONTENT));
+		}
+	}
 }
diff --git a/org.eclipse.jgit.pgm/META-INF/MANIFEST.MF b/org.eclipse.jgit.pgm/META-INF/MANIFEST.MF
index e10a772..da78a4d 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: 5.2.3.qualifier
+Bundle-Version: 5.3.7.qualifier
 Bundle-Vendor: %provider_name
 Bundle-ActivationPolicy: lazy
 Bundle-Localization: plugin
@@ -28,50 +28,50 @@
  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="[5.2.3,5.3.0)",
- org.eclipse.jgit.api.errors;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.archive;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.awtui;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.blame;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.diff;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.dircache;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.errors;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.gitrepo;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.internal.ketch;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.internal.storage.dfs;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.internal.storage.file;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.internal.storage.io;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.internal.storage.pack;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.internal.storage.reftable;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.internal.storage.reftree;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.lfs;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.lfs.lib;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.lfs.server;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.lfs.server.fs;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.lfs.server.s3;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.lib;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.merge;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.nls;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.notes;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.revplot;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.revwalk;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.revwalk.filter;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.storage.file;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.storage.pack;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.transport;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.transport.http.apache;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.transport.resolver;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.transport.sshd;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.treewalk;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.treewalk.filter;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.util;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.util.io;version="[5.2.3,5.3.0)",
+ org.eclipse.jgit.api;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.api.errors;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.archive;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.awtui;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.blame;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.diff;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.dircache;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.errors;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.gitrepo;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.internal.ketch;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.internal.storage.dfs;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.internal.storage.file;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.internal.storage.io;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.internal.storage.pack;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.internal.storage.reftable;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.internal.storage.reftree;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.lfs;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.lfs.lib;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.lfs.server;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.lfs.server.fs;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.lfs.server.s3;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.lib;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.merge;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.nls;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.notes;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.revplot;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.revwalk;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.revwalk.filter;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.storage.file;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.storage.pack;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.transport;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.transport.http.apache;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.transport.resolver;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.transport.sshd;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.treewalk;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.treewalk.filter;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.util;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.util.io;version="[5.3.7,5.4.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="5.2.3";
+Export-Package: org.eclipse.jgit.console;version="5.3.7";
   uses:="org.eclipse.jgit.transport,
    org.eclipse.jgit.util",
- org.eclipse.jgit.pgm;version="5.2.3";
+ org.eclipse.jgit.pgm;version="5.3.7";
   uses:="org.eclipse.jgit.revwalk,
    org.eclipse.jgit.treewalk.filter,
    org.eclipse.jgit.pgm.opt,
@@ -82,11 +82,11 @@
    org.eclipse.jgit.treewalk,
    javax.swing,
    org.eclipse.jgit.transport",
- org.eclipse.jgit.pgm.debug;version="5.2.3";
+ org.eclipse.jgit.pgm.debug;version="5.3.7";
   uses:="org.eclipse.jgit.util.io,
    org.eclipse.jgit.pgm",
- org.eclipse.jgit.pgm.internal;version="5.2.3";x-friends:="org.eclipse.jgit.pgm.test,org.eclipse.jgit.test",
- org.eclipse.jgit.pgm.opt;version="5.2.3";
+ org.eclipse.jgit.pgm.internal;version="5.3.7";x-friends:="org.eclipse.jgit.pgm.test,org.eclipse.jgit.test",
+ org.eclipse.jgit.pgm.opt;version="5.3.7";
   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 9831e13..d8196e1 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: 5.2.3.qualifier
-Eclipse-SourceBundle: org.eclipse.jgit.pgm;version="5.2.3.qualifier";roots="."
+Bundle-Version: 5.3.7.qualifier
+Eclipse-SourceBundle: org.eclipse.jgit.pgm;version="5.3.7.qualifier";roots="."
diff --git a/org.eclipse.jgit.pgm/jgit.sh b/org.eclipse.jgit.pgm/jgit.sh
index 8267147..e263782 100644
--- a/org.eclipse.jgit.pgm/jgit.sh
+++ b/org.eclipse.jgit.pgm/jgit.sh
@@ -110,9 +110,9 @@
 	LESS=${LESS:-FSRX}
 	export LESS
 
-	"$java" $java_args org.eclipse.jgit.pgm.Main "$@" | $use_pager
+	"$java" $java_args org.springframework.boot.loader.JarLauncher "$@" | $use_pager
 	exit
 else
-  exec "$java" $java_args org.eclipse.jgit.pgm.Main "$@"
+  exec "$java" $java_args org.springframework.boot.loader.JarLauncher "$@"
   exit 1
 fi
diff --git a/org.eclipse.jgit.pgm/pom.xml b/org.eclipse.jgit.pgm/pom.xml
index 81ef1b3..f77d72d 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>5.2.3-SNAPSHOT</version>
+    <version>5.3.7-SNAPSHOT</version>
   </parent>
 
   <artifactId>org.eclipse.jgit.pgm</artifactId>
@@ -172,40 +172,19 @@
       </plugin>
 
       <plugin>
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-shade-plugin</artifactId>
+        <groupId>org.springframework.boot</groupId>
+        <artifactId>spring-boot-maven-plugin</artifactId>
         <executions>
           <execution>
-            <phase>package</phase>
             <goals>
-              <goal>shade</goal>
+              <goal>repackage</goal>
             </goals>
             <configuration>
               <finalName>jgit-cli</finalName>
-              <createDependencyReducedPom>false</createDependencyReducedPom>
-              <transformers>
-                <transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer" />
-                <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
-                  <manifestEntries>
-                    <Main-Class>org.eclipse.jgit.pgm.Main</Main-Class>
-                    <Implementation-Title>JGit Command Line Interface</Implementation-Title>
-                  </manifestEntries>
-                </transformer>
-              </transformers>
-              <filters>
-                <!-- exclude the signing data for individual jars, ueberjar will be signed again -->
-                <filter>
-                  <artifact>*:*</artifact>
-                  <excludes>
-                    <exclude>META-INF/*.SF</exclude>
-                    <exclude>META-INF/*.DSA</exclude>
-                    <exclude>META-INF/*.RSA</exclude>
-                    <exclude>OSGI-OPT/**</exclude>
-                  </excludes>
-                </filter>
-              </filters>
-              <shadedArtifactAttached>true</shadedArtifactAttached>
-              <shadedClassifierName>shaded</shadedClassifierName> <!-- Any name that makes sense -->
+              <attach>false</attach>
+              <mainClass>org.eclipse.jgit.pgm.Main</mainClass>
+              <executable>true</executable>
+              <embeddedLaunchScript>jgit.sh</embeddedLaunchScript>
             </configuration>
           </execution>
         </executions>
@@ -220,11 +199,13 @@
             <phase>package</phase>
             <configuration>
               <target>
-                <concat destfile="${basedir}/target/jgit" force="yes" binary="true">
-                  <fileset file="${basedir}/jgit.sh" />
-                  <fileset file="${basedir}/target/jgit-cli.jar" />
-                </concat>
-                <chmod file="${basedir}/target/jgit" perm="a+x"/>
+                <move
+                  file="${basedir}/target/jgit-cli.jar"
+                  force="yes"
+                  tofile="${basedir}/target/jgit" />
+                <chmod
+                  file="${basedir}/target/jgit"
+                  perm="a+x" />
               </target>
             </configuration>
             <goals>
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 bbf9366..aa2608d 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
@@ -49,6 +49,7 @@
 clonedEmptyRepository=warning: You appear to have cloned an empty repository.
 cloningInto=Cloning into ''{0}''...
 commitLabel=commit
+configOnlyListOptionSupported=only the --list option is currently supported
 configFileNotFound=configuration file {0} not found
 conflictingUsageOf_git_dir_andArguments=conflicting usage of --git-dir and arguments
 couldNotCreateBranch=Could not create branch {0}: {1}
@@ -129,6 +130,7 @@
 metaVar_paths=path ...
 metaVar_pattern=pattern
 metaVar_port=PORT
+metaVar_prefix=PREFIX
 metaVar_ref=REF
 metaVar_refs=REFS
 metaVar_refspec=refspec
@@ -171,7 +173,7 @@
 onBranch=On branch {0}
 onBranchToBeBorn=You are on a branch yet to be born
 onlyOneMetaVarExpectedIn=Only one {0} expected in {1}.
-onlyOneOfIncludeOnlyAllInteractiveCanBeUsed=Only one of --include/--only/--all/--interactive can be used.
+onlyOneCommitOptionAllowed=Only one of --include/--only/--all/--interactive can be used.
 password=Password:
 pathspecDidNotMatch=error: pathspec ''{0}'' did not match any file(s) known to git.
 pushTo=To {0}
@@ -182,6 +184,7 @@
 remoteSideDoesNotSupportDeletingRefs=remote side does not support deleting refs
 removing=Removing {0}
 repaint=Repaint
+resetNoMode=no reset mode set
 s3InvalidBucket=Invalid S3 bucket ''{0}''
 serviceNotSupported=Service ''{0}'' not supported
 skippingObject=skipping {0} {1}
@@ -337,7 +340,8 @@
 usage_filesToAddContentFrom=Files to add content from
 usage_fixAThinPackToBeComplete=fix a thin pack to be complete
 usage_forEachRefOutput=for-each-ref output
-usage_forceCheckout=when switching branches, proceed even if the index or the working tree differs from HEAD
+usage_forcedSwitchBranch=when switching branches do it forcefully. Succeed even if resetting an existing branch would cause commits to become unreachable
+usage_forceCheckout=when checking out a commit succeed even if the working tree or the index is dirty. Overwrite the working tree or index in such cases
 usage_forceClean=required to delete files or directories
 usage_forceCreateBranchEvenExists=force create branch even exists
 usage_forcedFetch=force ref update fetch option
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Add.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Add.java
index 08a9f48..9ecbbf1 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Add.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Add.java
@@ -48,6 +48,7 @@
 
 import org.eclipse.jgit.api.AddCommand;
 import org.eclipse.jgit.api.Git;
+import org.eclipse.jgit.api.errors.GitAPIException;
 import org.kohsuke.args4j.Argument;
 import org.kohsuke.args4j.Option;
 
@@ -69,6 +70,8 @@ protected void run() throws Exception {
 			for (String p : filepatterns)
 				addCmd.addFilepattern(p);
 			addCmd.call();
+		} catch (GitAPIException e) {
+			throw die(e.getMessage(), e);
 		}
 	}
 }
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Archive.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Archive.java
index 4721b3a..cb63a9a 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Archive.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Archive.java
@@ -96,11 +96,11 @@ protected void run() throws Exception {
 				if (output != null)
 					cmd.setFilename(output);
 				cmd.call();
-		} catch (GitAPIException e) {
-			throw die(e.getMessage());
-		}
+			} catch (GitAPIException e) {
+				throw die(e.getMessage(), e);
+			}
 		} catch (FileNotFoundException e) {
-			throw die(e.getMessage());
+			throw die(e.getMessage(), e);
 		} finally {
 			if (output != null && stream != null)
 				stream.close();
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Blame.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Blame.java
index 13a38dd..3858b3d 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Blame.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Blame.java
@@ -65,6 +65,7 @@
 import org.eclipse.jgit.diff.RawText;
 import org.eclipse.jgit.diff.RawTextComparator;
 import org.eclipse.jgit.dircache.DirCache;
+import org.eclipse.jgit.errors.NoWorkTreeException;
 import org.eclipse.jgit.lib.Constants;
 import org.eclipse.jgit.lib.ObjectReader;
 import org.eclipse.jgit.lib.PersonIdent;
@@ -122,8 +123,6 @@ void ignoreAllSpace(@SuppressWarnings("unused") boolean on) {
 	@Argument(index = 1, required = false, metaVar = "metaVar_file")
 	private String file;
 
-	private ObjectReader reader;
-
 	private final Map<RevCommit, String> abbreviatedCommits = new HashMap<>();
 
 	private SimpleDateFormat dateFmt;
@@ -136,29 +135,34 @@ void ignoreAllSpace(@SuppressWarnings("unused") boolean on) {
 
 	/** {@inheritDoc} */
 	@Override
-	protected void run() throws Exception {
+	protected void run() {
 		if (file == null) {
-			if (revision == null)
+			if (revision == null) {
 				throw die(CLIText.get().fileIsRequired);
+			}
 			file = revision;
 			revision = null;
 		}
 
 		boolean autoAbbrev = abbrev == 0;
-		if (abbrev == 0)
+		if (abbrev == 0) {
 			abbrev = db.getConfig().getInt("core", "abbrev", 7); //$NON-NLS-1$ //$NON-NLS-2$
-		if (!showBlankBoundary)
+		}
+		if (!showBlankBoundary) {
 			root = db.getConfig().getBoolean("blame", "blankboundary", false); //$NON-NLS-1$ //$NON-NLS-2$
-		if (!root)
+		}
+		if (!root) {
 			root = db.getConfig().getBoolean("blame", "showroot", false); //$NON-NLS-1$ //$NON-NLS-2$
+		}
 
-		if (showRawTimestamp)
+		if (showRawTimestamp) {
 			dateFmt = new SimpleDateFormat("ZZZZ"); //$NON-NLS-1$
-		else
+		} else {
 			dateFmt = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss ZZZZ"); //$NON-NLS-1$
+		}
 
-		reader = db.newObjectReader();
-		try (BlameGenerator generator = new BlameGenerator(db, file)) {
+		try (ObjectReader reader = db.newObjectReader();
+				BlameGenerator generator = new BlameGenerator(db, file)) {
 			RevFlag scanned = generator.newFlag("SCANNED"); //$NON-NLS-1$
 			generator.setTextComparator(comparator);
 
@@ -166,10 +170,11 @@ protected void run() throws Exception {
 				RevCommit rangeStart = null;
 				List<RevCommit> rangeEnd = new ArrayList<>(2);
 				for (RevCommit c : reverseRange) {
-					if (c.has(RevFlag.UNINTERESTING))
+					if (c.has(RevFlag.UNINTERESTING)) {
 						rangeStart = c;
-					else
+					} else {
 						rangeEnd.add(c);
+					}
 				}
 				generator.reverse(rangeStart, rangeEnd);
 			} else if (revision != null) {
@@ -179,20 +184,23 @@ protected void run() throws Exception {
 				if (!db.isBare()) {
 					DirCache dc = db.readDirCache();
 					int entry = dc.findEntry(file);
-					if (0 <= entry)
+					if (0 <= entry) {
 						generator.push(null, dc.getEntry(entry).getObjectId());
+					}
 
 					File inTree = new File(db.getWorkTree(), file);
-					if (db.getFS().isFile(inTree))
+					if (db.getFS().isFile(inTree)) {
 						generator.push(null, new RawText(inTree));
+					}
 				}
 			}
 
 			blame = BlameResult.create(generator);
 			begin = 0;
 			end = blame.getResultContents().size();
-			if (rangeString != null)
+			if (rangeString != null) {
 				parseLineRangeOption();
+			}
 			blame.computeRange(begin, end);
 
 			int authorWidth = 8;
@@ -203,14 +211,16 @@ protected void run() throws Exception {
 				RevCommit c = blame.getSourceCommit(line);
 				if (c != null && !c.has(scanned)) {
 					c.add(scanned);
-					if (autoAbbrev)
-						abbrev = Math.max(abbrev, uniqueAbbrevLen(c));
+					if (autoAbbrev) {
+						abbrev = Math.max(abbrev, uniqueAbbrevLen(reader, c));
+					}
 					authorWidth = Math.max(authorWidth, author(line).length());
 					dateWidth = Math.max(dateWidth, date(line).length());
 					pathWidth = Math.max(pathWidth, path(line).length());
 				}
-				while (line + 1 < end && blame.getSourceCommit(line + 1) == c)
+				while (line + 1 < end && blame.getSourceCommit(line + 1) == c) {
 					line++;
+				}
 				maxSourceLine = Math.max(maxSourceLine, blame.getSourceLine(line));
 			}
 
@@ -224,7 +234,7 @@ protected void run() throws Exception {
 
 			for (int line = begin; line < end;) {
 				RevCommit c = blame.getSourceCommit(line);
-				String commit = abbreviate(c);
+				String commit = abbreviate(reader, c);
 				String author = null;
 				String date = null;
 				if (!noAuthor) {
@@ -233,12 +243,15 @@ protected void run() throws Exception {
 				}
 				do {
 					outw.print(commit);
-					if (showSourcePath)
+					if (showSourcePath) {
 						outw.format(pathFmt, path(line));
-					if (showSourceLine)
+					}
+					if (showSourceLine) {
 						outw.format(numFmt, valueOf(blame.getSourceLine(line) + 1));
-					if (!noAuthor)
+					}
+					if (!noAuthor) {
 						outw.format(authorFmt, author, date);
+					}
 					outw.format(lineFmt, valueOf(line + 1));
 					outw.flush();
 					blame.getResultContents().writeLine(outs, line);
@@ -246,12 +259,13 @@ protected void run() throws Exception {
 					outw.print('\n');
 				} while (++line < end && blame.getSourceCommit(line) == c);
 			}
-		} finally {
-			reader.close();
+		} catch (NoWorkTreeException | IOException e) {
+			throw die(e.getMessage(), e);
 		}
 	}
 
-	private int uniqueAbbrevLen(RevCommit commit) throws IOException {
+	private int uniqueAbbrevLen(ObjectReader reader, RevCommit commit)
+			throws IOException {
 		return reader.abbreviate(commit, abbrev).length();
 	}
 
@@ -345,7 +359,8 @@ private String date(int line) {
 				dateFmt.format(author.getWhen()));
 	}
 
-	private String abbreviate(RevCommit commit) throws IOException {
+	private String abbreviate(ObjectReader reader, RevCommit commit)
+			throws IOException {
 		String r = abbreviatedCommits.get(commit);
 		if (r != null)
 			return r;
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 a88354d..bac697f 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
@@ -54,6 +54,7 @@
 import org.eclipse.jgit.api.Git;
 import org.eclipse.jgit.api.ListBranchCommand;
 import org.eclipse.jgit.api.ListBranchCommand.ListMode;
+import org.eclipse.jgit.api.errors.GitAPIException;
 import org.eclipse.jgit.lib.Constants;
 import org.eclipse.jgit.lib.ObjectId;
 import org.eclipse.jgit.lib.ObjectReader;
@@ -182,15 +183,17 @@ public void moveRename(List<String> currentAndNew) {
 
 	/** {@inheritDoc} */
 	@Override
-	protected void run() throws Exception {
-		if (delete != null || deleteForce != null) {
-			if (delete != null) {
-				delete(delete, false);
+	protected void run() {
+		try {
+			if (delete != null || deleteForce != null) {
+				if (delete != null) {
+					delete(delete, false);
+				}
+				if (deleteForce != null) {
+					delete(deleteForce, true);
+				}
+				return;
 			}
-			if (deleteForce != null) {
-				delete(deleteForce, true);
-			}
-		} else {
 			if (rename) {
 				String src, dst;
 				if (otherBranch == null) {
@@ -204,22 +207,27 @@ protected void run() throws Exception {
 				} else {
 					src = branch;
 					final Ref old = db.findRef(src);
-					if (old == null)
+					if (old == null) {
 						throw die(MessageFormat.format(CLIText.get().doesNotExist, src));
-					if (!old.getName().startsWith(Constants.R_HEADS))
+					}
+					if (!old.getName().startsWith(Constants.R_HEADS)) {
 						throw die(MessageFormat.format(CLIText.get().notABranch, src));
+					}
 					src = old.getName();
 					dst = otherBranch;
 				}
 
-				if (!dst.startsWith(Constants.R_HEADS))
+				if (!dst.startsWith(Constants.R_HEADS)) {
 					dst = Constants.R_HEADS + dst;
-				if (!Repository.isValidRefName(dst))
+				}
+				if (!Repository.isValidRefName(dst)) {
 					throw die(MessageFormat.format(CLIText.get().notAValidRefName, dst));
+				}
 
 				RefRename r = db.renameRef(src, dst);
-				if (r.rename() != Result.RENAMED)
+				if (r.rename() != Result.RENAMED) {
 					throw die(MessageFormat.format(CLIText.get().cannotBeRenamed, src));
+				}
 
 			} else if (createForce || branch != null) {
 				String newHead = branch;
@@ -264,10 +272,12 @@ protected void run() throws Exception {
 				}
 				list();
 			}
+		} catch (IOException | GitAPIException e) {
+			throw die(e.getMessage(), e);
 		}
 	}
 
-	private void list() throws Exception {
+	private void list() throws IOException, GitAPIException {
 		Ref head = db.exactRef(Constants.HEAD);
 		// This can happen if HEAD is stillborn
 		if (head != null) {
@@ -316,7 +326,7 @@ private void addRef(String name, Ref ref) {
 	}
 
 	private void printHead(final ObjectReader reader, final String ref,
-			final boolean isCurrent, final Ref refObj) throws Exception {
+			final boolean isCurrent, final Ref refObj) throws IOException {
 		outw.print(isCurrent ? '*' : ' ');
 		outw.print(' ');
 		outw.print(ref);
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Checkout.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Checkout.java
index 6ff39fa..7e1737f 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Checkout.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Checkout.java
@@ -69,8 +69,11 @@ class Checkout extends TextBuiltin {
 	@Option(name = "-b", usage = "usage_createBranchAndCheckout")
 	private boolean createBranch = false;
 
+	@Option(name = "-B", usage = "usage_forcedSwitchBranch")
+	private boolean forceSwitchBranch = false;
+
 	@Option(name = "--force", aliases = { "-f" }, usage = "usage_forceCheckout")
-	private boolean force = false;
+	private boolean forced = false;
 
 	@Option(name = "--orphan", usage = "usage_orphan")
 	private boolean orphan = false;
@@ -103,7 +106,8 @@ protected void run() throws Exception {
 			} else {
 				command.setCreateBranch(createBranch);
 				command.setName(name);
-				command.setForce(force);
+				command.setForceRefUpdate(forceSwitchBranch);
+				command.setForced(forced);
 				command.setOrphan(orphan);
 			}
 			try {
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Clean.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Clean.java
index 6ae078c..db9e959 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Clean.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Clean.java
@@ -43,10 +43,13 @@
 
 package org.eclipse.jgit.pgm;
 
+import java.io.IOException;
 import java.text.MessageFormat;
 import java.util.Set;
 
 import org.eclipse.jgit.api.Git;
+import org.eclipse.jgit.api.errors.GitAPIException;
+import org.eclipse.jgit.errors.NoWorkTreeException;
 import org.eclipse.jgit.pgm.internal.CLIText;
 import org.kohsuke.args4j.Option;
 
@@ -64,7 +67,7 @@ class Clean extends TextBuiltin {
 
 	/** {@inheritDoc} */
 	@Override
-	protected void run() throws Exception {
+	protected void run() {
 		try (Git git = new Git(db)) {
 			boolean requireForce = git.getRepository().getConfig()
 					.getBoolean("clean", "requireForce", true); //$NON-NLS-1$ //$NON-NLS-2$
@@ -82,6 +85,8 @@ protected void run() throws Exception {
 				outw.println(MessageFormat.format(CLIText.get().removing,
 						removedFile));
 			}
+		} catch (NoWorkTreeException | GitAPIException | IOException e) {
+			throw die(e.getMessage(), e);
 		}
 	}
 }
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Clone.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Clone.java
index 393c607..fe24620 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Clone.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Clone.java
@@ -110,7 +110,7 @@ protected void run() throws Exception {
 						Constants.OS_USER_DIR), localName);
 			} catch (IllegalArgumentException e) {
 				throw die(MessageFormat.format(
-						CLIText.get().cannotGuessLocalNameFrom, sourceUri));
+						CLIText.get().cannotGuessLocalNameFrom, sourceUri), e);
 			}
 		} else
 			localNameF = new File(localName);
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Commit.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Commit.java
index 2e67c02..b0713f7 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Commit.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Commit.java
@@ -37,18 +37,18 @@
  */
 package org.eclipse.jgit.pgm;
 
+import java.io.IOException;
 import java.util.ArrayList;
 import java.util.List;
 
 import org.eclipse.jgit.api.CommitCommand;
 import org.eclipse.jgit.api.Git;
-import org.eclipse.jgit.api.errors.ConcurrentRefUpdateException;
+import org.eclipse.jgit.api.errors.GitAPIException;
 import org.eclipse.jgit.api.errors.JGitInternalException;
-import org.eclipse.jgit.api.errors.NoHeadException;
-import org.eclipse.jgit.api.errors.NoMessageException;
 import org.eclipse.jgit.lib.Constants;
 import org.eclipse.jgit.lib.Ref;
 import org.eclipse.jgit.pgm.internal.CLIText;
+import org.eclipse.jgit.pgm.opt.GpgSignHandler;
 import org.eclipse.jgit.revwalk.RevCommit;
 import org.eclipse.jgit.util.RawParseUtils;
 import org.kohsuke.args4j.Argument;
@@ -74,26 +74,46 @@ class Commit extends TextBuiltin {
 	@Option(name = "--amend", usage = "usage_CommitAmend")
 	private boolean amend;
 
+	@Option(name = "--gpg-sign", aliases = { "-S" }, forbids = {
+			"--no-gpg-sign" }, handler = GpgSignHandler.class)
+	private String gpgSigningKey;
+
+	@Option(name = "--no-gpg-sign", forbids = { "--gpg-sign" })
+	private boolean noGpgSign;
+
 	@Argument(metaVar = "metaVar_commitPaths", usage = "usage_CommitPaths")
 	private List<String> paths = new ArrayList<>();
 
 	/** {@inheritDoc} */
 	@Override
-	protected void run() throws NoHeadException, NoMessageException,
-			ConcurrentRefUpdateException, JGitInternalException, Exception {
+	protected void run() {
 		try (Git git = new Git(db)) {
 			CommitCommand commitCmd = git.commit();
-			if (author != null)
+			if (author != null) {
 				commitCmd.setAuthor(RawParseUtils.parsePersonIdent(author));
-			if (message != null)
+			}
+			if (message != null) {
 				commitCmd.setMessage(message);
-			if (only && paths.isEmpty())
+			}
+			if (noGpgSign) {
+				commitCmd.setSign(Boolean.FALSE);
+			} else if (gpgSigningKey != null) {
+				commitCmd.setSign(Boolean.TRUE);
+				if (!gpgSigningKey.equals(GpgSignHandler.DEFAULT)) {
+					commitCmd.setSigningKey(gpgSigningKey);
+				}
+			}
+			if (only && paths.isEmpty()) {
 				throw die(CLIText.get().pathsRequired);
-			if (only && all)
-				throw die(CLIText.get().onlyOneOfIncludeOnlyAllInteractiveCanBeUsed);
-			if (!paths.isEmpty())
-				for (String p : paths)
+			}
+			if (only && all) {
+				throw die(CLIText.get().onlyOneCommitOptionAllowed);
+			}
+			if (!paths.isEmpty()) {
+				for (String p : paths) {
 					commitCmd.setOnly(p);
+				}
+			}
 			commitCmd.setAmend(amend);
 			commitCmd.setAll(all);
 			Ref head = db.exactRef(Constants.HEAD);
@@ -103,20 +123,24 @@ protected void run() throws NoHeadException, NoMessageException,
 			RevCommit commit;
 			try {
 				commit = commitCmd.call();
-			} catch (JGitInternalException e) {
-				throw die(e.getMessage());
+			} catch (JGitInternalException | GitAPIException e) {
+				throw die(e.getMessage(), e);
 			}
 
 			String branchName;
-			if (!head.isSymbolic())
+			if (!head.isSymbolic()) {
 				branchName = CLIText.get().branchDetachedHEAD;
-			else {
+			} else {
 				branchName = head.getTarget().getName();
-				if (branchName.startsWith(Constants.R_HEADS))
-					branchName = branchName.substring(Constants.R_HEADS.length());
+				if (branchName.startsWith(Constants.R_HEADS)) {
+					branchName = branchName
+							.substring(Constants.R_HEADS.length());
+				}
 			}
-			outw.println("[" + branchName + " " + commit.name() + "] " //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+			outw.println('[' + branchName + ' ' + commit.name() + "] " //$NON-NLS-1$
 					+ commit.getShortMessage());
+		} catch (IOException e) {
+			throw die(e.getMessage(), e);
 		}
 	}
 }
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Config.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Config.java
index f762c0d..979c6fa 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Config.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Config.java
@@ -42,9 +42,9 @@
 import java.util.Set;
 
 import org.eclipse.jgit.errors.ConfigInvalidException;
-import org.eclipse.jgit.errors.NotSupportedException;
 import org.eclipse.jgit.lib.Constants;
 import org.eclipse.jgit.lib.StoredConfig;
+import org.eclipse.jgit.pgm.internal.CLIText;
 import org.eclipse.jgit.storage.file.FileBasedConfig;
 import org.eclipse.jgit.util.FS;
 import org.eclipse.jgit.util.StringUtils;
@@ -70,12 +70,15 @@ class Config extends TextBuiltin {
 
 	/** {@inheritDoc} */
 	@Override
-	protected void run() throws Exception {
-		if (list)
+	protected void run() {
+		if (!list) {
+			throw die(CLIText.get().configOnlyListOptionSupported);
+		}
+		try {
 			list();
-		else
-			throw new NotSupportedException(
-					"only --list option is currently supported"); //$NON-NLS-1$
+		} catch (IOException | ConfigInvalidException e) {
+			throw die(e.getMessage(), e);
+		}
 	}
 
 	private void list() throws IOException, ConfigInvalidException {
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Describe.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Describe.java
index f914748..d89fee6 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Describe.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Describe.java
@@ -42,12 +42,15 @@
  */
 package org.eclipse.jgit.pgm;
 
+import java.io.IOException;
 import java.util.ArrayList;
 import java.util.List;
 
 import org.eclipse.jgit.api.DescribeCommand;
 import org.eclipse.jgit.api.Git;
+import org.eclipse.jgit.api.errors.GitAPIException;
 import org.eclipse.jgit.api.errors.RefNotFoundException;
+import org.eclipse.jgit.errors.InvalidPatternException;
 import org.eclipse.jgit.lib.ObjectId;
 import org.eclipse.jgit.pgm.internal.CLIText;
 import org.kohsuke.args4j.Argument;
@@ -67,11 +70,12 @@ class Describe extends TextBuiltin {
 
 	/** {@inheritDoc} */
 	@Override
-	protected void run() throws Exception {
+	protected void run() {
 		try (Git git = new Git(db)) {
 			DescribeCommand cmd = git.describe();
-			if (tree != null)
+			if (tree != null) {
 				cmd.setTarget(tree);
+			}
 			cmd.setLong(longDesc);
 			cmd.setMatch(patterns.toArray(new String[0]));
 			String result = null;
@@ -80,10 +84,13 @@ protected void run() throws Exception {
 			} catch (RefNotFoundException e) {
 				throw die(CLIText.get().noNamesFound, e);
 			}
-			if (result == null)
+			if (result == null) {
 				throw die(CLIText.get().noNamesFound);
+			}
 
 			outw.println(result);
+		} catch (IOException | InvalidPatternException | GitAPIException e) {
+			throw die(e.getMessage(), e);
 		}
 	}
 }
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 97e3df3..7747dc7 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
@@ -62,6 +62,7 @@
 import org.eclipse.jgit.diff.RawTextComparator;
 import org.eclipse.jgit.diff.RenameDetector;
 import org.eclipse.jgit.dircache.DirCacheIterator;
+import org.eclipse.jgit.errors.RevisionSyntaxException;
 import org.eclipse.jgit.lib.ObjectId;
 import org.eclipse.jgit.lib.ObjectReader;
 import org.eclipse.jgit.lib.Repository;
@@ -150,12 +151,12 @@ void abbrev(@SuppressWarnings("unused") boolean on) {
 		diffFmt.setAbbreviationLength(OBJECT_ID_STRING_LENGTH);
 	}
 
-	@Option(name = "--src-prefix", usage = "usage_srcPrefix")
+	@Option(name = "--src-prefix", metaVar = "metaVar_prefix", usage = "usage_srcPrefix")
 	void sourcePrefix(String path) {
 		diffFmt.setOldPrefix(path);
 	}
 
-	@Option(name = "--dst-prefix", usage = "usage_dstPrefix")
+	@Option(name = "--dst-prefix", metaVar = "metaVar_prefix", usage = "usage_dstPrefix")
 	void dstPrefix(String path) {
 		diffFmt.setNewPrefix(path);
 	}
@@ -177,14 +178,15 @@ protected void init(Repository repository, String gitDir) {
 
 	/** {@inheritDoc} */
 	@Override
-	protected void run() throws Exception {
+	protected void run() {
 		diffFmt.setRepository(db);
 		try {
 			if (cached) {
 				if (oldTree == null) {
 					ObjectId head = db.resolve(HEAD + "^{tree}"); //$NON-NLS-1$
-					if (head == null)
+					if (head == null) {
 						die(MessageFormat.format(CLIText.get().notATree, HEAD));
+					}
 					CanonicalTreeParser p = new CanonicalTreeParser();
 					try (ObjectReader reader = db.newObjectReader()) {
 						p.reset(reader, head);
@@ -195,15 +197,17 @@ protected void run() throws Exception {
 			} else if (oldTree == null) {
 				oldTree = new DirCacheIterator(db.readDirCache());
 				newTree = new FileTreeIterator(db);
-			} else if (newTree == null)
+			} else if (newTree == null) {
 				newTree = new FileTreeIterator(db);
+			}
 
 			TextProgressMonitor pm = new TextProgressMonitor(errw);
 			pm.setDelayStart(2, TimeUnit.SECONDS);
 			diffFmt.setProgressMonitor(pm);
 			diffFmt.setPathFilter(pathFilter);
-			if (detectRenames != null)
+			if (detectRenames != null) {
 				diffFmt.setDetectRenames(detectRenames.booleanValue());
+			}
 			if (renameLimit != null && diffFmt.isDetectRenames()) {
 				RenameDetector rd = diffFmt.getRenameDetector();
 				rd.setRenameLimit(renameLimit.intValue());
@@ -212,11 +216,12 @@ protected void run() throws Exception {
 			if (showNameAndStatusOnly) {
 				nameStatus(outw, diffFmt.scan(oldTree, newTree));
 				outw.flush();
-
 			} else {
 				diffFmt.format(oldTree, newTree);
 				diffFmt.flush();
 			}
+		} catch (RevisionSyntaxException | IOException e) {
+			throw die(e.getMessage(), e);
 		} finally {
 			diffFmt.close();
 		}
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 42aabc2..371395b 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
@@ -44,6 +44,7 @@
 
 package org.eclipse.jgit.pgm;
 
+import java.io.IOException;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -74,7 +75,7 @@ void tree_0(final AbstractTreeIterator c) {
 
 	/** {@inheritDoc} */
 	@Override
-	protected void run() throws Exception {
+	protected void run() {
 		try (TreeWalk walk = new TreeWalk(db)) {
 			walk.setRecursive(recursive);
 			for (AbstractTreeIterator i : trees)
@@ -83,13 +84,15 @@ protected void run() throws Exception {
 
 			final int nTree = walk.getTreeCount();
 			while (walk.next()) {
-				for (int i = 1; i < nTree; i++)
+				for (int i = 1; i < nTree; i++) {
 					outw.print(':');
+				}
 				for (int i = 0; i < nTree; i++) {
 					final FileMode m = walk.getFileMode(i);
 					final String s = m.toString();
-					for (int pad = 6 - s.length(); pad > 0; pad--)
+					for (int pad = 6 - s.length(); pad > 0; pad--) {
 						outw.print('0');
+					}
 					outw.print(s);
 					outw.print(' ');
 				}
@@ -103,12 +106,13 @@ protected void run() throws Exception {
 				if (nTree == 2) {
 					final int m0 = walk.getRawMode(0);
 					final int m1 = walk.getRawMode(1);
-					if (m0 == 0 && m1 != 0)
+					if (m0 == 0 && m1 != 0) {
 						chg = 'A';
-					else if (m0 != 0 && m1 == 0)
+					} else if (m0 != 0 && m1 == 0) {
 						chg = 'D';
-					else if (m0 != m1 && walk.idEqual(0, 1))
+					} else if (m0 != m1 && walk.idEqual(0, 1)) {
 						chg = 'T';
+					}
 				}
 				outw.print(chg);
 
@@ -116,6 +120,8 @@ else if (m0 != m1 && walk.idEqual(0, 1))
 				outw.print(walk.getPathString());
 				outw.println();
 			}
+		} catch (IOException e) {
+			throw die(e.getMessage(), e);
 		}
 	}
 }
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 61fd521..da3c498 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
@@ -51,6 +51,7 @@
 
 import org.eclipse.jgit.api.FetchCommand;
 import org.eclipse.jgit.api.Git;
+import org.eclipse.jgit.api.errors.GitAPIException;
 import org.eclipse.jgit.lib.Constants;
 import org.eclipse.jgit.lib.SubmoduleConfig.FetchRecurseSubmodulesMode;
 import org.eclipse.jgit.lib.TextProgressMonitor;
@@ -136,27 +137,33 @@ void noRecurseSubmodules(@SuppressWarnings("unused")
 
 	/** {@inheritDoc} */
 	@Override
-	protected void run() throws Exception {
+	protected void run() {
 		try (Git git = new Git(db)) {
 			FetchCommand fetch = git.fetch();
-			if (fsck != null)
+			if (fsck != null) {
 				fetch.setCheckFetchedObjects(fsck.booleanValue());
-			if (prune != null)
+			}
+			if (prune != null) {
 				fetch.setRemoveDeletedRefs(prune.booleanValue());
-			if (toget != null)
+			}
+			if (toget != null) {
 				fetch.setRefSpecs(toget);
+			}
 			if (tags != null) {
 				fetch.setTagOpt(tags.booleanValue() ? TagOpt.FETCH_TAGS
 						: TagOpt.NO_TAGS);
 			}
-			if (0 <= timeout)
+			if (0 <= timeout) {
 				fetch.setTimeout(timeout);
+			}
 			fetch.setDryRun(dryRun);
 			fetch.setRemote(remote);
-			if (thin != null)
+			if (thin != null) {
 				fetch.setThin(thin.booleanValue());
-			if (quiet == null || !quiet.booleanValue())
+			}
+			if (quiet == null || !quiet.booleanValue()) {
 				fetch.setProgressMonitor(new TextProgressMonitor(errw));
+			}
 			fetch.setRecurseSubmodules(recurseSubmodules).setCallback(this);
 			if (force != null) {
 				fetch.setForceUpdate(force.booleanValue());
@@ -164,10 +171,12 @@ protected void run() throws Exception {
 
 			FetchResult result = fetch.call();
 			if (result.getTrackingRefUpdates().isEmpty()
-					&& result.submoduleResults().isEmpty())
+					&& result.submoduleResults().isEmpty()) {
 				return;
-
+			}
 			showFetchResult(result);
+		} catch (GitAPIException | IOException e) {
+			throw die(e.getMessage(), e);
 		}
 	}
 
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Gc.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Gc.java
index 56172f5..e65f0ec 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Gc.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Gc.java
@@ -44,6 +44,7 @@
 package org.eclipse.jgit.pgm;
 
 import org.eclipse.jgit.api.Git;
+import org.eclipse.jgit.api.errors.GitAPIException;
 import org.eclipse.jgit.lib.TextProgressMonitor;
 import org.kohsuke.args4j.Option;
 
@@ -60,11 +61,15 @@ class Gc extends TextBuiltin {
 
 	/** {@inheritDoc} */
 	@Override
-	protected void run() throws Exception {
+	protected void run() {
 		Git git = Git.wrap(db);
-		git.gc().setAggressive(aggressive)
-				.setPreserveOldPacks(preserveOldPacks)
-				.setPrunePreserved(prunePreserved)
-				.setProgressMonitor(new TextProgressMonitor(errw)).call();
+		try {
+			git.gc().setAggressive(aggressive)
+					.setPreserveOldPacks(preserveOldPacks)
+					.setPrunePreserved(prunePreserved)
+					.setProgressMonitor(new TextProgressMonitor(errw)).call();
+		} catch (GitAPIException e) {
+			throw die(e.getMessage(), e);
+		}
 	}
 }
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/IndexPack.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/IndexPack.java
index 2627671..394083c 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/IndexPack.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/IndexPack.java
@@ -45,6 +45,7 @@
 package org.eclipse.jgit.pgm;
 
 import java.io.BufferedInputStream;
+import java.io.IOException;
 
 import org.eclipse.jgit.internal.storage.file.ObjectDirectoryPackParser;
 import org.eclipse.jgit.lib.ObjectInserter;
@@ -62,7 +63,7 @@ class IndexPack extends TextBuiltin {
 
 	/** {@inheritDoc} */
 	@Override
-	protected void run() throws Exception {
+	protected void run() {
 		BufferedInputStream in = new BufferedInputStream(ins);
 		try (ObjectInserter inserter = db.newObjectInserter()) {
 			PackParser p = inserter.newPackParser(in);
@@ -73,6 +74,8 @@ protected void run() throws Exception {
 			}
 			p.parse(new TextProgressMonitor(errw));
 			inserter.flush();
+		} catch (IOException e) {
+			throw die(e.getMessage(), e);
 		}
 	}
 }
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Init.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Init.java
index f880fc2..d24733d 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Init.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Init.java
@@ -49,10 +49,12 @@
 package org.eclipse.jgit.pgm;
 
 import java.io.File;
+import java.io.IOException;
 import java.text.MessageFormat;
 
 import org.eclipse.jgit.api.Git;
 import org.eclipse.jgit.api.InitCommand;
+import org.eclipse.jgit.api.errors.GitAPIException;
 import org.eclipse.jgit.lib.Repository;
 import org.eclipse.jgit.pgm.internal.CLIText;
 import org.kohsuke.args4j.Argument;
@@ -74,7 +76,7 @@ protected final boolean requiresRepository() {
 
 	/** {@inheritDoc} */
 	@Override
-	protected void run() throws Exception {
+	protected void run() {
 		InitCommand command = Git.init();
 		command.setBare(bare);
 		if (gitdir != null) {
@@ -83,9 +85,14 @@ protected void run() throws Exception {
 		if (directory != null) {
 			command.setDirectory(new File(directory));
 		}
-		Repository repository = command.call().getRepository();
-		outw.println(MessageFormat.format(
-				CLIText.get().initializedEmptyGitRepositoryIn, repository
-						.getDirectory().getAbsolutePath()));
+		Repository repository;
+		try {
+			repository = command.call().getRepository();
+			outw.println(MessageFormat.format(
+					CLIText.get().initializedEmptyGitRepositoryIn,
+					repository.getDirectory().getAbsolutePath()));
+		} catch (GitAPIException | IOException e) {
+			throw die(e.getMessage(), e);
+		}
 	}
 }
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 ad92a78..05b7980 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
@@ -193,12 +193,13 @@ protected void init(Repository repository, String gitDir) {
 
 	/** {@inheritDoc} */
 	@Override
-	protected void run() throws Exception {
+	protected void run() {
 		diffFmt.setRepository(db);
 		try {
 			diffFmt.setPathFilter(pathFilter);
-			if (detectRenames != null)
+			if (detectRenames != null) {
 				diffFmt.setDetectRenames(detectRenames.booleanValue());
+			}
 			if (renameLimit != null && diffFmt.isDetectRenames()) {
 				RenameDetector rd = diffFmt.getRenameDetector();
 				rd.setRenameLimit(renameLimit.intValue());
@@ -220,11 +221,13 @@ protected void run() throws Exception {
 				}
 			}
 
-			if (decorate)
+			if (decorate) {
 				allRefsByPeeledObjectId = getRepository()
 						.getAllRefsByPeeledObjectId();
-
+			}
 			super.run();
+		} catch (Exception e) {
+			throw die(e.getMessage(), e);
 		} finally {
 			diffFmt.close();
 		}
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/LsFiles.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/LsFiles.java
index dc13000..ef25844 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/LsFiles.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/LsFiles.java
@@ -48,11 +48,13 @@
 import static org.eclipse.jgit.lib.FileMode.REGULAR_FILE;
 import static org.eclipse.jgit.lib.FileMode.SYMLINK;
 
+import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
 
 import org.eclipse.jgit.dircache.DirCacheIterator;
+import org.eclipse.jgit.errors.RevisionSyntaxException;
 import org.eclipse.jgit.lib.Constants;
 import org.eclipse.jgit.lib.FileMode;
 import org.eclipse.jgit.lib.ObjectId;
@@ -72,7 +74,7 @@ class LsFiles extends TextBuiltin {
 	private List<String> paths = new ArrayList<>();
 
 	@Override
-	protected void run() throws Exception {
+	protected void run() {
 		try (RevWalk rw = new RevWalk(db);
 				TreeWalk tw = new TreeWalk(db)) {
 			final ObjectId head = db.resolve(Constants.HEAD);
@@ -96,6 +98,8 @@ protected void run() throws Exception {
 							QuotedString.GIT_PATH.quote(tw.getPathString()));
 				}
 			}
+		} catch (RevisionSyntaxException | IOException e) {
+			throw die(e.getMessage(), e);
 		}
 	}
 
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 2711c15..1c2564d 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
@@ -51,6 +51,7 @@
 
 import org.eclipse.jgit.api.Git;
 import org.eclipse.jgit.api.LsRemoteCommand;
+import org.eclipse.jgit.api.errors.GitAPIException;
 import org.eclipse.jgit.lib.AnyObjectId;
 import org.eclipse.jgit.lib.Ref;
 import org.kohsuke.args4j.Argument;
@@ -72,7 +73,7 @@ class LsRemote extends TextBuiltin {
 
 	/** {@inheritDoc} */
 	@Override
-	protected void run() throws Exception {
+	protected void run() {
 		LsRemoteCommand command = Git.lsRemoteRepository().setRemote(remote)
 				.setTimeout(timeout).setHeads(heads).setTags(tags);
 		TreeSet<Ref> refs = new TreeSet<>(new Comparator<Ref>() {
@@ -82,11 +83,16 @@ public int compare(Ref r1, Ref r2) {
 				return r1.getName().compareTo(r2.getName());
 			}
 		});
-		refs.addAll(command.call());
-		for (Ref r : refs) {
-			show(r.getObjectId(), r.getName());
-			if (r.getPeeledObjectId() != null)
-				show(r.getPeeledObjectId(), r.getName() + "^{}"); //$NON-NLS-1$
+		try {
+			refs.addAll(command.call());
+			for (Ref r : refs) {
+				show(r.getObjectId(), r.getName());
+				if (r.getPeeledObjectId() != null) {
+					show(r.getPeeledObjectId(), r.getName() + "^{}"); //$NON-NLS-1$
+				}
+			}
+		} catch (GitAPIException | IOException e) {
+			throw die(e.getMessage(), e);
 		}
 	}
 
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 01fa7ee..2a2bb7c 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
@@ -45,6 +45,7 @@
 
 package org.eclipse.jgit.pgm;
 
+import java.io.IOException;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -72,18 +73,20 @@ class LsTree extends TextBuiltin {
 
 	/** {@inheritDoc} */
 	@Override
-	protected void run() throws Exception {
+	protected void run() {
 		try (TreeWalk walk = new TreeWalk(db)) {
 			walk.reset(); // drop the first empty tree, which we do not need here
-			if (paths.size() > 0)
+			if (paths.size() > 0) {
 				walk.setFilter(PathFilterGroup.createFromStrings(paths));
+			}
 			walk.setRecursive(recursive);
 			walk.addTree(tree);
 
 			while (walk.next()) {
 				final FileMode mode = walk.getFileMode(0);
-				if (mode == FileMode.TREE)
+				if (mode == FileMode.TREE) {
 					outw.print('0');
+				}
 				outw.print(mode);
 				outw.print(' ');
 				outw.print(Constants.typeString(mode.getObjectType()));
@@ -95,6 +98,8 @@ protected void run() throws Exception {
 				outw.print(QuotedString.GIT_PATH.quote(walk.getPathString()));
 				outw.println();
 			}
+		} catch (IOException e) {
+			throw die(e.getMessage(), e);
 		}
 	}
 }
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Merge.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Merge.java
index de059e9..0b362a4 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Merge.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Merge.java
@@ -52,6 +52,7 @@
 import org.eclipse.jgit.api.MergeCommand.FastForwardMode;
 import org.eclipse.jgit.api.MergeResult;
 import org.eclipse.jgit.api.errors.CheckoutConflictException;
+import org.eclipse.jgit.api.errors.GitAPIException;
 import org.eclipse.jgit.lib.AnyObjectId;
 import org.eclipse.jgit.lib.Constants;
 import org.eclipse.jgit.lib.ObjectId;
@@ -103,110 +104,124 @@ void ffonly(@SuppressWarnings("unused") final boolean ignored) {
 
 	/** {@inheritDoc} */
 	@Override
-	protected void run() throws Exception {
-		if (squash && ff == FastForwardMode.NO_FF)
+	protected void run() {
+		if (squash && ff == FastForwardMode.NO_FF) {
 			throw die(CLIText.get().cannotCombineSquashWithNoff);
+		}
 		// determine the merge strategy
 		if (strategyName != null) {
 			mergeStrategy = MergeStrategy.get(strategyName);
-			if (mergeStrategy == null)
+			if (mergeStrategy == null) {
 				throw die(MessageFormat.format(
 						CLIText.get().unknownMergeStrategy, strategyName));
-		}
-
-		// determine the other revision we want to merge with HEAD
-		final Ref srcRef = db.findRef(ref);
-		final ObjectId src = db.resolve(ref + "^{commit}"); //$NON-NLS-1$
-		if (src == null)
-			throw die(MessageFormat.format(
-					CLIText.get().refDoesNotExistOrNoCommit, ref));
-
-		Ref oldHead = getOldHead();
-		MergeResult result;
-		try (Git git = new Git(db)) {
-			MergeCommand mergeCmd = git.merge().setStrategy(mergeStrategy)
-					.setSquash(squash).setFastForward(ff).setCommit(!noCommit);
-			if (srcRef != null)
-				mergeCmd.include(srcRef);
-			else
-				mergeCmd.include(src);
-
-			if (message != null)
-				mergeCmd.setMessage(message);
-
-			try {
-				result = mergeCmd.call();
-			} catch (CheckoutConflictException e) {
-				result = new MergeResult(e.getConflictingPaths()); // CHECKOUT_CONFLICT
 			}
 		}
 
-		switch (result.getMergeStatus()) {
-		case ALREADY_UP_TO_DATE:
-			if (squash)
-				outw.print(CLIText.get().nothingToSquash);
-			outw.println(CLIText.get().alreadyUpToDate);
-			break;
-		case FAST_FORWARD:
-			ObjectId oldHeadId = oldHead.getObjectId();
-			if (oldHeadId != null) {
-				String oldId = oldHeadId.abbreviate(7).name();
-				String newId = result.getNewHead().abbreviate(7).name();
-				outw.println(MessageFormat.format(CLIText.get().updating, oldId,
-						newId));
+		try {
+			// determine the other revision we want to merge with HEAD
+			final Ref srcRef = db.findRef(ref);
+			final ObjectId src = db.resolve(ref + "^{commit}"); //$NON-NLS-1$
+			if (src == null) {
+				throw die(MessageFormat
+						.format(CLIText.get().refDoesNotExistOrNoCommit, ref));
 			}
-			outw.println(result.getMergeStatus().toString());
-			break;
-		case CHECKOUT_CONFLICT:
-			outw.println(CLIText.get().mergeCheckoutConflict);
-			for (String collidingPath : result.getCheckoutConflicts())
-				outw.println("\t" + collidingPath); //$NON-NLS-1$
-			outw.println(CLIText.get().mergeCheckoutFailed);
-			break;
-		case CONFLICTING:
-			for (String collidingPath : result.getConflicts().keySet())
-				outw.println(MessageFormat.format(CLIText.get().mergeConflict,
-						collidingPath));
-			outw.println(CLIText.get().mergeFailed);
-			break;
-		case FAILED:
-			for (Map.Entry<String, MergeFailureReason> entry : result
-					.getFailingPaths().entrySet())
-				switch (entry.getValue()) {
-				case DIRTY_WORKTREE:
-				case DIRTY_INDEX:
-					outw.println(CLIText.get().dontOverwriteLocalChanges);
-					outw.println("        " + entry.getKey()); //$NON-NLS-1$
-					break;
-				case COULD_NOT_DELETE:
-					outw.println(CLIText.get().cannotDeleteFile);
-					outw.println("        " + entry.getKey()); //$NON-NLS-1$
-					break;
+
+			Ref oldHead = getOldHead();
+			MergeResult result;
+			try (Git git = new Git(db)) {
+				MergeCommand mergeCmd = git.merge().setStrategy(mergeStrategy)
+						.setSquash(squash).setFastForward(ff)
+						.setCommit(!noCommit);
+				if (srcRef != null) {
+					mergeCmd.include(srcRef);
+				} else {
+					mergeCmd.include(src);
 				}
-			break;
-		case MERGED:
-			String name;
-			if (!isMergedInto(oldHead, src))
-				name = mergeStrategy.getName();
-			else
-				name = "recursive"; //$NON-NLS-1$
-			outw.println(MessageFormat.format(CLIText.get().mergeMadeBy, name));
-			break;
-		case MERGED_NOT_COMMITTED:
-			outw.println(CLIText.get().mergeWentWellStoppedBeforeCommitting);
-			break;
-		case MERGED_SQUASHED:
-		case FAST_FORWARD_SQUASHED:
-		case MERGED_SQUASHED_NOT_COMMITTED:
-			outw.println(CLIText.get().mergedSquashed);
-			outw.println(CLIText.get().mergeWentWellStoppedBeforeCommitting);
-			break;
-		case ABORTED:
-			throw die(CLIText.get().ffNotPossibleAborting);
-		case NOT_SUPPORTED:
-			outw.println(MessageFormat.format(
-					CLIText.get().unsupportedOperation, result.toString()));
+
+				if (message != null) {
+					mergeCmd.setMessage(message);
+				}
+
+				try {
+					result = mergeCmd.call();
+				} catch (CheckoutConflictException e) {
+					result = new MergeResult(e.getConflictingPaths()); // CHECKOUT_CONFLICT
+				}
+			}
+
+			switch (result.getMergeStatus()) {
+			case ALREADY_UP_TO_DATE:
+				if (squash) {
+					outw.print(CLIText.get().nothingToSquash);
+				}
+				outw.println(CLIText.get().alreadyUpToDate);
+				break;
+			case FAST_FORWARD:
+				ObjectId oldHeadId = oldHead.getObjectId();
+				if (oldHeadId != null) {
+					String oldId = oldHeadId.abbreviate(7).name();
+					String newId = result.getNewHead().abbreviate(7).name();
+					outw.println(MessageFormat.format(CLIText.get().updating,
+							oldId, newId));
+				}
+				outw.println(result.getMergeStatus().toString());
+				break;
+			case CHECKOUT_CONFLICT:
+				outw.println(CLIText.get().mergeCheckoutConflict);
+				for (String collidingPath : result.getCheckoutConflicts()) {
+					outw.println("\t" + collidingPath); //$NON-NLS-1$
+				}
+				outw.println(CLIText.get().mergeCheckoutFailed);
+				break;
+			case CONFLICTING:
+				for (String collidingPath : result.getConflicts().keySet())
+					outw.println(MessageFormat.format(
+							CLIText.get().mergeConflict, collidingPath));
+				outw.println(CLIText.get().mergeFailed);
+				break;
+			case FAILED:
+				for (Map.Entry<String, MergeFailureReason> entry : result
+						.getFailingPaths().entrySet())
+					switch (entry.getValue()) {
+					case DIRTY_WORKTREE:
+					case DIRTY_INDEX:
+						outw.println(CLIText.get().dontOverwriteLocalChanges);
+						outw.println("        " + entry.getKey()); //$NON-NLS-1$
+						break;
+					case COULD_NOT_DELETE:
+						outw.println(CLIText.get().cannotDeleteFile);
+						outw.println("        " + entry.getKey()); //$NON-NLS-1$
+						break;
+					}
+				break;
+			case MERGED:
+				MergeStrategy strategy = isMergedInto(oldHead, src)
+						? MergeStrategy.RECURSIVE
+						: mergeStrategy;
+				outw.println(MessageFormat.format(CLIText.get().mergeMadeBy,
+						strategy.getName()));
+				break;
+			case MERGED_NOT_COMMITTED:
+				outw.println(
+						CLIText.get().mergeWentWellStoppedBeforeCommitting);
+				break;
+			case MERGED_SQUASHED:
+			case FAST_FORWARD_SQUASHED:
+			case MERGED_SQUASHED_NOT_COMMITTED:
+				outw.println(CLIText.get().mergedSquashed);
+				outw.println(
+						CLIText.get().mergeWentWellStoppedBeforeCommitting);
+				break;
+			case ABORTED:
+				throw die(CLIText.get().ffNotPossibleAborting);
+			case NOT_SUPPORTED:
+				outw.println(MessageFormat.format(
+						CLIText.get().unsupportedOperation, result.toString()));
+			}
+		} catch (GitAPIException | IOException e) {
+			throw die(e.getMessage(), e);
 		}
+
 	}
 
 	private Ref getOldHead() throws IOException {
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 6842d8d..60b1743 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
@@ -44,6 +44,7 @@
 
 package org.eclipse.jgit.pgm;
 
+import java.io.IOException;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -67,16 +68,22 @@ void commit_0(final RevCommit c) {
 
 	/** {@inheritDoc} */
 	@Override
-	protected void run() throws Exception {
-		for (RevCommit c : commits)
-			argWalk.markStart(c);
-		argWalk.setRevFilter(RevFilter.MERGE_BASE);
-		int max = all ? Integer.MAX_VALUE : 1;
-		while (max-- > 0) {
-			final RevCommit b = argWalk.next();
-			if (b == null)
-				break;
-			outw.println(b.getId().name());
+	protected void run() {
+		try {
+			for (RevCommit c : commits) {
+				argWalk.markStart(c);
+			}
+			argWalk.setRevFilter(RevFilter.MERGE_BASE);
+			int max = all ? Integer.MAX_VALUE : 1;
+			while (max-- > 0) {
+				final RevCommit b = argWalk.next();
+				if (b == null) {
+					break;
+				}
+				outw.println(b.getId().name());
+			}
+		} catch (IOException e) {
+			throw die(e.getMessage(), e);
 		}
 	}
 }
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 be8ad37..e65e5d1 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
@@ -53,6 +53,7 @@
 
 import org.eclipse.jgit.api.Git;
 import org.eclipse.jgit.api.PushCommand;
+import org.eclipse.jgit.api.errors.GitAPIException;
 import org.eclipse.jgit.lib.Constants;
 import org.eclipse.jgit.lib.ObjectId;
 import org.eclipse.jgit.lib.ObjectReader;
@@ -115,7 +116,7 @@ void nothin(@SuppressWarnings("unused") final boolean ignored) {
 
 	/** {@inheritDoc} */
 	@Override
-	protected void run() throws Exception {
+	protected void run() {
 		try (Git git = new Git(db)) {
 			PushCommand push = git.push();
 			push.setDryRun(dryRun);
@@ -123,10 +124,12 @@ protected void run() throws Exception {
 			push.setProgressMonitor(new TextProgressMonitor(errw));
 			push.setReceivePack(receivePack);
 			push.setRefSpecs(refSpecs);
-			if (all)
+			if (all) {
 				push.setPushAll();
-			if (tags)
+			}
+			if (tags) {
 				push.setPushTags();
+			}
 			push.setRemote(remote);
 			push.setThin(thin);
 			push.setAtomic(atomic);
@@ -140,6 +143,8 @@ protected void run() throws Exception {
 					printPushResult(reader, result.getURI(), result);
 				}
 			}
+		} catch (GitAPIException | IOException e) {
+			throw die(e.getMessage(), e);
 		}
 	}
 
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/ReceivePack.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/ReceivePack.java
index f3baafb..b601d80 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/ReceivePack.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/ReceivePack.java
@@ -45,6 +45,7 @@
 package org.eclipse.jgit.pgm;
 
 import java.io.File;
+import java.io.IOException;
 import java.text.MessageFormat;
 
 import org.eclipse.jgit.errors.RepositoryNotFoundException;
@@ -66,7 +67,7 @@ protected final boolean requiresRepository() {
 
 	/** {@inheritDoc} */
 	@Override
-	protected void run() throws Exception {
+	protected void run() {
 		final org.eclipse.jgit.transport.ReceivePack rp;
 
 		try {
@@ -75,9 +76,15 @@ protected void run() throws Exception {
 		} catch (RepositoryNotFoundException notFound) {
 			throw die(MessageFormat.format(CLIText.get().notAGitRepository,
 					dstGitdir.getPath()));
+		} catch (IOException e) {
+			throw die(e.getMessage(), e);
 		}
 
 		rp = new org.eclipse.jgit.transport.ReceivePack(db);
-		rp.receive(ins, outs, errs);
+		try {
+			rp.receive(ins, outs, errs);
+		} catch (IOException e) {
+			throw die(e.getMessage(), e);
+		}
 	}
 }
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Reflog.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Reflog.java
index 6f4fcc2..410e88f 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Reflog.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Reflog.java
@@ -42,10 +42,12 @@
  */
 package org.eclipse.jgit.pgm;
 
+import java.io.IOException;
 import java.util.Collection;
 
 import org.eclipse.jgit.api.Git;
 import org.eclipse.jgit.api.ReflogCommand;
+import org.eclipse.jgit.api.errors.GitAPIException;
 import org.eclipse.jgit.lib.Constants;
 import org.eclipse.jgit.lib.ReflogEntry;
 import org.eclipse.jgit.lib.Repository;
@@ -59,7 +61,7 @@ class Reflog extends TextBuiltin {
 
 	/** {@inheritDoc} */
 	@Override
-	protected void run() throws Exception {
+	protected void run() {
 		try (Git git = new Git(db)) {
 			ReflogCommand cmd = git.reflog();
 			if (ref != null)
@@ -69,6 +71,8 @@ protected void run() throws Exception {
 			for (ReflogEntry entry : entries) {
 				outw.println(toString(entry, i++));
 			}
+		} catch (GitAPIException | IOException e) {
+			throw die(e.getMessage(), e);
 		}
 	}
 
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 63eba15..58138fa 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
@@ -53,6 +53,7 @@
 import org.eclipse.jgit.api.RemoteListCommand;
 import org.eclipse.jgit.api.RemoteRemoveCommand;
 import org.eclipse.jgit.api.RemoteSetUrlCommand;
+import org.eclipse.jgit.api.RemoteSetUrlCommand.UriType;
 import org.eclipse.jgit.api.errors.JGitInternalException;
 import org.eclipse.jgit.pgm.internal.CLIText;
 import org.eclipse.jgit.pgm.opt.CmdLineParser;
@@ -86,7 +87,7 @@ class Remote extends TextBuiltin {
 
 	/** {@inheritDoc} */
 	@Override
-	protected void run() throws Exception {
+	protected void run() {
 		try (Git git = new Git(db)) {
 			if (command == null) {
 				RemoteListCommand cmd = git.remoteList();
@@ -99,13 +100,13 @@ protected void run() throws Exception {
 				cmd.call();
 			} else if ("remove".equals(command) || "rm".equals(command)) { //$NON-NLS-1$ //$NON-NLS-2$
 				RemoteRemoveCommand cmd = git.remoteRemove();
-				cmd.setName(name);
+				cmd.setRemoteName(name);
 				cmd.call();
 			} else if ("set-url".equals(command)) { //$NON-NLS-1$
 				RemoteSetUrlCommand cmd = git.remoteSetUrl();
-				cmd.setName(name);
-				cmd.setUri(new URIish(uri));
-				cmd.setPush(push);
+				cmd.setRemoteName(name);
+				cmd.setRemoteUri(new URIish(uri));
+				cmd.setUriType(push ? UriType.PUSH : UriType.FETCH);
 				cmd.call();
 			} else if ("update".equals(command)) { //$NON-NLS-1$
 				// reuse fetch command for basic implementation of remote update
@@ -141,6 +142,8 @@ protected void run() throws Exception {
 				throw new JGitInternalException(MessageFormat
 						.format(CLIText.get().unknownSubcommand, command));
 			}
+		} catch (Exception e) {
+			throw die(e.getMessage(), e);
 		}
 	}
 
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Repo.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Repo.java
index f557211..eec562d 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Repo.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Repo.java
@@ -42,6 +42,7 @@
  */
 package org.eclipse.jgit.pgm;
 
+import org.eclipse.jgit.api.errors.GitAPIException;
 import org.eclipse.jgit.gitrepo.RepoCommand;
 import org.kohsuke.args4j.Argument;
 import org.kohsuke.args4j.Option;
@@ -60,11 +61,15 @@ class Repo extends TextBuiltin {
 
 	/** {@inheritDoc} */
 	@Override
-	protected void run() throws Exception {
-		new RepoCommand(db)
-			.setURI(uri)
-			.setPath(path)
-			.setGroups(groups)
-			.call();
+	protected void run() {
+		try {
+			new RepoCommand(db)
+				.setURI(uri)
+				.setPath(path)
+				.setGroups(groups)
+				.call();
+		} catch (GitAPIException e) {
+			throw die(e.getMessage(), e);
+		}
 	}
 }
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Reset.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Reset.java
index f84c848..b3e81c6 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Reset.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Reset.java
@@ -49,6 +49,8 @@
 import org.eclipse.jgit.api.Git;
 import org.eclipse.jgit.api.ResetCommand;
 import org.eclipse.jgit.api.ResetCommand.ResetType;
+import org.eclipse.jgit.api.errors.GitAPIException;
+import org.eclipse.jgit.pgm.internal.CLIText;
 import org.kohsuke.args4j.Argument;
 import org.kohsuke.args4j.Option;
 import org.kohsuke.args4j.spi.RestOfArgumentsHandler;
@@ -74,26 +76,33 @@ class Reset extends TextBuiltin {
 
 	/** {@inheritDoc} */
 	@Override
-	protected void run() throws Exception {
+	protected void run() {
 		try (Git git = new Git(db)) {
 			ResetCommand command = git.reset();
 			command.setRef(commit);
 			if (paths.size() > 0) {
-				for (String path : paths)
+				for (String path : paths) {
 					command.addPath(path);
+				}
 			} else {
 				ResetType mode = null;
-				if (soft)
+				if (soft) {
 					mode = selectMode(mode, ResetType.SOFT);
-				if (mixed)
+				}
+				if (mixed) {
 					mode = selectMode(mode, ResetType.MIXED);
-				if (hard)
+				}
+				if (hard) {
 					mode = selectMode(mode, ResetType.HARD);
-				if (mode == null)
-					throw die("no reset mode set"); //$NON-NLS-1$
+				}
+				if (mode == null) {
+					throw die(CLIText.get().resetNoMode);
+				}
 				command.setMode(mode);
 			}
 			command.call();
+		} catch (GitAPIException e) {
+			throw die(e.getMessage(), e);
 		}
 	}
 
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 ac08cd6..9ff12d8 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,6 +45,7 @@
 
 package org.eclipse.jgit.pgm;
 
+import java.io.IOException;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -69,27 +70,31 @@ class RevParse extends TextBuiltin {
 
 	/** {@inheritDoc} */
 	@Override
-	protected void run() throws Exception {
-		if (all) {
-			for (Ref r : db.getRefDatabase().getRefs()) {
-				ObjectId objectId = r.getObjectId();
-				// getRefs skips dangling symrefs, so objectId should never be
-				// null.
-				if (objectId == null) {
-					throw new NullPointerException();
+	protected void run() {
+		try {
+			if (all) {
+				for (Ref r : db.getRefDatabase().getRefs()) {
+					ObjectId objectId = r.getObjectId();
+					// getRefs skips dangling symrefs, so objectId should never
+					// be null.
+					if (objectId == null) {
+						throw new NullPointerException();
+					}
+					outw.println(objectId.name());
 				}
-				outw.println(objectId.name());
-			}
-		} else {
-			if (verify && commits.size() > 1) {
-				final CmdLineParser clp = new CmdLineParser(this);
-				throw new CmdLineException(clp,
-						CLIText.format(CLIText.get().needSingleRevision));
-			}
+			} else {
+				if (verify && commits.size() > 1) {
+					final CmdLineParser clp = new CmdLineParser(this);
+					throw new CmdLineException(clp,
+							CLIText.format(CLIText.get().needSingleRevision));
+				}
 
-			for (ObjectId o : commits) {
-				outw.println(o.name());
+				for (ObjectId o : commits) {
+					outw.println(o.name());
+				}
 			}
+		} catch (IOException | CmdLineException e) {
+			throw die(e.getMessage(), e);
 		}
 	}
 }
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Rm.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Rm.java
index f591610..4b66462 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Rm.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Rm.java
@@ -49,6 +49,7 @@
 
 import org.eclipse.jgit.api.Git;
 import org.eclipse.jgit.api.RmCommand;
+import org.eclipse.jgit.api.errors.GitAPIException;
 import org.kohsuke.args4j.Argument;
 import org.kohsuke.args4j.Option;
 import org.kohsuke.args4j.spi.StopOptionHandler;
@@ -61,12 +62,15 @@ class Rm extends TextBuiltin {
 
 	/** {@inheritDoc} */
 	@Override
-	protected void run() throws Exception {
+	protected void run() {
 		try (Git git = new Git(db)) {
 			RmCommand command = git.rm();
-			for (String p : paths)
+			for (String p : paths) {
 				command.addFilepattern(p);
+			}
 			command.call();
+		} catch (GitAPIException e) {
+			throw die(e.getMessage(), e);
 		}
 	}
 }
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 89a15fe..ff3d003 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
@@ -59,6 +59,7 @@
 import org.eclipse.jgit.errors.CorruptObjectException;
 import org.eclipse.jgit.errors.IncorrectObjectTypeException;
 import org.eclipse.jgit.errors.MissingObjectException;
+import org.eclipse.jgit.errors.RevisionSyntaxException;
 import org.eclipse.jgit.lib.Constants;
 import org.eclipse.jgit.lib.FileMode;
 import org.eclipse.jgit.lib.ObjectId;
@@ -175,22 +176,24 @@ protected void init(Repository repository, String gitDir) {
 	/** {@inheritDoc} */
 	@SuppressWarnings("boxing")
 	@Override
-	protected void run() throws Exception {
+	protected void run() {
 		diffFmt.setRepository(db);
 		try {
 			diffFmt.setPathFilter(pathFilter);
-			if (detectRenames != null)
+			if (detectRenames != null) {
 				diffFmt.setDetectRenames(detectRenames.booleanValue());
+			}
 			if (renameLimit != null && diffFmt.isDetectRenames()) {
 				RenameDetector rd = diffFmt.getRenameDetector();
 				rd.setRenameLimit(renameLimit.intValue());
 			}
 
 			ObjectId objectId;
-			if (objectName == null)
+			if (objectName == null) {
 				objectId = db.resolve(Constants.HEAD);
-			else
+			} else {
 				objectId = db.resolve(objectName);
+			}
 
 			try (RevWalk rw = new RevWalk(db)) {
 				RevObject obj = rw.parseAny(objectId);
@@ -224,6 +227,8 @@ protected void run() throws Exception {
 							obj.getType()));
 				}
 			}
+		} catch (RevisionSyntaxException | IOException e) {
+			throw die(e.getMessage(), e);
 		} finally {
 			diffFmt.close();
 		}
@@ -273,7 +278,7 @@ private void show(RevTree obj) throws MissingObjectException,
 		}
 	}
 
-	private void show(RevWalk rw, RevCommit c) throws Exception {
+	private void show(RevWalk rw, RevCommit c) throws IOException {
 		char[] outbuffer = new char[Constants.OBJECT_ID_LENGTH * 2];
 
 		outw.print(CLIText.get().commitLabel);
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 6318a63..b8442c5 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
@@ -56,15 +56,20 @@
 class ShowRef extends TextBuiltin {
 	/** {@inheritDoc} */
 	@Override
-	protected void run() throws Exception {
-		for (Ref r : getSortedRefs()) {
-			show(r.getObjectId(), r.getName());
-			if (r.getPeeledObjectId() != null)
-				show(r.getPeeledObjectId(), r.getName() + "^{}"); //$NON-NLS-1$
+	protected void run() {
+		try {
+			for (Ref r : getSortedRefs()) {
+				show(r.getObjectId(), r.getName());
+				if (r.getPeeledObjectId() != null) {
+					show(r.getPeeledObjectId(), r.getName() + "^{}"); //$NON-NLS-1$
+				}
+			}
+		} catch (IOException e) {
+			throw die(e.getMessage(), e);
 		}
 	}
 
-	private Iterable<Ref> getSortedRefs() throws Exception {
+	private Iterable<Ref> getSortedRefs() throws IOException {
 		List<Ref> all = db.getRefDatabase().getRefs();
 		// TODO(jrn) check if we can reintroduce fast-path by e.g. implementing
 		// SortedList
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Status.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Status.java
index fb2fd7e..dfc8a94 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Status.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Status.java
@@ -54,6 +54,8 @@
 
 import org.eclipse.jgit.api.Git;
 import org.eclipse.jgit.api.StatusCommand;
+import org.eclipse.jgit.api.errors.GitAPIException;
+import org.eclipse.jgit.errors.NoWorkTreeException;
 import org.eclipse.jgit.lib.Constants;
 import org.eclipse.jgit.lib.IndexDiff.StageState;
 import org.eclipse.jgit.lib.Ref;
@@ -88,14 +90,18 @@ class Status extends TextBuiltin {
 
 	/** {@inheritDoc} */
 	@Override
-	protected void run() throws Exception {
+	protected void run() {
 		try (Git git = new Git(db)) {
 			StatusCommand statusCommand = git.status();
-			if (filterPaths != null && filterPaths.size() > 0)
-				for (String path : filterPaths)
+			if (filterPaths != null && filterPaths.size() > 0) {
+				for (String path : filterPaths) {
 					statusCommand.addPath(path);
+				}
+			}
 			org.eclipse.jgit.api.Status status = statusCommand.call();
 			printStatus(status);
+		} catch (GitAPIException | NoWorkTreeException | IOException e) {
+			throw die(e.getMessage(), e);
 		}
 	}
 
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Tag.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Tag.java
index 43c1f54..1da4b1d 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Tag.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Tag.java
@@ -48,12 +48,14 @@
 
 package org.eclipse.jgit.pgm;
 
+import java.io.IOException;
 import java.text.MessageFormat;
 import java.util.List;
 
 import org.eclipse.jgit.api.Git;
 import org.eclipse.jgit.api.ListTagCommand;
 import org.eclipse.jgit.api.TagCommand;
+import org.eclipse.jgit.api.errors.GitAPIException;
 import org.eclipse.jgit.api.errors.RefAlreadyExistsException;
 import org.eclipse.jgit.lib.ObjectId;
 import org.eclipse.jgit.lib.Ref;
@@ -82,7 +84,7 @@ class Tag extends TextBuiltin {
 
 	/** {@inheritDoc} */
 	@Override
-	protected void run() throws Exception {
+	protected void run() {
 		try (Git git = new Git(db)) {
 			if (tagName != null) {
 				if (delete) {
@@ -115,6 +117,8 @@ protected void run() throws Exception {
 					outw.println(Repository.shortenRefName(ref.getName()));
 				}
 			}
+		} catch (GitAPIException | IOException e) {
+			throw die(e.getMessage(), e);
 		}
 	}
 }
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 c4b4018..05f2378 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
@@ -196,7 +196,7 @@ private Charset getLogOutputEncodingCharset(Repository repository) {
 				try {
 					return Charset.forName(logOutputEncoding);
 				} catch (IllegalArgumentException e) {
-					throw die(CLIText.get().cannotCreateOutputStream);
+					throw die(CLIText.get().cannotCreateOutputStream, e);
 				}
 			}
 		}
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/UploadPack.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/UploadPack.java
index 5d032d2..c138302 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/UploadPack.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/UploadPack.java
@@ -45,6 +45,7 @@
 package org.eclipse.jgit.pgm;
 
 import java.io.File;
+import java.io.IOException;
 import java.text.MessageFormat;
 
 import org.eclipse.jgit.errors.RepositoryNotFoundException;
@@ -70,20 +71,21 @@ protected final boolean requiresRepository() {
 
 	/** {@inheritDoc} */
 	@Override
-	protected void run() throws Exception {
-		final org.eclipse.jgit.transport.UploadPack up;
-
+	protected void run() {
 		try {
 			FileKey key = FileKey.lenient(srcGitdir, FS.DETECTED);
 			db = key.open(true /* must exist */);
+			org.eclipse.jgit.transport.UploadPack up = new org.eclipse.jgit.transport.UploadPack(
+					db);
+			if (0 <= timeout) {
+				up.setTimeout(timeout);
+			}
+			up.upload(ins, outs, errs);
 		} catch (RepositoryNotFoundException notFound) {
 			throw die(MessageFormat.format(CLIText.get().notAGitRepository,
 					srcGitdir.getPath()));
+		} catch (IOException e) {
+			throw die(e.getMessage(), e);
 		}
-
-		up = new org.eclipse.jgit.transport.UploadPack(db);
-		if (0 <= timeout)
-			up.setTimeout(timeout);
-		up.upload(ins, outs, errs);
 	}
 }
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 58acc5c..cb447e4 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
@@ -57,21 +57,28 @@
 class Version extends TextBuiltin {
 	/** {@inheritDoc} */
 	@Override
-	protected void run() throws Exception {
+	protected void run() {
 		// read the Implementation-Version from Manifest
 		String version = getImplementationVersion();
 
 		// if Implementation-Version is not available then try reading
 		// Bundle-Version
-		if (version == null)
+		if (version == null) {
 			version = getBundleVersion();
+		}
 
 		// if both Implementation-Version and Bundle-Version are not available
 		// then throw an exception
-		if (version == null)
+		if (version == null) {
 			throw die(CLIText.get().cannotReadPackageInformation);
+		}
 
-		outw.println(MessageFormat.format(CLIText.get().jgitVersion, version));
+		try {
+			outw.println(
+					MessageFormat.format(CLIText.get().jgitVersion, version));
+		} catch (IOException e) {
+			throw die(e.getMessage(), e);
+		}
 	}
 
 	/** {@inheritDoc} */
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/internal/CLIText.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/internal/CLIText.java
index 013ee1c..8a3e43e 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/internal/CLIText.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/internal/CLIText.java
@@ -163,6 +163,7 @@ public static String fatalError(String message) {
 	/***/ public String clonedEmptyRepository;
 	/***/ public String cloningInto;
 	/***/ public String commitLabel;
+	/***/ public String configOnlyListOptionSupported;
 	/***/ public String conflictingUsageOf_git_dir_andArguments;
 	/***/ public String couldNotCreateBranch;
 	/***/ public String dateInfo;
@@ -274,7 +275,7 @@ public static String fatalError(String message) {
 	/***/ public String onBranchToBeBorn;
 	/***/ public String onBranch;
 	/***/ public String onlyOneMetaVarExpectedIn;
-	/***/ public String onlyOneOfIncludeOnlyAllInteractiveCanBeUsed;
+	/***/ public String onlyOneCommitOptionAllowed;
 	/***/ public String password;
 	/***/ public String pathspecDidNotMatch;
 	/***/ public String pushTo;
@@ -285,6 +286,7 @@ public static String fatalError(String message) {
 	/***/ public String remoteSideDoesNotSupportDeletingRefs;
 	/***/ public String removing;
 	/***/ public String repaint;
+	/***/ public String resetNoMode;
 	/***/ public String s3InvalidBucket;
 	/***/ public String serviceNotSupported;
 	/***/ public String skippingObject;
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/GpgSignHandler.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/GpgSignHandler.java
new file mode 100644
index 0000000..e50301a
--- /dev/null
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/GpgSignHandler.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2018, Salesforce.
+ * 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.pgm.opt;
+
+import org.kohsuke.args4j.CmdLineException;
+import org.kohsuke.args4j.CmdLineParser;
+import org.kohsuke.args4j.OptionDef;
+import org.kohsuke.args4j.spi.Parameters;
+import org.kohsuke.args4j.spi.Setter;
+import org.kohsuke.args4j.spi.StringOptionHandler;
+
+/**
+ * Special handler for the <code>--gpg-sign</code> option of the
+ * <code>commit</code> command.
+ *
+ * The following rules apply:
+ * <ul>
+ * <li>If no key is given, i.e. just <code>--gpg-sign</code> is passed, then it
+ * is the same as <code>--gpg-sign=default</code></li>
+ * </ul>
+ *
+ * @since 5.3
+ */
+public class GpgSignHandler extends StringOptionHandler {
+
+	/**
+	 * The value "default" which will be used when just the option is specified
+	 * without any argument
+	 */
+	public static final String DEFAULT = "default"; //$NON-NLS-1$
+
+	/**
+	 * <p>
+	 * Constructor for GpgSignHandler.
+	 * </p>
+	 *
+	 * @param parser
+	 *            The parser to which this handler belongs.
+	 * @param option
+	 *            The annotation.
+	 * @param setter
+	 *            Object to be used for setting value.
+	 */
+	public GpgSignHandler(CmdLineParser parser, OptionDef option,
+			Setter<? super String> setter) {
+		super(parser, option, setter);
+	}
+
+	/** {@inheritDoc} */
+	@Override
+	public int parseArguments(Parameters params) throws CmdLineException {
+		String alias = params.getParameter(-1);
+		if ("--gpg-sign".equals(alias) || "-S".equals(alias)) { //$NON-NLS-1$ //$NON-NLS-2$
+			try {
+				String key = params.getParameter(0);
+				if (key == null || key.startsWith("-")) { //$NON-NLS-1$
+					// ignore invalid values and assume default
+					setter.addValue(DEFAULT);
+					return 0;
+				}
+
+				// use what we have
+				setter.addValue(key);
+				return 1;
+			} catch (CmdLineException e) {
+				// no additional value, assume default
+				setter.addValue(DEFAULT);
+				return 0;
+			}
+		}
+		return 0;
+	}
+
+}
diff --git a/org.eclipse.jgit.ssh.apache.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.ssh.apache.test/META-INF/MANIFEST.MF
index 5456949..602da1d 100644
--- a/org.eclipse.jgit.ssh.apache.test/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.ssh.apache.test/META-INF/MANIFEST.MF
@@ -3,17 +3,17 @@
 Bundle-Name: %Bundle-Name
 Automatic-Module-Name: org.eclipse.jgit.ssh.apache.test
 Bundle-SymbolicName: org.eclipse.jgit.ssh.apache.test
-Bundle-Version: 5.2.3.qualifier
+Bundle-Version: 5.3.7.qualifier
 Bundle-Vendor: %Provider-Name
 Bundle-RequiredExecutionEnvironment: JavaSE-1.8
-Import-Package: org.eclipse.jgit.internal.transport.sshd.proxy;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.junit;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.junit.ssh;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.lib;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.transport;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.transport.ssh;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.transport.sshd;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.util;version="[5.2.3,5.3.0)",
+Import-Package: org.eclipse.jgit.internal.transport.sshd.proxy;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.junit;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.junit.ssh;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.lib;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.transport;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.transport.ssh;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.transport.sshd;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.util;version="[5.3.7,5.4.0)",
  org.junit;version="[4.12,5.0.0)",
  org.junit.experimental.theories;version="[4.12,5.0.0)",
  org.junit.runner;version="[4.12,5.0.0)"
diff --git a/org.eclipse.jgit.ssh.apache.test/pom.xml b/org.eclipse.jgit.ssh.apache.test/pom.xml
index a03f4ec..cc17f91 100644
--- a/org.eclipse.jgit.ssh.apache.test/pom.xml
+++ b/org.eclipse.jgit.ssh.apache.test/pom.xml
@@ -50,7 +50,7 @@
   <parent>
     <groupId>org.eclipse.jgit</groupId>
     <artifactId>org.eclipse.jgit-parent</artifactId>
-    <version>5.2.3-SNAPSHOT</version>
+    <version>5.3.7-SNAPSHOT</version>
   </parent>
 
   <artifactId>org.eclipse.jgit.ssh.apache.test</artifactId>
@@ -106,7 +106,7 @@
             <groupId>org.apache.maven.plugins</groupId>
             <artifactId>maven-surefire-plugin</artifactId>
             <configuration>
-              <argLine>-Djgit.test.long=true</argLine>
+              <argLine>@{argLine} -Djgit.test.long=true</argLine>
             </configuration>
           </plugin>
         </plugins>
@@ -133,7 +133,7 @@
       <plugin>
         <artifactId>maven-surefire-plugin</artifactId>
         <configuration>
-          <argLine>-Xmx1024m -Dfile.encoding=UTF-8 -Djava.io.tmpdir=${project.build.directory}</argLine>
+          <argLine>@{argLine} -Xmx1024m -Dfile.encoding=UTF-8 -Djava.io.tmpdir=${project.build.directory}</argLine>
           <includes>
             <include>**/*Test.java</include>
             <include>**/*Tests.java</include>
diff --git a/org.eclipse.jgit.ssh.apache/META-INF/MANIFEST.MF b/org.eclipse.jgit.ssh.apache/META-INF/MANIFEST.MF
index 29a12bb..1e66e67 100644
--- a/org.eclipse.jgit.ssh.apache/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.ssh.apache/META-INF/MANIFEST.MF
@@ -5,9 +5,9 @@
 Bundle-SymbolicName: org.eclipse.jgit.ssh.apache
 Bundle-Vendor: %Provider-Name
 Bundle-ActivationPolicy: lazy
-Bundle-Version: 5.2.3.qualifier
+Bundle-Version: 5.3.7.qualifier
 Bundle-RequiredExecutionEnvironment: JavaSE-1.8
-Export-Package: org.eclipse.jgit.internal.transport.sshd;version="5.2.3";x-internal:=true;
+Export-Package: org.eclipse.jgit.internal.transport.sshd;version="5.3.7";x-internal:=true;
   uses:="org.apache.sshd.client,
    org.apache.sshd.client.auth,
    org.apache.sshd.client.auth.keyboard,
@@ -22,9 +22,9 @@
    org.apache.sshd.common.signature,
    org.apache.sshd.common.util.buffer,
    org.eclipse.jgit.transport",
- org.eclipse.jgit.internal.transport.sshd.auth;version="5.2.3";x-internal:=true,
- org.eclipse.jgit.internal.transport.sshd.proxy;version="5.2.3";x-friends:="org.eclipse.jgit.ssh.apache.test",
- org.eclipse.jgit.transport.sshd;version="5.2.3";
+ org.eclipse.jgit.internal.transport.sshd.auth;version="5.3.7";x-internal:=true,
+ org.eclipse.jgit.internal.transport.sshd.proxy;version="5.3.7";x-friends:="org.eclipse.jgit.ssh.apache.test",
+ org.eclipse.jgit.transport.sshd;version="5.3.7";
   uses:="org.eclipse.jgit.transport,
    org.apache.sshd.client.config.hosts,
    org.apache.sshd.common.keyprovider,
@@ -72,12 +72,12 @@
  org.apache.sshd.common.util.net;version="[2.0.0,2.1.0)",
  org.apache.sshd.common.util.security;version="[2.0.0,2.1.0)",
  org.apache.sshd.server.auth;version="[2.0.0,2.1.0)",
- org.eclipse.jgit.annotations;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.errors;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.fnmatch;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.internal.storage.file;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.internal.transport.ssh;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.nls;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.transport;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.util;version="[5.2.3,5.3.0)",
+ org.eclipse.jgit.annotations;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.errors;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.fnmatch;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.internal.storage.file;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.internal.transport.ssh;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.nls;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.transport;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.util;version="[5.3.7,5.4.0)",
  org.slf4j;version="[1.7.0,2.0.0)"
diff --git a/org.eclipse.jgit.ssh.apache/META-INF/SOURCE-MANIFEST.MF b/org.eclipse.jgit.ssh.apache/META-INF/SOURCE-MANIFEST.MF
index a16ebd3..2afdd6f 100644
--- a/org.eclipse.jgit.ssh.apache/META-INF/SOURCE-MANIFEST.MF
+++ b/org.eclipse.jgit.ssh.apache/META-INF/SOURCE-MANIFEST.MF
@@ -3,5 +3,5 @@
 Bundle-Name: org.eclipse.jgit.ssh.apache - Sources
 Bundle-SymbolicName: org.eclipse.jgit.ssh.apache.source
 Bundle-Vendor: Eclipse.org - JGit
-Bundle-Version: 5.2.3.qualifier
-Eclipse-SourceBundle: org.eclipse.jgit.ssh.apache;version="5.2.3.qualifier";roots="."
+Bundle-Version: 5.3.7.qualifier
+Eclipse-SourceBundle: org.eclipse.jgit.ssh.apache;version="5.3.7.qualifier";roots="."
diff --git a/org.eclipse.jgit.ssh.apache/pom.xml b/org.eclipse.jgit.ssh.apache/pom.xml
index 2254133..59066b7 100644
--- a/org.eclipse.jgit.ssh.apache/pom.xml
+++ b/org.eclipse.jgit.ssh.apache/pom.xml
@@ -50,7 +50,7 @@
   <parent>
     <groupId>org.eclipse.jgit</groupId>
     <artifactId>org.eclipse.jgit-parent</artifactId>
-    <version>5.2.3-SNAPSHOT</version>
+    <version>5.3.7-SNAPSHOT</version>
   </parent>
 
   <artifactId>org.eclipse.jgit.ssh.apache</artifactId>
@@ -195,7 +195,7 @@
                   <ignoreMissingClasses>false</ignoreMissingClasses>
                   <skipPomModules>true</skipPomModules>
               </parameter>
-              <skip>true</skip><!-- TODO: Enable after the first release -->
+              <skip>false</skip>
           </configuration>
           <executions>
             <execution>
@@ -248,7 +248,7 @@
                   <ignoreMissingClasses>false</ignoreMissingClasses>
                   <skipPomModules>true</skipPomModules>
               </parameter>
-              <skip>true</skip><!-- TODO: Enable after the first release -->
+              <skip>false</skip>
           </configuration>
       </plugin>
     </plugins>
diff --git a/org.eclipse.jgit.ssh.apache/resources/org/eclipse/jgit/internal/transport/sshd/SshdText.properties b/org.eclipse.jgit.ssh.apache/resources/org/eclipse/jgit/internal/transport/sshd/SshdText.properties
index aa4e4cc..bdb4a7d 100644
--- a/org.eclipse.jgit.ssh.apache/resources/org/eclipse/jgit/internal/transport/sshd/SshdText.properties
+++ b/org.eclipse.jgit.ssh.apache/resources/org/eclipse/jgit/internal/transport/sshd/SshdText.properties
@@ -13,6 +13,7 @@
 identityFileCannotDecrypt=Given passphrase cannot decrypt identity {0}
 identityFileNoKey=No keys found in identity {0}
 identityFileMultipleKeys=Multiple key pairs found in identity {0}
+identityFileNotFound=Skipping identity ''{0}'': file not found
 identityFileUnsupportedFormat=Unsupported format in identity {0}
 kexServerKeyInvalid=Server key did not validate
 keyEncryptedMsg=Key ''{0}'' is encrypted. Enter the passphrase to decrypt it.
diff --git a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/CachingKeyPairProvider.java b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/CachingKeyPairProvider.java
index ad2ff52..1072f32 100644
--- a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/CachingKeyPairProvider.java
+++ b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/CachingKeyPairProvider.java
@@ -45,6 +45,7 @@
 import static java.text.MessageFormat.format;
 
 import java.io.IOException;
+import java.nio.file.Files;
 import java.nio.file.Path;
 import java.security.GeneralSecurityException;
 import java.security.KeyPair;
@@ -62,7 +63,8 @@
  * A {@link EncryptedFileKeyPairProvider} that uses an external
  * {@link KeyCache}.
  */
-public class CachingKeyPairProvider extends EncryptedFileKeyPairProvider {
+public class CachingKeyPairProvider extends EncryptedFileKeyPairProvider
+		implements Iterable<KeyPair> {
 
 	private final KeyCache cache;
 
@@ -82,16 +84,26 @@ public CachingKeyPairProvider(List<Path> paths, KeyCache cache) {
 	}
 
 	@Override
-	protected Iterable<KeyPair> loadKeys(Collection<? extends Path> resources) {
+	public Iterator<KeyPair> iterator() {
+		Collection<? extends Path> resources = getPaths();
 		if (resources.isEmpty()) {
-			return Collections.emptyList();
+			return Collections.emptyListIterator();
 		}
-		return () -> new CancellingKeyPairIterator(resources);
+		return new CancellingKeyPairIterator(resources);
+	}
+
+	@Override
+	public Iterable<KeyPair> loadKeys() {
+		return this;
 	}
 
 	@Override
 	protected KeyPair doLoadKey(Path resource)
 			throws IOException, GeneralSecurityException {
+		if (!Files.exists(resource)) {
+			log.warn(format(SshdText.get().identityFileNotFound, resource));
+			return null;
+		}
 		// By calling doLoadKey(String, Path, FilePasswordProvider) instead of
 		// super.doLoadKey(Path) we can bypass the key caching in
 		// AbstractResourceKeyPairProvider, over which we have no real control.
diff --git a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/EncryptedFileKeyPairProvider.java b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/EncryptedFileKeyPairProvider.java
index ff81989..ef8e611 100644
--- a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/EncryptedFileKeyPairProvider.java
+++ b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/EncryptedFileKeyPairProvider.java
@@ -70,7 +70,7 @@
  * encrypted private key if the {@link FilePasswordProvider} is a
  * {@link RepeatingFilePasswordProvider}.
  */
-public class EncryptedFileKeyPairProvider extends FileKeyPairProvider {
+public abstract class EncryptedFileKeyPairProvider extends FileKeyPairProvider {
 
 	// TODO: remove this class once we're based on sshd > 2.1.0. See upstream
 	// issue SSHD-850 https://issues.apache.org/jira/browse/SSHD-850 and commit
diff --git a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitHostConfigEntry.java b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitHostConfigEntry.java
index a0705f2..7b22b88 100644
--- a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitHostConfigEntry.java
+++ b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitHostConfigEntry.java
@@ -54,7 +54,6 @@
  * lists of strings. The super class treats them as single strings containing
  * comma-separated lists.
  *
- * @since 5.2
  */
 public class JGitHostConfigEntry extends HostConfigEntry {
 
diff --git a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitSshClient.java b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitSshClient.java
index 212b67f..b9ff5e5 100644
--- a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitSshClient.java
+++ b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitSshClient.java
@@ -70,7 +70,7 @@
 import org.apache.sshd.common.future.SshFutureListener;
 import org.apache.sshd.common.io.IoConnectFuture;
 import org.apache.sshd.common.io.IoSession;
-import org.apache.sshd.common.keyprovider.FileKeyPairProvider;
+import org.apache.sshd.common.keyprovider.AbstractResourceKeyPairProvider;
 import org.apache.sshd.common.keyprovider.KeyPairProvider;
 import org.apache.sshd.common.session.helpers.AbstractSession;
 import org.apache.sshd.common.util.ValidateUtils;
@@ -243,12 +243,11 @@ private JGitClientSession createSession(IoSession ioSession,
 		int numberOfPasswordPrompts = getNumberOfPasswordPrompts(hostConfig);
 		session.getProperties().put(PASSWORD_PROMPTS,
 				Integer.valueOf(numberOfPasswordPrompts));
-		FilePasswordProvider provider = getFilePasswordProvider();
-		if (provider instanceof RepeatingFilePasswordProvider) {
-			((RepeatingFilePasswordProvider) provider)
+		FilePasswordProvider passwordProvider = getFilePasswordProvider();
+		if (passwordProvider instanceof RepeatingFilePasswordProvider) {
+			((RepeatingFilePasswordProvider) passwordProvider)
 					.setAttempts(numberOfPasswordPrompts);
 		}
-		FileKeyPairProvider ourConfiguredKeysProvider = null;
 		List<Path> identities = hostConfig.getIdentities().stream()
 				.map(s -> {
 					try {
@@ -260,16 +259,16 @@ private JGitClientSession createSession(IoSession ioSession,
 					}
 				}).filter(p -> p != null && Files.exists(p))
 				.collect(Collectors.toList());
-		ourConfiguredKeysProvider = new CachingKeyPairProvider(identities,
-				keyCache);
-		ourConfiguredKeysProvider.setPasswordFinder(getFilePasswordProvider());
+		CachingKeyPairProvider ourConfiguredKeysProvider = new CachingKeyPairProvider(
+				identities, keyCache);
+		ourConfiguredKeysProvider.setPasswordFinder(passwordProvider);
 		if (hostConfig.isIdentitiesOnly()) {
 			session.setKeyPairProvider(ourConfiguredKeysProvider);
 		} else {
 			KeyPairProvider defaultKeysProvider = getKeyPairProvider();
-			if (defaultKeysProvider instanceof FileKeyPairProvider) {
-				((FileKeyPairProvider) defaultKeysProvider)
-						.setPasswordFinder(getFilePasswordProvider());
+			if (defaultKeysProvider instanceof AbstractResourceKeyPairProvider<?>) {
+				((AbstractResourceKeyPairProvider<?>) defaultKeysProvider)
+						.setPasswordFinder(passwordProvider);
 			}
 			KeyPairProvider combinedProvider = new CombinedKeyPairProvider(
 					ourConfiguredKeysProvider, defaultKeysProvider);
diff --git a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitSshConfig.java b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitSshConfig.java
index 9eced0f..9846439 100644
--- a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitSshConfig.java
+++ b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitSshConfig.java
@@ -78,7 +78,6 @@
  * Therefore, this re-uses the parsing and caching from
  * {@link OpenSshConfigFile}.
  *
- * @since 5.2
  */
 public class JGitSshConfig implements HostConfigEntryResolver {
 
diff --git a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/KnownHostEntryReader.java b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/KnownHostEntryReader.java
index 4db24a1..659ffae 100644
--- a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/KnownHostEntryReader.java
+++ b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/KnownHostEntryReader.java
@@ -42,13 +42,13 @@
  */
 package org.eclipse.jgit.internal.transport.sshd;
 
+import static java.nio.charset.StandardCharsets.UTF_8;
 import static java.text.MessageFormat.format;
 import static org.apache.sshd.client.config.hosts.HostPatternsHolder.NON_STANDARD_PORT_PATTERN_ENCLOSURE_END_DELIM;
 import static org.apache.sshd.client.config.hosts.HostPatternsHolder.NON_STANDARD_PORT_PATTERN_ENCLOSURE_START_DELIM;
 
 import java.io.BufferedReader;
 import java.io.IOException;
-import java.nio.charset.StandardCharsets;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.util.Arrays;
@@ -99,8 +99,7 @@ private KnownHostEntryReader() {
 	public static List<KnownHostEntry> readFromFile(Path path)
 			throws IOException {
 		List<KnownHostEntry> result = new LinkedList<>();
-		try (BufferedReader r = Files.newBufferedReader(path,
-				StandardCharsets.UTF_8)) {
+		try (BufferedReader r = Files.newBufferedReader(path, UTF_8)) {
 			r.lines().forEachOrdered(l -> {
 				if (l == null) {
 					return;
diff --git a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/OpenSshServerKeyVerifier.java b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/OpenSshServerKeyVerifier.java
index 540b586..7d8f3fd 100644
--- a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/OpenSshServerKeyVerifier.java
+++ b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/OpenSshServerKeyVerifier.java
@@ -42,6 +42,7 @@
  */
 package org.eclipse.jgit.internal.transport.sshd;
 
+import static java.nio.charset.StandardCharsets.UTF_8;
 import static java.text.MessageFormat.format;
 
 import java.io.BufferedReader;
@@ -52,7 +53,6 @@
 import java.io.OutputStreamWriter;
 import java.net.InetSocketAddress;
 import java.net.SocketAddress;
-import java.nio.charset.StandardCharsets;
 import java.nio.file.Files;
 import java.nio.file.InvalidPathException;
 import java.nio.file.Path;
@@ -134,7 +134,7 @@
  * <p>
  * Note that adding a key to the known hosts file may create the file. You can
  * specify in the constructor whether the user shall be asked about that, too.
- * If the the user declines updating the file, but the key was otherwise
+ * If the user declines updating the file, but the key was otherwise
  * accepted (user confirmed for "<b>ask</b>", or "no" or "accept-new" are
  * active), the key is accepted for this session only.
  * </p>
@@ -386,7 +386,7 @@ private void updateKnownHostsFile(ClientSession clientSession,
 			try {
 				try (BufferedWriter writer = new BufferedWriter(
 						new OutputStreamWriter(lock.getOutputStream(),
-								StandardCharsets.UTF_8))) {
+								UTF_8))) {
 					writer.newLine();
 					writer.write(entry.getConfigLine());
 					writer.newLine();
@@ -422,10 +422,9 @@ private void updateModifiedServerKey(ClientSession clientSession,
 		if (lock.lock()) {
 			try {
 				try (BufferedWriter writer = new BufferedWriter(
-						new OutputStreamWriter(lock.getOutputStream(),
-								StandardCharsets.UTF_8));
+						new OutputStreamWriter(lock.getOutputStream(), UTF_8));
 						BufferedReader reader = Files.newBufferedReader(path,
-								StandardCharsets.UTF_8)) {
+								UTF_8)) {
 					boolean done = false;
 					String line;
 					while ((line = reader.readLine()) != null) {
diff --git a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/RepeatingFilePasswordProvider.java b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/RepeatingFilePasswordProvider.java
index 5d58bd6..e491cae 100644
--- a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/RepeatingFilePasswordProvider.java
+++ b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/RepeatingFilePasswordProvider.java
@@ -51,7 +51,6 @@
  * A {@link FilePasswordProvider} augmented to support repeatedly asking for
  * passwords.
  *
- * @since 5.2
  */
 public interface RepeatingFilePasswordProvider extends FilePasswordProvider {
 
diff --git a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/SshdText.java b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/SshdText.java
index 5c79f2d..bf432be 100644
--- a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/SshdText.java
+++ b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/SshdText.java
@@ -33,6 +33,7 @@ public static SshdText get() {
 	/***/ public String identityFileCannotDecrypt;
 	/***/ public String identityFileNoKey;
 	/***/ public String identityFileMultipleKeys;
+	/***/ public String identityFileNotFound;
 	/***/ public String identityFileUnsupportedFormat;
 	/***/ public String kexServerKeyInvalid;
 	/***/ public String keyEncryptedMsg;
diff --git a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/auth/BasicAuthentication.java b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/auth/BasicAuthentication.java
index efb1f55..a257a5e 100644
--- a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/auth/BasicAuthentication.java
+++ b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/auth/BasicAuthentication.java
@@ -42,13 +42,14 @@
  */
 package org.eclipse.jgit.internal.transport.sshd.auth;
 
+import static java.nio.charset.StandardCharsets.UTF_8;
+
 import java.net.Authenticator;
 import java.net.Authenticator.RequestorType;
 import java.net.InetSocketAddress;
 import java.net.PasswordAuthentication;
 import java.nio.ByteBuffer;
 import java.nio.CharBuffer;
-import java.nio.charset.StandardCharsets;
 import java.security.AccessController;
 import java.security.PrivilegedAction;
 import java.util.Arrays;
@@ -99,7 +100,7 @@ public BasicAuthentication(InetSocketAddress proxy, String initialUser,
 		if (pass == null) {
 			return new byte[0];
 		}
-		ByteBuffer bytes = StandardCharsets.UTF_8.encode(CharBuffer.wrap(pass));
+		ByteBuffer bytes = UTF_8.encode(CharBuffer.wrap(pass));
 		byte[] pwd = new byte[bytes.remaining()];
 		bytes.get(pwd);
 		if (bytes.hasArray()) {
diff --git a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/proxy/HttpClientConnector.java b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/proxy/HttpClientConnector.java
index 46cdd52..c66ee38 100644
--- a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/proxy/HttpClientConnector.java
+++ b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/proxy/HttpClientConnector.java
@@ -42,12 +42,13 @@
  */
 package org.eclipse.jgit.internal.transport.sshd.proxy;
 
+import static java.nio.charset.StandardCharsets.US_ASCII;
+import static java.nio.charset.StandardCharsets.UTF_8;
 import static java.text.MessageFormat.format;
 
 import java.io.IOException;
 import java.net.HttpURLConnection;
 import java.net.InetSocketAddress;
-import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Iterator;
@@ -164,7 +165,7 @@ public void sendClientProxyMetadata(ClientSession sshSession)
 	}
 
 	private void send(StringBuilder msg, IoSession session) throws Exception {
-		byte[] data = eol(msg).toString().getBytes(StandardCharsets.US_ASCII);
+		byte[] data = eol(msg).toString().getBytes(US_ASCII);
 		Buffer buffer = new ByteArrayBuffer(data.length, false);
 		buffer.putRawBytes(data);
 		session.writePacket(buffer).verify(getTimeout());
@@ -196,7 +197,7 @@ public void messageReceived(IoSession session, Readable buffer)
 			int length = buffer.available();
 			byte[] data = new byte[length];
 			buffer.getRawBytes(data, 0, length);
-			String[] reply = new String(data, StandardCharsets.US_ASCII)
+			String[] reply = new String(data, US_ASCII)
 					.split("\r\n"); //$NON-NLS-1$
 			handleMessage(session, Arrays.asList(reply));
 		} catch (Exception e) {
@@ -348,7 +349,7 @@ public String getToken() throws Exception {
 				throw new IOException(format(
 						SshdText.get().proxyHttpInvalidUserName, proxy, user));
 			}
-			byte[] rawUser = user.getBytes(StandardCharsets.UTF_8);
+			byte[] rawUser = user.getBytes(UTF_8);
 			byte[] toEncode = new byte[rawUser.length + 1 + password.length];
 			System.arraycopy(rawUser, 0, toEncode, 0, rawUser.length);
 			toEncode[rawUser.length] = ':';
diff --git a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/proxy/Socks5ClientConnector.java b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/proxy/Socks5ClientConnector.java
index 1844fdc..27d6f41 100644
--- a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/proxy/Socks5ClientConnector.java
+++ b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/proxy/Socks5ClientConnector.java
@@ -42,12 +42,13 @@
  */
 package org.eclipse.jgit.internal.transport.sshd.proxy;
 
+import static java.nio.charset.StandardCharsets.US_ASCII;
+import static java.nio.charset.StandardCharsets.UTF_8;
 import static java.text.MessageFormat.format;
 
 import java.io.IOException;
 import java.net.InetAddress;
 import java.net.InetSocketAddress;
-import java.nio.charset.StandardCharsets;
 
 import org.apache.sshd.client.session.ClientSession;
 import org.apache.sshd.common.io.IoSession;
@@ -295,8 +296,7 @@ private void sendConnectInfo(IoSession session) throws Exception {
 		byte type;
 		int length = 0;
 		if (rawAddress == null) {
-			remoteName = remoteAddress.getHostString()
-					.getBytes(StandardCharsets.US_ASCII);
+			remoteName = remoteAddress.getHostString().getBytes(US_ASCII);
 			if (remoteName == null || remoteName.length == 0) {
 				throw new IOException(
 						format(SshdText.get().proxySocksNoRemoteHostName,
@@ -542,7 +542,7 @@ public Buffer getToken() throws IOException {
 				return null;
 			}
 			try {
-				byte[] rawUser = user.getBytes(StandardCharsets.UTF_8);
+				byte[] rawUser = user.getBytes(UTF_8);
 				if (rawUser.length > 255) {
 					throw new IOException(format(
 							SshdText.get().proxySocksUsernameTooLong, proxy,
diff --git a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/transport/sshd/SshdSessionFactory.java b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/transport/sshd/SshdSessionFactory.java
index 4ec6f22..cdd47bf 100644
--- a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/transport/sshd/SshdSessionFactory.java
+++ b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/transport/sshd/SshdSessionFactory.java
@@ -47,6 +47,7 @@
 import java.io.IOException;
 import java.nio.file.Files;
 import java.nio.file.Path;
+import java.security.KeyPair;
 import java.time.Duration;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -68,7 +69,6 @@
 import org.apache.sshd.common.NamedFactory;
 import org.apache.sshd.common.compression.BuiltinCompressions;
 import org.apache.sshd.common.config.keys.FilePasswordProvider;
-import org.apache.sshd.common.keyprovider.FileKeyPairProvider;
 import org.apache.sshd.common.keyprovider.KeyPairProvider;
 import org.eclipse.jgit.annotations.NonNull;
 import org.eclipse.jgit.errors.TransportException;
@@ -89,7 +89,9 @@
 import org.eclipse.jgit.util.FS;
 
 /**
- * A {@link SshSessionFactory} that uses Apache MINA sshd.
+ * A {@link SshSessionFactory} that uses Apache MINA sshd. Classes from Apache
+ * MINA sshd are kept private to avoid API evolution problems when Apache MINA
+ * sshd interfaces change.
  *
  * @since 5.2
  */
@@ -103,7 +105,7 @@ public class SshdSessionFactory extends SshSessionFactory implements Closeable {
 
 	private final Map<Tuple, ServerKeyVerifier> defaultServerKeyVerifier = new ConcurrentHashMap<>();
 
-	private final Map<Tuple, FileKeyPairProvider> defaultKeys = new ConcurrentHashMap<>();
+	private final Map<Tuple, Iterable<KeyPair>> defaultKeys = new ConcurrentHashMap<>();
 
 	private final KeyCache keyCache;
 
@@ -161,7 +163,7 @@ public SshdSessionFactory(KeyCache keyCache, ProxyDataFactory proxies) {
 	private static final class Tuple {
 		private Object[] objects;
 
-		public Tuple(Object... objects) {
+		public Tuple(Object[] objects) {
 			this.objects = objects;
 		}
 
@@ -209,8 +211,8 @@ public SshdSession getSession(URIish uri,
 				}
 				HostConfigEntryResolver configFile = getHostConfigEntryResolver(
 						home, sshDir);
-				KeyPairProvider defaultKeysProvider = getDefaultKeysProvider(
-						sshDir);
+				KeyPairProvider defaultKeysProvider = toKeyPairProvider(
+						getDefaultKeys(sshDir));
 				KeyPasswordProvider passphrases = createKeyPasswordProvider(
 						credentialsProvider);
 				SshClient client = ClientBuilder.builder()
@@ -351,7 +353,7 @@ public File getSshDirectory() {
 	private HostConfigEntryResolver getHostConfigEntryResolver(
 			@NonNull File homeDir, @NonNull File sshDir) {
 		return defaultHostConfigEntryResolver.computeIfAbsent(
-				new Tuple(homeDir, sshDir),
+				new Tuple(new Object[] { homeDir, sshDir }),
 				t -> new JGitSshConfig(homeDir,
 						new File(sshDir, SshConstants.CONFIG),
 						getLocalUserName()));
@@ -375,7 +377,7 @@ private HostConfigEntryResolver getHostConfigEntryResolver(
 	private ServerKeyVerifier getServerKeyVerifier(@NonNull File homeDir,
 			@NonNull File sshDir) {
 		return defaultServerKeyVerifier.computeIfAbsent(
-				new Tuple(homeDir, sshDir),
+				new Tuple(new Object[] { homeDir, sshDir }),
 				t -> new OpenSshServerKeyVerifier(true,
 						getDefaultKnownHostsFiles(sshDir)));
 	}
@@ -395,20 +397,61 @@ protected List<Path> getDefaultKnownHostsFiles(@NonNull File sshDir) {
 	}
 
 	/**
-	 * Determines a {@link KeyPairProvider} to use to load the default keys.
+	 * Determines the default keys. The default implementation will lazy load
+	 * the {@link #getDefaultIdentities(File) default identity files}.
+	 * <p>
+	 * Subclasses may override and return an {@link Iterable} of whatever keys
+	 * are appropriate. If the returned iterable lazily loads keys, it should be
+	 * an instance of
+	 * {@link org.apache.sshd.common.keyprovider.AbstractResourceKeyPairProvider
+	 * AbstractResourceKeyPairProvider} so that the session can later pass it
+	 * the {@link #createKeyPasswordProvider(CredentialsProvider) password
+	 * provider} wrapped as a {@link FilePasswordProvider} via
+	 * {@link org.apache.sshd.common.keyprovider.AbstractResourceKeyPairProvider#setPasswordFinder(FilePasswordProvider)
+	 * AbstractResourceKeyPairProvider#setPasswordFinder(FilePasswordProvider)}
+	 * so that encrypted, password-protected keys can be loaded.
+	 * </p>
+	 * <p>
+	 * The default implementation uses exactly this mechanism; class
+	 * {@link CachingKeyPairProvider} may serve as a model for a customized
+	 * lazy-loading {@link Iterable} implementation
+	 * </p>
+	 * <p>
+	 * If the {@link Iterable} returned has the keys already pre-loaded or
+	 * otherwise doesn't need to decrypt encrypted keys, it can be any
+	 * {@link Iterable}, for instance a simple {@link java.util.List List}.
+	 * </p>
 	 *
 	 * @param sshDir
 	 *            to look in for keys
-	 * @return the {@link KeyPairProvider}
+	 * @return an {@link Iterable} over the default keys
+	 * @since 5.3
 	 */
 	@NonNull
-	private KeyPairProvider getDefaultKeysProvider(@NonNull File sshDir) {
-		return defaultKeys.computeIfAbsent(new Tuple(sshDir),
-				t -> new CachingKeyPairProvider(getDefaultIdentities(sshDir),
+	protected Iterable<KeyPair> getDefaultKeys(@NonNull File sshDir) {
+		List<Path> defaultIdentities = getDefaultIdentities(sshDir);
+		return defaultKeys.computeIfAbsent(
+				new Tuple(defaultIdentities.toArray(new Path[0])),
+				t -> new CachingKeyPairProvider(defaultIdentities,
 						getKeyCache()));
 	}
 
 	/**
+	 * Converts an {@link Iterable} of {link KeyPair}s into a
+	 * {@link KeyPairProvider}.
+	 *
+	 * @param keys
+	 *            to provide via the returned {@link KeyPairProvider}
+	 * @return a {@link KeyPairProvider} that provides the given {@code keys}
+	 */
+	private KeyPairProvider toKeyPairProvider(Iterable<KeyPair> keys) {
+		if (keys instanceof KeyPairProvider) {
+			return (KeyPairProvider) keys;
+		}
+		return () -> keys;
+	}
+
+	/**
 	 * Gets a list of default identities, i.e., private key files that shall
 	 * always be tried for public key authentication. Typically those are
 	 * ~/.ssh/id_dsa, ~/.ssh/id_rsa, and so on. The default implementation
diff --git a/org.eclipse.jgit.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.test/META-INF/MANIFEST.MF
index 8bd041c..8faf131 100644
--- a/org.eclipse.jgit.test/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.test/META-INF/MANIFEST.MF
@@ -3,7 +3,7 @@
 Bundle-Name: %plugin_name
 Automatic-Module-Name: org.eclipse.jgit.test
 Bundle-SymbolicName: org.eclipse.jgit.test
-Bundle-Version: 5.2.3.qualifier
+Bundle-Version: 5.3.7.qualifier
 Bundle-Localization: plugin
 Bundle-Vendor: %provider_name
 Bundle-ActivationPolicy: lazy
@@ -17,56 +17,57 @@
  org.apache.commons.compress.compressors.bzip2;version="[1.15.0,2.0)",
  org.apache.commons.compress.compressors.gzip;version="[1.15.0,2.0)",
  org.apache.commons.compress.compressors.xz;version="[1.15.0,2.0)",
- org.eclipse.jgit.annotations;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.api;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.api.errors;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.archive;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.attributes;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.awtui;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.blame;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.diff;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.dircache;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.errors;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.events;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.fnmatch;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.gitrepo;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.hooks;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.ignore;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.ignore.internal;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.internal;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.internal.fsck;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.internal.storage.dfs;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.internal.storage.file;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.internal.storage.io;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.internal.storage.pack;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.internal.storage.reftable;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.internal.storage.reftree;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.internal.transport.parser;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.junit;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.junit.ssh;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.junit.time;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.lfs;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.lib;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.merge;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.nls;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.notes;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.patch;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.pgm;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.pgm.internal;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.revplot;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.revwalk;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.revwalk.filter;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.storage.file;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.storage.pack;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.submodule;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.transport;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.transport.http;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.transport.resolver;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.treewalk;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.treewalk.filter;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.util;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.util.io;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.util.sha1;version="[5.2.3,5.3.0)",
+ org.bouncycastle.util.encoders;version="[1.60.0,2.0.0)",
+ org.eclipse.jgit.annotations;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.api;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.api.errors;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.archive;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.attributes;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.awtui;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.blame;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.diff;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.dircache;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.errors;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.events;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.fnmatch;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.gitrepo;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.hooks;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.ignore;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.ignore.internal;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.internal;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.internal.fsck;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.internal.storage.dfs;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.internal.storage.file;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.internal.storage.io;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.internal.storage.pack;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.internal.storage.reftable;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.internal.storage.reftree;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.internal.transport.parser;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.junit;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.junit.ssh;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.junit.time;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.lfs;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.lib;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.merge;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.nls;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.notes;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.patch;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.pgm;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.pgm.internal;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.revplot;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.revwalk;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.revwalk.filter;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.storage.file;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.storage.pack;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.submodule;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.transport;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.transport.http;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.transport.resolver;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.treewalk;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.treewalk.filter;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.util;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.util.io;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.util.sha1;version="[5.3.7,5.4.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)",
@@ -81,4 +82,4 @@
  org.tukaani.xz;version="[1.6.0,2.0)"
 Require-Bundle: org.hamcrest.core;bundle-version="[1.1.0,2.0.0)",
  org.hamcrest.library;bundle-version="[1.1.0,2.0.0)"
-Export-Package: org.eclipse.jgit.transport.ssh;version="5.2.3";x-friends:="org.eclipse.jgit.ssh.apache.test"
+Export-Package: org.eclipse.jgit.transport.ssh;version="5.3.7";x-friends:="org.eclipse.jgit.ssh.apache.test"
diff --git a/org.eclipse.jgit.test/pom.xml b/org.eclipse.jgit.test/pom.xml
index e6a99b2..d88d5e3 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>5.2.3-SNAPSHOT</version>
+    <version>5.3.7-SNAPSHOT</version>
   </parent>
 
   <artifactId>org.eclipse.jgit.test</artifactId>
@@ -76,11 +76,22 @@
     <dependency>
       <groupId>org.bouncycastle</groupId>
       <artifactId>bcprov-jdk15on</artifactId>
-      <version>1.59</version>
       <scope>test</scope>
      </dependency>
 
     <dependency>
+      <groupId>org.bouncycastle</groupId>
+      <artifactId>bcpg-jdk15on</artifactId>
+      <scope>test</scope>
+    </dependency>
+
+    <dependency>
+      <groupId>org.bouncycastle</groupId>
+      <artifactId>bcpkix-jdk15on</artifactId>
+      <scope>test</scope>
+    </dependency>
+
+    <dependency>
       <groupId>org.hamcrest</groupId>
       <artifactId>hamcrest-library</artifactId>
       <scope>test</scope>
@@ -141,7 +152,7 @@
             <artifactId>maven-surefire-plugin</artifactId>
             <version>${maven-surefire-plugin-version}</version>
             <configuration>
-              <argLine>-Djgit.test.long=true</argLine>
+              <argLine>@{argLine} -Djgit.test.long=true</argLine>
             </configuration>
           </plugin>
         </plugins>
@@ -186,7 +197,7 @@
       <plugin>
         <artifactId>maven-surefire-plugin</artifactId>
         <configuration>
-          <argLine>-Xmx1024m -Dfile.encoding=UTF-8 -Djava.io.tmpdir=${project.build.directory}</argLine>
+          <argLine>@{argLine} -Xmx1024m -Dfile.encoding=UTF-8 -Djava.io.tmpdir=${project.build.directory}</argLine>
           <includes>
             <include>**/*Test.java</include>
             <include>**/*Tests.java</include>
diff --git a/org.eclipse.jgit.test/src/org/eclipse/jgit/transport/ssh/SshTestBase.java b/org.eclipse.jgit.test/src/org/eclipse/jgit/transport/ssh/SshTestBase.java
index dde55b6..2f367ba 100644
--- a/org.eclipse.jgit.test/src/org/eclipse/jgit/transport/ssh/SshTestBase.java
+++ b/org.eclipse.jgit.test/src/org/eclipse/jgit/transport/ssh/SshTestBase.java
@@ -42,6 +42,7 @@
  */
 package org.eclipse.jgit.transport.ssh;
 
+import static java.nio.charset.StandardCharsets.UTF_8;
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
@@ -51,7 +52,6 @@
 
 import java.io.File;
 import java.io.IOException;
-import java.nio.charset.StandardCharsets;
 import java.nio.file.Files;
 import java.util.List;
 import java.util.Locale;
@@ -409,8 +409,7 @@ public void testSshModifiedHostKeyWithProviderDeny() throws Exception {
 
 	private void checkKnownHostsModifiedHostKey(File backup, File newFile,
 			String wrongKey) throws IOException {
-		List<String> oldLines = Files.readAllLines(backup.toPath(),
-				StandardCharsets.UTF_8);
+		List<String> oldLines = Files.readAllLines(backup.toPath(), UTF_8);
 		// Find the original entry. We should have that again in known_hosts.
 		String oldKeyPart = null;
 		for (String oldLine : oldLines) {
@@ -424,8 +423,7 @@ private void checkKnownHostsModifiedHostKey(File backup, File newFile,
 			}
 		}
 		assertNotNull("Old key not found", oldKeyPart);
-		List<String> newLines = Files.readAllLines(newFile.toPath(),
-				StandardCharsets.UTF_8);
+		List<String> newLines = Files.readAllLines(newFile.toPath(), UTF_8);
 		assertFalse("Old host key still found in known_hosts file" + newFile,
 				hasHostKey("localhost", testPort, wrongKey, newLines));
 		assertTrue("New host key not found in known_hosts file" + newFile,
@@ -448,10 +446,10 @@ public void testSshModifiedHostKeyAllow() throws Exception {
 				"IdentityFile " + privateKey1.getAbsolutePath());
 		// File should not have been updated!
 		String[] oldLines = Files
-				.readAllLines(backup.toPath(), StandardCharsets.UTF_8)
+				.readAllLines(backup.toPath(), UTF_8)
 				.toArray(new String[0]);
 		String[] newLines = Files
-				.readAllLines(knownHosts.toPath(), StandardCharsets.UTF_8)
+				.readAllLines(knownHosts.toPath(), UTF_8)
 				.toArray(new String[0]);
 		assertArrayEquals("Known hosts file should not be modified", oldLines,
 				newLines);
diff --git a/org.eclipse.jgit.test/src/org/eclipse/jgit/transport/ssh/SshTestHarness.java b/org.eclipse.jgit.test/src/org/eclipse/jgit/transport/ssh/SshTestHarness.java
index 59925a5..ada16b7 100644
--- a/org.eclipse.jgit.test/src/org/eclipse/jgit/transport/ssh/SshTestHarness.java
+++ b/org.eclipse.jgit.test/src/org/eclipse/jgit/transport/ssh/SshTestHarness.java
@@ -42,6 +42,8 @@
  */
 package org.eclipse.jgit.transport.ssh;
 
+import static java.nio.charset.StandardCharsets.US_ASCII;
+import static java.nio.charset.StandardCharsets.UTF_8;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotEquals;
@@ -54,7 +56,6 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
-import java.nio.charset.StandardCharsets;
 import java.nio.file.Files;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -150,7 +151,7 @@ public void setUp() throws Exception {
 		knownHosts = new File(sshDir, "known_hosts");
 		Files.write(knownHosts.toPath(), Collections.singleton("[localhost]:"
 				+ testPort + ' '
-				+ publicHostKey.toString(StandardCharsets.US_ASCII.name())));
+				+ publicHostKey.toString(US_ASCII.name())));
 		factory = createSessionFactory();
 		SshSessionFactory.setInstance(factory);
 	}
@@ -200,8 +201,7 @@ private static File createKeyPair(File privateKeyFile) throws Exception {
 	 */
 	protected static String createKnownHostsFile(File file, String host,
 			int port, File publicKey) throws IOException {
-		List<String> lines = Files.readAllLines(publicKey.toPath(),
-				StandardCharsets.UTF_8);
+		List<String> lines = Files.readAllLines(publicKey.toPath(), UTF_8);
 		assertEquals("Public key has too many lines", 1, lines.size());
 		String pubKey = lines.get(0);
 		// Strip off the comment.
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/AddCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/AddCommandTest.java
index 687926b..b28e26a 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/AddCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/AddCommandTest.java
@@ -501,11 +501,11 @@ public void testAddExistingSingleSmallFileWithNewLine() throws IOException,
 					indexState(CONTENT));
 			db.getConfig().setString("core", null, "autocrlf", "true");
 			git.add().addFilepattern("a.txt").call();
-			assertEquals("[a.txt, mode:100644, content:row1\nrow2]",
+			assertEquals("[a.txt, mode:100644, content:row1\r\nrow2]",
 					indexState(CONTENT));
 			db.getConfig().setString("core", null, "autocrlf", "input");
 			git.add().addFilepattern("a.txt").call();
-			assertEquals("[a.txt, mode:100644, content:row1\nrow2]",
+			assertEquals("[a.txt, mode:100644, content:row1\r\nrow2]",
 					indexState(CONTENT));
 		}
 	}
@@ -523,19 +523,18 @@ public void testAddExistingSingleMediumSizeFileWithNewLine()
 		try (PrintWriter writer = new PrintWriter(file, UTF_8.name())) {
 			writer.print(crData);
 		}
-		String lfData = data.toString().replaceAll("\r", "");
 		try (Git git = new Git(db)) {
 			db.getConfig().setString("core", null, "autocrlf", "false");
 			git.add().addFilepattern("a.txt").call();
-			assertEquals("[a.txt, mode:100644, content:" + data + "]",
+			assertEquals("[a.txt, mode:100644, content:" + crData + "]",
 					indexState(CONTENT));
 			db.getConfig().setString("core", null, "autocrlf", "true");
 			git.add().addFilepattern("a.txt").call();
-			assertEquals("[a.txt, mode:100644, content:" + lfData + "]",
+			assertEquals("[a.txt, mode:100644, content:" + crData + "]",
 					indexState(CONTENT));
 			db.getConfig().setString("core", null, "autocrlf", "input");
 			git.add().addFilepattern("a.txt").call();
-			assertEquals("[a.txt, mode:100644, content:" + lfData + "]",
+			assertEquals("[a.txt, mode:100644, content:" + crData + "]",
 					indexState(CONTENT));
 		}
 	}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CheckoutCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CheckoutCommandTest.java
index 65c20aa..1f3527f 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CheckoutCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CheckoutCommandTest.java
@@ -67,6 +67,7 @@
 
 import org.eclipse.jgit.api.CheckoutResult.Status;
 import org.eclipse.jgit.api.CreateBranchCommand.SetupUpstreamMode;
+import org.eclipse.jgit.api.errors.CheckoutConflictException;
 import org.eclipse.jgit.api.errors.GitAPIException;
 import org.eclipse.jgit.api.errors.InvalidRefNameException;
 import org.eclipse.jgit.api.errors.InvalidRemoteException;
@@ -115,7 +116,7 @@ public void setUp() throws Exception {
 		git.add().addFilepattern("Test.txt").call();
 		initialCommit = git.commit().setMessage("Initial commit").call();
 
-		// create a master branch and switch to it
+		// create a test branch and switch to it
 		git.branchCreate().setName("test").call();
 		RefUpdate rup = db.updateRef(Constants.HEAD);
 		rup.link("refs/heads/test");
@@ -144,6 +145,19 @@ public void testCheckout() throws Exception {
 	}
 
 	@Test
+	public void testCheckoutForced() throws Exception {
+		writeTrashFile("Test.txt", "Garbage");
+		try {
+			git.checkout().setName("master").call().getObjectId();
+			fail("Expected CheckoutConflictException didn't occur");
+		} catch (CheckoutConflictException e) {
+			// Expected
+		}
+		assertEquals(initialCommit.getId(), git.checkout().setName("master")
+				.setForced(true).call().getObjectId());
+	}
+
+	@Test
 	public void testCreateBranchOnCheckout() throws Exception {
 		git.checkout().setCreateBranch(true).setName("test2").call();
 		assertNotNull(db.exactRef("refs/heads/test2"));
@@ -171,7 +185,7 @@ public void testCheckoutWithConflict() throws Exception {
 			assertEquals(Status.CONFLICTS, co.getResult().getStatus());
 			assertTrue(co.getResult().getConflictList().contains("Test.txt"));
 		}
-		git.checkout().setName("master").setForce(true).call();
+		git.checkout().setName("master").setForced(true).call();
 		assertThat(read("Test.txt"), is("Hello world"));
 	}
 
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CloneCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CloneCommandTest.java
index f5f6529..383436c 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CloneCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CloneCommandTest.java
@@ -424,6 +424,32 @@ public void testBareCloneRepositoryOnlyOneBranch() throws Exception {
 				specs.get(0));
 	}
 
+	@Test
+	public void testCloneRepositoryOnlyOneTag() throws Exception {
+		File directory = createTempDirectory("testCloneRepositoryWithBranch");
+		CloneCommand command = Git.cloneRepository();
+		command.setBranch("tag-initial");
+		command.setBranchesToClone(
+				Collections.singletonList("refs/tags/tag-initial"));
+		command.setDirectory(directory);
+		command.setURI(fileUri());
+		Git git2 = command.call();
+		addRepoToClose(git2.getRepository());
+		assertNotNull(git2);
+		assertNull(git2.getRepository().resolve("tag-for-blob"));
+		assertNull(git2.getRepository().resolve("refs/heads/master"));
+		assertNotNull(git2.getRepository().resolve("tag-initial"));
+		ObjectId taggedCommit = db.resolve("tag-initial^{commit}");
+		assertEquals(taggedCommit.name(), git2.getRepository().getFullBranch());
+		RemoteConfig cfg = new RemoteConfig(git2.getRepository().getConfig(),
+				Constants.DEFAULT_REMOTE_NAME);
+		List<RefSpec> specs = cfg.getFetchRefSpecs();
+		assertEquals(1, specs.size());
+		assertEquals(
+				new RefSpec("+refs/tags/tag-initial:refs/tags/tag-initial"),
+				specs.get(0));
+	}
+
 	public static String allRefNames(List<Ref> refs) {
 		StringBuilder sb = new StringBuilder();
 		for (Ref f : refs) {
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 a6072a0..e4b7ed7 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
@@ -46,6 +46,7 @@
 import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
@@ -53,7 +54,10 @@
 import java.util.Date;
 import java.util.List;
 import java.util.TimeZone;
+import java.util.concurrent.atomic.AtomicInteger;
 
+import org.eclipse.jgit.api.CherryPickResult.CherryPickStatus;
+import org.eclipse.jgit.api.errors.CanceledException;
 import org.eclipse.jgit.api.errors.EmptyCommitException;
 import org.eclipse.jgit.api.errors.WrongRepositoryStateException;
 import org.eclipse.jgit.diff.DiffEntry;
@@ -62,9 +66,11 @@
 import org.eclipse.jgit.dircache.DirCacheEntry;
 import org.eclipse.jgit.junit.RepositoryTestCase;
 import org.eclipse.jgit.junit.time.TimeUtil;
+import org.eclipse.jgit.lib.CommitBuilder;
 import org.eclipse.jgit.lib.ConfigConstants;
 import org.eclipse.jgit.lib.Constants;
 import org.eclipse.jgit.lib.FileMode;
+import org.eclipse.jgit.lib.GpgSigner;
 import org.eclipse.jgit.lib.ObjectId;
 import org.eclipse.jgit.lib.PersonIdent;
 import org.eclipse.jgit.lib.RefUpdate;
@@ -73,7 +79,9 @@
 import org.eclipse.jgit.lib.Repository;
 import org.eclipse.jgit.lib.StoredConfig;
 import org.eclipse.jgit.revwalk.RevCommit;
+import org.eclipse.jgit.storage.file.FileBasedConfig;
 import org.eclipse.jgit.submodule.SubmoduleWalk;
+import org.eclipse.jgit.transport.CredentialsProvider;
 import org.eclipse.jgit.treewalk.TreeWalk;
 import org.eclipse.jgit.treewalk.filter.TreeFilter;
 import org.eclipse.jgit.util.FS;
@@ -616,9 +624,100 @@ public void commitOnlyShouldHandleIgnored() throws Exception {
 			writeTrashFile(".gitignore", "bar");
 			git.add().addFilepattern("subdir").call();
 			git.commit().setOnly("subdir").setMessage("first commit").call();
+			assertEquals("[subdir/foo, mode:100644, content:Hello World]",
+					indexState(CONTENT));
 		}
 	}
 
+	@Test
+	public void commitWithAutoCrlfAndNonNormalizedIndex() throws Exception {
+		try (Git git = new Git(db)) {
+			// Commit a file with CR/LF into the index
+			FileBasedConfig config = db.getConfig();
+			config.setString("core", null, "autocrlf", "false");
+			config.save();
+			writeTrashFile("file.txt", "line 1\r\nline 2\r\n");
+			git.add().addFilepattern("file.txt").call();
+			git.commit().setMessage("Initial").call();
+			assertEquals(
+					"[file.txt, mode:100644, content:line 1\r\nline 2\r\n]",
+					indexState(CONTENT));
+			config.setString("core", null, "autocrlf", "true");
+			config.save();
+			writeTrashFile("file.txt", "line 1\r\nline 1.5\r\nline 2\r\n");
+			writeTrashFile("file2.txt", "new\r\nfile\r\n");
+			git.add().addFilepattern("file.txt").addFilepattern("file2.txt")
+					.call();
+			git.commit().setMessage("Second").call();
+			assertEquals(
+					"[file.txt, mode:100644, content:line 1\r\nline 1.5\r\nline 2\r\n]"
+							+ "[file2.txt, mode:100644, content:new\nfile\n]",
+					indexState(CONTENT));
+			writeTrashFile("file2.txt", "new\r\nfile\r\ncontent\r\n");
+			git.add().addFilepattern("file2.txt").call();
+			git.commit().setMessage("Third").call();
+			assertEquals(
+					"[file.txt, mode:100644, content:line 1\r\nline 1.5\r\nline 2\r\n]"
+							+ "[file2.txt, mode:100644, content:new\nfile\ncontent\n]",
+					indexState(CONTENT));
+		}
+	}
+
+	private void testConflictWithAutoCrlf(String baseLf, String lf)
+			throws Exception {
+		try (Git git = new Git(db)) {
+			// Commit a file with CR/LF into the index
+			FileBasedConfig config = db.getConfig();
+			config.setString("core", null, "autocrlf", "false");
+			config.save();
+			writeTrashFile("file.txt", "foo" + baseLf);
+			git.add().addFilepattern("file.txt").call();
+			git.commit().setMessage("Initial").call();
+			// Switch to side branch
+			git.checkout().setCreateBranch(true).setName("side").call();
+			writeTrashFile("file.txt", "bar\r\n");
+			git.add().addFilepattern("file.txt").call();
+			RevCommit side = git.commit().setMessage("Side").call();
+			// Switch back to master and commit a conflict with the given lf
+			git.checkout().setName("master");
+			writeTrashFile("file.txt", "foob" + lf);
+			git.add().addFilepattern("file.txt").call();
+			git.commit().setMessage("Second").call();
+			// Switch on autocrlf=true
+			config.setString("core", null, "autocrlf", "true");
+			config.save();
+			// Cherry pick side: conflict. Resolve with CR-LF and commit.
+			CherryPickResult pick = git.cherryPick().include(side).call();
+			assertEquals("Expected a cherry-pick conflict",
+					CherryPickStatus.CONFLICTING, pick.getStatus());
+			writeTrashFile("file.txt", "foobar\r\n");
+			git.add().addFilepattern("file.txt").call();
+			git.commit().setMessage("Second").call();
+			assertEquals("[file.txt, mode:100644, content:foobar" + lf + "]",
+					indexState(CONTENT));
+		}
+	}
+
+	@Test
+	public void commitConflictWithAutoCrlfBaseCrLfOursLf() throws Exception {
+		testConflictWithAutoCrlf("\r\n", "\n");
+	}
+
+	@Test
+	public void commitConflictWithAutoCrlfBaseLfOursLf() throws Exception {
+		testConflictWithAutoCrlf("\n", "\n");
+	}
+
+	@Test
+	public void commitConflictWithAutoCrlfBasCrLfOursCrLf() throws Exception {
+		testConflictWithAutoCrlf("\r\n", "\r\n");
+	}
+
+	@Test
+	public void commitConflictWithAutoCrlfBaseLfOursCrLf() throws Exception {
+		testConflictWithAutoCrlf("\n", "\r\n");
+	}
+
 	private static void addUnmergedEntry(String file, DirCacheBuilder builder) {
 		DirCacheEntry stage1 = new DirCacheEntry(file, DirCacheEntry.STAGE_1);
 		DirCacheEntry stage2 = new DirCacheEntry(file, DirCacheEntry.STAGE_2);
@@ -630,4 +729,126 @@ private static void addUnmergedEntry(String file, DirCacheBuilder builder) {
 		builder.add(stage2);
 		builder.add(stage3);
 	}
+
+	@Test
+	public void callSignerWithProperSigningKey() throws Exception {
+		try (Git git = new Git(db)) {
+			writeTrashFile("file1", "file1");
+			git.add().addFilepattern("file1").call();
+
+			String[] signingKey = new String[1];
+			PersonIdent[] signingCommitters = new PersonIdent[1];
+			AtomicInteger callCount = new AtomicInteger();
+			GpgSigner.setDefault(new GpgSigner() {
+				@Override
+				public void sign(CommitBuilder commit, String gpgSigningKey,
+						PersonIdent signingCommitter, CredentialsProvider credentialsProvider) {
+					signingKey[0] = gpgSigningKey;
+					signingCommitters[0] = signingCommitter;
+					callCount.incrementAndGet();
+				}
+
+				@Override
+				public boolean canLocateSigningKey(String gpgSigningKey,
+						PersonIdent signingCommitter,
+						CredentialsProvider credentialsProvider)
+						throws CanceledException {
+					return false;
+				}
+			});
+
+			// first call should use config, which is expected to be null at
+			// this time
+			git.commit().setCommitter(committer).setSign(Boolean.TRUE)
+					.setMessage("initial commit")
+					.call();
+			assertNull(signingKey[0]);
+			assertEquals(1, callCount.get());
+			assertSame(committer, signingCommitters[0]);
+
+			writeTrashFile("file2", "file2");
+			git.add().addFilepattern("file2").call();
+
+			// second commit applies config value
+			String expectedConfigSigningKey = "config-" + System.nanoTime();
+			StoredConfig config = git.getRepository().getConfig();
+			config.setString("user", null, "signingKey",
+					expectedConfigSigningKey);
+			config.save();
+
+			git.commit().setCommitter(committer).setSign(Boolean.TRUE)
+					.setMessage("initial commit")
+					.call();
+			assertEquals(expectedConfigSigningKey, signingKey[0]);
+			assertEquals(2, callCount.get());
+			assertSame(committer, signingCommitters[0]);
+
+			writeTrashFile("file3", "file3");
+			git.add().addFilepattern("file3").call();
+
+			// now use specific on api
+			String expectedSigningKey = "my-" + System.nanoTime();
+			git.commit().setCommitter(committer).setSign(Boolean.TRUE)
+					.setSigningKey(expectedSigningKey)
+					.setMessage("initial commit").call();
+			assertEquals(expectedSigningKey, signingKey[0]);
+			assertEquals(3, callCount.get());
+			assertSame(committer, signingCommitters[0]);
+		}
+	}
+
+	@Test
+	public void callSignerOnlyWhenSigning() throws Exception {
+		try (Git git = new Git(db)) {
+			writeTrashFile("file1", "file1");
+			git.add().addFilepattern("file1").call();
+
+			AtomicInteger callCount = new AtomicInteger();
+			GpgSigner.setDefault(new GpgSigner() {
+				@Override
+				public void sign(CommitBuilder commit, String gpgSigningKey,
+						PersonIdent signingCommitter, CredentialsProvider credentialsProvider) {
+					callCount.incrementAndGet();
+				}
+
+				@Override
+				public boolean canLocateSigningKey(String gpgSigningKey,
+						PersonIdent signingCommitter,
+						CredentialsProvider credentialsProvider)
+						throws CanceledException {
+					return false;
+				}
+			});
+
+			// first call should use config, which is expected to be null at
+			// this time
+			git.commit().setMessage("initial commit").call();
+			assertEquals(0, callCount.get());
+
+			writeTrashFile("file2", "file2");
+			git.add().addFilepattern("file2").call();
+
+			// now force signing
+			git.commit().setSign(Boolean.TRUE).setMessage("commit").call();
+			assertEquals(1, callCount.get());
+
+			writeTrashFile("file3", "file3");
+			git.add().addFilepattern("file3").call();
+
+			// now rely on config
+			StoredConfig config = git.getRepository().getConfig();
+			config.setBoolean("commit", null, "gpgSign", true);
+			config.save();
+
+			git.commit().setMessage("commit").call();
+			assertEquals(2, callCount.get());
+
+			writeTrashFile("file4", "file4");
+			git.add().addFilepattern("file4").call();
+
+			// now force "no-sign" (even though config is true)
+			git.commit().setSign(Boolean.FALSE).setMessage("commit").call();
+			assertEquals(2, callCount.get());
+		}
+	}
 }
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 9af003d..5a15838 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
@@ -1557,32 +1557,37 @@ public void testFastForwardOnlyNotPossible() throws Exception {
 
 	@Test
 	public void testRecursiveMergeWithConflict() throws Exception {
-		TestRepository<Repository> db_t = new TestRepository<>(db);
-		BranchBuilder master = db_t.branch("master");
-		RevCommit m0 = master.commit().add("f", "1\n2\n3\n4\n5\n6\n7\n8\n9\n")
-				.message("m0").create();
-		RevCommit m1 = master.commit()
-				.add("f", "1-master\n2\n3\n4\n5\n6\n7\n8\n9\n").message("m1")
-				.create();
-		db_t.getRevWalk().parseCommit(m1);
+		try (TestRepository<Repository> db_t = new TestRepository<>(db)) {
+			BranchBuilder master = db_t.branch("master");
+			RevCommit m0 = master.commit()
+					.add("f", "1\n2\n3\n4\n5\n6\n7\n8\n9\n").message("m0")
+					.create();
+			RevCommit m1 = master.commit()
+					.add("f", "1-master\n2\n3\n4\n5\n6\n7\n8\n9\n")
+					.message("m1").create();
+			db_t.getRevWalk().parseCommit(m1);
 
-		BranchBuilder side = db_t.branch("side");
-		RevCommit s1 = side.commit().parent(m0)
-				.add("f", "1\n2\n3\n4\n5\n6\n7\n8\n9-side\n").message("s1")
-				.create();
-		RevCommit s2 = side.commit().parent(m1)
-				.add("f", "1-master\n2\n3\n4\n5\n6\n7-res(side)\n8\n9-side\n")
-				.message("s2(merge)").create();
-		master.commit().parent(s1)
-				.add("f", "1-master\n2\n3\n4\n5\n6\n7-conflict\n8\n9-side\n")
-				.message("m2(merge)").create();
+			BranchBuilder side = db_t.branch("side");
+			RevCommit s1 = side.commit().parent(m0)
+					.add("f", "1\n2\n3\n4\n5\n6\n7\n8\n9-side\n").message("s1")
+					.create();
+			RevCommit s2 = side.commit().parent(m1)
+					.add("f",
+							"1-master\n2\n3\n4\n5\n6\n7-res(side)\n8\n9-side\n")
+					.message("s2(merge)").create();
+			master.commit().parent(s1)
+					.add("f",
+							"1-master\n2\n3\n4\n5\n6\n7-conflict\n8\n9-side\n")
+					.message("m2(merge)").create();
 
-		Git git = Git.wrap(db);
-		git.checkout().setName("master").call();
+			Git git = Git.wrap(db);
+			git.checkout().setName("master").call();
 
-		MergeResult result = git.merge().setStrategy(MergeStrategy.RECURSIVE)
-				.include("side", s2).call();
-		assertEquals(MergeStatus.CONFLICTING, result.getMergeStatus());
+			MergeResult result = git.merge()
+					.setStrategy(MergeStrategy.RECURSIVE).include("side", s2)
+					.call();
+			assertEquals(MergeStatus.CONFLICTING, result.getMergeStatus());
+		}
 	}
 
 	private Ref prepareSuccessfulMerge(Git git) throws Exception {
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RemoteDeleteCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RemoteDeleteCommandTest.java
index 7055daf..50e7095 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RemoteDeleteCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RemoteDeleteCommandTest.java
@@ -56,7 +56,7 @@ public void testDelete() throws Exception {
 
 		// execute the command to remove the remote
 		RemoteRemoveCommand cmd = Git.wrap(db).remoteRemove();
-		cmd.setName(REMOTE_NAME);
+		cmd.setRemoteName(REMOTE_NAME);
 		RemoteConfig remote = cmd.call();
 
 		// assert that the removed remote is the initial remote
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RemoteSetUrlCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RemoteSetUrlCommandTest.java
index 6969c3d..d3265fe 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RemoteSetUrlCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RemoteSetUrlCommandTest.java
@@ -45,6 +45,7 @@
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
 
+import org.eclipse.jgit.api.RemoteSetUrlCommand.UriType;
 import org.eclipse.jgit.transport.RemoteConfig;
 import org.eclipse.jgit.transport.URIish;
 import org.junit.Test;
@@ -58,9 +59,9 @@ public void testSetUrl() throws Exception {
 
 		// execute the command to change the fetch url
 		RemoteSetUrlCommand cmd = Git.wrap(db).remoteSetUrl();
-		cmd.setName(REMOTE_NAME);
+		cmd.setRemoteName(REMOTE_NAME);
 		URIish newUri = new URIish("git://test.com/test");
-		cmd.setUri(newUri);
+		cmd.setRemoteUri(newUri);
 		RemoteConfig remote = cmd.call();
 
 		// assert that the changed remote has the new fetch url
@@ -79,10 +80,10 @@ public void testSetPushUrl() throws Exception {
 
 		// execute the command to change the push url
 		RemoteSetUrlCommand cmd = Git.wrap(db).remoteSetUrl();
-		cmd.setName(REMOTE_NAME);
+		cmd.setRemoteName(REMOTE_NAME);
 		URIish newUri = new URIish("git://test.com/test");
-		cmd.setUri(newUri);
-		cmd.setPush(true);
+		cmd.setRemoteUri(newUri);
+		cmd.setUriType(UriType.PUSH);
 		RemoteConfig remote = cmd.call();
 
 		// assert that the changed remote has the old fetch url and the new push
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RenameBranchCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RenameBranchCommandTest.java
index 5c437ac..9facce9 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RenameBranchCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RenameBranchCommandTest.java
@@ -49,14 +49,18 @@
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 
+import org.eclipse.jgit.api.errors.RefAlreadyExistsException;
 import org.eclipse.jgit.junit.RepositoryTestCase;
 import org.eclipse.jgit.lib.BranchConfig.BranchRebaseMode;
 import org.eclipse.jgit.lib.ConfigConstants;
 import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.Ref;
 import org.eclipse.jgit.lib.StoredConfig;
 import org.eclipse.jgit.revwalk.RevCommit;
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
+import org.junit.rules.ExpectedException;
 
 /**
  * Unit tests of {@link RenameBranchCommand}
@@ -69,6 +73,9 @@ public class RenameBranchCommandTest extends RepositoryTestCase {
 
 	private Git git;
 
+	@Rule
+	public ExpectedException thrown = ExpectedException.none();
+
 	@Override
 	@Before
 	public void setUp() throws Exception {
@@ -81,6 +88,45 @@ public void setUp() throws Exception {
 	}
 
 	@Test
+	public void renameToExisting() throws Exception {
+		assertNotNull(git.branchCreate().setName("foo").call());
+		thrown.expect(RefAlreadyExistsException.class);
+		git.branchRename().setOldName("master").setNewName("foo").call();
+	}
+
+	@Test
+	public void renameToTag() throws Exception {
+		Ref ref = git.tag().setName("foo").call();
+		assertNotNull(ref);
+		assertEquals("Unexpected tag name", Constants.R_TAGS + "foo",
+				ref.getName());
+		ref = git.branchRename().setNewName("foo").call();
+		assertNotNull(ref);
+		assertEquals("Unexpected ref name", Constants.R_HEADS + "foo",
+				ref.getName());
+		// Check that we can rename it back
+		ref = git.branchRename().setOldName("foo").setNewName(Constants.MASTER)
+				.call();
+		assertNotNull(ref);
+		assertEquals("Unexpected ref name",
+				Constants.R_HEADS + Constants.MASTER, ref.getName());
+	}
+
+	@Test
+	public void renameToStupidName() throws Exception {
+		Ref ref = git.branchRename().setNewName(Constants.R_HEADS + "foo")
+				.call();
+		assertEquals("Unexpected ref name",
+				Constants.R_HEADS + Constants.R_HEADS + "foo",
+				ref.getName());
+		// And check that we can rename it back to a sane name
+		ref = git.branchRename().setNewName("foo").call();
+		assertNotNull(ref);
+		assertEquals("Unexpected ref name", Constants.R_HEADS + "foo",
+				ref.getName());
+	}
+
+	@Test
 	public void renameBranchNoConfigValues() throws Exception {
 		StoredConfig config = git.getRepository().getConfig();
 		config.unsetSection(ConfigConstants.CONFIG_BRANCH_SECTION,
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributesNodeDirCacheIteratorTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributesNodeDirCacheIteratorTest.java
index 7421e90..837de74 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributesNodeDirCacheIteratorTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributesNodeDirCacheIteratorTest.java
@@ -64,7 +64,7 @@
 import org.junit.Test;
 
 /**
- * Tests attributes node behavior on the the index.
+ * Tests attributes node behavior on the index.
  */
 public class AttributesNodeDirCacheIteratorTest extends RepositoryTestCase {
 
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 178d620..5333451 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
@@ -79,6 +79,36 @@ public void testNul() {
 	}
 
 	@Test
+	public void testCrLfTextYes() {
+		assertTrue(RawText
+				.isCrLfText(Constants.encodeASCII("line 1\r\nline 2\r\n")));
+	}
+
+	@Test
+	public void testCrLfTextNo() {
+		assertFalse(
+				RawText.isCrLfText(Constants.encodeASCII("line 1\nline 2\n")));
+	}
+
+	@Test
+	public void testCrLfTextBinary() {
+		assertFalse(RawText
+				.isCrLfText(Constants.encodeASCII("line 1\r\nline\0 2\r\n")));
+	}
+
+	@Test
+	public void testCrLfTextMixed() {
+		assertTrue(RawText
+				.isCrLfText(Constants.encodeASCII("line 1\nline 2\r\n")));
+	}
+
+	@Test
+	public void testCrLfTextCutShort() {
+		assertFalse(
+				RawText.isCrLfText(Constants.encodeASCII("line 1\nline 2\r")));
+	}
+
+	@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"));
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsPackFileTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsPackFileTest.java
new file mode 100644
index 0000000..dd41b6f
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsPackFileTest.java
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2019, Google LLC.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ *   copyright notice, this list of conditions and the following
+ *   disclaimer in the documentation and/or other materials provided
+ *   with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ *   names of its contributors may be used to endorse or promote
+ *   products derived from this software without specific prior
+ *   written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.internal.storage.dfs;
+
+import static org.junit.Assert.assertEquals;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.zip.Deflater;
+
+import org.eclipse.jgit.internal.storage.pack.PackExt;
+import org.eclipse.jgit.internal.storage.pack.PackOutputStream;
+import org.eclipse.jgit.internal.storage.pack.PackWriter;
+import org.eclipse.jgit.junit.JGitTestUtil;
+import org.eclipse.jgit.junit.TestRng;
+import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.NullProgressMonitor;
+import org.junit.Before;
+import org.junit.Test;
+
+public class DfsPackFileTest {
+	InMemoryRepository db;
+	boolean bypassCache;
+	boolean clearCache;
+
+	@Before
+	public void setUp() {
+		db = new InMemoryRepository(new DfsRepositoryDescription("test"));
+	}
+
+	@Test
+	public void testCopyPackBypassCachesSmallCached() throws IOException {
+		bypassCache = true;
+		clearCache = false;
+		setupPack(512, 256);
+		assertPackSize();
+	}
+
+	@Test
+	public void testCopyPackBypassCacheSmallNoCache() throws IOException {
+		bypassCache = true;
+		clearCache = true;
+		setupPack(512, 256);
+		assertPackSize();
+	}
+
+	@Test
+	public void testCopyPackBypassCacheLargeCached() throws IOException {
+		bypassCache = true;
+		clearCache = false;
+		setupPack(512, 8000);
+		assertPackSize();
+	}
+
+	@Test
+	public void testCopyPackBypassCacheLargeNoCache() throws IOException {
+		bypassCache = true;
+		clearCache = true;
+		setupPack(512, 8000);
+		assertPackSize();
+	}
+
+	@Test
+	public void testCopyPackThroughCacheSmallCached() throws IOException {
+		bypassCache = false;
+		clearCache = false;
+		setupPack(512, 256);
+		assertPackSize();
+	}
+
+	@Test
+	public void testCopyPackThroughCacheSmallNoCache() throws IOException {
+		bypassCache = false;
+		clearCache = true;
+		setupPack(512, 256);
+		assertPackSize();
+	}
+
+	@Test
+	public void testCopyPackThroughCacheLargeCached() throws IOException {
+		bypassCache = false;
+		clearCache = false;
+		setupPack(512, 8000);
+		assertPackSize();
+	}
+
+	@Test
+	public void testCopyPackThroughCacheLargeNoCache() throws IOException {
+		bypassCache = false;
+		clearCache = true;
+		setupPack(512, 8000);
+		assertPackSize();
+	}
+
+	private void setupPack(int bs, int ps) throws IOException {
+		DfsBlockCacheConfig cfg = new DfsBlockCacheConfig().setBlockSize(bs)
+				.setBlockLimit(bs * 100).setStreamRatio(bypassCache ? 0F : 1F);
+		DfsBlockCache.reconfigure(cfg);
+
+		byte[] data = new TestRng(JGitTestUtil.getName()).nextBytes(ps);
+		DfsInserter ins = (DfsInserter) db.newObjectInserter();
+		ins.setCompressionLevel(Deflater.NO_COMPRESSION);
+		ins.insert(Constants.OBJ_BLOB, data);
+		ins.flush();
+
+		if (clearCache) {
+			DfsBlockCache.reconfigure(cfg);
+			db.getObjectDatabase().clearCache();
+		}
+	}
+
+	private void assertPackSize() throws IOException {
+		try (DfsReader ctx = db.getObjectDatabase().newReader();
+				PackWriter pw = new PackWriter(ctx);
+				ByteArrayOutputStream os = new ByteArrayOutputStream();
+				PackOutputStream out = new PackOutputStream(
+						NullProgressMonitor.INSTANCE, os, pw)) {
+			DfsPackFile pack = db.getObjectDatabase().getPacks()[0];
+			long packSize = pack.getPackDescription().getFileSize(PackExt.PACK);
+			pack.copyPackAsIs(out, ctx);
+			assertEquals(packSize - (12 + 20), os.size());
+		}
+	}
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcBranchPrunedTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcBranchPrunedTest.java
index c7ee925..8f29b3b 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcBranchPrunedTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcBranchPrunedTest.java
@@ -66,11 +66,11 @@ public void branch_historyNotPruned() throws Exception {
 		fsTick();
 		gc.prune(Collections.<ObjectId> emptySet());
 		do {
-			assertTrue(repo.hasObject(tip));
+			assertTrue(repo.getObjectDatabase().has(tip));
 			tr.parseBody(tip);
 			RevTree t = tip.getTree();
-			assertTrue(repo.hasObject(t));
-			assertTrue(repo.hasObject(tr.get(t, "a")));
+			assertTrue(repo.getObjectDatabase().has(t));
+			assertTrue(repo.getObjectDatabase().has(tr.get(t, "a")));
 			tip = tip.getParentCount() > 0 ? tip.getParent(0) : null;
 		} while (tip != null);
 	}
@@ -114,6 +114,6 @@ public void deleteMergedBranch_historyNotPruned() throws Exception {
 		gc.setExpireAgeMillis(0);
 		fsTick();
 		gc.prune(Collections.<ObjectId> emptySet());
-		assertTrue(repo.hasObject(b2Tip));
+		assertTrue(repo.getObjectDatabase().has(b2Tip));
 	}
 }
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcConcurrentTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcConcurrentTest.java
index c60c357..05f7c65 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcConcurrentTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcConcurrentTest.java
@@ -177,7 +177,7 @@ public void repackAndUploadPack() throws Exception {
 		gc2.gc();
 
 		// Simulate parts of an UploadPack. This is the situation on
-		// server side (e.g. gerrit) when when clients are
+		// server side (e.g. gerrit) when clients are
 		// cloning/fetching while the server side repo's
 		// are gc'ed by an external process (e.g. scheduled
 		// native git gc)
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcDeleteEmptyRefsFoldersTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcDeleteEmptyRefsFoldersTest.java
index 3caae72..d450f94 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcDeleteEmptyRefsFoldersTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcDeleteEmptyRefsFoldersTest.java
@@ -91,6 +91,20 @@ public void emptyRefFoldersAreDeleted() throws Exception {
 		assertFalse(refDir02.getParent().getParent().toFile().exists());
 	}
 
+	@Test
+	public void emptyRefFoldersSkipFiles() throws Exception {
+		FileTime fileTime = FileTime.from(Instant.now().minusSeconds(31));
+		Path refFile = Files.createFile(refsDir.resolve(".DS_Store"));
+		Path refDir01 = Files.createDirectories(heads.resolve(REF_FOLDER_01));
+		Path refDir02 = Files.createDirectories(heads.resolve(REF_FOLDER_02));
+		setLastModifiedTime(fileTime, heads, REF_FOLDER_01);
+		setLastModifiedTime(fileTime, heads, REF_FOLDER_02);
+		assertTrue(refDir01.toFile().exists());
+		assertTrue(refDir02.toFile().exists());
+		gc.gc();
+		assertTrue(Files.exists(refFile));
+	}
+
 	private void setLastModifiedTime(FileTime fileTime, Path path, String folder) throws IOException {
 		long numParents = folder.chars().filter(c -> c == '/').count();
 		Path folderPath = path.resolve(folder);
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcPruneNonReferencedTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcPruneNonReferencedTest.java
index 3452070..878dc86 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcPruneNonReferencedTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcPruneNonReferencedTest.java
@@ -64,7 +64,7 @@ public void nonReferencedNonExpiredObject_notPruned() throws Exception {
 		RevBlob a = tr.blob("a");
 		gc.setExpire(new Date(lastModified(a)));
 		gc.prune(Collections.<ObjectId> emptySet());
-		assertTrue(repo.hasObject(a));
+		assertTrue(repo.getObjectDatabase().has(a));
 	}
 
 	@Test
@@ -73,7 +73,7 @@ public void nonReferencedExpiredObject_pruned() throws Exception {
 		gc.setExpireAgeMillis(0);
 		fsTick();
 		gc.prune(Collections.<ObjectId> emptySet());
-		assertFalse(repo.hasObject(a));
+		assertFalse(repo.getObjectDatabase().has(a));
 	}
 
 	@Test
@@ -83,8 +83,8 @@ public void nonReferencedExpiredObjectTree_pruned() throws Exception {
 		gc.setExpireAgeMillis(0);
 		fsTick();
 		gc.prune(Collections.<ObjectId> emptySet());
-		assertFalse(repo.hasObject(t));
-		assertFalse(repo.hasObject(a));
+		assertFalse(repo.getObjectDatabase().has(t));
+		assertFalse(repo.getObjectDatabase().has(a));
 	}
 
 	@Test
@@ -96,8 +96,8 @@ public void nonReferencedObjects_onlyExpiredPruned() throws Exception {
 		RevBlob b = tr.blob("b");
 
 		gc.prune(Collections.<ObjectId> emptySet());
-		assertFalse(repo.hasObject(a));
-		assertTrue(repo.hasObject(b));
+		assertFalse(repo.getObjectDatabase().has(a));
+		assertTrue(repo.getObjectDatabase().has(b));
 	}
 
 	@Test
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcTagTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcTagTest.java
index 4afbeff..cf7a431 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcTagTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcTagTest.java
@@ -60,7 +60,7 @@ public void lightweightTag_objectNotPruned() throws Exception {
 		gc.setExpireAgeMillis(0);
 		fsTick();
 		gc.prune(Collections.<ObjectId> emptySet());
-		assertTrue(repo.hasObject(a));
+		assertTrue(repo.getObjectDatabase().has(a));
 	}
 
 	@Test
@@ -72,7 +72,7 @@ public void annotatedTag_objectNotPruned() throws Exception {
 		gc.setExpireAgeMillis(0);
 		fsTick();
 		gc.prune(Collections.<ObjectId> emptySet());
-		assertTrue(repo.hasObject(t));
-		assertTrue(repo.hasObject(a));
+		assertTrue(repo.getObjectDatabase().has(t));
+		assertTrue(repo.getObjectDatabase().has(a));
 	}
 }
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/ObjectDirectoryTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/ObjectDirectoryTest.java
index 1d3ca03..9d47c7e 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/ObjectDirectoryTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/ObjectDirectoryTest.java
@@ -127,7 +127,7 @@ public void testScanningForPackfiles() throws Exception {
 			// scanning of the packs directory
 			ObjectId id = commitFile("file.txt", "test", "master").getId();
 			gc.gc();
-			assertFalse(receivingDB.hasObject(unknownID));
+			assertFalse(receivingDB.getObjectDatabase().has(unknownID));
 			assertTrue(receivingDB.getObjectDatabase().hasPackedObject(id));
 
 			// preparations
@@ -151,7 +151,7 @@ public void testScanningForPackfiles() throws Exception {
 			// JGit will not rescan the packs folder later on and fails to see
 			// the pack file created during gc.
 			assertTrue(tmpFile.createNewFile());
-			assertFalse(receivingDB.hasObject(unknownID));
+			assertFalse(receivingDB.getObjectDatabase().has(unknownID));
 
 			// trigger a gc. This will create packfiles which have likely the
 			// same mtime than the packfolder
@@ -181,8 +181,8 @@ public boolean accept(File dir, String name) {
 					.equals(fs.lastModifiedInstant(ret[0])));
 
 			// all objects are in a new packfile but we will not detect it
-			assertFalse(receivingDB.hasObject(unknownID));
-			assertTrue(receivingDB.hasObject(id2));
+			assertFalse(receivingDB.getObjectDatabase().has(unknownID));
+			assertTrue(receivingDB.getObjectDatabase().has(id2));
 		}
 	}
 
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 04bed09..ca44862 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
@@ -469,10 +469,12 @@ public void testWritePack4SizeThinVsNoThin() throws Exception {
 	public void testDeltaStatistics() throws Exception {
 		config.setDeltaCompress(true);
 		FileRepository repo = createBareRepository();
-		TestRepository<FileRepository> testRepo = new TestRepository<>(repo);
 		ArrayList<RevObject> blobs = new ArrayList<>();
-		blobs.add(testRepo.blob(genDeltableData(1000)));
-		blobs.add(testRepo.blob(genDeltableData(1005)));
+		try (TestRepository<FileRepository> testRepo = new TestRepository<>(
+				repo)) {
+			blobs.add(testRepo.blob(genDeltableData(1000)));
+			blobs.add(testRepo.blob(genDeltableData(1005)));
+		}
 
 		try (PackWriter pw = new PackWriter(repo)) {
 			NullProgressMonitor m = NullProgressMonitor.INSTANCE;
@@ -535,25 +537,23 @@ public void testWriteIndex() throws Exception {
 	public void testExclude() throws Exception {
 		FileRepository repo = createBareRepository();
 
-		TestRepository<FileRepository> testRepo = new TestRepository<>(
-				repo);
-		BranchBuilder bb = testRepo.branch("refs/heads/master");
-		contentA = testRepo.blob("A");
-		c1 = bb.commit().add("f", contentA).create();
-		testRepo.getRevWalk().parseHeaders(c1);
-		PackIndex pf1 = writePack(repo, wants(c1), EMPTY_ID_SET);
-		assertContent(
-				pf1,
-				Arrays.asList(c1.getId(), c1.getTree().getId(),
-						contentA.getId()));
-		contentB = testRepo.blob("B");
-		c2 = bb.commit().add("f", contentB).create();
-		testRepo.getRevWalk().parseHeaders(c2);
-		PackIndex pf2 = writePack(repo, wants(c2), Sets.of((ObjectIdSet) pf1));
-		assertContent(
-				pf2,
-				Arrays.asList(c2.getId(), c2.getTree().getId(),
-						contentB.getId()));
+		try (TestRepository<FileRepository> testRepo = new TestRepository<>(
+				repo)) {
+			BranchBuilder bb = testRepo.branch("refs/heads/master");
+			contentA = testRepo.blob("A");
+			c1 = bb.commit().add("f", contentA).create();
+			testRepo.getRevWalk().parseHeaders(c1);
+			PackIndex pf1 = writePack(repo, wants(c1), EMPTY_ID_SET);
+			assertContent(pf1, Arrays.asList(c1.getId(), c1.getTree().getId(),
+					contentA.getId()));
+			contentB = testRepo.blob("B");
+			c2 = bb.commit().add("f", contentB).create();
+			testRepo.getRevWalk().parseHeaders(c2);
+			PackIndex pf2 = writePack(repo, wants(c2),
+					Sets.of((ObjectIdSet) pf1));
+			assertContent(pf2, Arrays.asList(c2.getId(), c2.getTree().getId(),
+					contentB.getId()));
+		}
 	}
 
 	private static void assertContent(PackIndex pi, List<ObjectId> expected) {
@@ -660,20 +660,21 @@ public void testShallowFetchShallowAncestorDepth2() throws Exception {
 
 	private FileRepository setupRepoForShallowFetch() throws Exception {
 		FileRepository repo = createBareRepository();
-		TestRepository<Repository> r = new TestRepository<>(repo);
-		BranchBuilder bb = r.branch("refs/heads/master");
-		contentA = r.blob("A");
-		contentB = r.blob("B");
-		contentC = r.blob("C");
-		contentD = r.blob("D");
-		contentE = r.blob("E");
-		c1 = bb.commit().add("a", contentA).create();
-		c2 = bb.commit().add("b", contentB).create();
-		c3 = bb.commit().add("c", contentC).create();
-		c4 = bb.commit().add("d", contentD).create();
-		c5 = bb.commit().add("e", contentE).create();
-		r.getRevWalk().parseHeaders(c5); // fully initialize the tip RevCommit
-		return repo;
+		try (TestRepository<Repository> r = new TestRepository<>(repo)) {
+			BranchBuilder bb = r.branch("refs/heads/master");
+			contentA = r.blob("A");
+			contentB = r.blob("B");
+			contentC = r.blob("C");
+			contentD = r.blob("D");
+			contentE = r.blob("E");
+			c1 = bb.commit().add("a", contentA).create();
+			c2 = bb.commit().add("b", contentB).create();
+			c3 = bb.commit().add("c", contentC).create();
+			c4 = bb.commit().add("d", contentD).create();
+			c5 = bb.commit().add("e", contentE).create();
+			r.getRevWalk().parseHeaders(c5); // fully initialize the tip RevCommit
+			return repo;
+		}
 	}
 
 	private static PackIndex writePack(FileRepository repo,
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 24e3bc0..2357edf 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
@@ -48,6 +48,7 @@
 import static org.eclipse.jgit.lib.Constants.R_TAGS;
 import static org.eclipse.jgit.lib.Ref.Storage.LOOSE;
 import static org.eclipse.jgit.lib.Ref.Storage.NEW;
+import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
@@ -62,6 +63,7 @@
 import java.time.Instant;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.List;
 import java.util.Map;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.atomic.AtomicReference;
@@ -137,6 +139,33 @@ public void testCreate() throws IOException {
 		assertEquals("ref: refs/heads/master\n", read(new File(d, HEAD)));
 	}
 
+	@Test(expected = UnsupportedOperationException.class)
+	public void testVersioningNotImplemented_exactRef() throws IOException {
+		assertFalse(refdir.hasVersioning());
+
+		Ref ref = refdir.exactRef(HEAD);
+		assertNotNull(ref);
+		ref.getUpdateIndex(); // Not implemented on FS
+	}
+
+	@Test
+	public void testVersioningNotImplemented_getRefs() throws Exception {
+		assertFalse(refdir.hasVersioning());
+
+		RevCommit C = repo.commit().parent(B).create();
+		repo.update("master", C);
+		List<Ref> refs = refdir.getRefs();
+
+		for (Ref ref : refs) {
+			try {
+				ref.getUpdateIndex();
+				fail("FS doesn't implement ref versioning");
+			} catch (UnsupportedOperationException e) {
+				// ok
+			}
+		}
+	}
+
 	@Test
 	public void testGetRefs_EmptyDatabase() throws IOException {
 		Map<String, Ref> all;
@@ -395,15 +424,15 @@ public void testGetRefs_InvalidName() throws IOException {
 
 	@Test
 	public void testReadNotExistingBranchConfig() throws IOException {
-		assertNull("find branch config", refdir.getRef("config"));
-		assertNull("find branch config", refdir.getRef("refs/heads/config"));
+		assertNull("find branch config", refdir.findRef("config"));
+		assertNull("find branch config", refdir.findRef("refs/heads/config"));
 	}
 
 	@Test
 	public void testReadBranchConfig() throws IOException {
 		writeLooseRef("refs/heads/config", A);
 
-		assertNotNull("find branch config", refdir.getRef("config"));
+		assertNotNull("find branch config", refdir.findRef("config"));
 	}
 
 	@Test
@@ -647,7 +676,7 @@ public void testGetRefs_DiscoversModifiedLoose() throws IOException {
 
 	@Repeat(n = 100, abortOnFailure = false)
 	@Test
-	public void testGetRef_DiscoversModifiedLoose() throws IOException {
+	public void testFindRef_DiscoversModifiedLoose() throws IOException {
 		Map<String, Ref> all;
 
 		writeLooseRef("refs/heads/master", A);
@@ -656,7 +685,7 @@ public void testGetRef_DiscoversModifiedLoose() throws IOException {
 
 		writeLooseRef("refs/heads/master", B);
 
-		Ref master = refdir.getRef("refs/heads/master");
+		Ref master = refdir.findRef("refs/heads/master");
 		assertEquals(B, master.getObjectId());
 	}
 
@@ -691,7 +720,7 @@ public void testGetRefs_DiscoversDeletedLoose1() throws IOException {
 	}
 
 	@Test
-	public void testGetRef_DiscoversDeletedLoose() throws IOException {
+	public void testFindRef_DiscoversDeletedLoose() throws IOException {
 		Map<String, Ref> all;
 
 		writeLooseRef("refs/heads/master", A);
@@ -699,7 +728,7 @@ public void testGetRef_DiscoversDeletedLoose() throws IOException {
 		assertEquals(A, all.get(HEAD).getObjectId());
 
 		deleteLooseRef("refs/heads/master");
-		assertNull(refdir.getRef("refs/heads/master"));
+		assertNull(refdir.findRef("refs/heads/master"));
 		assertTrue(refdir.getRefs(RefDatabase.ALL).isEmpty());
 	}
 
@@ -859,7 +888,7 @@ public void testGetRefs_CycleInSymbolicRef() throws IOException {
 	}
 
 	@Test
-	public void testGetRef_CycleInSymbolicRef() throws IOException {
+	public void testFindRef_CycleInSymbolicRef() throws IOException {
 		Ref r;
 
 		writeLooseRef("refs/1", "ref: refs/2\n");
@@ -869,7 +898,7 @@ public void testGetRef_CycleInSymbolicRef() throws IOException {
 		writeLooseRef("refs/5", "ref: refs/end\n");
 		writeLooseRef("refs/end", A);
 
-		r = refdir.getRef("1");
+		r = refdir.findRef("1");
 		assertEquals("refs/1", r.getName());
 		assertEquals(A, r.getObjectId());
 		assertTrue(r.isSymbolic());
@@ -877,12 +906,12 @@ public void testGetRef_CycleInSymbolicRef() throws IOException {
 		writeLooseRef("refs/5", "ref: refs/6\n");
 		writeLooseRef("refs/6", "ref: refs/end\n");
 
-		r = refdir.getRef("1");
+		r = refdir.findRef("1");
 		assertNull("missing 1 due to cycle", r);
 
 		writeLooseRef("refs/heads/1", B);
 
-		r = refdir.getRef("1");
+		r = refdir.findRef("1");
 		assertEquals("refs/heads/1", r.getName());
 		assertEquals(B, r.getObjectId());
 		assertFalse(r.isSymbolic());
@@ -923,16 +952,16 @@ public void testGetRefs_PackedNotPeeled_Sorted() throws IOException {
 	}
 
 	@Test
-	public void testGetRef_PackedNotPeeled_WrongSort() throws IOException {
+	public void testFindRef_PackedNotPeeled_WrongSort() throws IOException {
 		writePackedRefs("" + //
 				v1_0.name() + " refs/tags/v1.0\n" + //
 				B.name() + " refs/heads/other\n" + //
 				A.name() + " refs/heads/master\n");
 
-		final Ref head = refdir.getRef(HEAD);
-		final Ref master = refdir.getRef("refs/heads/master");
-		final Ref other = refdir.getRef("refs/heads/other");
-		final Ref tag = refdir.getRef("refs/tags/v1.0");
+		final Ref head = refdir.findRef(HEAD);
+		final Ref master = refdir.findRef("refs/heads/master");
+		final Ref other = refdir.findRef("refs/heads/other");
+		final Ref tag = refdir.findRef("refs/tags/v1.0");
 
 		assertEquals(A, master.getObjectId());
 		assertFalse(master.isPeeled());
@@ -1037,22 +1066,22 @@ public void test_repack() throws Exception {
 	}
 
 	@Test
-	public void testGetRef_EmptyDatabase() throws IOException {
+	public void testFindRef_EmptyDatabase() throws IOException {
 		Ref r;
 
-		r = refdir.getRef(HEAD);
+		r = refdir.findRef(HEAD);
 		assertTrue(r.isSymbolic());
 		assertSame(LOOSE, r.getStorage());
 		assertEquals("refs/heads/master", r.getTarget().getName());
 		assertSame(NEW, r.getTarget().getStorage());
 		assertNull(r.getTarget().getObjectId());
 
-		assertNull(refdir.getRef("refs/heads/master"));
-		assertNull(refdir.getRef("refs/tags/v1.0"));
-		assertNull(refdir.getRef("FETCH_HEAD"));
-		assertNull(refdir.getRef("NOT.A.REF.NAME"));
-		assertNull(refdir.getRef("master"));
-		assertNull(refdir.getRef("v1.0"));
+		assertNull(refdir.findRef("refs/heads/master"));
+		assertNull(refdir.findRef("refs/tags/v1.0"));
+		assertNull(refdir.findRef("FETCH_HEAD"));
+		assertNull(refdir.findRef("NOT.A.REF.NAME"));
+		assertNull(refdir.findRef("master"));
+		assertNull(refdir.findRef("v1.0"));
 	}
 
 	@Test
@@ -1075,7 +1104,29 @@ public void testExactRef_EmptyDatabase() throws IOException {
 	}
 
 	@Test
-	public void testGetRef_FetchHead() throws IOException {
+	public void testGetAdditionalRefs_OrigHead() throws IOException {
+		writeLooseRef("ORIG_HEAD", A);
+
+		List<Ref> refs = refdir.getAdditionalRefs();
+		assertEquals(1, refs.size());
+
+		Ref r = refs.get(0);
+		assertFalse(r.isSymbolic());
+		assertEquals(A, r.getObjectId());
+		assertEquals("ORIG_HEAD", r.getName());
+		assertFalse(r.isPeeled());
+		assertNull(r.getPeeledObjectId());
+	}
+
+	@Test
+	public void testGetAdditionalRefs_OrigHeadBranch() throws IOException {
+		writeLooseRef("refs/heads/ORIG_HEAD", A);
+		List<Ref> refs = refdir.getAdditionalRefs();
+		assertArrayEquals(new Ref[0], refs.toArray());
+	}
+
+	@Test
+	public void testFindRef_FetchHead() throws IOException {
 		// This is an odd special case where we need to make sure we read
 		// exactly the first 40 bytes of the file and nothing further on
 		// that line, or the remainder of the file.
@@ -1083,7 +1134,7 @@ public void testGetRef_FetchHead() throws IOException {
 				+ "\tnot-for-merge"
 				+ "\tbranch 'master' of git://egit.eclipse.org/jgit\n");
 
-		Ref r = refdir.getRef("FETCH_HEAD");
+		Ref r = refdir.findRef("FETCH_HEAD");
 		assertFalse(r.isSymbolic());
 		assertEquals(A, r.getObjectId());
 		assertEquals("FETCH_HEAD", r.getName());
@@ -1109,12 +1160,12 @@ public void testExactRef_FetchHead() throws IOException {
 	}
 
 	@Test
-	public void testGetRef_AnyHeadWithGarbage() throws IOException {
+	public void testFindRef_AnyHeadWithGarbage() throws IOException {
 		write(new File(diskRepo.getDirectory(), "refs/heads/A"), A.name()
 				+ "012345 . this is not a standard reference\n"
 				+ "#and even more junk\n");
 
-		Ref r = refdir.getRef("refs/heads/A");
+		Ref r = refdir.findRef("refs/heads/A");
 		assertFalse(r.isSymbolic());
 		assertEquals(A, r.getObjectId());
 		assertEquals("refs/heads/A", r.getName());
@@ -1130,11 +1181,11 @@ public void testGetRefs_CorruptSymbolicReference() throws IOException {
 	}
 
 	@Test
-	public void testGetRef_CorruptSymbolicReference() throws IOException {
+	public void testFindRef_CorruptSymbolicReference() throws IOException {
 		String name = "refs/heads/A";
 		writeLooseRef(name, "ref: \n");
 		try {
-			refdir.getRef(name);
+			refdir.findRef(name);
 			fail("read an invalid reference");
 		} catch (IOException err) {
 			String msg = err.getMessage();
@@ -1151,12 +1202,12 @@ public void testGetRefs_CorruptObjectIdReference() throws IOException {
 	}
 
 	@Test
-	public void testGetRef_CorruptObjectIdReference() throws IOException {
+	public void testFindRef_CorruptObjectIdReference() throws IOException {
 		String name = "refs/heads/A";
 		String content = "zoo" + A.name();
 		writeLooseRef(name, content + "\n");
 		try {
-			refdir.getRef(name);
+			refdir.findRef(name);
 			fail("read an invalid reference");
 		} catch (IOException err) {
 			String msg = err.getMessage();
@@ -1191,8 +1242,8 @@ public void testPeelLooseTag() throws IOException {
 		writeLooseRef("refs/tags/v1_0", v1_0);
 		writeLooseRef("refs/tags/current", "ref: refs/tags/v1_0\n");
 
-		final Ref tag = refdir.getRef("refs/tags/v1_0");
-		final Ref cur = refdir.getRef("refs/tags/current");
+		final Ref tag = refdir.findRef("refs/tags/v1_0");
+		final Ref cur = refdir.findRef("refs/tags/current");
 
 		assertEquals(v1_0, tag.getObjectId());
 		assertFalse(tag.isSymbolic());
@@ -1224,14 +1275,14 @@ public void testPeelLooseTag() throws IOException {
 
 		// reuses cached peeling later, but not immediately due to
 		// the implementation so we have to fetch it once.
-		final Ref tag_p2 = refdir.getRef("refs/tags/v1_0");
+		final Ref tag_p2 = refdir.findRef("refs/tags/v1_0");
 		assertFalse(tag_p2.isSymbolic());
 		assertTrue(tag_p2.isPeeled());
 		assertEquals(v1_0, tag_p2.getObjectId());
 		assertEquals(v1_0.getObject(), tag_p2.getPeeledObjectId());
 
-		assertSame(tag_p2, refdir.getRef("refs/tags/v1_0"));
-		assertSame(tag_p2, refdir.getRef("refs/tags/current").getTarget());
+		assertSame(tag_p2, refdir.findRef("refs/tags/v1_0"));
+		assertSame(tag_p2, refdir.findRef("refs/tags/current").getTarget());
 		assertSame(tag_p2, refdir.peel(tag_p2));
 	}
 
@@ -1239,7 +1290,7 @@ public void testPeelLooseTag() throws IOException {
 	public void testPeelCommit() throws IOException {
 		writeLooseRef("refs/heads/master", A);
 
-		Ref master = refdir.getRef("refs/heads/master");
+		Ref master = refdir.findRef("refs/heads/master");
 		assertEquals(A, master.getObjectId());
 		assertFalse(master.isPeeled());
 		assertNull(master.getPeeledObjectId());
@@ -1252,7 +1303,7 @@ public void testPeelCommit() throws IOException {
 
 		// reuses cached peeling later, but not immediately due to
 		// the implementation so we have to fetch it once.
-		Ref master_p2 = refdir.getRef("refs/heads/master");
+		Ref master_p2 = refdir.findRef("refs/heads/master");
 		assertNotSame(master, master_p2);
 		assertEquals(A, master_p2.getObjectId());
 		assertTrue(master_p2.isPeeled());
@@ -1304,7 +1355,7 @@ public void testPackedRefsLockFailure() throws Exception {
 		} finally {
 			myLock.unlock();
 		}
-		Ref ref = refdir.getRef("refs/heads/master");
+		Ref ref = refdir.findRef("refs/heads/master");
 		assertEquals(Storage.LOOSE, ref.getStorage());
 	}
 
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 9eb1816..e2887d9 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
@@ -540,7 +540,7 @@ public void test024_createCommitNonAscii() throws IOException {
 				4294967295000L, 60));
 		commit.setCommitter(new PersonIdent("Joe Hacker", "joe2@example.com",
 				4294967295000L, 60));
-		commit.setEncoding("ISO-8859-1");
+		commit.setEncoding(ISO_8859_1);
 		commit.setMessage("\u00dcbergeeks");
 		ObjectId cid = insertCommit(commit);
 		assertEquals("2979b39d385014b33287054b87f77bcb3ecb5ebf", cid.name());
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/reftable/MergedReftableTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/reftable/MergedReftableTest.java
index 1d11573..11d6439 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/reftable/MergedReftableTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/reftable/MergedReftableTest.java
@@ -44,6 +44,7 @@
 package org.eclipse.jgit.internal.storage.reftable;
 
 import static org.eclipse.jgit.lib.Constants.HEAD;
+import static org.eclipse.jgit.lib.Constants.MASTER;
 import static org.eclipse.jgit.lib.Constants.OBJECT_ID_LENGTH;
 import static org.eclipse.jgit.lib.Constants.R_HEADS;
 import static org.eclipse.jgit.lib.Ref.Storage.NEW;
@@ -68,6 +69,7 @@
 import org.eclipse.jgit.lib.ObjectIdRef;
 import org.eclipse.jgit.lib.Ref;
 import org.eclipse.jgit.lib.RefComparator;
+import org.eclipse.jgit.lib.SymbolicRef;
 import org.junit.Test;
 
 public class MergedReftableTest {
@@ -128,6 +130,7 @@ public void oneTableScan() throws IOException {
 				Ref act = rc.getRef();
 				assertEquals(exp.getName(), act.getName());
 				assertEquals(exp.getObjectId(), act.getObjectId());
+				assertEquals(1, act.getUpdateIndex());
 			}
 			assertFalse(rc.next());
 		}
@@ -145,6 +148,7 @@ public void deleteIsHidden() throws IOException {
 			assertTrue(rc.next());
 			assertEquals("refs/heads/master", rc.getRef().getName());
 			assertEquals(id(2), rc.getRef().getObjectId());
+			assertEquals(1, rc.getRef().getUpdateIndex());
 			assertFalse(rc.next());
 		}
 	}
@@ -162,6 +166,7 @@ public void twoTableSeek() throws IOException {
 			assertEquals("refs/heads/master", rc.getRef().getName());
 			assertEquals(id(2), rc.getRef().getObjectId());
 			assertFalse(rc.next());
+			assertEquals(1, rc.getRef().getUpdateIndex());
 		}
 	}
 
@@ -177,6 +182,7 @@ public void twoTableById() throws IOException {
 			assertTrue(rc.next());
 			assertEquals("refs/heads/master", rc.getRef().getName());
 			assertEquals(id(2), rc.getRef().getObjectId());
+			assertEquals(1, rc.getRef().getUpdateIndex());
 			assertFalse(rc.next());
 		}
 	}
@@ -212,6 +218,7 @@ public void fourTableScan() throws IOException {
 				Ref act = rc.getRef();
 				assertEquals(exp.getName(), act.getName());
 				assertEquals(exp.getObjectId(), act.getObjectId());
+				assertEquals(1, rc.getRef().getUpdateIndex());
 			}
 			assertFalse(rc.next());
 		}
@@ -231,9 +238,11 @@ public void scanDuplicates() throws IOException {
 			assertTrue(rc.next());
 			assertEquals("refs/heads/apple", rc.getRef().getName());
 			assertEquals(id(3), rc.getRef().getObjectId());
+			assertEquals(2000, rc.getRef().getUpdateIndex());
 			assertTrue(rc.next());
 			assertEquals("refs/heads/banana", rc.getRef().getName());
 			assertEquals(id(2), rc.getRef().getObjectId());
+			assertEquals(1000, rc.getRef().getUpdateIndex());
 			assertFalse(rc.next());
 		}
 	}
@@ -251,12 +260,14 @@ public void scanIncludeDeletes() throws IOException {
 			Ref r = rc.getRef();
 			assertEquals("refs/heads/master", r.getName());
 			assertEquals(id(8), r.getObjectId());
+			assertEquals(1, rc.getRef().getUpdateIndex());
 
 			assertTrue(rc.next());
 			r = rc.getRef();
 			assertEquals("refs/heads/next", r.getName());
 			assertEquals(NEW, r.getStorage());
 			assertNull(r.getObjectId());
+			assertEquals(1, rc.getRef().getUpdateIndex());
 
 			assertFalse(rc.next());
 		}
@@ -277,6 +288,7 @@ public void oneTableSeek() throws IOException {
 				Ref act = rc.getRef();
 				assertEquals(exp.getName(), act.getName());
 				assertEquals(exp.getObjectId(), act.getObjectId());
+				assertEquals(1, act.getUpdateIndex());
 				assertFalse(rc.next());
 			}
 		}
@@ -303,17 +315,17 @@ public void missedUpdate() throws IOException {
 			assertTrue(rc.next());
 			assertEquals("refs/heads/a", rc.getRef().getName());
 			assertEquals(id(1), rc.getRef().getObjectId());
-			assertEquals(1, rc.getUpdateIndex());
+			assertEquals(1, rc.getRef().getUpdateIndex());
 
 			assertTrue(rc.next());
 			assertEquals("refs/heads/b", rc.getRef().getName());
 			assertEquals(id(2), rc.getRef().getObjectId());
-			assertEquals(2, rc.getUpdateIndex());
+			assertEquals(2, rc.getRef().getUpdateIndex());
 
 			assertTrue(rc.next());
 			assertEquals("refs/heads/c", rc.getRef().getName());
 			assertEquals(id(3), rc.getRef().getObjectId());
-			assertEquals(3, rc.getUpdateIndex());
+			assertEquals(3, rc.getRef().getUpdateIndex());
 		}
 	}
 
@@ -344,6 +356,63 @@ public void compaction() throws IOException {
 		}
 	}
 
+	@Test
+	public void versioningSymbolicReftargetMoves() throws IOException {
+		Ref master = ref(MASTER, 100);
+
+		List<Ref> delta1 = Arrays.asList(master, sym(HEAD, MASTER));
+		List<Ref> delta2 = Arrays.asList(ref(MASTER, 200));
+
+		MergedReftable mr = merge(write(delta1, 1), write(delta2, 2));
+		Ref head = mr.exactRef(HEAD);
+		assertEquals(head.getUpdateIndex(), 1);
+
+		Ref masterRef = mr.exactRef(MASTER);
+		assertEquals(masterRef.getUpdateIndex(), 2);
+	}
+
+	@Test
+	public void versioningSymbolicRefMoves() throws IOException {
+		Ref branchX = ref("refs/heads/branchX", 200);
+
+		List<Ref> delta1 = Arrays.asList(ref(MASTER, 100), branchX,
+				sym(HEAD, MASTER));
+		List<Ref> delta2 = Arrays.asList(sym(HEAD, "refs/heads/branchX"));
+		List<Ref> delta3 = Arrays.asList(sym(HEAD, MASTER));
+
+		MergedReftable mr = merge(write(delta1, 1), write(delta2, 2),
+				write(delta3, 3));
+		Ref head = mr.exactRef(HEAD);
+		assertEquals(head.getUpdateIndex(), 3);
+
+		Ref masterRef = mr.exactRef(MASTER);
+		assertEquals(masterRef.getUpdateIndex(), 1);
+
+		Ref branchRef = mr.exactRef(MASTER);
+		assertEquals(branchRef.getUpdateIndex(), 1);
+	}
+
+	@Test
+	public void versioningResolveRef() throws IOException {
+		List<Ref> delta1 = Arrays.asList(sym(HEAD, "refs/heads/tmp"),
+				sym("refs/heads/tmp", MASTER), ref(MASTER, 100));
+		List<Ref> delta2 = Arrays.asList(ref(MASTER, 200));
+		List<Ref> delta3 = Arrays.asList(ref(MASTER, 300));
+
+		MergedReftable mr = merge(write(delta1, 1), write(delta2, 2),
+				write(delta3, 3));
+		Ref head = mr.exactRef(HEAD);
+		Ref resolvedHead = mr.resolve(head);
+		assertEquals(resolvedHead.getObjectId(), id(300));
+		assertEquals("HEAD has not moved", resolvedHead.getUpdateIndex(), 1);
+
+		Ref master = mr.exactRef(MASTER);
+		Ref resolvedMaster = mr.resolve(master);
+		assertEquals(resolvedMaster.getObjectId(), id(300));
+		assertEquals("master also has update index",
+				resolvedMaster.getUpdateIndex(), 3);
+	}
+
 	private static MergedReftable merge(byte[]... table) {
 		List<Reftable> stack = new ArrayList<>(table.length);
 		for (byte[] b : table) {
@@ -360,6 +429,14 @@ private static Ref ref(String name, int id) {
 		return new ObjectIdRef.PeeledNonTag(PACKED, name, id(id));
 	}
 
+	private static Ref sym(String name, String target) {
+		return new SymbolicRef(name, newRef(target));
+	}
+
+	private static Ref newRef(String name) {
+		return new ObjectIdRef.Unpeeled(NEW, name, null);
+	}
+
 	private static Ref delete(String name) {
 		return new ObjectIdRef.Unpeeled(NEW, name, null);
 	}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/reftable/ReftableCompactorTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/reftable/ReftableCompactorTest.java
index 46a37ff..1ea7309 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/reftable/ReftableCompactorTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/reftable/ReftableCompactorTest.java
@@ -108,7 +108,7 @@ public void oneTable() throws IOException {
 			assertTrue(rc.next());
 			assertEquals(MASTER, rc.getRef().getName());
 			assertEquals(id(1), rc.getRef().getObjectId());
-			assertEquals(0, rc.getUpdateIndex());
+			assertEquals(0, rc.getRef().getUpdateIndex());
 		}
 	}
 
@@ -155,7 +155,7 @@ public void twoTablesOneRef() throws IOException {
 			assertTrue(rc.next());
 			assertEquals(MASTER, rc.getRef().getName());
 			assertEquals(id(2), rc.getRef().getObjectId());
-			assertEquals(1, rc.getUpdateIndex());
+			assertEquals(1, rc.getRef().getUpdateIndex());
 		}
 	}
 
@@ -203,12 +203,12 @@ public void twoTablesTwoRefs() throws IOException {
 			assertTrue(rc.next());
 			assertEquals(MASTER, rc.getRef().getName());
 			assertEquals(id(3), rc.getRef().getObjectId());
-			assertEquals(1, rc.getUpdateIndex());
+			assertEquals(1, rc.getRef().getUpdateIndex());
 
 			assertTrue(rc.next());
 			assertEquals(NEXT, rc.getRef().getName());
 			assertEquals(id(2), rc.getRef().getObjectId());
-			assertEquals(0, rc.getUpdateIndex());
+			assertEquals(0, rc.getRef().getUpdateIndex());
 		}
 	}
 
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/reftable/ReftableTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/reftable/ReftableTest.java
index 0ee785c..a142166 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/reftable/ReftableTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/reftable/ReftableTest.java
@@ -186,6 +186,7 @@ public void oneIdRef() throws IOException {
 			assertFalse(act.isSymbolic());
 			assertEquals(exp.getName(), act.getName());
 			assertEquals(exp.getObjectId(), act.getObjectId());
+			assertEquals(0, act.getUpdateIndex());
 			assertNull(act.getPeeledObjectId());
 			assertFalse(rc.wasDeleted());
 			assertFalse(rc.next());
@@ -195,6 +196,7 @@ public void oneIdRef() throws IOException {
 			Ref act = rc.getRef();
 			assertNotNull(act);
 			assertEquals(exp.getName(), act.getName());
+			assertEquals(0, act.getUpdateIndex());
 			assertFalse(rc.next());
 		}
 	}
@@ -216,6 +218,7 @@ public void oneTagRef() throws IOException {
 			assertEquals(exp.getName(), act.getName());
 			assertEquals(exp.getObjectId(), act.getObjectId());
 			assertEquals(exp.getPeeledObjectId(), act.getPeeledObjectId());
+			assertEquals(0, act.getUpdateIndex());
 		}
 	}
 
@@ -237,6 +240,7 @@ public void oneSymbolicRef() throws IOException {
 			assertNotNull(act.getLeaf());
 			assertEquals(MASTER, act.getTarget().getName());
 			assertNull(act.getObjectId());
+			assertEquals(0, act.getUpdateIndex());
 		}
 	}
 
@@ -250,14 +254,17 @@ public void resolveSymbolicRef() throws IOException {
 		Ref head = t.exactRef(HEAD);
 		assertNull(head.getObjectId());
 		assertEquals("refs/heads/tmp", head.getTarget().getName());
+		assertEquals(0, head.getUpdateIndex());
 
 		head = t.resolve(head);
 		assertNotNull(head);
 		assertEquals(id(1), head.getObjectId());
+		assertEquals(0, head.getUpdateIndex());
 
 		Ref master = t.exactRef(MASTER);
 		assertNotNull(master);
 		assertSame(master, t.resolve(master));
+		assertEquals(0, master.getUpdateIndex());
 	}
 
 	@Test
@@ -335,14 +342,17 @@ public void namespaceHeads() throws IOException {
 		try (RefCursor rc = t.seekRefsWithPrefix("refs/tags/")) {
 			assertTrue(rc.next());
 			assertEquals(V1_0, rc.getRef().getName());
+			assertEquals(0, rc.getRef().getUpdateIndex());
 			assertFalse(rc.next());
 		}
 		try (RefCursor rc = t.seekRefsWithPrefix("refs/heads/")) {
 			assertTrue(rc.next());
 			assertEquals(MASTER, rc.getRef().getName());
+			assertEquals(0, rc.getRef().getUpdateIndex());
 
 			assertTrue(rc.next());
 			assertEquals(NEXT, rc.getRef().getName());
+			assertEquals(0, rc.getRef().getUpdateIndex());
 
 			assertFalse(rc.next());
 		}
@@ -432,11 +442,12 @@ public void withReflog() throws IOException {
 			assertTrue(rc.next());
 			assertEquals(MASTER, rc.getRef().getName());
 			assertEquals(id(1), rc.getRef().getObjectId());
-			assertEquals(1, rc.getUpdateIndex());
+			assertEquals(1, rc.getRef().getUpdateIndex());
 
 			assertTrue(rc.next());
 			assertEquals(NEXT, rc.getRef().getName());
 			assertEquals(id(2), rc.getRef().getObjectId());
+			assertEquals(1, rc.getRef().getUpdateIndex());
 			assertFalse(rc.next());
 		}
 		try (LogCursor lc = t.allLogs()) {
@@ -569,6 +580,7 @@ public void byObjectIdOneRefNoIndex() throws IOException {
 			assertTrue("has 42", rc.next());
 			assertEquals("refs/heads/42", rc.getRef().getName());
 			assertEquals(id(42), rc.getRef().getObjectId());
+			assertEquals(0, rc.getRef().getUpdateIndex());
 			assertFalse(rc.next());
 		}
 		try (RefCursor rc = t.byObjectId(id(100))) {
@@ -579,6 +591,7 @@ public void byObjectIdOneRefNoIndex() throws IOException {
 			assertTrue("has master", rc.next());
 			assertEquals("refs/heads/master", rc.getRef().getName());
 			assertEquals(id(100), rc.getRef().getObjectId());
+			assertEquals(0, rc.getRef().getUpdateIndex());
 
 			assertFalse(rc.next());
 		}
@@ -600,6 +613,7 @@ public void byObjectIdOneRefWithIndex() throws IOException {
 			assertTrue("has 42", rc.next());
 			assertEquals("refs/heads/42", rc.getRef().getName());
 			assertEquals(id(42), rc.getRef().getObjectId());
+			assertEquals(0, rc.getRef().getUpdateIndex());
 			assertFalse(rc.next());
 		}
 		try (RefCursor rc = t.byObjectId(id(100))) {
@@ -610,6 +624,7 @@ public void byObjectIdOneRefWithIndex() throws IOException {
 			assertTrue("has master", rc.next());
 			assertEquals("refs/heads/master", rc.getRef().getName());
 			assertEquals(id(100), rc.getRef().getObjectId());
+			assertEquals(0, rc.getRef().getUpdateIndex());
 
 			assertFalse(rc.next());
 		}
@@ -654,7 +669,6 @@ public void badCrc32() throws IOException {
 		}
 	}
 
-
 	private static void assertScan(List<Ref> refs, Reftable t)
 			throws IOException {
 		try (RefCursor rc = t.allRefs()) {
@@ -663,6 +677,7 @@ private static void assertScan(List<Ref> refs, Reftable t)
 				Ref act = rc.getRef();
 				assertEquals(exp.getName(), act.getName());
 				assertEquals(exp.getObjectId(), act.getObjectId());
+				assertEquals(0, rc.getRef().getUpdateIndex());
 			}
 			assertFalse(rc.next());
 		}
@@ -676,6 +691,7 @@ private static void assertSeek(List<Ref> refs, Reftable t)
 				Ref act = rc.getRef();
 				assertEquals(exp.getName(), act.getName());
 				assertEquals(exp.getObjectId(), act.getObjectId());
+				assertEquals(0, rc.getRef().getUpdateIndex());
 				assertFalse(rc.next());
 			}
 		}
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 ae52ad5..8ef21e6 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
@@ -362,8 +362,8 @@ public void testGetRefs_CycleInSymbolicRef() throws IOException {
 
 	@Test
 	public void testGetRef_NonExistingBranchConfig() throws IOException {
-		assertNull("find branch config", refdb.getRef("config"));
-		assertNull("find branch config", refdb.getRef("refs/heads/config"));
+		assertNull("find branch config", refdb.findRef("config"));
+		assertNull("find branch config", refdb.findRef("refs/heads/config"));
 	}
 
 	@Test
@@ -371,7 +371,7 @@ public void testGetRef_FindBranchConfig() throws IOException {
 		update("refs/heads/config", A);
 
 		for (String t : new String[] { "config", "refs/heads/config" }) {
-			Ref r = refdb.getRef(t);
+			Ref r = refdb.findRef(t);
 			assertNotNull("find branch config (" + t + ")", r);
 			assertEquals("for " + t, "refs/heads/config", r.getName());
 			assertEquals("for " + t, A, r.getObjectId());
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/CommitBuilderTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/CommitBuilderTest.java
new file mode 100644
index 0000000..27ea505
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/CommitBuilderTest.java
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) 2018, Salesforce.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ *   copyright notice, this list of conditions and the following
+ *   disclaimer in the documentation and/or other materials provided
+ *   with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ *   names of its contributors may be used to endorse or promote
+ *   products derived from this software without specific prior
+ *   written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.eclipse.jgit.lib;
+
+import static java.nio.charset.StandardCharsets.US_ASCII;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.fail;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.text.MessageFormat;
+
+import org.eclipse.jgit.internal.JGitText;
+import org.junit.Test;
+
+public class CommitBuilderTest {
+
+	private void assertGpgSignatureStringOutcome(String signature,
+			String expectedOutcome) throws IOException {
+		ByteArrayOutputStream out = new ByteArrayOutputStream();
+		CommitBuilder.writeGpgSignatureString(signature, out);
+		String formatted_signature = new String(out.toByteArray(), US_ASCII);
+		assertEquals(expectedOutcome, formatted_signature);
+	}
+
+	@Test
+	public void writeGpgSignatureString_1() throws Exception {
+		// @formatter:off
+		String signature = "-----BEGIN PGP SIGNATURE-----\n" +
+				"Version: BCPG v1.60\n" +
+				"\n" +
+				"iQEcBAABCAAGBQJb9cVhAAoJEKX+6Axg/6TZeFsH/0CY0WX/z7U8+7S5giFX4wH4\n" +
+				"opvBwqyt6OX8lgNwTwBGHFNt8LdmDCCmKoq/XwkNi3ARVjLhe3gBcKXNoavvPk2Z\n" +
+				"gIg5ChevGkU4afWCOMLVEYnkCBGw2+86XhrK1P7gTHEk1Rd+Yv1ZRDJBY+fFO7yz\n" +
+				"uSBuF5RpEY2sJiIvp27Gub/rY3B5NTR/feO/z+b9oiP/fMUhpRwG5KuWUsn9NPjw\n" +
+				"3tvbgawYpU/2UnS+xnavMY4t2fjRYjsoxndPLb2MUX8X7vC7FgWLBlmI/rquLZVM\n" +
+				"IQEKkjnA+lhejjK1rv+ulq4kGZJFKGYWYYhRDwFg5PTkzhudhN2SGUq5Wxq1Eg4=\n" +
+				"=b9OI\n" +
+				"-----END PGP SIGNATURE-----";
+		String expectedOutcome = "-----BEGIN PGP SIGNATURE-----\n" +
+				" Version: BCPG v1.60\n" +
+				" \n" +
+				" iQEcBAABCAAGBQJb9cVhAAoJEKX+6Axg/6TZeFsH/0CY0WX/z7U8+7S5giFX4wH4\n" +
+				" opvBwqyt6OX8lgNwTwBGHFNt8LdmDCCmKoq/XwkNi3ARVjLhe3gBcKXNoavvPk2Z\n" +
+				" gIg5ChevGkU4afWCOMLVEYnkCBGw2+86XhrK1P7gTHEk1Rd+Yv1ZRDJBY+fFO7yz\n" +
+				" uSBuF5RpEY2sJiIvp27Gub/rY3B5NTR/feO/z+b9oiP/fMUhpRwG5KuWUsn9NPjw\n" +
+				" 3tvbgawYpU/2UnS+xnavMY4t2fjRYjsoxndPLb2MUX8X7vC7FgWLBlmI/rquLZVM\n" +
+				" IQEKkjnA+lhejjK1rv+ulq4kGZJFKGYWYYhRDwFg5PTkzhudhN2SGUq5Wxq1Eg4=\n" +
+				" =b9OI\n" +
+				" -----END PGP SIGNATURE-----";
+		// @formatter:on
+		assertGpgSignatureStringOutcome(signature, expectedOutcome);
+	}
+
+	@Test
+	public void writeGpgSignatureString_failsForNonAscii() throws Exception {
+		String signature = "Ü Ä";
+		try {
+			CommitBuilder.writeGpgSignatureString(signature,
+					new ByteArrayOutputStream());
+			fail("Exception expected");
+		} catch (IllegalArgumentException e) {
+			// good
+			String message = MessageFormat.format(JGitText.get().notASCIIString,
+					signature);
+			assertEquals(message, e.getMessage());
+		}
+	}
+
+	@Test
+	public void writeGpgSignatureString_oneLineNotModified() throws Exception {
+		String signature = "    A string   ";
+		String expectedOutcome = signature;
+		assertGpgSignatureStringOutcome(signature, expectedOutcome);
+	}
+
+	@Test
+	public void writeGpgSignatureString_preservesRandomWhitespace()
+			throws Exception {
+		// @formatter:off
+		String signature = "    String with    \n"
+				+ "Line 2\n"
+				+ " Line 3\n"
+				+ "Line 4   \n"
+				+ "  Line 5  ";
+		String expectedOutcome = "    String with    \n"
+				+ " Line 2\n"
+				+ "  Line 3\n"
+				+ " Line 4   \n"
+				+ "   Line 5  ";
+		// @formatter:on
+		assertGpgSignatureStringOutcome(signature, expectedOutcome);
+	}
+
+	@Test
+	public void writeGpgSignatureString_replaceCR() throws Exception {
+		// @formatter:off
+		String signature = "String with \r"
+				+ "Line 2\r"
+				+ "Line 3\r"
+				+ "Line 4\r"
+				+ "Line 5";
+		String expectedOutcome = "String with \n"
+				+ " Line 2\n"
+				+ " Line 3\n"
+				+ " Line 4\n"
+				+ " Line 5";
+		// @formatter:on
+		assertGpgSignatureStringOutcome(signature, expectedOutcome);
+	}
+
+	@Test
+	public void writeGpgSignatureString_replaceCRLF() throws Exception {
+		// @formatter:off
+		String signature = "String with \r\n"
+				+ "Line 2\r\n"
+				+ "Line 3\r\n"
+				+ "Line 4\r\n"
+				+ "Line 5";
+		String expectedOutcome = "String with \n"
+				+ " Line 2\n"
+				+ " Line 3\n"
+				+ " Line 4\n"
+				+ " Line 5";
+		// @formatter:on
+		assertGpgSignatureStringOutcome(signature, expectedOutcome);
+	}
+
+	@Test
+	public void writeGpgSignatureString_replaceCRLFMixed() throws Exception {
+		// @formatter:off
+		String signature = "String with \r"
+				+ "Line 2\r\n"
+				+ "Line 3\r"
+				+ "Line 4\r\n"
+				+ "Line 5";
+		String expectedOutcome = "String with \n"
+				+ " Line 2\n"
+				+ " Line 3\n"
+				+ " Line 4\n"
+				+ " Line 5";
+		// @formatter:on
+		assertGpgSignatureStringOutcome(signature, expectedOutcome);
+	}
+
+	@Test
+	public void setGpgSignature() throws Exception {
+		GpgSignature dummy = new GpgSignature(new byte[0]);
+
+		CommitBuilder builder = new CommitBuilder();
+		assertNull(builder.getGpgSignature());
+
+		builder.setGpgSignature(dummy);
+		assertSame(dummy, builder.getGpgSignature());
+
+		builder.setGpgSignature(null);
+		assertNull(builder.getGpgSignature());
+	}
+}
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 534b323..483051c 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
@@ -267,10 +267,10 @@ public void testResetHardFromIndexEntryWithoutFileToTreeWithoutFile()
 	public void testInitialCheckout() throws Exception {
 		ChangeRecorder recorder = new ChangeRecorder();
 		ListenerHandle handle = null;
-		try (Git git = new Git(db)) {
+		try (Git git = new Git(db);
+				TestRepository<Repository> db_t = new TestRepository<>(db)) {
 			handle = db.getListenerList()
 					.addWorkingTreeModifiedListener(recorder);
-			TestRepository<Repository> db_t = new TestRepository<>(db);
 			BranchBuilder master = db_t.branch("master");
 			master.commit().add("f", "1").message("m0").create();
 			assertFalse(new File(db.getWorkTree(), "f").exists());
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ObjectIdRefTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ObjectIdRefTest.java
index fb16c6b..6553bfa 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ObjectIdRefTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ObjectIdRefTest.java
@@ -48,6 +48,10 @@
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertSame;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.util.Arrays;
+import java.util.List;
 
 import org.junit.Test;
 
@@ -115,10 +119,43 @@ public void testConstructor_Peeled() {
 	}
 
 	@Test
+	public void testUpdateIndex() {
+		ObjectIdRef r;
+
+		r = new ObjectIdRef.Unpeeled(Ref.Storage.LOOSE, name, ID_A, 3);
+		assertTrue(r.getUpdateIndex() == 3);
+
+		r = new ObjectIdRef.PeeledTag(Ref.Storage.LOOSE, name, ID_A, ID_B, 4);
+		assertTrue(r.getUpdateIndex() == 4);
+
+		r = new ObjectIdRef.PeeledNonTag(Ref.Storage.LOOSE, name, ID_A, 5);
+		assertTrue(r.getUpdateIndex() == 5);
+	}
+
+	@Test
+	public void testUpdateIndexNotSet() {
+		List<ObjectIdRef> r = Arrays.asList(
+				new ObjectIdRef.Unpeeled(Ref.Storage.LOOSE, name, ID_A),
+				new ObjectIdRef.PeeledTag(Ref.Storage.LOOSE, name, ID_A, ID_B),
+				new ObjectIdRef.PeeledNonTag(Ref.Storage.LOOSE, name, ID_A));
+
+		for (ObjectIdRef ref : r) {
+			try {
+				ref.getUpdateIndex();
+				fail("Update index wasn't set. It must throw");
+			} catch (UnsupportedOperationException u) {
+				// Ok
+			}
+		}
+	}
+
+
+	@Test
 	public void testToString() {
 		ObjectIdRef r;
 
 		r = new ObjectIdRef.Unpeeled(Ref.Storage.LOOSE, name, ID_A);
-		assertEquals("Ref[" + name + "=" + ID_A.name() + "]", r.toString());
+		assertEquals("Ref[" + name + "=" + ID_A.name() + "(-1)]",
+				r.toString());
 	}
 }
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RefDatabaseConflictingNamesTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RefDatabaseConflictingNamesTest.java
index 1c21194..cbb47fa 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RefDatabaseConflictingNamesTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RefDatabaseConflictingNamesTest.java
@@ -95,7 +95,7 @@ public boolean isNameConflicting(String name) throws IOException {
 		}
 
 		@Override
-		public Ref getRef(String name) throws IOException {
+		public Ref exactRef(String name) throws IOException {
 			return null;
 		}
 
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 58b005c..15c4e4a 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
@@ -110,7 +110,7 @@ public void testFileKeyOpenExisting() throws IOException {
 	@Test
 	public void testFileKeyOpenNew() throws IOException {
 		File gitdir;
-		try (Repository n = createRepository(true, false)) {
+		try (Repository n = createRepository(true)) {
 			gitdir = n.getDirectory();
 		}
 		recursiveDelete(gitdir);
@@ -192,7 +192,7 @@ public void testRepositoryUsageCount() throws Exception {
 	@Test
 	public void testRepositoryUsageCountWithRegisteredRepository()
 			throws IOException {
-		@SuppressWarnings("resource") // We are testing the close() method
+		@SuppressWarnings({"resource", "deprecation"}) // We are testing the close() method
 		Repository repo = createRepository(false, false);
 		assertEquals(1, repo.useCnt.get());
 		RepositoryCache.register(repo);
@@ -240,9 +240,9 @@ public void testRepositoryUnregisteringWhenExpiredAndUsageCountNegative()
 
 	@Test
 	public void testRepositoryUnregisteringWhenExpired() throws Exception {
-		@SuppressWarnings("resource") // We are testing the close() method
+		@SuppressWarnings({"resource", "deprecation"}) // We are testing the close() method
 		Repository repoA = createRepository(true, false);
-		@SuppressWarnings("resource") // We are testing the close() method
+		@SuppressWarnings({"resource", "deprecation"}) // We are testing the close() method
 		Repository repoB = createRepository(true, false);
 		Repository repoC = createBareRepository();
 		RepositoryCache.register(repoA);
@@ -276,7 +276,7 @@ public void testRepositoryUnregisteringWhenExpired() throws Exception {
 
 	@Test
 	public void testReconfigure() throws InterruptedException, IOException {
-		@SuppressWarnings("resource") // We are testing the close() method
+		@SuppressWarnings({"resource", "deprecation"}) // 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/SymbolicRefTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/SymbolicRefTest.java
index 1342253..99b2211 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/SymbolicRefTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/SymbolicRefTest.java
@@ -68,7 +68,7 @@ public void testConstructor() {
 		SymbolicRef r;
 
 		t = new ObjectIdRef.Unpeeled(Ref.Storage.NEW, targetName, null);
-		r = new SymbolicRef(name, t);
+		r = new SymbolicRef(name, t, 1);
 		assertSame(Ref.Storage.LOOSE, r.getStorage());
 		assertSame(name, r.getName());
 		assertNull("no id on new ref", r.getObjectId());
@@ -77,9 +77,10 @@ public void testConstructor() {
 		assertSame("leaf is t", t, r.getLeaf());
 		assertSame("target is t", t, r.getTarget());
 		assertTrue("is symbolic", r.isSymbolic());
+		assertTrue("holds update index", r.getUpdateIndex() == 1);
 
 		t = new ObjectIdRef.Unpeeled(Ref.Storage.PACKED, targetName, ID_A);
-		r = new SymbolicRef(name, t);
+		r = new SymbolicRef(name, t, 2);
 		assertSame(Ref.Storage.LOOSE, r.getStorage());
 		assertSame(name, r.getName());
 		assertSame(ID_A, r.getObjectId());
@@ -88,6 +89,7 @@ public void testConstructor() {
 		assertSame("leaf is t", t, r.getLeaf());
 		assertSame("target is t", t, r.getTarget());
 		assertTrue("is symbolic", r.isSymbolic());
+		assertTrue("holds update index", r.getUpdateIndex() == 2);
 	}
 
 	@Test
@@ -133,6 +135,6 @@ public void testToString() {
 		d = new SymbolicRef("D", c);
 
 		assertEquals("SymbolicRef[D -> C -> B -> " + targetName + "="
-				+ ID_A.name() + "]", d.toString());
+				+ ID_A.name() + "(-1)]", d.toString());
 	}
 }
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/MergerTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/MergerTest.java
index fa02227..2ae9c11 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/MergerTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/MergerTest.java
@@ -1071,7 +1071,7 @@ public void checkLockedFilesToBeDeleted(MergeStrategy strategy)
 		git.add().addFilepattern("c.txt").call();
 		git.commit().setMessage("added c.txt").call();
 
-		// Get a handle to the the file so on windows it can't be deleted.
+		// Get a handle to the file so on windows it can't be deleted.
 		try (FileInputStream fis = new FileInputStream(
 				new File(db.getWorkTree(), "b.txt"))) {
 			MergeResult mergeRes = git.merge().setStrategy(strategy)
@@ -1365,14 +1365,15 @@ private void checkModificationTimeStampOrder(String... pathes) {
 	}
 
 	private String readBlob(ObjectId treeish, String path) throws Exception {
-		TestRepository<?> tr = new TestRepository<>(db);
-		RevWalk rw = tr.getRevWalk();
-		RevTree tree = rw.parseTree(treeish);
-		RevObject obj = tr.get(tree, path);
-		if (obj == null) {
-			return null;
+		try (TestRepository<?> tr = new TestRepository<>(db)) {
+			RevWalk rw = tr.getRevWalk();
+			RevTree tree = rw.parseTree(treeish);
+			RevObject obj = tr.get(tree, path);
+			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(),
-				UTF_8);
 	}
 }
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleStatusTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleStatusTest.java
index 5832518..9151b04 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleStatusTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleStatusTest.java
@@ -263,8 +263,10 @@ public void repositoryWithInitializedSubmodule() throws Exception {
 				.getRepository();
 		assertNotNull(subRepo);
 
-		TestRepository<?> subTr = new TestRepository<>(subRepo);
-		ObjectId id = subTr.branch(Constants.HEAD).commit().create().copy();
+		ObjectId id;
+		try (TestRepository<?> subTr = new TestRepository<>(subRepo)) {
+			id = subTr.branch(Constants.HEAD).commit().create().copy();
+		}
 
 		DirCache cache = db.lockDirCache();
 		DirCacheEditor editor = cache.editor();
@@ -315,50 +317,52 @@ public void repositoryWithDifferentRevCheckedOutSubmodule() throws Exception {
 				.getRepository();
 		assertNotNull(subRepo);
 
-		TestRepository<?> subTr = new TestRepository<>(subRepo);
-		ObjectId id = subTr.branch(Constants.HEAD).commit().create().copy();
+		try (TestRepository<?> subTr = new TestRepository<>(subRepo)) {
+			ObjectId id = subTr.branch(Constants.HEAD).commit().create().copy();
+			DirCache cache = db.lockDirCache();
+			DirCacheEditor editor = cache.editor();
+			editor.add(new PathEdit(path) {
 
-		DirCache cache = db.lockDirCache();
-		DirCacheEditor editor = cache.editor();
-		editor.add(new PathEdit(path) {
+				@Override
+				public void apply(DirCacheEntry ent) {
+					ent.setFileMode(FileMode.GITLINK);
+					ent.setObjectId(id);
+				}
+			});
+			editor.commit();
 
-			@Override
-			public void apply(DirCacheEntry ent) {
-				ent.setFileMode(FileMode.GITLINK);
-				ent.setObjectId(id);
-			}
-		});
-		editor.commit();
+			String url = "git://server/repo.git";
+			StoredConfig config = db.getConfig();
+			config.setString(ConfigConstants.CONFIG_SUBMODULE_SECTION, path,
+					ConfigConstants.CONFIG_KEY_URL, url);
+			config.save();
 
-		String url = "git://server/repo.git";
-		StoredConfig config = db.getConfig();
-		config.setString(ConfigConstants.CONFIG_SUBMODULE_SECTION, path,
-				ConfigConstants.CONFIG_KEY_URL, url);
-		config.save();
+			FileBasedConfig modulesConfig = new FileBasedConfig(
+					new File(db.getWorkTree(), Constants.DOT_GIT_MODULES),
+					db.getFS());
+			modulesConfig.setString(ConfigConstants.CONFIG_SUBMODULE_SECTION,
+					path, ConfigConstants.CONFIG_KEY_PATH, path);
+			modulesConfig.setString(ConfigConstants.CONFIG_SUBMODULE_SECTION,
+					path, ConfigConstants.CONFIG_KEY_URL, url);
+			modulesConfig.save();
 
-		FileBasedConfig modulesConfig = new FileBasedConfig(new File(
-				db.getWorkTree(), Constants.DOT_GIT_MODULES), db.getFS());
-		modulesConfig.setString(ConfigConstants.CONFIG_SUBMODULE_SECTION, path,
-				ConfigConstants.CONFIG_KEY_PATH, path);
-		modulesConfig.setString(ConfigConstants.CONFIG_SUBMODULE_SECTION, path,
-				ConfigConstants.CONFIG_KEY_URL, url);
-		modulesConfig.save();
+			ObjectId newId = subTr.branch(Constants.HEAD).commit().create()
+					.copy();
 
-		ObjectId newId = subTr.branch(Constants.HEAD).commit().create().copy();
-
-		SubmoduleStatusCommand command = new SubmoduleStatusCommand(db);
-		Map<String, SubmoduleStatus> statuses = command.call();
-		assertNotNull(statuses);
-		assertEquals(1, statuses.size());
-		Entry<String, SubmoduleStatus> module = statuses.entrySet().iterator()
-				.next();
-		assertNotNull(module);
-		assertEquals(path, module.getKey());
-		SubmoduleStatus status = module.getValue();
-		assertNotNull(status);
-		assertEquals(path, status.getPath());
-		assertEquals(id, status.getIndexId());
-		assertEquals(newId, status.getHeadId());
-		assertEquals(SubmoduleStatusType.REV_CHECKED_OUT, status.getType());
+			SubmoduleStatusCommand command = new SubmoduleStatusCommand(db);
+			Map<String, SubmoduleStatus> statuses = command.call();
+			assertNotNull(statuses);
+			assertEquals(1, statuses.size());
+			Entry<String, SubmoduleStatus> module = statuses.entrySet()
+					.iterator().next();
+			assertNotNull(module);
+			assertEquals(path, module.getKey());
+			SubmoduleStatus status = module.getValue();
+			assertNotNull(status);
+			assertEquals(path, status.getPath());
+			assertEquals(id, status.getIndexId());
+			assertEquals(newId, status.getHeadId());
+			assertEquals(SubmoduleStatusType.REV_CHECKED_OUT, status.getType());
+		}
 	}
 }
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleWalkTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleWalkTest.java
index a0cd37e..ea1ace3 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleWalkTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleWalkTest.java
@@ -145,7 +145,6 @@ public void apply(DirCacheEntry ent) {
 		assertFalse(gen.next());
 	}
 
-	@SuppressWarnings("resource" /* java 7 */)
 	@Test
 	public void repositoryWithRootLevelSubmoduleAbsoluteRef()
 			throws IOException, ConfigInvalidException {
@@ -189,17 +188,16 @@ public void apply(DirCacheEntry ent) {
 		assertNull(gen.getModulesPath());
 		assertNull(gen.getModulesUpdate());
 		assertNull(gen.getModulesUrl());
-		Repository subRepo = gen.getRepository();
-		assertNotNull(subRepo);
-		assertEquals(modulesGitDir.getAbsolutePath(),
-				subRepo.getDirectory().getAbsolutePath());
-		assertEquals(new File(db.getWorkTree(), path).getAbsolutePath(),
-				subRepo.getWorkTree().getAbsolutePath());
-		subRepo.close();
+		try (Repository subRepo = gen.getRepository()) {
+			assertNotNull(subRepo);
+			assertEquals(modulesGitDir.getAbsolutePath(),
+					subRepo.getDirectory().getAbsolutePath());
+			assertEquals(new File(db.getWorkTree(), path).getAbsolutePath(),
+					subRepo.getWorkTree().getAbsolutePath());
+		}
 		assertFalse(gen.next());
 	}
 
-	@SuppressWarnings("resource" /* java 7 */)
 	@Test
 	public void repositoryWithRootLevelSubmoduleRelativeRef()
 			throws IOException, ConfigInvalidException {
@@ -244,13 +242,14 @@ public void apply(DirCacheEntry ent) {
 		assertNull(gen.getModulesPath());
 		assertNull(gen.getModulesUpdate());
 		assertNull(gen.getModulesUrl());
-		Repository subRepo = gen.getRepository();
-		assertNotNull(subRepo);
-		assertEqualsFile(modulesGitDir, subRepo.getDirectory());
-		assertEqualsFile(new File(db.getWorkTree(), path),
-				subRepo.getWorkTree());
-		subRepo.close();
-		assertFalse(gen.next());
+		try (Repository subRepo = gen.getRepository()) {
+			assertNotNull(subRepo);
+			assertEqualsFile(modulesGitDir, subRepo.getDirectory());
+			assertEqualsFile(new File(db.getWorkTree(), path),
+					subRepo.getWorkTree());
+			subRepo.close();
+			assertFalse(gen.next());
+		}
 	}
 
 	@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 7b31bfa..dce9db5 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
@@ -77,10 +77,38 @@
 import org.eclipse.jgit.revwalk.RevCommit;
 import org.eclipse.jgit.revwalk.RevWalk;
 import org.eclipse.jgit.test.resources.SampleDataRepositoryTestCase;
+import org.junit.Rule;
 import org.junit.Test;
+import org.junit.rules.ExpectedException;
 
 public class BundleWriterTest extends SampleDataRepositoryTestCase {
 
+	@Rule
+	public ExpectedException thrown = ExpectedException.none();
+
+	@Test
+	public void testEmptyBundleFails() throws Exception {
+		Repository newRepo = createBareRepository();
+		thrown.expect(TransportException.class);
+		fetchFromBundle(newRepo, new byte[0]);
+	}
+
+	@Test
+	public void testNonBundleFails() throws Exception {
+		Repository newRepo = createBareRepository();
+		thrown.expect(TransportException.class);
+		fetchFromBundle(newRepo, "Not a bundle file".getBytes(UTF_8));
+	}
+
+	@Test
+	public void testGarbageBundleFails() throws Exception {
+		Repository newRepo = createBareRepository();
+		thrown.expect(TransportException.class);
+		fetchFromBundle(newRepo,
+				(TransportBundle.V2_BUNDLE_SIGNATURE + '\n' + "Garbage")
+						.getBytes(UTF_8));
+	}
+
 	@Test
 	public void testWriteSingleRef() throws Exception {
 		// Create a tiny bundle, (well one of) the first commits only
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/JschConfigSessionFactoryTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/JschConfigSessionFactoryTest.java
index 1e65a20..3de4210 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/JschConfigSessionFactoryTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/JschConfigSessionFactoryTest.java
@@ -49,8 +49,11 @@
 import java.util.Arrays;
 import java.util.concurrent.TimeUnit;
 
+import org.eclipse.jgit.junit.MockSystemReader;
 import org.eclipse.jgit.util.FS;
+import org.eclipse.jgit.util.SystemReader;
 import org.junit.After;
+import org.junit.Before;
 import org.junit.Test;
 
 import com.jcraft.jsch.Session;
@@ -67,8 +70,14 @@ public class JschConfigSessionFactoryTest {
 
 	DefaultSshSessionFactory factory = new DefaultSshSessionFactory();
 
+	@Before
+	public void setup() {
+		SystemReader.setInstance(new MockSystemReader());
+	}
+
 	@After
 	public void removeTmpConfig() {
+		SystemReader.setInstance(null);
 		if (tmpConfigFile == null) {
 			return;
 		}
@@ -87,7 +96,8 @@ public void testNoConfigEntry() throws Exception {
 		Session session = createSession("ssh://egit/egit/egit");
 		assertEquals("egit", session.getHost());
 		// No user in URI, none in ssh config: default is OS user name
-		assertEquals(System.getProperty("user.name"), session.getUserName());
+		assertEquals(SystemReader.getInstance().getProperty("user.name"),
+				session.getUserName());
 		assertEquals(22, session.getPort());
 	}
 
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 b6d0611..fd952f3 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
@@ -141,8 +141,10 @@ public void test2() throws  IOException {
 
 	@Test
 	public void testTinyThinPack() throws Exception {
-		TestRepository d = new TestRepository<Repository>(db);
-		RevBlob a = d.blob("a");
+		RevBlob a;
+		try (TestRepository d = new TestRepository<Repository>(db)) {
+			a = d.blob("a");
+		}
 
 		TemporaryBuffer.Heap pack = new TemporaryBuffer.Heap(1024);
 
@@ -162,8 +164,9 @@ public void testTinyThinPack() throws Exception {
 	@Test
 	public void testPackWithDuplicateBlob() throws Exception {
 		final byte[] data = Constants.encode("0123456789abcdefg");
-		TestRepository<Repository> d = new TestRepository<>(db);
-		assertTrue(db.hasObject(d.blob(data)));
+		try (TestRepository<Repository> d = new TestRepository<>(db)) {
+			assertTrue(db.getObjectDatabase().has(d.blob(data)));
+		}
 
 		TemporaryBuffer.Heap pack = new TemporaryBuffer.Heap(1024);
 		packHeader(pack, 1);
@@ -179,8 +182,10 @@ public void testPackWithDuplicateBlob() throws Exception {
 
 	@Test
 	public void testPackWithTrailingGarbage() throws Exception {
-		TestRepository d = new TestRepository<Repository>(db);
-		RevBlob a = d.blob("a");
+		RevBlob a;
+		try (TestRepository d = new TestRepository<Repository>(db)) {
+			a = d.blob("a");
+		}
 
 		TemporaryBuffer.Heap pack = new TemporaryBuffer.Heap(1024);
 		packHeader(pack, 1);
@@ -206,9 +211,10 @@ public void testPackWithTrailingGarbage() throws Exception {
 
 	@Test
 	public void testMaxObjectSizeFullBlob() throws Exception {
-		TestRepository d = new TestRepository<Repository>(db);
 		final byte[] data = Constants.encode("0123456789");
-		d.blob(data);
+		try (TestRepository d = new TestRepository<Repository>(db)) {
+			d.blob(data);
+		}
 
 		TemporaryBuffer.Heap pack = new TemporaryBuffer.Heap(1024);
 
@@ -238,8 +244,10 @@ public void testMaxObjectSizeFullBlob() throws Exception {
 
 	@Test
 	public void testMaxObjectSizeDeltaBlock() throws Exception {
-		TestRepository d = new TestRepository<Repository>(db);
-		RevBlob a = d.blob("a");
+		RevBlob a;
+		try (TestRepository d = new TestRepository<Repository>(db)) {
+			a = d.blob("a");
+		}
 
 		TemporaryBuffer.Heap pack = new TemporaryBuffer.Heap(1024);
 
@@ -269,8 +277,10 @@ public void testMaxObjectSizeDeltaBlock() throws Exception {
 
 	@Test
 	public void testMaxObjectSizeDeltaResultSize() throws Exception {
-		TestRepository d = new TestRepository<Repository>(db);
-		RevBlob a = d.blob("0123456789");
+		RevBlob a;
+		try (TestRepository d = new TestRepository<Repository>(db)) {
+			a = d.blob("0123456789");
+		}
 
 		TemporaryBuffer.Heap pack = new TemporaryBuffer.Heap(1024);
 
@@ -299,8 +309,10 @@ public void testMaxObjectSizeDeltaResultSize() throws Exception {
 
 	@Test
 	public void testNonMarkingInputStream() throws Exception {
-		TestRepository d = new TestRepository<Repository>(db);
-		RevBlob a = d.blob("a");
+		RevBlob a;
+		try (TestRepository d = new TestRepository<Repository>(db)) {
+			a = d.blob("a");
+		}
 
 		TemporaryBuffer.Heap pack = new TemporaryBuffer.Heap(1024);
 		packHeader(pack, 1);
@@ -337,8 +349,10 @@ public void mark(int maxlength) {
 
 	@Test
 	public void testDataAfterPackFooterSingleRead() throws Exception {
-		TestRepository d = new TestRepository<Repository>(db);
-		RevBlob a = d.blob("a");
+		RevBlob a;
+		try (TestRepository d = new TestRepository<Repository>(db)) {
+			a = d.blob("a");
+		}
 
 		TemporaryBuffer.Heap pack = new TemporaryBuffer.Heap(32*1024);
 		packHeader(pack, 1);
@@ -395,9 +409,11 @@ public void testDataAfterPackFooterSplitObjectRead() throws Exception {
 
 	@Test
 	public void testDataAfterPackFooterSplitHeaderRead() throws Exception {
-		TestRepository d = new TestRepository<Repository>(db);
 		final byte[] data = Constants.encode("a");
-		RevBlob b = d.blob(data);
+		RevBlob b;
+		try (TestRepository d = new TestRepository<Repository>(db)) {
+			b = d.blob(data);
+		}
 
 		int objects = 248;
 		TemporaryBuffer.Heap pack = new TemporaryBuffer.Heap(32 * 1024);
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 63478f6..cea432e 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
@@ -216,15 +216,16 @@ public void limitCommandBytes() throws IOException {
 
 	@Test
 	public void commandOrder() throws Exception {
-		TestRepository<?> tr = new TestRepository<>(client);
 		List<RemoteRefUpdate> updates = new ArrayList<>();
-		// Arbitrary non-sorted order.
-		for (int i = 9; i >= 0; i--) {
-			String name = "refs/heads/b" + i;
-			tr.branch(name).commit().create();
-			RemoteRefUpdate rru = new RemoteRefUpdate(client, name, name, false, null,
-					ObjectId.zeroId());
-			updates.add(rru);
+		try (TestRepository<?> tr = new TestRepository<>(client)) {
+			// 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;
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 dfa50b6..50c8a29 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
@@ -110,24 +110,26 @@ public void setUp() throws Exception {
 
 		// Fill dst with a some common history.
 		//
-		TestRepository<Repository> d = new TestRepository<>(dst);
-		a = d.blob("a");
-		A = d.commit(d.tree(d.file("a", a)));
-		B = d.commit().parent(A).create();
-		d.update(R_MASTER, B);
+		try (TestRepository<Repository> d = new TestRepository<>(dst)) {
+			a = d.blob("a");
+			A = d.commit(d.tree(d.file("a", a)));
+			B = d.commit().parent(A).create();
+			d.update(R_MASTER, B);
 
-		// Clone from dst into src
-		//
-		try (Transport t = Transport.open(src, uriOf(dst))) {
-			t.fetch(PM, Collections.singleton(new RefSpec("+refs/*:refs/*")));
-			assertEquals(B, src.resolve(R_MASTER));
+			// Clone from dst into src
+			//
+			try (Transport t = Transport.open(src, uriOf(dst))) {
+				t.fetch(PM,
+						Collections.singleton(new RefSpec("+refs/*:refs/*")));
+				assertEquals(B, src.resolve(R_MASTER));
+			}
+
+			// Now put private stuff into dst.
+			//
+			b = d.blob("b");
+			P = d.commit(d.tree(d.file("b", b)), A);
+			d.update(R_PRIVATE, P);
 		}
-
-		// Now put private stuff into dst.
-		//
-		b = d.blob("b");
-		P = d.commit(d.tree(d.file("b", b)), A);
-		d.update(R_PRIVATE, P);
 	}
 
 	@Test
@@ -236,36 +238,38 @@ public void testSuccess() throws Exception {
 		// Verify the only storage of b is our packed delta above.
 		//
 		ObjectDirectory od = (ObjectDirectory) src.getObjectDatabase();
-		assertTrue("has b", src.hasObject(b));
+		assertTrue("has b", od.has(b));
 		assertFalse("b not loose", od.fileFor(b).exists());
 
 		// Now use b but in a different commit than what is hidden.
 		//
-		TestRepository<Repository> s = new TestRepository<>(src);
-		RevCommit N = s.commit().parent(B).add("q", b).create();
-		s.update(R_MASTER, N);
+		try (TestRepository<Repository> s = new TestRepository<>(src)) {
+			RevCommit N = s.commit().parent(B).add("q", b).create();
+			s.update(R_MASTER, N);
 
-		// Push this new content to the remote, doing strict validation.
-		//
-		PushResult r;
-		RemoteRefUpdate u = new RemoteRefUpdate( //
-				src, //
-				R_MASTER, // src name
-				R_MASTER, // dst name
-				false, // do not force update
-				null, // local tracking branch
-				null // expected id
-		);
-		try (TransportLocal t = newTransportLocalWithStrictValidation()) {
-			t.setPushThin(true);
-			r = t.push(PM, Collections.singleton(u));
-			dst.close();
+			// Push this new content to the remote, doing strict validation.
+			//
+			PushResult r;
+			RemoteRefUpdate u = new RemoteRefUpdate( //
+					src, //
+					R_MASTER, // src name
+					R_MASTER, // dst name
+					false, // do not force update
+					null, // local tracking branch
+					null // expected id
+			);
+			try (TransportLocal t = newTransportLocalWithStrictValidation()) {
+				t.setPushThin(true);
+				r = t.push(PM, Collections.singleton(u));
+				dst.close();
+			}
+
+			assertNotNull("have result", r);
+			assertNull("private not advertised", r.getAdvertisedRef(R_PRIVATE));
+			assertSame("master updated", RemoteRefUpdate.Status.OK,
+					u.getStatus());
+			assertEquals(N, dst.resolve(R_MASTER));
 		}
-
-		assertNotNull("have result", r);
-		assertNull("private not advertised", r.getAdvertisedRef(R_PRIVATE));
-		assertSame("master updated", RemoteRefUpdate.Status.OK, u.getStatus());
-		assertEquals(N, dst.resolve(R_MASTER));
 	}
 
 	@Test
@@ -318,154 +322,165 @@ private static void receive(final ReceivePack rp,
 	@Test
 	public void testUsingHiddenDeltaBaseFails() throws Exception {
 		byte[] delta = { 0x1, 0x1, 0x1, 'c' };
-		TestRepository<Repository> s = new TestRepository<>(src);
-		RevCommit N = s.commit().parent(B).add("q",
-				s.blob(BinaryDelta.apply(dst.open(b).getCachedBytes(), delta)))
-				.create();
+		try (TestRepository<Repository> s = new TestRepository<>(src)) {
+			RevCommit N = s.commit().parent(B)
+					.add("q",
+							s.blob(BinaryDelta.apply(
+									dst.open(b).getCachedBytes(), delta)))
+					.create();
 
-		final TemporaryBuffer.Heap pack = new TemporaryBuffer.Heap(1024);
-		packHeader(pack, 3);
-		copy(pack, src.open(N));
-		copy(pack, src.open(s.parseBody(N).getTree()));
-		pack.write((Constants.OBJ_REF_DELTA) << 4 | 4);
-		b.copyRawTo(pack);
-		deflate(pack, delta);
-		digest(pack);
+			final TemporaryBuffer.Heap pack = new TemporaryBuffer.Heap(1024);
+			packHeader(pack, 3);
+			copy(pack, src.open(N));
+			copy(pack, src.open(s.parseBody(N).getTree()));
+			pack.write((Constants.OBJ_REF_DELTA) << 4 | 4);
+			b.copyRawTo(pack);
+			deflate(pack, delta);
+			digest(pack);
 
-		final TemporaryBuffer.Heap inBuf = new TemporaryBuffer.Heap(1024);
-		final PacketLineOut inPckLine = new PacketLineOut(inBuf);
-		inPckLine.writeString(ObjectId.zeroId().name() + ' ' + N.name() + ' '
-				+ "refs/heads/s" + '\0'
-				+ BasePackPushConnection.CAPABILITY_REPORT_STATUS);
-		inPckLine.end();
-		pack.writeTo(inBuf, PM);
+			final TemporaryBuffer.Heap inBuf = new TemporaryBuffer.Heap(1024);
+			final PacketLineOut inPckLine = new PacketLineOut(inBuf);
+			inPckLine.writeString(ObjectId.zeroId().name() + ' ' + N.name()
+					+ ' ' + "refs/heads/s" + '\0'
+					+ BasePackPushConnection.CAPABILITY_REPORT_STATUS);
+			inPckLine.end();
+			pack.writeTo(inBuf, PM);
 
-		final TemporaryBuffer.Heap outBuf = new TemporaryBuffer.Heap(1024);
-		final ReceivePack rp = new ReceivePack(dst);
-		rp.setCheckReceivedObjects(true);
-		rp.setCheckReferencedObjectsAreReachable(true);
-		rp.setAdvertiseRefsHook(new HidePrivateHook());
-		try {
-			receive(rp, inBuf, outBuf);
-			fail("Expected UnpackException");
-		} catch (UnpackException failed) {
-			Throwable err = failed.getCause();
-			assertTrue(err instanceof MissingObjectException);
-			MissingObjectException moe = (MissingObjectException) err;
-			assertEquals(b, moe.getObjectId());
+			final TemporaryBuffer.Heap outBuf = new TemporaryBuffer.Heap(1024);
+			final ReceivePack rp = new ReceivePack(dst);
+			rp.setCheckReceivedObjects(true);
+			rp.setCheckReferencedObjectsAreReachable(true);
+			rp.setAdvertiseRefsHook(new HidePrivateHook());
+			try {
+				receive(rp, inBuf, outBuf);
+				fail("Expected UnpackException");
+			} catch (UnpackException failed) {
+				Throwable err = failed.getCause();
+				assertTrue(err instanceof MissingObjectException);
+				MissingObjectException moe = (MissingObjectException) err;
+				assertEquals(b, moe.getObjectId());
+			}
+
+			final PacketLineIn r = asPacketLineIn(outBuf);
+			String master = r.readString();
+			int nul = master.indexOf('\0');
+			assertTrue("has capability list", nul > 0);
+			assertEquals(B.name() + ' ' + R_MASTER, master.substring(0, nul));
+			assertSame(PacketLineIn.END, r.readString());
+
+			assertEquals("unpack error Missing blob " + b.name(),
+					r.readString());
+			assertEquals("ng refs/heads/s n/a (unpacker error)",
+					r.readString());
+			assertSame(PacketLineIn.END, r.readString());
 		}
-
-		final PacketLineIn r = asPacketLineIn(outBuf);
-		String master = r.readString();
-		int nul = master.indexOf('\0');
-		assertTrue("has capability list", nul > 0);
-		assertEquals(B.name() + ' ' + R_MASTER, master.substring(0, nul));
-		assertSame(PacketLineIn.END, r.readString());
-
-		assertEquals("unpack error Missing blob " + b.name(), r.readString());
-		assertEquals("ng refs/heads/s n/a (unpacker error)", r.readString());
-		assertSame(PacketLineIn.END, r.readString());
 	}
 
 	@Test
 	public void testUsingHiddenCommonBlobFails() throws Exception {
 		// Try to use the 'b' blob that is hidden.
 		//
-		TestRepository<Repository> s = new TestRepository<>(src);
-		RevCommit N = s.commit().parent(B).add("q", s.blob("b")).create();
+		try (TestRepository<Repository> s = new TestRepository<>(src)) {
+			RevCommit N = s.commit().parent(B).add("q", s.blob("b")).create();
 
-		// But don't include it in the pack.
-		//
-		final TemporaryBuffer.Heap pack = new TemporaryBuffer.Heap(1024);
-		packHeader(pack, 2);
-		copy(pack, src.open(N));
-		copy(pack,src.open(s.parseBody(N).getTree()));
-		digest(pack);
+			// But don't include it in the pack.
+			//
+			final TemporaryBuffer.Heap pack = new TemporaryBuffer.Heap(1024);
+			packHeader(pack, 2);
+			copy(pack, src.open(N));
+			copy(pack, src.open(s.parseBody(N).getTree()));
+			digest(pack);
 
-		final TemporaryBuffer.Heap inBuf = new TemporaryBuffer.Heap(1024);
-		final PacketLineOut inPckLine = new PacketLineOut(inBuf);
-		inPckLine.writeString(ObjectId.zeroId().name() + ' ' + N.name() + ' '
-				+ "refs/heads/s" + '\0'
-				+ BasePackPushConnection.CAPABILITY_REPORT_STATUS);
-		inPckLine.end();
-		pack.writeTo(inBuf, PM);
+			final TemporaryBuffer.Heap inBuf = new TemporaryBuffer.Heap(1024);
+			final PacketLineOut inPckLine = new PacketLineOut(inBuf);
+			inPckLine.writeString(ObjectId.zeroId().name() + ' ' + N.name()
+					+ ' ' + "refs/heads/s" + '\0'
+					+ BasePackPushConnection.CAPABILITY_REPORT_STATUS);
+			inPckLine.end();
+			pack.writeTo(inBuf, PM);
 
-		final TemporaryBuffer.Heap outBuf = new TemporaryBuffer.Heap(1024);
-		final ReceivePack rp = new ReceivePack(dst);
-		rp.setCheckReceivedObjects(true);
-		rp.setCheckReferencedObjectsAreReachable(true);
-		rp.setAdvertiseRefsHook(new HidePrivateHook());
-		try {
-			receive(rp, inBuf, outBuf);
-			fail("Expected UnpackException");
-		} catch (UnpackException failed) {
-			Throwable err = failed.getCause();
-			assertTrue(err instanceof MissingObjectException);
-			MissingObjectException moe = (MissingObjectException) err;
-			assertEquals(b, moe.getObjectId());
+			final TemporaryBuffer.Heap outBuf = new TemporaryBuffer.Heap(1024);
+			final ReceivePack rp = new ReceivePack(dst);
+			rp.setCheckReceivedObjects(true);
+			rp.setCheckReferencedObjectsAreReachable(true);
+			rp.setAdvertiseRefsHook(new HidePrivateHook());
+			try {
+				receive(rp, inBuf, outBuf);
+				fail("Expected UnpackException");
+			} catch (UnpackException failed) {
+				Throwable err = failed.getCause();
+				assertTrue(err instanceof MissingObjectException);
+				MissingObjectException moe = (MissingObjectException) err;
+				assertEquals(b, moe.getObjectId());
+			}
+
+			final PacketLineIn r = asPacketLineIn(outBuf);
+			String master = r.readString();
+			int nul = master.indexOf('\0');
+			assertTrue("has capability list", nul > 0);
+			assertEquals(B.name() + ' ' + R_MASTER, master.substring(0, nul));
+			assertSame(PacketLineIn.END, r.readString());
+
+			assertEquals("unpack error Missing blob " + b.name(),
+					r.readString());
+			assertEquals("ng refs/heads/s n/a (unpacker error)",
+					r.readString());
+			assertSame(PacketLineIn.END, r.readString());
 		}
-
-		final PacketLineIn r = asPacketLineIn(outBuf);
-		String master = r.readString();
-		int nul = master.indexOf('\0');
-		assertTrue("has capability list", nul > 0);
-		assertEquals(B.name() + ' ' + R_MASTER, master.substring(0, nul));
-		assertSame(PacketLineIn.END, r.readString());
-
-		assertEquals("unpack error Missing blob " + b.name(), r.readString());
-		assertEquals("ng refs/heads/s n/a (unpacker error)", r.readString());
-		assertSame(PacketLineIn.END, r.readString());
 	}
 
 	@Test
 	public void testUsingUnknownBlobFails() throws Exception {
 		// Try to use the 'n' blob that is not on the server.
 		//
-		TestRepository<Repository> s = new TestRepository<>(src);
-		RevBlob n = s.blob("n");
-		RevCommit N = s.commit().parent(B).add("q", n).create();
+		try (TestRepository<Repository> s = new TestRepository<>(src)) {
+			RevBlob n = s.blob("n");
+			RevCommit N = s.commit().parent(B).add("q", n).create();
 
-		// But don't include it in the pack.
-		//
-		final TemporaryBuffer.Heap pack = new TemporaryBuffer.Heap(1024);
-		packHeader(pack, 2);
-		copy(pack, src.open(N));
-		copy(pack,src.open(s.parseBody(N).getTree()));
-		digest(pack);
+			// But don't include it in the pack.
+			//
+			final TemporaryBuffer.Heap pack = new TemporaryBuffer.Heap(1024);
+			packHeader(pack, 2);
+			copy(pack, src.open(N));
+			copy(pack, src.open(s.parseBody(N).getTree()));
+			digest(pack);
 
-		final TemporaryBuffer.Heap inBuf = new TemporaryBuffer.Heap(1024);
-		final PacketLineOut inPckLine = new PacketLineOut(inBuf);
-		inPckLine.writeString(ObjectId.zeroId().name() + ' ' + N.name() + ' '
-				+ "refs/heads/s" + '\0'
-				+ BasePackPushConnection.CAPABILITY_REPORT_STATUS);
-		inPckLine.end();
-		pack.writeTo(inBuf, PM);
+			final TemporaryBuffer.Heap inBuf = new TemporaryBuffer.Heap(1024);
+			final PacketLineOut inPckLine = new PacketLineOut(inBuf);
+			inPckLine.writeString(ObjectId.zeroId().name() + ' ' + N.name()
+					+ ' ' + "refs/heads/s" + '\0'
+					+ BasePackPushConnection.CAPABILITY_REPORT_STATUS);
+			inPckLine.end();
+			pack.writeTo(inBuf, PM);
 
-		final TemporaryBuffer.Heap outBuf = new TemporaryBuffer.Heap(1024);
-		final ReceivePack rp = new ReceivePack(dst);
-		rp.setCheckReceivedObjects(true);
-		rp.setCheckReferencedObjectsAreReachable(true);
-		rp.setAdvertiseRefsHook(new HidePrivateHook());
-		try {
-			receive(rp, inBuf, outBuf);
-			fail("Expected UnpackException");
-		} catch (UnpackException failed) {
-			Throwable err = failed.getCause();
-			assertTrue(err instanceof MissingObjectException);
-			MissingObjectException moe = (MissingObjectException) err;
-			assertEquals(n, moe.getObjectId());
+			final TemporaryBuffer.Heap outBuf = new TemporaryBuffer.Heap(1024);
+			final ReceivePack rp = new ReceivePack(dst);
+			rp.setCheckReceivedObjects(true);
+			rp.setCheckReferencedObjectsAreReachable(true);
+			rp.setAdvertiseRefsHook(new HidePrivateHook());
+			try {
+				receive(rp, inBuf, outBuf);
+				fail("Expected UnpackException");
+			} catch (UnpackException failed) {
+				Throwable err = failed.getCause();
+				assertTrue(err instanceof MissingObjectException);
+				MissingObjectException moe = (MissingObjectException) err;
+				assertEquals(n, moe.getObjectId());
+			}
+
+			final PacketLineIn r = asPacketLineIn(outBuf);
+			String master = r.readString();
+			int nul = master.indexOf('\0');
+			assertTrue("has capability list", nul > 0);
+			assertEquals(B.name() + ' ' + R_MASTER, master.substring(0, nul));
+			assertSame(PacketLineIn.END, r.readString());
+
+			assertEquals("unpack error Missing blob " + n.name(),
+					r.readString());
+			assertEquals("ng refs/heads/s n/a (unpacker error)",
+					r.readString());
+			assertSame(PacketLineIn.END, r.readString());
 		}
-
-		final PacketLineIn r = asPacketLineIn(outBuf);
-		String master = r.readString();
-		int nul = master.indexOf('\0');
-		assertTrue("has capability list", nul > 0);
-		assertEquals(B.name() + ' ' + R_MASTER, master.substring(0, nul));
-		assertSame(PacketLineIn.END, r.readString());
-
-		assertEquals("unpack error Missing blob " + n.name(), r.readString());
-		assertEquals("ng refs/heads/s n/a (unpacker error)", r.readString());
-		assertSame(PacketLineIn.END, r.readString());
 	}
 
 	@Test
@@ -509,75 +524,79 @@ private TemporaryBuffer.Heap setupSourceRepoInvalidGitmodules()
 				.append("    url = -upayload.sh\n")
 				.toString();
 
-		TestRepository<Repository> s = new TestRepository<>(src);
-		RevBlob blob = s.blob(fakeGitmodules);
-		RevCommit N = s.commit().parent(B)
-				.add(".gitmodules", blob).create();
-		RevTree t = s.parseBody(N).getTree();
+		try (TestRepository<Repository> s = new TestRepository<>(src)) {
+			RevBlob blob = s.blob(fakeGitmodules);
+			RevCommit N = s.commit().parent(B).add(".gitmodules", blob)
+					.create();
+			RevTree t = s.parseBody(N).getTree();
 
-		final TemporaryBuffer.Heap pack = new TemporaryBuffer.Heap(1024);
-		packHeader(pack, 3);
-		copy(pack, src.open(N));
-		copy(pack, src.open(t));
-		copy(pack, src.open(blob));
-		digest(pack);
+			final TemporaryBuffer.Heap pack = new TemporaryBuffer.Heap(1024);
+			packHeader(pack, 3);
+			copy(pack, src.open(N));
+			copy(pack, src.open(t));
+			copy(pack, src.open(blob));
+			digest(pack);
 
-		final TemporaryBuffer.Heap inBuf = new TemporaryBuffer.Heap(1024);
-		final PacketLineOut inPckLine = new PacketLineOut(inBuf);
-		inPckLine.writeString(ObjectId.zeroId().name() + ' ' + N.name() + ' '
-				+ "refs/heads/s" + '\0'
-				+ BasePackPushConnection.CAPABILITY_REPORT_STATUS);
-		inPckLine.end();
-		pack.writeTo(inBuf, PM);
-		return inBuf;
+			final TemporaryBuffer.Heap inBuf = new TemporaryBuffer.Heap(1024);
+			final PacketLineOut inPckLine = new PacketLineOut(inBuf);
+			inPckLine.writeString(ObjectId.zeroId().name() + ' ' + N.name()
+					+ ' ' + "refs/heads/s" + '\0'
+					+ BasePackPushConnection.CAPABILITY_REPORT_STATUS);
+			inPckLine.end();
+			pack.writeTo(inBuf, PM);
+			return inBuf;
+		}
 	}
 
 	@Test
 	public void testUsingUnknownTreeFails() throws Exception {
-		TestRepository<Repository> s = new TestRepository<>(src);
-		RevCommit N = s.commit().parent(B).add("q", s.blob("a")).create();
-		RevTree t = s.parseBody(N).getTree();
+		try (TestRepository<Repository> s = new TestRepository<>(src)) {
+			RevCommit N = s.commit().parent(B).add("q", s.blob("a")).create();
+			RevTree t = s.parseBody(N).getTree();
 
-		// Don't include the tree in the pack.
-		//
-		final TemporaryBuffer.Heap pack = new TemporaryBuffer.Heap(1024);
-		packHeader(pack, 1);
-		copy(pack, src.open(N));
-		digest(pack);
+			// Don't include the tree in the pack.
+			//
+			final TemporaryBuffer.Heap pack = new TemporaryBuffer.Heap(1024);
+			packHeader(pack, 1);
+			copy(pack, src.open(N));
+			digest(pack);
 
-		final TemporaryBuffer.Heap inBuf = new TemporaryBuffer.Heap(1024);
-		final PacketLineOut inPckLine = new PacketLineOut(inBuf);
-		inPckLine.writeString(ObjectId.zeroId().name() + ' ' + N.name() + ' '
-				+ "refs/heads/s" + '\0'
-				+ BasePackPushConnection.CAPABILITY_REPORT_STATUS);
-		inPckLine.end();
-		pack.writeTo(inBuf, PM);
+			final TemporaryBuffer.Heap inBuf = new TemporaryBuffer.Heap(1024);
+			final PacketLineOut inPckLine = new PacketLineOut(inBuf);
+			inPckLine.writeString(ObjectId.zeroId().name() + ' ' + N.name()
+					+ ' ' + "refs/heads/s" + '\0'
+					+ BasePackPushConnection.CAPABILITY_REPORT_STATUS);
+			inPckLine.end();
+			pack.writeTo(inBuf, PM);
 
-		final TemporaryBuffer.Heap outBuf = new TemporaryBuffer.Heap(1024);
-		final ReceivePack rp = new ReceivePack(dst);
-		rp.setCheckReceivedObjects(true);
-		rp.setCheckReferencedObjectsAreReachable(true);
-		rp.setAdvertiseRefsHook(new HidePrivateHook());
-		try {
-			receive(rp, inBuf, outBuf);
-			fail("Expected UnpackException");
-		} catch (UnpackException failed) {
-			Throwable err = failed.getCause();
-			assertTrue(err instanceof MissingObjectException);
-			MissingObjectException moe = (MissingObjectException) err;
-			assertEquals(t, moe.getObjectId());
+			final TemporaryBuffer.Heap outBuf = new TemporaryBuffer.Heap(1024);
+			final ReceivePack rp = new ReceivePack(dst);
+			rp.setCheckReceivedObjects(true);
+			rp.setCheckReferencedObjectsAreReachable(true);
+			rp.setAdvertiseRefsHook(new HidePrivateHook());
+			try {
+				receive(rp, inBuf, outBuf);
+				fail("Expected UnpackException");
+			} catch (UnpackException failed) {
+				Throwable err = failed.getCause();
+				assertTrue(err instanceof MissingObjectException);
+				MissingObjectException moe = (MissingObjectException) err;
+				assertEquals(t, moe.getObjectId());
+			}
+
+			final PacketLineIn r = asPacketLineIn(outBuf);
+			String master = r.readString();
+			int nul = master.indexOf('\0');
+			assertTrue("has capability list", nul > 0);
+			assertEquals(B.name() + ' ' + R_MASTER, master.substring(0, nul));
+			assertSame(PacketLineIn.END, r.readString());
+
+			assertEquals("unpack error Missing tree " + t.name(),
+					r.readString());
+			assertEquals("ng refs/heads/s n/a (unpacker error)",
+					r.readString());
+			assertSame(PacketLineIn.END, r.readString());
 		}
-
-		final PacketLineIn r = asPacketLineIn(outBuf);
-		String master = r.readString();
-		int nul = master.indexOf('\0');
-		assertTrue("has capability list", nul > 0);
-		assertEquals(B.name() + ' ' + R_MASTER, master.substring(0, nul));
-		assertSame(PacketLineIn.END, r.readString());
-
-		assertEquals("unpack error Missing tree " + t.name(), r.readString());
-		assertEquals("ng refs/heads/s n/a (unpacker error)", r.readString());
-		assertSame(PacketLineIn.END, r.readString());
 	}
 
 	private static void packHeader(TemporaryBuffer.Heap tinyPack, int cnt)
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 b6cf356..0bf9a80 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
@@ -77,76 +77,76 @@ public void setUp() throws Exception {
 
 	@Test
 	public void testWrite_CH_DATA() throws IOException {
-		@SuppressWarnings("resource" /* java 7 */)
-		final SideBandOutputStream out = new SideBandOutputStream(CH_DATA,
-				SMALL_BUF, rawOut);
-		out.write(new byte[] { 'a', 'b', 'c' });
-		out.flush();
+		try (SideBandOutputStream out = new SideBandOutputStream(CH_DATA,
+				SMALL_BUF, rawOut)) {
+			out.write(new byte[] { 'a', 'b', 'c' });
+			out.flush();
+		}
 		assertBuffer("0008\001abc");
 	}
 
 	@Test
 	public void testWrite_CH_PROGRESS() throws IOException {
-		@SuppressWarnings("resource" /* java 7 */)
-		final SideBandOutputStream out = new SideBandOutputStream(CH_PROGRESS,
-				SMALL_BUF, rawOut);
-		out.write(new byte[] { 'a', 'b', 'c' });
-		out.flush();
+		try (SideBandOutputStream out = new SideBandOutputStream(CH_PROGRESS,
+				SMALL_BUF, rawOut)) {
+			out.write(new byte[] { 'a', 'b', 'c' });
+			out.flush();
+		}
 		assertBuffer("0008\002abc");
 	}
 
 	@Test
 	public void testWrite_CH_ERROR() throws IOException {
-		@SuppressWarnings("resource" /* java 7 */)
-		final SideBandOutputStream out = new SideBandOutputStream(CH_ERROR,
-				SMALL_BUF, rawOut);
-		out.write(new byte[] { 'a', 'b', 'c' });
-		out.flush();
+		try (SideBandOutputStream out = new SideBandOutputStream(CH_ERROR,
+				SMALL_BUF, rawOut)) {
+			out.write(new byte[] { 'a', 'b', 'c' });
+			out.flush();
+		}
 		assertBuffer("0008\003abc");
 	}
 
 	@Test
 	public void testWrite_Small() throws IOException {
-		@SuppressWarnings("resource" /* java 7 */)
-		final SideBandOutputStream out = new SideBandOutputStream(CH_DATA,
-				SMALL_BUF, rawOut);
-		out.write('a');
-		out.write('b');
-		out.write('c');
-		out.flush();
+		try (SideBandOutputStream out = new SideBandOutputStream(CH_DATA,
+				SMALL_BUF, rawOut)) {
+			out.write('a');
+			out.write('b');
+			out.write('c');
+			out.flush();
+		}
 		assertBuffer("0008\001abc");
 	}
 
 	@Test
 	public void testWrite_SmallBlocks1() throws IOException {
-		@SuppressWarnings("resource" /* java 7 */)
-		final SideBandOutputStream out = new SideBandOutputStream(CH_DATA, 6,
-				rawOut);
-		out.write('a');
-		out.write('b');
-		out.write('c');
-		out.flush();
+		try (SideBandOutputStream out = new SideBandOutputStream(CH_DATA, 6,
+				rawOut)) {
+			out.write('a');
+			out.write('b');
+			out.write('c');
+			out.flush();
+		}
 		assertBuffer("0006\001a0006\001b0006\001c");
 	}
 
 	@Test
 	public void testWrite_SmallBlocks2() throws IOException {
-		@SuppressWarnings("resource" /* java 7 */)
-		final SideBandOutputStream out = new SideBandOutputStream(CH_DATA, 6,
-				rawOut);
-		out.write(new byte[] { 'a', 'b', 'c' });
-		out.flush();
+		try (SideBandOutputStream out = new SideBandOutputStream(CH_DATA, 6,
+				rawOut)) {
+			out.write(new byte[] { 'a', 'b', 'c' });
+			out.flush();
+		}
 		assertBuffer("0006\001a0006\001b0006\001c");
 	}
 
 	@Test
 	public void testWrite_SmallBlocks3() throws IOException {
-		@SuppressWarnings("resource" /* java 7 */)
-		final SideBandOutputStream out = new SideBandOutputStream(CH_DATA, 7,
-				rawOut);
-		out.write('a');
-		out.write(new byte[] { 'b', 'c' });
-		out.flush();
+		try (SideBandOutputStream out = new SideBandOutputStream(CH_DATA, 7,
+				rawOut)) {
+			out.write('a');
+			out.write(new byte[] { 'b', 'c' });
+			out.flush();
+		}
 		assertBuffer("0007\001ab0006\001c");
 	}
 
@@ -158,11 +158,11 @@ public void testWrite_Large() throws IOException {
 			buf[i] = (byte) i;
 		}
 
-		@SuppressWarnings("resource" /* java 7 */)
-		final SideBandOutputStream out = new SideBandOutputStream(CH_DATA,
-				MAX_BUF, rawOut);
-		out.write(buf);
-		out.flush();
+		try (SideBandOutputStream out = new SideBandOutputStream(CH_DATA,
+				MAX_BUF, rawOut)) {
+			out.write(buf);
+			out.flush();
+		}
 
 		final byte[] act = rawOut.toByteArray();
 		final String explen = Integer.toString(buf.length + HDR_SIZE, 16);
@@ -174,7 +174,6 @@ public void testWrite_Large() throws IOException {
 		}
 	}
 
-	@SuppressWarnings("resource" /* java 7 */)
 	@Test
 	public void testFlush() throws IOException {
 		final int[] flushCnt = new int[1];
@@ -190,7 +189,10 @@ public void flush() throws IOException {
 			}
 		};
 
-		new SideBandOutputStream(CH_DATA, SMALL_BUF, mockout).flush();
+		try (SideBandOutputStream out = new SideBandOutputStream(CH_DATA,
+				SMALL_BUF, mockout)) {
+			out.flush();
+		}
 		assertEquals(1, flushCnt[0]);
 	}
 
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 8acbcce..1cbe8a4 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
@@ -128,13 +128,13 @@ public UploadPack create(Object req, Repository db)
 				}, null);
 		uri = testProtocol.register(ctx, server);
 
-		assertFalse(client.hasObject(commit0.toObjectId()));
+		assertFalse(client.getObjectDatabase().has(commit0.toObjectId()));
 
 		// Fetch of the parent of the shallow commit
 		try (Transport tn = testProtocol.open(uri, client, "server")) {
 			tn.fetch(NullProgressMonitor.INSTANCE,
 					Collections.singletonList(new RefSpec(commit0.name())));
-			assertTrue(client.hasObject(commit0.toObjectId()));
+			assertTrue(client.getObjectDatabase().has(commit0.toObjectId()));
 		}
 	}
 
@@ -147,7 +147,7 @@ public void testFetchUnreachableBlobWithBitmap() throws Exception {
 		testProtocol = generateReachableCommitUploadPackProtocol();
 		uri = testProtocol.register(ctx, server);
 
-		assertFalse(client.hasObject(blob.toObjectId()));
+		assertFalse(client.getObjectDatabase().has(blob.toObjectId()));
 
 		try (Transport tn = testProtocol.open(uri, client, "server")) {
 			thrown.expect(TransportException.class);
@@ -168,12 +168,12 @@ public void testFetchReachableBlobWithBitmap() throws Exception {
 		testProtocol = generateReachableCommitUploadPackProtocol();
 		uri = testProtocol.register(ctx, server);
 
-		assertFalse(client.hasObject(blob.toObjectId()));
+		assertFalse(client.getObjectDatabase().has(blob.toObjectId()));
 
 		try (Transport tn = testProtocol.open(uri, client, "server")) {
 			tn.fetch(NullProgressMonitor.INSTANCE,
 					Collections.singletonList(new RefSpec(blob.name())));
-			assertTrue(client.hasObject(blob.toObjectId()));
+			assertTrue(client.getObjectDatabase().has(blob.toObjectId()));
 		}
 	}
 
@@ -186,7 +186,7 @@ public void testFetchReachableBlobWithoutBitmap() throws Exception {
 		testProtocol = generateReachableCommitUploadPackProtocol();
 		uri = testProtocol.register(ctx, server);
 
-		assertFalse(client.hasObject(blob.toObjectId()));
+		assertFalse(client.getObjectDatabase().has(blob.toObjectId()));
 
 		try (Transport tn = testProtocol.open(uri, client, "server")) {
 			thrown.expect(TransportException.class);
@@ -200,224 +200,233 @@ public void testFetchReachableBlobWithoutBitmap() throws Exception {
 	@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);
+		try (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);
+			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);
+			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()));
+			try (Transport tn = testProtocol.open(uri, client, "server2")) {
+				tn.setFilterBlobLimit(0);
+				tn.fetch(NullProgressMonitor.INSTANCE,
+						Collections.singletonList(new RefSpec(commit.name())));
+				assertTrue(client.getObjectDatabase().has(tree.toObjectId()));
+				assertFalse(client.getObjectDatabase().has(blob1.toObjectId()));
+				assertFalse(client.getObjectDatabase().has(blob2.toObjectId()));
+			}
 		}
 	}
 
 	@Test
 	public void testFetchExplicitBlobWithFilter() 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);
-		remote2.update("a_blob", blob1);
+		try (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);
+			remote2.update("a_blob", blob1);
 
-		server2.getConfig().setBoolean("uploadpack", null, "allowfilter", true);
+			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);
+			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, Arrays.asList(
-						new RefSpec(commit.name()),
-						new RefSpec(blob1.name())));
-			assertTrue(client.hasObject(tree.toObjectId()));
-			assertTrue(client.hasObject(blob1.toObjectId()));
-			assertFalse(client.hasObject(blob2.toObjectId()));
+			try (Transport tn = testProtocol.open(uri, client, "server2")) {
+				tn.setFilterBlobLimit(0);
+				tn.fetch(NullProgressMonitor.INSTANCE, Arrays.asList(
+						new RefSpec(commit.name()), new RefSpec(blob1.name())));
+				assertTrue(client.getObjectDatabase().has(tree.toObjectId()));
+				assertTrue(client.getObjectDatabase().has(blob1.toObjectId()));
+				assertFalse(client.getObjectDatabase().has(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);
+		try (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);
+			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);
+			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()));
+			try (Transport tn = testProtocol.open(uri, client, "server2")) {
+				tn.setFilterBlobLimit(5);
+				tn.fetch(NullProgressMonitor.INSTANCE,
+						Collections.singletonList(new RefSpec(commit.name())));
+				assertFalse(
+						client.getObjectDatabase().has(longBlob.toObjectId()));
+				assertTrue(
+						client.getObjectDatabase().has(shortBlob.toObjectId()));
+			}
 		}
 	}
 
 	@Test
 	public void testFetchExplicitBlobWithFilterAndBitmaps() 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);
-		remote2.update("a_blob", blob1);
+		try (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);
+			remote2.update("a_blob", blob1);
 
-		server2.getConfig().setBoolean("uploadpack", null, "allowfilter", true);
+			server2.getConfig().setBoolean("uploadpack", null, "allowfilter",
+					true);
 
-		// generate bitmaps
-		new DfsGarbageCollector(server2).pack(null);
-		server2.scanForRepoChanges();
+			// 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);
+			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, Arrays.asList(
-						new RefSpec(commit.name()),
-						new RefSpec(blob1.name())));
-			assertTrue(client.hasObject(blob1.toObjectId()));
-			assertFalse(client.hasObject(blob2.toObjectId()));
+			try (Transport tn = testProtocol.open(uri, client, "server2")) {
+				tn.setFilterBlobLimit(0);
+				tn.fetch(NullProgressMonitor.INSTANCE, Arrays.asList(
+						new RefSpec(commit.name()), new RefSpec(blob1.name())));
+				assertTrue(client.getObjectDatabase().has(blob1.toObjectId()));
+				assertFalse(client.getObjectDatabase().has(blob2.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);
+		try (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);
+			server2.getConfig().setBoolean("uploadpack", null, "allowfilter",
+					true);
 
-		// generate bitmaps
-		new DfsGarbageCollector(server2).pack(null);
-		server2.scanForRepoChanges();
+			// 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);
+			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()));
+			try (Transport tn = testProtocol.open(uri, client, "server2")) {
+				tn.setFilterBlobLimit(5);
+				tn.fetch(NullProgressMonitor.INSTANCE,
+						Collections.singletonList(new RefSpec(commit.name())));
+				assertFalse(
+						client.getObjectDatabase().has(longBlob.toObjectId()));
+				assertTrue(
+						client.getObjectDatabase().has(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);
+		try (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);
+			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);
+			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);
+			try (Transport tn = testProtocol.open(uri, client, "server2")) {
+				tn.setFilterBlobLimit(0);
 
-			thrown.expect(TransportException.class);
-			thrown.expectMessage("filter requires server to advertise that capability");
+				thrown.expect(TransportException.class);
+				thrown.expectMessage(
+						"filter requires server to advertise that capability");
 
-			tn.fetch(NullProgressMonitor.INSTANCE,
-					Collections.singletonList(new RefSpec(commit.name())));
+				tn.fetch(NullProgressMonitor.INSTANCE,
+						Collections.singletonList(new RefSpec(commit.name())));
+			}
 		}
 	}
 
@@ -965,10 +974,10 @@ public void testV2FetchServerStopsNegotiation() throws Exception {
 		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()));
+		assertFalse(client.getObjectDatabase().has(fooParent.toObjectId()));
+		assertTrue(client.getObjectDatabase().has(fooChild.toObjectId()));
+		assertFalse(client.getObjectDatabase().has(barParent.toObjectId()));
+		assertTrue(client.getObjectDatabase().has(barChild.toObjectId()));
 	}
 
 	@Test
@@ -992,10 +1001,10 @@ public void testV2FetchClientStopsNegotiation() throws Exception {
 
 		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()));
+		assertFalse(client.getObjectDatabase().has(fooParent.toObjectId()));
+		assertTrue(client.getObjectDatabase().has(fooChild.toObjectId()));
+		assertTrue(client.getObjectDatabase().has(barParent.toObjectId()));
+		assertTrue(client.getObjectDatabase().has(barChild.toObjectId()));
 	}
 
 	@Test
@@ -1078,7 +1087,7 @@ public void testV2FetchIncludeTag() throws Exception {
 		PacketLineIn pckIn = new PacketLineIn(recvStream);
 		assertThat(pckIn.readString(), is("packfile"));
 		parsePack(recvStream);
-		assertFalse(client.hasObject(tag.toObjectId()));
+		assertFalse(client.getObjectDatabase().has(tag.toObjectId()));
 
 		// With tag.
 		recvStream = uploadPackV2(
@@ -1091,7 +1100,7 @@ public void testV2FetchIncludeTag() throws Exception {
 		pckIn = new PacketLineIn(recvStream);
 		assertThat(pckIn.readString(), is("packfile"));
 		parsePack(recvStream);
-		assertTrue(client.hasObject(tag.toObjectId()));
+		assertTrue(client.getObjectDatabase().has(tag.toObjectId()));
 	}
 
 	@Test
@@ -1149,8 +1158,8 @@ public void testV2FetchShallow() throws Exception {
 		PacketLineIn pckIn = new PacketLineIn(recvStream);
 		assertThat(pckIn.readString(), is("packfile"));
 		parsePack(recvStream);
-		assertTrue(client.hasObject(barChild.toObjectId()));
-		assertFalse(client.hasObject(commonParent.toObjectId()));
+		assertTrue(client.getObjectDatabase().has(barChild.toObjectId()));
+		assertFalse(client.getObjectDatabase().has(commonParent.toObjectId()));
 
 		// With shallow, the server knows that we don't have
 		// commonParent, so it sends it.
@@ -1165,7 +1174,7 @@ public void testV2FetchShallow() throws Exception {
 		pckIn = new PacketLineIn(recvStream);
 		assertThat(pckIn.readString(), is("packfile"));
 		parsePack(recvStream);
-		assertTrue(client.hasObject(commonParent.toObjectId()));
+		assertTrue(client.getObjectDatabase().has(commonParent.toObjectId()));
 	}
 
 	@Test
@@ -1188,8 +1197,8 @@ public void testV2FetchDeepenAndDone() throws Exception {
 		assertThat(pckIn.readString(), theInstance(PacketLineIn.DELIM));
 		assertThat(pckIn.readString(), is("packfile"));
 		parsePack(recvStream);
-		assertTrue(client.hasObject(child.toObjectId()));
-		assertFalse(client.hasObject(parent.toObjectId()));
+		assertTrue(client.getObjectDatabase().has(child.toObjectId()));
+		assertFalse(client.getObjectDatabase().has(parent.toObjectId()));
 
 		// Without that, the parent is sent too.
 		recvStream = uploadPackV2(
@@ -1201,7 +1210,7 @@ public void testV2FetchDeepenAndDone() throws Exception {
 		pckIn = new PacketLineIn(recvStream);
 		assertThat(pckIn.readString(), is("packfile"));
 		parsePack(recvStream);
-		assertTrue(client.hasObject(parent.toObjectId()));
+		assertTrue(client.getObjectDatabase().has(parent.toObjectId()));
 	}
 
 	@Test
@@ -1268,15 +1277,15 @@ public void testV2FetchShallowSince() throws Exception {
 
 		// The server does not send this because it is committed
 		// earlier than the given deepen-since time.
-		assertFalse(client.hasObject(tooOld.toObjectId()));
+		assertFalse(client.getObjectDatabase().has(tooOld.toObjectId()));
 
 		// The server does not send this because the client claims to
 		// have it.
-		assertFalse(client.hasObject(boundary.toObjectId()));
+		assertFalse(client.getObjectDatabase().has(boundary.toObjectId()));
 
 		// The server sends both these commits.
-		assertTrue(client.hasObject(beyondBoundary.toObjectId()));
-		assertTrue(client.hasObject(merge.toObjectId()));
+		assertTrue(client.getObjectDatabase().has(beyondBoundary.toObjectId()));
+		assertTrue(client.getObjectDatabase().has(merge.toObjectId()));
 	}
 
 	@Test
@@ -1316,9 +1325,9 @@ public void testV2FetchShallowSince_excludedParentWithMultipleChildren() throws
 		parsePack(recvStream);
 
 		// Only the children are sent.
-		assertFalse(client.hasObject(base.toObjectId()));
-		assertTrue(client.hasObject(child1.toObjectId()));
-		assertTrue(client.hasObject(child2.toObjectId()));
+		assertFalse(client.getObjectDatabase().has(base.toObjectId()));
+		assertTrue(client.getObjectDatabase().has(child1.toObjectId()));
+		assertTrue(client.getObjectDatabase().has(child2.toObjectId()));
 	}
 
 	@Test
@@ -1384,16 +1393,16 @@ public void testV2FetchDeepenNot() throws Exception {
 
 		// The server does not send these because they are excluded by
 		// deepen-not.
-		assertFalse(client.hasObject(side.toObjectId()));
-		assertFalse(client.hasObject(one.toObjectId()));
+		assertFalse(client.getObjectDatabase().has(side.toObjectId()));
+		assertFalse(client.getObjectDatabase().has(one.toObjectId()));
 
 		// The server does not send this because the client claims to
 		// have it.
-		assertFalse(client.hasObject(three.toObjectId()));
+		assertFalse(client.getObjectDatabase().has(three.toObjectId()));
 
 		// The server sends both these commits.
-		assertTrue(client.hasObject(merge.toObjectId()));
-		assertTrue(client.hasObject(two.toObjectId()));
+		assertTrue(client.getObjectDatabase().has(merge.toObjectId()));
+		assertTrue(client.getObjectDatabase().has(two.toObjectId()));
 	}
 
 	@Test
@@ -1441,10 +1450,10 @@ public void testV2FetchDeepenNot_supportAnnotatedTags() throws Exception {
 		assertThat(pckIn.readString(), theInstance(PacketLineIn.DELIM));
 		assertThat(pckIn.readString(), is("packfile"));
 		parsePack(recvStream);
-		assertFalse(client.hasObject(one.toObjectId()));
-		assertFalse(client.hasObject(two.toObjectId()));
-		assertTrue(client.hasObject(three.toObjectId()));
-		assertTrue(client.hasObject(four.toObjectId()));
+		assertFalse(client.getObjectDatabase().has(one.toObjectId()));
+		assertFalse(client.getObjectDatabase().has(two.toObjectId()));
+		assertTrue(client.getObjectDatabase().has(three.toObjectId()));
+		assertTrue(client.getObjectDatabase().has(four.toObjectId()));
 	}
 
 	@Test
@@ -1485,9 +1494,9 @@ public void testV2FetchDeepenNot_excludedParentWithMultipleChildren() throws Exc
 		parsePack(recvStream);
 
 		// Only the children are sent.
-		assertFalse(client.hasObject(base.toObjectId()));
-		assertTrue(client.hasObject(child1.toObjectId()));
-		assertTrue(client.hasObject(child2.toObjectId()));
+		assertFalse(client.getObjectDatabase().has(base.toObjectId()));
+		assertTrue(client.getObjectDatabase().has(child1.toObjectId()));
+		assertTrue(client.getObjectDatabase().has(child2.toObjectId()));
 	}
 
 	@Test
@@ -1538,8 +1547,8 @@ public void testV2FetchFilter() throws Exception {
 		assertThat(pckIn.readString(), is("packfile"));
 		parsePack(recvStream);
 
-		assertFalse(client.hasObject(big.toObjectId()));
-		assertTrue(client.hasObject(small.toObjectId()));
+		assertFalse(client.getObjectDatabase().has(big.toObjectId()));
+		assertTrue(client.getObjectDatabase().has(small.toObjectId()));
 	}
 
 	@Test
@@ -1610,9 +1619,9 @@ public void testV2FetchWantRef() throws Exception {
 		assertThat(pckIn.readString(), is("packfile"));
 		parsePack(recvStream);
 
-		assertTrue(client.hasObject(one.toObjectId()));
-		assertTrue(client.hasObject(two.toObjectId()));
-		assertFalse(client.hasObject(three.toObjectId()));
+		assertTrue(client.getObjectDatabase().has(one.toObjectId()));
+		assertTrue(client.getObjectDatabase().has(two.toObjectId()));
+		assertFalse(client.getObjectDatabase().has(three.toObjectId()));
 	}
 
 	@Test
@@ -1666,9 +1675,9 @@ public void testV2FetchMixedWantRef() throws Exception {
 		assertThat(pckIn.readString(), is("packfile"));
 		parsePack(recvStream);
 
-		assertTrue(client.hasObject(one.toObjectId()));
-		assertTrue(client.hasObject(two.toObjectId()));
-		assertFalse(client.hasObject(three.toObjectId()));
+		assertTrue(client.getObjectDatabase().has(one.toObjectId()));
+		assertTrue(client.getObjectDatabase().has(two.toObjectId()));
+		assertFalse(client.getObjectDatabase().has(three.toObjectId()));
 	}
 
 	@Test
@@ -1699,7 +1708,7 @@ public void testV2FetchWantRefWeAlreadyHave() throws Exception {
 		// ... but the client does not need the object itself.
 		assertThat(pckIn.readString(), is("packfile"));
 		parsePack(recvStream);
-		assertFalse(client.hasObject(one.toObjectId()));
+		assertFalse(client.getObjectDatabase().has(one.toObjectId()));
 	}
 
 	@Test
@@ -1728,8 +1737,8 @@ public void testV2FetchWantRefAndDeepen() throws Exception {
 		assertThat(pckIn.readString(), theInstance(PacketLineIn.DELIM));
 		assertThat(pckIn.readString(), is("packfile"));
 		parsePack(recvStream);
-		assertTrue(client.hasObject(child.toObjectId()));
-		assertFalse(client.hasObject(parent.toObjectId()));
+		assertTrue(client.getObjectDatabase().has(child.toObjectId()));
+		assertFalse(client.getObjectDatabase().has(parent.toObjectId()));
 	}
 
 	@Test
@@ -1765,9 +1774,9 @@ public void testV2FetchMissingShallow() throws Exception {
 		assertThat(pckIn.readString(), is("packfile"));
 		parsePack(recvStream);
 
-		assertTrue(client.hasObject(one.toObjectId()));
-		assertTrue(client.hasObject(two.toObjectId()));
-		assertTrue(client.hasObject(three.toObjectId()));
+		assertTrue(client.getObjectDatabase().has(one.toObjectId()));
+		assertTrue(client.getObjectDatabase().has(two.toObjectId()));
+		assertTrue(client.getObjectDatabase().has(three.toObjectId()));
 	}
 
 	@Test
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 9a0e7d2..754341d 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
@@ -48,9 +48,11 @@
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeNoException;
 
 import java.io.File;
 import java.io.IOException;
+import java.nio.file.InvalidPathException;
 import java.security.MessageDigest;
 import java.time.Instant;
 
@@ -668,9 +670,23 @@ public void testCustomFileModeStrategyFromParentIterator() throws Exception {
 	public void testFileModeSymLinkIsNotATree() throws IOException {
 		org.junit.Assume.assumeTrue(FS.DETECTED.supportsSymlinks());
 		FS fs = db.getFS();
-		// mål = target in swedish, just to get som unicode in here
+		// mål = target in swedish, just to get some unicode in here
 		writeTrashFile("mål/data", "targetdata");
-		fs.createSymLink(new File(trash, "länk"), "mål");
+		File file = new File(trash, "länk");
+
+		try {
+			file.toPath();
+		} catch (InvalidPathException e) {
+			// When executing a test with LANG environment variable set to non
+			// UTF-8 encoding, it seems that JRE cannot handle Unicode file
+			// paths. This happens when this test is executed in Bazel as it
+			// unsets LANG
+			// (https://docs.bazel.build/versions/master/test-encyclopedia.html#initial-conditions).
+			// Skip the test if the runtime cannot handle Unicode characters.
+			assumeNoException(e);
+		}
+
+		fs.createSymLink(file, "mål");
 		FileTreeIterator fti = new FileTreeIterator(db);
 		assertFalse(fti.eof());
 		while (!fti.getEntryPathString().equals("länk")) {
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FSTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FSTest.java
index 3e1202c..89a2fc4 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FSTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FSTest.java
@@ -47,12 +47,14 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeNoException;
 import static org.junit.Assume.assumeTrue;
 
 import java.io.File;
 import java.io.IOException;
 import java.nio.charset.Charset;
 import java.nio.file.Files;
+import java.nio.file.InvalidPathException;
 import java.nio.file.Path;
 import java.nio.file.attribute.FileTime;
 import java.nio.file.attribute.PosixFileAttributeView;
@@ -103,16 +105,17 @@ public void tearDown() throws Exception {
 	public void testSymlinkAttributes() throws IOException, InterruptedException {
 		Assume.assumeTrue(FS.DETECTED.supportsSymlinks());
 		FS fs = FS.DETECTED;
-		File link = new File(trash, "ä");
-		File target = new File(trash, "å");
-		fs.createSymLink(link, "å");
+		File link = new File(trash, "a");
+		File target = new File(trash, "b");
+		fs.createSymLink(link, "b");
 		assertTrue(fs.exists(link));
 		String targetName = fs.readSymLink(link);
-		assertEquals("å", targetName);
+		assertEquals("b", targetName);
 		assertTrue(fs.lastModifiedInstant(link).compareTo(EPOCH) > 0);
 		assertTrue(fs.exists(link));
 		assertFalse(fs.canExecute(link));
-		assertEquals(2, fs.length(link));
+		// The length of a symbolic link is a length of the target file path.
+		assertEquals(1, fs.length(link));
 		assertFalse(fs.exists(target));
 		assertFalse(fs.isFile(target));
 		assertFalse(fs.isDirectory(target));
@@ -133,6 +136,32 @@ public void testSymlinkAttributes() throws IOException, InterruptedException {
 	}
 
 	@Test
+	public void testUnicodeFilePath() throws IOException {
+		Assume.assumeTrue(FS.DETECTED.supportsSymlinks());
+		FS fs = FS.DETECTED;
+		File link = new File(trash, "ä");
+		File target = new File(trash, "å");
+
+		try {
+			// Check if the runtime can support Unicode file paths.
+			link.toPath();
+			target.toPath();
+		} catch (InvalidPathException e) {
+			// When executing a test with LANG environment variable set to non
+			// UTF-8 encoding, it seems that JRE cannot handle Unicode file
+			// paths. This happens when this test is executed in Bazel as it
+			// unsets LANG
+			// (https://docs.bazel.build/versions/master/test-encyclopedia.html#initial-conditions).
+			// Skip the test if the runtime cannot handle Unicode characters.
+			assumeNoException(e);
+		}
+
+		fs.createSymLink(link, "å");
+		assertTrue(fs.exists(link));
+		assertEquals("å", fs.readSymLink(link));
+	}
+
+	@Test
 	public void testExecutableAttributes() throws Exception {
 		FS fs = FS.DETECTED.newInstance();
 		// If this assumption fails the test is halted and ignored.
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 edcce12..9f1395b 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
@@ -404,16 +404,16 @@ public void testRandomWrites() throws IOException {
 
 	@Test
 	public void testHeap() throws IOException {
-		@SuppressWarnings("resource" /* java 7 */)
-		final TemporaryBuffer b = new TemporaryBuffer.Heap(2 * 8 * 1024);
-		final byte[] r = new byte[8 * 1024];
-		b.write(r);
-		b.write(r);
-		try {
-			b.write(1);
-			fail("accepted too many bytes of data");
-		} catch (IOException e) {
-			assertEquals("In-memory buffer limit exceeded", e.getMessage());
+		try (TemporaryBuffer b = new TemporaryBuffer.Heap(2 * 8 * 1024)) {
+			final byte[] r = new byte[8 * 1024];
+			b.write(r);
+			b.write(r);
+			try {
+				b.write(1);
+				fail("accepted too many bytes of data");
+			} catch (IOException e) {
+				assertEquals("In-memory buffer limit exceeded", e.getMessage());
+			}
 		}
 	}
 
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 a6e0eed..e38bbfe 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
@@ -69,53 +69,52 @@ public void testEmptyStream() throws IOException {
 
 	@Test
 	public void testReadSingleBytes() throws IOException {
-		@SuppressWarnings("resource" /* java 7 */)
-		final UnionInputStream u = new UnionInputStream();
+		try (UnionInputStream u = new UnionInputStream()) {
+			assertTrue(u.isEmpty());
+			u.add(new ByteArrayInputStream(new byte[] { 1, 0, 2 }));
+			u.add(new ByteArrayInputStream(new byte[] { 3 }));
+			u.add(new ByteArrayInputStream(new byte[] { 4, 5 }));
 
-		assertTrue(u.isEmpty());
-		u.add(new ByteArrayInputStream(new byte[] { 1, 0, 2 }));
-		u.add(new ByteArrayInputStream(new byte[] { 3 }));
-		u.add(new ByteArrayInputStream(new byte[] { 4, 5 }));
+			assertFalse(u.isEmpty());
+			assertEquals(3, u.available());
+			assertEquals(1, u.read());
+			assertEquals(0, u.read());
+			assertEquals(2, u.read());
+			assertEquals(0, u.available());
 
-		assertFalse(u.isEmpty());
-		assertEquals(3, u.available());
-		assertEquals(1, u.read());
-		assertEquals(0, u.read());
-		assertEquals(2, u.read());
-		assertEquals(0, u.available());
+			assertEquals(3, u.read());
+			assertEquals(0, u.available());
 
-		assertEquals(3, u.read());
-		assertEquals(0, u.available());
+			assertEquals(4, u.read());
+			assertEquals(1, u.available());
+			assertEquals(5, u.read());
+			assertEquals(0, u.available());
+			assertEquals(-1, u.read());
 
-		assertEquals(4, u.read());
-		assertEquals(1, u.available());
-		assertEquals(5, u.read());
-		assertEquals(0, u.available());
-		assertEquals(-1, u.read());
-
-		assertTrue(u.isEmpty());
-		u.add(new ByteArrayInputStream(new byte[] { (byte) 255 }));
-		assertEquals(255, u.read());
-		assertEquals(-1, u.read());
-		assertTrue(u.isEmpty());
+			assertTrue(u.isEmpty());
+			u.add(new ByteArrayInputStream(new byte[] { (byte) 255 }));
+			assertEquals(255, u.read());
+			assertEquals(-1, u.read());
+			assertTrue(u.isEmpty());
+		}
 	}
 
 	@Test
 	public void testReadByteBlocks() throws IOException {
-		@SuppressWarnings("resource" /* java 7 */)
-		final UnionInputStream u = new UnionInputStream();
-		u.add(new ByteArrayInputStream(new byte[] { 1, 0, 2 }));
-		u.add(new ByteArrayInputStream(new byte[] { 3 }));
-		u.add(new ByteArrayInputStream(new byte[] { 4, 5 }));
+		try (UnionInputStream u = new UnionInputStream()) {
+			u.add(new ByteArrayInputStream(new byte[] { 1, 0, 2 }));
+			u.add(new ByteArrayInputStream(new byte[] { 3 }));
+			u.add(new ByteArrayInputStream(new byte[] { 4, 5 }));
 
-		final byte[] r = new byte[5];
-		assertEquals(3, u.read(r, 0, 5));
-		assertTrue(Arrays.equals(new byte[] { 1, 0, 2, }, slice(r, 3)));
-		assertEquals(1, u.read(r, 0, 5));
-		assertEquals(3, r[0]);
-		assertEquals(2, u.read(r, 0, 5));
-		assertTrue(Arrays.equals(new byte[] { 4, 5, }, slice(r, 2)));
-		assertEquals(-1, u.read(r, 0, 5));
+			final byte[] r = new byte[5];
+			assertEquals(3, u.read(r, 0, 5));
+			assertTrue(Arrays.equals(new byte[] { 1, 0, 2, }, slice(r, 3)));
+			assertEquals(1, u.read(r, 0, 5));
+			assertEquals(3, r[0]);
+			assertEquals(2, u.read(r, 0, 5));
+			assertTrue(Arrays.equals(new byte[] { 4, 5, }, slice(r, 2)));
+			assertEquals(-1, u.read(r, 0, 5));
+		}
 	}
 
 	private static byte[] slice(byte[] in, int len) {
@@ -126,89 +125,88 @@ public void testReadByteBlocks() throws IOException {
 
 	@Test
 	public void testArrayConstructor() throws IOException {
-		@SuppressWarnings("resource" /* java 7 */)
-		final UnionInputStream u = new UnionInputStream(
+		try (UnionInputStream u = new UnionInputStream(
 				new ByteArrayInputStream(new byte[] { 1, 0, 2 }),
 				new ByteArrayInputStream(new byte[] { 3 }),
-				new ByteArrayInputStream(new byte[] { 4, 5 }));
-
-		final byte[] r = new byte[5];
-		assertEquals(3, u.read(r, 0, 5));
-		assertTrue(Arrays.equals(new byte[] { 1, 0, 2, }, slice(r, 3)));
-		assertEquals(1, u.read(r, 0, 5));
-		assertEquals(3, r[0]);
-		assertEquals(2, u.read(r, 0, 5));
-		assertTrue(Arrays.equals(new byte[] { 4, 5, }, slice(r, 2)));
-		assertEquals(-1, u.read(r, 0, 5));
+				new ByteArrayInputStream(new byte[] { 4, 5 }))) {
+			final byte[] r = new byte[5];
+			assertEquals(3, u.read(r, 0, 5));
+			assertTrue(Arrays.equals(new byte[] { 1, 0, 2, }, slice(r, 3)));
+			assertEquals(1, u.read(r, 0, 5));
+			assertEquals(3, r[0]);
+			assertEquals(2, u.read(r, 0, 5));
+			assertTrue(Arrays.equals(new byte[] { 4, 5, }, slice(r, 2)));
+			assertEquals(-1, u.read(r, 0, 5));
+		}
 	}
 
 	@Test
-	public void testMarkSupported() {
-		@SuppressWarnings("resource" /* java 7 */)
-		final UnionInputStream u = new UnionInputStream();
-		assertFalse(u.markSupported());
-		u.add(new ByteArrayInputStream(new byte[] { 1, 0, 2 }));
-		assertFalse(u.markSupported());
+	public void testMarkSupported() throws IOException {
+		try (UnionInputStream u = new UnionInputStream()) {
+			assertFalse(u.markSupported());
+			u.add(new ByteArrayInputStream(new byte[] { 1, 0, 2 }));
+			assertFalse(u.markSupported());
+		}
 	}
 
 	@Test
 	public void testSkip() throws IOException {
-		@SuppressWarnings("resource" /* java 7 */)
-		final UnionInputStream u = new UnionInputStream();
-		u.add(new ByteArrayInputStream(new byte[] { 1, 0, 2 }));
-		u.add(new ByteArrayInputStream(new byte[] { 3 }));
-		u.add(new ByteArrayInputStream(new byte[] { 4, 5 }));
-		assertEquals(0, u.skip(0));
-		assertEquals(3, u.skip(3));
-		assertEquals(3, u.read());
-		assertEquals(2, u.skip(5));
-		assertEquals(0, u.skip(5));
-		assertEquals(-1, u.read());
+		try (UnionInputStream u = new UnionInputStream()) {
+			u.add(new ByteArrayInputStream(new byte[] { 1, 0, 2 }));
+			u.add(new ByteArrayInputStream(new byte[] { 3 }));
+			u.add(new ByteArrayInputStream(new byte[] { 4, 5 }));
+			assertEquals(0, u.skip(0));
+			assertEquals(3, u.skip(3));
+			assertEquals(3, u.read());
+			assertEquals(2, u.skip(5));
+			assertEquals(0, u.skip(5));
+			assertEquals(-1, u.read());
 
-		u.add(new ByteArrayInputStream(new byte[] { 20, 30 }) {
-			@Override
-			@SuppressWarnings("UnsynchronizedOverridesSynchronized")
-			// This is only used in tests and is thread-safe
-			public long skip(long n) {
-				return 0;
-			}
-		});
-		assertEquals(2, u.skip(8));
-		assertEquals(-1, u.read());
+			u.add(new ByteArrayInputStream(new byte[] { 20, 30 }) {
+				@Override
+				@SuppressWarnings("UnsynchronizedOverridesSynchronized")
+				// This is only used in tests and is thread-safe
+				public long skip(long n) {
+					return 0;
+				}
+			});
+			assertEquals(2, u.skip(8));
+			assertEquals(-1, u.read());
+		}
 	}
 
 	@Test
 	public void testAutoCloseDuringRead() throws IOException {
-		@SuppressWarnings("resource" /* java 7 */)
-		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()) {
+			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;
+				}
+			});
 
-		assertFalse(closed[0]);
-		assertFalse(closed[1]);
+			assertFalse(closed[0]);
+			assertFalse(closed[1]);
 
-		assertEquals(1, u.read());
-		assertFalse(closed[0]);
-		assertFalse(closed[1]);
+			assertEquals(1, u.read());
+			assertFalse(closed[0]);
+			assertFalse(closed[1]);
 
-		assertEquals(2, u.read());
-		assertTrue(closed[0]);
-		assertFalse(closed[1]);
+			assertEquals(2, u.read());
+			assertTrue(closed[0]);
+			assertFalse(closed[1]);
 
-		assertEquals(-1, u.read());
-		assertTrue(closed[0]);
-		assertTrue(closed[1]);
+			assertEquals(-1, u.read());
+			assertTrue(closed[0]);
+			assertTrue(closed[1]);
+		}
 	}
 
 	@Test
@@ -267,18 +265,18 @@ public int read(byte b[], int off, int len) throws IOException {
 				throw new IOException("Expected");
 			}
 		};
-		@SuppressWarnings("resource" /* java 7 */)
-		final UnionInputStream u = new UnionInputStream(
-				new ByteArrayInputStream(new byte[]{1,2,3}),
-				errorReadStream);
-		byte buf[] = new byte[10];
-		assertEquals(3, u.read(buf, 0, 10));
-		assertTrue(Arrays.equals(new byte[] {1,2,3}, slice(buf, 3)));
-		try {
-			u.read(buf, 0, 1);
-			fail("Expected exception from errorReadStream");
-		} catch (IOException e) {
-			assertEquals("Expected", e.getMessage());
+		try (UnionInputStream u = new UnionInputStream(
+				new ByteArrayInputStream(new byte[] { 1, 2, 3 }),
+				errorReadStream)) {
+			byte buf[] = new byte[10];
+			assertEquals(3, u.read(buf, 0, 10));
+			assertTrue(Arrays.equals(new byte[] { 1, 2, 3 }, slice(buf, 3)));
+			try {
+				u.read(buf, 0, 1);
+				fail("Expected exception from errorReadStream");
+			} catch (IOException e) {
+				assertEquals("Expected", e.getMessage());
+			}
 		}
 	}
 }
diff --git a/org.eclipse.jgit.ui/META-INF/MANIFEST.MF b/org.eclipse.jgit.ui/META-INF/MANIFEST.MF
index 380de32..0c0fd09 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: 5.2.3.qualifier
+Bundle-Version: 5.3.7.qualifier
 Bundle-Vendor: %provider_name
 Bundle-RequiredExecutionEnvironment: JavaSE-1.8
-Export-Package: org.eclipse.jgit.awtui;version="5.2.3"
-Import-Package: org.eclipse.jgit.errors;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.lib;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.nls;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.revplot;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.revwalk;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.transport;version="[5.2.3,5.3.0)",
- org.eclipse.jgit.util;version="[5.2.3,5.3.0)"
+Export-Package: org.eclipse.jgit.awtui;version="5.3.7"
+Import-Package: org.eclipse.jgit.errors;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.lib;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.nls;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.revplot;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.revwalk;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.transport;version="[5.3.7,5.4.0)",
+ org.eclipse.jgit.util;version="[5.3.7,5.4.0)"
diff --git a/org.eclipse.jgit.ui/pom.xml b/org.eclipse.jgit.ui/pom.xml
index 0cb3d65..ec59722 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>5.2.3-SNAPSHOT</version>
+    <version>5.3.7-SNAPSHOT</version>
   </parent>
 
   <artifactId>org.eclipse.jgit.ui</artifactId>
diff --git a/org.eclipse.jgit/.settings/.api_filters b/org.eclipse.jgit/.settings/.api_filters
index a1ffe91..abdf350 100644
--- a/org.eclipse.jgit/.settings/.api_filters
+++ b/org.eclipse.jgit/.settings/.api_filters
@@ -34,28 +34,6 @@
             </message_arguments>
         </filter>
     </resource>
-    <resource path="src/org/eclipse/jgit/gitrepo/RepoCommand.java" type="org.eclipse.jgit.gitrepo.RepoCommand$DefaultRemoteReader">
-        <filter id="338792546">
-            <message_arguments>
-                <message_argument value="org.eclipse.jgit.gitrepo.RepoCommand.DefaultRemoteReader"/>
-                <message_argument value="readFile(String, String, String)"/>
-            </message_arguments>
-        </filter>
-        <filter id="338792546">
-            <message_arguments>
-                <message_argument value="org.eclipse.jgit.gitrepo.RepoCommand.DefaultRemoteReader"/>
-                <message_argument value="readFileFromRepo(Repository, String, String)"/>
-            </message_arguments>
-        </filter>
-    </resource>
-    <resource path="src/org/eclipse/jgit/gitrepo/RepoCommand.java" type="org.eclipse.jgit.gitrepo.RepoCommand$RemoteReader">
-        <filter id="403804204">
-            <message_arguments>
-                <message_argument value="org.eclipse.jgit.gitrepo.RepoCommand.RemoteReader"/>
-                <message_argument value="readFileWithMode(String, String, String)"/>
-            </message_arguments>
-        </filter>
-    </resource>
     <resource path="src/org/eclipse/jgit/lib/ConfigConstants.java" type="org.eclipse.jgit.lib.ConfigConstants">
         <filter id="1142947843">
             <message_arguments>
@@ -82,39 +60,33 @@
             </message_arguments>
         </filter>
     </resource>
-    <resource path="src/org/eclipse/jgit/lib/GitmoduleEntry.java" type="org.eclipse.jgit.lib.GitmoduleEntry">
-        <filter id="1109393411">
+    <resource path="src/org/eclipse/jgit/lib/ObjectIdRef.java" type="org.eclipse.jgit.lib.ObjectIdRef">
+        <filter id="338722907">
             <message_arguments>
-                <message_argument value="4.7.5"/>
-                <message_argument value="org.eclipse.jgit.lib.GitmoduleEntry"/>
+                <message_argument value="org.eclipse.jgit.lib.ObjectIdRef"/>
+                <message_argument value="ObjectIdRef(Ref.Storage, String, ObjectId)"/>
             </message_arguments>
         </filter>
     </resource>
-    <resource path="src/org/eclipse/jgit/lib/ObjectChecker.java" type="org.eclipse.jgit.lib.ObjectChecker">
-        <filter id="1142947843">
+    <resource path="src/org/eclipse/jgit/lib/Ref.java" type="org.eclipse.jgit.lib.Ref">
+        <filter id="404000815">
             <message_arguments>
-                <message_argument value="4.7.5"/>
-                <message_argument value="getGitsubmodules()"/>
+                <message_argument value="org.eclipse.jgit.lib.Ref"/>
+                <message_argument value="getUpdateIndex()"/>
             </message_arguments>
         </filter>
     </resource>
-    <resource path="src/org/eclipse/jgit/revwalk/DepthWalk.java" type="org.eclipse.jgit.revwalk.DepthWalk">
-        <filter id="403804204">
+    <resource path="src/org/eclipse/jgit/lib/RefDatabase.java" type="org.eclipse.jgit.lib.RefDatabase">
+        <filter id="421650549">
             <message_arguments>
-                <message_argument value="org.eclipse.jgit.revwalk.DepthWalk"/>
-                <message_argument value="getDeepenNotFlag()"/>
+                <message_argument value="org.eclipse.jgit.lib.RefDatabase"/>
+                <message_argument value="exactRef(String)"/>
             </message_arguments>
         </filter>
-        <filter id="404000815">
+        <filter id="421654647">
             <message_arguments>
-                <message_argument value="org.eclipse.jgit.revwalk.DepthWalk"/>
-                <message_argument value="getDeepenNots()"/>
-            </message_arguments>
-        </filter>
-        <filter id="404000815">
-            <message_arguments>
-                <message_argument value="org.eclipse.jgit.revwalk.DepthWalk"/>
-                <message_argument value="getDeepenSince()"/>
+                <message_argument value="org.eclipse.jgit.lib.RefDatabase"/>
+                <message_argument value="getRef(String)"/>
             </message_arguments>
         </filter>
     </resource>
@@ -183,11 +155,41 @@
             </message_arguments>
         </filter>
     </resource>
-    <resource path="src/org/eclipse/jgit/transport/RemoteSession.java" type="org.eclipse.jgit.transport.RemoteSession">
-        <filter id="404000815">
+    <resource path="src/org/eclipse/jgit/transport/BaseReceivePack.java" type="org.eclipse.jgit.transport.BaseReceivePack">
+        <filter id="421650549">
             <message_arguments>
-                <message_argument value="org.eclipse.jgit.transport.RemoteSession"/>
-                <message_argument value="getFtpChannel()"/>
+                <message_argument value="org.eclipse.jgit.transport.BaseReceivePack"/>
+                <message_argument value="getAdvertisedRefs()"/>
+            </message_arguments>
+        </filter>
+        <filter id="421650549">
+            <message_arguments>
+                <message_argument value="org.eclipse.jgit.transport.BaseReceivePack"/>
+                <message_argument value="getPushCertificate()"/>
+            </message_arguments>
+        </filter>
+        <filter id="421650549">
+            <message_arguments>
+                <message_argument value="org.eclipse.jgit.transport.BaseReceivePack"/>
+                <message_argument value="getRepository()"/>
+            </message_arguments>
+        </filter>
+        <filter id="421650549">
+            <message_arguments>
+                <message_argument value="org.eclipse.jgit.transport.BaseReceivePack"/>
+                <message_argument value="getRevWalk()"/>
+            </message_arguments>
+        </filter>
+        <filter id="421650549">
+            <message_arguments>
+                <message_argument value="org.eclipse.jgit.transport.BaseReceivePack"/>
+                <message_argument value="setAdvertisedRefs(Map&lt;String,Ref&gt;, Set&lt;ObjectId&gt;)"/>
+            </message_arguments>
+        </filter>
+        <filter id="421650549">
+            <message_arguments>
+                <message_argument value="org.eclipse.jgit.transport.BaseReceivePack"/>
+                <message_argument value="setPushCertificate(PushCertificate)"/>
             </message_arguments>
         </filter>
     </resource>
@@ -205,14 +207,6 @@
             </message_arguments>
         </filter>
     </resource>
-    <resource path="src/org/eclipse/jgit/transport/http/HttpConnection.java" type="org.eclipse.jgit.transport.http.HttpConnection">
-        <filter id="403804204">
-            <message_arguments>
-                <message_argument value="org.eclipse.jgit.transport.http.HttpConnection"/>
-                <message_argument value="getHeaderFields(String)"/>
-            </message_arguments>
-        </filter>
-    </resource>
     <resource path="src/org/eclipse/jgit/treewalk/WorkingTreeIterator.java" type="org.eclipse.jgit.treewalk.WorkingTreeIterator">
         <filter id="1142947843">
             <message_arguments>
diff --git a/org.eclipse.jgit/BUILD b/org.eclipse.jgit/BUILD
index 0549b23..c7d9fde 100644
--- a/org.eclipse.jgit/BUILD
+++ b/org.eclipse.jgit/BUILD
@@ -24,6 +24,9 @@
     resources = RESOURCES,
     deps = [
         ":insecure_cipher_factory",
+        "//lib:bcpg",
+        "//lib:bcpkix",
+        "//lib:bcprov",
         "//lib:javaewah",
         "//lib:jsch",
         "//lib:jzlib",
diff --git a/org.eclipse.jgit/META-INF/MANIFEST.MF b/org.eclipse.jgit/META-INF/MANIFEST.MF
index 66701b0..38b9452 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: 5.2.3.qualifier
+Bundle-Version: 5.3.7.qualifier
 Bundle-Localization: plugin
 Bundle-Vendor: %provider_name
 Bundle-ActivationPolicy: lazy
-Export-Package: org.eclipse.jgit.annotations;version="5.2.3",
- org.eclipse.jgit.api;version="5.2.3";
+Export-Package: org.eclipse.jgit.annotations;version="5.3.7",
+ org.eclipse.jgit.api;version="5.3.7";
   uses:="org.eclipse.jgit.revwalk,
    org.eclipse.jgit.treewalk.filter,
    org.eclipse.jgit.diff,
@@ -22,53 +22,53 @@
    org.eclipse.jgit.submodule,
    org.eclipse.jgit.transport,
    org.eclipse.jgit.merge",
- org.eclipse.jgit.api.errors;version="5.2.3";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.errors",
- org.eclipse.jgit.attributes;version="5.2.3",
- org.eclipse.jgit.blame;version="5.2.3";
+ org.eclipse.jgit.api.errors;version="5.3.7";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.errors",
+ org.eclipse.jgit.attributes;version="5.3.7",
+ org.eclipse.jgit.blame;version="5.3.7";
   uses:="org.eclipse.jgit.lib,
    org.eclipse.jgit.revwalk,
    org.eclipse.jgit.treewalk.filter,
    org.eclipse.jgit.diff",
- org.eclipse.jgit.diff;version="5.2.3";
+ org.eclipse.jgit.diff;version="5.3.7";
   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="5.2.3";
+ org.eclipse.jgit.dircache;version="5.3.7";
   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="5.2.3";
+ org.eclipse.jgit.errors;version="5.3.7";
   uses:="org.eclipse.jgit.lib,
    org.eclipse.jgit.internal.storage.pack,
    org.eclipse.jgit.transport,
    org.eclipse.jgit.dircache",
- org.eclipse.jgit.events;version="5.2.3";uses:="org.eclipse.jgit.lib",
- org.eclipse.jgit.fnmatch;version="5.2.3",
- org.eclipse.jgit.gitrepo;version="5.2.3";
+ org.eclipse.jgit.events;version="5.3.7";uses:="org.eclipse.jgit.lib",
+ org.eclipse.jgit.fnmatch;version="5.3.7",
+ org.eclipse.jgit.gitrepo;version="5.3.7";
   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="5.2.3";x-internal:=true,
- org.eclipse.jgit.hooks;version="5.2.3";uses:="org.eclipse.jgit.lib",
- org.eclipse.jgit.ignore;version="5.2.3",
- org.eclipse.jgit.ignore.internal;version="5.2.3";x-friends:="org.eclipse.jgit.test",
- org.eclipse.jgit.internal;version="5.2.3";x-friends:="org.eclipse.jgit.test,org.eclipse.jgit.http.test",
- org.eclipse.jgit.internal.fsck;version="5.2.3";x-friends:="org.eclipse.jgit.test",
- org.eclipse.jgit.internal.ketch;version="5.2.3";x-friends:="org.eclipse.jgit.junit,org.eclipse.jgit.test,org.eclipse.jgit.pgm",
- org.eclipse.jgit.internal.revwalk;version="5.2.3";x-internal:=true,
- org.eclipse.jgit.internal.storage.dfs;version="5.2.3";
+ org.eclipse.jgit.gitrepo.internal;version="5.3.7";x-internal:=true,
+ org.eclipse.jgit.hooks;version="5.3.7";uses:="org.eclipse.jgit.lib",
+ org.eclipse.jgit.ignore;version="5.3.7",
+ org.eclipse.jgit.ignore.internal;version="5.3.7";x-friends:="org.eclipse.jgit.test",
+ org.eclipse.jgit.internal;version="5.3.7";x-friends:="org.eclipse.jgit.test,org.eclipse.jgit.http.test",
+ org.eclipse.jgit.internal.fsck;version="5.3.7";x-friends:="org.eclipse.jgit.test",
+ org.eclipse.jgit.internal.ketch;version="5.3.7";x-friends:="org.eclipse.jgit.junit,org.eclipse.jgit.test,org.eclipse.jgit.pgm",
+ org.eclipse.jgit.internal.revwalk;version="5.3.7";x-internal:=true,
+ org.eclipse.jgit.internal.storage.dfs;version="5.3.7";
   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="5.2.3";
+ org.eclipse.jgit.internal.storage.file;version="5.3.7";
   x-friends:="org.eclipse.jgit.test,
    org.eclipse.jgit.junit,
    org.eclipse.jgit.junit.http,
@@ -77,18 +77,18 @@
    org.eclipse.jgit.pgm,
    org.eclipse.jgit.pgm.test,
    org.eclipse.jgit.ssh.apache",
- org.eclipse.jgit.internal.storage.io;version="5.2.3";x-friends:="org.eclipse.jgit.junit,org.eclipse.jgit.test,org.eclipse.jgit.pgm",
- org.eclipse.jgit.internal.storage.pack;version="5.2.3";x-friends:="org.eclipse.jgit.junit,org.eclipse.jgit.test,org.eclipse.jgit.pgm",
- org.eclipse.jgit.internal.storage.reftable;version="5.2.3";
+ org.eclipse.jgit.internal.storage.io;version="5.3.7";x-friends:="org.eclipse.jgit.junit,org.eclipse.jgit.test,org.eclipse.jgit.pgm",
+ org.eclipse.jgit.internal.storage.pack;version="5.3.7";x-friends:="org.eclipse.jgit.junit,org.eclipse.jgit.test,org.eclipse.jgit.pgm",
+ org.eclipse.jgit.internal.storage.reftable;version="5.3.7";
   x-friends:="org.eclipse.jgit.http.test,
    org.eclipse.jgit.junit,
    org.eclipse.jgit.test,
    org.eclipse.jgit.pgm",
- org.eclipse.jgit.internal.storage.reftree;version="5.2.3";x-friends:="org.eclipse.jgit.junit,org.eclipse.jgit.test,org.eclipse.jgit.pgm",
- org.eclipse.jgit.internal.submodule;version="5.2.3";x-internal:=true,
- org.eclipse.jgit.internal.transport.parser;version="5.2.3";x-friends:="org.eclipse.jgit.test,org.eclipse.jgit.http.server",
- org.eclipse.jgit.internal.transport.ssh;version="5.2.3";x-friends:="org.eclipse.jgit.ssh.apache",
- org.eclipse.jgit.lib;version="5.2.3";
+ org.eclipse.jgit.internal.storage.reftree;version="5.3.7";x-friends:="org.eclipse.jgit.junit,org.eclipse.jgit.test,org.eclipse.jgit.pgm",
+ org.eclipse.jgit.internal.submodule;version="5.3.7";x-internal:=true,
+ org.eclipse.jgit.internal.transport.parser;version="5.3.7";x-friends:="org.eclipse.jgit.http.server,org.eclipse.jgit.test",
+ org.eclipse.jgit.internal.transport.ssh;version="5.3.7";x-friends:="org.eclipse.jgit.ssh.apache",
+ org.eclipse.jgit.lib;version="5.3.7";
   uses:="org.eclipse.jgit.revwalk,
    org.eclipse.jgit.treewalk.filter,
    org.eclipse.jgit.util,
@@ -98,33 +98,33 @@
    org.eclipse.jgit.treewalk,
    org.eclipse.jgit.transport,
    org.eclipse.jgit.submodule",
- org.eclipse.jgit.lib.internal;version="5.2.3";x-internal:=true,
- org.eclipse.jgit.merge;version="5.2.3";
+ org.eclipse.jgit.lib.internal;version="5.3.7";x-internal:=true,
+ org.eclipse.jgit.merge;version="5.3.7";
   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="5.2.3",
- org.eclipse.jgit.notes;version="5.2.3";
+ org.eclipse.jgit.nls;version="5.3.7",
+ org.eclipse.jgit.notes;version="5.3.7";
   uses:="org.eclipse.jgit.lib,
    org.eclipse.jgit.treewalk,
    org.eclipse.jgit.revwalk,
    org.eclipse.jgit.merge",
- org.eclipse.jgit.patch;version="5.2.3";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.diff",
- org.eclipse.jgit.revplot;version="5.2.3";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.revwalk",
- org.eclipse.jgit.revwalk;version="5.2.3";
+ org.eclipse.jgit.patch;version="5.3.7";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.diff",
+ org.eclipse.jgit.revplot;version="5.3.7";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.revwalk",
+ org.eclipse.jgit.revwalk;version="5.3.7";
   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="5.2.3";uses:="org.eclipse.jgit.revwalk,org.eclipse.jgit.lib,org.eclipse.jgit.util",
- org.eclipse.jgit.storage.file;version="5.2.3";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.util",
- org.eclipse.jgit.storage.pack;version="5.2.3";uses:="org.eclipse.jgit.lib",
- org.eclipse.jgit.submodule;version="5.2.3";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.treewalk.filter,org.eclipse.jgit.treewalk",
- org.eclipse.jgit.transport;version="5.2.3";
+ org.eclipse.jgit.revwalk.filter;version="5.3.7";uses:="org.eclipse.jgit.revwalk,org.eclipse.jgit.lib,org.eclipse.jgit.util",
+ org.eclipse.jgit.storage.file;version="5.3.7";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.util",
+ org.eclipse.jgit.storage.pack;version="5.3.7";uses:="org.eclipse.jgit.lib",
+ org.eclipse.jgit.submodule;version="5.3.7";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.treewalk.filter,org.eclipse.jgit.treewalk",
+ org.eclipse.jgit.transport;version="5.3.7";
   uses:="org.eclipse.jgit.transport.resolver,
    org.eclipse.jgit.revwalk,
    org.eclipse.jgit.internal.storage.pack,
@@ -132,33 +132,44 @@
    org.eclipse.jgit.util,
    org.eclipse.jgit.util.io,
    org.eclipse.jgit.internal.storage.file,
+   org.eclipse.jgit.internal.transport.parser,
    org.eclipse.jgit.lib,
    org.eclipse.jgit.transport.http,
    org.eclipse.jgit.errors,
    org.eclipse.jgit.storage.pack",
- org.eclipse.jgit.transport.http;version="5.2.3";uses:="javax.net.ssl",
- org.eclipse.jgit.transport.resolver;version="5.2.3";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.transport",
- org.eclipse.jgit.treewalk;version="5.2.3";
+ org.eclipse.jgit.transport.http;version="5.3.7";uses:="javax.net.ssl",
+ org.eclipse.jgit.transport.resolver;version="5.3.7";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.transport",
+ org.eclipse.jgit.treewalk;version="5.3.7";
   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="5.2.3";uses:="org.eclipse.jgit.treewalk",
- org.eclipse.jgit.util;version="5.2.3";
+ org.eclipse.jgit.treewalk.filter;version="5.3.7";uses:="org.eclipse.jgit.treewalk",
+ org.eclipse.jgit.util;version="5.3.7";
   uses:="org.eclipse.jgit.lib,
    org.eclipse.jgit.transport.http,
    org.eclipse.jgit.storage.file,
    org.ietf.jgss",
- org.eclipse.jgit.util.io;version="5.2.3",
- org.eclipse.jgit.util.sha1;version="5.2.3",
- org.eclipse.jgit.util.time;version="5.2.3"
+ org.eclipse.jgit.util.io;version="5.3.7",
+ org.eclipse.jgit.util.sha1;version="5.3.7",
+ org.eclipse.jgit.util.time;version="5.3.7"
 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)",
  javax.crypto,
  javax.net.ssl,
+ org.bouncycastle;version="[1.60.0,2.0.0)",
+ org.bouncycastle.bcpg;version="[1.60.0,2.0.0)",
+ org.bouncycastle.gpg;version="[1.60.0,2.0.0)",
+ org.bouncycastle.gpg.keybox;version="[1.60.0,2.0.0)",
+ org.bouncycastle.jce.provider;version="[1.60.0,2.0.0)",
+ org.bouncycastle.openpgp;version="[1.60.0,2.0.0)",
+ org.bouncycastle.openpgp.jcajce;version="[1.60.0,2.0.0)",
+ org.bouncycastle.openpgp.operator;version="[1.60.0,2.0.0)",
+ org.bouncycastle.openpgp.operator.jcajce;version="[1.60.0,2.0.0)",
+ org.bouncycastle.util.encoders;version="[1.60.0,2.0.0)",
  org.slf4j;version="[1.7.0,2.0.0)",
  org.xml.sax,
  org.xml.sax.helpers
diff --git a/org.eclipse.jgit/META-INF/SOURCE-MANIFEST.MF b/org.eclipse.jgit/META-INF/SOURCE-MANIFEST.MF
index 8e22086..691174a 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: 5.2.3.qualifier
-Eclipse-SourceBundle: org.eclipse.jgit;version="5.2.3.qualifier";roots="."
+Bundle-Version: 5.3.7.qualifier
+Eclipse-SourceBundle: org.eclipse.jgit;version="5.3.7.qualifier";roots="."
diff --git a/org.eclipse.jgit/pom.xml b/org.eclipse.jgit/pom.xml
index c30d648..cec9e48 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>5.2.3-SNAPSHOT</version>
+    <version>5.3.7-SNAPSHOT</version>
   </parent>
 
   <artifactId>org.eclipse.jgit</artifactId>
@@ -84,12 +84,26 @@
       <artifactId>JavaEWAH</artifactId>
     </dependency>
 
-
     <dependency>
       <groupId>org.slf4j</groupId>
       <artifactId>slf4j-api</artifactId>
     </dependency>
 
+    <dependency>
+      <groupId>org.bouncycastle</groupId>
+      <artifactId>bcpg-jdk15on</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>org.bouncycastle</groupId>
+      <artifactId>bcprov-jdk15on</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>org.bouncycastle</groupId>
+      <artifactId>bcpkix-jdk15on</artifactId>
+    </dependency>
+
   </dependencies>
 
   <build>
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 ebb0414..c41a565 100644
--- a/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties
+++ b/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties
@@ -196,6 +196,7 @@
 createNewFileFailed=Could not create new file {0}
 createRequiresZeroOldId=Create requires old ID to be zero
 credentialPassword=Password
+credentialPassphrase=Passphrase
 credentialUsername=Username
 daemonAlreadyRunning=Daemon already running
 daysAgo={0} days ago
@@ -289,6 +290,14 @@
 funnyRefname=funny refname
 gcFailed=Garbage collection failed.
 gcTooManyUnpruned=Too many loose, unpruneable objects after garbage collection.  Consider adjusting gc.auto or gc.pruneExpire.
+gpgFailedToParseSecretKey=Failed to parse secret key file in directory: {0}. Is the entered passphrase correct?
+gpgNoCredentialsProvider=missing credentials provider
+gpgNoKeyring=neither pubring.kbx nor secring.gpg files found
+gpgNoKeyInLegacySecring=no matching secret key found in legacy secring.gpg for key or user id: {0}
+gpgNoPublicKeyFound=Unable to find a public-key with key or user id: {0}
+gpgNoSecretKeyForPublicKey=unable to find associated secret key for public key: {0}
+gpgKeyInfo=GPG Key (fingerprint {0})
+gpgSigningCancelled=Signing was cancelled
 headRequiredToStash=HEAD required to stash local changes
 hoursAgo={0} hours ago
 httpConfigCannotNormalizeURL=Cannot normalize URL path {0}: too many .. segments
@@ -456,6 +465,7 @@
 oldIdMustNotBeNull=Expected old ID must not be null
 onlyOneFetchSupported=Only one fetch supported
 onlyOneOperationCallPerConnectionIsSupported=Only one operation call per connection is supported.
+onlyOpenPgpSupportedForSigning=OpenPGP is the only supported signing option with JGit at this time (gpg.format must be set to openpgp).
 openFilesMustBeAtLeast1=Open files must be >= 1
 openingConnection=Opening connection
 operationCanceled=Operation {0} was canceled
@@ -531,8 +541,9 @@
 remoteDoesNotHaveSpec=Remote does not have {0} available for fetch.
 remoteDoesNotSupportSmartHTTPPush=remote does not support smart HTTP push
 remoteHungUpUnexpectedly=remote hung up unexpectedly
-remoteNameCantBeNull=Remote name can't be null.
-renameBranchFailedBecauseTag=Can not rename as Ref {0} is a tag
+remoteNameCannotBeNull=Remote name cannot be null.
+renameBranchFailedAmbiguous=Cannot rename branch {0}; name is ambiguous: {1} or {2}
+renameBranchFailedNotABranch=Cannot rename {0}: this is not a branch
 renameBranchFailedUnknownReason=Rename failed with unknown reason
 renameBranchUnexpectedResult=Unexpected rename result {0}
 renameCancelled=Rename detection was cancelled
@@ -572,7 +583,7 @@
 sequenceTooLargeForDiffAlgorithm=Sequence too large for difference algorithm.
 serviceNotEnabledNoName=Service not enabled
 serviceNotPermitted={1} not permitted on ''{0}''
-sha1CollisionDetected1=SHA-1 collision detected on {0}
+sha1CollisionDetected=SHA-1 collision detected on {0}
 shallowCommitsAlreadyInitialized=Shallow commits have already been initialized
 shallowPacksRequireDepthWalk=Shallow packs require a DepthWalk
 shortCompressedStreamAt=Short compressed stream at {0}
@@ -663,6 +674,7 @@
 unableToReadPackfile=Unable to read packfile {0}
 unableToRemovePath=Unable to remove path ''{0}''
 unableToWrite=Unable to write {0}
+unableToSignCommitNoSecretKey=Unable to sign commit. Signing key not available.
 unauthorized=Unauthorized
 unencodeableFile=Unencodable file: {0}
 unexpectedCompareResult=Unexpected metadata comparison result: {0}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/CheckoutCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/CheckoutCommand.java
index 455a2e6..e05f6f1 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/CheckoutCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/CheckoutCommand.java
@@ -162,7 +162,9 @@ private Stage(int number) {
 
 	private String name;
 
-	private boolean force = false;
+	private boolean forceRefUpdate = false;
+
+	private boolean forced = false;
 
 	private boolean createBranch = false;
 
@@ -269,7 +271,11 @@ public Ref call() throws GitAPIException, RefAlreadyExistsException,
 			try {
 				dco = new DirCacheCheckout(repo, headTree, dc,
 						newCommit.getTree());
-				dco.setFailOnConflict(!force);
+				dco.setFailOnConflict(true);
+				dco.setForce(forced);
+				if (forced) {
+					dco.setFailOnConflict(false);
+				}
 				dco.setProgressMonitor(monitor);
 				try {
 					dco.checkout();
@@ -286,7 +292,7 @@ public Ref call() throws GitAPIException, RefAlreadyExistsException,
 				ref = null;
 			String toName = Repository.shortenRefName(name);
 			RefUpdate refUpdate = repo.updateRef(Constants.HEAD, ref == null);
-			refUpdate.setForceUpdate(force);
+			refUpdate.setForceUpdate(forceRefUpdate);
 			refUpdate.setRefLogMessage(refLogMessage + " to " + toName, false); //$NON-NLS-1$
 			Result updateResult;
 			if (ref != null)
@@ -666,10 +672,54 @@ public CheckoutCommand setOrphan(boolean orphan) {
 	 *            set to a new start-point; if false, the existing branch will
 	 *            not be changed
 	 * @return this instance
+	 * @deprecated this method was badly named comparing its semantics to native
+	 *             git's checkout --force option, use
+	 *             {@link #setForceRefUpdate(boolean)} instead
 	 */
+	@Deprecated
 	public CheckoutCommand setForce(boolean force) {
+		return setForceRefUpdate(force);
+	}
+
+	/**
+	 * Specify to force the ref update in case of a branch switch.
+	 *
+	 * In releases prior to 5.2 this method was called setForce() but this name
+	 * was misunderstood to implement native git's --force option, which is not
+	 * true.
+	 *
+	 * @param forceRefUpdate
+	 *            if <code>true</code> and the branch with the given name
+	 *            already exists, the start-point of an existing branch will be
+	 *            set to a new start-point; if false, the existing branch will
+	 *            not be changed
+	 * @return this instance
+	 * @since 5.3
+	 */
+	public CheckoutCommand setForceRefUpdate(boolean forceRefUpdate) {
 		checkCallable();
-		this.force = force;
+		this.forceRefUpdate = forceRefUpdate;
+		return this;
+	}
+
+	/**
+	 * Allow a checkout even if the workingtree or index differs from HEAD. This
+	 * matches native git's '--force' option.
+	 *
+	 * JGit releases before 5.2 had a method <code>setForce()</code> offering
+	 * semantics different from this new <code>setForced()</code>. This old
+	 * semantic can now be found in {@link #setForceRefUpdate(boolean)}
+	 *
+	 * @param forced
+	 *            if set to <code>true</code> then allow the checkout even if
+	 *            workingtree or index doesn't match HEAD. Overwrite workingtree
+	 *            files and index content with the new content in this case.
+	 * @return this instance
+	 * @since 5.3
+	 */
+	public CheckoutCommand setForced(boolean forced) {
+		checkCallable();
+		this.forced = forced;
 		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 10a54ee..9f63d0f 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/CloneCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/CloneCommand.java
@@ -303,18 +303,25 @@ private FetchResult fetch(Repository clonedRepo, URIish u)
 	}
 
 	private List<RefSpec> calculateRefSpecs(boolean fetchAll, String dst) {
-		RefSpec wcrs = new RefSpec();
-		wcrs = wcrs.setForceUpdate(true);
-		wcrs = wcrs.setSourceDestination(Constants.R_HEADS + '*', dst);
+		RefSpec heads = new RefSpec();
+		heads = heads.setForceUpdate(true);
+		heads = heads.setSourceDestination(Constants.R_HEADS + '*', dst);
 		List<RefSpec> specs = new ArrayList<>();
 		if (!fetchAll) {
+			RefSpec tags = new RefSpec();
+			tags = tags.setForceUpdate(true);
+			tags = tags.setSourceDestination(Constants.R_TAGS + '*',
+					Constants.R_TAGS + '*');
 			for (String selectedRef : branchesToClone) {
-				if (wcrs.matchSource(selectedRef)) {
-					specs.add(wcrs.expandFromSource(selectedRef));
+				if (heads.matchSource(selectedRef)) {
+					specs.add(heads.expandFromSource(selectedRef));
+				} else if (tags.matchSource(selectedRef)) {
+					specs.add(tags.expandFromSource(selectedRef));
 				}
 			}
 		} else {
-			specs.add(wcrs);
+			// We'll fetch the tags anyway.
+			specs.add(heads);
 		}
 		return specs;
 	}
@@ -590,11 +597,15 @@ public CloneCommand setProgressMonitor(ProgressMonitor monitor) {
 	}
 
 	/**
-	 * Set whether all branches have to be fetched
+	 * Set whether all branches have to be fetched.
+	 * <p>
+	 * If {@code false}, use {@link #setBranchesToClone(Collection)} to define
+	 * what will be cloned. If neither are set, all branches will be cloned.
+	 * </p>
 	 *
 	 * @param cloneAllBranches
-	 *            true when all branches have to be fetched (indicates wildcard
-	 *            in created fetch refspec), false otherwise.
+	 *            {@code true} when all branches have to be fetched (indicates
+	 *            wildcard in created fetch refspec), {@code false} otherwise.
 	 * @return {@code this}
 	 */
 	public CloneCommand setCloneAllBranches(boolean cloneAllBranches) {
@@ -616,12 +627,17 @@ public CloneCommand setCloneSubmodules(boolean cloneSubmodules) {
 	}
 
 	/**
-	 * Set branches to clone
+	 * Set the branches or tags to clone.
+	 * <p>
+	 * This is ignored if {@link #setCloneAllBranches(boolean)
+	 * setCloneAllBranches(true)} is used. If {@code branchesToClone} is
+	 * {@code null} or empty, it's also ignored and all branches will be cloned.
+	 * </p>
 	 *
 	 * @param branchesToClone
-	 *            collection of branches to clone. Ignored when allSelected is
-	 *            true. Must be specified as full ref names (e.g.
-	 *            <code>refs/heads/master</code>).
+	 *            collection of branches to clone. Must be specified as full ref
+	 *            names (e.g. {@code refs/heads/master} or
+	 *            {@code refs/tags/v1.0.0}).
 	 * @return {@code this}
 	 */
 	public CloneCommand setBranchesToClone(Collection<String> branchesToClone) {
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 cea28fa..61d51cc 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/CommitCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/CommitCommand.java
@@ -61,6 +61,7 @@
 import org.eclipse.jgit.api.errors.NoHeadException;
 import org.eclipse.jgit.api.errors.NoMessageException;
 import org.eclipse.jgit.api.errors.UnmergedPathsException;
+import org.eclipse.jgit.api.errors.UnsupportedSigningFormatException;
 import org.eclipse.jgit.api.errors.WrongRepositoryStateException;
 import org.eclipse.jgit.dircache.DirCache;
 import org.eclipse.jgit.dircache.DirCacheBuildIterator;
@@ -76,6 +77,9 @@
 import org.eclipse.jgit.lib.CommitBuilder;
 import org.eclipse.jgit.lib.Constants;
 import org.eclipse.jgit.lib.FileMode;
+import org.eclipse.jgit.lib.GpgConfig;
+import org.eclipse.jgit.lib.GpgConfig.GpgFormat;
+import org.eclipse.jgit.lib.GpgSigner;
 import org.eclipse.jgit.lib.ObjectId;
 import org.eclipse.jgit.lib.ObjectInserter;
 import org.eclipse.jgit.lib.PersonIdent;
@@ -84,10 +88,12 @@
 import org.eclipse.jgit.lib.RefUpdate.Result;
 import org.eclipse.jgit.lib.Repository;
 import org.eclipse.jgit.lib.RepositoryState;
+import org.eclipse.jgit.lib.internal.BouncyCastleGpgSigner;
 import org.eclipse.jgit.revwalk.RevCommit;
 import org.eclipse.jgit.revwalk.RevObject;
 import org.eclipse.jgit.revwalk.RevTag;
 import org.eclipse.jgit.revwalk.RevWalk;
+import org.eclipse.jgit.transport.CredentialsProvider;
 import org.eclipse.jgit.treewalk.CanonicalTreeParser;
 import org.eclipse.jgit.treewalk.FileTreeIterator;
 import org.eclipse.jgit.treewalk.TreeWalk;
@@ -139,6 +145,14 @@ public class CommitCommand extends GitCommand<RevCommit> {
 
 	private Boolean allowEmpty;
 
+	private Boolean signCommit;
+
+	private String signingKey;
+
+	private GpgSigner gpgSigner;
+
+	private CredentialsProvider credentialsProvider;
+
 	/**
 	 * Constructor for CommitCommand
 	 *
@@ -147,6 +161,7 @@ public class CommitCommand extends GitCommand<RevCommit> {
 	 */
 	protected CommitCommand(Repository repo) {
 		super(repo);
+		this.credentialsProvider = CredentialsProvider.getDefault();
 	}
 
 	/**
@@ -251,6 +266,12 @@ public RevCommit call() throws GitAPIException, NoHeadException,
 
 				commit.setParentIds(parents);
 				commit.setTreeId(indexTreeId);
+
+				if (signCommit.booleanValue()) {
+					gpgSigner.sign(commit, signingKey, committer,
+							credentialsProvider);
+				}
+
 				ObjectId commitId = odi.insert(commit);
 				odi.flush();
 
@@ -517,9 +538,10 @@ private int lookupOnly(String pathString) {
 	 *
 	 * @throws NoMessageException
 	 *             if the commit message has not been specified
+	 * @throws UnsupportedSigningFormatException if the configured gpg.format is not supported
 	 */
 	private void processOptions(RepositoryState state, RevWalk rw)
-			throws NoMessageException {
+			throws NoMessageException, UnsupportedSigningFormatException {
 		if (committer == null)
 			committer = new PersonIdent(repo);
 		if (author == null && !amend)
@@ -572,6 +594,25 @@ private void processOptions(RepositoryState state, RevWalk rw)
 			// as long as we don't support -C option we have to have
 			// an explicit message
 			throw new NoMessageException(JGitText.get().commitMessageNotSpecified);
+
+		GpgConfig gpgConfig = new GpgConfig(repo.getConfig());
+		if (signCommit == null) {
+			signCommit = gpgConfig.isSignCommits() ? Boolean.TRUE
+					: Boolean.FALSE;
+		}
+		if (signingKey == null) {
+			signingKey = gpgConfig.getSigningKey();
+		}
+		if (gpgSigner == null) {
+			if (gpgConfig.getKeyFormat() != GpgFormat.OPENPGP) {
+				throw new UnsupportedSigningFormatException(
+						JGitText.get().onlyOpenPgpSupportedForSigning);
+			}
+			gpgSigner = GpgSigner.getDefault();
+			if (gpgSigner == null) {
+				gpgSigner = new BouncyCastleGpgSigner();
+			}
+		}
 	}
 
 	private boolean isMergeDuringRebase(RepositoryState state) {
@@ -873,4 +914,55 @@ public CommitCommand setHookOutputStream(String hookName,
 		hookOutRedirect.put(hookName, hookStdOut);
 		return this;
 	}
+
+	/**
+	 * Sets the signing key
+	 * <p>
+	 * Per spec of user.signingKey: this will be sent to the GPG program as is,
+	 * i.e. can be anything supported by the GPG program.
+	 * </p>
+	 * <p>
+	 * Note, if none was set or <code>null</code> is specified a default will be
+	 * obtained from the configuration.
+	 * </p>
+	 *
+	 * @param signingKey
+	 *            signing key (maybe <code>null</code>)
+	 * @return {@code this}
+	 * @since 5.3
+	 */
+	public CommitCommand setSigningKey(String signingKey) {
+		checkCallable();
+		this.signingKey = signingKey;
+		return this;
+	}
+
+	/**
+	 * Sets whether the commit should be signed.
+	 *
+	 * @param sign
+	 *            <code>true</code> to sign, <code>false</code> to not sign and
+	 *            <code>null</code> for default behavior (read from
+	 *            configuration)
+	 * @return {@code this}
+	 * @since 5.3
+	 */
+	public CommitCommand setSign(Boolean sign) {
+		checkCallable();
+		this.signCommit = sign;
+		return this;
+	}
+
+	/**
+	 * Sets a {@link CredentialsProvider}
+	 *
+	 * @param credentialsProvider
+	 *            the provider to use when querying for credentials (eg., during
+	 *            signing)
+	 * @since 5.3
+	 */
+	public void setCredentialsProvider(
+			CredentialsProvider credentialsProvider) {
+		this.credentialsProvider = credentialsProvider;
+	}
 }
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 73e93a1..2c9c5f2 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/FetchCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/FetchCommand.java
@@ -193,7 +193,8 @@ private void fetchSubmodules(FetchResult results)
 					// updated to an object that is not currently present in the
 					// submodule.
 					if ((recurseMode == FetchRecurseSubmodulesMode.ON_DEMAND
-							&& !submoduleRepo.hasObject(walk.getObjectId()))
+							&& !submoduleRepo.getObjectDatabase()
+									.has(walk.getObjectId()))
 							|| recurseMode == FetchRecurseSubmodulesMode.YES) {
 						FetchCommand f = new FetchCommand(submoduleRepo)
 								.setProgressMonitor(monitor)
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 9653c36..0e3d000 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/RebaseCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/RebaseCommand.java
@@ -158,11 +158,14 @@ public class RebaseCommand extends GitCommand<RebaseResult> {
 
 	private static final String ONTO = "onto"; //$NON-NLS-1$
 
-	private static final String ONTO_NAME = "onto-name"; //$NON-NLS-1$
+	private static final String ONTO_NAME = "onto_name"; //$NON-NLS-1$
 
 	private static final String PATCH = "patch"; //$NON-NLS-1$
 
-	private static final String REBASE_HEAD = "head"; //$NON-NLS-1$
+	private static final String REBASE_HEAD = "orig-head"; //$NON-NLS-1$
+
+	/** Pre git 1.7.6 file name for {@link #REBASE_HEAD}. */
+	private static final String REBASE_HEAD_LEGACY = "head"; //$NON-NLS-1$
 
 	private static final String AMEND = "amend"; //$NON-NLS-1$
 
@@ -177,6 +180,10 @@ public class RebaseCommand extends GitCommand<RebaseResult> {
 	/**
 	 * The folder containing the hashes of (potentially) rewritten commits when
 	 * --preserve-merges is used.
+	 * <p>
+	 * Native git rebase --merge uses a <em>file</em> of that name to record
+	 * commits to copy notes at the end of the whole rebase.
+	 * </p>
 	 */
 	private static final String REWRITTEN = "rewritten"; //$NON-NLS-1$
 
@@ -289,7 +296,7 @@ public RebaseResult call() throws GitAPIException, NoHeadException,
 				}
 				this.upstreamCommit = walk.parseCommit(repo
 						.resolve(upstreamCommitId));
-				preserveMerges = rebaseState.getRewrittenDir().exists();
+				preserveMerges = rebaseState.getRewrittenDir().isDirectory();
 				break;
 			case BEGIN:
 				autoStash();
@@ -1120,10 +1127,14 @@ else if (!isInteractive() && walk.isMergedInto(headCommit, upstream)) {
 
 		repo.writeOrigHead(headId);
 		rebaseState.createFile(REBASE_HEAD, headId.name());
+		rebaseState.createFile(REBASE_HEAD_LEGACY, headId.name());
 		rebaseState.createFile(HEAD_NAME, headName);
 		rebaseState.createFile(ONTO, upstreamCommit.name());
 		rebaseState.createFile(ONTO_NAME, upstreamCommitName);
-		if (isInteractive()) {
+		if (isInteractive() || preserveMerges) {
+			// --preserve-merges is an interactive mode for native git. Without
+			// this, native git rebase --continue after a conflict would fall
+			// into merge mode.
 			rebaseState.createFile(INTERACTIVE, ""); //$NON-NLS-1$
 		}
 		rebaseState.createFile(QUIET, ""); //$NON-NLS-1$
@@ -1333,8 +1344,8 @@ private void checkParameters() throws WrongRepositoryStateException {
 
 	private RebaseResult abort(RebaseResult result) throws IOException,
 			GitAPIException {
+		ObjectId origHead = getOriginalHead();
 		try {
-			ObjectId origHead = repo.readOrigHead();
 			String commitId = origHead != null ? origHead.name() : null;
 			monitor.beginTask(MessageFormat.format(
 					JGitText.get().abortingRebase, commitId),
@@ -1373,7 +1384,7 @@ private RebaseResult abort(RebaseResult result) throws IOException,
 				// update the HEAD
 				res = refUpdate.link(headName);
 			} else {
-				refUpdate.setNewObjectId(repo.readOrigHead());
+				refUpdate.setNewObjectId(origHead);
 				res = refUpdate.forceUpdate();
 
 			}
@@ -1400,6 +1411,19 @@ private RebaseResult abort(RebaseResult result) throws IOException,
 		}
 	}
 
+	private ObjectId getOriginalHead() throws IOException {
+		try {
+			return ObjectId.fromString(rebaseState.readFile(REBASE_HEAD));
+		} catch (FileNotFoundException e) {
+			try {
+				return ObjectId
+						.fromString(rebaseState.readFile(REBASE_HEAD_LEGACY));
+			} catch (FileNotFoundException ex) {
+				return repo.readOrigHead();
+			}
+		}
+	}
+
 	private boolean checkoutCommit(String headName, RevCommit commit)
 			throws IOException,
 			CheckoutConflictException {
@@ -1706,7 +1730,20 @@ public File getRewrittenDir() {
 		}
 
 		public String readFile(String name) throws IOException {
-			return readFile(getDir(), name);
+			try {
+				return readFile(getDir(), name);
+			} catch (FileNotFoundException e) {
+				if (ONTO_NAME.equals(name)) {
+					// Older JGit mistakenly wrote a file "onto-name" instead of
+					// "onto_name". Try that wrong name just in case somebody
+					// upgraded while a rebase started by JGit was in progress.
+					File oldFile = getFile(ONTO_NAME.replace('_', '-'));
+					if (oldFile.exists()) {
+						return readFile(oldFile);
+					}
+				}
+				throw e;
+			}
 		}
 
 		public void createFile(String name, String content) throws IOException {
@@ -1721,14 +1758,18 @@ public String getPath(String name) {
 			return (getDir().getName() + "/" + name); //$NON-NLS-1$
 		}
 
-		private static String readFile(File directory, String fileName)
-				throws IOException {
-			byte[] content = IO.readFully(new File(directory, fileName));
+		private static String readFile(File file) throws IOException {
+			byte[] content = IO.readFully(file);
 			// strip off the last LF
 			int end = RawParseUtils.prevLF(content, content.length);
 			return RawParseUtils.decode(content, 0, end + 1);
 		}
 
+		private static String readFile(File directory, String fileName)
+				throws IOException {
+			return readFile(new File(directory, fileName));
+		}
+
 		private static void createFile(File parentDir, String name,
 				String content)
 				throws IOException {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/RemoteRemoveCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/RemoteRemoveCommand.java
index 7a5885c..016cb15 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/RemoteRemoveCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/RemoteRemoveCommand.java
@@ -65,7 +65,7 @@
  */
 public class RemoteRemoveCommand extends GitCommand<RemoteConfig> {
 
-	private String name;
+	private String remoteName;
 
 	/**
 	 * <p>
@@ -84,9 +84,24 @@ protected RemoteRemoveCommand(Repository repo) {
 	 *
 	 * @param name
 	 *            a remote name
+	 * @deprecated use {@link #setRemoteName} instead
 	 */
+	@Deprecated
 	public void setName(String name) {
-		this.name = name;
+		this.remoteName = name;
+	}
+
+	/**
+	 * The name of the remote to remove.
+	 *
+	 * @param remoteName
+	 *            a remote name
+	 * @return {@code this}
+	 * @since 5.3
+	 */
+	public RemoteRemoveCommand setRemoteName(String remoteName) {
+		this.remoteName = remoteName;
+		return this;
 	}
 
 	/**
@@ -101,8 +116,8 @@ public RemoteConfig call() throws GitAPIException {
 
 		try {
 			StoredConfig config = repo.getConfig();
-			RemoteConfig remote = new RemoteConfig(config, name);
-			config.unsetSection(ConfigConstants.CONFIG_KEY_REMOTE, name);
+			RemoteConfig remote = new RemoteConfig(config, remoteName);
+			config.unsetSection(ConfigConstants.CONFIG_KEY_REMOTE, remoteName);
 			config.save();
 			return remote;
 		} catch (IOException | URISyntaxException e) {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/RemoteSetUrlCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/RemoteSetUrlCommand.java
index d7b7a31..21d4023 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/RemoteSetUrlCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/RemoteSetUrlCommand.java
@@ -54,7 +54,7 @@
 import org.eclipse.jgit.transport.URIish;
 
 /**
- * Used to to change the URL of a remote.
+ * Used to change the URL of a remote.
  *
  * This class has setters for all supported options and arguments of this
  * command and a {@link #call()} method to finally execute the command.
@@ -66,11 +66,28 @@
  */
 public class RemoteSetUrlCommand extends GitCommand<RemoteConfig> {
 
-	private String name;
+	/**
+	 * The available URI types for the remote.
+	 *
+	 * @since 5.3
+	 */
+	public enum UriType {
+		/**
+		 * Fetch URL for the remote.
+		 */
+		FETCH,
+		/**
+		 * Push URL for the remote.
+		 */
+		PUSH
+	}
 
-	private URIish uri;
 
-	private boolean push;
+	private String remoteName;
+
+	private URIish remoteUri;
+
+	private UriType type;
 
 	/**
 	 * <p>
@@ -89,9 +106,24 @@ protected RemoteSetUrlCommand(Repository repo) {
 	 *
 	 * @param name
 	 *            a remote name
+	 * @deprecated use {@link #setRemoteName} instead
 	 */
+	@Deprecated
 	public void setName(String name) {
-		this.name = name;
+		this.remoteName = name;
+	}
+
+	/**
+	 * The name of the remote to change the URL for.
+	 *
+	 * @param remoteName
+	 *            a remote remoteName
+	 * @return {@code this}
+	 * @since 5.3
+	 */
+	public RemoteSetUrlCommand setRemoteName(String remoteName) {
+		this.remoteName = remoteName;
+		return this;
 	}
 
 	/**
@@ -99,9 +131,24 @@ public void setName(String name) {
 	 *
 	 * @param uri
 	 *            an URL for the remote
+	 * @deprecated use {@link #setRemoteUri} instead
 	 */
+	@Deprecated
 	public void setUri(URIish uri) {
-		this.uri = uri;
+		this.remoteUri = uri;
+	}
+
+	/**
+	 * The new URL for the remote.
+	 *
+	 * @param remoteUri
+	 *            an URL for the remote
+	 * @return {@code this}
+	 * @since 5.3
+	 */
+	public RemoteSetUrlCommand setRemoteUri(URIish remoteUri) {
+		this.remoteUri = remoteUri;
+		return this;
 	}
 
 	/**
@@ -110,9 +157,28 @@ public void setUri(URIish uri) {
 	 * @param push
 	 *            <code>true</code> to set the push url, <code>false</code> to
 	 *            set the fetch url
+	 * @deprecated use {@link #setUriType} instead
 	 */
+	@Deprecated
 	public void setPush(boolean push) {
-		this.push = push;
+		if (push) {
+			setUriType(UriType.PUSH);
+		} else {
+			setUriType(UriType.FETCH);
+		}
+	}
+
+	/**
+	 * Whether to change the push URL of the remote instead of the fetch URL.
+	 *
+	 * @param type
+	 *            the <code>UriType</code> value to set
+	 * @return {@code this}
+	 * @since 5.3
+	 */
+	public RemoteSetUrlCommand setUriType(UriType type) {
+		this.type = type;
+		return this;
 	}
 
 	/**
@@ -127,8 +193,8 @@ public RemoteConfig call() throws GitAPIException {
 
 		try {
 			StoredConfig config = repo.getConfig();
-			RemoteConfig remote = new RemoteConfig(config, name);
-			if (push) {
+			RemoteConfig remote = new RemoteConfig(config, remoteName);
+			if (type == UriType.PUSH) {
 				List<URIish> uris = remote.getPushURIs();
 				if (uris.size() > 1) {
 					throw new JGitInternalException(
@@ -136,7 +202,7 @@ public RemoteConfig call() throws GitAPIException {
 				} else if (uris.size() == 1) {
 					remote.removePushURI(uris.get(0));
 				}
-				remote.addPushURI(uri);
+				remote.addPushURI(remoteUri);
 			} else {
 				List<URIish> uris = remote.getURIs();
 				if (uris.size() > 1) {
@@ -145,7 +211,7 @@ public RemoteConfig call() throws GitAPIException {
 				} else if (uris.size() == 1) {
 					remote.removeURI(uris.get(0));
 				}
-				remote.addURI(uri);
+				remote.addURI(remoteUri);
 			}
 
 			remote.update(config);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/RenameBranchCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/RenameBranchCommand.java
index 24d9dd4..7e8c33c 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/RenameBranchCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/RenameBranchCommand.java
@@ -94,25 +94,38 @@ public Ref call() throws GitAPIException, RefNotFoundException, InvalidRefNameEx
 			RefAlreadyExistsException, DetachedHeadException {
 		checkCallable();
 
-		if (newName == null)
+		if (newName == null) {
 			throw new InvalidRefNameException(MessageFormat.format(JGitText
 					.get().branchNameInvalid, "<null>")); //$NON-NLS-1$
-
+		}
 		try {
 			String fullOldName;
 			String fullNewName;
-			if (repo.findRef(newName) != null)
-				throw new RefAlreadyExistsException(MessageFormat.format(
-						JGitText.get().refAlreadyExists1, newName));
 			if (oldName != null) {
-				Ref ref = repo.findRef(oldName);
-				if (ref == null)
-					throw new RefNotFoundException(MessageFormat.format(
-							JGitText.get().refNotResolved, oldName));
-				if (ref.getName().startsWith(Constants.R_TAGS))
-					throw new RefNotFoundException(MessageFormat.format(
-							JGitText.get().renameBranchFailedBecauseTag,
-							oldName));
+				// Don't just rely on findRef -- if there are local and remote
+				// branches with the same name, and oldName is a short name, it
+				// does not uniquely identify the ref and we might end up
+				// renaming the wrong branch or finding a tag instead even
+				// if a unique branch for the name exists!
+				//
+				// OldName may be a either a short or a full name.
+				Ref ref = repo.exactRef(oldName);
+				if (ref == null) {
+					ref = repo.exactRef(Constants.R_HEADS + oldName);
+					Ref ref2 = repo.exactRef(Constants.R_REMOTES + oldName);
+					if (ref != null && ref2 != null) {
+						throw new RefNotFoundException(MessageFormat.format(
+								JGitText.get().renameBranchFailedAmbiguous,
+								oldName, ref.getName(), ref2.getName()));
+					} else if (ref == null) {
+						if (ref2 != null) {
+							ref = ref2;
+						} else {
+							throw new RefNotFoundException(MessageFormat.format(
+									JGitText.get().refNotResolved, oldName));
+						}
+					}
+				}
 				fullOldName = ref.getName();
 			} else {
 				fullOldName = repo.getFullBranch();
@@ -124,26 +137,34 @@ public Ref call() throws GitAPIException, RefNotFoundException, InvalidRefNameEx
 					throw new DetachedHeadException();
 			}
 
-			if (fullOldName.startsWith(Constants.R_REMOTES))
+			if (fullOldName.startsWith(Constants.R_REMOTES)) {
 				fullNewName = Constants.R_REMOTES + newName;
-			else {
+			} else if (fullOldName.startsWith(Constants.R_HEADS)) {
 				fullNewName = Constants.R_HEADS + newName;
+			} else {
+				throw new RefNotFoundException(MessageFormat.format(
+						JGitText.get().renameBranchFailedNotABranch,
+						fullOldName));
 			}
 
-			if (!Repository.isValidRefName(fullNewName))
+			if (!Repository.isValidRefName(fullNewName)) {
 				throw new InvalidRefNameException(MessageFormat.format(JGitText
 						.get().branchNameInvalid, fullNewName));
-
+			}
+			if (repo.exactRef(fullNewName) != null) {
+				throw new RefAlreadyExistsException(MessageFormat
+						.format(JGitText.get().refAlreadyExists1, fullNewName));
+			}
 			RefRename rename = repo.renameRef(fullOldName, fullNewName);
 			Result renameResult = rename.rename();
 
 			setCallable(false);
 
-			if (Result.RENAMED != renameResult)
+			if (Result.RENAMED != renameResult) {
 				throw new JGitInternalException(MessageFormat.format(JGitText
 						.get().renameBranchUnexpectedResult, renameResult
 						.name()));
-
+			}
 			if (fullNewName.startsWith(Constants.R_HEADS)) {
 				String shortOldName = fullOldName.substring(Constants.R_HEADS
 						.length());
@@ -154,8 +175,9 @@ public Ref call() throws GitAPIException, RefNotFoundException, InvalidRefNameEx
 					String[] values = repoConfig.getStringList(
 							ConfigConstants.CONFIG_BRANCH_SECTION,
 							shortOldName, name);
-					if (values.length == 0)
+					if (values.length == 0) {
 						continue;
+					}
 					// Keep any existing values already configured for the
 					// new branch name
 					String[] existing = repoConfig.getStringList(
@@ -180,10 +202,11 @@ public Ref call() throws GitAPIException, RefNotFoundException, InvalidRefNameEx
 				repoConfig.save();
 			}
 
-			Ref resultRef = repo.findRef(newName);
-			if (resultRef == null)
+			Ref resultRef = repo.exactRef(fullNewName);
+			if (resultRef == null) {
 				throw new JGitInternalException(
 						JGitText.get().renameBranchFailedUnknownReason);
+			}
 			return resultRef;
 		} catch (IOException ioe) {
 			throw new JGitInternalException(ioe.getMessage(), ioe);
@@ -191,7 +214,13 @@ public Ref call() throws GitAPIException, RefNotFoundException, InvalidRefNameEx
 	}
 
 	/**
-	 * Set the new name of the branch
+	 * Sets the new short name of the branch.
+	 * <p>
+	 * The full name is constructed using the prefix of the branch to be renamed
+	 * defined by either {@link #setOldName(String)} or HEAD. If that old branch
+	 * is a local branch, the renamed branch also will be, and if the old branch
+	 * is a remote branch, so will be the renamed branch.
+	 * </p>
 	 *
 	 * @param newName
 	 *            the new name
@@ -204,7 +233,11 @@ public RenameBranchCommand setNewName(String newName) {
 	}
 
 	/**
-	 * Set the old name of the branch
+	 * Sets the old name of the branch.
+	 * <p>
+	 * {@code oldName} may be a short or a full name. Using a full name is
+	 * recommended to unambiguously identify the branch to be renamed.
+	 * </p>
 	 *
 	 * @param oldName
 	 *            the name of the branch to rename; if not set, the currently
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 ff7c4c6..aeb9395 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/StashApplyCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/StashApplyCommand.java
@@ -96,9 +96,9 @@ public class StashApplyCommand extends GitCommand<ObjectId> {
 
 	private String stashRef;
 
-	private boolean applyIndex = true;
+	private boolean restoreIndex = true;
 
-	private boolean applyUntracked = true;
+	private boolean restoreUntracked = true;
 
 	private boolean ignoreRepositoryState;
 
@@ -196,7 +196,7 @@ public ObjectId call() throws GitAPIException,
 					.getParent(1));
 			ObjectId stashHeadCommit = stashCommit.getParent(0);
 			ObjectId untrackedCommit = null;
-			if (applyUntracked && stashCommit.getParentCount() == 3)
+			if (restoreUntracked && stashCommit.getParentCount() == 3)
 				untrackedCommit = revWalk.parseCommit(stashCommit.getParent(2));
 
 			ResolveMerger merger = (ResolveMerger) strategy.newMerger(repo);
@@ -216,7 +216,7 @@ public ObjectId call() throws GitAPIException,
 						dc, merger.getResultTreeId());
 				dco.setFailOnConflict(true);
 				dco.checkout(); // Ignoring failed deletes....
-				if (applyIndex) {
+				if (restoreIndex) {
 					ResolveMerger ixMerger = (ResolveMerger) strategy
 							.newMerger(repo, true);
 					ixMerger.setCommitNames(new String[] { "stashed HEAD", //$NON-NLS-1$
@@ -277,9 +277,24 @@ public ObjectId call() throws GitAPIException,
 	 *
 	 * @param applyIndex
 	 *            true (default) if the command should restore the index state
+	 * @deprecated use {@link #setRestoreIndex} instead
 	 */
+	@Deprecated
 	public void setApplyIndex(boolean applyIndex) {
-		this.applyIndex = applyIndex;
+		this.restoreIndex = applyIndex;
+	}
+
+	/**
+	 * Whether to restore the index state
+	 *
+	 * @param restoreIndex
+	 *            true (default) if the command should restore the index state
+	 * @return {@code this}
+	 * @since 5.3
+	 */
+	public StashApplyCommand setRestoreIndex(boolean restoreIndex) {
+		this.restoreIndex = restoreIndex;
+		return this;
 	}
 
 	/**
@@ -302,9 +317,24 @@ public StashApplyCommand setStrategy(MergeStrategy strategy) {
 	 * @param applyUntracked
 	 *            true (default) if the command should restore untracked files
 	 * @since 3.4
+	 * @deprecated use {@link #setRestoreUntracked} instead
 	 */
+	@Deprecated
 	public void setApplyUntracked(boolean applyUntracked) {
-		this.applyUntracked = applyUntracked;
+		this.restoreUntracked = applyUntracked;
+	}
+
+	/**
+	 * Whether the command should restore untracked files
+	 *
+	 * @param restoreUntracked
+	 *            true (default) if the command should restore untracked files
+	 * @return {@code this}
+	 * @since 5.3
+	 */
+	public StashApplyCommand setRestoreUntracked(boolean restoreUntracked) {
+		this.restoreUntracked = restoreUntracked;
+		return this;
 	}
 
 	private void resetIndex(RevTree tree) throws IOException {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/JGitInternalException.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/JGitInternalException.java
index 57d8a13..c723da3 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/JGitInternalException.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/JGitInternalException.java
@@ -44,7 +44,7 @@
  * <p>
  * During command execution a lot of exceptions may be thrown. Some of them
  * represent error situations which can be handled specifically by the caller of
- * the command. But a lot of exceptions are so low-level that is is unlikely
+ * the command. But a lot of exceptions are so low-level that it is unlikely
  * that the caller of the command can handle them effectively. The huge number
  * of these low-level exceptions which are thrown by the commands lead to a
  * complicated and wide interface of the commands. Callers of the API have to
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/UnsupportedSigningFormatException.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/UnsupportedSigningFormatException.java
new file mode 100644
index 0000000..eb5db6a
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/UnsupportedSigningFormatException.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2018, Salesforce and
+ * other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v1.0 which accompanies this
+ * distribution, is reproduced below, and is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.eclipse.jgit.api.errors;
+
+/**
+ * Exception thrown when the configured gpg.format is not supported.
+ *
+ * @since 5.3
+ */
+public class UnsupportedSigningFormatException extends GitAPIException {
+	private static final long serialVersionUID = 1L;
+
+	/**
+	 * Constructor for UnsupportedGpgFormatException
+	 *
+	 * @param message
+	 *            error message
+	 * @param cause
+	 *            a {@link java.lang.Throwable}
+	 */
+	public UnsupportedSigningFormatException(String message, Throwable cause) {
+		super(message, cause);
+	}
+
+	/**
+	 * Constructor for UnsupportedGpgFormatException
+	 *
+	 * @param message
+	 *            error message
+	 */
+	public UnsupportedSigningFormatException(String message) {
+		super(message);
+	}
+}
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 bd41d90..6c0d90e 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/diff/RawText.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/diff/RawText.java
@@ -309,6 +309,74 @@ public static boolean isBinary(byte[] raw, int length) {
 	}
 
 	/**
+	 * Determine heuristically whether a byte array represents text content
+	 * using CR-LF as line separator.
+	 *
+	 * @param raw
+	 *            the raw file content.
+	 * @return {@code true} if raw is likely to be CR-LF delimited text,
+	 *         {@code false} otherwise
+	 * @since 5.3
+	 */
+	public static boolean isCrLfText(byte[] raw) {
+		return isCrLfText(raw, raw.length);
+	}
+
+	/**
+	 * Determine heuristically whether the bytes contained in a stream represent
+	 * text content using CR-LF as line separator.
+	 *
+	 * Note: Do not further use this stream after having called this method! The
+	 * stream may not be fully read and will be left at an unknown position
+	 * after consuming an unknown number of bytes. The caller is responsible for
+	 * closing the stream.
+	 *
+	 * @param raw
+	 *            input stream containing the raw file content.
+	 * @return {@code true} if raw is likely to be CR-LF delimited text,
+	 *         {@code false} otherwise
+	 * @throws java.io.IOException
+	 *             if input stream could not be read
+	 * @since 5.3
+	 */
+	public static boolean isCrLfText(InputStream raw) throws IOException {
+		byte[] buffer = new byte[FIRST_FEW_BYTES];
+		int cnt = 0;
+		while (cnt < buffer.length) {
+			int n = raw.read(buffer, cnt, buffer.length - cnt);
+			if (n == -1) {
+				break;
+			}
+			cnt += n;
+		}
+		return isCrLfText(buffer, cnt);
+	}
+
+	/**
+	 * Determine heuristically whether a byte array represents text content
+	 * using CR-LF as line separator.
+	 *
+	 * @param raw
+	 *            the raw file content.
+	 * @param length
+	 *            number of bytes in {@code raw} to evaluate.
+	 * @return {@code true} if raw is likely to be CR-LF delimited text,
+	 *         {@code false} otherwise
+	 * @since 5.3
+	 */
+	public static boolean isCrLfText(byte[] raw, int length) {
+		boolean has_crlf = false;
+		for (int ptr = 0; ptr < length - 1; ptr++) {
+			if (raw[ptr] == '\0') {
+				return false; // binary
+			} else if (raw[ptr] == '\r' && raw[ptr + 1] == '\n') {
+				has_crlf = true;
+			}
+		}
+		return has_crlf;
+	}
+
+	/**
 	 * Get the line delimiter for the first line.
 	 *
 	 * @since 2.0
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/diff/SequenceComparator.java b/org.eclipse.jgit/src/org/eclipse/jgit/diff/SequenceComparator.java
index ccd0055..3bc95a2 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/diff/SequenceComparator.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/diff/SequenceComparator.java
@@ -84,7 +84,7 @@ public abstract class SequenceComparator<S extends Sequence> {
 	 * method must produce the same integer result for both items.
 	 *
 	 * It is not required for two items to have different hash values if they
-	 * are are unequal according to the {@code equals()} method.
+	 * are unequal according to the {@code equals()} method.
 	 *
 	 * @param seq
 	 *            the sequence.
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 5897ffb..539f237 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/diff/SimilarityIndex.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/diff/SimilarityIndex.java
@@ -236,7 +236,7 @@ void sort() {
 	 * A region of a file is defined as a line in a text file or a fixed-size
 	 * block in a binary file. To prepare an index, each region in the file is
 	 * hashed; the values and counts of hashes are retained in a sorted table.
-	 * Define the similarity fraction F as the the count of matching regions
+	 * Define the similarity fraction F as the count of matching regions
 	 * between the two files divided between the maximum count of regions in
 	 * either file. The similarity score is F multiplied by the maxScore
 	 * constant, yielding a range [0, maxScore]. It is defined as maxScore for
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java
index 8aa97df..2d62286 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java
@@ -156,9 +156,11 @@ public CheckoutMetadata(EolStreamType eolStreamType,
 
 	private boolean failOnConflict = true;
 
+	private boolean force = false;
+
 	private ArrayList<String> toBeDeleted = new ArrayList<>();
 
-	private boolean emptyDirCache;
+	private boolean initialCheckout;
 
 	private boolean performingCheckout;
 
@@ -231,7 +233,7 @@ public DirCacheCheckout(Repository repo, ObjectId headCommitTree, DirCache dc,
 		this.headCommitTree = headCommitTree;
 		this.mergeCommitTree = mergeCommitTree;
 		this.workingTree = workingTree;
-		this.emptyDirCache = (dc == null) || (dc.getEntryCount() == 0);
+		this.initialCheckout = !repo.isBare() && !repo.getIndexFile().exists();
 	}
 
 	/**
@@ -430,11 +432,11 @@ void processEntry(CanonicalTreeParser m, DirCacheBuildIterator i,
 					if (mtime == null || mtime.equals(Instant.EPOCH)) {
 						entry.setLastModified(f.getEntryLastModifiedInstant());
 					}
-					keep(entry);
+					keep(entry, f);
 				}
 			} else
 				// The index contains a folder
-				keep(i.getDirCacheEntry());
+				keep(i.getDirCacheEntry(), f);
 		} else {
 			// There is no entry in the merge commit. Means: we want to delete
 			// what's currently in the index and working tree
@@ -824,14 +826,14 @@ void processEntry(CanonicalTreeParser h, CanonicalTreeParser m,
 
 				break;
 			case 0xDFD: // 3 4
-				keep(dce);
+				keep(dce, f);
 				break;
 			case 0xF0D: // 18
 				remove(name);
 				break;
 			case 0xDFF: // 5 5b 6 6b
 				if (equalIdAndMode(iId, iMode, mId, mMode))
-					keep(dce); // 5 6
+					keep(dce, f); // 5 6
 				else
 					conflict(name, dce, h, m); // 5b 6b
 				break;
@@ -861,7 +863,7 @@ void processEntry(CanonicalTreeParser h, CanonicalTreeParser m,
 					conflict(name, dce, h, m); // 9
 				break;
 			case 0xFD0: // keep without a rule
-				keep(dce);
+				keep(dce, f);
 				break;
 			case 0xFFD: // 12 13 14
 				if (equalIdAndMode(hId, hMode, iId, iMode))
@@ -881,7 +883,7 @@ void processEntry(CanonicalTreeParser h, CanonicalTreeParser m,
 					conflict(name, dce, h, m);
 				break;
 			default:
-				keep(dce);
+				keep(dce, f);
 			}
 			return;
 		}
@@ -964,10 +966,10 @@ else if (m == null)
 				// called before). Ignore the cached deletion and use what we
 				// find in Merge. Potentially updates the file.
 				if (equalIdAndMode(hId, hMode, mId, mMode)) {
-					if (emptyDirCache)
+					if (initialCheckout)
 						update(name, mId, mMode);
 					else
-						keep(dce);
+						keep(dce, f);
 				} else
 					conflict(name, dce, h, m);
 			}
@@ -1030,7 +1032,7 @@ else if (m == null)
 						// Nothing in Head
 						// Something in Index
 						// -> Merge contains nothing new. Keep the index.
-						keep(dce);
+						keep(dce, f);
 				} else
 					// Merge contains something and it is not the same as Index
 					// Nothing in Head
@@ -1179,7 +1181,7 @@ && isModified_IndexTree(name, iId, iMode, mId, mMode,
 					// to the other one.
 					// -> In all three cases we don't touch index and file.
 
-					keep(dce);
+					keep(dce, f);
 				}
 			}
 		}
@@ -1228,9 +1230,15 @@ private void conflict(String path, DirCacheEntry e, AbstractTreeIterator h, Abst
 		}
 	}
 
-	private void keep(DirCacheEntry e) {
+	private void keep(DirCacheEntry e, WorkingTreeIterator f)
+			throws IOException {
 		if (e != null && !FileMode.TREE.equals(e.getFileMode()))
 			builder.add(e);
+		if (force) {
+			if (f.isModified(e, true, this.walk.getObjectReader())) {
+				checkoutEntry(repo, e, this.walk.getObjectReader());
+			}
+		}
 	}
 
 	private void remove(String path) {
@@ -1265,6 +1273,20 @@ public void setFailOnConflict(boolean failOnConflict) {
 	}
 
 	/**
+	 * If <code>true</code>, dirty worktree files may be overridden. If
+	 * <code>false</code> dirty worktree files will not be overridden in order
+	 * not to delete unsaved content. This corresponds to native git's 'git
+	 * checkout -f' option. By default this option is set to false.
+	 *
+	 * @param force
+	 *            a boolean.
+	 * @since 5.3
+	 */
+	public void setForce(boolean force) {
+		this.force = force;
+	}
+
+	/**
 	 * This method implements how to handle conflicts when
 	 * {@link #failOnConflict} is false
 	 *
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 e9d86df..cb62925 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoCommand.java
@@ -147,7 +147,7 @@ public interface RemoteReader {
 		 *            The URI of the remote repository
 		 * @param ref
 		 *            Name of the ref to lookup. May be a short-hand form, e.g.
-		 *            "master" which is is automatically expanded to
+		 *            "master" which is automatically expanded to
 		 *            "refs/heads/master" if "refs/heads/master" already exists.
 		 * @return the sha1 of the remote repository, or null if the ref does
 		 *         not exist.
@@ -187,7 +187,7 @@ public interface RemoteReader {
 		 *            The URI of the remote repository
 		 * @param ref
 		 *            Name of the ref to lookup. May be a short-hand form, e.g.
-		 *            "master" which is is automatically expanded to
+		 *            "master" which is automatically expanded to
 		 *            "refs/heads/master" if "refs/heads/master" already exists.
 		 * @param path
 		 *            The relative path (inside the repo) to the file to read
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 f65e374..d51e052 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java
@@ -257,6 +257,7 @@ public static JGitText get() {
 	/***/ public String createNewFileFailed;
 	/***/ public String createRequiresZeroOldId;
 	/***/ public String credentialPassword;
+	/***/ public String credentialPassphrase;
 	/***/ public String credentialUsername;
 	/***/ public String daemonAlreadyRunning;
 	/***/ public String daysAgo;
@@ -350,6 +351,14 @@ public static JGitText get() {
 	/***/ public String funnyRefname;
 	/***/ public String gcFailed;
 	/***/ public String gcTooManyUnpruned;
+	/***/ public String gpgFailedToParseSecretKey;
+	/***/ public String gpgNoCredentialsProvider;
+	/***/ public String gpgNoKeyring;
+	/***/ public String gpgNoKeyInLegacySecring;
+	/***/ public String gpgNoPublicKeyFound;
+	/***/ public String gpgNoSecretKeyForPublicKey;
+	/***/ public String gpgKeyInfo;
+	/***/ public String gpgSigningCancelled;
 	/***/ public String headRequiredToStash;
 	/***/ public String hoursAgo;
 	/***/ public String httpConfigCannotNormalizeURL;
@@ -517,6 +526,7 @@ public static JGitText get() {
 	/***/ public String oldIdMustNotBeNull;
 	/***/ public String onlyOneFetchSupported;
 	/***/ public String onlyOneOperationCallPerConnectionIsSupported;
+	/***/ public String onlyOpenPgpSupportedForSigning;
 	/***/ public String openFilesMustBeAtLeast1;
 	/***/ public String openingConnection;
 	/***/ public String operationCanceled;
@@ -592,8 +602,9 @@ public static JGitText get() {
 	/***/ public String remoteDoesNotHaveSpec;
 	/***/ public String remoteDoesNotSupportSmartHTTPPush;
 	/***/ public String remoteHungUpUnexpectedly;
-	/***/ public String remoteNameCantBeNull;
-	/***/ public String renameBranchFailedBecauseTag;
+	/***/ public String remoteNameCannotBeNull;
+	/***/ public String renameBranchFailedAmbiguous;
+	/***/ public String renameBranchFailedNotABranch;
 	/***/ public String renameBranchFailedUnknownReason;
 	/***/ public String renameBranchUnexpectedResult;
 	/***/ public String renameCancelled;
@@ -633,7 +644,7 @@ public static JGitText get() {
 	/***/ public String sequenceTooLargeForDiffAlgorithm;
 	/***/ public String serviceNotEnabledNoName;
 	/***/ public String serviceNotPermitted;
-	/***/ public String sha1CollisionDetected1;
+	/***/ public String sha1CollisionDetected;
 	/***/ public String shallowCommitsAlreadyInitialized;
 	/***/ public String shallowPacksRequireDepthWalk;
 	/***/ public String shortCompressedStreamAt;
@@ -724,6 +735,7 @@ public static JGitText get() {
 	/***/ public String unableToReadPackfile;
 	/***/ public String unableToRemovePath;
 	/***/ public String unableToWrite;
+	/***/ public String unableToSignCommitNoSecretKey;
 	/***/ public String unauthorized;
 	/***/ public String unencodeableFile;
 	/***/ public String unexpectedCompareResult;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/BlockBasedFile.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/BlockBasedFile.java
index 58d12ab..c7d6c58 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/BlockBasedFile.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/BlockBasedFile.java
@@ -48,7 +48,6 @@
 import java.nio.ByteBuffer;
 import java.text.MessageFormat;
 
-import org.eclipse.jgit.annotations.Nullable;
 import org.eclipse.jgit.errors.PackInvalidException;
 import org.eclipse.jgit.internal.storage.pack.PackExt;
 
@@ -133,19 +132,19 @@ else if (size < cache.getBlockSize())
 	}
 
 	DfsBlock getOrLoadBlock(long pos, DfsReader ctx) throws IOException {
-		return cache.getOrLoad(this, pos, ctx, null);
+		try (LazyChannel c = new LazyChannel(ctx, desc, ext)) {
+			return cache.getOrLoad(this, pos, ctx, c);
+		}
 	}
 
-	DfsBlock readOneBlock(long pos, DfsReader ctx,
-			@Nullable ReadableChannel fileChannel) throws IOException {
+	DfsBlock readOneBlock(long pos, DfsReader ctx, ReadableChannel rc)
+			throws IOException {
 		if (invalid) {
 			throw new PackInvalidException(getFileName(), invalidatingCause);
 		}
 
 		ctx.stats.readBlock++;
 		long start = System.nanoTime();
-		ReadableChannel rc = fileChannel != null ? fileChannel
-				: ctx.db.openFile(desc, ext);
 		try {
 			int size = blockSize(rc);
 			pos = (pos / size) * size;
@@ -193,9 +192,6 @@ DfsBlock readOneBlock(long pos, DfsReader ctx,
 
 			return new DfsBlock(key, pos, buf);
 		} finally {
-			if (rc != fileChannel) {
-				rc.close();
-			}
 			ctx.stats.readBlockMicros += elapsedMicros(start);
 		}
 	}
@@ -211,4 +207,37 @@ static int read(ReadableChannel rc, ByteBuffer buf) throws IOException {
 	static long elapsedMicros(long start) {
 		return (System.nanoTime() - start) / 1000L;
 	}
+
+	/**
+	 * A supplier of readable channel that opens the channel lazily.
+	 */
+	private static class LazyChannel
+			implements AutoCloseable, DfsBlockCache.ReadableChannelSupplier {
+		private final DfsReader ctx;
+		private final DfsPackDescription desc;
+		private final PackExt ext;
+
+		private ReadableChannel rc;
+
+		LazyChannel(DfsReader ctx, DfsPackDescription desc, PackExt ext) {
+			this.ctx = ctx;
+			this.desc = desc;
+			this.ext = ext;
+		}
+
+		@Override
+		public ReadableChannel get() throws IOException {
+			if (rc == null) {
+				rc = ctx.db.openFile(desc, ext);
+			}
+			return rc;
+		}
+
+		@Override
+		public void close() throws IOException {
+			if (rc != null) {
+				rc.close();
+			}
+		}
+	}
 }
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 4687952..c6e2fae 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
@@ -49,9 +49,9 @@
 import java.util.concurrent.atomic.AtomicReference;
 import java.util.concurrent.atomic.AtomicReferenceArray;
 import java.util.concurrent.locks.ReentrantLock;
+import java.util.function.Consumer;
 import java.util.stream.LongStream;
 
-import org.eclipse.jgit.annotations.Nullable;
 import org.eclipse.jgit.internal.JGitText;
 import org.eclipse.jgit.internal.storage.pack.PackExt;
 
@@ -128,9 +128,18 @@ public static DfsBlockCache getInstance() {
 	/** Hash bucket directory; entries are chained below. */
 	private final AtomicReferenceArray<HashEntry> table;
 
-	/** Locks to prevent concurrent loads for same (PackFile,position). */
+	/**
+	 * Locks to prevent concurrent loads for same (PackFile,position) block. The
+	 * number of locks is {@link DfsBlockCacheConfig#getConcurrencyLevel()} to
+	 * cap the overall concurrent block loads.
+	 */
 	private final ReentrantLock[] loadLocks;
 
+	/**
+	 * A separate pool of locks to prevent concurrent loads for same index or bitmap from PackFile.
+	 */
+	private final ReentrantLock[] refLocks;
+
 	/** Maximum number of bytes the cache should hold. */
 	private final long maxBytes;
 
@@ -177,19 +186,30 @@ public static DfsBlockCache getInstance() {
 	/** Protects the clock and its related data. */
 	private final ReentrantLock clockLock;
 
+	/**
+	 * A consumer of object reference lock wait time milliseconds.  May be used to build a metric.
+	 */
+	private final Consumer<Long> refLockWaitTime;
+
 	/** Current position of the clock. */
 	private Ref clockHand;
 
 	@SuppressWarnings("unchecked")
 	private DfsBlockCache(DfsBlockCacheConfig cfg) {
 		tableSize = tableSize(cfg);
-		if (tableSize < 1)
+		if (tableSize < 1) {
 			throw new IllegalArgumentException(JGitText.get().tSizeMustBeGreaterOrEqual1);
+		}
 
 		table = new AtomicReferenceArray<>(tableSize);
 		loadLocks = new ReentrantLock[cfg.getConcurrencyLevel()];
-		for (int i = 0; i < loadLocks.length; i++)
+		for (int i = 0; i < loadLocks.length; i++) {
 			loadLocks[i] = new ReentrantLock(true /* fair */);
+		}
+		refLocks = new ReentrantLock[cfg.getConcurrencyLevel()];
+		for (int i = 0; i < refLocks.length; i++) {
+			refLocks[i] = new ReentrantLock(true /* fair */);
+		}
 
 		maxBytes = cfg.getBlockLimit();
 		maxStreamThroughCache = (long) (maxBytes * cfg.getStreamRatio());
@@ -207,6 +227,8 @@ private DfsBlockCache(DfsBlockCacheConfig cfg) {
 		statMiss = new AtomicReference<>(newCounters());
 		statEvict = new AtomicReference<>(newCounters());
 		liveBytes = new AtomicReference<>(newCounters());
+
+		refLockWaitTime = cfg.getRefLockWaitTimeConsumer();
 	}
 
 	boolean shouldCopyThroughCache(long length) {
@@ -333,15 +355,17 @@ int getBlockSize() {
 	private static int tableSize(DfsBlockCacheConfig cfg) {
 		final int wsz = cfg.getBlockSize();
 		final long limit = cfg.getBlockLimit();
-		if (wsz <= 0)
+		if (wsz <= 0) {
 			throw new IllegalArgumentException(JGitText.get().invalidWindowSize);
-		if (limit < wsz)
+		}
+		if (limit < wsz) {
 			throw new IllegalArgumentException(JGitText.get().windowSizeMustBeLesserThanLimit);
+		}
 		return (int) Math.min(5 * (limit / wsz) / 2, Integer.MAX_VALUE);
 	}
 
 	/**
-	 * Lookup a cached object, creating and loading it if it doesn't exist.
+	 * Look up a cached object, creating and loading it if it doesn't exist.
 	 *
 	 * @param file
 	 *            the pack that "contains" the cached object.
@@ -350,13 +374,13 @@ private static int tableSize(DfsBlockCacheConfig cfg) {
 	 * @param ctx
 	 *            current thread's reader.
 	 * @param fileChannel
-	 *            optional channel to read {@code pack}.
+	 *            supplier for channel to read {@code pack}.
 	 * @return the object reference.
 	 * @throws IOException
 	 *             the reference was not in the cache and could not be loaded.
 	 */
 	DfsBlock getOrLoad(BlockBasedFile file, long position, DfsReader ctx,
-			@Nullable ReadableChannel fileChannel) throws IOException {
+			ReadableChannelSupplier fileChannel) throws IOException {
 		final long requestedPosition = position;
 		position = file.alignToBlock(position);
 
@@ -388,11 +412,13 @@ DfsBlock getOrLoad(BlockBasedFile file, long position, DfsReader ctx,
 			getStat(statMiss, key).incrementAndGet();
 			boolean credit = true;
 			try {
-				v = file.readOneBlock(requestedPosition, ctx, fileChannel);
+				v = file.readOneBlock(requestedPosition, ctx,
+						fileChannel.get());
 				credit = false;
 			} finally {
-				if (credit)
+				if (credit) {
 					creditSpace(blockSize, key);
+				}
 			}
 			if (position != v.start) {
 				// The file discovered its blockSize and adjusted.
@@ -405,8 +431,9 @@ DfsBlock getOrLoad(BlockBasedFile file, long position, DfsReader ctx,
 			ref.hot = true;
 			for (;;) {
 				HashEntry n = new HashEntry(clean(e2), ref);
-				if (table.compareAndSet(slot, e2, n))
+				if (table.compareAndSet(slot, e2, n)) {
 					break;
+				}
 				e2 = table.get(slot);
 			}
 			addToClock(ref, blockSize - v.size());
@@ -416,8 +443,9 @@ DfsBlock getOrLoad(BlockBasedFile file, long position, DfsReader ctx,
 
 		// If the block size changed from the default, it is possible the block
 		// that was loaded is the wrong block for the requested position.
-		if (v.contains(file.key, requestedPosition))
+		if (v.contains(file.key, requestedPosition)) {
 			return v;
+		}
 		return getOrLoad(file, requestedPosition, ctx, fileChannel);
 	}
 
@@ -488,6 +516,63 @@ void put(DfsBlock v) {
 		put(v.stream, v.start, v.size(), v);
 	}
 
+	/**
+	 * Look up a cached object, creating and loading it if it doesn't exist.
+	 *
+	 * @param key
+	 *            the stream key of the pack.
+	 * @param loader
+	 *            the function to load the reference.
+	 * @return the object reference.
+	 * @throws IOException
+	 *             the reference was not in the cache and could not be loaded.
+	 */
+	<T> Ref<T> getOrLoadRef(DfsStreamKey key, RefLoader<T> loader)
+			throws IOException {
+		int slot = slot(key, 0);
+		HashEntry e1 = table.get(slot);
+		Ref<T> ref = scanRef(e1, key, 0);
+		if (ref != null) {
+			getStat(statHit, key).incrementAndGet();
+			return ref;
+		}
+
+		ReentrantLock regionLock = lockForRef(key);
+		long lockStart = System.currentTimeMillis();
+		regionLock.lock();
+		try {
+			HashEntry e2 = table.get(slot);
+			if (e2 != e1) {
+				ref = scanRef(e2, key, 0);
+				if (ref != null) {
+					getStat(statHit, key).incrementAndGet();
+					return ref;
+				}
+			}
+
+			if (refLockWaitTime != null) {
+				refLockWaitTime.accept(
+						Long.valueOf(System.currentTimeMillis() - lockStart));
+			}
+			getStat(statMiss, key).incrementAndGet();
+			ref = loader.load();
+			ref.hot = true;
+			// Reserve after loading to get the size of the object
+			reserveSpace(ref.size, key);
+			for (;;) {
+				HashEntry n = new HashEntry(clean(e2), ref);
+				if (table.compareAndSet(slot, e2, n)) {
+					break;
+				}
+				e2 = table.get(slot);
+			}
+			addToClock(ref, 0);
+		} finally {
+			regionLock.unlock();
+		}
+		return ref;
+	}
+
 	<T> Ref<T> putRef(DfsStreamKey key, long size, T v) {
 		return put(key, 0, (int) Math.min(size, Integer.MAX_VALUE), v);
 	}
@@ -496,8 +581,9 @@ <T> Ref<T> put(DfsStreamKey key, long pos, int size, T v) {
 		int slot = slot(key, pos);
 		HashEntry e1 = table.get(slot);
 		Ref<T> ref = scanRef(e1, key, pos);
-		if (ref != null)
+		if (ref != null) {
 			return ref;
+		}
 
 		reserveSpace(size, key);
 		ReentrantLock regionLock = lockFor(key, pos);
@@ -516,8 +602,9 @@ <T> Ref<T> put(DfsStreamKey key, long pos, int size, T v) {
 			ref.hot = true;
 			for (;;) {
 				HashEntry n = new HashEntry(clean(e2), ref);
-				if (table.compareAndSet(slot, e2, n))
+				if (table.compareAndSet(slot, e2, n)) {
 					break;
+				}
 				e2 = table.get(slot);
 			}
 			addToClock(ref, 0);
@@ -534,10 +621,11 @@ boolean contains(DfsStreamKey key, long position) {
 	@SuppressWarnings("unchecked")
 	<T> T get(DfsStreamKey key, long position) {
 		T val = (T) scan(table.get(slot(key, position)), key, position);
-		if (val == null)
+		if (val == null) {
 			getStat(statMiss, key).incrementAndGet();
-		else
+		} else {
 			getStat(statHit, key).incrementAndGet();
+		}
 		return val;
 	}
 
@@ -546,21 +634,13 @@ private <T> T scan(HashEntry n, DfsStreamKey key, long position) {
 		return r != null ? r.get() : null;
 	}
 
-	<T> Ref<T> getRef(DfsStreamKey key) {
-		Ref<T> r = scanRef(table.get(slot(key, 0)), key, 0);
-		if (r != null)
-			getStat(statHit, key).incrementAndGet();
-		else
-			getStat(statMiss, key).incrementAndGet();
-		return r;
-	}
-
 	@SuppressWarnings("unchecked")
 	private <T> Ref<T> scanRef(HashEntry n, DfsStreamKey key, long position) {
 		for (; n != null; n = n.next) {
 			Ref<T> r = n.ref;
-			if (r.position == position && r.key.equals(key))
+			if (r.position == position && r.key.equals(key)) {
 				return r.get() != null ? r : null;
+			}
 		}
 		return null;
 	}
@@ -573,6 +653,10 @@ private ReentrantLock lockFor(DfsStreamKey key, long position) {
 		return loadLocks[(hash(key.hash, position) >>> 1) % loadLocks.length];
 	}
 
+	private ReentrantLock lockForRef(DfsStreamKey key) {
+		return refLocks[(key.hash >>> 1) % refLocks.length];
+	}
+
 	private static AtomicLong[] newCounters() {
 		AtomicLong[] ret = new AtomicLong[PackExt.values().length];
 		for (int i = 0; i < ret.length; i++) {
@@ -613,8 +697,9 @@ private static AtomicLong getStat(AtomicReference<AtomicLong[]> stats,
 	private static HashEntry clean(HashEntry top) {
 		while (top != null && top.ref.next == null)
 			top = top.next;
-		if (top == null)
+		if (top == null) {
 			return null;
+		}
 		HashEntry n = clean(top.next);
 		return n == top.next ? top : new HashEntry(n, top.ref);
 	}
@@ -649,8 +734,9 @@ static final class Ref<T> {
 
 		T get() {
 			T v = value;
-			if (v != null)
+			if (v != null) {
 				hot = true;
+			}
 			return v;
 		}
 
@@ -658,4 +744,21 @@ boolean has() {
 			return value != null;
 		}
 	}
+
+	@FunctionalInterface
+	interface RefLoader<T> {
+		Ref<T> load() throws IOException;
+	}
+
+	/**
+	 * Supplier for readable channel
+	 */
+	@FunctionalInterface
+	interface ReadableChannelSupplier {
+		/**
+		 * @return ReadableChannel
+		 * @throws IOException
+		 */
+		ReadableChannel get() throws IOException;
+	}
 }
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 dd7cb89..cd1fa5f 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
@@ -51,6 +51,7 @@
 import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_STREAM_RATIO;
 
 import java.text.MessageFormat;
+import java.util.function.Consumer;
 
 import org.eclipse.jgit.internal.JGitText;
 import org.eclipse.jgit.lib.Config;
@@ -71,6 +72,8 @@ public class DfsBlockCacheConfig {
 	private double streamRatio;
 	private int concurrencyLevel;
 
+	private Consumer<Long> refLock;
+
 	/**
 	 * Create a default configuration.
 	 */
@@ -194,6 +197,27 @@ public DfsBlockCacheConfig setStreamRatio(double ratio) {
 	}
 
 	/**
+	 * Get the consumer of the object reference lock wait time in milliseconds.
+	 *
+	 * @return consumer of wait time in milliseconds.
+	 */
+	public Consumer<Long> getRefLockWaitTimeConsumer() {
+		return refLock;
+	}
+
+	/**
+	 * Set the consumer for lock wait time.
+	 *
+	 * @param c
+	 *            consumer of wait time in milliseconds.
+	 * @return {@code this}
+	 */
+	public DfsBlockCacheConfig setRefLockWaitTimeConsumer(Consumer<Long> c) {
+		refLock = c;
+		return this;
+	}
+
+	/**
 	 * Update properties by setting fields from the configuration.
 	 * <p>
 	 * If a property is not defined in the configuration, then it is left
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 c131f94..be1387e 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
@@ -88,6 +88,8 @@
  * objects are similar.
  */
 public final class DfsPackFile extends BlockBasedFile {
+	private static final int REC_SIZE = Constants.OBJECT_ID_LENGTH + 8;
+
 	/**
 	 * Lock for initialization of {@link #index} and {@link #corruptObjects}.
 	 * <p>
@@ -96,13 +98,13 @@ public final class DfsPackFile extends BlockBasedFile {
 	private final Object initLock = new Object();
 
 	/** Index mapping {@link ObjectId} to position within the pack stream. */
-	private volatile DfsBlockCache.Ref<PackIndex> index;
+	private volatile PackIndex index;
 
 	/** Reverse version of {@link #index} mapping position to {@link ObjectId}. */
-	private volatile DfsBlockCache.Ref<PackReverseIndex> reverseIndex;
+	private volatile PackReverseIndex reverseIndex;
 
 	/** Index of compressed bitmap mapping entire object graph. */
-	private volatile DfsBlockCache.Ref<PackBitmapIndex> bitmapIndex;
+	private volatile PackBitmapIndex bitmapIndex;
 
 	/**
 	 * Objects we have tried to read, and discovered to be corrupt.
@@ -148,15 +150,15 @@ public DfsPackDescription getPackDescription() {
 	 * @return whether the pack index file is loaded and cached in memory.
 	 */
 	public boolean isIndexLoaded() {
-		DfsBlockCache.Ref<PackIndex> idxref = index;
-		return idxref != null && idxref.has();
+		return index != null;
 	}
 
 	void setPackIndex(PackIndex idx) {
 		long objCnt = idx.getObjectCount();
 		int recSize = Constants.OBJECT_ID_LENGTH + 8;
 		long sz = objCnt * recSize;
-		index = cache.putRef(desc.getStreamKey(INDEX), sz, idx);
+		cache.putRef(desc.getStreamKey(INDEX), sz, idx);
+		index = idx;
 	}
 
 	/**
@@ -174,11 +176,8 @@ public PackIndex getPackIndex(DfsReader ctx) throws IOException {
 	}
 
 	private PackIndex idx(DfsReader ctx) throws IOException {
-		DfsBlockCache.Ref<PackIndex> idxref = index;
-		if (idxref != null) {
-			PackIndex idx = idxref.get();
-			if (idx != null)
-				return idx;
+		if (index != null) {
+			return index;
 		}
 
 		if (invalid) {
@@ -189,56 +188,61 @@ private PackIndex idx(DfsReader ctx) throws IOException {
 				.dispatch(new BeforeDfsPackIndexLoadedEvent(this));
 
 		synchronized (initLock) {
-			idxref = index;
-			if (idxref != null) {
-				PackIndex idx = idxref.get();
-				if (idx != null)
-					return idx;
+			if (index != null) {
+				return index;
 			}
 
-			DfsStreamKey idxKey = desc.getStreamKey(INDEX);
-			idxref = cache.getRef(idxKey);
-			if (idxref != null) {
-				PackIndex idx = idxref.get();
-				if (idx != null) {
-					index = idxref;
-					return idx;
-				}
-			}
-
-			PackIndex idx;
 			try {
-				ctx.stats.readIdx++;
-				long start = System.nanoTime();
-				try (ReadableChannel rc = ctx.db.openFile(desc, INDEX)) {
-					InputStream in = Channels.newInputStream(rc);
-					int wantSize = 8192;
-					int bs = rc.blockSize();
-					if (0 < bs && bs < wantSize)
-						bs = (wantSize / bs) * bs;
-					else if (bs <= 0)
-						bs = wantSize;
-					idx = PackIndex.read(new BufferedInputStream(in, bs));
-					ctx.stats.readIdxBytes += rc.position();
-				} finally {
-					ctx.stats.readIdxMicros += elapsedMicros(start);
+				DfsStreamKey idxKey = desc.getStreamKey(INDEX);
+				DfsBlockCache.Ref<PackIndex> idxref = cache.getOrLoadRef(idxKey,
+						() -> {
+							try {
+								ctx.stats.readIdx++;
+								long start = System.nanoTime();
+								try (ReadableChannel rc = ctx.db.openFile(desc,
+										INDEX)) {
+									InputStream in = Channels
+											.newInputStream(rc);
+									int wantSize = 8192;
+									int bs = rc.blockSize();
+									if (0 < bs && bs < wantSize) {
+										bs = (wantSize / bs) * bs;
+									} else if (bs <= 0) {
+										bs = wantSize;
+									}
+									PackIndex idx = PackIndex.read(
+											new BufferedInputStream(in, bs));
+									int sz = (int) Math.min(
+											idx.getObjectCount() * REC_SIZE,
+											Integer.MAX_VALUE);
+									ctx.stats.readIdxBytes += rc.position();
+									index = idx;
+									return new DfsBlockCache.Ref<>(idxKey, 0,
+											sz, idx);
+								} finally {
+									ctx.stats.readIdxMicros += elapsedMicros(
+											start);
+								}
+							} catch (EOFException e) {
+								throw new IOException(MessageFormat.format(
+										DfsText.get().shortReadOfIndex,
+										desc.getFileName(INDEX)), e);
+							} catch (IOException e) {
+								throw new IOException(MessageFormat.format(
+										DfsText.get().cannotReadIndex,
+										desc.getFileName(INDEX)), e);
+							}
+						});
+				PackIndex idx = idxref.get();
+				if (index == null && idx != null) {
+					index = idx;
 				}
-			} catch (EOFException e) {
-				invalid = true;
-				invalidatingCause = e;
-				throw new IOException(MessageFormat.format(
-						DfsText.get().shortReadOfIndex,
-						desc.getFileName(INDEX)), e);
+				return index;
 			} catch (IOException e) {
 				invalid = true;
 				invalidatingCause = e;
-				throw new IOException(MessageFormat.format(
-						DfsText.get().cannotReadIndex,
-						desc.getFileName(INDEX)), e);
+				throw e;
 			}
-
-			setPackIndex(idx);
-			return idx;
 		}
 	}
 
@@ -247,102 +251,94 @@ final boolean isGarbage() {
 	}
 
 	PackBitmapIndex getBitmapIndex(DfsReader ctx) throws IOException {
-		if (invalid || isGarbage() || !desc.hasFileExt(BITMAP_INDEX))
+		if (invalid || isGarbage() || !desc.hasFileExt(BITMAP_INDEX)) {
 			return null;
+		}
 
-		DfsBlockCache.Ref<PackBitmapIndex> idxref = bitmapIndex;
-		if (idxref != null) {
-			PackBitmapIndex idx = idxref.get();
-			if (idx != null)
-				return idx;
+		if (bitmapIndex != null) {
+			return bitmapIndex;
 		}
 
 		synchronized (initLock) {
-			idxref = bitmapIndex;
-			if (idxref != null) {
-				PackBitmapIndex idx = idxref.get();
-				if (idx != null)
-					return idx;
+			if (bitmapIndex != null) {
+				return bitmapIndex;
 			}
 
+			PackIndex idx = idx(ctx);
+			PackReverseIndex revidx = getReverseIdx(ctx);
 			DfsStreamKey bitmapKey = desc.getStreamKey(BITMAP_INDEX);
-			idxref = cache.getRef(bitmapKey);
-			if (idxref != null) {
-				PackBitmapIndex idx = idxref.get();
-				if (idx != null) {
-					bitmapIndex = idxref;
-					return idx;
-				}
+			DfsBlockCache.Ref<PackBitmapIndex> idxref = cache
+					.getOrLoadRef(bitmapKey, () -> {
+						ctx.stats.readBitmap++;
+						long start = System.nanoTime();
+						try (ReadableChannel rc = ctx.db.openFile(desc,
+								BITMAP_INDEX)) {
+							long size;
+							PackBitmapIndex bmidx;
+							try {
+								InputStream in = Channels.newInputStream(rc);
+								int wantSize = 8192;
+								int bs = rc.blockSize();
+								if (0 < bs && bs < wantSize) {
+									bs = (wantSize / bs) * bs;
+								} else if (bs <= 0) {
+									bs = wantSize;
+								}
+								in = new BufferedInputStream(in, bs);
+								bmidx = PackBitmapIndex.read(in, idx, revidx);
+							} finally {
+								size = rc.position();
+								ctx.stats.readIdxBytes += size;
+								ctx.stats.readIdxMicros += elapsedMicros(start);
+							}
+							int sz = (int) Math.min(size, Integer.MAX_VALUE);
+							bitmapIndex = bmidx;
+							return new DfsBlockCache.Ref<>(bitmapKey, 0, sz,
+									bmidx);
+						} catch (EOFException e) {
+							throw new IOException(MessageFormat.format(
+									DfsText.get().shortReadOfIndex,
+									desc.getFileName(BITMAP_INDEX)), e);
+						} catch (IOException e) {
+							throw new IOException(MessageFormat.format(
+									DfsText.get().cannotReadIndex,
+									desc.getFileName(BITMAP_INDEX)), e);
+						}
+					});
+			PackBitmapIndex bmidx = idxref.get();
+			if (bitmapIndex == null && bmidx != null) {
+				bitmapIndex = bmidx;
 			}
-
-			long size;
-			PackBitmapIndex idx;
-			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;
-					int bs = rc.blockSize();
-					if (0 < bs && bs < wantSize)
-						bs = (wantSize / bs) * bs;
-					else if (bs <= 0)
-						bs = wantSize;
-					in = new BufferedInputStream(in, bs);
-					idx = PackBitmapIndex.read(
-							in, idx(ctx), getReverseIdx(ctx));
-				} finally {
-					size = rc.position();
-					ctx.stats.readIdxBytes += size;
-					ctx.stats.readIdxMicros += elapsedMicros(start);
-				}
-			} catch (EOFException e) {
-				throw new IOException(MessageFormat.format(
-						DfsText.get().shortReadOfIndex,
-						desc.getFileName(BITMAP_INDEX)), e);
-			} catch (IOException e) {
-				throw new IOException(MessageFormat.format(
-						DfsText.get().cannotReadIndex,
-						desc.getFileName(BITMAP_INDEX)), e);
-			}
-
-			bitmapIndex = cache.putRef(bitmapKey, size, idx);
-			return idx;
+			return bitmapIndex;
 		}
 	}
 
 	PackReverseIndex getReverseIdx(DfsReader ctx) throws IOException {
-		DfsBlockCache.Ref<PackReverseIndex> revref = reverseIndex;
-		if (revref != null) {
-			PackReverseIndex revidx = revref.get();
-			if (revidx != null)
-				return revidx;
+		if (reverseIndex != null) {
+			return reverseIndex;
 		}
 
 		synchronized (initLock) {
-			revref = reverseIndex;
-			if (revref != null) {
-				PackReverseIndex revidx = revref.get();
-				if (revidx != null)
-					return revidx;
-			}
-
-			DfsStreamKey revKey =
-					new DfsStreamKey.ForReverseIndex(desc.getStreamKey(INDEX));
-			revref = cache.getRef(revKey);
-			if (revref != null) {
-				PackReverseIndex idx = revref.get();
-				if (idx != null) {
-					reverseIndex = revref;
-					return idx;
-				}
+			if (reverseIndex != null) {
+				return reverseIndex;
 			}
 
 			PackIndex idx = idx(ctx);
-			PackReverseIndex revidx = new PackReverseIndex(idx);
-			long cnt = idx.getObjectCount();
-			reverseIndex = cache.putRef(revKey, cnt * 8, revidx);
-			return revidx;
+			DfsStreamKey revKey = new DfsStreamKey.ForReverseIndex(
+					desc.getStreamKey(INDEX));
+			DfsBlockCache.Ref<PackReverseIndex> revref = cache
+					.getOrLoadRef(revKey, () -> {
+						PackReverseIndex revidx = new PackReverseIndex(idx);
+						int sz = (int) Math.min(idx.getObjectCount() * 8,
+								Integer.MAX_VALUE);
+						reverseIndex = revidx;
+						return new DfsBlockCache.Ref<>(revKey, 0, sz, revidx);
+					});
+			PackReverseIndex revidx = revref.get();
+			if (reverseIndex == null && revidx != null) {
+				reverseIndex = revidx;
+			}
+			return reverseIndex;
 		}
 	}
 
@@ -420,110 +416,94 @@ long getObjectCount(DfsReader ctx) throws IOException {
 			return null;
 		}
 
-		if (ctx.inflate(this, position, dstbuf, false) != sz)
+		if (ctx.inflate(this, position, dstbuf, false) != sz) {
 			throw new EOFException(MessageFormat.format(
 					JGitText.get().shortCompressedStreamAt,
 					Long.valueOf(position)));
+		}
 		return dstbuf;
 	}
 
-	void copyPackAsIs(PackOutputStream out, DfsReader ctx)
-			throws IOException {
+	void copyPackAsIs(PackOutputStream out, DfsReader ctx) throws IOException {
 		// If the length hasn't been determined yet, pin to set it.
 		if (length == -1) {
 			ctx.pin(this, 0);
 			ctx.unpin();
 		}
-		if (cache.shouldCopyThroughCache(length))
-			copyPackThroughCache(out, ctx);
-		else
-			copyPackBypassCache(out, ctx);
+		try (ReadableChannel rc = ctx.db.openFile(desc, PACK)) {
+			int sz = ctx.getOptions().getStreamPackBufferSize();
+			if (sz > 0) {
+				rc.setReadAheadBytes(sz);
+			}
+			if (cache.shouldCopyThroughCache(length)) {
+				copyPackThroughCache(out, ctx, rc);
+			} else {
+				copyPackBypassCache(out, rc);
+			}
+		}
 	}
 
-	private void copyPackThroughCache(PackOutputStream out, DfsReader ctx)
-			throws IOException {
-		@SuppressWarnings("resource") // Explicitly closed in finally block
-		ReadableChannel rc = null;
-		try {
-			long position = 12;
-			long remaining = length - (12 + 20);
-			while (0 < remaining) {
-				DfsBlock b;
-				if (rc != null) {
-					b = cache.getOrLoad(this, position, ctx, rc);
-				} else {
-					b = cache.get(key, alignToBlock(position));
-					if (b == null) {
-						rc = ctx.db.openFile(desc, PACK);
-						int sz = ctx.getOptions().getStreamPackBufferSize();
-						if (sz > 0) {
-							rc.setReadAheadBytes(sz);
-						}
-						b = cache.getOrLoad(this, position, ctx, rc);
-					}
-				}
+	private void copyPackThroughCache(PackOutputStream out, DfsReader ctx,
+			ReadableChannel rc) throws IOException {
+		long position = 12;
+		long remaining = length - (12 + 20);
+		while (0 < remaining) {
+			DfsBlock b = cache.getOrLoad(this, position, ctx, () -> rc);
+			int ptr = (int) (position - b.start);
+			if (b.size() <= ptr) {
+				throw packfileIsTruncated();
+			}
+			int n = (int) Math.min(b.size() - ptr, remaining);
+			b.write(out, position, n);
+			position += n;
+			remaining -= n;
+		}
+	}
 
+	private long copyPackBypassCache(PackOutputStream out, ReadableChannel rc)
+			throws IOException {
+		ByteBuffer buf = newCopyBuffer(out, rc);
+		long position = 12;
+		long remaining = length - (12 + 20);
+		boolean packHeadSkipped = false;
+		while (0 < remaining) {
+			DfsBlock b = cache.get(key, alignToBlock(position));
+			if (b != null) {
 				int ptr = (int) (position - b.start);
+				if (b.size() <= ptr) {
+					throw packfileIsTruncated();
+				}
 				int n = (int) Math.min(b.size() - ptr, remaining);
 				b.write(out, position, n);
 				position += n;
 				remaining -= n;
+				rc.position(position);
+				packHeadSkipped = true;
+				continue;
 			}
-		} finally {
-			if (rc != null) {
-				rc.close();
+
+			// Need to skip the 'PACK' header for the first read
+			int ptr = packHeadSkipped ? 0 : 12;
+			buf.position(0);
+			int bufLen = read(rc, buf);
+			if (bufLen <= ptr) {
+				throw packfileIsTruncated();
 			}
+			int n = (int) Math.min(bufLen - ptr, remaining);
+			out.write(buf.array(), ptr, n);
+			position += n;
+			remaining -= n;
+			packHeadSkipped = true;
 		}
-	}
-
-	private long copyPackBypassCache(PackOutputStream out, DfsReader ctx)
-			throws IOException {
-		try (ReadableChannel rc = ctx.db.openFile(desc, PACK)) {
-			ByteBuffer buf = newCopyBuffer(out, rc);
-			if (ctx.getOptions().getStreamPackBufferSize() > 0)
-				rc.setReadAheadBytes(ctx.getOptions().getStreamPackBufferSize());
-			long position = 12;
-			long remaining = length - (12 + 20);
-			boolean packHeadSkipped = false;
-			while (0 < remaining) {
-				DfsBlock b = cache.get(key, alignToBlock(position));
-				if (b != null) {
-					int ptr = (int) (position - b.start);
-					int n = (int) Math.min(b.size() - ptr, remaining);
-					b.write(out, position, n);
-					position += n;
-					remaining -= n;
-					rc.position(position);
-					packHeadSkipped = true;
-					continue;
-				}
-
-				buf.position(0);
-				int n = read(rc, buf);
-				if (n <= 0)
-					throw packfileIsTruncated();
-				else if (n > remaining)
-					n = (int) remaining;
-
-				if (!packHeadSkipped) {
-					// Need skip the 'PACK' header for the first read
-					out.write(buf.array(), 12, n - 12);
-					packHeadSkipped = true;
-				} else {
-					out.write(buf.array(), 0, n);
-				}
-				position += n;
-				remaining -= n;
-			}
-			return position;
-		}
+		return position;
 	}
 
 	private ByteBuffer newCopyBuffer(PackOutputStream out, ReadableChannel rc) {
 		int bs = blockSize(rc);
 		byte[] copyBuf = out.getCopyBuffer();
-		if (bs > copyBuf.length)
+		if (bs > copyBuf.length) {
 			copyBuf = new byte[bs];
+		}
 		return ByteBuffer.wrap(copyBuf, 0, bs);
 	}
 
@@ -635,8 +615,9 @@ void copyAsIs(PackOutputStream out, DfsObjectToPack src,
 						readFully(pos, buf, 0, n, ctx);
 						crc1.update(buf, 0, n);
 						inf.setInput(buf, 0, n);
-						while (inf.inflate(tmp, 0, tmp.length) > 0)
+						while (inf.inflate(tmp, 0, tmp.length) > 0) {
 							continue;
+						}
 						pos += n;
 						cnt -= n;
 					}
@@ -770,8 +751,9 @@ ObjectLoader load(DfsReader ctx, long pos)
 
 					if (sz < ctx.getStreamFileThreshold()) {
 						data = decompress(pos + p, (int) sz, ctx);
-						if (data != null)
+						if (data != null) {
 							return new ObjectLoader.SmallObject(typeCode, data);
+						}
 					}
 					return new LargePackedWholeObject(typeCode, sz, pos, p, this, ctx.db);
 				}
@@ -787,8 +769,9 @@ ObjectLoader load(DfsReader ctx, long pos)
 					}
 					base = pos - base;
 					delta = new Delta(delta, pos, (int) sz, p, base);
-					if (sz != delta.deltaSize)
+					if (sz != delta.deltaSize) {
 						break SEARCH;
+					}
 
 					DeltaBaseCache.Entry e = ctx.getDeltaBaseCache().get(key, base);
 					if (e != null) {
@@ -805,8 +788,9 @@ ObjectLoader load(DfsReader ctx, long pos)
 					readFully(pos + p, ib, 0, 20, ctx);
 					long base = findDeltaBase(ctx, ObjectId.fromRaw(ib));
 					delta = new Delta(delta, pos, (int) sz, p + 20, base);
-					if (sz != delta.deltaSize)
+					if (sz != delta.deltaSize) {
 						break SEARCH;
+					}
 
 					DeltaBaseCache.Entry e = ctx.getDeltaBaseCache().get(key, base);
 					if (e != null) {
@@ -834,10 +818,11 @@ ObjectLoader load(DfsReader ctx, long pos)
 			assert(delta != null);
 			do {
 				// Cache only the base immediately before desired object.
-				if (cached)
+				if (cached) {
 					cached = false;
-				else if (delta.next == null)
+				} else if (delta.next == null) {
 					ctx.getDeltaBaseCache().put(key, delta.basePos, type, data);
+				}
 
 				pos = delta.deltaPos;
 
@@ -848,8 +833,9 @@ else if (delta.next == null)
 				}
 
 				final long sz = BinaryDelta.getResultSize(cmds);
-				if (Integer.MAX_VALUE <= sz)
+				if (Integer.MAX_VALUE <= sz) {
 					throw new LargeObjectException.ExceedsByteArrayLimit();
+				}
 
 				final byte[] result;
 				try {
@@ -879,9 +865,10 @@ else if (delta.next == null)
 	private long findDeltaBase(DfsReader ctx, ObjectId baseId)
 			throws IOException, MissingObjectException {
 		long ofs = idx(ctx).findOffset(baseId);
-		if (ofs < 0)
+		if (ofs < 0) {
 			throw new MissingObjectException(baseId,
 					JGitText.get().missingDeltaBase);
+		}
 		return ofs;
 	}
 
@@ -938,8 +925,9 @@ int getObjectType(DfsReader ctx, long pos) throws IOException {
 
 			case Constants.OBJ_OFS_DELTA: {
 				int p = 1;
-				while ((c & 0x80) != 0)
+				while ((c & 0x80) != 0) {
 					c = ib[p++] & 0xff;
+				}
 				c = ib[p++] & 0xff;
 				long ofs = c & 127;
 				while ((c & 128) != 0) {
@@ -954,8 +942,9 @@ int getObjectType(DfsReader ctx, long pos) throws IOException {
 
 			case Constants.OBJ_REF_DELTA: {
 				int p = 1;
-				while ((c & 0x80) != 0)
+				while ((c & 0x80) != 0) {
 					c = ib[p++] & 0xff;
+				}
 				readFully(pos + p, ib, 0, 20, ctx);
 				pos = findDeltaBase(ctx, ObjectId.fromRaw(ib));
 				continue;
@@ -998,8 +987,9 @@ long getObjectSize(DfsReader ctx, long pos)
 
 		case Constants.OBJ_OFS_DELTA:
 			c = ib[p++] & 0xff;
-			while ((c & 128) != 0)
+			while ((c & 128) != 0) {
 				c = ib[p++] & 0xff;
+			}
 			deltaAt = pos + p;
 			break;
 
@@ -1032,8 +1022,9 @@ void representation(DfsObjectRepresentation r, final long pos,
 		int c = ib[0] & 0xff;
 		int p = 1;
 		final int typeCode = (c >> 4) & 7;
-		while ((c & 0x80) != 0)
+		while ((c & 0x80) != 0) {
 			c = ib[p++] & 0xff;
+		}
 
 		long len = rev.findNextOffset(pos, length - 20) - pos;
 		switch (typeCode) {
@@ -1077,8 +1068,9 @@ void representation(DfsObjectRepresentation r, final long pos,
 
 	boolean isCorrupt(long offset) {
 		LongList list = corruptObjects;
-		if (list == null)
+		if (list == null) {
 			return false;
+		}
 		synchronized (list) {
 			return list.contains(offset);
 		}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsRefDatabase.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsRefDatabase.java
index a884346..8b2a03d 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsRefDatabase.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsRefDatabase.java
@@ -107,20 +107,6 @@ public Ref exactRef(String name) throws IOException {
 
 	/** {@inheritDoc} */
 	@Override
-	public Ref getRef(String needle) throws IOException {
-		RefCache curr = read();
-		for (String prefix : SEARCH_PATH) {
-			Ref ref = curr.ids.get(prefix + needle);
-			if (ref != null) {
-				ref = resolve(ref, 0, curr.ids);
-				return ref;
-			}
-		}
-		return null;
-	}
-
-	/** {@inheritDoc} */
-	@Override
 	public List<Ref> getAdditionalRefs() {
 		return Collections.emptyList();
 	}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsReftable.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsReftable.java
index 7502471..4853298 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsReftable.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsReftable.java
@@ -128,7 +128,7 @@ public ByteBuffer read(long pos, int cnt) throws IOException {
 				open().setReadAheadBytes(readAhead);
 			}
 
-			DfsBlock block = cache.getOrLoad(file, pos, ctx, ch);
+			DfsBlock block = cache.getOrLoad(file, pos, ctx, () -> open());
 			if (block.start == pos && block.size() >= cnt) {
 				return block.zeroCopyByteBuffer(cnt);
 			}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsReftableDatabase.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsReftableDatabase.java
index 7081630..83394bb 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsReftableDatabase.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsReftableDatabase.java
@@ -99,6 +99,12 @@ protected DfsReftableDatabase(DfsRepository repo) {
 
 	/** {@inheritDoc} */
 	@Override
+	public boolean hasVersioning() {
+		return true;
+	}
+
+	/** {@inheritDoc} */
+	@Override
 	public boolean performsAtomicTransactions() {
 		return true;
 	}
@@ -223,18 +229,6 @@ public Ref exactRef(String name) throws IOException {
 
 	/** {@inheritDoc} */
 	@Override
-	public Ref getRef(String needle) throws IOException {
-		for (String prefix : SEARCH_PATH) {
-			Ref ref = exactRef(prefix + needle);
-			if (ref != null) {
-				return ref;
-			}
-		}
-		return null;
-	}
-
-	/** {@inheritDoc} */
-	@Override
 	public Map<String, Ref> getRefs(String prefix) throws IOException {
 		RefList.Builder<Ref> all = new RefList.Builder<>();
 		lock.lock();
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 791a108..7400308 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
@@ -160,7 +160,6 @@ public class GC {
 	 *
 	 * @param e
 	 *            the executor to be used for running auto-gc
-	 * @since 4.8
 	 */
 	public static void setExecutor(ExecutorService e) {
 		executor = e;
@@ -918,7 +917,8 @@ private void deleteEmptyRefsFolders() throws IOException {
 		// Avoid deleting a folder that was created after the threshold so that concurrent
 		// operations trying to create a reference are not impacted
 		Instant threshold = Instant.now().minus(30, ChronoUnit.SECONDS);
-		try (Stream<Path> entries = Files.list(refs)) {
+		try (Stream<Path> entries = Files.list(refs)
+				.filter(Files::isDirectory)) {
 			Iterator<Path> iterator = entries.iterator();
 			while (iterator.hasNext()) {
 				try (Stream<Path> s = Files.list(iterator.next())) {
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 3552266..258ccee 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
@@ -198,7 +198,6 @@ public final File getDirectory() {
 	 * <p>Getter for the field <code>packDirectory</code>.</p>
 	 *
 	 * @return the location of the <code>pack</code> directory.
-	 * @since 4.10
 	 */
 	public final File getPackDirectory() {
 		return packDirectory;
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 de7e4b3..a4729bb 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
@@ -74,6 +74,7 @@
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
@@ -319,16 +320,14 @@ private RefList<LooseRef> getLooseRefs() {
 		return loose;
 	}
 
-	/** {@inheritDoc} */
-	@Override
-	public Ref exactRef(String name) throws IOException {
-		RefList<Ref> packed = getPackedRefs();
-		Ref ref;
+	@Nullable
+	private Ref readAndResolve(String name, RefList<Ref> packed) throws IOException {
 		try {
-			ref = readRef(name, packed);
+			Ref ref = readRef(name, packed);
 			if (ref != null) {
 				ref = resolve(ref, 0, null, null, packed);
 			}
+			return ref;
 		} catch (IOException e) {
 			if (name.contains("/") //$NON-NLS-1$
 					|| !(e.getCause() instanceof InvalidObjectIdException)) {
@@ -338,35 +337,55 @@ public Ref exactRef(String name) throws IOException {
 			// While looking for a ref outside of refs/ (e.g., 'config'), we
 			// found a non-ref file (e.g., a config file) instead.  Treat this
 			// as a ref-not-found condition.
-			ref = null;
+			return null;
 		}
-		fireRefsChanged();
-		return ref;
 	}
 
 	/** {@inheritDoc} */
 	@Override
-	public Ref getRef(String needle) throws IOException {
-		final RefList<Ref> packed = getPackedRefs();
-		Ref ref = null;
-		for (String prefix : SEARCH_PATH) {
-			try {
-				ref = readRef(prefix + needle, packed);
+	public Ref exactRef(String name) throws IOException {
+		try {
+			return readAndResolve(name, getPackedRefs());
+		} finally {
+			fireRefsChanged();
+		}
+	}
+
+	/** {@inheritDoc} */
+	@Override
+	@NonNull
+	public Map<String, Ref> exactRef(String... refs) throws IOException {
+		try {
+			RefList<Ref> packed = getPackedRefs();
+			Map<String, Ref> result = new HashMap<>(refs.length);
+			for (String name : refs) {
+				Ref ref = readAndResolve(name, packed);
 				if (ref != null) {
-					ref = resolve(ref, 0, null, null, packed);
-				}
-				if (ref != null) {
-					break;
-				}
-			} catch (IOException e) {
-				if (!(!needle.contains("/") && "".equals(prefix) && e //$NON-NLS-1$ //$NON-NLS-2$
-						.getCause() instanceof InvalidObjectIdException)) {
-					throw e;
+					result.put(name, ref);
 				}
 			}
+			return result;
+		} finally {
+			fireRefsChanged();
 		}
-		fireRefsChanged();
-		return ref;
+	}
+
+	/** {@inheritDoc} */
+	@Override
+	@Nullable
+	public Ref firstExactRef(String... refs) throws IOException {
+		try {
+			RefList<Ref> packed = getPackedRefs();
+			for (String name : refs) {
+				Ref ref = readAndResolve(name, packed);
+				if (ref != null) {
+					return ref;
+				}
+			}
+			return null;
+		} finally {
+			fireRefsChanged();
+		}
 	}
 
 	/** {@inheritDoc} */
@@ -414,7 +433,7 @@ public Map<String, Ref> getRefs(String prefix) throws IOException {
 	public List<Ref> getAdditionalRefs() throws IOException {
 		List<Ref> ret = new LinkedList<>();
 		for (String name : additionalRefsNames) {
-			Ref r = getRef(name);
+			Ref r = exactRef(name);
 			if (r != null)
 				ret.add(r);
 		}
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 45ce634..1a0d695 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
@@ -87,7 +87,7 @@ protected boolean tryLock(boolean deref) throws IOException {
 		String name = dst.getName();
 		lock = new LockFile(database.fileFor(name));
 		if (lock.lock()) {
-			dst = database.getRef(name);
+			dst = database.findRef(name);
 			setOldObjectId(dst != null ? dst.getObjectId() : null);
 			return true;
 		} else {
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 797507d..015866e 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
@@ -339,7 +339,7 @@ private static final int bits(int newSize) {
 	 * Modify the configuration of the window cache.
 	 * <p>
 	 * The new configuration is applied immediately. If the new limits are
-	 * smaller than what what is currently cached, older entries will be purged
+	 * smaller than what is currently cached, older entries will be purged
 	 * as soon as possible to allow the cache to meet the new limit.
 	 *
 	 * @deprecated use {@code cfg.install()} to avoid internal reference.
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/DeltaEncoder.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/DeltaEncoder.java
index 343faf4..cfc1ccd 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/DeltaEncoder.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/DeltaEncoder.java
@@ -73,7 +73,7 @@ public class DeltaEncoder {
 	/** Maximum number of bytes used by a copy instruction. */
 	private static final int MAX_COPY_CMD_SIZE = 8;
 
-	/** Maximum length that an an insert command can encode at once. */
+	/** Maximum length that an insert command can encode at once. */
 	private static final int MAX_INSERT_DATA_SIZE = 127;
 
 	private final OutputStream out;
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 24af8a7..1e3d74a 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
@@ -642,7 +642,6 @@ public void setShallowPack(int depth,
 
 	/**
 	 * @param bytes exclude blobs of size greater than this
-	 * @since 5.0
 	 */
 	public void setFilterBlobLimit(long bytes) {
 		filterBlobLimit = bytes;
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..44529bf 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
@@ -170,24 +170,27 @@ long readUpdateIndexDelta() {
 		return readVarint64();
 	}
 
-	Ref readRef() throws IOException {
+	Ref readRef(long minUpdateIndex) throws IOException {
+		long updateIndex = minUpdateIndex + readUpdateIndexDelta();
 		String name = RawParseUtils.decode(UTF_8, nameBuf, 0, nameLen);
 		switch (valueType & VALUE_TYPE_MASK) {
 		case VALUE_NONE: // delete
-			return newRef(name);
+			return newRef(name, updateIndex);
 
 		case VALUE_1ID:
-			return new ObjectIdRef.PeeledNonTag(PACKED, name, readValueId());
+			return new ObjectIdRef.PeeledNonTag(PACKED, name, readValueId(),
+					updateIndex);
 
 		case VALUE_2ID: { // annotated tag
 			ObjectId id1 = readValueId();
 			ObjectId id2 = readValueId();
-			return new ObjectIdRef.PeeledTag(PACKED, name, id1, id2);
+			return new ObjectIdRef.PeeledTag(PACKED, name, id1, id2,
+					updateIndex);
 		}
 
 		case VALUE_SYMREF: {
 			String val = readValueString();
-			return new SymbolicRef(name, newRef(val));
+			return new SymbolicRef(name, newRef(val, updateIndex), updateIndex);
 		}
 
 		default:
@@ -410,7 +413,7 @@ void verifyIndex() throws IOException {
 	 * <ul>
 	 * <li>{@link #name()}
 	 * <li>{@link #match(byte[], boolean)}
-	 * <li>{@link #readRef()}
+	 * <li>{@link #readRef(long)}
 	 * <li>{@link #readLogUpdateIndex()}
 	 * <li>{@link #readLogEntry()}
 	 * <li>{@link #readBlockPositionList()}
@@ -575,8 +578,8 @@ private long readVarint64() {
 		return val;
 	}
 
-	private static Ref newRef(String name) {
-		return new ObjectIdRef.Unpeeled(NEW, name, null);
+	private static Ref newRef(String name, long updateIndex) {
+		return new ObjectIdRef.Unpeeled(NEW, name, null, updateIndex);
 	}
 
 	private static IOException invalidBlock() {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/MergedReftable.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/MergedReftable.java
index 17894b1..c740bf2 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/MergedReftable.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/MergedReftable.java
@@ -168,7 +168,6 @@ private class MergedRefCursor extends RefCursor {
 		private final PriorityQueue<RefQueueEntry> queue;
 		private RefQueueEntry head;
 		private Ref ref;
-		private long updateIndex;
 
 		MergedRefCursor() {
 			queue = new PriorityQueue<>(queueSize(), RefQueueEntry::compare);
@@ -206,7 +205,6 @@ public boolean next() throws IOException {
 				}
 
 				ref = t.rc.getRef();
-				updateIndex = t.rc.getUpdateIndex();
 				boolean include = includeDeletes || !t.rc.wasDeleted();
 				add(t);
 				skipShadowedRefs(ref.getName());
@@ -242,11 +240,6 @@ public Ref getRef() {
 		}
 
 		@Override
-		public long getUpdateIndex() {
-			return updateIndex;
-		}
-
-		@Override
 		public void close() {
 			if (head != null) {
 				head.rc.close();
@@ -285,7 +278,7 @@ String name() {
 		}
 
 		long updateIndex() {
-			return rc.getUpdateIndex();
+			return rc.getRef().getUpdateIndex();
 		}
 	}
 
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/RefCursor.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/RefCursor.java
index 5d4af30..9749ffb 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/RefCursor.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/RefCursor.java
@@ -69,13 +69,6 @@ public abstract class RefCursor implements AutoCloseable {
 	public abstract Ref getRef();
 
 	/**
-	 * Get updateIndex that last modified the current reference.
-	 *
-	 * @return updateIndex that last modified the current reference.
-	 */
-	public abstract long getUpdateIndex();
-
-	/**
 	 * Whether the current reference was deleted.
 	 *
 	 * @return {@code true} if the current reference was deleted.
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/Reftable.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/Reftable.java
index a1087e2..cb02628 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/Reftable.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/Reftable.java
@@ -280,7 +280,7 @@ private Ref resolve(Ref ref, int depth) throws IOException {
 		if (dst == null) {
 			return null; // claim it doesn't exist
 		}
-		return new SymbolicRef(ref.getName(), dst);
+		return new SymbolicRef(ref.getName(), dst, ref.getUpdateIndex());
 	}
 
 	/** {@inheritDoc} */
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/ReftableCompactor.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/ReftableCompactor.java
index ed73a9e..c4e8f69 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/ReftableCompactor.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/ReftableCompactor.java
@@ -256,7 +256,7 @@ public Stats getStats() {
 	private void mergeRefs(MergedReftable mr) throws IOException {
 		try (RefCursor rc = mr.allRefs()) {
 			while (rc.next()) {
-				writer.writeRef(rc.getRef(), rc.getUpdateIndex());
+				writer.writeRef(rc.getRef(), rc.getRef().getUpdateIndex());
 			}
 		}
 	}
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 81b30e4..bf3a9ae 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
@@ -479,7 +479,6 @@ private class RefCursorImpl extends RefCursor {
 		private final boolean prefix;
 
 		private Ref ref;
-		private long updateIndex;
 		BlockReader block;
 
 		RefCursorImpl(long scanEnd, byte[] match, boolean prefix) {
@@ -508,8 +507,7 @@ public boolean next() throws IOException {
 					return false;
 				}
 
-				updateIndex = minUpdateIndex + block.readUpdateIndexDelta();
-				ref = block.readRef();
+				ref = block.readRef(minUpdateIndex);
 				if (!includeDeletes && wasDeleted()) {
 					continue;
 				}
@@ -523,11 +521,6 @@ public Ref getRef() {
 		}
 
 		@Override
-		public long getUpdateIndex() {
-			return updateIndex;
-		}
-
-		@Override
 		public void close() {
 			// Do nothing.
 		}
@@ -605,7 +598,6 @@ private class ObjCursorImpl extends RefCursor {
 		private final ObjectId match;
 
 		private Ref ref;
-		private long updateIndex;
 		private int listIdx;
 
 		private LongList blockPos;
@@ -679,8 +671,7 @@ public boolean next() throws IOException {
 				}
 
 				block.parseKey();
-				updateIndex = minUpdateIndex + block.readUpdateIndexDelta();
-				ref = block.readRef();
+				ref = block.readRef(minUpdateIndex);
 				ObjectId id = ref.getObjectId();
 				if (id != null && match.equals(id)
 						&& (includeDeletes || !wasDeleted())) {
@@ -695,11 +686,6 @@ public Ref getRef() {
 		}
 
 		@Override
-		public long getUpdateIndex() {
-			return updateIndex;
-		}
-
-		@Override
 		public void close() {
 			// Do nothing.
 		}
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 27daaf0..ddd05b3 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
@@ -206,16 +206,6 @@ public void close() {
 
 	/** {@inheritDoc} */
 	@Override
-	public Ref getRef(String name) throws IOException {
-		String[] needle = new String[SEARCH_PATH.length];
-		for (int i = 0; i < SEARCH_PATH.length; i++) {
-			needle[i] = SEARCH_PATH[i] + name;
-		}
-		return firstExactRef(needle);
-	}
-
-	/** {@inheritDoc} */
-	@Override
 	public Ref exactRef(String name) throws IOException {
 		if (!repo.isBare() && name.indexOf('/') < 0 && !HEAD.equals(name)) {
 			// Pass through names like MERGE_HEAD, ORIG_HEAD, FETCH_HEAD.
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftree/Scanner.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftree/Scanner.java
index 2ef0f20..2fa59f3 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftree/Scanner.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftree/Scanner.java
@@ -221,10 +221,11 @@ private static Ref resolve(Ref ref, int depth, RefList<Ref> refs)
 		return new SymbolicRef(ref.getName(), dst);
 	}
 
-	@SuppressWarnings("resource")
 	private static RevTree toTree(ObjectReader reader, AnyObjectId id)
 			throws IOException {
-		return new RevWalk(reader).parseTree(id);
+		try (RevWalk rw = new RevWalk(reader)) {
+			return rw.parseTree(id);
+		}
 	}
 
 	private static boolean curElementHasPeelSuffix(AbstractTreeIterator itr) {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/submodule/SubmoduleValidator.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/submodule/SubmoduleValidator.java
index 7b872b1..cd6af6a 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/submodule/SubmoduleValidator.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/submodule/SubmoduleValidator.java
@@ -61,7 +61,7 @@
  * Validations for the git submodule fields (name, path, uri).
  *
  * Invalid values in these fields can cause security problems as reported in
- * CVE-2018-11235 and and CVE-2018-17456
+ * CVE-2018-11235 and CVE-2018-17456
  */
 public class SubmoduleValidator {
 
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/transport/parser/FirstCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/transport/parser/FirstCommand.java
new file mode 100644
index 0000000..0426b17
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/transport/parser/FirstCommand.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2018, Google LLC.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ *   copyright notice, this list of conditions and the following
+ *   disclaimer in the documentation and/or other materials provided
+ *   with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ *   names of its contributors may be used to endorse or promote
+ *   products derived from this software without specific prior
+ *   written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.eclipse.jgit.internal.transport.parser;
+
+import static java.util.Arrays.asList;
+import static java.util.Collections.emptySet;
+import static java.util.Collections.unmodifiableSet;
+import static java.util.stream.Collectors.toSet;
+
+import java.util.Set;
+
+import org.eclipse.jgit.annotations.NonNull;
+
+/**
+ * In a push, the client sends a list of commands. The first command
+ * is special, as it can include a list of capabilities at its end.
+ * <p>
+ * For example:
+ * "oid oid name\0cap1 cap cap3"
+ * <p>
+ * Not to be confused with {@link FirstWant}, nor with the first line
+ * of the reference advertisement parsed by
+ * {@code BasePackConnection.readAdvertisedRefs}.
+ * <p>
+ * This class parses the inputted command line and holds the results:
+ * the actual command line and the capabilities.
+ */
+public final class FirstCommand {
+	private final String line;
+	private final Set<String> capabilities;
+
+	/**
+	 * Parse the first line of a receive-pack request.
+	 *
+	 * @param line
+	 *            line from the client.
+	 * @return an instance of FirstCommand with capabilities parsed out
+	 */
+	@NonNull
+	public static FirstCommand fromLine(String line) {
+		int nul = line.indexOf('\0');
+		if (nul < 0) {
+			return new FirstCommand(line, emptySet());
+		}
+		Set<String> opts =
+				asList(line.substring(nul + 1).split(" ")) //$NON-NLS-1$
+					.stream()
+					.collect(toSet());
+		return new FirstCommand(line.substring(0, nul), unmodifiableSet(opts));
+	}
+
+	private FirstCommand(String line, Set<String> capabilities) {
+		this.line = line;
+		this.capabilities = capabilities;
+	}
+
+	/** @return non-capabilities part of the line. */
+	@NonNull
+	public String getLine() {
+		return line;
+	}
+
+	/** @return capabilities parsed from the line, as an immutable set. */
+	@NonNull
+	public Set<String> getCapabilities() {
+		return capabilities;
+	}
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/transport/parser/FirstWant.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/transport/parser/FirstWant.java
index 2dae021..401c507 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/transport/parser/FirstWant.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/transport/parser/FirstWant.java
@@ -67,7 +67,6 @@
  * This class parses the input want line and holds the results: the actual want
  * line and the capabilities.
  *
- * @since 5.2
  */
 public class FirstWant {
 	private final String line;
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 c30833d..6cbddec 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/CommitBuilder.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/CommitBuilder.java
@@ -49,11 +49,15 @@
 
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
+import java.io.OutputStream;
 import java.io.OutputStreamWriter;
 import java.io.UnsupportedEncodingException;
 import java.nio.charset.Charset;
+import java.text.MessageFormat;
 import java.util.List;
 
+import org.eclipse.jgit.internal.JGitText;
+
 /**
  * Mutable builder to construct a commit recording the state of a project.
  *
@@ -76,6 +80,8 @@ public class CommitBuilder {
 
 	private static final byte[] hcommitter = Constants.encodeASCII("committer"); //$NON-NLS-1$
 
+	private static final byte[] hgpgsig = Constants.encodeASCII("gpgsig"); //$NON-NLS-1$
+
 	private static final byte[] hencoding = Constants.encodeASCII("encoding"); //$NON-NLS-1$
 
 	private ObjectId treeId;
@@ -86,6 +92,8 @@ public class CommitBuilder {
 
 	private PersonIdent committer;
 
+	private GpgSignature gpgSignature;
+
 	private String message;
 
 	private Charset encoding;
@@ -108,7 +116,7 @@ public ObjectId getTreeId() {
 	}
 
 	/**
-	 * Set the tree id for this commit object
+	 * Set the tree id for this commit object.
 	 *
 	 * @param id
 	 *            the tree identity.
@@ -146,7 +154,7 @@ public PersonIdent getCommitter() {
 	}
 
 	/**
-	 * Set the committer and commit time for this object
+	 * Set the committer and commit time for this object.
 	 *
 	 * @param newCommitter
 	 *            the committer information. Should not be null.
@@ -156,6 +164,38 @@ public void setCommitter(PersonIdent newCommitter) {
 	}
 
 	/**
+	 * Set the GPG signature of this commit.
+	 * <p>
+	 * Note, the signature set here will change the payload of the commit, i.e.
+	 * the output of {@link #build()} will include the signature. Thus, the
+	 * typical flow will be:
+	 * <ol>
+	 * <li>call {@link #build()} without a signature set to obtain payload</li>
+	 * <li>create {@link GpgSignature} from payload</li>
+	 * <li>set {@link GpgSignature}</li>
+	 * </ol>
+	 * </p>
+	 *
+	 * @param newSignature
+	 *            the signature to set or <code>null</code> to unset
+	 * @since 5.3
+	 */
+	public void setGpgSignature(GpgSignature newSignature) {
+		gpgSignature = newSignature;
+	}
+
+	/**
+	 * Get the GPG signature of this commit.
+	 *
+	 * @return the GPG signature of this commit, maybe <code>null</code> if the
+	 *         commit is not to be signed
+	 * @since 5.3
+	 */
+	public GpgSignature getGpgSignature() {
+		return gpgSignature;
+	}
+
+	/**
 	 * Get the ancestors of this commit.
 	 *
 	 * @return the ancestors of this commit. Never null.
@@ -250,18 +290,20 @@ public void setMessage(String newMessage) {
 	}
 
 	/**
-	 * Set the encoding for the commit information
+	 * Set the encoding for the commit information.
 	 *
 	 * @param encodingName
 	 *            the encoding name. See
 	 *            {@link java.nio.charset.Charset#forName(String)}.
+	 * @deprecated use {@link #setEncoding(Charset)} instead.
 	 */
+	@Deprecated
 	public void setEncoding(String encodingName) {
 		encoding = Charset.forName(encodingName);
 	}
 
 	/**
-	 * Set the encoding for the commit information
+	 * Set the encoding for the commit information.
 	 *
 	 * @param enc
 	 *            the encoding to use.
@@ -316,6 +358,13 @@ public Charset getEncoding() {
 			w.flush();
 			os.write('\n');
 
+			if (getGpgSignature() != null) {
+				os.write(hgpgsig);
+				os.write(' ');
+				writeGpgSignatureString(getGpgSignature().toExternalString(), os);
+				os.write('\n');
+			}
+
 			if (getEncoding() != UTF_8) {
 				os.write(hencoding);
 				os.write(' ');
@@ -339,6 +388,50 @@ public Charset getEncoding() {
 	}
 
 	/**
+	 * Writes signature to output as per <a href=
+	 * "https://github.com/git/git/blob/master/Documentation/technical/signature-format.txt#L66,L89">gpgsig
+	 * header</a>.
+	 * <p>
+	 * CRLF and CR will be sanitized to LF and signature will have a hanging
+	 * indent of one space starting with line two.
+	 * </p>
+	 *
+	 * @param in
+	 *            signature string with line breaks
+	 * @param out
+	 *            output stream
+	 * @throws IOException
+	 *             thrown by the output stream
+	 * @throws IllegalArgumentException
+	 *             if the signature string contains non 7-bit ASCII chars
+	 */
+	static void writeGpgSignatureString(String in, OutputStream out)
+			throws IOException, IllegalArgumentException {
+		for (int i = 0; i < in.length(); ++i) {
+			char ch = in.charAt(i);
+			if (ch == '\r') {
+				if (i + 1 < in.length() && in.charAt(i + 1) == '\n') {
+					out.write('\n');
+					out.write(' ');
+					++i;
+				} else {
+					out.write('\n');
+					out.write(' ');
+				}
+			} else if (ch == '\n') {
+				out.write('\n');
+				out.write(' ');
+			} else {
+				// sanity check
+				if (ch > 127)
+					throw new IllegalArgumentException(MessageFormat
+							.format(JGitText.get().notASCIIString, in));
+				out.write(ch);
+			}
+		}
+	}
+
+	/**
 	 * Format this builder's state as a commit object.
 	 *
 	 * @return this object in the canonical commit format, suitable for storage
@@ -377,6 +470,10 @@ public String toString() {
 		r.append(committer != null ? committer.toString() : "NOT_SET");
 		r.append("\n");
 
+		r.append("gpgSignature ");
+		r.append(gpgSignature != null ? gpgSignature.toString() : "NOT_SET");
+		r.append("\n");
+
 		if (encoding != null && encoding != UTF_8) {
 			r.append("encoding ");
 			r.append(encoding.name());
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/GpgSignature.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/GpgSignature.java
new file mode 100644
index 0000000..663f850
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/GpgSignature.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2018, Salesforce.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ *   copyright notice, this list of conditions and the following
+ *   disclaimer in the documentation and/or other materials provided
+ *   with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ *   names of its contributors may be used to endorse or promote
+ *   products derived from this software without specific prior
+ *   written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.eclipse.jgit.lib;
+
+import static java.nio.charset.StandardCharsets.US_ASCII;
+
+import java.io.Serializable;
+
+import org.eclipse.jgit.annotations.NonNull;
+
+/**
+ * A structure for holding GPG signature together with additional related data.
+ *
+ * @since 5.3
+ */
+public class GpgSignature implements Serializable {
+
+	private static final long serialVersionUID = 1L;
+
+	private byte[] signature;
+
+	/**
+	 * Creates a new instance with the specified signature
+	 *
+	 * @param signature
+	 *            the signature
+	 */
+	public GpgSignature(@NonNull byte[] signature) {
+		this.signature = signature;
+	}
+
+	/**
+	 * Format for Git storage.
+	 * <p>
+	 * This returns the ASCII Armor as per
+	 * https://tools.ietf.org/html/rfc4880#section-6.2.
+	 * </p>
+	 *
+	 * @return a string of the signature ready to be embedded in a Git object
+	 */
+	public String toExternalString() {
+		return new String(signature, US_ASCII);
+	}
+
+	/** {@inheritDoc} */
+	@Override
+	@SuppressWarnings("nls")
+	public String toString() {
+		final StringBuilder r = new StringBuilder();
+
+		r.append("GpgSignature[");
+		r.append(
+				this.signature != null ? "length " + signature.length : "null");
+		r.append("]");
+
+		return r.toString();
+	}
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/GpgSigner.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/GpgSigner.java
new file mode 100644
index 0000000..99a23c6
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/GpgSigner.java
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2018, Salesforce.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ *   copyright notice, this list of conditions and the following
+ *   disclaimer in the documentation and/or other materials provided
+ *   with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ *   names of its contributors may be used to endorse or promote
+ *   products derived from this software without specific prior
+ *   written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.eclipse.jgit.lib;
+
+import org.eclipse.jgit.annotations.NonNull;
+import org.eclipse.jgit.annotations.Nullable;
+import org.eclipse.jgit.api.errors.CanceledException;
+import org.eclipse.jgit.lib.internal.BouncyCastleGpgSigner;
+import org.eclipse.jgit.transport.CredentialsProvider;
+
+/**
+ * Creates GPG signatures for Git objects.
+ *
+ * @since 5.3
+ */
+public abstract class GpgSigner {
+
+	private static GpgSigner defaultSigner = new BouncyCastleGpgSigner();
+
+	/**
+	 * Get the default signer, or <code>null</code>.
+	 *
+	 * @return the default signer, or <code>null</code>.
+	 */
+	public static GpgSigner getDefault() {
+		return defaultSigner;
+	}
+
+	/**
+	 * Set the default signer.
+	 *
+	 * @param signer
+	 *            the new default signer, may be <code>null</code> to select no
+	 *            default.
+	 */
+	public static void setDefault(GpgSigner signer) {
+		GpgSigner.defaultSigner = signer;
+	}
+
+	/**
+	 * Signs the specified commit.
+	 *
+	 * <p>
+	 * Implementors should obtain the payload for signing from the specified
+	 * commit via {@link CommitBuilder#build()} and create a proper
+	 * {@link GpgSignature}. The generated signature must be set on the
+	 * specified {@code commit} (see
+	 * {@link CommitBuilder#setGpgSignature(GpgSignature)}).
+	 * </p>
+	 * <p>
+	 * Any existing signature on the commit must be discarded prior obtaining
+	 * the payload via {@link CommitBuilder#build()}.
+	 * </p>
+	 *
+	 * @param commit
+	 *            the commit to sign (must not be <code>null</code> and must be
+	 *            complete to allow proper calculation of payload)
+	 * @param gpgSigningKey
+	 *            the signing key to locate (passed as is to the GPG signing
+	 *            tool as is; eg., value of <code>user.signingkey</code>)
+	 * @param committer
+	 *            the signing identity (to help with key lookup in case signing
+	 *            key is not specified)
+	 * @param credentialsProvider
+	 *            provider to use when querying for signing key credentials (eg.
+	 *            passphrase)
+	 * @throws CanceledException
+	 *             when signing was canceled (eg., user aborted when entering
+	 *             passphrase)
+	 */
+	public abstract void sign(@NonNull CommitBuilder commit,
+			@Nullable String gpgSigningKey, @NonNull PersonIdent committer,
+			CredentialsProvider credentialsProvider) throws CanceledException;
+
+	/**
+	 * Indicates if a signing key is available for the specified committer
+	 * and/or signing key.
+	 *
+	 * @param gpgSigningKey
+	 *            the signing key to locate (passed as is to the GPG signing
+	 *            tool as is; eg., value of <code>user.signingkey</code>)
+	 * @param committer
+	 *            the signing identity (to help with key lookup in case signing
+	 *            key is not specified)
+	 * @param credentialsProvider
+	 *            provider to use when querying for signing key credentials (eg.
+	 *            passphrase)
+	 * @return <code>true</code> if a signing key is available,
+	 *         <code>false</code> otherwise
+	 * @throws CanceledException
+	 *             when signing was canceled (eg., user aborted when entering
+	 *             passphrase)
+	 */
+	public abstract boolean canLocateSigningKey(@Nullable String gpgSigningKey,
+			@NonNull PersonIdent committer,
+			CredentialsProvider credentialsProvider) throws CanceledException;
+
+}
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 764f890..0e96138 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectId.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectId.java
@@ -49,6 +49,7 @@
 import java.io.ObjectOutputStream;
 import java.io.Serializable;
 
+import org.eclipse.jgit.annotations.Nullable;
 import org.eclipse.jgit.errors.InvalidObjectIdException;
 import org.eclipse.jgit.util.NB;
 import org.eclipse.jgit.util.RawParseUtils;
@@ -86,7 +87,10 @@ public static final ObjectId zeroId() {
 	 *            the string to test.
 	 * @return true if the string can converted into an ObjectId.
 	 */
-	public static final boolean isId(String id) {
+	public static final boolean isId(@Nullable String id) {
+		if (id == null) {
+			return false;
+		}
 		if (id.length() != Constants.OBJECT_ID_STRING_LENGTH)
 			return false;
 		try {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectIdRef.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectIdRef.java
index 22aaa3a..b791c64 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectIdRef.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectIdRef.java
@@ -67,7 +67,26 @@ public static class Unpeeled extends ObjectIdRef {
 		 */
 		public Unpeeled(@NonNull Storage st, @NonNull String name,
 				@Nullable ObjectId id) {
-			super(st, name, id);
+			super(st, name, id, -1);
+		}
+
+		/**
+		 * Create a new ref pairing with update index.
+		 *
+		 * @param st
+		 *            method used to store this ref.
+		 * @param name
+		 *            name of this ref.
+		 * @param id
+		 *            current value of the ref. May be {@code null} to indicate
+		 *            a ref that does not exist yet.
+		 * @param updateIndex
+		 *            number increasing with each update to the reference.
+		 * @since 5.3
+		 */
+		public Unpeeled(@NonNull Storage st, @NonNull String name,
+				@Nullable ObjectId id, long updateIndex) {
+			super(st, name, id, updateIndex);
 		}
 
 		@Override
@@ -100,7 +119,29 @@ public static class PeeledTag extends ObjectIdRef {
 		 */
 		public PeeledTag(@NonNull Storage st, @NonNull String name,
 				@Nullable ObjectId id, @NonNull ObjectId p) {
-			super(st, name, id);
+			super(st, name, id, -1);
+			peeledObjectId = p;
+		}
+
+		/**
+		 * Create a new ref pairing with update index.
+		 *
+		 * @param st
+		 *            method used to store this ref.
+		 * @param name
+		 *            name of this ref.
+		 * @param id
+		 *            current value of the ref. May be {@code null} to indicate
+		 *            a ref that does not exist yet.
+		 * @param p
+		 *            the first non-tag object that tag {@code id} points to.
+		 * @param updateIndex
+		 *            number increasing with each update to the reference.
+		 * @since 5.3
+		 */
+		public PeeledTag(@NonNull Storage st, @NonNull String name,
+				@Nullable ObjectId id, @NonNull ObjectId p, long updateIndex) {
+			super(st, name, id, updateIndex);
 			peeledObjectId = p;
 		}
 
@@ -131,7 +172,26 @@ public static class PeeledNonTag extends ObjectIdRef {
 		 */
 		public PeeledNonTag(@NonNull Storage st, @NonNull String name,
 				@Nullable ObjectId id) {
-			super(st, name, id);
+			super(st, name, id, -1);
+		}
+
+		/**
+		 * Create a new ref pairing with update index.
+		 *
+		 * @param st
+		 *            method used to store this ref.
+		 * @param name
+		 *            name of this ref.
+		 * @param id
+		 *            current value of the ref. May be {@code null} to indicate
+		 *            a ref that does not exist yet.
+		 * @param updateIndex
+		 *            number increasing with each update to the reference.
+		 * @since 5.3
+		 */
+		public PeeledNonTag(@NonNull Storage st, @NonNull String name,
+				@Nullable ObjectId id, long updateIndex) {
+			super(st, name, id, updateIndex);
 		}
 
 		@Override
@@ -152,6 +212,8 @@ public boolean isPeeled() {
 
 	private final ObjectId objectId;
 
+	private final long updateIndex;
+
 	/**
 	 * Create a new ref pairing.
 	 *
@@ -162,12 +224,17 @@ public boolean isPeeled() {
 	 * @param id
 	 *            current value of the ref. May be {@code null} to indicate a
 	 *            ref that does not exist yet.
+	 * @param updateIndex
+	 *            number that increases with each ref update. Set to -1 if the
+	 *            storage doesn't support versioning.
+	 * @since 5.3
 	 */
 	protected ObjectIdRef(@NonNull Storage st, @NonNull String name,
-			@Nullable ObjectId id) {
+			@Nullable ObjectId id, long updateIndex) {
 		this.name = name;
 		this.storage = st;
 		this.objectId = id;
+		this.updateIndex = updateIndex;
 	}
 
 	/** {@inheritDoc} */
@@ -211,6 +278,18 @@ public Storage getStorage() {
 		return storage;
 	}
 
+	/**
+	 * {@inheritDoc}
+	 * @since 5.3
+	 */
+	@Override
+	public long getUpdateIndex() {
+		if (updateIndex == -1) {
+			throw new UnsupportedOperationException();
+		}
+		return updateIndex;
+	}
+
 	/** {@inheritDoc} */
 	@NonNull
 	@Override
@@ -220,7 +299,9 @@ public String toString() {
 		r.append(getName());
 		r.append('=');
 		r.append(ObjectId.toString(getObjectId()));
-		r.append(']');
+		r.append('(');
+		r.append(updateIndex); // Print value, even if -1
+		r.append(")]"); //$NON-NLS-1$
 		return r.toString();
 	}
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Ref.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Ref.java
index faabbf8..32c8b06 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Ref.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Ref.java
@@ -217,4 +217,27 @@ public boolean isPacked() {
 	 */
 	@NonNull
 	Storage getStorage();
+
+	/**
+	 * Indicator of the relative order between updates of a specific reference
+	 * name. A number that increases when a reference is updated.
+	 * <p>
+	 * With symbolic references, the update index refers to updates of the
+	 * symbolic reference itself. For example, if HEAD points to
+	 * refs/heads/master, then the update index for exactRef("HEAD") will only
+	 * increase when HEAD changes to point to another ref, regardless of how
+	 * many times refs/heads/master is updated.
+	 * <p>
+	 * Should not be used unless the {@code RefDatabase} that instantiated the
+	 * ref supports versioning (see {@link RefDatabase#hasVersioning()})
+	 *
+	 * @return the update index (i.e. version) of this reference.
+	 * @throws UnsupportedOperationException
+	 *             if the creator of the instance (e.g. {@link RefDatabase})
+	 *             doesn't support versioning and doesn't override this method
+	 * @since 5.3
+	 */
+	default long getUpdateIndex() {
+		throw new UnsupportedOperationException();
+	}
 }
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 68929b4..8777920 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefDatabase.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefDatabase.java
@@ -69,10 +69,10 @@ public abstract class RefDatabase {
 	/**
 	 * Order of prefixes to search when using non-absolute references.
 	 * <p>
-	 * The implementation's {@link #getRef(String)} method must take this search
-	 * space into consideration when locating a reference by name. The first
-	 * entry in the path is always {@code ""}, ensuring that absolute references
-	 * are resolved without further mangling.
+	 * {@link #findRef(String)} takes this search space into consideration
+	 * when locating a reference by name. The first entry in the path is
+	 * always {@code ""}, ensuring that absolute references are resolved
+	 * without further mangling.
 	 */
 	protected static final String[] SEARCH_PATH = { "", //$NON-NLS-1$
 			Constants.R_REFS, //
@@ -111,6 +111,19 @@ public abstract class RefDatabase {
 	public abstract void close();
 
 	/**
+	 * With versioning, each reference has a version number that increases on
+	 * update. See {@link Ref#getUpdateIndex()}.
+	 *
+	 * @implSpec This method returns false by default. Implementations
+	 *           supporting versioning must override it to return true.
+	 * @return true if the implementation assigns update indices to references.
+	 * @since 5.3
+	 */
+	public boolean hasVersioning() {
+		return false;
+	}
+
+	/**
 	 * Determine if a proposed reference name overlaps with an existing one.
 	 * <p>
 	 * Reference names use '/' as a component separator, and may be stored in a
@@ -244,6 +257,23 @@ public boolean performsAtomicTransactions() {
 	}
 
 	/**
+	 * Compatibility synonym for {@link #findRef(String)}.
+	 *
+	 * @param name
+	 *            the name of the reference. May be a short name which must be
+	 *            searched for using the standard {@link #SEARCH_PATH}.
+	 * @return the reference (if it exists); else {@code null}.
+	 * @throws IOException
+	 *             the reference space cannot be accessed.
+	 * @deprecated Use {@link #findRef(String)} instead.
+	 */
+	@Deprecated
+	@Nullable
+	public final Ref getRef(String name) throws IOException {
+		return findRef(name);
+	}
+
+	/**
 	 * Read a single reference.
 	 * <p>
 	 * Aside from taking advantage of {@link #SEARCH_PATH}, this method may be
@@ -259,14 +289,21 @@ public boolean performsAtomicTransactions() {
 	 * @return the reference (if it exists); else {@code null}.
 	 * @throws java.io.IOException
 	 *             the reference space cannot be accessed.
+	 * @since 5.3
 	 */
 	@Nullable
-	public abstract Ref getRef(String name) throws IOException;
+	public final Ref findRef(String name) throws IOException {
+		String[] names = new String[SEARCH_PATH.length];
+		for (int i = 0; i < SEARCH_PATH.length; i++) {
+			names[i] = SEARCH_PATH[i] + name;
+		}
+		return firstExactRef(names);
+	}
 
 	/**
 	 * Read a single reference.
 	 * <p>
-	 * Unlike {@link #getRef}, this method expects an unshortened reference
+	 * Unlike {@link #findRef}, this method expects an unshortened reference
 	 * name and does not search using the standard {@link #SEARCH_PATH}.
 	 *
 	 * @param name
@@ -277,13 +314,7 @@ public boolean performsAtomicTransactions() {
 	 * @since 4.1
 	 */
 	@Nullable
-	public Ref exactRef(String name) throws IOException {
-		Ref ref = getRef(name);
-		if (ref == null || !name.equals(ref.getName())) {
-			return null;
-		}
-		return ref;
-	}
+	public abstract Ref exactRef(String name) throws IOException;
 
 	/**
 	 * Read the specified references.
@@ -462,7 +493,7 @@ public boolean hasRefs() throws IOException {
 	 * <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()</code> but are accepted by {@link #getRef(String)}
+	 * <code>getRefs()</code> but are accepted by {@link #findRef(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 a05daa0..0bd34b5 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefRename.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefRename.java
@@ -184,7 +184,7 @@ public Result rename() throws IOException {
 	 *             the current value of {@code HEAD} cannot be read.
 	 */
 	protected boolean needToUpdateHEAD() throws IOException {
-		Ref head = source.getRefDatabase().getRef(Constants.HEAD);
+		Ref head = source.getRefDatabase().exactRef(Constants.HEAD);
 		if (head != null && head.isSymbolic()) {
 			head = head.getTarget();
 			return head.getName().equals(source.getName());
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 fc3ea84..1ce1528 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefUpdate.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefUpdate.java
@@ -665,7 +665,7 @@ public Result delete(RevWalk walk) throws IOException {
 				: getRef().getLeaf().getName();
 		if (myName.startsWith(Constants.R_HEADS) && !getRepository().isBare()) {
 			// Don't allow the currently checked out branch to be deleted.
-			Ref head = getRefDatabase().getRef(Constants.HEAD);
+			Ref head = getRefDatabase().exactRef(Constants.HEAD);
 			while (head != null && head.isSymbolic()) {
 				head = head.getTarget();
 				if (myName.equals(head.getName()))
@@ -708,7 +708,7 @@ public Result link(String target) throws IOException {
 			if (!tryLock(false))
 				return Result.LOCK_FAILURE;
 
-			final Ref old = getRefDatabase().getRef(getName());
+			final Ref old = getRefDatabase().exactRef(getName());
 			if (old != null && old.isSymbolic()) {
 				final Ref dst = old.getTarget();
 				if (target.equals(dst.getName()))
@@ -718,7 +718,7 @@ public Result link(String target) throws IOException {
 			if (old != null && old.getObjectId() != null)
 				setOldObjectId(old.getObjectId());
 
-			final Ref dst = getRefDatabase().getRef(target);
+			final Ref dst = getRefDatabase().exactRef(target);
 			if (dst != null && dst.getObjectId() != null)
 				setNewObjectId(dst.getObjectId());
 
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 77d268a..a61897a 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Repository.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Repository.java
@@ -57,6 +57,7 @@
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.OutputStream;
+import java.io.UncheckedIOException;
 import java.net.URISyntaxException;
 import java.text.MessageFormat;
 import java.util.Collection;
@@ -297,7 +298,7 @@ public ObjectReader newObjectReader() {
 	/**
 	 * Get the used file system abstraction.
 	 *
-	 * @return the used file system abstraction, or or {@code null} if
+	 * @return the used file system abstraction, or {@code null} if
 	 *         repository isn't local.
 	 */
 	/*
@@ -319,13 +320,14 @@ public FS getFS() {
 	 *            a {@link org.eclipse.jgit.lib.AnyObjectId} object.
 	 * @return true if the specified object is stored in this repo or any of the
 	 *         known shared repositories.
+	 * @deprecated use {@code getObjectDatabase().has(objectId)}
 	 */
+	@Deprecated
 	public boolean hasObject(AnyObjectId objectId) {
 		try {
 			return getObjectDatabase().has(objectId);
 		} catch (IOException e) {
-			// Legacy API, assume error means "no"
-			return false;
+			throw new UncheckedIOException(e);
 		}
 	}
 
@@ -849,7 +851,7 @@ private ObjectId resolveSimple(String revstr) throws IOException {
 			return ObjectId.fromString(revstr);
 
 		if (Repository.isValidRefName("x/" + revstr)) { //$NON-NLS-1$
-			Ref r = getRefDatabase().getRef(revstr);
+			Ref r = getRefDatabase().findRef(revstr);
 			if (r != null)
 				return r.getObjectId();
 		}
@@ -1079,7 +1081,7 @@ public final Ref exactRef(String name) throws IOException {
 	 *
 	 * @param name
 	 *            the name of the ref to lookup. May be a short-hand form, e.g.
-	 *            "master" which is is automatically expanded to
+	 *            "master" which 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
@@ -1087,7 +1089,7 @@ public final Ref exactRef(String name) throws IOException {
 	 */
 	@Nullable
 	public final Ref findRef(String name) throws IOException {
-		return getRefDatabase().getRef(name);
+		return getRefDatabase().findRef(name);
 	}
 
 	/**
@@ -1103,7 +1105,7 @@ public Map<String, Ref> getAllRefs() {
 		try {
 			return getRefDatabase().getRefs(RefDatabase.ALL);
 		} catch (IOException e) {
-			return new HashMap<>();
+			throw new UncheckedIOException(e);
 		}
 	}
 
@@ -1121,7 +1123,7 @@ public Map<String, Ref> getTags() {
 		try {
 			return getRefDatabase().getRefs(Constants.R_TAGS);
 		} catch (IOException e) {
-			return new HashMap<>();
+			throw new UncheckedIOException(e);
 		}
 	}
 
@@ -1320,9 +1322,7 @@ public RepositoryState getRepositoryState() {
 					return RepositoryState.MERGING_RESOLVED;
 				}
 			} catch (IOException e) {
-				// Can't decide whether unmerged paths exists. Return
-				// MERGING state to be on the safe side (in state MERGING
-				// you are not allow to do anything)
+				throw new UncheckedIOException(e);
 			}
 			return RepositoryState.MERGING;
 		}
@@ -1337,7 +1337,7 @@ public RepositoryState getRepositoryState() {
 					return RepositoryState.CHERRY_PICKING_RESOLVED;
 				}
 			} catch (IOException e) {
-				// fall through to CHERRY_PICKING
+				throw new UncheckedIOException(e);
 			}
 
 			return RepositoryState.CHERRY_PICKING;
@@ -1350,7 +1350,7 @@ public RepositoryState getRepositoryState() {
 					return RepositoryState.REVERTING_RESOLVED;
 				}
 			} catch (IOException e) {
-				// fall through to REVERTING
+				throw new UncheckedIOException(e);
 			}
 
 			return RepositoryState.REVERTING;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/SymbolicRef.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/SymbolicRef.java
index d4b83b0..00fcf52 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/SymbolicRef.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/SymbolicRef.java
@@ -58,6 +58,8 @@ public class SymbolicRef implements Ref {
 
 	private final Ref target;
 
+	private final long updateIndex;
+
 	/**
 	 * Create a new ref pairing.
 	 *
@@ -69,6 +71,25 @@ public class SymbolicRef implements Ref {
 	public SymbolicRef(@NonNull String refName, @NonNull Ref target) {
 		this.name = refName;
 		this.target = target;
+		this.updateIndex = -1;
+	}
+
+	/**
+	 * Create a new ref pairing.
+	 *
+	 * @param refName
+	 *            name of this ref.
+	 * @param target
+	 *            the ref we reference and derive our value from.
+	 * @param updateIndex
+	 *            index that increases with each update of the reference
+	 * @since 5.3
+	 */
+	public SymbolicRef(@NonNull String refName, @NonNull Ref target,
+			long updateIndex) {
+		this.name = refName;
+		this.target = target;
+		this.updateIndex = updateIndex;
 	}
 
 	/** {@inheritDoc} */
@@ -128,6 +149,18 @@ public boolean isPeeled() {
 		return getLeaf().isPeeled();
 	}
 
+	/**
+	 * {@inheritDoc}
+	 * @since 5.3
+	 */
+	@Override
+	public long getUpdateIndex() {
+		if (updateIndex == -1) {
+			throw new UnsupportedOperationException();
+		}
+		return updateIndex;
+	}
+
 	/** {@inheritDoc} */
 	@SuppressWarnings("nls")
 	@Override
@@ -143,7 +176,9 @@ public String toString() {
 		r.append(cur.getName());
 		r.append('=');
 		r.append(ObjectId.toString(cur.getObjectId()));
-		r.append("]");
+		r.append("(");
+		r.append(updateIndex); // Print value, even if -1
+		r.append(")]");
 		return r.toString();
 	}
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/internal/BouncyCastleGpgKey.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/internal/BouncyCastleGpgKey.java
new file mode 100644
index 0000000..ef9d7ee
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/internal/BouncyCastleGpgKey.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2018, Salesforce.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ *   copyright notice, this list of conditions and the following
+ *   disclaimer in the documentation and/or other materials provided
+ *   with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ *   names of its contributors may be used to endorse or promote
+ *   products derived from this software without specific prior
+ *   written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.eclipse.jgit.lib.internal;
+
+import java.nio.file.Path;
+
+import org.bouncycastle.openpgp.PGPSecretKey;
+
+/**
+ * Container which holds a {@link #getSecretKey()} together with the
+ * {@link #getOrigin() path it was loaded from}.
+ */
+class BouncyCastleGpgKey {
+
+	private PGPSecretKey secretKey;
+
+	private Path origin;
+
+	public BouncyCastleGpgKey(PGPSecretKey secretKey, Path origin) {
+		this.secretKey = secretKey;
+		this.origin = origin;
+	}
+
+	public PGPSecretKey getSecretKey() {
+		return secretKey;
+	}
+
+	public Path getOrigin() {
+		return origin;
+	}
+}
\ No newline at end of file
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/internal/BouncyCastleGpgKeyLocator.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/internal/BouncyCastleGpgKeyLocator.java
new file mode 100644
index 0000000..091667d
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/internal/BouncyCastleGpgKeyLocator.java
@@ -0,0 +1,373 @@
+/*
+ * Copyright (C) 2018, Salesforce.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ *   copyright notice, this list of conditions and the following
+ *   disclaimer in the documentation and/or other materials provided
+ *   with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ *   names of its contributors may be used to endorse or promote
+ *   products derived from this software without specific prior
+ *   written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.eclipse.jgit.lib.internal;
+
+import static java.nio.file.Files.exists;
+import static java.nio.file.Files.newInputStream;
+
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URISyntaxException;
+import java.nio.file.Files;
+import java.nio.file.InvalidPathException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.text.MessageFormat;
+import java.util.Iterator;
+import java.util.Locale;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import org.bouncycastle.gpg.SExprParser;
+import org.bouncycastle.gpg.keybox.BlobType;
+import org.bouncycastle.gpg.keybox.KeyBlob;
+import org.bouncycastle.gpg.keybox.KeyBox;
+import org.bouncycastle.gpg.keybox.KeyInformation;
+import org.bouncycastle.gpg.keybox.PublicKeyRingBlob;
+import org.bouncycastle.gpg.keybox.UserID;
+import org.bouncycastle.openpgp.PGPException;
+import org.bouncycastle.openpgp.PGPPublicKey;
+import org.bouncycastle.openpgp.PGPSecretKey;
+import org.bouncycastle.openpgp.PGPSecretKeyRing;
+import org.bouncycastle.openpgp.PGPSecretKeyRingCollection;
+import org.bouncycastle.openpgp.PGPUtil;
+import org.bouncycastle.openpgp.operator.PBEProtectionRemoverFactory;
+import org.bouncycastle.openpgp.operator.PGPDigestCalculatorProvider;
+import org.bouncycastle.openpgp.operator.jcajce.JcaKeyFingerprintCalculator;
+import org.bouncycastle.openpgp.operator.jcajce.JcaPGPDigestCalculatorProviderBuilder;
+import org.bouncycastle.openpgp.operator.jcajce.JcePBEProtectionRemoverFactory;
+import org.bouncycastle.util.encoders.Hex;
+import org.eclipse.jgit.annotations.NonNull;
+import org.eclipse.jgit.api.errors.CanceledException;
+import org.eclipse.jgit.errors.UnsupportedCredentialItem;
+import org.eclipse.jgit.internal.JGitText;
+import org.eclipse.jgit.util.FS;
+import org.eclipse.jgit.util.SystemReader;
+
+/**
+ * Locates GPG keys from either <code>~/.gnupg/private-keys-v1.d</code> or
+ * <code>~/.gnupg/secring.gpg</code>
+ */
+class BouncyCastleGpgKeyLocator {
+
+	private static final Path GPG_DIRECTORY = findGpgDirectory();
+
+	private static final Path USER_KEYBOX_PATH = GPG_DIRECTORY
+			.resolve("pubring.kbx"); //$NON-NLS-1$
+
+	private static final Path USER_SECRET_KEY_DIR = GPG_DIRECTORY
+			.resolve("private-keys-v1.d"); //$NON-NLS-1$
+
+	private static final Path USER_PGP_LEGACY_SECRING_FILE = GPG_DIRECTORY
+			.resolve("secring.gpg"); //$NON-NLS-1$
+
+	private final String signingKey;
+
+	private BouncyCastleGpgKeyPassphrasePrompt passphrasePrompt;
+
+	private static Path findGpgDirectory() {
+		SystemReader system = SystemReader.getInstance();
+		if (system.isWindows()) {
+			// On Windows prefer %APPDATA%\gnupg if it exists, even if Cygwin is
+			// used.
+			String appData = system.getenv("APPDATA"); //$NON-NLS-1$
+			if (appData != null && !appData.isEmpty()) {
+				try {
+					Path directory = Paths.get(appData).resolve("gnupg"); //$NON-NLS-1$
+					if (Files.isDirectory(directory)) {
+						return directory;
+					}
+				} catch (SecurityException | InvalidPathException e) {
+					// Ignore and return the default location below.
+				}
+			}
+		}
+		// All systems, including Cygwin and even Windows if
+		// %APPDATA%\gnupg doesn't exist: ~/.gnupg
+		File home = FS.DETECTED.userHome();
+		if (home == null) {
+			// Oops. What now?
+			home = new File(".").getAbsoluteFile(); //$NON-NLS-1$
+		}
+		return home.toPath().resolve(".gnupg"); //$NON-NLS-1$
+	}
+
+	/**
+	 * Create a new key locator for the specified signing key.
+	 * <p>
+	 * The signing key must either be a hex representation of a specific key or
+	 * a user identity substring (eg., email address). All keys in the KeyBox
+	 * will be looked up in the order as returned by the KeyBox. A key id will
+	 * be searched before attempting to find a key by user id.
+	 * </p>
+	 *
+	 * @param signingKey
+	 *            the signing key to search for
+	 * @param passphrasePrompt
+	 *            the provider to use when asking for key passphrase
+	 */
+	public BouncyCastleGpgKeyLocator(String signingKey,
+			@NonNull BouncyCastleGpgKeyPassphrasePrompt passphrasePrompt) {
+		this.signingKey = signingKey;
+		this.passphrasePrompt = passphrasePrompt;
+	}
+
+	private PGPSecretKey attemptParseSecretKey(Path keyFile,
+			PGPDigestCalculatorProvider calculatorProvider,
+			PBEProtectionRemoverFactory passphraseProvider,
+			PGPPublicKey publicKey) throws IOException {
+		try (InputStream in = newInputStream(keyFile)) {
+			return new SExprParser(calculatorProvider).parseSecretKey(
+					new BufferedInputStream(in), passphraseProvider, publicKey);
+		} catch (PGPException | ClassCastException e) {
+			return null;
+		}
+	}
+
+	private boolean containsSigningKey(String userId) {
+		return userId.toLowerCase(Locale.ROOT)
+				.contains(signingKey.toLowerCase(Locale.ROOT));
+	}
+
+	private PGPPublicKey findPublicKeyByKeyId(KeyBlob keyBlob)
+			throws IOException {
+		for (KeyInformation keyInfo : keyBlob.getKeyInformation()) {
+			if (signingKey.toLowerCase(Locale.ROOT)
+					.equals(Hex.toHexString(keyInfo.getKeyID())
+							.toLowerCase(Locale.ROOT))) {
+				return getFirstPublicKey(keyBlob);
+			}
+		}
+		return null;
+	}
+
+	private PGPPublicKey findPublicKeyByUserId(KeyBlob keyBlob)
+			throws IOException {
+		for (UserID userID : keyBlob.getUserIds()) {
+			if (containsSigningKey(userID.getUserIDAsString())) {
+				return getFirstPublicKey(keyBlob);
+			}
+		}
+		return null;
+	}
+
+	/**
+	 * Finds a public key associated with the signing key.
+	 *
+	 * @param keyboxFile
+	 *            the KeyBox file
+	 * @return publicKey the public key (maybe <code>null</code>)
+	 * @throws IOException
+	 *             in case of problems reading the file
+	 */
+	private PGPPublicKey findPublicKeyInKeyBox(Path keyboxFile)
+			throws IOException {
+		KeyBox keyBox = readKeyBoxFile(keyboxFile);
+		for (KeyBlob keyBlob : keyBox.getKeyBlobs()) {
+			if (keyBlob.getType() == BlobType.OPEN_PGP_BLOB) {
+				PGPPublicKey key = findPublicKeyByKeyId(keyBlob);
+				if (key != null) {
+					return key;
+				}
+				key = findPublicKeyByUserId(keyBlob);
+				if (key != null) {
+					return key;
+				}
+			}
+		}
+		return null;
+	}
+
+	/**
+	 * Use pubring.kbx when available, if not fallback to secring.gpg or secret
+	 * key path provided to parse and return secret key
+	 *
+	 * @return the secret key
+	 * @throws IOException
+	 *             in case of issues reading key files
+	 * @throws PGPException
+	 *             in case of issues finding a key
+	 * @throws CanceledException
+	 * @throws URISyntaxException
+	 * @throws UnsupportedCredentialItem
+	 */
+	public BouncyCastleGpgKey findSecretKey()
+			throws IOException, PGPException, CanceledException,
+			UnsupportedCredentialItem, URISyntaxException {
+		if (exists(USER_KEYBOX_PATH)) {
+			PGPPublicKey publicKey = //
+					findPublicKeyInKeyBox(USER_KEYBOX_PATH);
+
+			if (publicKey != null) {
+				return findSecretKeyForKeyBoxPublicKey(publicKey,
+						USER_KEYBOX_PATH);
+			}
+
+			throw new PGPException(MessageFormat
+					.format(JGitText.get().gpgNoPublicKeyFound, signingKey));
+		} else if (exists(USER_PGP_LEGACY_SECRING_FILE)) {
+			PGPSecretKey secretKey = findSecretKeyInLegacySecring(signingKey,
+					USER_PGP_LEGACY_SECRING_FILE);
+
+			if (secretKey != null) {
+				return new BouncyCastleGpgKey(secretKey, USER_PGP_LEGACY_SECRING_FILE);
+			}
+
+			throw new PGPException(MessageFormat.format(
+					JGitText.get().gpgNoKeyInLegacySecring, signingKey));
+		}
+
+		throw new PGPException(JGitText.get().gpgNoKeyring);
+	}
+
+	private BouncyCastleGpgKey findSecretKeyForKeyBoxPublicKey(
+			PGPPublicKey publicKey, Path userKeyboxPath)
+			throws PGPException, CanceledException, UnsupportedCredentialItem,
+			URISyntaxException {
+		/*
+		 * this is somewhat brute-force but there doesn't seem to be another
+		 * way; we have to walk all private key files we find and try to open
+		 * them
+		 */
+
+		PGPDigestCalculatorProvider calculatorProvider = new JcaPGPDigestCalculatorProviderBuilder()
+				.build();
+
+		PBEProtectionRemoverFactory passphraseProvider = new JcePBEProtectionRemoverFactory(
+				passphrasePrompt.getPassphrase(publicKey.getFingerprint(),
+						userKeyboxPath));
+
+		try (Stream<Path> keyFiles = Files.walk(USER_SECRET_KEY_DIR)) {
+			for (Path keyFile : keyFiles.filter(Files::isRegularFile)
+					.collect(Collectors.toList())) {
+				PGPSecretKey secretKey = attemptParseSecretKey(keyFile,
+						calculatorProvider, passphraseProvider, publicKey);
+				if (secretKey != null) {
+					return new BouncyCastleGpgKey(secretKey, userKeyboxPath);
+				}
+			}
+
+			passphrasePrompt.clear();
+			throw new PGPException(MessageFormat.format(
+					JGitText.get().gpgNoSecretKeyForPublicKey,
+					Long.toHexString(publicKey.getKeyID())));
+		} catch (RuntimeException e) {
+			passphrasePrompt.clear();
+			throw e;
+		} catch (IOException e) {
+			passphrasePrompt.clear();
+			throw new PGPException(MessageFormat.format(
+					JGitText.get().gpgFailedToParseSecretKey,
+					USER_SECRET_KEY_DIR.toAbsolutePath()), e);
+		}
+	}
+
+	/**
+	 * Return the first suitable key for signing in the key ring collection. For
+	 * this case we only expect there to be one key available for signing.
+	 * </p>
+	 *
+	 * @param signingkey
+	 * @param secringFile
+	 *
+	 * @return the first suitable PGP secret key found for signing
+	 * @throws IOException
+	 *             on I/O related errors
+	 * @throws PGPException
+	 *             on BouncyCastle errors
+	 */
+	private PGPSecretKey findSecretKeyInLegacySecring(String signingkey,
+			Path secringFile) throws IOException, PGPException {
+
+		try (InputStream in = newInputStream(secringFile)) {
+			PGPSecretKeyRingCollection pgpSec = new PGPSecretKeyRingCollection(
+					PGPUtil.getDecoderStream(new BufferedInputStream(in)),
+					new JcaKeyFingerprintCalculator());
+
+			Iterator<PGPSecretKeyRing> keyrings = pgpSec.getKeyRings();
+			while (keyrings.hasNext()) {
+				PGPSecretKeyRing keyRing = keyrings.next();
+				Iterator<PGPSecretKey> keys = keyRing.getSecretKeys();
+				while (keys.hasNext()) {
+					PGPSecretKey key = keys.next();
+					// try key id
+					String fingerprint = Hex
+							.toHexString(key.getPublicKey().getFingerprint())
+							.toLowerCase(Locale.ROOT);
+					if (fingerprint
+							.endsWith(signingkey.toLowerCase(Locale.ROOT))) {
+						return key;
+					}
+					// try user id
+					Iterator<String> userIDs = key.getUserIDs();
+					while (userIDs.hasNext()) {
+						String userId = userIDs.next();
+						if (containsSigningKey(userId)) {
+							return key;
+						}
+					}
+				}
+			}
+		}
+		return null;
+	}
+
+	private PGPPublicKey getFirstPublicKey(KeyBlob keyBlob) throws IOException {
+		return ((PublicKeyRingBlob) keyBlob).getPGPPublicKeyRing()
+				.getPublicKey();
+	}
+
+	private KeyBox readKeyBoxFile(Path keyboxFile) throws IOException {
+		KeyBox keyBox;
+		try (InputStream in = new BufferedInputStream(
+				newInputStream(keyboxFile))) {
+			// note: KeyBox constructor reads in the whole InputStream at once
+			// this code will change in 1.61 to
+			// either 'new BcKeyBox(in)' or 'new JcaKeyBoxBuilder().build(in)'
+			keyBox = new KeyBox(in, new JcaKeyFingerprintCalculator());
+		}
+		return keyBox;
+	}
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/internal/BouncyCastleGpgKeyPassphrasePrompt.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/internal/BouncyCastleGpgKeyPassphrasePrompt.java
new file mode 100644
index 0000000..2efe962
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/internal/BouncyCastleGpgKeyPassphrasePrompt.java
@@ -0,0 +1,134 @@
+/*-
+ * Copyright (C) 2019, Salesforce.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ *   copyright notice, this list of conditions and the following
+ *   disclaimer in the documentation and/or other materials provided
+ *   with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ *   names of its contributors may be used to endorse or promote
+ *   products derived from this software without specific prior
+ *   written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.eclipse.jgit.lib.internal;
+
+import java.net.URISyntaxException;
+import java.nio.file.Path;
+import java.text.MessageFormat;
+
+import org.bouncycastle.openpgp.PGPException;
+import org.bouncycastle.util.encoders.Hex;
+import org.eclipse.jgit.api.errors.CanceledException;
+import org.eclipse.jgit.errors.UnsupportedCredentialItem;
+import org.eclipse.jgit.internal.JGitText;
+import org.eclipse.jgit.transport.CredentialItem.CharArrayType;
+import org.eclipse.jgit.transport.CredentialItem.InformationalMessage;
+import org.eclipse.jgit.transport.CredentialsProvider;
+import org.eclipse.jgit.transport.URIish;
+
+/**
+ * Prompts for a passphrase and caches it until {@link #clear() cleared}.
+ * <p>
+ * Implements {@link AutoCloseable} so it can be used within a
+ * try-with-resources block.
+ * </p>
+ */
+class BouncyCastleGpgKeyPassphrasePrompt implements AutoCloseable {
+
+	private CharArrayType passphrase;
+
+	private CredentialsProvider credentialsProvider;
+
+	public BouncyCastleGpgKeyPassphrasePrompt(
+			CredentialsProvider credentialsProvider) {
+		this.credentialsProvider = credentialsProvider;
+	}
+
+	/**
+	 * Clears any cached passphrase
+	 */
+	public void clear() {
+		if (passphrase != null) {
+			passphrase.clear();
+			passphrase = null;
+		}
+	}
+
+	@Override
+	public void close() {
+		clear();
+	}
+
+	private URIish createURI(Path keyLocation) throws URISyntaxException {
+		return new URIish(keyLocation.toUri().toString());
+	}
+
+	/**
+	 * Prompts use for a passphrase unless one was cached from a previous
+	 * prompt.
+	 *
+	 * @param keyFingerprint
+	 *            the fingerprint to show to the user during prompting
+	 * @param keyLocation
+	 *            the location the key was loaded from
+	 * @return the passphrase (maybe <code>null</code>)
+	 * @throws PGPException
+	 * @throws CanceledException
+	 *             in case passphrase was not entered by user
+	 * @throws URISyntaxException
+	 * @throws UnsupportedCredentialItem
+	 */
+	public char[] getPassphrase(byte[] keyFingerprint, Path keyLocation)
+			throws PGPException, CanceledException, UnsupportedCredentialItem,
+			URISyntaxException {
+		if (passphrase == null) {
+			passphrase = new CharArrayType(JGitText.get().credentialPassphrase,
+					true);
+		}
+
+		if (credentialsProvider == null) {
+			throw new PGPException(JGitText.get().gpgNoCredentialsProvider);
+		}
+
+		if (passphrase.getValue() == null
+				&& !credentialsProvider.get(createURI(keyLocation),
+						new InformationalMessage(
+								MessageFormat.format(JGitText.get().gpgKeyInfo,
+										Hex.toHexString(keyFingerprint))),
+						passphrase)) {
+			throw new CanceledException(JGitText.get().gpgSigningCancelled);
+		}
+		return passphrase.getValue();
+	}
+
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/internal/BouncyCastleGpgSigner.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/internal/BouncyCastleGpgSigner.java
new file mode 100644
index 0000000..4d696dd
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/internal/BouncyCastleGpgSigner.java
@@ -0,0 +1,160 @@
+/*
+ * Copyright (C) 2018, Salesforce.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ *   copyright notice, this list of conditions and the following
+ *   disclaimer in the documentation and/or other materials provided
+ *   with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ *   names of its contributors may be used to endorse or promote
+ *   products derived from this software without specific prior
+ *   written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.eclipse.jgit.lib.internal;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.security.Security;
+
+import org.bouncycastle.bcpg.ArmoredOutputStream;
+import org.bouncycastle.bcpg.BCPGOutputStream;
+import org.bouncycastle.bcpg.HashAlgorithmTags;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.bouncycastle.openpgp.PGPException;
+import org.bouncycastle.openpgp.PGPPrivateKey;
+import org.bouncycastle.openpgp.PGPSecretKey;
+import org.bouncycastle.openpgp.PGPSignature;
+import org.bouncycastle.openpgp.PGPSignatureGenerator;
+import org.bouncycastle.openpgp.operator.jcajce.JcaPGPContentSignerBuilder;
+import org.bouncycastle.openpgp.operator.jcajce.JcePBESecretKeyDecryptorBuilder;
+import org.eclipse.jgit.annotations.NonNull;
+import org.eclipse.jgit.annotations.Nullable;
+import org.eclipse.jgit.api.errors.CanceledException;
+import org.eclipse.jgit.api.errors.JGitInternalException;
+import org.eclipse.jgit.errors.UnsupportedCredentialItem;
+import org.eclipse.jgit.internal.JGitText;
+import org.eclipse.jgit.lib.CommitBuilder;
+import org.eclipse.jgit.lib.GpgSignature;
+import org.eclipse.jgit.lib.GpgSigner;
+import org.eclipse.jgit.lib.PersonIdent;
+import org.eclipse.jgit.transport.CredentialsProvider;
+
+/**
+ * GPG Signer using BouncyCastle library
+ */
+public class BouncyCastleGpgSigner extends GpgSigner {
+
+	private static void registerBouncyCastleProviderIfNecessary() {
+		if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null) {
+			Security.addProvider(new BouncyCastleProvider());
+		}
+	}
+
+	/**
+	 * Create a new instance.
+	 * <p>
+	 * The BounceCastleProvider will be registered if necessary.
+	 * </p>
+	 */
+	public BouncyCastleGpgSigner() {
+		registerBouncyCastleProviderIfNecessary();
+	}
+
+	@Override
+	public boolean canLocateSigningKey(@Nullable String gpgSigningKey,
+			PersonIdent committer, CredentialsProvider credentialsProvider)
+			throws CanceledException {
+		try (BouncyCastleGpgKeyPassphrasePrompt passphrasePrompt = new BouncyCastleGpgKeyPassphrasePrompt(
+				credentialsProvider)) {
+			BouncyCastleGpgKey gpgKey = locateSigningKey(gpgSigningKey,
+					committer, passphrasePrompt);
+			return gpgKey != null;
+		} catch (PGPException | IOException | URISyntaxException e) {
+			return false;
+		}
+	}
+
+	private BouncyCastleGpgKey locateSigningKey(@Nullable String gpgSigningKey,
+			PersonIdent committer,
+			BouncyCastleGpgKeyPassphrasePrompt passphrasePrompt)
+			throws CanceledException, UnsupportedCredentialItem, IOException,
+			PGPException, URISyntaxException {
+		if (gpgSigningKey == null || gpgSigningKey.isEmpty()) {
+			gpgSigningKey = committer.getEmailAddress();
+		}
+
+		BouncyCastleGpgKeyLocator keyHelper = new BouncyCastleGpgKeyLocator(
+				gpgSigningKey, passphrasePrompt);
+
+		return keyHelper.findSecretKey();
+	}
+
+	@Override
+	public void sign(@NonNull CommitBuilder commit,
+			@Nullable String gpgSigningKey, @NonNull PersonIdent committer,
+			CredentialsProvider credentialsProvider) throws CanceledException {
+		try (BouncyCastleGpgKeyPassphrasePrompt passphrasePrompt = new BouncyCastleGpgKeyPassphrasePrompt(
+				credentialsProvider)) {
+			BouncyCastleGpgKey gpgKey = locateSigningKey(gpgSigningKey,
+					committer, passphrasePrompt);
+			PGPSecretKey secretKey = gpgKey.getSecretKey();
+			if (secretKey == null) {
+				throw new JGitInternalException(
+						JGitText.get().unableToSignCommitNoSecretKey);
+			}
+			char[] passphrase = passphrasePrompt.getPassphrase(
+					secretKey.getPublicKey().getFingerprint(),
+					gpgKey.getOrigin());
+			PGPPrivateKey privateKey = secretKey
+					.extractPrivateKey(new JcePBESecretKeyDecryptorBuilder()
+							.setProvider(BouncyCastleProvider.PROVIDER_NAME)
+							.build(passphrase));
+			PGPSignatureGenerator signatureGenerator = new PGPSignatureGenerator(
+					new JcaPGPContentSignerBuilder(
+							secretKey.getPublicKey().getAlgorithm(),
+							HashAlgorithmTags.SHA256).setProvider(
+									BouncyCastleProvider.PROVIDER_NAME));
+			signatureGenerator.init(PGPSignature.BINARY_DOCUMENT, privateKey);
+			ByteArrayOutputStream buffer = new ByteArrayOutputStream();
+			try (BCPGOutputStream out = new BCPGOutputStream(
+					new ArmoredOutputStream(buffer))) {
+				signatureGenerator.update(commit.build());
+				signatureGenerator.generate().encode(out);
+			}
+			commit.setGpgSignature(new GpgSignature(buffer.toByteArray()));
+		} catch (PGPException | IOException | URISyntaxException e) {
+			throw new JGitInternalException(e.getMessage(), e);
+		}
+	}
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeResult.java b/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeResult.java
index 062d86f..a533bf5 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeResult.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeResult.java
@@ -119,7 +119,7 @@ public void add(int srcIdx, int begin, int end, ConflictState conflictState) {
 
 	/**
 	 * Returns the common predecessor sequence and the merged sequence in one
-	 * list. The common predecessor is is the first element in the list
+	 * list. The common predecessor is the first element in the list
 	 *
 	 * @return the common predecessor at position 0 followed by the merged
 	 *         sequences.
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java b/org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java
index 909f3b1..75334dd 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java
@@ -1027,13 +1027,16 @@ private TemporaryBuffer doMerge(MergeResult<RawText> result)
 			throws IOException {
 		TemporaryBuffer.LocalFile buf = new TemporaryBuffer.LocalFile(
 				db != null ? nonNullRepo().getDirectory() : null, inCoreLimit);
+		boolean success = false;
 		try {
 			new MergeFormatter().formatMerge(buf, result,
 					Arrays.asList(commitNames), UTF_8);
 			buf.close();
-		} catch (IOException e) {
-			buf.destroy();
-			throw e;
+			success = true;
+		} finally {
+			if (!success) {
+				buf.destroy();
+			}
 		}
 		return buf;
 	}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/nls/NLS.java b/org.eclipse.jgit/src/org/eclipse/jgit/nls/NLS.java
index 89a87af..375cd32 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/nls/NLS.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/nls/NLS.java
@@ -79,7 +79,7 @@ public class NLS {
 	/**
 	 * Sets the locale for the calling thread.
 	 * <p>
-	 * The {@link #getBundleFor(Class)} method will honor this setting if if it
+	 * The {@link #getBundleFor(Class)} method will honor this setting if it
 	 * is supported by the provided resource bundle property files. Otherwise,
 	 * it will use a fall back locale as described in the
 	 * {@link TranslationBundle}
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 5e15316..45508ce 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revplot/PlotCommitList.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revplot/PlotCommitList.java
@@ -141,7 +141,8 @@ protected void enter(int index, PlotCommit<L> currCommit) {
 			final PlotCommit<L> c = currCommit.children[0];
 			currCommit.lane = c.lane;
 			Integer len = laneLength.get(currCommit.lane);
-			len = Integer.valueOf(len.intValue() + 1);
+			len = len != null ? Integer.valueOf(len.intValue() + 1)
+					: Integer.valueOf(0);
 			laneLength.put(currCommit.lane, len);
 		} else {
 			// More than one child, or our child is a merge.
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 e5903c9..fd578da 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/ObjectWalk.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/ObjectWalk.java
@@ -330,11 +330,11 @@ public RevCommit next() throws MissingObjectException,
 	 *
 	 * @return next most recent object; null if traversal is over.
 	 * @throws org.eclipse.jgit.errors.MissingObjectException
-	 *             one or or more of the next objects are not available from the
+	 *             one or more of the next objects are not available from the
 	 *             object database, but were thought to be candidates for
 	 *             traversal. This usually indicates a broken link.
 	 * @throws org.eclipse.jgit.errors.IncorrectObjectTypeException
-	 *             one or or more of the objects in a tree do not match the type
+	 *             one or more of the objects in a tree do not match the type
 	 *             indicated.
 	 * @throws java.io.IOException
 	 *             a pack file or loose object could not be read.
@@ -534,11 +534,11 @@ private static int parseMode(byte[] buf, int startPtr, int recEndPtr, TreeVisit
 	 * provides some detail about the connectivity failure.
 	 *
 	 * @throws org.eclipse.jgit.errors.MissingObjectException
-	 *             one or or more of the next objects are not available from the
+	 *             one or more of the next objects are not available from the
 	 *             object database, but were thought to be candidates for
 	 *             traversal. This usually indicates a broken link.
 	 * @throws org.eclipse.jgit.errors.IncorrectObjectTypeException
-	 *             one or or more of the objects in a tree do not match the type
+	 *             one or more of the objects in a tree do not match the type
 	 *             indicated.
 	 * @throws java.io.IOException
 	 *             a pack file or loose object could not be read.
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 400ea33..0a43e8f 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevWalk.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevWalk.java
@@ -394,11 +394,11 @@ public void markUninteresting(RevCommit c)
 	 *         <code>base</code> (and thus <code>base</code> is fully merged
 	 *         into <code>tip</code>); false otherwise.
 	 * @throws org.eclipse.jgit.errors.MissingObjectException
-	 *             one or or more of the next commit's parents are not available
+	 *             one or more of the next commit's parents are not available
 	 *             from the object database, but were thought to be candidates
 	 *             for traversal. This usually indicates a broken link.
 	 * @throws org.eclipse.jgit.errors.IncorrectObjectTypeException
-	 *             one or or more of the next commit's parents are not actually
+	 *             one or more of the next commit's parents are not actually
 	 *             commit objects.
 	 * @throws java.io.IOException
 	 *             a pack file or loose object could not be read.
@@ -431,11 +431,11 @@ public boolean isMergedInto(RevCommit base, RevCommit tip)
 	 *
 	 * @return next most recent commit; null if traversal is over.
 	 * @throws org.eclipse.jgit.errors.MissingObjectException
-	 *             one or or more of the next commit's parents are not available
+	 *             one or more of the next commit's parents are not available
 	 *             from the object database, but were thought to be candidates
 	 *             for traversal. This usually indicates a broken link.
 	 * @throws org.eclipse.jgit.errors.IncorrectObjectTypeException
-	 *             one or or more of the next commit's parents are not actually
+	 *             one or more of the next commit's parents are not actually
 	 *             commit objects.
 	 * @throws java.io.IOException
 	 *             a pack file or loose object could not be read.
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 c2e6a42..ff49976 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
@@ -251,7 +251,7 @@ public WindowCacheConfig fromConfig(Config rc) {
 	 * Install this configuration as the live settings.
 	 * <p>
 	 * The new configuration is applied immediately. If the new limits are
-	 * smaller than what what is currently cached, older entries will be purged
+	 * smaller than what is currently cached, older entries will be purged
 	 * as soon as possible to allow the cache to meet the new limit.
 	 *
 	 * @since 3.0
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 6bd32dd..6722e9b 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
@@ -1100,7 +1100,7 @@ public void setBitmapExcessiveBranchCount(int count) {
 	}
 
 	/**
-	 * Get the the age in days that marks a branch as "inactive".
+	 * Get the age in days that marks a branch as "inactive".
 	 *
 	 * Default setting: {@value #DEFAULT_BITMAP_INACTIVE_BRANCH_AGE_IN_DAYS}
 	 *
@@ -1112,7 +1112,7 @@ public int getBitmapInactiveBranchAgeInDays() {
 	}
 
 	/**
-	 * Set the the age in days that marks a branch as "inactive".
+	 * Set the age in days that marks a branch as "inactive".
 	 *
 	 * Default setting: {@value #DEFAULT_BITMAP_INACTIVE_BRANCH_AGE_IN_DAYS}
 	 *
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/AdvertiseRefsHook.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/AdvertiseRefsHook.java
index 72b4255..8512f2d 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/AdvertiseRefsHook.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/AdvertiseRefsHook.java
@@ -53,7 +53,7 @@ public interface AdvertiseRefsHook {
 	 * <p>
 	 * The method implementations do nothing to preserve the default behavior; see
 	 * {@link UploadPack#setAdvertisedRefs(java.util.Map)} and
-	 * {@link BaseReceivePack#setAdvertisedRefs(java.util.Map,java.util.Set)}.
+	 * {@link ReceivePack#setAdvertisedRefs(java.util.Map,java.util.Set)}.
 	 */
 	AdvertiseRefsHook DEFAULT = new AdvertiseRefsHook() {
 		@Override
@@ -85,7 +85,7 @@ void advertiseRefs(UploadPack uploadPack)
 	 *
 	 * @param receivePack
 	 *            instance on which to call
-	 *            {@link org.eclipse.jgit.transport.BaseReceivePack#setAdvertisedRefs(java.util.Map,java.util.Set)}
+	 *            {@link org.eclipse.jgit.transport.ReceivePack#setAdvertisedRefs(java.util.Map,java.util.Set)}
 	 *            if necessary.
 	 * @throws org.eclipse.jgit.transport.ServiceMayNotContinueException
 	 *             abort; the message will be sent to the user.
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/AdvertiseRefsHookChain.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/AdvertiseRefsHookChain.java
index 4ef3e1a..12238a1 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/AdvertiseRefsHookChain.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/AdvertiseRefsHookChain.java
@@ -52,7 +52,7 @@
  * Hooks are run in the order passed to the constructor. A hook may inspect or
  * modify the results of the previous hooks in the chain by calling
  * {@link org.eclipse.jgit.transport.UploadPack#getAdvertisedRefs()}, or
- * {@link org.eclipse.jgit.transport.BaseReceivePack#getAdvertisedRefs()} or
+ * {@link org.eclipse.jgit.transport.ReceivePack#getAdvertisedRefs()} or
  * {@link org.eclipse.jgit.transport.BaseReceivePack#getAdvertisedObjects()}.
  */
 public class AdvertiseRefsHookChain implements AdvertiseRefsHook {
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 69624ff..847e901 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackPushConnection.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackPushConnection.java
@@ -338,7 +338,7 @@ private void writePack(final Map<String, RemoteRefUpdate> refUpdates,
 			for (Ref r : getRefs()) {
 				// only add objects that we actually have
 				ObjectId oid = r.getObjectId();
-				if (local.hasObject(oid))
+				if (local.getObjectDatabase().has(oid))
 					remoteObjects.add(oid);
 			}
 			remoteObjects.addAll(additionalHaves);
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 0376336..6f17620 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BaseReceivePack.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BaseReceivePack.java
@@ -80,6 +80,7 @@
 import org.eclipse.jgit.internal.storage.file.PackLock;
 import org.eclipse.jgit.internal.submodule.SubmoduleValidator;
 import org.eclipse.jgit.internal.submodule.SubmoduleValidator.SubmoduleValidationException;
+import org.eclipse.jgit.internal.transport.parser.FirstCommand;
 import org.eclipse.jgit.lib.AnyObjectId;
 import org.eclipse.jgit.lib.BatchRefUpdate;
 import org.eclipse.jgit.lib.Config;
@@ -119,10 +120,14 @@
  * Subclasses compose these operations into full service implementations.
  */
 public abstract class BaseReceivePack {
-	/** Data in the first line of a request, the line itself plus capabilities. */
+	/**
+	 * Data in the first line of a request, the line itself plus capabilities.
+	 *
+	 * @deprecated Use {@link FirstCommand} instead.
+	 */
+	@Deprecated
 	public static class FirstLine {
-		private final String line;
-		private final Set<String> capabilities;
+		private final FirstCommand command;
 
 		/**
 		 * Parse the first line of a receive-pack request.
@@ -131,33 +136,25 @@ public static class FirstLine {
 		 *            line from the client.
 		 */
 		public FirstLine(String line) {
-			final HashSet<String> caps = new HashSet<>();
-			final int nul = line.indexOf('\0');
-			if (nul >= 0) {
-				for (String c : line.substring(nul + 1).split(" ")) //$NON-NLS-1$
-					caps.add(c);
-				this.line = line.substring(0, nul);
-			} else
-				this.line = line;
-			this.capabilities = Collections.unmodifiableSet(caps);
+			command = FirstCommand.fromLine(line);
 		}
 
 		/** @return non-capabilities part of the line. */
 		public String getLine() {
-			return line;
+			return command.getLine();
 		}
 
 		/** @return capabilities parsed from the line. */
 		public Set<String> getCapabilities() {
-			return capabilities;
+			return command.getCapabilities();
 		}
 	}
 
 	/** Database we write the stored objects into. */
-	private final Repository db;
+	final Repository db;
 
 	/** Revision traversal support over {@link #db}. */
-	private final RevWalk walk;
+	final RevWalk walk;
 
 	/**
 	 * Is the client connection a bi-directional socket or pipe?
@@ -207,7 +204,7 @@ public Set<String> getCapabilities() {
 	private AdvertiseRefsHook advertiseRefsHook;
 
 	/** Filter used while advertising the refs to the client. */
-	private RefFilter refFilter;
+	RefFilter refFilter;
 
 	/** Timeout in seconds to wait for client interaction. */
 	private int timeout;
@@ -242,10 +239,10 @@ public Set<String> getCapabilities() {
 	private PackParser parser;
 
 	/** The refs we advertised as existing at the start of the connection. */
-	private Map<String, Ref> refs;
+	Map<String, Ref> refs;
 
 	/** All SHA-1s shown to the client, which can be possible edges. */
-	private Set<ObjectId> advertisedHaves;
+	Set<ObjectId> advertisedHaves;
 
 	/** Capabilities requested by the client. */
 	private Set<String> enabledCapabilities;
@@ -278,7 +275,7 @@ public Set<String> getCapabilities() {
 
 	private PushCertificateParser pushCertificateParser;
 	private SignedPushConfig signedPushConfig;
-	private PushCertificate pushCert;
+	PushCertificate pushCert;
 	private ReceivedPackStatistics stats;
 
 	/**
@@ -289,10 +286,10 @@ public Set<String> getCapabilities() {
 	 * @return the parsed certificate, or null if push certificates are disabled
 	 *         or no cert was presented by the client.
 	 * @since 4.1
+	 * @deprecated use {@link ReceivePack#getPushCertificate}.
 	 */
-	public PushCertificate getPushCertificate() {
-		return pushCert;
-	}
+	@Deprecated
+	public abstract PushCertificate getPushCertificate();
 
 	/**
 	 * Set the push certificate used to verify the pusher's identity.
@@ -303,10 +300,10 @@ public PushCertificate getPushCertificate() {
 	 * @param cert
 	 *            the push certificate to set.
 	 * @since 4.1
+	 * @deprecated use {@link ReceivePack#setPushCertificate(PushCertificate)}.
 	 */
-	public void setPushCertificate(PushCertificate cert) {
-		pushCert = cert;
-	}
+	@Deprecated
+	public abstract void setPushCertificate(PushCertificate cert);
 
 	/**
 	 * Create a new pack receive for an open repository.
@@ -424,29 +421,29 @@ public void flush() {
 	 * Get the repository this receive completes into.
 	 *
 	 * @return the repository this receive completes into.
+	 * @deprecated use {@link ReceivePack#getRepository}
 	 */
-	public final Repository getRepository() {
-		return db;
-	}
+	@Deprecated
+	public abstract Repository getRepository();
 
 	/**
 	 * Get the RevWalk instance used by this connection.
 	 *
 	 * @return the RevWalk instance used by this connection.
+	 * @deprecated use {@link ReceivePack#getRevWalk}
 	 */
-	public final RevWalk getRevWalk() {
-		return walk;
-	}
+	@Deprecated
+	public abstract RevWalk getRevWalk();
 
 	/**
 	 * Get refs which were advertised to the client.
 	 *
 	 * @return all refs which were advertised to the client, or null if
 	 *         {@link #setAdvertisedRefs(Map, Set)} has not been called yet.
+	 * @deprecated use {@link ReceivePack#getAdvertisedRefs}
 	 */
-	public final Map<String, Ref> getAdvertisedRefs() {
-		return refs;
-	}
+	@Deprecated
+	public abstract Map<String, Ref> getAdvertisedRefs();
 
 	/**
 	 * Set the refs advertised by this ReceivePack.
@@ -464,25 +461,10 @@ public final Map<String, Ref> getAdvertisedRefs() {
 	 *            explicit set of additional haves to claim as advertised. If
 	 *            null, assumes the default set of additional haves from the
 	 *            repository.
+	 * @deprecated use {@link ReceivePack#setAdvertisedRefs}
 	 */
-	public void setAdvertisedRefs(Map<String, Ref> allRefs, Set<ObjectId> additionalHaves) {
-		refs = allRefs != null ? allRefs : db.getAllRefs();
-		refs = refFilter.filter(refs);
-		advertisedHaves.clear();
-
-		Ref head = refs.get(Constants.HEAD);
-		if (head != null && head.isSymbolic())
-			refs.remove(Constants.HEAD);
-
-		for (Ref ref : refs.values()) {
-			if (ref.getObjectId() != null)
-				advertisedHaves.add(ref.getObjectId());
-		}
-		if (additionalHaves != null)
-			advertisedHaves.addAll(additionalHaves);
-		else
-			advertisedHaves.addAll(db.getAdditionalHaves());
-	}
+	@Deprecated
+	public abstract void setAdvertisedRefs(Map<String, Ref> allRefs, Set<ObjectId> additionalHaves);
 
 	/**
 	 * Get objects advertised to the client.
@@ -1310,7 +1292,7 @@ protected void recvCommands() throws IOException {
 
 				if (firstPkt) {
 					firstPkt = false;
-					FirstLine firstLine = new FirstLine(line);
+					FirstCommand firstLine = FirstCommand.fromLine(line);
 					enabledCapabilities = firstLine.getCapabilities();
 					line = firstLine.getLine();
 					enableCapabilities();
@@ -1606,7 +1588,7 @@ private void checkConnectivity() throws IOException {
 						throw new MissingObjectException(o, o.getType());
 				}
 
-				if (o instanceof RevBlob && !db.hasObject(o))
+				if (o instanceof RevBlob && !db.getObjectDatabase().has(o))
 					throw new MissingObjectException(o, Constants.TYPE_BLOB);
 			}
 			checking.endTask();
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 4b20f6c..84a0972 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BundleFetchConnection.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BundleFetchConnection.java
@@ -50,6 +50,7 @@
 import static java.nio.charset.StandardCharsets.UTF_8;
 
 import java.io.BufferedInputStream;
+import java.io.EOFException;
 import java.io.IOException;
 import java.io.InputStream;
 import java.text.MessageFormat;
@@ -165,9 +166,13 @@ private String readLine(byte[] hdrbuf) throws IOException {
 		while (!done) {
 			bin.mark(hdrbuf.length);
 			final int cnt = bin.read(hdrbuf);
+			if (cnt < 0) {
+				throw new EOFException(JGitText.get().shortReadOfBlock);
+			}
 			int lf = 0;
-			while (lf < cnt && hdrbuf[lf] != '\n')
+			while (lf < cnt && hdrbuf[lf] != '\n') {
 				lf++;
+			}
 			bin.reset();
 			IO.skipFully(bin, lf);
 			if (lf < cnt && hdrbuf[lf] == '\n') {
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 211707e..681ae12 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/FetchProcess.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/FetchProcess.java
@@ -181,7 +181,7 @@ else if (tagopt == TagOpt.FETCH_TAGS)
 					ObjectId id = r.getPeeledObjectId();
 					if (id == null)
 						id = r.getObjectId();
-					if (transport.local.hasObject(id))
+					if (localHasObject(id))
 						wantTag(r);
 				}
 
@@ -393,6 +393,18 @@ private void expandSingle(RefSpec spec, Set<Ref> matched)
 		}
 	}
 
+	private boolean localHasObject(ObjectId id) throws TransportException {
+		try {
+			return transport.local.getObjectDatabase().has(id);
+		} catch (IOException err) {
+			throw new TransportException(
+					MessageFormat.format(
+							JGitText.get().readingObjectsFromLocalRepositoryFailed,
+							err.getMessage()),
+					err);
+		}
+	}
+
 	private Collection<Ref> expandAutoFollowTags() throws TransportException {
 		final Collection<Ref> additionalTags = new ArrayList<>();
 		final Map<String, Ref> haveRefs = localRefs();
@@ -410,7 +422,7 @@ private Collection<Ref> expandAutoFollowTags() throws TransportException {
 			if (obj == null)
 				obj = r.getObjectId();
 
-			if (askFor.containsKey(obj) || transport.local.hasObject(obj))
+			if (askFor.containsKey(obj) || localHasObject(obj))
 				wantTag(r);
 			else
 				additionalTags.add(r);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/InternalHttpServerGlue.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/InternalHttpServerGlue.java
index fe7aaf7..075cc9c 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/InternalHttpServerGlue.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/InternalHttpServerGlue.java
@@ -44,7 +44,7 @@
 package org.eclipse.jgit.transport;
 
 /**
- * Internal API to to assist {@code org.eclipse.jgit.http.server}.
+ * Internal API to assist {@code org.eclipse.jgit.http.server}.
  * <p>
  * <b>Do not call.</b>
  *
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/NonceGenerator.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/NonceGenerator.java
index fc22034..c573d12 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/NonceGenerator.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/NonceGenerator.java
@@ -81,7 +81,7 @@ String createNonce(Repository db, long timestamp)
 	 *            such that the pusher cannot forge nonces by pushing to another
 	 *            repository at the same time as well and reusing the nonce.
 	 * @param allowSlop
-	 *            If the receiving backend is is able to generate slop. This is
+	 *            If the receiving backend is able to generate slop. This is
 	 *            the case for serving via http protocol using more than one
 	 *            http frontend. The client would talk to different http
 	 *            frontends, which may have a slight difference of time due to
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 49acb4d..2b2795f 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PackParser.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PackParser.java
@@ -1237,7 +1237,7 @@ void use(int cnt) {
 		bAvail -= cnt;
 	}
 
-	// Ensure at least need bytes are available in in {@link #buf}.
+	// Ensure at least need bytes are available in {@link #buf}.
 	int fill(Source src, int need) throws IOException {
 		while (bAvail < need) {
 			int next = bOffset + bAvail;
@@ -1568,7 +1568,7 @@ protected abstract void onBeginWholeObject(long streamPosition, int type,
 			long inflatedSize) throws IOException;
 
 	/**
-	 * Event notifying the the current object.
+	 * Event notifying the current object.
 	 *
 	 *@param info
 	 *            object information.
@@ -1616,7 +1616,7 @@ protected abstract void onBeginRefDelta(long deltaStreamPosition,
 			AnyObjectId baseId, long inflatedSize) throws IOException;
 
 	/**
-	 * Event notifying the the current object.
+	 * Event notifying the current object.
 	 *
 	 *@return object information that must be populated with at least the
 	 *         offset.
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 577aaf4..4652c3f 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceivePack.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceivePack.java
@@ -43,6 +43,7 @@
 
 package org.eclipse.jgit.transport;
 
+import static org.eclipse.jgit.lib.Constants.HEAD;
 import static org.eclipse.jgit.transport.GitProtocolConstants.CAPABILITY_ATOMIC;
 import static org.eclipse.jgit.transport.GitProtocolConstants.CAPABILITY_PUSH_OPTIONS;
 import static org.eclipse.jgit.transport.GitProtocolConstants.CAPABILITY_REPORT_STATUS;
@@ -53,13 +54,18 @@
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
+import java.util.Map;
+import java.util.Set;
 
 import org.eclipse.jgit.annotations.Nullable;
 import org.eclipse.jgit.errors.UnpackException;
 import org.eclipse.jgit.lib.ConfigConstants;
 import org.eclipse.jgit.lib.Constants;
 import org.eclipse.jgit.lib.NullProgressMonitor;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.Ref;
 import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.revwalk.RevWalk;
 import org.eclipse.jgit.transport.ReceiveCommand.Result;
 import org.eclipse.jgit.transport.RefAdvertiser.PacketLineOutRefAdvertiser;
 
@@ -93,6 +99,106 @@ public ReceivePack(Repository into) {
 	}
 
 	/**
+	 * Get the repository this receive completes into.
+	 *
+	 * @return the repository this receive completes into.
+	 */
+	@Override
+	public final Repository getRepository() {
+		return db;
+	}
+
+	/**
+	 * Get the RevWalk instance used by this connection.
+	 *
+	 * @return the RevWalk instance used by this connection.
+	 */
+	@Override
+	public final RevWalk getRevWalk() {
+		return walk;
+	}
+
+	/**
+	 * Get refs which were advertised to the client.
+	 *
+	 * @return all refs which were advertised to the client, or null if
+	 *         {@link #setAdvertisedRefs(Map, Set)} has not been called yet.
+	 */
+	@Override
+	public final Map<String, Ref> getAdvertisedRefs() {
+		return refs;
+	}
+
+	/**
+	 * Set the refs advertised by this ReceivePack.
+	 * <p>
+	 * Intended to be called from a
+	 * {@link org.eclipse.jgit.transport.PreReceiveHook}.
+	 *
+	 * @param allRefs
+	 *            explicit set of references to claim as advertised by this
+	 *            ReceivePack instance. This overrides any references that may
+	 *            exist in the source repository. The map is passed to the
+	 *            configured {@link #getRefFilter()}. If null, assumes all refs
+	 *            were advertised.
+	 * @param additionalHaves
+	 *            explicit set of additional haves to claim as advertised. If
+	 *            null, assumes the default set of additional haves from the
+	 *            repository.
+	 */
+	@Override
+	public void setAdvertisedRefs(Map<String, Ref> allRefs, Set<ObjectId> additionalHaves) {
+		refs = allRefs != null ? allRefs : db.getAllRefs();
+		refs = refFilter.filter(refs);
+		advertisedHaves.clear();
+
+		Ref head = refs.get(HEAD);
+		if (head != null && head.isSymbolic()) {
+			refs.remove(HEAD);
+		}
+
+		for (Ref ref : refs.values()) {
+			if (ref.getObjectId() != null) {
+				advertisedHaves.add(ref.getObjectId());
+			}
+		}
+		if (additionalHaves != null) {
+			advertisedHaves.addAll(additionalHaves);
+		} else {
+			advertisedHaves.addAll(db.getAdditionalHaves());
+		}
+	}
+
+	/**
+	 * Get the push certificate used to verify the pusher's identity.
+	 * <p>
+	 * Only valid after commands are read from the wire.
+	 *
+	 * @return the parsed certificate, or null if push certificates are disabled
+	 *         or no cert was presented by the client.
+	 * @since 4.1
+	 */
+	@Override
+	public PushCertificate getPushCertificate() {
+		return pushCert;
+	}
+
+	/**
+	 * Set the push certificate used to verify the pusher's identity.
+	 * <p>
+	 * Should only be called if reconstructing an instance without going through
+	 * the normal {@link #recvCommands()} flow.
+	 *
+	 * @param cert
+	 *            the push certificate to set.
+	 * @since 4.1
+	 */
+	@Override
+	public void setPushCertificate(PushCertificate cert) {
+		pushCert = cert;
+	}
+
+	/**
 	 * Gets an unmodifiable view of the option strings associated with the push.
 	 *
 	 * @return an unmodifiable view of pushOptions, or null (if pushOptions is).
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 9a67f0f..c34e3b8 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/RemoteRefUpdate.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/RemoteRefUpdate.java
@@ -293,7 +293,7 @@ public RemoteRefUpdate(final Repository localDb, final String srcRef,
 			final boolean forceUpdate, final String localName,
 			final ObjectId expectedOldObjectId) throws IOException {
 		if (remoteName == null)
-			throw new IllegalArgumentException(JGitText.get().remoteNameCantBeNull);
+			throw new IllegalArgumentException(JGitText.get().remoteNameCannotBeNull);
 		if (srcId == null && srcRef != null)
 			throw new IOException(MessageFormat.format(
 					JGitText.get().sourceRefDoesntResolveToAnyObject, srcRef));
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 2fbcaa2..1d0f836 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java
@@ -43,6 +43,7 @@
 
 package org.eclipse.jgit.transport;
 
+import static java.util.Collections.unmodifiableMap;
 import static java.util.function.Function.identity;
 import static java.util.stream.Collectors.toMap;
 import static org.eclipse.jgit.lib.Constants.R_TAGS;
@@ -79,9 +80,11 @@
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 import java.util.Set;
 import java.util.TreeMap;
 
+import org.eclipse.jgit.annotations.NonNull;
 import org.eclipse.jgit.annotations.Nullable;
 import org.eclipse.jgit.errors.CorruptObjectException;
 import org.eclipse.jgit.errors.IncorrectObjectTypeException;
@@ -421,7 +424,7 @@ public final Map<String, Ref> getAdvertisedRefs() {
 	 *            configured {@link #getRefFilter()}. If null, assumes all refs
 	 *            were advertised.
 	 */
-	public void setAdvertisedRefs(Map<String, Ref> allRefs) {
+	public void setAdvertisedRefs(@Nullable Map<String, Ref> allRefs) {
 		if (allRefs != null)
 			refs = allRefs;
 		else
@@ -545,7 +548,7 @@ public void setRequestPolicy(RequestPolicy policy) {
 	 *            custom validator for client want list.
 	 * @since 3.1
 	 */
-	public void setRequestValidator(RequestValidator validator) {
+	public void setRequestValidator(@Nullable RequestValidator validator) {
 		requestValidator = validator != null ? validator
 				: new AdvertisedRequestValidator();
 	}
@@ -579,21 +582,21 @@ public RefFilter getRefFilter() {
 	 * @param advertiseRefsHook
 	 *            the hook; may be null to show all refs.
 	 */
-	public void setAdvertiseRefsHook(AdvertiseRefsHook advertiseRefsHook) {
-		if (advertiseRefsHook != null)
-			this.advertiseRefsHook = advertiseRefsHook;
-		else
-			this.advertiseRefsHook = AdvertiseRefsHook.DEFAULT;
+	public void setAdvertiseRefsHook(
+			@Nullable AdvertiseRefsHook advertiseRefsHook) {
+		this.advertiseRefsHook = advertiseRefsHook != null ? advertiseRefsHook
+				: AdvertiseRefsHook.DEFAULT;
 	}
 
 	/**
 	 * Set the protocol V2 hook.
 	 *
 	 * @param hook
+	 *            the hook; if null no special actions are taken.
 	 * @since 5.1
 	 */
-	public void setProtocolV2Hook(ProtocolV2Hook hook) {
-		this.protocolV2Hook = hook;
+	public void setProtocolV2Hook(@Nullable ProtocolV2Hook hook) {
+		this.protocolV2Hook = hook != null ? hook : ProtocolV2Hook.DEFAULT;
 	}
 
 	/**
@@ -608,7 +611,7 @@ public void setProtocolV2Hook(ProtocolV2Hook hook) {
 	 * @param refFilter
 	 *            the filter; may be null to show all refs.
 	 */
-	public void setRefFilter(RefFilter refFilter) {
+	public void setRefFilter(@Nullable RefFilter refFilter) {
 		this.refFilter = refFilter != null ? refFilter : RefFilter.DEFAULT;
 	}
 
@@ -627,7 +630,7 @@ public PreUploadHook getPreUploadHook() {
 	 * @param hook
 	 *            the hook; if null no special actions are taken.
 	 */
-	public void setPreUploadHook(PreUploadHook hook) {
+	public void setPreUploadHook(@Nullable PreUploadHook hook) {
 		preUploadHook = hook != null ? hook : PreUploadHook.NULL;
 	}
 
@@ -648,7 +651,7 @@ public PostUploadHook getPostUploadHook() {
 	 *            the hook; if null no special actions are taken.
 	 * @since 4.1
 	 */
-	public void setPostUploadHook(PostUploadHook hook) {
+	public void setPostUploadHook(@Nullable PostUploadHook hook) {
 		postUploadHook = hook != null ? hook : PostUploadHook.NULL;
 	}
 
@@ -659,7 +662,7 @@ public void setPostUploadHook(PostUploadHook hook) {
 	 *            configuration controlling packing parameters. If null the
 	 *            source repository's settings will be used.
 	 */
-	public void setPackConfig(PackConfig pc) {
+	public void setPackConfig(@Nullable PackConfig pc) {
 		this.packConfig = pc;
 	}
 
@@ -671,7 +674,7 @@ public void setPackConfig(PackConfig pc) {
 	 *            repository's settings will be used.
 	 * @since 3.1
 	 */
-	public void setTransferConfig(TransferConfig tc) {
+	public void setTransferConfig(@Nullable TransferConfig tc) {
 		this.transferConfig = tc != null ? tc : new TransferConfig(db);
 		if (transferConfig.isAllowTipSha1InWant()) {
 			setRequestPolicy(transferConfig.isAllowReachableSha1InWant()
@@ -849,22 +852,46 @@ private Map<String, Ref> getFilteredRefs(Collection<String> refPrefixes)
 	}
 
 	/**
-	 * Read a ref on behalf of the client.
+	 * Returns the specified references.
 	 * <p>
-	 * This checks that the ref is present in the ref advertisement since
-	 * otherwise the client might not be supposed to be able to read it.
+	 * This produces an immutable map containing whatever subset of the
+	 * refs named by the caller are present in the supplied {@code refs}
+	 * map.
 	 *
-	 * @param name
-	 *            the unabbreviated name of the reference.
-	 * @return the requested Ref, or {@code null} if it is not visible or
-	 *         does not exist.
-	 * @throws java.io.IOException
-	 *            on failure to read the ref or check it for visibility.
+	 * @param refs
+	 *            Map to search for refs to return.
+	 * @param names
+	 *            which refs to search for in {@code refs}.
+	 * @return the requested Refs, omitting any that are null or missing.
 	 */
-	@Nullable
-	private Ref getRef(String name) throws IOException {
+	@NonNull
+	private static Map<String, Ref> mapRefs(
+			Map<String, Ref> refs, List<String> names) {
+		return unmodifiableMap(
+				names.stream()
+					.map(refs::get)
+					.filter(Objects::nonNull)
+					.collect(toMap(Ref::getName, identity(), (a, b) -> b)));
+	}
+
+	/**
+	 * Read refs on behalf of the client.
+	 * <p>
+	 * This checks whether the refs are present in the ref advertisement
+	 * since otherwise the client might not be supposed to be able to
+	 * read them.
+	 *
+	 * @param names
+	 *            unabbreviated names of references.
+	 * @return the requested Refs, omitting any that are not visible or
+	 *         do not exist.
+	 * @throws java.io.IOException
+	 *            on failure to read a ref or check it for visibility.
+	 */
+	@NonNull
+	private Map<String, Ref> exactRefs(List<String> names) throws IOException {
 		if (refs != null) {
-			return refs.get(name);
+			return mapRefs(refs, names);
 		}
 		if (!advertiseRefsHookCalled) {
 			advertiseRefsHook.advertiseRefs(this);
@@ -874,9 +901,10 @@ private Ref getRef(String name) throws IOException {
 				refFilter == RefFilter.DEFAULT &&
 				transferConfig.hasDefaultRefFilter()) {
 			// Fast path: no ref filtering is needed.
-			return db.getRefDatabase().exactRef(name);
+			String[] ns = names.toArray(new String[0]);
+			return unmodifiableMap(db.getRefDatabase().exactRef(ns));
 		}
-		return getAdvertisedOrDefaultRefs().get(name);
+		return mapRefs(getAdvertisedOrDefaultRefs(), names);
 	}
 
 	/**
@@ -906,7 +934,7 @@ private Ref findRef(String name) throws IOException {
 				refFilter == RefFilter.DEFAULT &&
 				transferConfig.hasDefaultRefFilter()) {
 			// Fast path: no ref filtering is needed.
-			return db.getRefDatabase().getRef(name);
+			return db.getRefDatabase().findRef(name);
 		}
 		return RefDatabase.findRef(getAdvertisedOrDefaultRefs(), name);
 	}
@@ -1042,6 +1070,31 @@ private void lsRefsV2() throws IOException {
 		adv.end();
 	}
 
+	// Resolves ref names from the request's want-ref lines to
+	// object ids, throwing PackProtocolException if any are missing.
+	private Map<String, ObjectId> wantedRefs(FetchV2Request req)
+			throws IOException {
+		Map<String, ObjectId> result = new TreeMap<>();
+
+		List<String> wanted = req.getWantedRefs();
+		Map<String, Ref> resolved = exactRefs(wanted);
+
+		for (String refName : wanted) {
+			Ref ref = resolved.get(refName);
+			if (ref == null) {
+				throw new PackProtocolException(MessageFormat
+						.format(JGitText.get().invalidRefName, refName));
+			}
+			ObjectId oid = ref.getObjectId();
+			if (oid == null) {
+				throw new PackProtocolException(MessageFormat
+						.format(JGitText.get().invalidRefName, refName));
+			}
+			result.put(refName, oid);
+		}
+		return result;
+	}
+
 	private void fetchV2() throws IOException {
 		// Depending on the requestValidator, #processHaveLines may
 		// require that advertised be set. Set it only in the required
@@ -1074,22 +1127,9 @@ private void fetchV2() throws IOException {
 			deepenNots.add(ref.getObjectId());
 		}
 
-		Map<String, ObjectId> wantedRefs = new TreeMap<>();
-		for (String refName : req.getWantedRefs()) {
-			Ref ref = getRef(refName);
-			if (ref == null) {
-				throw new PackProtocolException(MessageFormat
-						.format(JGitText.get().invalidRefName, refName));
-			}
-			ObjectId oid = ref.getObjectId();
-			if (oid == null) {
-				throw new PackProtocolException(MessageFormat
-						.format(JGitText.get().invalidRefName, refName));
-			}
-			// TODO(ifrade): Avoid mutating the parsed request.
-			req.getWantIds().add(oid);
-			wantedRefs.put(refName, oid);
-		}
+		Map<String, ObjectId> wantedRefs = wantedRefs(req);
+		// TODO(ifrade): Avoid mutating the parsed request.
+		req.getWantIds().addAll(wantedRefs.values());
 		wantIds = req.getWantIds();
 
 		boolean sectionSent = false;
@@ -1486,6 +1526,20 @@ public int getDepth() {
 	}
 
 	/**
+	 * Returns the filter blob limit for the current request. Valid only after
+	 * calling recvWants(). A limit -1 means no limit.
+	 *
+	 * @return filter blob limit requested by the client, or -1 if no limit
+	 * @since 5.3
+	 */
+	public long getFilterBlobLimit() {
+		if (currentRequest == null) {
+			throw new RequestNotYetReadException();
+		}
+		return currentRequest.getFilterBlobLimit();
+	}
+
+	/**
 	 * Get the user agent of the client.
 	 * <p>
 	 * If the client is new enough to use {@code agent=} capability that value
@@ -2080,6 +2134,7 @@ else if (ref.getName().startsWith(Constants.R_HEADS))
 						: req.getDepth() - 1;
 				pw.setShallowPack(req.getDepth(), unshallowCommits);
 
+				@SuppressWarnings("resource") // Ownership is transferred below
 				DepthWalk.RevWalk dw = new DepthWalk.RevWalk(
 						walk.getObjectReader(), walkDepth);
 				dw.setDeepenSince(req.getDeepenSince());
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 9307914..2bb5814 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/WalkFetchConnection.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/WalkFetchConnection.java
@@ -555,10 +555,10 @@ private boolean downloadPackedObject(final ProgressMonitor monitor,
 				continue;
 			} finally {
 				// If the pack was good its in the local repository
-				// and Repository.hasObject(id) will succeed in the
-				// future, so we do not need this data anymore. If
-				// it failed the index and pack are unusable and we
-				// shouldn't consult them again.
+				// and Repository.getObjectDatabase().has(id) will
+				// succeed in the future, so we do not need this
+				// data any more. If it failed the index and pack
+				// are unusable and we shouldn't consult them again.
 				//
 				try {
 					if (pack.tmpIdx != null)
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 6d4df4f..5c67253 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/WalkRemoteObjectDatabase.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/WalkRemoteObjectDatabase.java
@@ -348,7 +348,7 @@ void writeInfoPacks(Collection<String> packNames) throws IOException {
 	/**
 	 * Open a buffered reader around a file.
 	 * <p>
-	 * This method is suitable for for reading line-oriented resources like
+	 * This method is suitable for reading line-oriented resources like
 	 * <code>info/packs</code>, <code>info/refs</code>, and the alternates list.
 	 *
 	 * @return a stream to read from the file. Never null.
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 c8b3ef3..e8ff1a9 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeIterator.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeIterator.java
@@ -75,6 +75,7 @@
 import org.eclipse.jgit.dircache.DirCacheEntry;
 import org.eclipse.jgit.dircache.DirCacheIterator;
 import org.eclipse.jgit.errors.CorruptObjectException;
+import org.eclipse.jgit.errors.LargeObjectException;
 import org.eclipse.jgit.errors.MissingObjectException;
 import org.eclipse.jgit.errors.NoWorkTreeException;
 import org.eclipse.jgit.ignore.FastIgnoreRule;
@@ -1494,9 +1495,18 @@ public EolStreamType getEolStreamType() throws IOException {
 	private EolStreamType getEolStreamType(OperationType opType)
 			throws IOException {
 		if (eolStreamTypeHolder == null) {
-			EolStreamType type=null;
+			EolStreamType type = null;
 			if (state.walk != null) {
 				type = state.walk.getEolStreamType(opType);
+				OperationType operationType = opType != null ? opType
+						: state.walk.getOperationType();
+				if (OperationType.CHECKIN_OP.equals(operationType)
+						&& EolStreamType.AUTO_LF.equals(type)
+						&& hasCrLfInIndex(getDirCacheIterator())) {
+					// If text=auto (or core.autocrlf=true) and the file has
+					// already been committed with CR/LF, then don't convert.
+					type = EolStreamType.DIRECT;
+				}
 			} else {
 				switch (getOptions().getAutoCRLF()) {
 				case FALSE:
@@ -1513,6 +1523,59 @@ private EolStreamType getEolStreamType(OperationType opType)
 		return eolStreamTypeHolder.get();
 	}
 
+	/**
+	 * Determines whether the file was committed un-normalized. If the iterator
+	 * points to a conflict entry, checks the "ours" version.
+	 *
+	 * @param dirCache
+	 *            iterator pointing to the current entry for the file in the
+	 *            index
+	 * @return {@code true} if the file in the index is not binary and has CR/LF
+	 *         line endings, {@code false} otherwise
+	 */
+	private boolean hasCrLfInIndex(DirCacheIterator dirCache) {
+		if (dirCache == null) {
+			return false;
+		}
+		// Read blob from index and check for CR/LF-delimited text.
+		DirCacheEntry entry = dirCache.getDirCacheEntry();
+		if (FileMode.REGULAR_FILE.equals(entry.getFileMode())) {
+			ObjectId blobId = entry.getObjectId();
+			if (entry.getStage() > 0
+					&& entry.getStage() != DirCacheEntry.STAGE_2) {
+				// Merge conflict: check ours (stage 2)
+				byte[] name = entry.getRawPath();
+				int i = 0;
+				while (!dirCache.eof()) {
+					dirCache.next(1);
+					i++;
+					entry = dirCache.getDirCacheEntry();
+					if (!Arrays.equals(name, entry.getRawPath())) {
+						break;
+					}
+					if (entry.getStage() == DirCacheEntry.STAGE_2) {
+						blobId = entry.getObjectId();
+						break;
+					}
+				}
+				dirCache.back(i);
+			}
+			try (ObjectReader reader = repository.newObjectReader()) {
+				ObjectLoader loader = reader.open(blobId, Constants.OBJ_BLOB);
+				try {
+					return RawText.isCrLfText(loader.getCachedBytes());
+				} catch (LargeObjectException e) {
+					try (InputStream in = loader.openStream()) {
+						return RawText.isCrLfText(in);
+					}
+				}
+			} catch (IOException e) {
+				// Ignore and return false below
+			}
+		}
+		return false;
+	}
+
 	private boolean isDirectoryIgnored(String pathRel) throws IOException {
 		final int pOff = 0 < pathOffset ? pathOffset - 1 : pathOffset;
 		final String base = TreeWalk.pathOf(this.path, 0, pOff);
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 eda8afb..eda0fae 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
@@ -51,6 +51,7 @@
 import java.io.InputStreamReader;
 import java.io.PrintStream;
 import java.nio.charset.Charset;
+import java.nio.file.AccessDeniedException;
 import java.nio.file.FileAlreadyExistsException;
 import java.nio.file.Files;
 import java.nio.file.InvalidPathException;
@@ -386,8 +387,9 @@ public boolean createNewFile(File lock) throws IOException {
 			Integer nlink = (Integer) (Files.getAttribute(lockPath,
 					"unix:nlink")); //$NON-NLS-1$
 			if (nlink > 2) {
-				LOG.warn("nlink of link to lock file {} was not 2 but {}", //$NON-NLS-1$
-						lock.getPath(), nlink);
+				LOG.warn(MessageFormat.format(
+						JGitText.get().failedAtomicFileCreation, lockPath,
+						nlink));
 				return false;
 			} else if (nlink < 2) {
 				supportsUnixNLink = false;
@@ -453,7 +455,8 @@ public LockToken createNewFileAtomic(File file) throws IOException {
 				supportsUnixNLink = false;
 			}
 			return token(true, link);
-		} catch (UnsupportedOperationException | IllegalArgumentException e) {
+		} catch (UnsupportedOperationException | IllegalArgumentException
+				| AccessDeniedException | SecurityException e) {
 			supportsUnixNLink = false;
 			return token(true, link);
 		}
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 e88e7a3..a07a4fd 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/IO.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/IO.java
@@ -203,12 +203,13 @@ public static ByteBuffer readWholeStream(InputStream in, int sizeHint)
 		if (last < 0)
 			return ByteBuffer.wrap(out, 0, pos);
 
-		@SuppressWarnings("resource" /* java 7 */)
-		TemporaryBuffer.Heap tmp = new TemporaryBuffer.Heap(Integer.MAX_VALUE);
-		tmp.write(out);
-		tmp.write(last);
-		tmp.copy(in);
-		return ByteBuffer.wrap(tmp.toByteArray());
+		try (TemporaryBuffer.Heap tmp = new TemporaryBuffer.Heap(
+				Integer.MAX_VALUE)) {
+			tmp.write(out);
+			tmp.write(last);
+			tmp.copy(in);
+			return ByteBuffer.wrap(tmp.toByteArray());
+		}
 	}
 
 	/**
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 a440cb2..2081bac 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/RawParseUtils.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/RawParseUtils.java
@@ -75,7 +75,9 @@ public final class RawParseUtils {
 	 * UTF-8 charset constant.
 	 *
 	 * @since 2.2
+	 * @deprecated use {@link java.nio.charset.StandardCharsets#UTF_8} instead
 	 */
+	@Deprecated
 	public static final Charset UTF8_CHARSET = UTF_8;
 
 	private static final byte[] digits10;
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 08377e6..4c60862 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
@@ -144,9 +144,18 @@ public void close() throws IOException {
 	}
 
 	private boolean fillBuffer() throws IOException {
-		cnt = in.read(buf, 0, buf.length);
-		if (cnt < 1)
+		cnt = 0;
+		while (cnt < buf.length) {
+			int n = in.read(buf, cnt, buf.length - cnt);
+			if (n < 0) {
+				break;
+			}
+			cnt += n;
+		}
+		if (cnt < 1) {
+			cnt = -1;
 			return false;
+		}
 		if (detectBinary) {
 			isBinary = RawText.isBinary(buf, cnt);
 			detectBinary = false;
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 ff28161..280cf7e 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
@@ -189,9 +189,18 @@ public void close() throws IOException {
 	}
 
 	private boolean fillBuffer() throws IOException {
-		cnt = in.read(buf, 0, buf.length);
-		if (cnt < 1)
+		cnt = 0;
+		while (cnt < buf.length) {
+			int n = in.read(buf, cnt, buf.length - cnt);
+			if (n < 0) {
+				break;
+			}
+			cnt += n;
+		}
+		if (cnt < 1) {
+			cnt = -1;
 			return false;
+		}
 		if (detectBinary) {
 			isBinary = RawText.isBinary(buf, cnt);
 			detectBinary = false;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/sha1/SHA1.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/sha1/SHA1.java
index 9fe01f1..1ad6602 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/sha1/SHA1.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/sha1/SHA1.java
@@ -48,8 +48,10 @@
 import static java.lang.Integer.rotateLeft;
 import static java.lang.Integer.rotateRight;
 
+import java.text.MessageFormat;
 import java.util.Arrays;
 
+import org.eclipse.jgit.internal.JGitText;
 import org.eclipse.jgit.lib.MutableObjectId;
 import org.eclipse.jgit.lib.ObjectId;
 import org.eclipse.jgit.util.NB;
@@ -497,7 +499,8 @@ private void finish() {
 
 		if (foundCollision) {
 			ObjectId id = h.toObjectId();
-			LOG.warn("possible SHA-1 collision " + id.name()); //$NON-NLS-1$
+			LOG.warn(MessageFormat.format(JGitText.get().sha1CollisionDetected,
+					id.name()));
 			throw new Sha1CollisionException(id);
 		}
 	}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/sha1/Sha1CollisionException.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/sha1/Sha1CollisionException.java
index dcefe95..0e5c919 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/sha1/Sha1CollisionException.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/sha1/Sha1CollisionException.java
@@ -65,7 +65,7 @@ public class Sha1CollisionException extends RuntimeException {
 	 */
 	public Sha1CollisionException(ObjectId id) {
 		super(MessageFormat.format(
-				JGitText.get().sha1CollisionDetected1,
+				JGitText.get().sha1CollisionDetected,
 				id.name()));
 	}
 }
diff --git a/pom.xml b/pom.xml
index b0fc1e7..bd81c5a 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>5.2.3-SNAPSHOT</version>
+  <version>5.3.7-SNAPSHOT</version>
 
   <name>JGit - Parent</name>
   <url>${jgit-url}</url>
@@ -182,7 +182,7 @@
     <maven.build.timestamp.format>yyyyMMddHHmm</maven.build.timestamp.format>
     <bundle-manifest>${project.build.directory}/META-INF/MANIFEST.MF</bundle-manifest>
 
-    <jgit-last-release-version>5.1.0.201809111528-r</jgit-last-release-version>
+    <jgit-last-release-version>5.2.0.201812061821-r</jgit-last-release-version>
     <apache-sshd-version>2.0.0</apache-sshd-version>
     <jsch-version>0.1.55</jsch-version>
     <jzlib-version>1.1.1</jzlib-version>
@@ -193,7 +193,7 @@
     <commons-compress-version>1.18</commons-compress-version>
     <osgi-core-version>4.3.1</osgi-core-version>
     <servlet-api-version>3.1.0</servlet-api-version>
-    <jetty-version>9.4.11.v20180605</jetty-version>
+    <jetty-version>9.4.14.v20181114</jetty-version>
     <japicmp-version>0.14.1</japicmp-version>
     <httpclient-version>4.5.6</httpclient-version>
     <httpcore-version>4.4.10</httpcore-version>
@@ -202,6 +202,8 @@
     <maven-javadoc-plugin-version>3.1.0</maven-javadoc-plugin-version>
     <tycho-extras-version>1.3.0</tycho-extras-version>
     <gson-version>2.8.2</gson-version>
+    <bouncycastle-version>1.60</bouncycastle-version>
+    <spotbugs-maven-plugin-version>3.1.11</spotbugs-maven-plugin-version>
     <maven-project-info-reports-plugin-version>3.0.0</maven-project-info-reports-plugin-version>
     <maven-jxr-plugin-version>3.0.0</maven-jxr-plugin-version>
     <spotbugs-maven-plugin-version>3.1.12</spotbugs-maven-plugin-version>
@@ -212,7 +214,7 @@
     <!-- Properties to enable jacoco code coverage analysis -->
     <sonar.core.codeCoveragePlugin>jacoco</sonar.core.codeCoveragePlugin>
     <sonar.dynamicAnalysis>reuseReports</sonar.dynamicAnalysis>
-    <sonar.jacoco.reportPath>../target/jacoco.exec</sonar.jacoco.reportPath>
+    <sonar.jacoco.reportPath>${project.build.directory}/jacoco.exec</sonar.jacoco.reportPath>
   </properties>
 
   <repositories>
@@ -298,6 +300,7 @@
           <configuration>
             <forkCount>${test-fork-count}</forkCount>
             <reuseForks>true</reuseForks>
+            <argLine>@{argLine}</argLine>
           </configuration>
         </plugin>
 
@@ -375,7 +378,7 @@
             <dependency><!-- add support for ssh/scp -->
               <groupId>org.apache.maven.wagon</groupId>
               <artifactId>wagon-ssh</artifactId>
-              <version>3.2.0</version>
+              <version>3.3.2</version>
             </dependency>
           </dependencies>
         </plugin>
@@ -414,6 +417,11 @@
           <artifactId>maven-resources-plugin</artifactId>
           <version>3.1.0</version>
         </plugin>
+        <plugin>
+          <groupId>org.springframework.boot</groupId>
+          <artifactId>spring-boot-maven-plugin</artifactId>
+          <version>2.1.2.RELEASE</version>
+        </plugin>
       </plugins>
     </pluginManagement>
 
@@ -519,6 +527,7 @@
         <artifactId>jacoco-maven-plugin</artifactId>
         <executions>
           <execution>
+            <id>default-prepare-agent</id>
             <goals>
               <goal>prepare-agent</goal>
             </goals>
@@ -533,6 +542,38 @@
               <append>true</append>
             </configuration>
           </execution>
+          <execution>
+            <id>default-report</id>
+            <goals>
+              <goal>report</goal>
+            </goals>
+          </execution>
+          <execution>
+            <id>default-check</id>
+            <goals>
+              <goal>check</goal>
+            </goals>
+            <configuration>
+            <haltOnFailure>false</haltOnFailure>
+            <rules>
+              <rule>
+                <element>BUNDLE</element>
+                  <limits>
+                    <limit>
+                      <counter>INSTRUCTION</counter>
+                      <value>COVEREDRATIO</value>
+                      <minimum>50%</minimum>
+                    </limit>
+                    <limit>
+                      <counter>CLASS</counter>
+                      <value>MISSEDCOUNT</value>
+                      <maximum>10</maximum>
+                    </limit>
+                  </limits>
+                </rule>
+              </rules>
+            </configuration>
+          </execution>
         </executions>
       </plugin>
       <plugin>
@@ -610,6 +651,24 @@
           </reportSet>
         </reportSets>
       </plugin>
+      <plugin>
+        <groupId>org.jacoco</groupId>
+        <artifactId>jacoco-maven-plugin</artifactId>
+        <reportSets>
+          <reportSet>
+            <reports>
+              <report>report</report>
+            </reports>
+          </reportSet>
+          <reportSet>
+            <id>aggregate</id>
+            <inherited>false</inherited>
+            <reports>
+              <report>report-aggregate</report>
+            </reports>
+          </reportSet>
+        </reportSets>
+      </plugin>
     </plugins>
   </reporting>
 
@@ -660,7 +719,7 @@
       <dependency>
         <groupId>org.tukaani</groupId>
         <artifactId>xz</artifactId>
-        <version>1.6</version>
+        <version>1.8</version>
         <optional>true</optional>
       </dependency>
 
@@ -729,6 +788,25 @@
         <artifactId>gson</artifactId>
         <version>${gson-version}</version>
       </dependency>
+
+      <dependency>
+        <groupId>org.bouncycastle</groupId>
+        <artifactId>bcpg-jdk15on</artifactId>
+        <version>${bouncycastle-version}</version>
+      </dependency>
+
+      <dependency>
+        <groupId>org.bouncycastle</groupId>
+        <artifactId>bcprov-jdk15on</artifactId>
+        <version>${bouncycastle-version}</version>
+      </dependency>
+
+      <dependency>
+        <groupId>org.bouncycastle</groupId>
+        <artifactId>bcpkix-jdk15on</artifactId>
+        <version>${bouncycastle-version}</version>
+      </dependency>
+
     </dependencies>
   </dependencyManagement>
 
@@ -957,6 +1035,7 @@
     <module>org.eclipse.jgit.lfs.test</module>
     <module>org.eclipse.jgit.lfs.server.test</module>
     <module>org.eclipse.jgit.ssh.apache.test</module>
+    <module>org.eclipse.jgit.coverage</module>
     <module>org.eclipse.jgit.benchmarks</module>
   </modules>
 
diff --git a/tools/BUILD b/tools/BUILD
index f1b1536..6741d23 100644
--- a/tools/BUILD
+++ b/tools/BUILD
@@ -1,9 +1,9 @@
-load("@rules_java//java:defs.bzl", "java_package_configuration")
 load(
     "@bazel_tools//tools/jdk:default_java_toolchain.bzl",
     "JDK9_JVM_OPTS",
     "default_java_toolchain",
 )
+load("@rules_java//java:defs.bzl", "java_package_configuration")
 
 default_java_toolchain(
     name = "error_prone_warnings_toolchain",
@@ -15,8 +15,10 @@
     visibility = ["//visibility:public"],
 )
 
-# This EP warnings list borrowed from here:
+# Error Prone errors enabled by default; see ../.bazelrc for how this is
+# enabled. This warnings list is originally based on:
 # https://github.com/bazelbuild/BUILD_file_generator/blob/master/tools/bazel_defs/java.bzl
+# However, feel free to add any additional errors. Thus far they have all been pretty useful.
 java_package_configuration(
     name = "error_prone",
     javacopts = [
@@ -24,61 +26,61 @@
         "-Xep:MissingCasesInEnumSwitch:ERROR",
         "-Xep:ReferenceEquality:WARN",
         "-Xep:StringEquality:WARN",
-        "-Xep:WildcardImport:WARN",
+        "-Xep:WildcardImport:ERROR",
         "-Xep:AmbiguousMethodReference:WARN",
-        "-Xep:BadAnnotationImplementation:WARN",
+        "-Xep:BadAnnotationImplementation:ERROR",
         "-Xep:BadComparable:WARN",
         "-Xep:BoxedPrimitiveConstructor:ERROR",
-        "-Xep:CannotMockFinalClass:WARN",
+        "-Xep:CannotMockFinalClass:ERROR",
         "-Xep:ClassCanBeStatic:ERROR",
         "-Xep:ClassNewInstance:WARN",
         "-Xep:DefaultCharset:ERROR",
-        "-Xep:DoubleCheckedLocking:WARN",
-        "-Xep:ElementsCountedInLoop:WARN",
-        "-Xep:EqualsHashCode:WARN",
-        "-Xep:EqualsIncompatibleType:WARN",
+        "-Xep:DoubleCheckedLocking:ERROR",
+        "-Xep:ElementsCountedInLoop:ERROR",
+        "-Xep:EqualsHashCode:ERROR",
+        "-Xep:EqualsIncompatibleType:ERROR",
         "-Xep:ExpectedExceptionChecker:ERROR",
         "-Xep:Finally:WARN",
-        "-Xep:FloatingPointLiteralPrecision:WARN",
-        "-Xep:FragmentInjection:WARN",
-        "-Xep:FragmentNotInstantiable:WARN",
-        "-Xep:FunctionalInterfaceClash:WARN",
+        "-Xep:FloatingPointLiteralPrecision:ERROR",
+        "-Xep:FragmentInjection:ERROR",
+        "-Xep:FragmentNotInstantiable:ERROR",
+        "-Xep:FunctionalInterfaceClash:ERROR",
         "-Xep:FutureReturnValueIgnored:WARN",
-        "-Xep:GetClassOnEnum:WARN",
-        "-Xep:ImmutableAnnotationChecker:WARN",
+        "-Xep:GetClassOnEnum:ERROR",
+        "-Xep:ImmutableAnnotationChecker:ERROR",
         "-Xep:ImmutableEnumChecker:WARN",
-        "-Xep:IncompatibleModifiers:WARN",
-        "-Xep:InjectOnConstructorOfAbstractClass:WARN",
-        "-Xep:InputStreamSlowMultibyteRead:WARN",
-        "-Xep:IterableAndIterator:WARN",
-        "-Xep:JUnit3FloatingPointComparisonWithoutDelta:WARN",
-        "-Xep:JUnitAmbiguousTestClass:WARN",
-        "-Xep:LiteralClassName:WARN",
+        "-Xep:IncompatibleModifiers:ERROR",
+        "-Xep:InjectOnConstructorOfAbstractClass:ERROR",
+        "-Xep:InputStreamSlowMultibyteRead:ERROR",
+        "-Xep:IterableAndIterator:ERROR",
+        "-Xep:JUnit3FloatingPointComparisonWithoutDelta:ERROR",
+        "-Xep:JUnitAmbiguousTestClass:ERROR",
+        "-Xep:LiteralClassName:ERROR",
         "-Xep:MissingFail:ERROR",
-        "-Xep:MissingOverride:WARN",
-        "-Xep:MutableConstantField:WARN",
+        "-Xep:MissingOverride:ERROR",
+        "-Xep:MutableConstantField:ERROR",
         "-Xep:NarrowingCompoundAssignment:WARN",
-        "-Xep:NonAtomicVolatileUpdate:WARN",
+        "-Xep:NonAtomicVolatileUpdate:ERROR",
         "-Xep:NonOverridingEquals:WARN",
-        "-Xep:NullableConstructor:WARN",
-        "-Xep:NullablePrimitive:WARN",
-        "-Xep:NullableVoid:WARN",
+        "-Xep:NullableConstructor:ERROR",
+        "-Xep:NullablePrimitive:ERROR",
+        "-Xep:NullableVoid:ERROR",
         "-Xep:OperatorPrecedence:WARN",
-        "-Xep:OverridesGuiceInjectableMethod:WARN",
-        "-Xep:PreconditionsInvalidPlaceholder:WARN",
-        "-Xep:ProtoFieldPreconditionsCheckNotNull:WARN",
-        "-Xep:ProtocolBufferOrdinal:WARN",
-        "-Xep:RequiredModifiers:WARN",
+        "-Xep:OverridesGuiceInjectableMethod:ERROR",
+        "-Xep:PreconditionsInvalidPlaceholder:ERROR",
+        "-Xep:ProtoFieldPreconditionsCheckNotNull:ERROR",
+        "-Xep:ProtocolBufferOrdinal:ERROR",
+        "-Xep:RequiredModifiers:ERROR",
         "-Xep:ShortCircuitBoolean:WARN",
-        "-Xep:SimpleDateFormatConstant:WARN",
-        "-Xep:StaticGuardedByInstance:WARN",
-        "-Xep:SynchronizeOnNonFinalField:WARN",
-        "-Xep:TruthConstantAsserts:WARN",
-        "-Xep:TypeParameterShadowing:WARN",
+        "-Xep:SimpleDateFormatConstant:ERROR",
+        "-Xep:StaticGuardedByInstance:ERROR",
+        "-Xep:SynchronizeOnNonFinalField:ERROR",
+        "-Xep:TruthConstantAsserts:ERROR",
+        "-Xep:TypeParameterShadowing:ERROR",
         "-Xep:TypeParameterUnusedInFormals:WARN",
-        "-Xep:URLEqualsHashCode:WARN",
-        "-Xep:UnsynchronizedOverridesSynchronized:WARN",
-        "-Xep:WaitNotInLoop:WARN",
+        "-Xep:URLEqualsHashCode:ERROR",
+        "-Xep:UnsynchronizedOverridesSynchronized:ERROR",
+        "-Xep:WaitNotInLoop:ERROR",
     ],
     packages = ["error_prone_packages"],
 )
diff --git a/tools/version.sh b/tools/version.sh
index e5c98ec..8b8095d 100755
--- a/tools/version.sh
+++ b/tools/version.sh
@@ -161,6 +161,17 @@
 		$seen_version = 0;
 		$old_argv = $ARGV;
 	}
+	if ($seen_version < 18) {
+			$seen_version++ if
+		s{<(version)>.*</\1>}{<${1}>'"$POM_V"'</${1}>};
+	}
+	' org.eclipse.jgit.coverage/pom.xml
+
+perl -pi~ -e '
+	if ($ARGV ne $old_argv) {
+		$seen_version = 0;
+		$old_argv = $ARGV;
+	}
 	if (!$seen_version) {
 		$seen_version = 1 if
 		s{<(version)>.*</\1>}{<${1}>'"$POM_V"'</${1}>};