Merge branch 'stable-5.2'

* stable-5.2:
  Prepare 5.2.2-SNAPSHOT builds
  JGit v5.2.1.201812262042-r
  Prepare 5.1.6-SNAPSHOT builds
  JGit v5.1.5.201812261915-r
  UploadPack: Filter refs used for deepen-not resolution
  UploadPack: Avoid calling AdvertiseRefsHook twice
  Prepare 5.1.5-SNAPSHOT builds
  JGit v5.1.4.201812251853-r
  UploadPack: Filter refs used for want-ref resolution
  UploadPack: Defer want-ref resolution to after parsing
  Call AdvertiseRefsHook for protocol v2
  Prepare 4.11.7-SNAPSHOT builds
  JGit v4.11.6.201812241910-r
  Prepare 4.9.9-SNAPSHOT builds
  JGit v4.9.8.201812241815-r
  UploadPack: Test filtering by AdvertiseRefsHook in stateless transports
  Prepare 4.7.8-SNAPSHOT builds
  JGit v4.7.7.201812240805-r
  Fix feature versions imported by feature org.eclipse.jgit.pgm
  Prepare 4.5.6-SNAPSHOT builds
  JGit v4.5.5.201812240535-r
  Call AdvertiseRefsHook before validating wants

Change-Id: Ia56348e54d62630d7c50a4747df89516fc5afad9
Signed-off-by: Jonathan Nieder <jrn@google.com>
diff --git a/WORKSPACE b/WORKSPACE
index 0eabecc..7a3cc4e 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -108,8 +108,8 @@
 
 maven_jar(
     name = "tukaani-xz",
-    artifact = "org.tukaani:xz:1.6",
-    sha1 = "05b6f921f1810bdf90e25471968f741f87168b64",
+    artifact = "org.tukaani:xz:1.8",
+    sha1 = "c4f7d054303948eb6a4066194253886c8af07128",
 )
 
 maven_jar(
diff --git a/org.eclipse.jgit.ant.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.ant.test/META-INF/MANIFEST.MF
index de61559..3750e85 100644
--- a/org.eclipse.jgit.ant.test/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.ant.test/META-INF/MANIFEST.MF
@@ -4,13 +4,13 @@
 Bundle-Name: %plugin_name
 Automatic-Module-Name: org.eclipse.jgit.ant.test
 Bundle-SymbolicName: org.eclipse.jgit.ant.test
-Bundle-Version: 5.2.2.qualifier
+Bundle-Version: 5.3.0.qualifier
 Bundle-ActivationPolicy: lazy
 Bundle-RequiredExecutionEnvironment: JavaSE-1.8
 Import-Package: org.apache.tools.ant,
- org.eclipse.jgit.ant.tasks;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.junit;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.lib;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.util;version="[5.2.2,5.3.0)",
+ org.eclipse.jgit.ant.tasks;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.junit;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.lib;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.util;version="[5.3.0,5.4.0)",
  org.hamcrest.core;version="[1.1.0,2.0.0)",
  org.junit;version="[4.12,5.0.0)"
diff --git a/org.eclipse.jgit.ant.test/pom.xml b/org.eclipse.jgit.ant.test/pom.xml
index c235914..0a20855 100644
--- a/org.eclipse.jgit.ant.test/pom.xml
+++ b/org.eclipse.jgit.ant.test/pom.xml
@@ -50,7 +50,7 @@
   <parent>
     <groupId>org.eclipse.jgit</groupId>
     <artifactId>org.eclipse.jgit-parent</artifactId>
-    <version>5.2.2-SNAPSHOT</version>
+    <version>5.3.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>org.eclipse.jgit.ant.test</artifactId>
@@ -105,7 +105,7 @@
       <plugin>
         <artifactId>maven-surefire-plugin</artifactId>
         <configuration>
-          <argLine>-Xmx256m -Dfile.encoding=UTF-8 -Djava.io.tmpdir=${project.build.directory}</argLine>
+          <argLine>@{argLine} -Xmx256m -Dfile.encoding=UTF-8 -Djava.io.tmpdir=${project.build.directory}</argLine>
         </configuration>
       </plugin>
     </plugins>
diff --git a/org.eclipse.jgit.ant/META-INF/MANIFEST.MF b/org.eclipse.jgit.ant/META-INF/MANIFEST.MF
index 84facb5..7119fd9 100644
--- a/org.eclipse.jgit.ant/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.ant/META-INF/MANIFEST.MF
@@ -3,11 +3,11 @@
 Bundle-Name: %Bundle-Name
 Automatic-Module-Name: org.eclipse.jgit.ant
 Bundle-SymbolicName: org.eclipse.jgit.ant
-Bundle-Version: 5.2.2.qualifier
+Bundle-Version: 5.3.0.qualifier
 Bundle-RequiredExecutionEnvironment: JavaSE-1.8
 Import-Package: org.apache.tools.ant,
-  org.eclipse.jgit.storage.file;version="[5.2.2,5.3.0)"
+  org.eclipse.jgit.storage.file;version="[5.3.0,5.4.0)"
 Bundle-Localization: plugin
 Bundle-Vendor: %Provider-Name
-Export-Package: org.eclipse.jgit.ant.tasks;version="5.2.2";
+Export-Package: org.eclipse.jgit.ant.tasks;version="5.3.0";
  uses:="org.apache.tools.ant.types,org.apache.tools.ant"
diff --git a/org.eclipse.jgit.ant/pom.xml b/org.eclipse.jgit.ant/pom.xml
index 9d92e5a..4d4875d 100644
--- a/org.eclipse.jgit.ant/pom.xml
+++ b/org.eclipse.jgit.ant/pom.xml
@@ -48,7 +48,7 @@
 	<parent>
 		<groupId>org.eclipse.jgit</groupId>
 		<artifactId>org.eclipse.jgit-parent</artifactId>
-		<version>5.2.2-SNAPSHOT</version>
+		<version>5.3.0-SNAPSHOT</version>
 	</parent>
 
 	<artifactId>org.eclipse.jgit.ant</artifactId>
diff --git a/org.eclipse.jgit.ant/src/org/eclipse/jgit/ant/tasks/GitCheckoutTask.java b/org.eclipse.jgit.ant/src/org/eclipse/jgit/ant/tasks/GitCheckoutTask.java
index 0b27cc2..5f80d00 100644
--- a/org.eclipse.jgit.ant/src/org/eclipse/jgit/ant/tasks/GitCheckoutTask.java
+++ b/org.eclipse.jgit.ant/src/org/eclipse/jgit/ant/tasks/GitCheckoutTask.java
@@ -123,7 +123,7 @@ public void execute() throws BuildException {
 		}
 
 		try {
-			checkout.setCreateBranch(createBranch).setForce(force)
+			checkout.setCreateBranch(createBranch).setForceRefUpdate(force)
 					.setName(branch);
 			checkout.call();
 		} catch (Exception e) {
diff --git a/org.eclipse.jgit.archive/META-INF/MANIFEST.MF b/org.eclipse.jgit.archive/META-INF/MANIFEST.MF
index 7efa906..cc98ea9 100644
--- a/org.eclipse.jgit.archive/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.archive/META-INF/MANIFEST.MF
@@ -3,7 +3,7 @@
 Bundle-Name: %plugin_name
 Automatic-Module-Name: org.eclipse.jgit.archive
 Bundle-SymbolicName: org.eclipse.jgit.archive
-Bundle-Version: 5.2.2.qualifier
+Bundle-Version: 5.3.0.qualifier
 Bundle-Vendor: %provider_name
 Bundle-Localization: plugin
 Bundle-RequiredExecutionEnvironment: JavaSE-1.8
@@ -13,15 +13,15 @@
  org.apache.commons.compress.compressors.bzip2;version="[1.4,2.0)",
  org.apache.commons.compress.compressors.gzip;version="[1.4,2.0)",
  org.apache.commons.compress.compressors.xz;version="[1.4,2.0)",
- org.eclipse.jgit.api;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.lib;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.nls;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.revwalk;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.util;version="[5.2.2,5.3.0)",
+ org.eclipse.jgit.api;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.lib;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.nls;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.revwalk;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.util;version="[5.3.0,5.4.0)",
  org.osgi.framework;version="[1.3.0,2.0.0)"
 Bundle-ActivationPolicy: lazy
 Bundle-Activator: org.eclipse.jgit.archive.FormatActivator
-Export-Package: org.eclipse.jgit.archive;version="5.2.2";
+Export-Package: org.eclipse.jgit.archive;version="5.3.0";
   uses:="org.eclipse.jgit.lib,
    org.eclipse.jgit.api,
    org.apache.commons.compress.archivers,
diff --git a/org.eclipse.jgit.archive/META-INF/SOURCE-MANIFEST.MF b/org.eclipse.jgit.archive/META-INF/SOURCE-MANIFEST.MF
index 29aa63e..41d5ef2 100644
--- a/org.eclipse.jgit.archive/META-INF/SOURCE-MANIFEST.MF
+++ b/org.eclipse.jgit.archive/META-INF/SOURCE-MANIFEST.MF
@@ -3,5 +3,5 @@
 Bundle-Name: org.eclipse.jgit.archive - Sources
 Bundle-SymbolicName: org.eclipse.jgit.archive.source
 Bundle-Vendor: Eclipse.org - JGit
-Bundle-Version: 5.2.2.qualifier
-Eclipse-SourceBundle: org.eclipse.jgit.archive;version="5.2.2.qualifier";roots="."
+Bundle-Version: 5.3.0.qualifier
+Eclipse-SourceBundle: org.eclipse.jgit.archive;version="5.3.0.qualifier";roots="."
diff --git a/org.eclipse.jgit.archive/pom.xml b/org.eclipse.jgit.archive/pom.xml
index 119bcb2..e1b76ca 100644
--- a/org.eclipse.jgit.archive/pom.xml
+++ b/org.eclipse.jgit.archive/pom.xml
@@ -50,7 +50,7 @@
   <parent>
     <groupId>org.eclipse.jgit</groupId>
     <artifactId>org.eclipse.jgit-parent</artifactId>
-    <version>5.2.2-SNAPSHOT</version>
+    <version>5.3.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>org.eclipse.jgit.archive</artifactId>
diff --git a/org.eclipse.jgit.coverage/.classpath b/org.eclipse.jgit.coverage/.classpath
new file mode 100644
index 0000000..248406b
--- /dev/null
+++ b/org.eclipse.jgit.coverage/.classpath
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8">
+		<attributes>
+			<attribute name="maven.pomderived" value="true"/>
+		</attributes>
+	</classpathentry>
+	<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
+		<attributes>
+			<attribute name="maven.pomderived" value="true"/>
+		</attributes>
+	</classpathentry>
+	<classpathentry kind="output" path="target/classes"/>
+</classpath>
diff --git a/org.eclipse.jgit.coverage/.gitignore b/org.eclipse.jgit.coverage/.gitignore
new file mode 100644
index 0000000..b83d222
--- /dev/null
+++ b/org.eclipse.jgit.coverage/.gitignore
@@ -0,0 +1 @@
+/target/
diff --git a/org.eclipse.jgit.coverage/.project b/org.eclipse.jgit.coverage/.project
new file mode 100644
index 0000000..6306b5c
--- /dev/null
+++ b/org.eclipse.jgit.coverage/.project
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>org.eclipse.jgit.coverage</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.m2e.core.maven2Builder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.m2e.core.maven2Nature</nature>
+	</natures>
+</projectDescription>
diff --git a/org.eclipse.jgit.coverage/.settings/org.eclipse.core.resources.prefs b/org.eclipse.jgit.coverage/.settings/org.eclipse.core.resources.prefs
new file mode 100644
index 0000000..99f26c0
--- /dev/null
+++ b/org.eclipse.jgit.coverage/.settings/org.eclipse.core.resources.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+encoding/<project>=UTF-8
diff --git a/org.eclipse.jgit.coverage/.settings/org.eclipse.m2e.core.prefs b/org.eclipse.jgit.coverage/.settings/org.eclipse.m2e.core.prefs
new file mode 100644
index 0000000..f897a7f
--- /dev/null
+++ b/org.eclipse.jgit.coverage/.settings/org.eclipse.m2e.core.prefs
@@ -0,0 +1,4 @@
+activeProfiles=
+eclipse.preferences.version=1
+resolveWorkspaceProjects=true
+version=1
diff --git a/org.eclipse.jgit.coverage/pom.xml b/org.eclipse.jgit.coverage/pom.xml
new file mode 100644
index 0000000..c908cfc
--- /dev/null
+++ b/org.eclipse.jgit.coverage/pom.xml
@@ -0,0 +1,143 @@
+<?xml version="1.0"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <parent>
+    <groupId>org.eclipse.jgit</groupId>
+    <artifactId>org.eclipse.jgit-parent</artifactId>
+    <version>5.3.0-SNAPSHOT</version>
+  </parent>
+  <modelVersion>4.0.0</modelVersion>
+
+  <artifactId>org.eclipse.jgit.coverage</artifactId>
+  <packaging>pom</packaging>
+
+  <name>JGit - Test Coverage</name>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.eclipse.jgit</groupId>
+      <artifactId>org.eclipse.jgit</artifactId>
+      <version>5.3.0-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.jgit</groupId>
+      <artifactId>org.eclipse.jgit.ant</artifactId>
+      <version>5.3.0-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.jgit</groupId>
+      <artifactId>org.eclipse.jgit.archive</artifactId>
+      <version>5.3.0-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.jgit</groupId>
+      <artifactId>org.eclipse.jgit.http.apache</artifactId>
+      <version>5.3.0-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.jgit</groupId>
+      <artifactId>org.eclipse.jgit.http.server</artifactId>
+      <version>5.3.0-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.jgit</groupId>
+      <artifactId>org.eclipse.jgit.lfs</artifactId>
+      <version>5.3.0-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.jgit</groupId>
+      <artifactId>org.eclipse.jgit.lfs.server</artifactId>
+      <version>5.3.0-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.jgit</groupId>
+      <artifactId>org.eclipse.jgit.pgm</artifactId>
+      <version>5.3.0-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.jgit</groupId>
+      <artifactId>org.eclipse.jgit.ui</artifactId>
+      <version>5.3.0-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.jgit</groupId>
+      <artifactId>org.eclipse.jgit.ssh.apache</artifactId>
+      <version>5.3.0-SNAPSHOT</version>
+    </dependency>
+
+    <dependency>
+      <groupId>org.eclipse.jgit</groupId>
+      <artifactId>org.eclipse.jgit.test</artifactId>
+      <version>5.3.0-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.jgit</groupId>
+      <artifactId>org.eclipse.jgit.ant.test</artifactId>
+      <version>5.3.0-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.jgit</groupId>
+      <artifactId>org.eclipse.jgit.http.test</artifactId>
+      <version>5.3.0-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.jgit</groupId>
+      <artifactId>org.eclipse.jgit.pgm.test</artifactId>
+      <version>5.3.0-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.jgit</groupId>
+      <artifactId>org.eclipse.jgit.lfs.test</artifactId>
+      <version>5.3.0-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.jgit</groupId>
+      <artifactId>org.eclipse.jgit.lfs.server.test</artifactId>
+      <version>5.3.0-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.jgit</groupId>
+      <artifactId>org.eclipse.jgit.ssh.apache.test</artifactId>
+      <version>5.3.0-SNAPSHOT</version>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.jacoco</groupId>
+        <artifactId>jacoco-maven-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>aggregate-reports-all</id>
+            <phase>verify</phase>
+            <goals>
+              <goal>report-aggregate</goal>
+            </goals>
+            <configuration>
+              <title>JGit Test Coverage </title>
+              <outputDirectory>${project.reporting.outputDirectory}/jacoco-aggregate</outputDirectory>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
+  </build>
+  <reporting>
+    <plugins>
+      <plugin>
+        <groupId>org.jacoco</groupId>
+        <artifactId>jacoco-maven-plugin</artifactId>
+        <reportSets>
+          <reportSet>
+            <id>aggregate</id>
+            <reports>
+              <report>report-aggregate</report>
+            </reports>
+          </reportSet>
+        </reportSets>
+      </plugin>
+    </plugins>
+  </reporting>
+</project>
diff --git a/org.eclipse.jgit.http.apache/META-INF/MANIFEST.MF b/org.eclipse.jgit.http.apache/META-INF/MANIFEST.MF
index 3d80ec9..57c4493 100644
--- a/org.eclipse.jgit.http.apache/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.http.apache/META-INF/MANIFEST.MF
@@ -3,7 +3,7 @@
 Bundle-Name: %Bundle-Name
 Automatic-Module-Name: org.eclipse.jgit.http.apache
 Bundle-SymbolicName: org.eclipse.jgit.http.apache
-Bundle-Version: 5.2.2.qualifier
+Bundle-Version: 5.3.0.qualifier
 Bundle-RequiredExecutionEnvironment: JavaSE-1.8
 Bundle-Localization: plugin
 Bundle-Vendor: %Provider-Name
@@ -23,11 +23,11 @@
  org.apache.http.impl.client;version="[4.3.0,5.0.0)",
  org.apache.http.impl.conn;version="[4.3.0,5.0.0)",
  org.apache.http.params;version="[4.3.0,5.0.0)",
- org.eclipse.jgit.annotations;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.nls;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.transport.http;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.util;version="[5.2.2,5.3.0)"
-Export-Package: org.eclipse.jgit.transport.http.apache;version="5.2.2";
+ org.eclipse.jgit.annotations;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.nls;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.transport.http;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.util;version="[5.3.0,5.4.0)"
+Export-Package: org.eclipse.jgit.transport.http.apache;version="5.3.0";
   uses:="org.apache.http.client,
    org.eclipse.jgit.transport.http,
    org.apache.http.entity,
diff --git a/org.eclipse.jgit.http.apache/pom.xml b/org.eclipse.jgit.http.apache/pom.xml
index 35577b2..ba9a0b3 100644
--- a/org.eclipse.jgit.http.apache/pom.xml
+++ b/org.eclipse.jgit.http.apache/pom.xml
@@ -48,7 +48,7 @@
 	<parent>
 		<groupId>org.eclipse.jgit</groupId>
 		<artifactId>org.eclipse.jgit-parent</artifactId>
-		<version>5.2.2-SNAPSHOT</version>
+		<version>5.3.0-SNAPSHOT</version>
 	</parent>
 
 	<artifactId>org.eclipse.jgit.http.apache</artifactId>
diff --git a/org.eclipse.jgit.http.server/META-INF/MANIFEST.MF b/org.eclipse.jgit.http.server/META-INF/MANIFEST.MF
index d3ed4a8..4cb154c 100644
--- a/org.eclipse.jgit.http.server/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.http.server/META-INF/MANIFEST.MF
@@ -3,13 +3,13 @@
 Bundle-Name: %plugin_name
 Automatic-Module-Name: org.eclipse.jgit.http.server
 Bundle-SymbolicName: org.eclipse.jgit.http.server
-Bundle-Version: 5.2.2.qualifier
+Bundle-Version: 5.3.0.qualifier
 Bundle-Localization: plugin
 Bundle-Vendor: %provider_name
-Export-Package: org.eclipse.jgit.http.server;version="5.2.2",
- org.eclipse.jgit.http.server.glue;version="5.2.2";
+Export-Package: org.eclipse.jgit.http.server;version="5.3.0",
+ org.eclipse.jgit.http.server.glue;version="5.3.0";
   uses:="javax.servlet,javax.servlet.http",
- org.eclipse.jgit.http.server.resolver;version="5.2.2";
+ org.eclipse.jgit.http.server.resolver;version="5.3.0";
   uses:="org.eclipse.jgit.transport.resolver,
    org.eclipse.jgit.lib,
    org.eclipse.jgit.transport,
@@ -18,13 +18,13 @@
 Bundle-RequiredExecutionEnvironment: JavaSE-1.8
 Import-Package: javax.servlet;version="[2.5.0,3.2.0)",
  javax.servlet.http;version="[2.5.0,3.2.0)",
- org.eclipse.jgit.errors;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.internal.storage.dfs;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.internal.storage.file;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.internal.transport.parser;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.lib;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.nls;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.revwalk;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.transport;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.transport.resolver;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.util;version="[5.2.2,5.3.0)"
+ org.eclipse.jgit.errors;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.internal.storage.dfs;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.internal.storage.file;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.internal.transport.parser;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.lib;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.nls;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.revwalk;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.transport;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.transport.resolver;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.util;version="[5.3.0,5.4.0)"
diff --git a/org.eclipse.jgit.http.server/pom.xml b/org.eclipse.jgit.http.server/pom.xml
index 1948592..87421f5 100644
--- a/org.eclipse.jgit.http.server/pom.xml
+++ b/org.eclipse.jgit.http.server/pom.xml
@@ -52,7 +52,7 @@
   <parent>
     <groupId>org.eclipse.jgit</groupId>
     <artifactId>org.eclipse.jgit-parent</artifactId>
-    <version>5.2.2-SNAPSHOT</version>
+    <version>5.3.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>org.eclipse.jgit.http.server</artifactId>
diff --git a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/GitSmartHttpTools.java b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/GitSmartHttpTools.java
index ee4b32e..8961d1b 100644
--- a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/GitSmartHttpTools.java
+++ b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/GitSmartHttpTools.java
@@ -63,6 +63,7 @@
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
+import org.eclipse.jgit.internal.transport.parser.FirstCommand;
 import org.eclipse.jgit.internal.transport.parser.FirstWant;
 import org.eclipse.jgit.lib.Constants;
 import org.eclipse.jgit.transport.PacketLineIn;
@@ -287,7 +288,7 @@ private static boolean isReceivePackSideBand(HttpServletRequest req) {
 			// not have a ReceivePack, or it might not have read any of the request.
 			// So, cheat and read the first line.
 			String line = new PacketLineIn(req.getInputStream()).readString();
-			ReceivePack.FirstLine parsed = new ReceivePack.FirstLine(line);
+			FirstCommand parsed = FirstCommand.fromLine(line);
 			return parsed.getCapabilities().contains(CAPABILITY_SIDE_BAND_64K);
 		} catch (IOException e) {
 			// Probably the connection is closed and a subsequent write will fail, but
diff --git a/org.eclipse.jgit.http.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.http.test/META-INF/MANIFEST.MF
index 5330327..15e9ac4 100644
--- a/org.eclipse.jgit.http.test/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.http.test/META-INF/MANIFEST.MF
@@ -3,7 +3,7 @@
 Bundle-Name: %plugin_name
 Automatic-Module-Name: org.eclipse.jgit.http.test
 Bundle-SymbolicName: org.eclipse.jgit.http.test
-Bundle-Version: 5.2.2.qualifier
+Bundle-Version: 5.3.0.qualifier
 Bundle-Vendor: %provider_name
 Bundle-Localization: plugin
 Bundle-RequiredExecutionEnvironment: JavaSE-1.8
@@ -28,25 +28,25 @@
  org.eclipse.jetty.util.log;version="[9.4.5,10.0.0)",
  org.eclipse.jetty.util.security;version="[9.4.5,10.0.0)",
  org.eclipse.jetty.util.thread;version="[9.4.5,10.0.0)",
- org.eclipse.jgit.errors;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.http.server;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.http.server.glue;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.http.server.resolver;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.internal;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.internal.storage.dfs;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.internal.storage.file;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.internal.storage.reftable;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.junit;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.junit.http;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.lib;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.nls;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.revwalk;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.storage.file;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.transport;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.transport.http;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.transport.http.apache;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.transport.resolver;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.util;version="[5.2.2,5.3.0)",
+ org.eclipse.jgit.errors;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.http.server;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.http.server.glue;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.http.server.resolver;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.internal;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.internal.storage.dfs;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.internal.storage.file;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.internal.storage.reftable;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.junit;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.junit.http;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.lib;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.nls;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.revwalk;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.storage.file;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.transport;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.transport.http;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.transport.http.apache;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.transport.resolver;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.util;version="[5.3.0,5.4.0)",
  org.hamcrest;version="[1.1.0,2.0.0)",
  org.hamcrest.core;version="[1.1.0,2.0.0)",
  org.junit;version="[4.12,5.0.0)",
diff --git a/org.eclipse.jgit.http.test/pom.xml b/org.eclipse.jgit.http.test/pom.xml
index ba17601..9eb8e7c 100644
--- a/org.eclipse.jgit.http.test/pom.xml
+++ b/org.eclipse.jgit.http.test/pom.xml
@@ -51,7 +51,7 @@
   <parent>
     <groupId>org.eclipse.jgit</groupId>
     <artifactId>org.eclipse.jgit-parent</artifactId>
-    <version>5.2.2-SNAPSHOT</version>
+    <version>5.3.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>org.eclipse.jgit.http.test</artifactId>
@@ -71,13 +71,6 @@
     </dependency>
 
     <dependency>
-      <groupId>org.hamcrest</groupId>
-      <artifactId>hamcrest-library</artifactId>
-      <scope>test</scope>
-      <version>[1.1.0,2.0.0)</version>
-    </dependency>
-
-    <dependency>
       <groupId>org.eclipse.jgit</groupId>
       <artifactId>org.eclipse.jgit</artifactId>
       <version>${project.version}</version>
@@ -91,6 +84,13 @@
     </dependency>
 
     <dependency>
+      <groupId>org.hamcrest</groupId>
+      <artifactId>hamcrest-library</artifactId>
+      <scope>test</scope>
+      <version>[1.1.0,2.0.0)</version>
+    </dependency>
+
+    <dependency>
       <groupId>org.eclipse.jgit</groupId>
       <artifactId>org.eclipse.jgit.junit.http</artifactId>
       <version>${project.version}</version>
@@ -139,7 +139,7 @@
       <plugin>
         <artifactId>maven-surefire-plugin</artifactId>
         <configuration>
-          <argLine>-Djava.io.tmpdir=${project.build.directory}  -Xmx300m</argLine>
+          <argLine>@{argLine} -Djava.io.tmpdir=${project.build.directory}  -Xmx300m</argLine>
           <includes>
             <include>**/*Test.java</include>
             <include>**/*Tests.java</include>
diff --git a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/DumbClientDumbServerTest.java b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/DumbClientDumbServerTest.java
index ab6dc35..422be56 100644
--- a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/DumbClientDumbServerTest.java
+++ b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/DumbClientDumbServerTest.java
@@ -194,13 +194,13 @@ public void testListRemote() throws IOException {
 	@Test
 	public void testInitialClone_Loose() throws Exception {
 		Repository dst = createBareRepository();
-		assertFalse(dst.hasObject(A_txt));
+		assertFalse(dst.getObjectDatabase().has(A_txt));
 
 		try (Transport t = Transport.open(dst, remoteURI)) {
 			t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
 		}
 
-		assertTrue(dst.hasObject(A_txt));
+		assertTrue(dst.getObjectDatabase().has(A_txt));
 		assertEquals(B, dst.exactRef(master).getObjectId());
 		fsck(dst, B);
 
@@ -216,13 +216,13 @@ public void testInitialClone_Packed() throws Exception {
 		new TestRepository<>(remoteRepository).packAndPrune();
 
 		Repository dst = createBareRepository();
-		assertFalse(dst.hasObject(A_txt));
+		assertFalse(dst.getObjectDatabase().has(A_txt));
 
 		try (Transport t = Transport.open(dst, remoteURI)) {
 			t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
 		}
 
-		assertTrue(dst.hasObject(A_txt));
+		assertTrue(dst.getObjectDatabase().has(A_txt));
 		assertEquals(B, dst.exactRef(master).getObjectId());
 		fsck(dst, B);
 
diff --git a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/DumbClientSmartServerTest.java b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/DumbClientSmartServerTest.java
index 4ff81c5..5fdc10e 100644
--- a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/DumbClientSmartServerTest.java
+++ b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/DumbClientSmartServerTest.java
@@ -193,14 +193,14 @@ public void testListRemote() throws IOException {
 	@Test
 	public void testInitialClone_Small() throws Exception {
 		Repository dst = createBareRepository();
-		assertFalse(dst.hasObject(A_txt));
+		assertFalse(dst.getObjectDatabase().has(A_txt));
 
 		try (Transport t = Transport.open(dst, remoteURI)) {
 		((TransportHttp) t).setUseSmartHttp(false);
 			t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
 		}
 
-		assertTrue(dst.hasObject(A_txt));
+		assertTrue(dst.getObjectDatabase().has(A_txt));
 		assertEquals(B, dst.exactRef(master).getObjectId());
 		fsck(dst, B);
 
@@ -218,14 +218,14 @@ public void testInitialClone_Packed() throws Exception {
 		new TestRepository<>(remoteRepository).packAndPrune();
 
 		Repository dst = createBareRepository();
-		assertFalse(dst.hasObject(A_txt));
+		assertFalse(dst.getObjectDatabase().has(A_txt));
 
 		try (Transport t = Transport.open(dst, remoteURI)) {
 			((TransportHttp) t).setUseSmartHttp(false);
 			t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
 		}
 
-		assertTrue(dst.hasObject(A_txt));
+		assertTrue(dst.getObjectDatabase().has(A_txt));
 		assertEquals(B, dst.exactRef(master).getObjectId());
 		fsck(dst, B);
 
diff --git a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/HookMessageTest.java b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/HookMessageTest.java
index 7795658..5a5ff1a 100644
--- a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/HookMessageTest.java
+++ b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/HookMessageTest.java
@@ -163,7 +163,7 @@ public void testPush_CreateBranch() throws Exception {
 					.singleton(update));
 		}
 
-		assertTrue(remoteRepository.hasObject(Q_txt));
+		assertTrue(remoteRepository.getObjectDatabase().has(Q_txt));
 		assertNotNull("has " + dstName, remoteRepository.exactRef(dstName));
 		assertEquals(Q, remoteRepository.exactRef(dstName).getObjectId());
 		fsck(remoteRepository, Q);
diff --git a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/SmartClientSmartServerSslTest.java b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/SmartClientSmartServerSslTest.java
index 7deb0d8..30501df 100644
--- a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/SmartClientSmartServerSslTest.java
+++ b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/SmartClientSmartServerSslTest.java
@@ -275,13 +275,13 @@ public void destroy() {
 	@Test
 	public void testInitialClone_ViaHttps() throws Exception {
 		Repository dst = createBareRepository();
-		assertFalse(dst.hasObject(A_txt));
+		assertFalse(dst.getObjectDatabase().has(A_txt));
 
 		try (Transport t = Transport.open(dst, secureURI)) {
 			t.setCredentialsProvider(testCredentials);
 			t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
 		}
-		assertTrue(dst.hasObject(A_txt));
+		assertTrue(dst.getObjectDatabase().has(A_txt));
 		assertEquals(B, dst.exactRef(master).getObjectId());
 		fsck(dst, B);
 
@@ -292,14 +292,14 @@ public void testInitialClone_ViaHttps() throws Exception {
 	@Test
 	public void testInitialClone_RedirectToHttps() throws Exception {
 		Repository dst = createBareRepository();
-		assertFalse(dst.hasObject(A_txt));
+		assertFalse(dst.getObjectDatabase().has(A_txt));
 
 		URIish cloneFrom = extendPath(remoteURI, "/https");
 		try (Transport t = Transport.open(dst, cloneFrom)) {
 			t.setCredentialsProvider(testCredentials);
 			t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
 		}
-		assertTrue(dst.hasObject(A_txt));
+		assertTrue(dst.getObjectDatabase().has(A_txt));
 		assertEquals(B, dst.exactRef(master).getObjectId());
 		fsck(dst, B);
 
@@ -310,7 +310,7 @@ public void testInitialClone_RedirectToHttps() throws Exception {
 	@Test
 	public void testInitialClone_RedirectBackToHttp() throws Exception {
 		Repository dst = createBareRepository();
-		assertFalse(dst.hasObject(A_txt));
+		assertFalse(dst.getObjectDatabase().has(A_txt));
 
 		URIish cloneFrom = extendPath(secureURI, "/back");
 		try (Transport t = Transport.open(dst, cloneFrom)) {
@@ -325,7 +325,7 @@ public void testInitialClone_RedirectBackToHttp() throws Exception {
 	@Test
 	public void testInitialClone_SslFailure() throws Exception {
 		Repository dst = createBareRepository();
-		assertFalse(dst.hasObject(A_txt));
+		assertFalse(dst.getObjectDatabase().has(A_txt));
 
 		try (Transport t = Transport.open(dst, secureURI)) {
 			// Set a credentials provider that doesn't handle questions
diff --git a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/SmartClientSmartServerTest.java b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/SmartClientSmartServerTest.java
index b26324d..ecab61e 100644
--- a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/SmartClientSmartServerTest.java
+++ b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/SmartClientSmartServerTest.java
@@ -537,13 +537,13 @@ protected Map<String, Ref> getAdvertisedRefs(Repository repository,
 	@Test
 	public void testInitialClone_Small() throws Exception {
 		Repository dst = createBareRepository();
-		assertFalse(dst.hasObject(A_txt));
+		assertFalse(dst.getObjectDatabase().has(A_txt));
 
 		try (Transport t = Transport.open(dst, remoteURI)) {
 			t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
 		}
 
-		assertTrue(dst.hasObject(A_txt));
+		assertTrue(dst.getObjectDatabase().has(A_txt));
 		assertEquals(B, dst.exactRef(master).getObjectId());
 		fsck(dst, B);
 
@@ -577,7 +577,7 @@ public void testInitialClone_Small() throws Exception {
 	private void initialClone_Redirect(int nofRedirects, int code)
 			throws Exception {
 		Repository dst = createBareRepository();
-		assertFalse(dst.hasObject(A_txt));
+		assertFalse(dst.getObjectDatabase().has(A_txt));
 
 		URIish cloneFrom = redirectURI;
 		if (code != 301 || nofRedirects > 1) {
@@ -588,7 +588,7 @@ private void initialClone_Redirect(int nofRedirects, int code)
 			t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
 		}
 
-		assertTrue(dst.hasObject(A_txt));
+		assertTrue(dst.getObjectDatabase().has(A_txt));
 		assertEquals(B, dst.exactRef(master).getObjectId());
 		fsck(dst, B);
 
@@ -666,7 +666,7 @@ public void testInitialClone_RedirectTooOften() throws Exception {
 		userConfig.setInt("http", null, "maxRedirects", 3);
 		userConfig.save();
 		Repository dst = createBareRepository();
-		assertFalse(dst.hasObject(A_txt));
+		assertFalse(dst.getObjectDatabase().has(A_txt));
 
 		URIish cloneFrom = extendPath(redirectURI, "/response/4/302");
 		String remoteUri = cloneFrom.toString();
@@ -688,7 +688,7 @@ public void testInitialClone_RedirectTooOften() throws Exception {
 	@Test
 	public void testInitialClone_RedirectLoop() throws Exception {
 		Repository dst = createBareRepository();
-		assertFalse(dst.hasObject(A_txt));
+		assertFalse(dst.getObjectDatabase().has(A_txt));
 
 		URIish cloneFrom = extendPath(redirectURI, "/loop");
 		try (Transport t = Transport.open(dst, cloneFrom)) {
@@ -706,14 +706,14 @@ public void testInitialClone_RedirectOnPostAllowed() throws Exception {
 		userConfig.setString("http", null, "followRedirects", "true");
 		userConfig.save();
 		Repository dst = createBareRepository();
-		assertFalse(dst.hasObject(A_txt));
+		assertFalse(dst.getObjectDatabase().has(A_txt));
 
 		URIish cloneFrom = extendPath(remoteURI, "/post");
 		try (Transport t = Transport.open(dst, cloneFrom)) {
 			t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
 		}
 
-		assertTrue(dst.hasObject(A_txt));
+		assertTrue(dst.getObjectDatabase().has(A_txt));
 		assertEquals(B, dst.exactRef(master).getObjectId());
 		fsck(dst, B);
 
@@ -751,7 +751,7 @@ public void testInitialClone_RedirectOnPostAllowed() throws Exception {
 	@Test
 	public void testInitialClone_RedirectOnPostForbidden() throws Exception {
 		Repository dst = createBareRepository();
-		assertFalse(dst.hasObject(A_txt));
+		assertFalse(dst.getObjectDatabase().has(A_txt));
 
 		URIish cloneFrom = extendPath(remoteURI, "/post");
 		try (Transport t = Transport.open(dst, cloneFrom)) {
@@ -770,7 +770,7 @@ public void testInitialClone_RedirectForbidden() throws Exception {
 		userConfig.save();
 
 		Repository dst = createBareRepository();
-		assertFalse(dst.hasObject(A_txt));
+		assertFalse(dst.getObjectDatabase().has(A_txt));
 
 		try (Transport t = Transport.open(dst, redirectURI)) {
 			t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
@@ -784,14 +784,14 @@ public void testInitialClone_RedirectForbidden() throws Exception {
 	@Test
 	public void testInitialClone_WithAuthentication() throws Exception {
 		Repository dst = createBareRepository();
-		assertFalse(dst.hasObject(A_txt));
+		assertFalse(dst.getObjectDatabase().has(A_txt));
 
 		try (Transport t = Transport.open(dst, authURI)) {
 			t.setCredentialsProvider(testCredentials);
 			t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
 		}
 
-		assertTrue(dst.hasObject(A_txt));
+		assertTrue(dst.getObjectDatabase().has(A_txt));
 		assertEquals(B, dst.exactRef(master).getObjectId());
 		fsck(dst, B);
 
@@ -830,7 +830,7 @@ public void testInitialClone_WithAuthentication() throws Exception {
 	public void testInitialClone_WithAuthenticationNoCredentials()
 			throws Exception {
 		Repository dst = createBareRepository();
-		assertFalse(dst.hasObject(A_txt));
+		assertFalse(dst.getObjectDatabase().has(A_txt));
 
 		try (Transport t = Transport.open(dst, authURI)) {
 			t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
@@ -852,7 +852,7 @@ public void testInitialClone_WithAuthenticationNoCredentials()
 	public void testInitialClone_WithAuthenticationWrongCredentials()
 			throws Exception {
 		Repository dst = createBareRepository();
-		assertFalse(dst.hasObject(A_txt));
+		assertFalse(dst.getObjectDatabase().has(A_txt));
 
 		try (Transport t = Transport.open(dst, authURI)) {
 			t.setCredentialsProvider(new UsernamePasswordCredentialsProvider(
@@ -878,7 +878,7 @@ public void testInitialClone_WithAuthenticationWrongCredentials()
 	public void testInitialClone_WithAuthenticationAfterRedirect()
 			throws Exception {
 		Repository dst = createBareRepository();
-		assertFalse(dst.hasObject(A_txt));
+		assertFalse(dst.getObjectDatabase().has(A_txt));
 
 		URIish cloneFrom = extendPath(redirectURI, "/target/auth");
 		CredentialsProvider uriSpecificCredentialsProvider = new UsernamePasswordCredentialsProvider(
@@ -902,7 +902,7 @@ public boolean get(URIish uri, CredentialItem... items)
 			t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
 		}
 
-		assertTrue(dst.hasObject(A_txt));
+		assertTrue(dst.getObjectDatabase().has(A_txt));
 		assertEquals(B, dst.exactRef(master).getObjectId());
 		fsck(dst, B);
 
@@ -947,14 +947,14 @@ public boolean get(URIish uri, CredentialItem... items)
 	public void testInitialClone_WithAuthenticationOnPostOnly()
 			throws Exception {
 		Repository dst = createBareRepository();
-		assertFalse(dst.hasObject(A_txt));
+		assertFalse(dst.getObjectDatabase().has(A_txt));
 
 		try (Transport t = Transport.open(dst, authOnPostURI)) {
 			t.setCredentialsProvider(testCredentials);
 			t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
 		}
 
-		assertTrue(dst.hasObject(A_txt));
+		assertTrue(dst.getObjectDatabase().has(A_txt));
 		assertEquals(B, dst.exactRef(master).getObjectId());
 		fsck(dst, B);
 
@@ -1124,7 +1124,7 @@ public void testFetch_TooManyLocalCommits() throws Exception {
 	@Test
 	public void testInitialClone_BrokenServer() throws Exception {
 		Repository dst = createBareRepository();
-		assertFalse(dst.hasObject(A_txt));
+		assertFalse(dst.getObjectDatabase().has(A_txt));
 
 		try (Transport t = Transport.open(dst, brokenURI)) {
 			try {
@@ -1283,7 +1283,7 @@ public void testPush_CreateBranch() throws Exception {
 			t.push(NullProgressMonitor.INSTANCE, Collections.singleton(u));
 		}
 
-		assertTrue(remoteRepository.hasObject(Q_txt));
+		assertTrue(remoteRepository.getObjectDatabase().has(Q_txt));
 		assertNotNull("has " + dstName, remoteRepository.exactRef(dstName));
 		assertEquals(Q, remoteRepository.exactRef(dstName).getObjectId());
 		fsck(remoteRepository, Q);
@@ -1357,7 +1357,7 @@ public void testPush_ChunkedEncoding() throws Exception {
 			t.push(NullProgressMonitor.INSTANCE, Collections.singleton(u));
 		}
 
-		assertTrue(remoteRepository.hasObject(Q_bin));
+		assertTrue(remoteRepository.getObjectDatabase().has(Q_bin));
 		assertNotNull("has " + dstName, remoteRepository.exactRef(dstName));
 		assertEquals(Q, remoteRepository.exactRef(dstName).getObjectId());
 		fsck(remoteRepository, Q);
diff --git a/org.eclipse.jgit.junit.http/META-INF/MANIFEST.MF b/org.eclipse.jgit.junit.http/META-INF/MANIFEST.MF
index 41ef859..7c05cd8 100644
--- a/org.eclipse.jgit.junit.http/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.junit.http/META-INF/MANIFEST.MF
@@ -3,7 +3,7 @@
 Bundle-Name: %plugin_name
 Automatic-Module-Name: org.eclipse.jgit.junit.http
 Bundle-SymbolicName: org.eclipse.jgit.junit.http
-Bundle-Version: 5.2.2.qualifier
+Bundle-Version: 5.3.0.qualifier
 Bundle-Localization: plugin
 Bundle-Vendor: %provider_name
 Bundle-ActivationPolicy: lazy
@@ -22,16 +22,16 @@
  org.eclipse.jetty.util.log;version="[9.4.5,10.0.0)",
  org.eclipse.jetty.util.security;version="[9.4.5,10.0.0)",
  org.eclipse.jetty.util.ssl;version="[9.4.5,10.0.0)",
- org.eclipse.jgit.errors;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.http.server;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.internal.storage.file;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.junit;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.lib;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.revwalk;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.transport;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.transport.resolver;version="[5.2.2,5.3.0)",
+ org.eclipse.jgit.errors;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.http.server;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.internal.storage.file;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.junit;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.lib;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.revwalk;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.transport;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.transport.resolver;version="[5.3.0,5.4.0)",
  org.junit;version="[4.12,5.0.0)"
-Export-Package: org.eclipse.jgit.junit.http;version="5.2.2";
+Export-Package: org.eclipse.jgit.junit.http;version="5.3.0";
   uses:="org.eclipse.jgit.transport,
    org.eclipse.jgit.junit,
    javax.servlet.http,
diff --git a/org.eclipse.jgit.junit.http/pom.xml b/org.eclipse.jgit.junit.http/pom.xml
index d4cfd44..3db9ace 100644
--- a/org.eclipse.jgit.junit.http/pom.xml
+++ b/org.eclipse.jgit.junit.http/pom.xml
@@ -50,7 +50,7 @@
   <parent>
     <groupId>org.eclipse.jgit</groupId>
     <artifactId>org.eclipse.jgit-parent</artifactId>
-    <version>5.2.2-SNAPSHOT</version>
+    <version>5.3.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>org.eclipse.jgit.junit.http</artifactId>
diff --git a/org.eclipse.jgit.junit.ssh/META-INF/MANIFEST.MF b/org.eclipse.jgit.junit.ssh/META-INF/MANIFEST.MF
index 5bf0cbc..48ea59b 100644
--- a/org.eclipse.jgit.junit.ssh/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.junit.ssh/META-INF/MANIFEST.MF
@@ -3,7 +3,7 @@
 Bundle-Name: %plugin_name
 Automatic-Module-Name: org.eclipse.jgit.junit.ssh
 Bundle-SymbolicName: org.eclipse.jgit.junit.ssh
-Bundle-Version: 5.2.2.qualifier
+Bundle-Version: 5.3.0.qualifier
 Bundle-Localization: plugin
 Bundle-Vendor: %provider_name
 Bundle-ActivationPolicy: lazy
@@ -29,8 +29,8 @@
  org.apache.sshd.server.shell;version="[2.0.0,2.1.0)",
  org.apache.sshd.server.subsystem;version="[2.0.0,2.1.0)",
  org.apache.sshd.server.subsystem.sftp;version="[2.0.0,2.1.0)",
- org.eclipse.jgit.annotations;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.lib;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.transport;version="[5.2.2,5.3.0)",
+ org.eclipse.jgit.annotations;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.lib;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.transport;version="[5.3.0,5.4.0)",
  org.slf4j;version="[1.7.0,2.0.0)"
-Export-Package: org.eclipse.jgit.junit.ssh;version="5.2.2"
+Export-Package: org.eclipse.jgit.junit.ssh;version="5.3.0"
diff --git a/org.eclipse.jgit.junit.ssh/pom.xml b/org.eclipse.jgit.junit.ssh/pom.xml
index ea1e5a2..8db9760 100644
--- a/org.eclipse.jgit.junit.ssh/pom.xml
+++ b/org.eclipse.jgit.junit.ssh/pom.xml
@@ -50,7 +50,7 @@
   <parent>
     <groupId>org.eclipse.jgit</groupId>
     <artifactId>org.eclipse.jgit-parent</artifactId>
-    <version>5.2.2-SNAPSHOT</version>
+    <version>5.3.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>org.eclipse.jgit.junit.ssh</artifactId>
diff --git a/org.eclipse.jgit.junit/META-INF/MANIFEST.MF b/org.eclipse.jgit.junit/META-INF/MANIFEST.MF
index b16e244..f76cee8 100644
--- a/org.eclipse.jgit.junit/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.junit/META-INF/MANIFEST.MF
@@ -3,34 +3,34 @@
 Bundle-Name: %plugin_name
 Automatic-Module-Name: org.eclipse.jgit.junit
 Bundle-SymbolicName: org.eclipse.jgit.junit
-Bundle-Version: 5.2.2.qualifier
+Bundle-Version: 5.3.0.qualifier
 Bundle-Localization: plugin
 Bundle-Vendor: %provider_name
 Bundle-ActivationPolicy: lazy
 Bundle-RequiredExecutionEnvironment: JavaSE-1.8
-Import-Package: org.eclipse.jgit.annotations;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.api;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.api.errors;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.dircache;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.errors;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.internal.storage.file;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.internal.storage.pack;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.lib;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.merge;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.revwalk;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.storage.file;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.transport;version="5.2.2",
- org.eclipse.jgit.treewalk;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.treewalk.filter;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.util;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.util.io;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.util.time;version="[5.2.2,5.3.0)",
+Import-Package: org.eclipse.jgit.annotations;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.api;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.api.errors;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.dircache;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.errors;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.internal.storage.file;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.internal.storage.pack;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.lib;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.merge;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.revwalk;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.storage.file;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.transport;version="5.3.0",
+ org.eclipse.jgit.treewalk;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.treewalk.filter;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.util;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.util.io;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.util.time;version="[5.3.0,5.4.0)",
  org.junit;version="[4.12,5.0.0)",
  org.junit.rules;version="[4.12,5.0.0)",
  org.junit.runner;version="[4.12,5.0.0)",
  org.junit.runners.model;version="[4.12,5.0.0)",
  org.slf4j;version="[1.7.0,2.0.0)"
-Export-Package: org.eclipse.jgit.junit;version="5.2.2";
+Export-Package: org.eclipse.jgit.junit;version="5.3.0";
   uses:="org.eclipse.jgit.dircache,
    org.eclipse.jgit.lib,
    org.eclipse.jgit.revwalk,
@@ -43,4 +43,4 @@
    org.junit.runners.model,
    org.junit.runner,
    org.eclipse.jgit.util.time",
- org.eclipse.jgit.junit.time;version="5.2.2";uses:="org.eclipse.jgit.util.time"
+ org.eclipse.jgit.junit.time;version="5.3.0";uses:="org.eclipse.jgit.util.time"
diff --git a/org.eclipse.jgit.junit/pom.xml b/org.eclipse.jgit.junit/pom.xml
index 482b2c3..71885d8 100644
--- a/org.eclipse.jgit.junit/pom.xml
+++ b/org.eclipse.jgit.junit/pom.xml
@@ -52,7 +52,7 @@
   <parent>
     <groupId>org.eclipse.jgit</groupId>
     <artifactId>org.eclipse.jgit-parent</artifactId>
-    <version>5.2.2-SNAPSHOT</version>
+    <version>5.3.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>org.eclipse.jgit.junit</artifactId>
diff --git a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/TestRepository.java b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/TestRepository.java
index c9fa2f5..55a7766 100644
--- a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/TestRepository.java
+++ b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/TestRepository.java
@@ -112,7 +112,7 @@
  * @param <R>
  *            type of Repository the test data is stored on.
  */
-public class TestRepository<R extends Repository> {
+public class TestRepository<R extends Repository> implements AutoCloseable {
 
 	/** Constant <code>AUTHOR="J. Author"</code> */
 	public static final String AUTHOR = "J. Author";
@@ -933,6 +933,23 @@ public void packAndPrune() throws Exception {
 		}
 	}
 
+	/**
+	 * Closes the underlying {@link Repository} object and any other internal
+	 * resources.
+	 * <p>
+	 * {@link AutoCloseable} resources that may escape this object, such as
+	 * those returned by the {@link #git} and {@link #getRevWalk()} methods are
+	 * not closed.
+	 */
+	@Override
+	public void close() {
+		try {
+			inserter.close();
+		} finally {
+			db.close();
+		}
+	}
+
 	private static void prunePacked(ObjectDirectory odb) throws IOException {
 		for (PackFile p : odb.getPacks()) {
 			for (MutableEntry e : p)
diff --git a/org.eclipse.jgit.lfs.server.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.lfs.server.test/META-INF/MANIFEST.MF
index 35d7b23..3311865 100644
--- a/org.eclipse.jgit.lfs.server.test/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.lfs.server.test/META-INF/MANIFEST.MF
@@ -3,7 +3,7 @@
 Bundle-Name: %plugin_name
 Automatic-Module-Name: org.eclipse.jgit.lfs.server.test
 Bundle-SymbolicName: org.eclipse.jgit.lfs.server.test
-Bundle-Version: 5.2.2.qualifier
+Bundle-Version: 5.3.0.qualifier
 Bundle-Vendor: %provider_name
 Bundle-Localization: plugin
 Bundle-RequiredExecutionEnvironment: JavaSE-1.8
@@ -28,24 +28,24 @@
  org.eclipse.jetty.util.log;version="[9.4.5,10.0.0)",
  org.eclipse.jetty.util.security;version="[9.4.5,10.0.0)",
  org.eclipse.jetty.util.thread;version="[9.4.5,10.0.0)",
- org.eclipse.jgit.api;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.api.errors;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.internal.storage.file;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.junit;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.junit.http;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.lfs;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.lfs.errors;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.lfs.lib;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.lfs.server;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.lfs.server.fs;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.lfs.test;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.lib;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.revwalk;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.storage.file;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.transport;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.treewalk;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.treewalk.filter;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.util;version="[5.2.2,5.3.0)",
+ org.eclipse.jgit.api;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.api.errors;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.internal.storage.file;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.junit;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.junit.http;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.lfs;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.lfs.errors;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.lfs.lib;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.lfs.server;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.lfs.server.fs;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.lfs.test;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.lib;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.revwalk;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.storage.file;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.transport;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.treewalk;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.treewalk.filter;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.util;version="[5.3.0,5.4.0)",
  org.hamcrest.core;version="[1.1.0,2.0.0)",
  org.junit;version="[4.12,5.0.0)",
  org.junit.rules;version="[4.12,5.0.0)",
diff --git a/org.eclipse.jgit.lfs.server.test/pom.xml b/org.eclipse.jgit.lfs.server.test/pom.xml
index aa5c86a..f8a4695 100644
--- a/org.eclipse.jgit.lfs.server.test/pom.xml
+++ b/org.eclipse.jgit.lfs.server.test/pom.xml
@@ -50,7 +50,7 @@
   <parent>
     <groupId>org.eclipse.jgit</groupId>
     <artifactId>org.eclipse.jgit-parent</artifactId>
-    <version>5.2.2-SNAPSHOT</version>
+    <version>5.3.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>org.eclipse.jgit.lfs.server.test</artifactId>
@@ -137,7 +137,7 @@
       <plugin>
         <artifactId>maven-surefire-plugin</artifactId>
         <configuration>
-          <argLine>-Djava.io.tmpdir=${project.build.directory}  -Xmx300m</argLine>
+          <argLine>@{argLine} -Djava.io.tmpdir=${project.build.directory}  -Xmx300m</argLine>
         </configuration>
       </plugin>
     </plugins>
diff --git a/org.eclipse.jgit.lfs.server/META-INF/MANIFEST.MF b/org.eclipse.jgit.lfs.server/META-INF/MANIFEST.MF
index a79f04e..bc2d237 100644
--- a/org.eclipse.jgit.lfs.server/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.lfs.server/META-INF/MANIFEST.MF
@@ -3,19 +3,19 @@
 Bundle-Name: %plugin_name
 Automatic-Module-Name: org.eclipse.jgit.lfs.server
 Bundle-SymbolicName: org.eclipse.jgit.lfs.server
-Bundle-Version: 5.2.2.qualifier
+Bundle-Version: 5.3.0.qualifier
 Bundle-Localization: plugin
 Bundle-Vendor: %provider_name
-Export-Package: org.eclipse.jgit.lfs.server;version="5.2.2";
+Export-Package: org.eclipse.jgit.lfs.server;version="5.3.0";
   uses:="javax.servlet.http,
    org.eclipse.jgit.lfs.lib",
- org.eclipse.jgit.lfs.server.fs;version="5.2.2";
+ org.eclipse.jgit.lfs.server.fs;version="5.3.0";
   uses:="javax.servlet,
    javax.servlet.http,
    org.eclipse.jgit.lfs.server,
    org.eclipse.jgit.lfs.lib",
- org.eclipse.jgit.lfs.server.internal;version="5.2.2";x-internal:=true,
- org.eclipse.jgit.lfs.server.s3;version="5.2.2";
+ org.eclipse.jgit.lfs.server.internal;version="5.3.0";x-internal:=true,
+ org.eclipse.jgit.lfs.server.s3;version="5.3.0";
   uses:="org.eclipse.jgit.lfs.server,
    org.eclipse.jgit.lfs.lib"
 Bundle-RequiredExecutionEnvironment: JavaSE-1.8
@@ -25,15 +25,15 @@
  javax.servlet.http;version="[3.1.0,4.0.0)",
  org.apache.http;version="[4.3.0,5.0.0)",
  org.apache.http.client;version="[4.3.0,5.0.0)",
- org.eclipse.jgit.annotations;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.internal;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.internal.storage.file;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.lfs.errors;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.lfs.internal;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.lfs.lib;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.lib;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.nls;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.transport.http;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.transport.http.apache;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.util;version="[5.2.2,5.3.0)",
+ org.eclipse.jgit.annotations;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.internal;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.internal.storage.file;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.lfs.errors;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.lfs.internal;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.lfs.lib;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.lib;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.nls;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.transport.http;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.transport.http.apache;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.util;version="[5.3.0,5.4.0)",
  org.slf4j;version="[1.7.0,2.0.0)"
diff --git a/org.eclipse.jgit.lfs.server/pom.xml b/org.eclipse.jgit.lfs.server/pom.xml
index 33b0869..eab96d3 100644
--- a/org.eclipse.jgit.lfs.server/pom.xml
+++ b/org.eclipse.jgit.lfs.server/pom.xml
@@ -50,7 +50,7 @@
   <parent>
     <groupId>org.eclipse.jgit</groupId>
     <artifactId>org.eclipse.jgit-parent</artifactId>
-    <version>5.2.2-SNAPSHOT</version>
+    <version>5.3.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>org.eclipse.jgit.lfs.server</artifactId>
diff --git a/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/internal/LfsGson.java b/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/internal/LfsGson.java
index 7974b24..3f6b780 100644
--- a/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/internal/LfsGson.java
+++ b/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/internal/LfsGson.java
@@ -53,8 +53,6 @@
 
 /**
  * Wrapper for {@link com.google.gson.Gson} used by LFS servlets.
- *
- * @since 4.10.0
  */
 public class LfsGson {
 	private static final Gson gson = new GsonBuilder()
diff --git a/org.eclipse.jgit.lfs.test/BUILD b/org.eclipse.jgit.lfs.test/BUILD
index 213ba57..cc8bc60 100644
--- a/org.eclipse.jgit.lfs.test/BUILD
+++ b/org.eclipse.jgit.lfs.test/BUILD
@@ -1,10 +1,10 @@
-package(default_visibility = ["//visibility:public"])
-
 load(
     "@com_googlesource_gerrit_bazlets//tools:junit.bzl",
     "junit_tests",
 )
 
+package(default_visibility = ["//visibility:public"])
+
 junit_tests(
     name = "lfs",
     srcs = glob(["tst/**/*.java"]),
diff --git a/org.eclipse.jgit.lfs.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.lfs.test/META-INF/MANIFEST.MF
index 5cd9146..5cf259e 100644
--- a/org.eclipse.jgit.lfs.test/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.lfs.test/META-INF/MANIFEST.MF
@@ -3,23 +3,23 @@
 Bundle-Name: %plugin_name
 Automatic-Module-Name: org.eclipse.jgit.lfs.test
 Bundle-SymbolicName: org.eclipse.jgit.lfs.test
-Bundle-Version: 5.2.2.qualifier
+Bundle-Version: 5.3.0.qualifier
 Bundle-Vendor: %provider_name
 Bundle-Localization: plugin
 Bundle-RequiredExecutionEnvironment: JavaSE-1.8
-Import-Package: org.eclipse.jgit.internal.storage.dfs;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.junit;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.lfs;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.lfs.errors;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.lfs.lib;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.lib;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.revwalk;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.treewalk;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.treewalk.filter;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.util;version="[5.2.2,5.3.0)",
+Import-Package: org.eclipse.jgit.internal.storage.dfs;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.junit;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.lfs;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.lfs.errors;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.lfs.lib;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.lib;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.revwalk;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.treewalk;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.treewalk.filter;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.util;version="[5.3.0,5.4.0)",
  org.hamcrest.core;version="[1.1.0,2.0.0)",
  org.junit;version="[4.12,5.0.0)",
  org.junit.runner;version="[4.12,5.0.0)",
  org.junit.runners;version="[4.12,5.0.0)"
-Export-Package: org.eclipse.jgit.lfs.test;version="5.2.2";x-friends:="org.eclipse.jgit.lfs.server.test"
+Export-Package: org.eclipse.jgit.lfs.test;version="5.3.0";x-friends:="org.eclipse.jgit.lfs.server.test"
 
diff --git a/org.eclipse.jgit.lfs.test/pom.xml b/org.eclipse.jgit.lfs.test/pom.xml
index fc23bc5..3c8508f 100644
--- a/org.eclipse.jgit.lfs.test/pom.xml
+++ b/org.eclipse.jgit.lfs.test/pom.xml
@@ -50,7 +50,7 @@
   <parent>
     <groupId>org.eclipse.jgit</groupId>
     <artifactId>org.eclipse.jgit-parent</artifactId>
-    <version>5.2.2-SNAPSHOT</version>
+    <version>5.3.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>org.eclipse.jgit.lfs.test</artifactId>
@@ -111,7 +111,7 @@
       <plugin>
         <artifactId>maven-surefire-plugin</artifactId>
         <configuration>
-          <argLine>-Djava.io.tmpdir=${project.build.directory}  -Xmx300m</argLine>
+          <argLine>@{argLine} -Djava.io.tmpdir=${project.build.directory}  -Xmx300m</argLine>
         </configuration>
       </plugin>
     </plugins>
diff --git a/org.eclipse.jgit.lfs/META-INF/MANIFEST.MF b/org.eclipse.jgit.lfs/META-INF/MANIFEST.MF
index fdfa26f..3051140 100644
--- a/org.eclipse.jgit.lfs/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.lfs/META-INF/MANIFEST.MF
@@ -3,33 +3,33 @@
 Bundle-Name: %plugin_name
 Automatic-Module-Name: org.eclipse.jgit.lfs
 Bundle-SymbolicName: org.eclipse.jgit.lfs
-Bundle-Version: 5.2.2.qualifier
+Bundle-Version: 5.3.0.qualifier
 Bundle-Localization: plugin
 Bundle-Vendor: %provider_name
-Export-Package: org.eclipse.jgit.lfs;version="5.2.2",
- org.eclipse.jgit.lfs.errors;version="5.2.2",
- org.eclipse.jgit.lfs.internal;version="5.2.2";x-friends:="org.eclipse.jgit.lfs.test,org.eclipse.jgit.lfs.server.fs,org.eclipse.jgit.lfs.server",
- org.eclipse.jgit.lfs.lib;version="5.2.2"
+Export-Package: org.eclipse.jgit.lfs;version="5.3.0",
+ org.eclipse.jgit.lfs.errors;version="5.3.0",
+ org.eclipse.jgit.lfs.internal;version="5.3.0";x-friends:="org.eclipse.jgit.lfs.test,org.eclipse.jgit.lfs.server.fs,org.eclipse.jgit.lfs.server",
+ org.eclipse.jgit.lfs.lib;version="5.3.0"
 Bundle-RequiredExecutionEnvironment: JavaSE-1.8
 Import-Package: com.google.gson;version="[2.8.2,3.0.0)",
  com.google.gson.stream;version="[2.8.2,3.0.0)",
  org.apache.http.impl.client;version="[4.2.6,5.0.0)",
  org.apache.http.impl.conn;version="[4.2.6,5.0.0)",
- org.eclipse.jgit.annotations;version="[5.2.2,5.3.0)";resolution:=optional,
- org.eclipse.jgit.api.errors;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.attributes;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.diff;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.errors;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.hooks;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.internal.storage.file;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.lib;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.nls;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.revwalk;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.storage.file;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.storage.pack;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.transport;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.transport.http;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.treewalk;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.treewalk.filter;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.util;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.util.io;version="[5.2.2,5.3.0)"
+ org.eclipse.jgit.annotations;version="[5.3.0,5.4.0)";resolution:=optional,
+ org.eclipse.jgit.api.errors;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.attributes;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.diff;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.errors;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.hooks;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.internal.storage.file;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.lib;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.nls;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.revwalk;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.storage.file;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.storage.pack;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.transport;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.transport.http;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.treewalk;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.treewalk.filter;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.util;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.util.io;version="[5.3.0,5.4.0)"
diff --git a/org.eclipse.jgit.lfs/pom.xml b/org.eclipse.jgit.lfs/pom.xml
index 5e35419..823521a 100644
--- a/org.eclipse.jgit.lfs/pom.xml
+++ b/org.eclipse.jgit.lfs/pom.xml
@@ -50,7 +50,7 @@
   <parent>
     <groupId>org.eclipse.jgit</groupId>
     <artifactId>org.eclipse.jgit-parent</artifactId>
-    <version>5.2.2-SNAPSHOT</version>
+    <version>5.3.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>org.eclipse.jgit.lfs</artifactId>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.feature/feature.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.feature/feature.xml
index ba8c901..8a6e2a7 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.feature/feature.xml
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.feature/feature.xml
@@ -2,7 +2,7 @@
 <feature
       id="org.eclipse.jgit"
       label="%featureName"
-      version="5.2.2.qualifier"
+      version="5.3.0.qualifier"
       provider-name="%providerName">
 
    <description url="http://www.eclipse.org/jgit/">
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.feature/pom.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.feature/pom.xml
index 6025970..83316ea 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.feature/pom.xml
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.feature/pom.xml
@@ -50,7 +50,7 @@
   <parent>
     <groupId>org.eclipse.jgit</groupId>
     <artifactId>jgit.tycho.parent</artifactId>
-    <version>5.2.2-SNAPSHOT</version>
+    <version>5.3.0-SNAPSHOT</version>
   </parent>
 
   <groupId>org.eclipse.jgit.feature</groupId>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.http.apache.feature/feature.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.http.apache.feature/feature.xml
index c15b255..8b4a11b 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.http.apache.feature/feature.xml
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.http.apache.feature/feature.xml
@@ -2,7 +2,7 @@
 <feature
       id="org.eclipse.jgit.http.apache"
       label="%featureName"
-      version="5.2.2.qualifier"
+      version="5.3.0.qualifier"
       provider-name="%providerName">
 
    <description url="http://www.eclipse.org/jgit/">
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.http.apache.feature/pom.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.http.apache.feature/pom.xml
index 5f795b3..2d918bc 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.http.apache.feature/pom.xml
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.http.apache.feature/pom.xml
@@ -50,7 +50,7 @@
   <parent>
     <groupId>org.eclipse.jgit</groupId>
     <artifactId>jgit.tycho.parent</artifactId>
-    <version>5.2.2-SNAPSHOT</version>
+    <version>5.3.0-SNAPSHOT</version>
   </parent>
 
   <groupId>org.eclipse.jgit.feature</groupId>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.junit.feature/feature.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.junit.feature/feature.xml
index 2836464..c07fe1d 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.junit.feature/feature.xml
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.junit.feature/feature.xml
@@ -2,7 +2,7 @@
 <feature
       id="org.eclipse.jgit.junit"
       label="%featureName"
-      version="5.2.2.qualifier"
+      version="5.3.0.qualifier"
       provider-name="%providerName">
 
    <description url="http://www.eclipse.org/jgit/">
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.junit.feature/pom.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.junit.feature/pom.xml
index 56ffe46..4ea0a01 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.junit.feature/pom.xml
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.junit.feature/pom.xml
@@ -50,7 +50,7 @@
   <parent>
     <groupId>org.eclipse.jgit</groupId>
     <artifactId>jgit.tycho.parent</artifactId>
-    <version>5.2.2-SNAPSHOT</version>
+    <version>5.3.0-SNAPSHOT</version>
   </parent>
 
   <groupId>org.eclipse.jgit.feature</groupId>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.lfs.feature/feature.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.lfs.feature/feature.xml
index a32bd23..101f331 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.lfs.feature/feature.xml
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.lfs.feature/feature.xml
@@ -2,7 +2,7 @@
 <feature
       id="org.eclipse.jgit.lfs"
       label="%featureName"
-      version="5.2.2.qualifier"
+      version="5.3.0.qualifier"
       provider-name="%providerName">
 
    <description url="http://www.eclipse.org/jgit/">
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.lfs.feature/pom.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.lfs.feature/pom.xml
index bc71812..ca25643 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.lfs.feature/pom.xml
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.lfs.feature/pom.xml
@@ -50,7 +50,7 @@
   <parent>
     <groupId>org.eclipse.jgit</groupId>
     <artifactId>jgit.tycho.parent</artifactId>
-    <version>5.2.2-SNAPSHOT</version>
+    <version>5.3.0-SNAPSHOT</version>
   </parent>
 
   <groupId>org.eclipse.jgit.feature</groupId>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.feature/feature.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.feature/feature.xml
index 86cd779..7c76b8e 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.feature/feature.xml
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.feature/feature.xml
@@ -2,7 +2,7 @@
 <feature
       id="org.eclipse.jgit.pgm"
       label="%featureName"
-      version="5.2.2.qualifier"
+      version="5.3.0.qualifier"
       provider-name="%providerName">
 
    <description url="http://www.eclipse.org/jgit/">
@@ -31,9 +31,9 @@
          version="0.0.0"/>
 
    <requires>
-      <import feature="org.eclipse.jgit" version="5.2.2" match="equivalent"/>
-      <import feature="org.eclipse.jgit.lfs" version="5.2.2" match="equivalent"/>
-      <import feature="org.eclipse.jgit.ssh.apache" version="5.2.2" match="equivalent"/>
+      <import feature="org.eclipse.jgit" version="5.3.0" match="equivalent"/>
+      <import feature="org.eclipse.jgit.lfs" version="5.3.0" match="equivalent"/>
+      <import feature="org.eclipse.jgit.ssh.apache" version="5.3.0" match="equivalent"/>
    </requires>
 
    <plugin
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.feature/pom.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.feature/pom.xml
index 9ca089e..1ade5a8 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.feature/pom.xml
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.feature/pom.xml
@@ -50,7 +50,7 @@
   <parent>
     <groupId>org.eclipse.jgit</groupId>
     <artifactId>jgit.tycho.parent</artifactId>
-    <version>5.2.2-SNAPSHOT</version>
+    <version>5.3.0-SNAPSHOT</version>
   </parent>
 
   <groupId>org.eclipse.jgit.feature</groupId>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.source.feature/feature.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.source.feature/feature.xml
index d748397..7817086 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.source.feature/feature.xml
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.source.feature/feature.xml
@@ -2,7 +2,7 @@
 <feature
       id="org.eclipse.jgit.pgm.source"
       label="%featureName"
-      version="5.2.2.qualifier"
+      version="5.3.0.qualifier"
       provider-name="%providerName">
 
    <description url="http://www.eclipse.org/jgit/">
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.source.feature/pom.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.source.feature/pom.xml
index d1e5f92..6827ca1 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.source.feature/pom.xml
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.source.feature/pom.xml
@@ -50,7 +50,7 @@
   <parent>
     <groupId>org.eclipse.jgit</groupId>
     <artifactId>jgit.tycho.parent</artifactId>
-    <version>5.2.2-SNAPSHOT</version>
+    <version>5.3.0-SNAPSHOT</version>
   </parent>
 
   <groupId>org.eclipse.jgit.feature</groupId>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.repository/pom.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.repository/pom.xml
index bb7484e..ae0c25d 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.repository/pom.xml
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.repository/pom.xml
@@ -50,7 +50,7 @@
   <parent>
     <groupId>org.eclipse.jgit</groupId>
     <artifactId>jgit.tycho.parent</artifactId>
-    <version>5.2.2-SNAPSHOT</version>
+    <version>5.3.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>org.eclipse.jgit.repository</artifactId>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.source.feature/feature.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.source.feature/feature.xml
index eb63de3..fc73b67 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.source.feature/feature.xml
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.source.feature/feature.xml
@@ -2,7 +2,7 @@
 <feature
       id="org.eclipse.jgit.source"
       label="%featureName"
-      version="5.2.2.qualifier"
+      version="5.3.0.qualifier"
       provider-name="%providerName">
 
    <description url="http://www.eclipse.org/jgit/">
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.source.feature/pom.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.source.feature/pom.xml
index 5db611d..482c2d8 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.source.feature/pom.xml
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.source.feature/pom.xml
@@ -50,7 +50,7 @@
   <parent>
     <groupId>org.eclipse.jgit</groupId>
     <artifactId>jgit.tycho.parent</artifactId>
-    <version>5.2.2-SNAPSHOT</version>
+    <version>5.3.0-SNAPSHOT</version>
   </parent>
 
   <groupId>org.eclipse.jgit.feature</groupId>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.ssh.apache.feature/feature.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.ssh.apache.feature/feature.xml
index ce9a54c..60a43da 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.ssh.apache.feature/feature.xml
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.ssh.apache.feature/feature.xml
@@ -2,7 +2,7 @@
 <feature
       id="org.eclipse.jgit.ssh.apache"
       label="%featureName"
-      version="5.2.2.qualifier"
+      version="5.3.0.qualifier"
       provider-name="%providerName">
 
    <description url="http://www.eclipse.org/jgit/">
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.ssh.apache.feature/pom.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.ssh.apache.feature/pom.xml
index 2e0ea99..5fcbea3 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.ssh.apache.feature/pom.xml
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.ssh.apache.feature/pom.xml
@@ -50,7 +50,7 @@
   <parent>
     <groupId>org.eclipse.jgit</groupId>
     <artifactId>jgit.tycho.parent</artifactId>
-    <version>5.2.2-SNAPSHOT</version>
+    <version>5.3.0-SNAPSHOT</version>
   </parent>
 
   <groupId>org.eclipse.jgit.feature</groupId>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.ssh.apache.source.feature/feature.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.ssh.apache.source.feature/feature.xml
index aea65bd..2bafe1c 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.ssh.apache.source.feature/feature.xml
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.ssh.apache.source.feature/feature.xml
@@ -2,7 +2,7 @@
 <feature
       id="org.eclipse.jgit.ssh.apache.source"
       label="%featureName"
-      version="5.2.2.qualifier"
+      version="5.3.0.qualifier"
       provider-name="%providerName">
 
    <description url="http://www.eclipse.org/jgit/">
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.ssh.apache.source.feature/pom.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.ssh.apache.source.feature/pom.xml
index 75a30a6..9aae419 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.ssh.apache.source.feature/pom.xml
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.ssh.apache.source.feature/pom.xml
@@ -50,7 +50,7 @@
   <parent>
     <groupId>org.eclipse.jgit</groupId>
     <artifactId>jgit.tycho.parent</artifactId>
-    <version>5.2.2-SNAPSHOT</version>
+    <version>5.3.0-SNAPSHOT</version>
   </parent>
 
   <groupId>org.eclipse.jgit.feature</groupId>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/META-INF/MANIFEST.MF b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/META-INF/MANIFEST.MF
index e560d8a..7a0a70b 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/META-INF/MANIFEST.MF
@@ -2,4 +2,4 @@
 Bundle-ManifestVersion: 2
 Bundle-Name: JGit Target Platform Bundle
 Bundle-SymbolicName: org.eclipse.jgit.target
-Bundle-Version: 5.2.2.qualifier
+Bundle-Version: 5.3.0.qualifier
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.10-staging.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.10-staging.target
index 98a2a6b..827619e 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.10-staging.target
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.10-staging.target
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
 <?pde?>
 <!-- generated with https://github.com/eclipse-cbi/targetplatform-dsl -->
-<target name="jgit-4.9-staging" sequenceNumber="1544018574">
+<target name="jgit-4.10-staging" sequenceNumber="1545531343">
   <locations>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
       <unit id="org.eclipse.jetty.client" version="9.4.11.v20180605"/>
@@ -62,8 +62,8 @@
       <unit id="org.junit.source" version="4.12.0.v201504281640"/>
       <unit id="javax.servlet" version="3.1.0.v201410161800"/>
       <unit id="javax.servlet.source" version="3.1.0.v201410161800"/>
-      <unit id="org.tukaani.xz" version="1.6.0.v20170629-1752"/>
-      <unit id="org.tukaani.xz.source" version="1.6.0.v20170629-1752"/>
+      <unit id="org.tukaani.xz" version="1.8.0.v20180207-1613"/>
+      <unit id="org.tukaani.xz.source" version="1.8.0.v20180207-1613"/>
       <unit id="org.slf4j.api" version="1.7.2.v20121108-1250"/>
       <unit id="org.slf4j.api.source" version="1.7.2.v20121108-1250"/>
       <unit id="org.slf4j.impl.log4j12" version="1.7.2.v20131105-2200"/>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.10-staging.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.10-staging.tpd
index 07594ea..3dd6b93 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.10-staging.tpd
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.10-staging.tpd
@@ -1,8 +1,8 @@
-target "jgit-4.9-staging" with source configurePhase
+target "jgit-4.10-staging" with source configurePhase
 
 include "projects/jetty-9.4.11.tpd"
 include "orbit/R20181128170323-2018-12.tpd"
 
 location "http://download.eclipse.org/staging/2018-12/" {
 	org.eclipse.osgi lazy
-}
\ No newline at end of file
+}
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.5.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.5.target
index 10ff3be..4bb6e24 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.5.target
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.5.target
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
 <?pde?>
 <!-- generated with https://github.com/eclipse-cbi/targetplatform-dsl -->
-<target name="jgit-4.5" sequenceNumber="1544018556">
+<target name="jgit-4.5" sequenceNumber="1545531390">
   <locations>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
       <unit id="org.eclipse.jetty.client" version="9.4.11.v20180605"/>
@@ -62,8 +62,8 @@
       <unit id="org.junit.source" version="4.12.0.v201504281640"/>
       <unit id="javax.servlet" version="3.1.0.v201410161800"/>
       <unit id="javax.servlet.source" version="3.1.0.v201410161800"/>
-      <unit id="org.tukaani.xz" version="1.6.0.v20170629-1752"/>
-      <unit id="org.tukaani.xz.source" version="1.6.0.v20170629-1752"/>
+      <unit id="org.tukaani.xz" version="1.8.0.v20180207-1613"/>
+      <unit id="org.tukaani.xz.source" version="1.8.0.v20180207-1613"/>
       <unit id="org.slf4j.api" version="1.7.2.v20121108-1250"/>
       <unit id="org.slf4j.api.source" version="1.7.2.v20121108-1250"/>
       <unit id="org.slf4j.impl.log4j12" version="1.7.2.v20131105-2200"/>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.6.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.6.target
index 11fd7fd..9a37922 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.6.target
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.6.target
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
 <?pde?>
 <!-- generated with https://github.com/eclipse-cbi/targetplatform-dsl -->
-<target name="jgit-4.6" sequenceNumber="1544018561">
+<target name="jgit-4.6" sequenceNumber="1545531423">
   <locations>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
       <unit id="org.eclipse.jetty.client" version="9.4.11.v20180605"/>
@@ -62,8 +62,8 @@
       <unit id="org.junit.source" version="4.12.0.v201504281640"/>
       <unit id="javax.servlet" version="3.1.0.v201410161800"/>
       <unit id="javax.servlet.source" version="3.1.0.v201410161800"/>
-      <unit id="org.tukaani.xz" version="1.6.0.v20170629-1752"/>
-      <unit id="org.tukaani.xz.source" version="1.6.0.v20170629-1752"/>
+      <unit id="org.tukaani.xz" version="1.8.0.v20180207-1613"/>
+      <unit id="org.tukaani.xz.source" version="1.8.0.v20180207-1613"/>
       <unit id="org.slf4j.api" version="1.7.2.v20121108-1250"/>
       <unit id="org.slf4j.api.source" version="1.7.2.v20121108-1250"/>
       <unit id="org.slf4j.impl.log4j12" version="1.7.2.v20131105-2200"/>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.7.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.7.target
index 061439c..80ca7a2 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.7.target
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.7.target
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
 <?pde?>
 <!-- generated with https://github.com/eclipse-cbi/targetplatform-dsl -->
-<target name="jgit-4.7" sequenceNumber="1544018548">
+<target name="jgit-4.7" sequenceNumber="1545531440">
   <locations>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
       <unit id="org.eclipse.jetty.client" version="9.4.11.v20180605"/>
@@ -62,8 +62,8 @@
       <unit id="org.junit.source" version="4.12.0.v201504281640"/>
       <unit id="javax.servlet" version="3.1.0.v201410161800"/>
       <unit id="javax.servlet.source" version="3.1.0.v201410161800"/>
-      <unit id="org.tukaani.xz" version="1.6.0.v20170629-1752"/>
-      <unit id="org.tukaani.xz.source" version="1.6.0.v20170629-1752"/>
+      <unit id="org.tukaani.xz" version="1.8.0.v20180207-1613"/>
+      <unit id="org.tukaani.xz.source" version="1.8.0.v20180207-1613"/>
       <unit id="org.slf4j.api" version="1.7.2.v20121108-1250"/>
       <unit id="org.slf4j.api.source" version="1.7.2.v20121108-1250"/>
       <unit id="org.slf4j.impl.log4j12" version="1.7.2.v20131105-2200"/>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.8.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.8.target
index da66fb9..470d5ca 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.8.target
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.8.target
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
 <?pde?>
 <!-- generated with https://github.com/eclipse-cbi/targetplatform-dsl -->
-<target name="jgit-4.8" sequenceNumber="1544018536">
+<target name="jgit-4.8" sequenceNumber="1545531452">
   <locations>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
       <unit id="org.eclipse.jetty.client" version="9.4.11.v20180605"/>
@@ -62,8 +62,8 @@
       <unit id="org.junit.source" version="4.12.0.v201504281640"/>
       <unit id="javax.servlet" version="3.1.0.v201410161800"/>
       <unit id="javax.servlet.source" version="3.1.0.v201410161800"/>
-      <unit id="org.tukaani.xz" version="1.6.0.v20170629-1752"/>
-      <unit id="org.tukaani.xz.source" version="1.6.0.v20170629-1752"/>
+      <unit id="org.tukaani.xz" version="1.8.0.v20180207-1613"/>
+      <unit id="org.tukaani.xz.source" version="1.8.0.v20180207-1613"/>
       <unit id="org.slf4j.api" version="1.7.2.v20121108-1250"/>
       <unit id="org.slf4j.api.source" version="1.7.2.v20121108-1250"/>
       <unit id="org.slf4j.impl.log4j12" version="1.7.2.v20131105-2200"/>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.9.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.9.target
index 025bb1f..7e19d35 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,7 +1,7 @@
 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
 <?pde?>
 <!-- generated with https://github.com/eclipse-cbi/targetplatform-dsl -->
-<target name="jgit-4.9" sequenceNumber="1544017335">
+<target name="jgit-4.9" sequenceNumber="1545531468">
   <locations>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
       <unit id="org.eclipse.jetty.client" version="9.4.11.v20180605"/>
@@ -62,8 +62,8 @@
       <unit id="org.junit.source" version="4.12.0.v201504281640"/>
       <unit id="javax.servlet" version="3.1.0.v201410161800"/>
       <unit id="javax.servlet.source" version="3.1.0.v201410161800"/>
-      <unit id="org.tukaani.xz" version="1.6.0.v20170629-1752"/>
-      <unit id="org.tukaani.xz.source" version="1.6.0.v20170629-1752"/>
+      <unit id="org.tukaani.xz" version="1.8.0.v20180207-1613"/>
+      <unit id="org.tukaani.xz.source" version="1.8.0.v20180207-1613"/>
       <unit id="org.slf4j.api" version="1.7.2.v20121108-1250"/>
       <unit id="org.slf4j.api.source" version="1.7.2.v20121108-1250"/>
       <unit id="org.slf4j.impl.log4j12" version="1.7.2.v20131105-2200"/>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/R20181128170323-2018-12.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/R20181128170323-2018-12.tpd
index d5a257d..d447d6c 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/R20181128170323-2018-12.tpd
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/R20181128170323-2018-12.tpd
@@ -41,8 +41,8 @@
 	org.junit.source [4.12.0.v201504281640,4.12.0.v201504281640]
 	javax.servlet [3.1.0.v201410161800,3.1.0.v201410161800]
 	javax.servlet.source [3.1.0.v201410161800,3.1.0.v201410161800]
-	org.tukaani.xz [1.6.0.v20170629-1752,1.6.0.v20170629-1752]
-	org.tukaani.xz.source [1.6.0.v20170629-1752,1.6.0.v20170629-1752]
+	org.tukaani.xz [1.8.0.v20180207-1613,1.8.0.v20180207-1613]
+	org.tukaani.xz.source [1.8.0.v20180207-1613,1.8.0.v20180207-1613]
 	org.slf4j.api [1.7.2.v20121108-1250,1.7.2.v20121108-1250]
 	org.slf4j.api.source [1.7.2.v20121108-1250,1.7.2.v20121108-1250]
 	org.slf4j.impl.log4j12 [1.7.2.v20131105-2200,1.7.2.v20131105-2200]
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/pom.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/pom.xml
index d6db1c0..a6a3371 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/pom.xml
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/pom.xml
@@ -49,7 +49,7 @@
   <parent>
     <groupId>org.eclipse.jgit</groupId>
     <artifactId>jgit.tycho.parent</artifactId>
-    <version>5.2.2-SNAPSHOT</version>
+    <version>5.3.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>org.eclipse.jgit.target</artifactId>
@@ -82,4 +82,4 @@
       </plugin>
     </plugins>
   </build>
-</project>
+</project>
\ No newline at end of file
diff --git a/org.eclipse.jgit.packaging/pom.xml b/org.eclipse.jgit.packaging/pom.xml
index eee67ed..9eb04e5 100644
--- a/org.eclipse.jgit.packaging/pom.xml
+++ b/org.eclipse.jgit.packaging/pom.xml
@@ -53,13 +53,13 @@
 
   <groupId>org.eclipse.jgit</groupId>
   <artifactId>jgit.tycho.parent</artifactId>
-  <version>5.2.2-SNAPSHOT</version>
+  <version>5.3.0-SNAPSHOT</version>
   <packaging>pom</packaging>
 
   <name>JGit Tycho Parent</name>
 
   <properties>
-    <tycho-version>1.2.0</tycho-version>
+    <tycho-version>1.3.0</tycho-version>
     <tycho-extras-version>${tycho-version}</tycho-extras-version>
     <target-platform>jgit-4.6</target-platform>
   </properties>
diff --git a/org.eclipse.jgit.pgm.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.pgm.test/META-INF/MANIFEST.MF
index 645a195..3819bb9 100644
--- a/org.eclipse.jgit.pgm.test/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.pgm.test/META-INF/MANIFEST.MF
@@ -3,28 +3,28 @@
 Bundle-Name: %plugin_name
 Automatic-Module-Name: org.eclipse.jgit.pgm.test
 Bundle-SymbolicName: org.eclipse.jgit.pgm.test
-Bundle-Version: 5.2.2.qualifier
+Bundle-Version: 5.3.0.qualifier
 Bundle-Vendor: %provider_name
 Bundle-Localization: plugin
 Bundle-ActivationPolicy: lazy
 Bundle-RequiredExecutionEnvironment: JavaSE-1.8
-Import-Package: org.eclipse.jgit.api;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.api.errors;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.diff;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.dircache;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.internal.storage.file;version="5.2.2",
- org.eclipse.jgit.junit;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.lib;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.merge;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.pgm;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.pgm.internal;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.pgm.opt;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.revwalk;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.storage.file;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.transport;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.treewalk;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.util;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.util.io;version="[5.2.2,5.3.0)",
+Import-Package: org.eclipse.jgit.api;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.api.errors;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.diff;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.dircache;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.internal.storage.file;version="5.3.0",
+ org.eclipse.jgit.junit;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.lib;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.merge;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.pgm;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.pgm.internal;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.pgm.opt;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.revwalk;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.storage.file;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.transport;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.treewalk;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.util;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.util.io;version="[5.3.0,5.4.0)",
  org.hamcrest.core;bundle-version="[1.1.0,2.0.0)",
  org.junit;version="[4.12,5.0.0)",
  org.junit.rules;version="[4.12,5.0.0)",
diff --git a/org.eclipse.jgit.pgm.test/pom.xml b/org.eclipse.jgit.pgm.test/pom.xml
index be0d37c..ea18b01 100644
--- a/org.eclipse.jgit.pgm.test/pom.xml
+++ b/org.eclipse.jgit.pgm.test/pom.xml
@@ -50,7 +50,7 @@
   <parent>
     <groupId>org.eclipse.jgit</groupId>
     <artifactId>org.eclipse.jgit-parent</artifactId>
-    <version>5.2.2-SNAPSHOT</version>
+    <version>5.3.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>org.eclipse.jgit.pgm.test</artifactId>
@@ -109,7 +109,7 @@
       <plugin>
         <artifactId>maven-surefire-plugin</artifactId>
         <configuration>
-          <argLine>-Djava.io.tmpdir=${project.build.directory}</argLine>
+          <argLine>@{argLine} -Djava.io.tmpdir=${project.build.directory}</argLine>
         </configuration>
       </plugin>
     </plugins>
diff --git a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/CheckoutTest.java b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/CheckoutTest.java
index b2115a4..f0e2b38 100644
--- a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/CheckoutTest.java
+++ b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/CheckoutTest.java
@@ -58,6 +58,7 @@
 import org.eclipse.jgit.api.Git;
 import org.eclipse.jgit.api.errors.CheckoutConflictException;
 import org.eclipse.jgit.diff.DiffEntry;
+import org.eclipse.jgit.junit.LocalDiskRepositoryTestCase;
 import org.eclipse.jgit.lib.CLIRepositoryTestCase;
 import org.eclipse.jgit.lib.FileMode;
 import org.eclipse.jgit.lib.Ref;
@@ -684,4 +685,19 @@ public void testCheckoutLink() throws Exception {
 			assertTrue(Files.isSymbolicLink(path));
 		}
 	}
+
+	@Test
+	public void testCheckoutForce_Bug530771() throws Exception {
+		try (Git git = new Git(db)) {
+			File f = writeTrashFile("a", "Hello world");
+			git.add().addFilepattern("a").call();
+			git.commit().setMessage("create a").call();
+			writeTrashFile("a", "Goodbye world");
+			assertEquals("[]",
+					Arrays.toString(execute("git checkout -f HEAD")));
+			assertEquals("Hello world", read(f));
+			assertEquals("[a, mode:100644, content:Hello world]",
+					indexState(db, LocalDiskRepositoryTestCase.CONTENT));
+		}
+	}
 }
diff --git a/org.eclipse.jgit.pgm/META-INF/MANIFEST.MF b/org.eclipse.jgit.pgm/META-INF/MANIFEST.MF
index af51008..c28bce1 100644
--- a/org.eclipse.jgit.pgm/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.pgm/META-INF/MANIFEST.MF
@@ -3,7 +3,7 @@
 Bundle-Name: %plugin_name
 Automatic-Module-Name: org.eclipse.jgit.pgm
 Bundle-SymbolicName: org.eclipse.jgit.pgm
-Bundle-Version: 5.2.2.qualifier
+Bundle-Version: 5.3.0.qualifier
 Bundle-Vendor: %provider_name
 Bundle-ActivationPolicy: lazy
 Bundle-Localization: plugin
@@ -28,50 +28,50 @@
  org.eclipse.jetty.util.log;version="[9.4.5,10.0.0)",
  org.eclipse.jetty.util.security;version="[9.4.5,10.0.0)",
  org.eclipse.jetty.util.thread;version="[9.4.5,10.0.0)",
- org.eclipse.jgit.api;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.api.errors;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.archive;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.awtui;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.blame;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.diff;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.dircache;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.errors;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.gitrepo;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.internal.ketch;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.internal.storage.dfs;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.internal.storage.file;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.internal.storage.io;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.internal.storage.pack;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.internal.storage.reftable;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.internal.storage.reftree;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.lfs;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.lfs.lib;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.lfs.server;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.lfs.server.fs;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.lfs.server.s3;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.lib;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.merge;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.nls;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.notes;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.revplot;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.revwalk;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.revwalk.filter;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.storage.file;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.storage.pack;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.transport;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.transport.http.apache;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.transport.resolver;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.transport.sshd;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.treewalk;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.treewalk.filter;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.util;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.util.io;version="[5.2.2,5.3.0)",
+ org.eclipse.jgit.api;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.api.errors;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.archive;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.awtui;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.blame;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.diff;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.dircache;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.errors;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.gitrepo;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.internal.ketch;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.internal.storage.dfs;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.internal.storage.file;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.internal.storage.io;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.internal.storage.pack;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.internal.storage.reftable;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.internal.storage.reftree;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.lfs;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.lfs.lib;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.lfs.server;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.lfs.server.fs;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.lfs.server.s3;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.lib;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.merge;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.nls;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.notes;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.revplot;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.revwalk;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.revwalk.filter;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.storage.file;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.storage.pack;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.transport;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.transport.http.apache;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.transport.resolver;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.transport.sshd;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.treewalk;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.treewalk.filter;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.util;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.util.io;version="[5.3.0,5.4.0)",
  org.kohsuke.args4j;version="[2.33.0,3.0.0)",
  org.kohsuke.args4j.spi;version="[2.33.0,3.0.0)"
-Export-Package: org.eclipse.jgit.console;version="5.2.2";
+Export-Package: org.eclipse.jgit.console;version="5.3.0";
   uses:="org.eclipse.jgit.transport,
    org.eclipse.jgit.util",
- org.eclipse.jgit.pgm;version="5.2.2";
+ org.eclipse.jgit.pgm;version="5.3.0";
   uses:="org.eclipse.jgit.revwalk,
    org.eclipse.jgit.treewalk.filter,
    org.eclipse.jgit.pgm.opt,
@@ -82,11 +82,11 @@
    org.eclipse.jgit.treewalk,
    javax.swing,
    org.eclipse.jgit.transport",
- org.eclipse.jgit.pgm.debug;version="5.2.2";
+ org.eclipse.jgit.pgm.debug;version="5.3.0";
   uses:="org.eclipse.jgit.util.io,
    org.eclipse.jgit.pgm",
- org.eclipse.jgit.pgm.internal;version="5.2.2";x-friends:="org.eclipse.jgit.pgm.test,org.eclipse.jgit.test",
- org.eclipse.jgit.pgm.opt;version="5.2.2";
+ org.eclipse.jgit.pgm.internal;version="5.3.0";x-friends:="org.eclipse.jgit.pgm.test,org.eclipse.jgit.test",
+ org.eclipse.jgit.pgm.opt;version="5.3.0";
   uses:="org.eclipse.jgit.lib,
    org.eclipse.jgit.revwalk,
    org.kohsuke.args4j.spi,
diff --git a/org.eclipse.jgit.pgm/META-INF/SOURCE-MANIFEST.MF b/org.eclipse.jgit.pgm/META-INF/SOURCE-MANIFEST.MF
index 20b0f33..e188427 100644
--- a/org.eclipse.jgit.pgm/META-INF/SOURCE-MANIFEST.MF
+++ b/org.eclipse.jgit.pgm/META-INF/SOURCE-MANIFEST.MF
@@ -3,5 +3,5 @@
 Bundle-Name: org.eclipse.jgit.pgm - Sources
 Bundle-SymbolicName: org.eclipse.jgit.pgm.source
 Bundle-Vendor: Eclipse.org - JGit
-Bundle-Version: 5.2.2.qualifier
-Eclipse-SourceBundle: org.eclipse.jgit.pgm;version="5.2.2.qualifier";roots="."
+Bundle-Version: 5.3.0.qualifier
+Eclipse-SourceBundle: org.eclipse.jgit.pgm;version="5.3.0.qualifier";roots="."
diff --git a/org.eclipse.jgit.pgm/pom.xml b/org.eclipse.jgit.pgm/pom.xml
index c10d11f..049d4de 100644
--- a/org.eclipse.jgit.pgm/pom.xml
+++ b/org.eclipse.jgit.pgm/pom.xml
@@ -50,7 +50,7 @@
   <parent>
     <groupId>org.eclipse.jgit</groupId>
     <artifactId>org.eclipse.jgit-parent</artifactId>
-    <version>5.2.2-SNAPSHOT</version>
+    <version>5.3.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>org.eclipse.jgit.pgm</artifactId>
diff --git a/org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/internal/CLIText.properties b/org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/internal/CLIText.properties
index d7d895a..538c876 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
@@ -341,7 +341,8 @@
 usage_filesToAddContentFrom=Files to add content from
 usage_fixAThinPackToBeComplete=fix a thin pack to be complete
 usage_forEachRefOutput=for-each-ref output
-usage_forceCheckout=when switching branches, proceed even if the index or the working tree differs from HEAD
+usage_forcedSwitchBranch=when switching branches do it forcefully. Succeed even if resetting an existing branch would cause commits to become unreachable
+usage_forceCheckout=when checking out a commit succeed even if the working tree or the index is dirty. Overwrite the working tree or index in such cases
 usage_forceClean=required to delete files or directories
 usage_forceCreateBranchEvenExists=force create branch even exists
 usage_forcedFetch=force ref update fetch option
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Checkout.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Checkout.java
index 6ff39fa..7e1737f 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Checkout.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Checkout.java
@@ -69,8 +69,11 @@ class Checkout extends TextBuiltin {
 	@Option(name = "-b", usage = "usage_createBranchAndCheckout")
 	private boolean createBranch = false;
 
+	@Option(name = "-B", usage = "usage_forcedSwitchBranch")
+	private boolean forceSwitchBranch = false;
+
 	@Option(name = "--force", aliases = { "-f" }, usage = "usage_forceCheckout")
-	private boolean force = false;
+	private boolean forced = false;
 
 	@Option(name = "--orphan", usage = "usage_orphan")
 	private boolean orphan = false;
@@ -103,7 +106,8 @@ protected void run() throws Exception {
 			} else {
 				command.setCreateBranch(createBranch);
 				command.setName(name);
-				command.setForce(force);
+				command.setForceRefUpdate(forceSwitchBranch);
+				command.setForced(forced);
 				command.setOrphan(orphan);
 			}
 			try {
diff --git a/org.eclipse.jgit.ssh.apache.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.ssh.apache.test/META-INF/MANIFEST.MF
index 3e95570..bc74d24 100644
--- a/org.eclipse.jgit.ssh.apache.test/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.ssh.apache.test/META-INF/MANIFEST.MF
@@ -3,17 +3,17 @@
 Bundle-Name: %Bundle-Name
 Automatic-Module-Name: org.eclipse.jgit.ssh.apache.test
 Bundle-SymbolicName: org.eclipse.jgit.ssh.apache.test
-Bundle-Version: 5.2.2.qualifier
+Bundle-Version: 5.3.0.qualifier
 Bundle-Vendor: %Provider-Name
 Bundle-RequiredExecutionEnvironment: JavaSE-1.8
-Import-Package: org.eclipse.jgit.internal.transport.sshd.proxy;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.junit;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.junit.ssh;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.lib;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.transport;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.transport.ssh;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.transport.sshd;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.util;version="[5.2.2,5.3.0)",
+Import-Package: org.eclipse.jgit.internal.transport.sshd.proxy;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.junit;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.junit.ssh;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.lib;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.transport;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.transport.ssh;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.transport.sshd;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.util;version="[5.3.0,5.4.0)",
  org.junit;version="[4.12,5.0.0)",
  org.junit.experimental.theories;version="[4.12,5.0.0)",
  org.junit.runner;version="[4.12,5.0.0)"
diff --git a/org.eclipse.jgit.ssh.apache.test/pom.xml b/org.eclipse.jgit.ssh.apache.test/pom.xml
index dd32902..9ca7937 100644
--- a/org.eclipse.jgit.ssh.apache.test/pom.xml
+++ b/org.eclipse.jgit.ssh.apache.test/pom.xml
@@ -50,7 +50,7 @@
   <parent>
     <groupId>org.eclipse.jgit</groupId>
     <artifactId>org.eclipse.jgit-parent</artifactId>
-    <version>5.2.2-SNAPSHOT</version>
+    <version>5.3.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>org.eclipse.jgit.ssh.apache.test</artifactId>
@@ -106,7 +106,7 @@
             <groupId>org.apache.maven.plugins</groupId>
             <artifactId>maven-surefire-plugin</artifactId>
             <configuration>
-              <argLine>-Djgit.test.long=true</argLine>
+              <argLine>@{argLine} -Djgit.test.long=true</argLine>
             </configuration>
           </plugin>
         </plugins>
@@ -133,7 +133,7 @@
       <plugin>
         <artifactId>maven-surefire-plugin</artifactId>
         <configuration>
-          <argLine>-Xmx1024m -Dfile.encoding=UTF-8 -Djava.io.tmpdir=${project.build.directory}</argLine>
+          <argLine>@{argLine} -Xmx1024m -Dfile.encoding=UTF-8 -Djava.io.tmpdir=${project.build.directory}</argLine>
           <includes>
             <include>**/*Test.java</include>
             <include>**/*Tests.java</include>
diff --git a/org.eclipse.jgit.ssh.apache/META-INF/MANIFEST.MF b/org.eclipse.jgit.ssh.apache/META-INF/MANIFEST.MF
index 4aaeb29..f4e824a 100644
--- a/org.eclipse.jgit.ssh.apache/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.ssh.apache/META-INF/MANIFEST.MF
@@ -5,9 +5,9 @@
 Bundle-SymbolicName: org.eclipse.jgit.ssh.apache
 Bundle-Vendor: %Provider-Name
 Bundle-ActivationPolicy: lazy
-Bundle-Version: 5.2.2.qualifier
+Bundle-Version: 5.3.0.qualifier
 Bundle-RequiredExecutionEnvironment: JavaSE-1.8
-Export-Package: org.eclipse.jgit.internal.transport.sshd;version="5.2.2";x-internal:=true;
+Export-Package: org.eclipse.jgit.internal.transport.sshd;version="5.3.0";x-internal:=true;
   uses:="org.apache.sshd.client,
    org.apache.sshd.client.auth,
    org.apache.sshd.client.auth.keyboard,
@@ -22,9 +22,9 @@
    org.apache.sshd.common.signature,
    org.apache.sshd.common.util.buffer,
    org.eclipse.jgit.transport",
- org.eclipse.jgit.internal.transport.sshd.auth;version="5.2.2";x-internal:=true,
- org.eclipse.jgit.internal.transport.sshd.proxy;version="5.2.2";x-friends:="org.eclipse.jgit.ssh.apache.test",
- org.eclipse.jgit.transport.sshd;version="5.2.2";
+ org.eclipse.jgit.internal.transport.sshd.auth;version="5.3.0";x-internal:=true,
+ org.eclipse.jgit.internal.transport.sshd.proxy;version="5.3.0";x-friends:="org.eclipse.jgit.ssh.apache.test",
+ org.eclipse.jgit.transport.sshd;version="5.3.0";
   uses:="org.eclipse.jgit.transport,
    org.apache.sshd.client.config.hosts,
    org.apache.sshd.common.keyprovider,
@@ -72,12 +72,12 @@
  org.apache.sshd.common.util.net;version="[2.0.0,2.1.0)",
  org.apache.sshd.common.util.security;version="[2.0.0,2.1.0)",
  org.apache.sshd.server.auth;version="[2.0.0,2.1.0)",
- org.eclipse.jgit.annotations;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.errors;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.fnmatch;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.internal.storage.file;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.internal.transport.ssh;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.nls;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.transport;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.util;version="[5.2.2,5.3.0)",
+ org.eclipse.jgit.annotations;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.errors;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.fnmatch;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.internal.storage.file;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.internal.transport.ssh;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.nls;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.transport;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.util;version="[5.3.0,5.4.0)",
  org.slf4j;version="[1.7.0,2.0.0)"
diff --git a/org.eclipse.jgit.ssh.apache/META-INF/SOURCE-MANIFEST.MF b/org.eclipse.jgit.ssh.apache/META-INF/SOURCE-MANIFEST.MF
index c4c2086..dc8cc85 100644
--- a/org.eclipse.jgit.ssh.apache/META-INF/SOURCE-MANIFEST.MF
+++ b/org.eclipse.jgit.ssh.apache/META-INF/SOURCE-MANIFEST.MF
@@ -3,5 +3,5 @@
 Bundle-Name: org.eclipse.jgit.ssh.apache - Sources
 Bundle-SymbolicName: org.eclipse.jgit.ssh.apache.source
 Bundle-Vendor: Eclipse.org - JGit
-Bundle-Version: 5.2.2.qualifier
-Eclipse-SourceBundle: org.eclipse.jgit.ssh.apache;version="5.2.2.qualifier";roots="."
+Bundle-Version: 5.3.0.qualifier
+Eclipse-SourceBundle: org.eclipse.jgit.ssh.apache;version="5.3.0.qualifier";roots="."
diff --git a/org.eclipse.jgit.ssh.apache/pom.xml b/org.eclipse.jgit.ssh.apache/pom.xml
index 130794e..0a1f460 100644
--- a/org.eclipse.jgit.ssh.apache/pom.xml
+++ b/org.eclipse.jgit.ssh.apache/pom.xml
@@ -50,7 +50,7 @@
   <parent>
     <groupId>org.eclipse.jgit</groupId>
     <artifactId>org.eclipse.jgit-parent</artifactId>
-    <version>5.2.2-SNAPSHOT</version>
+    <version>5.3.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>org.eclipse.jgit.ssh.apache</artifactId>
@@ -195,7 +195,7 @@
                   <ignoreMissingClasses>false</ignoreMissingClasses>
                   <skipPomModules>true</skipPomModules>
               </parameter>
-              <skip>true</skip><!-- TODO: Enable after the first release -->
+              <skip>false</skip>
           </configuration>
           <executions>
             <execution>
@@ -248,7 +248,7 @@
                   <ignoreMissingClasses>false</ignoreMissingClasses>
                   <skipPomModules>true</skipPomModules>
               </parameter>
-              <skip>true</skip><!-- TODO: Enable after the first release -->
+              <skip>false</skip>
           </configuration>
       </plugin>
     </plugins>
diff --git a/org.eclipse.jgit.ssh.apache/resources/org/eclipse/jgit/internal/transport/sshd/SshdText.properties b/org.eclipse.jgit.ssh.apache/resources/org/eclipse/jgit/internal/transport/sshd/SshdText.properties
index aa4e4cc..bdb4a7d 100644
--- a/org.eclipse.jgit.ssh.apache/resources/org/eclipse/jgit/internal/transport/sshd/SshdText.properties
+++ b/org.eclipse.jgit.ssh.apache/resources/org/eclipse/jgit/internal/transport/sshd/SshdText.properties
@@ -13,6 +13,7 @@
 identityFileCannotDecrypt=Given passphrase cannot decrypt identity {0}
 identityFileNoKey=No keys found in identity {0}
 identityFileMultipleKeys=Multiple key pairs found in identity {0}
+identityFileNotFound=Skipping identity ''{0}'': file not found
 identityFileUnsupportedFormat=Unsupported format in identity {0}
 kexServerKeyInvalid=Server key did not validate
 keyEncryptedMsg=Key ''{0}'' is encrypted. Enter the passphrase to decrypt it.
diff --git a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/CachingKeyPairProvider.java b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/CachingKeyPairProvider.java
index ad2ff52..06a0a5f 100644
--- a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/CachingKeyPairProvider.java
+++ b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/CachingKeyPairProvider.java
@@ -45,6 +45,7 @@
 import static java.text.MessageFormat.format;
 
 import java.io.IOException;
+import java.nio.file.Files;
 import java.nio.file.Path;
 import java.security.GeneralSecurityException;
 import java.security.KeyPair;
@@ -92,6 +93,10 @@ protected Iterable<KeyPair> loadKeys(Collection<? extends Path> resources) {
 	@Override
 	protected KeyPair doLoadKey(Path resource)
 			throws IOException, GeneralSecurityException {
+		if (!Files.exists(resource)) {
+			log.warn(format(SshdText.get().identityFileNotFound, resource));
+			return null;
+		}
 		// By calling doLoadKey(String, Path, FilePasswordProvider) instead of
 		// super.doLoadKey(Path) we can bypass the key caching in
 		// AbstractResourceKeyPairProvider, over which we have no real control.
diff --git a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitHostConfigEntry.java b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitHostConfigEntry.java
index a0705f2..7b22b88 100644
--- a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitHostConfigEntry.java
+++ b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitHostConfigEntry.java
@@ -54,7 +54,6 @@
  * lists of strings. The super class treats them as single strings containing
  * comma-separated lists.
  *
- * @since 5.2
  */
 public class JGitHostConfigEntry extends HostConfigEntry {
 
diff --git a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitSshConfig.java b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitSshConfig.java
index 9eced0f..9846439 100644
--- a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitSshConfig.java
+++ b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitSshConfig.java
@@ -78,7 +78,6 @@
  * Therefore, this re-uses the parsing and caching from
  * {@link OpenSshConfigFile}.
  *
- * @since 5.2
  */
 public class JGitSshConfig implements HostConfigEntryResolver {
 
diff --git a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/OpenSshServerKeyVerifier.java b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/OpenSshServerKeyVerifier.java
index 540b586..cfd3d19 100644
--- a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/OpenSshServerKeyVerifier.java
+++ b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/OpenSshServerKeyVerifier.java
@@ -134,7 +134,7 @@
  * <p>
  * Note that adding a key to the known hosts file may create the file. You can
  * specify in the constructor whether the user shall be asked about that, too.
- * If the the user declines updating the file, but the key was otherwise
+ * If the user declines updating the file, but the key was otherwise
  * accepted (user confirmed for "<b>ask</b>", or "no" or "accept-new" are
  * active), the key is accepted for this session only.
  * </p>
diff --git a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/RepeatingFilePasswordProvider.java b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/RepeatingFilePasswordProvider.java
index 5d58bd6..e491cae 100644
--- a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/RepeatingFilePasswordProvider.java
+++ b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/RepeatingFilePasswordProvider.java
@@ -51,7 +51,6 @@
  * A {@link FilePasswordProvider} augmented to support repeatedly asking for
  * passwords.
  *
- * @since 5.2
  */
 public interface RepeatingFilePasswordProvider extends FilePasswordProvider {
 
diff --git a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/SshdText.java b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/SshdText.java
index 5c79f2d..bf432be 100644
--- a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/SshdText.java
+++ b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/SshdText.java
@@ -33,6 +33,7 @@ public static SshdText get() {
 	/***/ public String identityFileCannotDecrypt;
 	/***/ public String identityFileNoKey;
 	/***/ public String identityFileMultipleKeys;
+	/***/ public String identityFileNotFound;
 	/***/ public String identityFileUnsupportedFormat;
 	/***/ public String kexServerKeyInvalid;
 	/***/ public String keyEncryptedMsg;
diff --git a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/transport/sshd/SshdSessionFactory.java b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/transport/sshd/SshdSessionFactory.java
index 4ec6f22..275cf58 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
@@ -161,7 +161,7 @@ public SshdSessionFactory(KeyCache keyCache, ProxyDataFactory proxies) {
 	private static final class Tuple {
 		private Object[] objects;
 
-		public Tuple(Object... objects) {
+		public Tuple(Object[] objects) {
 			this.objects = objects;
 		}
 
@@ -351,7 +351,7 @@ public File getSshDirectory() {
 	private HostConfigEntryResolver getHostConfigEntryResolver(
 			@NonNull File homeDir, @NonNull File sshDir) {
 		return defaultHostConfigEntryResolver.computeIfAbsent(
-				new Tuple(homeDir, sshDir),
+				new Tuple(new Object[] { homeDir, sshDir }),
 				t -> new JGitSshConfig(homeDir,
 						new File(sshDir, SshConstants.CONFIG),
 						getLocalUserName()));
@@ -375,7 +375,7 @@ private HostConfigEntryResolver getHostConfigEntryResolver(
 	private ServerKeyVerifier getServerKeyVerifier(@NonNull File homeDir,
 			@NonNull File sshDir) {
 		return defaultServerKeyVerifier.computeIfAbsent(
-				new Tuple(homeDir, sshDir),
+				new Tuple(new Object[] { homeDir, sshDir }),
 				t -> new OpenSshServerKeyVerifier(true,
 						getDefaultKnownHostsFiles(sshDir)));
 	}
@@ -403,8 +403,10 @@ protected List<Path> getDefaultKnownHostsFiles(@NonNull File sshDir) {
 	 */
 	@NonNull
 	private KeyPairProvider getDefaultKeysProvider(@NonNull File sshDir) {
-		return defaultKeys.computeIfAbsent(new Tuple(sshDir),
-				t -> new CachingKeyPairProvider(getDefaultIdentities(sshDir),
+		List<Path> defaultIdentities = getDefaultIdentities(sshDir);
+		return defaultKeys.computeIfAbsent(
+				new Tuple(defaultIdentities.toArray(new Path[0])),
+				t -> new CachingKeyPairProvider(defaultIdentities,
 						getKeyCache()));
 	}
 
diff --git a/org.eclipse.jgit.test/BUILD b/org.eclipse.jgit.test/BUILD
index 0b18e5e..95fb79b 100644
--- a/org.eclipse.jgit.test/BUILD
+++ b/org.eclipse.jgit.test/BUILD
@@ -1,8 +1,8 @@
-load(":tests.bzl", "tests")
 load(
     "@com_googlesource_gerrit_bazlets//tools:genrule2.bzl",
     "genrule2",
 )
+load(":tests.bzl", "tests")
 
 PKG = "tst/org/eclipse/jgit/"
 
diff --git a/org.eclipse.jgit.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.test/META-INF/MANIFEST.MF
index d77c74e..7bdb722 100644
--- a/org.eclipse.jgit.test/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.test/META-INF/MANIFEST.MF
@@ -3,7 +3,7 @@
 Bundle-Name: %plugin_name
 Automatic-Module-Name: org.eclipse.jgit.test
 Bundle-SymbolicName: org.eclipse.jgit.test
-Bundle-Version: 5.2.2.qualifier
+Bundle-Version: 5.3.0.qualifier
 Bundle-Localization: plugin
 Bundle-Vendor: %provider_name
 Bundle-ActivationPolicy: lazy
@@ -11,54 +11,54 @@
 Import-Package: com.googlecode.javaewah;version="[1.1.6,2.0.0)",
  com.jcraft.jsch;version="[0.1.54,0.2.0)",
  net.bytebuddy.dynamic.loading;version="[1.7.0,2.0.0)",
- org.eclipse.jgit.annotations;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.api;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.api.errors;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.attributes;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.awtui;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.blame;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.diff;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.dircache;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.errors;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.events;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.fnmatch;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.gitrepo;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.hooks;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.ignore;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.ignore.internal;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.internal;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.internal.fsck;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.internal.storage.dfs;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.internal.storage.file;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.internal.storage.io;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.internal.storage.pack;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.internal.storage.reftable;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.internal.storage.reftree;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.internal.transport.parser;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.junit;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.junit.ssh;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.lfs;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.lib;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.merge;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.nls;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.notes;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.patch;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.pgm;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.pgm.internal;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.revplot;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.revwalk;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.revwalk.filter;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.storage.file;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.storage.pack;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.submodule;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.transport;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.transport.http;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.transport.resolver;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.treewalk;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.treewalk.filter;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.util;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.util.io;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.util.sha1;version="[5.2.2,5.3.0)",
+ org.eclipse.jgit.annotations;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.api;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.api.errors;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.attributes;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.awtui;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.blame;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.diff;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.dircache;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.errors;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.events;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.fnmatch;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.gitrepo;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.hooks;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.ignore;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.ignore.internal;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.internal;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.internal.fsck;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.internal.storage.dfs;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.internal.storage.file;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.internal.storage.io;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.internal.storage.pack;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.internal.storage.reftable;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.internal.storage.reftree;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.internal.transport.parser;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.junit;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.junit.ssh;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.lfs;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.lib;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.merge;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.nls;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.notes;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.patch;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.pgm;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.pgm.internal;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.revplot;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.revwalk;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.revwalk.filter;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.storage.file;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.storage.pack;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.submodule;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.transport;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.transport.http;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.transport.resolver;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.treewalk;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.treewalk.filter;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.util;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.util.io;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.util.sha1;version="[5.3.0,5.4.0)",
  org.junit;version="[4.12,5.0.0)",
  org.junit.experimental.theories;version="[4.12,5.0.0)",
  org.junit.rules;version="[4.12,5.0.0)",
@@ -72,4 +72,4 @@
  org.slf4j;version="[1.7.0,2.0.0)"
 Require-Bundle: org.hamcrest.core;bundle-version="[1.1.0,2.0.0)",
  org.hamcrest.library;bundle-version="[1.1.0,2.0.0)"
-Export-Package: org.eclipse.jgit.transport.ssh;version="5.2.2";x-friends:="org.eclipse.jgit.ssh.apache.test"
+Export-Package: org.eclipse.jgit.transport.ssh;version="5.3.0";x-friends:="org.eclipse.jgit.ssh.apache.test"
diff --git a/org.eclipse.jgit.test/pom.xml b/org.eclipse.jgit.test/pom.xml
index 7c3eda4..10117d8 100644
--- a/org.eclipse.jgit.test/pom.xml
+++ b/org.eclipse.jgit.test/pom.xml
@@ -52,7 +52,7 @@
   <parent>
     <groupId>org.eclipse.jgit</groupId>
     <artifactId>org.eclipse.jgit-parent</artifactId>
-    <version>5.2.2-SNAPSHOT</version>
+    <version>5.3.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>org.eclipse.jgit.test</artifactId>
@@ -134,7 +134,7 @@
             <groupId>org.apache.maven.plugins</groupId>
             <artifactId>maven-surefire-plugin</artifactId>
             <configuration>
-              <argLine>-Djgit.test.long=true</argLine>
+              <argLine>@{argLine} -Djgit.test.long=true</argLine>
             </configuration>
           </plugin>
         </plugins>
@@ -179,7 +179,7 @@
       <plugin>
         <artifactId>maven-surefire-plugin</artifactId>
         <configuration>
-          <argLine>-Xmx1024m -Dfile.encoding=UTF-8 -Djava.io.tmpdir=${project.build.directory}</argLine>
+          <argLine>@{argLine} -Xmx1024m -Dfile.encoding=UTF-8 -Djava.io.tmpdir=${project.build.directory}</argLine>
           <includes>
             <include>**/*Test.java</include>
             <include>**/*Tests.java</include>
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CheckoutCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CheckoutCommandTest.java
index 498005d..749c344 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CheckoutCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CheckoutCommandTest.java
@@ -63,6 +63,7 @@
 
 import org.eclipse.jgit.api.CheckoutResult.Status;
 import org.eclipse.jgit.api.CreateBranchCommand.SetupUpstreamMode;
+import org.eclipse.jgit.api.errors.CheckoutConflictException;
 import org.eclipse.jgit.api.errors.GitAPIException;
 import org.eclipse.jgit.api.errors.InvalidRefNameException;
 import org.eclipse.jgit.api.errors.InvalidRemoteException;
@@ -109,7 +110,7 @@ public void setUp() throws Exception {
 		git.add().addFilepattern("Test.txt").call();
 		initialCommit = git.commit().setMessage("Initial commit").call();
 
-		// create a master branch and switch to it
+		// create a test branch and switch to it
 		git.branchCreate().setName("test").call();
 		RefUpdate rup = db.updateRef(Constants.HEAD);
 		rup.link("refs/heads/test");
@@ -138,6 +139,18 @@ public void testCheckout() throws Exception {
 	}
 
 	@Test
+	public void testCheckoutForced() throws Exception {
+		writeTrashFile("Test.txt", "Garbage");
+		try {
+			git.checkout().setName("master").call().getObjectId();
+			fail("Expected CheckoutConflictException didn't occur");
+		} catch (CheckoutConflictException e) {
+		}
+		assertEquals(initialCommit.getId(), git.checkout().setName("master")
+				.setForced(true).call().getObjectId());
+	}
+
+	@Test
 	public void testCreateBranchOnCheckout() throws Exception {
 		git.checkout().setCreateBranch(true).setName("test2").call();
 		assertNotNull(db.exactRef("refs/heads/test2"));
@@ -165,7 +178,7 @@ public void testCheckoutWithConflict() throws Exception {
 			assertEquals(Status.CONFLICTS, co.getResult().getStatus());
 			assertTrue(co.getResult().getConflictList().contains("Test.txt"));
 		}
-		git.checkout().setName("master").setForce(true).call();
+		git.checkout().setName("master").setForced(true).call();
 		assertThat(read("Test.txt"), is("Hello world"));
 	}
 
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributesNodeDirCacheIteratorTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributesNodeDirCacheIteratorTest.java
index 7421e90..837de74 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributesNodeDirCacheIteratorTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributesNodeDirCacheIteratorTest.java
@@ -64,7 +64,7 @@
 import org.junit.Test;
 
 /**
- * Tests attributes node behavior on the the index.
+ * Tests attributes node behavior on the index.
  */
 public class AttributesNodeDirCacheIteratorTest extends RepositoryTestCase {
 
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcBranchPrunedTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcBranchPrunedTest.java
index c7ee925..8f29b3b 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcBranchPrunedTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcBranchPrunedTest.java
@@ -66,11 +66,11 @@ public void branch_historyNotPruned() throws Exception {
 		fsTick();
 		gc.prune(Collections.<ObjectId> emptySet());
 		do {
-			assertTrue(repo.hasObject(tip));
+			assertTrue(repo.getObjectDatabase().has(tip));
 			tr.parseBody(tip);
 			RevTree t = tip.getTree();
-			assertTrue(repo.hasObject(t));
-			assertTrue(repo.hasObject(tr.get(t, "a")));
+			assertTrue(repo.getObjectDatabase().has(t));
+			assertTrue(repo.getObjectDatabase().has(tr.get(t, "a")));
 			tip = tip.getParentCount() > 0 ? tip.getParent(0) : null;
 		} while (tip != null);
 	}
@@ -114,6 +114,6 @@ public void deleteMergedBranch_historyNotPruned() throws Exception {
 		gc.setExpireAgeMillis(0);
 		fsTick();
 		gc.prune(Collections.<ObjectId> emptySet());
-		assertTrue(repo.hasObject(b2Tip));
+		assertTrue(repo.getObjectDatabase().has(b2Tip));
 	}
 }
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcConcurrentTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcConcurrentTest.java
index 643bb49..9ea62b3 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
@@ -169,7 +169,7 @@ public void repackAndUploadPack() throws Exception {
 		gc2.gc();
 
 		// Simulate parts of an UploadPack. This is the situation on
-		// server side (e.g. gerrit) when when clients are
+		// server side (e.g. gerrit) when clients are
 		// cloning/fetching while the server side repo's
 		// are gc'ed by an external process (e.g. scheduled
 		// native git gc)
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcPruneNonReferencedTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcPruneNonReferencedTest.java
index 5b1a417..44fb21d 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcPruneNonReferencedTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcPruneNonReferencedTest.java
@@ -63,7 +63,7 @@ public void nonReferencedNonExpiredObject_notPruned() throws Exception {
 		RevBlob a = tr.blob("a");
 		gc.setExpire(new Date(lastModified(a)));
 		gc.prune(Collections.<ObjectId> emptySet());
-		assertTrue(repo.hasObject(a));
+		assertTrue(repo.getObjectDatabase().has(a));
 	}
 
 	@Test
@@ -72,7 +72,7 @@ public void nonReferencedExpiredObject_pruned() throws Exception {
 		gc.setExpireAgeMillis(0);
 		fsTick();
 		gc.prune(Collections.<ObjectId> emptySet());
-		assertFalse(repo.hasObject(a));
+		assertFalse(repo.getObjectDatabase().has(a));
 	}
 
 	@Test
@@ -82,8 +82,8 @@ public void nonReferencedExpiredObjectTree_pruned() throws Exception {
 		gc.setExpireAgeMillis(0);
 		fsTick();
 		gc.prune(Collections.<ObjectId> emptySet());
-		assertFalse(repo.hasObject(t));
-		assertFalse(repo.hasObject(a));
+		assertFalse(repo.getObjectDatabase().has(t));
+		assertFalse(repo.getObjectDatabase().has(a));
 	}
 
 	@Test
@@ -95,8 +95,8 @@ public void nonReferencedObjects_onlyExpiredPruned() throws Exception {
 		RevBlob b = tr.blob("b");
 
 		gc.prune(Collections.<ObjectId> emptySet());
-		assertFalse(repo.hasObject(a));
-		assertTrue(repo.hasObject(b));
+		assertFalse(repo.getObjectDatabase().has(a));
+		assertTrue(repo.getObjectDatabase().has(b));
 	}
 
 	@Test
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcTagTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcTagTest.java
index 4afbeff..cf7a431 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcTagTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcTagTest.java
@@ -60,7 +60,7 @@ public void lightweightTag_objectNotPruned() throws Exception {
 		gc.setExpireAgeMillis(0);
 		fsTick();
 		gc.prune(Collections.<ObjectId> emptySet());
-		assertTrue(repo.hasObject(a));
+		assertTrue(repo.getObjectDatabase().has(a));
 	}
 
 	@Test
@@ -72,7 +72,7 @@ public void annotatedTag_objectNotPruned() throws Exception {
 		gc.setExpireAgeMillis(0);
 		fsTick();
 		gc.prune(Collections.<ObjectId> emptySet());
-		assertTrue(repo.hasObject(t));
-		assertTrue(repo.hasObject(a));
+		assertTrue(repo.getObjectDatabase().has(t));
+		assertTrue(repo.getObjectDatabase().has(a));
 	}
 }
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/ObjectDirectoryTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/ObjectDirectoryTest.java
index 3ca689a..a3a302d 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/ObjectDirectoryTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/ObjectDirectoryTest.java
@@ -126,7 +126,7 @@ public void testScanningForPackfiles() throws Exception {
 			// scanning of the packs directory
 			ObjectId id = commitFile("file.txt", "test", "master").getId();
 			gc.gc();
-			assertFalse(receivingDB.hasObject(unknownID));
+			assertFalse(receivingDB.getObjectDatabase().has(unknownID));
 			assertTrue(receivingDB.getObjectDatabase().hasPackedObject(id));
 
 			// preparations
@@ -150,7 +150,7 @@ public void testScanningForPackfiles() throws Exception {
 			// JGit will not rescan the packs folder later on and fails to see
 			// the pack file created during gc.
 			assertTrue(tmpFile.createNewFile());
-			assertFalse(receivingDB.hasObject(unknownID));
+			assertFalse(receivingDB.getObjectDatabase().has(unknownID));
 
 			// trigger a gc. This will create packfiles which have likely the
 			// same mtime than the packfolder
@@ -177,8 +177,8 @@ public boolean accept(File dir, String name) {
 			Assume.assumeTrue(tmpFile.lastModified() == ret[0].lastModified());
 
 			// all objects are in a new packfile but we will not detect it
-			assertFalse(receivingDB.hasObject(unknownID));
-			assertTrue(receivingDB.hasObject(id2));
+			assertFalse(receivingDB.getObjectDatabase().has(unknownID));
+			assertTrue(receivingDB.getObjectDatabase().has(id2));
 		}
 	}
 
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/RefDirectoryTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/RefDirectoryTest.java
index 5a2bd9c..7b3684c 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/RefDirectoryTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/RefDirectoryTest.java
@@ -48,6 +48,7 @@
 import static org.eclipse.jgit.lib.Constants.R_TAGS;
 import static org.eclipse.jgit.lib.Ref.Storage.LOOSE;
 import static org.eclipse.jgit.lib.Ref.Storage.NEW;
+import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
@@ -61,6 +62,7 @@
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.List;
 import java.util.Map;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.atomic.AtomicReference;
@@ -134,6 +136,33 @@ public void testCreate() throws IOException {
 		assertEquals("ref: refs/heads/master\n", read(new File(d, HEAD)));
 	}
 
+	@Test(expected = UnsupportedOperationException.class)
+	public void testVersioningNotImplemented_exactRef() throws IOException {
+		assertFalse(refdir.hasVersioning());
+
+		Ref ref = refdir.exactRef(HEAD);
+		assertNotNull(ref);
+		ref.getUpdateIndex(); // Not implemented on FS
+	}
+
+	@Test
+	public void testVersioningNotImplemented_getRefs() throws Exception {
+		assertFalse(refdir.hasVersioning());
+
+		RevCommit C = repo.commit().parent(B).create();
+		repo.update("master", C);
+		List<Ref> refs = refdir.getRefs();
+
+		for (Ref ref : refs) {
+			try {
+				ref.getUpdateIndex();
+				fail("FS doesn't implement ref versioning");
+			} catch (UnsupportedOperationException e) {
+				// ok
+			}
+		}
+	}
+
 	@Test
 	public void testGetRefs_EmptyDatabase() throws IOException {
 		Map<String, Ref> all;
@@ -392,15 +421,15 @@ public void testGetRefs_InvalidName() throws IOException {
 
 	@Test
 	public void testReadNotExistingBranchConfig() throws IOException {
-		assertNull("find branch config", refdir.getRef("config"));
-		assertNull("find branch config", refdir.getRef("refs/heads/config"));
+		assertNull("find branch config", refdir.findRef("config"));
+		assertNull("find branch config", refdir.findRef("refs/heads/config"));
 	}
 
 	@Test
 	public void testReadBranchConfig() throws IOException {
 		writeLooseRef("refs/heads/config", A);
 
-		assertNotNull("find branch config", refdir.getRef("config"));
+		assertNotNull("find branch config", refdir.findRef("config"));
 	}
 
 	@Test
@@ -643,7 +672,7 @@ public void testGetRefs_DiscoversModifiedLoose() throws IOException {
 	}
 
 	@Test
-	public void testGetRef_DiscoversModifiedLoose() throws IOException {
+	public void testFindRef_DiscoversModifiedLoose() throws IOException {
 		Map<String, Ref> all;
 
 		writeLooseRef("refs/heads/master", A);
@@ -652,7 +681,7 @@ public void testGetRef_DiscoversModifiedLoose() throws IOException {
 
 		writeLooseRef("refs/heads/master", B);
 
-		Ref master = refdir.getRef("refs/heads/master");
+		Ref master = refdir.findRef("refs/heads/master");
 		assertEquals(B, master.getObjectId());
 	}
 
@@ -687,7 +716,7 @@ public void testGetRefs_DiscoversDeletedLoose1() throws IOException {
 	}
 
 	@Test
-	public void testGetRef_DiscoversDeletedLoose() throws IOException {
+	public void testFindRef_DiscoversDeletedLoose() throws IOException {
 		Map<String, Ref> all;
 
 		writeLooseRef("refs/heads/master", A);
@@ -695,7 +724,7 @@ public void testGetRef_DiscoversDeletedLoose() throws IOException {
 		assertEquals(A, all.get(HEAD).getObjectId());
 
 		deleteLooseRef("refs/heads/master");
-		assertNull(refdir.getRef("refs/heads/master"));
+		assertNull(refdir.findRef("refs/heads/master"));
 		assertTrue(refdir.getRefs(RefDatabase.ALL).isEmpty());
 	}
 
@@ -855,7 +884,7 @@ public void testGetRefs_CycleInSymbolicRef() throws IOException {
 	}
 
 	@Test
-	public void testGetRef_CycleInSymbolicRef() throws IOException {
+	public void testFindRef_CycleInSymbolicRef() throws IOException {
 		Ref r;
 
 		writeLooseRef("refs/1", "ref: refs/2\n");
@@ -865,7 +894,7 @@ public void testGetRef_CycleInSymbolicRef() throws IOException {
 		writeLooseRef("refs/5", "ref: refs/end\n");
 		writeLooseRef("refs/end", A);
 
-		r = refdir.getRef("1");
+		r = refdir.findRef("1");
 		assertEquals("refs/1", r.getName());
 		assertEquals(A, r.getObjectId());
 		assertTrue(r.isSymbolic());
@@ -873,12 +902,12 @@ public void testGetRef_CycleInSymbolicRef() throws IOException {
 		writeLooseRef("refs/5", "ref: refs/6\n");
 		writeLooseRef("refs/6", "ref: refs/end\n");
 
-		r = refdir.getRef("1");
+		r = refdir.findRef("1");
 		assertNull("missing 1 due to cycle", r);
 
 		writeLooseRef("refs/heads/1", B);
 
-		r = refdir.getRef("1");
+		r = refdir.findRef("1");
 		assertEquals("refs/heads/1", r.getName());
 		assertEquals(B, r.getObjectId());
 		assertFalse(r.isSymbolic());
@@ -919,16 +948,16 @@ public void testGetRefs_PackedNotPeeled_Sorted() throws IOException {
 	}
 
 	@Test
-	public void testGetRef_PackedNotPeeled_WrongSort() throws IOException {
+	public void testFindRef_PackedNotPeeled_WrongSort() throws IOException {
 		writePackedRefs("" + //
 				v1_0.name() + " refs/tags/v1.0\n" + //
 				B.name() + " refs/heads/other\n" + //
 				A.name() + " refs/heads/master\n");
 
-		final Ref head = refdir.getRef(HEAD);
-		final Ref master = refdir.getRef("refs/heads/master");
-		final Ref other = refdir.getRef("refs/heads/other");
-		final Ref tag = refdir.getRef("refs/tags/v1.0");
+		final Ref head = refdir.findRef(HEAD);
+		final Ref master = refdir.findRef("refs/heads/master");
+		final Ref other = refdir.findRef("refs/heads/other");
+		final Ref tag = refdir.findRef("refs/tags/v1.0");
 
 		assertEquals(A, master.getObjectId());
 		assertFalse(master.isPeeled());
@@ -1033,22 +1062,22 @@ public void test_repack() throws Exception {
 	}
 
 	@Test
-	public void testGetRef_EmptyDatabase() throws IOException {
+	public void testFindRef_EmptyDatabase() throws IOException {
 		Ref r;
 
-		r = refdir.getRef(HEAD);
+		r = refdir.findRef(HEAD);
 		assertTrue(r.isSymbolic());
 		assertSame(LOOSE, r.getStorage());
 		assertEquals("refs/heads/master", r.getTarget().getName());
 		assertSame(NEW, r.getTarget().getStorage());
 		assertNull(r.getTarget().getObjectId());
 
-		assertNull(refdir.getRef("refs/heads/master"));
-		assertNull(refdir.getRef("refs/tags/v1.0"));
-		assertNull(refdir.getRef("FETCH_HEAD"));
-		assertNull(refdir.getRef("NOT.A.REF.NAME"));
-		assertNull(refdir.getRef("master"));
-		assertNull(refdir.getRef("v1.0"));
+		assertNull(refdir.findRef("refs/heads/master"));
+		assertNull(refdir.findRef("refs/tags/v1.0"));
+		assertNull(refdir.findRef("FETCH_HEAD"));
+		assertNull(refdir.findRef("NOT.A.REF.NAME"));
+		assertNull(refdir.findRef("master"));
+		assertNull(refdir.findRef("v1.0"));
 	}
 
 	@Test
@@ -1071,7 +1100,29 @@ public void testExactRef_EmptyDatabase() throws IOException {
 	}
 
 	@Test
-	public void testGetRef_FetchHead() throws IOException {
+	public void testGetAdditionalRefs_OrigHead() throws IOException {
+		writeLooseRef("ORIG_HEAD", A);
+
+		List<Ref> refs = refdir.getAdditionalRefs();
+		assertEquals(1, refs.size());
+
+		Ref r = refs.get(0);
+		assertFalse(r.isSymbolic());
+		assertEquals(A, r.getObjectId());
+		assertEquals("ORIG_HEAD", r.getName());
+		assertFalse(r.isPeeled());
+		assertNull(r.getPeeledObjectId());
+	}
+
+	@Test
+	public void testGetAdditionalRefs_OrigHeadBranch() throws IOException {
+		writeLooseRef("refs/heads/ORIG_HEAD", A);
+		List<Ref> refs = refdir.getAdditionalRefs();
+		assertArrayEquals(new Ref[0], refs.toArray());
+	}
+
+	@Test
+	public void testFindRef_FetchHead() throws IOException {
 		// This is an odd special case where we need to make sure we read
 		// exactly the first 40 bytes of the file and nothing further on
 		// that line, or the remainder of the file.
@@ -1079,7 +1130,7 @@ public void testGetRef_FetchHead() throws IOException {
 				+ "\tnot-for-merge"
 				+ "\tbranch 'master' of git://egit.eclipse.org/jgit\n");
 
-		Ref r = refdir.getRef("FETCH_HEAD");
+		Ref r = refdir.findRef("FETCH_HEAD");
 		assertFalse(r.isSymbolic());
 		assertEquals(A, r.getObjectId());
 		assertEquals("FETCH_HEAD", r.getName());
@@ -1105,12 +1156,12 @@ public void testExactRef_FetchHead() throws IOException {
 	}
 
 	@Test
-	public void testGetRef_AnyHeadWithGarbage() throws IOException {
+	public void testFindRef_AnyHeadWithGarbage() throws IOException {
 		write(new File(diskRepo.getDirectory(), "refs/heads/A"), A.name()
 				+ "012345 . this is not a standard reference\n"
 				+ "#and even more junk\n");
 
-		Ref r = refdir.getRef("refs/heads/A");
+		Ref r = refdir.findRef("refs/heads/A");
 		assertFalse(r.isSymbolic());
 		assertEquals(A, r.getObjectId());
 		assertEquals("refs/heads/A", r.getName());
@@ -1126,11 +1177,11 @@ public void testGetRefs_CorruptSymbolicReference() throws IOException {
 	}
 
 	@Test
-	public void testGetRef_CorruptSymbolicReference() throws IOException {
+	public void testFindRef_CorruptSymbolicReference() throws IOException {
 		String name = "refs/heads/A";
 		writeLooseRef(name, "ref: \n");
 		try {
-			refdir.getRef(name);
+			refdir.findRef(name);
 			fail("read an invalid reference");
 		} catch (IOException err) {
 			String msg = err.getMessage();
@@ -1147,12 +1198,12 @@ public void testGetRefs_CorruptObjectIdReference() throws IOException {
 	}
 
 	@Test
-	public void testGetRef_CorruptObjectIdReference() throws IOException {
+	public void testFindRef_CorruptObjectIdReference() throws IOException {
 		String name = "refs/heads/A";
 		String content = "zoo" + A.name();
 		writeLooseRef(name, content + "\n");
 		try {
-			refdir.getRef(name);
+			refdir.findRef(name);
 			fail("read an invalid reference");
 		} catch (IOException err) {
 			String msg = err.getMessage();
@@ -1187,8 +1238,8 @@ public void testPeelLooseTag() throws IOException {
 		writeLooseRef("refs/tags/v1_0", v1_0);
 		writeLooseRef("refs/tags/current", "ref: refs/tags/v1_0\n");
 
-		final Ref tag = refdir.getRef("refs/tags/v1_0");
-		final Ref cur = refdir.getRef("refs/tags/current");
+		final Ref tag = refdir.findRef("refs/tags/v1_0");
+		final Ref cur = refdir.findRef("refs/tags/current");
 
 		assertEquals(v1_0, tag.getObjectId());
 		assertFalse(tag.isSymbolic());
@@ -1220,14 +1271,14 @@ public void testPeelLooseTag() throws IOException {
 
 		// reuses cached peeling later, but not immediately due to
 		// the implementation so we have to fetch it once.
-		final Ref tag_p2 = refdir.getRef("refs/tags/v1_0");
+		final Ref tag_p2 = refdir.findRef("refs/tags/v1_0");
 		assertFalse(tag_p2.isSymbolic());
 		assertTrue(tag_p2.isPeeled());
 		assertEquals(v1_0, tag_p2.getObjectId());
 		assertEquals(v1_0.getObject(), tag_p2.getPeeledObjectId());
 
-		assertSame(tag_p2, refdir.getRef("refs/tags/v1_0"));
-		assertSame(tag_p2, refdir.getRef("refs/tags/current").getTarget());
+		assertSame(tag_p2, refdir.findRef("refs/tags/v1_0"));
+		assertSame(tag_p2, refdir.findRef("refs/tags/current").getTarget());
 		assertSame(tag_p2, refdir.peel(tag_p2));
 	}
 
@@ -1235,7 +1286,7 @@ public void testPeelLooseTag() throws IOException {
 	public void testPeelCommit() throws IOException {
 		writeLooseRef("refs/heads/master", A);
 
-		Ref master = refdir.getRef("refs/heads/master");
+		Ref master = refdir.findRef("refs/heads/master");
 		assertEquals(A, master.getObjectId());
 		assertFalse(master.isPeeled());
 		assertNull(master.getPeeledObjectId());
@@ -1248,7 +1299,7 @@ public void testPeelCommit() throws IOException {
 
 		// reuses cached peeling later, but not immediately due to
 		// the implementation so we have to fetch it once.
-		Ref master_p2 = refdir.getRef("refs/heads/master");
+		Ref master_p2 = refdir.findRef("refs/heads/master");
 		assertNotSame(master, master_p2);
 		assertEquals(A, master_p2.getObjectId());
 		assertTrue(master_p2.isPeeled());
@@ -1300,7 +1351,7 @@ public void testPackedRefsLockFailure() throws Exception {
 		} finally {
 			myLock.unlock();
 		}
-		Ref ref = refdir.getRef("refs/heads/master");
+		Ref ref = refdir.findRef("refs/heads/master");
 		assertEquals(Storage.LOOSE, ref.getStorage());
 	}
 
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/reftable/MergedReftableTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/reftable/MergedReftableTest.java
index 1d11573..11d6439 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/reftable/MergedReftableTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/reftable/MergedReftableTest.java
@@ -44,6 +44,7 @@
 package org.eclipse.jgit.internal.storage.reftable;
 
 import static org.eclipse.jgit.lib.Constants.HEAD;
+import static org.eclipse.jgit.lib.Constants.MASTER;
 import static org.eclipse.jgit.lib.Constants.OBJECT_ID_LENGTH;
 import static org.eclipse.jgit.lib.Constants.R_HEADS;
 import static org.eclipse.jgit.lib.Ref.Storage.NEW;
@@ -68,6 +69,7 @@
 import org.eclipse.jgit.lib.ObjectIdRef;
 import org.eclipse.jgit.lib.Ref;
 import org.eclipse.jgit.lib.RefComparator;
+import org.eclipse.jgit.lib.SymbolicRef;
 import org.junit.Test;
 
 public class MergedReftableTest {
@@ -128,6 +130,7 @@ public void oneTableScan() throws IOException {
 				Ref act = rc.getRef();
 				assertEquals(exp.getName(), act.getName());
 				assertEquals(exp.getObjectId(), act.getObjectId());
+				assertEquals(1, act.getUpdateIndex());
 			}
 			assertFalse(rc.next());
 		}
@@ -145,6 +148,7 @@ public void deleteIsHidden() throws IOException {
 			assertTrue(rc.next());
 			assertEquals("refs/heads/master", rc.getRef().getName());
 			assertEquals(id(2), rc.getRef().getObjectId());
+			assertEquals(1, rc.getRef().getUpdateIndex());
 			assertFalse(rc.next());
 		}
 	}
@@ -162,6 +166,7 @@ public void twoTableSeek() throws IOException {
 			assertEquals("refs/heads/master", rc.getRef().getName());
 			assertEquals(id(2), rc.getRef().getObjectId());
 			assertFalse(rc.next());
+			assertEquals(1, rc.getRef().getUpdateIndex());
 		}
 	}
 
@@ -177,6 +182,7 @@ public void twoTableById() throws IOException {
 			assertTrue(rc.next());
 			assertEquals("refs/heads/master", rc.getRef().getName());
 			assertEquals(id(2), rc.getRef().getObjectId());
+			assertEquals(1, rc.getRef().getUpdateIndex());
 			assertFalse(rc.next());
 		}
 	}
@@ -212,6 +218,7 @@ public void fourTableScan() throws IOException {
 				Ref act = rc.getRef();
 				assertEquals(exp.getName(), act.getName());
 				assertEquals(exp.getObjectId(), act.getObjectId());
+				assertEquals(1, rc.getRef().getUpdateIndex());
 			}
 			assertFalse(rc.next());
 		}
@@ -231,9 +238,11 @@ public void scanDuplicates() throws IOException {
 			assertTrue(rc.next());
 			assertEquals("refs/heads/apple", rc.getRef().getName());
 			assertEquals(id(3), rc.getRef().getObjectId());
+			assertEquals(2000, rc.getRef().getUpdateIndex());
 			assertTrue(rc.next());
 			assertEquals("refs/heads/banana", rc.getRef().getName());
 			assertEquals(id(2), rc.getRef().getObjectId());
+			assertEquals(1000, rc.getRef().getUpdateIndex());
 			assertFalse(rc.next());
 		}
 	}
@@ -251,12 +260,14 @@ public void scanIncludeDeletes() throws IOException {
 			Ref r = rc.getRef();
 			assertEquals("refs/heads/master", r.getName());
 			assertEquals(id(8), r.getObjectId());
+			assertEquals(1, rc.getRef().getUpdateIndex());
 
 			assertTrue(rc.next());
 			r = rc.getRef();
 			assertEquals("refs/heads/next", r.getName());
 			assertEquals(NEW, r.getStorage());
 			assertNull(r.getObjectId());
+			assertEquals(1, rc.getRef().getUpdateIndex());
 
 			assertFalse(rc.next());
 		}
@@ -277,6 +288,7 @@ public void oneTableSeek() throws IOException {
 				Ref act = rc.getRef();
 				assertEquals(exp.getName(), act.getName());
 				assertEquals(exp.getObjectId(), act.getObjectId());
+				assertEquals(1, act.getUpdateIndex());
 				assertFalse(rc.next());
 			}
 		}
@@ -303,17 +315,17 @@ public void missedUpdate() throws IOException {
 			assertTrue(rc.next());
 			assertEquals("refs/heads/a", rc.getRef().getName());
 			assertEquals(id(1), rc.getRef().getObjectId());
-			assertEquals(1, rc.getUpdateIndex());
+			assertEquals(1, rc.getRef().getUpdateIndex());
 
 			assertTrue(rc.next());
 			assertEquals("refs/heads/b", rc.getRef().getName());
 			assertEquals(id(2), rc.getRef().getObjectId());
-			assertEquals(2, rc.getUpdateIndex());
+			assertEquals(2, rc.getRef().getUpdateIndex());
 
 			assertTrue(rc.next());
 			assertEquals("refs/heads/c", rc.getRef().getName());
 			assertEquals(id(3), rc.getRef().getObjectId());
-			assertEquals(3, rc.getUpdateIndex());
+			assertEquals(3, rc.getRef().getUpdateIndex());
 		}
 	}
 
@@ -344,6 +356,63 @@ public void compaction() throws IOException {
 		}
 	}
 
+	@Test
+	public void versioningSymbolicReftargetMoves() throws IOException {
+		Ref master = ref(MASTER, 100);
+
+		List<Ref> delta1 = Arrays.asList(master, sym(HEAD, MASTER));
+		List<Ref> delta2 = Arrays.asList(ref(MASTER, 200));
+
+		MergedReftable mr = merge(write(delta1, 1), write(delta2, 2));
+		Ref head = mr.exactRef(HEAD);
+		assertEquals(head.getUpdateIndex(), 1);
+
+		Ref masterRef = mr.exactRef(MASTER);
+		assertEquals(masterRef.getUpdateIndex(), 2);
+	}
+
+	@Test
+	public void versioningSymbolicRefMoves() throws IOException {
+		Ref branchX = ref("refs/heads/branchX", 200);
+
+		List<Ref> delta1 = Arrays.asList(ref(MASTER, 100), branchX,
+				sym(HEAD, MASTER));
+		List<Ref> delta2 = Arrays.asList(sym(HEAD, "refs/heads/branchX"));
+		List<Ref> delta3 = Arrays.asList(sym(HEAD, MASTER));
+
+		MergedReftable mr = merge(write(delta1, 1), write(delta2, 2),
+				write(delta3, 3));
+		Ref head = mr.exactRef(HEAD);
+		assertEquals(head.getUpdateIndex(), 3);
+
+		Ref masterRef = mr.exactRef(MASTER);
+		assertEquals(masterRef.getUpdateIndex(), 1);
+
+		Ref branchRef = mr.exactRef(MASTER);
+		assertEquals(branchRef.getUpdateIndex(), 1);
+	}
+
+	@Test
+	public void versioningResolveRef() throws IOException {
+		List<Ref> delta1 = Arrays.asList(sym(HEAD, "refs/heads/tmp"),
+				sym("refs/heads/tmp", MASTER), ref(MASTER, 100));
+		List<Ref> delta2 = Arrays.asList(ref(MASTER, 200));
+		List<Ref> delta3 = Arrays.asList(ref(MASTER, 300));
+
+		MergedReftable mr = merge(write(delta1, 1), write(delta2, 2),
+				write(delta3, 3));
+		Ref head = mr.exactRef(HEAD);
+		Ref resolvedHead = mr.resolve(head);
+		assertEquals(resolvedHead.getObjectId(), id(300));
+		assertEquals("HEAD has not moved", resolvedHead.getUpdateIndex(), 1);
+
+		Ref master = mr.exactRef(MASTER);
+		Ref resolvedMaster = mr.resolve(master);
+		assertEquals(resolvedMaster.getObjectId(), id(300));
+		assertEquals("master also has update index",
+				resolvedMaster.getUpdateIndex(), 3);
+	}
+
 	private static MergedReftable merge(byte[]... table) {
 		List<Reftable> stack = new ArrayList<>(table.length);
 		for (byte[] b : table) {
@@ -360,6 +429,14 @@ private static Ref ref(String name, int id) {
 		return new ObjectIdRef.PeeledNonTag(PACKED, name, id(id));
 	}
 
+	private static Ref sym(String name, String target) {
+		return new SymbolicRef(name, newRef(target));
+	}
+
+	private static Ref newRef(String name) {
+		return new ObjectIdRef.Unpeeled(NEW, name, null);
+	}
+
 	private static Ref delete(String name) {
 		return new ObjectIdRef.Unpeeled(NEW, name, null);
 	}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/reftable/ReftableCompactorTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/reftable/ReftableCompactorTest.java
index 46a37ff..1ea7309 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/reftable/ReftableCompactorTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/reftable/ReftableCompactorTest.java
@@ -108,7 +108,7 @@ public void oneTable() throws IOException {
 			assertTrue(rc.next());
 			assertEquals(MASTER, rc.getRef().getName());
 			assertEquals(id(1), rc.getRef().getObjectId());
-			assertEquals(0, rc.getUpdateIndex());
+			assertEquals(0, rc.getRef().getUpdateIndex());
 		}
 	}
 
@@ -155,7 +155,7 @@ public void twoTablesOneRef() throws IOException {
 			assertTrue(rc.next());
 			assertEquals(MASTER, rc.getRef().getName());
 			assertEquals(id(2), rc.getRef().getObjectId());
-			assertEquals(1, rc.getUpdateIndex());
+			assertEquals(1, rc.getRef().getUpdateIndex());
 		}
 	}
 
@@ -203,12 +203,12 @@ public void twoTablesTwoRefs() throws IOException {
 			assertTrue(rc.next());
 			assertEquals(MASTER, rc.getRef().getName());
 			assertEquals(id(3), rc.getRef().getObjectId());
-			assertEquals(1, rc.getUpdateIndex());
+			assertEquals(1, rc.getRef().getUpdateIndex());
 
 			assertTrue(rc.next());
 			assertEquals(NEXT, rc.getRef().getName());
 			assertEquals(id(2), rc.getRef().getObjectId());
-			assertEquals(0, rc.getUpdateIndex());
+			assertEquals(0, rc.getRef().getUpdateIndex());
 		}
 	}
 
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/reftable/ReftableTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/reftable/ReftableTest.java
index 0ee785c..a142166 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/reftable/ReftableTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/reftable/ReftableTest.java
@@ -186,6 +186,7 @@ public void oneIdRef() throws IOException {
 			assertFalse(act.isSymbolic());
 			assertEquals(exp.getName(), act.getName());
 			assertEquals(exp.getObjectId(), act.getObjectId());
+			assertEquals(0, act.getUpdateIndex());
 			assertNull(act.getPeeledObjectId());
 			assertFalse(rc.wasDeleted());
 			assertFalse(rc.next());
@@ -195,6 +196,7 @@ public void oneIdRef() throws IOException {
 			Ref act = rc.getRef();
 			assertNotNull(act);
 			assertEquals(exp.getName(), act.getName());
+			assertEquals(0, act.getUpdateIndex());
 			assertFalse(rc.next());
 		}
 	}
@@ -216,6 +218,7 @@ public void oneTagRef() throws IOException {
 			assertEquals(exp.getName(), act.getName());
 			assertEquals(exp.getObjectId(), act.getObjectId());
 			assertEquals(exp.getPeeledObjectId(), act.getPeeledObjectId());
+			assertEquals(0, act.getUpdateIndex());
 		}
 	}
 
@@ -237,6 +240,7 @@ public void oneSymbolicRef() throws IOException {
 			assertNotNull(act.getLeaf());
 			assertEquals(MASTER, act.getTarget().getName());
 			assertNull(act.getObjectId());
+			assertEquals(0, act.getUpdateIndex());
 		}
 	}
 
@@ -250,14 +254,17 @@ public void resolveSymbolicRef() throws IOException {
 		Ref head = t.exactRef(HEAD);
 		assertNull(head.getObjectId());
 		assertEquals("refs/heads/tmp", head.getTarget().getName());
+		assertEquals(0, head.getUpdateIndex());
 
 		head = t.resolve(head);
 		assertNotNull(head);
 		assertEquals(id(1), head.getObjectId());
+		assertEquals(0, head.getUpdateIndex());
 
 		Ref master = t.exactRef(MASTER);
 		assertNotNull(master);
 		assertSame(master, t.resolve(master));
+		assertEquals(0, master.getUpdateIndex());
 	}
 
 	@Test
@@ -335,14 +342,17 @@ public void namespaceHeads() throws IOException {
 		try (RefCursor rc = t.seekRefsWithPrefix("refs/tags/")) {
 			assertTrue(rc.next());
 			assertEquals(V1_0, rc.getRef().getName());
+			assertEquals(0, rc.getRef().getUpdateIndex());
 			assertFalse(rc.next());
 		}
 		try (RefCursor rc = t.seekRefsWithPrefix("refs/heads/")) {
 			assertTrue(rc.next());
 			assertEquals(MASTER, rc.getRef().getName());
+			assertEquals(0, rc.getRef().getUpdateIndex());
 
 			assertTrue(rc.next());
 			assertEquals(NEXT, rc.getRef().getName());
+			assertEquals(0, rc.getRef().getUpdateIndex());
 
 			assertFalse(rc.next());
 		}
@@ -432,11 +442,12 @@ public void withReflog() throws IOException {
 			assertTrue(rc.next());
 			assertEquals(MASTER, rc.getRef().getName());
 			assertEquals(id(1), rc.getRef().getObjectId());
-			assertEquals(1, rc.getUpdateIndex());
+			assertEquals(1, rc.getRef().getUpdateIndex());
 
 			assertTrue(rc.next());
 			assertEquals(NEXT, rc.getRef().getName());
 			assertEquals(id(2), rc.getRef().getObjectId());
+			assertEquals(1, rc.getRef().getUpdateIndex());
 			assertFalse(rc.next());
 		}
 		try (LogCursor lc = t.allLogs()) {
@@ -569,6 +580,7 @@ public void byObjectIdOneRefNoIndex() throws IOException {
 			assertTrue("has 42", rc.next());
 			assertEquals("refs/heads/42", rc.getRef().getName());
 			assertEquals(id(42), rc.getRef().getObjectId());
+			assertEquals(0, rc.getRef().getUpdateIndex());
 			assertFalse(rc.next());
 		}
 		try (RefCursor rc = t.byObjectId(id(100))) {
@@ -579,6 +591,7 @@ public void byObjectIdOneRefNoIndex() throws IOException {
 			assertTrue("has master", rc.next());
 			assertEquals("refs/heads/master", rc.getRef().getName());
 			assertEquals(id(100), rc.getRef().getObjectId());
+			assertEquals(0, rc.getRef().getUpdateIndex());
 
 			assertFalse(rc.next());
 		}
@@ -600,6 +613,7 @@ public void byObjectIdOneRefWithIndex() throws IOException {
 			assertTrue("has 42", rc.next());
 			assertEquals("refs/heads/42", rc.getRef().getName());
 			assertEquals(id(42), rc.getRef().getObjectId());
+			assertEquals(0, rc.getRef().getUpdateIndex());
 			assertFalse(rc.next());
 		}
 		try (RefCursor rc = t.byObjectId(id(100))) {
@@ -610,6 +624,7 @@ public void byObjectIdOneRefWithIndex() throws IOException {
 			assertTrue("has master", rc.next());
 			assertEquals("refs/heads/master", rc.getRef().getName());
 			assertEquals(id(100), rc.getRef().getObjectId());
+			assertEquals(0, rc.getRef().getUpdateIndex());
 
 			assertFalse(rc.next());
 		}
@@ -654,7 +669,6 @@ public void badCrc32() throws IOException {
 		}
 	}
 
-
 	private static void assertScan(List<Ref> refs, Reftable t)
 			throws IOException {
 		try (RefCursor rc = t.allRefs()) {
@@ -663,6 +677,7 @@ private static void assertScan(List<Ref> refs, Reftable t)
 				Ref act = rc.getRef();
 				assertEquals(exp.getName(), act.getName());
 				assertEquals(exp.getObjectId(), act.getObjectId());
+				assertEquals(0, rc.getRef().getUpdateIndex());
 			}
 			assertFalse(rc.next());
 		}
@@ -676,6 +691,7 @@ private static void assertSeek(List<Ref> refs, Reftable t)
 				Ref act = rc.getRef();
 				assertEquals(exp.getName(), act.getName());
 				assertEquals(exp.getObjectId(), act.getObjectId());
+				assertEquals(0, rc.getRef().getUpdateIndex());
 				assertFalse(rc.next());
 			}
 		}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/reftree/RefTreeDatabaseTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/reftree/RefTreeDatabaseTest.java
index ae52ad5..8ef21e6 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/reftree/RefTreeDatabaseTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/reftree/RefTreeDatabaseTest.java
@@ -362,8 +362,8 @@ public void testGetRefs_CycleInSymbolicRef() throws IOException {
 
 	@Test
 	public void testGetRef_NonExistingBranchConfig() throws IOException {
-		assertNull("find branch config", refdb.getRef("config"));
-		assertNull("find branch config", refdb.getRef("refs/heads/config"));
+		assertNull("find branch config", refdb.findRef("config"));
+		assertNull("find branch config", refdb.findRef("refs/heads/config"));
 	}
 
 	@Test
@@ -371,7 +371,7 @@ public void testGetRef_FindBranchConfig() throws IOException {
 		update("refs/heads/config", A);
 
 		for (String t : new String[] { "config", "refs/heads/config" }) {
-			Ref r = refdb.getRef(t);
+			Ref r = refdb.findRef(t);
 			assertNotNull("find branch config (" + t + ")", r);
 			assertEquals("for " + t, "refs/heads/config", r.getName());
 			assertEquals("for " + t, A, r.getObjectId());
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ObjectIdRefTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ObjectIdRefTest.java
index fb16c6b..6553bfa 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ObjectIdRefTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ObjectIdRefTest.java
@@ -48,6 +48,10 @@
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertSame;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.util.Arrays;
+import java.util.List;
 
 import org.junit.Test;
 
@@ -115,10 +119,43 @@ public void testConstructor_Peeled() {
 	}
 
 	@Test
+	public void testUpdateIndex() {
+		ObjectIdRef r;
+
+		r = new ObjectIdRef.Unpeeled(Ref.Storage.LOOSE, name, ID_A, 3);
+		assertTrue(r.getUpdateIndex() == 3);
+
+		r = new ObjectIdRef.PeeledTag(Ref.Storage.LOOSE, name, ID_A, ID_B, 4);
+		assertTrue(r.getUpdateIndex() == 4);
+
+		r = new ObjectIdRef.PeeledNonTag(Ref.Storage.LOOSE, name, ID_A, 5);
+		assertTrue(r.getUpdateIndex() == 5);
+	}
+
+	@Test
+	public void testUpdateIndexNotSet() {
+		List<ObjectIdRef> r = Arrays.asList(
+				new ObjectIdRef.Unpeeled(Ref.Storage.LOOSE, name, ID_A),
+				new ObjectIdRef.PeeledTag(Ref.Storage.LOOSE, name, ID_A, ID_B),
+				new ObjectIdRef.PeeledNonTag(Ref.Storage.LOOSE, name, ID_A));
+
+		for (ObjectIdRef ref : r) {
+			try {
+				ref.getUpdateIndex();
+				fail("Update index wasn't set. It must throw");
+			} catch (UnsupportedOperationException u) {
+				// Ok
+			}
+		}
+	}
+
+
+	@Test
 	public void testToString() {
 		ObjectIdRef r;
 
 		r = new ObjectIdRef.Unpeeled(Ref.Storage.LOOSE, name, ID_A);
-		assertEquals("Ref[" + name + "=" + ID_A.name() + "]", r.toString());
+		assertEquals("Ref[" + name + "=" + ID_A.name() + "(-1)]",
+				r.toString());
 	}
 }
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RacyGitTests.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RacyGitTests.java
index bb24994..11100b6 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RacyGitTests.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RacyGitTests.java
@@ -46,7 +46,6 @@
 import static java.nio.charset.StandardCharsets.UTF_8;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
-import static org.junit.Assume.assumeTrue;
 
 import java.io.File;
 import java.io.FileOutputStream;
@@ -63,8 +62,8 @@
 
 public class RacyGitTests extends RepositoryTestCase {
 	@Test
-	public void testIterator() throws IllegalStateException, IOException,
-			InterruptedException {
+	public void testIterator()
+			throws IllegalStateException, IOException, InterruptedException {
 		TreeSet<Long> modTimes = new TreeSet<>();
 		File lastFile = null;
 		for (int i = 0; i < 10; i++) {
@@ -128,9 +127,6 @@ public void testIterator() throws IllegalStateException, IOException,
 
 	@Test
 	public void testRacyGitDetection() throws Exception {
-		TreeSet<Long> modTimes = new TreeSet<>();
-		File lastFile;
-
 		// Reset to force creation of index file
 		try (Git git = new Git(db)) {
 			git.reset().call();
@@ -138,45 +134,44 @@ public void testRacyGitDetection() throws Exception {
 
 		// wait to ensure that modtimes of the file doesn't match last index
 		// file modtime
-		modTimes.add(valueOf(fsTick(db.getIndexFile())));
+		fsTick(db.getIndexFile());
 
 		// create two files
-		addToWorkDir("a", "a");
-		lastFile = addToWorkDir("b", "b");
+		File a = addToWorkDir("a", "a");
+		File b = addToWorkDir("b", "b");
+		assertTrue(a.setLastModified(b.lastModified()));
+		assertTrue(b.setLastModified(b.lastModified()));
 
 		// wait to ensure that file-modTimes and therefore index entry modTime
 		// doesn't match the modtime of index-file after next persistance
-		modTimes.add(valueOf(fsTick(lastFile)));
+		fsTick(b);
 
 		// now add both files to the index. No racy git expected
-		resetIndex(new FileTreeIteratorWithTimeControl(db, modTimes));
+		resetIndex(new FileTreeIterator(db));
 
 		assertEquals(
-				"[a, mode:100644, time:t0, length:1, content:a]" +
-				"[b, mode:100644, time:t0, length:1, content:b]",
+				"[a, mode:100644, time:t0, length:1, content:a]"
+						+ "[b, mode:100644, time:t0, length:1, content:b]",
 				indexState(SMUDGE | MOD_TIME | LENGTH | CONTENT));
 
-		// Remember the last modTime of index file. All modifications times of
-		// further modification are translated to this value so it looks that
-		// files have been modified in the same time slot as the index file
-		long indexMod = db.getIndexFile().lastModified();
-		modTimes.add(Long.valueOf(indexMod));
+		// wait to ensure the file 'a' is updated at t1.
+		fsTick(db.getIndexFile());
 
-		// modify one file
-		long aMod = addToWorkDir("a", "a2").lastModified();
-		assumeTrue(aMod == indexMod);
-
-		// now update the index the index. 'a' has to be racily clean -- because
-		// it's modification time is exactly the same as the previous index file
-		// mod time.
-		resetIndex(new FileTreeIteratorWithTimeControl(db, modTimes));
+		// Create a racy git situation. This is a situation that the index is
+		// updated and then a file is modified within a second. By changing the
+		// index file artificially, we create a fake racy situation.
+		File updatedA = addToWorkDir("a", "a2");
+		assertTrue(updatedA.setLastModified(updatedA.lastModified() + 100));
+		resetIndex(new FileTreeIterator(db));
+		assertTrue(db.getIndexFile()
+				.setLastModified(updatedA.lastModified() + 90));
 
 		db.readDirCache();
 		// although racily clean a should not be reported as being dirty
 		assertEquals(
-				"[a, mode:100644, time:t1, smudged, length:0, content:a2]" +
-				"[b, mode:100644, time:t0, length:1, content:b]",
-				indexState(SMUDGE|MOD_TIME|LENGTH|CONTENT));
+				"[a, mode:100644, time:t1, smudged, length:0, content:a2]"
+						+ "[b, mode:100644, time:t0, length:1, content:b]",
+				indexState(SMUDGE | MOD_TIME | LENGTH | CONTENT));
 	}
 
 	private File addToWorkDir(String path, String content) throws IOException {
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RefDatabaseConflictingNamesTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RefDatabaseConflictingNamesTest.java
index 1c21194..cbb47fa 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RefDatabaseConflictingNamesTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RefDatabaseConflictingNamesTest.java
@@ -95,7 +95,7 @@ public boolean isNameConflicting(String name) throws IOException {
 		}
 
 		@Override
-		public Ref getRef(String name) throws IOException {
+		public Ref exactRef(String name) throws IOException {
 			return null;
 		}
 
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/SymbolicRefTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/SymbolicRefTest.java
index 1342253..99b2211 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/SymbolicRefTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/SymbolicRefTest.java
@@ -68,7 +68,7 @@ public void testConstructor() {
 		SymbolicRef r;
 
 		t = new ObjectIdRef.Unpeeled(Ref.Storage.NEW, targetName, null);
-		r = new SymbolicRef(name, t);
+		r = new SymbolicRef(name, t, 1);
 		assertSame(Ref.Storage.LOOSE, r.getStorage());
 		assertSame(name, r.getName());
 		assertNull("no id on new ref", r.getObjectId());
@@ -77,9 +77,10 @@ public void testConstructor() {
 		assertSame("leaf is t", t, r.getLeaf());
 		assertSame("target is t", t, r.getTarget());
 		assertTrue("is symbolic", r.isSymbolic());
+		assertTrue("holds update index", r.getUpdateIndex() == 1);
 
 		t = new ObjectIdRef.Unpeeled(Ref.Storage.PACKED, targetName, ID_A);
-		r = new SymbolicRef(name, t);
+		r = new SymbolicRef(name, t, 2);
 		assertSame(Ref.Storage.LOOSE, r.getStorage());
 		assertSame(name, r.getName());
 		assertSame(ID_A, r.getObjectId());
@@ -88,6 +89,7 @@ public void testConstructor() {
 		assertSame("leaf is t", t, r.getLeaf());
 		assertSame("target is t", t, r.getTarget());
 		assertTrue("is symbolic", r.isSymbolic());
+		assertTrue("holds update index", r.getUpdateIndex() == 2);
 	}
 
 	@Test
@@ -133,6 +135,6 @@ public void testToString() {
 		d = new SymbolicRef("D", c);
 
 		assertEquals("SymbolicRef[D -> C -> B -> " + targetName + "="
-				+ ID_A.name() + "]", d.toString());
+				+ ID_A.name() + "(-1)]", d.toString());
 	}
 }
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/MergerTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/MergerTest.java
index 8ca5d45..335a8ca 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/MergerTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/MergerTest.java
@@ -1069,7 +1069,7 @@ public void checkLockedFilesToBeDeleted(MergeStrategy strategy)
 		git.add().addFilepattern("c.txt").call();
 		git.commit().setMessage("added c.txt").call();
 
-		// Get a handle to the the file so on windows it can't be deleted.
+		// Get a handle to the file so on windows it can't be deleted.
 		try (FileInputStream fis = new FileInputStream(
 				new File(db.getWorkTree(), "b.txt"))) {
 			MergeResult mergeRes = git.merge().setStrategy(strategy)
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PackParserTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PackParserTest.java
index b6d0611..0f98fac 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
@@ -163,7 +163,7 @@ public void testTinyThinPack() throws Exception {
 	public void testPackWithDuplicateBlob() throws Exception {
 		final byte[] data = Constants.encode("0123456789abcdefg");
 		TestRepository<Repository> d = new TestRepository<>(db);
-		assertTrue(db.hasObject(d.blob(data)));
+		assertTrue(db.getObjectDatabase().has(d.blob(data)));
 
 		TemporaryBuffer.Heap pack = new TemporaryBuffer.Heap(1024);
 		packHeader(pack, 1);
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ReceivePackAdvertiseRefsHookTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ReceivePackAdvertiseRefsHookTest.java
index dfa50b6..fa8856d 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ReceivePackAdvertiseRefsHookTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ReceivePackAdvertiseRefsHookTest.java
@@ -236,7 +236,7 @@ public void testSuccess() throws Exception {
 		// Verify the only storage of b is our packed delta above.
 		//
 		ObjectDirectory od = (ObjectDirectory) src.getObjectDatabase();
-		assertTrue("has b", src.hasObject(b));
+		assertTrue("has b", od.has(b));
 		assertFalse("b not loose", od.fileFor(b).exists());
 
 		// Now use b but in a different commit than what is hidden.
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/UploadPackTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/UploadPackTest.java
index 8acbcce..a0635b7 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/UploadPackTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/UploadPackTest.java
@@ -128,13 +128,13 @@ public UploadPack create(Object req, Repository db)
 				}, null);
 		uri = testProtocol.register(ctx, server);
 
-		assertFalse(client.hasObject(commit0.toObjectId()));
+		assertFalse(client.getObjectDatabase().has(commit0.toObjectId()));
 
 		// Fetch of the parent of the shallow commit
 		try (Transport tn = testProtocol.open(uri, client, "server")) {
 			tn.fetch(NullProgressMonitor.INSTANCE,
 					Collections.singletonList(new RefSpec(commit0.name())));
-			assertTrue(client.hasObject(commit0.toObjectId()));
+			assertTrue(client.getObjectDatabase().has(commit0.toObjectId()));
 		}
 	}
 
@@ -147,7 +147,7 @@ public void testFetchUnreachableBlobWithBitmap() throws Exception {
 		testProtocol = generateReachableCommitUploadPackProtocol();
 		uri = testProtocol.register(ctx, server);
 
-		assertFalse(client.hasObject(blob.toObjectId()));
+		assertFalse(client.getObjectDatabase().has(blob.toObjectId()));
 
 		try (Transport tn = testProtocol.open(uri, client, "server")) {
 			thrown.expect(TransportException.class);
@@ -168,12 +168,12 @@ public void testFetchReachableBlobWithBitmap() throws Exception {
 		testProtocol = generateReachableCommitUploadPackProtocol();
 		uri = testProtocol.register(ctx, server);
 
-		assertFalse(client.hasObject(blob.toObjectId()));
+		assertFalse(client.getObjectDatabase().has(blob.toObjectId()));
 
 		try (Transport tn = testProtocol.open(uri, client, "server")) {
 			tn.fetch(NullProgressMonitor.INSTANCE,
 					Collections.singletonList(new RefSpec(blob.name())));
-			assertTrue(client.hasObject(blob.toObjectId()));
+			assertTrue(client.getObjectDatabase().has(blob.toObjectId()));
 		}
 	}
 
@@ -186,7 +186,7 @@ public void testFetchReachableBlobWithoutBitmap() throws Exception {
 		testProtocol = generateReachableCommitUploadPackProtocol();
 		uri = testProtocol.register(ctx, server);
 
-		assertFalse(client.hasObject(blob.toObjectId()));
+		assertFalse(client.getObjectDatabase().has(blob.toObjectId()));
 
 		try (Transport tn = testProtocol.open(uri, client, "server")) {
 			thrown.expect(TransportException.class);
@@ -227,9 +227,9 @@ public UploadPack create(Object req, Repository db)
 			tn.setFilterBlobLimit(0);
 			tn.fetch(NullProgressMonitor.INSTANCE,
 					Collections.singletonList(new RefSpec(commit.name())));
-			assertTrue(client.hasObject(tree.toObjectId()));
-			assertFalse(client.hasObject(blob1.toObjectId()));
-			assertFalse(client.hasObject(blob2.toObjectId()));
+			assertTrue(client.getObjectDatabase().has(tree.toObjectId()));
+			assertFalse(client.getObjectDatabase().has(blob1.toObjectId()));
+			assertFalse(client.getObjectDatabase().has(blob2.toObjectId()));
 		}
 	}
 
@@ -265,9 +265,9 @@ public UploadPack create(Object req, Repository db)
 			tn.fetch(NullProgressMonitor.INSTANCE, Arrays.asList(
 						new RefSpec(commit.name()),
 						new RefSpec(blob1.name())));
-			assertTrue(client.hasObject(tree.toObjectId()));
-			assertTrue(client.hasObject(blob1.toObjectId()));
-			assertFalse(client.hasObject(blob2.toObjectId()));
+			assertTrue(client.getObjectDatabase().has(tree.toObjectId()));
+			assertTrue(client.getObjectDatabase().has(blob1.toObjectId()));
+			assertFalse(client.getObjectDatabase().has(blob2.toObjectId()));
 		}
 	}
 
@@ -301,8 +301,8 @@ public UploadPack create(Object req, Repository db)
 			tn.setFilterBlobLimit(5);
 			tn.fetch(NullProgressMonitor.INSTANCE,
 					Collections.singletonList(new RefSpec(commit.name())));
-			assertFalse(client.hasObject(longBlob.toObjectId()));
-			assertTrue(client.hasObject(shortBlob.toObjectId()));
+			assertFalse(client.getObjectDatabase().has(longBlob.toObjectId()));
+			assertTrue(client.getObjectDatabase().has(shortBlob.toObjectId()));
 		}
 	}
 
@@ -342,8 +342,8 @@ public UploadPack create(Object req, Repository db)
 			tn.fetch(NullProgressMonitor.INSTANCE, Arrays.asList(
 						new RefSpec(commit.name()),
 						new RefSpec(blob1.name())));
-			assertTrue(client.hasObject(blob1.toObjectId()));
-			assertFalse(client.hasObject(blob2.toObjectId()));
+			assertTrue(client.getObjectDatabase().has(blob1.toObjectId()));
+			assertFalse(client.getObjectDatabase().has(blob2.toObjectId()));
 		}
 	}
 
@@ -381,8 +381,8 @@ public UploadPack create(Object req, Repository db)
 			tn.setFilterBlobLimit(5);
 			tn.fetch(NullProgressMonitor.INSTANCE,
 					Collections.singletonList(new RefSpec(commit.name())));
-			assertFalse(client.hasObject(longBlob.toObjectId()));
-			assertTrue(client.hasObject(shortBlob.toObjectId()));
+			assertFalse(client.getObjectDatabase().has(longBlob.toObjectId()));
+			assertTrue(client.getObjectDatabase().has(shortBlob.toObjectId()));
 		}
 	}
 
@@ -965,10 +965,10 @@ public void testV2FetchServerStopsNegotiation() throws Exception {
 		assertThat(pckIn.readString(), theInstance(PacketLineIn.DELIM));
 		assertThat(pckIn.readString(), is("packfile"));
 		parsePack(recvStream);
-		assertFalse(client.hasObject(fooParent.toObjectId()));
-		assertTrue(client.hasObject(fooChild.toObjectId()));
-		assertFalse(client.hasObject(barParent.toObjectId()));
-		assertTrue(client.hasObject(barChild.toObjectId()));
+		assertFalse(client.getObjectDatabase().has(fooParent.toObjectId()));
+		assertTrue(client.getObjectDatabase().has(fooChild.toObjectId()));
+		assertFalse(client.getObjectDatabase().has(barParent.toObjectId()));
+		assertTrue(client.getObjectDatabase().has(barChild.toObjectId()));
 	}
 
 	@Test
@@ -992,10 +992,10 @@ public void testV2FetchClientStopsNegotiation() throws Exception {
 
 		assertThat(pckIn.readString(), is("packfile"));
 		parsePack(recvStream);
-		assertFalse(client.hasObject(fooParent.toObjectId()));
-		assertTrue(client.hasObject(fooChild.toObjectId()));
-		assertTrue(client.hasObject(barParent.toObjectId()));
-		assertTrue(client.hasObject(barChild.toObjectId()));
+		assertFalse(client.getObjectDatabase().has(fooParent.toObjectId()));
+		assertTrue(client.getObjectDatabase().has(fooChild.toObjectId()));
+		assertTrue(client.getObjectDatabase().has(barParent.toObjectId()));
+		assertTrue(client.getObjectDatabase().has(barChild.toObjectId()));
 	}
 
 	@Test
@@ -1078,7 +1078,7 @@ public void testV2FetchIncludeTag() throws Exception {
 		PacketLineIn pckIn = new PacketLineIn(recvStream);
 		assertThat(pckIn.readString(), is("packfile"));
 		parsePack(recvStream);
-		assertFalse(client.hasObject(tag.toObjectId()));
+		assertFalse(client.getObjectDatabase().has(tag.toObjectId()));
 
 		// With tag.
 		recvStream = uploadPackV2(
@@ -1091,7 +1091,7 @@ public void testV2FetchIncludeTag() throws Exception {
 		pckIn = new PacketLineIn(recvStream);
 		assertThat(pckIn.readString(), is("packfile"));
 		parsePack(recvStream);
-		assertTrue(client.hasObject(tag.toObjectId()));
+		assertTrue(client.getObjectDatabase().has(tag.toObjectId()));
 	}
 
 	@Test
@@ -1149,8 +1149,8 @@ public void testV2FetchShallow() throws Exception {
 		PacketLineIn pckIn = new PacketLineIn(recvStream);
 		assertThat(pckIn.readString(), is("packfile"));
 		parsePack(recvStream);
-		assertTrue(client.hasObject(barChild.toObjectId()));
-		assertFalse(client.hasObject(commonParent.toObjectId()));
+		assertTrue(client.getObjectDatabase().has(barChild.toObjectId()));
+		assertFalse(client.getObjectDatabase().has(commonParent.toObjectId()));
 
 		// With shallow, the server knows that we don't have
 		// commonParent, so it sends it.
@@ -1165,7 +1165,7 @@ public void testV2FetchShallow() throws Exception {
 		pckIn = new PacketLineIn(recvStream);
 		assertThat(pckIn.readString(), is("packfile"));
 		parsePack(recvStream);
-		assertTrue(client.hasObject(commonParent.toObjectId()));
+		assertTrue(client.getObjectDatabase().has(commonParent.toObjectId()));
 	}
 
 	@Test
@@ -1188,8 +1188,8 @@ public void testV2FetchDeepenAndDone() throws Exception {
 		assertThat(pckIn.readString(), theInstance(PacketLineIn.DELIM));
 		assertThat(pckIn.readString(), is("packfile"));
 		parsePack(recvStream);
-		assertTrue(client.hasObject(child.toObjectId()));
-		assertFalse(client.hasObject(parent.toObjectId()));
+		assertTrue(client.getObjectDatabase().has(child.toObjectId()));
+		assertFalse(client.getObjectDatabase().has(parent.toObjectId()));
 
 		// Without that, the parent is sent too.
 		recvStream = uploadPackV2(
@@ -1201,7 +1201,7 @@ public void testV2FetchDeepenAndDone() throws Exception {
 		pckIn = new PacketLineIn(recvStream);
 		assertThat(pckIn.readString(), is("packfile"));
 		parsePack(recvStream);
-		assertTrue(client.hasObject(parent.toObjectId()));
+		assertTrue(client.getObjectDatabase().has(parent.toObjectId()));
 	}
 
 	@Test
@@ -1268,15 +1268,15 @@ public void testV2FetchShallowSince() throws Exception {
 
 		// The server does not send this because it is committed
 		// earlier than the given deepen-since time.
-		assertFalse(client.hasObject(tooOld.toObjectId()));
+		assertFalse(client.getObjectDatabase().has(tooOld.toObjectId()));
 
 		// The server does not send this because the client claims to
 		// have it.
-		assertFalse(client.hasObject(boundary.toObjectId()));
+		assertFalse(client.getObjectDatabase().has(boundary.toObjectId()));
 
 		// The server sends both these commits.
-		assertTrue(client.hasObject(beyondBoundary.toObjectId()));
-		assertTrue(client.hasObject(merge.toObjectId()));
+		assertTrue(client.getObjectDatabase().has(beyondBoundary.toObjectId()));
+		assertTrue(client.getObjectDatabase().has(merge.toObjectId()));
 	}
 
 	@Test
@@ -1316,9 +1316,9 @@ public void testV2FetchShallowSince_excludedParentWithMultipleChildren() throws
 		parsePack(recvStream);
 
 		// Only the children are sent.
-		assertFalse(client.hasObject(base.toObjectId()));
-		assertTrue(client.hasObject(child1.toObjectId()));
-		assertTrue(client.hasObject(child2.toObjectId()));
+		assertFalse(client.getObjectDatabase().has(base.toObjectId()));
+		assertTrue(client.getObjectDatabase().has(child1.toObjectId()));
+		assertTrue(client.getObjectDatabase().has(child2.toObjectId()));
 	}
 
 	@Test
@@ -1384,16 +1384,16 @@ public void testV2FetchDeepenNot() throws Exception {
 
 		// The server does not send these because they are excluded by
 		// deepen-not.
-		assertFalse(client.hasObject(side.toObjectId()));
-		assertFalse(client.hasObject(one.toObjectId()));
+		assertFalse(client.getObjectDatabase().has(side.toObjectId()));
+		assertFalse(client.getObjectDatabase().has(one.toObjectId()));
 
 		// The server does not send this because the client claims to
 		// have it.
-		assertFalse(client.hasObject(three.toObjectId()));
+		assertFalse(client.getObjectDatabase().has(three.toObjectId()));
 
 		// The server sends both these commits.
-		assertTrue(client.hasObject(merge.toObjectId()));
-		assertTrue(client.hasObject(two.toObjectId()));
+		assertTrue(client.getObjectDatabase().has(merge.toObjectId()));
+		assertTrue(client.getObjectDatabase().has(two.toObjectId()));
 	}
 
 	@Test
@@ -1441,10 +1441,10 @@ public void testV2FetchDeepenNot_supportAnnotatedTags() throws Exception {
 		assertThat(pckIn.readString(), theInstance(PacketLineIn.DELIM));
 		assertThat(pckIn.readString(), is("packfile"));
 		parsePack(recvStream);
-		assertFalse(client.hasObject(one.toObjectId()));
-		assertFalse(client.hasObject(two.toObjectId()));
-		assertTrue(client.hasObject(three.toObjectId()));
-		assertTrue(client.hasObject(four.toObjectId()));
+		assertFalse(client.getObjectDatabase().has(one.toObjectId()));
+		assertFalse(client.getObjectDatabase().has(two.toObjectId()));
+		assertTrue(client.getObjectDatabase().has(three.toObjectId()));
+		assertTrue(client.getObjectDatabase().has(four.toObjectId()));
 	}
 
 	@Test
@@ -1485,9 +1485,9 @@ public void testV2FetchDeepenNot_excludedParentWithMultipleChildren() throws Exc
 		parsePack(recvStream);
 
 		// Only the children are sent.
-		assertFalse(client.hasObject(base.toObjectId()));
-		assertTrue(client.hasObject(child1.toObjectId()));
-		assertTrue(client.hasObject(child2.toObjectId()));
+		assertFalse(client.getObjectDatabase().has(base.toObjectId()));
+		assertTrue(client.getObjectDatabase().has(child1.toObjectId()));
+		assertTrue(client.getObjectDatabase().has(child2.toObjectId()));
 	}
 
 	@Test
@@ -1538,8 +1538,8 @@ public void testV2FetchFilter() throws Exception {
 		assertThat(pckIn.readString(), is("packfile"));
 		parsePack(recvStream);
 
-		assertFalse(client.hasObject(big.toObjectId()));
-		assertTrue(client.hasObject(small.toObjectId()));
+		assertFalse(client.getObjectDatabase().has(big.toObjectId()));
+		assertTrue(client.getObjectDatabase().has(small.toObjectId()));
 	}
 
 	@Test
@@ -1610,9 +1610,9 @@ public void testV2FetchWantRef() throws Exception {
 		assertThat(pckIn.readString(), is("packfile"));
 		parsePack(recvStream);
 
-		assertTrue(client.hasObject(one.toObjectId()));
-		assertTrue(client.hasObject(two.toObjectId()));
-		assertFalse(client.hasObject(three.toObjectId()));
+		assertTrue(client.getObjectDatabase().has(one.toObjectId()));
+		assertTrue(client.getObjectDatabase().has(two.toObjectId()));
+		assertFalse(client.getObjectDatabase().has(three.toObjectId()));
 	}
 
 	@Test
@@ -1666,9 +1666,9 @@ public void testV2FetchMixedWantRef() throws Exception {
 		assertThat(pckIn.readString(), is("packfile"));
 		parsePack(recvStream);
 
-		assertTrue(client.hasObject(one.toObjectId()));
-		assertTrue(client.hasObject(two.toObjectId()));
-		assertFalse(client.hasObject(three.toObjectId()));
+		assertTrue(client.getObjectDatabase().has(one.toObjectId()));
+		assertTrue(client.getObjectDatabase().has(two.toObjectId()));
+		assertFalse(client.getObjectDatabase().has(three.toObjectId()));
 	}
 
 	@Test
@@ -1699,7 +1699,7 @@ public void testV2FetchWantRefWeAlreadyHave() throws Exception {
 		// ... but the client does not need the object itself.
 		assertThat(pckIn.readString(), is("packfile"));
 		parsePack(recvStream);
-		assertFalse(client.hasObject(one.toObjectId()));
+		assertFalse(client.getObjectDatabase().has(one.toObjectId()));
 	}
 
 	@Test
@@ -1728,8 +1728,8 @@ public void testV2FetchWantRefAndDeepen() throws Exception {
 		assertThat(pckIn.readString(), theInstance(PacketLineIn.DELIM));
 		assertThat(pckIn.readString(), is("packfile"));
 		parsePack(recvStream);
-		assertTrue(client.hasObject(child.toObjectId()));
-		assertFalse(client.hasObject(parent.toObjectId()));
+		assertTrue(client.getObjectDatabase().has(child.toObjectId()));
+		assertFalse(client.getObjectDatabase().has(parent.toObjectId()));
 	}
 
 	@Test
@@ -1765,9 +1765,9 @@ public void testV2FetchMissingShallow() throws Exception {
 		assertThat(pckIn.readString(), is("packfile"));
 		parsePack(recvStream);
 
-		assertTrue(client.hasObject(one.toObjectId()));
-		assertTrue(client.hasObject(two.toObjectId()));
-		assertTrue(client.hasObject(three.toObjectId()));
+		assertTrue(client.getObjectDatabase().has(one.toObjectId()));
+		assertTrue(client.getObjectDatabase().has(two.toObjectId()));
+		assertTrue(client.getObjectDatabase().has(three.toObjectId()));
 	}
 
 	@Test
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/FileTreeIteratorTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/FileTreeIteratorTest.java
index 33e32cd..6f61912 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/FileTreeIteratorTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/FileTreeIteratorTest.java
@@ -48,9 +48,11 @@
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeNoException;
 
 import java.io.File;
 import java.io.IOException;
+import java.nio.file.InvalidPathException;
 import java.security.MessageDigest;
 
 import org.eclipse.jgit.api.Git;
@@ -666,9 +668,23 @@ public void testCustomFileModeStrategyFromParentIterator() throws Exception {
 	public void testFileModeSymLinkIsNotATree() throws IOException {
 		org.junit.Assume.assumeTrue(FS.DETECTED.supportsSymlinks());
 		FS fs = db.getFS();
-		// mål = target in swedish, just to get som unicode in here
+		// mål = target in swedish, just to get some unicode in here
 		writeTrashFile("mål/data", "targetdata");
-		fs.createSymLink(new File(trash, "länk"), "mål");
+		File file = new File(trash, "länk");
+
+		try {
+			file.toPath();
+		} catch (InvalidPathException e) {
+			// When executing a test with LANG environment variable set to non
+			// UTF-8 encoding, it seems that JRE cannot handle Unicode file
+			// paths. This happens when this test is executed in Bazel as it
+			// unsets LANG
+			// (https://docs.bazel.build/versions/master/test-encyclopedia.html#initial-conditions).
+			// Skip the test if the runtime cannot handle Unicode characters.
+			assumeNoException(e);
+		}
+
+		fs.createSymLink(file, "mål");
 		FileTreeIterator fti = new FileTreeIterator(db);
 		assertFalse(fti.eof());
 		while (!fti.getEntryPathString().equals("länk")) {
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FSTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FSTest.java
index 2c8273d..5293ca4 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FSTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FSTest.java
@@ -47,11 +47,13 @@
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assume.assumeTrue;
+import static org.junit.Assume.assumeNoException;
 
 import java.io.File;
 import java.io.IOException;
 import java.nio.charset.Charset;
 import java.nio.file.Files;
+import java.nio.file.InvalidPathException;
 import java.nio.file.attribute.PosixFileAttributeView;
 import java.nio.file.attribute.PosixFilePermission;
 import java.util.Set;
@@ -92,16 +94,17 @@ public void tearDown() throws Exception {
 	public void testSymlinkAttributes() throws IOException, InterruptedException {
 		Assume.assumeTrue(FS.DETECTED.supportsSymlinks());
 		FS fs = FS.DETECTED;
-		File link = new File(trash, "ä");
-		File target = new File(trash, "å");
-		fs.createSymLink(link, "å");
+		File link = new File(trash, "a");
+		File target = new File(trash, "b");
+		fs.createSymLink(link, "b");
 		assertTrue(fs.exists(link));
 		String targetName = fs.readSymLink(link);
-		assertEquals("å", targetName);
+		assertEquals("b", targetName);
 		assertTrue(fs.lastModified(link) > 0);
 		assertTrue(fs.exists(link));
 		assertFalse(fs.canExecute(link));
-		assertEquals(2, fs.length(link));
+		// The length of a symbolic link is a length of the target file path.
+		assertEquals(1, fs.length(link));
 		assertFalse(fs.exists(target));
 		assertFalse(fs.isFile(target));
 		assertFalse(fs.isDirectory(target));
@@ -121,6 +124,32 @@ public void testSymlinkAttributes() throws IOException, InterruptedException {
 	}
 
 	@Test
+	public void testUnicodeFilePath() throws IOException {
+		Assume.assumeTrue(FS.DETECTED.supportsSymlinks());
+		FS fs = FS.DETECTED;
+		File link = new File(trash, "ä");
+		File target = new File(trash, "å");
+
+		try {
+			// Check if the runtime can support Unicode file paths.
+			link.toPath();
+			target.toPath();
+		} catch (InvalidPathException e) {
+			// When executing a test with LANG environment variable set to non
+			// UTF-8 encoding, it seems that JRE cannot handle Unicode file
+			// paths. This happens when this test is executed in Bazel as it
+			// unsets LANG
+			// (https://docs.bazel.build/versions/master/test-encyclopedia.html#initial-conditions).
+			// Skip the test if the runtime cannot handle Unicode characters.
+			assumeNoException(e);
+		}
+
+		fs.createSymLink(link, "å");
+		assertTrue(fs.exists(link));
+		assertEquals("å", fs.readSymLink(link));
+	}
+
+	@Test
 	public void testExecutableAttributes() throws Exception {
 		FS fs = FS.DETECTED.newInstance();
 		// If this assumption fails the test is halted and ignored.
diff --git a/org.eclipse.jgit.ui/META-INF/MANIFEST.MF b/org.eclipse.jgit.ui/META-INF/MANIFEST.MF
index 195e4d2..3ac2d9d 100644
--- a/org.eclipse.jgit.ui/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.ui/META-INF/MANIFEST.MF
@@ -4,14 +4,14 @@
 Bundle-Name: %plugin_name
 Automatic-Module-Name: org.eclipse.jgit.ui
 Bundle-SymbolicName: org.eclipse.jgit.ui
-Bundle-Version: 5.2.2.qualifier
+Bundle-Version: 5.3.0.qualifier
 Bundle-Vendor: %provider_name
 Bundle-RequiredExecutionEnvironment: JavaSE-1.8
-Export-Package: org.eclipse.jgit.awtui;version="5.2.2"
-Import-Package: org.eclipse.jgit.errors;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.lib;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.nls;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.revplot;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.revwalk;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.transport;version="[5.2.2,5.3.0)",
- org.eclipse.jgit.util;version="[5.2.2,5.3.0)"
+Export-Package: org.eclipse.jgit.awtui;version="5.3.0"
+Import-Package: org.eclipse.jgit.errors;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.lib;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.nls;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.revplot;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.revwalk;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.transport;version="[5.3.0,5.4.0)",
+ org.eclipse.jgit.util;version="[5.3.0,5.4.0)"
diff --git a/org.eclipse.jgit.ui/pom.xml b/org.eclipse.jgit.ui/pom.xml
index 78e642f..0d5330d 100644
--- a/org.eclipse.jgit.ui/pom.xml
+++ b/org.eclipse.jgit.ui/pom.xml
@@ -52,7 +52,7 @@
   <parent>
     <groupId>org.eclipse.jgit</groupId>
     <artifactId>org.eclipse.jgit-parent</artifactId>
-    <version>5.2.2-SNAPSHOT</version>
+    <version>5.3.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>org.eclipse.jgit.ui</artifactId>
diff --git a/org.eclipse.jgit/.settings/.api_filters b/org.eclipse.jgit/.settings/.api_filters
index 79183a6..ac2d094 100644
--- a/org.eclipse.jgit/.settings/.api_filters
+++ b/org.eclipse.jgit/.settings/.api_filters
@@ -1,68 +1,70 @@
 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
 <component id="org.eclipse.jgit" version="2">
-    <resource path="src/org/eclipse/jgit/gitrepo/RepoCommand.java" type="org.eclipse.jgit.gitrepo.RepoCommand$DefaultRemoteReader">
-        <filter id="338792546">
+    <resource path="src/org/eclipse/jgit/lib/ObjectIdRef.java" type="org.eclipse.jgit.lib.ObjectIdRef">
+        <filter comment="removing protected constructor breaks implementers which is ok in a minor release following OSGi semantic versioning" id="338722907">
             <message_arguments>
-                <message_argument value="org.eclipse.jgit.gitrepo.RepoCommand.DefaultRemoteReader"/>
-                <message_argument value="readFile(String, String, String)"/>
-            </message_arguments>
-        </filter>
-        <filter id="338792546">
-            <message_arguments>
-                <message_argument value="org.eclipse.jgit.gitrepo.RepoCommand.DefaultRemoteReader"/>
-                <message_argument value="readFileFromRepo(Repository, String, String)"/>
+                <message_argument value="org.eclipse.jgit.lib.ObjectIdRef"/>
+                <message_argument value="ObjectIdRef(Ref.Storage, String, ObjectId)"/>
             </message_arguments>
         </filter>
     </resource>
-    <resource path="src/org/eclipse/jgit/gitrepo/RepoCommand.java" type="org.eclipse.jgit.gitrepo.RepoCommand$RemoteReader">
-        <filter id="403804204">
-            <message_arguments>
-                <message_argument value="org.eclipse.jgit.gitrepo.RepoCommand.RemoteReader"/>
-                <message_argument value="readFileWithMode(String, String, String)"/>
-            </message_arguments>
-        </filter>
-    </resource>
-    <resource path="src/org/eclipse/jgit/lib/GitmoduleEntry.java" type="org.eclipse.jgit.lib.GitmoduleEntry">
-        <filter id="1109393411">
-            <message_arguments>
-                <message_argument value="4.7.5"/>
-                <message_argument value="org.eclipse.jgit.lib.GitmoduleEntry"/>
-            </message_arguments>
-        </filter>
-    </resource>
-    <resource path="src/org/eclipse/jgit/lib/ObjectChecker.java" type="org.eclipse.jgit.lib.ObjectChecker">
-        <filter id="1142947843">
-            <message_arguments>
-                <message_argument value="4.7.5"/>
-                <message_argument value="getGitsubmodules()"/>
-            </message_arguments>
-        </filter>
-    </resource>
-    <resource path="src/org/eclipse/jgit/revwalk/DepthWalk.java" type="org.eclipse.jgit.revwalk.DepthWalk">
-        <filter id="403804204">
-            <message_arguments>
-                <message_argument value="org.eclipse.jgit.revwalk.DepthWalk"/>
-                <message_argument value="getDeepenNotFlag()"/>
-            </message_arguments>
-        </filter>
+    <resource path="src/org/eclipse/jgit/lib/Ref.java" type="org.eclipse.jgit.lib.Ref">
         <filter id="404000815">
             <message_arguments>
-                <message_argument value="org.eclipse.jgit.revwalk.DepthWalk"/>
-                <message_argument value="getDeepenNots()"/>
-            </message_arguments>
-        </filter>
-        <filter id="404000815">
-            <message_arguments>
-                <message_argument value="org.eclipse.jgit.revwalk.DepthWalk"/>
-                <message_argument value="getDeepenSince()"/>
+                <message_argument value="org.eclipse.jgit.lib.Ref"/>
+                <message_argument value="getUpdateIndex()"/>
             </message_arguments>
         </filter>
     </resource>
-    <resource path="src/org/eclipse/jgit/transport/RemoteSession.java" type="org.eclipse.jgit.transport.RemoteSession">
-        <filter id="404000815">
+    <resource path="src/org/eclipse/jgit/lib/RefDatabase.java" type="org.eclipse.jgit.lib.RefDatabase">
+        <filter comment="class is extended by extenders but not clients of the API" id="421650549">
             <message_arguments>
-                <message_argument value="org.eclipse.jgit.transport.RemoteSession"/>
-                <message_argument value="getFtpChannel()"/>
+                <message_argument value="org.eclipse.jgit.lib.RefDatabase"/>
+                <message_argument value="exactRef(String)"/>
+            </message_arguments>
+        </filter>
+        <filter id="421654647">
+            <message_arguments>
+                <message_argument value="org.eclipse.jgit.lib.RefDatabase"/>
+                <message_argument value="getRef(String)"/>
+            </message_arguments>
+        </filter>
+    </resource>
+    <resource path="src/org/eclipse/jgit/transport/BaseReceivePack.java" type="org.eclipse.jgit.transport.BaseReceivePack">
+        <filter id="421650549">
+            <message_arguments>
+                <message_argument value="org.eclipse.jgit.transport.BaseReceivePack"/>
+                <message_argument value="getAdvertisedRefs()"/>
+            </message_arguments>
+        </filter>
+        <filter id="421650549">
+            <message_arguments>
+                <message_argument value="org.eclipse.jgit.transport.BaseReceivePack"/>
+                <message_argument value="getPushCertificate()"/>
+            </message_arguments>
+        </filter>
+        <filter id="421650549">
+            <message_arguments>
+                <message_argument value="org.eclipse.jgit.transport.BaseReceivePack"/>
+                <message_argument value="getRepository()"/>
+            </message_arguments>
+        </filter>
+        <filter id="421650549">
+            <message_arguments>
+                <message_argument value="org.eclipse.jgit.transport.BaseReceivePack"/>
+                <message_argument value="getRevWalk()"/>
+            </message_arguments>
+        </filter>
+        <filter id="421650549">
+            <message_arguments>
+                <message_argument value="org.eclipse.jgit.transport.BaseReceivePack"/>
+                <message_argument value="setAdvertisedRefs(Map&lt;String,Ref&gt;, Set&lt;ObjectId&gt;)"/>
+            </message_arguments>
+        </filter>
+        <filter id="421650549">
+            <message_arguments>
+                <message_argument value="org.eclipse.jgit.transport.BaseReceivePack"/>
+                <message_argument value="setPushCertificate(PushCertificate)"/>
             </message_arguments>
         </filter>
     </resource>
@@ -80,12 +82,4 @@
             </message_arguments>
         </filter>
     </resource>
-    <resource path="src/org/eclipse/jgit/transport/http/HttpConnection.java" type="org.eclipse.jgit.transport.http.HttpConnection">
-        <filter id="403804204">
-            <message_arguments>
-                <message_argument value="org.eclipse.jgit.transport.http.HttpConnection"/>
-                <message_argument value="getHeaderFields(String)"/>
-            </message_arguments>
-        </filter>
-    </resource>
 </component>
diff --git a/org.eclipse.jgit/META-INF/MANIFEST.MF b/org.eclipse.jgit/META-INF/MANIFEST.MF
index 0ecdfb0..38b734b 100644
--- a/org.eclipse.jgit/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit/META-INF/MANIFEST.MF
@@ -3,12 +3,12 @@
 Bundle-Name: %plugin_name
 Automatic-Module-Name: org.eclipse.jgit
 Bundle-SymbolicName: org.eclipse.jgit
-Bundle-Version: 5.2.2.qualifier
+Bundle-Version: 5.3.0.qualifier
 Bundle-Localization: plugin
 Bundle-Vendor: %provider_name
 Bundle-ActivationPolicy: lazy
-Export-Package: org.eclipse.jgit.annotations;version="5.2.2",
- org.eclipse.jgit.api;version="5.2.2";
+Export-Package: org.eclipse.jgit.annotations;version="5.3.0",
+ org.eclipse.jgit.api;version="5.3.0";
   uses:="org.eclipse.jgit.revwalk,
    org.eclipse.jgit.treewalk.filter,
    org.eclipse.jgit.diff,
@@ -22,53 +22,53 @@
    org.eclipse.jgit.submodule,
    org.eclipse.jgit.transport,
    org.eclipse.jgit.merge",
- org.eclipse.jgit.api.errors;version="5.2.2";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.errors",
- org.eclipse.jgit.attributes;version="5.2.2",
- org.eclipse.jgit.blame;version="5.2.2";
+ org.eclipse.jgit.api.errors;version="5.3.0";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.errors",
+ org.eclipse.jgit.attributes;version="5.3.0",
+ org.eclipse.jgit.blame;version="5.3.0";
   uses:="org.eclipse.jgit.lib,
    org.eclipse.jgit.revwalk,
    org.eclipse.jgit.treewalk.filter,
    org.eclipse.jgit.diff",
- org.eclipse.jgit.diff;version="5.2.2";
+ org.eclipse.jgit.diff;version="5.3.0";
   uses:="org.eclipse.jgit.patch,
    org.eclipse.jgit.lib,
    org.eclipse.jgit.treewalk,
    org.eclipse.jgit.revwalk,
    org.eclipse.jgit.treewalk.filter,
    org.eclipse.jgit.util",
- org.eclipse.jgit.dircache;version="5.2.2";
+ org.eclipse.jgit.dircache;version="5.3.0";
   uses:="org.eclipse.jgit.lib,
    org.eclipse.jgit.treewalk,
    org.eclipse.jgit.util,
    org.eclipse.jgit.events,
    org.eclipse.jgit.attributes",
- org.eclipse.jgit.errors;version="5.2.2";
+ org.eclipse.jgit.errors;version="5.3.0";
   uses:="org.eclipse.jgit.lib,
    org.eclipse.jgit.internal.storage.pack,
    org.eclipse.jgit.transport,
    org.eclipse.jgit.dircache",
- org.eclipse.jgit.events;version="5.2.2";uses:="org.eclipse.jgit.lib",
- org.eclipse.jgit.fnmatch;version="5.2.2",
- org.eclipse.jgit.gitrepo;version="5.2.2";
+ org.eclipse.jgit.events;version="5.3.0";uses:="org.eclipse.jgit.lib",
+ org.eclipse.jgit.fnmatch;version="5.3.0",
+ org.eclipse.jgit.gitrepo;version="5.3.0";
   uses:="org.eclipse.jgit.api,
    org.eclipse.jgit.lib,
    org.eclipse.jgit.revwalk,
    org.xml.sax.helpers,
    org.xml.sax",
- org.eclipse.jgit.gitrepo.internal;version="5.2.2";x-internal:=true,
- org.eclipse.jgit.hooks;version="5.2.2";uses:="org.eclipse.jgit.lib",
- org.eclipse.jgit.ignore;version="5.2.2",
- org.eclipse.jgit.ignore.internal;version="5.2.2";x-friends:="org.eclipse.jgit.test",
- org.eclipse.jgit.internal;version="5.2.2";x-friends:="org.eclipse.jgit.test,org.eclipse.jgit.http.test",
- org.eclipse.jgit.internal.fsck;version="5.2.2";x-friends:="org.eclipse.jgit.test",
- org.eclipse.jgit.internal.ketch;version="5.2.2";x-friends:="org.eclipse.jgit.junit,org.eclipse.jgit.test,org.eclipse.jgit.pgm",
- org.eclipse.jgit.internal.revwalk;version="5.2.2";x-internal:=true,
- org.eclipse.jgit.internal.storage.dfs;version="5.2.2";
+ org.eclipse.jgit.gitrepo.internal;version="5.3.0";x-internal:=true,
+ org.eclipse.jgit.hooks;version="5.3.0";uses:="org.eclipse.jgit.lib",
+ org.eclipse.jgit.ignore;version="5.3.0",
+ org.eclipse.jgit.ignore.internal;version="5.3.0";x-friends:="org.eclipse.jgit.test",
+ org.eclipse.jgit.internal;version="5.3.0";x-friends:="org.eclipse.jgit.test,org.eclipse.jgit.http.test",
+ org.eclipse.jgit.internal.fsck;version="5.3.0";x-friends:="org.eclipse.jgit.test",
+ org.eclipse.jgit.internal.ketch;version="5.3.0";x-friends:="org.eclipse.jgit.junit,org.eclipse.jgit.test,org.eclipse.jgit.pgm",
+ org.eclipse.jgit.internal.revwalk;version="5.3.0";x-internal:=true,
+ org.eclipse.jgit.internal.storage.dfs;version="5.3.0";
   x-friends:="org.eclipse.jgit.test,
    org.eclipse.jgit.http.server,
    org.eclipse.jgit.http.test,
    org.eclipse.jgit.lfs.test",
- org.eclipse.jgit.internal.storage.file;version="5.2.2";
+ org.eclipse.jgit.internal.storage.file;version="5.3.0";
   x-friends:="org.eclipse.jgit.test,
    org.eclipse.jgit.junit,
    org.eclipse.jgit.junit.http,
@@ -77,18 +77,18 @@
    org.eclipse.jgit.pgm,
    org.eclipse.jgit.pgm.test,
    org.eclipse.jgit.ssh.apache",
- org.eclipse.jgit.internal.storage.io;version="5.2.2";x-friends:="org.eclipse.jgit.junit,org.eclipse.jgit.test,org.eclipse.jgit.pgm",
- org.eclipse.jgit.internal.storage.pack;version="5.2.2";x-friends:="org.eclipse.jgit.junit,org.eclipse.jgit.test,org.eclipse.jgit.pgm",
- org.eclipse.jgit.internal.storage.reftable;version="5.2.2";
+ org.eclipse.jgit.internal.storage.io;version="5.3.0";x-friends:="org.eclipse.jgit.junit,org.eclipse.jgit.test,org.eclipse.jgit.pgm",
+ org.eclipse.jgit.internal.storage.pack;version="5.3.0";x-friends:="org.eclipse.jgit.junit,org.eclipse.jgit.test,org.eclipse.jgit.pgm",
+ org.eclipse.jgit.internal.storage.reftable;version="5.3.0";
   x-friends:="org.eclipse.jgit.http.test,
    org.eclipse.jgit.junit,
    org.eclipse.jgit.test,
    org.eclipse.jgit.pgm",
- org.eclipse.jgit.internal.storage.reftree;version="5.2.2";x-friends:="org.eclipse.jgit.junit,org.eclipse.jgit.test,org.eclipse.jgit.pgm",
- org.eclipse.jgit.internal.submodule;version="5.2.2";x-internal:=true,
- org.eclipse.jgit.internal.transport.parser;version="5.2.2";x-friends:="org.eclipse.jgit.test",
- org.eclipse.jgit.internal.transport.ssh;version="5.2.2";x-friends:="org.eclipse.jgit.ssh.apache",
- org.eclipse.jgit.lib;version="5.2.2";
+ org.eclipse.jgit.internal.storage.reftree;version="5.3.0";x-friends:="org.eclipse.jgit.junit,org.eclipse.jgit.test,org.eclipse.jgit.pgm",
+ org.eclipse.jgit.internal.submodule;version="5.3.0";x-internal:=true,
+ org.eclipse.jgit.internal.transport.parser;version="5.3.0";x-friends:="org.eclipse.jgit.http.server,org.eclipse.jgit.test",
+ org.eclipse.jgit.internal.transport.ssh;version="5.3.0";x-friends:="org.eclipse.jgit.ssh.apache",
+ org.eclipse.jgit.lib;version="5.3.0";
   uses:="org.eclipse.jgit.revwalk,
    org.eclipse.jgit.treewalk.filter,
    org.eclipse.jgit.util,
@@ -98,33 +98,33 @@
    org.eclipse.jgit.treewalk,
    org.eclipse.jgit.transport,
    org.eclipse.jgit.submodule",
- org.eclipse.jgit.lib.internal;version="5.2.2";x-internal:=true,
- org.eclipse.jgit.merge;version="5.2.2";
+ org.eclipse.jgit.lib.internal;version="5.3.0";x-internal:=true,
+ org.eclipse.jgit.merge;version="5.3.0";
   uses:="org.eclipse.jgit.lib,
    org.eclipse.jgit.treewalk,
    org.eclipse.jgit.revwalk,
    org.eclipse.jgit.diff,
    org.eclipse.jgit.dircache,
    org.eclipse.jgit.api",
- org.eclipse.jgit.nls;version="5.2.2",
- org.eclipse.jgit.notes;version="5.2.2";
+ org.eclipse.jgit.nls;version="5.3.0",
+ org.eclipse.jgit.notes;version="5.3.0";
   uses:="org.eclipse.jgit.lib,
    org.eclipse.jgit.treewalk,
    org.eclipse.jgit.revwalk,
    org.eclipse.jgit.merge",
- org.eclipse.jgit.patch;version="5.2.2";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.diff",
- org.eclipse.jgit.revplot;version="5.2.2";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.revwalk",
- org.eclipse.jgit.revwalk;version="5.2.2";
+ org.eclipse.jgit.patch;version="5.3.0";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.diff",
+ org.eclipse.jgit.revplot;version="5.3.0";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.revwalk",
+ org.eclipse.jgit.revwalk;version="5.3.0";
   uses:="org.eclipse.jgit.lib,
    org.eclipse.jgit.treewalk,
    org.eclipse.jgit.treewalk.filter,
    org.eclipse.jgit.diff,
    org.eclipse.jgit.revwalk.filter",
- org.eclipse.jgit.revwalk.filter;version="5.2.2";uses:="org.eclipse.jgit.revwalk,org.eclipse.jgit.lib,org.eclipse.jgit.util",
- org.eclipse.jgit.storage.file;version="5.2.2";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.util",
- org.eclipse.jgit.storage.pack;version="5.2.2";uses:="org.eclipse.jgit.lib",
- org.eclipse.jgit.submodule;version="5.2.2";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.treewalk.filter,org.eclipse.jgit.treewalk",
- org.eclipse.jgit.transport;version="5.2.2";
+ org.eclipse.jgit.revwalk.filter;version="5.3.0";uses:="org.eclipse.jgit.revwalk,org.eclipse.jgit.lib,org.eclipse.jgit.util",
+ org.eclipse.jgit.storage.file;version="5.3.0";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.util",
+ org.eclipse.jgit.storage.pack;version="5.3.0";uses:="org.eclipse.jgit.lib",
+ org.eclipse.jgit.submodule;version="5.3.0";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.treewalk.filter,org.eclipse.jgit.treewalk",
+ org.eclipse.jgit.transport;version="5.3.0";
   uses:="org.eclipse.jgit.transport.resolver,
    org.eclipse.jgit.revwalk,
    org.eclipse.jgit.internal.storage.pack,
@@ -132,28 +132,29 @@
    org.eclipse.jgit.util,
    org.eclipse.jgit.util.io,
    org.eclipse.jgit.internal.storage.file,
+   org.eclipse.jgit.internal.transport.parser,
    org.eclipse.jgit.lib,
    org.eclipse.jgit.transport.http,
    org.eclipse.jgit.errors,
    org.eclipse.jgit.storage.pack",
- org.eclipse.jgit.transport.http;version="5.2.2";uses:="javax.net.ssl",
- org.eclipse.jgit.transport.resolver;version="5.2.2";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.transport",
- org.eclipse.jgit.treewalk;version="5.2.2";
+ org.eclipse.jgit.transport.http;version="5.3.0";uses:="javax.net.ssl",
+ org.eclipse.jgit.transport.resolver;version="5.3.0";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.transport",
+ org.eclipse.jgit.treewalk;version="5.3.0";
   uses:="org.eclipse.jgit.lib,
    org.eclipse.jgit.revwalk,
    org.eclipse.jgit.attributes,
    org.eclipse.jgit.treewalk.filter,
    org.eclipse.jgit.util,
    org.eclipse.jgit.dircache",
- org.eclipse.jgit.treewalk.filter;version="5.2.2";uses:="org.eclipse.jgit.treewalk",
- org.eclipse.jgit.util;version="5.2.2";
+ org.eclipse.jgit.treewalk.filter;version="5.3.0";uses:="org.eclipse.jgit.treewalk",
+ org.eclipse.jgit.util;version="5.3.0";
   uses:="org.eclipse.jgit.lib,
    org.eclipse.jgit.transport.http,
    org.eclipse.jgit.storage.file,
    org.ietf.jgss",
- org.eclipse.jgit.util.io;version="5.2.2",
- org.eclipse.jgit.util.sha1;version="5.2.2",
- org.eclipse.jgit.util.time;version="5.2.2"
+ org.eclipse.jgit.util.io;version="5.3.0",
+ org.eclipse.jgit.util.sha1;version="5.3.0",
+ org.eclipse.jgit.util.time;version="5.3.0"
 Bundle-RequiredExecutionEnvironment: JavaSE-1.8
 Import-Package: com.googlecode.javaewah;version="[1.1.6,2.0.0)",
  com.jcraft.jsch;version="[0.1.37,0.2.0)",
diff --git a/org.eclipse.jgit/META-INF/SOURCE-MANIFEST.MF b/org.eclipse.jgit/META-INF/SOURCE-MANIFEST.MF
index 36aa84a..f497ced 100644
--- a/org.eclipse.jgit/META-INF/SOURCE-MANIFEST.MF
+++ b/org.eclipse.jgit/META-INF/SOURCE-MANIFEST.MF
@@ -3,5 +3,5 @@
 Bundle-Name: org.eclipse.jgit - Sources
 Bundle-SymbolicName: org.eclipse.jgit.source
 Bundle-Vendor: Eclipse.org - JGit
-Bundle-Version: 5.2.2.qualifier
-Eclipse-SourceBundle: org.eclipse.jgit;version="5.2.2.qualifier";roots="."
+Bundle-Version: 5.3.0.qualifier
+Eclipse-SourceBundle: org.eclipse.jgit;version="5.3.0.qualifier";roots="."
diff --git a/org.eclipse.jgit/pom.xml b/org.eclipse.jgit/pom.xml
index e3b7028..0659df2 100644
--- a/org.eclipse.jgit/pom.xml
+++ b/org.eclipse.jgit/pom.xml
@@ -53,7 +53,7 @@
   <parent>
     <groupId>org.eclipse.jgit</groupId>
     <artifactId>org.eclipse.jgit-parent</artifactId>
-    <version>5.2.2-SNAPSHOT</version>
+    <version>5.3.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>org.eclipse.jgit</artifactId>
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/CheckoutCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/CheckoutCommand.java
index 455a2e6..e05f6f1 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/CheckoutCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/CheckoutCommand.java
@@ -162,7 +162,9 @@ private Stage(int number) {
 
 	private String name;
 
-	private boolean force = false;
+	private boolean forceRefUpdate = false;
+
+	private boolean forced = false;
 
 	private boolean createBranch = false;
 
@@ -269,7 +271,11 @@ public Ref call() throws GitAPIException, RefAlreadyExistsException,
 			try {
 				dco = new DirCacheCheckout(repo, headTree, dc,
 						newCommit.getTree());
-				dco.setFailOnConflict(!force);
+				dco.setFailOnConflict(true);
+				dco.setForce(forced);
+				if (forced) {
+					dco.setFailOnConflict(false);
+				}
 				dco.setProgressMonitor(monitor);
 				try {
 					dco.checkout();
@@ -286,7 +292,7 @@ public Ref call() throws GitAPIException, RefAlreadyExistsException,
 				ref = null;
 			String toName = Repository.shortenRefName(name);
 			RefUpdate refUpdate = repo.updateRef(Constants.HEAD, ref == null);
-			refUpdate.setForceUpdate(force);
+			refUpdate.setForceUpdate(forceRefUpdate);
 			refUpdate.setRefLogMessage(refLogMessage + " to " + toName, false); //$NON-NLS-1$
 			Result updateResult;
 			if (ref != null)
@@ -666,10 +672,54 @@ public CheckoutCommand setOrphan(boolean orphan) {
 	 *            set to a new start-point; if false, the existing branch will
 	 *            not be changed
 	 * @return this instance
+	 * @deprecated this method was badly named comparing its semantics to native
+	 *             git's checkout --force option, use
+	 *             {@link #setForceRefUpdate(boolean)} instead
 	 */
+	@Deprecated
 	public CheckoutCommand setForce(boolean force) {
+		return setForceRefUpdate(force);
+	}
+
+	/**
+	 * Specify to force the ref update in case of a branch switch.
+	 *
+	 * In releases prior to 5.2 this method was called setForce() but this name
+	 * was misunderstood to implement native git's --force option, which is not
+	 * true.
+	 *
+	 * @param forceRefUpdate
+	 *            if <code>true</code> and the branch with the given name
+	 *            already exists, the start-point of an existing branch will be
+	 *            set to a new start-point; if false, the existing branch will
+	 *            not be changed
+	 * @return this instance
+	 * @since 5.3
+	 */
+	public CheckoutCommand setForceRefUpdate(boolean forceRefUpdate) {
 		checkCallable();
-		this.force = force;
+		this.forceRefUpdate = forceRefUpdate;
+		return this;
+	}
+
+	/**
+	 * Allow a checkout even if the workingtree or index differs from HEAD. This
+	 * matches native git's '--force' option.
+	 *
+	 * JGit releases before 5.2 had a method <code>setForce()</code> offering
+	 * semantics different from this new <code>setForced()</code>. This old
+	 * semantic can now be found in {@link #setForceRefUpdate(boolean)}
+	 *
+	 * @param forced
+	 *            if set to <code>true</code> then allow the checkout even if
+	 *            workingtree or index doesn't match HEAD. Overwrite workingtree
+	 *            files and index content with the new content in this case.
+	 * @return this instance
+	 * @since 5.3
+	 */
+	public CheckoutCommand setForced(boolean forced) {
+		checkCallable();
+		this.forced = forced;
 		return this;
 	}
 
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/FetchCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/FetchCommand.java
index 73e93a1..2c9c5f2 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/FetchCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/FetchCommand.java
@@ -193,7 +193,8 @@ private void fetchSubmodules(FetchResult results)
 					// updated to an object that is not currently present in the
 					// submodule.
 					if ((recurseMode == FetchRecurseSubmodulesMode.ON_DEMAND
-							&& !submoduleRepo.hasObject(walk.getObjectId()))
+							&& !submoduleRepo.getObjectDatabase()
+									.has(walk.getObjectId()))
 							|| recurseMode == FetchRecurseSubmodulesMode.YES) {
 						FetchCommand f = new FetchCommand(submoduleRepo)
 								.setProgressMonitor(monitor)
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/RemoteRemoveCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/RemoteRemoveCommand.java
index 7a5885c..016cb15 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/RemoteRemoveCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/RemoteRemoveCommand.java
@@ -65,7 +65,7 @@
  */
 public class RemoteRemoveCommand extends GitCommand<RemoteConfig> {
 
-	private String name;
+	private String remoteName;
 
 	/**
 	 * <p>
@@ -84,9 +84,24 @@ protected RemoteRemoveCommand(Repository repo) {
 	 *
 	 * @param name
 	 *            a remote name
+	 * @deprecated use {@link #setRemoteName} instead
 	 */
+	@Deprecated
 	public void setName(String name) {
-		this.name = name;
+		this.remoteName = name;
+	}
+
+	/**
+	 * The name of the remote to remove.
+	 *
+	 * @param remoteName
+	 *            a remote name
+	 * @return {@code this}
+	 * @since 5.3
+	 */
+	public RemoteRemoveCommand setRemoteName(String remoteName) {
+		this.remoteName = remoteName;
+		return this;
 	}
 
 	/**
@@ -101,8 +116,8 @@ public RemoteConfig call() throws GitAPIException {
 
 		try {
 			StoredConfig config = repo.getConfig();
-			RemoteConfig remote = new RemoteConfig(config, name);
-			config.unsetSection(ConfigConstants.CONFIG_KEY_REMOTE, name);
+			RemoteConfig remote = new RemoteConfig(config, remoteName);
+			config.unsetSection(ConfigConstants.CONFIG_KEY_REMOTE, remoteName);
 			config.save();
 			return remote;
 		} catch (IOException | URISyntaxException e) {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/RemoteSetUrlCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/RemoteSetUrlCommand.java
index d7b7a31..21d4023 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/RemoteSetUrlCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/RemoteSetUrlCommand.java
@@ -54,7 +54,7 @@
 import org.eclipse.jgit.transport.URIish;
 
 /**
- * Used to to change the URL of a remote.
+ * Used to change the URL of a remote.
  *
  * This class has setters for all supported options and arguments of this
  * command and a {@link #call()} method to finally execute the command.
@@ -66,11 +66,28 @@
  */
 public class RemoteSetUrlCommand extends GitCommand<RemoteConfig> {
 
-	private String name;
+	/**
+	 * The available URI types for the remote.
+	 *
+	 * @since 5.3
+	 */
+	public enum UriType {
+		/**
+		 * Fetch URL for the remote.
+		 */
+		FETCH,
+		/**
+		 * Push URL for the remote.
+		 */
+		PUSH
+	}
 
-	private URIish uri;
 
-	private boolean push;
+	private String remoteName;
+
+	private URIish remoteUri;
+
+	private UriType type;
 
 	/**
 	 * <p>
@@ -89,9 +106,24 @@ protected RemoteSetUrlCommand(Repository repo) {
 	 *
 	 * @param name
 	 *            a remote name
+	 * @deprecated use {@link #setRemoteName} instead
 	 */
+	@Deprecated
 	public void setName(String name) {
-		this.name = name;
+		this.remoteName = name;
+	}
+
+	/**
+	 * The name of the remote to change the URL for.
+	 *
+	 * @param remoteName
+	 *            a remote remoteName
+	 * @return {@code this}
+	 * @since 5.3
+	 */
+	public RemoteSetUrlCommand setRemoteName(String remoteName) {
+		this.remoteName = remoteName;
+		return this;
 	}
 
 	/**
@@ -99,9 +131,24 @@ public void setName(String name) {
 	 *
 	 * @param uri
 	 *            an URL for the remote
+	 * @deprecated use {@link #setRemoteUri} instead
 	 */
+	@Deprecated
 	public void setUri(URIish uri) {
-		this.uri = uri;
+		this.remoteUri = uri;
+	}
+
+	/**
+	 * The new URL for the remote.
+	 *
+	 * @param remoteUri
+	 *            an URL for the remote
+	 * @return {@code this}
+	 * @since 5.3
+	 */
+	public RemoteSetUrlCommand setRemoteUri(URIish remoteUri) {
+		this.remoteUri = remoteUri;
+		return this;
 	}
 
 	/**
@@ -110,9 +157,28 @@ public void setUri(URIish uri) {
 	 * @param push
 	 *            <code>true</code> to set the push url, <code>false</code> to
 	 *            set the fetch url
+	 * @deprecated use {@link #setUriType} instead
 	 */
+	@Deprecated
 	public void setPush(boolean push) {
-		this.push = push;
+		if (push) {
+			setUriType(UriType.PUSH);
+		} else {
+			setUriType(UriType.FETCH);
+		}
+	}
+
+	/**
+	 * Whether to change the push URL of the remote instead of the fetch URL.
+	 *
+	 * @param type
+	 *            the <code>UriType</code> value to set
+	 * @return {@code this}
+	 * @since 5.3
+	 */
+	public RemoteSetUrlCommand setUriType(UriType type) {
+		this.type = type;
+		return this;
 	}
 
 	/**
@@ -127,8 +193,8 @@ public RemoteConfig call() throws GitAPIException {
 
 		try {
 			StoredConfig config = repo.getConfig();
-			RemoteConfig remote = new RemoteConfig(config, name);
-			if (push) {
+			RemoteConfig remote = new RemoteConfig(config, remoteName);
+			if (type == UriType.PUSH) {
 				List<URIish> uris = remote.getPushURIs();
 				if (uris.size() > 1) {
 					throw new JGitInternalException(
@@ -136,7 +202,7 @@ public RemoteConfig call() throws GitAPIException {
 				} else if (uris.size() == 1) {
 					remote.removePushURI(uris.get(0));
 				}
-				remote.addPushURI(uri);
+				remote.addPushURI(remoteUri);
 			} else {
 				List<URIish> uris = remote.getURIs();
 				if (uris.size() > 1) {
@@ -145,7 +211,7 @@ public RemoteConfig call() throws GitAPIException {
 				} else if (uris.size() == 1) {
 					remote.removeURI(uris.get(0));
 				}
-				remote.addURI(uri);
+				remote.addURI(remoteUri);
 			}
 
 			remote.update(config);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/StashApplyCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/StashApplyCommand.java
index 01d070c..2136e51 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/StashApplyCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/StashApplyCommand.java
@@ -96,9 +96,9 @@ public class StashApplyCommand extends GitCommand<ObjectId> {
 
 	private String stashRef;
 
-	private boolean applyIndex = true;
+	private boolean restoreIndex = true;
 
-	private boolean applyUntracked = true;
+	private boolean restoreUntracked = true;
 
 	private boolean ignoreRepositoryState;
 
@@ -196,7 +196,7 @@ public ObjectId call() throws GitAPIException,
 					.getParent(1));
 			ObjectId stashHeadCommit = stashCommit.getParent(0);
 			ObjectId untrackedCommit = null;
-			if (applyUntracked && stashCommit.getParentCount() == 3)
+			if (restoreUntracked && stashCommit.getParentCount() == 3)
 				untrackedCommit = revWalk.parseCommit(stashCommit.getParent(2));
 
 			ResolveMerger merger = (ResolveMerger) strategy.newMerger(repo);
@@ -216,7 +216,7 @@ public ObjectId call() throws GitAPIException,
 						dc, merger.getResultTreeId());
 				dco.setFailOnConflict(true);
 				dco.checkout(); // Ignoring failed deletes....
-				if (applyIndex) {
+				if (restoreIndex) {
 					ResolveMerger ixMerger = (ResolveMerger) strategy
 							.newMerger(repo, true);
 					ixMerger.setCommitNames(new String[] { "stashed HEAD", //$NON-NLS-1$
@@ -277,9 +277,24 @@ public ObjectId call() throws GitAPIException,
 	 *
 	 * @param applyIndex
 	 *            true (default) if the command should restore the index state
+	 * @deprecated use {@link #setRestoreIndex} instead
 	 */
+	@Deprecated
 	public void setApplyIndex(boolean applyIndex) {
-		this.applyIndex = applyIndex;
+		this.restoreIndex = applyIndex;
+	}
+
+	/**
+	 * Whether to restore the index state
+	 *
+	 * @param restoreIndex
+	 *            true (default) if the command should restore the index state
+	 * @return {@code this}
+	 * @since 5.3
+	 */
+	public StashApplyCommand setRestoreIndex(boolean restoreIndex) {
+		this.restoreIndex = restoreIndex;
+		return this;
 	}
 
 	/**
@@ -302,9 +317,24 @@ public StashApplyCommand setStrategy(MergeStrategy strategy) {
 	 * @param applyUntracked
 	 *            true (default) if the command should restore untracked files
 	 * @since 3.4
+	 * @deprecated use {@link #setRestoreUntracked} instead
 	 */
+	@Deprecated
 	public void setApplyUntracked(boolean applyUntracked) {
-		this.applyUntracked = applyUntracked;
+		this.restoreUntracked = applyUntracked;
+	}
+
+	/**
+	 * Whether the command should restore untracked files
+	 *
+	 * @param restoreUntracked
+	 *            true (default) if the command should restore untracked files
+	 * @return {@code this}
+	 * @since 5.3
+	 */
+	public StashApplyCommand setRestoreUntracked(boolean restoreUntracked) {
+		this.restoreUntracked = restoreUntracked;
+		return this;
 	}
 
 	private void resetIndex(RevTree tree) throws IOException {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/JGitInternalException.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/JGitInternalException.java
index 57d8a13..c723da3 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/JGitInternalException.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/JGitInternalException.java
@@ -44,7 +44,7 @@
  * <p>
  * During command execution a lot of exceptions may be thrown. Some of them
  * represent error situations which can be handled specifically by the caller of
- * the command. But a lot of exceptions are so low-level that is is unlikely
+ * the command. But a lot of exceptions are so low-level that it is unlikely
  * that the caller of the command can handle them effectively. The huge number
  * of these low-level exceptions which are thrown by the commands lead to a
  * complicated and wide interface of the commands. Callers of the API have to
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/diff/SequenceComparator.java b/org.eclipse.jgit/src/org/eclipse/jgit/diff/SequenceComparator.java
index ccd0055..3bc95a2 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/diff/SequenceComparator.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/diff/SequenceComparator.java
@@ -84,7 +84,7 @@ public abstract class SequenceComparator<S extends Sequence> {
 	 * method must produce the same integer result for both items.
 	 *
 	 * It is not required for two items to have different hash values if they
-	 * are are unequal according to the {@code equals()} method.
+	 * are unequal according to the {@code equals()} method.
 	 *
 	 * @param seq
 	 *            the sequence.
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/diff/SimilarityIndex.java b/org.eclipse.jgit/src/org/eclipse/jgit/diff/SimilarityIndex.java
index 5897ffb..539f237 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/diff/SimilarityIndex.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/diff/SimilarityIndex.java
@@ -236,7 +236,7 @@ void sort() {
 	 * A region of a file is defined as a line in a text file or a fixed-size
 	 * block in a binary file. To prepare an index, each region in the file is
 	 * hashed; the values and counts of hashes are retained in a sorted table.
-	 * Define the similarity fraction F as the the count of matching regions
+	 * Define the similarity fraction F as the count of matching regions
 	 * between the two files divided between the maximum count of regions in
 	 * either file. The similarity score is F multiplied by the maxScore
 	 * constant, yielding a range [0, maxScore]. It is defined as maxScore for
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java
index db6073f..307fd3f 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java
@@ -155,9 +155,11 @@ public CheckoutMetadata(EolStreamType eolStreamType,
 
 	private boolean failOnConflict = true;
 
+	private boolean force = false;
+
 	private ArrayList<String> toBeDeleted = new ArrayList<>();
 
-	private boolean emptyDirCache;
+	private boolean initialCheckout;
 
 	private boolean performingCheckout;
 
@@ -230,7 +232,7 @@ public DirCacheCheckout(Repository repo, ObjectId headCommitTree, DirCache dc,
 		this.headCommitTree = headCommitTree;
 		this.mergeCommitTree = mergeCommitTree;
 		this.workingTree = workingTree;
-		this.emptyDirCache = (dc == null) || (dc.getEntryCount() == 0);
+		this.initialCheckout = !repo.isBare() && !repo.getIndexFile().exists();
 	}
 
 	/**
@@ -427,11 +429,11 @@ void processEntry(CanonicalTreeParser m, DirCacheBuildIterator i,
 					DirCacheEntry entry = i.getDirCacheEntry();
 					if (entry.getLastModified() == 0)
 						entry.setLastModified(f.getEntryLastModified());
-					keep(entry);
+					keep(entry, f);
 				}
 			} else
 				// The index contains a folder
-				keep(i.getDirCacheEntry());
+				keep(i.getDirCacheEntry(), f);
 		} else {
 			// There is no entry in the merge commit. Means: we want to delete
 			// what's currently in the index and working tree
@@ -821,14 +823,14 @@ void processEntry(CanonicalTreeParser h, CanonicalTreeParser m,
 
 				break;
 			case 0xDFD: // 3 4
-				keep(dce);
+				keep(dce, f);
 				break;
 			case 0xF0D: // 18
 				remove(name);
 				break;
 			case 0xDFF: // 5 5b 6 6b
 				if (equalIdAndMode(iId, iMode, mId, mMode))
-					keep(dce); // 5 6
+					keep(dce, f); // 5 6
 				else
 					conflict(name, dce, h, m); // 5b 6b
 				break;
@@ -858,7 +860,7 @@ void processEntry(CanonicalTreeParser h, CanonicalTreeParser m,
 					conflict(name, dce, h, m); // 9
 				break;
 			case 0xFD0: // keep without a rule
-				keep(dce);
+				keep(dce, f);
 				break;
 			case 0xFFD: // 12 13 14
 				if (equalIdAndMode(hId, hMode, iId, iMode))
@@ -878,7 +880,7 @@ void processEntry(CanonicalTreeParser h, CanonicalTreeParser m,
 					conflict(name, dce, h, m);
 				break;
 			default:
-				keep(dce);
+				keep(dce, f);
 			}
 			return;
 		}
@@ -961,10 +963,10 @@ else if (m == null)
 				// called before). Ignore the cached deletion and use what we
 				// find in Merge. Potentially updates the file.
 				if (equalIdAndMode(hId, hMode, mId, mMode)) {
-					if (emptyDirCache)
+					if (initialCheckout)
 						update(name, mId, mMode);
 					else
-						keep(dce);
+						keep(dce, f);
 				} else
 					conflict(name, dce, h, m);
 			}
@@ -1027,7 +1029,7 @@ else if (m == null)
 						// Nothing in Head
 						// Something in Index
 						// -> Merge contains nothing new. Keep the index.
-						keep(dce);
+						keep(dce, f);
 				} else
 					// Merge contains something and it is not the same as Index
 					// Nothing in Head
@@ -1176,7 +1178,7 @@ && isModified_IndexTree(name, iId, iMode, mId, mMode,
 					// to the other one.
 					// -> In all three cases we don't touch index and file.
 
-					keep(dce);
+					keep(dce, f);
 				}
 			}
 		}
@@ -1225,9 +1227,15 @@ private void conflict(String path, DirCacheEntry e, AbstractTreeIterator h, Abst
 		}
 	}
 
-	private void keep(DirCacheEntry e) {
+	private void keep(DirCacheEntry e, WorkingTreeIterator f)
+			throws IOException {
 		if (e != null && !FileMode.TREE.equals(e.getFileMode()))
 			builder.add(e);
+		if (force) {
+			if (f.isModified(e, true, this.walk.getObjectReader())) {
+				checkoutEntry(repo, e, this.walk.getObjectReader());
+			}
+		}
 	}
 
 	private void remove(String path) {
@@ -1262,6 +1270,20 @@ public void setFailOnConflict(boolean failOnConflict) {
 	}
 
 	/**
+	 * If <code>true</code>, dirty worktree files may be overridden. If
+	 * <code>false</code> dirty worktree files will not be overridden in order
+	 * not to delete unsaved content. This corresponds to native git's 'git
+	 * checkout -f' option. By default this option is set to false.
+	 *
+	 * @param force
+	 *            a boolean.
+	 * @since 5.3
+	 */
+	public void setForce(boolean force) {
+		this.force = force;
+	}
+
+	/**
 	 * This method implements how to handle conflicts when
 	 * {@link #failOnConflict} is false
 	 *
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoCommand.java
index e9d86df..cb62925 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoCommand.java
@@ -147,7 +147,7 @@ public interface RemoteReader {
 		 *            The URI of the remote repository
 		 * @param ref
 		 *            Name of the ref to lookup. May be a short-hand form, e.g.
-		 *            "master" which is is automatically expanded to
+		 *            "master" which is automatically expanded to
 		 *            "refs/heads/master" if "refs/heads/master" already exists.
 		 * @return the sha1 of the remote repository, or null if the ref does
 		 *         not exist.
@@ -187,7 +187,7 @@ public interface RemoteReader {
 		 *            The URI of the remote repository
 		 * @param ref
 		 *            Name of the ref to lookup. May be a short-hand form, e.g.
-		 *            "master" which is is automatically expanded to
+		 *            "master" which is automatically expanded to
 		 *            "refs/heads/master" if "refs/heads/master" already exists.
 		 * @param path
 		 *            The relative path (inside the repo) to the file to read
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/BlockBasedFile.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/BlockBasedFile.java
index b9758bd..4d14742 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/BlockBasedFile.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/BlockBasedFile.java
@@ -48,7 +48,6 @@
 import java.nio.ByteBuffer;
 import java.text.MessageFormat;
 
-import org.eclipse.jgit.annotations.Nullable;
 import org.eclipse.jgit.errors.PackInvalidException;
 import org.eclipse.jgit.internal.storage.pack.PackExt;
 
@@ -130,18 +129,18 @@ else if (size < cache.getBlockSize())
 	}
 
 	DfsBlock getOrLoadBlock(long pos, DfsReader ctx) throws IOException {
-		return cache.getOrLoad(this, pos, ctx, null);
+		try (LazyChannel c = new LazyChannel(ctx, desc, ext)) {
+			return cache.getOrLoad(this, pos, ctx, c);
+		}
 	}
 
-	DfsBlock readOneBlock(long pos, DfsReader ctx,
-			@Nullable ReadableChannel fileChannel) throws IOException {
+	DfsBlock readOneBlock(long pos, DfsReader ctx, ReadableChannel rc)
+			throws IOException {
 		if (invalid)
 			throw new PackInvalidException(getFileName());
 
 		ctx.stats.readBlock++;
 		long start = System.nanoTime();
-		ReadableChannel rc = fileChannel != null ? fileChannel
-				: ctx.db.openFile(desc, ext);
 		try {
 			int size = blockSize(rc);
 			pos = (pos / size) * size;
@@ -189,9 +188,6 @@ DfsBlock readOneBlock(long pos, DfsReader ctx,
 
 			return new DfsBlock(key, pos, buf);
 		} finally {
-			if (rc != fileChannel) {
-				rc.close();
-			}
 			ctx.stats.readBlockMicros += elapsedMicros(start);
 		}
 	}
@@ -207,4 +203,41 @@ static int read(ReadableChannel rc, ByteBuffer buf) throws IOException {
 	static long elapsedMicros(long start) {
 		return (System.nanoTime() - start) / 1000L;
 	}
+
+	/**
+	 * A supplier of readable channel that opens the channel lazily.
+	 */
+	private static class LazyChannel
+			implements AutoCloseable, DfsBlockCache.ReadableChannelSupplier {
+		private final DfsReader ctx;
+		private final DfsPackDescription desc;
+		private final PackExt ext;
+
+		private ReadableChannel rc = null;
+
+		LazyChannel(DfsReader ctx, DfsPackDescription desc, PackExt ext) {
+			this.ctx = ctx;
+			this.desc = desc;
+			this.ext = ext;
+		}
+
+		@Override
+		public ReadableChannel get() throws IOException {
+			if (rc == null) {
+				synchronized (this) {
+					if (rc == null) {
+						rc = ctx.db.openFile(desc, ext);
+					}
+				}
+			}
+			return rc;
+		}
+
+		@Override
+		public void close() throws IOException {
+			if (rc != null) {
+				rc.close();
+			}
+		}
+	}
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsBlockCache.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsBlockCache.java
index 4687952..c6e2fae 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsBlockCache.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsBlockCache.java
@@ -49,9 +49,9 @@
 import java.util.concurrent.atomic.AtomicReference;
 import java.util.concurrent.atomic.AtomicReferenceArray;
 import java.util.concurrent.locks.ReentrantLock;
+import java.util.function.Consumer;
 import java.util.stream.LongStream;
 
-import org.eclipse.jgit.annotations.Nullable;
 import org.eclipse.jgit.internal.JGitText;
 import org.eclipse.jgit.internal.storage.pack.PackExt;
 
@@ -128,9 +128,18 @@ public static DfsBlockCache getInstance() {
 	/** Hash bucket directory; entries are chained below. */
 	private final AtomicReferenceArray<HashEntry> table;
 
-	/** Locks to prevent concurrent loads for same (PackFile,position). */
+	/**
+	 * Locks to prevent concurrent loads for same (PackFile,position) block. The
+	 * number of locks is {@link DfsBlockCacheConfig#getConcurrencyLevel()} to
+	 * cap the overall concurrent block loads.
+	 */
 	private final ReentrantLock[] loadLocks;
 
+	/**
+	 * A separate pool of locks to prevent concurrent loads for same index or bitmap from PackFile.
+	 */
+	private final ReentrantLock[] refLocks;
+
 	/** Maximum number of bytes the cache should hold. */
 	private final long maxBytes;
 
@@ -177,19 +186,30 @@ public static DfsBlockCache getInstance() {
 	/** Protects the clock and its related data. */
 	private final ReentrantLock clockLock;
 
+	/**
+	 * A consumer of object reference lock wait time milliseconds.  May be used to build a metric.
+	 */
+	private final Consumer<Long> refLockWaitTime;
+
 	/** Current position of the clock. */
 	private Ref clockHand;
 
 	@SuppressWarnings("unchecked")
 	private DfsBlockCache(DfsBlockCacheConfig cfg) {
 		tableSize = tableSize(cfg);
-		if (tableSize < 1)
+		if (tableSize < 1) {
 			throw new IllegalArgumentException(JGitText.get().tSizeMustBeGreaterOrEqual1);
+		}
 
 		table = new AtomicReferenceArray<>(tableSize);
 		loadLocks = new ReentrantLock[cfg.getConcurrencyLevel()];
-		for (int i = 0; i < loadLocks.length; i++)
+		for (int i = 0; i < loadLocks.length; i++) {
 			loadLocks[i] = new ReentrantLock(true /* fair */);
+		}
+		refLocks = new ReentrantLock[cfg.getConcurrencyLevel()];
+		for (int i = 0; i < refLocks.length; i++) {
+			refLocks[i] = new ReentrantLock(true /* fair */);
+		}
 
 		maxBytes = cfg.getBlockLimit();
 		maxStreamThroughCache = (long) (maxBytes * cfg.getStreamRatio());
@@ -207,6 +227,8 @@ private DfsBlockCache(DfsBlockCacheConfig cfg) {
 		statMiss = new AtomicReference<>(newCounters());
 		statEvict = new AtomicReference<>(newCounters());
 		liveBytes = new AtomicReference<>(newCounters());
+
+		refLockWaitTime = cfg.getRefLockWaitTimeConsumer();
 	}
 
 	boolean shouldCopyThroughCache(long length) {
@@ -333,15 +355,17 @@ int getBlockSize() {
 	private static int tableSize(DfsBlockCacheConfig cfg) {
 		final int wsz = cfg.getBlockSize();
 		final long limit = cfg.getBlockLimit();
-		if (wsz <= 0)
+		if (wsz <= 0) {
 			throw new IllegalArgumentException(JGitText.get().invalidWindowSize);
-		if (limit < wsz)
+		}
+		if (limit < wsz) {
 			throw new IllegalArgumentException(JGitText.get().windowSizeMustBeLesserThanLimit);
+		}
 		return (int) Math.min(5 * (limit / wsz) / 2, Integer.MAX_VALUE);
 	}
 
 	/**
-	 * Lookup a cached object, creating and loading it if it doesn't exist.
+	 * Look up a cached object, creating and loading it if it doesn't exist.
 	 *
 	 * @param file
 	 *            the pack that "contains" the cached object.
@@ -350,13 +374,13 @@ private static int tableSize(DfsBlockCacheConfig cfg) {
 	 * @param ctx
 	 *            current thread's reader.
 	 * @param fileChannel
-	 *            optional channel to read {@code pack}.
+	 *            supplier for channel to read {@code pack}.
 	 * @return the object reference.
 	 * @throws IOException
 	 *             the reference was not in the cache and could not be loaded.
 	 */
 	DfsBlock getOrLoad(BlockBasedFile file, long position, DfsReader ctx,
-			@Nullable ReadableChannel fileChannel) throws IOException {
+			ReadableChannelSupplier fileChannel) throws IOException {
 		final long requestedPosition = position;
 		position = file.alignToBlock(position);
 
@@ -388,11 +412,13 @@ DfsBlock getOrLoad(BlockBasedFile file, long position, DfsReader ctx,
 			getStat(statMiss, key).incrementAndGet();
 			boolean credit = true;
 			try {
-				v = file.readOneBlock(requestedPosition, ctx, fileChannel);
+				v = file.readOneBlock(requestedPosition, ctx,
+						fileChannel.get());
 				credit = false;
 			} finally {
-				if (credit)
+				if (credit) {
 					creditSpace(blockSize, key);
+				}
 			}
 			if (position != v.start) {
 				// The file discovered its blockSize and adjusted.
@@ -405,8 +431,9 @@ DfsBlock getOrLoad(BlockBasedFile file, long position, DfsReader ctx,
 			ref.hot = true;
 			for (;;) {
 				HashEntry n = new HashEntry(clean(e2), ref);
-				if (table.compareAndSet(slot, e2, n))
+				if (table.compareAndSet(slot, e2, n)) {
 					break;
+				}
 				e2 = table.get(slot);
 			}
 			addToClock(ref, blockSize - v.size());
@@ -416,8 +443,9 @@ DfsBlock getOrLoad(BlockBasedFile file, long position, DfsReader ctx,
 
 		// If the block size changed from the default, it is possible the block
 		// that was loaded is the wrong block for the requested position.
-		if (v.contains(file.key, requestedPosition))
+		if (v.contains(file.key, requestedPosition)) {
 			return v;
+		}
 		return getOrLoad(file, requestedPosition, ctx, fileChannel);
 	}
 
@@ -488,6 +516,63 @@ void put(DfsBlock v) {
 		put(v.stream, v.start, v.size(), v);
 	}
 
+	/**
+	 * Look up a cached object, creating and loading it if it doesn't exist.
+	 *
+	 * @param key
+	 *            the stream key of the pack.
+	 * @param loader
+	 *            the function to load the reference.
+	 * @return the object reference.
+	 * @throws IOException
+	 *             the reference was not in the cache and could not be loaded.
+	 */
+	<T> Ref<T> getOrLoadRef(DfsStreamKey key, RefLoader<T> loader)
+			throws IOException {
+		int slot = slot(key, 0);
+		HashEntry e1 = table.get(slot);
+		Ref<T> ref = scanRef(e1, key, 0);
+		if (ref != null) {
+			getStat(statHit, key).incrementAndGet();
+			return ref;
+		}
+
+		ReentrantLock regionLock = lockForRef(key);
+		long lockStart = System.currentTimeMillis();
+		regionLock.lock();
+		try {
+			HashEntry e2 = table.get(slot);
+			if (e2 != e1) {
+				ref = scanRef(e2, key, 0);
+				if (ref != null) {
+					getStat(statHit, key).incrementAndGet();
+					return ref;
+				}
+			}
+
+			if (refLockWaitTime != null) {
+				refLockWaitTime.accept(
+						Long.valueOf(System.currentTimeMillis() - lockStart));
+			}
+			getStat(statMiss, key).incrementAndGet();
+			ref = loader.load();
+			ref.hot = true;
+			// Reserve after loading to get the size of the object
+			reserveSpace(ref.size, key);
+			for (;;) {
+				HashEntry n = new HashEntry(clean(e2), ref);
+				if (table.compareAndSet(slot, e2, n)) {
+					break;
+				}
+				e2 = table.get(slot);
+			}
+			addToClock(ref, 0);
+		} finally {
+			regionLock.unlock();
+		}
+		return ref;
+	}
+
 	<T> Ref<T> putRef(DfsStreamKey key, long size, T v) {
 		return put(key, 0, (int) Math.min(size, Integer.MAX_VALUE), v);
 	}
@@ -496,8 +581,9 @@ <T> Ref<T> put(DfsStreamKey key, long pos, int size, T v) {
 		int slot = slot(key, pos);
 		HashEntry e1 = table.get(slot);
 		Ref<T> ref = scanRef(e1, key, pos);
-		if (ref != null)
+		if (ref != null) {
 			return ref;
+		}
 
 		reserveSpace(size, key);
 		ReentrantLock regionLock = lockFor(key, pos);
@@ -516,8 +602,9 @@ <T> Ref<T> put(DfsStreamKey key, long pos, int size, T v) {
 			ref.hot = true;
 			for (;;) {
 				HashEntry n = new HashEntry(clean(e2), ref);
-				if (table.compareAndSet(slot, e2, n))
+				if (table.compareAndSet(slot, e2, n)) {
 					break;
+				}
 				e2 = table.get(slot);
 			}
 			addToClock(ref, 0);
@@ -534,10 +621,11 @@ boolean contains(DfsStreamKey key, long position) {
 	@SuppressWarnings("unchecked")
 	<T> T get(DfsStreamKey key, long position) {
 		T val = (T) scan(table.get(slot(key, position)), key, position);
-		if (val == null)
+		if (val == null) {
 			getStat(statMiss, key).incrementAndGet();
-		else
+		} else {
 			getStat(statHit, key).incrementAndGet();
+		}
 		return val;
 	}
 
@@ -546,21 +634,13 @@ private <T> T scan(HashEntry n, DfsStreamKey key, long position) {
 		return r != null ? r.get() : null;
 	}
 
-	<T> Ref<T> getRef(DfsStreamKey key) {
-		Ref<T> r = scanRef(table.get(slot(key, 0)), key, 0);
-		if (r != null)
-			getStat(statHit, key).incrementAndGet();
-		else
-			getStat(statMiss, key).incrementAndGet();
-		return r;
-	}
-
 	@SuppressWarnings("unchecked")
 	private <T> Ref<T> scanRef(HashEntry n, DfsStreamKey key, long position) {
 		for (; n != null; n = n.next) {
 			Ref<T> r = n.ref;
-			if (r.position == position && r.key.equals(key))
+			if (r.position == position && r.key.equals(key)) {
 				return r.get() != null ? r : null;
+			}
 		}
 		return null;
 	}
@@ -573,6 +653,10 @@ private ReentrantLock lockFor(DfsStreamKey key, long position) {
 		return loadLocks[(hash(key.hash, position) >>> 1) % loadLocks.length];
 	}
 
+	private ReentrantLock lockForRef(DfsStreamKey key) {
+		return refLocks[(key.hash >>> 1) % refLocks.length];
+	}
+
 	private static AtomicLong[] newCounters() {
 		AtomicLong[] ret = new AtomicLong[PackExt.values().length];
 		for (int i = 0; i < ret.length; i++) {
@@ -613,8 +697,9 @@ private static AtomicLong getStat(AtomicReference<AtomicLong[]> stats,
 	private static HashEntry clean(HashEntry top) {
 		while (top != null && top.ref.next == null)
 			top = top.next;
-		if (top == null)
+		if (top == null) {
 			return null;
+		}
 		HashEntry n = clean(top.next);
 		return n == top.next ? top : new HashEntry(n, top.ref);
 	}
@@ -649,8 +734,9 @@ static final class Ref<T> {
 
 		T get() {
 			T v = value;
-			if (v != null)
+			if (v != null) {
 				hot = true;
+			}
 			return v;
 		}
 
@@ -658,4 +744,21 @@ boolean has() {
 			return value != null;
 		}
 	}
+
+	@FunctionalInterface
+	interface RefLoader<T> {
+		Ref<T> load() throws IOException;
+	}
+
+	/**
+	 * Supplier for readable channel
+	 */
+	@FunctionalInterface
+	interface ReadableChannelSupplier {
+		/**
+		 * @return ReadableChannel
+		 * @throws IOException
+		 */
+		ReadableChannel get() throws IOException;
+	}
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsBlockCacheConfig.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsBlockCacheConfig.java
index dd7cb89..cd1fa5f 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsBlockCacheConfig.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsBlockCacheConfig.java
@@ -51,6 +51,7 @@
 import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_STREAM_RATIO;
 
 import java.text.MessageFormat;
+import java.util.function.Consumer;
 
 import org.eclipse.jgit.internal.JGitText;
 import org.eclipse.jgit.lib.Config;
@@ -71,6 +72,8 @@ public class DfsBlockCacheConfig {
 	private double streamRatio;
 	private int concurrencyLevel;
 
+	private Consumer<Long> refLock;
+
 	/**
 	 * Create a default configuration.
 	 */
@@ -194,6 +197,27 @@ public DfsBlockCacheConfig setStreamRatio(double ratio) {
 	}
 
 	/**
+	 * Get the consumer of the object reference lock wait time in milliseconds.
+	 *
+	 * @return consumer of wait time in milliseconds.
+	 */
+	public Consumer<Long> getRefLockWaitTimeConsumer() {
+		return refLock;
+	}
+
+	/**
+	 * Set the consumer for lock wait time.
+	 *
+	 * @param c
+	 *            consumer of wait time in milliseconds.
+	 * @return {@code this}
+	 */
+	public DfsBlockCacheConfig setRefLockWaitTimeConsumer(Consumer<Long> c) {
+		refLock = c;
+		return this;
+	}
+
+	/**
 	 * Update properties by setting fields from the configuration.
 	 * <p>
 	 * If a property is not defined in the configuration, then it is left
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackFile.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackFile.java
index 05b8f61..7d891b5 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackFile.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackFile.java
@@ -88,6 +88,8 @@
  * objects are similar.
  */
 public final class DfsPackFile extends BlockBasedFile {
+	private static final int REC_SIZE = Constants.OBJECT_ID_LENGTH + 8;
+
 	/**
 	 * Lock for initialization of {@link #index} and {@link #corruptObjects}.
 	 * <p>
@@ -177,12 +179,14 @@ private PackIndex idx(DfsReader ctx) throws IOException {
 		DfsBlockCache.Ref<PackIndex> idxref = index;
 		if (idxref != null) {
 			PackIndex idx = idxref.get();
-			if (idx != null)
+			if (idx != null) {
 				return idx;
+			}
 		}
 
-		if (invalid)
+		if (invalid) {
 			throw new PackInvalidException(getFileName());
+		}
 
 		Repository.getGlobalListenerList()
 				.dispatch(new BeforeDfsPackIndexLoadedEvent(this));
@@ -191,50 +195,55 @@ private PackIndex idx(DfsReader ctx) throws IOException {
 			idxref = index;
 			if (idxref != null) {
 				PackIndex idx = idxref.get();
-				if (idx != null)
+				if (idx != null) {
 					return idx;
+				}
 			}
 
 			DfsStreamKey idxKey = desc.getStreamKey(INDEX);
-			idxref = cache.getRef(idxKey);
-			if (idxref != null) {
-				PackIndex idx = idxref.get();
-				if (idx != null) {
-					index = idxref;
-					return idx;
-				}
-			}
-
-			PackIndex idx;
 			try {
-				ctx.stats.readIdx++;
-				long start = System.nanoTime();
-				try (ReadableChannel rc = ctx.db.openFile(desc, INDEX)) {
-					InputStream in = Channels.newInputStream(rc);
-					int wantSize = 8192;
-					int bs = rc.blockSize();
-					if (0 < bs && bs < wantSize)
-						bs = (wantSize / bs) * bs;
-					else if (bs <= 0)
-						bs = wantSize;
-					idx = PackIndex.read(new BufferedInputStream(in, bs));
-					ctx.stats.readIdxBytes += rc.position();
-				} finally {
-					ctx.stats.readIdxMicros += elapsedMicros(start);
-				}
-			} catch (EOFException e) {
-				invalid = true;
-				throw new IOException(MessageFormat.format(
-						DfsText.get().shortReadOfIndex,
-						desc.getFileName(INDEX)), e);
+				idxref = cache.getOrLoadRef(idxKey, () -> {
+					try {
+						ctx.stats.readIdx++;
+						long start = System.nanoTime();
+						try (ReadableChannel rc = ctx.db.openFile(desc,
+								INDEX)) {
+							InputStream in = Channels.newInputStream(rc);
+							int wantSize = 8192;
+							int bs = rc.blockSize();
+							if (0 < bs && bs < wantSize) {
+								bs = (wantSize / bs) * bs;
+							} else if (bs <= 0) {
+								bs = wantSize;
+							}
+							PackIndex idx = PackIndex
+									.read(new BufferedInputStream(in, bs));
+							int sz = (int) Math.min(
+									idx.getObjectCount() * REC_SIZE,
+									Integer.MAX_VALUE);
+							ctx.stats.readIdxBytes += rc.position();
+							return new DfsBlockCache.Ref<>(idxKey, 0, sz, idx);
+						} finally {
+							ctx.stats.readIdxMicros += elapsedMicros(start);
+						}
+					} catch (EOFException e) {
+						throw new IOException(MessageFormat.format(
+								DfsText.get().shortReadOfIndex,
+								desc.getFileName(INDEX)), e);
+					} catch (IOException e) {
+						throw new IOException(MessageFormat.format(
+								DfsText.get().cannotReadIndex,
+								desc.getFileName(INDEX)), e);
+					}
+				});
 			} catch (IOException e) {
 				invalid = true;
-				throw new IOException(MessageFormat.format(
-						DfsText.get().cannotReadIndex,
-						desc.getFileName(INDEX)), e);
+				throw e;
 			}
-
-			setPackIndex(idx);
+			PackIndex idx = idxref.get();
+			if (idx != null) {
+				index = idxref;
+			}
 			return idx;
 		}
 	}
@@ -244,67 +253,71 @@ final boolean isGarbage() {
 	}
 
 	PackBitmapIndex getBitmapIndex(DfsReader ctx) throws IOException {
-		if (invalid || isGarbage() || !desc.hasFileExt(BITMAP_INDEX))
+		if (invalid || isGarbage() || !desc.hasFileExt(BITMAP_INDEX)) {
 			return null;
+		}
 
 		DfsBlockCache.Ref<PackBitmapIndex> idxref = bitmapIndex;
 		if (idxref != null) {
-			PackBitmapIndex idx = idxref.get();
-			if (idx != null)
-				return idx;
+			PackBitmapIndex bmidx = idxref.get();
+			if (bmidx != null) {
+				return bmidx;
+			}
 		}
 
 		synchronized (initLock) {
 			idxref = bitmapIndex;
 			if (idxref != null) {
-				PackBitmapIndex idx = idxref.get();
-				if (idx != null)
-					return idx;
+				PackBitmapIndex bmidx = idxref.get();
+				if (bmidx != null) {
+					return bmidx;
+				}
 			}
 
+			PackIndex idx = idx(ctx);
+			PackReverseIndex revidx = getReverseIdx(ctx);
 			DfsStreamKey bitmapKey = desc.getStreamKey(BITMAP_INDEX);
-			idxref = cache.getRef(bitmapKey);
-			if (idxref != null) {
-				PackBitmapIndex idx = idxref.get();
-				if (idx != null) {
-					bitmapIndex = idxref;
-					return idx;
+			idxref = cache.getOrLoadRef(bitmapKey, () -> {
+				ctx.stats.readBitmap++;
+				long start = System.nanoTime();
+				try (ReadableChannel rc = ctx.db.openFile(desc, BITMAP_INDEX)) {
+					long size;
+					PackBitmapIndex bmidx;
+					try {
+						InputStream in = Channels.newInputStream(rc);
+						int wantSize = 8192;
+						int bs = rc.blockSize();
+						if (0 < bs && bs < wantSize) {
+							bs = (wantSize / bs) * bs;
+						} else if (bs <= 0) {
+							bs = wantSize;
+						}
+						in = new BufferedInputStream(in, bs);
+						bmidx = PackBitmapIndex.read(in, idx, revidx);
+					} finally {
+						size = rc.position();
+						ctx.stats.readIdxBytes += size;
+						ctx.stats.readIdxMicros += elapsedMicros(start);
+					}
+					int sz = (int) Math.min(size, Integer.MAX_VALUE);
+					return new DfsBlockCache.Ref<>(bitmapKey, 0, sz, bmidx);
+				} catch (EOFException e) {
+					throw new IOException(
+							MessageFormat.format(DfsText.get().shortReadOfIndex,
+									desc.getFileName(BITMAP_INDEX)),
+							e);
+				} catch (IOException e) {
+					throw new IOException(
+							MessageFormat.format(DfsText.get().cannotReadIndex,
+									desc.getFileName(BITMAP_INDEX)),
+							e);
 				}
+			});
+			PackBitmapIndex bmidx = idxref.get();
+			if (bmidx != null) {
+				bitmapIndex = idxref;
 			}
-
-			long size;
-			PackBitmapIndex idx;
-			ctx.stats.readBitmap++;
-			long start = System.nanoTime();
-			try (ReadableChannel rc = ctx.db.openFile(desc, BITMAP_INDEX)) {
-				try {
-					InputStream in = Channels.newInputStream(rc);
-					int wantSize = 8192;
-					int bs = rc.blockSize();
-					if (0 < bs && bs < wantSize)
-						bs = (wantSize / bs) * bs;
-					else if (bs <= 0)
-						bs = wantSize;
-					in = new BufferedInputStream(in, bs);
-					idx = PackBitmapIndex.read(
-							in, idx(ctx), getReverseIdx(ctx));
-				} finally {
-					size = rc.position();
-					ctx.stats.readIdxBytes += size;
-					ctx.stats.readIdxMicros += elapsedMicros(start);
-				}
-			} catch (EOFException e) {
-				throw new IOException(MessageFormat.format(
-						DfsText.get().shortReadOfIndex,
-						desc.getFileName(BITMAP_INDEX)), e);
-			} catch (IOException e) {
-				throw new IOException(MessageFormat.format(
-						DfsText.get().cannotReadIndex,
-						desc.getFileName(BITMAP_INDEX)), e);
-			}
-
-			bitmapIndex = cache.putRef(bitmapKey, size, idx);
-			return idx;
+			return bmidx;
 		}
 	}
 
@@ -312,33 +325,33 @@ PackReverseIndex getReverseIdx(DfsReader ctx) throws IOException {
 		DfsBlockCache.Ref<PackReverseIndex> revref = reverseIndex;
 		if (revref != null) {
 			PackReverseIndex revidx = revref.get();
-			if (revidx != null)
+			if (revidx != null) {
 				return revidx;
+			}
 		}
 
 		synchronized (initLock) {
 			revref = reverseIndex;
 			if (revref != null) {
 				PackReverseIndex revidx = revref.get();
-				if (revidx != null)
+				if (revidx != null) {
 					return revidx;
-			}
-
-			DfsStreamKey revKey =
-					new DfsStreamKey.ForReverseIndex(desc.getStreamKey(INDEX));
-			revref = cache.getRef(revKey);
-			if (revref != null) {
-				PackReverseIndex idx = revref.get();
-				if (idx != null) {
-					reverseIndex = revref;
-					return idx;
 				}
 			}
 
 			PackIndex idx = idx(ctx);
-			PackReverseIndex revidx = new PackReverseIndex(idx);
-			long cnt = idx.getObjectCount();
-			reverseIndex = cache.putRef(revKey, cnt * 8, revidx);
+			DfsStreamKey revKey = new DfsStreamKey.ForReverseIndex(
+					desc.getStreamKey(INDEX));
+			revref = cache.getOrLoadRef(revKey, () -> {
+				PackReverseIndex revidx = new PackReverseIndex(idx);
+				int sz = (int) Math.min(idx.getObjectCount() * 8,
+						Integer.MAX_VALUE);
+				return new DfsBlockCache.Ref<>(revKey, 0, sz, revidx);
+			});
+			PackReverseIndex revidx = revref.get();
+			if (revidx != null) {
+				reverseIndex = revref;
+			}
 			return revidx;
 		}
 	}
@@ -417,110 +430,93 @@ long getObjectCount(DfsReader ctx) throws IOException {
 			return null;
 		}
 
-		if (ctx.inflate(this, position, dstbuf, false) != sz)
+		if (ctx.inflate(this, position, dstbuf, false) != sz) {
 			throw new EOFException(MessageFormat.format(
 					JGitText.get().shortCompressedStreamAt,
 					Long.valueOf(position)));
+		}
 		return dstbuf;
 	}
 
-	void copyPackAsIs(PackOutputStream out, DfsReader ctx)
-			throws IOException {
+	void copyPackAsIs(PackOutputStream out, DfsReader ctx) throws IOException {
 		// If the length hasn't been determined yet, pin to set it.
 		if (length == -1) {
 			ctx.pin(this, 0);
 			ctx.unpin();
 		}
-		if (cache.shouldCopyThroughCache(length))
-			copyPackThroughCache(out, ctx);
-		else
-			copyPackBypassCache(out, ctx);
+		try (ReadableChannel rc = ctx.db.openFile(desc, PACK)) {
+			int sz = ctx.getOptions().getStreamPackBufferSize();
+			if (sz > 0) {
+				rc.setReadAheadBytes(sz);
+			}
+			if (cache.shouldCopyThroughCache(length)) {
+				copyPackThroughCache(out, ctx, rc);
+			} else {
+				copyPackBypassCache(out, rc);
+			}
+		}
 	}
 
-	private void copyPackThroughCache(PackOutputStream out, DfsReader ctx)
-			throws IOException {
-		@SuppressWarnings("resource") // Explicitly closed in finally block
-		ReadableChannel rc = null;
-		try {
-			long position = 12;
-			long remaining = length - (12 + 20);
-			while (0 < remaining) {
-				DfsBlock b;
-				if (rc != null) {
-					b = cache.getOrLoad(this, position, ctx, rc);
-				} else {
-					b = cache.get(key, alignToBlock(position));
-					if (b == null) {
-						rc = ctx.db.openFile(desc, PACK);
-						int sz = ctx.getOptions().getStreamPackBufferSize();
-						if (sz > 0) {
-							rc.setReadAheadBytes(sz);
-						}
-						b = cache.getOrLoad(this, position, ctx, rc);
-					}
-				}
+	private void copyPackThroughCache(PackOutputStream out, DfsReader ctx,
+			ReadableChannel rc) throws IOException {
+		long position = 12;
+		long remaining = length - (12 + 20);
+		while (0 < remaining) {
+			DfsBlock b = cache.getOrLoad(this, position, ctx, () -> rc);
+			int ptr = (int) (position - b.start);
+			int n = (int) Math.min(b.size() - ptr, remaining);
+			b.write(out, position, n);
+			position += n;
+			remaining -= n;
+		}
+	}
 
+	private long copyPackBypassCache(PackOutputStream out, ReadableChannel rc)
+			throws IOException {
+		ByteBuffer buf = newCopyBuffer(out, rc);
+		long position = 12;
+		long remaining = length - (12 + 20);
+		boolean packHeadSkipped = false;
+		while (0 < remaining) {
+			DfsBlock b = cache.get(key, alignToBlock(position));
+			if (b != null) {
 				int ptr = (int) (position - b.start);
 				int n = (int) Math.min(b.size() - ptr, remaining);
 				b.write(out, position, n);
 				position += n;
 				remaining -= n;
+				rc.position(position);
+				packHeadSkipped = true;
+				continue;
 			}
-		} finally {
-			if (rc != null) {
-				rc.close();
+
+			buf.position(0);
+			int n = read(rc, buf);
+			if (n <= 0) {
+				throw packfileIsTruncated();
+			} else if (n > remaining) {
+				n = (int) remaining;
 			}
+
+			if (!packHeadSkipped) {
+				// Need skip the 'PACK' header for the first read
+				out.write(buf.array(), 12, n - 12);
+				packHeadSkipped = true;
+			} else {
+				out.write(buf.array(), 0, n);
+			}
+			position += n;
+			remaining -= n;
 		}
-	}
-
-	private long copyPackBypassCache(PackOutputStream out, DfsReader ctx)
-			throws IOException {
-		try (ReadableChannel rc = ctx.db.openFile(desc, PACK)) {
-			ByteBuffer buf = newCopyBuffer(out, rc);
-			if (ctx.getOptions().getStreamPackBufferSize() > 0)
-				rc.setReadAheadBytes(ctx.getOptions().getStreamPackBufferSize());
-			long position = 12;
-			long remaining = length - (12 + 20);
-			boolean packHeadSkipped = false;
-			while (0 < remaining) {
-				DfsBlock b = cache.get(key, alignToBlock(position));
-				if (b != null) {
-					int ptr = (int) (position - b.start);
-					int n = (int) Math.min(b.size() - ptr, remaining);
-					b.write(out, position, n);
-					position += n;
-					remaining -= n;
-					rc.position(position);
-					packHeadSkipped = true;
-					continue;
-				}
-
-				buf.position(0);
-				int n = read(rc, buf);
-				if (n <= 0)
-					throw packfileIsTruncated();
-				else if (n > remaining)
-					n = (int) remaining;
-
-				if (!packHeadSkipped) {
-					// Need skip the 'PACK' header for the first read
-					out.write(buf.array(), 12, n - 12);
-					packHeadSkipped = true;
-				} else {
-					out.write(buf.array(), 0, n);
-				}
-				position += n;
-				remaining -= n;
-			}
-			return position;
-		}
+		return position;
 	}
 
 	private ByteBuffer newCopyBuffer(PackOutputStream out, ReadableChannel rc) {
 		int bs = blockSize(rc);
 		byte[] copyBuf = out.getCopyBuffer();
-		if (bs > copyBuf.length)
+		if (bs > copyBuf.length) {
 			copyBuf = new byte[bs];
+		}
 		return ByteBuffer.wrap(copyBuf, 0, bs);
 	}
 
@@ -632,8 +628,9 @@ void copyAsIs(PackOutputStream out, DfsObjectToPack src,
 						readFully(pos, buf, 0, n, ctx);
 						crc1.update(buf, 0, n);
 						inf.setInput(buf, 0, n);
-						while (inf.inflate(tmp, 0, tmp.length) > 0)
+						while (inf.inflate(tmp, 0, tmp.length) > 0) {
 							continue;
+						}
 						pos += n;
 						cnt -= n;
 					}
@@ -765,8 +762,9 @@ ObjectLoader load(DfsReader ctx, long pos)
 
 					if (sz < ctx.getStreamFileThreshold()) {
 						data = decompress(pos + p, (int) sz, ctx);
-						if (data != null)
+						if (data != null) {
 							return new ObjectLoader.SmallObject(typeCode, data);
+						}
 					}
 					return new LargePackedWholeObject(typeCode, sz, pos, p, this, ctx.db);
 				}
@@ -782,8 +780,9 @@ ObjectLoader load(DfsReader ctx, long pos)
 					}
 					base = pos - base;
 					delta = new Delta(delta, pos, (int) sz, p, base);
-					if (sz != delta.deltaSize)
+					if (sz != delta.deltaSize) {
 						break SEARCH;
+					}
 
 					DeltaBaseCache.Entry e = ctx.getDeltaBaseCache().get(key, base);
 					if (e != null) {
@@ -800,8 +799,9 @@ ObjectLoader load(DfsReader ctx, long pos)
 					readFully(pos + p, ib, 0, 20, ctx);
 					long base = findDeltaBase(ctx, ObjectId.fromRaw(ib));
 					delta = new Delta(delta, pos, (int) sz, p + 20, base);
-					if (sz != delta.deltaSize)
+					if (sz != delta.deltaSize) {
 						break SEARCH;
+					}
 
 					DeltaBaseCache.Entry e = ctx.getDeltaBaseCache().get(key, base);
 					if (e != null) {
@@ -829,10 +829,11 @@ ObjectLoader load(DfsReader ctx, long pos)
 			assert(delta != null);
 			do {
 				// Cache only the base immediately before desired object.
-				if (cached)
+				if (cached) {
 					cached = false;
-				else if (delta.next == null)
+				} else if (delta.next == null) {
 					ctx.getDeltaBaseCache().put(key, delta.basePos, type, data);
+				}
 
 				pos = delta.deltaPos;
 
@@ -843,8 +844,9 @@ else if (delta.next == null)
 				}
 
 				final long sz = BinaryDelta.getResultSize(cmds);
-				if (Integer.MAX_VALUE <= sz)
+				if (Integer.MAX_VALUE <= sz) {
 					throw new LargeObjectException.ExceedsByteArrayLimit();
+				}
 
 				final byte[] result;
 				try {
@@ -874,9 +876,10 @@ else if (delta.next == null)
 	private long findDeltaBase(DfsReader ctx, ObjectId baseId)
 			throws IOException, MissingObjectException {
 		long ofs = idx(ctx).findOffset(baseId);
-		if (ofs < 0)
+		if (ofs < 0) {
 			throw new MissingObjectException(baseId,
 					JGitText.get().missingDeltaBase);
+		}
 		return ofs;
 	}
 
@@ -933,8 +936,9 @@ int getObjectType(DfsReader ctx, long pos) throws IOException {
 
 			case Constants.OBJ_OFS_DELTA: {
 				int p = 1;
-				while ((c & 0x80) != 0)
+				while ((c & 0x80) != 0) {
 					c = ib[p++] & 0xff;
+				}
 				c = ib[p++] & 0xff;
 				long ofs = c & 127;
 				while ((c & 128) != 0) {
@@ -949,8 +953,9 @@ int getObjectType(DfsReader ctx, long pos) throws IOException {
 
 			case Constants.OBJ_REF_DELTA: {
 				int p = 1;
-				while ((c & 0x80) != 0)
+				while ((c & 0x80) != 0) {
 					c = ib[p++] & 0xff;
+				}
 				readFully(pos + p, ib, 0, 20, ctx);
 				pos = findDeltaBase(ctx, ObjectId.fromRaw(ib));
 				continue;
@@ -993,8 +998,9 @@ long getObjectSize(DfsReader ctx, long pos)
 
 		case Constants.OBJ_OFS_DELTA:
 			c = ib[p++] & 0xff;
-			while ((c & 128) != 0)
+			while ((c & 128) != 0) {
 				c = ib[p++] & 0xff;
+			}
 			deltaAt = pos + p;
 			break;
 
@@ -1027,8 +1033,9 @@ void representation(DfsObjectRepresentation r, final long pos,
 		int c = ib[0] & 0xff;
 		int p = 1;
 		final int typeCode = (c >> 4) & 7;
-		while ((c & 0x80) != 0)
+		while ((c & 0x80) != 0) {
 			c = ib[p++] & 0xff;
+		}
 
 		long len = rev.findNextOffset(pos, length - 20) - pos;
 		switch (typeCode) {
@@ -1072,8 +1079,9 @@ void representation(DfsObjectRepresentation r, final long pos,
 
 	boolean isCorrupt(long offset) {
 		LongList list = corruptObjects;
-		if (list == null)
+		if (list == null) {
 			return false;
+		}
 		synchronized (list) {
 			return list.contains(offset);
 		}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsRefDatabase.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsRefDatabase.java
index a884346..8b2a03d 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsRefDatabase.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsRefDatabase.java
@@ -107,20 +107,6 @@ public Ref exactRef(String name) throws IOException {
 
 	/** {@inheritDoc} */
 	@Override
-	public Ref getRef(String needle) throws IOException {
-		RefCache curr = read();
-		for (String prefix : SEARCH_PATH) {
-			Ref ref = curr.ids.get(prefix + needle);
-			if (ref != null) {
-				ref = resolve(ref, 0, curr.ids);
-				return ref;
-			}
-		}
-		return null;
-	}
-
-	/** {@inheritDoc} */
-	@Override
 	public List<Ref> getAdditionalRefs() {
 		return Collections.emptyList();
 	}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsReftable.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsReftable.java
index 7502471..4853298 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsReftable.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsReftable.java
@@ -128,7 +128,7 @@ public ByteBuffer read(long pos, int cnt) throws IOException {
 				open().setReadAheadBytes(readAhead);
 			}
 
-			DfsBlock block = cache.getOrLoad(file, pos, ctx, ch);
+			DfsBlock block = cache.getOrLoad(file, pos, ctx, () -> open());
 			if (block.start == pos && block.size() >= cnt) {
 				return block.zeroCopyByteBuffer(cnt);
 			}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsReftableDatabase.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsReftableDatabase.java
index 7081630..83394bb 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsReftableDatabase.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsReftableDatabase.java
@@ -99,6 +99,12 @@ protected DfsReftableDatabase(DfsRepository repo) {
 
 	/** {@inheritDoc} */
 	@Override
+	public boolean hasVersioning() {
+		return true;
+	}
+
+	/** {@inheritDoc} */
+	@Override
 	public boolean performsAtomicTransactions() {
 		return true;
 	}
@@ -223,18 +229,6 @@ public Ref exactRef(String name) throws IOException {
 
 	/** {@inheritDoc} */
 	@Override
-	public Ref getRef(String needle) throws IOException {
-		for (String prefix : SEARCH_PATH) {
-			Ref ref = exactRef(prefix + needle);
-			if (ref != null) {
-				return ref;
-			}
-		}
-		return null;
-	}
-
-	/** {@inheritDoc} */
-	@Override
 	public Map<String, Ref> getRefs(String prefix) throws IOException {
 		RefList.Builder<Ref> all = new RefList.Builder<>();
 		lock.lock();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GC.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GC.java
index 7bfec3f..037338e 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GC.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GC.java
@@ -160,7 +160,6 @@ public class GC {
 	 *
 	 * @param e
 	 *            the executor to be used for running auto-gc
-	 * @since 4.8
 	 */
 	public static void setExecutor(ExecutorService e) {
 		executor = e;
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 4d5c1c0..9b4323e 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectory.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectory.java
@@ -198,7 +198,6 @@ public final File getDirectory() {
 	 * <p>Getter for the field <code>packDirectory</code>.</p>
 	 *
 	 * @return the location of the <code>pack</code> directory.
-	 * @since 4.10
 	 */
 	public final File getPackDirectory() {
 		return packDirectory;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/RefDirectory.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/RefDirectory.java
index de7e4b3..a4729bb 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/RefDirectory.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/RefDirectory.java
@@ -74,6 +74,7 @@
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
@@ -319,16 +320,14 @@ private RefList<LooseRef> getLooseRefs() {
 		return loose;
 	}
 
-	/** {@inheritDoc} */
-	@Override
-	public Ref exactRef(String name) throws IOException {
-		RefList<Ref> packed = getPackedRefs();
-		Ref ref;
+	@Nullable
+	private Ref readAndResolve(String name, RefList<Ref> packed) throws IOException {
 		try {
-			ref = readRef(name, packed);
+			Ref ref = readRef(name, packed);
 			if (ref != null) {
 				ref = resolve(ref, 0, null, null, packed);
 			}
+			return ref;
 		} catch (IOException e) {
 			if (name.contains("/") //$NON-NLS-1$
 					|| !(e.getCause() instanceof InvalidObjectIdException)) {
@@ -338,35 +337,55 @@ public Ref exactRef(String name) throws IOException {
 			// While looking for a ref outside of refs/ (e.g., 'config'), we
 			// found a non-ref file (e.g., a config file) instead.  Treat this
 			// as a ref-not-found condition.
-			ref = null;
+			return null;
 		}
-		fireRefsChanged();
-		return ref;
 	}
 
 	/** {@inheritDoc} */
 	@Override
-	public Ref getRef(String needle) throws IOException {
-		final RefList<Ref> packed = getPackedRefs();
-		Ref ref = null;
-		for (String prefix : SEARCH_PATH) {
-			try {
-				ref = readRef(prefix + needle, packed);
+	public Ref exactRef(String name) throws IOException {
+		try {
+			return readAndResolve(name, getPackedRefs());
+		} finally {
+			fireRefsChanged();
+		}
+	}
+
+	/** {@inheritDoc} */
+	@Override
+	@NonNull
+	public Map<String, Ref> exactRef(String... refs) throws IOException {
+		try {
+			RefList<Ref> packed = getPackedRefs();
+			Map<String, Ref> result = new HashMap<>(refs.length);
+			for (String name : refs) {
+				Ref ref = readAndResolve(name, packed);
 				if (ref != null) {
-					ref = resolve(ref, 0, null, null, packed);
-				}
-				if (ref != null) {
-					break;
-				}
-			} catch (IOException e) {
-				if (!(!needle.contains("/") && "".equals(prefix) && e //$NON-NLS-1$ //$NON-NLS-2$
-						.getCause() instanceof InvalidObjectIdException)) {
-					throw e;
+					result.put(name, ref);
 				}
 			}
+			return result;
+		} finally {
+			fireRefsChanged();
 		}
-		fireRefsChanged();
-		return ref;
+	}
+
+	/** {@inheritDoc} */
+	@Override
+	@Nullable
+	public Ref firstExactRef(String... refs) throws IOException {
+		try {
+			RefList<Ref> packed = getPackedRefs();
+			for (String name : refs) {
+				Ref ref = readAndResolve(name, packed);
+				if (ref != null) {
+					return ref;
+				}
+			}
+			return null;
+		} finally {
+			fireRefsChanged();
+		}
 	}
 
 	/** {@inheritDoc} */
@@ -414,7 +433,7 @@ public Map<String, Ref> getRefs(String prefix) throws IOException {
 	public List<Ref> getAdditionalRefs() throws IOException {
 		List<Ref> ret = new LinkedList<>();
 		for (String name : additionalRefsNames) {
-			Ref r = getRef(name);
+			Ref r = exactRef(name);
 			if (r != null)
 				ret.add(r);
 		}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/RefDirectoryUpdate.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/RefDirectoryUpdate.java
index 45ce634..1a0d695 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/RefDirectoryUpdate.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/RefDirectoryUpdate.java
@@ -87,7 +87,7 @@ protected boolean tryLock(boolean deref) throws IOException {
 		String name = dst.getName();
 		lock = new LockFile(database.fileFor(name));
 		if (lock.lock()) {
-			dst = database.getRef(name);
+			dst = database.findRef(name);
 			setOldObjectId(dst != null ? dst.getObjectId() : null);
 			return true;
 		} else {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/WindowCache.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/WindowCache.java
index 8cf1d4e..e8fac51 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/WindowCache.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/WindowCache.java
@@ -146,7 +146,7 @@ private static final int bits(int newSize) {
 	 * Modify the configuration of the window cache.
 	 * <p>
 	 * The new configuration is applied immediately. If the new limits are
-	 * smaller than what what is currently cached, older entries will be purged
+	 * smaller than what is currently cached, older entries will be purged
 	 * as soon as possible to allow the cache to meet the new limit.
 	 *
 	 * @deprecated use {@code cfg.install()} to avoid internal reference.
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/DeltaEncoder.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/DeltaEncoder.java
index 343faf4..cfc1ccd 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/DeltaEncoder.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/DeltaEncoder.java
@@ -73,7 +73,7 @@ public class DeltaEncoder {
 	/** Maximum number of bytes used by a copy instruction. */
 	private static final int MAX_COPY_CMD_SIZE = 8;
 
-	/** Maximum length that an an insert command can encode at once. */
+	/** Maximum length that an insert command can encode at once. */
 	private static final int MAX_INSERT_DATA_SIZE = 127;
 
 	private final OutputStream out;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackWriter.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackWriter.java
index 24af8a7..1e3d74a 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackWriter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackWriter.java
@@ -642,7 +642,6 @@ public void setShallowPack(int depth,
 
 	/**
 	 * @param bytes exclude blobs of size greater than this
-	 * @since 5.0
 	 */
 	public void setFilterBlobLimit(long bytes) {
 		filterBlobLimit = bytes;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/BlockReader.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/BlockReader.java
index ce2ba4a..44529bf 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/BlockReader.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/BlockReader.java
@@ -170,24 +170,27 @@ long readUpdateIndexDelta() {
 		return readVarint64();
 	}
 
-	Ref readRef() throws IOException {
+	Ref readRef(long minUpdateIndex) throws IOException {
+		long updateIndex = minUpdateIndex + readUpdateIndexDelta();
 		String name = RawParseUtils.decode(UTF_8, nameBuf, 0, nameLen);
 		switch (valueType & VALUE_TYPE_MASK) {
 		case VALUE_NONE: // delete
-			return newRef(name);
+			return newRef(name, updateIndex);
 
 		case VALUE_1ID:
-			return new ObjectIdRef.PeeledNonTag(PACKED, name, readValueId());
+			return new ObjectIdRef.PeeledNonTag(PACKED, name, readValueId(),
+					updateIndex);
 
 		case VALUE_2ID: { // annotated tag
 			ObjectId id1 = readValueId();
 			ObjectId id2 = readValueId();
-			return new ObjectIdRef.PeeledTag(PACKED, name, id1, id2);
+			return new ObjectIdRef.PeeledTag(PACKED, name, id1, id2,
+					updateIndex);
 		}
 
 		case VALUE_SYMREF: {
 			String val = readValueString();
-			return new SymbolicRef(name, newRef(val));
+			return new SymbolicRef(name, newRef(val, updateIndex), updateIndex);
 		}
 
 		default:
@@ -410,7 +413,7 @@ void verifyIndex() throws IOException {
 	 * <ul>
 	 * <li>{@link #name()}
 	 * <li>{@link #match(byte[], boolean)}
-	 * <li>{@link #readRef()}
+	 * <li>{@link #readRef(long)}
 	 * <li>{@link #readLogUpdateIndex()}
 	 * <li>{@link #readLogEntry()}
 	 * <li>{@link #readBlockPositionList()}
@@ -575,8 +578,8 @@ private long readVarint64() {
 		return val;
 	}
 
-	private static Ref newRef(String name) {
-		return new ObjectIdRef.Unpeeled(NEW, name, null);
+	private static Ref newRef(String name, long updateIndex) {
+		return new ObjectIdRef.Unpeeled(NEW, name, null, updateIndex);
 	}
 
 	private static IOException invalidBlock() {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/MergedReftable.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/MergedReftable.java
index 17894b1..c740bf2 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/MergedReftable.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/MergedReftable.java
@@ -168,7 +168,6 @@ private class MergedRefCursor extends RefCursor {
 		private final PriorityQueue<RefQueueEntry> queue;
 		private RefQueueEntry head;
 		private Ref ref;
-		private long updateIndex;
 
 		MergedRefCursor() {
 			queue = new PriorityQueue<>(queueSize(), RefQueueEntry::compare);
@@ -206,7 +205,6 @@ public boolean next() throws IOException {
 				}
 
 				ref = t.rc.getRef();
-				updateIndex = t.rc.getUpdateIndex();
 				boolean include = includeDeletes || !t.rc.wasDeleted();
 				add(t);
 				skipShadowedRefs(ref.getName());
@@ -242,11 +240,6 @@ public Ref getRef() {
 		}
 
 		@Override
-		public long getUpdateIndex() {
-			return updateIndex;
-		}
-
-		@Override
 		public void close() {
 			if (head != null) {
 				head.rc.close();
@@ -285,7 +278,7 @@ String name() {
 		}
 
 		long updateIndex() {
-			return rc.getUpdateIndex();
+			return rc.getRef().getUpdateIndex();
 		}
 	}
 
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/RefCursor.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/RefCursor.java
index 5d4af30..9749ffb 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/RefCursor.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/RefCursor.java
@@ -69,13 +69,6 @@ public abstract class RefCursor implements AutoCloseable {
 	public abstract Ref getRef();
 
 	/**
-	 * Get updateIndex that last modified the current reference.
-	 *
-	 * @return updateIndex that last modified the current reference.
-	 */
-	public abstract long getUpdateIndex();
-
-	/**
 	 * Whether the current reference was deleted.
 	 *
 	 * @return {@code true} if the current reference was deleted.
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/Reftable.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/Reftable.java
index a1087e2..cb02628 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/Reftable.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/Reftable.java
@@ -280,7 +280,7 @@ private Ref resolve(Ref ref, int depth) throws IOException {
 		if (dst == null) {
 			return null; // claim it doesn't exist
 		}
-		return new SymbolicRef(ref.getName(), dst);
+		return new SymbolicRef(ref.getName(), dst, ref.getUpdateIndex());
 	}
 
 	/** {@inheritDoc} */
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/ReftableCompactor.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/ReftableCompactor.java
index ed73a9e..c4e8f69 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/ReftableCompactor.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/ReftableCompactor.java
@@ -256,7 +256,7 @@ public Stats getStats() {
 	private void mergeRefs(MergedReftable mr) throws IOException {
 		try (RefCursor rc = mr.allRefs()) {
 			while (rc.next()) {
-				writer.writeRef(rc.getRef(), rc.getUpdateIndex());
+				writer.writeRef(rc.getRef(), rc.getRef().getUpdateIndex());
 			}
 		}
 	}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/ReftableReader.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/ReftableReader.java
index 81b30e4..bf3a9ae 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/ReftableReader.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/ReftableReader.java
@@ -479,7 +479,6 @@ private class RefCursorImpl extends RefCursor {
 		private final boolean prefix;
 
 		private Ref ref;
-		private long updateIndex;
 		BlockReader block;
 
 		RefCursorImpl(long scanEnd, byte[] match, boolean prefix) {
@@ -508,8 +507,7 @@ public boolean next() throws IOException {
 					return false;
 				}
 
-				updateIndex = minUpdateIndex + block.readUpdateIndexDelta();
-				ref = block.readRef();
+				ref = block.readRef(minUpdateIndex);
 				if (!includeDeletes && wasDeleted()) {
 					continue;
 				}
@@ -523,11 +521,6 @@ public Ref getRef() {
 		}
 
 		@Override
-		public long getUpdateIndex() {
-			return updateIndex;
-		}
-
-		@Override
 		public void close() {
 			// Do nothing.
 		}
@@ -605,7 +598,6 @@ private class ObjCursorImpl extends RefCursor {
 		private final ObjectId match;
 
 		private Ref ref;
-		private long updateIndex;
 		private int listIdx;
 
 		private LongList blockPos;
@@ -679,8 +671,7 @@ public boolean next() throws IOException {
 				}
 
 				block.parseKey();
-				updateIndex = minUpdateIndex + block.readUpdateIndexDelta();
-				ref = block.readRef();
+				ref = block.readRef(minUpdateIndex);
 				ObjectId id = ref.getObjectId();
 				if (id != null && match.equals(id)
 						&& (includeDeletes || !wasDeleted())) {
@@ -695,11 +686,6 @@ public Ref getRef() {
 		}
 
 		@Override
-		public long getUpdateIndex() {
-			return updateIndex;
-		}
-
-		@Override
 		public void close() {
 			// Do nothing.
 		}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftree/RefTreeDatabase.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftree/RefTreeDatabase.java
index 27daaf0..ddd05b3 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftree/RefTreeDatabase.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftree/RefTreeDatabase.java
@@ -206,16 +206,6 @@ public void close() {
 
 	/** {@inheritDoc} */
 	@Override
-	public Ref getRef(String name) throws IOException {
-		String[] needle = new String[SEARCH_PATH.length];
-		for (int i = 0; i < SEARCH_PATH.length; i++) {
-			needle[i] = SEARCH_PATH[i] + name;
-		}
-		return firstExactRef(needle);
-	}
-
-	/** {@inheritDoc} */
-	@Override
 	public Ref exactRef(String name) throws IOException {
 		if (!repo.isBare() && name.indexOf('/') < 0 && !HEAD.equals(name)) {
 			// Pass through names like MERGE_HEAD, ORIG_HEAD, FETCH_HEAD.
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/submodule/SubmoduleValidator.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/submodule/SubmoduleValidator.java
index 7b872b1..cd6af6a 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/submodule/SubmoduleValidator.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/submodule/SubmoduleValidator.java
@@ -61,7 +61,7 @@
  * Validations for the git submodule fields (name, path, uri).
  *
  * Invalid values in these fields can cause security problems as reported in
- * CVE-2018-11235 and and CVE-2018-17456
+ * CVE-2018-11235 and CVE-2018-17456
  */
 public class SubmoduleValidator {
 
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/transport/parser/FirstCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/transport/parser/FirstCommand.java
new file mode 100644
index 0000000..0426b17
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/transport/parser/FirstCommand.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2018, Google LLC.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ *   copyright notice, this list of conditions and the following
+ *   disclaimer in the documentation and/or other materials provided
+ *   with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ *   names of its contributors may be used to endorse or promote
+ *   products derived from this software without specific prior
+ *   written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.eclipse.jgit.internal.transport.parser;
+
+import static java.util.Arrays.asList;
+import static java.util.Collections.emptySet;
+import static java.util.Collections.unmodifiableSet;
+import static java.util.stream.Collectors.toSet;
+
+import java.util.Set;
+
+import org.eclipse.jgit.annotations.NonNull;
+
+/**
+ * In a push, the client sends a list of commands. The first command
+ * is special, as it can include a list of capabilities at its end.
+ * <p>
+ * For example:
+ * "oid oid name\0cap1 cap cap3"
+ * <p>
+ * Not to be confused with {@link FirstWant}, nor with the first line
+ * of the reference advertisement parsed by
+ * {@code BasePackConnection.readAdvertisedRefs}.
+ * <p>
+ * This class parses the inputted command line and holds the results:
+ * the actual command line and the capabilities.
+ */
+public final class FirstCommand {
+	private final String line;
+	private final Set<String> capabilities;
+
+	/**
+	 * Parse the first line of a receive-pack request.
+	 *
+	 * @param line
+	 *            line from the client.
+	 * @return an instance of FirstCommand with capabilities parsed out
+	 */
+	@NonNull
+	public static FirstCommand fromLine(String line) {
+		int nul = line.indexOf('\0');
+		if (nul < 0) {
+			return new FirstCommand(line, emptySet());
+		}
+		Set<String> opts =
+				asList(line.substring(nul + 1).split(" ")) //$NON-NLS-1$
+					.stream()
+					.collect(toSet());
+		return new FirstCommand(line.substring(0, nul), unmodifiableSet(opts));
+	}
+
+	private FirstCommand(String line, Set<String> capabilities) {
+		this.line = line;
+		this.capabilities = capabilities;
+	}
+
+	/** @return non-capabilities part of the line. */
+	@NonNull
+	public String getLine() {
+		return line;
+	}
+
+	/** @return capabilities parsed from the line, as an immutable set. */
+	@NonNull
+	public Set<String> getCapabilities() {
+		return capabilities;
+	}
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/transport/parser/FirstWant.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/transport/parser/FirstWant.java
index 2dae021..401c507 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/transport/parser/FirstWant.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/transport/parser/FirstWant.java
@@ -67,7 +67,6 @@
  * This class parses the input want line and holds the results: the actual want
  * line and the capabilities.
  *
- * @since 5.2
  */
 public class FirstWant {
 	private final String line;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectIdRef.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectIdRef.java
index 22aaa3a..bcda538 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectIdRef.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectIdRef.java
@@ -67,7 +67,26 @@ public static class Unpeeled extends ObjectIdRef {
 		 */
 		public Unpeeled(@NonNull Storage st, @NonNull String name,
 				@Nullable ObjectId id) {
-			super(st, name, id);
+			super(st, name, id, -1);
+		}
+
+		/**
+		 * Create a new ref pairing with update index.
+		 *
+		 * @param st
+		 *            method used to store this ref.
+		 * @param name
+		 *            name of this ref.
+		 * @param id
+		 *            current value of the ref. May be {@code null} to indicate
+		 *            a ref that does not exist yet.
+		 * @param updateIndex
+		 *            number increasing with each update to the reference.
+		 * @since 5.3
+		 */
+		public Unpeeled(@NonNull Storage st, @NonNull String name,
+				@Nullable ObjectId id, long updateIndex) {
+			super(st, name, id, updateIndex);
 		}
 
 		@Override
@@ -100,7 +119,29 @@ public static class PeeledTag extends ObjectIdRef {
 		 */
 		public PeeledTag(@NonNull Storage st, @NonNull String name,
 				@Nullable ObjectId id, @NonNull ObjectId p) {
-			super(st, name, id);
+			super(st, name, id, -1);
+			peeledObjectId = p;
+		}
+
+		/**
+		 * Create a new ref pairing with update index.
+		 *
+		 * @param st
+		 *            method used to store this ref.
+		 * @param name
+		 *            name of this ref.
+		 * @param id
+		 *            current value of the ref. May be {@code null} to indicate
+		 *            a ref that does not exist yet.
+		 * @param p
+		 *            the first non-tag object that tag {@code id} points to.
+		 * @param updateIndex
+		 *            number increasing with each update to the reference.
+		 * @since 5.3
+		 */
+		public PeeledTag(@NonNull Storage st, @NonNull String name,
+				@Nullable ObjectId id, @NonNull ObjectId p, long updateIndex) {
+			super(st, name, id, updateIndex);
 			peeledObjectId = p;
 		}
 
@@ -131,7 +172,26 @@ public static class PeeledNonTag extends ObjectIdRef {
 		 */
 		public PeeledNonTag(@NonNull Storage st, @NonNull String name,
 				@Nullable ObjectId id) {
-			super(st, name, id);
+			super(st, name, id, -1);
+		}
+
+		/**
+		 * Create a new ref pairing with update index.
+		 *
+		 * @param st
+		 *            method used to store this ref.
+		 * @param name
+		 *            name of this ref.
+		 * @param id
+		 *            current value of the ref. May be {@code null} to indicate
+		 *            a ref that does not exist yet.
+		 * @param updateIndex
+		 *            number increasing with each update to the reference.
+		 * @since 5.3
+		 */
+		public PeeledNonTag(@NonNull Storage st, @NonNull String name,
+				@Nullable ObjectId id, long updateIndex) {
+			super(st, name, id, updateIndex);
 		}
 
 		@Override
@@ -152,6 +212,8 @@ public boolean isPeeled() {
 
 	private final ObjectId objectId;
 
+	private final long updateIndex;
+
 	/**
 	 * Create a new ref pairing.
 	 *
@@ -162,12 +224,17 @@ public boolean isPeeled() {
 	 * @param id
 	 *            current value of the ref. May be {@code null} to indicate a
 	 *            ref that does not exist yet.
+	 * @param updateIndex
+	 *            number that increases with each ref update. Set to -1 if the
+	 *            storage doesn't support versioning.
+	 * @since 5.3
 	 */
 	protected ObjectIdRef(@NonNull Storage st, @NonNull String name,
-			@Nullable ObjectId id) {
+			@Nullable ObjectId id, long updateIndex) {
 		this.name = name;
 		this.storage = st;
 		this.objectId = id;
+		this.updateIndex = updateIndex;
 	}
 
 	/** {@inheritDoc} */
@@ -212,6 +279,15 @@ public Storage getStorage() {
 	}
 
 	/** {@inheritDoc} */
+	@Override
+	public long getUpdateIndex() {
+		if (updateIndex == -1) {
+			throw new UnsupportedOperationException();
+		}
+		return updateIndex;
+	}
+
+	/** {@inheritDoc} */
 	@NonNull
 	@Override
 	public String toString() {
@@ -220,7 +296,9 @@ public String toString() {
 		r.append(getName());
 		r.append('=');
 		r.append(ObjectId.toString(getObjectId()));
-		r.append(']');
+		r.append('(');
+		r.append(updateIndex); // Print value, even if -1
+		r.append(")]"); //$NON-NLS-1$
 		return r.toString();
 	}
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Ref.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Ref.java
index faabbf8..32c8b06 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Ref.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Ref.java
@@ -217,4 +217,27 @@ public boolean isPacked() {
 	 */
 	@NonNull
 	Storage getStorage();
+
+	/**
+	 * Indicator of the relative order between updates of a specific reference
+	 * name. A number that increases when a reference is updated.
+	 * <p>
+	 * With symbolic references, the update index refers to updates of the
+	 * symbolic reference itself. For example, if HEAD points to
+	 * refs/heads/master, then the update index for exactRef("HEAD") will only
+	 * increase when HEAD changes to point to another ref, regardless of how
+	 * many times refs/heads/master is updated.
+	 * <p>
+	 * Should not be used unless the {@code RefDatabase} that instantiated the
+	 * ref supports versioning (see {@link RefDatabase#hasVersioning()})
+	 *
+	 * @return the update index (i.e. version) of this reference.
+	 * @throws UnsupportedOperationException
+	 *             if the creator of the instance (e.g. {@link RefDatabase})
+	 *             doesn't support versioning and doesn't override this method
+	 * @since 5.3
+	 */
+	default long getUpdateIndex() {
+		throw new UnsupportedOperationException();
+	}
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefDatabase.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefDatabase.java
index 68929b4..8777920 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefDatabase.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefDatabase.java
@@ -69,10 +69,10 @@ public abstract class RefDatabase {
 	/**
 	 * Order of prefixes to search when using non-absolute references.
 	 * <p>
-	 * The implementation's {@link #getRef(String)} method must take this search
-	 * space into consideration when locating a reference by name. The first
-	 * entry in the path is always {@code ""}, ensuring that absolute references
-	 * are resolved without further mangling.
+	 * {@link #findRef(String)} takes this search space into consideration
+	 * when locating a reference by name. The first entry in the path is
+	 * always {@code ""}, ensuring that absolute references are resolved
+	 * without further mangling.
 	 */
 	protected static final String[] SEARCH_PATH = { "", //$NON-NLS-1$
 			Constants.R_REFS, //
@@ -111,6 +111,19 @@ public abstract class RefDatabase {
 	public abstract void close();
 
 	/**
+	 * With versioning, each reference has a version number that increases on
+	 * update. See {@link Ref#getUpdateIndex()}.
+	 *
+	 * @implSpec This method returns false by default. Implementations
+	 *           supporting versioning must override it to return true.
+	 * @return true if the implementation assigns update indices to references.
+	 * @since 5.3
+	 */
+	public boolean hasVersioning() {
+		return false;
+	}
+
+	/**
 	 * Determine if a proposed reference name overlaps with an existing one.
 	 * <p>
 	 * Reference names use '/' as a component separator, and may be stored in a
@@ -244,6 +257,23 @@ public boolean performsAtomicTransactions() {
 	}
 
 	/**
+	 * Compatibility synonym for {@link #findRef(String)}.
+	 *
+	 * @param name
+	 *            the name of the reference. May be a short name which must be
+	 *            searched for using the standard {@link #SEARCH_PATH}.
+	 * @return the reference (if it exists); else {@code null}.
+	 * @throws IOException
+	 *             the reference space cannot be accessed.
+	 * @deprecated Use {@link #findRef(String)} instead.
+	 */
+	@Deprecated
+	@Nullable
+	public final Ref getRef(String name) throws IOException {
+		return findRef(name);
+	}
+
+	/**
 	 * Read a single reference.
 	 * <p>
 	 * Aside from taking advantage of {@link #SEARCH_PATH}, this method may be
@@ -259,14 +289,21 @@ public boolean performsAtomicTransactions() {
 	 * @return the reference (if it exists); else {@code null}.
 	 * @throws java.io.IOException
 	 *             the reference space cannot be accessed.
+	 * @since 5.3
 	 */
 	@Nullable
-	public abstract Ref getRef(String name) throws IOException;
+	public final Ref findRef(String name) throws IOException {
+		String[] names = new String[SEARCH_PATH.length];
+		for (int i = 0; i < SEARCH_PATH.length; i++) {
+			names[i] = SEARCH_PATH[i] + name;
+		}
+		return firstExactRef(names);
+	}
 
 	/**
 	 * Read a single reference.
 	 * <p>
-	 * Unlike {@link #getRef}, this method expects an unshortened reference
+	 * Unlike {@link #findRef}, this method expects an unshortened reference
 	 * name and does not search using the standard {@link #SEARCH_PATH}.
 	 *
 	 * @param name
@@ -277,13 +314,7 @@ public boolean performsAtomicTransactions() {
 	 * @since 4.1
 	 */
 	@Nullable
-	public Ref exactRef(String name) throws IOException {
-		Ref ref = getRef(name);
-		if (ref == null || !name.equals(ref.getName())) {
-			return null;
-		}
-		return ref;
-	}
+	public abstract Ref exactRef(String name) throws IOException;
 
 	/**
 	 * Read the specified references.
@@ -462,7 +493,7 @@ public boolean hasRefs() throws IOException {
 	 * <p>
 	 * The result list includes non-ref items such as MERGE_HEAD and
 	 * FETCH_RESULT cast to be refs. The names of these refs are not returned by
-	 * <code>getRefs()</code> but are accepted by {@link #getRef(String)}
+	 * <code>getRefs()</code> but are accepted by {@link #findRef(String)}
 	 * and {@link #exactRef(String)}.
 	 *
 	 * @return a list of additional refs
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefRename.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefRename.java
index a05daa0..0bd34b5 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefRename.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefRename.java
@@ -184,7 +184,7 @@ public Result rename() throws IOException {
 	 *             the current value of {@code HEAD} cannot be read.
 	 */
 	protected boolean needToUpdateHEAD() throws IOException {
-		Ref head = source.getRefDatabase().getRef(Constants.HEAD);
+		Ref head = source.getRefDatabase().exactRef(Constants.HEAD);
 		if (head != null && head.isSymbolic()) {
 			head = head.getTarget();
 			return head.getName().equals(source.getName());
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefUpdate.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefUpdate.java
index fc3ea84..1ce1528 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefUpdate.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefUpdate.java
@@ -665,7 +665,7 @@ public Result delete(RevWalk walk) throws IOException {
 				: getRef().getLeaf().getName();
 		if (myName.startsWith(Constants.R_HEADS) && !getRepository().isBare()) {
 			// Don't allow the currently checked out branch to be deleted.
-			Ref head = getRefDatabase().getRef(Constants.HEAD);
+			Ref head = getRefDatabase().exactRef(Constants.HEAD);
 			while (head != null && head.isSymbolic()) {
 				head = head.getTarget();
 				if (myName.equals(head.getName()))
@@ -708,7 +708,7 @@ public Result link(String target) throws IOException {
 			if (!tryLock(false))
 				return Result.LOCK_FAILURE;
 
-			final Ref old = getRefDatabase().getRef(getName());
+			final Ref old = getRefDatabase().exactRef(getName());
 			if (old != null && old.isSymbolic()) {
 				final Ref dst = old.getTarget();
 				if (target.equals(dst.getName()))
@@ -718,7 +718,7 @@ public Result link(String target) throws IOException {
 			if (old != null && old.getObjectId() != null)
 				setOldObjectId(old.getObjectId());
 
-			final Ref dst = getRefDatabase().getRef(target);
+			final Ref dst = getRefDatabase().exactRef(target);
 			if (dst != null && dst.getObjectId() != null)
 				setNewObjectId(dst.getObjectId());
 
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Repository.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Repository.java
index 77d268a..a61897a 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Repository.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Repository.java
@@ -57,6 +57,7 @@
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.OutputStream;
+import java.io.UncheckedIOException;
 import java.net.URISyntaxException;
 import java.text.MessageFormat;
 import java.util.Collection;
@@ -297,7 +298,7 @@ public ObjectReader newObjectReader() {
 	/**
 	 * Get the used file system abstraction.
 	 *
-	 * @return the used file system abstraction, or or {@code null} if
+	 * @return the used file system abstraction, or {@code null} if
 	 *         repository isn't local.
 	 */
 	/*
@@ -319,13 +320,14 @@ public FS getFS() {
 	 *            a {@link org.eclipse.jgit.lib.AnyObjectId} object.
 	 * @return true if the specified object is stored in this repo or any of the
 	 *         known shared repositories.
+	 * @deprecated use {@code getObjectDatabase().has(objectId)}
 	 */
+	@Deprecated
 	public boolean hasObject(AnyObjectId objectId) {
 		try {
 			return getObjectDatabase().has(objectId);
 		} catch (IOException e) {
-			// Legacy API, assume error means "no"
-			return false;
+			throw new UncheckedIOException(e);
 		}
 	}
 
@@ -849,7 +851,7 @@ private ObjectId resolveSimple(String revstr) throws IOException {
 			return ObjectId.fromString(revstr);
 
 		if (Repository.isValidRefName("x/" + revstr)) { //$NON-NLS-1$
-			Ref r = getRefDatabase().getRef(revstr);
+			Ref r = getRefDatabase().findRef(revstr);
 			if (r != null)
 				return r.getObjectId();
 		}
@@ -1079,7 +1081,7 @@ public final Ref exactRef(String name) throws IOException {
 	 *
 	 * @param name
 	 *            the name of the ref to lookup. May be a short-hand form, e.g.
-	 *            "master" which is is automatically expanded to
+	 *            "master" which is automatically expanded to
 	 *            "refs/heads/master" if "refs/heads/master" already exists.
 	 * @return the Ref with the given name, or {@code null} if it does not exist
 	 * @throws java.io.IOException
@@ -1087,7 +1089,7 @@ public final Ref exactRef(String name) throws IOException {
 	 */
 	@Nullable
 	public final Ref findRef(String name) throws IOException {
-		return getRefDatabase().getRef(name);
+		return getRefDatabase().findRef(name);
 	}
 
 	/**
@@ -1103,7 +1105,7 @@ public Map<String, Ref> getAllRefs() {
 		try {
 			return getRefDatabase().getRefs(RefDatabase.ALL);
 		} catch (IOException e) {
-			return new HashMap<>();
+			throw new UncheckedIOException(e);
 		}
 	}
 
@@ -1121,7 +1123,7 @@ public Map<String, Ref> getTags() {
 		try {
 			return getRefDatabase().getRefs(Constants.R_TAGS);
 		} catch (IOException e) {
-			return new HashMap<>();
+			throw new UncheckedIOException(e);
 		}
 	}
 
@@ -1320,9 +1322,7 @@ public RepositoryState getRepositoryState() {
 					return RepositoryState.MERGING_RESOLVED;
 				}
 			} catch (IOException e) {
-				// Can't decide whether unmerged paths exists. Return
-				// MERGING state to be on the safe side (in state MERGING
-				// you are not allow to do anything)
+				throw new UncheckedIOException(e);
 			}
 			return RepositoryState.MERGING;
 		}
@@ -1337,7 +1337,7 @@ public RepositoryState getRepositoryState() {
 					return RepositoryState.CHERRY_PICKING_RESOLVED;
 				}
 			} catch (IOException e) {
-				// fall through to CHERRY_PICKING
+				throw new UncheckedIOException(e);
 			}
 
 			return RepositoryState.CHERRY_PICKING;
@@ -1350,7 +1350,7 @@ public RepositoryState getRepositoryState() {
 					return RepositoryState.REVERTING_RESOLVED;
 				}
 			} catch (IOException e) {
-				// fall through to REVERTING
+				throw new UncheckedIOException(e);
 			}
 
 			return RepositoryState.REVERTING;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/SymbolicRef.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/SymbolicRef.java
index d4b83b0..ee0eb2f 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/SymbolicRef.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/SymbolicRef.java
@@ -58,6 +58,8 @@ public class SymbolicRef implements Ref {
 
 	private final Ref target;
 
+	private final long updateIndex;
+
 	/**
 	 * Create a new ref pairing.
 	 *
@@ -69,6 +71,25 @@ public class SymbolicRef implements Ref {
 	public SymbolicRef(@NonNull String refName, @NonNull Ref target) {
 		this.name = refName;
 		this.target = target;
+		this.updateIndex = -1;
+	}
+
+	/**
+	 * Create a new ref pairing.
+	 *
+	 * @param refName
+	 *            name of this ref.
+	 * @param target
+	 *            the ref we reference and derive our value from.
+	 * @param updateIndex
+	 *            index that increases with each update of the reference
+	 * @since 5.3
+	 */
+	public SymbolicRef(@NonNull String refName, @NonNull Ref target,
+			long updateIndex) {
+		this.name = refName;
+		this.target = target;
+		this.updateIndex = updateIndex;
 	}
 
 	/** {@inheritDoc} */
@@ -129,6 +150,15 @@ public boolean isPeeled() {
 	}
 
 	/** {@inheritDoc} */
+	@Override
+	public long getUpdateIndex() {
+		if (updateIndex == -1) {
+			throw new UnsupportedOperationException();
+		}
+		return updateIndex;
+	}
+
+	/** {@inheritDoc} */
 	@SuppressWarnings("nls")
 	@Override
 	public String toString() {
@@ -143,7 +173,9 @@ public String toString() {
 		r.append(cur.getName());
 		r.append('=');
 		r.append(ObjectId.toString(cur.getObjectId()));
-		r.append("]");
+		r.append("(");
+		r.append(updateIndex); // Print value, even if -1
+		r.append(")]");
 		return r.toString();
 	}
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeResult.java b/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeResult.java
index 062d86f..a533bf5 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeResult.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeResult.java
@@ -119,7 +119,7 @@ public void add(int srcIdx, int begin, int end, ConflictState conflictState) {
 
 	/**
 	 * Returns the common predecessor sequence and the merged sequence in one
-	 * list. The common predecessor is is the first element in the list
+	 * list. The common predecessor is the first element in the list
 	 *
 	 * @return the common predecessor at position 0 followed by the merged
 	 *         sequences.
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/nls/NLS.java b/org.eclipse.jgit/src/org/eclipse/jgit/nls/NLS.java
index 89a87af..375cd32 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/nls/NLS.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/nls/NLS.java
@@ -79,7 +79,7 @@ public class NLS {
 	/**
 	 * Sets the locale for the calling thread.
 	 * <p>
-	 * The {@link #getBundleFor(Class)} method will honor this setting if if it
+	 * The {@link #getBundleFor(Class)} method will honor this setting if it
 	 * is supported by the provided resource bundle property files. Otherwise,
 	 * it will use a fall back locale as described in the
 	 * {@link TranslationBundle}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/ObjectWalk.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/ObjectWalk.java
index e5903c9..fd578da 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/ObjectWalk.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/ObjectWalk.java
@@ -330,11 +330,11 @@ public RevCommit next() throws MissingObjectException,
 	 *
 	 * @return next most recent object; null if traversal is over.
 	 * @throws org.eclipse.jgit.errors.MissingObjectException
-	 *             one or or more of the next objects are not available from the
+	 *             one or more of the next objects are not available from the
 	 *             object database, but were thought to be candidates for
 	 *             traversal. This usually indicates a broken link.
 	 * @throws org.eclipse.jgit.errors.IncorrectObjectTypeException
-	 *             one or or more of the objects in a tree do not match the type
+	 *             one or more of the objects in a tree do not match the type
 	 *             indicated.
 	 * @throws java.io.IOException
 	 *             a pack file or loose object could not be read.
@@ -534,11 +534,11 @@ private static int parseMode(byte[] buf, int startPtr, int recEndPtr, TreeVisit
 	 * provides some detail about the connectivity failure.
 	 *
 	 * @throws org.eclipse.jgit.errors.MissingObjectException
-	 *             one or or more of the next objects are not available from the
+	 *             one or more of the next objects are not available from the
 	 *             object database, but were thought to be candidates for
 	 *             traversal. This usually indicates a broken link.
 	 * @throws org.eclipse.jgit.errors.IncorrectObjectTypeException
-	 *             one or or more of the objects in a tree do not match the type
+	 *             one or more of the objects in a tree do not match the type
 	 *             indicated.
 	 * @throws java.io.IOException
 	 *             a pack file or loose object could not be read.
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevWalk.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevWalk.java
index 400ea33..0a43e8f 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevWalk.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevWalk.java
@@ -394,11 +394,11 @@ public void markUninteresting(RevCommit c)
 	 *         <code>base</code> (and thus <code>base</code> is fully merged
 	 *         into <code>tip</code>); false otherwise.
 	 * @throws org.eclipse.jgit.errors.MissingObjectException
-	 *             one or or more of the next commit's parents are not available
+	 *             one or more of the next commit's parents are not available
 	 *             from the object database, but were thought to be candidates
 	 *             for traversal. This usually indicates a broken link.
 	 * @throws org.eclipse.jgit.errors.IncorrectObjectTypeException
-	 *             one or or more of the next commit's parents are not actually
+	 *             one or more of the next commit's parents are not actually
 	 *             commit objects.
 	 * @throws java.io.IOException
 	 *             a pack file or loose object could not be read.
@@ -431,11 +431,11 @@ public boolean isMergedInto(RevCommit base, RevCommit tip)
 	 *
 	 * @return next most recent commit; null if traversal is over.
 	 * @throws org.eclipse.jgit.errors.MissingObjectException
-	 *             one or or more of the next commit's parents are not available
+	 *             one or more of the next commit's parents are not available
 	 *             from the object database, but were thought to be candidates
 	 *             for traversal. This usually indicates a broken link.
 	 * @throws org.eclipse.jgit.errors.IncorrectObjectTypeException
-	 *             one or or more of the next commit's parents are not actually
+	 *             one or more of the next commit's parents are not actually
 	 *             commit objects.
 	 * @throws java.io.IOException
 	 *             a pack file or loose object could not be read.
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/storage/file/WindowCacheConfig.java b/org.eclipse.jgit/src/org/eclipse/jgit/storage/file/WindowCacheConfig.java
index c2e6a42..ff49976 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/storage/file/WindowCacheConfig.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/storage/file/WindowCacheConfig.java
@@ -251,7 +251,7 @@ public WindowCacheConfig fromConfig(Config rc) {
 	 * Install this configuration as the live settings.
 	 * <p>
 	 * The new configuration is applied immediately. If the new limits are
-	 * smaller than what what is currently cached, older entries will be purged
+	 * smaller than what is currently cached, older entries will be purged
 	 * as soon as possible to allow the cache to meet the new limit.
 	 *
 	 * @since 3.0
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/storage/pack/PackConfig.java b/org.eclipse.jgit/src/org/eclipse/jgit/storage/pack/PackConfig.java
index 256e41d..ed3fe2a 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/storage/pack/PackConfig.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/storage/pack/PackConfig.java
@@ -1006,7 +1006,7 @@ public void setBitmapExcessiveBranchCount(int count) {
 	}
 
 	/**
-	 * Get the the age in days that marks a branch as "inactive".
+	 * Get the age in days that marks a branch as "inactive".
 	 *
 	 * Default setting: {@value #DEFAULT_BITMAP_INACTIVE_BRANCH_AGE_IN_DAYS}
 	 *
@@ -1018,7 +1018,7 @@ public int getBitmapInactiveBranchAgeInDays() {
 	}
 
 	/**
-	 * Set the the age in days that marks a branch as "inactive".
+	 * Set the age in days that marks a branch as "inactive".
 	 *
 	 * Default setting: {@value #DEFAULT_BITMAP_INACTIVE_BRANCH_AGE_IN_DAYS}
 	 *
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/AdvertiseRefsHook.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/AdvertiseRefsHook.java
index 72b4255..8512f2d 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/AdvertiseRefsHook.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/AdvertiseRefsHook.java
@@ -53,7 +53,7 @@ public interface AdvertiseRefsHook {
 	 * <p>
 	 * The method implementations do nothing to preserve the default behavior; see
 	 * {@link UploadPack#setAdvertisedRefs(java.util.Map)} and
-	 * {@link BaseReceivePack#setAdvertisedRefs(java.util.Map,java.util.Set)}.
+	 * {@link ReceivePack#setAdvertisedRefs(java.util.Map,java.util.Set)}.
 	 */
 	AdvertiseRefsHook DEFAULT = new AdvertiseRefsHook() {
 		@Override
@@ -85,7 +85,7 @@ void advertiseRefs(UploadPack uploadPack)
 	 *
 	 * @param receivePack
 	 *            instance on which to call
-	 *            {@link org.eclipse.jgit.transport.BaseReceivePack#setAdvertisedRefs(java.util.Map,java.util.Set)}
+	 *            {@link org.eclipse.jgit.transport.ReceivePack#setAdvertisedRefs(java.util.Map,java.util.Set)}
 	 *            if necessary.
 	 * @throws org.eclipse.jgit.transport.ServiceMayNotContinueException
 	 *             abort; the message will be sent to the user.
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/AdvertiseRefsHookChain.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/AdvertiseRefsHookChain.java
index 4ef3e1a..12238a1 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/AdvertiseRefsHookChain.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/AdvertiseRefsHookChain.java
@@ -52,7 +52,7 @@
  * Hooks are run in the order passed to the constructor. A hook may inspect or
  * modify the results of the previous hooks in the chain by calling
  * {@link org.eclipse.jgit.transport.UploadPack#getAdvertisedRefs()}, or
- * {@link org.eclipse.jgit.transport.BaseReceivePack#getAdvertisedRefs()} or
+ * {@link org.eclipse.jgit.transport.ReceivePack#getAdvertisedRefs()} or
  * {@link org.eclipse.jgit.transport.BaseReceivePack#getAdvertisedObjects()}.
  */
 public class AdvertiseRefsHookChain implements AdvertiseRefsHook {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackPushConnection.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackPushConnection.java
index 69624ff..847e901 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackPushConnection.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackPushConnection.java
@@ -338,7 +338,7 @@ private void writePack(final Map<String, RemoteRefUpdate> refUpdates,
 			for (Ref r : getRefs()) {
 				// only add objects that we actually have
 				ObjectId oid = r.getObjectId();
-				if (local.hasObject(oid))
+				if (local.getObjectDatabase().has(oid))
 					remoteObjects.add(oid);
 			}
 			remoteObjects.addAll(additionalHaves);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BaseReceivePack.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BaseReceivePack.java
index 0376336..6f17620 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BaseReceivePack.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BaseReceivePack.java
@@ -80,6 +80,7 @@
 import org.eclipse.jgit.internal.storage.file.PackLock;
 import org.eclipse.jgit.internal.submodule.SubmoduleValidator;
 import org.eclipse.jgit.internal.submodule.SubmoduleValidator.SubmoduleValidationException;
+import org.eclipse.jgit.internal.transport.parser.FirstCommand;
 import org.eclipse.jgit.lib.AnyObjectId;
 import org.eclipse.jgit.lib.BatchRefUpdate;
 import org.eclipse.jgit.lib.Config;
@@ -119,10 +120,14 @@
  * Subclasses compose these operations into full service implementations.
  */
 public abstract class BaseReceivePack {
-	/** Data in the first line of a request, the line itself plus capabilities. */
+	/**
+	 * Data in the first line of a request, the line itself plus capabilities.
+	 *
+	 * @deprecated Use {@link FirstCommand} instead.
+	 */
+	@Deprecated
 	public static class FirstLine {
-		private final String line;
-		private final Set<String> capabilities;
+		private final FirstCommand command;
 
 		/**
 		 * Parse the first line of a receive-pack request.
@@ -131,33 +136,25 @@ public static class FirstLine {
 		 *            line from the client.
 		 */
 		public FirstLine(String line) {
-			final HashSet<String> caps = new HashSet<>();
-			final int nul = line.indexOf('\0');
-			if (nul >= 0) {
-				for (String c : line.substring(nul + 1).split(" ")) //$NON-NLS-1$
-					caps.add(c);
-				this.line = line.substring(0, nul);
-			} else
-				this.line = line;
-			this.capabilities = Collections.unmodifiableSet(caps);
+			command = FirstCommand.fromLine(line);
 		}
 
 		/** @return non-capabilities part of the line. */
 		public String getLine() {
-			return line;
+			return command.getLine();
 		}
 
 		/** @return capabilities parsed from the line. */
 		public Set<String> getCapabilities() {
-			return capabilities;
+			return command.getCapabilities();
 		}
 	}
 
 	/** Database we write the stored objects into. */
-	private final Repository db;
+	final Repository db;
 
 	/** Revision traversal support over {@link #db}. */
-	private final RevWalk walk;
+	final RevWalk walk;
 
 	/**
 	 * Is the client connection a bi-directional socket or pipe?
@@ -207,7 +204,7 @@ public Set<String> getCapabilities() {
 	private AdvertiseRefsHook advertiseRefsHook;
 
 	/** Filter used while advertising the refs to the client. */
-	private RefFilter refFilter;
+	RefFilter refFilter;
 
 	/** Timeout in seconds to wait for client interaction. */
 	private int timeout;
@@ -242,10 +239,10 @@ public Set<String> getCapabilities() {
 	private PackParser parser;
 
 	/** The refs we advertised as existing at the start of the connection. */
-	private Map<String, Ref> refs;
+	Map<String, Ref> refs;
 
 	/** All SHA-1s shown to the client, which can be possible edges. */
-	private Set<ObjectId> advertisedHaves;
+	Set<ObjectId> advertisedHaves;
 
 	/** Capabilities requested by the client. */
 	private Set<String> enabledCapabilities;
@@ -278,7 +275,7 @@ public Set<String> getCapabilities() {
 
 	private PushCertificateParser pushCertificateParser;
 	private SignedPushConfig signedPushConfig;
-	private PushCertificate pushCert;
+	PushCertificate pushCert;
 	private ReceivedPackStatistics stats;
 
 	/**
@@ -289,10 +286,10 @@ public Set<String> getCapabilities() {
 	 * @return the parsed certificate, or null if push certificates are disabled
 	 *         or no cert was presented by the client.
 	 * @since 4.1
+	 * @deprecated use {@link ReceivePack#getPushCertificate}.
 	 */
-	public PushCertificate getPushCertificate() {
-		return pushCert;
-	}
+	@Deprecated
+	public abstract PushCertificate getPushCertificate();
 
 	/**
 	 * Set the push certificate used to verify the pusher's identity.
@@ -303,10 +300,10 @@ public PushCertificate getPushCertificate() {
 	 * @param cert
 	 *            the push certificate to set.
 	 * @since 4.1
+	 * @deprecated use {@link ReceivePack#setPushCertificate(PushCertificate)}.
 	 */
-	public void setPushCertificate(PushCertificate cert) {
-		pushCert = cert;
-	}
+	@Deprecated
+	public abstract void setPushCertificate(PushCertificate cert);
 
 	/**
 	 * Create a new pack receive for an open repository.
@@ -424,29 +421,29 @@ public void flush() {
 	 * Get the repository this receive completes into.
 	 *
 	 * @return the repository this receive completes into.
+	 * @deprecated use {@link ReceivePack#getRepository}
 	 */
-	public final Repository getRepository() {
-		return db;
-	}
+	@Deprecated
+	public abstract Repository getRepository();
 
 	/**
 	 * Get the RevWalk instance used by this connection.
 	 *
 	 * @return the RevWalk instance used by this connection.
+	 * @deprecated use {@link ReceivePack#getRevWalk}
 	 */
-	public final RevWalk getRevWalk() {
-		return walk;
-	}
+	@Deprecated
+	public abstract RevWalk getRevWalk();
 
 	/**
 	 * Get refs which were advertised to the client.
 	 *
 	 * @return all refs which were advertised to the client, or null if
 	 *         {@link #setAdvertisedRefs(Map, Set)} has not been called yet.
+	 * @deprecated use {@link ReceivePack#getAdvertisedRefs}
 	 */
-	public final Map<String, Ref> getAdvertisedRefs() {
-		return refs;
-	}
+	@Deprecated
+	public abstract Map<String, Ref> getAdvertisedRefs();
 
 	/**
 	 * Set the refs advertised by this ReceivePack.
@@ -464,25 +461,10 @@ public final Map<String, Ref> getAdvertisedRefs() {
 	 *            explicit set of additional haves to claim as advertised. If
 	 *            null, assumes the default set of additional haves from the
 	 *            repository.
+	 * @deprecated use {@link ReceivePack#setAdvertisedRefs}
 	 */
-	public void setAdvertisedRefs(Map<String, Ref> allRefs, Set<ObjectId> additionalHaves) {
-		refs = allRefs != null ? allRefs : db.getAllRefs();
-		refs = refFilter.filter(refs);
-		advertisedHaves.clear();
-
-		Ref head = refs.get(Constants.HEAD);
-		if (head != null && head.isSymbolic())
-			refs.remove(Constants.HEAD);
-
-		for (Ref ref : refs.values()) {
-			if (ref.getObjectId() != null)
-				advertisedHaves.add(ref.getObjectId());
-		}
-		if (additionalHaves != null)
-			advertisedHaves.addAll(additionalHaves);
-		else
-			advertisedHaves.addAll(db.getAdditionalHaves());
-	}
+	@Deprecated
+	public abstract void setAdvertisedRefs(Map<String, Ref> allRefs, Set<ObjectId> additionalHaves);
 
 	/**
 	 * Get objects advertised to the client.
@@ -1310,7 +1292,7 @@ protected void recvCommands() throws IOException {
 
 				if (firstPkt) {
 					firstPkt = false;
-					FirstLine firstLine = new FirstLine(line);
+					FirstCommand firstLine = FirstCommand.fromLine(line);
 					enabledCapabilities = firstLine.getCapabilities();
 					line = firstLine.getLine();
 					enableCapabilities();
@@ -1606,7 +1588,7 @@ private void checkConnectivity() throws IOException {
 						throw new MissingObjectException(o, o.getType());
 				}
 
-				if (o instanceof RevBlob && !db.hasObject(o))
+				if (o instanceof RevBlob && !db.getObjectDatabase().has(o))
 					throw new MissingObjectException(o, Constants.TYPE_BLOB);
 			}
 			checking.endTask();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/FetchProcess.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/FetchProcess.java
index 211707e..681ae12 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/FetchProcess.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/FetchProcess.java
@@ -181,7 +181,7 @@ else if (tagopt == TagOpt.FETCH_TAGS)
 					ObjectId id = r.getPeeledObjectId();
 					if (id == null)
 						id = r.getObjectId();
-					if (transport.local.hasObject(id))
+					if (localHasObject(id))
 						wantTag(r);
 				}
 
@@ -393,6 +393,18 @@ private void expandSingle(RefSpec spec, Set<Ref> matched)
 		}
 	}
 
+	private boolean localHasObject(ObjectId id) throws TransportException {
+		try {
+			return transport.local.getObjectDatabase().has(id);
+		} catch (IOException err) {
+			throw new TransportException(
+					MessageFormat.format(
+							JGitText.get().readingObjectsFromLocalRepositoryFailed,
+							err.getMessage()),
+					err);
+		}
+	}
+
 	private Collection<Ref> expandAutoFollowTags() throws TransportException {
 		final Collection<Ref> additionalTags = new ArrayList<>();
 		final Map<String, Ref> haveRefs = localRefs();
@@ -410,7 +422,7 @@ private Collection<Ref> expandAutoFollowTags() throws TransportException {
 			if (obj == null)
 				obj = r.getObjectId();
 
-			if (askFor.containsKey(obj) || transport.local.hasObject(obj))
+			if (askFor.containsKey(obj) || localHasObject(obj))
 				wantTag(r);
 			else
 				additionalTags.add(r);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/InternalHttpServerGlue.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/InternalHttpServerGlue.java
index fe7aaf7..075cc9c 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/InternalHttpServerGlue.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/InternalHttpServerGlue.java
@@ -44,7 +44,7 @@
 package org.eclipse.jgit.transport;
 
 /**
- * Internal API to to assist {@code org.eclipse.jgit.http.server}.
+ * Internal API to assist {@code org.eclipse.jgit.http.server}.
  * <p>
  * <b>Do not call.</b>
  *
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/NonceGenerator.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/NonceGenerator.java
index fc22034..c573d12 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/NonceGenerator.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/NonceGenerator.java
@@ -81,7 +81,7 @@ String createNonce(Repository db, long timestamp)
 	 *            such that the pusher cannot forge nonces by pushing to another
 	 *            repository at the same time as well and reusing the nonce.
 	 * @param allowSlop
-	 *            If the receiving backend is is able to generate slop. This is
+	 *            If the receiving backend is able to generate slop. This is
 	 *            the case for serving via http protocol using more than one
 	 *            http frontend. The client would talk to different http
 	 *            frontends, which may have a slight difference of time due to
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PackParser.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PackParser.java
index 49acb4d..2b2795f 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PackParser.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PackParser.java
@@ -1237,7 +1237,7 @@ void use(int cnt) {
 		bAvail -= cnt;
 	}
 
-	// Ensure at least need bytes are available in in {@link #buf}.
+	// Ensure at least need bytes are available in {@link #buf}.
 	int fill(Source src, int need) throws IOException {
 		while (bAvail < need) {
 			int next = bOffset + bAvail;
@@ -1568,7 +1568,7 @@ protected abstract void onBeginWholeObject(long streamPosition, int type,
 			long inflatedSize) throws IOException;
 
 	/**
-	 * Event notifying the the current object.
+	 * Event notifying the current object.
 	 *
 	 *@param info
 	 *            object information.
@@ -1616,7 +1616,7 @@ protected abstract void onBeginRefDelta(long deltaStreamPosition,
 			AnyObjectId baseId, long inflatedSize) throws IOException;
 
 	/**
-	 * Event notifying the the current object.
+	 * Event notifying the current object.
 	 *
 	 *@return object information that must be populated with at least the
 	 *         offset.
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceivePack.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceivePack.java
index 577aaf4..4652c3f 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceivePack.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceivePack.java
@@ -43,6 +43,7 @@
 
 package org.eclipse.jgit.transport;
 
+import static org.eclipse.jgit.lib.Constants.HEAD;
 import static org.eclipse.jgit.transport.GitProtocolConstants.CAPABILITY_ATOMIC;
 import static org.eclipse.jgit.transport.GitProtocolConstants.CAPABILITY_PUSH_OPTIONS;
 import static org.eclipse.jgit.transport.GitProtocolConstants.CAPABILITY_REPORT_STATUS;
@@ -53,13 +54,18 @@
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
+import java.util.Map;
+import java.util.Set;
 
 import org.eclipse.jgit.annotations.Nullable;
 import org.eclipse.jgit.errors.UnpackException;
 import org.eclipse.jgit.lib.ConfigConstants;
 import org.eclipse.jgit.lib.Constants;
 import org.eclipse.jgit.lib.NullProgressMonitor;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.Ref;
 import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.revwalk.RevWalk;
 import org.eclipse.jgit.transport.ReceiveCommand.Result;
 import org.eclipse.jgit.transport.RefAdvertiser.PacketLineOutRefAdvertiser;
 
@@ -93,6 +99,106 @@ public ReceivePack(Repository into) {
 	}
 
 	/**
+	 * Get the repository this receive completes into.
+	 *
+	 * @return the repository this receive completes into.
+	 */
+	@Override
+	public final Repository getRepository() {
+		return db;
+	}
+
+	/**
+	 * Get the RevWalk instance used by this connection.
+	 *
+	 * @return the RevWalk instance used by this connection.
+	 */
+	@Override
+	public final RevWalk getRevWalk() {
+		return walk;
+	}
+
+	/**
+	 * Get refs which were advertised to the client.
+	 *
+	 * @return all refs which were advertised to the client, or null if
+	 *         {@link #setAdvertisedRefs(Map, Set)} has not been called yet.
+	 */
+	@Override
+	public final Map<String, Ref> getAdvertisedRefs() {
+		return refs;
+	}
+
+	/**
+	 * Set the refs advertised by this ReceivePack.
+	 * <p>
+	 * Intended to be called from a
+	 * {@link org.eclipse.jgit.transport.PreReceiveHook}.
+	 *
+	 * @param allRefs
+	 *            explicit set of references to claim as advertised by this
+	 *            ReceivePack instance. This overrides any references that may
+	 *            exist in the source repository. The map is passed to the
+	 *            configured {@link #getRefFilter()}. If null, assumes all refs
+	 *            were advertised.
+	 * @param additionalHaves
+	 *            explicit set of additional haves to claim as advertised. If
+	 *            null, assumes the default set of additional haves from the
+	 *            repository.
+	 */
+	@Override
+	public void setAdvertisedRefs(Map<String, Ref> allRefs, Set<ObjectId> additionalHaves) {
+		refs = allRefs != null ? allRefs : db.getAllRefs();
+		refs = refFilter.filter(refs);
+		advertisedHaves.clear();
+
+		Ref head = refs.get(HEAD);
+		if (head != null && head.isSymbolic()) {
+			refs.remove(HEAD);
+		}
+
+		for (Ref ref : refs.values()) {
+			if (ref.getObjectId() != null) {
+				advertisedHaves.add(ref.getObjectId());
+			}
+		}
+		if (additionalHaves != null) {
+			advertisedHaves.addAll(additionalHaves);
+		} else {
+			advertisedHaves.addAll(db.getAdditionalHaves());
+		}
+	}
+
+	/**
+	 * Get the push certificate used to verify the pusher's identity.
+	 * <p>
+	 * Only valid after commands are read from the wire.
+	 *
+	 * @return the parsed certificate, or null if push certificates are disabled
+	 *         or no cert was presented by the client.
+	 * @since 4.1
+	 */
+	@Override
+	public PushCertificate getPushCertificate() {
+		return pushCert;
+	}
+
+	/**
+	 * Set the push certificate used to verify the pusher's identity.
+	 * <p>
+	 * Should only be called if reconstructing an instance without going through
+	 * the normal {@link #recvCommands()} flow.
+	 *
+	 * @param cert
+	 *            the push certificate to set.
+	 * @since 4.1
+	 */
+	@Override
+	public void setPushCertificate(PushCertificate cert) {
+		pushCert = cert;
+	}
+
+	/**
 	 * Gets an unmodifiable view of the option strings associated with the push.
 	 *
 	 * @return an unmodifiable view of pushOptions, or null (if pushOptions is).
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java
index 2fbcaa2..62c8dc9 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java
@@ -421,7 +421,7 @@ public final Map<String, Ref> getAdvertisedRefs() {
 	 *            configured {@link #getRefFilter()}. If null, assumes all refs
 	 *            were advertised.
 	 */
-	public void setAdvertisedRefs(Map<String, Ref> allRefs) {
+	public void setAdvertisedRefs(@Nullable Map<String, Ref> allRefs) {
 		if (allRefs != null)
 			refs = allRefs;
 		else
@@ -545,7 +545,7 @@ public void setRequestPolicy(RequestPolicy policy) {
 	 *            custom validator for client want list.
 	 * @since 3.1
 	 */
-	public void setRequestValidator(RequestValidator validator) {
+	public void setRequestValidator(@Nullable RequestValidator validator) {
 		requestValidator = validator != null ? validator
 				: new AdvertisedRequestValidator();
 	}
@@ -579,21 +579,21 @@ public RefFilter getRefFilter() {
 	 * @param advertiseRefsHook
 	 *            the hook; may be null to show all refs.
 	 */
-	public void setAdvertiseRefsHook(AdvertiseRefsHook advertiseRefsHook) {
-		if (advertiseRefsHook != null)
-			this.advertiseRefsHook = advertiseRefsHook;
-		else
-			this.advertiseRefsHook = AdvertiseRefsHook.DEFAULT;
+	public void setAdvertiseRefsHook(
+			@Nullable AdvertiseRefsHook advertiseRefsHook) {
+		this.advertiseRefsHook = advertiseRefsHook != null ? advertiseRefsHook
+				: AdvertiseRefsHook.DEFAULT;
 	}
 
 	/**
 	 * Set the protocol V2 hook.
 	 *
 	 * @param hook
+	 *            the hook; if null no special actions are taken.
 	 * @since 5.1
 	 */
-	public void setProtocolV2Hook(ProtocolV2Hook hook) {
-		this.protocolV2Hook = hook;
+	public void setProtocolV2Hook(@Nullable ProtocolV2Hook hook) {
+		this.protocolV2Hook = hook != null ? hook : ProtocolV2Hook.DEFAULT;
 	}
 
 	/**
@@ -608,7 +608,7 @@ public void setProtocolV2Hook(ProtocolV2Hook hook) {
 	 * @param refFilter
 	 *            the filter; may be null to show all refs.
 	 */
-	public void setRefFilter(RefFilter refFilter) {
+	public void setRefFilter(@Nullable RefFilter refFilter) {
 		this.refFilter = refFilter != null ? refFilter : RefFilter.DEFAULT;
 	}
 
@@ -627,7 +627,7 @@ public PreUploadHook getPreUploadHook() {
 	 * @param hook
 	 *            the hook; if null no special actions are taken.
 	 */
-	public void setPreUploadHook(PreUploadHook hook) {
+	public void setPreUploadHook(@Nullable PreUploadHook hook) {
 		preUploadHook = hook != null ? hook : PreUploadHook.NULL;
 	}
 
@@ -648,7 +648,7 @@ public PostUploadHook getPostUploadHook() {
 	 *            the hook; if null no special actions are taken.
 	 * @since 4.1
 	 */
-	public void setPostUploadHook(PostUploadHook hook) {
+	public void setPostUploadHook(@Nullable PostUploadHook hook) {
 		postUploadHook = hook != null ? hook : PostUploadHook.NULL;
 	}
 
@@ -659,7 +659,7 @@ public void setPostUploadHook(PostUploadHook hook) {
 	 *            configuration controlling packing parameters. If null the
 	 *            source repository's settings will be used.
 	 */
-	public void setPackConfig(PackConfig pc) {
+	public void setPackConfig(@Nullable PackConfig pc) {
 		this.packConfig = pc;
 	}
 
@@ -671,7 +671,7 @@ public void setPackConfig(PackConfig pc) {
 	 *            repository's settings will be used.
 	 * @since 3.1
 	 */
-	public void setTransferConfig(TransferConfig tc) {
+	public void setTransferConfig(@Nullable TransferConfig tc) {
 		this.transferConfig = tc != null ? tc : new TransferConfig(db);
 		if (transferConfig.isAllowTipSha1InWant()) {
 			setRequestPolicy(transferConfig.isAllowReachableSha1InWant()
@@ -906,7 +906,7 @@ private Ref findRef(String name) throws IOException {
 				refFilter == RefFilter.DEFAULT &&
 				transferConfig.hasDefaultRefFilter()) {
 			// Fast path: no ref filtering is needed.
-			return db.getRefDatabase().getRef(name);
+			return db.getRefDatabase().findRef(name);
 		}
 		return RefDatabase.findRef(getAdvertisedOrDefaultRefs(), name);
 	}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/WalkFetchConnection.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/WalkFetchConnection.java
index 9307914..2bb5814 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/WalkFetchConnection.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/WalkFetchConnection.java
@@ -555,10 +555,10 @@ private boolean downloadPackedObject(final ProgressMonitor monitor,
 				continue;
 			} finally {
 				// If the pack was good its in the local repository
-				// and Repository.hasObject(id) will succeed in the
-				// future, so we do not need this data anymore. If
-				// it failed the index and pack are unusable and we
-				// shouldn't consult them again.
+				// and Repository.getObjectDatabase().has(id) will
+				// succeed in the future, so we do not need this
+				// data any more. If it failed the index and pack
+				// are unusable and we shouldn't consult them again.
 				//
 				try {
 					if (pack.tmpIdx != null)
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/WalkRemoteObjectDatabase.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/WalkRemoteObjectDatabase.java
index 6d4df4f..5c67253 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/WalkRemoteObjectDatabase.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/WalkRemoteObjectDatabase.java
@@ -348,7 +348,7 @@ void writeInfoPacks(Collection<String> packNames) throws IOException {
 	/**
 	 * Open a buffered reader around a file.
 	 * <p>
-	 * This method is suitable for for reading line-oriented resources like
+	 * This method is suitable for reading line-oriented resources like
 	 * <code>info/packs</code>, <code>info/refs</code>, and the alternates list.
 	 *
 	 * @return a stream to read from the file. Never null.
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/RawParseUtils.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/RawParseUtils.java
index a440cb2..9feb20a 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/RawParseUtils.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/RawParseUtils.java
@@ -57,6 +57,7 @@
 import java.nio.charset.CharsetDecoder;
 import java.nio.charset.CodingErrorAction;
 import java.nio.charset.IllegalCharsetNameException;
+import java.nio.charset.StandardCharsets;
 import java.nio.charset.UnsupportedCharsetException;
 import java.util.Arrays;
 import java.util.HashMap;
@@ -75,7 +76,9 @@ public final class RawParseUtils {
 	 * UTF-8 charset constant.
 	 *
 	 * @since 2.2
+	 * @deprecated use {@link StandardCharsets#UTF_8} instead
 	 */
+	@Deprecated
 	public static final Charset UTF8_CHARSET = UTF_8;
 
 	private static final byte[] digits10;
diff --git a/pom.xml b/pom.xml
index 04238e8..4928e5b 100644
--- a/pom.xml
+++ b/pom.xml
@@ -51,7 +51,7 @@
   <groupId>org.eclipse.jgit</groupId>
   <artifactId>org.eclipse.jgit-parent</artifactId>
   <packaging>pom</packaging>
-  <version>5.2.2-SNAPSHOT</version>
+  <version>5.3.0-SNAPSHOT</version>
 
   <name>JGit - Parent</name>
   <url>${jgit-url}</url>
@@ -182,7 +182,7 @@
     <maven.build.timestamp.format>yyyyMMddHHmm</maven.build.timestamp.format>
     <bundle-manifest>${project.build.directory}/META-INF/MANIFEST.MF</bundle-manifest>
 
-    <jgit-last-release-version>5.1.0.201809111528-r</jgit-last-release-version>
+    <jgit-last-release-version>5.2.0.201812061821-r</jgit-last-release-version>
     <apache-sshd-version>2.0.0</apache-sshd-version>
     <jsch-version>0.1.54</jsch-version>
     <jzlib-version>1.1.1</jzlib-version>
@@ -200,9 +200,9 @@
     <slf4j-version>1.7.2</slf4j-version>
     <log4j-version>1.2.15</log4j-version>
     <maven-javadoc-plugin-version>3.0.1</maven-javadoc-plugin-version>
-    <tycho-extras-version>1.2.0</tycho-extras-version>
+    <tycho-extras-version>1.3.0</tycho-extras-version>
     <gson-version>2.8.2</gson-version>
-    <spotbugs-maven-plugin-version>3.1.8</spotbugs-maven-plugin-version>
+    <spotbugs-maven-plugin-version>3.1.10</spotbugs-maven-plugin-version>
     <maven-surefire-version>2.22.1</maven-surefire-version>
     <maven-compiler-plugin-version>3.8.0</maven-compiler-plugin-version>
     <maven-project-info-reports-plugin-version>3.0.0</maven-project-info-reports-plugin-version>
@@ -211,7 +211,7 @@
     <!-- Properties to enable jacoco code coverage analysis -->
     <sonar.core.codeCoveragePlugin>jacoco</sonar.core.codeCoveragePlugin>
     <sonar.dynamicAnalysis>reuseReports</sonar.dynamicAnalysis>
-    <sonar.jacoco.reportPath>../target/jacoco.exec</sonar.jacoco.reportPath>
+    <sonar.jacoco.reportPath>${project.build.directory}/jacoco.exec</sonar.jacoco.reportPath>
   </properties>
 
   <repositories>
@@ -238,7 +238,7 @@
         <plugin>
           <groupId>org.apache.maven.plugins</groupId>
           <artifactId>maven-jar-plugin</artifactId>
-          <version>3.1.0</version>
+          <version>3.1.1</version>
           <configuration>
             <archive>
               <manifestEntries>
@@ -297,6 +297,7 @@
           <configuration>
             <forkCount>${test-fork-count}</forkCount>
             <reuseForks>true</reuseForks>
+            <argLine>@{argLine}</argLine>
           </configuration>
         </plugin>
 
@@ -374,7 +375,7 @@
             <dependency><!-- add support for ssh/scp -->
               <groupId>org.apache.maven.wagon</groupId>
               <artifactId>wagon-ssh</artifactId>
-              <version>3.2.0</version>
+              <version>3.3.1</version>
             </dependency>
           </dependencies>
         </plugin>
@@ -498,6 +499,7 @@
         <artifactId>jacoco-maven-plugin</artifactId>
         <executions>
           <execution>
+            <id>default-prepare-agent</id>
             <goals>
               <goal>prepare-agent</goal>
             </goals>
@@ -512,6 +514,38 @@
               <append>true</append>
             </configuration>
           </execution>
+          <execution>
+            <id>default-report</id>
+            <goals>
+              <goal>report</goal>
+            </goals>
+          </execution>
+          <execution>
+            <id>default-check</id>
+            <goals>
+              <goal>check</goal>
+            </goals>
+            <configuration>
+            <haltOnFailure>false</haltOnFailure>
+            <rules>
+              <rule>
+                <element>BUNDLE</element>
+                  <limits>
+                    <limit>
+                      <counter>INSTRUCTION</counter>
+                      <value>COVEREDRATIO</value>
+                      <minimum>50%</minimum>
+                    </limit>
+                    <limit>
+                      <counter>CLASS</counter>
+                      <value>MISSEDCOUNT</value>
+                      <maximum>10</maximum>
+                    </limit>
+                  </limits>
+                </rule>
+              </rules>
+            </configuration>
+          </execution>
         </executions>
       </plugin>
       <plugin>
@@ -589,6 +623,24 @@
           </reportSet>
         </reportSets>
       </plugin>
+      <plugin>
+        <groupId>org.jacoco</groupId>
+        <artifactId>jacoco-maven-plugin</artifactId>
+        <reportSets>
+          <reportSet>
+            <reports>
+              <report>report</report>
+            </reports>
+          </reportSet>
+          <reportSet>
+            <id>aggregate</id>
+            <inherited>false</inherited>
+            <reports>
+              <report>report-aggregate</report>
+            </reports>
+          </reportSet>
+        </reportSets>
+      </plugin>
     </plugins>
   </reporting>
 
@@ -639,7 +691,7 @@
       <dependency>
         <groupId>org.tukaani</groupId>
         <artifactId>xz</artifactId>
-        <version>1.6</version>
+        <version>1.8</version>
         <optional>true</optional>
       </dependency>
 
@@ -783,7 +835,7 @@
               <dependency>
                 <groupId>org.codehaus.plexus</groupId>
                 <artifactId>plexus-compiler-javac-errorprone</artifactId>
-                <version>2.8.4</version>
+                <version>2.8.5</version>
               </dependency>
               <!-- override plexus-compiler-javac-errorprone's dependency on
                   Error Prone with the latest version -->
@@ -938,6 +990,8 @@
     <module>org.eclipse.jgit.lfs.test</module>
     <module>org.eclipse.jgit.lfs.server.test</module>
     <module>org.eclipse.jgit.ssh.apache.test</module>
+
+    <module>org.eclipse.jgit.coverage</module>
   </modules>
 
 </project>