Merge branch 'stable-5.2' into stable-5.3

* stable-5.2:
  Prepare 5.1.9-SNAPSHOT builds
  JGit v5.1.8.201906050907-r
  Test detecting modified packfiles
  Enhance fsTick() to use filesystem timer resolution
  Add debug trace to measure time needed to open pack index
  Extend FileSnapshot for packfiles to also use checksum to detect changes
  Wait opening new packfile until it can't be racy anymore
  Avoid null PackConfig in GC
  Add FileSnapshot test testing recognition of file size changes
  Capture reason for result of FileSnapshot#isModified
  Skip FileSnapshotTest#testSimulatePackfileReplacement on Windows
  Tune max heap size for tests
  Fix FileSnapshotTest.testNewFileNoWait() to match its javadoc
  ObjectDirectory: fix closing of obsolete packs
  Include filekey file attribute when comparing FileSnapshots
  Measure file timestamp resolution used in FileSnapshot
  Fix FileSnapshot's consideration of file size
  Fix API problem filters
  Fix API problem filters

Change-Id: Id79a3a19f9a31dff94d10a406c2b6e08a506931a
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 0eabecc..c9ffb73 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -48,14 +48,14 @@
 
 maven_jar(
     name = "httpclient",
-    artifact = "org.apache.httpcomponents:httpclient:4.5.5",
-    sha1 = "1603dfd56ebcd583ccdf337b6c3984ac55d89e58",
+    artifact = "org.apache.httpcomponents:httpclient:4.5.6",
+    sha1 = "1afe5621985efe90a92d0fbc9be86271efbe796f",
 )
 
 maven_jar(
     name = "httpcore",
-    artifact = "org.apache.httpcomponents:httpcore:4.4.9",
-    sha1 = "a86ce739e5a7175b4b234c290a00a5fdb80957a0",
+    artifact = "org.apache.httpcomponents:httpcore:4.4.10",
+    sha1 = "acc54d9b28bdffe4bbde89ed2e4a1e86b5285e2b",
 )
 
 maven_jar(
@@ -108,8 +108,8 @@
 
 maven_jar(
     name = "tukaani-xz",
-    artifact = "org.tukaani:xz:1.6",
-    sha1 = "05b6f921f1810bdf90e25471968f741f87168b64",
+    artifact = "org.tukaani:xz:1.8",
+    sha1 = "c4f7d054303948eb6a4066194253886c8af07128",
 )
 
 maven_jar(
@@ -168,46 +168,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 0c5c224..d89ebab 100644
--- a/lib/BUILD
+++ b/lib/BUILD
@@ -148,6 +148,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..b6fe970 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.2.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.2,5.4.0)",
+ org.eclipse.jgit.junit;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.lib;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.util;version="[5.3.2,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..888d869 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.2-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..543e4c5 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.2.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.2,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.2";
  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..9c227b7 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.2-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 @@
 		}
 
 		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..b63ba7a 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.2.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.2,5.4.0)",
+ org.eclipse.jgit.lib;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.nls;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.revwalk;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.util;version="[5.3.2,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.2";
   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..ecf53bf 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.2.qualifier
+Eclipse-SourceBundle: org.eclipse.jgit.archive;version="5.3.2.qualifier";roots="."
diff --git a/org.eclipse.jgit.archive/pom.xml b/org.eclipse.jgit.archive/pom.xml
index f36a3a6..f59382d 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.2-SNAPSHOT</version>
   </parent>
 
   <artifactId>org.eclipse.jgit.archive</artifactId>
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..e4f156d
--- /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.2-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.2-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.jgit</groupId>
+      <artifactId>org.eclipse.jgit.ant</artifactId>
+      <version>5.3.2-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.jgit</groupId>
+      <artifactId>org.eclipse.jgit.archive</artifactId>
+      <version>5.3.2-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.jgit</groupId>
+      <artifactId>org.eclipse.jgit.http.apache</artifactId>
+      <version>5.3.2-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.jgit</groupId>
+      <artifactId>org.eclipse.jgit.http.server</artifactId>
+      <version>5.3.2-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.jgit</groupId>
+      <artifactId>org.eclipse.jgit.lfs</artifactId>
+      <version>5.3.2-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.jgit</groupId>
+      <artifactId>org.eclipse.jgit.lfs.server</artifactId>
+      <version>5.3.2-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.jgit</groupId>
+      <artifactId>org.eclipse.jgit.pgm</artifactId>
+      <version>5.3.2-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.jgit</groupId>
+      <artifactId>org.eclipse.jgit.ui</artifactId>
+      <version>5.3.2-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.jgit</groupId>
+      <artifactId>org.eclipse.jgit.ssh.apache</artifactId>
+      <version>5.3.2-SNAPSHOT</version>
+    </dependency>
+
+    <dependency>
+      <groupId>org.eclipse.jgit</groupId>
+      <artifactId>org.eclipse.jgit.test</artifactId>
+      <version>5.3.2-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.jgit</groupId>
+      <artifactId>org.eclipse.jgit.ant.test</artifactId>
+      <version>5.3.2-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.jgit</groupId>
+      <artifactId>org.eclipse.jgit.http.test</artifactId>
+      <version>5.3.2-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.jgit</groupId>
+      <artifactId>org.eclipse.jgit.pgm.test</artifactId>
+      <version>5.3.2-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.jgit</groupId>
+      <artifactId>org.eclipse.jgit.lfs.test</artifactId>
+      <version>5.3.2-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.jgit</groupId>
+      <artifactId>org.eclipse.jgit.lfs.server.test</artifactId>
+      <version>5.3.2-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.jgit</groupId>
+      <artifactId>org.eclipse.jgit.ssh.apache.test</artifactId>
+      <version>5.3.2-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..bc9bebc 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.2.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.2,5.4.0)",
+ org.eclipse.jgit.nls;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.transport.http;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.util;version="[5.3.2,5.4.0)"
+Export-Package: org.eclipse.jgit.transport.http.apache;version="5.3.2";
   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..22a3abf 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.2-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..7de280e 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.2.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.2",
+ org.eclipse.jgit.http.server.glue;version="5.3.2";
   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.2";
   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.2,5.4.0)",
+ org.eclipse.jgit.internal.storage.dfs;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.internal.storage.file;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.internal.transport.parser;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.lib;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.nls;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.revwalk;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.transport;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.transport.resolver;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.util;version="[5.3.2,5.4.0)"
diff --git a/org.eclipse.jgit.http.server/pom.xml b/org.eclipse.jgit.http.server/pom.xml
index 78191ef..b2af14e 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.2-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 @@
 			// 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 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..ca2c8e6 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.2.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.2,5.4.0)",
+ org.eclipse.jgit.http.server;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.http.server.glue;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.http.server.resolver;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.internal;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.internal.storage.dfs;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.internal.storage.file;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.internal.storage.reftable;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.junit;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.junit.http;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.lib;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.nls;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.revwalk;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.storage.file;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.transport;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.transport.http;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.transport.http.apache;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.transport.resolver;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.util;version="[5.3.2,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..5ed3ae1 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.2-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 @@
 	@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 @@
 
 	@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 @@
 	@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 @@
 
 	@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 @@
 					.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 @@
 	@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 @@
 	@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 @@
 	@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 @@
 	@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 b26324d..aad029c 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
@@ -208,7 +208,7 @@
 
 		ServletContextHandler app = addNormalContext(gs, src, srcName);
 
-		ServletContextHandler broken = addBrokenContext(gs, src, srcName);
+		ServletContextHandler broken = addBrokenContext(gs, srcName);
 
 		ServletContextHandler redirect = addRedirectContext(gs);
 
@@ -287,8 +287,8 @@
 		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() {
 
@@ -416,12 +416,11 @@
 
 	@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
@@ -459,9 +458,9 @@
 
 	@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");
@@ -486,23 +485,20 @@
 
 	@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"));
@@ -514,9 +510,6 @@
 	@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,
@@ -525,7 +518,9 @@
 			}
 		};
 
-		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"));
@@ -536,17 +531,15 @@
 
 	@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());
 
@@ -576,21 +569,20 @@
 
 	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());
@@ -665,12 +657,12 @@
 				.openUserConfig(null, FS.DETECTED);
 		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) {
@@ -687,11 +679,10 @@
 
 	@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) {
@@ -705,18 +696,17 @@
 				.openUserConfig(null, FS.DETECTED);
 		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());
 
@@ -750,11 +740,10 @@
 
 	@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) {
@@ -769,10 +758,9 @@
 		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) {
@@ -783,18 +771,16 @@
 
 	@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());
 
@@ -829,10 +815,9 @@
 	@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) {
@@ -851,10 +836,9 @@
 	@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));
@@ -877,9 +861,6 @@
 	@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") {
@@ -897,15 +878,16 @@
 				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());
 
@@ -946,18 +928,16 @@
 	@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());
 
@@ -1008,8 +988,12 @@
 
 		// 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.
 		//
@@ -1068,8 +1052,12 @@
 
 		// 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.
 		//
@@ -1123,10 +1111,9 @@
 
 	@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");
@@ -1161,12 +1148,14 @@
 
 	@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);
@@ -1203,8 +1192,8 @@
 			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.
@@ -1283,7 +1272,7 @@
 			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);
@@ -1357,7 +1346,7 @@
 			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..d07176b 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.2.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.2,5.4.0)",
+ org.eclipse.jgit.http.server;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.internal.storage.file;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.junit;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.lib;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.revwalk;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.transport;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.transport.resolver;version="[5.3.2,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.2";
   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..2f068ed 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.2-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 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..02a64fa 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.2.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.2,5.4.0)",
+ org.eclipse.jgit.lib;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.transport;version="[5.3.2,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.2"
diff --git a/org.eclipse.jgit.junit.ssh/pom.xml b/org.eclipse.jgit.junit.ssh/pom.xml
index 4cd68eb..92e31d9 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.2-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..d0ca797 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.2.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.2,5.4.0)",
+ org.eclipse.jgit.api;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.api.errors;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.dircache;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.errors;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.internal.storage.file;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.internal.storage.pack;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.lib;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.merge;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.revwalk;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.storage.file;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.transport;version="5.3.2",
+ org.eclipse.jgit.treewalk;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.treewalk.filter;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.util;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.util.io;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.util.time;version="[5.3.2,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.2";
   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.2";uses:="org.eclipse.jgit.util.time"
diff --git a/org.eclipse.jgit.junit/pom.xml b/org.eclipse.jgit.junit/pom.xml
index e198193..1cbd50b 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.2-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 12b2169..4b2eadf 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
@@ -394,10 +394,11 @@
 	 * @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 */);
 	}
 
 	/**
@@ -407,11 +408,13 @@
 	 *            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 c9fa2f5..55a7766 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 @@
 		}
 	}
 
+	/**
+	 * 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..321ab44 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.2.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.2,5.4.0)",
+ org.eclipse.jgit.api.errors;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.internal.storage.file;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.junit;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.junit.http;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.lfs;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.lfs.errors;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.lfs.lib;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.lfs.server;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.lfs.server.fs;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.lfs.test;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.lib;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.revwalk;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.storage.file;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.transport;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.treewalk;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.treewalk.filter;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.util;version="[5.3.2,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..3648f1f 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.2-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/.settings/.api_filters b/org.eclipse.jgit.lfs.server/.settings/.api_filters
index 3e60680..2a47dd3 100644
--- a/org.eclipse.jgit.lfs.server/.settings/.api_filters
+++ b/org.eclipse.jgit.lfs.server/.settings/.api_filters
@@ -3,8 +3,8 @@
     <resource path="META-INF/MANIFEST.MF">
         <filter id="924844039">
             <message_arguments>
-                <message_argument value="5.2.3"/>
-                <message_argument value="5.2.0"/>
+                <message_argument value="5.3.2"/>
+                <message_argument value="5.3.0"/>
             </message_arguments>
         </filter>
     </resource>
diff --git a/org.eclipse.jgit.lfs.server/META-INF/MANIFEST.MF b/org.eclipse.jgit.lfs.server/META-INF/MANIFEST.MF
index 7bed133..cbf38f0 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.2.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.2";
   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.2";
   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.2";x-internal:=true,
+ org.eclipse.jgit.lfs.server.s3;version="5.3.2";
   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.2,5.4.0)",
+ org.eclipse.jgit.internal;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.internal.storage.file;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.lfs.errors;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.lfs.internal;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.lfs.lib;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.lib;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.nls;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.transport.http;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.transport.http.apache;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.util;version="[5.3.2,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..ad1ecd7 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.2-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 213ba57..cc8bc60 100644
--- a/org.eclipse.jgit.lfs.test/BUILD
+++ b/org.eclipse.jgit.lfs.test/BUILD
@@ -1,10 +1,10 @@
-package(default_visibility = ["//visibility:public"])
-
 load(
     "@com_googlesource_gerrit_bazlets//tools:junit.bzl",
     "junit_tests",
 )
 
+package(default_visibility = ["//visibility:public"])
+
 junit_tests(
     name = "lfs",
     srcs = glob(["tst/**/*.java"]),
diff --git a/org.eclipse.jgit.lfs.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.lfs.test/META-INF/MANIFEST.MF
index 2863967..9a3d44e 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.2.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.2,5.4.0)",
+ org.eclipse.jgit.junit;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.lfs;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.lfs.errors;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.lfs.lib;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.lib;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.revwalk;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.treewalk;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.treewalk.filter;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.util;version="[5.3.2,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.2";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..b19f186 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.2-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..4ed33ce 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.2.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.2",
+ org.eclipse.jgit.lfs.errors;version="5.3.2",
+ org.eclipse.jgit.lfs.internal;version="5.3.2";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.2"
 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.2,5.4.0)";resolution:=optional,
+ org.eclipse.jgit.api.errors;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.attributes;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.diff;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.errors;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.hooks;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.internal.storage.file;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.lib;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.nls;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.revwalk;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.storage.file;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.storage.pack;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.transport;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.transport.http;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.treewalk;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.treewalk.filter;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.util;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.util.io;version="[5.3.2,5.4.0)"
diff --git a/org.eclipse.jgit.lfs/pom.xml b/org.eclipse.jgit.lfs/pom.xml
index f7cad33..94f5ae9 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.2-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..46a7d3b 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.2.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..fecc73e 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.2-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..87de691 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.2.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..8d437d5 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.2-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..ce20331 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.2.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..b55b8b9 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.2-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..d8c7fd9 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.2.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..6580764 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.2-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..4c53bc0 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.2.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.2" match="equivalent"/>
+      <import feature="org.eclipse.jgit.lfs" version="5.3.2" match="equivalent"/>
+      <import feature="org.eclipse.jgit.ssh.apache" version="5.3.2" 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..ea14357 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.2-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..e5b35d1 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.2.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..c2db7ad 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.2-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..e077b89 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.2-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..ea40f4d 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.2.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..986f0b6 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.2-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..e2d1c7e 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.2.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..2cc1cd7 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.2-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..94770ef 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.2.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..500fcbb 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.2-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..19edcce 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.2.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 07594ea..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/R20181128170323-2018-12.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 62%
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 10ff3be..1a6a0fc 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,28 +1,25 @@
-<?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="1544018556">
+<?xml version="1.0" encoding="UTF-8" standalone="no"?><?pde?><!-- generated with https://github.com/eclipse-cbi/targetplatform-dsl --><target name="jgit-4.10" sequenceNumber="1551829107">
   <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"/>
+    <location includeAllPlatforms="false" includeConfigurePhase="true" includeMode="slicer" includeSource="true" type="InstallableUnit">
+      <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">
+    <location includeAllPlatforms="false" includeConfigurePhase="true" includeMode="slicer" includeSource="true" type="InstallableUnit">
       <unit id="org.apache.ant" version="1.10.5.v20180808-0324"/>
       <unit id="org.apache.ant.source" version="1.10.5.v20180808-0324"/>
       <unit id="org.apache.commons.codec" version="1.10.0.v20180409-1845"/>
@@ -31,12 +28,18 @@
       <unit id="org.apache.commons.compress.source" version="1.18.0.v20181121-2221"/>
       <unit id="org.apache.commons.logging" version="1.2.0.v20180409-1502"/>
       <unit id="org.apache.commons.logging.source" version="1.2.0.v20180409-1502"/>
-      <unit id="org.apache.httpcomponents.httpclient" version="4.5.5.v20180409-1525"/>
-      <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.5.v20180409-1525"/>
-      <unit id="org.apache.httpcomponents.httpcore" version="4.4.9.v20180409-1525"/>
-      <unit id="org.apache.httpcomponents.httpcore.source" version="4.4.9.v20180409-1525"/>
+      <unit id="org.apache.httpcomponents.httpclient" version="4.5.6.v20190213-1430"/>
+      <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.6.v20190213-1430"/>
+      <unit id="org.apache.httpcomponents.httpcore" version="4.4.10.v20190123-2214"/>
+      <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 +65,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"/>
@@ -76,11 +79,11 @@
       <unit id="org.apache.sshd.core.source" version="2.0.0.v20181102-1323"/>
       <unit id="org.apache.sshd.sftp" version="2.0.0.v20181102-1323"/>
       <unit id="org.apache.sshd.sftp.source" version="2.0.0.v20181102-1323"/>
-      <repository location="http://download.eclipse.org/tools/orbit/downloads/drops/R20181128170323/repository"/>
+      <repository location="http://download.eclipse.org/tools/orbit/downloads/drops/R20190226160451/repository"/>
     </location>
-    <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
+    <location includeAllPlatforms="false" includeConfigurePhase="true" includeMode="slicer" includeSource="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>
+</target>
\ No newline at end of file
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..31981f2
--- /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/R20190226160451-2019-03.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 70%
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 98a2a6b..14cd0d7 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="1544018574">
+<target name="jgit-4.11-staging" sequenceNumber="1551829209">
   <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.v20180808-0324"/>
@@ -31,12 +31,18 @@
       <unit id="org.apache.commons.compress.source" version="1.18.0.v20181121-2221"/>
       <unit id="org.apache.commons.logging" version="1.2.0.v20180409-1502"/>
       <unit id="org.apache.commons.logging.source" version="1.2.0.v20180409-1502"/>
-      <unit id="org.apache.httpcomponents.httpclient" version="4.5.5.v20180409-1525"/>
-      <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.5.v20180409-1525"/>
-      <unit id="org.apache.httpcomponents.httpcore" version="4.4.9.v20180409-1525"/>
-      <unit id="org.apache.httpcomponents.httpcore.source" version="4.4.9.v20180409-1525"/>
+      <unit id="org.apache.httpcomponents.httpclient" version="4.5.6.v20190213-1430"/>
+      <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.6.v20190213-1430"/>
+      <unit id="org.apache.httpcomponents.httpcore" version="4.4.10.v20190123-2214"/>
+      <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"/>
@@ -76,11 +82,11 @@
       <unit id="org.apache.sshd.core.source" version="2.0.0.v20181102-1323"/>
       <unit id="org.apache.sshd.sftp" version="2.0.0.v20181102-1323"/>
       <unit id="org.apache.sshd.sftp.source" version="2.0.0.v20181102-1323"/>
-      <repository location="http://download.eclipse.org/tools/orbit/downloads/drops/R20181128170323/repository"/>
+      <repository location="http://download.eclipse.org/tools/orbit/downloads/drops/R20190226160451/repository"/>
     </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..05002f2
--- /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/R20190226160451-2019-03.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 f099b34..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/R20181128170323-2018-12.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 11fd7fd..f8641ca 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="1544018561">
+<target name="jgit-4.6" sequenceNumber="1551829238">
   <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.v20180808-0324"/>
@@ -31,12 +31,18 @@
       <unit id="org.apache.commons.compress.source" version="1.18.0.v20181121-2221"/>
       <unit id="org.apache.commons.logging" version="1.2.0.v20180409-1502"/>
       <unit id="org.apache.commons.logging.source" version="1.2.0.v20180409-1502"/>
-      <unit id="org.apache.httpcomponents.httpclient" version="4.5.5.v20180409-1525"/>
-      <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.5.v20180409-1525"/>
-      <unit id="org.apache.httpcomponents.httpcore" version="4.4.9.v20180409-1525"/>
-      <unit id="org.apache.httpcomponents.httpcore.source" version="4.4.9.v20180409-1525"/>
+      <unit id="org.apache.httpcomponents.httpclient" version="4.5.6.v20190213-1430"/>
+      <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.6.v20190213-1430"/>
+      <unit id="org.apache.httpcomponents.httpcore" version="4.4.10.v20190123-2214"/>
+      <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"/>
@@ -76,7 +82,7 @@
       <unit id="org.apache.sshd.core.source" version="2.0.0.v20181102-1323"/>
       <unit id="org.apache.sshd.sftp" version="2.0.0.v20181102-1323"/>
       <unit id="org.apache.sshd.sftp.source" version="2.0.0.v20181102-1323"/>
-      <repository location="http://download.eclipse.org/tools/orbit/downloads/drops/R20181128170323/repository"/>
+      <repository location="http://download.eclipse.org/tools/orbit/downloads/drops/R20190226160451/repository"/>
     </location>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
       <unit id="org.eclipse.osgi" version="0.0.0"/>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.6.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.6.tpd
index 39f166c..81eb219 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.6.tpd
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.6.tpd
@@ -1,7 +1,7 @@
 target "jgit-4.6" with source configurePhase
 
-include "projects/jetty-9.4.11.tpd"
-include "orbit/R20181128170323-2018-12.tpd"
+include "projects/jetty-9.4.14.tpd"
+include "orbit/R20190226160451-2019-03.tpd"
 
 location "http://download.eclipse.org/releases/neon/" {
 	org.eclipse.osgi lazy
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.7.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.7.target
index 061439c..427f9dc 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="1544018548">
+<target name="jgit-4.7" sequenceNumber="1551829255">
   <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.v20180808-0324"/>
@@ -31,12 +31,18 @@
       <unit id="org.apache.commons.compress.source" version="1.18.0.v20181121-2221"/>
       <unit id="org.apache.commons.logging" version="1.2.0.v20180409-1502"/>
       <unit id="org.apache.commons.logging.source" version="1.2.0.v20180409-1502"/>
-      <unit id="org.apache.httpcomponents.httpclient" version="4.5.5.v20180409-1525"/>
-      <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.5.v20180409-1525"/>
-      <unit id="org.apache.httpcomponents.httpcore" version="4.4.9.v20180409-1525"/>
-      <unit id="org.apache.httpcomponents.httpcore.source" version="4.4.9.v20180409-1525"/>
+      <unit id="org.apache.httpcomponents.httpclient" version="4.5.6.v20190213-1430"/>
+      <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.6.v20190213-1430"/>
+      <unit id="org.apache.httpcomponents.httpcore" version="4.4.10.v20190123-2214"/>
+      <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"/>
@@ -76,7 +82,7 @@
       <unit id="org.apache.sshd.core.source" version="2.0.0.v20181102-1323"/>
       <unit id="org.apache.sshd.sftp" version="2.0.0.v20181102-1323"/>
       <unit id="org.apache.sshd.sftp.source" version="2.0.0.v20181102-1323"/>
-      <repository location="http://download.eclipse.org/tools/orbit/downloads/drops/R20181128170323/repository"/>
+      <repository location="http://download.eclipse.org/tools/orbit/downloads/drops/R20190226160451/repository"/>
     </location>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
       <unit id="org.eclipse.osgi" version="0.0.0"/>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.7.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.7.tpd
index b1f0568..10a4eb7 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.7.tpd
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.7.tpd
@@ -1,7 +1,7 @@
 target "jgit-4.7" with source configurePhase
 
-include "projects/jetty-9.4.11.tpd"
-include "orbit/R20181128170323-2018-12.tpd"
+include "projects/jetty-9.4.14.tpd"
+include "orbit/R20190226160451-2019-03.tpd"
 
 location "http://download.eclipse.org/releases/oxygen/" {
 	org.eclipse.osgi lazy
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.8.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.8.target
index da66fb9..fe641ef 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="1544018536">
+<target name="jgit-4.8" sequenceNumber="1551829263">
   <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.v20180808-0324"/>
@@ -31,12 +31,18 @@
       <unit id="org.apache.commons.compress.source" version="1.18.0.v20181121-2221"/>
       <unit id="org.apache.commons.logging" version="1.2.0.v20180409-1502"/>
       <unit id="org.apache.commons.logging.source" version="1.2.0.v20180409-1502"/>
-      <unit id="org.apache.httpcomponents.httpclient" version="4.5.5.v20180409-1525"/>
-      <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.5.v20180409-1525"/>
-      <unit id="org.apache.httpcomponents.httpcore" version="4.4.9.v20180409-1525"/>
-      <unit id="org.apache.httpcomponents.httpcore.source" version="4.4.9.v20180409-1525"/>
+      <unit id="org.apache.httpcomponents.httpclient" version="4.5.6.v20190213-1430"/>
+      <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.6.v20190213-1430"/>
+      <unit id="org.apache.httpcomponents.httpcore" version="4.4.10.v20190123-2214"/>
+      <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"/>
@@ -76,7 +82,7 @@
       <unit id="org.apache.sshd.core.source" version="2.0.0.v20181102-1323"/>
       <unit id="org.apache.sshd.sftp" version="2.0.0.v20181102-1323"/>
       <unit id="org.apache.sshd.sftp.source" version="2.0.0.v20181102-1323"/>
-      <repository location="http://download.eclipse.org/tools/orbit/downloads/drops/R20181128170323/repository"/>
+      <repository location="http://download.eclipse.org/tools/orbit/downloads/drops/R20190226160451/repository"/>
     </location>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
       <unit id="org.eclipse.osgi" version="0.0.0"/>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.8.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.8.tpd
index 959abae..daa24dd 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.8.tpd
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.8.tpd
@@ -1,7 +1,7 @@
 target "jgit-4.8" with source configurePhase
 
-include "projects/jetty-9.4.11.tpd"
-include "orbit/R20181128170323-2018-12.tpd"
+include "projects/jetty-9.4.14.tpd"
+include "orbit/R20190226160451-2019-03.tpd"
 
 location "http://download.eclipse.org/releases/photon/" {
 	org.eclipse.osgi lazy
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 025bb1f..4f63f66 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="1544017335">
+<target name="jgit-4.9" sequenceNumber="1551829271">
   <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.v20180808-0324"/>
@@ -31,12 +31,18 @@
       <unit id="org.apache.commons.compress.source" version="1.18.0.v20181121-2221"/>
       <unit id="org.apache.commons.logging" version="1.2.0.v20180409-1502"/>
       <unit id="org.apache.commons.logging.source" version="1.2.0.v20180409-1502"/>
-      <unit id="org.apache.httpcomponents.httpclient" version="4.5.5.v20180409-1525"/>
-      <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.5.v20180409-1525"/>
-      <unit id="org.apache.httpcomponents.httpcore" version="4.4.9.v20180409-1525"/>
-      <unit id="org.apache.httpcomponents.httpcore.source" version="4.4.9.v20180409-1525"/>
+      <unit id="org.apache.httpcomponents.httpclient" version="4.5.6.v20190213-1430"/>
+      <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.6.v20190213-1430"/>
+      <unit id="org.apache.httpcomponents.httpcore" version="4.4.10.v20190123-2214"/>
+      <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"/>
@@ -76,7 +82,7 @@
       <unit id="org.apache.sshd.core.source" version="2.0.0.v20181102-1323"/>
       <unit id="org.apache.sshd.sftp" version="2.0.0.v20181102-1323"/>
       <unit id="org.apache.sshd.sftp.source" version="2.0.0.v20181102-1323"/>
-      <repository location="http://download.eclipse.org/tools/orbit/downloads/drops/R20181128170323/repository"/>
+      <repository location="http://download.eclipse.org/tools/orbit/downloads/drops/R20190226160451/repository"/>
     </location>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
       <unit id="org.eclipse.osgi" version="0.0.0"/>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.9.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.9.tpd
index 0b6277d..d024dca 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,7 +1,7 @@
 target "jgit-4.9" with source configurePhase
 
-include "projects/jetty-9.4.11.tpd"
-include "orbit/R20181128170323-2018-12.tpd"
+include "projects/jetty-9.4.14.tpd"
+include "orbit/R20190226160451-2019-03.tpd"
 
 location "http://download.eclipse.org/releases/2018-09/" {
 	org.eclipse.osgi lazy
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/pom.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/pom.xml
index dba70d3..25caf70 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.2-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 bc069c6..d83cc28 100644
--- a/org.eclipse.jgit.packaging/pom.xml
+++ b/org.eclipse.jgit.packaging/pom.xml
@@ -53,13 +53,13 @@
 
   <groupId>org.eclipse.jgit</groupId>
   <artifactId>jgit.tycho.parent</artifactId>
-  <version>5.2.3-SNAPSHOT</version>
+  <version>5.3.2-SNAPSHOT</version>
   <packaging>pom</packaging>
 
   <name>JGit Tycho Parent</name>
 
   <properties>
-    <tycho-version>1.2.0</tycho-version>
+    <tycho-version>1.3.0</tycho-version>
     <tycho-extras-version>${tycho-version}</tycho-extras-version>
     <target-platform>jgit-4.6</target-platform>
   </properties>
diff --git a/org.eclipse.jgit.pgm.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.pgm.test/META-INF/MANIFEST.MF
index 90398a9..5ce3167 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.2.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.2,5.4.0)",
+ org.eclipse.jgit.api.errors;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.diff;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.dircache;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.internal.storage.file;version="5.3.2",
+ org.eclipse.jgit.junit;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.lib;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.merge;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.pgm;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.pgm.internal;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.pgm.opt;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.revwalk;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.storage.file;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.transport;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.treewalk;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.util;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.util.io;version="[5.3.2,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..b380825 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.2-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 @@
 			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..df745e3 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.2.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.2,5.4.0)",
+ org.eclipse.jgit.api.errors;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.archive;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.awtui;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.blame;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.diff;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.dircache;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.errors;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.gitrepo;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.internal.ketch;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.internal.storage.dfs;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.internal.storage.file;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.internal.storage.io;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.internal.storage.pack;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.internal.storage.reftable;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.internal.storage.reftree;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.lfs;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.lfs.lib;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.lfs.server;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.lfs.server.fs;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.lfs.server.s3;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.lib;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.merge;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.nls;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.notes;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.revplot;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.revwalk;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.revwalk.filter;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.storage.file;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.storage.pack;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.transport;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.transport.http.apache;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.transport.resolver;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.transport.sshd;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.treewalk;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.treewalk.filter;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.util;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.util.io;version="[5.3.2,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.2";
   uses:="org.eclipse.jgit.transport,
    org.eclipse.jgit.util",
- org.eclipse.jgit.pgm;version="5.2.3";
+ org.eclipse.jgit.pgm;version="5.3.2";
   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.2";
   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.2";x-friends:="org.eclipse.jgit.pgm.test,org.eclipse.jgit.test",
+ org.eclipse.jgit.pgm.opt;version="5.3.2";
   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..6b676a2 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.2.qualifier
+Eclipse-SourceBundle: org.eclipse.jgit.pgm;version="5.3.2.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..2922fd8 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.2-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 d7d895a..a482ce3 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
@@ -51,6 +51,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}
@@ -132,6 +133,7 @@
 metaVar_paths=path ...
 metaVar_pattern=pattern
 metaVar_port=PORT
+metaVar_prefix=PREFIX
 metaVar_ref=REF
 metaVar_refs=REFS
 metaVar_refspec=refspec
@@ -175,7 +177,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}
@@ -186,6 +188,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}
@@ -341,7 +344,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 @@
 			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 @@
 				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 @@
 	@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 @@
 
 	/** {@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 @@
 				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 @@
 				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 @@
 				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 @@
 
 			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 @@
 				}
 				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 @@
 					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 @@
 				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 @@
 
 	/** {@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 @@
 				} 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 @@
 				}
 				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 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 @@
 	@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 @@
 			} 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 @@
 
 	/** {@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 @@
 				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 @@
 						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 @@
 	@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 @@
 			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 @@
 
 	/** {@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 @@
 
 	/** {@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 @@
 			} 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 @@
 		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 @@
 
 	/** {@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 @@
 			} 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 @@
 			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 @@
 
 	/** {@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 @@
 
 			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 @@
 				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 @@
 				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 @@
 
 	/** {@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 @@
 
 			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 @@
 
 	/** {@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 @@
 
 	/** {@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 @@
 			}
 			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 @@
 
 	/** {@inheritDoc} */
 	@Override
-	protected void run() throws Exception {
+	protected void run() {
 		InitCommand command = Git.init();
 		command.setBare(bare);
 		if (gitdir != null) {
@@ -83,9 +85,14 @@
 		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 @@
 
 	/** {@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 @@
 				}
 			}
 
-			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 @@
 	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 @@
 							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 @@
 
 	/** {@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 @@
 				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 @@
 
 	/** {@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 @@
 				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 @@
 
 	/** {@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 @@
 
 	/** {@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 @@
 
 	/** {@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 @@
 			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 @@
 					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 @@
 
 	/** {@inheritDoc} */
 	@Override
-	protected void run() throws Exception {
+	protected void run() {
 		final org.eclipse.jgit.transport.ReceivePack rp;
 
 		try {
@@ -75,9 +76,15 @@
 		} 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 @@
 
 	/** {@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 @@
 			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 @@
 
 	/** {@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 @@
 				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 @@
 				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 @@
 
 	/** {@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 @@
 
 	/** {@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 @@
 
 	/** {@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 @@
 
 	/** {@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 @@
 	/** {@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 @@
 							obj.getType()));
 				}
 			}
+		} catch (RevisionSyntaxException | IOException e) {
+			throw die(e.getMessage(), e);
 		} finally {
 			diffFmt.close();
 		}
@@ -273,7 +278,7 @@
 		}
 	}
 
-	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 @@
 
 	/** {@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 @@
 
 	/** {@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 @@
 					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 @@
 				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 @@
 
 	/** {@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 b3ad8bf..d0288a8 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
@@ -165,6 +165,7 @@
 	/***/ public String clonedEmptyRepository;
 	/***/ public String cloningInto;
 	/***/ public String commitLabel;
+	/***/ public String configOnlyListOptionSupported;
 	/***/ public String conflictingUsageOf_git_dir_andArguments;
 	/***/ public String couldNotCreateBranch;
 	/***/ public String dateInfo;
@@ -278,7 +279,7 @@
 	/***/ public String onBranchToBeBorn;
 	/***/ public String onBranch;
 	/***/ public String onlyOneMetaVarExpectedIn;
-	/***/ public String onlyOneOfIncludeOnlyAllInteractiveCanBeUsed;
+	/***/ public String onlyOneCommitOptionAllowed;
 	/***/ public String password;
 	/***/ public String pathspecDidNotMatch;
 	/***/ public String pushTo;
@@ -289,6 +290,7 @@
 	/***/ 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..e320f9e 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.2.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.2,5.4.0)",
+ org.eclipse.jgit.junit;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.junit.ssh;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.lib;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.transport;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.transport.ssh;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.transport.sshd;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.util;version="[5.3.2,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..f0b0a3b 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.2-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..1951372 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.2.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.2";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.2";x-internal:=true,
+ org.eclipse.jgit.internal.transport.sshd.proxy;version="5.3.2";x-friends:="org.eclipse.jgit.ssh.apache.test",
+ org.eclipse.jgit.transport.sshd;version="5.3.2";
   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.2,5.4.0)",
+ org.eclipse.jgit.errors;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.fnmatch;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.internal.storage.file;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.internal.transport.ssh;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.nls;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.transport;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.util;version="[5.3.2,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..f201dcb 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.2.qualifier
+Eclipse-SourceBundle: org.eclipse.jgit.ssh.apache;version="5.3.2.qualifier";roots="."
diff --git a/org.eclipse.jgit.ssh.apache/pom.xml b/org.eclipse.jgit.ssh.apache/pom.xml
index 2254133..e306158 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.2-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 @@
 	}
 
 	@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 @@
 		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 @@
 					}
 				}).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 @@
 	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 @@
 			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 @@
 		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 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 @@
 		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 @@
 	}
 
 	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 @@
 			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 @@
 				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 @@
 		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 @@
 				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 @@
 
 	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 @@
 	private static final class Tuple {
 		private Object[] objects;
 
-		public Tuple(Object... objects) {
+		public Tuple(Object[] objects) {
 			this.objects = objects;
 		}
 
@@ -209,8 +211,8 @@
 				}
 				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 @@
 	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 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 @@
 	}
 
 	/**
-	 * 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/BUILD b/org.eclipse.jgit.test/BUILD
index 0b18e5e..95fb79b 100644
--- a/org.eclipse.jgit.test/BUILD
+++ b/org.eclipse.jgit.test/BUILD
@@ -1,8 +1,8 @@
-load(":tests.bzl", "tests")
 load(
     "@com_googlesource_gerrit_bazlets//tools:genrule2.bzl",
     "genrule2",
 )
+load(":tests.bzl", "tests")
 
 PKG = "tst/org/eclipse/jgit/"
 
diff --git a/org.eclipse.jgit.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.test/META-INF/MANIFEST.MF
index 55ccecf..62e3cd6 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.2.qualifier
 Bundle-Localization: plugin
 Bundle-Vendor: %provider_name
 Bundle-ActivationPolicy: lazy
@@ -11,54 +11,55 @@
 Import-Package: com.googlecode.javaewah;version="[1.1.6,2.0.0)",
  com.jcraft.jsch;version="[0.1.54,0.2.0)",
  net.bytebuddy.dynamic.loading;version="[1.7.0,2.0.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.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.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.2,5.4.0)",
+ org.eclipse.jgit.api;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.api.errors;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.attributes;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.awtui;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.blame;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.diff;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.dircache;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.errors;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.events;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.fnmatch;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.gitrepo;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.hooks;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.ignore;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.ignore.internal;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.internal;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.internal.fsck;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.internal.storage.dfs;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.internal.storage.file;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.internal.storage.io;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.internal.storage.pack;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.internal.storage.reftable;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.internal.storage.reftree;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.internal.transport.parser;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.junit;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.junit.ssh;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.lfs;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.lib;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.merge;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.nls;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.notes;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.patch;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.pgm;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.pgm.internal;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.revplot;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.revwalk;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.revwalk.filter;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.storage.file;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.storage.pack;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.submodule;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.transport;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.transport.http;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.transport.resolver;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.treewalk;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.treewalk.filter;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.util;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.util.io;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.util.sha1;version="[5.3.2,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)",
@@ -72,4 +73,4 @@
  org.slf4j;version="[1.7.0,2.0.0)"
 Require-Bundle: org.hamcrest.core;bundle-version="[1.1.0,2.0.0)",
  org.hamcrest.library;bundle-version="[1.1.0,2.0.0)"
-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.2";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 6b19eb3..e4acd7a 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.2-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>
@@ -134,7 +145,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>
@@ -179,7 +190,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 @@
 
 	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 @@
 			}
 		}
 		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 @@
 				"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 @@
 		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 @@
 	 */
 	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 1a5793c..3fee51a 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 @@
 					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 @@
 		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 498005d..98a8adc 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
@@ -63,6 +63,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;
@@ -109,7 +110,7 @@
 		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");
@@ -138,6 +139,19 @@
 	}
 
 	@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"));
@@ -165,7 +179,7 @@
 			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 6b5fe50..1523b49 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 @@
 				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 3a13aa5..cd96f41 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;
@@ -61,9 +65,11 @@
 import org.eclipse.jgit.dircache.DirCacheBuilder;
 import org.eclipse.jgit.dircache.DirCacheEntry;
 import org.eclipse.jgit.junit.RepositoryTestCase;
+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;
@@ -72,7 +78,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;
@@ -614,9 +622,100 @@
 			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);
@@ -628,4 +727,126 @@
 		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 @@
 
 	@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 @@
 
 		// 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 @@
 
 		// 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 @@
 
 		// 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 @@
 
 	private Git git;
 
+	@Rule
+	public ExpectedException thrown = ExpectedException.none();
+
 	@Override
 	@Before
 	public void setUp() throws Exception {
@@ -81,6 +88,45 @@
 	}
 
 	@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 @@
 	}
 
 	@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 @@
 		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 @@
 		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 @@
 		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 @@
 		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 @@
 		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 @@
 		gc.setExpireAgeMillis(0);
 		fsTick();
 		gc.prune(Collections.<ObjectId> emptySet());
-		assertFalse(repo.hasObject(a));
+		assertFalse(repo.getObjectDatabase().has(a));
 	}
 
 	@Test
@@ -83,8 +83,8 @@
 		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 @@
 		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 @@
 		gc.setExpireAgeMillis(0);
 		fsTick();
 		gc.prune(Collections.<ObjectId> emptySet());
-		assertTrue(repo.hasObject(a));
+		assertTrue(repo.getObjectDatabase().has(a));
 	}
 
 	@Test
@@ -72,7 +72,7 @@
 		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 3ca689a..a3a302d 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
@@ -126,7 +126,7 @@
 			// 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
@@ -150,7 +150,7 @@
 			// 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
@@ -177,8 +177,8 @@
 			Assume.assumeTrue(tmpFile.lastModified() == ret[0].lastModified());
 
 			// 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 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 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 @@
 
 	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 5a2bd9c..7b3684c 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;
@@ -61,6 +62,7 @@
 import java.io.IOException;
 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;
@@ -134,6 +136,33 @@
 		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;
@@ -392,15 +421,15 @@
 
 	@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
@@ -643,7 +672,7 @@
 	}
 
 	@Test
-	public void testGetRef_DiscoversModifiedLoose() throws IOException {
+	public void testFindRef_DiscoversModifiedLoose() throws IOException {
 		Map<String, Ref> all;
 
 		writeLooseRef("refs/heads/master", A);
@@ -652,7 +681,7 @@
 
 		writeLooseRef("refs/heads/master", B);
 
-		Ref master = refdir.getRef("refs/heads/master");
+		Ref master = refdir.findRef("refs/heads/master");
 		assertEquals(B, master.getObjectId());
 	}
 
@@ -687,7 +716,7 @@
 	}
 
 	@Test
-	public void testGetRef_DiscoversDeletedLoose() throws IOException {
+	public void testFindRef_DiscoversDeletedLoose() throws IOException {
 		Map<String, Ref> all;
 
 		writeLooseRef("refs/heads/master", A);
@@ -695,7 +724,7 @@
 		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());
 	}
 
@@ -855,7 +884,7 @@
 	}
 
 	@Test
-	public void testGetRef_CycleInSymbolicRef() throws IOException {
+	public void testFindRef_CycleInSymbolicRef() throws IOException {
 		Ref r;
 
 		writeLooseRef("refs/1", "ref: refs/2\n");
@@ -865,7 +894,7 @@
 		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());
@@ -873,12 +902,12 @@
 		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());
@@ -919,16 +948,16 @@
 	}
 
 	@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());
@@ -1033,22 +1062,22 @@
 	}
 
 	@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
@@ -1071,7 +1100,29 @@
 	}
 
 	@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.
@@ -1079,7 +1130,7 @@
 				+ "\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());
@@ -1105,12 +1156,12 @@
 	}
 
 	@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());
@@ -1126,11 +1177,11 @@
 	}
 
 	@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();
@@ -1147,12 +1198,12 @@
 	}
 
 	@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();
@@ -1187,8 +1238,8 @@
 		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());
@@ -1220,14 +1271,14 @@
 
 		// 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));
 	}
 
@@ -1235,7 +1286,7 @@
 	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());
@@ -1248,7 +1299,7 @@
 
 		// 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());
@@ -1300,7 +1351,7 @@
 		} 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 96caa01..c613849 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
@@ -538,7 +538,7 @@
 				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 @@
 				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 @@
 			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 @@
 			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 @@
 			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 @@
 				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 @@
 			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 @@
 			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 @@
 				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 @@
 			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 @@
 		}
 	}
 
+	@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 @@
 		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 @@
 			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 @@
 			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 @@
 			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 @@
 			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 @@
 			Ref act = rc.getRef();
 			assertNotNull(act);
 			assertEquals(exp.getName(), act.getName());
+			assertEquals(0, act.getUpdateIndex());
 			assertFalse(rc.next());
 		}
 	}
@@ -216,6 +218,7 @@
 			assertEquals(exp.getName(), act.getName());
 			assertEquals(exp.getObjectId(), act.getObjectId());
 			assertEquals(exp.getPeeledObjectId(), act.getPeeledObjectId());
+			assertEquals(0, act.getUpdateIndex());
 		}
 	}
 
@@ -237,6 +240,7 @@
 			assertNotNull(act.getLeaf());
 			assertEquals(MASTER, act.getTarget().getName());
 			assertNull(act.getObjectId());
+			assertEquals(0, act.getUpdateIndex());
 		}
 	}
 
@@ -250,14 +254,17 @@
 		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 @@
 		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 @@
 			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 @@
 			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 @@
 			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 @@
 			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 @@
 			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 @@
 		}
 	}
 
-
 	private static void assertScan(List<Ref> refs, Reftable t)
 			throws IOException {
 		try (RefCursor rc = t.allRefs()) {
@@ -663,6 +677,7 @@
 				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 @@
 				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 @@
 
 	@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 @@
 		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 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 @@
 	}
 
 	@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/RacyGitTests.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RacyGitTests.java
index bb24994..11100b6 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RacyGitTests.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RacyGitTests.java
@@ -46,7 +46,6 @@
 import static java.nio.charset.StandardCharsets.UTF_8;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
-import static org.junit.Assume.assumeTrue;
 
 import java.io.File;
 import java.io.FileOutputStream;
@@ -63,8 +62,8 @@
 
 public class RacyGitTests extends RepositoryTestCase {
 	@Test
-	public void testIterator() throws IllegalStateException, IOException,
-			InterruptedException {
+	public void testIterator()
+			throws IllegalStateException, IOException, InterruptedException {
 		TreeSet<Long> modTimes = new TreeSet<>();
 		File lastFile = null;
 		for (int i = 0; i < 10; i++) {
@@ -128,9 +127,6 @@
 
 	@Test
 	public void testRacyGitDetection() throws Exception {
-		TreeSet<Long> modTimes = new TreeSet<>();
-		File lastFile;
-
 		// Reset to force creation of index file
 		try (Git git = new Git(db)) {
 			git.reset().call();
@@ -138,45 +134,44 @@
 
 		// wait to ensure that modtimes of the file doesn't match last index
 		// file modtime
-		modTimes.add(valueOf(fsTick(db.getIndexFile())));
+		fsTick(db.getIndexFile());
 
 		// create two files
-		addToWorkDir("a", "a");
-		lastFile = addToWorkDir("b", "b");
+		File a = addToWorkDir("a", "a");
+		File b = addToWorkDir("b", "b");
+		assertTrue(a.setLastModified(b.lastModified()));
+		assertTrue(b.setLastModified(b.lastModified()));
 
 		// wait to ensure that file-modTimes and therefore index entry modTime
 		// doesn't match the modtime of index-file after next persistance
-		modTimes.add(valueOf(fsTick(lastFile)));
+		fsTick(b);
 
 		// now add both files to the index. No racy git expected
-		resetIndex(new FileTreeIteratorWithTimeControl(db, modTimes));
+		resetIndex(new FileTreeIterator(db));
 
 		assertEquals(
-				"[a, mode:100644, time:t0, length:1, content:a]" +
-				"[b, mode:100644, time:t0, length:1, content:b]",
+				"[a, mode:100644, time:t0, length:1, content:a]"
+						+ "[b, mode:100644, time:t0, length:1, content:b]",
 				indexState(SMUDGE | MOD_TIME | LENGTH | CONTENT));
 
-		// Remember the last modTime of index file. All modifications times of
-		// further modification are translated to this value so it looks that
-		// files have been modified in the same time slot as the index file
-		long indexMod = db.getIndexFile().lastModified();
-		modTimes.add(Long.valueOf(indexMod));
+		// wait to ensure the file 'a' is updated at t1.
+		fsTick(db.getIndexFile());
 
-		// modify one file
-		long aMod = addToWorkDir("a", "a2").lastModified();
-		assumeTrue(aMod == indexMod);
-
-		// now update the index the index. 'a' has to be racily clean -- because
-		// it's modification time is exactly the same as the previous index file
-		// mod time.
-		resetIndex(new FileTreeIteratorWithTimeControl(db, modTimes));
+		// Create a racy git situation. This is a situation that the index is
+		// updated and then a file is modified within a second. By changing the
+		// index file artificially, we create a fake racy situation.
+		File updatedA = addToWorkDir("a", "a2");
+		assertTrue(updatedA.setLastModified(updatedA.lastModified() + 100));
+		resetIndex(new FileTreeIterator(db));
+		assertTrue(db.getIndexFile()
+				.setLastModified(updatedA.lastModified() + 90));
 
 		db.readDirCache();
 		// although racily clean a should not be reported as being dirty
 		assertEquals(
-				"[a, mode:100644, time:t1, smudged, length:0, content:a2]" +
-				"[b, mode:100644, time:t0, length:1, content:b]",
-				indexState(SMUDGE|MOD_TIME|LENGTH|CONTENT));
+				"[a, mode:100644, time:t1, smudged, length:0, content:a2]"
+						+ "[b, mode:100644, time:t0, length:1, content:b]",
+				indexState(SMUDGE | MOD_TIME | LENGTH | CONTENT));
 	}
 
 	private File addToWorkDir(String path, String content) throws IOException {
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 @@
 		}
 
 		@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 @@
 	@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 @@
 	@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 @@
 
 	@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 @@
 
 	@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 @@
 		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 @@
 		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 @@
 		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 @@
 		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 8ca5d45..f6fc00c 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
@@ -1069,7 +1069,7 @@
 		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)
@@ -1360,14 +1360,15 @@
 	}
 
 	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 @@
 				.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 @@
 				.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 @@
 		assertFalse(gen.next());
 	}
 
-	@SuppressWarnings("resource" /* java 7 */)
 	@Test
 	public void repositoryWithRootLevelSubmoduleAbsoluteRef()
 			throws IOException, ConfigInvalidException {
@@ -189,17 +188,16 @@
 		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 @@
 		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 @@
 
 	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 @@
 		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 @@
 
 	@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 @@
 	@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 @@
 
 	@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 @@
 
 	@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 @@
 
 	@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 @@
 
 	@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 @@
 
 	@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 @@
 
 	@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 @@
 
 	@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 @@
 
 	@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 @@
 
 		// 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 @@
 		// 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 @@
 	@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 @@
 				.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 @@
 
 	@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 @@
 			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 @@
 		}
 	}
 
-	@SuppressWarnings("resource" /* java 7 */)
 	@Test
 	public void testFlush() throws IOException {
 		final int[] flushCnt = new int[1];
@@ -190,7 +189,10 @@
 			}
 		};
 
-		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 @@
 				}, 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 @@
 		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 @@
 		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 @@
 		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 @@
 	@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 @@
 		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 @@
 
 		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 @@
 		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 @@
 		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 @@
 		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 @@
 		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 @@
 		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 @@
 		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 @@
 
 		// 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 @@
 		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 @@
 
 		// 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 @@
 		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 @@
 		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 @@
 		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 @@
 		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 @@
 		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 @@
 		// ... 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 @@
 		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 @@
 		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 33e32cd..6f61912 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 org.eclipse.jgit.api.Git;
@@ -666,9 +668,23 @@
 	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 59c8e31..6dfa6ef 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
@@ -46,12 +46,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;
@@ -99,16 +101,17 @@
 	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.lastModified(link) > 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));
@@ -128,6 +131,32 @@
 	}
 
 	@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 @@
 
 	@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 @@
 
 	@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 @@
 
 	@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 @@
 				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..a0a4396 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.2.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.2"
+Import-Package: org.eclipse.jgit.errors;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.lib;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.nls;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.revplot;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.revwalk;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.transport;version="[5.3.2,5.4.0)",
+ org.eclipse.jgit.util;version="[5.3.2,5.4.0)"
diff --git a/org.eclipse.jgit.ui/pom.xml b/org.eclipse.jgit.ui/pom.xml
index 0cb3d65..70e66f6 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.2-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 4131901..eb93d3e 100644
--- a/org.eclipse.jgit/.settings/.api_filters
+++ b/org.eclipse.jgit/.settings/.api_filters
@@ -3,8 +3,8 @@
     <resource path="META-INF/MANIFEST.MF">
         <filter id="924844039">
             <message_arguments>
-                <message_argument value="5.2.3"/>
-                <message_argument value="5.2.0"/>
+                <message_argument value="5.3.2"/>
+                <message_argument value="5.3.0"/>
             </message_arguments>
         </filter>
     </resource>
@@ -78,29 +78,9 @@
             </message_arguments>
         </filter>
     </resource>
-    <resource path="src/org/eclipse/jgit/transport/TransferConfig.java" type="org.eclipse.jgit.transport.TransferConfig">
-        <filter id="1159725059">
-            <message_arguments>
-                <message_argument value="5.1.4"/>
-                <message_argument value="TransferConfig(Config)"/>
-            </message_arguments>
-        </filter>
-        <filter id="1159725059">
-            <message_arguments>
-                <message_argument value="5.1.4"/>
-                <message_argument value="TransferConfig(Repository)"/>
-            </message_arguments>
-        </filter>
-    </resource>
     <resource path="src/org/eclipse/jgit/util/FS.java" type="org.eclipse.jgit.util.FS">
         <filter id="1142947843">
             <message_arguments>
-                <message_argument value="4.5.6"/>
-                <message_argument value="fileAttributes(File)"/>
-            </message_arguments>
-        </filter>
-        <filter id="1142947843">
-            <message_arguments>
                 <message_argument value="5.2.3"/>
                 <message_argument value="getFsTimerResolution(Path)"/>
             </message_arguments>
diff --git a/org.eclipse.jgit/BUILD b/org.eclipse.jgit/BUILD
index 6ba7796..b67bfac 100644
--- a/org.eclipse.jgit/BUILD
+++ b/org.eclipse.jgit/BUILD
@@ -22,6 +22,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 b03ff4a..1c3f8aa 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.2.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.2",
+ org.eclipse.jgit.api;version="5.3.2";
   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.2";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.errors",
+ org.eclipse.jgit.attributes;version="5.3.2",
+ org.eclipse.jgit.blame;version="5.3.2";
   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.2";
   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.2";
   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.2";
   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.2";uses:="org.eclipse.jgit.lib",
+ org.eclipse.jgit.fnmatch;version="5.3.2",
+ org.eclipse.jgit.gitrepo;version="5.3.2";
   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.2";x-internal:=true,
+ org.eclipse.jgit.hooks;version="5.3.2";uses:="org.eclipse.jgit.lib",
+ org.eclipse.jgit.ignore;version="5.3.2",
+ org.eclipse.jgit.ignore.internal;version="5.3.2";x-friends:="org.eclipse.jgit.test",
+ org.eclipse.jgit.internal;version="5.3.2";x-friends:="org.eclipse.jgit.test,org.eclipse.jgit.http.test",
+ org.eclipse.jgit.internal.fsck;version="5.3.2";x-friends:="org.eclipse.jgit.test",
+ org.eclipse.jgit.internal.ketch;version="5.3.2";x-friends:="org.eclipse.jgit.junit,org.eclipse.jgit.test,org.eclipse.jgit.pgm",
+ org.eclipse.jgit.internal.revwalk;version="5.3.2";x-internal:=true,
+ org.eclipse.jgit.internal.storage.dfs;version="5.3.2";
   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.2";
   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.2";x-friends:="org.eclipse.jgit.junit,org.eclipse.jgit.test,org.eclipse.jgit.pgm",
+ org.eclipse.jgit.internal.storage.pack;version="5.3.2";x-friends:="org.eclipse.jgit.junit,org.eclipse.jgit.test,org.eclipse.jgit.pgm",
+ org.eclipse.jgit.internal.storage.reftable;version="5.3.2";
   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.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.2";x-friends:="org.eclipse.jgit.junit,org.eclipse.jgit.test,org.eclipse.jgit.pgm",
+ org.eclipse.jgit.internal.submodule;version="5.3.2";x-internal:=true,
+ org.eclipse.jgit.internal.transport.parser;version="5.3.2";x-friends:="org.eclipse.jgit.http.server,org.eclipse.jgit.test",
+ org.eclipse.jgit.internal.transport.ssh;version="5.3.2";x-friends:="org.eclipse.jgit.ssh.apache",
+ org.eclipse.jgit.lib;version="5.3.2";
   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.2";x-internal:=true,
+ org.eclipse.jgit.merge;version="5.3.2";
   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.2",
+ org.eclipse.jgit.notes;version="5.3.2";
   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.2";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.diff",
+ org.eclipse.jgit.revplot;version="5.3.2";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.revwalk",
+ org.eclipse.jgit.revwalk;version="5.3.2";
   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.2";uses:="org.eclipse.jgit.revwalk,org.eclipse.jgit.lib,org.eclipse.jgit.util",
+ org.eclipse.jgit.storage.file;version="5.3.2";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.util",
+ org.eclipse.jgit.storage.pack;version="5.3.2";uses:="org.eclipse.jgit.lib",
+ org.eclipse.jgit.submodule;version="5.3.2";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.treewalk.filter,org.eclipse.jgit.treewalk",
+ org.eclipse.jgit.transport;version="5.3.2";
   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.2";uses:="javax.net.ssl",
+ org.eclipse.jgit.transport.resolver;version="5.3.2";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.transport",
+ org.eclipse.jgit.treewalk;version="5.3.2";
   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.2";uses:="org.eclipse.jgit.treewalk",
+ org.eclipse.jgit.util;version="5.3.2";
   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.2",
+ org.eclipse.jgit.util.sha1;version="5.3.2",
+ org.eclipse.jgit.util.time;version="5.3.2"
 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..f62ca38 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.2.qualifier
+Eclipse-SourceBundle: org.eclipse.jgit;version="5.3.2.qualifier";roots="."
diff --git a/org.eclipse.jgit/pom.xml b/org.eclipse.jgit/pom.xml
index c74e26f..4cbccc4 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.2-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 12fded8..51910f8 100644
--- a/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties
+++ b/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties
@@ -223,6 +223,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
@@ -301,7 +302,7 @@
 expectedPktLineWithService=expected pkt-line with ''# service=-'', got ''{0}''
 expectedReceivedContentType=expected Content-Type {0}; received Content-Type {1}
 expectedReportForRefNotReceived={0}: expected report for ref {1} not received
-failedAtomicFileCreation=Atomic file creation failed, number of hard links to file {0} was not 2 but {1}"
+failedAtomicFileCreation=Atomic file creation failed, number of hard links to file {0} was not 2 but {1}
 failedToDetermineFilterDefinition=An exception occurred while determining filter definitions
 failedUpdatingRefs=failed updating refs
 failureDueToOneOfTheFollowing=Failure due to one of the following:
@@ -323,6 +324,14 @@
 gcLogExists=A previous GC run reported an error: ''{0}''.  Automatic gc will fail until ''{1}'' is removed.
 gcTooManyUnpruned=Too many loose, unpruneable objects after garbage collection.  Consider adjusting gc.auto or gc.pruneExpire.
 gitmodulesNotFound=.gitmodules not found in tree.
+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
@@ -505,6 +514,7 @@
 onlyAlreadyUpToDateAndFastForwardMergesAreAvailable=only already-up-to-date and fast forward merges are available
 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
@@ -580,8 +590,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
@@ -620,7 +631,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}
@@ -716,6 +727,7 @@
 unableToRemovePath=Unable to remove path ''{0}''
 unableToStore=Unable to store {0}.
 unableToWrite=Unable to write {0}
+unableToSignCommitNoSecretKey=Unable to sign commit. Signing key not available.
 unauthorized=Unauthorized
 underflowedReftableBlock=Underflowed reftable block
 unencodeableFile=Unencodable file: {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 String name;
 
-	private boolean force = false;
+	private boolean forceRefUpdate = false;
+
+	private boolean forced = false;
 
 	private boolean createBranch = false;
 
@@ -269,7 +271,11 @@
 			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 @@
 				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 @@
 	 *            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 73af8ba..0248ba2 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 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 @@
 	}
 
 	/**
-	 * 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 @@
 	}
 
 	/**
-	 * 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 d07532c..9f071c4 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 @@
 
 	private Boolean allowEmpty;
 
+	private Boolean signCommit;
+
+	private String signingKey;
+
+	private GpgSigner gpgSigner;
+
+	private CredentialsProvider credentialsProvider;
+
 	/**
 	 * Constructor for CommitCommand
 	 *
@@ -147,6 +161,7 @@
 	 */
 	protected CommitCommand(Repository repo) {
 		super(repo);
+		this.credentialsProvider = CredentialsProvider.getDefault();
 	}
 
 	/**
@@ -251,6 +266,12 @@
 
 				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 @@
 	 *
 	 * @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 @@
 			// 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 @@
 		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 @@
 					// 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 @@
 
 	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 @@
 	/**
 	 * 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 @@
 				}
 				this.upstreamCommit = walk.parseCommit(repo
 						.resolve(upstreamCommitId));
-				preserveMerges = rebaseState.getRewrittenDir().exists();
+				preserveMerges = rebaseState.getRewrittenDir().isDirectory();
 				break;
 			case BEGIN:
 				autoStash();
@@ -1120,10 +1127,14 @@
 
 		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 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 @@
 				// update the HEAD
 				res = refUpdate.link(headName);
 			} else {
-				refUpdate.setNewObjectId(repo.readOrigHead());
+				refUpdate.setNewObjectId(origHead);
 				res = refUpdate.forceUpdate();
 
 			}
@@ -1400,6 +1411,19 @@
 		}
 	}
 
+	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 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 @@
 			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 @@
 	 *
 	 * @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 @@
 
 		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 @@
 	 *
 	 * @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 @@
 	 *
 	 * @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 @@
 	 * @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 @@
 
 		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 @@
 				} 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 @@
 				} 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 @@
 			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 @@
 					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 @@
 					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 @@
 				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 @@
 	}
 
 	/**
-	 * 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 @@
 	}
 
 	/**
-	 * 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 01d070c..2136e51 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 @@
 
 	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 @@
 					.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 @@
 						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 @@
 	 *
 	 * @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 @@
 	 * @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 @@
 	}
 
 	/**
+	 * 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 @@
 	 * 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 @@
 	 * 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 db6073f..307fd3f 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java
@@ -155,9 +155,11 @@
 
 	private boolean failOnConflict = true;
 
+	private boolean force = false;
+
 	private ArrayList<String> toBeDeleted = new ArrayList<>();
 
-	private boolean emptyDirCache;
+	private boolean initialCheckout;
 
 	private boolean performingCheckout;
 
@@ -230,7 +232,7 @@
 		this.headCommitTree = headCommitTree;
 		this.mergeCommitTree = mergeCommitTree;
 		this.workingTree = workingTree;
-		this.emptyDirCache = (dc == null) || (dc.getEntryCount() == 0);
+		this.initialCheckout = !repo.isBare() && !repo.getIndexFile().exists();
 	}
 
 	/**
@@ -427,11 +429,11 @@
 					DirCacheEntry entry = i.getDirCacheEntry();
 					if (entry.getLastModified() == 0)
 						entry.setLastModified(f.getEntryLastModified());
-					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
@@ -821,14 +823,14 @@
 
 				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;
@@ -858,7 +860,7 @@
 					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))
@@ -878,7 +880,7 @@
 					conflict(name, dce, h, m);
 				break;
 			default:
-				keep(dce);
+				keep(dce, f);
 			}
 			return;
 		}
@@ -961,10 +963,10 @@
 				// 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);
 			}
@@ -1027,7 +1029,7 @@
 						// 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
@@ -1176,7 +1178,7 @@
 					// to the other one.
 					// -> In all three cases we don't touch index and file.
 
-					keep(dce);
+					keep(dce, f);
 				}
 			}
 		}
@@ -1225,9 +1227,15 @@
 		}
 	}
 
-	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) {
@@ -1262,6 +1270,20 @@
 	}
 
 	/**
+	 * 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 @@
 		 *            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 @@
 		 *            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 8f884b4..018b643 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java
@@ -284,6 +284,7 @@
 	/***/ public String createNewFileFailed;
 	/***/ public String createRequiresZeroOldId;
 	/***/ public String credentialPassword;
+	/***/ public String credentialPassphrase;
 	/***/ public String credentialUsername;
 	/***/ public String daemonAlreadyRunning;
 	/***/ public String daysAgo;
@@ -384,6 +385,14 @@
 	/***/ public String gcLogExists;
 	/***/ public String gcTooManyUnpruned;
 	/***/ public String gitmodulesNotFound;
+	/***/ 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;
@@ -566,6 +575,7 @@
 	/***/ public String onlyAlreadyUpToDateAndFastForwardMergesAreAvailable;
 	/***/ public String onlyOneFetchSupported;
 	/***/ public String onlyOneOperationCallPerConnectionIsSupported;
+	/***/ public String onlyOpenPgpSupportedForSigning;
 	/***/ public String openFilesMustBeAtLeast1;
 	/***/ public String openingConnection;
 	/***/ public String operationCanceled;
@@ -641,8 +651,9 @@
 	/***/ 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;
@@ -681,7 +692,7 @@
 	/***/ public String sequenceTooLargeForDiffAlgorithm;
 	/***/ public String serviceNotEnabledNoName;
 	/***/ public String serviceNotPermitted;
-	/***/ public String sha1CollisionDetected1;
+	/***/ public String sha1CollisionDetected;
 	/***/ public String shallowCommitsAlreadyInitialized;
 	/***/ public String shallowPacksRequireDepthWalk;
 	/***/ public String shortCompressedStreamAt;
@@ -776,6 +787,7 @@
 	/***/ public String unableToRemovePath;
 	/***/ public String unableToStore;
 	/***/ public String unableToWrite;
+	/***/ public String unableToSignCommitNoSecretKey;
 	/***/ public String unauthorized;
 	/***/ public String underflowedReftableBlock;
 	/***/ public String unencodeableFile;
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 @@
 	}
 
 	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 @@
 
 			return new DfsBlock(key, pos, buf);
 		} finally {
-			if (rc != fileChannel) {
-				rc.close();
-			}
 			ctx.stats.readBlockMicros += elapsedMicros(start);
 		}
 	}
@@ -211,4 +207,37 @@
 	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 @@
 	/** 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 @@
 	/** 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 @@
 		statMiss = new AtomicReference<>(newCounters());
 		statEvict = new AtomicReference<>(newCounters());
 		liveBytes = new AtomicReference<>(newCounters());
+
+		refLockWaitTime = cfg.getRefLockWaitTimeConsumer();
 	}
 
 	boolean shouldCopyThroughCache(long length) {
@@ -333,15 +355,17 @@
 	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 @@
 	 * @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 @@
 			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 @@
 			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 @@
 
 		// 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 @@
 		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 @@
 		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 @@
 			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 @@
 	@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 @@
 		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 @@
 		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 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 @@
 
 		T get() {
 			T v = value;
-			if (v != null)
+			if (v != null) {
 				hot = true;
+			}
 			return v;
 		}
 
@@ -658,4 +744,21 @@
 			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 @@
 	private double streamRatio;
 	private int concurrencyLevel;
 
+	private Consumer<Long> refLock;
+
 	/**
 	 * Create a default configuration.
 	 */
@@ -194,6 +197,27 @@
 	}
 
 	/**
+	 * 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 @@
 	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 @@
 	 * @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 @@
 	}
 
 	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 @@
 				.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 @@
 	}
 
 	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 @@
 			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 @@
 						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 @@
 
 					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 @@
 					}
 					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 @@
 					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 @@
 			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 @@
 				}
 
 				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 @@
 	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 @@
 
 			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 @@
 
 			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 @@
 
 		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 @@
 		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 @@
 
 	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 @@
 
 	/** {@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 @@
 				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 @@
 
 	/** {@inheritDoc} */
 	@Override
+	public boolean hasVersioning() {
+		return true;
+	}
+
+	/** {@inheritDoc} */
+	@Override
 	public boolean performsAtomicTransactions() {
 		return true;
 	}
@@ -223,18 +229,6 @@
 
 	/** {@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 3c830e8..00124bc 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 @@
 	 *
 	 * @param e
 	 *            the executor to be used for running auto-gc
-	 * @since 4.8
 	 */
 	public static void setExecutor(ExecutorService e) {
 		executor = e;
@@ -915,7 +914,8 @@
 		// 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 @@
 	 * <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 @@
 		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 @@
 			// 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 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 @@
 		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 8cf1d4e..e8fac51 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
@@ -146,7 +146,7 @@
 	 * 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 @@
 	/** 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 @@
 
 	/**
 	 * @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 @@
 		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 @@
 	 * <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 @@
 		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 final PriorityQueue<RefQueueEntry> queue;
 		private RefQueueEntry head;
 		private Ref ref;
-		private long updateIndex;
 
 		MergedRefCursor() {
 			queue = new PriorityQueue<>(queueSize(), RefQueueEntry::compare);
@@ -206,7 +205,6 @@
 				}
 
 				ref = t.rc.getRef();
-				updateIndex = t.rc.getUpdateIndex();
 				boolean include = includeDeletes || !t.rc.wasDeleted();
 				add(t);
 				skipShadowedRefs(ref.getName());
@@ -242,11 +240,6 @@
 		}
 
 		@Override
-		public long getUpdateIndex() {
-			return updateIndex;
-		}
-
-		@Override
 		public void close() {
 			if (head != null) {
 				head.rc.close();
@@ -285,7 +278,7 @@
 		}
 
 		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 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 @@
 		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 @@
 	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 final boolean prefix;
 
 		private Ref ref;
-		private long updateIndex;
 		BlockReader block;
 
 		RefCursorImpl(long scanEnd, byte[] match, boolean prefix) {
@@ -508,8 +507,7 @@
 					return false;
 				}
 
-				updateIndex = minUpdateIndex + block.readUpdateIndexDelta();
-				ref = block.readRef();
+				ref = block.readRef(minUpdateIndex);
 				if (!includeDeletes && wasDeleted()) {
 					continue;
 				}
@@ -523,11 +521,6 @@
 		}
 
 		@Override
-		public long getUpdateIndex() {
-			return updateIndex;
-		}
-
-		@Override
 		public void close() {
 			// Do nothing.
 		}
@@ -605,7 +598,6 @@
 		private final ObjectId match;
 
 		private Ref ref;
-		private long updateIndex;
 		private int listIdx;
 
 		private LongList blockPos;
@@ -679,8 +671,7 @@
 				}
 
 				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 @@
 		}
 
 		@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 @@
 
 	/** {@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 @@
 		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 @@
 
 	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 @@
 
 	private PersonIdent committer;
 
+	private GpgSignature gpgSignature;
+
 	private String message;
 
 	private Charset encoding;
@@ -108,7 +116,7 @@
 	}
 
 	/**
-	 * 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 @@
 	}
 
 	/**
-	 * 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 @@
 	}
 
 	/**
+	 * 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 @@
 	}
 
 	/**
-	 * 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 @@
 			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 @@
 	}
 
 	/**
+	 * 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 @@
 		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 @@
 	 *            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 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 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 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 @@
 
 	private final ObjectId objectId;
 
+	private final long updateIndex;
+
 	/**
 	 * Create a new ref pairing.
 	 *
@@ -162,12 +224,17 @@
 	 * @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 @@
 		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 @@
 		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 @@
 	 */
 	@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 @@
 	/**
 	 * 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 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 @@
 	}
 
 	/**
+	 * 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 @@
 	 * @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 @@
 	 * @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 @@
 	 * <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 @@
 	 *             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 @@
 				: 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 @@
 			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 @@
 			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 @@
 	/**
 	 * 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 @@
 	 *            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 @@
 			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 @@
 	 *
 	 * @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 @@
 	 */
 	@Nullable
 	public final Ref findRef(String name) throws IOException {
-		return getRefDatabase().getRef(name);
+		return getRefDatabase().findRef(name);
 	}
 
 	/**
@@ -1103,7 +1105,7 @@
 		try {
 			return getRefDatabase().getRefs(RefDatabase.ALL);
 		} catch (IOException e) {
-			return new HashMap<>();
+			throw new UncheckedIOException(e);
 		}
 	}
 
@@ -1121,7 +1123,7 @@
 		try {
 			return getRefDatabase().getRefs(Constants.R_TAGS);
 		} catch (IOException e) {
-			return new HashMap<>();
+			throw new UncheckedIOException(e);
 		}
 	}
 
@@ -1320,9 +1322,7 @@
 					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 @@
 					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 @@
 					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 @@
 
 	private final Ref target;
 
+	private final long updateIndex;
+
 	/**
 	 * Create a new ref pairing.
 	 *
@@ -69,6 +71,25 @@
 	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 @@
 		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 @@
 		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 @@
 
 	/**
 	 * 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 412d9bb..9ea1868 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java
@@ -1024,13 +1024,16 @@
 			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 @@
 	/**
 	 * 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 @@
 			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 @@
 	 *
 	 * @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 @@
 	 * 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 @@
 	 *         <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 @@
 	 *
 	 * @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 @@
 	 * 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 @@
 	}
 
 	/**
-	 * 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 @@
 	}
 
 	/**
-	 * 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 @@
 	 * <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 @@
 	 *
 	 * @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 @@
 			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 @@
 		 *            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 @@
 	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 @@
 	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 @@
 
 	private PushCertificateParser pushCertificateParser;
 	private SignedPushConfig signedPushConfig;
-	private PushCertificate pushCert;
+	PushCertificate pushCert;
 	private ReceivedPackStatistics stats;
 
 	/**
@@ -289,10 +286,10 @@
 	 * @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 @@
 	 * @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 @@
 	 * 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 @@
 	 *            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 @@
 
 				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 @@
 						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 @@
 		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 @@
 					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 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 @@
 			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 @@
 	 *            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 @@
 		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 @@
 			long inflatedSize) throws IOException;
 
 	/**
-	 * Event notifying the the current object.
+	 * Event notifying the current object.
 	 *
 	 *@param info
 	 *            object information.
@@ -1616,7 +1616,7 @@
 			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 @@
 	}
 
 	/**
+	 * 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 @@
 			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 @@
 	 *            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 @@
 	 *            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 @@
 	 * @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 @@
 	 * @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 @@
 	 * @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 @@
 	 *            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 @@
 	 *            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 @@
 	 *            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 @@
 	}
 
 	/**
-	 * 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 @@
 				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 @@
 				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 @@
 		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 @@
 			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 @@
 	}
 
 	/**
+	 * 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 @@
 						: 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 @@
 				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 @@
 	/**
 	 * 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 1fa1db5..b768acd 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeIterator.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeIterator.java
@@ -74,6 +74,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;
@@ -1471,9 +1472,18 @@
 	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:
@@ -1490,6 +1500,59 @@
 		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 8795329..716711e 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
@@ -48,6 +48,7 @@
 import java.io.InputStreamReader;
 import java.io.PrintStream;
 import java.nio.charset.Charset;
+import java.nio.file.AccessDeniedException;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
@@ -399,8 +400,9 @@
 			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;
@@ -463,7 +465,8 @@
 				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 @@
 		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 @@
 	 * 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/SystemReader.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/SystemReader.java
index 953c976..7497750 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/SystemReader.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/SystemReader.java
@@ -101,7 +101,7 @@
 		public FileBasedConfig openSystemConfig(Config parent, FS fs) {
 			File configFile = fs.getGitSystemConfig();
 			if (configFile == null) {
-				return new FileBasedConfig(null, fs) {
+				return new FileBasedConfig(parent, null, fs) {
 					@Override
 					public void load() {
 						// empty, do not load
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 @@
 	}
 
 	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 @@
 	}
 
 	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 @@
 
 		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 Sha1CollisionException(ObjectId id) {
 		super(MessageFormat.format(
-				JGitText.get().sha1CollisionDetected1,
+				JGitText.get().sha1CollisionDetected,
 				id.name()));
 	}
 }
diff --git a/pom.xml b/pom.xml
index 25fa24d..db556bf 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.2-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.54</jsch-version>
     <jzlib-version>1.1.1</jzlib-version>
@@ -193,16 +193,17 @@
     <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.13.0</japicmp-version>
-    <httpclient-version>4.5.5</httpclient-version>
-    <httpcore-version>4.4.9</httpcore-version>
+    <httpclient-version>4.5.6</httpclient-version>
+    <httpcore-version>4.4.10</httpcore-version>
     <slf4j-version>1.7.2</slf4j-version>
     <log4j-version>1.2.15</log4j-version>
-    <maven-javadoc-plugin-version>3.0.1</maven-javadoc-plugin-version>
-    <tycho-extras-version>1.2.0</tycho-extras-version>
+    <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>
-    <spotbugs-maven-plugin-version>3.1.8</spotbugs-maven-plugin-version>
+    <bouncycastle-version>1.60</bouncycastle-version>
+    <spotbugs-maven-plugin-version>3.1.11</spotbugs-maven-plugin-version>
     <maven-surefire-version>2.22.1</maven-surefire-version>
     <maven-compiler-plugin-version>3.8.0</maven-compiler-plugin-version>
     <maven-project-info-reports-plugin-version>3.0.0</maven-project-info-reports-plugin-version>
@@ -211,7 +212,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>
@@ -238,7 +239,7 @@
         <plugin>
           <groupId>org.apache.maven.plugins</groupId>
           <artifactId>maven-jar-plugin</artifactId>
-          <version>3.1.0</version>
+          <version>3.1.1</version>
           <configuration>
             <archive>
               <manifestEntries>
@@ -297,6 +298,7 @@
           <configuration>
             <forkCount>${test-fork-count}</forkCount>
             <reuseForks>true</reuseForks>
+            <argLine>@{argLine}</argLine>
           </configuration>
         </plugin>
 
@@ -364,7 +366,7 @@
         <plugin>
           <groupId>org.jacoco</groupId>
           <artifactId>jacoco-maven-plugin</artifactId>
-          <version>0.8.2</version>
+          <version>0.8.3</version>
         </plugin>
         <plugin>
           <groupId>org.apache.maven.plugins</groupId>
@@ -374,7 +376,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>
@@ -393,6 +395,12 @@
           <artifactId>maven-project-info-reports-plugin</artifactId>
           <version>${maven-project-info-reports-plugin-version}</version>
         </plugin>
+
+        <plugin>
+          <groupId>org.springframework.boot</groupId>
+          <artifactId>spring-boot-maven-plugin</artifactId>
+          <version>2.1.2.RELEASE</version>
+        </plugin>
       </plugins>
     </pluginManagement>
 
@@ -498,6 +506,7 @@
         <artifactId>jacoco-maven-plugin</artifactId>
         <executions>
           <execution>
+            <id>default-prepare-agent</id>
             <goals>
               <goal>prepare-agent</goal>
             </goals>
@@ -512,6 +521,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>
@@ -589,6 +630,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>
 
@@ -639,7 +698,7 @@
       <dependency>
         <groupId>org.tukaani</groupId>
         <artifactId>xz</artifactId>
-        <version>1.6</version>
+        <version>1.8</version>
         <optional>true</optional>
       </dependency>
 
@@ -708,6 +767,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>
 
@@ -783,14 +861,14 @@
               <dependency>
                 <groupId>org.codehaus.plexus</groupId>
                 <artifactId>plexus-compiler-javac-errorprone</artifactId>
-                <version>2.8.4</version>
+                <version>2.8.5</version>
               </dependency>
               <!-- override plexus-compiler-javac-errorprone's dependency on
                   Error Prone with the latest version -->
               <dependency>
                 <groupId>com.google.errorprone</groupId>
                 <artifactId>error_prone_core</artifactId>
-                <version>2.3.2</version>
+                <version>2.3.3</version>
               </dependency>
             </dependencies>
           </plugin>
@@ -823,12 +901,12 @@
               <dependency>
                 <groupId>org.codehaus.plexus</groupId>
                 <artifactId>plexus-compiler-eclipse</artifactId>
-                <version>2.8.4</version>
+                <version>2.8.5</version>
               </dependency>
               <dependency>
                 <groupId>org.eclipse.jdt</groupId>
                 <artifactId>ecj</artifactId>
-                <version>3.15.0</version>
+                <version>3.16.0</version>
               </dependency>
             </dependencies>
           </plugin>
@@ -938,6 +1016,8 @@
     <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>
   </modules>
 
 </project>
diff --git a/tools/BUILD b/tools/BUILD
index 9025e0a..f0342ad 100644
--- a/tools/BUILD
+++ b/tools/BUILD
@@ -14,8 +14,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 = [
@@ -23,61 +25,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}>};