Merge branch 'master' into stable-5.11

* master: (35 commits)
  [releng] japicmp: update last release version
  IgnoreNode: include path to file for invalid .gitignore patterns
  FastIgnoreRule: include bad pattern in log message
  init: add config option to set default for the initial branch name
  init: allow specifying the initial branch name for the new repository
  Fail clone if initial branch doesn't exist in remote repository
  GPG: fix reading unprotected old-format secret keys
  Update Orbit to S20210216215844
  Add missing bazel dependency for o.e.j.gpg.bc.test
  GPG: handle extended private key format
  dfs: handle short copies
  [GPG] Provide a factory for the BouncyCastleGpgSigner
  Fix boxing warnings
  GPG: compute the keygrip to find a secret key
  GPG signature verification via BouncyCastle
  Post commit hook failure should not cause commit failure
  Allow to define additional Hook classes outside JGit
  GitHook: use default charset for output and error streams
  GitHook: use generic OutputStream instead of PrintStream
  Update jetty to 9.4.36.v20210114
  ...

Change-Id: I1cf5ab262c67b986e82422c48dfc103e335d28cc
diff --git a/.bazelversion b/.bazelversion
index 8faff82..fcdb2e1 100644
--- a/.bazelversion
+++ b/.bazelversion
@@ -1 +1 @@
-4.0.0rc2
+4.0.0
diff --git a/BUILD b/BUILD
index be6dd76..184ab27 100644
--- a/BUILD
+++ b/BUILD
@@ -13,6 +13,8 @@
         "//org.eclipse.jgit.lfs:jgit-lfs",
         "//org.eclipse.jgit.lfs.server:jgit-lfs-server",
         "//org.eclipse.jgit.junit:junit",
+        "//org.eclipse.jgit.ssh.apache:ssh-apache",
+        "//org.eclipse.jgit.ssh.jsch:ssh-jsch",
     ],
     outs = ["all.zip"],
     cmd = " && ".join([
diff --git a/WORKSPACE b/WORKSPACE
index 768682d..224968a 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -111,26 +111,26 @@
 
 maven_jar(
     name = "httpclient",
-    artifact = "org.apache.httpcomponents:httpclient:4.5.10",
-    sha1 = "7ca2e4276f4ef95e4db725a8cd4a1d1e7585b9e5",
+    artifact = "org.apache.httpcomponents:httpclient:4.5.13",
+    sha1 = "e5f6cae5ca7ecaac1ec2827a9e2d65ae2869cada",
 )
 
 maven_jar(
     name = "httpcore",
-    artifact = "org.apache.httpcomponents:httpcore:4.4.12",
-    sha1 = "21ebaf6d532bc350ba95bd81938fa5f0e511c132",
+    artifact = "org.apache.httpcomponents:httpcore:4.4.14",
+    sha1 = "9dd1a631c082d92ecd4bd8fd4cf55026c720a8c1",
 )
 
 maven_jar(
     name = "sshd-osgi",
-    artifact = "org.apache.sshd:sshd-osgi:2.4.0",
-    sha1 = "fc4551c1eeda35e4671b263297d37d2bca81c4d4",
+    artifact = "org.apache.sshd:sshd-osgi:2.6.0",
+    sha1 = "40e365bb799e1bff3d31dc858b1e59a93c123f29",
 )
 
 maven_jar(
     name = "sshd-sftp",
-    artifact = "org.apache.sshd:sshd-sftp:2.4.0",
-    sha1 = "92e1b7d1e19c715efb4a8871d34145da8f87cdb2",
+    artifact = "org.apache.sshd:sshd-sftp:2.6.0",
+    sha1 = "6eddfe8fdf59a3d9a49151e4177f8c1bebeb30c9",
 )
 
 maven_jar(
@@ -237,55 +237,55 @@
     sha1 = "9180733b7df8542621dc12e21e87557e8c99b8cb",
 )
 
-JETTY_VER = "9.4.35.v20201120"
+JETTY_VER = "9.4.36.v20210114"
 
 maven_jar(
     name = "jetty-servlet",
     artifact = "org.eclipse.jetty:jetty-servlet:" + JETTY_VER,
-    sha1 = "3e61bcb471e1bfc545ce866cbbe33c3aedeec9b1",
-    src_sha1 = "e237af9dd6556756736fcdc7da00194fa00d3c2b",
+    sha1 = "b189e52a5ee55ae172e4e99e29c5c314f5daf4b9",
+    src_sha1 = "3a0fa449772ab0d76625f6afb81f60c32a490613",
 )
 
 maven_jar(
     name = "jetty-security",
     artifact = "org.eclipse.jetty:jetty-security:" + JETTY_VER,
-    sha1 = "80dc2f422789c78315de76d289b7a5b36c3232d5",
-    src_sha1 = "3c0d03191fdffd9cf1e46fa206d79eeb9e3adb90",
+    sha1 = "42030d6ed7dfc0f75818cde0adcf738efc477574",
+    src_sha1 = "612220a97d45fad3983ccc56b0cb9a271f3fd003",
 )
 
 maven_jar(
     name = "jetty-server",
     artifact = "org.eclipse.jetty:jetty-server:" + JETTY_VER,
-    sha1 = "513502352fd689d4730b2935421b990ada8cc818",
-    src_sha1 = "760d3574ebc7f9b9b1ba51242b9c1dda6fe5505b",
+    sha1 = "88a7d342974aadca658e7386e8d0fcc5c0788f41",
+    src_sha1 = "4552c0c6db2948e8557db477b6b48d291006e481",
 )
 
 maven_jar(
     name = "jetty-http",
     artifact = "org.eclipse.jetty:jetty-http:" + JETTY_VER,
-    sha1 = "45d35131a35a1e76991682174421e8cdf765fb9f",
-    src_sha1 = "491cd5b8abe8fe6f3db0086907a3f12440188e73",
+    sha1 = "1eee89a55e04ff94df0f85d95200fc48acb43d86",
+    src_sha1 = "552a784ec789c7ba581c5341ae6d8b6353ed5ace",
 )
 
 maven_jar(
     name = "jetty-io",
     artifact = "org.eclipse.jetty:jetty-io:" + JETTY_VER,
-    sha1 = "eb9460700b99b71ecd82a53697f5ff99f69b9e1c",
-    src_sha1 = "fed96a4559a49e7173dbe2d9d8e100d72aee2a10",
+    sha1 = "84a8faf9031eb45a5a2ddb7681e22c483d81ab3a",
+    src_sha1 = "72d5fc6d909e28f8720394b25babda80805a46b9",
 )
 
 maven_jar(
     name = "jetty-util",
     artifact = "org.eclipse.jetty:jetty-util:" + JETTY_VER,
-    sha1 = "ef61b83f9715c3b5355b633d9f01d2834f908ece",
-    src_sha1 = "8f178bebeb34c8365a06d854daa9b22da1b301d7",
+    sha1 = "925257fbcca6b501a25252c7447dbedb021f7404",
+    src_sha1 = "532e8b66044f4e58ca5da3aec19f02a2f3c16ddd",
 )
 
 maven_jar(
     name = "jetty-util-ajax",
     artifact = "org.eclipse.jetty:jetty-util-ajax:" + JETTY_VER,
-    sha1 = "ebbb43912c6423bedb3458e44aee28eeb4d66f27",
-    src_sha1 = "b3acea974a17493afb125a9dfbe783870ce1d2f9",
+    sha1 = "2f478130c21787073facb64d7242e06f94980c60",
+    src_sha1 = "7153d7ca38878d971fd90992c303bb7719ba7a21",
 )
 
 BOUNCYCASTLE_VER = "1.65"
diff --git a/lib/BUILD b/lib/BUILD
index b56ba2f..8ad49d4 100644
--- a/lib/BUILD
+++ b/lib/BUILD
@@ -162,6 +162,7 @@
         "//org.eclipse.jgit:__pkg__",
         "//org.eclipse.jgit.gpg.bc:__pkg__",
         "//org.eclipse.jgit.test:__pkg__",
+        "//org.eclipse.jgit.gpg.bc.test:__pkg__",
     ],
     exports = ["@bcpg//jar"],
 )
@@ -172,6 +173,7 @@
         "//org.eclipse.jgit:__pkg__",
         "//org.eclipse.jgit.gpg.bc:__pkg__",
         "//org.eclipse.jgit.test:__pkg__",
+        "//org.eclipse.jgit.gpg.bc.test:__pkg__",
     ],
     exports = ["@bcprov//jar"],
 )
diff --git a/org.eclipse.jgit.gpg.bc.test/.classpath b/org.eclipse.jgit.gpg.bc.test/.classpath
index f08af0a..0acccba 100644
--- a/org.eclipse.jgit.gpg.bc.test/.classpath
+++ b/org.eclipse.jgit.gpg.bc.test/.classpath
@@ -2,10 +2,15 @@
 <classpath>
 	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
 	<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
-	<classpathentry kind="src" path="tst">
+	<classpathentry kind="src" output="bin-tst" path="tst">
 		<attributes>
 			<attribute name="test" value="true"/>
 		</attributes>
 	</classpathentry>
-	<classpathentry kind="output" path="bin"/>
+	<classpathentry kind="src" output="bin-tst" path="tst-rsrc">
+		<attributes>
+			<attribute name="test" value="true"/>
+		</attributes>
+	</classpathentry>
+	<classpathentry kind="output" path="bin-tst"/>
 </classpath>
diff --git a/org.eclipse.jgit.gpg.bc.test/.gitignore b/org.eclipse.jgit.gpg.bc.test/.gitignore
index 934e0e0..8b6760c 100644
--- a/org.eclipse.jgit.gpg.bc.test/.gitignore
+++ b/org.eclipse.jgit.gpg.bc.test/.gitignore
@@ -1,2 +1,3 @@
 /bin
+/bin-tst
 /target
diff --git a/org.eclipse.jgit.gpg.bc.test/BUILD b/org.eclipse.jgit.gpg.bc.test/BUILD
index 1e3677d..925536e 100644
--- a/org.eclipse.jgit.gpg.bc.test/BUILD
+++ b/org.eclipse.jgit.gpg.bc.test/BUILD
@@ -1,4 +1,9 @@
 load(
+    "@com_googlesource_gerrit_bazlets//tools:genrule2.bzl",
+    "genrule2",
+)
+load("@rules_java//java:defs.bzl", "java_import")
+load(
     "@com_googlesource_gerrit_bazlets//tools:junit.bzl",
     "junit_tests",
 )
@@ -8,7 +13,23 @@
     srcs = glob(["tst/**/*.java"]),
     tags = ["bc"],
     deps = [
+        "//lib:bcpg",
+        "//lib:bcprov",
         "//lib:junit",
+        "//org.eclipse.jgit:jgit",
         "//org.eclipse.jgit.gpg.bc:gpg-bc",
+        "//org.eclipse.jgit.gpg.bc.test:tst_rsrc",
     ],
 )
+
+java_import(
+    name = "tst_rsrc",
+    jars = [":tst_rsrc_jar"],
+)
+
+genrule2(
+    name = "tst_rsrc_jar",
+    srcs = glob(["tst-rsrc/**"]),
+    outs = ["tst_rsrc.jar"],
+    cmd = "o=$$PWD/$@ && tar cf - $(SRCS) | tar -C $$TMP --strip-components=2 -xf - && cd  $$TMP && zip -qr $$o .",
+)
diff --git a/org.eclipse.jgit.gpg.bc.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.gpg.bc.test/META-INF/MANIFEST.MF
index 35a418c..57c3747 100644
--- a/org.eclipse.jgit.gpg.bc.test/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.gpg.bc.test/META-INF/MANIFEST.MF
@@ -7,8 +7,18 @@
 Bundle-Vendor: %Bundle-Vendor
 Bundle-Localization: plugin
 Bundle-RequiredExecutionEnvironment: JavaSE-1.8
-Import-Package: org.eclipse.jgit.gpg.bc.internal;version="[5.11.0,5.12.0)",
- org.junit;version="[4.13,5.0.0)"
-Export-Package: org.eclipse.jgit.gpg.bc.internal;x-internal:=true
+Import-Package: org.bouncycastle.jce.provider;version="[1.65.0,2.0.0)",
+ org.bouncycastle.openpgp;version="[1.65.0,2.0.0)",
+ org.bouncycastle.openpgp.operator;version="[1.65.0,2.0.0)",
+ org.bouncycastle.openpgp.operator.jcajce;version="[1.65.0,2.0.0)",
+ org.bouncycastle.util.encoders;version="[1.65.0,2.0.0)",
+ org.eclipse.jgit.gpg.bc.internal;version="[5.11.0,5.12.0)",
+ org.eclipse.jgit.gpg.bc.internal.keys;version="[5.11.0,5.12.0)",
+ org.eclipse.jgit.util.sha1;version="[5.11.0,5.12.0)",
+ org.junit;version="[4.13,5.0.0)",
+ org.junit.runner;version="[4.13,5.0.0)",
+ org.junit.runners;version="[4.13,5.0.0)"
+Export-Package: org.eclipse.jgit.gpg.bc.internal;x-internal:=true,
+ org.eclipse.jgit.gpg.bc.internal.keys;x-internal:=true
 Require-Bundle: org.hamcrest.core;bundle-version="[1.1.0,2.0.0)",
  org.hamcrest.library;bundle-version="[1.1.0,2.0.0)"
diff --git a/org.eclipse.jgit.gpg.bc.test/build.properties b/org.eclipse.jgit.gpg.bc.test/build.properties
index 9ffa0ca..e36d666 100644
--- a/org.eclipse.jgit.gpg.bc.test/build.properties
+++ b/org.eclipse.jgit.gpg.bc.test/build.properties
@@ -1,5 +1,5 @@
 source.. = tst/
-output.. = bin/
+output.. = bin-tst/
 bin.includes = META-INF/,\
                .,\
                plugin.properties
diff --git a/org.eclipse.jgit.gpg.bc.test/pom.xml b/org.eclipse.jgit.gpg.bc.test/pom.xml
index f244fb4..cac7e15 100644
--- a/org.eclipse.jgit.gpg.bc.test/pom.xml
+++ b/org.eclipse.jgit.gpg.bc.test/pom.xml
@@ -85,6 +85,12 @@
     <sourceDirectory>src/</sourceDirectory>
     <testSourceDirectory>tst/</testSourceDirectory>
 
+    <testResources>
+      <testResource>
+        <directory>tst-rsrc/</directory>
+      </testResource>
+    </testResources>
+
     <plugins>
       <plugin>
         <groupId>org.apache.maven.plugins</groupId>
diff --git a/org.eclipse.jgit.gpg.bc.test/tst-rsrc/org/eclipse/jgit/gpg/bc/internal/keys/2FB05DBB70FC07CB84C13431F640CA6CEA1DBF8A.asc b/org.eclipse.jgit.gpg.bc.test/tst-rsrc/org/eclipse/jgit/gpg/bc/internal/keys/2FB05DBB70FC07CB84C13431F640CA6CEA1DBF8A.asc
new file mode 100644
index 0000000..355462c
--- /dev/null
+++ b/org.eclipse.jgit.gpg.bc.test/tst-rsrc/org/eclipse/jgit/gpg/bc/internal/keys/2FB05DBB70FC07CB84C13431F640CA6CEA1DBF8A.asc
@@ -0,0 +1,41 @@
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+
+mQGNBGAHBLQBDACsS1vFqE3qgKD2R5X9n90Gz8bucwwvJWIqaHDsVoAtF6IcKIDo
+1hQC9YksTQYl/L7BsMDdmjyEbWRfzW4ory5596d342Hl6g7ZB5jJR5kJJdhy2MCJ
+BUiMy/724Fr/Dz8PNPcEoULz9ZH7HEaPRKqWWEQDUCq5ak0MfLKXtWVUBgsY5Mry
+29d/GLJvnxZ5v16PK+P4oqZ7vh7FWJPlqPK2TCZ6s1rYfWlu9XbHOzwXwozVg7IX
+tfFq4Rij4c0sg0S0GY8hGAlnOpRc/6J2S41Y8p3WqND6r1LPDQUFnNCKXVoHUGeK
+X9U5iAP7pxZSuonsFCqr3CDGxr+kKUpbfZeLrqTA4lBUK7T6w6Wq0qHosCYUU7YC
+GZjlEeCZBRWNfeq45LKlhdNUxHWWgaBsgWaaDmpFWaivblmQGOvmSv1nJMNmedRs
+DSF51nsJnkQceprsvThSa6qJwEYi7pj6L9HO2UGgJLCb3dL5VTQih2gdhghckUSB
+okUkvqBvvdiP2nEAEQEAAbQdVGVzdGVyMiA8dGVzdGVyMkBleGFtcGxlLm9yZz6J
+Ac4EEwEKADgWIQRPCAvglun3I2Bs1iITM2XBzCpwbgUCYAcEtAIbAwULCQgHAwUV
+CgkICwUWAgMBAAIeAQIXgAAKCRATM2XBzCpwboiBC/493+ruANV2eiro8MY8wZ3Y
+gdjp3pHBSg9RK74SIh95J+MW5qzPwkU+vHd8l0+aj9e1sDQb5BFcFk/Z1ioI3TDW
+B4vYWoMkdN932fJ/LcIlhOGjWwSNFZphbYmJzrAwUTA499yx3jt9Dg+vSU88S+8S
+FzYe6CBNt+PqDCbk6Gm+ZcVpR+elq/QJeyhdDzCCrrfNXwPwsVGAM61Z8SvdvNKE
+DA5gHXRsOKf8fu8lqW2Ay0MCvgsZLMIGOMDPCyBUd1bhlU0p18V6D6wdatfzu9gR
+X/k36HJyqB2cHh89/F2KdBSonRVRJOvHc/88zEeRFkiV5pUyrXv40l099+5dvA+2
+h4ODftY7ZbR22k4iX5rqj2BRow3H+N5lTIWgiADPUl+H8z4ZY5G+LWk9Xms3o1G9
+DmEepM3ma1pg4sZbxf0iStikch7aPvL/HgGRPJnDxA/W4KJxqmSw9TTMH/6XHq3D
+ah5Z1lbcylChgrFLFVJi+shnLTZSYttTeKOIqTPi0765AY0EYAcEtAEMANS23tqF
+Dr69wz0AaT7tjoccT/WlSO/gxd80ShMr4vbr21PZp8qGklFmlcrSrMDRwfXY04x2
+qxHR/Kf+hCD5gNvg8kh/yH2lQRcvekzQ4/rLmSXBfGOFg+LioQQ3CZJ1MZyIHzu5
+YVZ2pqALfJwJSw9P5Z340y8sq8AOPaJ+cpIC0rYBp9BUAmz9IeLVT7fUc6CjaWBo
+++E8H+9FyZC71RIPNcCvY+24Qky8ms7nw4hA47Dlht1pqL8dzOggCnohuSYMCXs2
+YPLvDGdZMg7GgQ3AyZawDmjTxFWt51VU5hunGfGiC5Aock8rVHSYsQzUFjVBSR+Y
+Zy+c4noxZD1eRfb8KdFnrewyVqGKFtc/JwA61qhhyYFe5AWMAFtudjGYG0WiTP82
+CmFFc1Qsvyls9G2yMkLuay5wsdIJMnRW9XwBzwxm0mdZI6D3nSbWjPUUfRcGBY8C
+Hqpc736G+UzMevZtorwy/5Q6D8v+Obrk02DIDKa6CJ7g7dTwK0I/fleJlwARAQAB
+iQG2BBgBCgAgFiEETwgL4Jbp9yNgbNYiEzNlwcwqcG4FAmAHBLQCGwwACgkQEzNl
+wcwqcG6mYQv8CFIVGj7/Qnr+wmviMzm8+B4WwQIUHGryqv9hnfp9hLOXMFmNuEDl
+QYkHVChWO7ehrR3fpvpebhcieV19skf/WO8xm0pGSXyjV2/0/bVhXq01xesXHH9r
+4aFxsCu0E8M9fZVAHP7NBr4A67knQ4EHRF6Rwml2ba6Zt2oP15IHvsAq/2B3f8ar
+5sUau4zM1cItG3tg49rbYr6V71HdgkWA22+EkbXL/Qq3haY/er2dIGc73lu8t7oQ
+msGK4LSAGc2661wMvJ6w6feCagkXAtrqyxodhSLoWgF3i0QVQnMbgmYWKEK2B6YA
+g669CZCCXJF+9Ebq+PP/d3Cy/k9iUmWDh72C7iL136kYZt+71b+yOmlDRT9l6DvU
+FP3bhRZWomOt3F3aP5mAdbwrP1NbvlxTYUAf++nUPdpr0Jrvgi67/VHVjaUtVh/K
+gVQ2C+4Cp/fllxXXKQMPcC8dD1x/AL6ytDzPu099ETMULntgbt7A5Lsd/fFScnF3
+ZNx6wjRReIvT
+=8E/K
+-----END PGP PUBLIC KEY BLOCK-----
diff --git a/org.eclipse.jgit.gpg.bc.test/tst-rsrc/org/eclipse/jgit/gpg/bc/internal/keys/2FB05DBB70FC07CB84C13431F640CA6CEA1DBF8A.key b/org.eclipse.jgit.gpg.bc.test/tst-rsrc/org/eclipse/jgit/gpg/bc/internal/keys/2FB05DBB70FC07CB84C13431F640CA6CEA1DBF8A.key
new file mode 100644
index 0000000..afa459c
--- /dev/null
+++ b/org.eclipse.jgit.gpg.bc.test/tst-rsrc/org/eclipse/jgit/gpg/bc/internal/keys/2FB05DBB70FC07CB84C13431F640CA6CEA1DBF8A.key
@@ -0,0 +1,42 @@
+Key: (private-key (rsa (n #00AC4B5BC5A84DEA80A0F64795FD9FDD06CFC6EE730C
+ 2F25622A6870EC56802D17A21C2880E8D61402F5892C4D0625FCBEC1B0C0DD9A3C846D
+ 645FCD6E28AF2E79F7A777E361E5EA0ED90798C947990925D872D8C08905488CCBFEF6
+ E05AFF0F3F0F34F704A142F3F591FB1C468F44AA96584403502AB96A4D0C7CB297B565
+ 54060B18E4CAF2DBD77F18B26F9F1679BF5E8F2BE3F8A2A67BBE1EC55893E5A8F2B64C
+ 267AB35AD87D696EF576C73B3C17C28CD583B217B5F16AE118A3E1CD2C8344B4198F21
+ 1809673A945CFFA2764B8D58F29DD6A8D0FAAF52CF0D05059CD08A5D5A0750678A5FD5
+ 398803FBA71652BA89EC142AABDC20C6C6BFA4294A5B7D978BAEA4C0E250542BB4FAC3
+ A5AAD2A1E8B0261453B6021998E511E09905158D7DEAB8E4B2A585D354C4759681A06C
+ 81669A0E6A4559A8AF6E599018EBE64AFD6724C36679D46C0D2179D67B099E441C7A9A
+ ECBD38526BAA89C04622EE98FA2FD1CED941A024B09BDDD2F955342287681D86085C91
+ 4481A24524BEA06FBDD88FDA71#)(e #010001#)(d
+  #208024A31FF0F6B3E5E91F2ED58572F1A67F1D9AD9290991BF732D1DFFE134E058E5
+ 9BE459478CC5D42058997CF7EC79E55A9CBF10A9AAC761E04A85A5AA0A07DAE61DD0E8
+ 36311534EE606D5392B42D8DEB7824B594280FDB2950D39886B58F0D24CE15F2FF88BA
+ 819B8F4566202B57A9F5C6743862FA80E7429C83CEA57B189ABE4AE657B28DAF7D6EA7
+ 6CA89635B9B6232EE14779452D636B919E707B92B13DA3229133A953DAF021E0928B83
+ 75EDEE98163C2189E22CE9A236C3D0EABD2608DAEF09211B2C77FFE9158A95F8EF2750
+ 221C5ADEDAED0446DC0E4CD8D38AD897D44FA3915934B6CF03F489DFAA6D939AB9F8EF
+ 1C2A0CDCFC3F2207D63A9EB55B09A0A45323D5F59AE4A9D48E819E98E53D04F022905A
+ 9C4D137F32CB33A974F202B0D3AD4AC64CFBA2A4C18650B671AB753D1D3BD7C4FCC8D2
+ 0F85D1876D89A3D94C77423778C08BDF8FBA23A8501D766FC1B4D51F2D4BB4C27B8491
+ CC2595FF54034F4F192D668C1934D292752A4E44C95135D29449B75928BAF1A2389ED9
+ #)(p #00CCD74AC0DC1CC46052F784DB19545A09FF904846247BAD1AFA5E00CE84A4DA
+ BFCD3BCA175508C068553226DBA49EDAFBCC33CF2A914F9006326FCB62C0473B1E93F6
+ DCF89A24006B090834E5686464A8C216B70AD797732E671ED78CD3E922161069E46BA7
+ 489F2A79CE46BDC4E6F5FCE97C3C9DC59399212235C53246609F8B7FDBF2AD191B3FB4
+ 4CC59760BA6D2029541811D1E9B72DC2ADC98513589A9715C82EE88ADF9000A41512C9
+ 6D491D2A30269FBFCD9CF5D2F275A1DBFFEEB72BE5#)(q
+  #00D7532ABA5F442A994ED8290AA71EAAB6F8137FE3F01488298637084157972D31EA
+ E9F495B4360A6E92ABA7C2418A5960DF29B8C8146CC7D1DF1201C17509D7315B6ECF86
+ F0A73C9F5B48D96F2108DD323FAE6BF897A8CB773EDCF5C82E203813945405F414E3F2
+ 99EEDE43EE6259FDED1C01B47C20F67AC488209585FE6FB7D958AF5EF567737E1ACCB4
+ E293724BE8AB6159CD5A6603FFEFC2DBC30FB6EAF647DBE7D9664ED0BBA1C4A2268AE3
+ DE0850572E145BA811EB2087E1E26490F9439D#)(u
+  #00A8026DB6685170EC05DA3574451678718501489843227BCEB772FDB86B20AB2F2A
+ 00B790A2373FD5DF7AD2CAA2E3896C4C9CBA08581F3644DF67743FA4BE1153421F8FB2
+ 47F0EFB64C566CB7E361BAB21CCAF029B43B7172232D11D14912BC035E17FB8BC663CA
+ 6766E6D2531F87AF378896A2AC7D98824AA8F51C5D6C11B7DC266209BCD3B23597F02B
+ A317CCAACC979402F84E47F3D143187F9739FE9A6C71829CC94E4003D70CFFA33AC0FA
+ A12776EFAFFB8261ABE664C6A6FAE623D3678F#)))
+Created: 20210119T161132
diff --git a/org.eclipse.jgit.gpg.bc.test/tst-rsrc/org/eclipse/jgit/gpg/bc/internal/keys/66CCECEC2AB46A9735B10FEC54EDF9FD0F77BAF9.asc b/org.eclipse.jgit.gpg.bc.test/tst-rsrc/org/eclipse/jgit/gpg/bc/internal/keys/66CCECEC2AB46A9735B10FEC54EDF9FD0F77BAF9.asc
new file mode 100644
index 0000000..362e210
--- /dev/null
+++ b/org.eclipse.jgit.gpg.bc.test/tst-rsrc/org/eclipse/jgit/gpg/bc/internal/keys/66CCECEC2AB46A9735B10FEC54EDF9FD0F77BAF9.asc
@@ -0,0 +1,42 @@
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+
+mQGNBGAHBAUBDADAzIW1FhCcQmP/NDhzXoeRQ+DNACqTed7eEhqm3rowkW4wKi56
+v1UxFR0ZoA3LoT1oQQjiL3IS2l4/qpBR3JQhMFH3pl7yBsCIrN7JvZfAvxq2Ud4e
+YbdonY8mv/yCLq+nkTWlHkWGCppKMm6DupEUw5CFUCiptPXIxikU0uQYB7VRtXhh
+Q1RGdsv6mcOwMIh7hj9flTrX025x0vRypjqgDR05RuM3hMMpJDGMAuf51w/lbRl9
+dAsJzFzg2cf+8qv92Gx3RuP3a3yl6pEuKnkpddC47lj2pvuhWZBf2sXZMyPvMIvA
+Dve4GIVj6k+wXE3DMp0xMy0Fvaxw5OORPxUAKNBR/BgjoRbkbjm+rJZzviu/XVPR
+42+78isvsa+lnEAmTeoTqiz9nlTTPN+6JjwJXYn2LuiFM8XzNPJwNmd/86lW1qbP
+DxZHhD9jjeXZNHUBUCKTIj2Rs2uFa0xrALdhhhGEao9JlVcUqz/Tw85qC+DlzSa3
+3re5C6wGe2pnW3sAEQEAAbRGVGVzdGVyICjDhG5kZXJ1bmdlbiBpbiBHUEcga8O2
+bm5lbiBGb2xnZW4gaGFiZW4hKSA8dGVzdGVyQGV4YW1wbGUub3JnPokBzgQTAQoA
+OBYhBPidC43dWzUvOqsRbzx6+72u3pDoBQJgBwQFAhsDBQsJCAcDBRUKCQgLBRYC
+AwEAAh4BAheAAAoJEDx6+72u3pDogeAL/iNn1aKxA7pKmucyuzcbzvUjtcbbqFL8
+lOLdRxkrQNCDMb+wHgGY1UqJ6wsDruhV+TdPLzUXHpCl731MeLxZyIENr4wnjTBf
+Cr4SU8eFUkusVf3aWK3rlk54W50EkfBjMvDVavRKNkVbCWAAwXZ7mTRf3UlWxg+F
+9Sq4j2P/hEZIznKV3y7zXLDYg0OpMZLgbo3si0CD19/1T/8Z9C680qSwyAiPtjRo
+vfJYqZFQc+ZH7j1Hmvg68d2Qwrkg/WMfOGoTLZq/6PQcM5leQBAodcS1t7C8o1JQ
+6D+f2gLHpMfFdUKh9TkmvnKYI20TWUVm9XQLqyAHsOn2vRMUhydcZ8OP103TKmP4
+mbpgiyp4i4S/7XofHSeFBrbdqt73ebubESuZVXNjTuuSUjH8Jq5nHq22ZrmotSd0
+FNwc9qQmwPG/gmOGq3rUdT/KzUVntc66QN/+hMhFDYMRJsjJhhyszvGuuBp6vBzI
+lMZqx5jqOaI9ON0m0o8CKC50sKdJ25G3wLkBjQRgBwQFAQwAqMXwgfSaIM+eSQWs
+xb4Sf2aCr/RZi5wzZz89lSomMcblqtCpuHv9/C1PSd+N/D1yJKzPChbDjHh6B6gc
+4OUvuDKHmxK+oAiURpvR+yJEdbSEYwiBhfAUD6u2q3IfY5PpyyZT3NjZ9EY8FpOX
+wpgdSOdSiZVZfZt0xUPsGbW/xP1yVR1NHYLuZX5P5oTCvyNJyP8zQQmToamJsvzR
+v9r+2sa5di9roe53kZwq24VjIvTDOOE4xoYEXk5UD83u1LA++9Nfdisxxts1bxgj
+w1ThO/IRTyY5y5bKSQPskYFD3eVz+azjVurqhbj6ep69mR2X2gjLCetz6G1l4PU2
+R6wcqVG6gR6XpGFPsN+M2JRtbgKrtMElA8egJIMMpH4hdXYqIqmpe/31zXhClHkO
+99EbBpk6OawZC+MnreQFN4NIK5uO2aLi+3KL1FFnNlFCXkh/8afbt4+6rHcWC6En
+q5W0ZkLZnpjdFOF5NPTinAdei+14gnf2QhIlFLeMHvqiVEXvABEBAAGJAbYEGAEK
+ACAWIQT4nQuN3Vs1LzqrEW88evu9rt6Q6AUCYAcEBQIbDAAKCRA8evu9rt6Q6DcX
+C/4orMX1YBZNJK5hLLdjfk45EsQDfCnhf8H991xd0Rq4VPJP6bvzikSdOn9bTUEz
+AAhA4JnFu9AMTh8ioOA7ZtViIccplFBivsxi3rAVrQvmCfoP2AdHfG/jB6D9uWGs
+MV5/o1p93Hr0ReO73HK6G4Q3FbJOG3fg6wTcMYyyEQrD5g4IQhKiIhudUlSkKUkA
+9hWKlXSLw3Yx/S2Nq5Ye+Pqr4CU7UFOTCsBIH4Ky+6gLTmP6esPx0k8vXLcOjaCk
+ENcLi0OaL/AgfATH/InN3wzrx2AFfU6eQdEG7HS+402eHl0fmWwMGV+SCsLl+2hx
+AguLFwjetuVrroc/d+XeZdTcpr/2vojsr4UgbkH8Pa2KrGIpK7V85nSOeVbpDUru
+tuimIRSxIQ6GDF2c7Ih5yBy+JPV47gppSV/GgHPgrOlebeqy4sytshRiEYw/nJzZ
+LKBaG6gykN+6MeV6+A7c1BlCYpyi2vcyvouU+l3/Z9gR7vY+Oj1eAaxrqeTFf++3
+qnA=
+=03Wd
+-----END PGP PUBLIC KEY BLOCK-----
diff --git a/org.eclipse.jgit.gpg.bc.test/tst-rsrc/org/eclipse/jgit/gpg/bc/internal/keys/66CCECEC2AB46A9735B10FEC54EDF9FD0F77BAF9.key b/org.eclipse.jgit.gpg.bc.test/tst-rsrc/org/eclipse/jgit/gpg/bc/internal/keys/66CCECEC2AB46A9735B10FEC54EDF9FD0F77BAF9.key
new file mode 100644
index 0000000..cef72f6
--- /dev/null
+++ b/org.eclipse.jgit.gpg.bc.test/tst-rsrc/org/eclipse/jgit/gpg/bc/internal/keys/66CCECEC2AB46A9735B10FEC54EDF9FD0F77BAF9.key
@@ -0,0 +1,45 @@
+Key: (protected-private-key (rsa (n #00C0CC85B516109C4263FF3438735E8791
+ 43E0CD002A9379DEDE121AA6DEBA30916E302A2E7ABF5531151D19A00DCBA13D684108
+ E22F7212DA5E3FAA9051DC94213051F7A65EF206C088ACDEC9BD97C0BF1AB651DE1E61
+ B7689D8F26BFFC822EAFA79135A51E45860A9A4A326E83BA9114C390855028A9B4F5C8
+ C62914D2E41807B551B5786143544676CBFA99C3B030887B863F5F953AD7D36E71D2F4
+ 72A63AA00D1D3946E33784C32924318C02E7F9D70FE56D197D740B09CC5CE0D9C7FEF2
+ ABFDD86C7746E3F76B7CA5EA912E2A792975D0B8EE58F6A6FBA159905FDAC5D93323EF
+ 308BC00EF7B8188563EA4FB05C4DC3329D31332D05BDAC70E4E3913F150028D051FC18
+ 23A116E46E39BEAC9673BE2BBF5D53D1E36FBBF22B2FB1AFA59C40264DEA13AA2CFD9E
+ 54D33CDFBA263C095D89F62EE88533C5F334F27036677FF3A956D6A6CF0F1647843F63
+ 8DE5D9347501502293223D91B36B856B4C6B00B7618611846A8F49955714AB3FD3C3CE
+ 6A0BE0E5CD26B7DEB7B90BAC067B6A675B7B#)(e #010001#)(protected
+  openpgp-s2k3-ocb-aes ((sha1 #84A4A8051974D94E#
+  "26420224")#914E6847983627126D1CDF93#)#DEB66FA3201F91591F688F5D2B1B79
+ 39FD75F58A962C227BC739C6F2F814ADE5115BD85B2E55427153CEC82612F0C5BBE8B9
+ 71A0E5A6B796111B6B1A03C4C926825F03B871CBFE0F64BD0F0CC65EA34E718BA823BD
+ 136D78C9E88CA1733DFC8D6A38830274322A589BC522A2A824FCEAF453523CDD9BC391
+ EEF1355470C110E9A92681DA0C61563465D5238CECCA2D6CFA78FFDFBDDA17A308D6E1
+ 3B1858890EF25A7655F22FE6305AA0129DE5A353B657065E608A616A23C6AF561C4472
+ 5AA705E55343E9C728641BB63C64F804F76A4C5008CE5FFBC09F03B632B42180425D28
+ 9DC1201D91B1989627EE5930E6EF2F6606108B2F048934A9D79DB4834DD950C4A2013C
+ A40B50EE54FA9E3CCB20C210244BFACA795494A1FCFF35856ACF63214A0498ED894BAB
+ FE80CC24D8A478AD08D0BE8CDC8F357FB7F28A30B87540B9B4970D6EA0AEEF46A2549F
+ BA43A98FAD75B4228108DB50D1C3654422E24B4C7754673A66281BB283CD6A1EA8E64B
+ 97DC9083C62034BF7FBCD193830F8FEC3589673B864E50EF7AF4DEE046BD26041E2925
+ 170EB7B6DC6060E78309CC8A136AE9CE44D3B4EBDEE4479482464D0D23C13529184021
+ 795557323D353A70CC710EC2A79C66E860095C082E40724867A9ABBFD3407B2F92CB2A
+ D0D95CC8DAC2FB2C0187B3BB09AEDF869AF1969BA641027D4D5DAA31B1DA5822D40A5A
+ 7FAD1C054C02CF8F8F692B1C45C879299C0E9D5E5A165F6C22DEEBB8C16FFB91F381C4
+ 8FCB209657A7BF9268BD34808D0A9D3D6F50F7026BC297FD3A08790B8EB5CC0291246B
+ 16E4B50A7E9630B33F59B5EA24EEA396F07AEFD0C262BE9915CB32D5F03673CBD3D20A
+ 831FDF55B5BA3D03440A8E1A331147A8AE0760EC593EDC881F5F0A04F4FCBC80C1531A
+ 4DE71D014E3612C2C679BEF3AED59F358ABA5731FF80FA15EAD2CB95AC548F6AB0FD7B
+ BBBB2CB63DFFE9E672605B7F54EEA4B4C046C4CC8036F2F76260CF068D232A40F492FF
+ 9648CC7459F0F46FEABA3D62B9F421B0F8A1BF914E41702540213848345498AA13F989
+ 49EFC2888D3720DC34D20634472FC3A194F1403C1609C38A020F7E47F3205CA5C0CB50
+ 26270083ED153BF97375407514BA15D92808A8C10F8160880F6981BE53294292E4EEE8
+ D215E7854FC79016B64984BBBAD2E99EED8D66B25575183C279E4DAFCB63F1067FA2B0
+ 0888A9C226D4846376520720FC1E947A93A1D32444F78B2F4EB836A6F8C685C1D82958
+ E31560C3FC861D2B68B889E1B5EE0476B914DFE316411F750D252F24076E53557AD5F0
+ 4050E5E839B33E5B8AF16FDD9FE033B39796A52DE8AF65375966D4DB137C85C800B5B9
+ 0E29434E4B215DE35E60C85391DFDFA572C6F9747A0EA0964236FBB3B04394D9DF0694
+ 6E4CC9CBCE352382908148D265293C6EADE7C2AED6F5AE#)(protected-at
+  "20210119T160858")))
+Created: 20210119T160837
diff --git a/org.eclipse.jgit.gpg.bc.test/tst-rsrc/org/eclipse/jgit/gpg/bc/internal/keys/AFDA8EA10E185ACF8C0D0F8885A0EF61A72ECB11.asc b/org.eclipse.jgit.gpg.bc.test/tst-rsrc/org/eclipse/jgit/gpg/bc/internal/keys/AFDA8EA10E185ACF8C0D0F8885A0EF61A72ECB11.asc
new file mode 100644
index 0000000..f412019
--- /dev/null
+++ b/org.eclipse.jgit.gpg.bc.test/tst-rsrc/org/eclipse/jgit/gpg/bc/internal/keys/AFDA8EA10E185ACF8C0D0F8885A0EF61A72ECB11.asc
@@ -0,0 +1,30 @@
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+
+mQENBF7EL8wBCADO46xh7nXn7vZ5ow2Zdrp7WTh9BlT2wtaHNKpnKvSoYHjJbbGz
+yF8Jf/qVPuXNbjx2df1lT7zT7x3evcjQoNy80deftCw8ApZB9RMOo3uUIqS2VpO+
+cS9rjTgBRFL6xDv3g4++CE9s+5dKE9gKkwleZ5/tVqUIoHPAIUEjpcPHngi5m2bi
+tSmQUYWLGcliR1E79sJMSzPt1neksqHFMJ1KTEJLAABZ0t3PiBzmycIQWThX3uU/
+lcgnZmmhWCJIqV0yRZqxl61ejUfq+zK0T7MzhAAugqe7D6BM1FRwZRNCHwDQXIvt
+/t3fczTe+x9oTy4qX4MfaP8lHM0223MwGR13ABEBAAG0H0EgVSBUaG9yIDxhLnUu
+dGhvckBleGFtcGxlLm9yZz6JAU4EEwEKADgWIQQILQAv4wNQfEJ6I/NEWemKCmiQ
++wUCXsQvzAIbAwULCQgHAwUVCgkICwUWAgMBAAIeAQIXgAAKCRBEWemKCmiQ+xev
+CACZSWh4xjTgafwGMP9RnReOhubVmfHS+XGlidDQzJDtshDQddPZ3oQwyTe3OgkW
+ZgOrzjrHGsZp3WZmGUZejrKt2Brqp+h+VRujFVcKk4N9A52BkM6OeT9lzBabOpuA
+UaDsNMSFsMcGTTYpB16+sDcyui8LW1jGi1y+8aQa+u1lIk/vVycq8o4htn2Af8xZ
+rAT8peapsjoNjETEs8OQ0al3Q0UX9amW6Rq1zZZ0XtoXDCPTI01EfczDMN+AZoFk
+UYHwSREDFLSh+c+q1HhYp4TqP+2a5Rayna//n7zci1PmSX7zD3iWzV1jEQ3Jm8U3
+DY+P/WLezQdSJIBVCFpCualquQENBF7EL8wBCAC+ef+vNvfu1jl9BXpu6K9PG0I5
+DQfrNtcdPq90O32ipvsYvqGOJX9MHoTyxBPLew+e5UsYb3ex62JyJqdAaqSwYXEN
+MBESZx7yBqBMUvildfh8dowbJeblxCf5KsE4C9uNfg4ApWGD7PjVsUCh47V8VcfG
+ymCxxq80r+4GfFtt/HC+l9fPUnDLuXpAWEM2GPUzcauUoEXxZK6nhstYCRlKlQcK
+Tn+LtCC7SGpYlqvwWBzAnOYP9+eZfSJ897g0AiTEhK0JsBlDAb3UAWHYHkAkVa1+
+oU/UedhPC4j2Q7RzPQFMun6aGkaDrntCxvT7IFiMplPG7iy0JDd6ubrWSzivABEB
+AAGJATYEGAEKACAWIQQILQAv4wNQfEJ6I/NEWemKCmiQ+wUCXsQvzAIbDAAKCRBE
+WemKCmiQ+xoBB/9BAmlHQUmVl/bkwszAcyXkR5HsyA4htMJt+6GKlqftuhLP0SGK
+Il+7GeK6NqNdQXxXG5Wj6dn7ZqWalQRA0evEa6VLH+74zrn0llWfzTPIcP1bHW7l
+uYaOzZ1z/q4FoEGNJxp/jdToZ4970OXLzqY/G/QlMJIlXWCC0EXNYbKCEpOE9uvW
+h4kWe5xeGOmhZylYbzurTDzqEtKy+LZ9f2xNYn6ElcWtwxsxwSY7L9B3eNcCYE46
+Np6uqzPffB9s7PHW46yEL1lQs6ME+9hBGyjeVop+Wg9qkh3YCrp+KY5Vkmdndwkn
+Th4FnTpcCiS06fCVHHC5kelh+H6TgRA+XQ/V
+=WGUq
+-----END PGP PUBLIC KEY BLOCK-----
diff --git a/org.eclipse.jgit.gpg.bc.test/tst-rsrc/org/eclipse/jgit/gpg/bc/internal/keys/AFDA8EA10E185ACF8C0D0F8885A0EF61A72ECB11.key b/org.eclipse.jgit.gpg.bc.test/tst-rsrc/org/eclipse/jgit/gpg/bc/internal/keys/AFDA8EA10E185ACF8C0D0F8885A0EF61A72ECB11.key
new file mode 100644
index 0000000..b8765aa
--- /dev/null
+++ b/org.eclipse.jgit.gpg.bc.test/tst-rsrc/org/eclipse/jgit/gpg/bc/internal/keys/AFDA8EA10E185ACF8C0D0F8885A0EF61A72ECB11.key
Binary files differ
diff --git a/org.eclipse.jgit.gpg.bc.test/tst-rsrc/org/eclipse/jgit/gpg/bc/internal/keys/F727FAB884DA3BD402B6E0F5472E108D21033124.asc b/org.eclipse.jgit.gpg.bc.test/tst-rsrc/org/eclipse/jgit/gpg/bc/internal/keys/F727FAB884DA3BD402B6E0F5472E108D21033124.asc
new file mode 100644
index 0000000..c6e0408
--- /dev/null
+++ b/org.eclipse.jgit.gpg.bc.test/tst-rsrc/org/eclipse/jgit/gpg/bc/internal/keys/F727FAB884DA3BD402B6E0F5472E108D21033124.asc
@@ -0,0 +1,30 @@
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+
+mQENBGAHViwBCADaE67a5U8oqNjqg//SmlNLd+MrFIccHsg+pkSDhF6ipjZEXdFu
+oRQ116tH/qY1SzsHw/TMLujYeTBW0KwQ5E2+TWagckL8pJpDt7ZC08CTK6u0Xvjy
+BSqy/t29NPTuQxxxqRx5gq91mtuo8v00fQmqkbFUgkVfEOKOv4qe2tlaR5pTvpmV
+VboXOls87RPgP/X665kamHjsywrsDpZ5FbvPS8E2kKdYXqeHaiEU4i0Bizjx3diK
+ilPEIxxl8zgDsROXyKagCy0KOOajBqhFhStQH1soIzvk8aG/9eItKmTa2v1BD2mV
+UlZNQ9ZfsnXx3QIBLmA3jugH69rkcekHRCWPABEBAAG0HVRlc3RlcjQgPHRlc3Rl
+cjRAZXhhbXBsZS5vcmc+iQFOBBMBCgA4FiEEJJx/+EvV3v35cJ+Jx5r/T8UxegwF
+AmAHViwCGwMFCwkIBwMFFQoJCAsFFgIDAQACHgECF4AACgkQx5r/T8Uxegx+hQgA
+pIy+E58aWh9FIHW/POqLB/y3v/GbYdIbzk9ro0FAXQ2tQsoGQbsuLckJVIlyja7n
+oQX23OmWTOc2tj/Kpy9lZ2ButW43FaMSiLh1G/VtM5pqJ9yHFdb1z7Q+LHMhhB7w
+RKOoNSEgkwtxv4LAkKz5t/BrDU0hvDPxWPqCSRvSAEE6qIY0fa3mLf9ijy3gLlCd
+hBayUC53W0tL7gLHgprTM/fX7b1pDab8beorroPHs5XzcYUBleaCGmEYbtV2eXPQ
+5irOXOC/D/E8vOfOZwhOhFOZk9b4UnhFK4OCfpKIzIooc6tlboVPhdx7jb5DkXQo
+rozfavEvAPx8INi9KNmdBrkBDQRgB1YsAQgA6q/O6mAPB0kj3pnpuIdJC8EumgKm
+7W8rv+ZfRGePg+IEEm5DeFKtfWl70YH33nGmwnWB95wO5412JCNC174z5LKDBbz5
+PWT/yTNnmjooxj6G4p/YVwXYJkvfaDP+kQnYgJAybpeqTa30tES0eqvI0J9aQo1h
+GSMRCkE6QMV45IMj6gH9rptQv9e8U6gbnwBPxWPG2FH5rsGIGQGzIEmGxmKRyxXm
+YDU4f7oWPHSg1ikQqCzAxxCBxeCOaid3acLK8//TOwF/Do8GPJbcupEDqsgbFNGM
+BDWtmkmxjrLntlU+dvIPcsBxdBUrrADiJ/k7EfFv3kHfLfdAonSdKZL85wARAQAB
+iQE2BBgBCgAgFiEEJJx/+EvV3v35cJ+Jx5r/T8UxegwFAmAHViwCGwwACgkQx5r/
+T8Uxegy4+AgA1bzFKpsqkwrjZKDCCT759xeuUbxnYE9kBJgFSVuhn7fUbB4MoHx4
+shBptx7iBOdxxT7yC0oaDPhbiIkttb/c5W0f6JuLr08JpjkFfkrWF+dMcVrtXwPx
+i/30ccV98qWJDCBunyeCwBNie1Ck+qXMxm3FYy4qIbftMQ7mG6KKN6eFlbxu8B6M
+p93DFUvycGH9CWz0yJcho7KT0NSSyoLZhJz2uxRe1BwGMV20O9AG9yicsU0/uJxY
+a2Hble8NkH54XDuZkrsBaAb/o8UsWP7AJdYYsb904UZDIZNRfjWapOmODnlnK8Ta
+Q8pyYRGS5of1SapatMfpQZF6hdsamnTH6A==
+=guSE
+-----END PGP PUBLIC KEY BLOCK-----
diff --git a/org.eclipse.jgit.gpg.bc.test/tst-rsrc/org/eclipse/jgit/gpg/bc/internal/keys/F727FAB884DA3BD402B6E0F5472E108D21033124.key b/org.eclipse.jgit.gpg.bc.test/tst-rsrc/org/eclipse/jgit/gpg/bc/internal/keys/F727FAB884DA3BD402B6E0F5472E108D21033124.key
new file mode 100644
index 0000000..63617c0
--- /dev/null
+++ b/org.eclipse.jgit.gpg.bc.test/tst-rsrc/org/eclipse/jgit/gpg/bc/internal/keys/F727FAB884DA3BD402B6E0F5472E108D21033124.key
@@ -0,0 +1,32 @@
+Key: (protected-private-key (rsa (n #00DA13AEDAE54F28A8D8EA83FFD29A534B
+ 77E32B14871C1EC83EA64483845EA2A636445DD16EA11435D7AB47FEA6354B3B07C3F4
+ CC2EE8D8793056D0AC10E44DBE4D66A07242FCA49A43B7B642D3C0932BABB45EF8F205
+ 2AB2FEDDBD34F4EE431C71A91C7982AF759ADBA8F2FD347D09AA91B15482455F10E28E
+ BF8A9EDAD95A479A53BE999555BA173A5B3CED13E03FF5FAEB991A9878ECCB0AEC0E96
+ 7915BBCF4BC13690A7585EA7876A2114E22D018B38F1DDD88A8A53C4231C65F33803B1
+ 1397C8A6A00B2D0A38E6A306A845852B501F5B28233BE4F1A1BFF5E22D2A64DADAFD41
+ 0F699552564D43D65FB275F1DD02012E60378EE807EBDAE471E90744258F#)(e
+  #010001#)(protected openpgp-s2k3-ocb-aes ((sha1 #3E87FF0806B054D6#
+  "26420224")#7E8282B83522F91C53D76805#)#70B1997D514FF5800155A90FD785E7
+ 7DC2D782C48FC9BE44D0192C0AD56804468C910A202191EAD077B5542C95FE72BCC450
+ 0C2A8E8313C0CBD6C881236AC13E0BE893663946B5AABBDA57FFE4BA49973D547FA5DD
+ 1236DEF9FA5A9CE52F7AF1947F42A6C3502A47E8EF7E8CEFDDD44D0BFE090EA3220C2B
+ 52E11776DE36DD6C72D3B39A56F5D7295D26A69DB8CDAD1ABDBE1B21C1B754C9184E65
+ 2CAE169E2F492FA0EE5908AC5CB3BE5F4C7F6CD9F41314D1BD9B1DE713A4E6C7DFB11D
+ 2E64000ECFBBC89326B1322A8A227ECE7B919408C9187B5C9D53FC3985833E76D72164
+ 40B7386569E4DE270C3616ABD2A91A657AC58AA872704CB3DD4DF08C77D03D8E3CEDB5
+ 0D83BC3837FFE45D64B457AFE9A6ABF680637C51F80CB54691233BC4DE640026ACDAAC
+ 3FC0749FA8353F6EAD5D362A63C1CF25ACA73A9CF3290B54C18DB3214AF078D918682E
+ 513C434EFA06D9045571B1734CAE42990A1BE962D6E2A45846169EAAF2CDBD520813C2
+ D4DE97FFFABE582A02CA893F91EAF0EBCDCEB70B35850FDDF56EEA60C845A7E5C052C4
+ 33344776E7A4C787690CC0E13F32373EE425CA10520C251D045C0AE73EE7A0CA83C858
+ E2E528CDBD117BC022ED3F5DDE40CED0128B761E29B11F422C8E7C4281BF94F6F75D07
+ 0EE58426137548ABA38019A34DF1A66F700C29EF5545AC88BED75B5036801F0D8D4DB9
+ C6CCEA83D9DE3D626A04A80F218EFE9C74C173412A8A86786AB4A85403E8F8292CFED5
+ B8BA72FB5CE1BDD094AD9D633FD482F8FDBFA540DD2224149786ADA8DB6310A7C0C6E5
+ 9167815B2CEF34E7C458C41B5C56A79414BA57073E9B06D28CA08C56ED5E685EEA2BA5
+ DD112F87B253A0D02AC7CF93EDE93F48A80B2DB57B254937EA80E9AC1CEBD36FD297EB
+ C8A3B42CBC3D2CA732891B49457F3F15AA3F9BF93553968A07CB1A834B392F27B2D152
+ 47D93E46A6338694EA53CA0F5968109B4FAC9A#)(protected-at
+  "20210119T215925")))
+Created: 20210119T215908
diff --git a/org.eclipse.jgit.gpg.bc.test/tst-rsrc/org/eclipse/jgit/gpg/bc/internal/keys/brainpool256.asc b/org.eclipse.jgit.gpg.bc.test/tst-rsrc/org/eclipse/jgit/gpg/bc/internal/keys/brainpool256.asc
new file mode 100644
index 0000000..8427cfc
--- /dev/null
+++ b/org.eclipse.jgit.gpg.bc.test/tst-rsrc/org/eclipse/jgit/gpg/bc/internal/keys/brainpool256.asc
@@ -0,0 +1,14 @@
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+
+mFMEWsODvRMJKyQDAwIIAQEHAgMEQLOxiiHZ/V6v3kvrhbnRtTp+oOPVpuvDKOiy
+gJOCZ7EWMVAwTr4syaSh8W8hdRgZ85Evv/1PYNFovYb6vzgVr7QJZWNjLWJwMjU2
+iJQEExMIADwCGwMFCwkIBwIDIgIBBhUKCQgLAgQWAgMBAh4DAheAFiEEBjPF9yoZ
+j1HmUOSr0Mij2vngY0oFAlxVsKIACgkQ0Mij2vngY0pARAD/RozGDidH/0aFlxeU
+VWNJKjPiax6vdHqur5dqBS/RhhIA/1sPUnyAIvAXXID1uhK6oIBRKi7WJ5rI7vSy
+rBR5MlNJuFcEWsODvRIJKyQDAwIIAQEHAgMEE9Vd8dIjHJkmRs/8MLz4Krfwz5BK
+hunq1T0xnp65OEZJd00VxA+VUXdEUHfaDehtSv7izCpq4lbXGCkEGFN7QwMBCAeI
+eAQYEwgAIAIbDBYhBAYzxfcqGY9R5lDkq9DIo9r54GNKBQJcVbCpAAoJENDIo9r5
+4GNK0MYA/2p5cq5smjSvKD/EGkosQwfcqkeygsQuEpDDLeEdsv8vAP9j+RHKX2tl
+W08zbayxGB0E+aCHuKCF8iLPeI4eroi/fw==
+=vsa4
+-----END PGP PUBLIC KEY BLOCK-----
diff --git a/org.eclipse.jgit.gpg.bc.test/tst-rsrc/org/eclipse/jgit/gpg/bc/internal/keys/brainpool384.asc b/org.eclipse.jgit.gpg.bc.test/tst-rsrc/org/eclipse/jgit/gpg/bc/internal/keys/brainpool384.asc
new file mode 100644
index 0000000..bdb20fe
--- /dev/null
+++ b/org.eclipse.jgit.gpg.bc.test/tst-rsrc/org/eclipse/jgit/gpg/bc/internal/keys/brainpool384.asc
@@ -0,0 +1,17 @@
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+
+mHMEWsOEUBMJKyQDAwIIAQELAwMEivcvlPJsPmivhJcrfHx+ORxyum57GtRhWM49
+Yr8fJ48gyFqj9cLYOBdhEVvcfceyBPXmyt0TozWtjkGzgbF4LIvN1EB0DW0Rlsdn
+p72/hf0gnXvWZdD8euArX4RaAYuQtAllY2MtYnAzODSItAQTEwkAPAIbAwULCQgH
+AgMiAgEGFQoJCAsCBBYCAwECHgMCF4AWIQRbiiVMgjztmN7NEO1s8tzoVZmtogUC
+XFWwugAKCRBs8tzoVZmtoj1yAX9P1UV7FYpGUIP13aPP0d5Bx8HdQDAoexdXz3WW
+WPL/7OhSjPde23Q8TfgWyO21M2wBf1oWjOsDSjO5mDLCr7ypAFF6IJAgx76tSUe9
+Qmy7sL94OWDQ4+1Dccnc9GGiHLtRI7h3BFrDhFASCSskAwMCCAEBCwMDBETUkqGr
+7p8kX2dm38jzzxXRh1+OL7nmY168Zeo9yfwDbnyx8BoihP9ZgPWjGXmefT78GSfw
+ZDaYgC2NFQOcI/b8agh3PcjrXgZaFCZbUR9v2DnLUpCF8ZbxDJwEqweNTAMBCQmI
+mAQYEwkAIAIbDBYhBFuKJUyCPO2Y3s0Q7Wzy3OhVma2iBQJcVbDCAAoJEGzy3OhV
+ma2ig1IBfifduIiwdAlD45MOolSpHMX0AT7KoJHpt9ZFvWnjQkq9ZGEA/RA9vx7Z
+sLb7IsG1GgF/Sn+gtf/JIteXaZMnOhEOZ2oFUufij6o8gII8/9s8mkIjkrIICy//
+0n3q82ndFg0c
+=fcpz
+-----END PGP PUBLIC KEY BLOCK-----
diff --git a/org.eclipse.jgit.gpg.bc.test/tst-rsrc/org/eclipse/jgit/gpg/bc/internal/keys/brainpool512.asc b/org.eclipse.jgit.gpg.bc.test/tst-rsrc/org/eclipse/jgit/gpg/bc/internal/keys/brainpool512.asc
new file mode 100644
index 0000000..5b4bca2
--- /dev/null
+++ b/org.eclipse.jgit.gpg.bc.test/tst-rsrc/org/eclipse/jgit/gpg/bc/internal/keys/brainpool512.asc
@@ -0,0 +1,19 @@
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+
+mJMEWsOEhxMJKyQDAwIIAQENBAMEA28ylDnn3LR7t6EQow5DszCpmUA+yup03LsT
+9o0Tw4/asi8nAz+1tlRY5HD49j53PziOlsGzKYa/jxGWjhVESgqLrJp/Eo65zK9v
+yDhX+iCkSYQ15WGKr3QaRUmBOUbX9PqE6dY+DDGQ1kewI93QIGCB1gn+OSmyKPm3
+YaVIbo60CWVjYy1icDUxMojUBBMTCgA8AhsDBQsJCAcCAyICAQYVCgkICwIEFgID
+AQIeAwIXgBYhBExZq5JyqmofYLhb0KpcWNFPe49IBQJcVbDYAAoJEKpcWNFPe49I
+F8UB/i8DwypbNusdbAqTbu1Twpn/QFMaVKHn8Ysgzqpimv+6hRq7uzekCvEOPOjl
+Oke5yLp8bpTTMPRKyfjNatQhdn8B/2+54qtXJuQd9oTSz7f2eFYvA8ZsMQgApYNl
+ksvKSw6dhSNX/DXK7JYIlgZXx7UGTkP4h3FQSiyCUJhVpClVVGa4lwRaw4SHEgkr
+JAMDAggBAQ0EAwRCtEqQkEgzQDxNGCj0duj0aGvnH+DHKlP4V6p9LJVIL0TuF1uZ
+BzP04efRvZT2vzCTcvvdE/G6G/txEZsR/989OchbkVWOPM/oCVktkaA02rBMcefh
+k9wKD+O9E3oHEN+tBt3yhmsv0MIR9IfPwi1GCsu55p4WUI//+ysB2T0YaQMBCgmI
+uAQYEwoAIAIbDBYhBExZq5JyqmofYLhb0KpcWNFPe49IBQJcVbDgAAoJEKpcWNFP
+e49IZQUB/R4U4aWBMimZSL8kyaK+/Y8NcInIGqRzrm5zPnTSHrgQeH55SVKahzsq
+j57D1Ec1HnUd4ctISVocOxpUfnJq5NAB/1fzbh+1RN2ZyNW6tAJlA/Irkwzzbil9
+6fAIvRolwwaGsUZNMEiCF3rTcFaenJg9UhQvX6BoqXCdwawqTZCRN6E=
+=h+On
+-----END PGP PUBLIC KEY BLOCK-----
diff --git a/org.eclipse.jgit.gpg.bc.test/tst-rsrc/org/eclipse/jgit/gpg/bc/internal/keys/dsa-elgamal.asc b/org.eclipse.jgit.gpg.bc.test/tst-rsrc/org/eclipse/jgit/gpg/bc/internal/keys/dsa-elgamal.asc
new file mode 100644
index 0000000..db06732
--- /dev/null
+++ b/org.eclipse.jgit.gpg.bc.test/tst-rsrc/org/eclipse/jgit/gpg/bc/internal/keys/dsa-elgamal.asc
@@ -0,0 +1,44 @@
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+
+mQMuBFrDf8YRCACHbPXT8jG3RNWdNms9xvdaiLrY+Iui1Gq2WGLSajPEZVASEWN+
+JuuX8k9d05rb+F2VAqLnW3CQreDW6unVNeRf52tdM8J4eXmeu/Bkk8y1Qx/HbGca
+sAGSIEKg34TuV5Ly5m4Z07bs3HPYUUQbmu0uclGfnX/ArZ+4Jp+uypC9bErdiXM0
+cM7d52tb9IvOlXNu23rzHDbgVP6qF/AxLSRD8SQPvshu3/5b0bvdBkHVk+dHoLO0
+fC5j476ibHGGZcnPMrTwqEIAxUCy5wQ3Lb/2/G31kuV55bAZ41tUNEvfzbiRN1L5
+1uiO+XX96bRqLN13t0Coaba9fq1aN5Zr6piXAQCuNzvj8aaLXAOEXVRej6a2k+/C
+Jny91MgjSM701twUDQf/RMWHwQuFPe6zSDQs4pWlxkHwXJw3AVidkoWg/DCwv2pJ
+5VYQxBXRwND2OhcZvmeDT94UzPws0dFbprWyymtA49ZXitPGzFARAFWHWxk/IsOf
+Idc6w5eHXDMHxLhiPFqfjKeNpibzO2P7LXP2bUKzwybkKZarz1N6pfanDXAtC4DU
+SC3qWNqywYlfINAGCdwsPu5qFUNSnkjTYxe/MiHb4kL1p/z8qFNWrvg6GryXygp5
+cLdqckjPaUHlR+B9wQZIVRzVdlFAbMDJ0EERLFG7FbIuY8dzy5x7n+oBOgRxee2I
+ytUpGVMLIJuecARLXNKsMXviCMYVE7Tj5hiSoM0TIgf8CwLLFsSa0EDm/wlXYZMj
+2gg3Z8iCz6ycxvFD9PXNt+8jyELO8CwS2pWu7ptBgaugkinqd40EQslQoP76CcHq
+bGQEohm4SnmfGsV8dicuziMVVKkVrYgbGvZ5cQ/ONGTTnSJuiTPN19oztwh8JOEc
+Jd4l+wFuVSm8OS1mj5eexeX1Tz3NfWQMT4deKh+jiTLe9Sw/57sSjxiw/8IczqhN
+Fu3YIy40d3Bv+OF6i8I+94WLbJPiX1ban1wqcA0bMaps1aYVtTRZ+mP0b3M9W7qa
+383/SLCBjUzQ7zm6PX/7uAXFyZOQfcyLaJ8Hc34yOE0git1DWmRS7U16Zv54v1Uh
+HbQGZHNhLWVniJQEExEIADwCGwMFCwkIBwIDIgIBBhUKCQgLAgQWAgMBAh4DAheA
+FiEECRxEzpz7w/9+x6ZNyKEKfXgnPhAFAlxVr2sACgkQyKEKfXgnPhABkgD7BfEd
+jhB+ApC9icNLs893i2jiHbAxZGSOQMRhCaJ7AzoBAIipcSIsBa3LJ4eTec1esiCY
+a8xzxquCTA+oANNoX7p6uQMNBFrDf8YQDADMPZ6+/YAIjXMLfQKX80jz6FZ4Kdfx
+Dc60m4O+ZElMv7eXtQJC2L/xOh4Th1fZUQIhSdtFiwaCSkCD8occfJwyt+lH3Dj0
+Qrh3mIycAfPrjj0Rgxz8nRQbBLDbLF1QGPimt0zP69ByJ3opLujVVi5ixwgwza9S
+eGffKwGdyb9uFcB9MVnC997zfLvx/uNV44BwLnCH6Tp68Lynf+FpuvSX+Rsj4li3
+UiLoVxEIbBZ/5Bn3ygc7aW4fM4bR4hKjWwJR0Hh1y/kt6A7dEAypVKBfSqAtAu2A
+zYAq3USsbtq1X1FaGEsmvcJY8IGa+aLTArq7dkhXzcv7K3EVdqOawS1zS/ARuG+B
+k6kct3zzyj1EitiTvdMAkGOoyk16qKVzUcbFRVC1HsZtxYj6OxU4Eazvh0LjvZ0A
++eft/XO/ZmN6vyRaF1/10z+uHPfj1FLMpS8Zn4SN6x7Qtsx3iLL1n9cKBDFRXCqD
+HDaxLVC3N4zAI2hMMmZid+fbTuhsqYbSX2cAAwUL/j/H4/9Ml7PUUCXoozX2V4K+
+gi6WEYmY+pXN/we9NuFulW4aURo7jK4wRYBu0BS3K9e8f8WUMAV5V6ShPWHXcobt
+iuSjLYJwdBJkgHbnKFWPZUozJ3Ftyp0Lh1M5bN7/ECofAxLHbRpCVrcOP2LC7vAU
+AeMgdiFDqEiLCnr/aGvqUOxbGO6Isi4jvaM/ZUfGjGe/Z6yVoqm6wEsNM7+9cFGQ
+QR1lRPeCPKcLeasCdbM5EIt1aLFNijZigWuDRLIgG5PuzA8Kpdk/u/UuCUeUFwJN
+ym8MEv2JJDiWHmb8IcgFMp40VenUs0fte0LWwrMjWVPpLsHKmkraRjQ1UtarRhT0
+ANYilGjZWCnCb11xGKhlM7r5IkLGY/L/Eh4vjLgg9T5rGwOF8p1jSgx9mA8SpHV0
+O0BoKNX1ApWEHayTLcyayCnTYbY/e4axnSKodixAI/NghOnJHqGr4LeZeKk/Q0mm
+GlljzFv3EAdoru4DVowWGFBmrwBy7o+GLgHs6K/+yIh4BBgRCAAgAhsMFiEECRxE
+zpz7w/9+x6ZNyKEKfXgnPhAFAlxVr64ACgkQyKEKfXgnPhCETQEApruWUqCwfibQ
+vyI/OZohPzljlvIoioj3rFjYNpufQD8A/RTaYtnPiEvsPynEZCj9zTV/SuHiKbHS
+v5BhpoOOm+jM
+=PnGk
+-----END PGP PUBLIC KEY BLOCK-----
diff --git a/org.eclipse.jgit.gpg.bc.test/tst-rsrc/org/eclipse/jgit/gpg/bc/internal/keys/ed25519.asc b/org.eclipse.jgit.gpg.bc.test/tst-rsrc/org/eclipse/jgit/gpg/bc/internal/keys/ed25519.asc
new file mode 100644
index 0000000..636a5a9
--- /dev/null
+++ b/org.eclipse.jgit.gpg.bc.test/tst-rsrc/org/eclipse/jgit/gpg/bc/internal/keys/ed25519.asc
@@ -0,0 +1,9 @@
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+
+mDMEWsN6MBYJKwYBBAHaRw8BAQdAAS+nkv9BdVi0JX7g6d+O201bdKhdowbielOo
+ugCpCfi0CWVjYy0yNTUxOYiUBBMWCAA8AhsDBQsJCAcCAyICAQYVCgkICwIEFgID
+AQIeAwIXgBYhBCH8aCdKrjtd45pCd8x4YniYGwcoBQJcVa/NAAoJEMx4YniYGwco
+lFAA/jMt3RUUb5xt63JW6HFcrYq0RrDAcYMsXAY73iZpPsEcAQDmKbH21LkwoClU
+9RrUJSYZnMla/pQdgOxd7/PjRCpbCg==
+=miZp
+-----END PGP PUBLIC KEY BLOCK-----
diff --git a/org.eclipse.jgit.gpg.bc.test/tst-rsrc/org/eclipse/jgit/gpg/bc/internal/keys/faked.key b/org.eclipse.jgit.gpg.bc.test/tst-rsrc/org/eclipse/jgit/gpg/bc/internal/keys/faked.key
new file mode 100644
index 0000000..405afad
--- /dev/null
+++ b/org.eclipse.jgit.gpg.bc.test/tst-rsrc/org/eclipse/jgit/gpg/bc/internal/keys/faked.key
@@ -0,0 +1,23 @@
+Meta-Description: Example from GPG file 'keyformat.txt'.
+Description: Key to sign all GnuPG released tarballs.
+  The key is actually stored on a smart card.
+Use-for-ssh: yes
+OpenSSH-cert: long base64 encoded string wrapped so that this
+  key file can be easily edited with a standard editor.
+Token: D2760001240102000005000011730000 OPENPGP.1
+Token: FF020001008A77C1 PIV.9C
+Key: (shadowed-private-key
+  (rsa
+  (n #00AA1AD2A55FD8C8FDE9E1941772D9CC903FA43B268CB1B5A1BAFDC900
+  2961D8AEA153424DC851EF13B83AC64FBE365C59DC1BD3E83017C90D4365B4
+  83E02859FC13DB5842A00E969480DB96CE6F7D1C03600392B8E08EF0C01FC7
+  19F9F9086B25AD39B4F1C2A2DF3E2BE317110CFFF21D4A11455508FE407997
+  601260816C8422297C0637BB291C3A079B9CB38A92CE9E551F80AA0EBF4F0E
+  72C3F250461E4D31F23A7087857FC8438324A013634563D34EFDDCBF2EA80D
+  F9662C9CCD4BEF2522D8BDFED24CEF78DC6B309317407EAC576D889F88ADA0
+  8C4FFB480981FB68C5C6CA27503381D41018E6CDC52AAAE46B166BDC10637A
+  E186A02BA2497FDC5D1221#)
+  (e #00010001#)
+  (shadowed t1-v1
+   (#D2760001240102000005000011730000# OPENPGP.1)
+  )))
\ No newline at end of file
diff --git a/org.eclipse.jgit.gpg.bc.test/tst-rsrc/org/eclipse/jgit/gpg/bc/internal/keys/nistp256.asc b/org.eclipse.jgit.gpg.bc.test/tst-rsrc/org/eclipse/jgit/gpg/bc/internal/keys/nistp256.asc
new file mode 100644
index 0000000..fd1509e
--- /dev/null
+++ b/org.eclipse.jgit.gpg.bc.test/tst-rsrc/org/eclipse/jgit/gpg/bc/internal/keys/nistp256.asc
@@ -0,0 +1,14 @@
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+
+mFIEWsOCNRMIKoZIzj0DAQcCAwQS5G6mn5dhamZ6678SXE1azavqf8BItWO9Qv8V
+dS1vEEoD14urr5OQKTLuHhDRjvSQdaxRtkf0sI51T7230sT3tAhlY2MtcDI1NoiU
+BBMTCAA8AhsDBQsJCAcCAyICAQYVCgkICwIEFgIDAQIeAwIXgBYhBLVP3ru2c0I6
+XQqlRCNnTyGyRBUnBQJcVa/nAAoJECNnTyGyRBUn1ycA+wVg9sEfHDBaGtLqlUSB
+WdGKURrHN7CJe2UTz1/7oQCBAQDDi4RQyLHs+TfOrBNSbLEswCu1oEh8VmHt/SN7
++mqNLbhWBFrDgjUSCCqGSM49AwEHAgMELDOArLIG85ABQu1IwgQMpiIuUwj+N7ib
+gGenTRck5dkBpX48eK3lbjovXn4YkBneA7z14iez3+Sdg6UFAMFV2QMBCAeIeAQY
+EwgAIAIbDBYhBLVP3ru2c0I6XQqlRCNnTyGyRBUnBQJcVa/vAAoJECNnTyGyRBUn
+ZKoBAJ64gv3w27nFBERvIsRqufvR6xcimqS7Gif+WehBU+P5AQC5bqoISh0oSQid
+adI84f60RuOaozpjvR3B1bPZiR6u7w==
+=H2xn
+-----END PGP PUBLIC KEY BLOCK-----
diff --git a/org.eclipse.jgit.gpg.bc.test/tst-rsrc/org/eclipse/jgit/gpg/bc/internal/keys/nistp384.asc b/org.eclipse.jgit.gpg.bc.test/tst-rsrc/org/eclipse/jgit/gpg/bc/internal/keys/nistp384.asc
new file mode 100644
index 0000000..b2b5995
--- /dev/null
+++ b/org.eclipse.jgit.gpg.bc.test/tst-rsrc/org/eclipse/jgit/gpg/bc/internal/keys/nistp384.asc
@@ -0,0 +1,16 @@
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+
+mG8EWsOCnBMFK4EEACIDAwTRTCLBHlq6SUTiXZfWR0vbUh/0VAlrePaqHVIE4LEK
+0UBhPCIQOGuGL4JIufc8UzBWhiMLJ0z7KRjBWufsMZR2+rqj+unOK2lLu7sc9or8
+X6B74hhP3Ili24PgGFAeAG+0CGVjYy1wMzg0iLQEExMJADwCGwMFCwkIBwIDIgIB
+BhUKCQgLAgQWAgMBAh4DAheAFiEEqyXLoELdkkw6zD7TJCo6peqF9EoFAlxVsBEA
+CgkQJCo6peqF9EooJQF7BPZelriXwZ/kJzaamImHBddkLFc7d2WbuSfDxEZQ+Mfw
+BAP3+QYUaFtfeqApjY69AX4w6LhTUgI2kl4O0Vc7ZOlqZBlwAc8CMV08TTfOEio2
+b51SItvhLdDrFRJ2K4jiO+a4cwRaw4KcEgUrgQQAIgMDBORWqhYflSrYzF04SK8q
+8Om+DYTvwRtUlr3Aoq44+gm5yBcmJmgT3TKrp/bx5Jg/zwzIASFn0agbxkqKpQqH
+sHeelWsSBROQzy98HXdCp3nVmghI2aDk8zdD6AV4m7c2ewMBCQmImAQYEwkAIAIb
+DBYhBKsly6BC3ZJMOsw+0yQqOqXqhfRKBQJcVbAZAAoJECQqOqXqhfRKgAIBf3Wk
+TsqUA1JXkPGetA9sjHglIICN+DZY5k+PwTJUxaW2zrkiPJ3BYEnKbmmBLzA7BgGA
+4RYatyl2WOUYh/poRLgu7JpE4oRqdmNA+QOpCILMId1AeXfj4W01RKFWaKeH+3Yy
+=2H/0
+-----END PGP PUBLIC KEY BLOCK-----
diff --git a/org.eclipse.jgit.gpg.bc.test/tst-rsrc/org/eclipse/jgit/gpg/bc/internal/keys/nistp521.asc b/org.eclipse.jgit.gpg.bc.test/tst-rsrc/org/eclipse/jgit/gpg/bc/internal/keys/nistp521.asc
new file mode 100644
index 0000000..db18f81
--- /dev/null
+++ b/org.eclipse.jgit.gpg.bc.test/tst-rsrc/org/eclipse/jgit/gpg/bc/internal/keys/nistp521.asc
@@ -0,0 +1,19 @@
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+
+mJMEWsODGxMFK4EEACMEIwQA8OZCJ8Iv4Qr2oRr0kqez0nPSW/vNxYBZRpCJ9ab8
+kVaRhW7+5vEsecm5XugZSePbAmERmk3oEiSgu35r6aovowcAGrOBfBm9fyIVqaoX
+veTS3yRHH6NEf044+pC+uBaaFukkrDmVTecdRvYr3Yrdc5ifyOve053znlpQ6a4n
+9bh4GGy0CGVjYy1wNTIxiNYEExMKADwCGwMFCwkIBwIDIgIBBhUKCQgLAgQWAgMB
+Ah4DAheAFiEET7Of9vpIV6S9fvW0IJLKgyQmO2oFAlxVsCkACgkQIJLKgyQmO2oK
+DwIGO72zo6otVkbHfeI9hWx/8FAOXh4MT4YtDicF/sj8QbHzdbEBHcLCByLYAnph
+8VVoCxpPcBLmNSHbNyreoksjEE0CB10P5kPrd/bYkdNx/HTu+1i8f7a448+Nr2rF
+PwdI9tOsghkT41qobZavjjnBlT/xv5DqXldJkEfaeiJxPHOKvMhWuJcEWsODGxIF
+K4EEACMEIwQBAY7ZCAjks1MWWxibg/EVaz5t6iEKJTwu8mGGKWdPZAQRKKNtNpf0
+pZAMV3I8ue/WQMsYKRYv5AGq1PnjV19DmLsA0aGw4MDM260coctkcn/2MAJQMC9+
+3Z+BJS3hqzwDuZ+LS13r0RLpgnt3ks+3ucG4II38ZZ1lTwKoIc+w/OuhsOIDAQoJ
+iLsEGBMKACACGwwWIQRPs5/2+khXpL1+9bQgksqDJCY7agUCXFWwLgAKCRAgksqD
+JCY7ahqbAgkBiXYtiBlp5dmSYnbc4JoIYWcxTBQ+/dGHyU6ZEfC5VQz2mrdJetK1
+bIID0rFSsd24/8IzAqM3L+nY9h9bULWroroCBjTohh0j2EbW+hFOrRqL01osnlY+
+1/G8e44blB5JqsPI9FqOZOUj6IzsUuV1N9gJbm1RHu/hSpm52d6rX4nOTbqt
+=3jnl
+-----END PGP PUBLIC KEY BLOCK-----
diff --git a/org.eclipse.jgit.gpg.bc.test/tst-rsrc/org/eclipse/jgit/gpg/bc/internal/keys/rsa.asc b/org.eclipse.jgit.gpg.bc.test/tst-rsrc/org/eclipse/jgit/gpg/bc/internal/keys/rsa.asc
new file mode 100644
index 0000000..e74df7a
--- /dev/null
+++ b/org.eclipse.jgit.gpg.bc.test/tst-rsrc/org/eclipse/jgit/gpg/bc/internal/keys/rsa.asc
@@ -0,0 +1,40 @@
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+
+mQGNBFrDgZ4BDACxg83nNkYvIAz6Nk4Np4BscWDrrL3tyiiQSz1yfCotxO8zUtVl
+JorSlqRurNdAYU2XJLakMqpQHE7VVIMI/WdXCC8CrQbULOBxIf/LGiQf0VDo8ukg
+iFFd5vUeMRRILWKnMc/GCmFkFOUHd1Y60h96oe5f/d286fRZQnCO8PGS8CgB1mDJ
+GBY8U1DCCkt6g9O6bfFkfcwetr1+kB2cBIY7uDzN1Sm8dz2VrkqPqtqt/F02giRN
+hD2GxX9HVYCkCKEE9DFsB+MDKR9z5lXrI3SAsL/3htXK/ukWgBe4DIFjTXbrzgP+
+nuWb4s1NxwSD7yjlnqVD7mZTGAwMsQbCjhwIeY4t5onsCJ4/40zm1jIZ5TJsfQ/b
+5gA7iu9kMKzxO0bPI2loJEB/K9aH7qsyQHgtt7G3+G8JrixLBUobtreY9V2QvhtC
+Q4OAHRO5nIKYIazDuKv9bxautZ0WuLOk/qmWMMoqFAn5bzQeVTTBD6kvr6l8/+MZ
+zaij9YPeUbeKJuMAEQEAAbQHcnNhLXJzYYkB0gQTAQIAPAIbAwULCQgHAgMiAgEG
+FQoJCAsCBBYCAwECHgMCF4AWIQRrwEpaPds1dmuaQNgvuReRGImOiwUCXFWwhwAK
+CRAvuReRGImOi1NiC/0RPjbQTWMw4/GxIMkRb9kmmsSUe7kCgqBCqZTxcI7rxZdn
+JFDbP5c6DAS/11bRQJ9OsoUjbDx0d81UuBlXB/mNsb9nCcXOrqAUHRqgWoNSDk4g
+9Oa1Kx77OM9BvRJbJGch2YW5Wcch5vcqQNu+6x3VGt7ipljYEJSQ6Dre+dgxYjXK
+60x63/ulFk2XImPQYjQ8VHbW/HDg/+DLf++phjVy9l58U1sUKSSdO8uuYoW6dBv2
+xRg18Sn3DWOU+mrkV8Ld95+NRRE1cSHTQv5hu4ELqrV+YdGNmv9DgQAMJOl3xy8i
+vOz4cpKaOBasm423wr5Y56nOTzLFN+dxnYR8tbqswLkCldRY6fvL1NsS77rj0yZp
+pecCyi0E6RAcmSiZJqpnOpcuI76AkZuWSDEP3Y3x5QBf5fu2uiQQsPXYN8ie6xcC
+zeYtXsHyNxF0oBh2c26po8fo4E4T70RSO8Oqs1XzXnjIIle8pKU9M5U5ISbWS3Hj
+vtOn5ZrLC5KYnVRna3G5AY0EWsOBngEMALmXpJoPC1m4THYrfHibtt2/OwAlDm20
+3xn+Klw69bkeXdc71wsLOAHVL3+7gXpip+IYmN7CBIyqlOCtsluu+gwP3MczPJZX
+vk1uXMMfLKiXl9Kodx/Fqq0Y26Tqse5PPMlagPStIvKyT0WTa3RCD28uVklapLuy
+1w1k4G5hIDPt6uKyxXq/HzneRSGWafmqoCWOmXQZzfOMG249bMXNOcPMJhOejPRS
+jREnnntbpvZ8DU/38+JFtqCUkPwuqYQkvGCKReSBifMiG3XAhHWOGzXPzdW1XdAi
+aA+NQP/kMUs45jS3hDdp4EObllYRBsQwtFpKPMNmwaVuOmVlbrXTP0YsDYGndkE6
+5nJ46/2xPhl8+nIgDLg3SBBzQdOiPOGtHYjs0bRKdwXTeAq4fDq0vCQXMJF2fwAQ
+LEYWs7kabKhcPpWzTtoCG78WzR3TgldEPhPjE0offvVQO56x1XDqMBctoiDWkWkS
+bdi03GhbFdK5A7uYBTJYEoo61Yp/2/MjyQARAQABiQG2BBgBAgAgAhsMFiEEa8BK
+Wj3bNXZrmkDYL7kXkRiJjosFAlxVsI8ACgkQL7kXkRiJjoumjwv/c6a9G1bi3sh7
+wRFhpsrFUoFfEBDI4eyI/haWhCIfI8n7p3lCSIy8lmf9yvUs75d5M3EQW08NQjIs
+/o8FcFoUBnKQv2whWSHTpx/BkuhcNVY+NIwyBKomU0WkFSm3+80ix0uh97KSlRlW
+Q5nMVExNxZ4mRFAhDQrJ2/pZ2DaddeO+4uZ7Twquaix+PMxpNKvkj2+757L23YjF
+QmHdk6E8burofpSCfBTB84eUSDvzs6Eb/34/KlbBZhKMYdffMDCSAZIMfIav6YVJ
+UDzT40kmS0vRW6bDIetSbpBM+GD1cSq0wKdlt+Giur9ZiaiyHIEqbPgr6WgdND25
+Vx/i23Ik2o8wMb0Ub8cKD9wjdGAk+Rt2r7d2RzyO/R3ThKbUOGkQX6acAAZAjhPs
+UGxt1dDojmQ3nF4l2hZ9PcsyD3pz226wUUPT4JA1eE6tdoVjzY2J7EhfNaVcQQlb
+bQJQ+BQcO4oP1mPRCx1GiSmB+jRNQ4npxVJxLO/j7T27CrSZbhT7
+=aibx
+-----END PGP PUBLIC KEY BLOCK-----
diff --git a/org.eclipse.jgit.gpg.bc.test/tst-rsrc/org/eclipse/jgit/gpg/bc/internal/keys/secp256k1.asc b/org.eclipse.jgit.gpg.bc.test/tst-rsrc/org/eclipse/jgit/gpg/bc/internal/keys/secp256k1.asc
new file mode 100644
index 0000000..837f8a8
--- /dev/null
+++ b/org.eclipse.jgit.gpg.bc.test/tst-rsrc/org/eclipse/jgit/gpg/bc/internal/keys/secp256k1.asc
@@ -0,0 +1,14 @@
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+
+mE8EWsOE8xMFK4EEAAoCAwQVHqFZWqedXUIkNFs82PsQB3bsCDhrL/73xZca3+vo
+kB4T7jHcACThuMZYuUqUo9NzNTJioluOvZG+UdYXPdfdtAplY2MtcDI1NmsxiJQE
+ExMIADwCGwMFCwkIBwIDIgIBBhUKCQgLAgQWAgMBAh4DAheAFiEEgfdytX1Ov+cA
+CmYjPqW7b5aSwaAFAlxVsQ0ACgkQPqW7b5aSwaD2tQD/R4d15NBuSJ6IB1brH0E9
+nEWkqo892PaAY5akdCO/i9EBAMsjE5NPxBnCs03c+VHFU200k27ixdrWpUa+HZEI
+A5wSuFMEWsOE8xIFK4EEAAoCAwSUWwe7CaaOYRANiKet2evLiOumefIHuvRpyOSK
+hyRdclIWpBUCAWEnmalkEL/8cEM5fjtILtCOKXqCOBsPv45HAwEIB4h4BBgTCAAg
+AhsMFiEEgfdytX1Ov+cACmYjPqW7b5aSwaAFAlxVsRUACgkQPqW7b5aSwaCETgD/
+YXzCMYMbPGAU2oTitjAno8hDWmgTeaFWeCmqf6l9mP8BAKvpewWeFGZfWGAQcWPi
+E+jv7vadvEt1yMA8rmT041F5
+=mDCI
+-----END PGP PUBLIC KEY BLOCK-----
diff --git a/org.eclipse.jgit.gpg.bc.test/tst-rsrc/org/eclipse/jgit/gpg/bc/internal/keys/x25519.asc b/org.eclipse.jgit.gpg.bc.test/tst-rsrc/org/eclipse/jgit/gpg/bc/internal/keys/x25519.asc
new file mode 100644
index 0000000..d531d7a
--- /dev/null
+++ b/org.eclipse.jgit.gpg.bc.test/tst-rsrc/org/eclipse/jgit/gpg/bc/internal/keys/x25519.asc
@@ -0,0 +1,13 @@
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+
+mDMEW8SVGhYJKwYBBAHaRw8BAQdA9SMZ2uw0YugMFcl5TpEZeBRAGniEk9a42XNs
+7QA4Tky0DGVkZHNhLXgyNTUxOYiQBBMWCAA4FiEETJc4pvK+Thp5bJt7lBgioPwb
+MKUFAlvElRoCGwMFCwkIBwIGFQoJCAsCBBYCAwECHgECF4AACgkQlBgioPwbMKUi
+1wEAgMq3X7o17OJBPfY3He/exDR6LhWwAAXrVQR/WdRiHkEBALd1Mj0BlZZLoKTr
+uJ4MD5CYZLicXTRwOv6e52F/DHwJuDgEW8SVGhIKKwYBBAGXVQEFAQEHQA0Lh2mG
+lB1O4xDYgztm/aX7+8AdHEGaMsCF1RQ6wVUeAwEIB4h4BBgWCAAgFiEETJc4pvK+
+Thp5bJt7lBgioPwbMKUFAlvElRoCGwwACgkQlBgioPwbMKXmlQD+KxVg2dGL8lRW
+rQajwzmuwMrJX1lvJylg5Ozk6SGrBeABANZrdt8bmArEqeRVxFO2F4P7btyIpf1w
+5aNpqqtvkRcB
+=EYfV
+-----END PGP PUBLIC KEY BLOCK-----
diff --git a/org.eclipse.jgit.gpg.bc.test/tst/org/eclipse/jgit/gpg/bc/internal/keys/KeyGrip25519Test.java b/org.eclipse.jgit.gpg.bc.test/tst/org/eclipse/jgit/gpg/bc/internal/keys/KeyGrip25519Test.java
new file mode 100644
index 0000000..e300802
--- /dev/null
+++ b/org.eclipse.jgit.gpg.bc.test/tst/org/eclipse/jgit/gpg/bc/internal/keys/KeyGrip25519Test.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2021, Thomas Wolf <thomas.wolf@paranor.ch> and others
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0 which is available at
+ * https://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+package org.eclipse.jgit.gpg.bc.internal.keys;
+
+import static org.junit.Assert.assertEquals;
+
+import java.math.BigInteger;
+import java.util.Locale;
+
+import org.bouncycastle.openpgp.PGPException;
+import org.bouncycastle.util.encoders.Hex;
+import org.eclipse.jgit.util.sha1.SHA1;
+import org.junit.Test;
+
+public class KeyGrip25519Test {
+
+	interface Hash {
+		byte[] hash(SHA1 sha, BigInteger q) throws PGPException;
+	}
+
+	private void assertKeyGrip(String key, String expectedKeyGrip, Hash hash)
+			throws Exception {
+		SHA1 grip = SHA1.newInstance();
+		grip.setDetectCollision(false);
+		BigInteger pk = new BigInteger(key, 16);
+		byte[] keyGrip = hash.hash(grip, pk);
+		assertEquals("Keygrip should match", expectedKeyGrip,
+				Hex.toHexString(keyGrip).toUpperCase(Locale.ROOT));
+	}
+
+	@Test
+	public void testCompressed() throws Exception {
+		assertKeyGrip("40"
+				+ "773E72848C1FD5F9652B29E2E7AF79571A04990E96F2016BF4E0EC1890C2B7DB",
+				"9DB6C64A38830F4960701789475520BE8C821F47",
+				KeyGrip::hashEd25519);
+	}
+
+	@Test
+	public void testCompressedNoPrefix() throws Exception {
+		assertKeyGrip(
+				"773E72848C1FD5F9652B29E2E7AF79571A04990E96F2016BF4E0EC1890C2B7DB",
+				"9DB6C64A38830F4960701789475520BE8C821F47",
+				KeyGrip::hashEd25519);
+	}
+
+	@Test
+	public void testCurve25519() throws Exception {
+		assertKeyGrip("40"
+				+ "918C1733127F6BF2646FAE3D081A18AE77111C903B906310B077505EFFF12740",
+				"0F89A565D3EA187CE839332398F5D480677DF49C",
+				KeyGrip::hashCurve25519);
+	}
+}
diff --git a/org.eclipse.jgit.gpg.bc.test/tst/org/eclipse/jgit/gpg/bc/internal/keys/KeyGripTest.java b/org.eclipse.jgit.gpg.bc.test/tst/org/eclipse/jgit/gpg/bc/internal/keys/KeyGripTest.java
new file mode 100644
index 0000000..a4aaf40
--- /dev/null
+++ b/org.eclipse.jgit.gpg.bc.test/tst/org/eclipse/jgit/gpg/bc/internal/keys/KeyGripTest.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2021, Thomas Wolf <thomas.wolf@paranor.ch> and others
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0 which is available at
+ * https://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+package org.eclipse.jgit.gpg.bc.internal.keys;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.Security;
+import java.util.Iterator;
+import java.util.Locale;
+import java.util.function.Consumer;
+
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.bouncycastle.openpgp.PGPException;
+import org.bouncycastle.openpgp.PGPPublicKey;
+import org.bouncycastle.openpgp.PGPPublicKeyRing;
+import org.bouncycastle.openpgp.PGPPublicKeyRingCollection;
+import org.bouncycastle.openpgp.PGPUtil;
+import org.bouncycastle.openpgp.operator.jcajce.JcaKeyFingerprintCalculator;
+import org.bouncycastle.util.encoders.Hex;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class KeyGripTest {
+
+	@BeforeClass
+	public static void ensureBC() {
+		if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null) {
+			Security.addProvider(new BouncyCastleProvider());
+		}
+	}
+
+	protected static class TestData {
+
+		String filename;
+
+		String[] expectedKeyGrips;
+
+		TestData(String filename, String... keyGrips) {
+			this.filename = filename;
+			this.expectedKeyGrips = keyGrips;
+		}
+
+		@Override
+		public String toString() {
+			return filename;
+		}
+	}
+
+	@Parameters(name = "{0}")
+	public static TestData[] initTestData() {
+		return new TestData[] {
+				new TestData("rsa.asc",
+						"D148210FAF36468055B83D0F5A6DEB83FBC8E864",
+						"A5E4CD2CBBE44A16E4D6EC05C2E3C3A599DC763C"),
+				new TestData("dsa-elgamal.asc",
+						"552286BEB2999F0A9E26A50385B90D9724001187",
+						"CED7034A8EB5F4CE90DF99147EC33D86FCD3296C"),
+				new TestData("brainpool256.asc",
+						"A01BAA22A72F09A0FF0A1D4CBCE70844DD52DDD7",
+						"C1678B7DE5F144C93B89468D5F9764ACE182ED36"),
+				new TestData("brainpool384.asc",
+						"2F25DB025DEBF3EA2715350209B985829B04F50A",
+						"B6BD8B81F75AF914163D97DF8DE8F6FC64C283F8"),
+				new TestData("brainpool512.asc",
+						"5A484F56AB4B8B6583B6365034999F6543FAE1AE",
+						"9133E4A7E8FC8515518DF444C3F2F247EEBBADEC"),
+				new TestData("nistp256.asc",
+						"FC81AECE90BCE6E54D0D637D266109783AC8DAC0",
+						"A56DC8DB8355747A809037459B4258B8A743EAB5"),
+				new TestData("nistp384.asc",
+						"A1338230AED1C9C125663518470B49056C9D1733",
+						"797A83FE041FFE06A7F4B1D32C6F4AE0F6D87ADF"),
+				new TestData("nistp521.asc",
+						"D91B789603EC9138AA20342A2B6DC86C81B70F5D",
+						"FD048B2CA1919CB241DC8A2C7FA3E742EF343DCA"),
+				new TestData("secp256k1.asc",
+						"498B89C485489BA16B40755C0EBA580166393074",
+						"48FFED40D018747363BDEFFDD404D1F4870F8064"),
+				new TestData("ed25519.asc",
+						"940D97D75C306D737A59A98EAFF1272832CEDC0B"),
+				new TestData("x25519.asc",
+						"A77DC8173DA6BEE126F5BD6F5A14E01200B52FCE",
+						"636C983EDB558527BA82780B52CB5DAE011BE46B")
+		};
+	}
+
+	// Injected by JUnit
+	@Parameter
+	public TestData data;
+
+	private void readAsc(InputStream in, Consumer<PGPPublicKey> process)
+			throws IOException, PGPException {
+		PGPPublicKeyRingCollection pgpPub = new PGPPublicKeyRingCollection(
+			PGPUtil.getDecoderStream(in), new JcaKeyFingerprintCalculator());
+
+		Iterator<PGPPublicKeyRing> keyRings = pgpPub.getKeyRings();
+		while (keyRings.hasNext()) {
+			PGPPublicKeyRing keyRing = keyRings.next();
+
+			Iterator<PGPPublicKey> keys = keyRing.getPublicKeys();
+			while (keys.hasNext()) {
+				process.accept(keys.next());
+			}
+		}
+	}
+
+	@Test
+	public void testGrip() throws Exception {
+		try (InputStream in = this.getClass()
+				.getResourceAsStream(data.filename)) {
+			int index[] = { 0 };
+			readAsc(in, key -> {
+				byte[] keyGrip = null;
+				try {
+					keyGrip = KeyGrip.getKeyGrip(key);
+				} catch (PGPException e) {
+					throw new RuntimeException(e);
+				}
+				assertTrue("More keys than expected",
+						index[0] < data.expectedKeyGrips.length);
+				assertEquals("Wrong keygrip", data.expectedKeyGrips[index[0]++],
+						Hex.toHexString(keyGrip).toUpperCase(Locale.ROOT));
+			});
+			assertEquals("Missing keys", data.expectedKeyGrips.length,
+					index[0]);
+		}
+	}
+}
diff --git a/org.eclipse.jgit.gpg.bc.test/tst/org/eclipse/jgit/gpg/bc/internal/keys/SecretKeysTest.java b/org.eclipse.jgit.gpg.bc.test/tst/org/eclipse/jgit/gpg/bc/internal/keys/SecretKeysTest.java
new file mode 100644
index 0000000..5e5e303
--- /dev/null
+++ b/org.eclipse.jgit.gpg.bc.test/tst/org/eclipse/jgit/gpg/bc/internal/keys/SecretKeysTest.java
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2021 Thomas Wolf <thomas.wolf@paranor.ch> and others
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0 which is available at
+ * https://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+package org.eclipse.jgit.gpg.bc.internal.keys;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.io.BufferedInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.Security;
+import java.util.Iterator;
+
+import javax.crypto.Cipher;
+
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.bouncycastle.openpgp.PGPException;
+import org.bouncycastle.openpgp.PGPPublicKey;
+import org.bouncycastle.openpgp.PGPPublicKeyRing;
+import org.bouncycastle.openpgp.PGPPublicKeyRingCollection;
+import org.bouncycastle.openpgp.PGPSecretKey;
+import org.bouncycastle.openpgp.PGPUtil;
+import org.bouncycastle.openpgp.operator.PGPDigestCalculatorProvider;
+import org.bouncycastle.openpgp.operator.jcajce.JcaKeyFingerprintCalculator;
+import org.bouncycastle.openpgp.operator.jcajce.JcaPGPDigestCalculatorProviderBuilder;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class SecretKeysTest {
+
+	@BeforeClass
+	public static void ensureBC() {
+		if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null) {
+			Security.addProvider(new BouncyCastleProvider());
+		}
+	}
+
+	private static volatile Boolean haveOCB;
+
+	private static boolean ocbAvailable() {
+		Boolean haveIt = haveOCB;
+		if (haveIt != null) {
+			return haveIt.booleanValue();
+		}
+		try {
+			Cipher c = Cipher.getInstance("AES/OCB/NoPadding"); //$NON-NLS-1$
+			if (c == null) {
+				haveOCB = Boolean.FALSE;
+				return false;
+			}
+		} catch (NoClassDefFoundError | Exception e) {
+			haveOCB = Boolean.FALSE;
+			return false;
+		}
+		haveOCB = Boolean.TRUE;
+		return true;
+	}
+
+	private static class TestData {
+
+		final String name;
+
+		final boolean encrypted;
+
+		final boolean keyValue;
+
+		TestData(String name, boolean encrypted, boolean keyValue) {
+			this.name = name;
+			this.encrypted = encrypted;
+			this.keyValue = keyValue;
+		}
+
+		@Override
+		public String toString() {
+			return name;
+		}
+	}
+
+	@Parameters(name = "{0}")
+	public static TestData[] initTestData() {
+		return new TestData[] {
+				new TestData("AFDA8EA10E185ACF8C0D0F8885A0EF61A72ECB11", false, false),
+				new TestData("2FB05DBB70FC07CB84C13431F640CA6CEA1DBF8A", false, true),
+				new TestData("66CCECEC2AB46A9735B10FEC54EDF9FD0F77BAF9", true, true),
+				new TestData("F727FAB884DA3BD402B6E0F5472E108D21033124", true, true),
+				new TestData("faked", false, true) };
+	}
+
+	private static byte[] readTestKey(String filename) throws Exception {
+		try (InputStream in = new BufferedInputStream(
+				SecretKeysTest.class.getResourceAsStream(filename))) {
+			return SecretKeys.keyFromNameValueFormat(in);
+		}
+	}
+
+	private static PGPPublicKey readAsc(InputStream in)
+			throws IOException, PGPException {
+		PGPPublicKeyRingCollection pgpPub = new PGPPublicKeyRingCollection(
+			PGPUtil.getDecoderStream(in), new JcaKeyFingerprintCalculator());
+
+		Iterator<PGPPublicKeyRing> keyRings = pgpPub.getKeyRings();
+		while (keyRings.hasNext()) {
+			PGPPublicKeyRing keyRing = keyRings.next();
+
+			Iterator<PGPPublicKey> keys = keyRing.getPublicKeys();
+			if (keys.hasNext()) {
+				return keys.next();
+			}
+		}
+		return null;
+	}
+
+	// Injected by JUnit
+	@Parameter
+	public TestData data;
+
+	@Test
+	public void testKeyRead() throws Exception {
+		if (data.keyValue) {
+			byte[] bytes = readTestKey(data.name + ".key");
+			assertEquals('(', bytes[0]);
+			assertEquals(')', bytes[bytes.length - 1]);
+		}
+		try (InputStream pubIn = this.getClass()
+				.getResourceAsStream(data.name + ".asc")) {
+			if (pubIn != null) {
+				PGPPublicKey publicKey = readAsc(pubIn);
+				// Do a full test trying to load the secret key.
+				PGPDigestCalculatorProvider calculatorProvider = new JcaPGPDigestCalculatorProviderBuilder()
+						.build();
+				try (InputStream in = new BufferedInputStream(this.getClass()
+						.getResourceAsStream(data.name + ".key"))) {
+					PGPSecretKey secretKey = SecretKeys.readSecretKey(in,
+							calculatorProvider,
+							data.encrypted ? () -> "nonsense".toCharArray()
+									: null,
+							publicKey);
+					assertNotNull(secretKey);
+				} catch (PGPException e) {
+					// Currently we may not be able to load OCB-encrypted keys.
+					assertTrue(e.getMessage().contains("OCB"));
+					assertTrue(data.encrypted);
+					assertFalse(ocbAvailable());
+				}
+			}
+		}
+	}
+
+}
diff --git a/org.eclipse.jgit.gpg.bc/META-INF/MANIFEST.MF b/org.eclipse.jgit.gpg.bc/META-INF/MANIFEST.MF
index 655dcca..afb0ee1 100644
--- a/org.eclipse.jgit.gpg.bc/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.gpg.bc/META-INF/MANIFEST.MF
@@ -8,22 +8,30 @@
 Bundle-Localization: plugin
 Bundle-Version: 5.11.0.qualifier
 Bundle-RequiredExecutionEnvironment: JavaSE-1.8
-Import-Package: org.bouncycastle.bcpg;version="[1.65.0,2.0.0)",
+Import-Package: org.bouncycastle.asn1;version="[1.65.0,2.0.0)",
+ org.bouncycastle.asn1.cryptlib;version="[1.65.0,2.0.0)",
+ org.bouncycastle.asn1.x9;version="[1.65.0,2.0.0)",
+ org.bouncycastle.bcpg;version="[1.65.0,2.0.0)",
+ org.bouncycastle.bcpg.sig;version="[1.65.0,2.0.0)",
+ org.bouncycastle.crypto.ec;version="[1.65.0,2.0.0)",
  org.bouncycastle.gpg;version="[1.65.0,2.0.0)",
  org.bouncycastle.gpg.keybox;version="[1.65.0,2.0.0)",
  org.bouncycastle.gpg.keybox.jcajce;version="[1.65.0,2.0.0)",
+ org.bouncycastle.jcajce.interfaces;version="[1.65.0,2.0.0)",
+ org.bouncycastle.jcajce.util;version="[1.65.0,2.0.0)",
  org.bouncycastle.jce.provider;version="[1.65.0,2.0.0)",
+ org.bouncycastle.math.ec;version="[1.65.0,2.0.0)",
+ org.bouncycastle.math.field;version="[1.65.0,2.0.0)",
  org.bouncycastle.openpgp;version="[1.65.0,2.0.0)",
+ org.bouncycastle.openpgp.jcajce;version="[1.65.0,2.0.0)",
  org.bouncycastle.openpgp.operator;version="[1.65.0,2.0.0)",
  org.bouncycastle.openpgp.operator.jcajce;version="[1.65.0,2.0.0)",
+ org.bouncycastle.util;version="[1.65.0,2.0.0)",
  org.bouncycastle.util.encoders;version="[1.65.0,2.0.0)",
+ org.bouncycastle.util.io;version="[1.65.0,2.0.0)",
  org.eclipse.jgit.annotations;version="[5.11.0,5.12.0)",
  org.eclipse.jgit.api.errors;version="[5.11.0,5.12.0)",
- org.eclipse.jgit.errors;version="[5.11.0,5.12.0)",
- org.eclipse.jgit.lib;version="[5.11.0,5.12.0)",
- org.eclipse.jgit.nls;version="[5.11.0,5.12.0)",
- org.eclipse.jgit.transport;version="[5.11.0,5.12.0)",
- org.eclipse.jgit.util;version="[5.11.0,5.12.0)",
  org.slf4j;version="[1.7.0,2.0.0)"
-Export-Package: org.eclipse.jgit.gpg.bc.internal;version="5.11.0";
-  x-friends:="org.eclipse.jgit.gpg.bc.test"
+Export-Package: org.eclipse.jgit.gpg.bc;version="5.11.0",
+ org.eclipse.jgit.gpg.bc.internal;version="5.11.0";x-friends:="org.eclipse.jgit.gpg.bc.test",
+ org.eclipse.jgit.gpg.bc.internal.keys;version="5.11.0";x-friends:="org.eclipse.jgit.gpg.bc.test"
diff --git a/org.eclipse.jgit.gpg.bc/about.html b/org.eclipse.jgit.gpg.bc/about.html
index f971af1..fc527d5 100644
--- a/org.eclipse.jgit.gpg.bc/about.html
+++ b/org.eclipse.jgit.gpg.bc/about.html
@@ -11,7 +11,7 @@
     margin: 0.25in 0.5in 0.25in 0.5in;
     tab-interval: 0.5in;
     }
-  p {  	
+  p {
     margin-left: auto;
     margin-top:  0.5em;
     margin-bottom: 0.5em;
@@ -36,60 +36,53 @@
 <p>Copyright (c) 2007, Eclipse Foundation, Inc. and its licensors. </p>
 
 <p>All rights reserved.</p>
-<p>Redistribution and use in source and binary forms, with or without modification, 
+<p>Redistribution and use in source and binary forms, with or without modification,
 	are permitted provided that the following conditions are met:
-<ul><li>Redistributions of source code must retain the above copyright notice, 
+<ul><li>Redistributions of source code must retain the above copyright notice,
 	this list of conditions and the following disclaimer. </li>
-<li>Redistributions in binary form must reproduce the above copyright notice, 
-	this list of conditions and the following disclaimer in the documentation 
+<li>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. </li>
-<li>Neither the name of the Eclipse Foundation, Inc. nor the names of its 
-	contributors may be used to endorse or promote products derived from 
+<li>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. </li></ul>
 </p>
-<p>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 
+<p>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.</p>
 
 <hr>
-<p><b>SHA-1 UbcCheck - MIT</b></p>
+<p><b>org.eclipse.jgit.gpg.bc.internal.keys.SExprParser - MIT</b></p>
 
-<p>Copyright (c) 2017:</p>
-<div class="ubc-name">
-Marc Stevens
-Cryptology Group
-Centrum Wiskunde & Informatica
-P.O. Box 94079, 1090 GB Amsterdam, Netherlands
-marc@marc-stevens.nl
-</div>
-<div class="ubc-name">
-Dan Shumow
-Microsoft Research
-danshu@microsoft.com
-</div>
-<p>Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
+<p>Copyright (c) 2000-2021 The Legion of the Bouncy Castle Inc.
+(<a href="https://www.bouncycastle.org">https://www.bouncycastle.org</a>)</p>
+
+<p>
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+and associated documentation files (the "Software"), to deal in the Software without restriction,
+including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
 </p>
-<ul><li>The above copyright notice and this permission notice shall be included
-in all copies or substantial portions of the Software.</li></ul>
-<p>THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.</p>
+<p>
+The above copyright notice and this permission notice shall be included in all copies or substantial
+portions of the Software.
+</p>
+<p>
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+</p>
 
 </body>
 
diff --git a/org.eclipse.jgit.gpg.bc/resources/META-INF/services/org.eclipse.jgit.lib.GpgSignatureVerifierFactory b/org.eclipse.jgit.gpg.bc/resources/META-INF/services/org.eclipse.jgit.lib.GpgSignatureVerifierFactory
new file mode 100644
index 0000000..17ab30f
--- /dev/null
+++ b/org.eclipse.jgit.gpg.bc/resources/META-INF/services/org.eclipse.jgit.lib.GpgSignatureVerifierFactory
@@ -0,0 +1 @@
+org.eclipse.jgit.gpg.bc.internal.BouncyCastleGpgSignatureVerifierFactory
\ No newline at end of file
diff --git a/org.eclipse.jgit.gpg.bc/resources/org/eclipse/jgit/gpg/bc/internal/BCText.properties b/org.eclipse.jgit.gpg.bc/resources/org/eclipse/jgit/gpg/bc/internal/BCText.properties
index 1441c63..e4b1bab 100644
--- a/org.eclipse.jgit.gpg.bc/resources/org/eclipse/jgit/gpg/bc/internal/BCText.properties
+++ b/org.eclipse.jgit.gpg.bc/resources/org/eclipse/jgit/gpg/bc/internal/BCText.properties
@@ -1,11 +1,36 @@
+corrupt25519Key=Ed25519/Curve25519 public key has wrong length: {0}
 credentialPassphrase=Passphrase
-gpgFailedToParseSecretKey=Failed to parse secret key file in directory: {0}. Is the entered passphrase correct?
+cryptCipherError=Cannot create cipher to decrypt: {0}
+cryptWrongDecryptedLength=Decrypted key has wrong length; expected {0} bytes, got only {1} bytes
+gpgFailedToParseSecretKey=Failed to parse secret key file {0}. Is the entered passphrase correct?
 gpgNoCredentialsProvider=missing credentials provider
+gpgNoKeygrip=Cannot find key {0}: cannot determine key grip
 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}
+gpgNoSuchAlgorithm=Cannot decrypt encrypted secret key: encryption algorithm {0} is not available
 gpgNotASigningKey=Secret key ({0}) is not suitable for signing
 gpgKeyInfo=GPG Key (fingerprint {0})
 gpgSigningCancelled=Signing was cancelled
+nonSignatureError=Signature does not decode into a signature object
+secretKeyTooShort=Secret key file corrupt; only {0} bytes read
+sexprHexNotClosed=Hex number in s-expression not closed
+sexprHexOdd=Hex number in s-expression has an odd number of digits
+sexprStringInvalidEscape=Invalid escape {0} in s-expression
+sexprStringInvalidEscapeAtEnd=Invalid s-expression: quoted string ends with escape character
+sexprStringInvalidHexEscape=Invalid hex escape in s-expression
+sexprStringInvalidOctalEscape=Invalid octal escape in s-expression
+sexprStringNotClosed=String in s-expression not closed
+sexprUnhandled=Unhandled token {0} in s-expression
+signatureInconsistent=Inconsistent signature; key ID {0} does not match issuer fingerprint {1}
+signatureKeyLookupError=Error occurred while looking for public key
+signatureNoKeyInfo=No way to determine a public key from the signature
+signatureNoPublicKey=No public key found to verify the signature
+signatureParseError=Signature cannot be parsed
+signatureVerificationError=Signature verification failed
 unableToSignCommitNoSecretKey=Unable to sign commit. Signing key not available.
+uncompressed25519Key=Cannot handle ed25519 public key with uncompressed data: {0}
+unknownCurve=Unknown curve {0}
+unknownCurveParameters=Curve {0} does not have a prime field
+unknownKeyType=Unknown key type {0}
\ No newline at end of file
diff --git a/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/BouncyCastleGpgSignerFactory.java b/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/BouncyCastleGpgSignerFactory.java
new file mode 100644
index 0000000..fdd1a2b
--- /dev/null
+++ b/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/BouncyCastleGpgSignerFactory.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2021 Thomas Wolf <thomas.wolf@paranor.ch> and others
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0 which is available at
+ * https://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+package org.eclipse.jgit.gpg.bc;
+
+import org.eclipse.jgit.gpg.bc.internal.BouncyCastleGpgSigner;
+import org.eclipse.jgit.lib.GpgSigner;
+
+/**
+ * Factory for creating a {@link GpgSigner} based on Bouncy Castle.
+ *
+ * @since 5.11
+ */
+public final class BouncyCastleGpgSignerFactory {
+
+	private BouncyCastleGpgSignerFactory() {
+		// No instantiation
+	}
+
+	/**
+	 * Creates a new {@link GpgSigner}.
+	 *
+	 * @return the {@link GpgSigner}
+	 */
+	public static GpgSigner create() {
+		return new BouncyCastleGpgSigner();
+	}
+}
diff --git a/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/BCText.java b/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/BCText.java
index 1a00b0f..aedf8a5 100644
--- a/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/BCText.java
+++ b/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/BCText.java
@@ -1,3 +1,12 @@
+/*
+ * Copyright (C) 2018, 2021 Salesforce and others
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0 which is available at
+ * https://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
 package org.eclipse.jgit.gpg.bc.internal;
 
 import org.eclipse.jgit.nls.NLS;
@@ -18,16 +27,41 @@
 	}
 
 	// @formatter:off
+	/***/ public String corrupt25519Key;
 	/***/ public String credentialPassphrase;
+	/***/ public String cryptCipherError;
+	/***/ public String cryptWrongDecryptedLength;
 	/***/ public String gpgFailedToParseSecretKey;
 	/***/ public String gpgNoCredentialsProvider;
+	/***/ public String gpgNoKeygrip;
 	/***/ public String gpgNoKeyring;
 	/***/ public String gpgNoKeyInLegacySecring;
 	/***/ public String gpgNoPublicKeyFound;
 	/***/ public String gpgNoSecretKeyForPublicKey;
+	/***/ public String gpgNoSuchAlgorithm;
 	/***/ public String gpgNotASigningKey;
 	/***/ public String gpgKeyInfo;
 	/***/ public String gpgSigningCancelled;
+	/***/ public String nonSignatureError;
+	/***/ public String secretKeyTooShort;
+	/***/ public String sexprHexNotClosed;
+	/***/ public String sexprHexOdd;
+	/***/ public String sexprStringInvalidEscape;
+	/***/ public String sexprStringInvalidEscapeAtEnd;
+	/***/ public String sexprStringInvalidHexEscape;
+	/***/ public String sexprStringInvalidOctalEscape;
+	/***/ public String sexprStringNotClosed;
+	/***/ public String sexprUnhandled;
+	/***/ public String signatureInconsistent;
+	/***/ public String signatureKeyLookupError;
+	/***/ public String signatureNoKeyInfo;
+	/***/ public String signatureNoPublicKey;
+	/***/ public String signatureParseError;
+	/***/ public String signatureVerificationError;
 	/***/ public String unableToSignCommitNoSecretKey;
+	/***/ public String uncompressed25519Key;
+	/***/ public String unknownCurve;
+	/***/ public String unknownCurveParameters;
+	/***/ public String unknownKeyType;
 
 }
diff --git a/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/BouncyCastleGpgKeyLocator.java b/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/BouncyCastleGpgKeyLocator.java
index 1389f8b..cf4d3d2 100644
--- a/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/BouncyCastleGpgKeyLocator.java
+++ b/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/BouncyCastleGpgKeyLocator.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2018, 2020 Salesforce and others
+ * Copyright (C) 2018, 2021 Salesforce and others
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Distribution License v. 1.0 which is available at
@@ -14,25 +14,22 @@
 
 import java.io.BufferedInputStream;
 import java.io.File;
+import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.InputStream;
 import java.net.URISyntaxException;
 import java.nio.file.DirectoryStream;
 import java.nio.file.Files;
 import java.nio.file.InvalidPathException;
+import java.nio.file.NoSuchFileException;
 import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.security.NoSuchAlgorithmException;
 import java.security.NoSuchProviderException;
 import java.text.MessageFormat;
-import java.util.ArrayList;
 import java.util.Iterator;
-import java.util.List;
 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;
@@ -50,15 +47,15 @@
 import org.bouncycastle.openpgp.PGPSecretKeyRingCollection;
 import org.bouncycastle.openpgp.PGPSignature;
 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.gpg.bc.internal.keys.KeyGrip;
+import org.eclipse.jgit.gpg.bc.internal.keys.SecretKeys;
 import org.eclipse.jgit.util.FS;
 import org.eclipse.jgit.util.StringUtils;
 import org.eclipse.jgit.util.SystemReader;
@@ -78,17 +75,10 @@
 
 	}
 
-	/** Thrown if we try to read an encrypted private key without password. */
-	private static class EncryptedPgpKeyException extends RuntimeException {
-
-		private static final long serialVersionUID = 1L;
-
-	}
-
 	private static final Logger log = LoggerFactory
 			.getLogger(BouncyCastleGpgKeyLocator.class);
 
-	private static final Path GPG_DIRECTORY = findGpgDirectory();
+	static final Path GPG_DIRECTORY = findGpgDirectory();
 
 	private static final Path USER_KEYBOX_PATH = GPG_DIRECTORY
 			.resolve("pubring.kbx"); //$NON-NLS-1$
@@ -155,16 +145,13 @@
 
 	private PGPSecretKey attemptParseSecretKey(Path keyFile,
 			PGPDigestCalculatorProvider calculatorProvider,
-			PBEProtectionRemoverFactory passphraseProvider,
-			PGPPublicKey publicKey) {
+			SecretKeys.PassphraseSupplier passphraseSupplier,
+			PGPPublicKey publicKey)
+			throws IOException, PGPException, CanceledException,
+			UnsupportedCredentialItem, URISyntaxException {
 		try (InputStream in = newInputStream(keyFile)) {
-			return new SExprParser(calculatorProvider).parseSecretKey(
-					new BufferedInputStream(in), passphraseProvider, publicKey);
-		} catch (IOException | PGPException | ClassCastException e) {
-			if (log.isDebugEnabled())
-				log.debug("Ignoring unreadable file '{}': {}", keyFile, //$NON-NLS-1$
-						e.getMessage(), e);
-			return null;
+			return SecretKeys.readSecretKey(in, calculatorProvider,
+					passphraseSupplier, publicKey);
 		}
 	}
 
@@ -247,16 +234,32 @@
 		return false;
 	}
 
-	private String toFingerprint(String keyId) {
+	private static String toFingerprint(String keyId) {
 		if (keyId.startsWith("0x")) { //$NON-NLS-1$
 			return keyId.substring(2);
 		}
 		return keyId;
 	}
 
-	private PGPPublicKey findPublicKeyByKeyId(KeyBlob keyBlob)
+	static PGPPublicKey findPublicKey(String fingerprint, String keySpec)
+			throws IOException, PGPException {
+		PGPPublicKey result = findPublicKeyInPubring(USER_PGP_PUBRING_FILE,
+				fingerprint, keySpec);
+		if (result == null && exists(USER_KEYBOX_PATH)) {
+			try {
+				result = findPublicKeyInKeyBox(USER_KEYBOX_PATH, fingerprint,
+						keySpec);
+			} catch (NoSuchAlgorithmException | NoSuchProviderException
+					| IOException | NoOpenPgpKeyException e) {
+				log.error(e.getMessage(), e);
+			}
+		}
+		return result;
+	}
+
+	private static PGPPublicKey findPublicKeyByKeyId(KeyBlob keyBlob,
+			String keyId)
 			throws IOException {
-		String keyId = toFingerprint(signingKey).toLowerCase(Locale.ROOT);
 		if (keyId.isEmpty()) {
 			return null;
 		}
@@ -270,10 +273,11 @@
 		return null;
 	}
 
-	private PGPPublicKey findPublicKeyByUserId(KeyBlob keyBlob)
+	private static PGPPublicKey findPublicKeyByUserId(KeyBlob keyBlob,
+			String keySpec)
 			throws IOException {
 		for (UserID userID : keyBlob.getUserIds()) {
-			if (containsSigningKey(userID.getUserIDAsString(), signingKey)) {
+			if (containsSigningKey(userID.getUserIDAsString(), keySpec)) {
 				return getSigningPublicKey(keyBlob);
 			}
 		}
@@ -285,6 +289,10 @@
 	 *
 	 * @param keyboxFile
 	 *            the KeyBox file
+	 * @param keyId
+	 *            to look for, may be null
+	 * @param keySpec
+	 *            to look for
 	 * @return publicKey the public key (maybe <code>null</code>)
 	 * @throws IOException
 	 *             in case of problems reading the file
@@ -293,19 +301,22 @@
 	 * @throws NoOpenPgpKeyException
 	 *             if the file does not contain any OpenPGP key
 	 */
-	private PGPPublicKey findPublicKeyInKeyBox(Path keyboxFile)
+	private static PGPPublicKey findPublicKeyInKeyBox(Path keyboxFile,
+			String keyId, String keySpec)
 			throws IOException, NoSuchAlgorithmException,
 			NoSuchProviderException, NoOpenPgpKeyException {
 		KeyBox keyBox = readKeyBoxFile(keyboxFile);
+		String id = keyId != null ? keyId
+				: toFingerprint(keySpec).toLowerCase(Locale.ROOT);
 		boolean hasOpenPgpKey = false;
 		for (KeyBlob keyBlob : keyBox.getKeyBlobs()) {
 			if (keyBlob.getType() == BlobType.OPEN_PGP_BLOB) {
 				hasOpenPgpKey = true;
-				PGPPublicKey key = findPublicKeyByKeyId(keyBlob);
+				PGPPublicKey key = findPublicKeyByKeyId(keyBlob, id);
 				if (key != null) {
 					return key;
 				}
-				key = findPublicKeyByUserId(keyBlob);
+				key = findPublicKeyByUserId(keyBlob, keySpec);
 				if (key != null) {
 					return key;
 				}
@@ -349,7 +360,8 @@
 			// pubring.gpg also try secring.gpg to find the secret key.
 			if (exists(USER_KEYBOX_PATH)) {
 				try {
-					publicKey = findPublicKeyInKeyBox(USER_KEYBOX_PATH);
+					publicKey = findPublicKeyInKeyBox(USER_KEYBOX_PATH, null,
+							signingKey);
 					if (publicKey != null) {
 						key = findSecretKeyForKeyBoxPublicKey(publicKey,
 								USER_KEYBOX_PATH);
@@ -372,7 +384,8 @@
 				}
 			}
 			if (exists(USER_PGP_PUBRING_FILE)) {
-				publicKey = findPublicKeyInPubring(USER_PGP_PUBRING_FILE);
+				publicKey = findPublicKeyInPubring(USER_PGP_PUBRING_FILE, null,
+						signingKey);
 				if (publicKey != null) {
 					// GPG < 2.1 may have both; the agent using the directory
 					// and gpg using secring.gpg. GPG >= 2.1 delegates all
@@ -444,67 +457,59 @@
 			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();
-
-		try (Stream<Path> keyFiles = Files.walk(USER_SECRET_KEY_DIR)) {
-			List<Path> allPaths = keyFiles.filter(Files::isRegularFile)
-					.collect(Collectors.toCollection(ArrayList::new));
-			if (allPaths.isEmpty()) {
-				return null;
+		byte[] keyGrip = null;
+		try {
+			keyGrip = KeyGrip.getKeyGrip(publicKey);
+		} catch (PGPException e) {
+			throw new PGPException(
+					MessageFormat.format(BCText.get().gpgNoKeygrip,
+							Hex.toHexString(publicKey.getFingerprint())),
+					e);
+		}
+		String filename = Hex.toHexString(keyGrip).toUpperCase(Locale.ROOT)
+				+ ".key"; //$NON-NLS-1$
+		Path keyFile = USER_SECRET_KEY_DIR.resolve(filename);
+		if (!Files.exists(keyFile)) {
+			return null;
+		}
+		boolean clearPrompt = false;
+		try {
+			PGPDigestCalculatorProvider calculatorProvider = new JcaPGPDigestCalculatorProviderBuilder()
+					.build();
+			clearPrompt = true;
+			PGPSecretKey secretKey = null;
+			try {
+				secretKey = attemptParseSecretKey(keyFile, calculatorProvider,
+						() -> passphrasePrompt.getPassphrase(
+								publicKey.getFingerprint(), userKeyboxPath),
+						publicKey);
+			} catch (PGPException e) {
+				throw new PGPException(MessageFormat.format(
+						BCText.get().gpgFailedToParseSecretKey,
+						keyFile.toAbsolutePath()), e);
 			}
-			PBEProtectionRemoverFactory passphraseProvider = p -> {
-				throw new EncryptedPgpKeyException();
-			};
-			for (int attempts = 0; attempts < 2; attempts++) {
-				// Second pass will traverse only the encrypted keys with a real
-				// passphrase provider.
-				Iterator<Path> pathIterator = allPaths.iterator();
-				while (pathIterator.hasNext()) {
-					Path keyFile = pathIterator.next();
-					try {
-						PGPSecretKey secretKey = attemptParseSecretKey(keyFile,
-								calculatorProvider, passphraseProvider,
-								publicKey);
-						pathIterator.remove();
-						if (secretKey != null) {
-							if (!secretKey.isSigningKey()) {
-								throw new PGPException(MessageFormat.format(
-										BCText.get().gpgNotASigningKey,
-										signingKey));
-							}
-							return new BouncyCastleGpgKey(secretKey,
-									userKeyboxPath);
-						}
-					} catch (EncryptedPgpKeyException e) {
-						// Ignore; we'll try again.
-					}
+			if (secretKey != null) {
+				if (!secretKey.isSigningKey()) {
+					throw new PGPException(MessageFormat.format(
+							BCText.get().gpgNotASigningKey, signingKey));
 				}
-				if (attempts > 0 || allPaths.isEmpty()) {
-					break;
-				}
-				// allPaths contains only the encrypted keys now.
-				passphraseProvider = new JcePBEProtectionRemoverFactory(
-						passphrasePrompt.getPassphrase(
-								publicKey.getFingerprint(), userKeyboxPath));
+				clearPrompt = false;
+				return new BouncyCastleGpgKey(secretKey, userKeyboxPath);
 			}
-
-			passphrasePrompt.clear();
 			return null;
 		} catch (RuntimeException e) {
-			passphrasePrompt.clear();
 			throw e;
+		} catch (FileNotFoundException | NoSuchFileException e) {
+			clearPrompt = false;
+			return null;
 		} catch (IOException e) {
-			passphrasePrompt.clear();
 			throw new PGPException(MessageFormat.format(
 					BCText.get().gpgFailedToParseSecretKey,
-					USER_SECRET_KEY_DIR.toAbsolutePath()), e);
+					keyFile.toAbsolutePath()), e);
+		} finally {
+			if (clearPrompt) {
+				passphrasePrompt.clear();
+			}
 		}
 	}
 
@@ -562,6 +567,11 @@
 	 * Return the first public key matching the key id ({@link #signingKey}.
 	 *
 	 * @param pubringFile
+	 *            to search
+	 * @param keyId
+	 *            to look for, may be null
+	 * @param keySpec
+	 *            to look for
 	 *
 	 * @return the PGP public key, or {@code null} if none found
 	 * @throws IOException
@@ -569,14 +579,16 @@
 	 * @throws PGPException
 	 *             on BouncyCastle errors
 	 */
-	private PGPPublicKey findPublicKeyInPubring(Path pubringFile)
+	private static PGPPublicKey findPublicKeyInPubring(Path pubringFile,
+			String keyId, String keySpec)
 			throws IOException, PGPException {
 		try (InputStream in = newInputStream(pubringFile)) {
 			PGPPublicKeyRingCollection pgpPub = new PGPPublicKeyRingCollection(
 					new BufferedInputStream(in),
 					new JcaKeyFingerprintCalculator());
 
-			String keyId = toFingerprint(signingKey).toLowerCase(Locale.ROOT);
+			String id = keyId != null ? keyId
+					: toFingerprint(keySpec).toLowerCase(Locale.ROOT);
 			Iterator<PGPPublicKeyRing> keyrings = pgpPub.getKeyRings();
 			while (keyrings.hasNext()) {
 				PGPPublicKeyRing keyRing = keyrings.next();
@@ -586,30 +598,33 @@
 					// try key id
 					String fingerprint = Hex.toHexString(key.getFingerprint())
 							.toLowerCase(Locale.ROOT);
-					if (fingerprint.endsWith(keyId)) {
+					if (fingerprint.endsWith(id)) {
 						return key;
 					}
 					// try user id
 					Iterator<String> userIDs = key.getUserIDs();
 					while (userIDs.hasNext()) {
 						String userId = userIDs.next();
-						if (containsSigningKey(userId, signingKey)) {
+						if (containsSigningKey(userId, keySpec)) {
 							return key;
 						}
 					}
 				}
 			}
+		} catch (FileNotFoundException | NoSuchFileException e) {
+			// Ignore and return null
 		}
 		return null;
 	}
 
-	private PGPPublicKey getPublicKey(KeyBlob blob, byte[] fingerprint)
+	private static PGPPublicKey getPublicKey(KeyBlob blob, byte[] fingerprint)
 			throws IOException {
 		return ((PublicKeyRingBlob) blob).getPGPPublicKeyRing()
 				.getPublicKey(fingerprint);
 	}
 
-	private PGPPublicKey getSigningPublicKey(KeyBlob blob) throws IOException {
+	private static PGPPublicKey getSigningPublicKey(KeyBlob blob)
+			throws IOException {
 		PGPPublicKey masterKey = null;
 		Iterator<PGPPublicKey> keys = ((PublicKeyRingBlob) blob)
 				.getPGPPublicKeyRing().getPublicKeys();
@@ -629,7 +644,7 @@
 		return masterKey;
 	}
 
-	private boolean isSigningKey(PGPPublicKey key) {
+	private static boolean isSigningKey(PGPPublicKey key) {
 		Iterator signatures = key.getSignatures();
 		while (signatures.hasNext()) {
 			PGPSignature sig = (PGPSignature) signatures.next();
@@ -641,7 +656,7 @@
 		return false;
 	}
 
-	private KeyBox readKeyBoxFile(Path keyboxFile) throws IOException,
+	private static KeyBox readKeyBoxFile(Path keyboxFile) throws IOException,
 			NoSuchAlgorithmException, NoSuchProviderException,
 			NoOpenPgpKeyException {
 		if (keyboxFile.toFile().length() == 0) {
diff --git a/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/BouncyCastleGpgKeyPassphrasePrompt.java b/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/BouncyCastleGpgKeyPassphrasePrompt.java
index e47f64f..6144195 100644
--- a/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/BouncyCastleGpgKeyPassphrasePrompt.java
+++ b/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/BouncyCastleGpgKeyPassphrasePrompt.java
@@ -17,8 +17,8 @@
 import org.bouncycastle.util.encoders.Hex;
 import org.eclipse.jgit.api.errors.CanceledException;
 import org.eclipse.jgit.errors.UnsupportedCredentialItem;
-import org.eclipse.jgit.transport.CredentialItem.CharArrayType;
 import org.eclipse.jgit.transport.CredentialItem.InformationalMessage;
+import org.eclipse.jgit.transport.CredentialItem.Password;
 import org.eclipse.jgit.transport.CredentialsProvider;
 import org.eclipse.jgit.transport.URIish;
 
@@ -31,7 +31,7 @@
  */
 class BouncyCastleGpgKeyPassphrasePrompt implements AutoCloseable {
 
-	private CharArrayType passphrase;
+	private Password passphrase;
 
 	private CredentialsProvider credentialsProvider;
 
@@ -78,8 +78,7 @@
 			throws PGPException, CanceledException, UnsupportedCredentialItem,
 			URISyntaxException {
 		if (passphrase == null) {
-			passphrase = new CharArrayType(BCText.get().credentialPassphrase,
-					true);
+			passphrase = new Password(BCText.get().credentialPassphrase);
 		}
 
 		if (credentialsProvider == null) {
diff --git a/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/BouncyCastleGpgSignatureVerifier.java b/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/BouncyCastleGpgSignatureVerifier.java
new file mode 100644
index 0000000..7161895
--- /dev/null
+++ b/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/BouncyCastleGpgSignatureVerifier.java
@@ -0,0 +1,388 @@
+/*
+ * Copyright (C) 2021, Thomas Wolf <thomas.wolf@paranor.ch> and others
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0 which is available at
+ * https://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+package org.eclipse.jgit.gpg.bc.internal;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.Security;
+import java.text.MessageFormat;
+import java.time.Instant;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.Locale;
+
+import org.bouncycastle.bcpg.sig.IssuerFingerprint;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.bouncycastle.openpgp.PGPCompressedData;
+import org.bouncycastle.openpgp.PGPException;
+import org.bouncycastle.openpgp.PGPPublicKey;
+import org.bouncycastle.openpgp.PGPSignature;
+import org.bouncycastle.openpgp.PGPSignatureList;
+import org.bouncycastle.openpgp.PGPSignatureSubpacketVector;
+import org.bouncycastle.openpgp.PGPUtil;
+import org.bouncycastle.openpgp.jcajce.JcaPGPObjectFactory;
+import org.bouncycastle.openpgp.operator.jcajce.JcaPGPContentVerifierBuilderProvider;
+import org.bouncycastle.util.encoders.Hex;
+import org.eclipse.jgit.annotations.NonNull;
+import org.eclipse.jgit.annotations.Nullable;
+import org.eclipse.jgit.api.errors.JGitInternalException;
+import org.eclipse.jgit.lib.GpgConfig;
+import org.eclipse.jgit.lib.GpgSignatureVerifier;
+import org.eclipse.jgit.revwalk.RevCommit;
+import org.eclipse.jgit.revwalk.RevObject;
+import org.eclipse.jgit.revwalk.RevTag;
+import org.eclipse.jgit.util.LRUMap;
+import org.eclipse.jgit.util.RawParseUtils;
+import org.eclipse.jgit.util.StringUtils;
+
+/**
+ * A {@link GpgSignatureVerifier} to verify GPG signatures using BouncyCastle.
+ */
+public class BouncyCastleGpgSignatureVerifier implements GpgSignatureVerifier {
+
+	private static void registerBouncyCastleProviderIfNecessary() {
+		if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null) {
+			Security.addProvider(new BouncyCastleProvider());
+		}
+	}
+
+	/**
+	 * Creates a new instance and registers the BouncyCastle security provider
+	 * if needed.
+	 */
+	public BouncyCastleGpgSignatureVerifier() {
+		registerBouncyCastleProviderIfNecessary();
+	}
+
+	// To support more efficient signature verification of multiple objects we
+	// cache public keys once found in a LRU cache.
+
+	private static final Object NO_KEY = new Object();
+
+	private LRUMap<String, Object> byFingerprint = new LRUMap<>(16, 200);
+
+	private LRUMap<String, Object> bySigner = new LRUMap<>(16, 200);
+
+	@Override
+	public String getName() {
+		return "bc"; //$NON-NLS-1$
+	}
+
+	@Override
+	@Nullable
+	public SignatureVerification verifySignature(@NonNull RevObject object,
+			@NonNull GpgConfig config) throws IOException {
+		if (object instanceof RevCommit) {
+			RevCommit commit = (RevCommit) object;
+			byte[] signatureData = commit.getRawGpgSignature();
+			if (signatureData == null) {
+				return null;
+			}
+			byte[] raw = commit.getRawBuffer();
+			// Now remove the GPG signature
+			byte[] header = { 'g', 'p', 'g', 's', 'i', 'g' };
+			int start = RawParseUtils.headerStart(header, raw, 0);
+			if (start < 0) {
+				return null;
+			}
+			int end = RawParseUtils.headerEnd(raw, start);
+			// start is at the beginning of the header's content
+			start -= header.length + 1;
+			// end is on the terminating LF; we need to skip that, too
+			if (end < raw.length) {
+				end++;
+			}
+			byte[] data = new byte[raw.length - (end - start)];
+			System.arraycopy(raw, 0, data, 0, start);
+			System.arraycopy(raw, end, data, start, raw.length - end);
+			return verify(data, signatureData);
+		} else if (object instanceof RevTag) {
+			RevTag tag = (RevTag) object;
+			byte[] signatureData = tag.getRawGpgSignature();
+			if (signatureData == null) {
+				return null;
+			}
+			byte[] raw = tag.getRawBuffer();
+			// The signature is just tacked onto the end of the message, which
+			// is last in the buffer.
+			byte[] data = Arrays.copyOfRange(raw, 0,
+					raw.length - signatureData.length);
+			return verify(data, signatureData);
+		}
+		return null;
+	}
+
+	static PGPSignature parseSignature(InputStream in)
+			throws IOException, PGPException {
+		try (InputStream sigIn = PGPUtil.getDecoderStream(in)) {
+			JcaPGPObjectFactory pgpFactory = new JcaPGPObjectFactory(sigIn);
+			Object obj = pgpFactory.nextObject();
+			if (obj instanceof PGPCompressedData) {
+				obj = new JcaPGPObjectFactory(
+						((PGPCompressedData) obj).getDataStream()).nextObject();
+			}
+			if (obj instanceof PGPSignatureList) {
+				return ((PGPSignatureList) obj).get(0);
+			}
+			return null;
+		}
+	}
+
+	@Override
+	public SignatureVerification verify(byte[] data, byte[] signatureData)
+			throws IOException {
+		PGPSignature signature = null;
+		String fingerprint = null;
+		String signer = null;
+		String keyId = null;
+		try (InputStream sigIn = new ByteArrayInputStream(signatureData)) {
+			signature = parseSignature(sigIn);
+			if (signature != null) {
+				// Try to figure out something to find the public key with.
+				if (signature.hasSubpackets()) {
+					PGPSignatureSubpacketVector packets = signature
+							.getHashedSubPackets();
+					IssuerFingerprint fingerprintPacket = packets
+							.getIssuerFingerprint();
+					if (fingerprintPacket != null) {
+						fingerprint = Hex
+								.toHexString(fingerprintPacket.getFingerprint())
+								.toLowerCase(Locale.ROOT);
+					}
+					signer = packets.getSignerUserID();
+					if (signer != null) {
+						signer = BouncyCastleGpgSigner.extractSignerId(signer);
+					}
+				}
+				keyId = Long.toUnsignedString(signature.getKeyID(), 16)
+						.toLowerCase(Locale.ROOT);
+			} else {
+				throw new JGitInternalException(BCText.get().nonSignatureError);
+			}
+		} catch (PGPException e) {
+			throw new JGitInternalException(BCText.get().signatureParseError,
+					e);
+		}
+		Date signatureCreatedAt = signature.getCreationTime();
+		if (fingerprint == null && signer == null && keyId == null) {
+			return new VerificationResult(signatureCreatedAt, null, null, null,
+					false, false, TrustLevel.UNKNOWN,
+					BCText.get().signatureNoKeyInfo);
+		}
+		if (fingerprint != null && keyId != null
+				&& !fingerprint.endsWith(keyId)) {
+			return new VerificationResult(signatureCreatedAt, signer, fingerprint,
+					null, false, false, TrustLevel.UNKNOWN,
+					MessageFormat.format(BCText.get().signatureInconsistent,
+							keyId, fingerprint));
+		}
+		if (fingerprint == null && keyId != null) {
+			fingerprint = keyId;
+		}
+		// Try to find the public key
+		String keySpec = '<' + signer + '>';
+		Object cached = null;
+		PGPPublicKey publicKey = null;
+		try {
+			cached = byFingerprint.get(fingerprint);
+			if (cached != null) {
+				if (cached instanceof PGPPublicKey) {
+					publicKey = (PGPPublicKey) cached;
+				}
+			} else if (!StringUtils.isEmptyOrNull(signer)) {
+				cached = bySigner.get(signer);
+				if (cached != null) {
+					if (cached instanceof PGPPublicKey) {
+						publicKey = (PGPPublicKey) cached;
+					}
+				}
+			}
+			if (cached == null) {
+				publicKey = BouncyCastleGpgKeyLocator.findPublicKey(fingerprint,
+						keySpec);
+			}
+		} catch (IOException | PGPException e) {
+			throw new JGitInternalException(
+					BCText.get().signatureKeyLookupError, e);
+		}
+		if (publicKey == null) {
+			if (cached == null) {
+				byFingerprint.put(fingerprint, NO_KEY);
+				byFingerprint.put(keyId, NO_KEY);
+				if (signer != null) {
+					bySigner.put(signer, NO_KEY);
+				}
+			}
+			return new VerificationResult(signatureCreatedAt, signer,
+					fingerprint, null, false, false, TrustLevel.UNKNOWN,
+					BCText.get().signatureNoPublicKey);
+		}
+		if (cached == null) {
+			byFingerprint.put(fingerprint, publicKey);
+			byFingerprint.put(keyId, publicKey);
+			if (signer != null) {
+				bySigner.put(signer, publicKey);
+			}
+		}
+		String user = null;
+		Iterator<String> userIds = publicKey.getUserIDs();
+		if (!StringUtils.isEmptyOrNull(signer)) {
+			while (userIds.hasNext()) {
+				String userId = userIds.next();
+				if (BouncyCastleGpgKeyLocator.containsSigningKey(userId,
+						keySpec)) {
+					user = userId;
+					break;
+				}
+			}
+		}
+		if (user == null) {
+			userIds = publicKey.getUserIDs();
+			if (userIds.hasNext()) {
+				user = userIds.next();
+			}
+		}
+		boolean expired = false;
+		long validFor = publicKey.getValidSeconds();
+		if (validFor > 0 && signatureCreatedAt != null) {
+			Instant expiredAt = publicKey.getCreationTime().toInstant()
+					.plusSeconds(validFor);
+			expired = expiredAt.isBefore(signatureCreatedAt.toInstant());
+		}
+		// Trust data is not defined in OpenPGP; the format is implementation
+		// specific. We don't use the GPG trustdb but simply the trust packet
+		// on the public key, if present. Even if present, it may or may not
+		// be set.
+		byte[] trustData = publicKey.getTrustData();
+		TrustLevel trust = parseGpgTrustPacket(trustData);
+		boolean verified = false;
+		try {
+			signature.init(
+					new JcaPGPContentVerifierBuilderProvider()
+							.setProvider(BouncyCastleProvider.PROVIDER_NAME),
+					publicKey);
+			signature.update(data);
+			verified = signature.verify();
+		} catch (PGPException e) {
+			throw new JGitInternalException(
+					BCText.get().signatureVerificationError, e);
+		}
+		return new VerificationResult(signatureCreatedAt, signer, fingerprint, user,
+				verified, expired, trust, null);
+	}
+
+	private TrustLevel parseGpgTrustPacket(byte[] packet) {
+		if (packet == null || packet.length < 6) {
+			// A GPG trust packet has at least 6 bytes.
+			return TrustLevel.UNKNOWN;
+		}
+		if (packet[2] != 'g' || packet[3] != 'p' || packet[4] != 'g') {
+			// Not a GPG trust packet
+			return TrustLevel.UNKNOWN;
+		}
+		int trust = packet[0] & 0x0F;
+		switch (trust) {
+		case 0: // No determined/set
+		case 1: // Trust expired; i.e., calculation outdated or key expired
+		case 2: // Undefined: not enough information to set
+			return TrustLevel.UNKNOWN;
+		case 3:
+			return TrustLevel.NEVER;
+		case 4:
+			return TrustLevel.MARGINAL;
+		case 5:
+			return TrustLevel.FULL;
+		case 6:
+			return TrustLevel.ULTIMATE;
+		default:
+			return TrustLevel.UNKNOWN;
+		}
+	}
+
+	@Override
+	public void clear() {
+		byFingerprint.clear();
+		bySigner.clear();
+	}
+
+	private static class VerificationResult implements SignatureVerification {
+
+		private final Date creationDate;
+
+		private final String signer;
+
+		private final String keyUser;
+
+		private final String fingerprint;
+
+		private final boolean verified;
+
+		private final boolean expired;
+
+		private final @NonNull TrustLevel trustLevel;
+
+		private final String message;
+
+		public VerificationResult(Date creationDate, String signer,
+				String fingerprint, String user, boolean verified,
+				boolean expired, @NonNull TrustLevel trust, String message) {
+			this.creationDate = creationDate;
+			this.signer = signer;
+			this.fingerprint = fingerprint;
+			this.keyUser = user;
+			this.verified = verified;
+			this.expired = expired;
+			this.trustLevel = trust;
+			this.message = message;
+		}
+
+		@Override
+		public Date getCreationDate() {
+			return creationDate;
+		}
+
+		@Override
+		public String getSigner() {
+			return signer;
+		}
+
+		@Override
+		public String getKeyUser() {
+			return keyUser;
+		}
+
+		@Override
+		public String getKeyFingerprint() {
+			return fingerprint;
+		}
+
+		@Override
+		public boolean isExpired() {
+			return expired;
+		}
+
+		@Override
+		public TrustLevel getTrustLevel() {
+			return trustLevel;
+		}
+
+		@Override
+		public String getMessage() {
+			return message;
+		}
+
+		@Override
+		public boolean getVerified() {
+			return verified;
+		}
+	}
+}
diff --git a/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/BouncyCastleGpgSignatureVerifierFactory.java b/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/BouncyCastleGpgSignatureVerifierFactory.java
new file mode 100644
index 0000000..ae82b75
--- /dev/null
+++ b/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/BouncyCastleGpgSignatureVerifierFactory.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2021, Thomas Wolf <thomas.wolf@paranor.ch> and others
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0 which is available at
+ * https://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+package org.eclipse.jgit.gpg.bc.internal;
+
+import org.eclipse.jgit.lib.GpgSignatureVerifier;
+import org.eclipse.jgit.lib.GpgSignatureVerifierFactory;
+
+/**
+ * A {@link GpgSignatureVerifierFactory} that creates
+ * {@link GpgSignatureVerifier} instances that verify GPG signatures using
+ * BouncyCastle and that do cache public keys.
+ */
+public final class BouncyCastleGpgSignatureVerifierFactory
+		extends GpgSignatureVerifierFactory {
+
+	@Override
+	public GpgSignatureVerifier getVerifier() {
+		return new BouncyCastleGpgSignatureVerifier();
+	}
+
+}
diff --git a/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/BouncyCastleGpgSigner.java b/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/BouncyCastleGpgSigner.java
index 449c4a4..211bd7b 100644
--- a/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/BouncyCastleGpgSigner.java
+++ b/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/BouncyCastleGpgSigner.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2018, 2020, Salesforce and others
+ * Copyright (C) 2018, 2021, Salesforce and others
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Distribution License v. 1.0 which is available at
@@ -34,18 +34,22 @@
 import org.eclipse.jgit.annotations.Nullable;
 import org.eclipse.jgit.api.errors.CanceledException;
 import org.eclipse.jgit.api.errors.JGitInternalException;
+import org.eclipse.jgit.api.errors.UnsupportedSigningFormatException;
 import org.eclipse.jgit.errors.UnsupportedCredentialItem;
+import org.eclipse.jgit.internal.JGitText;
 import org.eclipse.jgit.lib.CommitBuilder;
+import org.eclipse.jgit.lib.GpgConfig;
+import org.eclipse.jgit.lib.GpgObjectSigner;
 import org.eclipse.jgit.lib.GpgSignature;
 import org.eclipse.jgit.lib.GpgSigner;
-import org.eclipse.jgit.lib.GpgObjectSigner;
 import org.eclipse.jgit.lib.ObjectBuilder;
 import org.eclipse.jgit.lib.PersonIdent;
+import org.eclipse.jgit.lib.GpgConfig.GpgFormat;
 import org.eclipse.jgit.transport.CredentialsProvider;
 import org.eclipse.jgit.util.StringUtils;
 
 /**
- * GPG Signer using BouncyCastle library
+ * GPG Signer using the BouncyCastle library.
  */
 public class BouncyCastleGpgSigner extends GpgSigner
 		implements GpgObjectSigner {
@@ -70,13 +74,32 @@
 	public boolean canLocateSigningKey(@Nullable String gpgSigningKey,
 			PersonIdent committer, CredentialsProvider credentialsProvider)
 			throws CanceledException {
+		try {
+			return canLocateSigningKey(gpgSigningKey, committer,
+					credentialsProvider, null);
+		} catch (UnsupportedSigningFormatException e) {
+			// Cannot occur with a null config
+			return false;
+		}
+	}
+
+	@Override
+	public boolean canLocateSigningKey(@Nullable String gpgSigningKey,
+			PersonIdent committer, CredentialsProvider credentialsProvider,
+			GpgConfig config)
+			throws CanceledException, UnsupportedSigningFormatException {
+		if (config != null && config.getKeyFormat() != GpgFormat.OPENPGP) {
+			throw new UnsupportedSigningFormatException(
+					JGitText.get().onlyOpenPgpSupportedForSigning);
+		}
 		try (BouncyCastleGpgKeyPassphrasePrompt passphrasePrompt = new BouncyCastleGpgKeyPassphrasePrompt(
 				credentialsProvider)) {
 			BouncyCastleGpgKey gpgKey = locateSigningKey(gpgSigningKey,
 					committer, passphrasePrompt);
 			return gpgKey != null;
-		} catch (PGPException | IOException | NoSuchAlgorithmException
-				| NoSuchProviderException | URISyntaxException e) {
+		} catch (CanceledException e) {
+			throw e;
+		} catch (Exception e) {
 			return false;
 		}
 	}
@@ -101,17 +124,28 @@
 	public void sign(@NonNull CommitBuilder commit,
 			@Nullable String gpgSigningKey, @NonNull PersonIdent committer,
 			CredentialsProvider credentialsProvider) throws CanceledException {
-		signObject(commit, gpgSigningKey, committer, credentialsProvider);
+		try {
+			signObject(commit, gpgSigningKey, committer, credentialsProvider,
+					null);
+		} catch (UnsupportedSigningFormatException e) {
+			// Cannot occur with a null config
+		}
 	}
 
 	@Override
 	public void signObject(@NonNull ObjectBuilder object,
 			@Nullable String gpgSigningKey, @NonNull PersonIdent committer,
-			CredentialsProvider credentialsProvider) throws CanceledException {
+			CredentialsProvider credentialsProvider, GpgConfig config)
+			throws CanceledException, UnsupportedSigningFormatException {
+		if (config != null && config.getKeyFormat() != GpgFormat.OPENPGP) {
+			throw new UnsupportedSigningFormatException(
+					JGitText.get().onlyOpenPgpSupportedForSigning);
+		}
 		try (BouncyCastleGpgKeyPassphrasePrompt passphrasePrompt = new BouncyCastleGpgKeyPassphrasePrompt(
 				credentialsProvider)) {
 			BouncyCastleGpgKey gpgKey = locateSigningKey(gpgSigningKey,
-					committer, passphrasePrompt);
+					committer,
+						passphrasePrompt);
 			PGPSecretKey secretKey = gpgKey.getSecretKey();
 			if (secretKey == null) {
 				throw new JGitInternalException(
@@ -178,7 +212,7 @@
 		}
 	}
 
-	private String extractSignerId(String pgpUserId) {
+	static String extractSignerId(String pgpUserId) {
 		int from = pgpUserId.indexOf('<');
 		if (from >= 0) {
 			int to = pgpUserId.indexOf('>', from + 1);
diff --git a/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/keys/KeyGrip.java b/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/keys/KeyGrip.java
new file mode 100644
index 0000000..b1d4446
--- /dev/null
+++ b/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/keys/KeyGrip.java
@@ -0,0 +1,322 @@
+/*
+ * Copyright (C) 2021, Thomas Wolf <thomas.wolf@paranor.ch> and others
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0 which is available at
+ * https://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+package org.eclipse.jgit.gpg.bc.internal.keys;
+
+import java.math.BigInteger;
+import java.nio.charset.StandardCharsets;
+import java.text.MessageFormat;
+import java.util.Arrays;
+
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.cryptlib.CryptlibObjectIdentifiers;
+import org.bouncycastle.asn1.x9.ECNamedCurveTable;
+import org.bouncycastle.asn1.x9.X9ECParameters;
+import org.bouncycastle.bcpg.DSAPublicBCPGKey;
+import org.bouncycastle.bcpg.ECPublicBCPGKey;
+import org.bouncycastle.bcpg.ElGamalPublicBCPGKey;
+import org.bouncycastle.bcpg.PublicKeyAlgorithmTags;
+import org.bouncycastle.bcpg.RSAPublicBCPGKey;
+import org.bouncycastle.crypto.ec.CustomNamedCurves;
+import org.bouncycastle.math.ec.ECAlgorithms;
+import org.bouncycastle.math.field.FiniteField;
+import org.bouncycastle.openpgp.PGPException;
+import org.bouncycastle.openpgp.PGPPublicKey;
+import org.bouncycastle.util.encoders.Hex;
+import org.eclipse.jgit.annotations.NonNull;
+import org.eclipse.jgit.gpg.bc.internal.BCText;
+import org.eclipse.jgit.util.sha1.SHA1;
+
+/**
+ * Utilities to compute the <em>keygrip</em> of a key. A keygrip is a SHA1 hash
+ * over the public key parameters and is used internally by the gpg-agent to
+ * find the secret key belonging to a public key: the secret key is stored in a
+ * file under ~/.gnupg/private-keys-v1.d/ with a name "&lt;keygrip>.key". While
+ * this storage organization is an implementation detail of GPG, the way
+ * keygrips are computed is not; they are computed by libgcrypt and their
+ * definition is stable.
+ */
+public final class KeyGrip {
+
+	// Some OIDs apparently unknown to BouncyCastle.
+
+	private static String OID_OPENPGP_ED25519 = "1.3.6.1.4.1.11591.15.1"; //$NON-NLS-1$
+
+	private static String OID_RFC8410_CURVE25519 = "1.3.101.110"; //$NON-NLS-1$
+
+	private static String OID_RFC8410_ED25519 = "1.3.101.112"; //$NON-NLS-1$
+
+	private KeyGrip() {
+		// No instantiation
+	}
+
+	/**
+	 * Computes the keygrip for a {@link PGPPublicKey}.
+	 *
+	 * @param publicKey
+	 *            to get the keygrip of
+	 * @return the keygrip
+	 * @throws PGPException
+	 *             if an unknown key type is encountered.
+	 */
+	@NonNull
+	public static byte[] getKeyGrip(PGPPublicKey publicKey)
+			throws PGPException {
+		SHA1 grip = SHA1.newInstance();
+		grip.setDetectCollision(false);
+
+		switch (publicKey.getAlgorithm()) {
+		case PublicKeyAlgorithmTags.RSA_GENERAL:
+		case PublicKeyAlgorithmTags.RSA_ENCRYPT:
+		case PublicKeyAlgorithmTags.RSA_SIGN:
+			BigInteger modulus = ((RSAPublicBCPGKey) publicKey
+					.getPublicKeyPacket().getKey()).getModulus();
+			hash(grip, modulus.toByteArray());
+			break;
+		case PublicKeyAlgorithmTags.DSA:
+			DSAPublicBCPGKey dsa = (DSAPublicBCPGKey) publicKey
+					.getPublicKeyPacket().getKey();
+			hash(grip, dsa.getP().toByteArray(), 'p', true);
+			hash(grip, dsa.getQ().toByteArray(), 'q', true);
+			hash(grip, dsa.getG().toByteArray(), 'g', true);
+			hash(grip, dsa.getY().toByteArray(), 'y', true);
+			break;
+		case PublicKeyAlgorithmTags.ELGAMAL_GENERAL:
+		case PublicKeyAlgorithmTags.ELGAMAL_ENCRYPT:
+			ElGamalPublicBCPGKey eg = (ElGamalPublicBCPGKey) publicKey
+					.getPublicKeyPacket().getKey();
+			hash(grip, eg.getP().toByteArray(), 'p', true);
+			hash(grip, eg.getG().toByteArray(), 'g', true);
+			hash(grip, eg.getY().toByteArray(), 'y', true);
+			break;
+		case PublicKeyAlgorithmTags.ECDH:
+		case PublicKeyAlgorithmTags.ECDSA:
+		case PublicKeyAlgorithmTags.EDDSA:
+			ECPublicBCPGKey ec = (ECPublicBCPGKey) publicKey
+					.getPublicKeyPacket().getKey();
+			ASN1ObjectIdentifier curveOID = ec.getCurveOID();
+			// BC doesn't know these OIDs.
+			if (OID_OPENPGP_ED25519.equals(curveOID.getId())
+					|| OID_RFC8410_ED25519.equals(curveOID.getId())) {
+				return hashEd25519(grip, ec.getEncodedPoint());
+			} else if (CryptlibObjectIdentifiers.curvey25519.equals(curveOID)
+					|| OID_RFC8410_CURVE25519.equals(curveOID.getId())) {
+				// curvey25519 actually is the OpenPGP OID for Curve25519 and is
+				// known to BC, but the parameters are for the short Weierstrass
+				// form. See https://github.com/bcgit/bc-java/issues/399 .
+				// libgcrypt uses Montgomery form.
+				return hashCurve25519(grip, ec.getEncodedPoint());
+			}
+			X9ECParameters params = getX9Parameters(curveOID);
+			if (params == null) {
+				throw new PGPException(MessageFormat
+						.format(BCText.get().unknownCurve, curveOID.getId()));
+			}
+			// Need to write p, a, b, g, n, q
+			BigInteger q = ec.getEncodedPoint();
+			byte[] g = params.getG().getEncoded(false);
+			BigInteger a = params.getCurve().getA().toBigInteger();
+			BigInteger b = params.getCurve().getB().toBigInteger();
+			BigInteger n = params.getN();
+			BigInteger p = null;
+			FiniteField field = params.getCurve().getField();
+			if (ECAlgorithms.isFpField(field)) {
+				p = field.getCharacteristic();
+			}
+			if (p == null) {
+				// Don't know...
+				throw new PGPException(MessageFormat.format(
+						BCText.get().unknownCurveParameters, curveOID.getId()));
+			}
+			hash(grip, p.toByteArray(), 'p', false);
+			hash(grip, a.toByteArray(), 'a', false);
+			hash(grip, b.toByteArray(), 'b', false);
+			hash(grip, g, 'g', false);
+			hash(grip, n.toByteArray(), 'n', false);
+			if (publicKey.getAlgorithm() == PublicKeyAlgorithmTags.EDDSA) {
+				hashQ25519(grip, q);
+			} else {
+				hash(grip, q.toByteArray(), 'q', false);
+			}
+			break;
+		default:
+			throw new PGPException(
+					MessageFormat.format(BCText.get().unknownKeyType,
+							Integer.toString(publicKey.getAlgorithm())));
+		}
+		return grip.digest();
+	}
+
+	private static void hash(SHA1 grip, byte[] data) {
+		// Need to skip leading zero bytes
+		int i = 0;
+		while (i < data.length && data[i] == 0) {
+			i++;
+		}
+		int length = data.length - i;
+		if (i < data.length) {
+			if ((data[i] & 0x80) != 0) {
+				grip.update((byte) 0);
+			}
+			grip.update(data, i, length);
+		}
+	}
+
+	private static void hash(SHA1 grip, byte[] data, char id, boolean zeroPad) {
+		// Need to skip leading zero bytes
+		int i = 0;
+		while (i < data.length && data[i] == 0) {
+			i++;
+		}
+		int length = data.length - i;
+		boolean addZero = false;
+		if (i < data.length && zeroPad && (data[i] & 0x80) != 0) {
+			addZero = true;
+		}
+		// libgcrypt includes an SExp in the hash
+		String prefix = "(1:" + id + (addZero ? length + 1 : length) + ':'; //$NON-NLS-1$
+		grip.update(prefix.getBytes(StandardCharsets.US_ASCII));
+		// For some items, gcrypt prepends a zero byte if the high bit is set
+		if (addZero) {
+			grip.update((byte) 0);
+		}
+		if (i < data.length) {
+			grip.update(data, i, length);
+		}
+		grip.update((byte) ')');
+	}
+
+	private static void hashQ25519(SHA1 grip, BigInteger q)
+			throws PGPException {
+		byte[] data = q.toByteArray();
+		switch (data[0]) {
+		case 0x04:
+			if (data.length != 65) {
+				throw new PGPException(MessageFormat.format(
+						BCText.get().corrupt25519Key, Hex.toHexString(data)));
+			}
+			// Uncompressed: should not occur with ed25519 or curve25519
+			throw new PGPException(MessageFormat.format(
+					BCText.get().uncompressed25519Key, Hex.toHexString(data)));
+		case 0x40:
+			if (data.length != 33) {
+				throw new PGPException(MessageFormat.format(
+						BCText.get().corrupt25519Key, Hex.toHexString(data)));
+			}
+			// Compressed; normal case. Skip prefix.
+			hash(grip, Arrays.copyOfRange(data, 1, data.length), 'q', false);
+			break;
+		default:
+			if (data.length != 32) {
+				throw new PGPException(MessageFormat.format(
+						BCText.get().corrupt25519Key, Hex.toHexString(data)));
+			}
+			// Compressed format without prefix. Should not occur?
+			hash(grip, data, 'q', false);
+			break;
+		}
+	}
+
+	/**
+	 * Computes the keygrip for an ed25519 public key.
+	 * <p>
+	 * Package-visible for tests only.
+	 * </p>
+	 *
+	 * @param grip
+	 *            initialized {@link SHA1}
+	 * @param q
+	 *            the public key's EC point
+	 * @return the keygrip
+	 * @throws PGPException
+	 *             if q indicates uncompressed format
+	 */
+	@SuppressWarnings("nls")
+	static byte[] hashEd25519(SHA1 grip, BigInteger q) throws PGPException {
+		// For the values, see RFC 7748: https://tools.ietf.org/html/rfc7748
+		// p = 2^255 - 19
+		hash(grip, Hex.decodeStrict(
+				"7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFED"),
+				'p', false);
+		// Field: a = 1
+		hash(grip, new byte[] { 0x01 }, 'a', false);
+		// Field: b = 121665/121666 (mod p)
+		// See Berstein et.al., "Twisted Edwards Curves",
+		// https://doi.org/10.1007/978-3-540-68164-9_26
+		hash(grip, Hex.decodeStrict(
+				"2DFC9311D490018C7338BF8688861767FF8FF5B2BEBE27548A14B235ECA6874A"),
+				'b', false);
+		// Generator point with affine X,Y
+		// @formatter:off
+		// X(P) = 15112221349535400772501151409588531511454012693041857206046113283949847762202
+		// Y(P) = 46316835694926478169428394003475163141307993866256225615783033603165251855960
+		// the "04" signifies uncompressed format.
+		// @formatter:on
+		hash(grip, Hex.decodeStrict("04"
+				+ "216936D3CD6E53FEC0A4E231FDD6DC5C692CC7609525A7B2C9562D608F25D51A"
+				+ "6666666666666666666666666666666666666666666666666666666666666658"),
+				'g', false);
+		// order = 2^252 + 0x14def9dea2f79cd65812631a5cf5d3ed
+		hash(grip, Hex.decodeStrict(
+				"1000000000000000000000000000000014DEF9DEA2F79CD65812631A5CF5D3ED"),
+				'n', false);
+		hashQ25519(grip, q);
+		return grip.digest();
+	}
+
+	/**
+	 * Computes the keygrip for a curve25519 public key.
+	 * <p>
+	 * Package-visible for tests only.
+	 * </p>
+	 *
+	 * @param grip
+	 *            initialized {@link SHA1}
+	 * @param q
+	 *            the public key's EC point
+	 * @return the keygrip
+	 * @throws PGPException
+	 *             if q indicates uncompressed format
+	 */
+	@SuppressWarnings("nls")
+	static byte[] hashCurve25519(SHA1 grip, BigInteger q) throws PGPException {
+		hash(grip, Hex.decodeStrict(
+				"7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFED"),
+				'p', false);
+		// Unclear: RFC 7748 says A = 486662. This value here is (A-2)/4 =
+		// 121665. Compare ecc-curves.c in libgcrypt:
+		// https://github.com/gpg/libgcrypt/blob/361a058/cipher/ecc-curves.c#L146
+		hash(grip, new byte[] { 0x01, (byte) 0xDB, 0x41 }, 'a', false);
+		hash(grip, new byte[] { 0x01 }, 'b', false);
+		// libgcrypt uses the old g.y value before the erratum to RFC 7748 for
+		// the keygrip. The new value would be
+		// 5F51E65E475F794B1FE122D388B72EB36DC2B28192839E4DD6163A5D81312C14. See
+		// https://www.rfc-editor.org/errata/eid4730 and
+		// https://github.com/gpg/libgcrypt/commit/f67b6492e0b0
+		hash(grip, Hex.decodeStrict("04"
+				+ "0000000000000000000000000000000000000000000000000000000000000009"
+				+ "20AE19A1B8A086B4E01EDD2C7748D14C923D4D7E6D7C61B229E9C5A27ECED3D9"),
+				'g', false);
+		hash(grip, Hex.decodeStrict(
+				"1000000000000000000000000000000014DEF9DEA2F79CD65812631A5CF5D3ED"),
+				'n', false);
+		hashQ25519(grip, q);
+		return grip.digest();
+	}
+
+	private static X9ECParameters getX9Parameters(
+			ASN1ObjectIdentifier curveOID) {
+		X9ECParameters params = CustomNamedCurves.getByOID(curveOID);
+		if (params == null) {
+			params = ECNamedCurveTable.getByOID(curveOID);
+		}
+		return params;
+	}
+
+}
diff --git a/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/keys/OCBPBEProtectionRemoverFactory.java b/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/keys/OCBPBEProtectionRemoverFactory.java
new file mode 100644
index 0000000..68f8a45
--- /dev/null
+++ b/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/keys/OCBPBEProtectionRemoverFactory.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2021 Thomas Wolf <thomas.wolf@paranor.ch> and others
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0 which is available at
+ * https://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+package org.eclipse.jgit.gpg.bc.internal.keys;
+
+import java.security.NoSuchAlgorithmException;
+import java.text.MessageFormat;
+
+import javax.crypto.Cipher;
+import javax.crypto.SecretKey;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+
+import org.bouncycastle.openpgp.PGPException;
+import org.bouncycastle.openpgp.PGPUtil;
+import org.bouncycastle.openpgp.operator.PBEProtectionRemoverFactory;
+import org.bouncycastle.openpgp.operator.PBESecretKeyDecryptor;
+import org.bouncycastle.openpgp.operator.PGPDigestCalculatorProvider;
+import org.bouncycastle.util.Arrays;
+import org.eclipse.jgit.gpg.bc.internal.BCText;
+
+/**
+ * A {@link PBEProtectionRemoverFactory} using AES/OCB/NoPadding for decryption.
+ * It accepts an AAD in the factory's constructor, so the factory can be used to
+ * create a {@link PBESecretKeyDecryptor} only for a particular input.
+ * <p>
+ * For JGit's needs, this is sufficient, but for a general upstream
+ * implementation that limitation might not be acceptable.
+ * </p>
+ */
+class OCBPBEProtectionRemoverFactory
+		implements PBEProtectionRemoverFactory {
+
+	private final PGPDigestCalculatorProvider calculatorProvider;
+
+	private final char[] passphrase;
+
+	private final byte[] aad;
+
+	/**
+	 * Creates a new factory instance with the given parameters.
+	 * <p>
+	 * Because the AAD is given at factory level, the {@link PBESecretKeyDecryptor}s
+	 * created by the factory can be used to decrypt only a particular input
+	 * matching this AAD.
+	 * </p>
+	 *
+	 * @param passphrase         to use for secret key derivation
+	 * @param calculatorProvider for computing digests
+	 * @param aad                for the OCB decryption
+	 */
+	OCBPBEProtectionRemoverFactory(char[] passphrase,
+			PGPDigestCalculatorProvider calculatorProvider, byte[] aad) {
+		this.calculatorProvider = calculatorProvider;
+		this.passphrase = passphrase;
+		this.aad = aad;
+	}
+
+	@Override
+	public PBESecretKeyDecryptor createDecryptor(String protection)
+			throws PGPException {
+		return new PBESecretKeyDecryptor(passphrase, calculatorProvider) {
+
+			@Override
+			public byte[] recoverKeyData(int encAlgorithm, byte[] key,
+					byte[] iv, byte[] encrypted, int encryptedOffset,
+					int encryptedLength) throws PGPException {
+				String algorithmName = PGPUtil
+						.getSymmetricCipherName(encAlgorithm);
+				byte[] decrypted = null;
+				try {
+					Cipher c = Cipher
+							.getInstance(algorithmName + "/OCB/NoPadding"); //$NON-NLS-1$
+					SecretKey secretKey = new SecretKeySpec(key, algorithmName);
+					c.init(Cipher.DECRYPT_MODE, secretKey,
+							new IvParameterSpec(iv));
+					c.updateAAD(aad);
+					decrypted = new byte[c.getOutputSize(encryptedLength)];
+					int decryptedLength = c.update(encrypted, encryptedOffset,
+							encryptedLength, decrypted);
+					// doFinal() for OCB will check the MAC and throw an
+					// exception if it doesn't match
+					decryptedLength += c.doFinal(decrypted, decryptedLength);
+					if (decryptedLength != decrypted.length) {
+						throw new PGPException(MessageFormat.format(
+								BCText.get().cryptWrongDecryptedLength,
+								Integer.valueOf(decryptedLength),
+								Integer.valueOf(decrypted.length)));
+					}
+					byte[] result = decrypted;
+					decrypted = null; // Don't clear in finally
+					return result;
+				} catch (NoClassDefFoundError e) {
+					String msg = MessageFormat.format(
+							BCText.get().gpgNoSuchAlgorithm,
+							algorithmName + "/OCB"); //$NON-NLS-1$
+					throw new PGPException(msg,
+							new NoSuchAlgorithmException(msg, e));
+				} catch (PGPException e) {
+					throw e;
+				} catch (Exception e) {
+					throw new PGPException(
+							MessageFormat.format(BCText.get().cryptCipherError,
+									e.getLocalizedMessage()),
+							e);
+				} finally {
+					if (decrypted != null) {
+						// Prevent halfway decrypted data leaking.
+						Arrays.fill(decrypted, (byte) 0);
+					}
+				}
+			}
+		};
+	}
+}
\ No newline at end of file
diff --git a/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/keys/SExprParser.java b/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/keys/SExprParser.java
new file mode 100644
index 0000000..a9bb22c
--- /dev/null
+++ b/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/keys/SExprParser.java
@@ -0,0 +1,826 @@
+/*
+ * Copyright (c) 2000-2021 The Legion of the Bouncy Castle Inc. (https://www.bouncycastle.org)
+ * <p>
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+ * and associated documentation files (the "Software"), to deal in the Software without restriction,
+ *including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ * </p>
+ * <p>
+ * The above copyright notice and this permission notice shall be included in all copies or substantial
+ * portions of the Software.
+ * </p>
+ * <p>
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ * </p>
+ */
+package org.eclipse.jgit.gpg.bc.internal.keys;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.math.BigInteger;
+import java.util.Date;
+
+import org.bouncycastle.asn1.x9.ECNamedCurveTable;
+import org.bouncycastle.bcpg.DSAPublicBCPGKey;
+import org.bouncycastle.bcpg.DSASecretBCPGKey;
+import org.bouncycastle.bcpg.ECDSAPublicBCPGKey;
+import org.bouncycastle.bcpg.ECPublicBCPGKey;
+import org.bouncycastle.bcpg.ECSecretBCPGKey;
+import org.bouncycastle.bcpg.ElGamalPublicBCPGKey;
+import org.bouncycastle.bcpg.ElGamalSecretBCPGKey;
+import org.bouncycastle.bcpg.HashAlgorithmTags;
+import org.bouncycastle.bcpg.PublicKeyAlgorithmTags;
+import org.bouncycastle.bcpg.PublicKeyPacket;
+import org.bouncycastle.bcpg.RSAPublicBCPGKey;
+import org.bouncycastle.bcpg.RSASecretBCPGKey;
+import org.bouncycastle.bcpg.S2K;
+import org.bouncycastle.bcpg.SecretKeyPacket;
+import org.bouncycastle.bcpg.SymmetricKeyAlgorithmTags;
+import org.bouncycastle.openpgp.PGPException;
+import org.bouncycastle.openpgp.PGPPublicKey;
+import org.bouncycastle.openpgp.PGPSecretKey;
+import org.bouncycastle.openpgp.operator.KeyFingerPrintCalculator;
+import org.bouncycastle.openpgp.operator.PBEProtectionRemoverFactory;
+import org.bouncycastle.openpgp.operator.PBESecretKeyDecryptor;
+import org.bouncycastle.openpgp.operator.PGPDigestCalculator;
+import org.bouncycastle.openpgp.operator.PGPDigestCalculatorProvider;
+import org.bouncycastle.util.Arrays;
+import org.bouncycastle.util.Strings;
+
+/**
+ * A parser for secret keys stored in s-expressions. Original BouncyCastle code
+ * modified by the JGit team to:
+ * <ul>
+ * <li>handle unencrypted DSA, EC, and ElGamal keys (upstream only handles
+ * unencrypted RSA), and</li>
+ * <li>handle secret keys using AES/OCB as encryption (those don't have a
+ * hash).</li>
+ * </ul>
+ */
+@SuppressWarnings("nls")
+public class SExprParser {
+	private final PGPDigestCalculatorProvider digestProvider;
+
+	/**
+	 * Base constructor.
+	 *
+	 * @param digestProvider
+	 *            a provider for digest calculations. Used to confirm key
+	 *            protection hashes.
+	 */
+	public SExprParser(PGPDigestCalculatorProvider digestProvider) {
+		this.digestProvider = digestProvider;
+	}
+
+	/**
+	 * Parse a secret key from one of the GPG S expression keys associating it
+	 * with the passed in public key.
+	 *
+	 * @param inputStream
+	 *            to read from
+	 * @param keyProtectionRemoverFactory
+	 *            for decrypting encrypted keys
+	 * @param pubKey
+	 *            the private key should belong to
+	 *
+	 * @return a secret key object.
+	 * @throws IOException
+	 * @throws PGPException
+	 */
+	public PGPSecretKey parseSecretKey(InputStream inputStream,
+			PBEProtectionRemoverFactory keyProtectionRemoverFactory,
+			PGPPublicKey pubKey) throws IOException, PGPException {
+		SXprUtils.skipOpenParenthesis(inputStream);
+
+		String type;
+
+		type = SXprUtils.readString(inputStream, inputStream.read());
+		if (type.equals("protected-private-key")
+				|| type.equals("private-key")) {
+			SXprUtils.skipOpenParenthesis(inputStream);
+
+			String keyType = SXprUtils.readString(inputStream,
+					inputStream.read());
+			if (keyType.equals("ecc")) {
+				SXprUtils.skipOpenParenthesis(inputStream);
+
+				String curveID = SXprUtils.readString(inputStream,
+						inputStream.read());
+				String curveName = SXprUtils.readString(inputStream,
+						inputStream.read());
+
+				SXprUtils.skipCloseParenthesis(inputStream);
+
+				byte[] qVal;
+
+				SXprUtils.skipOpenParenthesis(inputStream);
+
+				type = SXprUtils.readString(inputStream, inputStream.read());
+				if (type.equals("q")) {
+					qVal = SXprUtils.readBytes(inputStream, inputStream.read());
+				} else {
+					throw new PGPException("no q value found");
+				}
+
+				SXprUtils.skipCloseParenthesis(inputStream);
+
+				BigInteger d = processECSecretKey(inputStream, curveID,
+						curveName, qVal, keyProtectionRemoverFactory);
+
+				if (curveName.startsWith("NIST ")) {
+					curveName = curveName.substring("NIST ".length());
+				}
+
+				ECPublicBCPGKey basePubKey = new ECDSAPublicBCPGKey(
+						ECNamedCurveTable.getOID(curveName),
+						new BigInteger(1, qVal));
+				ECPublicBCPGKey assocPubKey = (ECPublicBCPGKey) pubKey
+						.getPublicKeyPacket().getKey();
+				if (!basePubKey.getCurveOID().equals(assocPubKey.getCurveOID())
+						|| !basePubKey.getEncodedPoint()
+								.equals(assocPubKey.getEncodedPoint())) {
+					throw new PGPException(
+							"passed in public key does not match secret key");
+				}
+
+				return new PGPSecretKey(
+						new SecretKeyPacket(pubKey.getPublicKeyPacket(),
+								SymmetricKeyAlgorithmTags.NULL, null, null,
+								new ECSecretBCPGKey(d).getEncoded()),
+						pubKey);
+			} else if (keyType.equals("dsa")) {
+				BigInteger p = readBigInteger("p", inputStream);
+				BigInteger q = readBigInteger("q", inputStream);
+				BigInteger g = readBigInteger("g", inputStream);
+
+				BigInteger y = readBigInteger("y", inputStream);
+
+				BigInteger x = processDSASecretKey(inputStream, p, q, g, y,
+						keyProtectionRemoverFactory);
+
+				DSAPublicBCPGKey basePubKey = new DSAPublicBCPGKey(p, q, g, y);
+				DSAPublicBCPGKey assocPubKey = (DSAPublicBCPGKey) pubKey
+						.getPublicKeyPacket().getKey();
+				if (!basePubKey.getP().equals(assocPubKey.getP())
+						|| !basePubKey.getQ().equals(assocPubKey.getQ())
+						|| !basePubKey.getG().equals(assocPubKey.getG())
+						|| !basePubKey.getY().equals(assocPubKey.getY())) {
+					throw new PGPException(
+							"passed in public key does not match secret key");
+				}
+				return new PGPSecretKey(
+						new SecretKeyPacket(pubKey.getPublicKeyPacket(),
+								SymmetricKeyAlgorithmTags.NULL, null, null,
+								new DSASecretBCPGKey(x).getEncoded()),
+						pubKey);
+			} else if (keyType.equals("elg")) {
+				BigInteger p = readBigInteger("p", inputStream);
+				BigInteger g = readBigInteger("g", inputStream);
+
+				BigInteger y = readBigInteger("y", inputStream);
+
+				BigInteger x = processElGamalSecretKey(inputStream, p, g, y,
+						keyProtectionRemoverFactory);
+
+				ElGamalPublicBCPGKey basePubKey = new ElGamalPublicBCPGKey(p, g,
+						y);
+				ElGamalPublicBCPGKey assocPubKey = (ElGamalPublicBCPGKey) pubKey
+						.getPublicKeyPacket().getKey();
+				if (!basePubKey.getP().equals(assocPubKey.getP())
+						|| !basePubKey.getG().equals(assocPubKey.getG())
+						|| !basePubKey.getY().equals(assocPubKey.getY())) {
+					throw new PGPException(
+							"passed in public key does not match secret key");
+				}
+
+				return new PGPSecretKey(
+						new SecretKeyPacket(pubKey.getPublicKeyPacket(),
+								SymmetricKeyAlgorithmTags.NULL, null, null,
+								new ElGamalSecretBCPGKey(x).getEncoded()),
+						pubKey);
+			} else if (keyType.equals("rsa")) {
+				BigInteger n = readBigInteger("n", inputStream);
+				BigInteger e = readBigInteger("e", inputStream);
+
+				BigInteger[] values = processRSASecretKey(inputStream, n, e,
+						keyProtectionRemoverFactory);
+
+				// TODO: type of RSA key?
+				RSAPublicBCPGKey basePubKey = new RSAPublicBCPGKey(n, e);
+				RSAPublicBCPGKey assocPubKey = (RSAPublicBCPGKey) pubKey
+						.getPublicKeyPacket().getKey();
+				if (!basePubKey.getModulus().equals(assocPubKey.getModulus())
+						|| !basePubKey.getPublicExponent()
+								.equals(assocPubKey.getPublicExponent())) {
+					throw new PGPException(
+							"passed in public key does not match secret key");
+				}
+
+				return new PGPSecretKey(new SecretKeyPacket(
+						pubKey.getPublicKeyPacket(),
+						SymmetricKeyAlgorithmTags.NULL, null, null,
+						new RSASecretBCPGKey(values[0], values[1], values[2])
+								.getEncoded()),
+						pubKey);
+			} else {
+				throw new PGPException("unknown key type: " + keyType);
+			}
+		}
+
+		throw new PGPException("unknown key type found");
+	}
+
+	/**
+	 * Parse a secret key from one of the GPG S expression keys.
+	 *
+	 * @param inputStream
+	 *            to read from
+	 * @param keyProtectionRemoverFactory
+	 *            for decrypting encrypted keys
+	 * @param fingerPrintCalculator
+	 *            for calculating key fingerprints
+	 *
+	 * @return a secret key object.
+	 * @throws IOException
+	 * @throws PGPException
+	 */
+	public PGPSecretKey parseSecretKey(InputStream inputStream,
+			PBEProtectionRemoverFactory keyProtectionRemoverFactory,
+			KeyFingerPrintCalculator fingerPrintCalculator)
+			throws IOException, PGPException {
+		SXprUtils.skipOpenParenthesis(inputStream);
+
+		String type;
+
+		type = SXprUtils.readString(inputStream, inputStream.read());
+		if (type.equals("protected-private-key")
+				|| type.equals("private-key")) {
+			SXprUtils.skipOpenParenthesis(inputStream);
+
+			String keyType = SXprUtils.readString(inputStream,
+					inputStream.read());
+			if (keyType.equals("ecc")) {
+				SXprUtils.skipOpenParenthesis(inputStream);
+
+				String curveID = SXprUtils.readString(inputStream,
+						inputStream.read());
+				String curveName = SXprUtils.readString(inputStream,
+						inputStream.read());
+
+				if (curveName.startsWith("NIST ")) {
+					curveName = curveName.substring("NIST ".length());
+				}
+
+				SXprUtils.skipCloseParenthesis(inputStream);
+
+				byte[] qVal;
+
+				SXprUtils.skipOpenParenthesis(inputStream);
+
+				type = SXprUtils.readString(inputStream, inputStream.read());
+				if (type.equals("q")) {
+					qVal = SXprUtils.readBytes(inputStream, inputStream.read());
+				} else {
+					throw new PGPException("no q value found");
+				}
+
+				PublicKeyPacket pubPacket = new PublicKeyPacket(
+						PublicKeyAlgorithmTags.ECDSA, new Date(),
+						new ECDSAPublicBCPGKey(
+								ECNamedCurveTable.getOID(curveName),
+								new BigInteger(1, qVal)));
+
+				SXprUtils.skipCloseParenthesis(inputStream);
+
+				BigInteger d = processECSecretKey(inputStream, curveID,
+						curveName, qVal, keyProtectionRemoverFactory);
+
+				return new PGPSecretKey(
+						new SecretKeyPacket(pubPacket,
+								SymmetricKeyAlgorithmTags.NULL, null, null,
+								new ECSecretBCPGKey(d).getEncoded()),
+						new PGPPublicKey(pubPacket, fingerPrintCalculator));
+			} else if (keyType.equals("dsa")) {
+				BigInteger p = readBigInteger("p", inputStream);
+				BigInteger q = readBigInteger("q", inputStream);
+				BigInteger g = readBigInteger("g", inputStream);
+
+				BigInteger y = readBigInteger("y", inputStream);
+
+				BigInteger x = processDSASecretKey(inputStream, p, q, g, y,
+						keyProtectionRemoverFactory);
+
+				PublicKeyPacket pubPacket = new PublicKeyPacket(
+						PublicKeyAlgorithmTags.DSA, new Date(),
+						new DSAPublicBCPGKey(p, q, g, y));
+
+				return new PGPSecretKey(
+						new SecretKeyPacket(pubPacket,
+								SymmetricKeyAlgorithmTags.NULL, null, null,
+								new DSASecretBCPGKey(x).getEncoded()),
+						new PGPPublicKey(pubPacket, fingerPrintCalculator));
+			} else if (keyType.equals("elg")) {
+				BigInteger p = readBigInteger("p", inputStream);
+				BigInteger g = readBigInteger("g", inputStream);
+
+				BigInteger y = readBigInteger("y", inputStream);
+
+				BigInteger x = processElGamalSecretKey(inputStream, p, g, y,
+						keyProtectionRemoverFactory);
+
+				PublicKeyPacket pubPacket = new PublicKeyPacket(
+						PublicKeyAlgorithmTags.ELGAMAL_ENCRYPT, new Date(),
+						new ElGamalPublicBCPGKey(p, g, y));
+
+				return new PGPSecretKey(
+						new SecretKeyPacket(pubPacket,
+								SymmetricKeyAlgorithmTags.NULL, null, null,
+								new ElGamalSecretBCPGKey(x).getEncoded()),
+						new PGPPublicKey(pubPacket, fingerPrintCalculator));
+			} else if (keyType.equals("rsa")) {
+				BigInteger n = readBigInteger("n", inputStream);
+				BigInteger e = readBigInteger("e", inputStream);
+
+				BigInteger[] values = processRSASecretKey(inputStream, n, e,
+						keyProtectionRemoverFactory);
+
+				// TODO: type of RSA key?
+				PublicKeyPacket pubPacket = new PublicKeyPacket(
+						PublicKeyAlgorithmTags.RSA_GENERAL, new Date(),
+						new RSAPublicBCPGKey(n, e));
+
+				return new PGPSecretKey(
+						new SecretKeyPacket(pubPacket,
+								SymmetricKeyAlgorithmTags.NULL, null, null,
+								new RSASecretBCPGKey(values[0], values[1],
+										values[2]).getEncoded()),
+						new PGPPublicKey(pubPacket, fingerPrintCalculator));
+			} else {
+				throw new PGPException("unknown key type: " + keyType);
+			}
+		}
+
+		throw new PGPException("unknown key type found");
+	}
+
+	private BigInteger readBigInteger(String expectedType,
+			InputStream inputStream) throws IOException, PGPException {
+		SXprUtils.skipOpenParenthesis(inputStream);
+
+		String type = SXprUtils.readString(inputStream, inputStream.read());
+		if (!type.equals(expectedType)) {
+			throw new PGPException(expectedType + " value expected");
+		}
+
+		byte[] nBytes = SXprUtils.readBytes(inputStream, inputStream.read());
+		BigInteger v = new BigInteger(1, nBytes);
+
+		SXprUtils.skipCloseParenthesis(inputStream);
+
+		return v;
+	}
+
+	private static byte[][] extractData(InputStream inputStream,
+			PBEProtectionRemoverFactory keyProtectionRemoverFactory)
+			throws PGPException, IOException {
+		byte[] data;
+		byte[] protectedAt = null;
+
+		SXprUtils.skipOpenParenthesis(inputStream);
+
+		String type = SXprUtils.readString(inputStream, inputStream.read());
+		if (type.equals("protected")) {
+			String protection = SXprUtils.readString(inputStream,
+					inputStream.read());
+
+			SXprUtils.skipOpenParenthesis(inputStream);
+
+			S2K s2k = SXprUtils.parseS2K(inputStream);
+
+			byte[] iv = SXprUtils.readBytes(inputStream, inputStream.read());
+
+			SXprUtils.skipCloseParenthesis(inputStream);
+
+			byte[] secKeyData = SXprUtils.readBytes(inputStream,
+					inputStream.read());
+
+			SXprUtils.skipCloseParenthesis(inputStream);
+
+			PBESecretKeyDecryptor keyDecryptor = keyProtectionRemoverFactory
+					.createDecryptor(protection);
+
+			// TODO: recognise other algorithms
+			byte[] key = keyDecryptor.makeKeyFromPassPhrase(
+					SymmetricKeyAlgorithmTags.AES_128, s2k);
+
+			data = keyDecryptor.recoverKeyData(
+					SymmetricKeyAlgorithmTags.AES_128, key, iv, secKeyData, 0,
+					secKeyData.length);
+
+			// check if protected at is present
+			if (inputStream.read() == '(') {
+				ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+
+				bOut.write('(');
+				int ch;
+				while ((ch = inputStream.read()) >= 0 && ch != ')') {
+					bOut.write(ch);
+				}
+
+				if (ch != ')') {
+					throw new IOException("unexpected end to SExpr");
+				}
+
+				bOut.write(')');
+
+				protectedAt = bOut.toByteArray();
+			}
+
+			SXprUtils.skipCloseParenthesis(inputStream);
+			SXprUtils.skipCloseParenthesis(inputStream);
+		} else if (type.equals("d") || type.equals("x")) {
+			// JGit modification: unencrypted DSA or ECC keys can have an "x"
+			// here
+			return null;
+		} else {
+			throw new PGPException("protected block not found");
+		}
+
+		return new byte[][] { data, protectedAt };
+	}
+
+	private BigInteger processDSASecretKey(InputStream inputStream,
+			BigInteger p, BigInteger q, BigInteger g, BigInteger y,
+			PBEProtectionRemoverFactory keyProtectionRemoverFactory)
+			throws IOException, PGPException {
+		String type;
+		byte[][] basicData = extractData(inputStream,
+				keyProtectionRemoverFactory);
+
+		// JGit modification: handle unencrypted DSA keys
+		if (basicData == null) {
+			byte[] nBytes = SXprUtils.readBytes(inputStream,
+					inputStream.read());
+			BigInteger x = new BigInteger(1, nBytes);
+			SXprUtils.skipCloseParenthesis(inputStream);
+			return x;
+		}
+
+		byte[] keyData = basicData[0];
+		byte[] protectedAt = basicData[1];
+
+		//
+		// parse the secret key S-expr
+		//
+		InputStream keyIn = new ByteArrayInputStream(keyData);
+
+		SXprUtils.skipOpenParenthesis(keyIn);
+		SXprUtils.skipOpenParenthesis(keyIn);
+
+		BigInteger x = readBigInteger("x", keyIn);
+
+		SXprUtils.skipCloseParenthesis(keyIn);
+
+		// JGit modification: OCB-encrypted keys don't have and don't need a
+		// hash
+		if (keyProtectionRemoverFactory instanceof OCBPBEProtectionRemoverFactory) {
+			return x;
+		}
+
+		SXprUtils.skipOpenParenthesis(keyIn);
+		type = SXprUtils.readString(keyIn, keyIn.read());
+
+		if (!type.equals("hash")) {
+			throw new PGPException("hash keyword expected");
+		}
+		type = SXprUtils.readString(keyIn, keyIn.read());
+
+		if (!type.equals("sha1")) {
+			throw new PGPException("hash keyword expected");
+		}
+
+		byte[] hashBytes = SXprUtils.readBytes(keyIn, keyIn.read());
+
+		SXprUtils.skipCloseParenthesis(keyIn);
+
+		if (digestProvider != null) {
+			PGPDigestCalculator digestCalculator = digestProvider
+					.get(HashAlgorithmTags.SHA1);
+
+			OutputStream dOut = digestCalculator.getOutputStream();
+
+			dOut.write(Strings.toByteArray("(3:dsa"));
+			writeCanonical(dOut, "p", p);
+			writeCanonical(dOut, "q", q);
+			writeCanonical(dOut, "g", g);
+			writeCanonical(dOut, "y", y);
+			writeCanonical(dOut, "x", x);
+
+			// check protected-at
+			if (protectedAt != null) {
+				dOut.write(protectedAt);
+			}
+
+			dOut.write(Strings.toByteArray(")"));
+
+			byte[] check = digestCalculator.getDigest();
+			if (!Arrays.constantTimeAreEqual(check, hashBytes)) {
+				throw new PGPException(
+						"checksum on protected data failed in SExpr");
+			}
+		}
+
+		return x;
+	}
+
+	private BigInteger processElGamalSecretKey(InputStream inputStream,
+			BigInteger p, BigInteger g, BigInteger y,
+			PBEProtectionRemoverFactory keyProtectionRemoverFactory)
+			throws IOException, PGPException {
+		String type;
+		byte[][] basicData = extractData(inputStream,
+				keyProtectionRemoverFactory);
+
+		// JGit modification: handle unencrypted EC keys
+		if (basicData == null) {
+			byte[] nBytes = SXprUtils.readBytes(inputStream,
+					inputStream.read());
+			BigInteger x = new BigInteger(1, nBytes);
+			SXprUtils.skipCloseParenthesis(inputStream);
+			return x;
+		}
+
+		byte[] keyData = basicData[0];
+		byte[] protectedAt = basicData[1];
+
+		//
+		// parse the secret key S-expr
+		//
+		InputStream keyIn = new ByteArrayInputStream(keyData);
+
+		SXprUtils.skipOpenParenthesis(keyIn);
+		SXprUtils.skipOpenParenthesis(keyIn);
+
+		BigInteger x = readBigInteger("x", keyIn);
+
+		SXprUtils.skipCloseParenthesis(keyIn);
+
+		// JGit modification: OCB-encrypted keys don't have and don't need a
+		// hash
+		if (keyProtectionRemoverFactory instanceof OCBPBEProtectionRemoverFactory) {
+			return x;
+		}
+
+		SXprUtils.skipOpenParenthesis(keyIn);
+		type = SXprUtils.readString(keyIn, keyIn.read());
+
+		if (!type.equals("hash")) {
+			throw new PGPException("hash keyword expected");
+		}
+		type = SXprUtils.readString(keyIn, keyIn.read());
+
+		if (!type.equals("sha1")) {
+			throw new PGPException("hash keyword expected");
+		}
+
+		byte[] hashBytes = SXprUtils.readBytes(keyIn, keyIn.read());
+
+		SXprUtils.skipCloseParenthesis(keyIn);
+
+		if (digestProvider != null) {
+			PGPDigestCalculator digestCalculator = digestProvider
+					.get(HashAlgorithmTags.SHA1);
+
+			OutputStream dOut = digestCalculator.getOutputStream();
+
+			dOut.write(Strings.toByteArray("(3:elg"));
+			writeCanonical(dOut, "p", p);
+			writeCanonical(dOut, "g", g);
+			writeCanonical(dOut, "y", y);
+			writeCanonical(dOut, "x", x);
+
+			// check protected-at
+			if (protectedAt != null) {
+				dOut.write(protectedAt);
+			}
+
+			dOut.write(Strings.toByteArray(")"));
+
+			byte[] check = digestCalculator.getDigest();
+			if (!Arrays.constantTimeAreEqual(check, hashBytes)) {
+				throw new PGPException(
+						"checksum on protected data failed in SExpr");
+			}
+		}
+
+		return x;
+	}
+
+	private BigInteger processECSecretKey(InputStream inputStream,
+			String curveID, String curveName, byte[] qVal,
+			PBEProtectionRemoverFactory keyProtectionRemoverFactory)
+			throws IOException, PGPException {
+		String type;
+
+		byte[][] basicData = extractData(inputStream,
+				keyProtectionRemoverFactory);
+
+		// JGit modification: handle unencrypted EC keys
+		if (basicData == null) {
+			byte[] nBytes = SXprUtils.readBytes(inputStream,
+					inputStream.read());
+			BigInteger d = new BigInteger(1, nBytes);
+			SXprUtils.skipCloseParenthesis(inputStream);
+			return d;
+		}
+
+		byte[] keyData = basicData[0];
+		byte[] protectedAt = basicData[1];
+
+		//
+		// parse the secret key S-expr
+		//
+		InputStream keyIn = new ByteArrayInputStream(keyData);
+
+		SXprUtils.skipOpenParenthesis(keyIn);
+		SXprUtils.skipOpenParenthesis(keyIn);
+		BigInteger d = readBigInteger("d", keyIn);
+		SXprUtils.skipCloseParenthesis(keyIn);
+
+		// JGit modification: OCB-encrypted keys don't have and don't need a
+		// hash
+		if (keyProtectionRemoverFactory instanceof OCBPBEProtectionRemoverFactory) {
+			return d;
+		}
+
+		SXprUtils.skipOpenParenthesis(keyIn);
+
+		type = SXprUtils.readString(keyIn, keyIn.read());
+
+		if (!type.equals("hash")) {
+			throw new PGPException("hash keyword expected");
+		}
+		type = SXprUtils.readString(keyIn, keyIn.read());
+
+		if (!type.equals("sha1")) {
+			throw new PGPException("hash keyword expected");
+		}
+
+		byte[] hashBytes = SXprUtils.readBytes(keyIn, keyIn.read());
+
+		SXprUtils.skipCloseParenthesis(keyIn);
+
+		if (digestProvider != null) {
+			PGPDigestCalculator digestCalculator = digestProvider
+					.get(HashAlgorithmTags.SHA1);
+
+			OutputStream dOut = digestCalculator.getOutputStream();
+
+			dOut.write(Strings.toByteArray("(3:ecc"));
+
+			dOut.write(Strings.toByteArray("(" + curveID.length() + ":"
+					+ curveID + curveName.length() + ":" + curveName + ")"));
+
+			writeCanonical(dOut, "q", qVal);
+			writeCanonical(dOut, "d", d);
+
+			// check protected-at
+			if (protectedAt != null) {
+				dOut.write(protectedAt);
+			}
+
+			dOut.write(Strings.toByteArray(")"));
+
+			byte[] check = digestCalculator.getDigest();
+
+			if (!Arrays.constantTimeAreEqual(check, hashBytes)) {
+				throw new PGPException(
+						"checksum on protected data failed in SExpr");
+			}
+		}
+
+		return d;
+	}
+
+	private BigInteger[] processRSASecretKey(InputStream inputStream,
+			BigInteger n, BigInteger e,
+			PBEProtectionRemoverFactory keyProtectionRemoverFactory)
+			throws IOException, PGPException {
+		String type;
+		byte[][] basicData = extractData(inputStream,
+				keyProtectionRemoverFactory);
+
+		byte[] keyData;
+		byte[] protectedAt = null;
+
+		InputStream keyIn;
+		BigInteger d;
+
+		if (basicData == null) {
+			keyIn = inputStream;
+			byte[] nBytes = SXprUtils.readBytes(inputStream,
+					inputStream.read());
+			d = new BigInteger(1, nBytes);
+
+			SXprUtils.skipCloseParenthesis(inputStream);
+
+		} else {
+			keyData = basicData[0];
+			protectedAt = basicData[1];
+
+			keyIn = new ByteArrayInputStream(keyData);
+
+			SXprUtils.skipOpenParenthesis(keyIn);
+			SXprUtils.skipOpenParenthesis(keyIn);
+			d = readBigInteger("d", keyIn);
+		}
+
+		//
+		// parse the secret key S-expr
+		//
+
+		BigInteger p = readBigInteger("p", keyIn);
+		BigInteger q = readBigInteger("q", keyIn);
+		BigInteger u = readBigInteger("u", keyIn);
+
+		// JGit modification: OCB-encrypted keys don't have and don't need a
+		// hash
+		if (basicData == null
+				|| keyProtectionRemoverFactory instanceof OCBPBEProtectionRemoverFactory) {
+			return new BigInteger[] { d, p, q, u };
+		}
+
+		SXprUtils.skipCloseParenthesis(keyIn);
+
+		SXprUtils.skipOpenParenthesis(keyIn);
+		type = SXprUtils.readString(keyIn, keyIn.read());
+
+		if (!type.equals("hash")) {
+			throw new PGPException("hash keyword expected");
+		}
+		type = SXprUtils.readString(keyIn, keyIn.read());
+
+		if (!type.equals("sha1")) {
+			throw new PGPException("hash keyword expected");
+		}
+
+		byte[] hashBytes = SXprUtils.readBytes(keyIn, keyIn.read());
+
+		SXprUtils.skipCloseParenthesis(keyIn);
+
+		if (digestProvider != null) {
+			PGPDigestCalculator digestCalculator = digestProvider
+					.get(HashAlgorithmTags.SHA1);
+
+			OutputStream dOut = digestCalculator.getOutputStream();
+
+			dOut.write(Strings.toByteArray("(3:rsa"));
+
+			writeCanonical(dOut, "n", n);
+			writeCanonical(dOut, "e", e);
+			writeCanonical(dOut, "d", d);
+			writeCanonical(dOut, "p", p);
+			writeCanonical(dOut, "q", q);
+			writeCanonical(dOut, "u", u);
+
+			// check protected-at
+			if (protectedAt != null) {
+				dOut.write(protectedAt);
+			}
+
+			dOut.write(Strings.toByteArray(")"));
+
+			byte[] check = digestCalculator.getDigest();
+
+			if (!Arrays.constantTimeAreEqual(check, hashBytes)) {
+				throw new PGPException(
+						"checksum on protected data failed in SExpr");
+			}
+		}
+
+		return new BigInteger[] { d, p, q, u };
+	}
+
+	private void writeCanonical(OutputStream dOut, String label, BigInteger i)
+			throws IOException {
+		writeCanonical(dOut, label, i.toByteArray());
+	}
+
+	private void writeCanonical(OutputStream dOut, String label, byte[] data)
+			throws IOException {
+		dOut.write(Strings.toByteArray(
+				"(" + label.length() + ":" + label + data.length + ":"));
+		dOut.write(data);
+		dOut.write(Strings.toByteArray(")"));
+	}
+}
diff --git a/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/keys/SXprUtils.java b/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/keys/SXprUtils.java
new file mode 100644
index 0000000..220aa28
--- /dev/null
+++ b/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/keys/SXprUtils.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2000-2021 The Legion of the Bouncy Castle Inc. (https://www.bouncycastle.org)
+ * <p>
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+ * and associated documentation files (the "Software"), to deal in the Software without restriction,
+ *including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ * </p>
+ * <p>
+ * The above copyright notice and this permission notice shall be included in all copies or substantial
+ * portions of the Software.
+ * </p>
+ * <p>
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ * </p>
+ */
+package org.eclipse.jgit.gpg.bc.internal.keys;
+
+// This class is an unmodified copy from Bouncy Castle; needed because it's package-visible only and used by SExprParser.
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.bouncycastle.bcpg.HashAlgorithmTags;
+import org.bouncycastle.bcpg.S2K;
+import org.bouncycastle.util.io.Streams;
+
+/**
+ * Utility functions for looking a S-expression keys. This class will move when
+ * it finds a better home!
+ * <p>
+ * Format documented here:
+ * http://git.gnupg.org/cgi-bin/gitweb.cgi?p=gnupg.git;a=blob;f=agent/keyformat.txt;h=42c4b1f06faf1bbe71ffadc2fee0fad6bec91a97;hb=refs/heads/master
+ * </p>
+ */
+class SXprUtils {
+	private static int readLength(InputStream in, int ch) throws IOException {
+		int len = ch - '0';
+
+		while ((ch = in.read()) >= 0 && ch != ':') {
+			len = len * 10 + ch - '0';
+		}
+
+		return len;
+	}
+
+	static String readString(InputStream in, int ch) throws IOException {
+		int len = readLength(in, ch);
+
+		char[] chars = new char[len];
+
+		for (int i = 0; i != chars.length; i++) {
+			chars[i] = (char) in.read();
+		}
+
+		return new String(chars);
+	}
+
+	static byte[] readBytes(InputStream in, int ch) throws IOException {
+		int len = readLength(in, ch);
+
+		byte[] data = new byte[len];
+
+		Streams.readFully(in, data);
+
+		return data;
+	}
+
+	static S2K parseS2K(InputStream in) throws IOException {
+		skipOpenParenthesis(in);
+
+		// Algorithm is hard-coded to SHA1 below anyway.
+		readString(in, in.read());
+		byte[] iv = readBytes(in, in.read());
+		final long iterationCount = Long.parseLong(readString(in, in.read()));
+
+		skipCloseParenthesis(in);
+
+		// we have to return the actual iteration count provided.
+		S2K s2k = new S2K(HashAlgorithmTags.SHA1, iv, (int) iterationCount) {
+			@Override
+			public long getIterationCount() {
+				return iterationCount;
+			}
+		};
+
+		return s2k;
+	}
+
+	static void skipOpenParenthesis(InputStream in) throws IOException {
+		int ch = in.read();
+		if (ch != '(') {
+			throw new IOException(
+					"unknown character encountered: " + (char) ch); //$NON-NLS-1$
+		}
+	}
+
+	static void skipCloseParenthesis(InputStream in) throws IOException {
+		int ch = in.read();
+		if (ch != ')') {
+			throw new IOException("unknown character encountered"); //$NON-NLS-1$
+		}
+	}
+}
diff --git a/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/keys/SecretKeys.java b/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/keys/SecretKeys.java
new file mode 100644
index 0000000..269a1ba
--- /dev/null
+++ b/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/keys/SecretKeys.java
@@ -0,0 +1,597 @@
+/*
+ * Copyright (C) 2021 Thomas Wolf <thomas.wolf@paranor.ch> and others
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0 which is available at
+ * https://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+package org.eclipse.jgit.gpg.bc.internal.keys;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.StreamCorruptedException;
+import java.net.URISyntaxException;
+import java.nio.charset.StandardCharsets;
+import java.text.MessageFormat;
+import java.util.Arrays;
+
+import org.bouncycastle.openpgp.PGPException;
+import org.bouncycastle.openpgp.PGPPublicKey;
+import org.bouncycastle.openpgp.PGPSecretKey;
+import org.bouncycastle.openpgp.operator.PBEProtectionRemoverFactory;
+import org.bouncycastle.openpgp.operator.PGPDigestCalculatorProvider;
+import org.bouncycastle.openpgp.operator.jcajce.JcePBEProtectionRemoverFactory;
+import org.bouncycastle.util.io.Streams;
+import org.eclipse.jgit.api.errors.CanceledException;
+import org.eclipse.jgit.errors.UnsupportedCredentialItem;
+import org.eclipse.jgit.gpg.bc.internal.BCText;
+import org.eclipse.jgit.util.RawParseUtils;
+
+/**
+ * Utilities for reading GPG secret keys from a gpg-agent key file.
+ */
+public final class SecretKeys {
+
+	private SecretKeys() {
+		// No instantiation.
+	}
+
+	/**
+	 * Something that can supply a passphrase to decrypt an encrypted secret
+	 * key.
+	 */
+	public interface PassphraseSupplier {
+
+		/**
+		 * Supplies a passphrase.
+		 *
+		 * @return the passphrase
+		 * @throws PGPException
+		 *             if no passphrase can be obtained
+		 * @throws CanceledException
+		 *             if the user canceled passphrase entry
+		 * @throws UnsupportedCredentialItem
+		 *             if an internal error occurred
+		 * @throws URISyntaxException
+		 *             if an internal error occurred
+		 */
+		char[] getPassphrase() throws PGPException, CanceledException,
+				UnsupportedCredentialItem, URISyntaxException;
+	}
+
+	private static final byte[] PROTECTED_KEY = "protected-private-key" //$NON-NLS-1$
+			.getBytes(StandardCharsets.US_ASCII);
+
+	private static final byte[] OCB_PROTECTED = "openpgp-s2k3-ocb-aes" //$NON-NLS-1$
+			.getBytes(StandardCharsets.US_ASCII);
+
+	/**
+	 * Reads a GPG secret key from the given stream.
+	 *
+	 * @param in
+	 *            {@link InputStream} to read from, doesn't need to be buffered
+	 * @param calculatorProvider
+	 *            for checking digests
+	 * @param passphraseSupplier
+	 *            for decrypting encrypted keys
+	 * @param publicKey
+	 *            the secret key should be for
+	 * @return the secret key
+	 * @throws IOException
+	 *             if the stream cannot be parsed
+	 * @throws PGPException
+	 *             if thrown by the underlying S-Expression parser, for instance
+	 *             when the passphrase is wrong
+	 * @throws CanceledException
+	 *             if thrown by the {@code passphraseSupplier}
+	 * @throws UnsupportedCredentialItem
+	 *             if thrown by the {@code passphraseSupplier}
+	 * @throws URISyntaxException
+	 *             if thrown by the {@code passphraseSupplier}
+	 */
+	public static PGPSecretKey readSecretKey(InputStream in,
+			PGPDigestCalculatorProvider calculatorProvider,
+			PassphraseSupplier passphraseSupplier, PGPPublicKey publicKey)
+			throws IOException, PGPException, CanceledException,
+			UnsupportedCredentialItem, URISyntaxException {
+		byte[] data = Streams.readAll(in);
+		if (data.length == 0) {
+			throw new EOFException();
+		} else if (data.length < 4 + PROTECTED_KEY.length) {
+			// +4 for "(21:" for a binary protected key
+			throw new IOException(
+					MessageFormat.format(BCText.get().secretKeyTooShort,
+							Integer.toUnsignedString(data.length)));
+		}
+		SExprParser parser = new SExprParser(calculatorProvider);
+		byte firstChar = data[0];
+		try {
+			if (firstChar == '(') {
+				// Binary format.
+				PBEProtectionRemoverFactory decryptor = null;
+				if (matches(data, 4, PROTECTED_KEY)) {
+					// AES/CBC encrypted.
+					decryptor = new JcePBEProtectionRemoverFactory(
+							passphraseSupplier.getPassphrase(),
+							calculatorProvider);
+				}
+				try (InputStream sIn = new ByteArrayInputStream(data)) {
+					return parser.parseSecretKey(sIn, decryptor, publicKey);
+				}
+			}
+			// Assume it's the new key-value format.
+			try (ByteArrayInputStream keyIn = new ByteArrayInputStream(data)) {
+				byte[] rawData = keyFromNameValueFormat(keyIn);
+				if (!matches(rawData, 1, PROTECTED_KEY)) {
+					// Not encrypted human-readable format.
+					try (InputStream sIn = new ByteArrayInputStream(
+							convertSexpression(rawData))) {
+						return parser.parseSecretKey(sIn, null, publicKey);
+					}
+				}
+				// An encrypted key from a key-value file. Most likely AES/OCB
+				// encrypted.
+				boolean isOCB[] = { false };
+				byte[] sExp = convertSexpression(rawData, isOCB);
+				PBEProtectionRemoverFactory decryptor;
+				if (isOCB[0]) {
+					decryptor = new OCBPBEProtectionRemoverFactory(
+							passphraseSupplier.getPassphrase(),
+							calculatorProvider, getAad(sExp));
+				} else {
+					decryptor = new JcePBEProtectionRemoverFactory(
+							passphraseSupplier.getPassphrase(),
+							calculatorProvider);
+				}
+				try (InputStream sIn = new ByteArrayInputStream(sExp)) {
+					return parser.parseSecretKey(sIn, decryptor, publicKey);
+				}
+			}
+		} catch (IOException e) {
+			throw new PGPException(e.getLocalizedMessage(), e);
+		}
+	}
+
+	/**
+	 * Extract the AAD for the OCB decryption from an s-expression.
+	 *
+	 * @param sExp
+	 *            buffer containing a valid binary s-expression
+	 * @return the AAD
+	 */
+	private static byte[] getAad(byte[] sExp) {
+		// Given a key
+		// @formatter:off
+		// (protected-private-key (rsa ... (protected openpgp-s2k3-ocb-aes ... )(protected-at ...)))
+		//                        A        B                                    C                  D
+		// The AAD is [A..B)[C..D). (From the binary serialized form.)
+		// @formatter:on
+		int i = 1; // Skip initial '('
+		while (sExp[i] != '(') {
+			i++;
+		}
+		int aadStart = i++;
+		int aadEnd = skip(sExp, aadStart);
+		byte[] protectedPrefix = "(9:protected" //$NON-NLS-1$
+				.getBytes(StandardCharsets.US_ASCII);
+		while (!matches(sExp, i, protectedPrefix)) {
+			i++;
+		}
+		int protectedStart = i;
+		int protectedEnd = skip(sExp, protectedStart);
+		byte[] aadData = new byte[aadEnd - aadStart
+				- (protectedEnd - protectedStart)];
+		System.arraycopy(sExp, aadStart, aadData, 0, protectedStart - aadStart);
+		System.arraycopy(sExp, protectedEnd, aadData, protectedStart - aadStart,
+				aadEnd - protectedEnd);
+		return aadData;
+	}
+
+	/**
+	 * Skips a list including nested lists.
+	 *
+	 * @param sExp
+	 *            buffer containing valid binary s-expression data
+	 * @param start
+	 *            index of the opening '(' of the list to skip
+	 * @return the index after the closing ')' of the skipped list
+	 */
+	private static int skip(byte[] sExp, int start) {
+		int i = start + 1;
+		int depth = 1;
+		while (depth > 0) {
+			switch (sExp[i]) {
+			case '(':
+				depth++;
+				break;
+			case ')':
+				depth--;
+				break;
+			default:
+				// We must be on a length
+				int j = i;
+				while (sExp[j] >= '0' && sExp[j] <= '9') {
+					j++;
+				}
+				// j is on the colon
+				int length = Integer.parseInt(
+						new String(sExp, i, j - i, StandardCharsets.US_ASCII));
+				i = j + length;
+			}
+			i++;
+		}
+		return i;
+	}
+
+	/**
+	 * Checks whether the {@code needle} matches {@code src} at offset
+	 * {@code from}.
+	 *
+	 * @param src
+	 *            to match against {@code needle}
+	 * @param from
+	 *            position in {@code src} to start matching
+	 * @param needle
+	 *            to match against
+	 * @return {@code true} if {@code src} contains {@code needle} at position
+	 *         {@code from}, {@code false} otherwise
+	 */
+	private static boolean matches(byte[] src, int from, byte[] needle) {
+		if (from < 0 || from + needle.length > src.length) {
+			return false;
+		}
+		return org.bouncycastle.util.Arrays.constantTimeAreEqual(needle.length,
+				src, from, needle, 0);
+	}
+
+	/**
+	 * Converts a human-readable serialized s-expression into a binary
+	 * serialized s-expression.
+	 *
+	 * @param humanForm
+	 *            to convert
+	 * @return the converted s-expression
+	 * @throws IOException
+	 *             if the conversion fails
+	 */
+	private static byte[] convertSexpression(byte[] humanForm)
+			throws IOException {
+		boolean[] isOCB = { false };
+		return convertSexpression(humanForm, isOCB);
+	}
+
+	/**
+	 * Converts a human-readable serialized s-expression into a binary
+	 * serialized s-expression.
+	 *
+	 * @param humanForm
+	 *            to convert
+	 * @param isOCB
+	 *            returns whether the s-expression specified AES/OCB encryption
+	 * @return the converted s-expression
+	 * @throws IOException
+	 *             if the conversion fails
+	 */
+	private static byte[] convertSexpression(byte[] humanForm, boolean[] isOCB)
+			throws IOException {
+		int pos = 0;
+		try (ByteArrayOutputStream out = new ByteArrayOutputStream(
+				humanForm.length)) {
+			while (pos < humanForm.length) {
+				byte b = humanForm[pos];
+				if (b == '(' || b == ')') {
+					out.write(b);
+					pos++;
+				} else if (isGpgSpace(b)) {
+					pos++;
+				} else if (b == '#') {
+					// Hex value follows up to the next #
+					int i = ++pos;
+					while (i < humanForm.length && isHex(humanForm[i])) {
+						i++;
+					}
+					if (i == pos || humanForm[i] != '#') {
+						throw new StreamCorruptedException(
+								BCText.get().sexprHexNotClosed);
+					}
+					if ((i - pos) % 2 != 0) {
+						throw new StreamCorruptedException(
+								BCText.get().sexprHexOdd);
+					}
+					int l = (i - pos) / 2;
+					out.write(Integer.toString(l)
+							.getBytes(StandardCharsets.US_ASCII));
+					out.write(':');
+					while (pos < i) {
+						int x = (nibble(humanForm[pos]) << 4)
+								| nibble(humanForm[pos + 1]);
+						pos += 2;
+						out.write(x);
+					}
+					pos = i + 1;
+				} else if (isTokenChar(b)) {
+					// Scan the token
+					int start = pos++;
+					while (pos < humanForm.length
+							&& isTokenChar(humanForm[pos])) {
+						pos++;
+					}
+					int l = pos - start;
+					if (pos - start == OCB_PROTECTED.length
+							&& matches(humanForm, start, OCB_PROTECTED)) {
+						isOCB[0] = true;
+					}
+					out.write(Integer.toString(l)
+							.getBytes(StandardCharsets.US_ASCII));
+					out.write(':');
+					out.write(humanForm, start, pos - start);
+				} else if (b == '"') {
+					// Potentially quoted string.
+					int start = ++pos;
+					boolean escaped = false;
+					while (pos < humanForm.length
+							&& (escaped || humanForm[pos] != '"')) {
+						int ch = humanForm[pos++];
+						escaped = !escaped && ch == '\\';
+					}
+					if (pos >= humanForm.length) {
+						throw new StreamCorruptedException(
+								BCText.get().sexprStringNotClosed);
+					}
+					// start is on the first character of the string, pos on the
+					// closing quote.
+					byte[] dq = dequote(humanForm, start, pos);
+					out.write(Integer.toString(dq.length)
+							.getBytes(StandardCharsets.US_ASCII));
+					out.write(':');
+					out.write(dq);
+					pos++;
+				} else {
+					throw new StreamCorruptedException(
+							MessageFormat.format(BCText.get().sexprUnhandled,
+									Integer.toHexString(b & 0xFF)));
+				}
+			}
+			return out.toByteArray();
+		}
+	}
+
+	/**
+	 * GPG-style string de-quoting, which is basically C-style, with some
+	 * literal CR/LF escaping.
+	 *
+	 * @param in
+	 *            buffer containing the quoted string
+	 * @param from
+	 *            index after the opening quote in {@code in}
+	 * @param to
+	 *            index of the closing quote in {@code in}
+	 * @return the dequoted raw string value
+	 * @throws StreamCorruptedException
+	 */
+	private static byte[] dequote(byte[] in, int from, int to)
+			throws StreamCorruptedException {
+		// Result must be shorter or have the same length
+		byte[] out = new byte[to - from];
+		int j = 0;
+		int i = from;
+		while (i < to) {
+			byte b = in[i++];
+			if (b != '\\') {
+				out[j++] = b;
+				continue;
+			}
+			if (i == to) {
+				throw new StreamCorruptedException(
+						BCText.get().sexprStringInvalidEscapeAtEnd);
+			}
+			b = in[i++];
+			switch (b) {
+			case 'b':
+				out[j++] = '\b';
+				break;
+			case 'f':
+				out[j++] = '\f';
+				break;
+			case 'n':
+				out[j++] = '\n';
+				break;
+			case 'r':
+				out[j++] = '\r';
+				break;
+			case 't':
+				out[j++] = '\t';
+				break;
+			case 'v':
+				out[j++] = 0x0B;
+				break;
+			case '"':
+			case '\'':
+			case '\\':
+				out[j++] = b;
+				break;
+			case '\r':
+				// Escaped literal line end. If an LF is following, skip that,
+				// too.
+				if (i < to && in[i] == '\n') {
+					i++;
+				}
+				break;
+			case '\n':
+				// Same for LF possibly followed by CR.
+				if (i < to && in[i] == '\r') {
+					i++;
+				}
+				break;
+			case 'x':
+				if (i + 1 >= to || !isHex(in[i]) || !isHex(in[i + 1])) {
+					throw new StreamCorruptedException(
+							BCText.get().sexprStringInvalidHexEscape);
+				}
+				out[j++] = (byte) ((nibble(in[i]) << 4) | nibble(in[i + 1]));
+				i += 2;
+				break;
+			case '0':
+			case '1':
+			case '2':
+			case '3':
+				if (i + 2 >= to || !isOctal(in[i]) || !isOctal(in[i + 1])
+						|| !isOctal(in[i + 2])) {
+					throw new StreamCorruptedException(
+							BCText.get().sexprStringInvalidOctalEscape);
+				}
+				out[j++] = (byte) (((((in[i] - '0') << 3)
+						| (in[i + 1] - '0')) << 3) | (in[i + 2] - '0'));
+				i += 3;
+				break;
+			default:
+				throw new StreamCorruptedException(MessageFormat.format(
+						BCText.get().sexprStringInvalidEscape,
+						Integer.toHexString(b & 0xFF)));
+			}
+		}
+		return Arrays.copyOf(out, j);
+	}
+
+	/**
+	 * Extracts the key from a GPG name-value-pair key file.
+	 * <p>
+	 * Package-visible for tests only.
+	 * </p>
+	 *
+	 * @param in
+	 *            {@link InputStream} to read from; should be buffered
+	 * @return the raw key data as extracted from the file
+	 * @throws IOException
+	 *             if the {@code in} stream cannot be read or does not contain a
+	 *             key
+	 */
+	static byte[] keyFromNameValueFormat(InputStream in) throws IOException {
+		// It would be nice if we could use RawParseUtils here, but GPG compares
+		// names case-insensitively. We're only interested in the "Key:"
+		// name-value pair.
+		int[] nameLow = { 'k', 'e', 'y', ':' };
+		int[] nameCap = { 'K', 'E', 'Y', ':' };
+		int nameIdx = 0;
+		for (;;) {
+			int next = in.read();
+			if (next < 0) {
+				throw new EOFException();
+			}
+			if (next == '\n') {
+				nameIdx = 0;
+			} else if (nameIdx >= 0) {
+				if (nameLow[nameIdx] == next || nameCap[nameIdx] == next) {
+					nameIdx++;
+					if (nameIdx == nameLow.length) {
+						break;
+					}
+				} else {
+					nameIdx = -1;
+				}
+			}
+		}
+		// We're after "Key:". Read the value as continuation lines.
+		int last = ':';
+		byte[] rawData;
+		try (ByteArrayOutputStream out = new ByteArrayOutputStream(8192)) {
+			for (;;) {
+				int next = in.read();
+				if (next < 0) {
+					break;
+				}
+				if (last == '\n') {
+					if (next == ' ' || next == '\t') {
+						// Continuation line; skip this whitespace
+						last = next;
+						continue;
+					}
+					break; // Not a continuation line
+				}
+				out.write(next);
+				last = next;
+			}
+			rawData = out.toByteArray();
+		}
+		// GPG trims off trailing whitespace, and a line having only whitespace
+		// is a single LF.
+		try (ByteArrayOutputStream out = new ByteArrayOutputStream(
+				rawData.length)) {
+			int lineStart = 0;
+			boolean trimLeading = true;
+			while (lineStart < rawData.length) {
+				int nextLineStart = RawParseUtils.nextLF(rawData, lineStart);
+				if (trimLeading) {
+					while (lineStart < nextLineStart
+							&& isGpgSpace(rawData[lineStart])) {
+						lineStart++;
+					}
+				}
+				// Trim trailing
+				int i = nextLineStart - 1;
+				while (lineStart < i && isGpgSpace(rawData[i])) {
+					i--;
+				}
+				if (i <= lineStart) {
+					// Empty line signifies LF
+					out.write('\n');
+					trimLeading = true;
+				} else {
+					out.write(rawData, lineStart, i - lineStart + 1);
+					trimLeading = false;
+				}
+				lineStart = nextLineStart;
+			}
+			return out.toByteArray();
+		}
+	}
+
+	private static boolean isGpgSpace(int ch) {
+		return ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n';
+	}
+
+	private static boolean isTokenChar(int ch) {
+		switch (ch) {
+		case '-':
+		case '.':
+		case '/':
+		case '_':
+		case ':':
+		case '*':
+		case '+':
+		case '=':
+			return true;
+		default:
+			if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')
+					|| (ch >= '0' && ch <= '9')) {
+				return true;
+			}
+			return false;
+		}
+	}
+
+	private static boolean isHex(int ch) {
+		return (ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'F')
+				|| (ch >= 'a' && ch <= 'f');
+	}
+
+	private static boolean isOctal(int ch) {
+		return (ch >= '0' && ch <= '7');
+	}
+
+	private static int nibble(int ch) {
+		if (ch >= '0' && ch <= '9') {
+			return ch - '0';
+		} else if (ch >= 'A' && ch <= 'F') {
+			return ch - 'A' + 10;
+		} else if (ch >= 'a' && ch <= 'f') {
+			return ch - 'a' + 10;
+		}
+		return -1;
+	}
+}
diff --git a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/InfoPacksServlet.java b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/InfoPacksServlet.java
index c3d7255..e90580b 100644
--- a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/InfoPacksServlet.java
+++ b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/InfoPacksServlet.java
@@ -20,7 +20,7 @@
 import javax.servlet.http.HttpServletResponse;
 
 import org.eclipse.jgit.internal.storage.file.ObjectDirectory;
-import org.eclipse.jgit.internal.storage.file.PackFile;
+import org.eclipse.jgit.internal.storage.file.Pack;
 import org.eclipse.jgit.lib.ObjectDatabase;
 
 /** Sends the current list of pack files, sorted most recent first. */
@@ -38,7 +38,7 @@
 		final StringBuilder out = new StringBuilder();
 		final ObjectDatabase db = getRepository(req).getObjectDatabase();
 		if (db instanceof ObjectDirectory) {
-			for (PackFile pack : ((ObjectDirectory) db).getPacks()) {
+			for (Pack pack : ((ObjectDirectory) db).getPacks()) {
 				out.append("P ");
 				out.append(pack.getPackFile().getName());
 				out.append('\n');
diff --git a/org.eclipse.jgit.junit.ssh/META-INF/MANIFEST.MF b/org.eclipse.jgit.junit.ssh/META-INF/MANIFEST.MF
index 46b59fe..f7b9a28 100644
--- a/org.eclipse.jgit.junit.ssh/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.junit.ssh/META-INF/MANIFEST.MF
@@ -8,28 +8,31 @@
 Bundle-Vendor: %Bundle-Vendor
 Bundle-ActivationPolicy: lazy
 Bundle-RequiredExecutionEnvironment: JavaSE-1.8
-Import-Package: org.apache.sshd.common;version="[2.4.0,2.5.0)",
- org.apache.sshd.common.config.keys;version="[2.4.0,2.5.0)",
- org.apache.sshd.common.file.virtualfs;version="[2.4.0,2.5.0)",
- org.apache.sshd.common.helpers;version="[2.4.0,2.5.0)",
- org.apache.sshd.common.io;version="[2.4.0,2.5.0)",
- org.apache.sshd.common.kex;version="[2.4.0,2.5.0)",
- org.apache.sshd.common.keyprovider;version="[2.4.0,2.5.0)",
- org.apache.sshd.common.session;version="[2.4.0,2.5.0)",
- org.apache.sshd.common.util.buffer;version="[2.4.0,2.5.0)",
- org.apache.sshd.common.util.logging;version="[2.4.0,2.5.0)",
- org.apache.sshd.common.util.security;version="[2.4.0,2.5.0)",
- org.apache.sshd.common.util.threads;version="[2.4.0,2.5.0)",
- org.apache.sshd.server;version="[2.4.0,2.5.0)",
- org.apache.sshd.server.auth;version="[2.4.0,2.5.0)",
- org.apache.sshd.server.auth.gss;version="[2.4.0,2.5.0)",
- org.apache.sshd.server.auth.keyboard;version="[2.4.0,2.5.0)",
- org.apache.sshd.server.auth.password;version="[2.4.0,2.5.0)",
- org.apache.sshd.server.command;version="[2.4.0,2.5.0)",
- org.apache.sshd.server.session;version="[2.4.0,2.5.0)",
- org.apache.sshd.server.shell;version="[2.4.0,2.5.0)",
- org.apache.sshd.server.subsystem;version="[2.4.0,2.5.0)",
- org.apache.sshd.server.subsystem.sftp;version="[2.4.0,2.5.0)",
+Import-Package: org.apache.sshd.common;version="[2.6.0,2.7.0)",
+ org.apache.sshd.common.config.keys;version="[2.6.0,2.7.0)",
+ org.apache.sshd.common.file.virtualfs;version="[2.6.0,2.7.0)",
+ org.apache.sshd.common.helpers;version="[2.6.0,2.7.0)",
+ org.apache.sshd.common.io;version="[2.6.0,2.7.0)",
+ org.apache.sshd.common.kex;version="[2.6.0,2.7.0)",
+ org.apache.sshd.common.keyprovider;version="[2.6.0,2.7.0)",
+ org.apache.sshd.common.session;version="[2.6.0,2.7.0)",
+ org.apache.sshd.common.signature;version="[2.6.0,2.7.0)",
+ org.apache.sshd.common.util.buffer;version="[2.6.0,2.7.0)",
+ org.apache.sshd.common.util.logging;version="[2.6.0,2.7.0)",
+ org.apache.sshd.common.util.security;version="[2.6.0,2.7.0)",
+ org.apache.sshd.common.util.threads;version="[2.6.0,2.7.0)",
+ org.apache.sshd.core;version="[2.6.0,2.7.0)",
+ org.apache.sshd.server;version="[2.6.0,2.7.0)",
+ org.apache.sshd.server.auth;version="[2.6.0,2.7.0)",
+ org.apache.sshd.server.auth.gss;version="[2.6.0,2.7.0)",
+ org.apache.sshd.server.auth.keyboard;version="[2.6.0,2.7.0)",
+ org.apache.sshd.server.auth.password;version="[2.6.0,2.7.0)",
+ org.apache.sshd.server.command;version="[2.6.0,2.7.0)",
+ org.apache.sshd.server.session;version="[2.6.0,2.7.0)",
+ org.apache.sshd.server.shell;version="[2.6.0,2.7.0)",
+ org.apache.sshd.server.subsystem;version="[2.6.0,2.7.0)",
+ org.apache.sshd.sftp;version="[2.6.0,2.7.0)",
+ org.apache.sshd.sftp.server;version="[2.6.0,2.7.0)",
  org.eclipse.jgit.annotations;version="[5.11.0,5.12.0)",
  org.eclipse.jgit.api;version="[5.11.0,5.12.0)",
  org.eclipse.jgit.api.errors;version="[5.11.0,5.12.0)",
diff --git a/org.eclipse.jgit.junit.ssh/src/org/eclipse/jgit/junit/ssh/SshTestGitServer.java b/org.eclipse.jgit.junit.ssh/src/org/eclipse/jgit/junit/ssh/SshTestGitServer.java
index 8494a2f..4fe98f8 100644
--- a/org.eclipse.jgit.junit.ssh/src/org/eclipse/jgit/junit/ssh/SshTestGitServer.java
+++ b/org.eclipse.jgit.junit.ssh/src/org/eclipse/jgit/junit/ssh/SshTestGitServer.java
@@ -9,6 +9,9 @@
  */
 package org.eclipse.jgit.junit.ssh;
 
+import static org.apache.sshd.core.CoreModuleProperties.SERVER_EXTRA_IDENTIFICATION_LINES;
+import static org.apache.sshd.core.CoreModuleProperties.SERVER_EXTRA_IDENT_LINES_SEPARATOR;
+
 import java.io.ByteArrayInputStream;
 import java.io.IOException;
 import java.io.InputStream;
@@ -21,26 +24,28 @@
 import java.security.PublicKey;
 import java.text.MessageFormat;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
 import java.util.Locale;
 import java.util.concurrent.TimeUnit;
 
+import org.apache.sshd.common.NamedFactory;
 import org.apache.sshd.common.NamedResource;
 import org.apache.sshd.common.PropertyResolver;
-import org.apache.sshd.common.PropertyResolverUtils;
 import org.apache.sshd.common.SshConstants;
 import org.apache.sshd.common.config.keys.AuthorizedKeyEntry;
 import org.apache.sshd.common.config.keys.KeyUtils;
 import org.apache.sshd.common.config.keys.PublicKeyEntryResolver;
 import org.apache.sshd.common.file.virtualfs.VirtualFileSystemFactory;
-import org.apache.sshd.common.session.Session;
+import org.apache.sshd.common.signature.BuiltinSignatures;
+import org.apache.sshd.common.signature.Signature;
 import org.apache.sshd.common.util.buffer.Buffer;
 import org.apache.sshd.common.util.security.SecurityUtils;
 import org.apache.sshd.common.util.threads.CloseableExecutorService;
 import org.apache.sshd.common.util.threads.ThreadUtils;
 import org.apache.sshd.server.ServerAuthenticationManager;
-import org.apache.sshd.server.ServerFactoryManager;
+import org.apache.sshd.server.ServerBuilder;
 import org.apache.sshd.server.SshServer;
 import org.apache.sshd.server.auth.UserAuth;
 import org.apache.sshd.server.auth.UserAuthFactory;
@@ -52,7 +57,7 @@
 import org.apache.sshd.server.session.ServerSession;
 import org.apache.sshd.server.shell.UnknownCommand;
 import org.apache.sshd.server.subsystem.SubsystemFactory;
-import org.apache.sshd.server.subsystem.sftp.SftpSubsystemFactory;
+import org.apache.sshd.sftp.server.SftpSubsystemFactory;
 import org.eclipse.jgit.annotations.NonNull;
 import org.eclipse.jgit.annotations.Nullable;
 import org.eclipse.jgit.lib.Repository;
@@ -162,7 +167,9 @@
 		this.testUser = testUser;
 		setTestUserPublicKey(testKey);
 		this.repository = repository;
-		server = SshServer.setUpDefaultServer();
+		ServerBuilder builder = ServerBuilder.builder()
+				.signatureFactories(getSignatureFactories());
+		server = builder.build();
 		hostKeys.add(hostKey);
 		server.setKeyPairProvider((session) -> hostKeys);
 
@@ -187,6 +194,37 @@
 		});
 	}
 
+	/**
+	 * Apache MINA sshd 2.6.0 has removed DSA, DSA_CERT and RSA_CERT. We have to
+	 * set it up explicitly to still allow users to connect with DSA keys.
+	 *
+	 * @return a list of supported signature factories
+	 */
+	@SuppressWarnings("deprecation")
+	private static List<NamedFactory<Signature>> getSignatureFactories() {
+		// @formatter:off
+		return Arrays.asList(
+                BuiltinSignatures.nistp256_cert,
+                BuiltinSignatures.nistp384_cert,
+                BuiltinSignatures.nistp521_cert,
+                BuiltinSignatures.ed25519_cert,
+                BuiltinSignatures.rsaSHA512_cert,
+                BuiltinSignatures.rsaSHA256_cert,
+                BuiltinSignatures.rsa_cert,
+                BuiltinSignatures.nistp256,
+                BuiltinSignatures.nistp384,
+                BuiltinSignatures.nistp521,
+                BuiltinSignatures.ed25519,
+                BuiltinSignatures.sk_ecdsa_sha2_nistp256,
+                BuiltinSignatures.sk_ssh_ed25519,
+                BuiltinSignatures.rsaSHA512,
+                BuiltinSignatures.rsaSHA256,
+                BuiltinSignatures.rsa,
+                BuiltinSignatures.dsa_cert,
+                BuiltinSignatures.dsa);
+		// @formatter:on
+	}
+
 	private static PublicKey readPublicKey(Path key)
 			throws IOException, GeneralSecurityException {
 		return AuthorizedKeyEntry.readAuthorizedKeys(key).get(0)
@@ -278,14 +316,8 @@
 	@NonNull
 	protected List<SubsystemFactory> configureSubsystems() {
 		// SFTP.
-		server.setFileSystemFactory(new VirtualFileSystemFactory() {
-
-			@Override
-			protected Path computeRootDir(Session session) throws IOException {
-				return SshTestGitServer.this.repository.getDirectory()
-						.getParentFile().getAbsoluteFile().toPath();
-			}
-		});
+		server.setFileSystemFactory(new VirtualFileSystemFactory(repository
+				.getDirectory().getParentFile().getAbsoluteFile().toPath()));
 		return Collections
 				.singletonList((new SftpSubsystemFactory.Builder()).build());
 	}
@@ -434,9 +466,8 @@
 	 */
 	public void setPreamble(String... lines) {
 		if (lines != null && lines.length > 0) {
-			PropertyResolverUtils.updateProperty(this.server,
-					ServerFactoryManager.SERVER_EXTRA_IDENTIFICATION_LINES,
-					String.join("|", lines));
+			SERVER_EXTRA_IDENTIFICATION_LINES.set(server, String.join(
+					String.valueOf(SERVER_EXTRA_IDENT_LINES_SEPARATOR), lines));
 		}
 	}
 
diff --git a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/SeparateClassloaderTestRunner.java b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/SeparateClassloaderTestRunner.java
index b982787..4a4dc92 100644
--- a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/SeparateClassloaderTestRunner.java
+++ b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/SeparateClassloaderTestRunner.java
@@ -9,10 +9,10 @@
  */
 package org.eclipse.jgit.junit;
 
-import static java.lang.ClassLoader.getSystemClassLoader;
-
+import java.net.MalformedURLException;
 import java.net.URL;
 import java.net.URLClassLoader;
+import java.nio.file.Paths;
 
 import org.junit.runners.BlockJUnit4ClassRunner;
 import org.junit.runners.model.InitializationError;
@@ -40,7 +40,13 @@
 	private static Class<?> loadNewClass(Class<?> klass)
 			throws InitializationError {
 		try {
-			URL[] urls = ((URLClassLoader) getSystemClassLoader()).getURLs();
+			String pathSeparator = System.getProperty("path.separator");
+			String[] classPathEntries = System.getProperty("java.class.path")
+					.split(pathSeparator);
+			URL[] urls = new URL[classPathEntries.length];
+			for (int i = 0; i < classPathEntries.length; i++) {
+				urls[i] = Paths.get(classPathEntries[i]).toUri().toURL();
+			}
 			ClassLoader testClassLoader = new URLClassLoader(urls) {
 
 				@Override
@@ -54,7 +60,7 @@
 				}
 			};
 			return Class.forName(klass.getName(), true, testClassLoader);
-		} catch (ClassNotFoundException e) {
+		} catch (ClassNotFoundException | MalformedURLException e) {
 			throw new InitializationError(e);
 		}
 	}
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 a5b3b1f..e3eb2c5 100644
--- a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/TestRepository.java
+++ b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/TestRepository.java
@@ -43,7 +43,7 @@
 import org.eclipse.jgit.internal.storage.file.FileRepository;
 import org.eclipse.jgit.internal.storage.file.LockFile;
 import org.eclipse.jgit.internal.storage.file.ObjectDirectory;
-import org.eclipse.jgit.internal.storage.file.PackFile;
+import org.eclipse.jgit.internal.storage.file.Pack;
 import org.eclipse.jgit.internal.storage.file.PackIndex.MutableEntry;
 import org.eclipse.jgit.internal.storage.pack.PackWriter;
 import org.eclipse.jgit.lib.AnyObjectId;
@@ -773,7 +773,7 @@
 			rw.writeInfoRefs();
 
 			final StringBuilder w = new StringBuilder();
-			for (PackFile p : fr.getObjectDatabase().getPacks()) {
+			for (Pack p : fr.getObjectDatabase().getPacks()) {
 				w.append("P ");
 				w.append(p.getPackFile().getName());
 				w.append('\n');
@@ -954,7 +954,7 @@
 	}
 
 	private static void prunePacked(ObjectDirectory odb) throws IOException {
-		for (PackFile p : odb.getPacks()) {
+		for (Pack p : odb.getPacks()) {
 			for (MutableEntry e : p)
 				FileUtils.delete(odb.fileFor(e.toObjectId()));
 		}
diff --git a/org.eclipse.jgit.lfs.test/tst/org/eclipse/jgit/lfs/lib/LFSPointerTest.java b/org.eclipse.jgit.lfs.test/tst/org/eclipse/jgit/lfs/lib/LFSPointerTest.java
index fd83ff1..da78b28 100644
--- a/org.eclipse.jgit.lfs.test/tst/org/eclipse/jgit/lfs/lib/LFSPointerTest.java
+++ b/org.eclipse.jgit.lfs.test/tst/org/eclipse/jgit/lfs/lib/LFSPointerTest.java
@@ -241,6 +241,7 @@
 	}
 
 	@Test
+	@SuppressWarnings("SelfComparison")
 	public void testCompareToSame() throws Exception {
 		AnyLongObjectId id = LongObjectId.fromString(TEST_SHA256);
 		LfsPointer lfs = new LfsPointer(id, 4);
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.10.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.10.target
index 1629266..68378a2 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.10.target
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.10.target
@@ -1,28 +1,28 @@
 <?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="1610487371">
+<target name="jgit-4.10" sequenceNumber="1613861945">
   <locations>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
-      <unit id="org.eclipse.jetty.client" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.client.source" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.continuation" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.continuation.source" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.http" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.http.source" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.io" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.io.source" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.security" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.security.source" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.server" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.server.source" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.servlet" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.servlet.source" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.util" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.util.source" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.util.ajax" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.util.ajax.source" version="9.4.35.v20201120"/>
-      <repository id="jetty-9.4.30" location="https://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.4.35.v20201120/"/>
+      <unit id="org.eclipse.jetty.client" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.client.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.continuation" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.continuation.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.http" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.http.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.io" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.io.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.security" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.security.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.server" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.server.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.servlet" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.servlet.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.util" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.util.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.util.ajax" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.util.ajax.source" version="9.4.36.v20210114"/>
+      <repository id="jetty-9.4.36" location="https://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.4.36.v20210114/"/>
     </location>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
       <unit id="com.google.gson" version="2.8.6.v20201231-1626"/>
@@ -49,16 +49,16 @@
       <unit id="org.apache.commons.compress.source" version="1.19.0.v20200106-2343"/>
       <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.10.v20200830-2311"/>
-      <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.10.v20200830-2311"/>
-      <unit id="org.apache.httpcomponents.httpcore" version="4.4.12.v20200108-1212"/>
-      <unit id="org.apache.httpcomponents.httpcore.source" version="4.4.12.v20200108-1212"/>
+      <unit id="org.apache.httpcomponents.httpclient" version="4.5.13.v20210128-2225"/>
+      <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.13.v20210128-2225"/>
+      <unit id="org.apache.httpcomponents.httpcore" version="4.4.14.v20210128-2225"/>
+      <unit id="org.apache.httpcomponents.httpcore.source" version="4.4.14.v20210128-2225"/>
       <unit id="org.apache.log4j" version="1.2.15.v201012070815"/>
       <unit id="org.apache.log4j.source" version="1.2.15.v201012070815"/>
-      <unit id="org.apache.sshd.osgi" version="2.4.0.v20200318-1614"/>
-      <unit id="org.apache.sshd.osgi.source" version="2.4.0.v20200318-1614"/>
-      <unit id="org.apache.sshd.sftp" version="2.4.0.v20200319-1547"/>
-      <unit id="org.apache.sshd.sftp.source" version="2.4.0.v20200319-1547"/>
+      <unit id="org.apache.sshd.osgi" version="2.6.0.v20210201-2003"/>
+      <unit id="org.apache.sshd.osgi.source" version="2.6.0.v20210201-2003"/>
+      <unit id="org.apache.sshd.sftp" version="2.6.0.v20210201-2003"/>
+      <unit id="org.apache.sshd.sftp.source" version="2.6.0.v20210201-2003"/>
       <unit id="org.assertj" version="3.14.0.v20200120-1926"/>
       <unit id="org.assertj.source" version="3.14.0.v20200120-1926"/>
       <unit id="org.bouncycastle.bcpg" version="1.65.0.v20200527-1955"/>
@@ -86,7 +86,7 @@
       <unit id="org.slf4j.binding.log4j12.source" version="1.7.30.v20201108-2042"/>
       <unit id="org.tukaani.xz" version="1.8.0.v20180207-1613"/>
       <unit id="org.tukaani.xz.source" version="1.8.0.v20180207-1613"/>
-      <repository location="https://download.eclipse.org/tools/orbit/downloads/drops/S20210105214148/repository"/>
+      <repository location="https://download.eclipse.org/tools/orbit/downloads/drops/S20210216215844/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.10.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.10.tpd
index ac4da5c..fb1ac6b 100644
--- 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
@@ -1,7 +1,7 @@
 target "jgit-4.10" with source configurePhase
 
 include "projects/jetty-9.4.x.tpd"
-include "orbit/S20210105214148.tpd"
+include "orbit/S20210216215844.tpd"
 
 location "https://download.eclipse.org/releases/2018-12/" {
 	org.eclipse.osgi lazy
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.11.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.11.target
index afe7936..18d525d 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.11.target
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.11.target
@@ -1,28 +1,28 @@
 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
 <?pde?>
 <!-- generated with https://github.com/eclipse-cbi/targetplatform-dsl -->
-<target name="jgit-4.11" sequenceNumber="1610487371">
+<target name="jgit-4.11" sequenceNumber="1613862033">
   <locations>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
-      <unit id="org.eclipse.jetty.client" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.client.source" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.continuation" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.continuation.source" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.http" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.http.source" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.io" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.io.source" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.security" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.security.source" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.server" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.server.source" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.servlet" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.servlet.source" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.util" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.util.source" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.util.ajax" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.util.ajax.source" version="9.4.35.v20201120"/>
-      <repository id="jetty-9.4.30" location="https://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.4.35.v20201120/"/>
+      <unit id="org.eclipse.jetty.client" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.client.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.continuation" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.continuation.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.http" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.http.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.io" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.io.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.security" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.security.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.server" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.server.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.servlet" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.servlet.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.util" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.util.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.util.ajax" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.util.ajax.source" version="9.4.36.v20210114"/>
+      <repository id="jetty-9.4.36" location="https://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.4.36.v20210114/"/>
     </location>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
       <unit id="com.google.gson" version="2.8.6.v20201231-1626"/>
@@ -49,16 +49,16 @@
       <unit id="org.apache.commons.compress.source" version="1.19.0.v20200106-2343"/>
       <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.10.v20200830-2311"/>
-      <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.10.v20200830-2311"/>
-      <unit id="org.apache.httpcomponents.httpcore" version="4.4.12.v20200108-1212"/>
-      <unit id="org.apache.httpcomponents.httpcore.source" version="4.4.12.v20200108-1212"/>
+      <unit id="org.apache.httpcomponents.httpclient" version="4.5.13.v20210128-2225"/>
+      <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.13.v20210128-2225"/>
+      <unit id="org.apache.httpcomponents.httpcore" version="4.4.14.v20210128-2225"/>
+      <unit id="org.apache.httpcomponents.httpcore.source" version="4.4.14.v20210128-2225"/>
       <unit id="org.apache.log4j" version="1.2.15.v201012070815"/>
       <unit id="org.apache.log4j.source" version="1.2.15.v201012070815"/>
-      <unit id="org.apache.sshd.osgi" version="2.4.0.v20200318-1614"/>
-      <unit id="org.apache.sshd.osgi.source" version="2.4.0.v20200318-1614"/>
-      <unit id="org.apache.sshd.sftp" version="2.4.0.v20200319-1547"/>
-      <unit id="org.apache.sshd.sftp.source" version="2.4.0.v20200319-1547"/>
+      <unit id="org.apache.sshd.osgi" version="2.6.0.v20210201-2003"/>
+      <unit id="org.apache.sshd.osgi.source" version="2.6.0.v20210201-2003"/>
+      <unit id="org.apache.sshd.sftp" version="2.6.0.v20210201-2003"/>
+      <unit id="org.apache.sshd.sftp.source" version="2.6.0.v20210201-2003"/>
       <unit id="org.assertj" version="3.14.0.v20200120-1926"/>
       <unit id="org.assertj.source" version="3.14.0.v20200120-1926"/>
       <unit id="org.bouncycastle.bcpg" version="1.65.0.v20200527-1955"/>
@@ -86,7 +86,7 @@
       <unit id="org.slf4j.binding.log4j12.source" version="1.7.30.v20201108-2042"/>
       <unit id="org.tukaani.xz" version="1.8.0.v20180207-1613"/>
       <unit id="org.tukaani.xz.source" version="1.8.0.v20180207-1613"/>
-      <repository location="https://download.eclipse.org/tools/orbit/downloads/drops/S20210105214148/repository"/>
+      <repository location="https://download.eclipse.org/tools/orbit/downloads/drops/S20210216215844/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.11.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.11.tpd
index c3ac590..0d56280 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.11.tpd
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.11.tpd
@@ -1,7 +1,7 @@
 target "jgit-4.11" with source configurePhase
 
 include "projects/jetty-9.4.x.tpd"
-include "orbit/S20210105214148.tpd"
+include "orbit/S20210216215844.tpd"
 
 location "https://download.eclipse.org/releases/2019-03/" {
 	org.eclipse.osgi lazy
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.12.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.12.target
index b7de53d..d72f08d 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.12.target
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.12.target
@@ -1,28 +1,28 @@
 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
 <?pde?>
 <!-- generated with https://github.com/eclipse-cbi/targetplatform-dsl -->
-<target name="jgit-4.12" sequenceNumber="1610487371">
+<target name="jgit-4.12" sequenceNumber="1613862033">
   <locations>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
-      <unit id="org.eclipse.jetty.client" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.client.source" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.continuation" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.continuation.source" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.http" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.http.source" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.io" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.io.source" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.security" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.security.source" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.server" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.server.source" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.servlet" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.servlet.source" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.util" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.util.source" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.util.ajax" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.util.ajax.source" version="9.4.35.v20201120"/>
-      <repository id="jetty-9.4.30" location="https://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.4.35.v20201120/"/>
+      <unit id="org.eclipse.jetty.client" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.client.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.continuation" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.continuation.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.http" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.http.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.io" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.io.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.security" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.security.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.server" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.server.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.servlet" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.servlet.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.util" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.util.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.util.ajax" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.util.ajax.source" version="9.4.36.v20210114"/>
+      <repository id="jetty-9.4.36" location="https://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.4.36.v20210114/"/>
     </location>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
       <unit id="com.google.gson" version="2.8.6.v20201231-1626"/>
@@ -49,16 +49,16 @@
       <unit id="org.apache.commons.compress.source" version="1.19.0.v20200106-2343"/>
       <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.10.v20200830-2311"/>
-      <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.10.v20200830-2311"/>
-      <unit id="org.apache.httpcomponents.httpcore" version="4.4.12.v20200108-1212"/>
-      <unit id="org.apache.httpcomponents.httpcore.source" version="4.4.12.v20200108-1212"/>
+      <unit id="org.apache.httpcomponents.httpclient" version="4.5.13.v20210128-2225"/>
+      <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.13.v20210128-2225"/>
+      <unit id="org.apache.httpcomponents.httpcore" version="4.4.14.v20210128-2225"/>
+      <unit id="org.apache.httpcomponents.httpcore.source" version="4.4.14.v20210128-2225"/>
       <unit id="org.apache.log4j" version="1.2.15.v201012070815"/>
       <unit id="org.apache.log4j.source" version="1.2.15.v201012070815"/>
-      <unit id="org.apache.sshd.osgi" version="2.4.0.v20200318-1614"/>
-      <unit id="org.apache.sshd.osgi.source" version="2.4.0.v20200318-1614"/>
-      <unit id="org.apache.sshd.sftp" version="2.4.0.v20200319-1547"/>
-      <unit id="org.apache.sshd.sftp.source" version="2.4.0.v20200319-1547"/>
+      <unit id="org.apache.sshd.osgi" version="2.6.0.v20210201-2003"/>
+      <unit id="org.apache.sshd.osgi.source" version="2.6.0.v20210201-2003"/>
+      <unit id="org.apache.sshd.sftp" version="2.6.0.v20210201-2003"/>
+      <unit id="org.apache.sshd.sftp.source" version="2.6.0.v20210201-2003"/>
       <unit id="org.assertj" version="3.14.0.v20200120-1926"/>
       <unit id="org.assertj.source" version="3.14.0.v20200120-1926"/>
       <unit id="org.bouncycastle.bcpg" version="1.65.0.v20200527-1955"/>
@@ -86,7 +86,7 @@
       <unit id="org.slf4j.binding.log4j12.source" version="1.7.30.v20201108-2042"/>
       <unit id="org.tukaani.xz" version="1.8.0.v20180207-1613"/>
       <unit id="org.tukaani.xz.source" version="1.8.0.v20180207-1613"/>
-      <repository location="https://download.eclipse.org/tools/orbit/downloads/drops/S20210105214148/repository"/>
+      <repository location="https://download.eclipse.org/tools/orbit/downloads/drops/S20210216215844/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.12.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.12.tpd
index 7e6ad8e..5a02415 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.12.tpd
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.12.tpd
@@ -1,7 +1,7 @@
 target "jgit-4.12" with source configurePhase
 
 include "projects/jetty-9.4.x.tpd"
-include "orbit/S20210105214148.tpd"
+include "orbit/S20210216215844.tpd"
 
 location "https://download.eclipse.org/releases/2019-06/" {
 	org.eclipse.osgi lazy
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.13.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.13.target
index 3f9d17d..d0e5592 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.13.target
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.13.target
@@ -1,28 +1,28 @@
 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
 <?pde?>
 <!-- generated with https://github.com/eclipse-cbi/targetplatform-dsl -->
-<target name="jgit-4.13" sequenceNumber="1610487371">
+<target name="jgit-4.13" sequenceNumber="1613862034">
   <locations>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
-      <unit id="org.eclipse.jetty.client" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.client.source" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.continuation" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.continuation.source" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.http" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.http.source" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.io" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.io.source" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.security" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.security.source" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.server" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.server.source" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.servlet" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.servlet.source" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.util" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.util.source" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.util.ajax" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.util.ajax.source" version="9.4.35.v20201120"/>
-      <repository id="jetty-9.4.30" location="https://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.4.35.v20201120/"/>
+      <unit id="org.eclipse.jetty.client" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.client.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.continuation" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.continuation.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.http" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.http.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.io" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.io.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.security" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.security.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.server" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.server.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.servlet" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.servlet.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.util" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.util.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.util.ajax" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.util.ajax.source" version="9.4.36.v20210114"/>
+      <repository id="jetty-9.4.36" location="https://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.4.36.v20210114/"/>
     </location>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
       <unit id="com.google.gson" version="2.8.6.v20201231-1626"/>
@@ -49,16 +49,16 @@
       <unit id="org.apache.commons.compress.source" version="1.19.0.v20200106-2343"/>
       <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.10.v20200830-2311"/>
-      <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.10.v20200830-2311"/>
-      <unit id="org.apache.httpcomponents.httpcore" version="4.4.12.v20200108-1212"/>
-      <unit id="org.apache.httpcomponents.httpcore.source" version="4.4.12.v20200108-1212"/>
+      <unit id="org.apache.httpcomponents.httpclient" version="4.5.13.v20210128-2225"/>
+      <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.13.v20210128-2225"/>
+      <unit id="org.apache.httpcomponents.httpcore" version="4.4.14.v20210128-2225"/>
+      <unit id="org.apache.httpcomponents.httpcore.source" version="4.4.14.v20210128-2225"/>
       <unit id="org.apache.log4j" version="1.2.15.v201012070815"/>
       <unit id="org.apache.log4j.source" version="1.2.15.v201012070815"/>
-      <unit id="org.apache.sshd.osgi" version="2.4.0.v20200318-1614"/>
-      <unit id="org.apache.sshd.osgi.source" version="2.4.0.v20200318-1614"/>
-      <unit id="org.apache.sshd.sftp" version="2.4.0.v20200319-1547"/>
-      <unit id="org.apache.sshd.sftp.source" version="2.4.0.v20200319-1547"/>
+      <unit id="org.apache.sshd.osgi" version="2.6.0.v20210201-2003"/>
+      <unit id="org.apache.sshd.osgi.source" version="2.6.0.v20210201-2003"/>
+      <unit id="org.apache.sshd.sftp" version="2.6.0.v20210201-2003"/>
+      <unit id="org.apache.sshd.sftp.source" version="2.6.0.v20210201-2003"/>
       <unit id="org.assertj" version="3.14.0.v20200120-1926"/>
       <unit id="org.assertj.source" version="3.14.0.v20200120-1926"/>
       <unit id="org.bouncycastle.bcpg" version="1.65.0.v20200527-1955"/>
@@ -86,7 +86,7 @@
       <unit id="org.slf4j.binding.log4j12.source" version="1.7.30.v20201108-2042"/>
       <unit id="org.tukaani.xz" version="1.8.0.v20180207-1613"/>
       <unit id="org.tukaani.xz.source" version="1.8.0.v20180207-1613"/>
-      <repository location="https://download.eclipse.org/tools/orbit/downloads/drops/S20210105214148/repository"/>
+      <repository location="https://download.eclipse.org/tools/orbit/downloads/drops/S20210216215844/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.13.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.13.tpd
index af0f845..84e5c25 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.13.tpd
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.13.tpd
@@ -1,7 +1,7 @@
 target "jgit-4.13" with source configurePhase
 
 include "projects/jetty-9.4.x.tpd"
-include "orbit/S20210105214148.tpd"
+include "orbit/S20210216215844.tpd"
 
 location "https://download.eclipse.org/releases/2019-09/" {
 	org.eclipse.osgi lazy
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.14.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.14.target
index 9b84908..42278f6 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.14.target
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.14.target
@@ -1,28 +1,28 @@
 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
 <?pde?>
 <!-- generated with https://github.com/eclipse-cbi/targetplatform-dsl -->
-<target name="jgit-4.14" sequenceNumber="1610487371">
+<target name="jgit-4.14" sequenceNumber="1613862030">
   <locations>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
-      <unit id="org.eclipse.jetty.client" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.client.source" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.continuation" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.continuation.source" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.http" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.http.source" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.io" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.io.source" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.security" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.security.source" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.server" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.server.source" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.servlet" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.servlet.source" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.util" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.util.source" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.util.ajax" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.util.ajax.source" version="9.4.35.v20201120"/>
-      <repository id="jetty-9.4.30" location="https://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.4.35.v20201120/"/>
+      <unit id="org.eclipse.jetty.client" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.client.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.continuation" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.continuation.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.http" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.http.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.io" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.io.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.security" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.security.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.server" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.server.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.servlet" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.servlet.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.util" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.util.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.util.ajax" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.util.ajax.source" version="9.4.36.v20210114"/>
+      <repository id="jetty-9.4.36" location="https://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.4.36.v20210114/"/>
     </location>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
       <unit id="com.google.gson" version="2.8.6.v20201231-1626"/>
@@ -49,16 +49,16 @@
       <unit id="org.apache.commons.compress.source" version="1.19.0.v20200106-2343"/>
       <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.10.v20200830-2311"/>
-      <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.10.v20200830-2311"/>
-      <unit id="org.apache.httpcomponents.httpcore" version="4.4.12.v20200108-1212"/>
-      <unit id="org.apache.httpcomponents.httpcore.source" version="4.4.12.v20200108-1212"/>
+      <unit id="org.apache.httpcomponents.httpclient" version="4.5.13.v20210128-2225"/>
+      <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.13.v20210128-2225"/>
+      <unit id="org.apache.httpcomponents.httpcore" version="4.4.14.v20210128-2225"/>
+      <unit id="org.apache.httpcomponents.httpcore.source" version="4.4.14.v20210128-2225"/>
       <unit id="org.apache.log4j" version="1.2.15.v201012070815"/>
       <unit id="org.apache.log4j.source" version="1.2.15.v201012070815"/>
-      <unit id="org.apache.sshd.osgi" version="2.4.0.v20200318-1614"/>
-      <unit id="org.apache.sshd.osgi.source" version="2.4.0.v20200318-1614"/>
-      <unit id="org.apache.sshd.sftp" version="2.4.0.v20200319-1547"/>
-      <unit id="org.apache.sshd.sftp.source" version="2.4.0.v20200319-1547"/>
+      <unit id="org.apache.sshd.osgi" version="2.6.0.v20210201-2003"/>
+      <unit id="org.apache.sshd.osgi.source" version="2.6.0.v20210201-2003"/>
+      <unit id="org.apache.sshd.sftp" version="2.6.0.v20210201-2003"/>
+      <unit id="org.apache.sshd.sftp.source" version="2.6.0.v20210201-2003"/>
       <unit id="org.assertj" version="3.14.0.v20200120-1926"/>
       <unit id="org.assertj.source" version="3.14.0.v20200120-1926"/>
       <unit id="org.bouncycastle.bcpg" version="1.65.0.v20200527-1955"/>
@@ -86,7 +86,7 @@
       <unit id="org.slf4j.binding.log4j12.source" version="1.7.30.v20201108-2042"/>
       <unit id="org.tukaani.xz" version="1.8.0.v20180207-1613"/>
       <unit id="org.tukaani.xz.source" version="1.8.0.v20180207-1613"/>
-      <repository location="https://download.eclipse.org/tools/orbit/downloads/drops/S20210105214148/repository"/>
+      <repository location="https://download.eclipse.org/tools/orbit/downloads/drops/S20210216215844/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.14.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.14.tpd
index 0c89f0e..6d793a6 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.14.tpd
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.14.tpd
@@ -1,7 +1,7 @@
 target "jgit-4.14" with source configurePhase
 
 include "projects/jetty-9.4.x.tpd"
-include "orbit/S20210105214148.tpd"
+include "orbit/S20210216215844.tpd"
 
 location "https://download.eclipse.org/releases/2019-12/201912181000/" {
 	org.eclipse.osgi lazy
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.15.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.15.target
index b533aa1..0d5166e 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.15.target
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.15.target
@@ -1,28 +1,28 @@
 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
 <?pde?>
 <!-- generated with https://github.com/eclipse-cbi/targetplatform-dsl -->
-<target name="jgit-4.15" sequenceNumber="1610487371">
+<target name="jgit-4.15" sequenceNumber="1613862030">
   <locations>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
-      <unit id="org.eclipse.jetty.client" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.client.source" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.continuation" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.continuation.source" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.http" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.http.source" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.io" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.io.source" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.security" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.security.source" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.server" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.server.source" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.servlet" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.servlet.source" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.util" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.util.source" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.util.ajax" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.util.ajax.source" version="9.4.35.v20201120"/>
-      <repository id="jetty-9.4.30" location="https://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.4.35.v20201120/"/>
+      <unit id="org.eclipse.jetty.client" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.client.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.continuation" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.continuation.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.http" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.http.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.io" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.io.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.security" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.security.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.server" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.server.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.servlet" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.servlet.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.util" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.util.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.util.ajax" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.util.ajax.source" version="9.4.36.v20210114"/>
+      <repository id="jetty-9.4.36" location="https://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.4.36.v20210114/"/>
     </location>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
       <unit id="com.google.gson" version="2.8.6.v20201231-1626"/>
@@ -49,16 +49,16 @@
       <unit id="org.apache.commons.compress.source" version="1.19.0.v20200106-2343"/>
       <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.10.v20200830-2311"/>
-      <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.10.v20200830-2311"/>
-      <unit id="org.apache.httpcomponents.httpcore" version="4.4.12.v20200108-1212"/>
-      <unit id="org.apache.httpcomponents.httpcore.source" version="4.4.12.v20200108-1212"/>
+      <unit id="org.apache.httpcomponents.httpclient" version="4.5.13.v20210128-2225"/>
+      <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.13.v20210128-2225"/>
+      <unit id="org.apache.httpcomponents.httpcore" version="4.4.14.v20210128-2225"/>
+      <unit id="org.apache.httpcomponents.httpcore.source" version="4.4.14.v20210128-2225"/>
       <unit id="org.apache.log4j" version="1.2.15.v201012070815"/>
       <unit id="org.apache.log4j.source" version="1.2.15.v201012070815"/>
-      <unit id="org.apache.sshd.osgi" version="2.4.0.v20200318-1614"/>
-      <unit id="org.apache.sshd.osgi.source" version="2.4.0.v20200318-1614"/>
-      <unit id="org.apache.sshd.sftp" version="2.4.0.v20200319-1547"/>
-      <unit id="org.apache.sshd.sftp.source" version="2.4.0.v20200319-1547"/>
+      <unit id="org.apache.sshd.osgi" version="2.6.0.v20210201-2003"/>
+      <unit id="org.apache.sshd.osgi.source" version="2.6.0.v20210201-2003"/>
+      <unit id="org.apache.sshd.sftp" version="2.6.0.v20210201-2003"/>
+      <unit id="org.apache.sshd.sftp.source" version="2.6.0.v20210201-2003"/>
       <unit id="org.assertj" version="3.14.0.v20200120-1926"/>
       <unit id="org.assertj.source" version="3.14.0.v20200120-1926"/>
       <unit id="org.bouncycastle.bcpg" version="1.65.0.v20200527-1955"/>
@@ -86,7 +86,7 @@
       <unit id="org.slf4j.binding.log4j12.source" version="1.7.30.v20201108-2042"/>
       <unit id="org.tukaani.xz" version="1.8.0.v20180207-1613"/>
       <unit id="org.tukaani.xz.source" version="1.8.0.v20180207-1613"/>
-      <repository location="https://download.eclipse.org/tools/orbit/downloads/drops/S20210105214148/repository"/>
+      <repository location="https://download.eclipse.org/tools/orbit/downloads/drops/S20210216215844/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.15.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.15.tpd
index c176a4b..4ce832b 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.15.tpd
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.15.tpd
@@ -1,7 +1,7 @@
 target "jgit-4.15" with source configurePhase
 
 include "projects/jetty-9.4.x.tpd"
-include "orbit/S20210105214148.tpd"
+include "orbit/S20210216215844.tpd"
 
 location "https://download.eclipse.org/releases/2020-03/202003181000/" {
 	org.eclipse.osgi lazy
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.16.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.16.target
index 45c665a..b4d5306 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.16.target
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.16.target
@@ -1,28 +1,28 @@
 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
 <?pde?>
 <!-- generated with https://github.com/eclipse-cbi/targetplatform-dsl -->
-<target name="jgit-4.16" sequenceNumber="1610487371">
+<target name="jgit-4.16" sequenceNumber="1613862033">
   <locations>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
-      <unit id="org.eclipse.jetty.client" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.client.source" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.continuation" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.continuation.source" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.http" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.http.source" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.io" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.io.source" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.security" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.security.source" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.server" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.server.source" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.servlet" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.servlet.source" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.util" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.util.source" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.util.ajax" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.util.ajax.source" version="9.4.35.v20201120"/>
-      <repository id="jetty-9.4.30" location="https://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.4.35.v20201120/"/>
+      <unit id="org.eclipse.jetty.client" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.client.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.continuation" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.continuation.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.http" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.http.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.io" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.io.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.security" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.security.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.server" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.server.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.servlet" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.servlet.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.util" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.util.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.util.ajax" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.util.ajax.source" version="9.4.36.v20210114"/>
+      <repository id="jetty-9.4.36" location="https://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.4.36.v20210114/"/>
     </location>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
       <unit id="com.google.gson" version="2.8.6.v20201231-1626"/>
@@ -49,16 +49,16 @@
       <unit id="org.apache.commons.compress.source" version="1.19.0.v20200106-2343"/>
       <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.10.v20200830-2311"/>
-      <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.10.v20200830-2311"/>
-      <unit id="org.apache.httpcomponents.httpcore" version="4.4.12.v20200108-1212"/>
-      <unit id="org.apache.httpcomponents.httpcore.source" version="4.4.12.v20200108-1212"/>
+      <unit id="org.apache.httpcomponents.httpclient" version="4.5.13.v20210128-2225"/>
+      <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.13.v20210128-2225"/>
+      <unit id="org.apache.httpcomponents.httpcore" version="4.4.14.v20210128-2225"/>
+      <unit id="org.apache.httpcomponents.httpcore.source" version="4.4.14.v20210128-2225"/>
       <unit id="org.apache.log4j" version="1.2.15.v201012070815"/>
       <unit id="org.apache.log4j.source" version="1.2.15.v201012070815"/>
-      <unit id="org.apache.sshd.osgi" version="2.4.0.v20200318-1614"/>
-      <unit id="org.apache.sshd.osgi.source" version="2.4.0.v20200318-1614"/>
-      <unit id="org.apache.sshd.sftp" version="2.4.0.v20200319-1547"/>
-      <unit id="org.apache.sshd.sftp.source" version="2.4.0.v20200319-1547"/>
+      <unit id="org.apache.sshd.osgi" version="2.6.0.v20210201-2003"/>
+      <unit id="org.apache.sshd.osgi.source" version="2.6.0.v20210201-2003"/>
+      <unit id="org.apache.sshd.sftp" version="2.6.0.v20210201-2003"/>
+      <unit id="org.apache.sshd.sftp.source" version="2.6.0.v20210201-2003"/>
       <unit id="org.assertj" version="3.14.0.v20200120-1926"/>
       <unit id="org.assertj.source" version="3.14.0.v20200120-1926"/>
       <unit id="org.bouncycastle.bcpg" version="1.65.0.v20200527-1955"/>
@@ -86,7 +86,7 @@
       <unit id="org.slf4j.binding.log4j12.source" version="1.7.30.v20201108-2042"/>
       <unit id="org.tukaani.xz" version="1.8.0.v20180207-1613"/>
       <unit id="org.tukaani.xz.source" version="1.8.0.v20180207-1613"/>
-      <repository location="https://download.eclipse.org/tools/orbit/downloads/drops/S20210105214148/repository"/>
+      <repository location="https://download.eclipse.org/tools/orbit/downloads/drops/S20210216215844/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.16.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.16.tpd
index 6352099..1b56447 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.16.tpd
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.16.tpd
@@ -1,7 +1,7 @@
 target "jgit-4.16" with source configurePhase
 
 include "projects/jetty-9.4.x.tpd"
-include "orbit/S20210105214148.tpd"
+include "orbit/S20210216215844.tpd"
 
 location "https://download.eclipse.org/releases/2020-06/" {
 	org.eclipse.osgi lazy
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.17.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.17.target
index a3027bc..47fc74b 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.17.target
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.17.target
@@ -1,28 +1,28 @@
 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
 <?pde?>
 <!-- generated with https://github.com/eclipse-cbi/targetplatform-dsl -->
-<target name="jgit-4.17" sequenceNumber="1610487371">
+<target name="jgit-4.17" sequenceNumber="1613862034">
   <locations>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
-      <unit id="org.eclipse.jetty.client" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.client.source" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.continuation" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.continuation.source" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.http" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.http.source" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.io" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.io.source" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.security" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.security.source" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.server" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.server.source" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.servlet" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.servlet.source" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.util" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.util.source" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.util.ajax" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.util.ajax.source" version="9.4.35.v20201120"/>
-      <repository id="jetty-9.4.30" location="https://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.4.35.v20201120/"/>
+      <unit id="org.eclipse.jetty.client" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.client.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.continuation" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.continuation.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.http" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.http.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.io" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.io.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.security" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.security.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.server" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.server.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.servlet" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.servlet.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.util" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.util.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.util.ajax" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.util.ajax.source" version="9.4.36.v20210114"/>
+      <repository id="jetty-9.4.36" location="https://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.4.36.v20210114/"/>
     </location>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
       <unit id="com.google.gson" version="2.8.6.v20201231-1626"/>
@@ -49,16 +49,16 @@
       <unit id="org.apache.commons.compress.source" version="1.19.0.v20200106-2343"/>
       <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.10.v20200830-2311"/>
-      <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.10.v20200830-2311"/>
-      <unit id="org.apache.httpcomponents.httpcore" version="4.4.12.v20200108-1212"/>
-      <unit id="org.apache.httpcomponents.httpcore.source" version="4.4.12.v20200108-1212"/>
+      <unit id="org.apache.httpcomponents.httpclient" version="4.5.13.v20210128-2225"/>
+      <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.13.v20210128-2225"/>
+      <unit id="org.apache.httpcomponents.httpcore" version="4.4.14.v20210128-2225"/>
+      <unit id="org.apache.httpcomponents.httpcore.source" version="4.4.14.v20210128-2225"/>
       <unit id="org.apache.log4j" version="1.2.15.v201012070815"/>
       <unit id="org.apache.log4j.source" version="1.2.15.v201012070815"/>
-      <unit id="org.apache.sshd.osgi" version="2.4.0.v20200318-1614"/>
-      <unit id="org.apache.sshd.osgi.source" version="2.4.0.v20200318-1614"/>
-      <unit id="org.apache.sshd.sftp" version="2.4.0.v20200319-1547"/>
-      <unit id="org.apache.sshd.sftp.source" version="2.4.0.v20200319-1547"/>
+      <unit id="org.apache.sshd.osgi" version="2.6.0.v20210201-2003"/>
+      <unit id="org.apache.sshd.osgi.source" version="2.6.0.v20210201-2003"/>
+      <unit id="org.apache.sshd.sftp" version="2.6.0.v20210201-2003"/>
+      <unit id="org.apache.sshd.sftp.source" version="2.6.0.v20210201-2003"/>
       <unit id="org.assertj" version="3.14.0.v20200120-1926"/>
       <unit id="org.assertj.source" version="3.14.0.v20200120-1926"/>
       <unit id="org.bouncycastle.bcpg" version="1.65.0.v20200527-1955"/>
@@ -86,7 +86,7 @@
       <unit id="org.slf4j.binding.log4j12.source" version="1.7.30.v20201108-2042"/>
       <unit id="org.tukaani.xz" version="1.8.0.v20180207-1613"/>
       <unit id="org.tukaani.xz.source" version="1.8.0.v20180207-1613"/>
-      <repository location="https://download.eclipse.org/tools/orbit/downloads/drops/S20210105214148/repository"/>
+      <repository location="https://download.eclipse.org/tools/orbit/downloads/drops/S20210216215844/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.17.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.17.tpd
index 4c75934..367020c 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.17.tpd
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.17.tpd
@@ -1,7 +1,7 @@
 target "jgit-4.17" with source configurePhase
 
 include "projects/jetty-9.4.x.tpd"
-include "orbit/S20210105214148.tpd"
+include "orbit/S20210216215844.tpd"
 
 location "https://download.eclipse.org/releases/2020-09/" {
 	org.eclipse.osgi lazy
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.18.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.18.target
index 578fe23..b393e60 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.18.target
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.18.target
@@ -1,28 +1,28 @@
 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
 <?pde?>
 <!-- generated with https://github.com/eclipse-cbi/targetplatform-dsl -->
-<target name="jgit-4.18" sequenceNumber="1610487371">
+<target name="jgit-4.18" sequenceNumber="1613862034">
   <locations>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
-      <unit id="org.eclipse.jetty.client" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.client.source" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.continuation" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.continuation.source" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.http" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.http.source" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.io" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.io.source" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.security" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.security.source" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.server" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.server.source" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.servlet" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.servlet.source" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.util" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.util.source" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.util.ajax" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.util.ajax.source" version="9.4.35.v20201120"/>
-      <repository id="jetty-9.4.30" location="https://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.4.35.v20201120/"/>
+      <unit id="org.eclipse.jetty.client" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.client.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.continuation" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.continuation.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.http" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.http.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.io" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.io.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.security" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.security.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.server" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.server.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.servlet" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.servlet.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.util" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.util.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.util.ajax" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.util.ajax.source" version="9.4.36.v20210114"/>
+      <repository id="jetty-9.4.36" location="https://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.4.36.v20210114/"/>
     </location>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
       <unit id="com.google.gson" version="2.8.6.v20201231-1626"/>
@@ -49,16 +49,16 @@
       <unit id="org.apache.commons.compress.source" version="1.19.0.v20200106-2343"/>
       <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.10.v20200830-2311"/>
-      <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.10.v20200830-2311"/>
-      <unit id="org.apache.httpcomponents.httpcore" version="4.4.12.v20200108-1212"/>
-      <unit id="org.apache.httpcomponents.httpcore.source" version="4.4.12.v20200108-1212"/>
+      <unit id="org.apache.httpcomponents.httpclient" version="4.5.13.v20210128-2225"/>
+      <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.13.v20210128-2225"/>
+      <unit id="org.apache.httpcomponents.httpcore" version="4.4.14.v20210128-2225"/>
+      <unit id="org.apache.httpcomponents.httpcore.source" version="4.4.14.v20210128-2225"/>
       <unit id="org.apache.log4j" version="1.2.15.v201012070815"/>
       <unit id="org.apache.log4j.source" version="1.2.15.v201012070815"/>
-      <unit id="org.apache.sshd.osgi" version="2.4.0.v20200318-1614"/>
-      <unit id="org.apache.sshd.osgi.source" version="2.4.0.v20200318-1614"/>
-      <unit id="org.apache.sshd.sftp" version="2.4.0.v20200319-1547"/>
-      <unit id="org.apache.sshd.sftp.source" version="2.4.0.v20200319-1547"/>
+      <unit id="org.apache.sshd.osgi" version="2.6.0.v20210201-2003"/>
+      <unit id="org.apache.sshd.osgi.source" version="2.6.0.v20210201-2003"/>
+      <unit id="org.apache.sshd.sftp" version="2.6.0.v20210201-2003"/>
+      <unit id="org.apache.sshd.sftp.source" version="2.6.0.v20210201-2003"/>
       <unit id="org.assertj" version="3.14.0.v20200120-1926"/>
       <unit id="org.assertj.source" version="3.14.0.v20200120-1926"/>
       <unit id="org.bouncycastle.bcpg" version="1.65.0.v20200527-1955"/>
@@ -86,7 +86,7 @@
       <unit id="org.slf4j.binding.log4j12.source" version="1.7.30.v20201108-2042"/>
       <unit id="org.tukaani.xz" version="1.8.0.v20180207-1613"/>
       <unit id="org.tukaani.xz.source" version="1.8.0.v20180207-1613"/>
-      <repository location="https://download.eclipse.org/tools/orbit/downloads/drops/S20210105214148/repository"/>
+      <repository location="https://download.eclipse.org/tools/orbit/downloads/drops/S20210216215844/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.18.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.18.tpd
index 77384a3..507ddd1 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.18.tpd
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.18.tpd
@@ -1,7 +1,7 @@
 target "jgit-4.18" with source configurePhase
 
 include "projects/jetty-9.4.x.tpd"
-include "orbit/S20210105214148.tpd"
+include "orbit/S20210216215844.tpd"
 
 location "https://download.eclipse.org/releases/2020-12/" {
 	org.eclipse.osgi lazy
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.19-staging.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.19-staging.target
index 567767c..f376926 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.19-staging.target
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.19-staging.target
@@ -1,28 +1,28 @@
 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
 <?pde?>
 <!-- generated with https://github.com/eclipse-cbi/targetplatform-dsl -->
-<target name="jgit-4.19-staging" sequenceNumber="1610487085">
+<target name="jgit-4.19-staging" sequenceNumber="1613862034">
   <locations>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
-      <unit id="org.eclipse.jetty.client" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.client.source" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.continuation" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.continuation.source" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.http" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.http.source" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.io" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.io.source" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.security" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.security.source" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.server" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.server.source" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.servlet" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.servlet.source" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.util" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.util.source" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.util.ajax" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.util.ajax.source" version="9.4.35.v20201120"/>
-      <repository id="jetty-9.4.30" location="https://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.4.35.v20201120/"/>
+      <unit id="org.eclipse.jetty.client" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.client.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.continuation" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.continuation.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.http" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.http.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.io" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.io.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.security" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.security.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.server" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.server.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.servlet" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.servlet.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.util" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.util.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.util.ajax" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.util.ajax.source" version="9.4.36.v20210114"/>
+      <repository id="jetty-9.4.36" location="https://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.4.36.v20210114/"/>
     </location>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
       <unit id="com.google.gson" version="2.8.6.v20201231-1626"/>
@@ -49,16 +49,16 @@
       <unit id="org.apache.commons.compress.source" version="1.19.0.v20200106-2343"/>
       <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.10.v20200830-2311"/>
-      <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.10.v20200830-2311"/>
-      <unit id="org.apache.httpcomponents.httpcore" version="4.4.12.v20200108-1212"/>
-      <unit id="org.apache.httpcomponents.httpcore.source" version="4.4.12.v20200108-1212"/>
+      <unit id="org.apache.httpcomponents.httpclient" version="4.5.13.v20210128-2225"/>
+      <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.13.v20210128-2225"/>
+      <unit id="org.apache.httpcomponents.httpcore" version="4.4.14.v20210128-2225"/>
+      <unit id="org.apache.httpcomponents.httpcore.source" version="4.4.14.v20210128-2225"/>
       <unit id="org.apache.log4j" version="1.2.15.v201012070815"/>
       <unit id="org.apache.log4j.source" version="1.2.15.v201012070815"/>
-      <unit id="org.apache.sshd.osgi" version="2.4.0.v20200318-1614"/>
-      <unit id="org.apache.sshd.osgi.source" version="2.4.0.v20200318-1614"/>
-      <unit id="org.apache.sshd.sftp" version="2.4.0.v20200319-1547"/>
-      <unit id="org.apache.sshd.sftp.source" version="2.4.0.v20200319-1547"/>
+      <unit id="org.apache.sshd.osgi" version="2.6.0.v20210201-2003"/>
+      <unit id="org.apache.sshd.osgi.source" version="2.6.0.v20210201-2003"/>
+      <unit id="org.apache.sshd.sftp" version="2.6.0.v20210201-2003"/>
+      <unit id="org.apache.sshd.sftp.source" version="2.6.0.v20210201-2003"/>
       <unit id="org.assertj" version="3.14.0.v20200120-1926"/>
       <unit id="org.assertj.source" version="3.14.0.v20200120-1926"/>
       <unit id="org.bouncycastle.bcpg" version="1.65.0.v20200527-1955"/>
@@ -86,7 +86,7 @@
       <unit id="org.slf4j.binding.log4j12.source" version="1.7.30.v20201108-2042"/>
       <unit id="org.tukaani.xz" version="1.8.0.v20180207-1613"/>
       <unit id="org.tukaani.xz.source" version="1.8.0.v20180207-1613"/>
-      <repository location="https://download.eclipse.org/tools/orbit/downloads/drops/S20210105214148/repository"/>
+      <repository location="https://download.eclipse.org/tools/orbit/downloads/drops/S20210216215844/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.19-staging.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.19-staging.tpd
index d016028..3b1b19c 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.19-staging.tpd
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.19-staging.tpd
@@ -1,7 +1,7 @@
 target "jgit-4.19-staging" with source configurePhase
 
 include "projects/jetty-9.4.x.tpd"
-include "orbit/S20210105214148.tpd"
+include "orbit/S20210216215844.tpd"
 
 location "https://download.eclipse.org/staging/2021-03/" {
 	org.eclipse.osgi lazy
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.6.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.6.target
index 9cc4290..26715ee 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,28 +1,28 @@
 <?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="1610487371">
+<target name="jgit-4.6" sequenceNumber="1613862049">
   <locations>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
-      <unit id="org.eclipse.jetty.client" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.client.source" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.continuation" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.continuation.source" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.http" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.http.source" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.io" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.io.source" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.security" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.security.source" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.server" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.server.source" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.servlet" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.servlet.source" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.util" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.util.source" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.util.ajax" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.util.ajax.source" version="9.4.35.v20201120"/>
-      <repository id="jetty-9.4.30" location="https://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.4.35.v20201120/"/>
+      <unit id="org.eclipse.jetty.client" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.client.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.continuation" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.continuation.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.http" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.http.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.io" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.io.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.security" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.security.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.server" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.server.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.servlet" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.servlet.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.util" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.util.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.util.ajax" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.util.ajax.source" version="9.4.36.v20210114"/>
+      <repository id="jetty-9.4.36" location="https://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.4.36.v20210114/"/>
     </location>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
       <unit id="com.google.gson" version="2.8.6.v20201231-1626"/>
@@ -49,16 +49,16 @@
       <unit id="org.apache.commons.compress.source" version="1.19.0.v20200106-2343"/>
       <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.10.v20200830-2311"/>
-      <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.10.v20200830-2311"/>
-      <unit id="org.apache.httpcomponents.httpcore" version="4.4.12.v20200108-1212"/>
-      <unit id="org.apache.httpcomponents.httpcore.source" version="4.4.12.v20200108-1212"/>
+      <unit id="org.apache.httpcomponents.httpclient" version="4.5.13.v20210128-2225"/>
+      <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.13.v20210128-2225"/>
+      <unit id="org.apache.httpcomponents.httpcore" version="4.4.14.v20210128-2225"/>
+      <unit id="org.apache.httpcomponents.httpcore.source" version="4.4.14.v20210128-2225"/>
       <unit id="org.apache.log4j" version="1.2.15.v201012070815"/>
       <unit id="org.apache.log4j.source" version="1.2.15.v201012070815"/>
-      <unit id="org.apache.sshd.osgi" version="2.4.0.v20200318-1614"/>
-      <unit id="org.apache.sshd.osgi.source" version="2.4.0.v20200318-1614"/>
-      <unit id="org.apache.sshd.sftp" version="2.4.0.v20200319-1547"/>
-      <unit id="org.apache.sshd.sftp.source" version="2.4.0.v20200319-1547"/>
+      <unit id="org.apache.sshd.osgi" version="2.6.0.v20210201-2003"/>
+      <unit id="org.apache.sshd.osgi.source" version="2.6.0.v20210201-2003"/>
+      <unit id="org.apache.sshd.sftp" version="2.6.0.v20210201-2003"/>
+      <unit id="org.apache.sshd.sftp.source" version="2.6.0.v20210201-2003"/>
       <unit id="org.assertj" version="3.14.0.v20200120-1926"/>
       <unit id="org.assertj.source" version="3.14.0.v20200120-1926"/>
       <unit id="org.bouncycastle.bcpg" version="1.65.0.v20200527-1955"/>
@@ -86,7 +86,7 @@
       <unit id="org.slf4j.binding.log4j12.source" version="1.7.30.v20201108-2042"/>
       <unit id="org.tukaani.xz" version="1.8.0.v20180207-1613"/>
       <unit id="org.tukaani.xz.source" version="1.8.0.v20180207-1613"/>
-      <repository location="https://download.eclipse.org/tools/orbit/downloads/drops/S20210105214148/repository"/>
+      <repository location="https://download.eclipse.org/tools/orbit/downloads/drops/S20210216215844/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 cbc1f30..23bf87c 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.x.tpd"
-include "orbit/S20210105214148.tpd"
+include "orbit/S20210216215844.tpd"
 
 location "https://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 b7a8c40..64fe054 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,28 +1,28 @@
 <?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="1610487371">
+<target name="jgit-4.7" sequenceNumber="1613862039">
   <locations>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
-      <unit id="org.eclipse.jetty.client" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.client.source" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.continuation" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.continuation.source" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.http" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.http.source" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.io" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.io.source" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.security" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.security.source" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.server" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.server.source" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.servlet" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.servlet.source" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.util" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.util.source" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.util.ajax" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.util.ajax.source" version="9.4.35.v20201120"/>
-      <repository id="jetty-9.4.30" location="https://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.4.35.v20201120/"/>
+      <unit id="org.eclipse.jetty.client" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.client.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.continuation" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.continuation.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.http" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.http.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.io" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.io.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.security" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.security.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.server" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.server.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.servlet" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.servlet.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.util" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.util.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.util.ajax" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.util.ajax.source" version="9.4.36.v20210114"/>
+      <repository id="jetty-9.4.36" location="https://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.4.36.v20210114/"/>
     </location>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
       <unit id="com.google.gson" version="2.8.6.v20201231-1626"/>
@@ -49,16 +49,16 @@
       <unit id="org.apache.commons.compress.source" version="1.19.0.v20200106-2343"/>
       <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.10.v20200830-2311"/>
-      <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.10.v20200830-2311"/>
-      <unit id="org.apache.httpcomponents.httpcore" version="4.4.12.v20200108-1212"/>
-      <unit id="org.apache.httpcomponents.httpcore.source" version="4.4.12.v20200108-1212"/>
+      <unit id="org.apache.httpcomponents.httpclient" version="4.5.13.v20210128-2225"/>
+      <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.13.v20210128-2225"/>
+      <unit id="org.apache.httpcomponents.httpcore" version="4.4.14.v20210128-2225"/>
+      <unit id="org.apache.httpcomponents.httpcore.source" version="4.4.14.v20210128-2225"/>
       <unit id="org.apache.log4j" version="1.2.15.v201012070815"/>
       <unit id="org.apache.log4j.source" version="1.2.15.v201012070815"/>
-      <unit id="org.apache.sshd.osgi" version="2.4.0.v20200318-1614"/>
-      <unit id="org.apache.sshd.osgi.source" version="2.4.0.v20200318-1614"/>
-      <unit id="org.apache.sshd.sftp" version="2.4.0.v20200319-1547"/>
-      <unit id="org.apache.sshd.sftp.source" version="2.4.0.v20200319-1547"/>
+      <unit id="org.apache.sshd.osgi" version="2.6.0.v20210201-2003"/>
+      <unit id="org.apache.sshd.osgi.source" version="2.6.0.v20210201-2003"/>
+      <unit id="org.apache.sshd.sftp" version="2.6.0.v20210201-2003"/>
+      <unit id="org.apache.sshd.sftp.source" version="2.6.0.v20210201-2003"/>
       <unit id="org.assertj" version="3.14.0.v20200120-1926"/>
       <unit id="org.assertj.source" version="3.14.0.v20200120-1926"/>
       <unit id="org.bouncycastle.bcpg" version="1.65.0.v20200527-1955"/>
@@ -86,7 +86,7 @@
       <unit id="org.slf4j.binding.log4j12.source" version="1.7.30.v20201108-2042"/>
       <unit id="org.tukaani.xz" version="1.8.0.v20180207-1613"/>
       <unit id="org.tukaani.xz.source" version="1.8.0.v20180207-1613"/>
-      <repository location="https://download.eclipse.org/tools/orbit/downloads/drops/S20210105214148/repository"/>
+      <repository location="https://download.eclipse.org/tools/orbit/downloads/drops/S20210216215844/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 403ec02..c33e4a3 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.x.tpd"
-include "orbit/S20210105214148.tpd"
+include "orbit/S20210216215844.tpd"
 
 location "https://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 8084e34..f7a3a3b 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,28 +1,28 @@
 <?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="1610487371">
+<target name="jgit-4.8" sequenceNumber="1613862034">
   <locations>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
-      <unit id="org.eclipse.jetty.client" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.client.source" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.continuation" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.continuation.source" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.http" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.http.source" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.io" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.io.source" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.security" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.security.source" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.server" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.server.source" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.servlet" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.servlet.source" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.util" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.util.source" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.util.ajax" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.util.ajax.source" version="9.4.35.v20201120"/>
-      <repository id="jetty-9.4.30" location="https://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.4.35.v20201120/"/>
+      <unit id="org.eclipse.jetty.client" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.client.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.continuation" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.continuation.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.http" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.http.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.io" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.io.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.security" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.security.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.server" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.server.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.servlet" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.servlet.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.util" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.util.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.util.ajax" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.util.ajax.source" version="9.4.36.v20210114"/>
+      <repository id="jetty-9.4.36" location="https://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.4.36.v20210114/"/>
     </location>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
       <unit id="com.google.gson" version="2.8.6.v20201231-1626"/>
@@ -49,16 +49,16 @@
       <unit id="org.apache.commons.compress.source" version="1.19.0.v20200106-2343"/>
       <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.10.v20200830-2311"/>
-      <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.10.v20200830-2311"/>
-      <unit id="org.apache.httpcomponents.httpcore" version="4.4.12.v20200108-1212"/>
-      <unit id="org.apache.httpcomponents.httpcore.source" version="4.4.12.v20200108-1212"/>
+      <unit id="org.apache.httpcomponents.httpclient" version="4.5.13.v20210128-2225"/>
+      <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.13.v20210128-2225"/>
+      <unit id="org.apache.httpcomponents.httpcore" version="4.4.14.v20210128-2225"/>
+      <unit id="org.apache.httpcomponents.httpcore.source" version="4.4.14.v20210128-2225"/>
       <unit id="org.apache.log4j" version="1.2.15.v201012070815"/>
       <unit id="org.apache.log4j.source" version="1.2.15.v201012070815"/>
-      <unit id="org.apache.sshd.osgi" version="2.4.0.v20200318-1614"/>
-      <unit id="org.apache.sshd.osgi.source" version="2.4.0.v20200318-1614"/>
-      <unit id="org.apache.sshd.sftp" version="2.4.0.v20200319-1547"/>
-      <unit id="org.apache.sshd.sftp.source" version="2.4.0.v20200319-1547"/>
+      <unit id="org.apache.sshd.osgi" version="2.6.0.v20210201-2003"/>
+      <unit id="org.apache.sshd.osgi.source" version="2.6.0.v20210201-2003"/>
+      <unit id="org.apache.sshd.sftp" version="2.6.0.v20210201-2003"/>
+      <unit id="org.apache.sshd.sftp.source" version="2.6.0.v20210201-2003"/>
       <unit id="org.assertj" version="3.14.0.v20200120-1926"/>
       <unit id="org.assertj.source" version="3.14.0.v20200120-1926"/>
       <unit id="org.bouncycastle.bcpg" version="1.65.0.v20200527-1955"/>
@@ -86,7 +86,7 @@
       <unit id="org.slf4j.binding.log4j12.source" version="1.7.30.v20201108-2042"/>
       <unit id="org.tukaani.xz" version="1.8.0.v20180207-1613"/>
       <unit id="org.tukaani.xz.source" version="1.8.0.v20180207-1613"/>
-      <repository location="https://download.eclipse.org/tools/orbit/downloads/drops/S20210105214148/repository"/>
+      <repository location="https://download.eclipse.org/tools/orbit/downloads/drops/S20210216215844/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 c120bc9..c40bacd 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.x.tpd"
-include "orbit/S20210105214148.tpd"
+include "orbit/S20210216215844.tpd"
 
 location "https://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 d51e023..4afbe99 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,28 +1,28 @@
 <?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="1610487371">
+<target name="jgit-4.9" sequenceNumber="1613862033">
   <locations>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
-      <unit id="org.eclipse.jetty.client" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.client.source" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.continuation" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.continuation.source" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.http" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.http.source" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.io" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.io.source" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.security" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.security.source" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.server" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.server.source" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.servlet" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.servlet.source" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.util" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.util.source" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.util.ajax" version="9.4.35.v20201120"/>
-      <unit id="org.eclipse.jetty.util.ajax.source" version="9.4.35.v20201120"/>
-      <repository id="jetty-9.4.30" location="https://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.4.35.v20201120/"/>
+      <unit id="org.eclipse.jetty.client" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.client.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.continuation" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.continuation.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.http" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.http.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.io" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.io.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.security" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.security.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.server" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.server.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.servlet" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.servlet.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.util" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.util.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.util.ajax" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.util.ajax.source" version="9.4.36.v20210114"/>
+      <repository id="jetty-9.4.36" location="https://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.4.36.v20210114/"/>
     </location>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
       <unit id="com.google.gson" version="2.8.6.v20201231-1626"/>
@@ -49,16 +49,16 @@
       <unit id="org.apache.commons.compress.source" version="1.19.0.v20200106-2343"/>
       <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.10.v20200830-2311"/>
-      <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.10.v20200830-2311"/>
-      <unit id="org.apache.httpcomponents.httpcore" version="4.4.12.v20200108-1212"/>
-      <unit id="org.apache.httpcomponents.httpcore.source" version="4.4.12.v20200108-1212"/>
+      <unit id="org.apache.httpcomponents.httpclient" version="4.5.13.v20210128-2225"/>
+      <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.13.v20210128-2225"/>
+      <unit id="org.apache.httpcomponents.httpcore" version="4.4.14.v20210128-2225"/>
+      <unit id="org.apache.httpcomponents.httpcore.source" version="4.4.14.v20210128-2225"/>
       <unit id="org.apache.log4j" version="1.2.15.v201012070815"/>
       <unit id="org.apache.log4j.source" version="1.2.15.v201012070815"/>
-      <unit id="org.apache.sshd.osgi" version="2.4.0.v20200318-1614"/>
-      <unit id="org.apache.sshd.osgi.source" version="2.4.0.v20200318-1614"/>
-      <unit id="org.apache.sshd.sftp" version="2.4.0.v20200319-1547"/>
-      <unit id="org.apache.sshd.sftp.source" version="2.4.0.v20200319-1547"/>
+      <unit id="org.apache.sshd.osgi" version="2.6.0.v20210201-2003"/>
+      <unit id="org.apache.sshd.osgi.source" version="2.6.0.v20210201-2003"/>
+      <unit id="org.apache.sshd.sftp" version="2.6.0.v20210201-2003"/>
+      <unit id="org.apache.sshd.sftp.source" version="2.6.0.v20210201-2003"/>
       <unit id="org.assertj" version="3.14.0.v20200120-1926"/>
       <unit id="org.assertj.source" version="3.14.0.v20200120-1926"/>
       <unit id="org.bouncycastle.bcpg" version="1.65.0.v20200527-1955"/>
@@ -86,7 +86,7 @@
       <unit id="org.slf4j.binding.log4j12.source" version="1.7.30.v20201108-2042"/>
       <unit id="org.tukaani.xz" version="1.8.0.v20180207-1613"/>
       <unit id="org.tukaani.xz.source" version="1.8.0.v20180207-1613"/>
-      <repository location="https://download.eclipse.org/tools/orbit/downloads/drops/S20210105214148/repository"/>
+      <repository location="https://download.eclipse.org/tools/orbit/downloads/drops/S20210216215844/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 0c896b4..5aa63be 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.x.tpd"
-include "orbit/S20210105214148.tpd"
+include "orbit/S20210216215844.tpd"
 
 location "https://download.eclipse.org/releases/2018-09/" {
 	org.eclipse.osgi lazy
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/S20210105214148.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/S20210216215844.tpd
similarity index 83%
rename from org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/S20210105214148.tpd
rename to org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/S20210216215844.tpd
index 58f2417..29e5bc8 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/S20210105214148.tpd
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/S20210216215844.tpd
@@ -1,7 +1,7 @@
-target "S20210105214148" with source configurePhase
+target "S20210216215844" with source configurePhase
 // see https://download.eclipse.org/tools/orbit/downloads/
 
-location "https://download.eclipse.org/tools/orbit/downloads/drops/S20210105214148/repository" {
+location "https://download.eclipse.org/tools/orbit/downloads/drops/S20210216215844/repository" {
 	com.google.gson [2.8.6.v20201231-1626,2.8.6.v20201231-1626]
 	com.google.gson.source [2.8.6.v20201231-1626,2.8.6.v20201231-1626]
 	com.jcraft.jsch [0.1.55.v20190404-1902,0.1.55.v20190404-1902]
@@ -26,16 +26,16 @@
 	org.apache.commons.compress.source [1.19.0.v20200106-2343,1.19.0.v20200106-2343]
 	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.10.v20200830-2311,4.5.10.v20200830-2311]
-	org.apache.httpcomponents.httpclient.source [4.5.10.v20200830-2311,4.5.10.v20200830-2311]
-	org.apache.httpcomponents.httpcore [4.4.12.v20200108-1212,4.4.12.v20200108-1212]
-	org.apache.httpcomponents.httpcore.source [4.4.12.v20200108-1212,4.4.12.v20200108-1212]
+	org.apache.httpcomponents.httpclient [4.5.13.v20210128-2225,4.5.13.v20210128-2225]
+	org.apache.httpcomponents.httpclient.source [4.5.13.v20210128-2225,4.5.13.v20210128-2225]
+	org.apache.httpcomponents.httpcore [4.4.14.v20210128-2225,4.4.14.v20210128-2225]
+	org.apache.httpcomponents.httpcore.source [4.4.14.v20210128-2225,4.4.14.v20210128-2225]
 	org.apache.log4j [1.2.15.v201012070815,1.2.15.v201012070815]
 	org.apache.log4j.source [1.2.15.v201012070815,1.2.15.v201012070815]
-	org.apache.sshd.osgi [2.4.0.v20200318-1614,2.4.0.v20200318-1614]
-	org.apache.sshd.osgi.source [2.4.0.v20200318-1614,2.4.0.v20200318-1614]
-	org.apache.sshd.sftp [2.4.0.v20200319-1547,2.4.0.v20200319-1547]
-	org.apache.sshd.sftp.source [2.4.0.v20200319-1547,2.4.0.v20200319-1547]
+	org.apache.sshd.osgi [2.6.0.v20210201-2003,2.6.0.v20210201-2003]
+	org.apache.sshd.osgi.source [2.6.0.v20210201-2003,2.6.0.v20210201-2003]
+	org.apache.sshd.sftp [2.6.0.v20210201-2003,2.6.0.v20210201-2003]
+	org.apache.sshd.sftp.source [2.6.0.v20210201-2003,2.6.0.v20210201-2003]
 	org.assertj [3.14.0.v20200120-1926,3.14.0.v20200120-1926]
 	org.assertj.source [3.14.0.v20200120-1926,3.14.0.v20200120-1926]
 	org.bouncycastle.bcpg [1.65.0.v20200527-1955,1.65.0.v20200527-1955]
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/projects/jetty-9.4.x.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/projects/jetty-9.4.x.tpd
index 72f20c4..4eec8aa 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/projects/jetty-9.4.x.tpd
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/projects/jetty-9.4.x.tpd
@@ -1,22 +1,22 @@
 target "jetty-9.4.x" with source configurePhase
 
-location jetty-9.4.30 "https://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.4.35.v20201120/" {
-	org.eclipse.jetty.client [9.4.35.v20201120,9.4.35.v20201120]
-	org.eclipse.jetty.client.source [9.4.35.v20201120,9.4.35.v20201120]
-	org.eclipse.jetty.continuation [9.4.35.v20201120,9.4.35.v20201120]
-	org.eclipse.jetty.continuation.source [9.4.35.v20201120,9.4.35.v20201120]
-	org.eclipse.jetty.http [9.4.35.v20201120,9.4.35.v20201120]
-	org.eclipse.jetty.http.source [9.4.35.v20201120,9.4.35.v20201120]
-	org.eclipse.jetty.io [9.4.35.v20201120,9.4.35.v20201120]
-	org.eclipse.jetty.io.source [9.4.35.v20201120,9.4.35.v20201120]
-	org.eclipse.jetty.security [9.4.35.v20201120,9.4.35.v20201120]
-	org.eclipse.jetty.security.source [9.4.35.v20201120,9.4.35.v20201120]
-	org.eclipse.jetty.server [9.4.35.v20201120,9.4.35.v20201120]
-	org.eclipse.jetty.server.source [9.4.35.v20201120,9.4.35.v20201120]
-	org.eclipse.jetty.servlet [9.4.35.v20201120,9.4.35.v20201120]
-	org.eclipse.jetty.servlet.source [9.4.35.v20201120,9.4.35.v20201120]
-	org.eclipse.jetty.util [9.4.35.v20201120,9.4.35.v20201120]
-	org.eclipse.jetty.util.source [9.4.35.v20201120,9.4.35.v20201120]
-	org.eclipse.jetty.util.ajax [9.4.35.v20201120,9.4.35.v20201120]
-	org.eclipse.jetty.util.ajax.source [9.4.35.v20201120,9.4.35.v20201120]
+location jetty-9.4.36 "https://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.4.36.v20210114/" {
+	org.eclipse.jetty.client [9.4.36.v20210114,9.4.36.v20210114]
+	org.eclipse.jetty.client.source [9.4.36.v20210114,9.4.36.v20210114]
+	org.eclipse.jetty.continuation [9.4.36.v20210114,9.4.36.v20210114]
+	org.eclipse.jetty.continuation.source [9.4.36.v20210114,9.4.36.v20210114]
+	org.eclipse.jetty.http [9.4.36.v20210114,9.4.36.v20210114]
+	org.eclipse.jetty.http.source [9.4.36.v20210114,9.4.36.v20210114]
+	org.eclipse.jetty.io [9.4.36.v20210114,9.4.36.v20210114]
+	org.eclipse.jetty.io.source [9.4.36.v20210114,9.4.36.v20210114]
+	org.eclipse.jetty.security [9.4.36.v20210114,9.4.36.v20210114]
+	org.eclipse.jetty.security.source [9.4.36.v20210114,9.4.36.v20210114]
+	org.eclipse.jetty.server [9.4.36.v20210114,9.4.36.v20210114]
+	org.eclipse.jetty.server.source [9.4.36.v20210114,9.4.36.v20210114]
+	org.eclipse.jetty.servlet [9.4.36.v20210114,9.4.36.v20210114]
+	org.eclipse.jetty.servlet.source [9.4.36.v20210114,9.4.36.v20210114]
+	org.eclipse.jetty.util [9.4.36.v20210114,9.4.36.v20210114]
+	org.eclipse.jetty.util.source [9.4.36.v20210114,9.4.36.v20210114]
+	org.eclipse.jetty.util.ajax [9.4.36.v20210114,9.4.36.v20210114]
+	org.eclipse.jetty.util.ajax.source [9.4.36.v20210114,9.4.36.v20210114]
 }
diff --git a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/CloneTest.java b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/CloneTest.java
index 2f09b7f..4cbd61c 100644
--- a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/CloneTest.java
+++ b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/CloneTest.java
@@ -11,7 +11,9 @@
 
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertThrows;
 import static org.junit.Assert.assertTrue;
 
 import java.io.File;
@@ -25,6 +27,7 @@
 import org.eclipse.jgit.lib.ObjectId;
 import org.eclipse.jgit.lib.Ref;
 import org.eclipse.jgit.lib.RefUpdate;
+import org.eclipse.jgit.lib.Repository;
 import org.eclipse.jgit.lib.StoredConfig;
 import org.eclipse.jgit.revwalk.RevCommit;
 import org.eclipse.jgit.transport.RefSpec;
@@ -64,6 +67,45 @@
 		assertEquals("expected 1 branch", 1, branches.size());
 	}
 
+	@Test
+	public void testCloneInitialBranch() throws Exception {
+		createInitialCommit();
+
+		File gitDir = db.getDirectory();
+		String sourceURI = gitDir.toURI().toString();
+		File target = createTempDirectory("target");
+		String cmd = "git clone --branch master " + sourceURI + " "
+				+ shellQuote(target.getPath());
+		String[] result = execute(cmd);
+		assertArrayEquals(new String[] {
+				"Cloning into '" + target.getPath() + "'...", "", "" }, result);
+
+		Git git2 = Git.open(target);
+		List<Ref> branches = git2.branchList().call();
+		assertEquals("expected 1 branch", 1, branches.size());
+
+		Repository db2 = git2.getRepository();
+		ObjectId head = db2.resolve("HEAD");
+		assertNotNull(head);
+		assertNotEquals(ObjectId.zeroId(), head);
+		ObjectId master = db2.resolve("master");
+		assertEquals(head, master);
+	}
+
+	@Test
+	public void testCloneInitialBranchMissing() throws Exception {
+		createInitialCommit();
+
+		File gitDir = db.getDirectory();
+		String sourceURI = gitDir.toURI().toString();
+		File target = createTempDirectory("target");
+		String cmd = "git clone --branch foo " + sourceURI + " "
+				+ shellQuote(target.getPath());
+		Die e = assertThrows(Die.class, () -> execute(cmd));
+		assertEquals("Remote branch 'foo' not found in upstream origin",
+				e.getMessage());
+	}
+
 	private RevCommit createInitialCommit() throws Exception {
 		JGitTestUtil.writeTrashFile(db, "hello.txt", "world");
 		git.add().addFilepattern("hello.txt").call();
diff --git a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/InitTest.java b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/InitTest.java
index 84474e3..88789d3 100644
--- a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/InitTest.java
+++ b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/InitTest.java
@@ -11,11 +11,14 @@
 package org.eclipse.jgit.pgm;
 
 import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
 
 import java.io.File;
 
+import org.eclipse.jgit.internal.storage.file.FileRepository;
 import org.eclipse.jgit.lib.CLIRepositoryTestCase;
 import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.Repository;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.TemporaryFolder;
@@ -54,4 +57,22 @@
 		assertArrayEquals(expecteds, result);
 	}
 
+	@Test
+	public void testInitDirectoryInitialBranch() throws Exception {
+		File workDirectory = tempFolder.getRoot();
+		File gitDirectory = new File(workDirectory, Constants.DOT_GIT);
+
+		String[] result = execute(
+				"git init -b main '" + workDirectory.getCanonicalPath() + "'");
+
+		String[] expecteds = new String[] {
+				"Initialized empty Git repository in "
+						+ gitDirectory.getCanonicalPath(),
+				"" };
+		assertArrayEquals(expecteds, result);
+
+		try (Repository repo = new FileRepository(gitDirectory)) {
+			assertEquals("refs/heads/main", repo.getFullBranch());
+		}
+	}
 }
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 afa253e..83846ee 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
@@ -77,14 +77,15 @@
 invalidRecurseSubmodulesMode=Invalid recurse submodules mode: {0}
 invalidUntrackedFilesMode=Invalid untracked files mode ''{0}''
 jgitVersion=jgit version {0}
-lineFormat={0}
-listeningOn=Listening on {0}
 lfsNoAccessKey=No accessKey in {0}
 lfsNoSecretKey=No secretKey in {0}
 lfsProtocolUrl=LFS protocol URL: {0}
 lfsStoreDirectory=LFS objects stored in: {0}
 lfsStoreUrl=LFS store URL: {0}
 lfsUnknownStoreType="Unknown LFS store type: {0}"
+lineFormat={0}
+listeningOn=Listening on {0}
+logNoSignatureVerifier="No signature verifier available"
 mergeConflict=CONFLICT(content): Merge conflict in {0}
 mergeCheckoutConflict=error: Your local changes to the following files would be overwritten by merge:
 mergeFailed=Automatic merge failed; fix conflicts and then commit the result
@@ -411,6 +412,7 @@
 usage_showRefNamesMatchingCommits=Show ref names matching commits
 usage_showPatch=display patch
 usage_showNotes=Add this ref to the list of note branches from which notes are displayed
+usage_showSignature=Verify signatures of signed commits in the log
 usage_showTimeInMilliseconds=Show mtime in milliseconds
 usage_squash=Squash commits as if a real merge happened, but do not make a commit or move the HEAD.
 usage_srcPrefix=show the source prefix instead of "a/"
@@ -424,11 +426,13 @@
 usage_tagMessage=create an annotated tag with the given message, unsigned unless -s or -u are given, or config tag.gpgSign is true, or tar.forceSignAnnotated is true and -a is not given
 usage_tagSign=create a signed annotated tag
 usage_tagNoSign=suppress signing the tag
+usage_tagVerify=Verify the GPG signature
 usage_untrackedFilesMode=show untracked files
 usage_updateRef=reference to update
 usage_updateRemoteRefsFromAnotherRepository=Update remote refs from another repository
 usage_useNameInsteadOfOriginToTrackUpstream=use <name> instead of 'origin' to track upstream
 usage_checkoutBranchAfterClone=check out named branch instead of remote's HEAD
+usage_initialBranch=initial branch of the newly created repository (default 'master', can be configured via config option init.defaultBranch)
 usage_viewCommitHistory=View commit history
 usage_orphan=Create a new orphan branch. The first commit made on this new branch will have no parents and it will be the root of a new history totally disconnected from other branches and commits.
 usernameFor=Username for {0}:
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 fe94b03..f28915d 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
@@ -18,6 +18,7 @@
 import org.eclipse.jgit.api.CloneCommand;
 import org.eclipse.jgit.api.Git;
 import org.eclipse.jgit.api.errors.InvalidRemoteException;
+import org.eclipse.jgit.api.errors.TransportException;
 import org.eclipse.jgit.lib.AnyObjectId;
 import org.eclipse.jgit.lib.Constants;
 import org.eclipse.jgit.lib.TextProgressMonitor;
@@ -110,6 +111,8 @@
 			db = command.call().getRepository();
 			if (msgs && db.resolve(Constants.HEAD) == null)
 				outw.println(CLIText.get().clonedEmptyRepository);
+		} catch (TransportException e) {
+			throw die(e.getMessage(), e);
 		} catch (InvalidRemoteException e) {
 			throw die(MessageFormat.format(CLIText.get().doesNotExist,
 					sourceUri), 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 7f59ef4..7a0d96d 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
@@ -24,6 +24,7 @@
 import org.eclipse.jgit.api.errors.GitAPIException;
 import org.eclipse.jgit.lib.Repository;
 import org.eclipse.jgit.pgm.internal.CLIText;
+import org.eclipse.jgit.util.StringUtils;
 import org.kohsuke.args4j.Argument;
 import org.kohsuke.args4j.Option;
 
@@ -32,6 +33,10 @@
 	@Option(name = "--bare", usage = "usage_CreateABareRepository")
 	private boolean bare;
 
+	@Option(name = "--initial-branch", aliases = { "-b" },
+			metaVar = "metaVar_branchName", usage = "usage_initialBranch")
+	private String branch;
+
 	@Argument(index = 0, metaVar = "metaVar_directory")
 	private String directory;
 
@@ -54,6 +59,9 @@
 		}
 		Repository repository;
 		try {
+			if (!StringUtils.isEmptyOrNull(branch)) {
+				command.setInitialBranch(branch);
+			}
 			repository = command.call().getRepository();
 			outw.println(MessageFormat.format(
 					CLIText.get().initializedEmptyGitRepositoryIn,
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 55efd23..353b64b 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
@@ -1,7 +1,7 @@
 /*
  * Copyright (C) 2010, Google Inc.
- * Copyright (C) 2006-2008, Robin Rosenberg <robin.rosenberg@dewire.com>
- * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org> and others
+ * Copyright (C) 2006, 2008, Robin Rosenberg <robin.rosenberg@dewire.com>
+ * Copyright (C) 2008, 2021, Shawn O. Pearce <spearce@spearce.org> and others
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Distribution License v. 1.0 which is available at
@@ -31,12 +31,17 @@
 import org.eclipse.jgit.errors.LargeObjectException;
 import org.eclipse.jgit.lib.AnyObjectId;
 import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.GpgConfig;
+import org.eclipse.jgit.lib.GpgSignatureVerifier;
+import org.eclipse.jgit.lib.GpgSignatureVerifier.SignatureVerification;
+import org.eclipse.jgit.lib.GpgSignatureVerifierFactory;
 import org.eclipse.jgit.lib.ObjectId;
 import org.eclipse.jgit.lib.PersonIdent;
 import org.eclipse.jgit.lib.Ref;
 import org.eclipse.jgit.lib.Repository;
 import org.eclipse.jgit.notes.NoteMap;
 import org.eclipse.jgit.pgm.internal.CLIText;
+import org.eclipse.jgit.pgm.internal.VerificationUtils;
 import org.eclipse.jgit.revwalk.RevCommit;
 import org.eclipse.jgit.revwalk.RevTree;
 import org.eclipse.jgit.util.GitDateFormatter;
@@ -68,6 +73,9 @@
 		additionalNoteRefs.add(notesRef);
 	}
 
+	@Option(name = "--show-signature", usage = "usage_showSignature")
+	private boolean showSignature;
+
 	@Option(name = "--date", usage = "usage_date")
 	void dateFormat(String date) {
 		if (date.toLowerCase(Locale.ROOT).equals(date))
@@ -147,6 +155,10 @@
 	// END -- Options shared with Diff
 
 
+	private GpgSignatureVerifier verifier;
+
+	private GpgConfig config;
+
 	Log() {
 		dateFormatter = new GitDateFormatter(Format.DEFAULT);
 	}
@@ -161,6 +173,7 @@
 	/** {@inheritDoc} */
 	@Override
 	protected void run() {
+		config = new GpgConfig(db.getConfig());
 		diffFmt.setRepository(db);
 		try {
 			diffFmt.setPathFilter(pathFilter);
@@ -197,6 +210,9 @@
 			throw die(e.getMessage(), e);
 		} finally {
 			diffFmt.close();
+			if (verifier != null) {
+				verifier.clear();
+			}
 		}
 	}
 
@@ -229,6 +245,9 @@
 		}
 		outw.println();
 
+		if (showSignature) {
+			showSignature(c);
+		}
 		final PersonIdent author = c.getAuthorIdent();
 		outw.println(MessageFormat.format(CLIText.get().authorInfo, author.getName(), author.getEmailAddress()));
 		outw.println(MessageFormat.format(CLIText.get().dateInfo,
@@ -252,6 +271,27 @@
 		outw.flush();
 	}
 
+	private void showSignature(RevCommit c) throws IOException {
+		if (c.getRawGpgSignature() == null) {
+			return;
+		}
+		if (verifier == null) {
+			GpgSignatureVerifierFactory factory = GpgSignatureVerifierFactory
+					.getDefault();
+			if (factory == null) {
+				throw die(CLIText.get().logNoSignatureVerifier, null);
+			}
+			verifier = factory.getVerifier();
+		}
+		SignatureVerification verification = verifier.verifySignature(c,
+				config);
+		if (verification == null) {
+			return;
+		}
+		VerificationUtils.writeVerification(outw, verification,
+				verifier.getName(), c.getCommitterIdent());
+	}
+
 	/**
 	 * @param c
 	 * @return <code>true</code> if at least one note was printed,
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 1d43220..3beab60 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
@@ -29,10 +29,15 @@
 import org.eclipse.jgit.errors.RevisionSyntaxException;
 import org.eclipse.jgit.lib.Constants;
 import org.eclipse.jgit.lib.FileMode;
+import org.eclipse.jgit.lib.GpgConfig;
+import org.eclipse.jgit.lib.GpgSignatureVerifier;
+import org.eclipse.jgit.lib.GpgSignatureVerifierFactory;
 import org.eclipse.jgit.lib.ObjectId;
 import org.eclipse.jgit.lib.PersonIdent;
 import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.lib.GpgSignatureVerifier.SignatureVerification;
 import org.eclipse.jgit.pgm.internal.CLIText;
+import org.eclipse.jgit.pgm.internal.VerificationUtils;
 import org.eclipse.jgit.pgm.opt.PathTreeFilterHandler;
 import org.eclipse.jgit.revwalk.RevCommit;
 import org.eclipse.jgit.revwalk.RevObject;
@@ -59,6 +64,9 @@
 	@Option(name = "--", metaVar = "metaVar_path", handler = PathTreeFilterHandler.class)
 	protected TreeFilter pathFilter = TreeFilter.ALL;
 
+	@Option(name = "--show-signature", usage = "usage_showSignature")
+	private boolean showSignature;
+
 	// BEGIN -- Options shared with Diff
 	@Option(name = "-p", usage = "usage_showPatch")
 	boolean showPatch;
@@ -220,13 +228,16 @@
 		}
 
 		outw.println();
-		String[] lines = tag.getFullMessage().split("\n"); //$NON-NLS-1$
-		for (String s : lines) {
-			outw.println(s);
+		String fullMessage = tag.getFullMessage();
+		if (!fullMessage.isEmpty()) {
+			String[] lines = tag.getFullMessage().split("\n"); //$NON-NLS-1$
+			for (String s : lines) {
+				outw.println(s);
+			}
 		}
 		byte[] rawSignature = tag.getRawGpgSignature();
 		if (rawSignature != null) {
-			lines = RawParseUtils.decode(rawSignature).split("\n"); //$NON-NLS-1$
+			String[] lines = RawParseUtils.decode(rawSignature).split("\n"); //$NON-NLS-1$
 			for (String s : lines) {
 				outw.println(s);
 			}
@@ -258,6 +269,10 @@
 		c.getId().copyTo(outbuffer, outw);
 		outw.println();
 
+		if (showSignature) {
+			showSignature(c);
+		}
+
 		final PersonIdent author = c.getAuthorIdent();
 		outw.println(MessageFormat.format(CLIText.get().authorInfo,
 				author.getName(), author.getEmailAddress()));
@@ -296,4 +311,28 @@
 		}
 		outw.println();
 	}
+
+	private void showSignature(RevCommit c) throws IOException {
+		if (c.getRawGpgSignature() == null) {
+			return;
+		}
+		GpgSignatureVerifierFactory factory = GpgSignatureVerifierFactory
+				.getDefault();
+		if (factory == null) {
+			throw die(CLIText.get().logNoSignatureVerifier, null);
+		}
+		GpgSignatureVerifier verifier = factory.getVerifier();
+		GpgConfig config = new GpgConfig(db.getConfig());
+		try {
+			SignatureVerification verification = verifier.verifySignature(c,
+					config);
+			if (verification == null) {
+				return;
+			}
+			VerificationUtils.writeVerification(outw, verification,
+					verifier.getName(), c.getCommitterIdent());
+		} finally {
+			verifier.clear();
+		}
+	}
 }
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 4cc62b3..e2cd31d 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
@@ -4,7 +4,7 @@
  * Copyright (C) 2008, Charles O'Farrell <charleso@charleso.org>
  * Copyright (C) 2008, Robin Rosenberg <robin.rosenberg.lists@dewire.com>
  * Copyright (C) 2008, Robin Rosenberg <robin.rosenberg@dewire.com>
- * Copyright (C) 2008, 2020 Shawn O. Pearce <spearce@spearce.org> and others
+ * Copyright (C) 2008, 2021 Shawn O. Pearce <spearce@spearce.org> and others
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Distribution License v. 1.0 which is available at
@@ -22,43 +22,60 @@
 import org.eclipse.jgit.api.Git;
 import org.eclipse.jgit.api.ListTagCommand;
 import org.eclipse.jgit.api.TagCommand;
+import org.eclipse.jgit.api.VerificationResult;
+import org.eclipse.jgit.api.VerifySignatureCommand;
 import org.eclipse.jgit.api.errors.GitAPIException;
 import org.eclipse.jgit.api.errors.RefAlreadyExistsException;
+import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.GpgSignatureVerifier.SignatureVerification;
 import org.eclipse.jgit.lib.ObjectId;
 import org.eclipse.jgit.lib.Ref;
 import org.eclipse.jgit.lib.Repository;
 import org.eclipse.jgit.pgm.internal.CLIText;
+import org.eclipse.jgit.pgm.internal.VerificationUtils;
+import org.eclipse.jgit.revwalk.RevTag;
 import org.eclipse.jgit.revwalk.RevWalk;
 import org.kohsuke.args4j.Argument;
 import org.kohsuke.args4j.Option;
 
 @Command(common = true, usage = "usage_CreateATag")
 class Tag extends TextBuiltin {
-	@Option(name = "-f", usage = "usage_forceReplacingAnExistingTag")
+
+	@Option(name = "--force", aliases = { "-f" }, forbids = { "--delete",
+			"--verify" }, usage = "usage_forceReplacingAnExistingTag")
 	private boolean force;
 
-	@Option(name = "-d", usage = "usage_tagDelete")
+	@Option(name = "--delete", aliases = { "-d" }, forbids = {
+			"--verify" }, usage = "usage_tagDelete")
 	private boolean delete;
 
 	@Option(name = "--annotate", aliases = {
-			"-a" }, usage = "usage_tagAnnotated")
+			"-a" }, forbids = { "--delete",
+					"--verify" }, usage = "usage_tagAnnotated")
 	private boolean annotated;
 
-	@Option(name = "-m", metaVar = "metaVar_message", usage = "usage_tagMessage")
+	@Option(name = "-m", forbids = { "--delete",
+			"--verify" }, metaVar = "metaVar_message", usage = "usage_tagMessage")
 	private String message;
 
 	@Option(name = "--sign", aliases = { "-s" }, forbids = {
-			"--no-sign" }, usage = "usage_tagSign")
+			"--no-sign", "--delete", "--verify" }, usage = "usage_tagSign")
 	private boolean sign;
 
 	@Option(name = "--no-sign", usage = "usage_tagNoSign", forbids = {
-			"--sign" })
+			"--sign", "--delete", "--verify" })
 	private boolean noSign;
 
 	@Option(name = "--local-user", aliases = {
-			"-u" }, metaVar = "metaVar_tagLocalUser", usage = "usage_tagLocalUser")
+			"-u" }, forbids = { "--delete",
+					"--verify" }, metaVar = "metaVar_tagLocalUser", usage = "usage_tagLocalUser")
 	private String gpgKeyId;
 
+	@Option(name = "--verify", aliases = { "-v" }, forbids = { "--delete",
+			"--force", "--annotate", "-m", "--sign", "--no-sign",
+			"--local-user" }, usage = "usage_tagVerify")
+	private boolean verify;
+
 	@Argument(index = 0, metaVar = "metaVar_name")
 	private String tagName;
 
@@ -70,7 +87,25 @@
 	protected void run() {
 		try (Git git = new Git(db)) {
 			if (tagName != null) {
-				if (delete) {
+				if (verify) {
+					VerifySignatureCommand verifySig = git.verifySignature()
+							.setMode(VerifySignatureCommand.VerifyMode.TAGS)
+							.addName(tagName);
+
+					VerificationResult verification = verifySig.call()
+							.get(tagName);
+					if (verification == null) {
+						showUnsigned(git, tagName);
+					} else {
+						Throwable error = verification.getException();
+						if (error != null) {
+							throw die(error.getMessage(), error);
+						}
+						writeVerification(verifySig.getVerifier().getName(),
+								(RevTag) verification.getObject(),
+								verification.getVerification());
+					}
+				} else if (delete) {
 					List<String> deletedTags = git.tagDelete().setTags(tagName)
 							.call();
 					if (deletedTags.isEmpty()) {
@@ -116,4 +151,36 @@
 			throw die(e.getMessage(), e);
 		}
 	}
+
+	private void showUnsigned(Git git, String wantedTag) throws IOException {
+		ObjectId id = git.getRepository().resolve(wantedTag);
+		if (id != null && !ObjectId.zeroId().equals(id)) {
+			try (RevWalk walk = new RevWalk(git.getRepository())) {
+				showTag(walk.parseTag(id));
+			}
+		} else {
+			throw die(
+					MessageFormat.format(CLIText.get().tagNotFound, wantedTag));
+		}
+	}
+
+	private void showTag(RevTag tag) throws IOException {
+		outw.println("object " + tag.getObject().name()); //$NON-NLS-1$
+		outw.println("type " + Constants.typeString(tag.getObject().getType())); //$NON-NLS-1$
+		outw.println("tag " + tag.getTagName()); //$NON-NLS-1$
+		outw.println("tagger " + tag.getTaggerIdent().toExternalString()); //$NON-NLS-1$
+		outw.println();
+		outw.print(tag.getFullMessage());
+	}
+
+	private void writeVerification(String name, RevTag tag,
+			SignatureVerification verification) throws IOException {
+		showTag(tag);
+		if (verification == null) {
+			outw.println();
+			return;
+		}
+		VerificationUtils.writeVerification(outw, verification, name,
+				tag.getTaggerIdent());
+	}
 }
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 c68019e..991b3ba 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
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2010, 2013 Sasa Zivkov <sasa.zivkov@sap.com>
- * Copyright (C) 2013, Obeo and others
+ * Copyright (C) 2013, 2021 Obeo and others
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Distribution License v. 1.0 which is available at
@@ -163,6 +163,7 @@
 	/***/ public String lfsUnknownStoreType;
 	/***/ public String lineFormat;
 	/***/ public String listeningOn;
+	/***/ public String logNoSignatureVerifier;
 	/***/ public String mergeCheckoutConflict;
 	/***/ public String mergeConflict;
 	/***/ public String mergeFailed;
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/internal/VerificationUtils.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/internal/VerificationUtils.java
new file mode 100644
index 0000000..c1f8a86
--- /dev/null
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/internal/VerificationUtils.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2021, Thomas Wolf <thomas.wolf@paranor.ch> and others
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0 which is available at
+ * https://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+package org.eclipse.jgit.pgm.internal;
+
+import java.io.IOException;
+
+import org.eclipse.jgit.lib.GpgSignatureVerifier.SignatureVerification;
+import org.eclipse.jgit.lib.PersonIdent;
+import org.eclipse.jgit.util.GitDateFormatter;
+import org.eclipse.jgit.util.SignatureUtils;
+import org.eclipse.jgit.util.io.ThrowingPrintWriter;
+
+/**
+ * Utilities for signature verification.
+ */
+public final class VerificationUtils {
+
+	private VerificationUtils() {
+		// No instantiation
+	}
+
+	/**
+	 * Writes information about a signature verification to the given writer.
+	 *
+	 * @param out
+	 *            to write to
+	 * @param verification
+	 *            to show
+	 * @param name
+	 *            of the verifier used
+	 * @param creator
+	 *            of the object verified; used for time zone information
+	 * @throws IOException
+	 *             if writing fails
+	 */
+	public static void writeVerification(ThrowingPrintWriter out,
+			SignatureVerification verification, String name,
+			PersonIdent creator) throws IOException {
+		String[] text = SignatureUtils
+				.toString(verification, creator,
+						new GitDateFormatter(GitDateFormatter.Format.LOCALE))
+				.split("\n"); //$NON-NLS-1$
+		for (String line : text) {
+			out.print(name);
+			out.print(": "); //$NON-NLS-1$
+			out.println(line);
+		}
+	}
+}
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 e959242..de173f8 100644
--- a/org.eclipse.jgit.ssh.apache.test/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.ssh.apache.test/META-INF/MANIFEST.MF
@@ -7,17 +7,18 @@
 Bundle-Vendor: %Bundle-Vendor
 Bundle-Localization: plugin
 Bundle-RequiredExecutionEnvironment: JavaSE-1.8
-Import-Package: org.apache.sshd.client.config.hosts;version="[2.4.0,2.5.0)",
- org.apache.sshd.common;version="[2.4.0,2.5.0)",
- org.apache.sshd.common.auth;version="[2.4.0,2.5.0)",
- org.apache.sshd.common.config.keys;version="[2.4.0,2.5.0)",
- org.apache.sshd.common.helpers;version="[2.4.0,2.5.0)",
- org.apache.sshd.common.keyprovider;version="[2.4.0,2.5.0)",
- org.apache.sshd.common.session;version="[2.4.0,2.5.0)",
- org.apache.sshd.common.util.net;version="[2.4.0,2.5.0)",
- org.apache.sshd.common.util.security;version="[2.4.0,2.5.0)",
- org.apache.sshd.server;version="[2.4.0,2.5.0)",
- org.apache.sshd.server.forward;version="[2.4.0,2.5.0)",
+Import-Package: org.apache.sshd.client.config.hosts;version="[2.6.0,2.7.0)",
+ org.apache.sshd.common;version="[2.6.0,2.7.0)",
+ org.apache.sshd.common.auth;version="[2.6.0,2.7.0)",
+ org.apache.sshd.common.config.keys;version="[2.6.0,2.7.0)",
+ org.apache.sshd.common.helpers;version="[2.6.0,2.7.0)",
+ org.apache.sshd.common.keyprovider;version="[2.6.0,2.7.0)",
+ org.apache.sshd.common.session;version="[2.6.0,2.7.0)",
+ org.apache.sshd.common.util.net;version="[2.6.0,2.7.0)",
+ org.apache.sshd.common.util.security;version="[2.6.0,2.7.0)",
+ org.apache.sshd.core;version="[2.6.0,2.7.0)",
+ org.apache.sshd.server;version="[2.6.0,2.7.0)",
+ org.apache.sshd.server.forward;version="[2.6.0,2.7.0)",
  org.eclipse.jgit.api;version="[5.11.0,5.12.0)",
  org.eclipse.jgit.api.errors;version="[5.11.0,5.12.0)",
  org.eclipse.jgit.internal.transport.sshd.proxy;version="[5.11.0,5.12.0)",
diff --git a/org.eclipse.jgit.ssh.apache.test/tst/org/eclipse/jgit/transport/sshd/ApacheSshTest.java b/org.eclipse.jgit.ssh.apache.test/tst/org/eclipse/jgit/transport/sshd/ApacheSshTest.java
index 3427da6..97f97f9 100644
--- a/org.eclipse.jgit.ssh.apache.test/tst/org/eclipse/jgit/transport/sshd/ApacheSshTest.java
+++ b/org.eclipse.jgit.ssh.apache.test/tst/org/eclipse/jgit/transport/sshd/ApacheSshTest.java
@@ -9,6 +9,7 @@
  */
 package org.eclipse.jgit.transport.sshd;
 
+import static org.apache.sshd.core.CoreModuleProperties.MAX_CONCURRENT_SESSIONS;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
@@ -33,7 +34,6 @@
 
 import org.apache.sshd.client.config.hosts.KnownHostEntry;
 import org.apache.sshd.client.config.hosts.KnownHostHashValue;
-import org.apache.sshd.common.PropertyResolverUtils;
 import org.apache.sshd.common.config.keys.AuthorizedKeyEntry;
 import org.apache.sshd.common.config.keys.KeyUtils;
 import org.apache.sshd.common.config.keys.PublicKeyEntry;
@@ -41,7 +41,6 @@
 import org.apache.sshd.common.session.Session;
 import org.apache.sshd.common.util.net.SshdSocketAddress;
 import org.apache.sshd.server.ServerAuthenticationManager;
-import org.apache.sshd.server.ServerFactoryManager;
 import org.apache.sshd.server.SshServer;
 import org.apache.sshd.server.forward.StaticDecisionForwardingFilter;
 import org.eclipse.jgit.api.Git;
@@ -216,8 +215,8 @@
 	 */
 	@Test
 	public void testCloneAndFetchWithSessionLimit() throws Exception {
-		PropertyResolverUtils.updateProperty(server.getPropertyResolver(),
-				ServerFactoryManager.MAX_CONCURRENT_SESSIONS, 2);
+		MAX_CONCURRENT_SESSIONS
+				.set(server.getPropertyResolver(), Integer.valueOf(2));
 		File localClone = cloneWith("ssh://localhost/doesntmatter",
 				defaultCloneDir, null, //
 				"Host localhost", //
diff --git a/org.eclipse.jgit.ssh.apache/META-INF/MANIFEST.MF b/org.eclipse.jgit.ssh.apache/META-INF/MANIFEST.MF
index 59eafa4..6ff43ff 100644
--- a/org.eclipse.jgit.ssh.apache/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.ssh.apache/META-INF/MANIFEST.MF
@@ -33,49 +33,51 @@
    org.apache.sshd.client.session,
    org.apache.sshd.client.keyverifier"
 Import-Package: net.i2p.crypto.eddsa;version="[0.3.0,0.4.0)",
- org.apache.sshd.agent;version="[2.4.0,2.5.0)",
- org.apache.sshd.client;version="[2.4.0,2.5.0)",
- org.apache.sshd.client.auth;version="[2.4.0,2.5.0)",
- org.apache.sshd.client.auth.keyboard;version="[2.4.0,2.5.0)",
- org.apache.sshd.client.auth.password;version="[2.4.0,2.5.0)",
- org.apache.sshd.client.auth.pubkey;version="[2.4.0,2.5.0)",
- org.apache.sshd.client.channel;version="[2.4.0,2.5.0)",
- org.apache.sshd.client.config.hosts;version="[2.4.0,2.5.0)",
- org.apache.sshd.client.config.keys;version="[2.4.0,2.5.0)",
- org.apache.sshd.client.future;version="[2.4.0,2.5.0)",
- org.apache.sshd.client.keyverifier;version="[2.4.0,2.5.0)",
- org.apache.sshd.client.session;version="[2.4.0,2.5.0)",
- org.apache.sshd.client.session.forward;version="[2.4.0,2.5.0)",
- org.apache.sshd.client.subsystem.sftp;version="[2.4.0,2.5.0)",
- org.apache.sshd.common;version="[2.4.0,2.5.0)",
- org.apache.sshd.common.auth;version="[2.4.0,2.5.0)",
- org.apache.sshd.common.channel;version="[2.4.0,2.5.0)",
- org.apache.sshd.common.compression;version="[2.4.0,2.5.0)",
- org.apache.sshd.common.config.keys;version="[2.4.0,2.5.0)",
- org.apache.sshd.common.config.keys.loader;version="[2.4.0,2.5.0)",
- org.apache.sshd.common.config.keys.loader.openssh.kdf;version="[2.4.0,2.5.0)",
- org.apache.sshd.common.digest;version="[2.4.0,2.5.0)",
- org.apache.sshd.common.forward;version="[2.4.0,2.5.0)",
- org.apache.sshd.common.future;version="[2.4.0,2.5.0)",
- org.apache.sshd.common.helpers;version="[2.4.0,2.5.0)",
- org.apache.sshd.common.io;version="[2.4.0,2.5.0)",
- org.apache.sshd.common.kex;version="[2.4.0,2.5.0)",
- org.apache.sshd.common.keyprovider;version="[2.4.0,2.5.0)",
- org.apache.sshd.common.mac;version="[2.4.0,2.5.0)",
- org.apache.sshd.common.random;version="[2.4.0,2.5.0)",
- org.apache.sshd.common.session;version="[2.4.0,2.5.0)",
- org.apache.sshd.common.session.helpers;version="[2.4.0,2.5.0)",
- org.apache.sshd.common.signature;version="[2.4.0,2.5.0)",
- org.apache.sshd.common.subsystem.sftp;version="[2.4.0,2.5.0)",
- org.apache.sshd.common.util;version="[2.4.0,2.5.0)",
- org.apache.sshd.common.util.buffer;version="[2.4.0,2.5.0)",
- org.apache.sshd.common.util.closeable;version="[2.4.0,2.5.0)",
- org.apache.sshd.common.util.io;version="[2.4.0,2.5.0)",
- org.apache.sshd.common.util.io.resource;version="[2.4.0,2.5.0)",
- org.apache.sshd.common.util.logging;version="[2.4.0,2.5.0)",
- org.apache.sshd.common.util.net;version="[2.4.0,2.5.0)",
- org.apache.sshd.common.util.security;version="[2.4.0,2.5.0)",
- org.apache.sshd.server.auth;version="[2.4.0,2.5.0)",
+ org.apache.sshd.agent;version="[2.6.0,2.7.0)",
+ org.apache.sshd.client;version="[2.6.0,2.7.0)",
+ org.apache.sshd.client.auth;version="[2.6.0,2.7.0)",
+ org.apache.sshd.client.auth.keyboard;version="[2.6.0,2.7.0)",
+ org.apache.sshd.client.auth.password;version="[2.6.0,2.7.0)",
+ org.apache.sshd.client.auth.pubkey;version="[2.6.0,2.7.0)",
+ org.apache.sshd.client.channel;version="[2.6.0,2.7.0)",
+ org.apache.sshd.client.config.hosts;version="[2.6.0,2.7.0)",
+ org.apache.sshd.client.config.keys;version="[2.6.0,2.7.0)",
+ org.apache.sshd.client.future;version="[2.6.0,2.7.0)",
+ org.apache.sshd.client.keyverifier;version="[2.6.0,2.7.0)",
+ org.apache.sshd.client.session;version="[2.6.0,2.7.0)",
+ org.apache.sshd.client.session.forward;version="[2.6.0,2.7.0)",
+ org.apache.sshd.common;version="[2.6.0,2.7.0)",
+ org.apache.sshd.common.auth;version="[2.6.0,2.7.0)",
+ org.apache.sshd.common.channel;version="[2.6.0,2.7.0)",
+ org.apache.sshd.common.compression;version="[2.6.0,2.7.0)",
+ org.apache.sshd.common.config.keys;version="[2.6.0,2.7.0)",
+ org.apache.sshd.common.config.keys.loader;version="[2.6.0,2.7.0)",
+ org.apache.sshd.common.config.keys.loader.openssh.kdf;version="[2.6.0,2.7.0)",
+ org.apache.sshd.common.digest;version="[2.6.0,2.7.0)",
+ org.apache.sshd.common.forward;version="[2.6.0,2.7.0)",
+ org.apache.sshd.common.future;version="[2.6.0,2.7.0)",
+ org.apache.sshd.common.helpers;version="[2.6.0,2.7.0)",
+ org.apache.sshd.common.io;version="[2.6.0,2.7.0)",
+ org.apache.sshd.common.kex;version="[2.6.0,2.7.0)",
+ org.apache.sshd.common.keyprovider;version="[2.6.0,2.7.0)",
+ org.apache.sshd.common.mac;version="[2.6.0,2.7.0)",
+ org.apache.sshd.common.random;version="[2.6.0,2.7.0)",
+ org.apache.sshd.common.session;version="[2.6.0,2.7.0)",
+ org.apache.sshd.common.session.helpers;version="[2.6.0,2.7.0)",
+ org.apache.sshd.common.signature;version="[2.6.0,2.7.0)",
+ org.apache.sshd.common.util;version="[2.6.0,2.7.0)",
+ org.apache.sshd.common.util.buffer;version="[2.6.0,2.7.0)",
+ org.apache.sshd.common.util.closeable;version="[2.6.0,2.7.0)",
+ org.apache.sshd.common.util.io;version="[2.6.0,2.7.0)",
+ org.apache.sshd.common.util.io.resource;version="[2.6.0,2.7.0)",
+ org.apache.sshd.common.util.logging;version="[2.6.0,2.7.0)",
+ org.apache.sshd.common.util.net;version="[2.6.0,2.7.0)",
+ org.apache.sshd.common.util.security;version="[2.6.0,2.7.0)",
+ org.apache.sshd.core;version="[2.6.0,2.7.0)",
+ org.apache.sshd.server.auth;version="[2.6.0,2.7.0)",
+ org.apache.sshd.sftp;version="[2.6.0,2.7.0)",
+ org.apache.sshd.sftp.client;version="[2.6.0,2.7.0)",
+ org.apache.sshd.sftp.common;version="[2.6.0,2.7.0)",
  org.eclipse.jgit.annotations;version="[5.11.0,5.12.0)",
  org.eclipse.jgit.errors;version="[5.11.0,5.12.0)",
  org.eclipse.jgit.fnmatch;version="[5.11.0,5.12.0)",
diff --git a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitClientSession.java b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitClientSession.java
index 0d6f302..66713ba 100644
--- a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitClientSession.java
+++ b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitClientSession.java
@@ -10,6 +10,7 @@
 package org.eclipse.jgit.internal.transport.sshd;
 
 import static java.text.MessageFormat.format;
+import static org.apache.sshd.core.CoreModuleProperties.MAX_IDENTIFICATION_SIZE;
 
 import java.io.IOException;
 import java.io.StreamCorruptedException;
@@ -29,19 +30,14 @@
 
 import org.apache.sshd.client.ClientFactoryManager;
 import org.apache.sshd.client.config.hosts.HostConfigEntry;
-import org.apache.sshd.client.future.AuthFuture;
 import org.apache.sshd.client.keyverifier.ServerKeyVerifier;
 import org.apache.sshd.client.session.ClientSessionImpl;
-import org.apache.sshd.client.session.ClientUserAuthService;
 import org.apache.sshd.common.AttributeRepository;
 import org.apache.sshd.common.FactoryManager;
 import org.apache.sshd.common.PropertyResolver;
-import org.apache.sshd.common.PropertyResolverUtils;
-import org.apache.sshd.common.SshException;
 import org.apache.sshd.common.config.keys.KeyUtils;
 import org.apache.sshd.common.io.IoSession;
 import org.apache.sshd.common.io.IoWriteFuture;
-import org.apache.sshd.common.kex.KexState;
 import org.apache.sshd.common.util.Readable;
 import org.apache.sshd.common.util.buffer.Buffer;
 import org.eclipse.jgit.errors.InvalidPatternException;
@@ -66,7 +62,8 @@
 	 * protocol version exchange. 64kb is what OpenSSH < 8.0 read; OpenSSH 8.0
 	 * changed it to 8Mb, but that seems excessive for the purpose stated in RFC
 	 * 4253. The Apache MINA sshd default in
-	 * {@link FactoryManager#DEFAULT_MAX_IDENTIFICATION_SIZE} is 16kb.
+	 * {@link org.apache.sshd.core.CoreModuleProperties#MAX_IDENTIFICATION_SIZE}
+	 * is 16kb.
 	 */
 	private static final int DEFAULT_MAX_IDENTIFICATION_SIZE = 64 * 1024;
 
@@ -77,17 +74,6 @@
 	private volatile StatefulProxyConnector proxyHandler;
 
 	/**
-	 * Work-around for bug 565394 / SSHD-1050; remove when using sshd 2.6.0.
-	 */
-	private volatile AuthFuture authFuture;
-
-	/** Records exceptions before there is an authFuture. */
-	private List<Throwable> earlyErrors = new ArrayList<>();
-
-	/** Guards setting an earlyError and the authFuture together. */
-	private final Object errorLock = new Object();
-
-	/**
 	 * @param manager
 	 * @param session
 	 * @throws Exception
@@ -97,125 +83,6 @@
 		super(manager, session);
 	}
 
-	// BEGIN Work-around for bug 565394 / SSHD-1050
-	// Remove when using sshd 2.6.0.
-
-	@Override
-	public AuthFuture auth() throws IOException {
-		if (getUsername() == null) {
-			throw new IllegalStateException(
-					SshdText.get().sessionWithoutUsername);
-		}
-		ClientUserAuthService authService = getUserAuthService();
-		String serviceName = nextServiceName();
-		List<Throwable> errors = null;
-		AuthFuture future;
-		// Guard both getting early errors and setting authFuture
-		synchronized (errorLock) {
-			future = authService.auth(serviceName);
-			if (future == null) {
-				// Internal error; no translation.
-				throw new IllegalStateException(
-						"No auth future generated by service '" //$NON-NLS-1$
-								+ serviceName + '\'');
-			}
-			errors = earlyErrors;
-			earlyErrors = null;
-			authFuture = future;
-		}
-		if (errors != null && !errors.isEmpty()) {
-			Iterator<Throwable> iter = errors.iterator();
-			Throwable first = iter.next();
-			iter.forEachRemaining(t -> {
-				if (t != first && t != null) {
-					first.addSuppressed(t);
-				}
-			});
-			// Mark the future as having had an exception; just to be on the
-			// safe side. Actually, there shouldn't be anyone waiting on this
-			// future yet.
-			future.setException(first);
-			if (log.isDebugEnabled()) {
-				log.debug("auth({}) early exception type={}: {}", //$NON-NLS-1$
-						this, first.getClass().getSimpleName(),
-						first.getMessage());
-			}
-			if (first instanceof SshException) {
-				throw new SshException(
-						((SshException) first).getDisconnectCode(),
-						first.getMessage(), first);
-			}
-			throw new IOException(first.getMessage(), first);
-		}
-		return future;
-	}
-
-	@Override
-	protected void signalAuthFailure(AuthFuture future, Throwable t) {
-		signalAuthFailure(t);
-	}
-
-	private void signalAuthFailure(Throwable t) {
-		AuthFuture future = authFuture;
-		if (future == null) {
-			synchronized (errorLock) {
-				if (earlyErrors != null) {
-					earlyErrors.add(t);
-				}
-				future = authFuture;
-			}
-		}
-		if (future != null) {
-			future.setException(t);
-		}
-		if (log.isDebugEnabled()) {
-			boolean signalled = future != null && t == future.getException();
-			log.debug("signalAuthFailure({}) type={}, signalled={}: {}", this, //$NON-NLS-1$
-					t.getClass().getSimpleName(), Boolean.valueOf(signalled),
-					t.getMessage());
-		}
-	}
-
-	@Override
-	public void exceptionCaught(Throwable t) {
-		signalAuthFailure(t);
-		super.exceptionCaught(t);
-	}
-
-	@Override
-	protected void preClose() {
-		signalAuthFailure(
-				new SshException(SshdText.get().authenticationOnClosedSession));
-		super.preClose();
-	}
-
-	@Override
-	protected void handleDisconnect(int code, String msg, String lang,
-			Buffer buffer) throws Exception {
-		signalAuthFailure(new SshException(code, msg));
-		super.handleDisconnect(code, msg, lang, buffer);
-	}
-
-	@Override
-	protected <C extends Collection<ClientSessionEvent>> C updateCurrentSessionState(
-			C newState) {
-		if (closeFuture.isClosed()) {
-			newState.add(ClientSessionEvent.CLOSED);
-		}
-		if (isAuthenticated()) { // authFuture.isSuccess()
-			newState.add(ClientSessionEvent.AUTHED);
-		}
-		if (KexState.DONE.equals(getKexState())) {
-			AuthFuture future = authFuture;
-			if (future == null || future.isFailure()) {
-				newState.add(ClientSessionEvent.WAIT_AUTH);
-			}
-		}
-		return newState;
-	}
-
-	// END Work-around for bug 565394 / SSHD-1050
-
 	/**
 	 * Retrieves the {@link HostConfigEntry} this session was created for.
 	 *
@@ -332,22 +199,6 @@
 	}
 
 	@Override
-	protected void checkKeys() throws SshException {
-		ServerKeyVerifier serverKeyVerifier = getServerKeyVerifier();
-		// The super implementation always uses
-		// getIoSession().getRemoteAddress(). In case of a proxy connection,
-		// that would be the address of the proxy!
-		SocketAddress remoteAddress = getConnectAddress();
-		PublicKey serverKey = getKex().getServerKey();
-		if (!serverKeyVerifier.verifyServerKey(this, remoteAddress,
-				serverKey)) {
-			throw new SshException(
-					org.apache.sshd.common.SshConstants.SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE,
-					SshdText.get().kexServerKeyInvalid);
-		}
-	}
-
-	@Override
 	protected String resolveAvailableSignaturesProposal(
 			FactoryManager manager) {
 		Set<String> defaultSignatures = new LinkedHashSet<>();
@@ -477,9 +328,15 @@
 			throw new IllegalStateException(
 					"doReadIdentification of client called with server=true"); //$NON-NLS-1$
 		}
-		int maxIdentSize = PropertyResolverUtils.getIntProperty(this,
-				FactoryManager.MAX_IDENTIFICATION_SIZE,
-				DEFAULT_MAX_IDENTIFICATION_SIZE);
+		Integer maxIdentLength = MAX_IDENTIFICATION_SIZE.get(this).orElse(null);
+		int maxIdentSize;
+		if (maxIdentLength == null || maxIdentLength
+				.intValue() < DEFAULT_MAX_IDENTIFICATION_SIZE) {
+			maxIdentSize = DEFAULT_MAX_IDENTIFICATION_SIZE;
+			MAX_IDENTIFICATION_SIZE.set(this, Integer.valueOf(maxIdentSize));
+		} else {
+			maxIdentSize = maxIdentLength.intValue();
+		}
 		int current = buffer.rpos();
 		int end = current + buffer.available();
 		if (current >= end) {
diff --git a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitPasswordAuthentication.java b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitPasswordAuthentication.java
index 4abd6e9..ff8caaa 100644
--- a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitPasswordAuthentication.java
+++ b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitPasswordAuthentication.java
@@ -9,7 +9,8 @@
  */
 package org.eclipse.jgit.internal.transport.sshd;
 
-import org.apache.sshd.client.ClientAuthenticationManager;
+import static org.apache.sshd.core.CoreModuleProperties.PASSWORD_PROMPTS;
+
 import org.apache.sshd.client.auth.keyboard.UserInteraction;
 import org.apache.sshd.client.auth.password.UserAuthPassword;
 import org.apache.sshd.client.session.ClientSession;
@@ -29,9 +30,7 @@
 	public void init(ClientSession session, String service) throws Exception {
 		super.init(session, service);
 		maxAttempts = Math.max(1,
-				session.getIntProperty(
-						ClientAuthenticationManager.PASSWORD_PROMPTS,
-						ClientAuthenticationManager.DEFAULT_PASSWORD_PROMPTS));
+				PASSWORD_PROMPTS.getRequired(session).intValue());
 		attempts = 0;
 	}
 
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 beaaeca..74455dc 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
@@ -10,6 +10,8 @@
 package org.eclipse.jgit.internal.transport.sshd;
 
 import static java.text.MessageFormat.format;
+import static org.apache.sshd.core.CoreModuleProperties.PASSWORD_PROMPTS;
+import static org.apache.sshd.core.CoreModuleProperties.PREFERRED_AUTHS;
 import static org.eclipse.jgit.internal.transport.ssh.OpenSshConfigFile.positive;
 
 import java.io.IOException;
@@ -32,7 +34,6 @@
 import java.util.Objects;
 import java.util.stream.Collectors;
 
-import org.apache.sshd.client.ClientAuthenticationManager;
 import org.apache.sshd.client.SshClient;
 import org.apache.sshd.client.config.hosts.HostConfigEntry;
 import org.apache.sshd.client.future.ConnectFuture;
@@ -169,12 +170,15 @@
 		Map<AttributeKey<?>, Object> data = new HashMap<>();
 		data.put(HOST_CONFIG_ENTRY, hostConfig);
 		data.put(ORIGINAL_REMOTE_ADDRESS, originalAddress);
+		data.put(TARGET_SERVER, new SshdSocketAddress(originalAddress));
 		String preferredAuths = hostConfig.getProperty(
 				SshConstants.PREFERRED_AUTHENTICATIONS,
 				resolveAttribute(PREFERRED_AUTHENTICATIONS));
 		if (!StringUtils.isEmptyOrNull(preferredAuths)) {
 			data.put(SessionAttributes.PROPERTIES,
-					Collections.singletonMap(PREFERRED_AUTHS, preferredAuths));
+					Collections.singletonMap(
+							PREFERRED_AUTHS.getName(),
+							preferredAuths));
 		}
 		return new SessionAttributes(
 				AttributeRepository.ofAttributesMap(data),
@@ -267,8 +271,7 @@
 			session.setCredentialsProvider(getCredentialsProvider());
 		}
 		int numberOfPasswordPrompts = getNumberOfPasswordPrompts(hostConfig);
-		session.getProperties().put(PASSWORD_PROMPTS,
-				Integer.valueOf(numberOfPasswordPrompts));
+		PASSWORD_PROMPTS.set(session, Integer.valueOf(numberOfPasswordPrompts));
 		List<Path> identities = hostConfig.getIdentities().stream()
 				.map(s -> {
 					try {
@@ -311,7 +314,7 @@
 			log.warn(format(SshdText.get().configInvalidPositive,
 					SshConstants.NUMBER_OF_PASSWORD_PROMPTS, prompts));
 		}
-		return ClientAuthenticationManager.DEFAULT_PASSWORD_PROMPTS;
+		return PASSWORD_PROMPTS.getRequiredDefault().intValue();
 	}
 
 	/**
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 97e0fcc..6b0d9fb 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
@@ -46,7 +46,7 @@
 
 	@Override
 	public HostConfigEntry resolveEffectiveHost(String host, int port,
-			SocketAddress localAddress, String username,
+			SocketAddress localAddress, String username, String proxyJump,
 			AttributeRepository attributes) throws IOException {
 		SshConfigStore.HostConfig entry = configFile == null
 				? SshConfigStore.EMPTY_CONFIG
diff --git a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/PasswordProviderWrapper.java b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/PasswordProviderWrapper.java
index 078e411..2cd0669 100644
--- a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/PasswordProviderWrapper.java
+++ b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/PasswordProviderWrapper.java
@@ -9,6 +9,8 @@
  */
 package org.eclipse.jgit.internal.transport.sshd;
 
+import static org.apache.sshd.core.CoreModuleProperties.PASSWORD_PROMPTS;
+
 import java.io.IOException;
 import java.net.URISyntaxException;
 import java.security.GeneralSecurityException;
@@ -18,7 +20,6 @@
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.function.Supplier;
 
-import org.apache.sshd.client.ClientAuthenticationManager;
 import org.apache.sshd.common.AttributeRepository.AttributeKey;
 import org.apache.sshd.common.NamedResource;
 import org.apache.sshd.common.config.keys.FilePasswordProvider;
@@ -62,15 +63,8 @@
 		if (state == null) {
 			state = new PerSessionState();
 			state.delegate = factory.get();
-			Integer maxNumberOfAttempts = context
-					.getInteger(ClientAuthenticationManager.PASSWORD_PROMPTS);
-			if (maxNumberOfAttempts != null
-					&& maxNumberOfAttempts.intValue() > 0) {
-				state.delegate.setAttempts(maxNumberOfAttempts.intValue());
-			} else {
-				state.delegate.setAttempts(
-						ClientAuthenticationManager.DEFAULT_PASSWORD_PROMPTS);
-			}
+			state.delegate.setAttempts(
+					PASSWORD_PROMPTS.getRequiredDefault().intValue());
 			context.setAttribute(STATE, state);
 		}
 		return state;
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 8ac752b..e5d1e80 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
@@ -135,7 +135,7 @@
 		byte[] data = eol(msg).toString().getBytes(US_ASCII);
 		Buffer buffer = new ByteArrayBuffer(data.length, false);
 		buffer.putRawBytes(data);
-		session.writePacket(buffer).verify(getTimeout());
+		session.writeBuffer(buffer).verify(getTimeout());
 	}
 
 	private StringBuilder connect() {
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 78b8d45..8844efa 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
@@ -235,7 +235,7 @@
 		buffer.putByte((byte) authenticationProposals.length);
 		buffer.putRawBytes(authenticationProposals);
 		state = ProtocolState.INIT;
-		session.writePacket(buffer).verify(getTimeout());
+		session.writeBuffer(buffer).verify(getTimeout());
 	}
 
 	private byte[] getAuthenticationProposals() {
@@ -298,7 +298,7 @@
 		buffer.putByte((byte) ((port >> 8) & 0xFF));
 		buffer.putByte((byte) (port & 0xFF));
 		state = ProtocolState.CONNECTING;
-		session.writePacket(buffer).verify(getTimeout());
+		session.writeBuffer(buffer).verify(getTimeout());
 	}
 
 	private void doPasswordAuth(IoSession session) throws Exception {
@@ -335,7 +335,7 @@
 						"No data for proxy authentication with " //$NON-NLS-1$
 								+ proxyAddress);
 			}
-			session.writePacket(buffer).verify(getTimeout());
+			session.writeBuffer(buffer).verify(getTimeout());
 		} finally {
 			if (buffer != null) {
 				buffer.clear(true);
@@ -350,7 +350,7 @@
 			authenticator.process();
 			buffer = authenticator.getToken();
 			if (buffer != null) {
-				session.writePacket(buffer).verify(getTimeout());
+				session.writeBuffer(buffer).verify(getTimeout());
 			}
 		} finally {
 			if (buffer != null) {
diff --git a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/transport/sshd/SshdSession.java b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/transport/sshd/SshdSession.java
index 5a50cc8..33b234b 100644
--- a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/transport/sshd/SshdSession.java
+++ b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/transport/sshd/SshdSession.java
@@ -11,6 +11,7 @@
 
 import static java.text.MessageFormat.format;
 import static org.apache.sshd.common.SshConstants.SSH2_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE;
+import static org.apache.sshd.sftp.SftpModuleProperties.SFTP_CHANNEL_OPEN_TIMEOUT;
 
 import java.io.Closeable;
 import java.io.IOException;
@@ -38,17 +39,17 @@
 import org.apache.sshd.client.future.ConnectFuture;
 import org.apache.sshd.client.session.ClientSession;
 import org.apache.sshd.client.session.forward.PortForwardingTracker;
-import org.apache.sshd.client.subsystem.sftp.SftpClient;
-import org.apache.sshd.client.subsystem.sftp.SftpClient.CloseableHandle;
-import org.apache.sshd.client.subsystem.sftp.SftpClient.CopyMode;
-import org.apache.sshd.client.subsystem.sftp.SftpClientFactory;
 import org.apache.sshd.common.AttributeRepository;
 import org.apache.sshd.common.SshException;
 import org.apache.sshd.common.future.CloseFuture;
 import org.apache.sshd.common.future.SshFutureListener;
-import org.apache.sshd.common.subsystem.sftp.SftpException;
 import org.apache.sshd.common.util.io.IoUtils;
 import org.apache.sshd.common.util.net.SshdSocketAddress;
+import org.apache.sshd.sftp.client.SftpClient;
+import org.apache.sshd.sftp.client.SftpClient.CloseableHandle;
+import org.apache.sshd.sftp.client.SftpClient.CopyMode;
+import org.apache.sshd.sftp.client.SftpClientFactory;
+import org.apache.sshd.sftp.common.SftpException;
 import org.eclipse.jgit.annotations.NonNull;
 import org.eclipse.jgit.errors.TransportException;
 import org.eclipse.jgit.internal.transport.sshd.JGitSshClient;
@@ -205,7 +206,7 @@
 	private HostConfigEntry getHostConfig(String username, String host,
 			int port) throws IOException {
 		HostConfigEntry entry = client.getHostConfigEntryResolver()
-				.resolveEffectiveHost(host, port, null, username, null);
+				.resolveEffectiveHost(host, port, null, username, null, null);
 		if (entry == null) {
 			if (SshdSocketAddress.isIPv6Address(host)) {
 				return new HostConfigEntry("", host, port, username); //$NON-NLS-1$
@@ -439,13 +440,12 @@
 		@Override
 		public void connect(int timeout, TimeUnit unit) throws IOException {
 			if (timeout <= 0) {
-				session.getProperties().put(
-						SftpClient.SFTP_CHANNEL_OPEN_TIMEOUT,
-						Long.valueOf(Long.MAX_VALUE));
+				// This timeout must not be null!
+				SFTP_CHANNEL_OPEN_TIMEOUT.set(session,
+						Duration.ofMillis(Long.MAX_VALUE));
 			} else {
-				session.getProperties().put(
-						SftpClient.SFTP_CHANNEL_OPEN_TIMEOUT,
-						Long.valueOf(unit.toMillis(timeout)));
+				SFTP_CHANNEL_OPEN_TIMEOUT.set(session,
+						Duration.ofMillis(unit.toMillis(timeout)));
 			}
 			ftp = SftpClientFactory.instance().createSftpClient(session);
 			try {
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 df0e1d2..357994d 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
@@ -35,10 +35,13 @@
 import org.apache.sshd.client.auth.pubkey.UserAuthPublicKeyFactory;
 import org.apache.sshd.client.config.hosts.HostConfigEntryResolver;
 import org.apache.sshd.common.SshException;
+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.config.keys.loader.openssh.kdf.BCryptKdfOptions;
 import org.apache.sshd.common.keyprovider.KeyIdentityProvider;
+import org.apache.sshd.common.signature.BuiltinSignatures;
+import org.apache.sshd.common.signature.Signature;
 import org.eclipse.jgit.annotations.NonNull;
 import org.eclipse.jgit.errors.TransportException;
 import org.eclipse.jgit.internal.transport.ssh.OpenSshConfigFile;
@@ -205,6 +208,7 @@
 						.hostConfigEntryResolver(configFile)
 						.serverKeyVerifier(new JGitServerKeyVerifier(
 								getServerKeyDatabase(home, sshDir)))
+						.signatureFactories(getSignatureFactories())
 						.compressionFactories(
 								new ArrayList<>(BuiltinCompressions.VALUES))
 						.build();
@@ -590,4 +594,35 @@
 	protected String getDefaultPreferredAuthentications() {
 		return null;
 	}
+
+	/**
+	 * Apache MINA sshd 2.6.0 has removed DSA, DSA_CERT and RSA_CERT. We have to
+	 * set it up explicitly to still allow users to connect with DSA keys.
+	 *
+	 * @return a list of supported signature factories
+	 */
+	@SuppressWarnings("deprecation")
+	private static List<NamedFactory<Signature>> getSignatureFactories() {
+		// @formatter:off
+		return Arrays.asList(
+				BuiltinSignatures.nistp256_cert,
+				BuiltinSignatures.nistp384_cert,
+				BuiltinSignatures.nistp521_cert,
+				BuiltinSignatures.ed25519_cert,
+				BuiltinSignatures.rsaSHA512_cert,
+				BuiltinSignatures.rsaSHA256_cert,
+				BuiltinSignatures.rsa_cert,
+				BuiltinSignatures.nistp256,
+				BuiltinSignatures.nistp384,
+				BuiltinSignatures.nistp521,
+				BuiltinSignatures.ed25519,
+				BuiltinSignatures.sk_ecdsa_sha2_nistp256,
+				BuiltinSignatures.sk_ssh_ed25519,
+				BuiltinSignatures.rsaSHA512,
+				BuiltinSignatures.rsaSHA256,
+				BuiltinSignatures.rsa,
+				BuiltinSignatures.dsa_cert,
+				BuiltinSignatures.dsa);
+		// @formatter:on
+	}
 }
diff --git a/org.eclipse.jgit.test/BUILD b/org.eclipse.jgit.test/BUILD
index f12646e..c9b5d37 100644
--- a/org.eclipse.jgit.test/BUILD
+++ b/org.eclipse.jgit.test/BUILD
@@ -13,6 +13,8 @@
 ) + [PKG + c for c in [
     "api/AbstractRemoteCommandTest.java",
     "diff/AbstractDiffTestCase.java",
+    "internal/revwalk/ObjectReachabilityTestCase.java",
+    "internal/revwalk/ReachabilityCheckerTestCase.java",
     "internal/storage/file/GcTestCase.java",
     "internal/storage/file/PackIndexTestCase.java",
     "internal/storage/file/XInputStream.java",
@@ -20,8 +22,6 @@
     "nls/MissingPropertyBundle.java",
     "nls/NoPropertiesBundle.java",
     "nls/NonTranslatedBundle.java",
-    "revwalk/ObjectReachabilityTestCase.java",
-    "revwalk/ReachabilityCheckerTestCase.java",
     "revwalk/RevQueueTestCase.java",
     "revwalk/RevWalkTestCase.java",
     "transport/ObjectIdMatcher.java",
@@ -44,8 +44,6 @@
     PKG + "api/SecurityManagerMissingPermissionsTest.java",
 ]
 
-RESOURCES = glob(["resources/**"])
-
 tests(tests = glob(
     ["tst/**/*.java"],
     exclude = HELPERS + DATA + EXCLUDED,
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/InitCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/InitCommandTest.java
index 1c18b5a..48d835e 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/InitCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/InitCommandTest.java
@@ -9,6 +9,7 @@
  */
 package org.eclipse.jgit.api;
 
+import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
@@ -21,8 +22,10 @@
 import org.eclipse.jgit.errors.NoWorkTreeException;
 import org.eclipse.jgit.junit.MockSystemReader;
 import org.eclipse.jgit.junit.RepositoryTestCase;
+import org.eclipse.jgit.lib.ConfigConstants;
 import org.eclipse.jgit.lib.Constants;
 import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.lib.StoredConfig;
 import org.eclipse.jgit.util.SystemReader;
 import org.junit.Before;
 import org.junit.Test;
@@ -42,7 +45,73 @@
 		InitCommand command = new InitCommand();
 		command.setDirectory(directory);
 		try (Git git = command.call()) {
-			assertNotNull(git.getRepository());
+			Repository r = git.getRepository();
+			assertNotNull(r);
+			assertEquals("refs/heads/master", r.getFullBranch());
+		}
+	}
+
+	@Test
+	public void testInitRepositoryMainInitialBranch()
+			throws IOException, JGitInternalException, GitAPIException {
+		File directory = createTempDirectory("testInitRepository");
+		InitCommand command = new InitCommand();
+		command.setDirectory(directory);
+		command.setInitialBranch("main");
+		try (Git git = command.call()) {
+			Repository r = git.getRepository();
+			assertNotNull(r);
+			assertEquals("refs/heads/main", r.getFullBranch());
+		}
+	}
+
+	@Test
+	public void testInitRepositoryCustomDefaultBranch()
+			throws Exception {
+		File directory = createTempDirectory("testInitRepository");
+		InitCommand command = new InitCommand();
+		command.setDirectory(directory);
+		MockSystemReader reader = (MockSystemReader) SystemReader.getInstance();
+		StoredConfig c = reader.getUserConfig();
+		String old = c.getString(ConfigConstants.CONFIG_INIT_SECTION, null,
+				ConfigConstants.CONFIG_KEY_DEFAULT_BRANCH);
+		c.setString(ConfigConstants.CONFIG_INIT_SECTION, null,
+				ConfigConstants.CONFIG_KEY_DEFAULT_BRANCH, "main");
+		try (Git git = command.call()) {
+			Repository r = git.getRepository();
+			assertNotNull(r);
+			assertEquals("refs/heads/main", r.getFullBranch());
+		} finally {
+			c.setString(ConfigConstants.CONFIG_INIT_SECTION, null,
+					ConfigConstants.CONFIG_KEY_DEFAULT_BRANCH, old);
+		}
+	}
+
+	@Test
+	public void testInitRepositoryNullInitialBranch() throws Exception {
+		File directory = createTempDirectory("testInitRepository");
+		InitCommand command = new InitCommand();
+		command.setDirectory(directory);
+		command.setInitialBranch("main");
+		command.setInitialBranch(null);
+		try (Git git = command.call()) {
+			Repository r = git.getRepository();
+			assertNotNull(r);
+			assertEquals("refs/heads/master", r.getFullBranch());
+		}
+	}
+
+	@Test
+	public void testInitRepositoryEmptyInitialBranch() throws Exception {
+		File directory = createTempDirectory("testInitRepository");
+		InitCommand command = new InitCommand();
+		command.setDirectory(directory);
+		command.setInitialBranch("main");
+		command.setInitialBranch("");
+		try (Git git = command.call()) {
+			Repository r = git.getRepository();
+			assertNotNull(r);
+			assertEquals("refs/heads/master", r.getFullBranch());
 		}
 	}
 
@@ -72,6 +141,23 @@
 			Repository repository = git.getRepository();
 			assertNotNull(repository);
 			assertTrue(repository.isBare());
+			assertEquals("refs/heads/master", repository.getFullBranch());
+		}
+	}
+
+	@Test
+	public void testInitBareRepositoryMainInitialBranch()
+			throws IOException, JGitInternalException, GitAPIException {
+		File directory = createTempDirectory("testInitBareRepository");
+		InitCommand command = new InitCommand();
+		command.setDirectory(directory);
+		command.setBare(true);
+		command.setInitialBranch("main");
+		try (Git git = command.call()) {
+			Repository repository = git.getRepository();
+			assertNotNull(repository);
+			assertTrue(repository.isBare());
+			assertEquals("refs/heads/main", repository.getFullBranch());
 		}
 	}
 
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/LogCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/LogCommandTest.java
index 6460c79..c563d5a 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/LogCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/LogCommandTest.java
@@ -232,6 +232,53 @@
 		assertFalse(i.hasNext());
 	}
 
+	/**
+	 * <pre>
+	 * A - B - C - M
+	 *      \     /
+	 *        -D(side)
+	 * </pre>
+	 */
+	@Test
+	public void addRangeWithMerge() throws Exception{
+		String fileA = "fileA";
+		String fileB = "fileB";
+		Git git = Git.wrap(db);
+
+		writeTrashFile(fileA, fileA);
+		git.add().addFilepattern(fileA).call();
+		git.commit().setMessage("commit a").call();
+
+		writeTrashFile(fileA, fileA);
+		git.add().addFilepattern(fileA).call();
+		RevCommit b = git.commit().setMessage("commit b").call();
+
+		writeTrashFile(fileA, fileA);
+		git.add().addFilepattern(fileA).call();
+		RevCommit c = git.commit().setMessage("commit c").call();
+
+		createBranch(b, "refs/heads/side");
+		checkoutBranch("refs/heads/side");
+
+		writeTrashFile(fileB, fileB);
+		git.add().addFilepattern(fileB).call();
+		RevCommit d = git.commit().setMessage("commit d").call();
+
+		checkoutBranch("refs/heads/master");
+		MergeResult m = git.merge().include(d.getId()).call();
+		assertEquals(MergeResult.MergeStatus.MERGED, m.getMergeStatus());
+
+		Iterator<RevCommit> rangeLog = git.log().addRange(b.getId(), m.getNewHead()).call().iterator();
+
+		RevCommit commit = rangeLog.next();
+		assertEquals(m.getNewHead(), commit.getId());
+		commit = rangeLog.next();
+		assertEquals(c.getId(), commit.getId());
+		commit = rangeLog.next();
+		assertEquals(d.getId(), commit.getId());
+		assertFalse(rangeLog.hasNext());
+	}
+
 	private void setCommitsAndMerge() throws Exception {
 		Git git = Git.wrap(db);
 		writeTrashFile("file1", "1\n2\n3\n4\n");
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcBasicPackingTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcBasicPackingTest.java
index d007dd4..42e4238 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcBasicPackingTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcBasicPackingTest.java
@@ -157,7 +157,7 @@
 				.create();
 		tr.update("refs/tags/t1", second);
 
-		Collection<PackFile> oldPacks = tr.getRepository().getObjectDatabase()
+		Collection<Pack> oldPacks = tr.getRepository().getObjectDatabase()
 				.getPacks();
 		assertEquals(0, oldPacks.size());
 		stats = gc.getStatistics();
@@ -171,7 +171,7 @@
 		stats = gc.getStatistics();
 		assertEquals(0, stats.numberOfLooseObjects);
 
-		List<PackFile> packs = new ArrayList<>(
+		List<Pack> packs = new ArrayList<>(
 				repo.getObjectDatabase().getPacks());
 		assertEquals(11, packs.get(0).getObjectCount());
 	}
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 bb8455f..5cac1e3 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
@@ -156,8 +156,8 @@
 		}
 	}
 
-	PackFile getSinglePack(FileRepository r) {
-		Collection<PackFile> packs = r.getObjectDatabase().getPacks();
+	Pack getSinglePack(FileRepository r) {
+		Collection<Pack> packs = r.getObjectDatabase().getPacks();
 		assertEquals(1, packs.size());
 		return packs.iterator().next();
 	}
@@ -206,11 +206,11 @@
 		SampleDataRepositoryTestCase.copyCGitTestPacks(repo);
 		ExecutorService executor = Executors.newSingleThreadExecutor();
 		final CountDownLatch latch = new CountDownLatch(1);
-		Future<Collection<PackFile>> result = executor.submit(() -> {
+		Future<Collection<Pack>> result = executor.submit(() -> {
 			long start = System.currentTimeMillis();
 			System.out.println("starting gc");
 			latch.countDown();
-			Collection<PackFile> r = gc.gc();
+			Collection<Pack> r = gc.gc();
 			System.out.println(
 					"gc took " + (System.currentTimeMillis() - start) + " ms");
 			return r;
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcKeepFilesTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcKeepFilesTest.java
index e155958..8472983 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcKeepFilesTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcKeepFilesTest.java
@@ -36,9 +36,9 @@
 		assertEquals(4, stats.numberOfPackedObjects);
 		assertEquals(1, stats.numberOfPackFiles);
 
-		Iterator<PackFile> packIt = repo.getObjectDatabase().getPacks()
+		Iterator<Pack> packIt = repo.getObjectDatabase().getPacks()
 				.iterator();
-		PackFile singlePack = packIt.next();
+		Pack singlePack = packIt.next();
 		assertFalse(packIt.hasNext());
 		String packFileName = singlePack.getPackFile().getPath();
 		String keepFileName = packFileName.substring(0,
@@ -58,7 +58,7 @@
 		assertEquals(2, stats.numberOfPackFiles);
 
 		// check that no object is packed twice
-		Iterator<PackFile> packs = repo.getObjectDatabase().getPacks()
+		Iterator<Pack> packs = repo.getObjectDatabase().getPacks()
 				.iterator();
 		PackIndex ind1 = packs.next().getIndex();
 		assertEquals(4, ind1.getObjectCount());
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackFileSnapshotTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackFileSnapshotTest.java
index 1f1e094..7c32ce7 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackFileSnapshotTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackFileSnapshotTest.java
@@ -72,14 +72,14 @@
 		c.setInt(ConfigConstants.CONFIG_GC_SECTION, null,
 				ConfigConstants.CONFIG_KEY_AUTOPACKLIMIT, 1);
 		c.save();
-		Collection<PackFile> packs = gc(Deflater.NO_COMPRESSION);
+		Collection<Pack> packs = gc(Deflater.NO_COMPRESSION);
 		assertEquals("expected 1 packfile after gc", 1, packs.size());
-		PackFile p1 = packs.iterator().next();
+		Pack p1 = packs.iterator().next();
 		PackFileSnapshot snapshot = p1.getFileSnapshot();
 
 		packs = gc(Deflater.BEST_COMPRESSION);
 		assertEquals("expected 1 packfile after gc", 1, packs.size());
-		PackFile p2 = packs.iterator().next();
+		Pack p2 = packs.iterator().next();
 		File pf = p2.getPackFile();
 
 		// changing compression level with aggressive gc may change size,
@@ -153,11 +153,11 @@
 		createTestRepo(testDataSeed, testDataLength);
 
 		// repack to create initial packfile
-		PackFile pf = repackAndCheck(5, null, null, null);
-		Path packFilePath = pf.getPackFile().toPath();
-		AnyObjectId chk1 = pf.getPackChecksum();
-		String name = pf.getPackName();
-		Long length = Long.valueOf(pf.getPackFile().length());
+		Pack p = repackAndCheck(5, null, null, null);
+		Path packFilePath = p.getPackFile().toPath();
+		AnyObjectId chk1 = p.getPackChecksum();
+		String name = p.getPackName();
+		Long length = Long.valueOf(p.getPackFile().length());
 		FS fs = db.getFS();
 		Instant m1 = fs.lastModifiedInstant(packFilePath);
 
@@ -207,16 +207,16 @@
 		createTestRepo(testDataSeed, testDataLength);
 
 		// Repack to create initial packfile. Make a copy of it
-		PackFile pf = repackAndCheck(5, null, null, null);
-		Path packFilePath = pf.getPackFile().toPath();
+		Pack p = repackAndCheck(5, null, null, null);
+		Path packFilePath = p.getPackFile().toPath();
 		Path fn = packFilePath.getFileName();
 		assertNotNull(fn);
 		String packFileName = fn.toString();
 		Path packFileBasePath = packFilePath
 				.resolveSibling(packFileName.replaceAll(".pack", ""));
-		AnyObjectId chk1 = pf.getPackChecksum();
-		String name = pf.getPackName();
-		Long length = Long.valueOf(pf.getPackFile().length());
+		AnyObjectId chk1 = p.getPackChecksum();
+		String name = p.getPackName();
+		Long length = Long.valueOf(p.getPackFile().length());
 		copyPack(packFileBasePath, "", ".copy1");
 
 		// Repack to create second packfile. Make a copy of it
@@ -280,10 +280,10 @@
 				Paths.get(base + ".pack" + dstSuffix));
 	}
 
-	private PackFile repackAndCheck(int compressionLevel, String oldName,
+	private Pack repackAndCheck(int compressionLevel, String oldName,
 			Long oldLength, AnyObjectId oldChkSum)
 			throws IOException, ParseException {
-		PackFile p = getSinglePack(gc(compressionLevel));
+		Pack p = getSinglePack(gc(compressionLevel));
 		File pf = p.getPackFile();
 		// The following two assumptions should not cause the test to fail. If
 		// on a certain platform we get packfiles (containing the same git
@@ -298,14 +298,14 @@
 		return p;
 	}
 
-	private PackFile getSinglePack(Collection<PackFile> packs) {
-		Iterator<PackFile> pIt = packs.iterator();
-		PackFile p = pIt.next();
+	private Pack getSinglePack(Collection<Pack> packs) {
+		Iterator<Pack> pIt = packs.iterator();
+		Pack p = pIt.next();
 		assertFalse(pIt.hasNext());
 		return p;
 	}
 
-	private Collection<PackFile> gc(int compressionLevel)
+	private Collection<Pack> gc(int compressionLevel)
 			throws IOException, ParseException {
 		GC gc = new GC(db);
 		PackConfig pc = new PackConfig(db.getConfig());
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackInserterTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackInserterTest.java
index 8c56480..8504303 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackInserterTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackInserterTest.java
@@ -160,7 +160,7 @@
 		}
 
 		assertPacksOnly();
-		List<PackFile> packs = listPacks();
+		List<Pack> packs = listPacks();
 		assertEquals(1, packs.size());
 		assertEquals(3, packs.get(0).getObjectCount());
 
@@ -193,7 +193,7 @@
 		}
 
 		assertPacksOnly();
-		List<PackFile> packs = listPacks();
+		List<Pack> packs = listPacks();
 		assertEquals(2, packs.size());
 		assertEquals(1, packs.get(0).getObjectCount());
 		assertEquals(1, packs.get(1).getObjectCount());
@@ -216,9 +216,9 @@
 		}
 
 		assertPacksOnly();
-		Collection<PackFile> packs = listPacks();
+		Collection<Pack> packs = listPacks();
 		assertEquals(1, packs.size());
-		PackFile p = packs.iterator().next();
+		Pack p = packs.iterator().next();
 		assertEquals(1, p.getObjectCount());
 
 		try (ObjectReader reader = db.newObjectReader()) {
@@ -237,9 +237,9 @@
 		}
 
 		assertPacksOnly();
-		List<PackFile> packs = listPacks();
+		List<Pack> packs = listPacks();
 		assertEquals(1, packs.size());
-		PackFile pack = packs.get(0);
+		Pack pack = packs.get(0);
 		assertEquals(1, pack.getObjectCount());
 
 		String inode = getInode(pack.getPackFile());
@@ -372,7 +372,7 @@
 		}
 
 		assertPacksOnly();
-		List<PackFile> packs = listPacks();
+		List<Pack> packs = listPacks();
 		assertEquals(1, packs.size());
 		assertEquals(2, packs.get(0).getObjectCount());
 
@@ -489,16 +489,16 @@
 		}
 	}
 
-	private List<PackFile> listPacks() throws Exception {
-		List<PackFile> fromOpenDb = listPacks(db);
-		List<PackFile> reopened;
+	private List<Pack> listPacks() throws Exception {
+		List<Pack> fromOpenDb = listPacks(db);
+		List<Pack> reopened;
 		try (FileRepository db2 = new FileRepository(db.getDirectory())) {
 			reopened = listPacks(db2);
 		}
 		assertEquals(fromOpenDb.size(), reopened.size());
 		for (int i = 0 ; i < fromOpenDb.size(); i++) {
-			PackFile a = fromOpenDb.get(i);
-			PackFile b = reopened.get(i);
+			Pack a = fromOpenDb.get(i);
+			Pack b = reopened.get(i);
 			assertEquals(a.getPackName(), b.getPackName());
 			assertEquals(
 					a.getPackFile().getAbsolutePath(), b.getPackFile().getAbsolutePath());
@@ -508,9 +508,9 @@
 		return fromOpenDb;
 	}
 
-	private static List<PackFile> listPacks(FileRepository db) throws Exception {
+	private static List<Pack> listPacks(FileRepository db) throws Exception {
 		return db.getObjectDatabase().getPacks().stream()
-				.sorted(comparing(PackFile::getPackName)).collect(toList());
+				.sorted(comparing(Pack::getPackName)).collect(toList());
 	}
 
 	private PackInserter newInserter() {
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackFileTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackTest.java
similarity index 94%
rename from org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackFileTest.java
rename to org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackTest.java
index 97a86e2..182e422 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackFileTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackTest.java
@@ -57,7 +57,7 @@
 import org.junit.Before;
 import org.junit.Test;
 
-public class PackFileTest extends LocalDiskRepositoryTestCase {
+public class PackTest extends LocalDiskRepositoryTestCase {
 	private int streamThreshold = 16 * 1024;
 
 	private TestRng rng;
@@ -228,21 +228,21 @@
 			PackedObjectInfo a = new PackedObjectInfo(idA);
 			PackedObjectInfo b = new PackedObjectInfo(idB);
 
-			TemporaryBuffer.Heap pack = new TemporaryBuffer.Heap(64 * 1024);
-			packHeader(pack, 2);
-			a.setOffset(pack.length());
-			objectHeader(pack, Constants.OBJ_BLOB, base.length);
-			deflate(pack, base);
+			TemporaryBuffer.Heap packContents = new TemporaryBuffer.Heap(64 * 1024);
+			packHeader(packContents, 2);
+			a.setOffset(packContents.length());
+			objectHeader(packContents, Constants.OBJ_BLOB, base.length);
+			deflate(packContents, base);
 
 			ByteArrayOutputStream tmp = new ByteArrayOutputStream();
 			DeltaEncoder de = new DeltaEncoder(tmp, base.length, 3L << 30);
 			de.copy(0, 1);
 			byte[] delta = tmp.toByteArray();
-			b.setOffset(pack.length());
-			objectHeader(pack, Constants.OBJ_REF_DELTA, delta.length);
-			idA.copyRawTo(pack);
-			deflate(pack, delta);
-			byte[] footer = digest(pack);
+			b.setOffset(packContents.length());
+			objectHeader(packContents, Constants.OBJ_REF_DELTA, delta.length);
+			idA.copyRawTo(packContents);
+			deflate(packContents, delta);
+			byte[] footer = digest(packContents);
 
 			File dir = new File(repo.getObjectDatabase().getDirectory(),
 					"pack");
@@ -250,7 +250,7 @@
 			File idxName = new File(dir, idA.name() + ".idx");
 
 			try (FileOutputStream f = new FileOutputStream(packName)) {
-				f.write(pack.toByteArray());
+				f.write(packContents.toByteArray());
 			}
 
 			try (FileOutputStream f = new FileOutputStream(idxName)) {
@@ -261,14 +261,14 @@
 				new PackIndexWriterV1(f).write(list, footer);
 			}
 
-			PackFile packFile = new PackFile(packName, PackExt.INDEX.getBit());
+			Pack pack = new Pack(packName, PackExt.INDEX.getBit());
 			try {
-				packFile.get(wc, b);
+				pack.get(wc, b);
 				fail("expected LargeObjectException.ExceedsByteArrayLimit");
 			} catch (LargeObjectException.ExceedsByteArrayLimit bad) {
 				assertNull(bad.getObjectId());
 			} finally {
-				packFile.close();
+				pack.close();
 			}
 		}
 	}
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 c90310e..214ddb9 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
@@ -72,7 +72,7 @@
 
 	private ByteArrayOutputStream os;
 
-	private PackFile pack;
+	private Pack pack;
 
 	private ObjectInserter inserter;
 
@@ -840,7 +840,7 @@
 		p.setAllowThin(thin);
 		p.setIndexVersion(2);
 		p.parse(NullProgressMonitor.INSTANCE);
-		pack = p.getPackFile();
+		pack = p.getPack();
 		assertNotNull("have PackFile after parsing", pack);
 	}
 
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/T0004_PackReaderTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/T0004_PackReaderTest.java
index ee4c9b1..8f1371e 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/T0004_PackReaderTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/T0004_PackReaderTest.java
@@ -32,8 +32,8 @@
 		final ObjectId id;
 		final ObjectLoader or;
 
-		PackFile pr = null;
-		for (PackFile p : db.getObjectDatabase().getPacks()) {
+		Pack pr = null;
+		for (Pack p : db.getObjectDatabase().getPacks()) {
 			if (PACK_NAME.equals(p.getPackName())) {
 				pr = p;
 				break;
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 56f881e..0d739b9 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
@@ -487,7 +487,7 @@
 	public void seekPastWithLotsOfRefs() throws IOException {
 		Ref[] refs = new Ref[500];
 		for (int i = 1; i <= 500; i++) {
-			refs[i - 1] = ref(String.format("refs/%d", i), i);
+			refs[i - 1] = ref(String.format("refs/%d", Integer.valueOf(i)), i);
 		}
 		ReftableReader t = read(write(refs));
 		try (RefCursor rc = t.allRefs()) {
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 e2ac89b..eecf25b 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
@@ -1384,6 +1384,270 @@
 		git.merge().include(commitB).call();
 	}
 
+	/**
+	 * Merging two commits with a file/dir conflict in the virtual ancestor.
+	 *
+	 * <p>
+	 * Those conflicts should be ignored, otherwise the found base can not be used by the
+	 * RecursiveMerger.
+	 * <pre>
+	 *  --------------
+	 * |              \
+	 * |         C1 - C4 --- ?     master
+	 * |        /          /
+	 * |  I - A1 - C2 - C3         second-branch
+	 * |   \            /
+	 * \    \          /
+	 *  ----A2--------             branch-to-merge
+	 *  </pre>
+	 * <p>
+	 * <p>
+	 * Path "a" is initially a file in I and A1. It is changed to a directory in A2
+	 * ("branch-to-merge").
+	 * <p>
+	 * A2 is merged into "master" and "second-branch". The dir/file merge conflict is resolved
+	 * manually, results in C4 and C3.
+	 * <p>
+	 * While merging C3 and C4, A1 and A2 are the base commits found by the recursive merge that
+	 * have the dir/file conflict.
+	 */
+	@Theory
+	public void checkFileDirMergeConflictInVirtualAncestor_NoConflictInChildren(
+			MergeStrategy strategy)
+			throws Exception {
+		if (!strategy.equals(MergeStrategy.RECURSIVE)) {
+			return;
+		}
+
+		Git git = Git.wrap(db);
+
+		// master
+		writeTrashFile("a", "initial content");
+		git.add().addFilepattern("a").call();
+		RevCommit commitI = git.commit().setMessage("Initial commit").call();
+
+		writeTrashFile("a", "content in Ancestor 1");
+		git.add().addFilepattern("a").call();
+		RevCommit commitA1 = git.commit().setMessage("Ancestor 1").call();
+
+		writeTrashFile("a", "content in Child 1 (commited on master)");
+		git.add().addFilepattern("a").call();
+		// commit C1M
+		git.commit().setMessage("Child 1 on master").call();
+
+		git.checkout().setCreateBranch(true).setStartPoint(commitI).setName("branch-to-merge").call();
+		// "a" becomes a directory in A2
+		git.rm().addFilepattern("a").call();
+		writeTrashFile("a/content", "content in Ancestor 2 (commited on branch-to-merge)");
+		git.add().addFilepattern("a/content").call();
+		RevCommit commitA2 = git.commit().setMessage("Ancestor 2").call();
+
+		// second branch
+		git.checkout().setCreateBranch(true).setStartPoint(commitA1).setName("second-branch").call();
+		writeTrashFile("a", "content in Child 2 (commited on second-branch)");
+		git.add().addFilepattern("a").call();
+		// commit C2S
+		git.commit().setMessage("Child 2 on second-branch").call();
+
+		// Merge branch-to-merge into second-branch
+		MergeResult mergeResult = git.merge().include(commitA2).setStrategy(strategy).call();
+		assertEquals(mergeResult.getNewHead(), null);
+		assertEquals(mergeResult.getMergeStatus(), MergeStatus.CONFLICTING);
+		// Resolve the conflict manually, merge "a" as a file
+		git.rm().addFilepattern("a").call();
+		git.rm().addFilepattern("a/content").call();
+		writeTrashFile("a", "merge conflict resolution");
+		git.add().addFilepattern("a").call();
+		RevCommit commitC3S = git.commit().setMessage("Child 3 on second bug - resolve merge conflict")
+				.call();
+
+		// Merge branch-to-merge into master
+		git.checkout().setName("master").call();
+		mergeResult = git.merge().include(commitA2).setStrategy(strategy).call();
+		assertEquals(mergeResult.getNewHead(), null);
+		assertEquals(mergeResult.getMergeStatus(), MergeStatus.CONFLICTING);
+
+		// Resolve the conflict manually - merge "a" as a file
+		git.rm().addFilepattern("a").call();
+		git.rm().addFilepattern("a/content").call();
+		writeTrashFile("a", "merge conflict resolution");
+		git.add().addFilepattern("a").call();
+		// commit C4M
+		git.commit().setMessage("Child 4 on master - resolve merge conflict").call();
+
+		// Merge C4M (second-branch) into master (C3S)
+		// Conflict in virtual base should be here, but there are no conflicts in
+		// children
+		mergeResult = git.merge().include(commitC3S).call();
+		assertEquals(mergeResult.getMergeStatus(), MergeStatus.MERGED);
+
+	}
+
+	@Theory
+	public void checkFileDirMergeConflictInVirtualAncestor_ConflictInChildren_FileDir(MergeStrategy strategy)
+			throws Exception {
+		if (!strategy.equals(MergeStrategy.RECURSIVE)) {
+			return;
+		}
+
+		Git git = Git.wrap(db);
+
+		// master
+		writeTrashFile("a", "initial content");
+		git.add().addFilepattern("a").call();
+		RevCommit commitI = git.commit().setMessage("Initial commit").call();
+
+		writeTrashFile("a", "content in Ancestor 1");
+		git.add().addFilepattern("a").call();
+		RevCommit commitA1 = git.commit().setMessage("Ancestor 1").call();
+
+		writeTrashFile("a", "content in Child 1 (commited on master)");
+		git.add().addFilepattern("a").call();
+		// commit C1M
+		git.commit().setMessage("Child 1 on master").call();
+
+		git.checkout().setCreateBranch(true).setStartPoint(commitI).setName("branch-to-merge").call();
+
+		// "a" becomes a directory in A2
+		git.rm().addFilepattern("a").call();
+		writeTrashFile("a/content", "content in Ancestor 2 (commited on branch-to-merge)");
+		git.add().addFilepattern("a/content").call();
+		RevCommit commitA2 = git.commit().setMessage("Ancestor 2").call();
+
+		// second branch
+		git.checkout().setCreateBranch(true).setStartPoint(commitA1).setName("second-branch").call();
+		writeTrashFile("a", "content in Child 2 (commited on second-branch)");
+		git.add().addFilepattern("a").call();
+		// commit C2S
+		git.commit().setMessage("Child 2 on second-branch").call();
+
+		// Merge branch-to-merge into second-branch
+		MergeResult mergeResult = git.merge().include(commitA2).setStrategy(strategy).call();
+		assertEquals(mergeResult.getNewHead(), null);
+		assertEquals(mergeResult.getMergeStatus(), MergeStatus.CONFLICTING);
+		// Resolve the conflict manually - write a file
+		git.rm().addFilepattern("a").call();
+		git.rm().addFilepattern("a/content").call();
+		writeTrashFile("a",
+				"content in Child 3 (commited on second-branch) - merge conflict resolution");
+		git.add().addFilepattern("a").call();
+		RevCommit commitC3S = git.commit().setMessage("Child 3 on second bug - resolve merge conflict")
+				.call();
+
+		// Merge branch-to-merge into master
+		git.checkout().setName("master").call();
+		mergeResult = git.merge().include(commitA2).setStrategy(strategy).call();
+		assertEquals(mergeResult.getNewHead(), null);
+		assertEquals(mergeResult.getMergeStatus(), MergeStatus.CONFLICTING);
+
+		// Resolve the conflict manually - write a file
+		git.rm().addFilepattern("a").call();
+		git.rm().addFilepattern("a/content").call();
+		writeTrashFile("a", "content in Child 4 (commited on master) - merge conflict resolution");
+		git.add().addFilepattern("a").call();
+		// commit C4M
+		git.commit().setMessage("Child 4 on master - resolve merge conflict").call();
+
+		// Merge C4M (second-branch) into master (C3S)
+		// Conflict in virtual base should be here
+		mergeResult = git.merge().include(commitC3S).call();
+		assertEquals(mergeResult.getMergeStatus(), MergeStatus.CONFLICTING);
+		String expected =
+				"<<<<<<< HEAD\n" + "content in Child 4 (commited on master) - merge conflict resolution\n"
+						+ "=======\n"
+						+ "content in Child 3 (commited on second-branch) - merge conflict resolution\n"
+						+ ">>>>>>> " + commitC3S.name() + "\n";
+		assertEquals(expected, read("a"));
+		// Nothing was populated from the ancestors.
+		assertEquals(
+				"[a, mode:100644, stage:2, content:content in Child 4 (commited on master) - merge conflict resolution][a, mode:100644, stage:3, content:content in Child 3 (commited on second-branch) - merge conflict resolution]",
+				indexState(CONTENT));
+	}
+
+	/**
+	 * Same test as above, but "a" is a dir in A1 and a file in A2
+	 */
+	@Theory
+	public void checkFileDirMergeConflictInVirtualAncestor_ConflictInChildren_DirFile(MergeStrategy strategy)
+			throws Exception {
+		if (!strategy.equals(MergeStrategy.RECURSIVE)) {
+			return;
+		}
+
+		Git git = Git.wrap(db);
+
+		// master
+		writeTrashFile("a/content", "initial content");
+		git.add().addFilepattern("a/content").call();
+		RevCommit commitI = git.commit().setMessage("Initial commit").call();
+
+		writeTrashFile("a/content", "content in Ancestor 1");
+		git.add().addFilepattern("a/content").call();
+		RevCommit commitA1 = git.commit().setMessage("Ancestor 1").call();
+
+		writeTrashFile("a/content", "content in Child 1 (commited on master)");
+		git.add().addFilepattern("a/content").call();
+		// commit C1M
+		git.commit().setMessage("Child 1 on master").call();
+
+		git.checkout().setCreateBranch(true).setStartPoint(commitI).setName("branch-to-merge").call();
+
+		// "a" becomes a file in A2
+		git.rm().addFilepattern("a/content").call();
+		writeTrashFile("a", "content in Ancestor 2 (commited on branch-to-merge)");
+		git.add().addFilepattern("a").call();
+		RevCommit commitA2 = git.commit().setMessage("Ancestor 2").call();
+
+		// second branch
+		git.checkout().setCreateBranch(true).setStartPoint(commitA1).setName("second-branch").call();
+		writeTrashFile("a/content", "content in Child 2 (commited on second-branch)");
+		git.add().addFilepattern("a/content").call();
+		// commit C2S
+		git.commit().setMessage("Child 2 on second-branch").call();
+
+		// Merge branch-to-merge into second-branch
+		MergeResult mergeResult = git.merge().include(commitA2).setStrategy(strategy).call();
+		assertEquals(mergeResult.getNewHead(), null);
+		assertEquals(mergeResult.getMergeStatus(), MergeStatus.CONFLICTING);
+		// Resolve the conflict manually - write a file
+		git.rm().addFilepattern("a").call();
+		git.rm().addFilepattern("a/content").call();
+		deleteTrashFile("a/content");
+		deleteTrashFile("a");
+		writeTrashFile("a", "content in Child 3 (commited on second-branch) - merge conflict resolution");
+		git.add().addFilepattern("a").call();
+		RevCommit commitC3S = git.commit().setMessage("Child 3 on second bug - resolve merge conflict").call();
+
+		// Merge branch-to-merge into master
+		git.checkout().setName("master").call();
+		mergeResult = git.merge().include(commitA2).setStrategy(strategy).call();
+		assertEquals(mergeResult.getNewHead(), null);
+		assertEquals(mergeResult.getMergeStatus(), MergeStatus.CONFLICTING);
+
+		// Resolve the conflict manually - write a file
+		git.rm().addFilepattern("a").call();
+		git.rm().addFilepattern("a/content").call();
+		deleteTrashFile("a/content");
+		deleteTrashFile("a");
+		writeTrashFile("a", "content in Child 4 (commited on master) - merge conflict resolution");
+		git.add().addFilepattern("a").call();
+		// commit C4M
+		git.commit().setMessage("Child 4 on master - resolve merge conflict").call();
+
+		// Merge C4M (second-branch) into master (C3S)
+		// Conflict in virtual base should be here
+		mergeResult = git.merge().include(commitC3S).call();
+		assertEquals(mergeResult.getMergeStatus(), MergeStatus.CONFLICTING);
+		String expected = "<<<<<<< HEAD\n" + "content in Child 4 (commited on master) - merge conflict resolution\n"
+				+ "=======\n" + "content in Child 3 (commited on second-branch) - merge conflict resolution\n"
+				+ ">>>>>>> " + commitC3S.name() + "\n";
+		assertEquals(expected, read("a"));
+		// Nothing was populated from the ancestors.
+		assertEquals(
+				"[a, mode:100644, stage:2, content:content in Child 4 (commited on master) - merge conflict resolution][a, mode:100644, stage:3, content:content in Child 3 (commited on second-branch) - merge conflict resolution]",
+				indexState(CONTENT));
+	}
+
 	private void writeSubmodule(String path, ObjectId commit)
 			throws IOException, ConfigInvalidException {
 		addSubmoduleToIndex(path, commit);
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/DateRevQueueTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/DateRevQueueTest.java
index a9dfe15..852d18c 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/DateRevQueueTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/DateRevQueueTest.java
@@ -59,20 +59,26 @@
 	public void testInsertTie() throws Exception {
 		final RevCommit a = parseBody(commit());
 		final RevCommit b = parseBody(commit(0, a));
+		final RevCommit c = parseBody(commit(0, b));
+
 		{
 			q = create();
 			q.add(a);
 			q.add(b);
+			q.add(c);
 
 			assertCommit(a, q.next());
 			assertCommit(b, q.next());
+			assertCommit(c, q.next());
 			assertNull(q.next());
 		}
 		{
 			q = create();
+			q.add(c);
 			q.add(b);
 			q.add(a);
 
+			assertCommit(c, q.next());
 			assertCommit(b, q.next());
 			assertCommit(a, q.next());
 			assertNull(q.next());
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 07c236d..60b8098 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
@@ -29,7 +29,7 @@
 import org.eclipse.jgit.errors.TooLargeObjectInPackException;
 import org.eclipse.jgit.internal.JGitText;
 import org.eclipse.jgit.internal.storage.file.ObjectDirectoryPackParser;
-import org.eclipse.jgit.internal.storage.file.PackFile;
+import org.eclipse.jgit.internal.storage.file.Pack;
 import org.eclipse.jgit.junit.JGitTestUtil;
 import org.eclipse.jgit.junit.RepositoryTestCase;
 import org.eclipse.jgit.junit.TestRepository;
@@ -63,16 +63,16 @@
 		try (InputStream is = new FileInputStream(packFile)) {
 			ObjectDirectoryPackParser p = (ObjectDirectoryPackParser) index(is);
 			p.parse(NullProgressMonitor.INSTANCE);
-			PackFile file = p.getPackFile();
+			Pack pack = p.getPack();
 
-			assertTrue(file.hasObject(ObjectId.fromString("4b825dc642cb6eb9a060e54bf8d69288fbee4904")));
-			assertTrue(file.hasObject(ObjectId.fromString("540a36d136cf413e4b064c2b0e0a4db60f77feab")));
-			assertTrue(file.hasObject(ObjectId.fromString("5b6e7c66c276e7610d4a73c70ec1a1f7c1003259")));
-			assertTrue(file.hasObject(ObjectId.fromString("6ff87c4664981e4397625791c8ea3bbb5f2279a3")));
-			assertTrue(file.hasObject(ObjectId.fromString("82c6b885ff600be425b4ea96dee75dca255b69e7")));
-			assertTrue(file.hasObject(ObjectId.fromString("902d5476fa249b7abc9d84c611577a81381f0327")));
-			assertTrue(file.hasObject(ObjectId.fromString("aabf2ffaec9b497f0950352b3e582d73035c2035")));
-			assertTrue(file.hasObject(ObjectId.fromString("c59759f143fb1fe21c197981df75a7ee00290799")));
+			assertTrue(pack.hasObject(ObjectId.fromString("4b825dc642cb6eb9a060e54bf8d69288fbee4904")));
+			assertTrue(pack.hasObject(ObjectId.fromString("540a36d136cf413e4b064c2b0e0a4db60f77feab")));
+			assertTrue(pack.hasObject(ObjectId.fromString("5b6e7c66c276e7610d4a73c70ec1a1f7c1003259")));
+			assertTrue(pack.hasObject(ObjectId.fromString("6ff87c4664981e4397625791c8ea3bbb5f2279a3")));
+			assertTrue(pack.hasObject(ObjectId.fromString("82c6b885ff600be425b4ea96dee75dca255b69e7")));
+			assertTrue(pack.hasObject(ObjectId.fromString("902d5476fa249b7abc9d84c611577a81381f0327")));
+			assertTrue(pack.hasObject(ObjectId.fromString("aabf2ffaec9b497f0950352b3e582d73035c2035")));
+			assertTrue(pack.hasObject(ObjectId.fromString("c59759f143fb1fe21c197981df75a7ee00290799")));
 		}
 	}
 
@@ -88,20 +88,20 @@
 		try (InputStream is = new FileInputStream(packFile)) {
 			ObjectDirectoryPackParser p = (ObjectDirectoryPackParser) index(is);
 			p.parse(NullProgressMonitor.INSTANCE);
-			PackFile file = p.getPackFile();
+			Pack pack = p.getPack();
 
-			assertTrue(file.hasObject(ObjectId.fromString("02ba32d3649e510002c21651936b7077aa75ffa9")));
-			assertTrue(file.hasObject(ObjectId.fromString("0966a434eb1a025db6b71485ab63a3bfbea520b6")));
-			assertTrue(file.hasObject(ObjectId.fromString("09efc7e59a839528ac7bda9fa020dc9101278680")));
-			assertTrue(file.hasObject(ObjectId.fromString("0a3d7772488b6b106fb62813c4d6d627918d9181")));
-			assertTrue(file.hasObject(ObjectId.fromString("1004d0d7ac26fbf63050a234c9b88a46075719d3")));
-			assertTrue(file.hasObject(ObjectId.fromString("10da5895682013006950e7da534b705252b03be6")));
-			assertTrue(file.hasObject(ObjectId.fromString("1203b03dc816ccbb67773f28b3c19318654b0bc8")));
-			assertTrue(file.hasObject(ObjectId.fromString("15fae9e651043de0fd1deef588aa3fbf5a7a41c6")));
-			assertTrue(file.hasObject(ObjectId.fromString("16f9ec009e5568c435f473ba3a1df732d49ce8c3")));
-			assertTrue(file.hasObject(ObjectId.fromString("1fd7d579fb6ae3fe942dc09c2c783443d04cf21e")));
-			assertTrue(file.hasObject(ObjectId.fromString("20a8ade77639491ea0bd667bf95de8abf3a434c8")));
-			assertTrue(file.hasObject(ObjectId.fromString("2675188fd86978d5bc4d7211698b2118ae3bf658")));
+			assertTrue(pack.hasObject(ObjectId.fromString("02ba32d3649e510002c21651936b7077aa75ffa9")));
+			assertTrue(pack.hasObject(ObjectId.fromString("0966a434eb1a025db6b71485ab63a3bfbea520b6")));
+			assertTrue(pack.hasObject(ObjectId.fromString("09efc7e59a839528ac7bda9fa020dc9101278680")));
+			assertTrue(pack.hasObject(ObjectId.fromString("0a3d7772488b6b106fb62813c4d6d627918d9181")));
+			assertTrue(pack.hasObject(ObjectId.fromString("1004d0d7ac26fbf63050a234c9b88a46075719d3")));
+			assertTrue(pack.hasObject(ObjectId.fromString("10da5895682013006950e7da534b705252b03be6")));
+			assertTrue(pack.hasObject(ObjectId.fromString("1203b03dc816ccbb67773f28b3c19318654b0bc8")));
+			assertTrue(pack.hasObject(ObjectId.fromString("15fae9e651043de0fd1deef588aa3fbf5a7a41c6")));
+			assertTrue(pack.hasObject(ObjectId.fromString("16f9ec009e5568c435f473ba3a1df732d49ce8c3")));
+			assertTrue(pack.hasObject(ObjectId.fromString("1fd7d579fb6ae3fe942dc09c2c783443d04cf21e")));
+			assertTrue(pack.hasObject(ObjectId.fromString("20a8ade77639491ea0bd667bf95de8abf3a434c8")));
+			assertTrue(pack.hasObject(ObjectId.fromString("2675188fd86978d5bc4d7211698b2118ae3bf658")));
 			// and lots more...
 		}
 	}
diff --git a/org.eclipse.jgit/.settings/.api_filters b/org.eclipse.jgit/.settings/.api_filters
index b74e703..d389ac5 100644
--- a/org.eclipse.jgit/.settings/.api_filters
+++ b/org.eclipse.jgit/.settings/.api_filters
@@ -24,4 +24,34 @@
             </message_arguments>
         </filter>
     </resource>
+    <resource path="src/org/eclipse/jgit/util/FS.java" type="org.eclipse.jgit.util.FS">
+        <filter id="338792546">
+            <message_arguments>
+                <message_argument value="org.eclipse.jgit.util.FS"/>
+                <message_argument value="internalRunHookIfPresent(Repository, String, String[], PrintStream, PrintStream, String)"/>
+            </message_arguments>
+        </filter>
+        <filter id="338792546">
+            <message_arguments>
+                <message_argument value="org.eclipse.jgit.util.FS"/>
+                <message_argument value="runHookIfPresent(Repository, String, String[], PrintStream, PrintStream, String)"/>
+            </message_arguments>
+        </filter>
+    </resource>
+    <resource path="src/org/eclipse/jgit/util/FS_POSIX.java" type="org.eclipse.jgit.util.FS_POSIX">
+        <filter id="338792546">
+            <message_arguments>
+                <message_argument value="org.eclipse.jgit.util.FS_POSIX"/>
+                <message_argument value="runHookIfPresent(Repository, String, String[], PrintStream, PrintStream, String)"/>
+            </message_arguments>
+        </filter>
+    </resource>
+    <resource path="src/org/eclipse/jgit/util/FS_Win32_Cygwin.java" type="org.eclipse.jgit.util.FS_Win32_Cygwin">
+        <filter id="338792546">
+            <message_arguments>
+                <message_argument value="org.eclipse.jgit.util.FS_Win32_Cygwin"/>
+                <message_argument value="runHookIfPresent(Repository, String, String[], PrintStream, PrintStream, String)"/>
+            </message_arguments>
+        </filter>
+    </resource>
 </component>
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 a8b2e56..c00203d 100644
--- a/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties
+++ b/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties
@@ -30,6 +30,8 @@
 badEntryName=Bad entry name: {0}
 badEscape=Bad escape: {0}
 badGroupHeader=Bad group header
+badIgnorePattern=Cannot parse .gitignore pattern ''{0}''
+badIgnorePatternFull=File {0} line {1}: cannot parse pattern ''{2}'': {3}
 badObjectType=Bad object type: {0}
 badRef=Bad ref: {0}: {1}
 badSectionEntry=Bad section entry: {0}
@@ -568,6 +570,7 @@
 reftableDirExists=reftable dir exists and is nonempty
 reftableRecordsMustIncrease=records must be increasing: last {0}, this {1}
 refUpdateReturnCodeWas=RefUpdate return code was: {0}
+remoteBranchNotFound=Remote branch ''{0}'' not found in upstream origin
 remoteConfigHasNoURIAssociated=Remote config "{0}" has no URIs associated
 remoteDoesNotHaveSpec=Remote does not have {0} available for fetch.
 remoteDoesNotSupportSmartHTTPPush=remote does not support smart HTTP push
@@ -622,6 +625,8 @@
 shortReadOfBlock=Short read of block.
 shortReadOfOptionalDIRCExtensionExpectedAnotherBytes=Short read of optional DIRC extension {0}; expected another {1} bytes within the section.
 shortSkipOfBlock=Short skip of block.
+signatureVerificationError=Signature verification failed
+signatureVerificationUnavailable=No signature verifier registered
 signedTagMessageNoLf=A non-empty message of a signed tag must end in LF.
 signingServiceUnavailable=Signing service is not available
 similarityScoreMustBeWithinBounds=Similarity score must be between 0 and 100.
@@ -763,6 +768,13 @@
 URINotSupported=URI not supported: {0}
 userConfigInvalid=Git config in the user's home directory {0} is invalid {1}
 validatingGitModules=Validating .gitmodules files
+verifySignatureBad=BAD signature from "{0}"
+verifySignatureExpired=Expired signature from "{0}"
+verifySignatureGood=Good signature from "{0}"
+verifySignatureIssuer=issuer "{0}"
+verifySignatureKey=using key {0}
+verifySignatureMade=Signature made {0}
+verifySignatureTrust=[{0}]
 walkFailure=Walk failure.
 wantNoSpaceWithCapabilities=No space between oid and first capability in first want line
 wantNotValid=want {0} not valid
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 aba86fc..cf7bc1f 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/CloneCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/CloneCommand.java
@@ -297,6 +297,7 @@
 			command.setTagOpt(
 					fetchAll ? TagOpt.FETCH_TAGS : TagOpt.AUTO_FOLLOW);
 		}
+		command.setInitialBranch(branch);
 		configure(command);
 
 		return command.call();
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 b4f7175..31f6a31 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/CommitCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/CommitCommand.java
@@ -47,6 +47,7 @@
 import org.eclipse.jgit.lib.FileMode;
 import org.eclipse.jgit.lib.GpgConfig;
 import org.eclipse.jgit.lib.GpgConfig.GpgFormat;
+import org.eclipse.jgit.lib.GpgObjectSigner;
 import org.eclipse.jgit.lib.GpgSigner;
 import org.eclipse.jgit.lib.ObjectId;
 import org.eclipse.jgit.lib.ObjectInserter;
@@ -120,6 +121,8 @@
 
 	private GpgSigner gpgSigner;
 
+	private GpgConfig gpgConfig;
+
 	private CredentialsProvider credentialsProvider;
 
 	/**
@@ -247,8 +250,18 @@
 						throw new ServiceUnavailableException(
 								JGitText.get().signingServiceUnavailable);
 					}
-					gpgSigner.sign(commit, signingKey, committer,
-							credentialsProvider);
+					if (gpgSigner instanceof GpgObjectSigner) {
+						((GpgObjectSigner) gpgSigner).signObject(commit,
+								signingKey, committer, credentialsProvider,
+								gpgConfig);
+					} else {
+						if (gpgConfig.getKeyFormat() != GpgFormat.OPENPGP) {
+							throw new UnsupportedSigningFormatException(JGitText
+									.get().onlyOpenPgpSupportedForSigning);
+						}
+						gpgSigner.sign(commit, signingKey, committer,
+								credentialsProvider);
+					}
 				}
 
 				ObjectId commitId = odi.insert(commit);
@@ -576,7 +589,9 @@
 			// an explicit message
 			throw new NoMessageException(JGitText.get().commitMessageNotSpecified);
 
-		GpgConfig gpgConfig = new GpgConfig(repo.getConfig());
+		if (gpgConfig == null) {
+			gpgConfig = new GpgConfig(repo.getConfig());
+		}
 		if (signCommit == null) {
 			signCommit = gpgConfig.isSignCommits() ? Boolean.TRUE
 					: Boolean.FALSE;
@@ -585,10 +600,6 @@
 			signingKey = gpgConfig.getSigningKey();
 		}
 		if (gpgSigner == null) {
-			if (gpgConfig.getKeyFormat() != GpgFormat.OPENPGP) {
-				throw new UnsupportedSigningFormatException(
-						JGitText.get().onlyOpenPgpSupportedForSigning);
-			}
 			gpgSigner = GpgSigner.getDefault();
 		}
 	}
@@ -973,6 +984,36 @@
 	}
 
 	/**
+	 * Sets the {@link GpgSigner} to use if the commit is to be signed.
+	 *
+	 * @param signer
+	 *            to use; if {@code null}, the default signer will be used
+	 * @return {@code this}
+	 * @since 5.11
+	 */
+	public CommitCommand setGpgSigner(GpgSigner signer) {
+		checkCallable();
+		this.gpgSigner = signer;
+		return this;
+	}
+
+	/**
+	 * Sets an external {@link GpgConfig} to use. Whether it will be used is at
+	 * the discretion of the {@link #setGpgSigner(GpgSigner)}.
+	 *
+	 * @param config
+	 *            to set; if {@code null}, the config will be loaded from the
+	 *            git config of the repository
+	 * @return {@code this}
+	 * @since 5.11
+	 */
+	public CommitCommand setGpgConfig(GpgConfig config) {
+		checkCallable();
+		this.gpgConfig = config;
+		return this;
+	}
+
+	/**
 	 * Sets a {@link CredentialsProvider}
 	 *
 	 * @param 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 033dd60..90c1515 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/FetchCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/FetchCommand.java
@@ -74,6 +74,8 @@
 
 	private boolean isForceUpdate;
 
+	private String initialBranch;
+
 	/**
 	 * Callback for status of fetch operation.
 	 *
@@ -209,7 +211,7 @@
 			transport.setFetchThin(thin);
 			configure(transport);
 			FetchResult result = transport.fetch(monitor,
-					applyOptions(refSpecs));
+					applyOptions(refSpecs), initialBranch);
 			if (!repo.isBare()) {
 				fetchSubmodules(result);
 			}
@@ -488,6 +490,24 @@
 	}
 
 	/**
+	 * Set the initial branch
+	 *
+	 * @param branch
+	 *            the initial branch to check out when cloning the repository.
+	 *            Can be specified as ref name (<code>refs/heads/master</code>),
+	 *            branch name (<code>master</code>) or tag name
+	 *            (<code>v1.2.3</code>). The default is to use the branch
+	 *            pointed to by the cloned repository's HEAD and can be
+	 *            requested by passing {@code null} or <code>HEAD</code>.
+	 * @return {@code this}
+	 * @since 5.11
+	 */
+	public FetchCommand setInitialBranch(String branch) {
+		this.initialBranch = branch;
+		return this;
+	}
+
+	/**
 	 * Register a progress callback.
 	 *
 	 * @param callback
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/Git.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/Git.java
index 6431477..3b3e10e 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/Git.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/Git.java
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2010, Christian Halstrick <christian.halstrick@sap.com>
- * Copyright (C) 2010, Chris Aniszczyk <caniszczyk@gmail.com> and others
+ * Copyright (C) 2010, 2021 Chris Aniszczyk <caniszczyk@gmail.com> and others
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Distribution License v. 1.0 which is available at
@@ -773,6 +773,16 @@
 	}
 
 	/**
+	 * Return a command to verify signatures of tags or commits.
+	 *
+	 * @return a {@link VerifySignatureCommand}
+	 * @since 5.11
+	 */
+	public VerifySignatureCommand verifySignature() {
+		return new VerifySignatureCommand(repo);
+	}
+
+	/**
 	 * Get repository
 	 *
 	 * @return the git repository this class is interacting with; see
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/InitCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/InitCommand.java
index 41fcf29..240290f 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/InitCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/InitCommand.java
@@ -15,12 +15,16 @@
 import java.util.concurrent.Callable;
 
 import org.eclipse.jgit.api.errors.GitAPIException;
+import org.eclipse.jgit.api.errors.InvalidRefNameException;
 import org.eclipse.jgit.api.errors.JGitInternalException;
+import org.eclipse.jgit.errors.ConfigInvalidException;
 import org.eclipse.jgit.internal.JGitText;
+import org.eclipse.jgit.lib.ConfigConstants;
 import org.eclipse.jgit.lib.Constants;
 import org.eclipse.jgit.lib.Repository;
 import org.eclipse.jgit.lib.RepositoryBuilder;
 import org.eclipse.jgit.util.FS;
+import org.eclipse.jgit.util.StringUtils;
 import org.eclipse.jgit.util.SystemReader;
 
 /**
@@ -38,6 +42,8 @@
 
 	private FS fs;
 
+	private String initialBranch;
+
 	/**
 	 * {@inheritDoc}
 	 * <p>
@@ -87,11 +93,16 @@
 					builder.setWorkTree(new File(dStr));
 				}
 			}
+			builder.setInitialBranch(StringUtils.isEmptyOrNull(initialBranch)
+					? SystemReader.getInstance().getUserConfig().getString(
+							ConfigConstants.CONFIG_INIT_SECTION, null,
+							ConfigConstants.CONFIG_KEY_DEFAULT_BRANCH)
+					: initialBranch);
 			Repository repository = builder.build();
 			if (!repository.getObjectDatabase().exists())
 				repository.create(bare);
 			return new Git(repository, true);
-		} catch (IOException e) {
+		} catch (IOException | ConfigInvalidException e) {
 			throw new JGitInternalException(e.getMessage(), e);
 		}
 	}
@@ -184,4 +195,23 @@
 		this.fs = fs;
 		return this;
 	}
+
+	/**
+	 * Set the initial branch of the new repository. If not specified
+	 * ({@code null} or empty), fall back to the default name (currently
+	 * master).
+	 *
+	 * @param branch
+	 *            initial branch name of the new repository
+	 * @return {@code this}
+	 * @throws InvalidRefNameException
+	 *             if the branch name is not valid
+	 *
+	 * @since 5.11
+	 */
+	public InitCommand setInitialBranch(String branch)
+			throws InvalidRefNameException {
+		this.initialBranch = branch;
+		return this;
+	}
 }
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 6678af1..836175d 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/RebaseCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/RebaseCommand.java
@@ -67,6 +67,7 @@
 import org.eclipse.jgit.lib.Repository;
 import org.eclipse.jgit.merge.MergeStrategy;
 import org.eclipse.jgit.revwalk.RevCommit;
+import org.eclipse.jgit.revwalk.RevSort;
 import org.eclipse.jgit.revwalk.RevWalk;
 import org.eclipse.jgit.revwalk.filter.RevFilter;
 import org.eclipse.jgit.submodule.SubmoduleWalk.IgnoreSubmoduleMode;
@@ -1137,15 +1138,19 @@
 
 	private List<RevCommit> calculatePickList(RevCommit headCommit)
 			throws GitAPIException, NoHeadException, IOException {
-		Iterable<RevCommit> commitsToUse;
-		try (Git git = new Git(repo)) {
-			LogCommand cmd = git.log().addRange(upstreamCommit, headCommit);
-			commitsToUse = cmd.call();
-		}
 		List<RevCommit> cherryPickList = new ArrayList<>();
-		for (RevCommit commit : commitsToUse) {
-			if (preserveMerges || commit.getParentCount() == 1)
-				cherryPickList.add(commit);
+		try (RevWalk r = new RevWalk(repo)) {
+			r.sort(RevSort.TOPO_KEEP_BRANCH_TOGETHER, true);
+			r.sort(RevSort.COMMIT_TIME_DESC, true);
+			r.markUninteresting(r.lookupCommit(upstreamCommit));
+			r.markStart(r.lookupCommit(headCommit));
+			Iterator<RevCommit> commitsToUse = r.iterator();
+			while (commitsToUse.hasNext()) {
+				RevCommit commit = commitsToUse.next();
+				if (preserveMerges || commit.getParentCount() == 1) {
+					cherryPickList.add(commit);
+				}
+			}
 		}
 		Collections.reverse(cherryPickList);
 
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/TagCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/TagCommand.java
index 75f942d..58c18b3 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/TagCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/TagCommand.java
@@ -23,6 +23,7 @@
 import org.eclipse.jgit.internal.JGitText;
 import org.eclipse.jgit.lib.Constants;
 import org.eclipse.jgit.lib.GpgConfig;
+import org.eclipse.jgit.lib.GpgConfig.GpgFormat;
 import org.eclipse.jgit.lib.GpgObjectSigner;
 import org.eclipse.jgit.lib.GpgSigner;
 import org.eclipse.jgit.lib.ObjectId;
@@ -34,7 +35,6 @@
 import org.eclipse.jgit.lib.Repository;
 import org.eclipse.jgit.lib.RepositoryState;
 import org.eclipse.jgit.lib.TagBuilder;
-import org.eclipse.jgit.lib.GpgConfig.GpgFormat;
 import org.eclipse.jgit.revwalk.RevObject;
 import org.eclipse.jgit.revwalk.RevWalk;
 import org.eclipse.jgit.transport.CredentialsProvider;
@@ -80,6 +80,8 @@
 
 	private String signingKey;
 
+	private GpgConfig gpgConfig;
+
 	private GpgObjectSigner gpgSigner;
 
 	private CredentialsProvider credentialsProvider;
@@ -138,7 +140,7 @@
 
 			if (gpgSigner != null) {
 				gpgSigner.signObject(newTag, signingKey, tagger,
-						credentialsProvider);
+						credentialsProvider, gpgConfig);
 			}
 
 			// write the tag object
@@ -228,7 +230,9 @@
 			}
 			// Figure out whether to sign.
 			if (!(Boolean.FALSE.equals(signed) && signingKey == null)) {
-				GpgConfig gpgConfig = new GpgConfig(repo.getConfig());
+				if (gpgConfig == null) {
+					gpgConfig = new GpgConfig(repo.getConfig());
+				}
 				boolean doSign = isSigned() || gpgConfig.isSignAllTags();
 				if (!Boolean.TRUE.equals(annotated) && !doSign) {
 					doSign = gpgConfig.isSignAnnotated();
@@ -237,16 +241,14 @@
 					if (signingKey == null) {
 						signingKey = gpgConfig.getSigningKey();
 					}
-					if (gpgConfig.getKeyFormat() != GpgFormat.OPENPGP) {
-						throw new UnsupportedSigningFormatException(
-								JGitText.get().onlyOpenPgpSupportedForSigning);
+					if (gpgSigner == null) {
+						GpgSigner signer = GpgSigner.getDefault();
+						if (!(signer instanceof GpgObjectSigner)) {
+							throw new ServiceUnavailableException(
+									JGitText.get().signingServiceUnavailable);
+						}
+						gpgSigner = (GpgObjectSigner) signer;
 					}
-					GpgSigner signer = GpgSigner.getDefault();
-					if (!(signer instanceof GpgObjectSigner)) {
-						throw new ServiceUnavailableException(
-								JGitText.get().signingServiceUnavailable);
-					}
-					gpgSigner = (GpgObjectSigner) signer;
 					// The message of a signed tag must end in a newline because
 					// the signature will be appended.
 					if (message != null && !message.isEmpty()
@@ -332,6 +334,36 @@
 	}
 
 	/**
+	 * Sets the {@link GpgSigner} to use if the commit is to be signed.
+	 *
+	 * @param signer
+	 *            to use; if {@code null}, the default signer will be used
+	 * @return {@code this}
+	 * @since 5.11
+	 */
+	public TagCommand setGpgSigner(GpgObjectSigner signer) {
+		checkCallable();
+		this.gpgSigner = signer;
+		return this;
+	}
+
+	/**
+	 * Sets an external {@link GpgConfig} to use. Whether it will be used is at
+	 * the discretion of the {@link #setGpgSigner(GpgObjectSigner)}.
+	 *
+	 * @param config
+	 *            to set; if {@code null}, the config will be loaded from the
+	 *            git config of the repository
+	 * @return {@code this}
+	 * @since 5.11
+	 */
+	public TagCommand setGpgConfig(GpgConfig config) {
+		checkCallable();
+		this.gpgConfig = config;
+		return this;
+	}
+
+	/**
 	 * Sets the tagger of the tag. If the tagger is null, a PersonIdent will be
 	 * created from the info in the repository.
 	 *
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/VerificationResult.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/VerificationResult.java
new file mode 100644
index 0000000..21cddf7
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/VerificationResult.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2021, Thomas Wolf <thomas.wolf@paranor.ch> and others
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0 which is available at
+ * https://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+package org.eclipse.jgit.api;
+
+import org.eclipse.jgit.lib.GpgSignatureVerifier;
+import org.eclipse.jgit.revwalk.RevObject;
+
+/**
+ * A {@code VerificationResult} describes the outcome of a signature
+ * verification.
+ *
+ * @see VerifySignatureCommand
+ *
+ * @since 5.11
+ */
+public interface VerificationResult {
+
+	/**
+	 * If an error occurred during signature verification, this retrieves the
+	 * exception.
+	 *
+	 * @return the exception, or {@code null} if none occurred
+	 */
+	Throwable getException();
+
+	/**
+	 * Retrieves the signature verification result.
+	 *
+	 * @return the result, or {@code null} if none was computed
+	 */
+	GpgSignatureVerifier.SignatureVerification getVerification();
+
+	/**
+	 * Retrieves the git object of which the signature was verified.
+	 *
+	 * @return the git object
+	 */
+	RevObject getObject();
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/VerifySignatureCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/VerifySignatureCommand.java
new file mode 100644
index 0000000..6a2a44e
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/VerifySignatureCommand.java
@@ -0,0 +1,307 @@
+/*
+ * Copyright (C) 2021, Thomas Wolf <thomas.wolf@paranor.ch> and others
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0 which is available at
+ * https://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+package org.eclipse.jgit.api;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.eclipse.jgit.annotations.NonNull;
+import org.eclipse.jgit.api.errors.JGitInternalException;
+import org.eclipse.jgit.api.errors.ServiceUnavailableException;
+import org.eclipse.jgit.api.errors.WrongObjectTypeException;
+import org.eclipse.jgit.errors.MissingObjectException;
+import org.eclipse.jgit.internal.JGitText;
+import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.GpgConfig;
+import org.eclipse.jgit.lib.GpgSignatureVerifier;
+import org.eclipse.jgit.lib.GpgSignatureVerifier.SignatureVerification;
+import org.eclipse.jgit.lib.GpgSignatureVerifierFactory;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.revwalk.RevObject;
+import org.eclipse.jgit.revwalk.RevWalk;
+
+/**
+ * A command to verify GPG signatures on tags or commits.
+ *
+ * @since 5.11
+ */
+public class VerifySignatureCommand extends GitCommand<Map<String, VerificationResult>> {
+
+	/**
+	 * Describes what kind of objects shall be handled by a
+	 * {@link VerifySignatureCommand}.
+	 */
+	public enum VerifyMode {
+		/**
+		 * Handle any object type, ignore anything that is not a commit or tag.
+		 */
+		ANY,
+		/**
+		 * Handle only commits; throw a {@link WrongObjectTypeException} for
+		 * anything else.
+		 */
+		COMMITS,
+		/**
+		 * Handle only tags; throw a {@link WrongObjectTypeException} for
+		 * anything else.
+		 */
+		TAGS
+	}
+
+	private final Set<String> namesToCheck = new HashSet<>();
+
+	private VerifyMode mode = VerifyMode.ANY;
+
+	private GpgSignatureVerifier verifier;
+
+	private GpgConfig config;
+
+	private boolean ownVerifier;
+
+	/**
+	 * Creates a new {@link VerifySignatureCommand} for the given {@link Repository}.
+	 *
+	 * @param repo
+	 *            to operate on
+	 */
+	public VerifySignatureCommand(Repository repo) {
+		super(repo);
+	}
+
+	/**
+	 * Add a name of an object (SHA-1, ref name; anything that can be
+	 * {@link Repository#resolve(String) resolved}) to the command to have its
+	 * signature verified.
+	 *
+	 * @param name
+	 *            to add
+	 * @return {@code this}
+	 */
+	public VerifySignatureCommand addName(String name) {
+		checkCallable();
+		namesToCheck.add(name);
+		return this;
+	}
+
+	/**
+	 * Add names of objects (SHA-1, ref name; anything that can be
+	 * {@link Repository#resolve(String) resolved}) to the command to have their
+	 * signatures verified.
+	 *
+	 * @param names
+	 *            to add; duplicates will be ignored
+	 * @return {@code this}
+	 */
+	public VerifySignatureCommand addNames(String... names) {
+		checkCallable();
+		namesToCheck.addAll(Arrays.asList(names));
+		return this;
+	}
+
+	/**
+	 * Add names of objects (SHA-1, ref name; anything that can be
+	 * {@link Repository#resolve(String) resolved}) to the command to have their
+	 * signatures verified.
+	 *
+	 * @param names
+	 *            to add; duplicates will be ignored
+	 * @return {@code this}
+	 */
+	public VerifySignatureCommand addNames(Collection<String> names) {
+		checkCallable();
+		namesToCheck.addAll(names);
+		return this;
+	}
+
+	/**
+	 * Sets the mode of operation for this command.
+	 *
+	 * @param mode
+	 *            the {@link VerifyMode} to set
+	 * @return {@code this}
+	 */
+	public VerifySignatureCommand setMode(@NonNull VerifyMode mode) {
+		checkCallable();
+		this.mode = mode;
+		return this;
+	}
+
+	/**
+	 * Sets the {@link GpgSignatureVerifier} to use.
+	 *
+	 * @param verifier
+	 *            the {@link GpgSignatureVerifier} to use, or {@code null} to
+	 *            use the default verifier
+	 * @return {@code this}
+	 */
+	public VerifySignatureCommand setVerifier(GpgSignatureVerifier verifier) {
+		checkCallable();
+		this.verifier = verifier;
+		return this;
+	}
+
+	/**
+	 * Sets an external {@link GpgConfig} to use. Whether it will be used it at
+	 * the discretion of the {@link #setVerifier(GpgSignatureVerifier)}.
+	 *
+	 * @param config
+	 *            to set; if {@code null}, the config will be loaded from the
+	 *            git config of the repository
+	 * @return {@code this}
+	 * @since 5.11
+	 */
+	public VerifySignatureCommand setGpgConfig(GpgConfig config) {
+		checkCallable();
+		this.config = config;
+		return this;
+	}
+
+	/**
+	 * Retrieves the currently set {@link GpgSignatureVerifier}. Can be used
+	 * after a successful {@link #call()} to get the verifier that was used.
+	 *
+	 * @return the {@link GpgSignatureVerifier}
+	 */
+	public GpgSignatureVerifier getVerifier() {
+		return verifier;
+	}
+
+	/**
+	 * {@link Repository#resolve(String) Resolves} all names added to the
+	 * command to git objects and verifies their signature. Non-existing objects
+	 * are ignored.
+	 * <p>
+	 * Depending on the {@link #setMode(VerifyMode)}, only tags or commits or
+	 * any kind of objects are allowed.
+	 * </p>
+	 * <p>
+	 * Unsigned objects are silently skipped.
+	 * </p>
+	 *
+	 * @return a map of the given names to the corresponding
+	 *         {@link VerificationResult}, excluding ignored or skipped objects.
+	 * @throws ServiceUnavailableException
+	 *             if no {@link GpgSignatureVerifier} was set and no
+	 *             {@link GpgSignatureVerifierFactory} is available
+	 * @throws WrongObjectTypeException
+	 *             if a name resolves to an object of a type not allowed by the
+	 *             {@link #setMode(VerifyMode)} mode
+	 */
+	@Override
+	@NonNull
+	public Map<String, VerificationResult> call()
+			throws ServiceUnavailableException, WrongObjectTypeException {
+		checkCallable();
+		setCallable(false);
+		Map<String, VerificationResult> result = new HashMap<>();
+		if (verifier == null) {
+			GpgSignatureVerifierFactory factory = GpgSignatureVerifierFactory
+					.getDefault();
+			if (factory == null) {
+				throw new ServiceUnavailableException(
+						JGitText.get().signatureVerificationUnavailable);
+			}
+			verifier = factory.getVerifier();
+			ownVerifier = true;
+		}
+		if (config == null) {
+			config = new GpgConfig(repo.getConfig());
+		}
+		try (RevWalk walk = new RevWalk(repo)) {
+			for (String toCheck : namesToCheck) {
+				ObjectId id = repo.resolve(toCheck);
+				if (id != null && !ObjectId.zeroId().equals(id)) {
+					RevObject object;
+					try {
+						object = walk.parseAny(id);
+					} catch (MissingObjectException e) {
+						continue;
+					}
+					VerificationResult verification = verifyOne(object);
+					if (verification != null) {
+						result.put(toCheck, verification);
+					}
+				}
+			}
+		} catch (IOException e) {
+			throw new JGitInternalException(
+					JGitText.get().signatureVerificationError, e);
+		} finally {
+			if (ownVerifier) {
+				verifier.clear();
+			}
+		}
+		return result;
+	}
+
+	private VerificationResult verifyOne(RevObject object)
+			throws WrongObjectTypeException, IOException {
+		int type = object.getType();
+		if (VerifyMode.TAGS.equals(mode) && type != Constants.OBJ_TAG) {
+			throw new WrongObjectTypeException(object, Constants.OBJ_TAG);
+		} else if (VerifyMode.COMMITS.equals(mode)
+				&& type != Constants.OBJ_COMMIT) {
+			throw new WrongObjectTypeException(object, Constants.OBJ_COMMIT);
+		}
+		if (type == Constants.OBJ_COMMIT || type == Constants.OBJ_TAG) {
+			try {
+				GpgSignatureVerifier.SignatureVerification verification = verifier
+						.verifySignature(object, config);
+				if (verification == null) {
+					// Not signed
+					return null;
+				}
+				// Create new result
+				return new Result(object, verification, null);
+			} catch (JGitInternalException e) {
+				return new Result(object, null, e);
+			}
+		}
+		return null;
+	}
+
+	private static class Result implements VerificationResult {
+
+		private final Throwable throwable;
+
+		private final SignatureVerification verification;
+
+		private final RevObject object;
+
+		public Result(RevObject object, SignatureVerification verification,
+				Throwable throwable) {
+			this.object = object;
+			this.verification = verification;
+			this.throwable = throwable;
+		}
+
+		@Override
+		public Throwable getException() {
+			return throwable;
+		}
+
+		@Override
+		public SignatureVerification getVerification() {
+			return verification;
+		}
+
+		@Override
+		public RevObject getObject() {
+			return object;
+		}
+
+	}
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/WrongObjectTypeException.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/WrongObjectTypeException.java
new file mode 100644
index 0000000..f639c2f
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/WrongObjectTypeException.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2021, Thomas Wolf <thomas.wolf@paranor.ch> and others
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0 which is available at
+ * https://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+package org.eclipse.jgit.api.errors;
+
+import java.text.MessageFormat;
+
+import org.eclipse.jgit.internal.JGitText;
+import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.ObjectId;
+
+/**
+ * A given object is not of an expected object type.
+ *
+ * @since 5.11
+ */
+public class WrongObjectTypeException extends GitAPIException {
+
+	private static final long serialVersionUID = 1L;
+
+	private String name;
+
+	private int type;
+
+	/**
+	 * Construct a {@link WrongObjectTypeException} for the specified object id,
+	 * giving the expected type.
+	 *
+	 * @param id
+	 *            {@link ObjectId} of the object with the unexpected type
+	 * @param type
+	 *            expected object type code; see
+	 *            {@link Constants}{@code .OBJ_*}.
+	 */
+	public WrongObjectTypeException(ObjectId id, int type) {
+		super(MessageFormat.format(JGitText.get().objectIsNotA, id.name(),
+				Constants.typeString(type)));
+		this.name = id.name();
+		this.type = type;
+	}
+
+	/**
+	 * Retrieves the name (SHA-1) of the object.
+	 *
+	 * @return the name
+	 */
+	public String getObjectId() {
+		return name;
+	}
+
+	/**
+	 * Retrieves the expected type code. See {@link Constants}{@code .OBJ_*}.
+	 *
+	 * @return the type code
+	 */
+	public int getExpectedType() {
+		return type;
+	}
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/errors/NoPackSignatureException.java b/org.eclipse.jgit/src/org/eclipse/jgit/errors/NoPackSignatureException.java
index c3b1df9..a37b8be 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/errors/NoPackSignatureException.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/errors/NoPackSignatureException.java
@@ -13,8 +13,7 @@
 import java.io.IOException;
 
 /**
- * Thrown when a PackFile is found not to contain the pack signature defined by
- * git.
+ * Thrown when a Pack is found not to contain the pack signature defined by git.
  *
  * @since 4.5
  */
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/errors/PackInvalidException.java b/org.eclipse.jgit/src/org/eclipse/jgit/errors/PackInvalidException.java
index c484984..1fd8086 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/errors/PackInvalidException.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/errors/PackInvalidException.java
@@ -17,7 +17,7 @@
 import org.eclipse.jgit.internal.JGitText;
 
 /**
- * Thrown when a PackFile previously failed and is known to be unusable
+ * Thrown when a Pack previously failed and is known to be unusable
  */
 public class PackInvalidException extends IOException {
 	private static final long serialVersionUID = 1L;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/errors/PackMismatchException.java b/org.eclipse.jgit/src/org/eclipse/jgit/errors/PackMismatchException.java
index ad5664c..44b8e01 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/errors/PackMismatchException.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/errors/PackMismatchException.java
@@ -13,7 +13,7 @@
 import java.io.IOException;
 
 /**
- * Thrown when a PackFile no longer matches the PackIndex.
+ * Thrown when a Pack no longer matches the PackIndex.
  */
 public class PackMismatchException extends IOException {
 	private static final long serialVersionUID = 1L;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/errors/UnsupportedPackVersionException.java b/org.eclipse.jgit/src/org/eclipse/jgit/errors/UnsupportedPackVersionException.java
index 7538229..07aa756 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/errors/UnsupportedPackVersionException.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/errors/UnsupportedPackVersionException.java
@@ -16,7 +16,7 @@
 import org.eclipse.jgit.internal.JGitText;
 
 /**
- * Thrown when a PackFile uses a pack version not supported by JGit.
+ * Thrown when a Pack uses a pack version not supported by JGit.
  *
  * @since 4.5
  */
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/hooks/GitHook.java b/org.eclipse.jgit/src/org/eclipse/jgit/hooks/GitHook.java
index 4059b16..ce3ad22 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/hooks/GitHook.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/hooks/GitHook.java
@@ -9,12 +9,10 @@
  */
 package org.eclipse.jgit.hooks;
 
-import static java.nio.charset.StandardCharsets.UTF_8;
-
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
-import java.io.PrintStream;
-import java.io.UnsupportedEncodingException;
+import java.io.OutputStream;
+import java.nio.charset.Charset;
 import java.util.concurrent.Callable;
 
 import org.eclipse.jgit.api.errors.AbortedByHookException;
@@ -35,21 +33,21 @@
  *            the return type which is expected from {@link #call()}
  * @see <a href="http://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks">Git
  *      Hooks on the git-scm official site</a>
- * @since 4.0
+ * @since 5.11
  */
-abstract class GitHook<T> implements Callable<T> {
+public abstract class GitHook<T> implements Callable<T> {
 
 	private final Repository repo;
 
 	/**
 	 * The output stream to be used by the hook.
 	 */
-	protected final PrintStream outputStream;
+	private final OutputStream outputStream;
 
 	/**
 	 * The error stream to be used by the hook.
 	 */
-	protected final PrintStream errorStream;
+	private final OutputStream errorStream;
 
 	/**
 	 * Constructor for GitHook.
@@ -63,7 +61,7 @@
 	 *            The output stream the hook must use. {@code null} is allowed,
 	 *            in which case the hook will use {@code System.out}.
 	 */
-	protected GitHook(Repository repo, PrintStream outputStream) {
+	protected GitHook(Repository repo, OutputStream outputStream) {
 		this(repo, outputStream, null);
 	}
 
@@ -79,8 +77,8 @@
 	 *            The error stream the hook must use. {@code null} is allowed,
 	 *            in which case the hook will use {@code System.err}.
 	 */
-	protected GitHook(Repository repo, PrintStream outputStream,
-			PrintStream errorStream) {
+	protected GitHook(Repository repo, OutputStream outputStream,
+			OutputStream errorStream) {
 		this.repo = repo;
 		this.outputStream = outputStream;
 		this.errorStream = errorStream;
@@ -137,7 +135,7 @@
 	 * @return The output stream the hook must use. Never {@code null},
 	 *         {@code System.out} is returned by default.
 	 */
-	protected PrintStream getOutputStream() {
+	protected OutputStream getOutputStream() {
 		return outputStream == null ? System.out : outputStream;
 	}
 
@@ -147,7 +145,7 @@
 	 * @return The error stream the hook must use. Never {@code null},
 	 *         {@code System.err} is returned by default.
 	 */
-	protected PrintStream getErrorStream() {
+	protected OutputStream getErrorStream() {
 		return errorStream == null ? System.err : errorStream;
 	}
 
@@ -156,34 +154,48 @@
 	 *
 	 * @throws org.eclipse.jgit.api.errors.AbortedByHookException
 	 *             If the underlying hook script exited with non-zero.
+	 * @throws IOException
+	 *             if an IO error occurred
 	 */
-	protected void doRun() throws AbortedByHookException {
+	protected void doRun() throws AbortedByHookException, IOException {
 		final ByteArrayOutputStream errorByteArray = new ByteArrayOutputStream();
 		final TeeOutputStream stderrStream = new TeeOutputStream(errorByteArray,
 				getErrorStream());
-		PrintStream hookErrRedirect = null;
-		try {
-			hookErrRedirect = new PrintStream(stderrStream, false,
-					UTF_8.name());
-		} catch (UnsupportedEncodingException e) {
-			// UTF-8 is guaranteed to be available
-		}
 		Repository repository = getRepository();
 		FS fs = repository.getFS();
 		if (fs == null) {
 			fs = FS.DETECTED;
 		}
 		ProcessResult result = fs.runHookIfPresent(repository, getHookName(),
-				getParameters(), getOutputStream(), hookErrRedirect,
+				getParameters(), getOutputStream(), stderrStream,
 				getStdinArgs());
 		if (result.isExecutedWithError()) {
-			throw new AbortedByHookException(
-					new String(errorByteArray.toByteArray(), UTF_8),
-					getHookName(), result.getExitCode());
+			handleError(new String(errorByteArray.toByteArray(),
+					Charset.defaultCharset().name()), result);
 		}
 	}
 
 	/**
+	 * Process that the hook exited with an error. This default implementation
+	 * throws an {@link AbortedByHookException }. Hooks which need a different
+	 * behavior can overwrite this method.
+	 *
+	 * @param message
+	 *            error message
+	 * @param result
+	 *            The process result of the hook
+	 * @throws AbortedByHookException
+	 *             When the hook should be aborted
+	 * @since 5.11
+	 */
+	protected void handleError(String message,
+			final ProcessResult result)
+			throws AbortedByHookException {
+		throw new AbortedByHookException(message, getHookName(),
+				result.getExitCode());
+	}
+
+	/**
 	 * Check whether a 'native' (i.e. script) hook is installed in the
 	 * repository.
 	 *
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/hooks/PostCommitHook.java b/org.eclipse.jgit/src/org/eclipse/jgit/hooks/PostCommitHook.java
index 0b61ebe..b9dafcc 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/hooks/PostCommitHook.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/hooks/PostCommitHook.java
@@ -14,6 +14,7 @@
 
 import org.eclipse.jgit.api.errors.AbortedByHookException;
 import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.util.ProcessResult;
 
 /**
  * The <code>post-commit</code> hook implementation. This hook is run after the
@@ -73,4 +74,16 @@
 		return NAME;
 	}
 
+
+	/**
+	 * Overwrites the default implementation to never throw an
+	 * {@link AbortedByHookException}, as the commit has already been done and
+	 * the exit code of the post-commit hook has no effect.
+	 */
+	@Override
+	protected void handleError(String message, ProcessResult result)
+			throws AbortedByHookException {
+		// Do nothing as the exit code of the post-commit hook has no effect.
+	}
+
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/ignore/FastIgnoreRule.java b/org.eclipse.jgit/src/org/eclipse/jgit/ignore/FastIgnoreRule.java
index d7e4f79..9dd565f 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/ignore/FastIgnoreRule.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/ignore/FastIgnoreRule.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2014, Andrey Loskutov <loskutov@gmx.de> and others
+ * Copyright (C) 2014, 2021 Andrey Loskutov <loskutov@gmx.de> and others
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Distribution License v. 1.0 which is available at
@@ -14,8 +14,11 @@
 import static org.eclipse.jgit.ignore.internal.Strings.stripTrailing;
 import static org.eclipse.jgit.ignore.internal.Strings.stripTrailingWhitespace;
 
+import java.text.MessageFormat;
+
 import org.eclipse.jgit.errors.InvalidPatternException;
 import org.eclipse.jgit.ignore.internal.PathMatcher;
+import org.eclipse.jgit.internal.JGitText;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -36,11 +39,11 @@
 	 */
 	public static final char PATH_SEPARATOR = '/';
 
-	private final IMatcher matcher;
+	private IMatcher matcher;
 
-	private final boolean inverse;
+	private boolean inverse;
 
-	private final boolean dirOnly;
+	private boolean dirOnly;
 
 	/**
 	 * Constructor for FastIgnoreRule
@@ -52,8 +55,23 @@
 	 *            (comment), this rule doesn't match anything.
 	 */
 	public FastIgnoreRule(String pattern) {
-		if (pattern == null)
+		this();
+		try {
+			parse(pattern);
+		} catch (InvalidPatternException e) {
+			LOG.error(MessageFormat.format(JGitText.get().badIgnorePattern,
+					e.getPattern()), e);
+		}
+	}
+
+	FastIgnoreRule() {
+		matcher = IMatcher.NO_MATCH;
+	}
+
+	void parse(String pattern) throws InvalidPatternException {
+		if (pattern == null) {
 			throw new IllegalArgumentException("Pattern must not be null!"); //$NON-NLS-1$
+		}
 		if (pattern.length() == 0) {
 			dirOnly = false;
 			inverse = false;
@@ -90,15 +108,8 @@
 				return;
 			}
 		}
-		IMatcher m;
-		try {
-			m = PathMatcher.createPathMatcher(pattern,
-					Character.valueOf(PATH_SEPARATOR), dirOnly);
-		} catch (InvalidPatternException e) {
-			m = NO_MATCH;
-			LOG.error(e.getMessage(), e);
-		}
-		this.matcher = m;
+		this.matcher = PathMatcher.createPathMatcher(pattern,
+				Character.valueOf(PATH_SEPARATOR), dirOnly);
 	}
 
 	/**
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/ignore/IgnoreNode.java b/org.eclipse.jgit/src/org/eclipse/jgit/ignore/IgnoreNode.java
index 1a1b2d3..4e7f126 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/ignore/IgnoreNode.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/ignore/IgnoreNode.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2010, Red Hat Inc. and others
+ * Copyright (C) 2010, 2021 Red Hat Inc. and others
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Distribution License v. 1.0 which is available at
@@ -15,11 +15,16 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
+import java.text.MessageFormat;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 
 import org.eclipse.jgit.annotations.Nullable;
+import org.eclipse.jgit.errors.InvalidPatternException;
+import org.eclipse.jgit.internal.JGitText;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 /**
  * Represents a bundle of ignore rules inherited from a base directory.
@@ -27,6 +32,9 @@
  * This class is not thread safe, it maintains state about the last match.
  */
 public class IgnoreNode {
+
+	private static final Logger LOG = LoggerFactory.getLogger(IgnoreNode.class);
+
 	/** Result from {@link IgnoreNode#isIgnored(String, boolean)}. */
 	public enum MatchResult {
 		/** The file is not ignored, due to a rule saying its not ignored. */
@@ -54,7 +62,7 @@
 	 * Create an empty ignore node with no rules.
 	 */
 	public IgnoreNode() {
-		rules = new ArrayList<>();
+		this(new ArrayList<>());
 	}
 
 	/**
@@ -77,15 +85,47 @@
 	 *             Error thrown when reading an ignore file.
 	 */
 	public void parse(InputStream in) throws IOException {
+		parse(null, in);
+	}
+
+	/**
+	 * Parse files according to gitignore standards.
+	 *
+	 * @param sourceName
+	 *            identifying the source of the stream
+	 * @param in
+	 *            input stream holding the standard ignore format. The caller is
+	 *            responsible for closing the stream.
+	 * @throws java.io.IOException
+	 *             Error thrown when reading an ignore file.
+	 * @since 5.11
+	 */
+	public void parse(String sourceName, InputStream in) throws IOException {
 		BufferedReader br = asReader(in);
 		String txt;
+		int lineNumber = 1;
 		while ((txt = br.readLine()) != null) {
 			if (txt.length() > 0 && !txt.startsWith("#") && !txt.equals("/")) { //$NON-NLS-1$ //$NON-NLS-2$
-				FastIgnoreRule rule = new FastIgnoreRule(txt);
+				FastIgnoreRule rule = new FastIgnoreRule();
+				try {
+					rule.parse(txt);
+				} catch (InvalidPatternException e) {
+					if (sourceName != null) {
+						LOG.error(MessageFormat.format(
+								JGitText.get().badIgnorePatternFull, sourceName,
+								Integer.toString(lineNumber), e.getPattern(),
+								e.getLocalizedMessage()), e);
+					} else {
+						LOG.error(MessageFormat.format(
+								JGitText.get().badIgnorePattern,
+								e.getPattern()), e);
+					}
+				}
 				if (!rule.isEmpty()) {
 					rules.add(rule);
 				}
 			}
+			lineNumber++;
 		}
 	}
 
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 07fb59d..9d215ca 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2010, 2013 Sasa Zivkov <sasa.zivkov@sap.com>
- * Copyright (C) 2012, Research In Motion Limited and others
+ * Copyright (C) 2012, 2021 Research In Motion Limited and others
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Distribution License v. 1.0 which is available at
@@ -58,6 +58,8 @@
 	/***/ public String badEntryName;
 	/***/ public String badEscape;
 	/***/ public String badGroupHeader;
+	/***/ public String badIgnorePattern;
+	/***/ public String badIgnorePatternFull;
 	/***/ public String badObjectType;
 	/***/ public String badRef;
 	/***/ public String badSectionEntry;
@@ -596,6 +598,7 @@
 	/***/ public String reftableDirExists;
 	/***/ public String reftableRecordsMustIncrease;
 	/***/ public String refUpdateReturnCodeWas;
+	/***/ public String remoteBranchNotFound;
 	/***/ public String remoteConfigHasNoURIAssociated;
 	/***/ public String remoteDoesNotHaveSpec;
 	/***/ public String remoteDoesNotSupportSmartHTTPPush;
@@ -650,6 +653,8 @@
 	/***/ public String shortReadOfBlock;
 	/***/ public String shortReadOfOptionalDIRCExtensionExpectedAnotherBytes;
 	/***/ public String shortSkipOfBlock;
+	/***/ public String signatureVerificationError;
+	/***/ public String signatureVerificationUnavailable;
 	/***/ public String signedTagMessageNoLf;
 	/***/ public String signingServiceUnavailable;
 	/***/ public String similarityScoreMustBeWithinBounds;
@@ -791,6 +796,13 @@
 	/***/ public String URINotSupported;
 	/***/ public String userConfigInvalid;
 	/***/ public String validatingGitModules;
+	/***/ public String verifySignatureBad;
+	/***/ public String verifySignatureExpired;
+	/***/ public String verifySignatureGood;
+	/***/ public String verifySignatureIssuer;
+	/***/ public String verifySignatureKey;
+	/***/ public String verifySignatureMade;
+	/***/ public String verifySignatureTrust;
 	/***/ public String walkFailure;
 	/***/ public String wantNoSpaceWithCapabilities;
 	/***/ public String wantNotValid;
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 b1e9552..96ca690 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
@@ -607,8 +607,15 @@
 
 	private void readFully(long position, byte[] dstbuf, int dstoff, int cnt,
 			DfsReader ctx) throws IOException {
-		if (ctx.copy(this, position, dstbuf, dstoff, cnt) != cnt)
-			throw new EOFException();
+		while (cnt > 0) {
+			int copied = ctx.copy(this, position, dstbuf, dstoff, cnt);
+			if (copied == 0) {
+				throw new EOFException();
+			}
+			position += copied;
+			dstoff += copied;
+			cnt -= copied;
+		}
 	}
 
 	ObjectLoader load(DfsReader ctx, long pos)
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ByteArrayWindow.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ByteArrayWindow.java
index 45d9c85..1036535 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ByteArrayWindow.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ByteArrayWindow.java
@@ -25,7 +25,7 @@
 final class ByteArrayWindow extends ByteWindow {
 	private final byte[] array;
 
-	ByteArrayWindow(PackFile pack, long o, byte[] b) {
+	ByteArrayWindow(Pack pack, long o, byte[] b) {
 		super(pack, o, b.length);
 		array = b;
 	}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ByteBufferWindow.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ByteBufferWindow.java
index 8703216..b687757 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ByteBufferWindow.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ByteBufferWindow.java
@@ -27,7 +27,7 @@
 final class ByteBufferWindow extends ByteWindow {
 	private final ByteBuffer buffer;
 
-	ByteBufferWindow(PackFile pack, long o, ByteBuffer b) {
+	ByteBufferWindow(Pack pack, long o, ByteBuffer b) {
 		super(pack, o, b.capacity());
 		buffer = b;
 	}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ByteWindow.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ByteWindow.java
index 159f31c..31e7ead 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ByteWindow.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ByteWindow.java
@@ -27,7 +27,7 @@
  * </p>
  */
 abstract class ByteWindow {
-	protected final PackFile pack;
+	protected final Pack pack;
 
 	protected final long start;
 
@@ -37,13 +37,13 @@
 	 * Constructor for ByteWindow.
 	 *
 	 * @param p
-	 *            a {@link org.eclipse.jgit.internal.storage.file.PackFile}.
+	 *            a {@link org.eclipse.jgit.internal.storage.file.Pack}.
 	 * @param s
 	 *            where the byte window starts in the pack file
 	 * @param n
 	 *            size of the byte window
 	 */
-	protected ByteWindow(PackFile p, long s, int n) {
+	protected ByteWindow(Pack p, long s, int n) {
 		pack = p;
 		start = s;
 		end = start + n;
@@ -53,8 +53,8 @@
 		return (int) (end - start);
 	}
 
-	final boolean contains(PackFile neededFile, long neededPos) {
-		return pack == neededFile && start <= neededPos && neededPos < end;
+	final boolean contains(Pack neededPack, long neededPos) {
+		return pack == neededPack && start <= neededPos && neededPos < end;
 	}
 
 	/**
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/CachedObjectDirectory.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/CachedObjectDirectory.java
index 9c7a2e7..7dedeb5 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/CachedObjectDirectory.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/CachedObjectDirectory.java
@@ -239,7 +239,7 @@
 	}
 
 	@Override
-	PackFile openPack(File pack) throws IOException {
+	Pack openPack(File pack) throws IOException {
 		return wrapped.openPack(pack);
 	}
 
@@ -250,7 +250,7 @@
 	}
 
 	@Override
-	Collection<PackFile> getPacks() {
+	Collection<Pack> getPacks() {
 		return wrapped.getPacks();
 	}
 
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/DeltaBaseCache.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/DeltaBaseCache.java
index cef5a33..69cebad 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/DeltaBaseCache.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/DeltaBaseCache.java
@@ -49,7 +49,7 @@
 		cache = new Slot[CACHE_SZ];
 	}
 
-	Entry get(PackFile pack, long position) {
+	Entry get(Pack pack, long position) {
 		Slot e = cache[hash(position)];
 		if (e == null)
 			return null;
@@ -63,7 +63,7 @@
 		return null;
 	}
 
-	void store(final PackFile pack, final long position,
+	void store(final Pack pack, final long position,
 			final byte[] data, final int objectType) {
 		if (data.length > maxByteCount)
 			return; // Too large to cache.
@@ -146,7 +146,7 @@
 
 		Slot lruNext;
 
-		PackFile provider;
+		Pack provider;
 
 		long position;
 
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileObjectDatabase.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileObjectDatabase.java
index 11ed10c..01dd27d 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileObjectDatabase.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileObjectDatabase.java
@@ -71,7 +71,7 @@
 	abstract InsertLooseObjectResult insertUnpackedObject(File tmp,
 			ObjectId id, boolean createDuplicate) throws IOException;
 
-	abstract PackFile openPack(File pack) throws IOException;
+	abstract Pack openPack(File pack) throws IOException;
 
-	abstract Collection<PackFile> getPacks();
+	abstract Collection<Pack> getPacks();
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileReftableStack.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileReftableStack.java
index db454b9..b5e3927 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileReftableStack.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileReftableStack.java
@@ -21,6 +21,7 @@
 import java.io.InputStreamReader;
 import java.nio.file.Files;
 import java.nio.file.StandardCopyOption;
+import java.security.SecureRandom;
 import java.util.ArrayList;
 import java.util.Comparator;
 import java.util.List;
@@ -65,6 +66,8 @@
 
 	private final Runnable onChange;
 
+	private final SecureRandom random = new SecureRandom();
+
 	private final Supplier<Config> configSupplier;
 
 	// Used for stats & testing.
@@ -365,8 +368,9 @@
 	}
 
 	private String filename(long low, long high) {
-		return String.format("%012x-%012x", //$NON-NLS-1$
-				Long.valueOf(low), Long.valueOf(high));
+		return String.format("%012x-%012x-%08x", //$NON-NLS-1$
+				Long.valueOf(low), Long.valueOf(high),
+				Integer.valueOf(random.nextInt()));
 	}
 
 	/**
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileRepository.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileRepository.java
index b939d37..fecced1 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileRepository.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileRepository.java
@@ -243,7 +243,7 @@
 
 		RefUpdate head = updateRef(Constants.HEAD);
 		head.disableRefLog();
-		head.link(Constants.R_HEADS + Constants.MASTER);
+		head.link(Constants.R_HEADS + getInitialBranch());
 
 		final boolean fileMode;
 		if (getFS().supportsExecute()) {
@@ -759,12 +759,14 @@
 			}
 		} else {
 			FileUtils.delete(packedRefs, FileUtils.SKIP_MISSING);
-			FileUtils.delete(headFile);
-			FileUtils.delete(logsDir, FileUtils.RECURSIVE);
-			FileUtils.delete(refsFile, FileUtils.RECURSIVE);
+			FileUtils.delete(headFile, FileUtils.SKIP_MISSING);
+			FileUtils.delete(logsDir,
+					FileUtils.RECURSIVE | FileUtils.SKIP_MISSING);
+			FileUtils.delete(refsFile,
+					FileUtils.RECURSIVE | FileUtils.SKIP_MISSING);
 			for (String r : additional) {
 				new File(getDirectory(), r).delete();
-		}
+			}
 		}
 
 		FileUtils.mkdir(refsFile, true);
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 3240752..75de3be 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
@@ -205,16 +205,16 @@
 	 * gc.log.
 	 *
 	 * @return the collection of
-	 *         {@link org.eclipse.jgit.internal.storage.file.PackFile}'s which
+	 *         {@link org.eclipse.jgit.internal.storage.file.Pack}'s which
 	 *         are newly created
 	 * @throws java.io.IOException
 	 * @throws java.text.ParseException
 	 *             If the configuration parameter "gc.pruneexpire" couldn't be
 	 *             parsed
 	 */
-	// TODO(ms): change signature and return Future<Collection<PackFile>>
+	// TODO(ms): change signature and return Future<Collection<Pack>>
 	@SuppressWarnings("FutureReturnValueIgnored")
-	public Collection<PackFile> gc() throws IOException, ParseException {
+	public Collection<Pack> gc() throws IOException, ParseException {
 		if (!background) {
 			return doGc();
 		}
@@ -224,9 +224,9 @@
 			return Collections.emptyList();
 		}
 
-		Callable<Collection<PackFile>> gcTask = () -> {
+		Callable<Collection<Pack>> gcTask = () -> {
 			try {
-				Collection<PackFile> newPacks = doGc();
+				Collection<Pack> newPacks = doGc();
 				if (automatic && tooManyLooseObjects()) {
 					String message = JGitText.get().gcTooManyUnpruned;
 					gcLog.write(message);
@@ -258,14 +258,14 @@
 		return (executor != null) ? executor : WorkQueue.getExecutor();
 	}
 
-	private Collection<PackFile> doGc() throws IOException, ParseException {
+	private Collection<Pack> doGc() throws IOException, ParseException {
 		if (automatic && !needGc()) {
 			return Collections.emptyList();
 		}
 		pm.start(6 /* tasks */);
 		packRefs();
 		// TODO: implement reflog_expire(pm, repo);
-		Collection<PackFile> newPacks = repack();
+		Collection<Pack> newPacks = repack();
 		prune(Collections.emptySet());
 		// TODO: implement rerere_gc(pm);
 		return newPacks;
@@ -281,7 +281,7 @@
 	 * @param existing
 	 * @throws IOException
 	 */
-	private void loosen(ObjectDirectoryInserter inserter, ObjectReader reader, PackFile pack, HashSet<ObjectId> existing)
+	private void loosen(ObjectDirectoryInserter inserter, ObjectReader reader, Pack pack, HashSet<ObjectId> existing)
 			throws IOException {
 		for (PackIndex.MutableEntry entry : pack) {
 			ObjectId oid = entry.toObjectId();
@@ -313,10 +313,10 @@
 	 * @throws ParseException
 	 * @throws IOException
 	 */
-	private void deleteOldPacks(Collection<PackFile> oldPacks,
-			Collection<PackFile> newPacks) throws ParseException, IOException {
+	private void deleteOldPacks(Collection<Pack> oldPacks,
+			Collection<Pack> newPacks) throws ParseException, IOException {
 		HashSet<ObjectId> ids = new HashSet<>();
-		for (PackFile pack : newPacks) {
+		for (Pack pack : newPacks) {
 			for (PackIndex.MutableEntry entry : pack) {
 				ids.add(entry.toObjectId());
 			}
@@ -329,12 +329,12 @@
 
 		prunePreserved();
 		long packExpireDate = getPackExpireDate();
-		oldPackLoop: for (PackFile oldPack : oldPacks) {
+		oldPackLoop: for (Pack oldPack : oldPacks) {
 			checkCancelled();
 			String oldName = oldPack.getPackName();
 			// check whether an old pack file is also among the list of new
 			// pack files. Then we must not delete it.
-			for (PackFile newPack : newPacks)
+			for (Pack newPack : newPacks)
 				if (oldName.equals(newPack.getPackName()))
 					continue oldPackLoop;
 
@@ -438,7 +438,7 @@
 	 */
 	public void prunePacked() throws IOException {
 		ObjectDirectory objdb = repo.getObjectDatabase();
-		Collection<PackFile> packs = objdb.getPacks();
+		Collection<Pack> packs = objdb.getPacks();
 		File objects = repo.getObjectsDirectory();
 		String[] fanout = objects.list();
 
@@ -466,7 +466,7 @@
 							continue;
 						}
 						boolean found = false;
-						for (PackFile p : packs) {
+						for (Pack p : packs) {
 							checkCancelled();
 							if (p.hasObject(id)) {
 								found = true;
@@ -788,8 +788,8 @@
 	 *             reflog-entries or during writing to the packfiles
 	 *             {@link java.io.IOException} occurs
 	 */
-	public Collection<PackFile> repack() throws IOException {
-		Collection<PackFile> toBeDeleted = repo.getObjectDatabase().getPacks();
+	public Collection<Pack> repack() throws IOException {
+		Collection<Pack> toBeDeleted = repo.getObjectDatabase().getPacks();
 
 		long time = System.currentTimeMillis();
 		Collection<Ref> refsBefore = getAllRefs();
@@ -821,10 +821,10 @@
 		}
 
 		List<ObjectIdSet> excluded = new LinkedList<>();
-		for (PackFile f : repo.getObjectDatabase().getPacks()) {
+		for (Pack p : repo.getObjectDatabase().getPacks()) {
 			checkCancelled();
-			if (f.shouldBeKept())
-				excluded.add(f.getIndex());
+			if (p.shouldBeKept())
+				excluded.add(p.getIndex());
 		}
 
 		// Don't exclude tags that are also branch tips
@@ -842,8 +842,8 @@
 			nonHeads.clear();
 		}
 
-		List<PackFile> ret = new ArrayList<>(2);
-		PackFile heads = null;
+		List<Pack> ret = new ArrayList<>(2);
+		Pack heads = null;
 		if (!allHeadsAndTags.isEmpty()) {
 			heads = writePack(allHeadsAndTags, PackWriter.NONE, allTags,
 					tagTargets, excluded);
@@ -853,13 +853,13 @@
 			}
 		}
 		if (!nonHeads.isEmpty()) {
-			PackFile rest = writePack(nonHeads, allHeadsAndTags, PackWriter.NONE,
+			Pack rest = writePack(nonHeads, allHeadsAndTags, PackWriter.NONE,
 					tagTargets, excluded);
 			if (rest != null)
 				ret.add(rest);
 		}
 		if (!txnHeads.isEmpty()) {
-			PackFile txn = writePack(txnHeads, PackWriter.NONE, PackWriter.NONE,
+			Pack txn = writePack(txnHeads, PackWriter.NONE, PackWriter.NONE,
 					null, excluded);
 			if (txn != null)
 				ret.add(txn);
@@ -1129,7 +1129,7 @@
 		}
 	}
 
-	private PackFile writePack(@NonNull Set<? extends ObjectId> want,
+	private Pack writePack(@NonNull Set<? extends ObjectId> want,
 			@NonNull Set<? extends ObjectId> have, @NonNull Set<ObjectId> tags,
 			Set<ObjectId> tagTargets, List<ObjectIdSet> excludeObjects)
 			throws IOException {
@@ -1356,13 +1356,13 @@
 	 */
 	public RepoStatistics getStatistics() throws IOException {
 		RepoStatistics ret = new RepoStatistics();
-		Collection<PackFile> packs = repo.getObjectDatabase().getPacks();
-		for (PackFile f : packs) {
-			ret.numberOfPackedObjects += f.getIndex().getObjectCount();
+		Collection<Pack> packs = repo.getObjectDatabase().getPacks();
+		for (Pack p : packs) {
+			ret.numberOfPackedObjects += p.getIndex().getObjectCount();
 			ret.numberOfPackFiles++;
-			ret.sizeOfPackedObjects += f.getPackFile().length();
-			if (f.getBitmapIndex() != null)
-				ret.numberOfBitmaps += f.getBitmapIndex().getBitmapCount();
+			ret.sizeOfPackedObjects += p.getPackFile().length();
+			if (p.getBitmapIndex() != null)
+				ret.numberOfBitmaps += p.getBitmapIndex().getBitmapCount();
 		}
 		File objDir = repo.getObjectsDirectory();
 		String[] fanout = objDir.list();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/LargePackedWholeObject.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/LargePackedWholeObject.java
index ee4bbc1..e2fbd7a 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/LargePackedWholeObject.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/LargePackedWholeObject.java
@@ -30,12 +30,12 @@
 
 	private final int headerLength;
 
-	private final PackFile pack;
+	private final Pack pack;
 
 	private final FileObjectDatabase db;
 
 	LargePackedWholeObject(int type, long size, long objectOffset,
-			int headerLength, PackFile pack, FileObjectDatabase db) {
+			int headerLength, Pack pack, FileObjectDatabase db) {
 		this.type = type;
 		this.size = size;
 		this.objectOffset = objectOffset;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/LocalCachedPack.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/LocalCachedPack.java
index 9d04062..ae5bce6 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/LocalCachedPack.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/LocalCachedPack.java
@@ -25,31 +25,31 @@
 
 	private final String[] packNames;
 
-	private PackFile[] packs;
+	private Pack[] packs;
 
 	LocalCachedPack(ObjectDirectory odb, List<String> packNames) {
 		this.odb = odb;
 		this.packNames = packNames.toArray(new String[0]);
 	}
 
-	LocalCachedPack(List<PackFile> packs) {
+	LocalCachedPack(List<Pack> packs) {
 		odb = null;
 		packNames = null;
-		this.packs = packs.toArray(new PackFile[0]);
+		this.packs = packs.toArray(new Pack[0]);
 	}
 
 	/** {@inheritDoc} */
 	@Override
 	public long getObjectCount() throws IOException {
 		long cnt = 0;
-		for (PackFile pack : getPacks())
+		for (Pack pack : getPacks())
 			cnt += pack.getObjectCount();
 		return cnt;
 	}
 
 	void copyAsIs(PackOutputStream out, WindowCursor wc)
 			throws IOException {
-		for (PackFile pack : getPacks())
+		for (Pack pack : getPacks())
 			pack.copyPackAsIs(out, wc);
 	}
 
@@ -58,7 +58,7 @@
 	public boolean hasObject(ObjectToPack obj, StoredObjectRepresentation rep) {
 		try {
 			LocalObjectRepresentation local = (LocalObjectRepresentation) rep;
-			for (PackFile pack : getPacks()) {
+			for (Pack pack : getPacks()) {
 				if (local.pack == pack)
 					return true;
 			}
@@ -68,9 +68,9 @@
 		}
 	}
 
-	private PackFile[] getPacks() throws FileNotFoundException {
+	private Pack[] getPacks() throws FileNotFoundException {
 		if (packs == null) {
-			PackFile[] p = new PackFile[packNames.length];
+			Pack[] p = new Pack[packNames.length];
 			for (int i = 0; i < packNames.length; i++)
 				p[i] = getPackFile(packNames[i]);
 			packs = p;
@@ -78,8 +78,8 @@
 		return packs;
 	}
 
-	private PackFile getPackFile(String packName) throws FileNotFoundException {
-		for (PackFile pack : odb.getPacks()) {
+	private Pack getPackFile(String packName) throws FileNotFoundException {
+		for (Pack pack : odb.getPacks()) {
 			if (packName.equals(pack.getPackName()))
 				return pack;
 		}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/LocalObjectRepresentation.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/LocalObjectRepresentation.java
index 3950dde..559718a 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/LocalObjectRepresentation.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/LocalObjectRepresentation.java
@@ -16,40 +16,40 @@
 import org.eclipse.jgit.lib.ObjectId;
 
 class LocalObjectRepresentation extends StoredObjectRepresentation {
-	static LocalObjectRepresentation newWhole(PackFile f, long p, long length) {
+	static LocalObjectRepresentation newWhole(Pack pack, long offset, long length) {
 		LocalObjectRepresentation r = new LocalObjectRepresentation() {
 			@Override
 			public int getFormat() {
 				return PACK_WHOLE;
 			}
 		};
-		r.pack = f;
-		r.offset = p;
+		r.pack = pack;
+		r.offset = offset;
 		r.length = length;
 		return r;
 	}
 
-	static LocalObjectRepresentation newDelta(PackFile f, long p, long n,
+	static LocalObjectRepresentation newDelta(Pack pack, long offset, long length,
 			ObjectId base) {
 		LocalObjectRepresentation r = new Delta();
-		r.pack = f;
-		r.offset = p;
-		r.length = n;
+		r.pack = pack;
+		r.offset = offset;
+		r.length = length;
 		r.baseId = base;
 		return r;
 	}
 
-	static LocalObjectRepresentation newDelta(PackFile f, long p, long n,
+	static LocalObjectRepresentation newDelta(Pack pack, long offset, long length,
 			long base) {
 		LocalObjectRepresentation r = new Delta();
-		r.pack = f;
-		r.offset = p;
-		r.length = n;
+		r.pack = pack;
+		r.offset = offset;
+		r.length = length;
 		r.baseOffset = base;
 		return r;
 	}
 
-	PackFile pack;
+	Pack pack;
 
 	long offset;
 
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/LocalObjectToPack.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/LocalObjectToPack.java
index 4a0ac1f..ac6cd21 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/LocalObjectToPack.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/LocalObjectToPack.java
@@ -17,7 +17,7 @@
 /** {@link ObjectToPack} for {@link ObjectDirectory}. */
 class LocalObjectToPack extends ObjectToPack {
 	/** Pack to reuse compressed data from, otherwise null. */
-	PackFile pack;
+	Pack pack;
 
 	/** Offset of the object's header in {@link #pack}. */
 	long offset;
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 4a40db6..e71a960 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
@@ -51,7 +51,7 @@
  * This is the classical object database representation for a Git repository,
  * where objects are stored loose by hashing them into directories by their
  * {@link org.eclipse.jgit.lib.ObjectId}, or are stored in compressed containers
- * known as {@link org.eclipse.jgit.internal.storage.file.PackFile}s.
+ * known as {@link org.eclipse.jgit.internal.storage.file.Pack}s.
  * <p>
  * Optionally an object database can reference one or more alternates; other
  * ObjectDatabase instances that are searched in addition to the current
@@ -206,7 +206,7 @@
 
 	/** {@inheritDoc} */
 	@Override
-	public Collection<PackFile> getPacks() {
+	public Collection<Pack> getPacks() {
 		return packed.getPacks();
 	}
 
@@ -216,7 +216,7 @@
 	 * Add a single existing pack to the list of available pack files.
 	 */
 	@Override
-	public PackFile openPack(File pack)
+	public Pack openPack(File pack)
 			throws IOException {
 		final String p = pack.getName();
 		if (p.length() != 50 || !p.startsWith("pack-") || !p.endsWith(".pack")) //$NON-NLS-1$ //$NON-NLS-2$
@@ -235,7 +235,7 @@
 			}
 		}
 
-		PackFile res = new PackFile(pack, extensions);
+		Pack res = new Pack(pack, extensions);
 		packed.insert(res);
 		return res;
 	}
@@ -509,7 +509,7 @@
 		// PackConfig) then make sure we get rid of all handles on the file.
 		// Windows will not allow for rename otherwise.
 		if (packFile.exists()) {
-			for (PackFile p : packed.getPacks()) {
+			for (Pack p : packed.getPacks()) {
 				if (packFile.getPath().equals(p.getPackFile().getPath())) {
 					p.close();
 					break;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectoryPackParser.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectoryPackParser.java
index e275186..04d2ff8 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectoryPackParser.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectoryPackParser.java
@@ -88,7 +88,7 @@
 	private Deflater def;
 
 	/** The pack that was created, if parsing was successful. */
-	private PackFile newPack;
+	private Pack newPack;
 
 	private PackConfig pconfig;
 
@@ -129,14 +129,14 @@
 	}
 
 	/**
-	 * Get the imported {@link org.eclipse.jgit.internal.storage.file.PackFile}.
+	 * Get the imported {@link org.eclipse.jgit.internal.storage.file.Pack}.
 	 * <p>
 	 * This method is supplied only to support testing; applications shouldn't
 	 * be using it directly to access the imported data.
 	 *
 	 * @return the imported PackFile, if parsing was successful.
 	 */
-	public PackFile getPackFile() {
+	public Pack getPack() {
 		return newPack;
 	}
 
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackFile.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/Pack.java
similarity index 98%
rename from org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackFile.java
rename to org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/Pack.java
index e112fe7..d928633 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackFile.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/Pack.java
@@ -69,13 +69,13 @@
  * delta packed format yielding high compression of lots of object where some
  * objects are similar.
  */
-public class PackFile implements Iterable<PackIndex.MutableEntry> {
-	private static final Logger LOG = LoggerFactory.getLogger(PackFile.class);
+public class Pack implements Iterable<PackIndex.MutableEntry> {
+	private static final Logger LOG = LoggerFactory.getLogger(Pack.class);
 
 	/**
 	 * Sorts PackFiles to be most recently created to least recently created.
 	 */
-	public static final Comparator<PackFile> SORT = (a, b) -> b.packLastModified
+	public static final Comparator<Pack> SORT = (a, b) -> b.packLastModified
 			.compareTo(a.packLastModified);
 
 	private final File packFile;
@@ -136,7 +136,7 @@
 	 * @param extensions
 	 *            additional pack file extensions with the same base as the pack
 	 */
-	public PackFile(File packFile, int extensions) {
+	public Pack(File packFile, int extensions) {
 		this.packFile = packFile;
 		this.fileSnapshot = PackFileSnapshot.save(packFile);
 		this.packLastModified = fileSnapshot.lastModifiedInstant();
@@ -1201,7 +1201,7 @@
 	@SuppressWarnings("nls")
 	@Override
 	public String toString() {
-		return "PackFile [packFileName=" + packFile.getName() + ", length="
+		return "Pack [packFileName=" + packFile.getName() + ", length="
 				+ packFile.length() + ", packChecksum="
 				+ ObjectId.fromRaw(packChecksum).name() + "]";
 	}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackDirectory.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackDirectory.java
index fd9da7c..b2ba36b 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackDirectory.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackDirectory.java
@@ -47,16 +47,17 @@
 /**
  * Traditional file system packed objects directory handler.
  * <p>
- * This is the {@code PackFile}s object representation for a Git object
- * database, where objects are stored in compressed containers known as
- * {@link org.eclipse.jgit.internal.storage.file.PackFile}s.
+ * This is the {@link org.eclipse.jgit.internal.storage.file.Pack}s object
+ * representation for a Git object database, where objects are stored in
+ * compressed containers known as
+ * {@link org.eclipse.jgit.internal.storage.file.Pack}s.
  */
 class PackDirectory {
 	private final static Logger LOG = LoggerFactory
 			.getLogger(PackDirectory.class);
 
 	private static final PackList NO_PACKS = new PackList(FileSnapshot.DIRTY,
-			new PackFile[0]);
+			new Pack[0]);
 
 	private final Config config;
 
@@ -94,18 +95,18 @@
 	void close() {
 		PackList packs = packList.get();
 		if (packs != NO_PACKS && packList.compareAndSet(packs, NO_PACKS)) {
-			for (PackFile p : packs.packs) {
+			for (Pack p : packs.packs) {
 				p.close();
 			}
 		}
 	}
 
-	Collection<PackFile> getPacks() {
+	Collection<Pack> getPacks() {
 		PackList list = packList.get();
 		if (list == NO_PACKS) {
 			list = scanPacks(list);
 		}
-		PackFile[] packs = list.packs;
+		Pack[] packs = list.packs;
 		return Collections.unmodifiableCollection(Arrays.asList(packs));
 	}
 
@@ -126,7 +127,7 @@
 		PackList pList;
 		do {
 			pList = packList.get();
-			for (PackFile p : pList.packs) {
+			for (Pack p : pList.packs) {
 				try {
 					if (p.hasObject(objectId)) {
 						return true;
@@ -167,7 +168,7 @@
 		PackList pList;
 		do {
 			pList = packList.get();
-			for (PackFile p : pList.packs) {
+			for (Pack p : pList.packs) {
 				try {
 					p.resolve(matches, id, matchLimit);
 					p.resetTransientErrorCount();
@@ -187,7 +188,7 @@
 		do {
 			SEARCH: for (;;) {
 				pList = packList.get();
-				for (PackFile p : pList.packs) {
+				for (Pack p : pList.packs) {
 					try {
 						ObjectLoader ldr = p.get(curs, objectId);
 						p.resetTransientErrorCount();
@@ -213,7 +214,7 @@
 		do {
 			SEARCH: for (;;) {
 				pList = packList.get();
-				for (PackFile p : pList.packs) {
+				for (Pack p : pList.packs) {
 					try {
 						long len = p.getObjectSize(curs, id);
 						p.resetTransientErrorCount();
@@ -239,7 +240,7 @@
 			WindowCursor curs) {
 		PackList pList = packList.get();
 		SEARCH: for (;;) {
-			for (PackFile p : pList.packs) {
+			for (Pack p : pList.packs) {
 				try {
 					LocalObjectRepresentation rep = p.representation(curs, otp);
 					p.resetTransientErrorCount();
@@ -259,7 +260,7 @@
 		}
 	}
 
-	private void handlePackError(IOException e, PackFile p) {
+	private void handlePackError(IOException e, Pack p) {
 		String warnTmpl = null;
 		int transientErrorCount = 0;
 		String errTmpl = JGitText.get().exceptionWhileReadingPack;
@@ -322,7 +323,7 @@
 				&& old != scanPacks(old);
 	}
 
-	void insert(PackFile pf) {
+	void insert(Pack pack) {
 		PackList o, n;
 		do {
 			o = packList.get();
@@ -331,33 +332,33 @@
 			// (picked up by a concurrent thread that did a scan?) we
 			// do not want to insert it a second time.
 			//
-			final PackFile[] oldList = o.packs;
-			final String name = pf.getPackFile().getName();
-			for (PackFile p : oldList) {
+			final Pack[] oldList = o.packs;
+			final String name = pack.getPackFile().getName();
+			for (Pack p : oldList) {
 				if (name.equals(p.getPackFile().getName())) {
 					return;
 				}
 			}
 
-			final PackFile[] newList = new PackFile[1 + oldList.length];
-			newList[0] = pf;
+			final Pack[] newList = new Pack[1 + oldList.length];
+			newList[0] = pack;
 			System.arraycopy(oldList, 0, newList, 1, oldList.length);
 			n = new PackList(o.snapshot, newList);
 		} while (!packList.compareAndSet(o, n));
 	}
 
-	private void remove(PackFile deadPack) {
+	private void remove(Pack deadPack) {
 		PackList o, n;
 		do {
 			o = packList.get();
 
-			final PackFile[] oldList = o.packs;
+			final Pack[] oldList = o.packs;
 			final int j = indexOf(oldList, deadPack);
 			if (j < 0) {
 				break;
 			}
 
-			final PackFile[] newList = new PackFile[oldList.length - 1];
+			final Pack[] newList = new Pack[oldList.length - 1];
 			System.arraycopy(oldList, 0, newList, 0, j);
 			System.arraycopy(oldList, j + 1, newList, j, newList.length - j);
 			n = new PackList(o.snapshot, newList);
@@ -365,7 +366,7 @@
 		deadPack.close();
 	}
 
-	private static int indexOf(PackFile[] list, PackFile pack) {
+	private static int indexOf(Pack[] list, Pack pack) {
 		for (int i = 0; i < list.length; i++) {
 			if (list[i] == pack) {
 				return i;
@@ -395,10 +396,10 @@
 	}
 
 	private PackList scanPacksImpl(PackList old) {
-		final Map<String, PackFile> forReuse = reuseMap(old);
+		final Map<String, Pack> forReuse = reuseMap(old);
 		final FileSnapshot snapshot = FileSnapshot.save(directory);
 		final Set<String> names = listPackDirectory();
-		final List<PackFile> list = new ArrayList<>(names.size() >> 2);
+		final List<Pack> list = new ArrayList<>(names.size() >> 2);
 		boolean foundNew = false;
 		for (String indexName : names) {
 			// Must match "pack-[0-9a-f]{40}.idx" to be an index.
@@ -425,7 +426,7 @@
 
 			final String packName = base + PACK.getExtension();
 			final File packFile = new File(directory, packName);
-			final PackFile oldPack = forReuse.get(packName);
+			final Pack oldPack = forReuse.get(packName);
 			if (oldPack != null
 					&& !oldPack.getFileSnapshot().isModified(packFile)) {
 				forReuse.remove(packName);
@@ -433,7 +434,7 @@
 				continue;
 			}
 
-			list.add(new PackFile(packFile, extensions));
+			list.add(new Pack(packFile, extensions));
 			foundNew = true;
 		}
 
@@ -447,7 +448,7 @@
 			return old;
 		}
 
-		for (PackFile p : forReuse.values()) {
+		for (Pack p : forReuse.values()) {
 			p.close();
 		}
 
@@ -455,14 +456,14 @@
 			return new PackList(snapshot, NO_PACKS.packs);
 		}
 
-		final PackFile[] r = list.toArray(new PackFile[0]);
-		Arrays.sort(r, PackFile.SORT);
+		final Pack[] r = list.toArray(new Pack[0]);
+		Arrays.sort(r, Pack.SORT);
 		return new PackList(snapshot, r);
 	}
 
-	private static Map<String, PackFile> reuseMap(PackList old) {
-		final Map<String, PackFile> forReuse = new HashMap<>();
-		for (PackFile p : old.packs) {
+	private static Map<String, Pack> reuseMap(PackList old) {
+		final Map<String, Pack> forReuse = new HashMap<>();
+		for (Pack p : old.packs) {
 			if (p.invalid()) {
 				// The pack instance is corrupted, and cannot be safely used
 				// again. Do not include it in our reuse map.
@@ -471,7 +472,7 @@
 				continue;
 			}
 
-			final PackFile prior = forReuse.put(p.getPackFile().getName(), p);
+			final Pack prior = forReuse.put(p.getPackFile().getName(), p);
 			if (prior != null) {
 				// This should never occur. It should be impossible for us
 				// to have two pack files with the same name, as all of them
@@ -504,10 +505,10 @@
 		/** State just before reading the pack directory. */
 		final FileSnapshot snapshot;
 
-		/** All known packs, sorted by {@link PackFile#SORT}. */
-		final PackFile[] packs;
+		/** All known packs, sorted by {@link Pack#SORT}. */
+		final Pack[] packs;
 
-		PackList(FileSnapshot monitor, PackFile[] packs) {
+		PackList(FileSnapshot monitor, Pack[] packs) {
 			this.snapshot = monitor;
 			this.packs = packs;
 		}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackIndex.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackIndex.java
index 31686be..942cc96 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackIndex.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackIndex.java
@@ -34,7 +34,7 @@
 
 /**
  * Access path to locate objects by {@link org.eclipse.jgit.lib.ObjectId} in a
- * {@link org.eclipse.jgit.internal.storage.file.PackFile}.
+ * {@link org.eclipse.jgit.internal.storage.file.Pack}.
  * <p>
  * Indexes are strictly redundant information in that we can rebuild all of the
  * data held in the index file from the on disk representation of the pack file
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackIndexWriter.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackIndexWriter.java
index 612b123..87e0b44 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackIndexWriter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackIndexWriter.java
@@ -25,7 +25,7 @@
 
 /**
  * Creates a table of contents to support random access by
- * {@link org.eclipse.jgit.internal.storage.file.PackFile}.
+ * {@link org.eclipse.jgit.internal.storage.file.Pack}.
  * <p>
  * Pack index files (the <code>.idx</code> suffix in a pack file pair) provides
  * random access to any object in the pack by associating an ObjectId to the
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackInputStream.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackInputStream.java
index a9e0588..0bceca7 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackInputStream.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackInputStream.java
@@ -16,11 +16,11 @@
 class PackInputStream extends InputStream {
 	private final WindowCursor wc;
 
-	private final PackFile pack;
+	private final Pack pack;
 
 	private long pos;
 
-	PackInputStream(PackFile pack, long pos, WindowCursor wc)
+	PackInputStream(Pack pack, long pos, WindowCursor wc)
 			throws IOException {
 		this.pack = pack;
 		this.pos = pos;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackLock.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackLock.java
index 2c2f791..482b143 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackLock.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackLock.java
@@ -18,7 +18,7 @@
 import org.eclipse.jgit.util.FileUtils;
 
 /**
- * Keeps track of a {@link org.eclipse.jgit.internal.storage.file.PackFile}'s
+ * Keeps track of a {@link org.eclipse.jgit.internal.storage.file.Pack}'s
  * associated <code>.keep</code> file.
  */
 public class PackLock {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackReverseIndex.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackReverseIndex.java
index 4d80a03..ee458e2 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackReverseIndex.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackReverseIndex.java
@@ -25,7 +25,7 @@
  * </p>
  *
  * @see PackIndex
- * @see PackFile
+ * @see Pack
  */
 public class PackReverseIndex {
 	/** Index we were created from, and that has our ObjectId data. */
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/RefDirectoryRename.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/RefDirectoryRename.java
index 9dbdbc7..2c0ade6 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/RefDirectoryRename.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/RefDirectoryRename.java
@@ -51,9 +51,6 @@
 	 */
 	private ObjectId objId;
 
-	/** True if HEAD must be moved to the destination reference. */
-	private boolean updateHEAD;
-
 	/** A reference we backup {@link #objId} into during the rename. */
 	private RefDirectoryUpdate tmp;
 
@@ -69,7 +66,7 @@
 			return Result.IO_FAILURE; // not supported
 
 		objId = source.getOldObjectId();
-		updateHEAD = needToUpdateHEAD();
+		boolean updateHEAD = needToUpdateHEAD();
 		tmp = refdb.newTemporaryUpdate();
 		try (RevWalk rw = new RevWalk(refdb.getRepository())) {
 			// First backup the source so its never unreachable.
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 3e8cb3a..25653b3 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
@@ -33,7 +33,7 @@
 import org.eclipse.jgit.util.Monitoring;
 
 /**
- * Caches slices of a {@link org.eclipse.jgit.internal.storage.file.PackFile} in
+ * Caches slices of a {@link org.eclipse.jgit.internal.storage.file.Pack} in
  * memory for faster read access.
  * <p>
  * The WindowCache serves as a Java based "buffer cache", loading segments of a
@@ -41,7 +41,7 @@
  * only tiny slices of a file, the WindowCache tries to smooth out these tiny
  * reads into larger block-sized IO operations.
  * <p>
- * Whenever a cache miss occurs, {@link #load(PackFile, long)} is invoked by
+ * Whenever a cache miss occurs, {@link #load(Pack, long)} is invoked by
  * exactly one thread for the given <code>(PackFile,position)</code> key tuple.
  * This is ensured by an array of locks, with the tuple hashed to a lock
  * instance.
@@ -80,10 +80,10 @@
  * <p>
  * This cache has an implementation rule such that:
  * <ul>
- * <li>{@link #load(PackFile, long)} is invoked by at most one thread at a time
+ * <li>{@link #load(Pack, long)} is invoked by at most one thread at a time
  * for a given <code>(PackFile,position)</code> tuple.</li>
  * <li>For every <code>load()</code> invocation there is exactly one
- * {@link #createRef(PackFile, long, ByteWindow)} invocation to wrap a
+ * {@link #createRef(Pack, long, ByteWindow)} invocation to wrap a
  * SoftReference or a StrongReference around the cached entity.</li>
  * <li>For every Reference created by <code>createRef()</code> there will be
  * exactly one call to {@link #clear(PageRef)} to cleanup any resources associated
@@ -91,10 +91,10 @@
  * </ul>
  * <p>
  * Therefore, it is safe to perform resource accounting increments during the
- * {@link #load(PackFile, long)} or
- * {@link #createRef(PackFile, long, ByteWindow)} methods, and matching
+ * {@link #load(Pack, long)} or
+ * {@link #createRef(Pack, long, ByteWindow)} methods, and matching
  * decrements during {@link #clear(PageRef)}. Implementors may need to override
- * {@link #createRef(PackFile, long, ByteWindow)} in order to embed additional
+ * {@link #createRef(Pack, long, ByteWindow)} in order to embed additional
  * accounting information into an implementation specific
  * {@link org.eclipse.jgit.internal.storage.file.WindowCache.PageRef} subclass, as
  * the cached entity may have already been evicted by the JRE's garbage
@@ -170,7 +170,7 @@
 		 * @param delta
 		 *            delta of cached bytes
 		 */
-		void recordOpenBytes(PackFile pack, int delta);
+		void recordOpenBytes(Pack pack, int delta);
 
 		/**
 		 * Returns a snapshot of this recorder's stats. Note that this may be an
@@ -242,7 +242,7 @@
 		}
 
 		@Override
-		public void recordOpenBytes(PackFile pack, int delta) {
+		public void recordOpenBytes(Pack pack, int delta) {
 			openByteCount.add(delta);
 			String repositoryId = repositoryId(pack);
 			LongAdder la = openByteCountPerRepository
@@ -254,9 +254,8 @@
 			}
 		}
 
-		private static String repositoryId(PackFile pack) {
-			// use repository's gitdir since packfile doesn't know its
-			// repository
+		private static String repositoryId(Pack pack) {
+			// use repository's gitdir since Pack doesn't know its repository
 			return pack.getPackFile().getParentFile().getParentFile()
 					.getParent();
 		}
@@ -380,7 +379,7 @@
 		return cache.publishMBeanIfNeeded();
 	}
 
-	static final ByteWindow get(PackFile pack, long offset)
+	static final ByteWindow get(Pack pack, long offset)
 			throws IOException {
 		final WindowCache c = cache;
 		final ByteWindow r = c.getOrLoad(pack, c.toStart(offset));
@@ -395,7 +394,7 @@
 		return r;
 	}
 
-	static final void purge(PackFile pack) {
+	static final void purge(Pack pack) {
 		cache.removeAll(pack);
 	}
 
@@ -506,7 +505,7 @@
 		return packHash + (int) (off >>> windowSizeShift);
 	}
 
-	private ByteWindow load(PackFile pack, long offset) throws IOException {
+	private ByteWindow load(Pack pack, long offset) throws IOException {
 		long startTime = System.nanoTime();
 		if (pack.beginWindowCache())
 			statsRecorder.recordOpenFiles(1);
@@ -525,7 +524,7 @@
 		}
 	}
 
-	private PageRef<ByteWindow> createRef(PackFile p, long o, ByteWindow v) {
+	private PageRef<ByteWindow> createRef(Pack p, long o, ByteWindow v) {
 		final PageRef<ByteWindow> ref = useStrongRefs
 				? new StrongRef(p, o, v, queue)
 				: new SoftRef(p, o, v, (SoftCleanupQueue) queue);
@@ -539,7 +538,7 @@
 		close(ref.getPack());
 	}
 
-	private void close(PackFile pack) {
+	private void close(Pack pack) {
 		if (pack.endWindowCache()) {
 			statsRecorder.recordOpenFiles(-1);
 		}
@@ -578,9 +577,9 @@
 	 * @return the object reference.
 	 * @throws IOException
 	 *             the object reference was not in the cache and could not be
-	 *             obtained by {@link #load(PackFile, long)}.
+	 *             obtained by {@link #load(Pack, long)}.
 	 */
-	private ByteWindow getOrLoad(PackFile pack, long position)
+	private ByteWindow getOrLoad(Pack pack, long position)
 			throws IOException {
 		final int slot = slot(pack, position);
 		final Entry e1 = table.get(slot);
@@ -623,7 +622,7 @@
 		return v;
 	}
 
-	private ByteWindow scan(Entry n, PackFile pack, long position) {
+	private ByteWindow scan(Entry n, Pack pack, long position) {
 		for (; n != null; n = n.next) {
 			final PageRef<ByteWindow> r = n.ref;
 			if (r.getPack() == pack && r.getPosition() == position) {
@@ -704,7 +703,7 @@
 	/**
 	 * Clear all entries related to a single file.
 	 * <p>
-	 * Typically this method is invoked during {@link PackFile#close()}, when we
+	 * Typically this method is invoked during {@link Pack#close()}, when we
 	 * know the pack is never going to be useful to us again (for example, it no
 	 * longer exists on disk). A concurrent reader loading an entry from this
 	 * same pack may cause the pack to become stuck in the cache anyway.
@@ -712,7 +711,7 @@
 	 * @param pack
 	 *            the file to purge all entries of.
 	 */
-	private void removeAll(PackFile pack) {
+	private void removeAll(Pack pack) {
 		for (int s = 0; s < tableSize; s++) {
 			final Entry e1 = table.get(s);
 			boolean hasDead = false;
@@ -733,11 +732,11 @@
 		queue.gc();
 	}
 
-	private int slot(PackFile pack, long position) {
+	private int slot(Pack pack, long position) {
 		return (hash(pack.hash, position) >>> 1) % tableSize;
 	}
 
-	private Lock lock(PackFile pack, long position) {
+	private Lock lock(Pack pack, long position) {
 		return locks[(hash(pack.hash, position) >>> 1) % locks.length];
 	}
 
@@ -799,16 +798,20 @@
 		boolean kill();
 
 		/**
-		 * Get the packfile the referenced cache page is allocated for
+		 * Get the {@link org.eclipse.jgit.internal.storage.file.Pack} the
+		 * referenced cache page is allocated for
 		 *
-		 * @return the packfile the referenced cache page is allocated for
+		 * @return the {@link org.eclipse.jgit.internal.storage.file.Pack} the
+		 *         referenced cache page is allocated for
 		 */
-		PackFile getPack();
+		Pack getPack();
 
 		/**
-		 * Get the position of the referenced cache page in the packfile
+		 * Get the position of the referenced cache page in the
+		 * {@link org.eclipse.jgit.internal.storage.file.Pack}
 		 *
-		 * @return the position of the referenced cache page in the packfile
+		 * @return the position of the referenced cache page in the
+		 *         {@link org.eclipse.jgit.internal.storage.file.Pack}
 		 */
 		long getPosition();
 
@@ -844,7 +847,7 @@
 	/** A soft reference wrapped around a cached object. */
 	private static class SoftRef extends SoftReference<ByteWindow>
 			implements PageRef<ByteWindow> {
-		private final PackFile pack;
+		private final Pack pack;
 
 		private final long position;
 
@@ -852,7 +855,7 @@
 
 		private long lastAccess;
 
-		protected SoftRef(final PackFile pack, final long position,
+		protected SoftRef(final Pack pack, final long position,
 				final ByteWindow v, final SoftCleanupQueue queue) {
 			super(v, queue);
 			this.pack = pack;
@@ -861,7 +864,7 @@
 		}
 
 		@Override
-		public PackFile getPack() {
+		public Pack getPack() {
 			return pack;
 		}
 
@@ -900,7 +903,7 @@
 	private static class StrongRef implements PageRef<ByteWindow> {
 		private ByteWindow referent;
 
-		private final PackFile pack;
+		private final Pack pack;
 
 		private final long position;
 
@@ -910,7 +913,7 @@
 
 		private CleanupQueue queue;
 
-		protected StrongRef(final PackFile pack, final long position,
+		protected StrongRef(final Pack pack, final long position,
 				final ByteWindow v, final CleanupQueue queue) {
 			this.pack = pack;
 			this.position = position;
@@ -920,7 +923,7 @@
 		}
 
 		@Override
-		public PackFile getPack() {
+		public Pack getPack() {
 			return pack;
 		}
 
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/WindowCursor.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/WindowCursor.java
index 6c97570..e7fd7b9 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/WindowCursor.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/WindowCursor.java
@@ -86,7 +86,7 @@
 	/** {@inheritDoc} */
 	@Override
 	public BitmapIndex getBitmapIndex() throws IOException {
-		for (PackFile pack : db.getPacks()) {
+		for (Pack pack : db.getPacks()) {
 			PackBitmapIndex index = pack.getBitmapIndex();
 			if (index != null)
 				return new BitmapIndexImpl(index);
@@ -98,7 +98,7 @@
 	@Override
 	public Collection<CachedPack> getCachedPacksAndUpdate(
 			BitmapBuilder needBitmap) throws IOException {
-		for (PackFile pack : db.getPacks()) {
+		for (Pack pack : db.getPacks()) {
 			PackBitmapIndex index = pack.getBitmapIndex();
 			if (needBitmap.removeAllOrNone(index))
 				return Collections.<CachedPack> singletonList(
@@ -218,7 +218,7 @@
 	 *             this cursor does not match the provider or id and the proper
 	 *             window could not be acquired through the provider's cache.
 	 */
-	int copy(final PackFile pack, long position, final byte[] dstbuf,
+	int copy(final Pack pack, long position, final byte[] dstbuf,
 			int dstoff, final int cnt) throws IOException {
 		final long length = pack.length;
 		int need = cnt;
@@ -239,7 +239,7 @@
 		((LocalCachedPack) pack).copyAsIs(out, this);
 	}
 
-	void copyPackAsIs(final PackFile pack, final long length,
+	void copyPackAsIs(final Pack pack, final long length,
 			final PackOutputStream out) throws IOException {
 		long position = 12;
 		long remaining = length - (12 + 20);
@@ -275,7 +275,7 @@
 	 *             the inflater encountered an invalid chunk of data. Data
 	 *             stream corruption is likely.
 	 */
-	int inflate(final PackFile pack, long position, final byte[] dstbuf,
+	int inflate(final Pack pack, long position, final byte[] dstbuf,
 			boolean headerOnly) throws IOException, DataFormatException {
 		prepareInflater();
 		pin(pack, position);
@@ -293,7 +293,7 @@
 		}
 	}
 
-	ByteArrayWindow quickCopy(PackFile p, long pos, long cnt)
+	ByteArrayWindow quickCopy(Pack p, long pos, long cnt)
 			throws IOException {
 		pin(p, pos);
 		if (window instanceof ByteArrayWindow
@@ -314,7 +314,7 @@
 			inf.reset();
 	}
 
-	void pin(PackFile pack, long position)
+	void pin(Pack pack, long position)
 			throws IOException {
 		final ByteWindow w = window;
 		if (w == null || !w.contains(pack, position)) {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/BaseRepositoryBuilder.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/BaseRepositoryBuilder.java
index e51995f..b2242a1 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/BaseRepositoryBuilder.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/BaseRepositoryBuilder.java
@@ -28,6 +28,8 @@
 import java.util.LinkedList;
 import java.util.List;
 
+import org.eclipse.jgit.annotations.NonNull;
+import org.eclipse.jgit.api.errors.InvalidRefNameException;
 import org.eclipse.jgit.errors.ConfigInvalidException;
 import org.eclipse.jgit.errors.RepositoryNotFoundException;
 import org.eclipse.jgit.internal.JGitText;
@@ -38,6 +40,7 @@
 import org.eclipse.jgit.util.FS;
 import org.eclipse.jgit.util.IO;
 import org.eclipse.jgit.util.RawParseUtils;
+import org.eclipse.jgit.util.StringUtils;
 import org.eclipse.jgit.util.SystemReader;
 
 /**
@@ -107,6 +110,8 @@
 
 	private File workTree;
 
+	private String initialBranch = Constants.MASTER;
+
 	/** Directories limiting the search for a Git repository. */
 	private List<File> ceilingDirectories;
 
@@ -350,6 +355,43 @@
 	}
 
 	/**
+	 * Set the initial branch of the new repository. If not specified
+	 * ({@code null} or empty), fall back to the default name (currently
+	 * master).
+	 *
+	 * @param branch
+	 *            initial branch name of the new repository. If {@code null} or
+	 *            empty the configured default branch will be used.
+	 * @return {@code this}
+	 * @throws InvalidRefNameException
+	 *             if the branch name is not valid
+	 *
+	 * @since 5.11
+	 */
+	public B setInitialBranch(String branch) throws InvalidRefNameException {
+		if (StringUtils.isEmptyOrNull(branch)) {
+			this.initialBranch = Constants.MASTER;
+		} else {
+			if (!Repository.isValidRefName(Constants.R_HEADS + branch)) {
+				throw new InvalidRefNameException(MessageFormat
+						.format(JGitText.get().branchNameInvalid, branch));
+			}
+			this.initialBranch = branch;
+		}
+		return self();
+	}
+
+	/**
+	 * Get the initial branch of the new repository.
+	 *
+	 * @return the initial branch of the new repository.
+	 * @since 5.11
+	 */
+	public @NonNull String getInitialBranch() {
+		return initialBranch;
+	}
+
+	/**
 	 * Read standard Git environment variables and configure from those.
 	 * <p>
 	 * This method tries to read the standard Git environment variables, such as
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java
index 954a75c..03c1ef9 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java
@@ -105,7 +105,15 @@
 	public static final String CONFIG_KEY_FORMAT = "format";
 
 	/**
+	 * The "program" key
+	 *
+	 * @since 5.11
+	 */
+	public static final String CONFIG_KEY_PROGRAM = "program";
+
+	/**
 	 * The "signingKey" key
+	 *
 	 * @since 5.2
 	 */
 	public static final String CONFIG_KEY_SIGNINGKEY = "signingKey";
@@ -707,4 +715,17 @@
 	 */
 	public static final String CONFIG_KEY_VERSION = "version";
 
+	/**
+	 * The "init" section
+	 *
+	 * @since 5.11
+	 */
+	public static final String CONFIG_INIT_SECTION = "init";
+
+	/**
+	 * The "defaultBranch" key
+	 *
+	 * @since 5.11
+	 */
+	public static final String CONFIG_KEY_DEFAULT_BRANCH = "defaultbranch";
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/GpgConfig.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/GpgConfig.java
index 5b43729..427a235 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/GpgConfig.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/GpgConfig.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2018, Salesforce. and others
+ * Copyright (C) 2018, 2021 Salesforce and others
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Distribution License v. 1.0 which is available at
@@ -43,16 +43,65 @@
 		}
 	}
 
-	private final Config config;
+	private final GpgFormat keyFormat;
+
+	private final String signingKey;
+
+	private final String program;
+
+	private final boolean signCommits;
+
+	private final boolean signAllTags;
+
+	private final boolean forceAnnotated;
 
 	/**
-	 * Create a new GPG config, which will read configuration from config.
+	 * Create a {@link GpgConfig} with the given parameters and default
+	 * {@code true} for signing commits and {@code false} for tags.
+	 *
+	 * @param keySpec
+	 *            to use
+	 * @param format
+	 *            to use
+	 * @param gpgProgram
+	 *            to use
+	 * @since 5.11
+	 */
+	public GpgConfig(String keySpec, GpgFormat format, String gpgProgram) {
+		keyFormat = format;
+		signingKey = keySpec;
+		program = gpgProgram;
+		signCommits = true;
+		signAllTags = false;
+		forceAnnotated = false;
+	}
+
+	/**
+	 * Create a new GPG config that reads the configuration from config.
 	 *
 	 * @param config
 	 *            the config to read from
 	 */
 	public GpgConfig(Config config) {
-		this.config = config;
+		keyFormat = config.getEnum(GpgFormat.values(),
+				ConfigConstants.CONFIG_GPG_SECTION, null,
+				ConfigConstants.CONFIG_KEY_FORMAT, GpgFormat.OPENPGP);
+		signingKey = config.getString(ConfigConstants.CONFIG_USER_SECTION, null,
+				ConfigConstants.CONFIG_KEY_SIGNINGKEY);
+
+		String exe = config.getString(ConfigConstants.CONFIG_GPG_SECTION,
+				keyFormat.toConfigValue(), ConfigConstants.CONFIG_KEY_PROGRAM);
+		if (exe == null) {
+			exe = config.getString(ConfigConstants.CONFIG_GPG_SECTION, null,
+					ConfigConstants.CONFIG_KEY_PROGRAM);
+		}
+		program = exe;
+		signCommits = config.getBoolean(ConfigConstants.CONFIG_COMMIT_SECTION,
+				ConfigConstants.CONFIG_KEY_GPGSIGN, false);
+		signAllTags = config.getBoolean(ConfigConstants.CONFIG_TAG_SECTION,
+				ConfigConstants.CONFIG_KEY_GPGSIGN, false);
+		forceAnnotated = config.getBoolean(ConfigConstants.CONFIG_TAG_SECTION,
+				ConfigConstants.CONFIG_KEY_FORCE_SIGN_ANNOTATED, false);
 	}
 
 	/**
@@ -61,9 +110,19 @@
 	 * @return the {@link org.eclipse.jgit.lib.GpgConfig.GpgFormat}
 	 */
 	public GpgFormat getKeyFormat() {
-		return config.getEnum(GpgFormat.values(),
-				ConfigConstants.CONFIG_GPG_SECTION, null,
-				ConfigConstants.CONFIG_KEY_FORMAT, GpgFormat.OPENPGP);
+		return keyFormat;
+	}
+
+	/**
+	 * Retrieves the value of the configured GPG program to use, as defined by
+	 * gpg.openpgp.program, gpg.x509.program (depending on the defined
+	 * {@link #getKeyFormat() format}), or gpg.program.
+	 *
+	 * @return the program string configured, or {@code null} if none
+	 * @since 5.11
+	 */
+	public String getProgram() {
+		return program;
 	}
 
 	/**
@@ -72,8 +131,7 @@
 	 * @return the value of user.signingKey (may be <code>null</code>)
 	 */
 	public String getSigningKey() {
-		return config.getString(ConfigConstants.CONFIG_USER_SECTION, null,
-				ConfigConstants.CONFIG_KEY_SIGNINGKEY);
+		return signingKey;
 	}
 
 	/**
@@ -82,8 +140,7 @@
 	 * @return the value of commit.gpgSign (defaults to <code>false</code>)
 	 */
 	public boolean isSignCommits() {
-		return config.getBoolean(ConfigConstants.CONFIG_COMMIT_SECTION,
-				ConfigConstants.CONFIG_KEY_GPGSIGN, false);
+		return signCommits;
 	}
 
 	/**
@@ -94,8 +151,7 @@
 	 * @since 5.11
 	 */
 	public boolean isSignAllTags() {
-		return config.getBoolean(ConfigConstants.CONFIG_TAG_SECTION,
-				ConfigConstants.CONFIG_KEY_GPGSIGN, false);
+		return signAllTags;
 	}
 
 	/**
@@ -107,7 +163,6 @@
 	 * @since 5.11
 	 */
 	public boolean isSignAnnotated() {
-		return config.getBoolean(ConfigConstants.CONFIG_TAG_SECTION,
-						ConfigConstants.CONFIG_KEY_FORCE_SIGN_ANNOTATED, false);
+		return forceAnnotated;
 	}
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/GpgObjectSigner.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/GpgObjectSigner.java
index 6fb7677..074f465 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/GpgObjectSigner.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/GpgObjectSigner.java
@@ -12,6 +12,7 @@
 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.UnsupportedSigningFormatException;
 import org.eclipse.jgit.transport.CredentialsProvider;
 
 /**
@@ -48,12 +49,47 @@
 	 * @param credentialsProvider
 	 *            provider to use when querying for signing key credentials (eg.
 	 *            passphrase)
+	 * @param config
+	 *            GPG settings from the git config
 	 * @throws CanceledException
 	 *             when signing was canceled (eg., user aborted when entering
 	 *             passphrase)
+	 * @throws UnsupportedSigningFormatException
+	 *             if a config is given and the wanted key format is not
+	 *             supported
 	 */
 	void signObject(@NonNull ObjectBuilder object,
 			@Nullable String gpgSigningKey, @NonNull PersonIdent committer,
-			CredentialsProvider credentialsProvider) throws CanceledException;
+			CredentialsProvider credentialsProvider, GpgConfig config)
+			throws CanceledException, UnsupportedSigningFormatException;
+
+	/**
+	 * 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)
+	 * @param config
+	 *            GPG settings from the git config
+	 * @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)
+	 * @throws UnsupportedSigningFormatException
+	 *             if a config is given and the wanted key format is not
+	 *             supported
+	 */
+	public abstract boolean canLocateSigningKey(@Nullable String gpgSigningKey,
+			@NonNull PersonIdent committer,
+			CredentialsProvider credentialsProvider, GpgConfig config)
+			throws CanceledException, UnsupportedSigningFormatException;
 
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/GpgSignatureVerifier.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/GpgSignatureVerifier.java
new file mode 100644
index 0000000..a7a39c9
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/GpgSignatureVerifier.java
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2021, Thomas Wolf <thomas.wolf@paranor.ch> and others
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0 which is available at
+ * https://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+package org.eclipse.jgit.lib;
+
+import java.io.IOException;
+import java.util.Date;
+
+import org.eclipse.jgit.annotations.NonNull;
+import org.eclipse.jgit.annotations.Nullable;
+import org.eclipse.jgit.api.errors.JGitInternalException;
+import org.eclipse.jgit.revwalk.RevObject;
+
+/**
+ * A {@code GpgVerifier} can verify GPG signatures on git commits and tags.
+ *
+ * @since 5.11
+ */
+public interface GpgSignatureVerifier {
+
+	/**
+	 * Verifies the signature on a signed commit or tag.
+	 *
+	 * @param object
+	 *            to verify
+	 * @param config
+	 *            the {@link GpgConfig} to use
+	 * @return a {@link SignatureVerification} describing the outcome of the
+	 *         verification, or {@code null} if the object was not signed
+	 * @throws IOException
+	 *             if an error occurs getting a public key
+	 * @throws org.eclipse.jgit.api.errors.JGitInternalException
+	 *             if signature verification fails
+	 */
+	@Nullable
+	SignatureVerification verifySignature(@NonNull RevObject object,
+			@NonNull GpgConfig config) throws IOException;
+
+
+	/**
+	 * Verifies a given signature for given data.
+	 *
+	 * @param data
+	 *            the signature is for
+	 * @param signatureData
+	 *            the ASCII-armored signature
+	 * @return a {@link SignatureVerification} describing the outcome
+	 * @throws IOException
+	 *             if the signature cannot be parsed
+	 * @throws JGitInternalException
+	 *             if signature verification fails
+	 */
+	public SignatureVerification verify(byte[] data, byte[] signatureData)
+			throws IOException;
+
+	/**
+	 * Retrieves the name of this verifier. This should be a short string
+	 * identifying the engine that verified the signature, like "gpg" if GPG is
+	 * used, or "bc" for a BouncyCastle implementation.
+	 *
+	 * @return the name
+	 */
+	@NonNull
+	String getName();
+
+	/**
+	 * A {@link GpgSignatureVerifier} may cache public keys to speed up
+	 * verifying signatures on multiple objects. This clears this cache, if any.
+	 */
+	void clear();
+
+	/**
+	 * A {@code SignatureVerification} returns data about a (positively or
+	 * negatively) verified signature.
+	 */
+	interface SignatureVerification {
+
+		// Data about the signature.
+
+		@NonNull
+		Date getCreationDate();
+
+		// Data from the signature used to find a public key.
+
+		/**
+		 * Obtains the signer as stored in the signature, if known.
+		 *
+		 * @return the signer, or {@code null} if unknown
+		 */
+		String getSigner();
+
+		/**
+		 * Obtains the short or long fingerprint of the public key as stored in
+		 * the signature, if known.
+		 *
+		 * @return the fingerprint, or {@code null} if unknown
+		 */
+		String getKeyFingerprint();
+
+		// Some information about the found public key.
+
+		/**
+		 * Obtains the OpenPGP user ID associated with the key.
+		 *
+		 * @return the user id, or {@code null} if unknown
+		 */
+		String getKeyUser();
+
+		/**
+		 * Tells whether the public key used for this signature verification was
+		 * expired when the signature was created.
+		 *
+		 * @return {@code true} if the key was expired already, {@code false}
+		 *         otherwise
+		 */
+		boolean isExpired();
+
+		/**
+		 * Obtains the trust level of the public key used to verify the
+		 * signature.
+		 *
+		 * @return the trust level
+		 */
+		@NonNull
+		TrustLevel getTrustLevel();
+
+		// The verification result.
+
+		/**
+		 * Tells whether the signature verification was successful.
+		 *
+		 * @return {@code true} if the signature was verified successfully;
+		 *         {@code false} if not.
+		 */
+		boolean getVerified();
+
+		/**
+		 * Obtains a human-readable message giving additional information about
+		 * the outcome of the verification.
+		 *
+		 * @return the message, or {@code null} if none set.
+		 */
+		String getMessage();
+	}
+
+	/**
+	 * The owner's trust in a public key.
+	 */
+	enum TrustLevel {
+		UNKNOWN, NEVER, MARGINAL, FULL, ULTIMATE
+	}
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/GpgSignatureVerifierFactory.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/GpgSignatureVerifierFactory.java
new file mode 100644
index 0000000..4b1dbed
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/GpgSignatureVerifierFactory.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2021, Thomas Wolf <thomas.wolf@paranor.ch> and others
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0 which is available at
+ * https://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+package org.eclipse.jgit.lib;
+
+import java.util.Iterator;
+import java.util.ServiceConfigurationError;
+import java.util.ServiceLoader;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A {@code GpgSignatureVerifierFactory} creates {@link GpgSignatureVerifier} instances.
+ *
+ * @since 5.11
+ */
+public abstract class GpgSignatureVerifierFactory {
+
+	private static final Logger LOG = LoggerFactory
+			.getLogger(GpgSignatureVerifierFactory.class);
+
+	private static volatile GpgSignatureVerifierFactory defaultFactory = loadDefault();
+
+	private static GpgSignatureVerifierFactory loadDefault() {
+		try {
+			ServiceLoader<GpgSignatureVerifierFactory> loader = ServiceLoader
+					.load(GpgSignatureVerifierFactory.class);
+			Iterator<GpgSignatureVerifierFactory> iter = loader.iterator();
+			if (iter.hasNext()) {
+				return iter.next();
+			}
+		} catch (ServiceConfigurationError e) {
+			LOG.error(e.getMessage(), e);
+		}
+		return null;
+	}
+
+	/**
+	 * Retrieves the default factory.
+	 *
+	 * @return the default factory or {@code null} if none set
+	 */
+	public static GpgSignatureVerifierFactory getDefault() {
+		return defaultFactory;
+	}
+
+	/**
+	 * Sets the default factory.
+	 *
+	 * @param factory
+	 *            the new default factory
+	 */
+	public static void setDefault(GpgSignatureVerifierFactory factory) {
+		defaultFactory = factory;
+	}
+
+	/**
+	 * Creates a new {@link GpgSignatureVerifier}.
+	 *
+	 * @return the new {@link GpgSignatureVerifier}
+	 */
+	public abstract GpgSignatureVerifier getVerifier();
+
+}
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 a7a832c..1e8a6c9 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Repository.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Repository.java
@@ -127,6 +127,8 @@
 	/** If not bare, the index file caching the working file states. */
 	private final File indexFile;
 
+	private final String initialBranch;
+
 	/**
 	 * Initialize a new repository instance.
 	 *
@@ -138,6 +140,7 @@
 		fs = options.getFS();
 		workTree = options.getWorkTree();
 		indexFile = options.getIndexFile();
+		initialBranch = options.getInitialBranch();
 	}
 
 	/**
@@ -1034,6 +1037,16 @@
 	}
 
 	/**
+	 * Get the initial branch name of a new repository
+	 *
+	 * @return the initial branch name of a new repository
+	 * @since 5.11
+	 */
+	protected @NonNull String getInitialBranch() {
+		return initialBranch;
+	}
+
+	/**
 	 * Objects known to exist but not expressed by {@link #getAllRefs()}.
 	 * <p>
 	 * When a repository borrows objects from another repository, it can
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 6c217fd..4bfb38d 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java
@@ -703,18 +703,21 @@
 			// conflict between ours and theirs. file/folder conflicts between
 			// base/index/workingTree and something else are not relevant or
 			// detected later
-			if (nonTree(modeO) && !nonTree(modeT)) {
+			if (nonTree(modeO) != nonTree(modeT)) {
+				if (ignoreConflicts) {
+					// In case of merge failures, ignore this path instead of reporting unmerged, so
+					// a caller can use virtual commit. This will not result in files with conflict
+					// markers in the index/working tree. The actual diff on the path will be
+					// computed directly on children.
+					enterSubtree = false;
+					return true;
+				}
 				if (nonTree(modeB))
 					add(tw.getRawPath(), base, DirCacheEntry.STAGE_1, EPOCH, 0);
-				add(tw.getRawPath(), ours, DirCacheEntry.STAGE_2, EPOCH, 0);
-				unmergedPaths.add(tw.getPathString());
-				enterSubtree = false;
-				return true;
-			}
-			if (nonTree(modeT) && !nonTree(modeO)) {
-				if (nonTree(modeB))
-					add(tw.getRawPath(), base, DirCacheEntry.STAGE_1, EPOCH, 0);
-				add(tw.getRawPath(), theirs, DirCacheEntry.STAGE_3, EPOCH, 0);
+				if (nonTree(modeO))
+					add(tw.getRawPath(), ours, DirCacheEntry.STAGE_2, EPOCH, 0);
+				if (nonTree(modeT))
+					add(tw.getRawPath(), theirs, DirCacheEntry.STAGE_3, EPOCH, 0);
 				unmergedPaths.add(tw.getPathString());
 				enterSubtree = false;
 				return true;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/DateRevQueue.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/DateRevQueue.java
index b875be9..0cabf07 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/DateRevQueue.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/DateRevQueue.java
@@ -93,7 +93,7 @@
 			head = n;
 		} else {
 			Entry p = q.next;
-			while (p != null && p.commit.commitTime > when) {
+			while (p != null && p.commit.commitTime >= when) {
 				q = p;
 				p = q.next;
 			}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevTag.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevTag.java
index 3499136..b9d1450 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevTag.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevTag.java
@@ -1,7 +1,7 @@
 /*
- * Copyright (C) 2008-2009, Google Inc.
+ * Copyright (C) 2008, 2009, Google Inc.
  * Copyright (C) 2008, Marek Zawirski <marek.zawirski@gmail.com>
- * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org> and others
+ * Copyright (C) 2008, 2021, Shawn O. Pearce <spearce@spearce.org> and others
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Distribution License v. 1.0 which is available at
@@ -344,6 +344,22 @@
 	}
 
 	/**
+	 * Obtain the raw unparsed tag body (<b>NOTE - THIS IS NOT A COPY</b>).
+	 * <p>
+	 * This method is exposed only to provide very fast, efficient access to
+	 * this tag's message buffer. Applications relying on this buffer should be
+	 * very careful to ensure they do not modify its contents during their use
+	 * of it.
+	 *
+	 * @return the raw unparsed tag body. This is <b>NOT A COPY</b>. Do not
+	 *         alter the returned array.
+	 * @since 5.11
+	 */
+	public final byte[] getRawBuffer() {
+		return buffer;
+	}
+
+	/**
 	 * Discard the message buffer to reduce memory usage.
 	 * <p>
 	 * After discarding the memory usage of the {@code RevTag} is reduced to
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 bdebfa6..34bad6e 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/FetchProcess.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/FetchProcess.java
@@ -48,6 +48,7 @@
 import org.eclipse.jgit.lib.RefDatabase;
 import org.eclipse.jgit.revwalk.ObjectWalk;
 import org.eclipse.jgit.revwalk.RevWalk;
+import org.eclipse.jgit.util.StringUtils;
 
 class FetchProcess {
 	/** Transport we will fetch over. */
@@ -79,7 +80,8 @@
 		toFetch = f;
 	}
 
-	void execute(ProgressMonitor monitor, FetchResult result)
+	void execute(ProgressMonitor monitor, FetchResult result,
+			String initialBranch)
 			throws NotSupportedException, TransportException {
 		askFor.clear();
 		localUpdates.clear();
@@ -89,7 +91,7 @@
 
 		Throwable e1 = null;
 		try {
-			executeImp(monitor, result);
+			executeImp(monitor, result, initialBranch);
 		} catch (NotSupportedException | TransportException err) {
 			e1 = err;
 			throw err;
@@ -107,9 +109,22 @@
 		}
 	}
 
+	private boolean isInitialBranchMissing(Map<String, Ref> refsMap,
+			String initialBranch) {
+		if (StringUtils.isEmptyOrNull(initialBranch) || refsMap.isEmpty()) {
+			return false;
+		}
+		if (refsMap.containsKey(initialBranch)
+				|| refsMap.containsKey(Constants.R_HEADS + initialBranch)
+				|| refsMap.containsKey(Constants.R_TAGS + initialBranch)) {
+			return false;
+		}
+		return true;
+	}
+
 	private void executeImp(final ProgressMonitor monitor,
-			final FetchResult result) throws NotSupportedException,
-			TransportException {
+			final FetchResult result, String initialBranch)
+			throws NotSupportedException, TransportException {
 		final TagOpt tagopt = transport.getTagOpt();
 		String getTags = (tagopt == TagOpt.NO_TAGS) ? null : Constants.R_TAGS;
 		String getHead = null;
@@ -126,7 +141,12 @@
 		}
 		conn = transport.openFetch(toFetch, getTags, getHead);
 		try {
-			result.setAdvertisedRefs(transport.getURI(), conn.getRefsMap());
+			Map<String, Ref> refsMap = conn.getRefsMap();
+			if (isInitialBranchMissing(refsMap, initialBranch)) {
+				throw new TransportException(MessageFormat.format(
+						JGitText.get().remoteBranchNotFound, initialBranch));
+			}
+			result.setAdvertisedRefs(transport.getURI(), refsMap);
 			result.peerUserAgent = conn.getPeerUserAgent();
 			final Set<Ref> matched = new HashSet<>();
 			for (RefSpec spec : toFetch) {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/Transport.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/Transport.java
index 1c998f4..5b781ac 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/Transport.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/Transport.java
@@ -1231,9 +1231,52 @@
 	 *             the remote connection could not be established or object
 	 *             copying (if necessary) failed or update specification was
 	 *             incorrect.
+	 * @since 5.11
 	 */
 	public FetchResult fetch(final ProgressMonitor monitor,
-			Collection<RefSpec> toFetch) throws NotSupportedException,
+			Collection<RefSpec> toFetch)
+			throws NotSupportedException, TransportException {
+		return fetch(monitor, toFetch, null);
+	}
+
+	/**
+	 * Fetch objects and refs from the remote repository to the local one.
+	 * <p>
+	 * This is a utility function providing standard fetch behavior. Local
+	 * tracking refs associated with the remote repository are automatically
+	 * updated if this transport was created from a
+	 * {@link org.eclipse.jgit.transport.RemoteConfig} with fetch RefSpecs
+	 * defined.
+	 *
+	 * @param monitor
+	 *            progress monitor to inform the user about our processing
+	 *            activity. Must not be null. Use
+	 *            {@link org.eclipse.jgit.lib.NullProgressMonitor} if progress
+	 *            updates are not interesting or necessary.
+	 * @param toFetch
+	 *            specification of refs to fetch locally. May be null or the
+	 *            empty collection to use the specifications from the
+	 *            RemoteConfig. Source for each RefSpec can't be null.
+	 * @param branch
+	 *            the initial branch to check out when cloning the repository.
+	 *            Can be specified as ref name (<code>refs/heads/master</code>),
+	 *            branch name (<code>master</code>) or tag name
+	 *            (<code>v1.2.3</code>). The default is to use the branch
+	 *            pointed to by the cloned repository's HEAD and can be
+	 *            requested by passing {@code null} or <code>HEAD</code>.
+	 * @return information describing the tracking refs updated.
+	 * @throws org.eclipse.jgit.errors.NotSupportedException
+	 *             this transport implementation does not support fetching
+	 *             objects.
+	 * @throws org.eclipse.jgit.errors.TransportException
+	 *             the remote connection could not be established or object
+	 *             copying (if necessary) failed or update specification was
+	 *             incorrect.
+	 * @since 5.11
+	 */
+	public FetchResult fetch(final ProgressMonitor monitor,
+			Collection<RefSpec> toFetch, String branch)
+			throws NotSupportedException,
 			TransportException {
 		if (toFetch == null || toFetch.isEmpty()) {
 			// If the caller did not ask for anything use the defaults.
@@ -1263,7 +1306,7 @@
 		}
 
 		final FetchResult result = new FetchResult();
-		new FetchProcess(this, toFetch).execute(monitor, result);
+		new FetchProcess(this, toFetch).execute(monitor, result, branch);
 
 		local.autoGC(monitor);
 
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportGitAnon.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportGitAnon.java
index fa4392d..a1914b6 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportGitAnon.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportGitAnon.java
@@ -121,7 +121,6 @@
 		final Socket s = new Socket();
 		try {
 			final InetAddress host = InetAddress.getByName(uri.getHost());
-			s.bind(null);
 			s.connect(new InetSocketAddress(host, port), tms);
 		} catch (IOException c) {
 			try {
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 6faf42b..55b7d62 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeIterator.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeIterator.java
@@ -2,7 +2,7 @@
  * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org>
  * Copyright (C) 2010, Christian Halstrick <christian.halstrick@sap.com>
  * Copyright (C) 2010, Matthias Sohn <matthias.sohn@sap.com>
- * Copyright (C) 2012-2020, Robin Rosenberg and others
+ * Copyright (C) 2012-2021, Robin Rosenberg and others
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Distribution License v. 1.0 which is available at
@@ -800,7 +800,10 @@
 			if (Constants.DOT_GIT.equals(name))
 				continue;
 			if (Constants.DOT_GIT_IGNORE.equals(name))
-				ignoreNode = new PerDirectoryIgnoreNode(e);
+				ignoreNode = new PerDirectoryIgnoreNode(
+						TreeWalk.pathOf(path, 0, pathOffset)
+								+ Constants.DOT_GIT_IGNORE,
+						e);
 			if (Constants.DOT_GIT_ATTRIBUTES.equals(name))
 				attributesNode = new PerDirectoryAttributesNode(e);
 			if (i != o)
@@ -1274,17 +1277,20 @@
 
 	/** Magic type indicating we know rules exist, but they aren't loaded. */
 	private static class PerDirectoryIgnoreNode extends IgnoreNode {
-		final Entry entry;
+		protected final Entry entry;
 
-		PerDirectoryIgnoreNode(Entry entry) {
+		private final String name;
+
+		PerDirectoryIgnoreNode(String name, Entry entry) {
 			super(Collections.<FastIgnoreRule> emptyList());
+			this.name = name;
 			this.entry = entry;
 		}
 
 		IgnoreNode load() throws IOException {
 			IgnoreNode r = new IgnoreNode();
 			try (InputStream in = entry.openInputStream()) {
-				r.parse(in);
+				r.parse(name, in);
 			}
 			return r.getRules().isEmpty() ? null : r;
 		}
@@ -1295,7 +1301,7 @@
 		final Repository repository;
 
 		RootIgnoreNode(Entry entry, Repository repository) {
-			super(entry);
+			super(entry != null ? entry.getName() : null, entry);
 			this.repository = repository;
 		}
 
@@ -1329,7 +1335,7 @@
 				throws FileNotFoundException, IOException {
 			if (FS.DETECTED.exists(exclude)) {
 				try (FileInputStream in = new FileInputStream(exclude)) {
-					r.parse(in);
+					r.parse(exclude.getAbsolutePath(), in);
 				}
 			}
 		}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/FS.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/FS.java
index c80a3a4..0946f64 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/FS.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/FS.java
@@ -22,7 +22,6 @@
 import java.io.InputStreamReader;
 import java.io.OutputStream;
 import java.io.OutputStreamWriter;
-import java.io.PrintStream;
 import java.io.Writer;
 import java.nio.charset.Charset;
 import java.nio.file.AccessDeniedException;
@@ -1873,18 +1872,18 @@
 	 * @throws org.eclipse.jgit.api.errors.JGitInternalException
 	 *             if we fail to run the hook somehow. Causes may include an
 	 *             interrupted process or I/O errors.
-	 * @since 4.0
+	 * @since 5.11
 	 */
 	public ProcessResult runHookIfPresent(Repository repository,
 			final String hookName,
-			String[] args, PrintStream outRedirect, PrintStream errRedirect,
+			String[] args, OutputStream outRedirect, OutputStream errRedirect,
 			String stdinArgs) throws JGitInternalException {
 		return new ProcessResult(Status.NOT_SUPPORTED);
 	}
 
 	/**
 	 * See
-	 * {@link #runHookIfPresent(Repository, String, String[], PrintStream, PrintStream, String)}
+	 * {@link #runHookIfPresent(Repository, String, String[], OutputStream, OutputStream, String)}
 	 * . Should only be called by FS supporting shell scripts execution.
 	 *
 	 * @param repository
@@ -1909,11 +1908,11 @@
 	 * @throws org.eclipse.jgit.api.errors.JGitInternalException
 	 *             if we fail to run the hook somehow. Causes may include an
 	 *             interrupted process or I/O errors.
-	 * @since 4.0
+	 * @since 5.11
 	 */
 	protected ProcessResult internalRunHookIfPresent(Repository repository,
-			final String hookName, String[] args, PrintStream outRedirect,
-			PrintStream errRedirect, String stdinArgs)
+			final String hookName, String[] args, OutputStream outRedirect,
+			OutputStream errRedirect, String stdinArgs)
 			throws JGitInternalException {
 		File hookFile = findHook(repository, hookName);
 		if (hookFile == null || hookName == null) {
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 fb63dc0..946d81c 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
@@ -16,7 +16,7 @@
 import java.io.File;
 import java.io.IOException;
 import java.io.InputStreamReader;
-import java.io.PrintStream;
+import java.io.OutputStream;
 import java.nio.charset.Charset;
 import java.nio.file.FileAlreadyExistsException;
 import java.nio.file.FileStore;
@@ -268,7 +268,7 @@
 	/** {@inheritDoc} */
 	@Override
 	public ProcessResult runHookIfPresent(Repository repository, String hookName,
-			String[] args, PrintStream outRedirect, PrintStream errRedirect,
+			String[] args, OutputStream outRedirect, OutputStream errRedirect,
 			String stdinArgs) throws JGitInternalException {
 		return internalRunHookIfPresent(repository, hookName, args, outRedirect,
 				errRedirect, stdinArgs);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_Win32_Cygwin.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_Win32_Cygwin.java
index d53bff7..add5498 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_Win32_Cygwin.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_Win32_Cygwin.java
@@ -13,7 +13,7 @@
 import static java.nio.charset.StandardCharsets.UTF_8;
 
 import java.io.File;
-import java.io.PrintStream;
+import java.io.OutputStream;
 import java.security.AccessController;
 import java.security.PrivilegedAction;
 import java.util.ArrayList;
@@ -139,7 +139,7 @@
 	/** {@inheritDoc} */
 	@Override
 	public ProcessResult runHookIfPresent(Repository repository, String hookName,
-			String[] args, PrintStream outRedirect, PrintStream errRedirect,
+			String[] args, OutputStream outRedirect, OutputStream errRedirect,
 			String stdinArgs) throws JGitInternalException {
 		return internalRunHookIfPresent(repository, hookName, args, outRedirect,
 				errRedirect, stdinArgs);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/SignatureUtils.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/SignatureUtils.java
new file mode 100644
index 0000000..cf06172
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/SignatureUtils.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2021, Thomas Wolf <thomas.wolf@paranor.ch> and others
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0 which is available at
+ * https://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+package org.eclipse.jgit.util;
+
+import java.text.MessageFormat;
+import java.util.Locale;
+
+import org.eclipse.jgit.internal.JGitText;
+import org.eclipse.jgit.lib.GpgSignatureVerifier.SignatureVerification;
+import org.eclipse.jgit.lib.GpgSignatureVerifier.TrustLevel;
+import org.eclipse.jgit.lib.PersonIdent;
+
+/**
+ * Utilities for signature verification.
+ *
+ * @since 5.11
+ */
+public final class SignatureUtils {
+
+	private SignatureUtils() {
+		// No instantiation
+	}
+
+	/**
+	 * Writes information about a signature verification to a string.
+	 *
+	 * @param verification
+	 *            to show
+	 * @param creator
+	 *            of the object verified; used for time zone information
+	 * @param formatter
+	 *            to use for dates
+	 * @return a textual representation of the {@link SignatureVerification},
+	 *         using LF as line separator
+	 */
+	public static String toString(SignatureVerification verification,
+			PersonIdent creator, GitDateFormatter formatter) {
+		StringBuilder result = new StringBuilder();
+		// Use the creator's timezone for the signature date
+		PersonIdent dateId = new PersonIdent(creator,
+				verification.getCreationDate());
+		result.append(MessageFormat.format(JGitText.get().verifySignatureMade,
+				formatter.formatDate(dateId)));
+		result.append('\n');
+		result.append(MessageFormat.format(
+				JGitText.get().verifySignatureKey,
+				verification.getKeyFingerprint().toUpperCase(Locale.ROOT)));
+		result.append('\n');
+		if (!StringUtils.isEmptyOrNull(verification.getSigner())) {
+			result.append(
+					MessageFormat.format(JGitText.get().verifySignatureIssuer,
+							verification.getSigner()));
+			result.append('\n');
+		}
+		String msg;
+		if (verification.getVerified()) {
+			if (verification.isExpired()) {
+				msg = JGitText.get().verifySignatureExpired;
+			} else {
+				msg = JGitText.get().verifySignatureGood;
+			}
+		} else {
+			msg = JGitText.get().verifySignatureBad;
+		}
+		result.append(MessageFormat.format(msg, verification.getKeyUser()));
+		if (!TrustLevel.UNKNOWN.equals(verification.getTrustLevel())) {
+			result.append(' ' + MessageFormat
+					.format(JGitText.get().verifySignatureTrust, verification
+							.getTrustLevel().name().toLowerCase(Locale.ROOT)));
+		}
+		result.append('\n');
+		msg = verification.getMessage();
+		if (!StringUtils.isEmptyOrNull(msg)) {
+			result.append(msg);
+			result.append('\n');
+		}
+		return result.toString();
+	}
+}
diff --git a/pom.xml b/pom.xml
index e2aa7ca..e7d35ff 100644
--- a/pom.xml
+++ b/pom.xml
@@ -151,8 +151,8 @@
     <maven.compiler.target>1.8</maven.compiler.target>
     <bundle-manifest>${project.build.directory}/META-INF/MANIFEST.MF</bundle-manifest>
 
-    <jgit-last-release-version>5.9.0.202009080501-r</jgit-last-release-version>
-    <apache-sshd-version>2.4.0</apache-sshd-version>
+    <jgit-last-release-version>5.10.0.202012080955-r</jgit-last-release-version>
+    <apache-sshd-version>2.6.0</apache-sshd-version>
     <jsch-version>0.1.55</jsch-version>
     <jzlib-version>1.1.1</jzlib-version>
     <javaewah-version>1.1.7</javaewah-version>
@@ -162,10 +162,10 @@
     <commons-compress-version>1.19</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.35.v20201120</jetty-version>
+    <jetty-version>9.4.36.v20210114</jetty-version>
     <japicmp-version>0.14.4</japicmp-version>
-    <httpclient-version>4.5.10</httpclient-version>
-    <httpcore-version>4.4.12</httpcore-version>
+    <httpclient-version>4.5.13</httpclient-version>
+    <httpcore-version>4.4.14</httpcore-version>
     <slf4j-version>1.7.30</slf4j-version>
     <log4j-version>1.2.15</log4j-version>
     <maven-javadoc-plugin-version>3.2.0</maven-javadoc-plugin-version>