Merge branch 'stable-4.5' into stable-4.6

* stable-4.5:
  Fix exception handling for opening bitmap index files

Change-Id: Ifb511238e3e98b1bc9f79a990807b940a17ebaa6
Signed-off-by: Matthias Sohn <matthias.sohn@sap.com>
diff --git a/.buckconfig b/.buckconfig
index 8d2572b..7986494 100644
--- a/.buckconfig
+++ b/.buckconfig
@@ -12,6 +12,8 @@
 
 [java]
   src_roots = src, resources, tst
+  source_level = 8
+  target_level = 8
 
 [project]
   ignore = .git
diff --git a/.buckversion b/.buckversion
index f5fe016..7eb591f 100644
--- a/.buckversion
+++ b/.buckversion
@@ -1 +1 @@
-e64a2e2ada022f81e42be750b774024469551398
+e27df656657f93f8d57a7aaac69a5ae0e298a292
diff --git a/.gitignore b/.gitignore
index 95ad174..e78f8fd 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,3 +3,4 @@
 /buck-cache
 /buck-out
 /target
+infer-out
diff --git a/.mvn/jvm.config b/.mvn/jvm.config
new file mode 100644
index 0000000..9b109f3
--- /dev/null
+++ b/.mvn/jvm.config
@@ -0,0 +1 @@
+-Xmx1024m
\ No newline at end of file
diff --git a/.mvn/maven.config b/.mvn/maven.config
new file mode 100644
index 0000000..ebbe288
--- /dev/null
+++ b/.mvn/maven.config
@@ -0,0 +1 @@
+-T 1C
diff --git a/README.md b/README.md
index 9aca10f..54133e1 100644
--- a/README.md
+++ b/README.md
@@ -72,7 +72,7 @@
 - Only the timestamp of the index is used by jgit if the index is
   dirty.
 
-- JGit requires at least a Java 7 JDK.
+- JGit requires at least a Java 8 JDK.
 
 - CRLF conversion is performed depending on the core.autocrlf setting,
   however Git for Windows by default stores that setting during
diff --git a/lib/BUCK b/lib/BUCK
index 2421b40..d89af5d 100644
--- a/lib/BUCK
+++ b/lib/BUCK
@@ -9,11 +9,11 @@
 
 maven_jar(
   name = 'javaewah',
-  bin_sha1 = 'eceaf316a8faf0e794296ebe158ae110c7d72a5a',
-  src_sha1 = 'a50d78eb630e05439461f3130b94b3bcd1ea6f03',
+  bin_sha1 = '94ad16d728b374d65bd897625f3fbb3da223a2b6',
+  src_sha1 = 'ca2745e91c6a51f8e6809d1579bda36ad83f1f58',
   group = 'com.googlecode.javaewah',
   artifact = 'JavaEWAH',
-  version = '0.7.9',
+  version = '1.1.6',
 )
 
 maven_jar(
diff --git a/lib/jetty/BUCK b/lib/jetty/BUCK
index 6e7dec3..fbb37c1 100644
--- a/lib/jetty/BUCK
+++ b/lib/jetty/BUCK
@@ -1,10 +1,10 @@
-VERSION = '9.2.13.v20150730'
+VERSION = '9.3.17.v20170317'
 GROUP = 'org.eclipse.jetty'
 
 maven_jar(
   name = 'servlet',
-  bin_sha1 = '5ad6e38015a97ae9a60b6c2ad744ccfa9cf93a50',
-  src_sha1 = '78fbec19321150552d91f9e079c2f2ca33222b01',
+  bin_sha1 = 'ed6986b0d0ca7b9b0f9015c9efb80442e3043a8e',
+  src_sha1 = 'ee6b4784a00a92e5c1b6111033b7ae41ac6052a3',
   group = GROUP,
   artifact = 'jetty-servlet',
   version = VERSION,
@@ -12,8 +12,8 @@
 
 maven_jar(
   name = 'security',
-  bin_sha1 = 'cc7c7f27ec4cc279253be1675d9e47e58b995943',
-  src_sha1 = '75632ebdf8bd651faafb97106c92496db59e165d',
+  bin_sha1 = 'ca52535569445682d42aaa97c7039442719a0507',
+  src_sha1 = '2ff9f4fb18b320fd5a0272a427bacc4d5fe7bc86',
   group = GROUP,
   artifact = 'jetty-security',
   version = VERSION,
@@ -21,8 +21,8 @@
 
 maven_jar(
   name = 'server',
-  bin_sha1 = '5be7d1da0a7abffd142de3091d160717c120b6ab',
-  src_sha1 = '203e123f83efe2a5b8a9c74854c7897fe3563302',
+  bin_sha1 = '194e9a02e6ba249ef4a3f4bd56b4993087992299',
+  src_sha1 = '0c9bd572f530c411592aefb71781ecca0b3719a9',
   group = GROUP,
   artifact = 'jetty-server',
   version = VERSION,
@@ -30,8 +30,8 @@
 
 maven_jar(
   name = 'http',
-  bin_sha1 = '23a745d9177ef67ef53cc46b9b70c5870082efc2',
-  src_sha1 = '5f87f7ff2057cd4b0995bc4fffe17b2aff64c130',
+  bin_sha1 = '6c02d728e15d4868486254039c867a1ac3e4a52e',
+  src_sha1 = '3c0a2a82792f268631b4fefd77be9f126ec974b1',
   group = GROUP,
   artifact = 'jetty-http',
   version = VERSION,
@@ -39,8 +39,8 @@
 
 maven_jar(
   name = 'io',
-  bin_sha1 = '7a351e6a1b63dfd56b6632623f7ca2793ffb67ad',
-  src_sha1 = 'bbd61a84b748fc295456e1c5c3070aaf40a68f62',
+  bin_sha1 = '756a8cd2a1cbfb84a94973b6332dd3eccd47c0cd',
+  src_sha1 = 'a9afa99cccb19b441364fa805d027f457cbbb136',
   group = GROUP,
   artifact = 'jetty-io',
   version = VERSION,
@@ -48,8 +48,8 @@
 
 maven_jar(
   name = 'util',
-  bin_sha1 = 'c101476360a7cdd0670462de04053507d5e70c97',
-  src_sha1 = '15ceecce141971b4e0facb861b3d10120ad6ce03',
+  bin_sha1 = 'b8512ab02819de01f0f5a5c6026163041f579beb',
+  src_sha1 = '96f8e3dcdc3660a5c91f19c46695daa70ac95625',
   group = GROUP,
   artifact = 'jetty-util',
   version = VERSION,
diff --git a/org.eclipse.jgit.ant.test/.classpath b/org.eclipse.jgit.ant.test/.classpath
index 098194c..eca7bdb 100644
--- a/org.eclipse.jgit.ant.test/.classpath
+++ b/org.eclipse.jgit.ant.test/.classpath
@@ -1,6 +1,6 @@
 <?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.7"/>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
 	<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
 	<classpathentry kind="src" path="src"/>
 	<classpathentry kind="output" path="bin"/>
diff --git a/org.eclipse.jgit.ant.test/.settings/org.eclipse.jdt.core.prefs b/org.eclipse.jgit.ant.test/.settings/org.eclipse.jdt.core.prefs
index 87210fb..10c29d5 100644
--- a/org.eclipse.jgit.ant.test/.settings/org.eclipse.jdt.core.prefs
+++ b/org.eclipse.jgit.ant.test/.settings/org.eclipse.jdt.core.prefs
@@ -7,9 +7,9 @@
 org.eclipse.jdt.core.compiler.annotation.nullanalysis=disabled
 org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
 org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
-org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
 org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
-org.eclipse.jdt.core.compiler.compliance=1.7
+org.eclipse.jdt.core.compiler.compliance=1.8
 org.eclipse.jdt.core.compiler.debug.lineNumber=generate
 org.eclipse.jdt.core.compiler.debug.localVariable=generate
 org.eclipse.jdt.core.compiler.debug.sourceFile=generate
@@ -112,7 +112,7 @@
 org.eclipse.jdt.core.compiler.problem.unusedTypeParameter=ignore
 org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning
 org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=error
-org.eclipse.jdt.core.compiler.source=1.7
+org.eclipse.jdt.core.compiler.source=1.8
 org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16
 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0
diff --git a/org.eclipse.jgit.ant.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.ant.test/META-INF/MANIFEST.MF
index 5eff9d9..3bf69c3 100644
--- a/org.eclipse.jgit.ant.test/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.ant.test/META-INF/MANIFEST.MF
@@ -3,14 +3,14 @@
 Bundle-ManifestVersion: 2
 Bundle-Name: %plugin_name
 Bundle-SymbolicName: org.eclipse.jgit.ant.test
-Bundle-Version: 4.5.3.qualifier
+Bundle-Version: 4.6.2.qualifier
 Bundle-ActivationPolicy: lazy
-Bundle-RequiredExecutionEnvironment: JavaSE-1.7
+Bundle-RequiredExecutionEnvironment: JavaSE-1.8
 Import-Package: org.apache.tools.ant,
- org.eclipse.jgit.ant.tasks;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.internal.storage.file;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.junit;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.lib;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.util;version="[4.5.3,4.6.0)",
+ org.eclipse.jgit.ant.tasks;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.internal.storage.file;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.junit;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.lib;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.util;version="[4.6.2,4.7.0)",
  org.hamcrest;version="[1.1.0,2.0.0)",
  org.junit;version="[4.0.0,5.0.0)"
diff --git a/org.eclipse.jgit.ant.test/build.properties b/org.eclipse.jgit.ant.test/build.properties
index e3effea..4a2d892 100644
--- a/org.eclipse.jgit.ant.test/build.properties
+++ b/org.eclipse.jgit.ant.test/build.properties
@@ -3,5 +3,5 @@
 bin.includes = plugin.properties,\
 			   META-INF/,\
 			   .
-jre.compilation.profile = JavaSE-1.7
+jre.compilation.profile = JavaSE-1.8
 additional.bundles = org.eclipse.jgit
diff --git a/org.eclipse.jgit.ant.test/pom.xml b/org.eclipse.jgit.ant.test/pom.xml
index ea58132..9592841 100644
--- a/org.eclipse.jgit.ant.test/pom.xml
+++ b/org.eclipse.jgit.ant.test/pom.xml
@@ -50,7 +50,7 @@
   <parent>
     <groupId>org.eclipse.jgit</groupId>
     <artifactId>org.eclipse.jgit-parent</artifactId>
-    <version>4.5.3-SNAPSHOT</version>
+    <version>4.6.2-SNAPSHOT</version>
   </parent>
 
   <artifactId>org.eclipse.jgit.ant.test</artifactId>
diff --git a/org.eclipse.jgit.ant/.classpath b/org.eclipse.jgit.ant/.classpath
index a14ade4..110168f 100644
--- a/org.eclipse.jgit.ant/.classpath
+++ b/org.eclipse.jgit.ant/.classpath
@@ -1,6 +1,6 @@
 <?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.7"/>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
 	<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
 	<classpathentry kind="src" path="src"/>
 	<classpathentry kind="src" path="resources"/>
diff --git a/org.eclipse.jgit.ant/.settings/org.eclipse.jdt.core.prefs b/org.eclipse.jgit.ant/.settings/org.eclipse.jdt.core.prefs
index cd620c3..80cfbbb 100644
--- a/org.eclipse.jgit.ant/.settings/org.eclipse.jdt.core.prefs
+++ b/org.eclipse.jgit.ant/.settings/org.eclipse.jdt.core.prefs
@@ -7,9 +7,9 @@
 org.eclipse.jdt.core.compiler.annotation.nullanalysis=disabled
 org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
 org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
-org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
 org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
-org.eclipse.jdt.core.compiler.compliance=1.7
+org.eclipse.jdt.core.compiler.compliance=1.8
 org.eclipse.jdt.core.compiler.debug.lineNumber=generate
 org.eclipse.jdt.core.compiler.debug.localVariable=generate
 org.eclipse.jdt.core.compiler.debug.sourceFile=generate
@@ -112,7 +112,7 @@
 org.eclipse.jdt.core.compiler.problem.unusedTypeParameter=ignore
 org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning
 org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=error
-org.eclipse.jdt.core.compiler.source=1.7
+org.eclipse.jdt.core.compiler.source=1.8
 org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16
 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0
diff --git a/org.eclipse.jgit.ant/META-INF/MANIFEST.MF b/org.eclipse.jgit.ant/META-INF/MANIFEST.MF
index dfa9311..6b008e1 100644
--- a/org.eclipse.jgit.ant/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.ant/META-INF/MANIFEST.MF
@@ -2,11 +2,11 @@
 Bundle-ManifestVersion: 2
 Bundle-Name: %Bundle-Name
 Bundle-SymbolicName: org.eclipse.jgit.ant
-Bundle-Version: 4.5.3.qualifier
-Bundle-RequiredExecutionEnvironment: JavaSE-1.7
+Bundle-Version: 4.6.2.qualifier
+Bundle-RequiredExecutionEnvironment: JavaSE-1.8
 Import-Package: org.apache.tools.ant,
-  org.eclipse.jgit.storage.file;version="[4.5.3,4.6.0)"
+  org.eclipse.jgit.storage.file;version="[4.6.2,4.7.0)"
 Bundle-Localization: plugin
 Bundle-Vendor: %Provider-Name
-Export-Package: org.eclipse.jgit.ant.tasks;version="4.5.3";
+Export-Package: org.eclipse.jgit.ant.tasks;version="4.6.2";
  uses:="org.apache.tools.ant.types,org.apache.tools.ant"
diff --git a/org.eclipse.jgit.ant/pom.xml b/org.eclipse.jgit.ant/pom.xml
index 3a3052e..194c9dd 100644
--- a/org.eclipse.jgit.ant/pom.xml
+++ b/org.eclipse.jgit.ant/pom.xml
@@ -48,7 +48,7 @@
 	<parent>
 		<groupId>org.eclipse.jgit</groupId>
 		<artifactId>org.eclipse.jgit-parent</artifactId>
-		<version>4.5.3-SNAPSHOT</version>
+		<version>4.6.2-SNAPSHOT</version>
 	</parent>
 
 	<artifactId>org.eclipse.jgit.ant</artifactId>
diff --git a/org.eclipse.jgit.ant/src/org/eclipse/jgit/ant/tasks/GitAddTask.java b/org.eclipse.jgit.ant/src/org/eclipse/jgit/ant/tasks/GitAddTask.java
index b9a8688..db6f008 100644
--- a/org.eclipse.jgit.ant/src/org/eclipse/jgit/ant/tasks/GitAddTask.java
+++ b/org.eclipse.jgit.ant/src/org/eclipse/jgit/ant/tasks/GitAddTask.java
@@ -53,9 +53,10 @@
 import org.apache.tools.ant.types.resources.Union;
 import org.eclipse.jgit.api.AddCommand;
 import org.eclipse.jgit.api.Git;
-import org.eclipse.jgit.storage.file.FileRepositoryBuilder;
+import org.eclipse.jgit.api.errors.GitAPIException;
 import org.eclipse.jgit.lib.Repository;
 import org.eclipse.jgit.lib.RepositoryCache;
+import org.eclipse.jgit.storage.file.FileRepositoryBuilder;
 import org.eclipse.jgit.util.FS;
 
 /**
@@ -135,7 +136,7 @@
 				gitAdd.addFilepattern(toAdd);
 			}
 			gitAdd.call();
-		} catch (Exception e) {
+		} catch (IOException | GitAPIException e) {
 			throw new BuildException("Could not add files to index." + src, e);
 		}
 
diff --git a/org.eclipse.jgit.ant/src/org/eclipse/jgit/ant/tasks/GitCloneTask.java b/org.eclipse.jgit.ant/src/org/eclipse/jgit/ant/tasks/GitCloneTask.java
index f23f3b7..b2cb35c 100644
--- a/org.eclipse.jgit.ant/src/org/eclipse/jgit/ant/tasks/GitCloneTask.java
+++ b/org.eclipse.jgit.ant/src/org/eclipse/jgit/ant/tasks/GitCloneTask.java
@@ -49,12 +49,14 @@
 import org.apache.tools.ant.Task;
 import org.eclipse.jgit.api.CloneCommand;
 import org.eclipse.jgit.api.Git;
+import org.eclipse.jgit.api.errors.GitAPIException;
+import org.eclipse.jgit.api.errors.JGitInternalException;
 import org.eclipse.jgit.lib.Constants;
 import org.eclipse.jgit.transport.URIish;
 
 /**
  * Clone a repository into a new directory.
- * 
+ *
  * @see <a href="http://www.kernel.org/pub/software/scm/git/docs/git-clone.html"
  *      >git-clone(1)</a>
  */
@@ -76,9 +78,9 @@
 	/**
 	 * The optional directory associated with the clone operation. If the
 	 * directory isn't set, a name associated with the source uri will be used.
-	 * 
+	 *
 	 * @see URIish#getHumanishName()
-	 * 
+	 *
 	 * @param destination
 	 *            the directory to clone to
 	 */
@@ -105,12 +107,12 @@
 	@Override
 	public void execute() throws BuildException {
 		log("Cloning repository " + uri);
-		
+
 		CloneCommand clone = Git.cloneRepository();
 		try {
 			clone.setURI(uri).setDirectory(destination).setBranch(branch).setBare(bare);
 			clone.call().getRepository().close();
-		} catch (Exception e) {
+		} catch (GitAPIException | JGitInternalException e) {
 			log("Could not clone repository: " + e, e, Project.MSG_ERR);
 			throw new BuildException("Could not clone repository: " + e.getMessage(), e);
 		}
diff --git a/org.eclipse.jgit.archive/.classpath b/org.eclipse.jgit.archive/.classpath
index 3bc2475..22f3064 100644
--- a/org.eclipse.jgit.archive/.classpath
+++ b/org.eclipse.jgit.archive/.classpath
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <classpath>
 	<classpathentry kind="src" path="src"/>
-	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7"/>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
 	<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
 	<classpathentry kind="output" path="bin"/>
 </classpath>
diff --git a/org.eclipse.jgit.archive/.settings/org.eclipse.jdt.core.prefs b/org.eclipse.jgit.archive/.settings/org.eclipse.jdt.core.prefs
index bfaf736..4f1759f 100644
--- a/org.eclipse.jgit.archive/.settings/org.eclipse.jdt.core.prefs
+++ b/org.eclipse.jgit.archive/.settings/org.eclipse.jdt.core.prefs
@@ -7,9 +7,9 @@
 org.eclipse.jdt.core.compiler.annotation.nullanalysis=enabled
 org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
 org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
-org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
 org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
-org.eclipse.jdt.core.compiler.compliance=1.7
+org.eclipse.jdt.core.compiler.compliance=1.8
 org.eclipse.jdt.core.compiler.debug.lineNumber=generate
 org.eclipse.jdt.core.compiler.debug.localVariable=generate
 org.eclipse.jdt.core.compiler.debug.sourceFile=generate
@@ -112,7 +112,7 @@
 org.eclipse.jdt.core.compiler.problem.unusedTypeParameter=ignore
 org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning
 org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=error
-org.eclipse.jdt.core.compiler.source=1.7
+org.eclipse.jdt.core.compiler.source=1.8
 org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16
 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0
diff --git a/org.eclipse.jgit.archive/META-INF/MANIFEST.MF b/org.eclipse.jgit.archive/META-INF/MANIFEST.MF
index e3f8d6c..b2fe6b2 100644
--- a/org.eclipse.jgit.archive/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.archive/META-INF/MANIFEST.MF
@@ -2,24 +2,24 @@
 Bundle-ManifestVersion: 2
 Bundle-Name: %plugin_name
 Bundle-SymbolicName: org.eclipse.jgit.archive
-Bundle-Version: 4.5.3.qualifier
+Bundle-Version: 4.6.2.qualifier
 Bundle-Vendor: %provider_name
 Bundle-Localization: plugin
-Bundle-RequiredExecutionEnvironment: JavaSE-1.7
+Bundle-RequiredExecutionEnvironment: JavaSE-1.8
 Import-Package: org.apache.commons.compress.archivers;version="[1.4,2.0)",
  org.apache.commons.compress.archivers.tar;version="[1.4,2.0)",
  org.apache.commons.compress.archivers.zip;version="[1.4,2.0)",
  org.apache.commons.compress.compressors.bzip2;version="[1.4,2.0)",
  org.apache.commons.compress.compressors.gzip;version="[1.4,2.0)",
  org.apache.commons.compress.compressors.xz;version="[1.4,2.0)",
- org.eclipse.jgit.api;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.lib;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.nls;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.util;version="[4.5.3,4.6.0)",
+ org.eclipse.jgit.api;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.lib;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.nls;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.util;version="[4.6.2,4.7.0)",
  org.osgi.framework;version="[1.3.0,2.0.0)"
 Bundle-ActivationPolicy: lazy
 Bundle-Activator: org.eclipse.jgit.archive.FormatActivator
-Export-Package: org.eclipse.jgit.archive;version="4.5.3";
+Export-Package: org.eclipse.jgit.archive;version="4.6.2";
   uses:="org.eclipse.jgit.lib,
    org.eclipse.jgit.api,
    org.apache.commons.compress.archivers,
diff --git a/org.eclipse.jgit.archive/META-INF/SOURCE-MANIFEST.MF b/org.eclipse.jgit.archive/META-INF/SOURCE-MANIFEST.MF
index 0230bf9..7d7477c 100644
--- a/org.eclipse.jgit.archive/META-INF/SOURCE-MANIFEST.MF
+++ b/org.eclipse.jgit.archive/META-INF/SOURCE-MANIFEST.MF
@@ -3,5 +3,5 @@
 Bundle-Name: org.eclipse.jgit.archive - Sources
 Bundle-SymbolicName: org.eclipse.jgit.archive.source
 Bundle-Vendor: Eclipse.org - JGit
-Bundle-Version: 4.5.3.qualifier
-Eclipse-SourceBundle: org.eclipse.jgit.archive;version="4.5.3.qualifier";roots="."
+Bundle-Version: 4.6.2.qualifier
+Eclipse-SourceBundle: org.eclipse.jgit.archive;version="4.6.2.qualifier";roots="."
diff --git a/org.eclipse.jgit.archive/pom.xml b/org.eclipse.jgit.archive/pom.xml
index 4f87945..9c38817 100644
--- a/org.eclipse.jgit.archive/pom.xml
+++ b/org.eclipse.jgit.archive/pom.xml
@@ -50,7 +50,7 @@
   <parent>
     <groupId>org.eclipse.jgit</groupId>
     <artifactId>org.eclipse.jgit-parent</artifactId>
-    <version>4.5.3-SNAPSHOT</version>
+    <version>4.6.2-SNAPSHOT</version>
   </parent>
 
   <artifactId>org.eclipse.jgit.archive</artifactId>
diff --git a/org.eclipse.jgit.http.apache/.classpath b/org.eclipse.jgit.http.apache/.classpath
index a14ade4..110168f 100644
--- a/org.eclipse.jgit.http.apache/.classpath
+++ b/org.eclipse.jgit.http.apache/.classpath
@@ -1,6 +1,6 @@
 <?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.7"/>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
 	<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
 	<classpathentry kind="src" path="src"/>
 	<classpathentry kind="src" path="resources"/>
diff --git a/org.eclipse.jgit.http.apache/.settings/org.eclipse.jdt.core.prefs b/org.eclipse.jgit.http.apache/.settings/org.eclipse.jdt.core.prefs
index cd620c3..80cfbbb 100644
--- a/org.eclipse.jgit.http.apache/.settings/org.eclipse.jdt.core.prefs
+++ b/org.eclipse.jgit.http.apache/.settings/org.eclipse.jdt.core.prefs
@@ -7,9 +7,9 @@
 org.eclipse.jdt.core.compiler.annotation.nullanalysis=disabled
 org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
 org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
-org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
 org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
-org.eclipse.jdt.core.compiler.compliance=1.7
+org.eclipse.jdt.core.compiler.compliance=1.8
 org.eclipse.jdt.core.compiler.debug.lineNumber=generate
 org.eclipse.jdt.core.compiler.debug.localVariable=generate
 org.eclipse.jdt.core.compiler.debug.sourceFile=generate
@@ -112,7 +112,7 @@
 org.eclipse.jdt.core.compiler.problem.unusedTypeParameter=ignore
 org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning
 org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=error
-org.eclipse.jdt.core.compiler.source=1.7
+org.eclipse.jdt.core.compiler.source=1.8
 org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16
 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0
diff --git a/org.eclipse.jgit.http.apache/META-INF/MANIFEST.MF b/org.eclipse.jgit.http.apache/META-INF/MANIFEST.MF
index fa1d6f1..978be27 100644
--- a/org.eclipse.jgit.http.apache/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.http.apache/META-INF/MANIFEST.MF
@@ -2,30 +2,36 @@
 Bundle-ManifestVersion: 2
 Bundle-Name: %Bundle-Name
 Bundle-SymbolicName: org.eclipse.jgit.http.apache
-Bundle-Version: 4.5.3.qualifier
-Bundle-RequiredExecutionEnvironment: JavaSE-1.7
+Bundle-Version: 4.6.2.qualifier
+Bundle-RequiredExecutionEnvironment: JavaSE-1.8
 Bundle-Localization: plugin
 Bundle-Vendor: %Provider-Name
 Bundle-ActivationPolicy: lazy
-Import-Package: org.apache.http;version="[4.1.0,5.0.0)",
- org.apache.http.client;version="[4.1.0,5.0.0)",
- org.apache.http.client.methods;version="[4.1.0,5.0.0)",
- org.apache.http.client.params;version="[4.1.0,5.0.0)",
- org.apache.http.conn;version="[4.1.0,5.0.0)",
- org.apache.http.conn.params;version="[4.1.0,5.0.0)",
- org.apache.http.conn.scheme;version="[4.1.0,5.0.0)",
- org.apache.http.conn.ssl;version="[4.1.0,5.0.0)",
- org.apache.http.entity;version="[4.1.0,5.0.0)",
- org.apache.http.impl.client;version="[4.1.0,5.0.0)",
- org.apache.http.impl.client.cache;version="[4.1.0,5.0.0)",
- org.apache.http.params;version="[4.1.0,5.0.0)",
- org.eclipse.jgit.nls;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.transport.http;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.util;version="[4.5.3,4.6.0)"
-Export-Package: org.eclipse.jgit.transport.http.apache;version="4.5.3";
-  uses:="org.eclipse.jgit.transport.http,
-   javax.net.ssl,
-   org.apache.http.client,
+Import-Package: org.apache.http;version="[4.3.0,5.0.0)",
+ org.apache.http.client;version="[4.3.0,5.0.0)",
+ org.apache.http.client.config;version="[4.3.0,5.0.0)",
+ org.apache.http.client.methods;version="[4.3.0,5.0.0)",
+ org.apache.http.client.params;version="[4.3.0,5.0.0)",
+ org.apache.http.config;version="[4.3.0,5.0.0)",
+ org.apache.http.conn;version="[4.3.0,5.0.0)",
+ org.apache.http.conn.params;version="[4.3.0,5.0.0)",
+ org.apache.http.conn.scheme;version="[4.3.0,5.0.0)",
+ org.apache.http.conn.socket;version="[4.3.0,5.0.0)",
+ org.apache.http.conn.ssl;version="[4.3.0,5.0.0)",
+ org.apache.http.entity;version="[4.3.0,5.0.0)",
+ org.apache.http.impl.client;version="[4.3.0,5.0.0)",
+ org.apache.http.impl.client.cache;version="[4.3.0,5.0.0)",
+ org.apache.http.impl.conn;version="[4.3.0,5.0.0)",
+ org.apache.http.params;version="[4.3.0,5.0.0)",
+ org.eclipse.jgit.nls;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.transport.http;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.util;version="[4.6.2,4.7.0)"
+Export-Package: org.eclipse.jgit.transport.http.apache;version="4.6.2";
+  uses:="org.apache.http.client,
+   org.eclipse.jgit.transport.http,
+   org.apache.http.entity,
    org.apache.http.client.methods,
+   javax.net.ssl,
+   org.eclipse.jgit.util,
    org.apache.http",
  org.eclipse.jgit.transport.http.apache.internal;x-internal:=true
diff --git a/org.eclipse.jgit.http.apache/pom.xml b/org.eclipse.jgit.http.apache/pom.xml
index 7c2de00..dfd8585 100644
--- a/org.eclipse.jgit.http.apache/pom.xml
+++ b/org.eclipse.jgit.http.apache/pom.xml
@@ -48,7 +48,7 @@
 	<parent>
 		<groupId>org.eclipse.jgit</groupId>
 		<artifactId>org.eclipse.jgit-parent</artifactId>
-		<version>4.5.3-SNAPSHOT</version>
+		<version>4.6.2-SNAPSHOT</version>
 	</parent>
 
 	<artifactId>org.eclipse.jgit.http.apache</artifactId>
diff --git a/org.eclipse.jgit.http.apache/src/org/eclipse/jgit/transport/http/apache/HttpClientConnection.java b/org.eclipse.jgit.http.apache/src/org/eclipse/jgit/transport/http/apache/HttpClientConnection.java
index 2d9d17a..281154f 100644
--- a/org.eclipse.jgit.http.apache/src/org/eclipse/jgit/transport/http/apache/HttpClientConnection.java
+++ b/org.eclipse.jgit.http.apache/src/org/eclipse/jgit/transport/http/apache/HttpClientConnection.java
@@ -80,19 +80,21 @@
 import org.apache.http.HttpResponse;
 import org.apache.http.client.ClientProtocolException;
 import org.apache.http.client.HttpClient;
+import org.apache.http.client.config.RequestConfig;
 import org.apache.http.client.methods.HttpGet;
 import org.apache.http.client.methods.HttpHead;
 import org.apache.http.client.methods.HttpPost;
 import org.apache.http.client.methods.HttpPut;
 import org.apache.http.client.methods.HttpUriRequest;
-import org.apache.http.client.params.ClientPNames;
-import org.apache.http.conn.params.ConnRoutePNames;
-import org.apache.http.conn.scheme.Scheme;
-import org.apache.http.conn.ssl.SSLSocketFactory;
+import org.apache.http.config.Registry;
+import org.apache.http.config.RegistryBuilder;
+import org.apache.http.conn.socket.ConnectionSocketFactory;
+import org.apache.http.conn.socket.PlainConnectionSocketFactory;
+import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
 import org.apache.http.conn.ssl.X509HostnameVerifier;
-import org.apache.http.impl.client.DefaultHttpClient;
-import org.apache.http.params.CoreConnectionPNames;
-import org.apache.http.params.HttpParams;
+import org.apache.http.impl.client.HttpClientBuilder;
+import org.apache.http.impl.client.HttpClients;
+import org.apache.http.impl.conn.BasicHttpClientConnectionManager;
 import org.eclipse.jgit.transport.http.HttpConnection;
 import org.eclipse.jgit.transport.http.apache.internal.HttpApacheText;
 import org.eclipse.jgit.util.TemporaryBuffer;
@@ -131,29 +133,39 @@
 	SSLContext ctx;
 
 	private HttpClient getClient() {
-		if (client == null)
-			client = new DefaultHttpClient();
-		HttpParams params = client.getParams();
-		if (proxy != null && !Proxy.NO_PROXY.equals(proxy)) {
-			isUsingProxy = true;
-			InetSocketAddress adr = (InetSocketAddress) proxy.address();
-			params.setParameter(ConnRoutePNames.DEFAULT_PROXY,
-					new HttpHost(adr.getHostName(), adr.getPort()));
-		}
-		if (timeout != null)
-			params.setIntParameter(CoreConnectionPNames.CONNECTION_TIMEOUT,
-					timeout.intValue());
-		if (readTimeout != null)
-			params.setIntParameter(CoreConnectionPNames.SO_TIMEOUT,
-					readTimeout.intValue());
-		if (followRedirects != null)
-			params.setBooleanParameter(ClientPNames.HANDLE_REDIRECTS,
-					followRedirects.booleanValue());
-		if (hostnameverifier != null) {
-			SSLSocketFactory sf;
-			sf = new SSLSocketFactory(getSSLContext(), hostnameverifier);
-			Scheme https = new Scheme("https", 443, sf); //$NON-NLS-1$
-			client.getConnectionManager().getSchemeRegistry().register(https);
+		if (client == null) {
+			HttpClientBuilder clientBuilder = HttpClients.custom();
+			RequestConfig.Builder configBuilder = RequestConfig.custom();
+			if (proxy != null && !Proxy.NO_PROXY.equals(proxy)) {
+				isUsingProxy = true;
+				InetSocketAddress adr = (InetSocketAddress) proxy.address();
+				clientBuilder.setProxy(
+						new HttpHost(adr.getHostName(), adr.getPort()));
+			}
+			if (timeout != null) {
+				configBuilder.setConnectTimeout(timeout.intValue());
+			}
+			if (readTimeout != null) {
+				configBuilder.setSocketTimeout(readTimeout.intValue());
+			}
+			if (followRedirects != null) {
+				configBuilder
+						.setRedirectsEnabled(followRedirects.booleanValue());
+			}
+			if (hostnameverifier != null) {
+				SSLConnectionSocketFactory sslConnectionFactory = new SSLConnectionSocketFactory(
+						getSSLContext(), hostnameverifier);
+				clientBuilder.setSSLSocketFactory(sslConnectionFactory);
+				Registry<ConnectionSocketFactory> registry = RegistryBuilder
+						.<ConnectionSocketFactory> create()
+						.register("https", sslConnectionFactory)
+						.register("http", PlainConnectionSocketFactory.INSTANCE)
+						.build();
+				clientBuilder.setConnectionManager(
+						new BasicHttpClientConnectionManager(registry));
+			}
+			clientBuilder.setDefaultRequestConfig(configBuilder.build());
+			client = clientBuilder.build();
 		}
 
 		return client;
@@ -283,11 +295,11 @@
 	}
 
 	public void setConnectTimeout(int timeout) {
-		this.timeout = new Integer(timeout);
+		this.timeout = Integer.valueOf(timeout);
 	}
 
 	public void setReadTimeout(int readTimeout) {
-		this.readTimeout = new Integer(readTimeout);
+		this.readTimeout = Integer.valueOf(readTimeout);
 	}
 
 	public String getContentType() {
@@ -311,12 +323,21 @@
 	}
 
 	public int getContentLength() {
-		return Integer.parseInt(resp.getFirstHeader("content-length") //$NON-NLS-1$
-				.getValue());
+		Header contentLength = resp.getFirstHeader("content-length"); //$NON-NLS-1$
+		if (contentLength == null) {
+			return -1;
+		}
+
+		try {
+			int l = Integer.parseInt(contentLength.getValue());
+			return l < 0 ? -1 : l;
+		} catch (NumberFormatException e) {
+			return -1;
+		}
 	}
 
 	public void setInstanceFollowRedirects(boolean followRedirects) {
-		this.followRedirects = new Boolean(followRedirects);
+		this.followRedirects = Boolean.valueOf(followRedirects);
 	}
 
 	public void setDoOutput(boolean dooutput) {
diff --git a/org.eclipse.jgit.http.apache/src/org/eclipse/jgit/transport/http/apache/TemporaryBufferEntity.java b/org.eclipse.jgit.http.apache/src/org/eclipse/jgit/transport/http/apache/TemporaryBufferEntity.java
index 377e5ca..93328c9 100644
--- a/org.eclipse.jgit.http.apache/src/org/eclipse/jgit/transport/http/apache/TemporaryBufferEntity.java
+++ b/org.eclipse.jgit.http.apache/src/org/eclipse/jgit/transport/http/apache/TemporaryBufferEntity.java
@@ -105,7 +105,7 @@
 	 * @param contentLength
 	 */
 	public void setContentLength(int contentLength) {
-		this.contentLength = new Integer(contentLength);
+		this.contentLength = Integer.valueOf(contentLength);
 	}
 
 	/**
diff --git a/org.eclipse.jgit.http.server/.classpath b/org.eclipse.jgit.http.server/.classpath
index 04a2be7..cfcf24a 100644
--- a/org.eclipse.jgit.http.server/.classpath
+++ b/org.eclipse.jgit.http.server/.classpath
@@ -2,7 +2,7 @@
 <classpath>
 	<classpathentry kind="src" path="src"/>
 	<classpathentry kind="src" path="resources"/>
-	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7"/>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
 	<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
 	<classpathentry kind="output" path="bin"/>
 </classpath>
diff --git a/org.eclipse.jgit.http.server/.settings/org.eclipse.jdt.core.prefs b/org.eclipse.jgit.http.server/.settings/org.eclipse.jdt.core.prefs
index cd620c3..80cfbbb 100644
--- a/org.eclipse.jgit.http.server/.settings/org.eclipse.jdt.core.prefs
+++ b/org.eclipse.jgit.http.server/.settings/org.eclipse.jdt.core.prefs
@@ -7,9 +7,9 @@
 org.eclipse.jdt.core.compiler.annotation.nullanalysis=disabled
 org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
 org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
-org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
 org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
-org.eclipse.jdt.core.compiler.compliance=1.7
+org.eclipse.jdt.core.compiler.compliance=1.8
 org.eclipse.jdt.core.compiler.debug.lineNumber=generate
 org.eclipse.jdt.core.compiler.debug.localVariable=generate
 org.eclipse.jdt.core.compiler.debug.sourceFile=generate
@@ -112,7 +112,7 @@
 org.eclipse.jdt.core.compiler.problem.unusedTypeParameter=ignore
 org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning
 org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=error
-org.eclipse.jdt.core.compiler.source=1.7
+org.eclipse.jdt.core.compiler.source=1.8
 org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16
 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0
diff --git a/org.eclipse.jgit.http.server/META-INF/MANIFEST.MF b/org.eclipse.jgit.http.server/META-INF/MANIFEST.MF
index 6e9422d..be3bb33 100644
--- a/org.eclipse.jgit.http.server/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.http.server/META-INF/MANIFEST.MF
@@ -2,27 +2,27 @@
 Bundle-ManifestVersion: 2
 Bundle-Name: %plugin_name
 Bundle-SymbolicName: org.eclipse.jgit.http.server
-Bundle-Version: 4.5.3.qualifier
+Bundle-Version: 4.6.2.qualifier
 Bundle-Localization: plugin
 Bundle-Vendor: %provider_name
-Export-Package: org.eclipse.jgit.http.server;version="4.5.3",
- org.eclipse.jgit.http.server.glue;version="4.5.3";
+Export-Package: org.eclipse.jgit.http.server;version="4.6.2",
+ org.eclipse.jgit.http.server.glue;version="4.6.2";
   uses:="javax.servlet,javax.servlet.http",
- org.eclipse.jgit.http.server.resolver;version="4.5.3";
+ org.eclipse.jgit.http.server.resolver;version="4.6.2";
   uses:="org.eclipse.jgit.transport.resolver,
    org.eclipse.jgit.lib,
    org.eclipse.jgit.transport,
    javax.servlet.http"
 Bundle-ActivationPolicy: lazy
-Bundle-RequiredExecutionEnvironment: JavaSE-1.7
+Bundle-RequiredExecutionEnvironment: JavaSE-1.8
 Import-Package: javax.servlet;version="[2.5.0,3.2.0)",
  javax.servlet.http;version="[2.5.0,3.2.0)",
- org.eclipse.jgit.errors;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.internal.storage.dfs;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.internal.storage.file;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.lib;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.nls;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.revwalk;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.transport;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.transport.resolver;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.util;version="[4.5.3,4.6.0)"
+ org.eclipse.jgit.errors;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.internal.storage.dfs;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.internal.storage.file;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.lib;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.nls;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.revwalk;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.transport;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.transport.resolver;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.util;version="[4.6.2,4.7.0)"
diff --git a/org.eclipse.jgit.http.server/pom.xml b/org.eclipse.jgit.http.server/pom.xml
index 0d685d3..843ec4b 100644
--- a/org.eclipse.jgit.http.server/pom.xml
+++ b/org.eclipse.jgit.http.server/pom.xml
@@ -52,7 +52,7 @@
   <parent>
     <groupId>org.eclipse.jgit</groupId>
     <artifactId>org.eclipse.jgit-parent</artifactId>
-    <version>4.5.3-SNAPSHOT</version>
+    <version>4.6.2-SNAPSHOT</version>
   </parent>
 
   <artifactId>org.eclipse.jgit.http.server</artifactId>
diff --git a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/GitSmartHttpTools.java b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/GitSmartHttpTools.java
index d8cd61d..03c9d8d 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
@@ -43,15 +43,15 @@
 
 package org.eclipse.jgit.http.server;
 
-import static org.eclipse.jgit.http.server.ServletUtils.ATTRIBUTE_HANDLER;
-import static org.eclipse.jgit.transport.GitProtocolConstants.OPTION_SIDE_BAND;
-import static org.eclipse.jgit.transport.GitProtocolConstants.OPTION_SIDE_BAND_64K;
-import static org.eclipse.jgit.transport.GitProtocolConstants.CAPABILITY_SIDE_BAND_64K;
-import static org.eclipse.jgit.transport.SideBandOutputStream.CH_ERROR;
-import static org.eclipse.jgit.transport.SideBandOutputStream.SMALL_BUF;
 import static javax.servlet.http.HttpServletResponse.SC_FORBIDDEN;
 import static javax.servlet.http.HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
 import static javax.servlet.http.HttpServletResponse.SC_NOT_FOUND;
+import static org.eclipse.jgit.http.server.ServletUtils.ATTRIBUTE_HANDLER;
+import static org.eclipse.jgit.transport.GitProtocolConstants.CAPABILITY_SIDE_BAND_64K;
+import static org.eclipse.jgit.transport.GitProtocolConstants.OPTION_SIDE_BAND;
+import static org.eclipse.jgit.transport.GitProtocolConstants.OPTION_SIDE_BAND_64K;
+import static org.eclipse.jgit.transport.SideBandOutputStream.CH_ERROR;
+import static org.eclipse.jgit.transport.SideBandOutputStream.SMALL_BUF;
 
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
diff --git a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/ServletUtils.java b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/ServletUtils.java
index 042ccf3..1336d6e 100644
--- a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/ServletUtils.java
+++ b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/ServletUtils.java
@@ -44,6 +44,7 @@
 package org.eclipse.jgit.http.server;
 
 import static org.eclipse.jgit.util.HttpSupport.ENCODING_GZIP;
+import static org.eclipse.jgit.util.HttpSupport.ENCODING_X_GZIP;
 import static org.eclipse.jgit.util.HttpSupport.HDR_ACCEPT_ENCODING;
 import static org.eclipse.jgit.util.HttpSupport.HDR_CONTENT_ENCODING;
 import static org.eclipse.jgit.util.HttpSupport.HDR_ETAG;
@@ -111,7 +112,7 @@
 			throws IOException {
 		InputStream in = req.getInputStream();
 		final String enc = req.getHeader(HDR_CONTENT_ENCODING);
-		if (ENCODING_GZIP.equals(enc) || "x-gzip".equals(enc)) //$NON-NLS-1$
+		if (ENCODING_GZIP.equals(enc) || ENCODING_X_GZIP.equals(enc)) //$NON-NLS-1$
 			in = new GZIPInputStream(in);
 		else if (enc != null)
 			throw new IOException(MessageFormat.format(HttpServerText.get().encodingNotSupportedByThisLibrary
diff --git a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/glue/RegexGroupFilter.java b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/glue/RegexGroupFilter.java
index 2d466e2..2414660 100644
--- a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/glue/RegexGroupFilter.java
+++ b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/glue/RegexGroupFilter.java
@@ -43,6 +43,8 @@
 
 package org.eclipse.jgit.http.server.glue;
 
+import static java.lang.Integer.valueOf;
+
 import java.io.IOException;
 import java.text.MessageFormat;
 
@@ -53,8 +55,6 @@
 import javax.servlet.ServletRequest;
 import javax.servlet.ServletResponse;
 
-import static java.lang.Integer.valueOf;
-
 import org.eclipse.jgit.http.server.HttpServerText;
 
 /**
diff --git a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/glue/WrappedRequest.java b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/glue/WrappedRequest.java
index 7f8da7c..b702c07 100644
--- a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/glue/WrappedRequest.java
+++ b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/glue/WrappedRequest.java
@@ -72,7 +72,7 @@
 	@Override
 	public String getPathTranslated() {
 		final String p = getPathInfo();
-		return p != null ? getRealPath(p) : null;
+		return p != null ? getSession().getServletContext().getRealPath(p) : null;
 	}
 
 	@Override
diff --git a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/resolver/AsIsFileService.java b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/resolver/AsIsFileService.java
index 43a7e24..4ef2a7c 100644
--- a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/resolver/AsIsFileService.java
+++ b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/resolver/AsIsFileService.java
@@ -47,8 +47,8 @@
 
 import org.eclipse.jgit.http.server.GitServlet;
 import org.eclipse.jgit.lib.Config;
-import org.eclipse.jgit.lib.Repository;
 import org.eclipse.jgit.lib.Config.SectionParser;
+import org.eclipse.jgit.lib.Repository;
 import org.eclipse.jgit.transport.resolver.ServiceNotAuthorizedException;
 import org.eclipse.jgit.transport.resolver.ServiceNotEnabledException;
 
diff --git a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/resolver/DefaultReceivePackFactory.java b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/resolver/DefaultReceivePackFactory.java
index df876ba..8c39b79 100644
--- a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/resolver/DefaultReceivePackFactory.java
+++ b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/resolver/DefaultReceivePackFactory.java
@@ -46,9 +46,9 @@
 import javax.servlet.http.HttpServletRequest;
 
 import org.eclipse.jgit.lib.Config;
+import org.eclipse.jgit.lib.Config.SectionParser;
 import org.eclipse.jgit.lib.PersonIdent;
 import org.eclipse.jgit.lib.Repository;
-import org.eclipse.jgit.lib.Config.SectionParser;
 import org.eclipse.jgit.transport.ReceivePack;
 import org.eclipse.jgit.transport.resolver.ReceivePackFactory;
 import org.eclipse.jgit.transport.resolver.ServiceNotAuthorizedException;
diff --git a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/resolver/DefaultUploadPackFactory.java b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/resolver/DefaultUploadPackFactory.java
index 76f40c5..34c069e 100644
--- a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/resolver/DefaultUploadPackFactory.java
+++ b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/resolver/DefaultUploadPackFactory.java
@@ -46,8 +46,8 @@
 import javax.servlet.http.HttpServletRequest;
 
 import org.eclipse.jgit.lib.Config;
-import org.eclipse.jgit.lib.Repository;
 import org.eclipse.jgit.lib.Config.SectionParser;
+import org.eclipse.jgit.lib.Repository;
 import org.eclipse.jgit.transport.UploadPack;
 import org.eclipse.jgit.transport.resolver.ServiceNotAuthorizedException;
 import org.eclipse.jgit.transport.resolver.ServiceNotEnabledException;
diff --git a/org.eclipse.jgit.http.test/.classpath b/org.eclipse.jgit.http.test/.classpath
index e1a1a64..e6014c7 100644
--- a/org.eclipse.jgit.http.test/.classpath
+++ b/org.eclipse.jgit.http.test/.classpath
@@ -1,6 +1,6 @@
 <?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.7"/>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
 	<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
 	<classpathentry kind="src" path="tst"/>
 	<classpathentry kind="src" path="src"/>
diff --git a/org.eclipse.jgit.http.test/.settings/org.eclipse.jdt.core.prefs b/org.eclipse.jgit.http.test/.settings/org.eclipse.jdt.core.prefs
index 87210fb..10c29d5 100644
--- a/org.eclipse.jgit.http.test/.settings/org.eclipse.jdt.core.prefs
+++ b/org.eclipse.jgit.http.test/.settings/org.eclipse.jdt.core.prefs
@@ -7,9 +7,9 @@
 org.eclipse.jdt.core.compiler.annotation.nullanalysis=disabled
 org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
 org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
-org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
 org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
-org.eclipse.jdt.core.compiler.compliance=1.7
+org.eclipse.jdt.core.compiler.compliance=1.8
 org.eclipse.jdt.core.compiler.debug.lineNumber=generate
 org.eclipse.jdt.core.compiler.debug.localVariable=generate
 org.eclipse.jdt.core.compiler.debug.sourceFile=generate
@@ -112,7 +112,7 @@
 org.eclipse.jdt.core.compiler.problem.unusedTypeParameter=ignore
 org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning
 org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=error
-org.eclipse.jdt.core.compiler.source=1.7
+org.eclipse.jdt.core.compiler.source=1.8
 org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16
 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0
diff --git a/org.eclipse.jgit.http.test/BUCK b/org.eclipse.jgit.http.test/BUCK
index d65cdad..f5cd10e 100644
--- a/org.eclipse.jgit.http.test/BUCK
+++ b/org.eclipse.jgit.http.test/BUCK
@@ -25,7 +25,7 @@
       '//lib/jetty:util',
       '//lib:commons-logging',
     ],
-    source_under_test = ['//org.eclipse.jgit.http.server:jgit-servlet'],
+    vm_args = ['-Djava.io.tmpdir=buck-out'],
   )
 
 java_library(
diff --git a/org.eclipse.jgit.http.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.http.test/META-INF/MANIFEST.MF
index bc8f08e..6effed6 100644
--- a/org.eclipse.jgit.http.test/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.http.test/META-INF/MANIFEST.MF
@@ -2,44 +2,44 @@
 Bundle-ManifestVersion: 2
 Bundle-Name: %plugin_name
 Bundle-SymbolicName: org.eclipse.jgit.http.test
-Bundle-Version: 4.5.3.qualifier
+Bundle-Version: 4.6.2.qualifier
 Bundle-Vendor: %provider_name
 Bundle-Localization: plugin
-Bundle-RequiredExecutionEnvironment: JavaSE-1.7
+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.jetty.continuation;version="[9.0.0,10.0.0)",
- org.eclipse.jetty.http;version="[9.0.0,10.0.0)",
- org.eclipse.jetty.io;version="[9.0.0,10.0.0)",
- org.eclipse.jetty.security;version="[9.0.0,10.0.0)",
- org.eclipse.jetty.security.authentication;version="[9.0.0,10.0.0)",
- org.eclipse.jetty.server;version="[9.0.0,10.0.0)",
- org.eclipse.jetty.server.handler;version="[9.0.0,10.0.0)",
- org.eclipse.jetty.server.nio;version="[9.0.0,10.0.0)",
- org.eclipse.jetty.servlet;version="[9.0.0,10.0.0)",
- org.eclipse.jetty.util;version="[9.0.0,10.0.0)",
- org.eclipse.jetty.util.component;version="[9.0.0,10.0.0)",
- org.eclipse.jetty.util.log;version="[9.0.0,10.0.0)",
- org.eclipse.jetty.util.security;version="[9.0.0,10.0.0)",
- org.eclipse.jetty.util.thread;version="[9.0.0,10.0.0)",
- org.eclipse.jgit.errors;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.http.server;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.http.server.glue;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.http.server.resolver;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.internal;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.internal.storage.dfs;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.internal.storage.file;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.junit;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.junit.http;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.lib;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.nls;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.revwalk;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.storage.file;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.transport;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.transport.http;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.transport.http.apache;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.transport.resolver;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.util;version="[4.5.3,4.6.0)",
+ org.eclipse.jetty.continuation;version="[9.0.0,9.4.0)",
+ org.eclipse.jetty.http;version="[9.0.0,9.4.0)",
+ org.eclipse.jetty.io;version="[9.0.0,9.4.0)",
+ org.eclipse.jetty.security;version="[9.0.0,9.4.0)",
+ org.eclipse.jetty.security.authentication;version="[9.0.0,9.4.0)",
+ org.eclipse.jetty.server;version="[9.0.0,9.4.0)",
+ org.eclipse.jetty.server.handler;version="[9.0.0,9.4.0)",
+ org.eclipse.jetty.server.nio;version="[9.0.0,9.4.0)",
+ org.eclipse.jetty.servlet;version="[9.0.0,9.4.0)",
+ org.eclipse.jetty.util;version="[9.0.0,9.4.0)",
+ org.eclipse.jetty.util.component;version="[9.0.0,9.4.0)",
+ org.eclipse.jetty.util.log;version="[9.0.0,9.4.0)",
+ org.eclipse.jetty.util.security;version="[9.0.0,9.4.0)",
+ org.eclipse.jetty.util.thread;version="[9.0.0,9.4.0)",
+ org.eclipse.jgit.errors;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.http.server;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.http.server.glue;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.http.server.resolver;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.internal;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.internal.storage.dfs;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.internal.storage.file;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.junit;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.junit.http;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.lib;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.nls;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.revwalk;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.storage.file;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.transport;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.transport.http;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.transport.http.apache;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.transport.resolver;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.util;version="[4.6.2,4.7.0)",
  org.hamcrest.core;version="[1.1.0,2.0.0)",
  org.junit;version="[4.0.0,5.0.0)",
  org.junit.runner;version="[4.0.0,5.0.0)",
diff --git a/org.eclipse.jgit.http.test/pom.xml b/org.eclipse.jgit.http.test/pom.xml
index 8ce1aa2..0366f75 100644
--- a/org.eclipse.jgit.http.test/pom.xml
+++ b/org.eclipse.jgit.http.test/pom.xml
@@ -51,7 +51,7 @@
   <parent>
     <groupId>org.eclipse.jgit</groupId>
     <artifactId>org.eclipse.jgit-parent</artifactId>
-    <version>4.5.3-SNAPSHOT</version>
+    <version>4.6.2-SNAPSHOT</version>
   </parent>
 
   <artifactId>org.eclipse.jgit.http.test</artifactId>
@@ -60,7 +60,9 @@
   <description>
     Tests for the HTTP transport.
   </description>
-
+  <properties>
+      <maven.javadoc.skip>true</maven.javadoc.skip>
+  </properties>
   <dependencies>
     <dependency>
       <groupId>junit</groupId>
diff --git a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/server/ClientVersionUtilTest.java b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/server/ClientVersionUtilTest.java
index a8c604c..c7260e3 100644
--- a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/server/ClientVersionUtilTest.java
+++ b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/server/ClientVersionUtilTest.java
@@ -43,11 +43,11 @@
 
 package org.eclipse.jgit.http.server;
 
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
 import static org.eclipse.jgit.http.server.ClientVersionUtil.hasPushStatusBug;
 import static org.eclipse.jgit.http.server.ClientVersionUtil.invalidVersion;
 import static org.eclipse.jgit.http.server.ClientVersionUtil.parseVersion;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
 
 import org.junit.Assert;
 import org.junit.Test;
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 da3a098..bce44f9 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
@@ -199,7 +199,7 @@
 				.startsWith("JGit/"));
 		assertEquals("*/*", info.getRequestHeader(HDR_ACCEPT));
 		assertEquals(200, info.getStatus());
-		assertEquals("text/plain; charset=UTF-8",
+		assertEquals("text/plain;charset=utf-8",
 				info
 				.getResponseHeader(HDR_CONTENT_TYPE));
 
@@ -269,7 +269,7 @@
 		assertEquals("GET", req.get(0).getMethod());
 		assertEquals(0, req.get(0).getParameters().size());
 		assertEquals(200, req.get(0).getStatus());
-		assertEquals("text/plain; charset=UTF-8",
+		assertEquals("text/plain;charset=utf-8",
 				req.get(0).getResponseHeader(
 				HDR_CONTENT_TYPE));
 	}
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 2b9105c..3e88271 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
@@ -454,7 +454,7 @@
 			} catch (TransportException err) {
 				String exp = brokenURI + ": expected"
 						+ " Content-Type application/x-git-upload-pack-result;"
-						+ " received Content-Type text/plain; charset=UTF-8";
+						+ " received Content-Type text/plain;charset=utf-8";
 				assertEquals(exp, err.getMessage());
 			}
 		}
@@ -476,7 +476,7 @@
 		assertEquals(join(brokenURI, "git-upload-pack"), service.getPath());
 		assertEquals(0, service.getParameters().size());
 		assertEquals(200, service.getStatus());
-		assertEquals("text/plain; charset=UTF-8",
+		assertEquals("text/plain;charset=utf-8",
 				service.getResponseHeader(HDR_CONTENT_TYPE));
 	}
 
diff --git a/org.eclipse.jgit.junit.http/.classpath b/org.eclipse.jgit.junit.http/.classpath
index b1dabee..b862a29 100644
--- a/org.eclipse.jgit.junit.http/.classpath
+++ b/org.eclipse.jgit.junit.http/.classpath
@@ -1,6 +1,6 @@
 <?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.7"/>

+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>

 	<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>

 	<classpathentry kind="src" path="src"/>

 	<classpathentry kind="output" path="bin"/>

diff --git a/org.eclipse.jgit.junit.http/.settings/org.eclipse.jdt.core.prefs b/org.eclipse.jgit.junit.http/.settings/org.eclipse.jdt.core.prefs
index 87210fb..10c29d5 100644
--- a/org.eclipse.jgit.junit.http/.settings/org.eclipse.jdt.core.prefs
+++ b/org.eclipse.jgit.junit.http/.settings/org.eclipse.jdt.core.prefs
@@ -7,9 +7,9 @@
 org.eclipse.jdt.core.compiler.annotation.nullanalysis=disabled
 org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
 org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
-org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
 org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
-org.eclipse.jdt.core.compiler.compliance=1.7
+org.eclipse.jdt.core.compiler.compliance=1.8
 org.eclipse.jdt.core.compiler.debug.lineNumber=generate
 org.eclipse.jdt.core.compiler.debug.localVariable=generate
 org.eclipse.jdt.core.compiler.debug.sourceFile=generate
@@ -112,7 +112,7 @@
 org.eclipse.jdt.core.compiler.problem.unusedTypeParameter=ignore
 org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning
 org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=error
-org.eclipse.jdt.core.compiler.source=1.7
+org.eclipse.jdt.core.compiler.source=1.8
 org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16
 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0
diff --git a/org.eclipse.jgit.junit.http/META-INF/MANIFEST.MF b/org.eclipse.jgit.junit.http/META-INF/MANIFEST.MF
index fb080db..cd42e2c 100644
--- a/org.eclipse.jgit.junit.http/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.junit.http/META-INF/MANIFEST.MF
@@ -2,34 +2,34 @@
 Bundle-ManifestVersion: 2
 Bundle-Name: %plugin_name
 Bundle-SymbolicName: org.eclipse.jgit.junit.http
-Bundle-Version: 4.5.3.qualifier
+Bundle-Version: 4.6.2.qualifier
 Bundle-Localization: plugin
 Bundle-Vendor: %provider_name
 Bundle-ActivationPolicy: lazy
-Bundle-RequiredExecutionEnvironment: JavaSE-1.7
+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.apache.commons.logging;version="[1.1.1,2.0.0)",
- org.eclipse.jetty.http;version="[9.0.0,10.0.0)",
- org.eclipse.jetty.security;version="[9.0.0,10.0.0)",
- org.eclipse.jetty.security.authentication;version="[9.0.0,10.0.0)",
- org.eclipse.jetty.server;version="[9.0.0,10.0.0)",
- org.eclipse.jetty.server.handler;version="[9.0.0,10.0.0)",
- org.eclipse.jetty.server.nio;version="[9.0.0,10.0.0)",
- org.eclipse.jetty.servlet;version="[9.0.0,10.0.0)",
- org.eclipse.jetty.util.component;version="[9.0.0,10.0.0)",
- org.eclipse.jetty.util.log;version="[9.0.0,10.0.0)",
- org.eclipse.jetty.util.security;version="[9.0.0,10.0.0)",
- org.eclipse.jgit.errors;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.http.server;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.internal.storage.file;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.junit;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.lib;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.revwalk;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.transport;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.transport.resolver;version="[4.5.3,4.6.0)",
+ org.eclipse.jetty.http;version="[9.0.0,9.4.0)",
+ org.eclipse.jetty.security;version="[9.0.0,9.4.0)",
+ org.eclipse.jetty.security.authentication;version="[9.0.0,9.4.0)",
+ org.eclipse.jetty.server;version="[9.0.0,9.4.0)",
+ org.eclipse.jetty.server.handler;version="[9.0.0,9.4.0)",
+ org.eclipse.jetty.server.nio;version="[9.0.0,9.4.0)",
+ org.eclipse.jetty.servlet;version="[9.0.0,9.4.0)",
+ org.eclipse.jetty.util.component;version="[9.0.0,9.4.0)",
+ org.eclipse.jetty.util.log;version="[9.0.0,9.4.0)",
+ org.eclipse.jetty.util.security;version="[9.0.0,9.4.0)",
+ org.eclipse.jgit.errors;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.http.server;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.internal.storage.file;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.junit;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.lib;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.revwalk;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.transport;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.transport.resolver;version="[4.6.2,4.7.0)",
  org.junit;version="[4.0.0,5.0.0)"
-Export-Package: org.eclipse.jgit.junit.http;version="4.5.3";
+Export-Package: org.eclipse.jgit.junit.http;version="4.6.2";
   uses:="org.eclipse.jgit.transport,
    org.eclipse.jgit.junit,
    javax.servlet.http,
diff --git a/org.eclipse.jgit.junit.http/pom.xml b/org.eclipse.jgit.junit.http/pom.xml
index 685a5ee..ced9c2c 100644
--- a/org.eclipse.jgit.junit.http/pom.xml
+++ b/org.eclipse.jgit.junit.http/pom.xml
@@ -50,7 +50,7 @@
   <parent>
     <groupId>org.eclipse.jgit</groupId>
     <artifactId>org.eclipse.jgit-parent</artifactId>
-    <version>4.5.3-SNAPSHOT</version>
+    <version>4.6.2-SNAPSHOT</version>
   </parent>
 
   <artifactId>org.eclipse.jgit.junit.http</artifactId>
diff --git a/org.eclipse.jgit.junit.http/src/org/eclipse/jgit/junit/http/AppServer.java b/org.eclipse.jgit.junit.http/src/org/eclipse/jgit/junit/http/AppServer.java
index cca4f43..44c1977 100644
--- a/org.eclipse.jgit.junit.http/src/org/eclipse/jgit/junit/http/AppServer.java
+++ b/org.eclipse.jgit.junit.http/src/org/eclipse/jgit/junit/http/AppServer.java
@@ -185,13 +185,11 @@
 			putUser(username, new Password(password), new String[] { role });
 		}
 
-		protected String[] loadRoleInfo(
-				@SuppressWarnings("unused") KnownUser user) {
+		protected String[] loadRoleInfo(KnownUser user) {
 			return null;
 		}
 
-		protected KnownUser loadUserInfo(
-				@SuppressWarnings("unused") String usrname) {
+		protected KnownUser loadUserInfo(String usrname) {
 			return null;
 		}
 	}
diff --git a/org.eclipse.jgit.junit/.classpath b/org.eclipse.jgit.junit/.classpath
index 098194c..eca7bdb 100644
--- a/org.eclipse.jgit.junit/.classpath
+++ b/org.eclipse.jgit.junit/.classpath
@@ -1,6 +1,6 @@
 <?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.7"/>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
 	<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
 	<classpathentry kind="src" path="src"/>
 	<classpathentry kind="output" path="bin"/>
diff --git a/org.eclipse.jgit.junit/.settings/org.eclipse.jdt.core.prefs b/org.eclipse.jgit.junit/.settings/org.eclipse.jdt.core.prefs
index 87210fb..10c29d5 100644
--- a/org.eclipse.jgit.junit/.settings/org.eclipse.jdt.core.prefs
+++ b/org.eclipse.jgit.junit/.settings/org.eclipse.jdt.core.prefs
@@ -7,9 +7,9 @@
 org.eclipse.jdt.core.compiler.annotation.nullanalysis=disabled
 org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
 org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
-org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
 org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
-org.eclipse.jdt.core.compiler.compliance=1.7
+org.eclipse.jdt.core.compiler.compliance=1.8
 org.eclipse.jdt.core.compiler.debug.lineNumber=generate
 org.eclipse.jdt.core.compiler.debug.localVariable=generate
 org.eclipse.jdt.core.compiler.debug.sourceFile=generate
@@ -112,7 +112,7 @@
 org.eclipse.jdt.core.compiler.problem.unusedTypeParameter=ignore
 org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning
 org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=error
-org.eclipse.jdt.core.compiler.source=1.7
+org.eclipse.jdt.core.compiler.source=1.8
 org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16
 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0
diff --git a/org.eclipse.jgit.junit/META-INF/MANIFEST.MF b/org.eclipse.jgit.junit/META-INF/MANIFEST.MF
index e16b8be..9de6239 100644
--- a/org.eclipse.jgit.junit/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.junit/META-INF/MANIFEST.MF
@@ -2,30 +2,31 @@
 Bundle-ManifestVersion: 2
 Bundle-Name: %plugin_name
 Bundle-SymbolicName: org.eclipse.jgit.junit
-Bundle-Version: 4.5.3.qualifier
+Bundle-Version: 4.6.2.qualifier
 Bundle-Localization: plugin
 Bundle-Vendor: %provider_name
 Bundle-ActivationPolicy: lazy
-Bundle-RequiredExecutionEnvironment: JavaSE-1.7
-Import-Package: org.eclipse.jgit.api;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.api.errors;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.dircache;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.errors;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.internal.storage.file;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.internal.storage.pack;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.lib;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.merge;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.revwalk;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.storage.file;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.treewalk;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.treewalk.filter;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.util;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.util.io;version="[4.5.3,4.6.0)",
+Bundle-RequiredExecutionEnvironment: JavaSE-1.8
+Import-Package: org.eclipse.jgit.api;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.api.errors;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.dircache;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.errors;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.internal.storage.file;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.internal.storage.pack;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.lib;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.merge;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.revwalk;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.storage.file;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.treewalk;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.treewalk.filter;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.util;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.util.io;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.util.time;version="[4.6.2,4.7.0)",
  org.junit;version="[4.0.0,5.0.0)",
  org.junit.rules;version="[4.9.0,5.0.0)",
  org.junit.runner;version="[4.0.0,5.0.0)",
  org.junit.runners.model;version="[4.5.0,5.0.0)"
-Export-Package: org.eclipse.jgit.junit;version="4.5.3";
+Export-Package: org.eclipse.jgit.junit;version="4.6.2";
   uses:="org.eclipse.jgit.dircache,
    org.eclipse.jgit.lib,
    org.eclipse.jgit.revwalk,
@@ -33,4 +34,5 @@
    org.eclipse.jgit.treewalk,
    org.eclipse.jgit.util,
    org.eclipse.jgit.storage.file,
-   org.eclipse.jgit.api"
+   org.eclipse.jgit.api",
+ org.eclipse.jgit.junit.time;version="4.6.2"
diff --git a/org.eclipse.jgit.junit/pom.xml b/org.eclipse.jgit.junit/pom.xml
index 37c60ca..ab757af 100644
--- a/org.eclipse.jgit.junit/pom.xml
+++ b/org.eclipse.jgit.junit/pom.xml
@@ -52,7 +52,7 @@
   <parent>
     <groupId>org.eclipse.jgit</groupId>
     <artifactId>org.eclipse.jgit-parent</artifactId>
-    <version>4.5.3-SNAPSHOT</version>
+    <version>4.6.2-SNAPSHOT</version>
   </parent>
 
   <artifactId>org.eclipse.jgit.junit</artifactId>
diff --git a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/LocalDiskRepositoryTestCase.java b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/LocalDiskRepositoryTestCase.java
index 4d713b5..dc2e8bf 100644
--- a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/LocalDiskRepositoryTestCase.java
+++ b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/LocalDiskRepositoryTestCase.java
@@ -50,12 +50,21 @@
 
 import java.io.File;
 import java.io.IOException;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeSet;
 
 import org.eclipse.jgit.dircache.DirCache;
 import org.eclipse.jgit.dircache.DirCacheEntry;
 import org.eclipse.jgit.internal.storage.file.FileRepository;
-import org.eclipse.jgit.lib.*;
+import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.PersonIdent;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.lib.RepositoryCache;
 import org.eclipse.jgit.storage.file.FileBasedConfig;
 import org.eclipse.jgit.storage.file.WindowCacheConfig;
 import org.eclipse.jgit.util.FS;
@@ -113,13 +122,8 @@
 		ceilTestDirectories(getCeilings());
 		SystemReader.setInstance(mockSystemReader);
 
-		final long now = mockSystemReader.getCurrentTime();
-		final int tz = mockSystemReader.getTimezone(now);
 		author = new PersonIdent("J. Author", "jauthor@example.com");
-		author = new PersonIdent(author, now, tz);
-
 		committer = new PersonIdent("J. Committer", "jcommitter@example.com");
-		committer = new PersonIdent(committer, now, tz);
 
 		final WindowCacheConfig c = new WindowCacheConfig();
 		c.setPackedGitLimit(128 * WindowCacheConfig.KB);
diff --git a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/MockSystemReader.java b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/MockSystemReader.java
index 28a9556..6faa2ec 100644
--- a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/MockSystemReader.java
+++ b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/MockSystemReader.java
@@ -50,10 +50,12 @@
 import java.lang.reflect.Field;
 import java.text.DateFormat;
 import java.text.SimpleDateFormat;
+import java.time.Duration;
 import java.util.HashMap;
 import java.util.Locale;
 import java.util.Map;
 import java.util.TimeZone;
+import java.util.concurrent.TimeUnit;
 
 import org.eclipse.jgit.errors.ConfigInvalidException;
 import org.eclipse.jgit.lib.Config;
@@ -61,6 +63,8 @@
 import org.eclipse.jgit.storage.file.FileBasedConfig;
 import org.eclipse.jgit.util.FS;
 import org.eclipse.jgit.util.SystemReader;
+import org.eclipse.jgit.util.time.MonotonicClock;
+import org.eclipse.jgit.util.time.ProposedTimestamp;
 
 /**
  * Mock {@link SystemReader} for tests.
@@ -146,6 +150,27 @@
 		return now;
 	}
 
+	@Override
+	public MonotonicClock getClock() {
+		return new MonotonicClock() {
+			@Override
+			public ProposedTimestamp propose() {
+				long t = getCurrentTime();
+				return new ProposedTimestamp() {
+					@Override
+					public long read(TimeUnit unit) {
+						return unit.convert(t, TimeUnit.MILLISECONDS);
+					}
+
+					@Override
+					public void blockUntil(Duration maxWait) {
+						// Do not wait.
+					}
+				};
+			}
+		};
+	}
+
 	/**
 	 * Adjusts the current time in seconds.
 	 *
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 0a2345f..a44e999 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
@@ -46,6 +46,7 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.fail;
 
+import java.io.BufferedOutputStream;
 import java.io.File;
 import java.io.FileOutputStream;
 import java.io.IOException;
@@ -103,7 +104,6 @@
 import org.eclipse.jgit.treewalk.filter.PathFilterGroup;
 import org.eclipse.jgit.util.ChangeIdUtil;
 import org.eclipse.jgit.util.FileUtils;
-import org.eclipse.jgit.util.io.SafeBufferedOutputStream;
 
 /**
  * Wrapper to make creating test data easier.
@@ -885,14 +885,14 @@
 
 				pack = nameFor(odb, name, ".pack");
 				try (OutputStream out =
-						new SafeBufferedOutputStream(new FileOutputStream(pack))) {
+						new BufferedOutputStream(new FileOutputStream(pack))) {
 					pw.writePack(m, m, out);
 				}
 				pack.setReadOnly();
 
 				idx = nameFor(odb, name, ".idx");
 				try (OutputStream out =
-						new SafeBufferedOutputStream(new FileOutputStream(idx))) {
+						new BufferedOutputStream(new FileOutputStream(idx))) {
 					pw.writeIndex(out);
 				}
 				idx.setReadOnly();
diff --git a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/time/MonotonicFakeClock.java b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/time/MonotonicFakeClock.java
new file mode 100644
index 0000000..f09d303
--- /dev/null
+++ b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/time/MonotonicFakeClock.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2016, Google Inc.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ *   copyright notice, this list of conditions and the following
+ *   disclaimer in the documentation and/or other materials provided
+ *   with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ *   names of its contributors may be used to endorse or promote
+ *   products derived from this software without specific prior
+ *   written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.junit.time;
+
+import java.time.Duration;
+import java.util.concurrent.TimeUnit;
+
+import org.eclipse.jgit.util.time.MonotonicClock;
+import org.eclipse.jgit.util.time.ProposedTimestamp;
+
+/**
+ * Fake {@link MonotonicClock} for testing code that uses Clock.
+ *
+ * @since 4.6
+ */
+public class MonotonicFakeClock implements MonotonicClock {
+	private long now = TimeUnit.SECONDS.toMicros(42);
+
+	/**
+	 * Advance the time returned by future calls to {@link #propose()}.
+	 *
+	 * @param add
+	 *            amount of time to add; must be {@code > 0}.
+	 * @param unit
+	 *            unit of {@code add}.
+	 */
+	public void tick(long add, TimeUnit unit) {
+		if (add <= 0) {
+			throw new IllegalArgumentException();
+		}
+		now += unit.toMillis(add);
+	}
+
+	@Override
+	public ProposedTimestamp propose() {
+		long t = now++;
+		return new ProposedTimestamp() {
+			@Override
+			public long read(TimeUnit unit) {
+				return unit.convert(t, TimeUnit.MILLISECONDS);
+			}
+
+			@Override
+			public void blockUntil(Duration maxWait) {
+				// Nothing to do, since fake time does not go backwards.
+			}
+		};
+	}
+}
diff --git a/org.eclipse.jgit.lfs.server.test/.classpath b/org.eclipse.jgit.lfs.server.test/.classpath
index 2fdcc94..4f9f6bf 100644
--- a/org.eclipse.jgit.lfs.server.test/.classpath
+++ b/org.eclipse.jgit.lfs.server.test/.classpath
@@ -1,6 +1,6 @@
 <?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.7"/>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
 	<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
 	<classpathentry kind="src" path="tst"/>
 	<classpathentry kind="output" path="bin"/>
diff --git a/org.eclipse.jgit.lfs.server.test/.settings/org.eclipse.jdt.core.prefs b/org.eclipse.jgit.lfs.server.test/.settings/org.eclipse.jdt.core.prefs
index 87210fb..10c29d5 100644
--- a/org.eclipse.jgit.lfs.server.test/.settings/org.eclipse.jdt.core.prefs
+++ b/org.eclipse.jgit.lfs.server.test/.settings/org.eclipse.jdt.core.prefs
@@ -7,9 +7,9 @@
 org.eclipse.jdt.core.compiler.annotation.nullanalysis=disabled
 org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
 org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
-org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
 org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
-org.eclipse.jdt.core.compiler.compliance=1.7
+org.eclipse.jdt.core.compiler.compliance=1.8
 org.eclipse.jdt.core.compiler.debug.lineNumber=generate
 org.eclipse.jdt.core.compiler.debug.localVariable=generate
 org.eclipse.jdt.core.compiler.debug.sourceFile=generate
@@ -112,7 +112,7 @@
 org.eclipse.jdt.core.compiler.problem.unusedTypeParameter=ignore
 org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning
 org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=error
-org.eclipse.jdt.core.compiler.source=1.7
+org.eclipse.jdt.core.compiler.source=1.8
 org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16
 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0
diff --git a/org.eclipse.jgit.lfs.server.test/BUCK b/org.eclipse.jgit.lfs.server.test/BUCK
index 9d6e72f..25e9f09 100644
--- a/org.eclipse.jgit.lfs.server.test/BUCK
+++ b/org.eclipse.jgit.lfs.server.test/BUCK
@@ -30,6 +30,5 @@
       '//lib:servlet-api',
       '//lib:commons-logging',
     ],
-    source_under_test = ['//org.eclipse.jgit.lfs.server:jgit-lfs-server'],
     vm_args = ['-Xmx256m', '-Dfile.encoding=UTF-8'],
   )
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 2513eb2..405e07a 100644
--- a/org.eclipse.jgit.lfs.server.test/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.lfs.server.test/META-INF/MANIFEST.MF
@@ -2,10 +2,10 @@
 Bundle-ManifestVersion: 2
 Bundle-Name: %plugin_name
 Bundle-SymbolicName: org.eclipse.jgit.lfs.server.test
-Bundle-Version: 4.5.3.qualifier
+Bundle-Version: 4.6.2.qualifier
 Bundle-Vendor: %provider_name
 Bundle-Localization: plugin
-Bundle-RequiredExecutionEnvironment: JavaSE-1.7
+Bundle-RequiredExecutionEnvironment: JavaSE-1.8
 Import-Package: javax.servlet;version="[3.1.0,4.0.0)",
  javax.servlet.http;version="[3.1.0,4.0.0)",
  org.apache.http;version="[4.3.0,5.0.0)",
@@ -13,25 +13,25 @@
  org.apache.http.client.methods;version="[4.3.0,5.0.0)",
  org.apache.http.entity;version="[4.3.0,5.0.0)",
  org.apache.http.impl.client;version="[4.3.0,5.0.0)",
- org.eclipse.jetty.continuation;version="[9.0.0,10.0.0)",
- org.eclipse.jetty.http;version="[9.0.0,10.0.0)",
- org.eclipse.jetty.io;version="[9.0.0,10.0.0)",
- org.eclipse.jetty.security;version="[9.0.0,10.0.0)",
- org.eclipse.jetty.security.authentication;version="[9.0.0,10.0.0)",
- org.eclipse.jetty.server;version="[9.0.0,10.0.0)",
- org.eclipse.jetty.server.handler;version="[9.0.0,10.0.0)",
- org.eclipse.jetty.server.nio;version="[9.0.0,10.0.0)",
- org.eclipse.jetty.servlet;version="[9.0.0,10.0.0)",
- org.eclipse.jetty.util;version="[9.0.0,10.0.0)",
- org.eclipse.jetty.util.component;version="[9.0.0,10.0.0)",
- org.eclipse.jetty.util.log;version="[9.0.0,10.0.0)",
- org.eclipse.jetty.util.security;version="[9.0.0,10.0.0)",
- org.eclipse.jetty.util.thread;version="[9.0.0,10.0.0)",
- org.eclipse.jgit.junit.http;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.lfs.lib;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.lfs.server.fs;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.lfs.test;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.util;version="[4.5.3,4.6.0)",
+ org.eclipse.jetty.continuation;version="[9.0.0,9.4.0)",
+ org.eclipse.jetty.http;version="[9.0.0,9.4.0)",
+ org.eclipse.jetty.io;version="[9.0.0,9.4.0)",
+ org.eclipse.jetty.security;version="[9.0.0,9.4.0)",
+ org.eclipse.jetty.security.authentication;version="[9.0.0,9.4.0)",
+ org.eclipse.jetty.server;version="[9.0.0,9.4.0)",
+ org.eclipse.jetty.server.handler;version="[9.0.0,9.4.0)",
+ org.eclipse.jetty.server.nio;version="[9.0.0,9.4.0)",
+ org.eclipse.jetty.servlet;version="[9.0.0,9.4.0)",
+ org.eclipse.jetty.util;version="[9.0.0,9.4.0)",
+ org.eclipse.jetty.util.component;version="[9.0.0,9.4.0)",
+ org.eclipse.jetty.util.log;version="[9.0.0,9.4.0)",
+ org.eclipse.jetty.util.security;version="[9.0.0,9.4.0)",
+ org.eclipse.jetty.util.thread;version="[9.0.0,9.4.0)",
+ org.eclipse.jgit.junit.http;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.lfs.lib;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.lfs.server.fs;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.lfs.test;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.util;version="[4.6.2,4.7.0)",
  org.hamcrest.core;version="[1.1.0,2.0.0)",
  org.junit;version="[4.0.0,5.0.0)",
  org.junit.runner;version="[4.0.0,5.0.0)",
diff --git a/org.eclipse.jgit.lfs.server.test/pom.xml b/org.eclipse.jgit.lfs.server.test/pom.xml
index bcfbd37..d178fef 100644
--- a/org.eclipse.jgit.lfs.server.test/pom.xml
+++ b/org.eclipse.jgit.lfs.server.test/pom.xml
@@ -50,7 +50,7 @@
   <parent>
     <groupId>org.eclipse.jgit</groupId>
     <artifactId>org.eclipse.jgit-parent</artifactId>
-    <version>4.5.3-SNAPSHOT</version>
+    <version>4.6.2-SNAPSHOT</version>
   </parent>
 
   <artifactId>org.eclipse.jgit.lfs.server.test</artifactId>
diff --git a/org.eclipse.jgit.lfs.server.test/tst/org/eclipse/jgit/lfs/server/fs/LfsServerTest.java b/org.eclipse.jgit.lfs.server.test/tst/org/eclipse/jgit/lfs/server/fs/LfsServerTest.java
index 4d948b9..e10660d 100644
--- a/org.eclipse.jgit.lfs.server.test/tst/org/eclipse/jgit/lfs/server/fs/LfsServerTest.java
+++ b/org.eclipse.jgit.lfs.server.test/tst/org/eclipse/jgit/lfs/server/fs/LfsServerTest.java
@@ -84,7 +84,6 @@
 import org.junit.After;
 import org.junit.Before;
 
-@SuppressWarnings("restriction")
 public abstract class LfsServerTest {
 
 	private static final long timeout = /* 10 sec */ 10 * 1000;
diff --git a/org.eclipse.jgit.lfs.server/.classpath b/org.eclipse.jgit.lfs.server/.classpath
index 04a2be7..cfcf24a 100644
--- a/org.eclipse.jgit.lfs.server/.classpath
+++ b/org.eclipse.jgit.lfs.server/.classpath
@@ -2,7 +2,7 @@
 <classpath>
 	<classpathentry kind="src" path="src"/>
 	<classpathentry kind="src" path="resources"/>
-	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7"/>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
 	<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
 	<classpathentry kind="output" path="bin"/>
 </classpath>
diff --git a/org.eclipse.jgit.lfs.server/.settings/org.eclipse.jdt.core.prefs b/org.eclipse.jgit.lfs.server/.settings/org.eclipse.jdt.core.prefs
index 1ce7cd0..808ec3a 100644
--- a/org.eclipse.jgit.lfs.server/.settings/org.eclipse.jdt.core.prefs
+++ b/org.eclipse.jgit.lfs.server/.settings/org.eclipse.jdt.core.prefs
@@ -7,9 +7,9 @@
 org.eclipse.jdt.core.compiler.annotation.nullanalysis=disabled
 org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
 org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
-org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
 org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
-org.eclipse.jdt.core.compiler.compliance=1.7
+org.eclipse.jdt.core.compiler.compliance=1.8
 org.eclipse.jdt.core.compiler.debug.lineNumber=generate
 org.eclipse.jdt.core.compiler.debug.localVariable=generate
 org.eclipse.jdt.core.compiler.debug.sourceFile=generate
@@ -112,7 +112,7 @@
 org.eclipse.jdt.core.compiler.problem.unusedTypeParameter=ignore
 org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning
 org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=error
-org.eclipse.jdt.core.compiler.source=1.7
+org.eclipse.jdt.core.compiler.source=1.8
 org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16
 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0
diff --git a/org.eclipse.jgit.lfs.server/META-INF/MANIFEST.MF b/org.eclipse.jgit.lfs.server/META-INF/MANIFEST.MF
index 8090f15..3e8a9d1 100644
--- a/org.eclipse.jgit.lfs.server/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.lfs.server/META-INF/MANIFEST.MF
@@ -2,34 +2,35 @@
 Bundle-ManifestVersion: 2
 Bundle-Name: %plugin_name
 Bundle-SymbolicName: org.eclipse.jgit.lfs.server
-Bundle-Version: 4.5.3.qualifier
+Bundle-Version: 4.6.2.qualifier
 Bundle-Localization: plugin
 Bundle-Vendor: %provider_name
-Export-Package: org.eclipse.jgit.lfs.server;version="4.5.3";
+Export-Package: org.eclipse.jgit.lfs.server;version="4.6.2";
   uses:="javax.servlet.http,
    org.eclipse.jgit.lfs.lib",
- org.eclipse.jgit.lfs.server.fs;version="4.5.3";
+ org.eclipse.jgit.lfs.server.fs;version="4.6.2";
   uses:="javax.servlet,
    javax.servlet.http,
    org.eclipse.jgit.lfs.server,
    org.eclipse.jgit.lfs.lib",
- org.eclipse.jgit.lfs.server.internal;version="4.5.3";x-internal:=true,
- org.eclipse.jgit.lfs.server.s3;version="4.5.3";
+ org.eclipse.jgit.lfs.server.internal;version="4.6.2";x-internal:=true,
+ org.eclipse.jgit.lfs.server.s3;version="4.6.2";
   uses:="org.eclipse.jgit.lfs.server,
    org.eclipse.jgit.lfs.lib"
-Bundle-RequiredExecutionEnvironment: JavaSE-1.7
+Bundle-RequiredExecutionEnvironment: JavaSE-1.8
 Import-Package: com.google.gson;version="[2.2.4,3.0.0)",
  javax.servlet;version="[3.1.0,4.0.0)",
  javax.servlet.annotation;version="[3.1.0,4.0.0)",
  javax.servlet.http;version="[3.1.0,4.0.0)",
  org.apache.http;version="[4.3.0,5.0.0)",
  org.apache.http.client;version="[4.3.0,5.0.0)",
- org.eclipse.jgit.annotations;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.internal;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.internal.storage.file;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.lfs.errors;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.lfs.lib;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.nls;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.transport.http;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.transport.http.apache;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.util;version="[4.5.3,4.6.0)"
+ org.eclipse.jgit.annotations;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.internal;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.internal.storage.file;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.lfs.errors;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.lfs.internal;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.lfs.lib;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.nls;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.transport.http;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.transport.http.apache;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.util;version="[4.6.2,4.7.0)"
diff --git a/org.eclipse.jgit.lfs.server/pom.xml b/org.eclipse.jgit.lfs.server/pom.xml
index 935767b..cc84686 100644
--- a/org.eclipse.jgit.lfs.server/pom.xml
+++ b/org.eclipse.jgit.lfs.server/pom.xml
@@ -50,7 +50,7 @@
   <parent>
     <groupId>org.eclipse.jgit</groupId>
     <artifactId>org.eclipse.jgit-parent</artifactId>
-    <version>4.5.3-SNAPSHOT</version>
+    <version>4.6.2-SNAPSHOT</version>
   </parent>
 
   <artifactId>org.eclipse.jgit.lfs.server</artifactId>
diff --git a/org.eclipse.jgit.lfs.server/resources/org/eclipse/jgit/lfs/server/internal/LfsServerText.properties b/org.eclipse.jgit.lfs.server/resources/org/eclipse/jgit/lfs/server/internal/LfsServerText.properties
index f97acac..b2b487e 100644
--- a/org.eclipse.jgit.lfs.server/resources/org/eclipse/jgit/lfs/server/internal/LfsServerText.properties
+++ b/org.eclipse.jgit.lfs.server/resources/org/eclipse/jgit/lfs/server/internal/LfsServerText.properties
@@ -1,4 +1,3 @@
-corruptLongObject=The content hash ''{0}'' of the long object ''{1}'' doesn''t match its id, the corrupt object will be deleted.
 failedToCalcSignature=Failed to calculate a request signature: {0}
 invalidPathInfo=Invalid pathInfo ''{0}'' does not match ''/'{'SHA-256'}'''
 objectNotFound=Object ''{0}'' not found
diff --git a/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/LfsProtocolServlet.java b/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/LfsProtocolServlet.java
index eb49ff0..841074b 100644
--- a/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/LfsProtocolServlet.java
+++ b/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/LfsProtocolServlet.java
@@ -44,8 +44,8 @@
 
 import static java.nio.charset.StandardCharsets.UTF_8;
 import static org.apache.http.HttpStatus.SC_FORBIDDEN;
-import static org.apache.http.HttpStatus.SC_INTERNAL_SERVER_ERROR;
 import static org.apache.http.HttpStatus.SC_INSUFFICIENT_STORAGE;
+import static org.apache.http.HttpStatus.SC_INTERNAL_SERVER_ERROR;
 import static org.apache.http.HttpStatus.SC_NOT_FOUND;
 import static org.apache.http.HttpStatus.SC_OK;
 import static org.apache.http.HttpStatus.SC_SERVICE_UNAVAILABLE;
diff --git a/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/fs/FileLfsRepository.java b/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/fs/FileLfsRepository.java
index dd70a36..a05fa01 100644
--- a/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/fs/FileLfsRepository.java
+++ b/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/fs/FileLfsRepository.java
@@ -53,6 +53,7 @@
 import java.util.Collections;
 
 import org.eclipse.jgit.annotations.Nullable;
+import org.eclipse.jgit.lfs.internal.AtomicObjectOutputStream;
 import org.eclipse.jgit.lfs.lib.AnyLongObjectId;
 import org.eclipse.jgit.lfs.lib.Constants;
 import org.eclipse.jgit.lfs.server.LargeFileRepository;
diff --git a/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/fs/FileLfsServlet.java b/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/fs/FileLfsServlet.java
index 2ecba6d..a8e3c11 100644
--- a/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/fs/FileLfsServlet.java
+++ b/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/fs/FileLfsServlet.java
@@ -125,7 +125,20 @@
 		}
 	}
 
-	private AnyLongObjectId getObjectToTransfer(HttpServletRequest req,
+	/**
+	 * Retrieve object id from request
+	 *
+	 * @param req
+	 *            servlet request
+	 * @param rsp
+	 *            servlet response
+	 * @return object id, or <code>null</code> if the object id could not be
+	 *         retrieved
+	 * @throws IOException
+	 *             if an I/O error occurs
+         * @since 4.6
+	 */
+	protected AnyLongObjectId getObjectToTransfer(HttpServletRequest req,
 			HttpServletResponse rsp) throws IOException {
 		String info = req.getPathInfo();
 		int length = 1 + Constants.LONG_OBJECT_ID_STRING_LENGTH;
@@ -174,7 +187,20 @@
 		}
 	}
 
-	static void sendError(HttpServletResponse rsp, int status, String message)
+	/**
+	 * Send an error response.
+	 *
+	 * @param rsp
+	 *            the servlet response
+	 * @param status
+	 *            HTTP status code
+	 * @param message
+	 *            error message
+	 * @throws IOException
+	 *             on failure to send the response
+	 * @since 4.6
+	 */
+	protected static void sendError(HttpServletResponse rsp, int status, String message)
 			throws IOException {
 		rsp.setStatus(status);
 		PrintWriter writer = rsp.getWriter();
diff --git a/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/fs/ObjectUploadListener.java b/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/fs/ObjectUploadListener.java
index d44b3db..84e4e6f 100644
--- a/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/fs/ObjectUploadListener.java
+++ b/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/fs/ObjectUploadListener.java
@@ -59,13 +59,16 @@
 
 import org.apache.http.HttpStatus;
 import org.eclipse.jgit.lfs.errors.CorruptLongObjectException;
+import org.eclipse.jgit.lfs.internal.AtomicObjectOutputStream;
 import org.eclipse.jgit.lfs.lib.AnyLongObjectId;
 import org.eclipse.jgit.lfs.lib.Constants;
 
 /**
- * Handle asynchronous object upload
+ * Handle asynchronous object upload.
+ *
+ * @since 4.6
  */
-class ObjectUploadListener implements ReadListener {
+public class ObjectUploadListener implements ReadListener {
 
 	private static Logger LOG = Logger
 			.getLogger(ObjectUploadListener.class.getName());
@@ -138,6 +141,9 @@
 		close();
 	}
 
+	/**
+	 * @throws IOException
+	 */
 	protected void close() throws IOException {
 		try {
 			inChannel.close();
@@ -173,4 +179,4 @@
 			LOG.log(Level.SEVERE, ex.getMessage(), ex);
 		}
 	}
-}
\ No newline at end of file
+}
diff --git a/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/internal/LfsServerText.java b/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/internal/LfsServerText.java
index c5ad53a..2e088fd 100644
--- a/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/internal/LfsServerText.java
+++ b/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/internal/LfsServerText.java
@@ -58,7 +58,6 @@
 	}
 
 	// @formatter:off
-	/***/ public String corruptLongObject;
 	/***/ public String failedToCalcSignature;
 	/***/ public String invalidPathInfo;
 	/***/ public String objectNotFound;
diff --git a/org.eclipse.jgit.lfs.test/.classpath b/org.eclipse.jgit.lfs.test/.classpath
index efc781d..e43ae76 100644
--- a/org.eclipse.jgit.lfs.test/.classpath
+++ b/org.eclipse.jgit.lfs.test/.classpath
@@ -1,6 +1,6 @@
 <?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.7"/>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
 	<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
 	<classpathentry kind="src" path="src"/>
 	<classpathentry kind="src" path="tst"/>
diff --git a/org.eclipse.jgit.lfs.test/.settings/org.eclipse.jdt.core.prefs b/org.eclipse.jgit.lfs.test/.settings/org.eclipse.jdt.core.prefs
index 87210fb..10c29d5 100644
--- a/org.eclipse.jgit.lfs.test/.settings/org.eclipse.jdt.core.prefs
+++ b/org.eclipse.jgit.lfs.test/.settings/org.eclipse.jdt.core.prefs
@@ -7,9 +7,9 @@
 org.eclipse.jdt.core.compiler.annotation.nullanalysis=disabled
 org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
 org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
-org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
 org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
-org.eclipse.jdt.core.compiler.compliance=1.7
+org.eclipse.jdt.core.compiler.compliance=1.8
 org.eclipse.jdt.core.compiler.debug.lineNumber=generate
 org.eclipse.jdt.core.compiler.debug.localVariable=generate
 org.eclipse.jdt.core.compiler.debug.sourceFile=generate
@@ -112,7 +112,7 @@
 org.eclipse.jdt.core.compiler.problem.unusedTypeParameter=ignore
 org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning
 org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=error
-org.eclipse.jdt.core.compiler.source=1.7
+org.eclipse.jdt.core.compiler.source=1.8
 org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16
 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0
diff --git a/org.eclipse.jgit.lfs.test/BUCK b/org.eclipse.jgit.lfs.test/BUCK
index d0fb96f..1298e16 100644
--- a/org.eclipse.jgit.lfs.test/BUCK
+++ b/org.eclipse.jgit.lfs.test/BUCK
@@ -15,7 +15,6 @@
       '//lib:hamcrest-library',
       '//lib:junit',
     ],
-    source_under_test = ['//org.eclipse.jgit.lfs:jgit-lfs'],
   )
 
 java_library(
diff --git a/org.eclipse.jgit.lfs.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.lfs.test/META-INF/MANIFEST.MF
index 933002a..e859f63 100644
--- a/org.eclipse.jgit.lfs.test/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.lfs.test/META-INF/MANIFEST.MF
@@ -2,18 +2,19 @@
 Bundle-ManifestVersion: 2
 Bundle-Name: %plugin_name
 Bundle-SymbolicName: org.eclipse.jgit.lfs.test
-Bundle-Version: 4.5.3.qualifier
+Bundle-Version: 4.6.2.qualifier
 Bundle-Vendor: %provider_name
 Bundle-Localization: plugin
-Bundle-RequiredExecutionEnvironment: JavaSE-1.7
-Import-Package: org.eclipse.jgit.junit;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.lfs.errors;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.lfs.lib;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.lib;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.util;version="[4.5.3,4.6.0)",
+Bundle-RequiredExecutionEnvironment: JavaSE-1.8
+Import-Package: org.eclipse.jgit.junit;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.lfs;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.lfs.errors;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.lfs.lib;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.lib;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.util;version="[4.6.2,4.7.0)",
  org.hamcrest.core;version="[1.1.0,2.0.0)",
  org.junit;version="[4.0.0,5.0.0)",
  org.junit.runner;version="[4.0.0,5.0.0)",
  org.junit.runners;version="[4.0.0,5.0.0)"
-Export-Package: org.eclipse.jgit.lfs.test;version="4.5.3";x-friends:="org.eclipse.jgit.lfs.server.test"
+Export-Package: org.eclipse.jgit.lfs.test;version="4.6.2";x-friends:="org.eclipse.jgit.lfs.server.test"
 
diff --git a/org.eclipse.jgit.lfs.test/pom.xml b/org.eclipse.jgit.lfs.test/pom.xml
index 77d8d0e..a06aefc 100644
--- a/org.eclipse.jgit.lfs.test/pom.xml
+++ b/org.eclipse.jgit.lfs.test/pom.xml
@@ -50,7 +50,7 @@
   <parent>
     <groupId>org.eclipse.jgit</groupId>
     <artifactId>org.eclipse.jgit-parent</artifactId>
-    <version>4.5.3-SNAPSHOT</version>
+    <version>4.6.2-SNAPSHOT</version>
   </parent>
 
   <artifactId>org.eclipse.jgit.lfs.test</artifactId>
diff --git a/org.eclipse.jgit.lfs.test/tst/org/eclipse/jgit/lfs/lib/LFSPointerTest.java b/org.eclipse.jgit.lfs.test/tst/org/eclipse/jgit/lfs/lib/LFSPointerTest.java
new file mode 100644
index 0000000..4827d3d
--- /dev/null
+++ b/org.eclipse.jgit.lfs.test/tst/org/eclipse/jgit/lfs/lib/LFSPointerTest.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2016, Christian Halstrick <christian.halstrick@sap.com>
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ *   copyright notice, this list of conditions and the following
+ *   disclaimer in the documentation and/or other materials provided
+ *   with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ *   names of its contributors may be used to endorse or promote
+ *   products derived from this software without specific prior
+ *   written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.lfs.lib;
+
+import static org.junit.Assert.assertEquals;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+
+import org.eclipse.jgit.lfs.LfsPointer;
+import org.junit.Test;
+
+/*
+ * Test LfsPointer file abstraction
+ */
+public class LFSPointerTest {
+	@Test
+	public void testEncoding() throws IOException {
+		final String s = "27e15b72937fc8f558da24ac3d50ec20302a4cf21e33b87ae8e4ce90e89c4b10";
+		AnyLongObjectId id = LongObjectId.fromString(s);
+		LfsPointer ptr = new LfsPointer(id, 4);
+		ByteArrayOutputStream baos = new ByteArrayOutputStream();
+		ptr.encode(baos);
+		baos.close();
+		assertEquals("version https://git-lfs.github.com/spec/v1\noid sha256:"
+				+ s + "\nsize 4\n",
+				baos.toString(StandardCharsets.UTF_8.name()));
+	}
+}
diff --git a/org.eclipse.jgit.lfs/.classpath b/org.eclipse.jgit.lfs/.classpath
index 04a2be7..cfcf24a 100644
--- a/org.eclipse.jgit.lfs/.classpath
+++ b/org.eclipse.jgit.lfs/.classpath
@@ -2,7 +2,7 @@
 <classpath>
 	<classpathentry kind="src" path="src"/>
 	<classpathentry kind="src" path="resources"/>
-	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7"/>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
 	<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
 	<classpathentry kind="output" path="bin"/>
 </classpath>
diff --git a/org.eclipse.jgit.lfs/.settings/.api_filters b/org.eclipse.jgit.lfs/.settings/.api_filters
new file mode 100644
index 0000000..be675b1
--- /dev/null
+++ b/org.eclipse.jgit.lfs/.settings/.api_filters
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<component id="org.eclipse.jgit.lfs" version="2">
+    <resource path="src/org/eclipse/jgit/lfs/lib/Constants.java" type="org.eclipse.jgit.lfs.lib.Constants">
+        <filter id="388100214">
+            <message_arguments>
+                <message_argument value="org.eclipse.jgit.lfs.lib.Constants"/>
+                <message_argument value="CONTENT_TYPE_GIT_LFS_JSON"/>
+            </message_arguments>
+        </filter>
+        <filter id="388100214">
+            <message_arguments>
+                <message_argument value="org.eclipse.jgit.lfs.lib.Constants"/>
+                <message_argument value="HDR_APPLICATION_OCTET_STREAM"/>
+            </message_arguments>
+        </filter>
+    </resource>
+</component>
diff --git a/org.eclipse.jgit.lfs/.settings/org.eclipse.jdt.core.prefs b/org.eclipse.jgit.lfs/.settings/org.eclipse.jdt.core.prefs
index 1ce7cd0..808ec3a 100644
--- a/org.eclipse.jgit.lfs/.settings/org.eclipse.jdt.core.prefs
+++ b/org.eclipse.jgit.lfs/.settings/org.eclipse.jdt.core.prefs
@@ -7,9 +7,9 @@
 org.eclipse.jdt.core.compiler.annotation.nullanalysis=disabled
 org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
 org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
-org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
 org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
-org.eclipse.jdt.core.compiler.compliance=1.7
+org.eclipse.jdt.core.compiler.compliance=1.8
 org.eclipse.jdt.core.compiler.debug.lineNumber=generate
 org.eclipse.jdt.core.compiler.debug.localVariable=generate
 org.eclipse.jdt.core.compiler.debug.sourceFile=generate
@@ -112,7 +112,7 @@
 org.eclipse.jdt.core.compiler.problem.unusedTypeParameter=ignore
 org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning
 org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=error
-org.eclipse.jdt.core.compiler.source=1.7
+org.eclipse.jdt.core.compiler.source=1.8
 org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16
 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0
diff --git a/org.eclipse.jgit.lfs/META-INF/MANIFEST.MF b/org.eclipse.jgit.lfs/META-INF/MANIFEST.MF
index 854ca1d..d5d1f7c 100644
--- a/org.eclipse.jgit.lfs/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.lfs/META-INF/MANIFEST.MF
@@ -2,14 +2,17 @@
 Bundle-ManifestVersion: 2
 Bundle-Name: %plugin_name
 Bundle-SymbolicName: org.eclipse.jgit.lfs
-Bundle-Version: 4.5.3.qualifier
+Bundle-Version: 4.6.2.qualifier
 Bundle-Localization: plugin
 Bundle-Vendor: %provider_name
-Export-Package: org.eclipse.jgit.lfs.errors;version="4.5.3",
- org.eclipse.jgit.lfs.internal;version="4.5.3";x-friends:="org.eclipse.jgit.lfs.test",
- org.eclipse.jgit.lfs.lib;version="4.5.3"
-Bundle-RequiredExecutionEnvironment: JavaSE-1.7
-Import-Package: org.eclipse.jgit.internal.storage.file;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.lib;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.nls;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.util;version="[4.5.3,4.6.0)"
+Export-Package: org.eclipse.jgit.lfs;version="4.6.2",
+ org.eclipse.jgit.lfs.errors;version="4.6.2",
+ org.eclipse.jgit.lfs.internal;version="4.6.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="4.6.2"
+Bundle-RequiredExecutionEnvironment: JavaSE-1.8
+Import-Package: org.eclipse.jgit.annotations;version="[4.6.2,4.7.0)";resolution:=optional,
+ org.eclipse.jgit.attributes;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.internal.storage.file;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.lib;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.nls;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.util;version="[4.6.2,4.7.0)"
diff --git a/org.eclipse.jgit.lfs/pom.xml b/org.eclipse.jgit.lfs/pom.xml
index 179479e..049b360 100644
--- a/org.eclipse.jgit.lfs/pom.xml
+++ b/org.eclipse.jgit.lfs/pom.xml
@@ -50,7 +50,7 @@
   <parent>
     <groupId>org.eclipse.jgit</groupId>
     <artifactId>org.eclipse.jgit-parent</artifactId>
-    <version>4.5.3-SNAPSHOT</version>
+    <version>4.6.2-SNAPSHOT</version>
   </parent>
 
   <artifactId>org.eclipse.jgit.lfs</artifactId>
diff --git a/org.eclipse.jgit.lfs/resources/org/eclipse/jgit/lfs/internal/LfsText.properties b/org.eclipse.jgit.lfs/resources/org/eclipse/jgit/lfs/internal/LfsText.properties
index 7c3aea2..5e52a78 100644
--- a/org.eclipse.jgit.lfs/resources/org/eclipse/jgit/lfs/internal/LfsText.properties
+++ b/org.eclipse.jgit.lfs/resources/org/eclipse/jgit/lfs/internal/LfsText.properties
@@ -1,7 +1,9 @@
+corruptLongObject=The content hash ''{0}'' of the long object ''{1}'' doesn''t match its id, the corrupt object will be deleted.
 incorrectLONG_OBJECT_ID_LENGTH=Incorrect LONG_OBJECT_ID_LENGTH.
+inconsistentMediafileLength=mediafile {0} has unexpected length; expected {1} but found {2}.
 invalidLongId=Invalid id: {0}
 invalidLongIdLength=Invalid id length {0}; should be {1}
 requiredHashFunctionNotAvailable=Required hash function {0} not available.
 repositoryNotFound=Repository {0} not found
 repositoryReadOnly=Repository {0} is read-only
-lfsUnavailable=LFS is not available for repository {0}
\ No newline at end of file
+lfsUnavailable=LFS is not available for repository {0}
diff --git a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/CleanFilter.java b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/CleanFilter.java
new file mode 100644
index 0000000..66feca7
--- /dev/null
+++ b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/CleanFilter.java
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2016, Christian Halstrick <christian.halstrick@sap.com>
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ *   copyright notice, this list of conditions and the following
+ *   disclaimer in the documentation and/or other materials provided
+ *   with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ *   names of its contributors may be used to endorse or promote
+ *   products derived from this software without specific prior
+ *   written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.eclipse.jgit.lfs;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.StandardCopyOption;
+
+import org.eclipse.jgit.attributes.FilterCommand;
+import org.eclipse.jgit.attributes.FilterCommandFactory;
+import org.eclipse.jgit.attributes.FilterCommandRegistry;
+import org.eclipse.jgit.lfs.errors.CorruptMediaFile;
+import org.eclipse.jgit.lfs.internal.AtomicObjectOutputStream;
+import org.eclipse.jgit.lfs.lib.AnyLongObjectId;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.util.FileUtils;
+
+/**
+ * Built-in LFS clean filter
+ *
+ * When new content is about to be added to the git repository and this filter
+ * is configured for that content, then this filter will replace the original
+ * content with content of a so-called LFS pointer file. The pointer file
+ * content will then be added to the git repository. Additionally this filter
+ * writes the original content in a so-called 'media file' to '.git/lfs/objects/
+ * <first-two-characters-of-contentid>/<rest-of-contentid>'
+ *
+ * @see <a href="https://github.com/github/git-lfs/blob/master/docs/spec.md">Git
+ *      LFS Specification</a>
+ * @since 4.6
+ */
+public class CleanFilter extends FilterCommand {
+	/**
+	 * The factory is responsible for creating instances of {@link CleanFilter}
+	 */
+	public final static FilterCommandFactory FACTORY = new FilterCommandFactory() {
+
+		@Override
+		public FilterCommand create(Repository db, InputStream in,
+				OutputStream out) throws IOException {
+			return new CleanFilter(db, in, out);
+		}
+	};
+
+	/**
+	 * Registers this filter by calling
+	 * {@link FilterCommandRegistry#register(String, FilterCommandFactory)}
+	 */
+	public final static void register() {
+		FilterCommandRegistry.register(
+				org.eclipse.jgit.lib.Constants.BUILTIN_FILTER_PREFIX
+						+ "lfs/clean", //$NON-NLS-1$
+				FACTORY);
+	}
+
+	// Used to compute the hash for the original content
+	private AtomicObjectOutputStream aOut;
+
+	private Lfs lfsUtil;
+
+	// the size of the original content
+	private long size;
+
+	// a temporary file into which the original content is written. When no
+	// errors occur this file will be renamed to the mediafile
+	private Path tmpFile;
+
+	/**
+	 * @param db
+	 *            the repository
+	 * @param in
+	 *            an {@link InputStream} providing the original content
+	 * @param out
+	 *            the {@link OutputStream} into which the content of the pointer
+	 *            file should be written. That's the content which will be added
+	 *            to the git repository
+	 * @throws IOException
+	 *             when the creation of the temporary file fails or when no
+	 *             {@link OutputStream} for this file can be created
+	 */
+	public CleanFilter(Repository db, InputStream in, OutputStream out)
+			throws IOException {
+		super(in, out);
+		lfsUtil = new Lfs(db.getDirectory().toPath().resolve("lfs")); //$NON-NLS-1$
+		Files.createDirectories(lfsUtil.getLfsTmpDir());
+		tmpFile = lfsUtil.createTmpFile();
+		this.aOut = new AtomicObjectOutputStream(tmpFile.toAbsolutePath());
+	}
+
+	public int run() throws IOException {
+		try {
+			byte[] buf = new byte[8192];
+			int length = in.read(buf);
+			if (length != -1) {
+				aOut.write(buf, 0, length);
+				size += length;
+				return length;
+			} else {
+				aOut.close();
+				AnyLongObjectId loid = aOut.getId();
+				aOut = null;
+				Path mediaFile = lfsUtil.getMediaFile(loid);
+				if (Files.isRegularFile(mediaFile)) {
+					long fsSize = Files.size(mediaFile);
+					if (fsSize != size) {
+						throw new CorruptMediaFile(mediaFile, size, fsSize);
+					} else {
+						FileUtils.delete(tmpFile.toFile());
+					}
+				} else {
+					FileUtils.mkdirs(mediaFile.getParent().toFile(), true);
+					FileUtils.rename(tmpFile.toFile(), mediaFile.toFile(),
+							StandardCopyOption.ATOMIC_MOVE);
+				}
+				LfsPointer lfsPointer = new LfsPointer(loid, size);
+				lfsPointer.encode(out);
+				out.close();
+				return -1;
+			}
+		} catch (IOException e) {
+			if (aOut != null) {
+				aOut.abort();
+			}
+			out.close();
+			throw e;
+		}
+	}
+}
diff --git a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/Lfs.java b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/Lfs.java
new file mode 100644
index 0000000..75e34e0
--- /dev/null
+++ b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/Lfs.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2016, Christian Halstrick <christian.halstrick@sap.com>
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ *   copyright notice, this list of conditions and the following
+ *   disclaimer in the documentation and/or other materials provided
+ *   with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ *   names of its contributors may be used to endorse or promote
+ *   products derived from this software without specific prior
+ *   written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.eclipse.jgit.lfs;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+
+import org.eclipse.jgit.lfs.lib.AnyLongObjectId;
+
+/**
+ * Class which represents the lfs folder hierarchy inside a .git folder
+ *
+ * @since 4.6
+ */
+public class Lfs {
+	private Path root;
+
+	private Path objDir;
+
+	private Path tmpDir;
+
+	/**
+	 * @param root
+	 *            the path to the LFS media directory. Will be "<repo>/.git/lfs"
+	 */
+	public Lfs(Path root) {
+		this.root = root;
+	}
+
+	/**
+	 * @return the path to the LFS directory
+	 */
+	public Path getLfsRoot() {
+		return root;
+	}
+
+	/**
+	 * @return the path to the temp directory used by LFS. Will be
+	 *         "<repo>/.git/lfs/tmp"
+	 */
+	public Path getLfsTmpDir() {
+		if (tmpDir == null) {
+			tmpDir = root.resolve("tmp"); //$NON-NLS-1$
+		}
+		return tmpDir;
+	}
+
+	/**
+	 * @return the path to the object directory used by LFS. Will be
+	 *         "<repo>/.git/lfs/objects"
+	 */
+	public Path getLfsObjDir() {
+		if (objDir == null) {
+			objDir = root.resolve("objects"); //$NON-NLS-1$
+		}
+		return objDir;
+	}
+
+	/**
+	 * @param id
+	 *            the id of the mediafile
+	 * @return the file which stores the original content. This will be files
+	 *         underneath
+	 *         "<repo>/.git/lfs/objects/<firstTwoLettersOfID>/<remainingLettersOfID>"
+	 */
+	public Path getMediaFile(AnyLongObjectId id) {
+		String idStr = id.name();
+		return getLfsObjDir().resolve(idStr.substring(0, 2))
+				.resolve(idStr.substring(2));
+	}
+
+	/**
+	 * Create a new temp file in the LFS directory
+	 *
+	 * @return a new temporary file in the LFS directory
+	 * @throws IOException
+	 *             when the temp file could not be created
+	 */
+	public Path createTmpFile() throws IOException {
+		return Files.createTempFile(getLfsTmpDir(), null, null);
+	}
+
+}
diff --git a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/LfsPointer.java b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/LfsPointer.java
new file mode 100644
index 0000000..bbea535
--- /dev/null
+++ b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/LfsPointer.java
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2016, Christian Halstrick <christian.halstrick@sap.com>
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ *   copyright notice, this list of conditions and the following
+ *   disclaimer in the documentation and/or other materials provided
+ *   with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ *   names of its contributors may be used to endorse or promote
+ *   products derived from this software without specific prior
+ *   written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.eclipse.jgit.lfs;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.io.UnsupportedEncodingException;
+import java.nio.charset.StandardCharsets;
+import java.nio.charset.UnsupportedCharsetException;
+
+import org.eclipse.jgit.annotations.Nullable;
+import org.eclipse.jgit.lfs.lib.AnyLongObjectId;
+import org.eclipse.jgit.lfs.lib.Constants;
+import org.eclipse.jgit.lfs.lib.LongObjectId;
+
+/**
+ * Represents an LFS pointer file
+ *
+ * @since 4.6
+ */
+public class LfsPointer {
+	/**
+	 * The version of the LfsPointer file format
+	 */
+	public static final String VERSION = "https://git-lfs.github.com/spec/v1"; //$NON-NLS-1$
+
+	/**
+	 * The name of the hash function as used in the pointer files. This will
+	 * evaluate to "sha256"
+	 */
+	public static final String HASH_FUNCTION_NAME = Constants.LONG_HASH_FUNCTION
+			.toLowerCase().replace("-", ""); //$NON-NLS-1$ //$NON-NLS-2$
+
+	private AnyLongObjectId oid;
+
+	private long size;
+
+	/**
+	 * @param oid
+	 *            the id of the content
+	 * @param size
+	 *            the size of the content
+	 */
+	public LfsPointer(AnyLongObjectId oid, long size) {
+		this.oid = oid;
+		this.size = size;
+	}
+
+	/**
+	 * @return the id of the content
+	 */
+	public AnyLongObjectId getOid() {
+		return oid;
+	}
+
+	/**
+	 * @return the size of the content
+	 */
+	public long getSize() {
+		return size;
+	}
+
+	/**
+	 * Encode this object into the LFS format defined by {@link #VERSION}
+	 *
+	 * @param out
+	 *            the {@link OutputStream} into which the encoded data should be
+	 *            written
+	 */
+	public void encode(OutputStream out) {
+		try (PrintStream ps = new PrintStream(out, false,
+				StandardCharsets.UTF_8.name())) {
+			ps.print("version "); //$NON-NLS-1$
+			ps.print(VERSION + "\n"); //$NON-NLS-1$
+			ps.print("oid " + HASH_FUNCTION_NAME + ":"); //$NON-NLS-1$ //$NON-NLS-2$
+			ps.print(oid.name() + "\n"); //$NON-NLS-1$
+			ps.print("size "); //$NON-NLS-1$
+			ps.print(size + "\n"); //$NON-NLS-1$
+		} catch (UnsupportedEncodingException e) {
+			// should not happen, we are using a standard charset
+			throw new UnsupportedCharsetException(
+					StandardCharsets.UTF_8.name());
+		}
+	}
+
+	/**
+	 * Try to parse the data provided by an InputStream to the format defined by
+	 * {@link #VERSION}
+	 *
+	 * @param in
+	 *            the {@link InputStream} from where to read the data
+	 * @return an {@link LfsPointer} or <code>null</code> if the stream was not
+	 *         parseable as LfsPointer
+	 * @throws IOException
+	 */
+	@Nullable
+	public static LfsPointer parseLfsPointer(InputStream in)
+			throws IOException {
+		boolean versionLine = false;
+		LongObjectId id = null;
+		long sz = -1;
+
+		try (BufferedReader br = new BufferedReader(
+				new InputStreamReader(in, StandardCharsets.UTF_8.name()))) {
+			for (String s = br.readLine(); s != null; s = br.readLine()) {
+				if (s.startsWith("#") || s.length() == 0) { //$NON-NLS-1$
+					continue;
+				} else if (s.startsWith("version") && s.length() > 8 //$NON-NLS-1$
+						&& s.substring(8).trim().equals(VERSION)) {
+					versionLine = true;
+				} else if (s.startsWith("oid sha256:")) { //$NON-NLS-1$
+					id = LongObjectId.fromString(s.substring(11).trim());
+				} else if (s.startsWith("size") && s.length() > 5) { //$NON-NLS-1$
+					sz = Long.parseLong(s.substring(5).trim());
+				} else {
+					return null;
+				}
+			}
+			if (versionLine && id != null && sz > -1) {
+				return new LfsPointer(id, sz);
+			}
+		}
+		return null;
+	}
+
+	@Override
+	public String toString() {
+		return "LfsPointer: oid=" + oid.name() + ", size=" //$NON-NLS-1$ //$NON-NLS-2$
+				+ size;
+	}
+}
+
diff --git a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/SmudgeFilter.java b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/SmudgeFilter.java
new file mode 100644
index 0000000..2332477
--- /dev/null
+++ b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/SmudgeFilter.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2016, Christian Halstrick <christian.halstrick@sap.com>
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ *   copyright notice, this list of conditions and the following
+ *   disclaimer in the documentation and/or other materials provided
+ *   with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ *   names of its contributors may be used to endorse or promote
+ *   products derived from this software without specific prior
+ *   written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.eclipse.jgit.lfs;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+
+import org.eclipse.jgit.attributes.FilterCommand;
+import org.eclipse.jgit.attributes.FilterCommandFactory;
+import org.eclipse.jgit.attributes.FilterCommandRegistry;
+import org.eclipse.jgit.lfs.lib.Constants;
+import org.eclipse.jgit.lib.Repository;
+
+/**
+ * Built-in LFS smudge filter
+ *
+ * When content is read from git's object-database and written to the filesystem
+ * and this filter is configured for that content, then this filter will replace
+ * the content of LFS pointer files with the original content. This happens e.g.
+ * when a checkout needs to update a working tree file which is under LFS
+ * control. This implementation expects that the origin content is already
+ * available in the .git/lfs/objects folder. This implementation will not
+ * contact any LFS servers in order to get the missing content.
+ *
+ * @since 4.6
+ */
+public class SmudgeFilter extends FilterCommand {
+	/**
+	 * The factory is responsible for creating instances of {@link SmudgeFilter}
+	 */
+	public final static FilterCommandFactory FACTORY = new FilterCommandFactory() {
+		@Override
+		public FilterCommand create(Repository db, InputStream in,
+				OutputStream out) throws IOException {
+			return new SmudgeFilter(db, in, out);
+		}
+	};
+
+	/**
+	 * Registers this filter in JGit by calling
+	 */
+	public final static void register() {
+		FilterCommandRegistry.register(
+				org.eclipse.jgit.lib.Constants.BUILTIN_FILTER_PREFIX
+						+ "lfs/smudge", //$NON-NLS-1$
+				FACTORY);
+	}
+
+	private Lfs lfs;
+
+	/**
+	 * @param db
+	 * @param in
+	 * @param out
+	 * @throws IOException
+	 */
+	public SmudgeFilter(Repository db, InputStream in, OutputStream out)
+			throws IOException {
+		super(in, out);
+		lfs = new Lfs(db.getDirectory().toPath().resolve(Constants.LFS));
+		LfsPointer res = LfsPointer.parseLfsPointer(in);
+		if (res != null) {
+			Path mediaFile = lfs.getMediaFile(res.getOid());
+			if (Files.exists(mediaFile)) {
+				this.in = Files.newInputStream(mediaFile);
+			}
+		}
+	}
+
+	@Override
+	public int run() throws IOException {
+		int b;
+		if (in != null) {
+			while ((b = in.read()) != -1) {
+				out.write(b);
+			}
+			in.close();
+		}
+		out.close();
+		return -1;
+	}
+}
diff --git a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/errors/CorruptMediaFile.java b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/errors/CorruptMediaFile.java
new file mode 100644
index 0000000..f2b51c0
--- /dev/null
+++ b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/errors/CorruptMediaFile.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2016, Christian Halstrick <christian.halstrick@sap.com>
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ *   copyright notice, this list of conditions and the following
+ *   disclaimer in the documentation and/or other materials provided
+ *   with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ *   names of its contributors may be used to endorse or promote
+ *   products derived from this software without specific prior
+ *   written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.eclipse.jgit.lfs.errors;
+
+import java.io.IOException;
+import java.nio.file.Path;
+import java.text.MessageFormat;
+
+import org.eclipse.jgit.lfs.internal.LfsText;
+
+/**
+ * Thrown when a LFS mediafile is found which doesn't have the expected size
+ *
+ * @since 4.6
+ */
+public class CorruptMediaFile extends IOException {
+	private static final long serialVersionUID = 1L;
+
+	private Path mediaFile;
+
+	private long expectedSize;
+
+	private long size;
+
+	/**
+	 * @param mediaFile
+	 * @param expectedSize
+	 * @param size
+	 */
+	@SuppressWarnings("boxing")
+	public CorruptMediaFile(Path mediaFile, long expectedSize,
+			long size) {
+		super(MessageFormat.format(LfsText.get().inconsistentMediafileLength,
+				mediaFile, expectedSize, size));
+		this.mediaFile = mediaFile;
+		this.expectedSize = expectedSize;
+		this.size = size;
+	}
+
+	/**
+	 * @return the media file which seems to be corrupt
+	 */
+	public Path getMediaFile() {
+		return mediaFile;
+	}
+
+	/**
+	 * @return the expected size of the media file
+	 */
+	public long getExpectedSize() {
+		return expectedSize;
+	}
+
+	/**
+	 * @return the actual size of the media file in the file system
+	 */
+	public long getSize() {
+		return size;
+	}
+}
diff --git a/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/fs/AtomicObjectOutputStream.java b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/internal/AtomicObjectOutputStream.java
similarity index 79%
rename from org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/fs/AtomicObjectOutputStream.java
rename to org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/internal/AtomicObjectOutputStream.java
index ecc7c1f..867cca5 100644
--- a/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/fs/AtomicObjectOutputStream.java
+++ b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/internal/AtomicObjectOutputStream.java
@@ -40,7 +40,7 @@
  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
-package org.eclipse.jgit.lfs.server.fs;
+package org.eclipse.jgit.lfs.internal;
 
 import java.io.IOException;
 import java.io.OutputStream;
@@ -48,19 +48,19 @@
 import java.security.DigestOutputStream;
 import java.text.MessageFormat;
 
+import org.eclipse.jgit.annotations.Nullable;
 import org.eclipse.jgit.internal.storage.file.LockFile;
 import org.eclipse.jgit.lfs.errors.CorruptLongObjectException;
 import org.eclipse.jgit.lfs.lib.AnyLongObjectId;
 import org.eclipse.jgit.lfs.lib.Constants;
 import org.eclipse.jgit.lfs.lib.LongObjectId;
-import org.eclipse.jgit.lfs.server.internal.LfsServerText;
 
 /**
  * Output stream writing content to a {@link LockFile} which is committed on
  * close(). The stream checks if the hash of the stream content matches the
  * id.
  */
-class AtomicObjectOutputStream extends OutputStream {
+public class AtomicObjectOutputStream extends OutputStream {
 
 	private LockFile locked;
 
@@ -70,7 +70,12 @@
 
 	private AnyLongObjectId id;
 
-	AtomicObjectOutputStream(Path path, AnyLongObjectId id)
+	/**
+	 * @param path
+	 * @param id
+	 * @throws IOException
+	 */
+	public AtomicObjectOutputStream(Path path, AnyLongObjectId id)
 			throws IOException {
 		locked = new LockFile(path.toFile());
 		locked.lock();
@@ -79,6 +84,22 @@
 				Constants.newMessageDigest());
 	}
 
+	/**
+	 * @param path
+	 * @throws IOException
+	 */
+	public AtomicObjectOutputStream(Path path) throws IOException {
+		this(path, null);
+	}
+
+	/**
+	 * @return content hash of the object which was streamed through this
+	 *         stream. May return {@code null} if called before closing this stream.
+	 */
+	public @Nullable AnyLongObjectId getId() {
+		return id;
+	}
+
 	@Override
 	public void write(int b) throws IOException {
 		out.write(b);
@@ -98,7 +119,11 @@
 	public void close() throws IOException {
 		out.close();
 		if (!aborted) {
-			verifyHash();
+			if (id != null) {
+				verifyHash();
+			} else {
+				id = LongObjectId.fromRaw(out.getMessageDigest().digest());
+			}
 			locked.commit();
 		}
 	}
@@ -109,12 +134,15 @@
 		if (!contentHash.equals(id)) {
 			abort();
 			throw new CorruptLongObjectException(id, contentHash,
-					MessageFormat.format(LfsServerText.get().corruptLongObject,
+					MessageFormat.format(LfsText.get().corruptLongObject,
 							contentHash, id));
 		}
 	}
 
-	void abort() {
+	/**
+	 * Aborts the stream. Temporary file will be deleted
+	 */
+	public void abort() {
 		locked.unlock();
 		aborted = true;
 	}
diff --git a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/internal/LfsText.java b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/internal/LfsText.java
index 365eaa1..c76df39 100644
--- a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/internal/LfsText.java
+++ b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/internal/LfsText.java
@@ -58,6 +58,8 @@
 	}
 
 	// @formatter:off
+	/***/ public String corruptLongObject;
+	/***/ public String inconsistentMediafileLength;
 	/***/ public String incorrectLONG_OBJECT_ID_LENGTH;
 	/***/ public String invalidLongId;
 	/***/ public String invalidLongIdLength;
diff --git a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/lib/Constants.java b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/lib/Constants.java
index d246412..a88057a 100644
--- a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/lib/Constants.java
+++ b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/lib/Constants.java
@@ -55,8 +55,19 @@
  **/
 @SuppressWarnings("nls")
 public final class Constants {
-	/** Hash function used natively by Git LFS extension for large objects. */
-	private static final String LONG_HASH_FUNCTION = "SHA-256";
+	/**
+	 * lfs folder
+	 *
+	 * @since 4.6
+	 */
+	public static final String LFS = "lfs";
+
+	/**
+	 * Hash function used natively by Git LFS extension for large objects.
+	 *
+	 * @since 4.6
+	 */
+	public static final String LONG_HASH_FUNCTION = "SHA-256";
 
 	/**
 	 * A Git LFS large object hash is 256 bits, i.e. 32 bytes.
@@ -104,11 +115,11 @@
 	 * Content type used by LFS REST API as defined in
 	 * {@link "https://github.com/github/git-lfs/blob/master/docs/api/v1/http-v1-batch.md"}
 	 */
-	public static String CONTENT_TYPE_GIT_LFS_JSON = "application/vnd.git-lfs+json";
+	public static final String CONTENT_TYPE_GIT_LFS_JSON = "application/vnd.git-lfs+json";
 
 	/**
 	 * "arbitrary binary data" as defined in RFC 2046
 	 * {@link "https://www.ietf.org/rfc/rfc2046.txt"}
 	 */
-	public static String HDR_APPLICATION_OCTET_STREAM = "application/octet-stream";
+	public static final String HDR_APPLICATION_OCTET_STREAM = "application/octet-stream";
 }
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 89e9085..85ac88b 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.feature/feature.xml
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.feature/feature.xml
@@ -2,7 +2,7 @@
 <feature
       id="org.eclipse.jgit"
       label="%featureName"
-      version="4.5.3.qualifier"
+      version="4.6.2.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 a94261d..6f75186 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.feature/pom.xml
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.feature/pom.xml
@@ -50,7 +50,7 @@
   <parent>
     <groupId>org.eclipse.jgit</groupId>
     <artifactId>jgit.tycho.parent</artifactId>
-    <version>4.5.3-SNAPSHOT</version>
+    <version>4.6.2-SNAPSHOT</version>
   </parent>
 
   <groupId>org.eclipse.jgit.feature</groupId>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.http.apache.feature/feature.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.http.apache.feature/feature.xml
index 8ec3289..e272c0b 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.http.apache.feature/feature.xml
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.http.apache.feature/feature.xml
@@ -2,7 +2,7 @@
 <feature
       id="org.eclipse.jgit.http.apache"
       label="%featureName"
-      version="4.5.3.qualifier"
+      version="4.6.2.qualifier"
       provider-name="%providerName">
 
    <description url="http://www.eclipse.org/jgit/">
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.http.apache.feature/pom.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.http.apache.feature/pom.xml
index 0e05a9a..679f880 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.http.apache.feature/pom.xml
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.http.apache.feature/pom.xml
@@ -50,7 +50,7 @@
   <parent>
     <groupId>org.eclipse.jgit</groupId>
     <artifactId>jgit.tycho.parent</artifactId>
-    <version>4.5.3-SNAPSHOT</version>
+    <version>4.6.2-SNAPSHOT</version>
   </parent>
 
   <groupId>org.eclipse.jgit.feature</groupId>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.junit.feature/feature.properties b/org.eclipse.jgit.packaging/org.eclipse.jgit.junit.feature/feature.properties
index 9ef46ba..4450bbb 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.junit.feature/feature.properties
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.junit.feature/feature.properties
@@ -9,14 +9,13 @@
 #
 ###############################################################################
 
-featureName=JUnit test support for Java implementation of Git
+featureName=Java implementation of Git - JUnit test support
 providerName=Eclipse JGit
 
 updateSiteName=Eclipse JGit Update Site
 
 # description property - text of the "Feature Description"
-description=\
-JUnit test support for JGit.\n
+description=JUnit test support for JGit
 ################ end of description property ##################################
 
 # "copyright" property - text of the "Feature Update Copyright"
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 0ec7d18..fe7e3ac 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.junit.feature/feature.xml
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.junit.feature/feature.xml
@@ -2,7 +2,7 @@
 <feature
       id="org.eclipse.jgit.junit"
       label="%featureName"
-      version="4.5.3.qualifier"
+      version="4.6.2.qualifier"
       provider-name="%providerName">
 
    <description url="http://www.eclipse.org/jgit/">
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.junit.feature/pom.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.junit.feature/pom.xml
index 8076aa2..0b0a335 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.junit.feature/pom.xml
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.junit.feature/pom.xml
@@ -50,7 +50,7 @@
   <parent>
     <groupId>org.eclipse.jgit</groupId>
     <artifactId>jgit.tycho.parent</artifactId>
-    <version>4.5.3-SNAPSHOT</version>
+    <version>4.6.2-SNAPSHOT</version>
   </parent>
 
   <groupId>org.eclipse.jgit.feature</groupId>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.lfs.feature/feature.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.lfs.feature/feature.xml
index 5f0a5a5..4aefd72 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.lfs.feature/feature.xml
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.lfs.feature/feature.xml
@@ -2,7 +2,7 @@
 <feature
       id="org.eclipse.jgit.lfs"
       label="%featureName"
-      version="4.5.3.qualifier"
+      version="4.6.2.qualifier"
       provider-name="%providerName">
 
    <description url="http://www.eclipse.org/jgit/">
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.lfs.feature/pom.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.lfs.feature/pom.xml
index 5cf3de9..893c492 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.lfs.feature/pom.xml
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.lfs.feature/pom.xml
@@ -50,7 +50,7 @@
   <parent>
     <groupId>org.eclipse.jgit</groupId>
     <artifactId>jgit.tycho.parent</artifactId>
-    <version>4.5.3-SNAPSHOT</version>
+    <version>4.6.2-SNAPSHOT</version>
   </parent>
 
   <groupId>org.eclipse.jgit.feature</groupId>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.feature/feature.properties b/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.feature/feature.properties
index 1d1130a..8992ad3 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.feature/feature.properties
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.feature/feature.properties
@@ -8,14 +8,14 @@
 #
 ###############################################################################
 
-featureName=Command Line Interface for Java implementation of Git
+featureName=Java implementation of Git - Command Line Interface
 providerName=Eclipse JGit
 
 updateSiteName=Eclipse JGit Update Site
 
 # description property - text of the "Feature Description"
 description=\
-Command line interface for a pure Java implementation of the Git version control system.\n
+Command line interface for a pure Java implementation of the Git version control system
 ################ end of description property ##################################
 
 # "copyright" property - text of the "Feature Update Copyright"
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 6b40fbb..81f5e71 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.feature/feature.xml
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.feature/feature.xml
@@ -2,7 +2,7 @@
 <feature
       id="org.eclipse.jgit.pgm"
       label="%featureName"
-      version="4.5.3.qualifier"
+      version="4.6.2.qualifier"
       provider-name="%providerName">
 
    <description url="http://www.eclipse.org/jgit/">
@@ -31,8 +31,8 @@
          version="0.0.0"/>
 
    <requires>
-      <import feature="org.eclipse.jgit" version="4.5.0" match="equivalent"/>
-      <import feature="org.eclipse.jgit.lfs" version="4.5.0" match="equivalent"/>
+      <import feature="org.eclipse.jgit" version="4.6.1" match="equivalent"/>
+      <import feature="org.eclipse.jgit.lfs" version="4.6.1" 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 9ea842f..b6c5846 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.feature/pom.xml
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.feature/pom.xml
@@ -50,7 +50,7 @@
   <parent>
     <groupId>org.eclipse.jgit</groupId>
     <artifactId>jgit.tycho.parent</artifactId>
-    <version>4.5.3-SNAPSHOT</version>
+    <version>4.6.2-SNAPSHOT</version>
   </parent>
 
   <groupId>org.eclipse.jgit.feature</groupId>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.source.feature/feature.properties b/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.source.feature/feature.properties
index 20d6641..012c217 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.source.feature/feature.properties
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.source.feature/feature.properties
@@ -8,7 +8,7 @@
 #
 ###############################################################################
 
-featureName=Command Line Interface for Java implementation of Git - Source Code
+featureName=Java implementation of Git - Command Line Interface - Source Code
 providerName=Eclipse JGit
 
 updateSiteName=Eclipse JGit Update Site
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 b2af67e..444a872 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.source.feature/feature.xml
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.source.feature/feature.xml
@@ -2,7 +2,7 @@
 <feature
       id="org.eclipse.jgit.pgm.source"
       label="%featureName"
-      version="4.5.3.qualifier"
+      version="4.6.2.qualifier"
       provider-name="%providerName">
 
    <description url="http://www.eclipse.org/jgit/">
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.source.feature/pom.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.source.feature/pom.xml
index 6683d43..a35034a 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.source.feature/pom.xml
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.source.feature/pom.xml
@@ -50,7 +50,7 @@
   <parent>
     <groupId>org.eclipse.jgit</groupId>
     <artifactId>jgit.tycho.parent</artifactId>
-    <version>4.5.3-SNAPSHOT</version>
+    <version>4.6.2-SNAPSHOT</version>
   </parent>
 
   <groupId>org.eclipse.jgit.feature</groupId>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.repository/category.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.repository/category.xml
index 15d10e6..0149029 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.repository/category.xml
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.repository/category.xml
@@ -24,9 +24,9 @@
    <feature url="features/org.eclipse.jgit.lfs_0.0.0.qualifier.jar" id="org.eclipse.jgit.lfs" version="0.0.0">
       <category name="JGit"/>
    </feature>
-   <category-def name="JGit" label="JGit">
+   <category-def name="JGit" label="Java implementation of Git">
       <description>
-         JGit
+         Java implementation of Git
       </description>
    </category-def>
 </site>
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 2fa4e3f..d611d29 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.repository/pom.xml
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.repository/pom.xml
@@ -50,7 +50,7 @@
   <parent>
     <groupId>org.eclipse.jgit</groupId>
     <artifactId>jgit.tycho.parent</artifactId>
-    <version>4.5.3-SNAPSHOT</version>
+    <version>4.6.2-SNAPSHOT</version>
   </parent>
 
   <artifactId>org.eclipse.jgit.repository</artifactId>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.source.feature/feature.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.source.feature/feature.xml
index 12bee38..20ab58c 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.source.feature/feature.xml
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.source.feature/feature.xml
@@ -2,7 +2,7 @@
 <feature
       id="org.eclipse.jgit.source"
       label="%featureName"
-      version="4.5.3.qualifier"
+      version="4.6.2.qualifier"
       provider-name="%providerName">
 
    <description url="http://www.eclipse.org/jgit/">
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.source.feature/pom.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.source.feature/pom.xml
index 54eb5c0..e11e042 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.source.feature/pom.xml
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.source.feature/pom.xml
@@ -50,7 +50,7 @@
   <parent>
     <groupId>org.eclipse.jgit</groupId>
     <artifactId>jgit.tycho.parent</artifactId>
-    <version>4.5.3-SNAPSHOT</version>
+    <version>4.6.2-SNAPSHOT</version>
   </parent>
 
   <groupId>org.eclipse.jgit.feature</groupId>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/.classpath b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/.classpath
index 098194c..eca7bdb 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/.classpath
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/.classpath
@@ -1,6 +1,6 @@
 <?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.7"/>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
 	<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
 	<classpathentry kind="src" path="src"/>
 	<classpathentry kind="output" path="bin"/>
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 be64ac2..cd39231 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/META-INF/MANIFEST.MF
@@ -2,4 +2,4 @@
 Bundle-ManifestVersion: 2
 Bundle-Name: JGit Target Platform Bundle
 Bundle-SymbolicName: org.eclipse.jgit.target
-Bundle-Version: 4.5.3.qualifier
+Bundle-Version: 4.6.2.qualifier
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.3.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.3.target
deleted file mode 100644
index 19edf51..0000000
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.3.target
+++ /dev/null
@@ -1,68 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<?pde?>
-<!-- generated with https://github.com/mbarbero/fr.obeo.releng.targetplatform -->
-<target name="jgit-4.3" sequenceNumber="1440024094">
-  <locations>
-    <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
-      <unit id="org.eclipse.jetty.client" version="9.2.13.v20150730"/>
-      <unit id="org.eclipse.jetty.client.source" version="9.2.13.v20150730"/>
-      <unit id="org.eclipse.jetty.continuation" version="9.2.13.v20150730"/>
-      <unit id="org.eclipse.jetty.continuation.source" version="9.2.13.v20150730"/>
-      <unit id="org.eclipse.jetty.http" version="9.2.13.v20150730"/>
-      <unit id="org.eclipse.jetty.http.source" version="9.2.13.v20150730"/>
-      <unit id="org.eclipse.jetty.io" version="9.2.13.v20150730"/>
-      <unit id="org.eclipse.jetty.io.source" version="9.2.13.v20150730"/>
-      <unit id="org.eclipse.jetty.security" version="9.2.13.v20150730"/>
-      <unit id="org.eclipse.jetty.security.source" version="9.2.13.v20150730"/>
-      <unit id="org.eclipse.jetty.server" version="9.2.13.v20150730"/>
-      <unit id="org.eclipse.jetty.server.source" version="9.2.13.v20150730"/>
-      <unit id="org.eclipse.jetty.servlet" version="9.2.13.v20150730"/>
-      <unit id="org.eclipse.jetty.servlet.source" version="9.2.13.v20150730"/>
-      <unit id="org.eclipse.jetty.util" version="9.2.13.v20150730"/>
-      <unit id="org.eclipse.jetty.util.source" version="9.2.13.v20150730"/>
-      <repository id="jetty-9.2.13" location="http://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.2.13.v20150730/"/>
-    </location>
-    <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
-      <unit id="org.apache.ant" version="1.9.2.v201404171502"/>
-      <unit id="org.apache.ant.source" version="1.9.2.v201404171502"/>
-      <unit id="org.apache.commons.compress" version="1.6.0.v201310281400"/>
-      <unit id="org.apache.commons.compress.source" version="1.6.0.v201310281400"/>
-      <unit id="org.apache.commons.logging" version="1.1.1.v201101211721"/>
-      <unit id="org.apache.commons.logging.source" version="1.1.1.v201101211721"/>
-      <unit id="org.apache.httpcomponents.httpcore" version="4.3.3.v201411290715"/>
-      <unit id="org.apache.httpcomponents.httpcore.source" version="4.3.3.v201411290715"/>
-      <unit id="org.apache.httpcomponents.httpclient" version="4.3.6.v201411290715"/>
-      <unit id="org.apache.httpcomponents.httpclient.source" version="4.3.6.v201411290715"/>
-      <unit id="org.apache.log4j" version="1.2.15.v201012070815"/>
-      <unit id="org.apache.log4j.source" version="1.2.15.v201012070815"/>
-      <unit id="org.kohsuke.args4j" version="2.0.21.v201301150030"/>
-      <unit id="org.kohsuke.args4j.source" version="2.0.21.v201301150030"/>
-      <unit id="org.hamcrest.core" version="1.3.0.v201303031735"/>
-      <unit id="org.hamcrest.core.source" version="1.3.0.v201303031735"/>
-      <unit id="javaewah" version="0.7.9.v201401101600"/>
-      <unit id="javaewah.source" version="0.7.9.v201401101600"/>
-      <unit id="org.objenesis" version="1.0.0.v201105211943"/>
-      <unit id="org.objenesis.source" version="1.0.0.v201105211943"/>
-      <unit id="org.mockito" version="1.8.4.v201303031500"/>
-      <unit id="org.mockito.source" version="1.8.4.v201303031500"/>
-      <unit id="com.google.gson" version="2.2.4.v201311231704"/>
-      <unit id="com.jcraft.jsch" version="0.1.51.v201410302000"/>
-      <unit id="com.jcraft.jsch.source" version="0.1.51.v201410302000"/>
-      <unit id="org.junit" version="4.11.0.v201303080030"/>
-      <unit id="org.junit.source" version="4.11.0.v201303080030"/>
-      <unit id="javax.servlet" version="3.1.0.v20140303-1611"/>
-      <unit id="javax.servlet.source" version="3.1.0.v20140303-1611"/>
-      <unit id="org.tukaani.xz" version="1.3.0.v201308270617"/>
-      <unit id="org.tukaani.xz.source" version="1.3.0.v201308270617"/>
-      <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"/>
-      <unit id="org.slf4j.impl.log4j12.source" version="1.7.2.v20131105-2200"/>
-      <repository location="http://download.eclipse.org/tools/orbit/downloads/drops/R20150124073747/repository/"/>
-    </location>
-    <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
-      <unit id="org.eclipse.osgi" version="0.0.0"/>
-      <repository location="http://download.eclipse.org/releases/kepler/"/>
-    </location>
-  </locations>
-</target>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.3.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.3.tpd
deleted file mode 100644
index 062e930..0000000
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.3.tpd
+++ /dev/null
@@ -1,8 +0,0 @@
-target "jgit-4.3" with source configurePhase
-
-include "projects/jetty-9.2.13.tpd"
-include "orbit/R20150124073747-Luna-SR2.tpd"
-
-location "http://download.eclipse.org/releases/kepler/" {
-	org.eclipse.osgi lazy
-}
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.4.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.4.target
deleted file mode 100644
index 3451b42..0000000
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.4.target
+++ /dev/null
@@ -1,68 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<?pde?>
-<!-- generated with https://github.com/mbarbero/fr.obeo.releng.targetplatform -->
-<target name="jgit-4.4" sequenceNumber="1444167820">
-  <locations>
-    <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
-      <unit id="org.eclipse.jetty.client" version="9.2.13.v20150730"/>
-      <unit id="org.eclipse.jetty.client.source" version="9.2.13.v20150730"/>
-      <unit id="org.eclipse.jetty.continuation" version="9.2.13.v20150730"/>
-      <unit id="org.eclipse.jetty.continuation.source" version="9.2.13.v20150730"/>
-      <unit id="org.eclipse.jetty.http" version="9.2.13.v20150730"/>
-      <unit id="org.eclipse.jetty.http.source" version="9.2.13.v20150730"/>
-      <unit id="org.eclipse.jetty.io" version="9.2.13.v20150730"/>
-      <unit id="org.eclipse.jetty.io.source" version="9.2.13.v20150730"/>
-      <unit id="org.eclipse.jetty.security" version="9.2.13.v20150730"/>
-      <unit id="org.eclipse.jetty.security.source" version="9.2.13.v20150730"/>
-      <unit id="org.eclipse.jetty.server" version="9.2.13.v20150730"/>
-      <unit id="org.eclipse.jetty.server.source" version="9.2.13.v20150730"/>
-      <unit id="org.eclipse.jetty.servlet" version="9.2.13.v20150730"/>
-      <unit id="org.eclipse.jetty.servlet.source" version="9.2.13.v20150730"/>
-      <unit id="org.eclipse.jetty.util" version="9.2.13.v20150730"/>
-      <unit id="org.eclipse.jetty.util.source" version="9.2.13.v20150730"/>
-      <repository id="jetty-9.2.13" location="http://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.2.13.v20150730/"/>
-    </location>
-    <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
-      <unit id="org.apache.ant" version="1.9.2.v201404171502"/>
-      <unit id="org.apache.ant.source" version="1.9.2.v201404171502"/>
-      <unit id="org.apache.commons.compress" version="1.6.0.v201310281400"/>
-      <unit id="org.apache.commons.compress.source" version="1.6.0.v201310281400"/>
-      <unit id="org.apache.commons.logging" version="1.1.1.v201101211721"/>
-      <unit id="org.apache.commons.logging.source" version="1.1.1.v201101211721"/>
-      <unit id="org.apache.httpcomponents.httpcore" version="4.3.3.v201411290715"/>
-      <unit id="org.apache.httpcomponents.httpcore.source" version="4.3.3.v201411290715"/>
-      <unit id="org.apache.httpcomponents.httpclient" version="4.3.6.v201411290715"/>
-      <unit id="org.apache.httpcomponents.httpclient.source" version="4.3.6.v201411290715"/>
-      <unit id="org.apache.log4j" version="1.2.15.v201012070815"/>
-      <unit id="org.apache.log4j.source" version="1.2.15.v201012070815"/>
-      <unit id="org.kohsuke.args4j" version="2.0.21.v201301150030"/>
-      <unit id="org.kohsuke.args4j.source" version="2.0.21.v201301150030"/>
-      <unit id="org.hamcrest.core" version="1.3.0.v201303031735"/>
-      <unit id="org.hamcrest.core.source" version="1.3.0.v201303031735"/>
-      <unit id="javaewah" version="0.7.9.v201401101600"/>
-      <unit id="javaewah.source" version="0.7.9.v201401101600"/>
-      <unit id="org.objenesis" version="1.0.0.v201105211943"/>
-      <unit id="org.objenesis.source" version="1.0.0.v201105211943"/>
-      <unit id="org.mockito" version="1.8.4.v201303031500"/>
-      <unit id="org.mockito.source" version="1.8.4.v201303031500"/>
-      <unit id="com.google.gson" version="2.2.4.v201311231704"/>
-      <unit id="com.jcraft.jsch" version="0.1.51.v201410302000"/>
-      <unit id="com.jcraft.jsch.source" version="0.1.51.v201410302000"/>
-      <unit id="org.junit" version="4.11.0.v201303080030"/>
-      <unit id="org.junit.source" version="4.11.0.v201303080030"/>
-      <unit id="javax.servlet" version="3.1.0.v20140303-1611"/>
-      <unit id="javax.servlet.source" version="3.1.0.v20140303-1611"/>
-      <unit id="org.tukaani.xz" version="1.3.0.v201308270617"/>
-      <unit id="org.tukaani.xz.source" version="1.3.0.v201308270617"/>
-      <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"/>
-      <unit id="org.slf4j.impl.log4j12.source" version="1.7.2.v20131105-2200"/>
-      <repository location="http://download.eclipse.org/tools/orbit/downloads/drops/R20150124073747/repository/"/>
-    </location>
-    <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
-      <unit id="org.eclipse.osgi" version="0.0.0"/>
-      <repository location="http://download.eclipse.org/releases/luna/"/>
-    </location>
-  </locations>
-</target>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.4.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.4.tpd
deleted file mode 100644
index 9b9558f..0000000
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.4.tpd
+++ /dev/null
@@ -1,8 +0,0 @@
-target "jgit-4.4" with source configurePhase
-
-include "projects/jetty-9.2.13.tpd"
-include "orbit/R20150124073747-Luna-SR2.tpd"
-
-location "http://download.eclipse.org/releases/luna/" {
-	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 08116eb..d0da0c4 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,26 +1,26 @@
 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
 <?pde?>
 <!-- generated with https://github.com/mbarbero/fr.obeo.releng.targetplatform -->
-<target name="jgit-4.5" sequenceNumber="1456522731">
+<target name="jgit-4.5" sequenceNumber="1502746491">
   <locations>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
-      <unit id="org.eclipse.jetty.client" version="9.2.13.v20150730"/>
-      <unit id="org.eclipse.jetty.client.source" version="9.2.13.v20150730"/>
-      <unit id="org.eclipse.jetty.continuation" version="9.2.13.v20150730"/>
-      <unit id="org.eclipse.jetty.continuation.source" version="9.2.13.v20150730"/>
-      <unit id="org.eclipse.jetty.http" version="9.2.13.v20150730"/>
-      <unit id="org.eclipse.jetty.http.source" version="9.2.13.v20150730"/>
-      <unit id="org.eclipse.jetty.io" version="9.2.13.v20150730"/>
-      <unit id="org.eclipse.jetty.io.source" version="9.2.13.v20150730"/>
-      <unit id="org.eclipse.jetty.security" version="9.2.13.v20150730"/>
-      <unit id="org.eclipse.jetty.security.source" version="9.2.13.v20150730"/>
-      <unit id="org.eclipse.jetty.server" version="9.2.13.v20150730"/>
-      <unit id="org.eclipse.jetty.server.source" version="9.2.13.v20150730"/>
-      <unit id="org.eclipse.jetty.servlet" version="9.2.13.v20150730"/>
-      <unit id="org.eclipse.jetty.servlet.source" version="9.2.13.v20150730"/>
-      <unit id="org.eclipse.jetty.util" version="9.2.13.v20150730"/>
-      <unit id="org.eclipse.jetty.util.source" version="9.2.13.v20150730"/>
-      <repository id="jetty-9.2.13" location="http://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.2.13.v20150730/"/>
+      <unit id="org.eclipse.jetty.client" version="9.3.17.v20170317"/>
+      <unit id="org.eclipse.jetty.client.source" version="9.3.17.v20170317"/>
+      <unit id="org.eclipse.jetty.continuation" version="9.3.17.v20170317"/>
+      <unit id="org.eclipse.jetty.continuation.source" version="9.3.17.v20170317"/>
+      <unit id="org.eclipse.jetty.http" version="9.3.17.v20170317"/>
+      <unit id="org.eclipse.jetty.http.source" version="9.3.17.v20170317"/>
+      <unit id="org.eclipse.jetty.io" version="9.3.17.v20170317"/>
+      <unit id="org.eclipse.jetty.io.source" version="9.3.17.v20170317"/>
+      <unit id="org.eclipse.jetty.security" version="9.3.17.v20170317"/>
+      <unit id="org.eclipse.jetty.security.source" version="9.3.17.v20170317"/>
+      <unit id="org.eclipse.jetty.server" version="9.3.17.v20170317"/>
+      <unit id="org.eclipse.jetty.server.source" version="9.3.17.v20170317"/>
+      <unit id="org.eclipse.jetty.servlet" version="9.3.17.v20170317"/>
+      <unit id="org.eclipse.jetty.servlet.source" version="9.3.17.v20170317"/>
+      <unit id="org.eclipse.jetty.util" version="9.3.17.v20170317"/>
+      <unit id="org.eclipse.jetty.util.source" version="9.3.17.v20170317"/>
+      <repository id="jetty-9.3.17" location="http://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.3.17.v20170317/"/>
     </location>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
       <unit id="org.apache.ant" version="1.9.4.v201504302020"/>
@@ -61,6 +61,46 @@
       <repository location="http://download.eclipse.org/tools/orbit/downloads/drops/R20160221192158/repository/"/>
     </location>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
+      <unit id="org.apache.ant" version="1.9.6.v201510161327"/>
+      <unit id="org.apache.ant.source" version="1.9.6.v201510161327"/>
+      <unit id="org.apache.commons.compress" version="1.6.0.v201310281400"/>
+      <unit id="org.apache.commons.compress.source" version="1.6.0.v201310281400"/>
+      <unit id="org.apache.commons.logging" version="1.1.1.v201101211721"/>
+      <unit id="org.apache.commons.logging.source" version="1.1.1.v201101211721"/>
+      <unit id="org.apache.httpcomponents.httpcore" version="4.3.3.v201411290715"/>
+      <unit id="org.apache.httpcomponents.httpcore.source" version="4.3.3.v201411290715"/>
+      <unit id="org.apache.httpcomponents.httpclient" version="4.3.6.v201511171540"/>
+      <unit id="org.apache.httpcomponents.httpclient.source" version="4.3.6.v201511171540"/>
+      <unit id="org.apache.log4j" version="1.2.15.v201012070815"/>
+      <unit id="org.apache.log4j.source" version="1.2.15.v201012070815"/>
+      <unit id="org.kohsuke.args4j" version="2.0.21.v201301150030"/>
+      <unit id="org.kohsuke.args4j.source" version="2.0.21.v201301150030"/>
+      <unit id="org.hamcrest.core" version="1.3.0.v201303031735"/>
+      <unit id="org.hamcrest.core.source" version="1.3.0.v201303031735"/>
+      <unit id="org.hamcrest.library" version="1.3.0.v201505072020"/>
+      <unit id="org.hamcrest.library.source" version="1.3.0.v201505072020"/>
+      <unit id="javaewah" version="1.1.6.v20160919-1400"/>
+      <unit id="javaewah.source" version="1.1.6.v20160919-1400"/>
+      <unit id="org.objenesis" version="1.0.0.v201505121915"/>
+      <unit id="org.objenesis.source" version="1.0.0.v201505121915"/>
+      <unit id="org.mockito" version="1.8.4.v201303031500"/>
+      <unit id="org.mockito.source" version="1.8.4.v201303031500"/>
+      <unit id="com.google.gson" version="2.2.4.v201311231704"/>
+      <unit id="com.jcraft.jsch" version="0.1.54.v20170116-1932"/>
+      <unit id="com.jcraft.jsch.source" version="0.1.54.v20170116-1932"/>
+      <unit id="org.junit" version="4.12.0.v201504281640"/>
+      <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.3.0.v201308270617"/>
+      <unit id="org.tukaani.xz.source" version="1.3.0.v201308270617"/>
+      <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"/>
+      <unit id="org.slf4j.impl.log4j12.source" version="1.7.2.v20131105-2200"/>
+      <repository location="http://download.eclipse.org/tools/orbit/R-builds/R20170516192513/repository"/>
+    </location>
+    <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
       <unit id="org.eclipse.osgi" version="0.0.0"/>
       <repository location="http://download.eclipse.org/releases/mars/"/>
     </location>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.5.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.5.tpd
index 5cd1037..efc1f44 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.5.tpd
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.5.tpd
@@ -1,7 +1,8 @@
 target "jgit-4.5" with source configurePhase
 
-include "projects/jetty-9.2.13.tpd"
+include "projects/jetty-9.3.17.tpd"
 include "orbit/R20160221192158-Mars.tpd"
+include "orbit/R20170516192513-Oxygen.tpd"
 
 location "http://download.eclipse.org/releases/mars/" {
 	org.eclipse.osgi lazy
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.6.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.6.target
index a1f5abf..065284d 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.6.target
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.6.target
@@ -1,26 +1,26 @@
 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
 <?pde?>
 <!-- generated with https://github.com/mbarbero/fr.obeo.releng.targetplatform -->
-<target name="jgit-4.6" sequenceNumber="1465553981">
+<target name="jgit-4.6" sequenceNumber="1502746433">
   <locations>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
-      <unit id="org.eclipse.jetty.client" version="9.2.13.v20150730"/>
-      <unit id="org.eclipse.jetty.client.source" version="9.2.13.v20150730"/>
-      <unit id="org.eclipse.jetty.continuation" version="9.2.13.v20150730"/>
-      <unit id="org.eclipse.jetty.continuation.source" version="9.2.13.v20150730"/>
-      <unit id="org.eclipse.jetty.http" version="9.2.13.v20150730"/>
-      <unit id="org.eclipse.jetty.http.source" version="9.2.13.v20150730"/>
-      <unit id="org.eclipse.jetty.io" version="9.2.13.v20150730"/>
-      <unit id="org.eclipse.jetty.io.source" version="9.2.13.v20150730"/>
-      <unit id="org.eclipse.jetty.security" version="9.2.13.v20150730"/>
-      <unit id="org.eclipse.jetty.security.source" version="9.2.13.v20150730"/>
-      <unit id="org.eclipse.jetty.server" version="9.2.13.v20150730"/>
-      <unit id="org.eclipse.jetty.server.source" version="9.2.13.v20150730"/>
-      <unit id="org.eclipse.jetty.servlet" version="9.2.13.v20150730"/>
-      <unit id="org.eclipse.jetty.servlet.source" version="9.2.13.v20150730"/>
-      <unit id="org.eclipse.jetty.util" version="9.2.13.v20150730"/>
-      <unit id="org.eclipse.jetty.util.source" version="9.2.13.v20150730"/>
-      <repository id="jetty-9.2.13" location="http://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.2.13.v20150730/"/>
+      <unit id="org.eclipse.jetty.client" version="9.3.17.v20170317"/>
+      <unit id="org.eclipse.jetty.client.source" version="9.3.17.v20170317"/>
+      <unit id="org.eclipse.jetty.continuation" version="9.3.17.v20170317"/>
+      <unit id="org.eclipse.jetty.continuation.source" version="9.3.17.v20170317"/>
+      <unit id="org.eclipse.jetty.http" version="9.3.17.v20170317"/>
+      <unit id="org.eclipse.jetty.http.source" version="9.3.17.v20170317"/>
+      <unit id="org.eclipse.jetty.io" version="9.3.17.v20170317"/>
+      <unit id="org.eclipse.jetty.io.source" version="9.3.17.v20170317"/>
+      <unit id="org.eclipse.jetty.security" version="9.3.17.v20170317"/>
+      <unit id="org.eclipse.jetty.security.source" version="9.3.17.v20170317"/>
+      <unit id="org.eclipse.jetty.server" version="9.3.17.v20170317"/>
+      <unit id="org.eclipse.jetty.server.source" version="9.3.17.v20170317"/>
+      <unit id="org.eclipse.jetty.servlet" version="9.3.17.v20170317"/>
+      <unit id="org.eclipse.jetty.servlet.source" version="9.3.17.v20170317"/>
+      <unit id="org.eclipse.jetty.util" version="9.3.17.v20170317"/>
+      <unit id="org.eclipse.jetty.util.source" version="9.3.17.v20170317"/>
+      <repository id="jetty-9.3.17" location="http://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.3.17.v20170317/"/>
     </location>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
       <unit id="org.apache.ant" version="1.9.6.v201510161327"/>
@@ -39,15 +39,17 @@
       <unit id="org.kohsuke.args4j.source" version="2.0.21.v201301150030"/>
       <unit id="org.hamcrest.core" version="1.3.0.v201303031735"/>
       <unit id="org.hamcrest.core.source" version="1.3.0.v201303031735"/>
-      <unit id="javaewah" version="0.7.9.v201605172130"/>
-      <unit id="javaewah.source" version="0.7.9.v201605172130"/>
+      <unit id="org.hamcrest.library" version="1.3.0.v201505072020"/>
+      <unit id="org.hamcrest.library.source" version="1.3.0.v201505072020"/>
+      <unit id="javaewah" version="1.1.6.v20160919-1400"/>
+      <unit id="javaewah.source" version="1.1.6.v20160919-1400"/>
       <unit id="org.objenesis" version="1.0.0.v201505121915"/>
       <unit id="org.objenesis.source" version="1.0.0.v201505121915"/>
       <unit id="org.mockito" version="1.8.4.v201303031500"/>
       <unit id="org.mockito.source" version="1.8.4.v201303031500"/>
       <unit id="com.google.gson" version="2.2.4.v201311231704"/>
-      <unit id="com.jcraft.jsch" version="0.1.53.v201508180515"/>
-      <unit id="com.jcraft.jsch.source" version="0.1.53.v201508180515"/>
+      <unit id="com.jcraft.jsch" version="0.1.54.v20170116-1932"/>
+      <unit id="com.jcraft.jsch.source" version="0.1.54.v20170116-1932"/>
       <unit id="org.junit" version="4.12.0.v201504281640"/>
       <unit id="org.junit.source" version="4.12.0.v201504281640"/>
       <unit id="javax.servlet" version="3.1.0.v201410161800"/>
@@ -58,7 +60,7 @@
       <unit id="org.slf4j.api.source" version="1.7.2.v20121108-1250"/>
       <unit id="org.slf4j.impl.log4j12" version="1.7.2.v20131105-2200"/>
       <unit id="org.slf4j.impl.log4j12.source" version="1.7.2.v20131105-2200"/>
-      <repository location="http://download.eclipse.org/tools/orbit/downloads/drops/R20160520211859/repository/"/>
+      <repository location="http://download.eclipse.org/tools/orbit/R-builds/R20170516192513/repository"/>
     </location>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
       <unit id="org.eclipse.osgi" version="0.0.0"/>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.6.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.6.tpd
index c784c1f..90f62ae 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.6.tpd
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.6.tpd
@@ -1,7 +1,7 @@
 target "jgit-4.6" with source configurePhase
 
-include "projects/jetty-9.2.13.tpd"
-include "orbit/R20160520211859-Neon.tpd"
+include "projects/jetty-9.3.17.tpd"
+include "orbit/R20170516192513-Oxygen.tpd"
 
 location "http://download.eclipse.org/releases/neon/" {
 	org.eclipse.osgi lazy
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.7.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.7.target
new file mode 100644
index 0000000..d3a1131
--- /dev/null
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.7.target
@@ -0,0 +1,70 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<?pde?>
+<!-- generated with https://github.com/mbarbero/fr.obeo.releng.targetplatform -->
+<target name="jgit-4.7" sequenceNumber="1502746477">
+  <locations>
+    <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
+      <unit id="org.eclipse.jetty.client" version="9.3.17.v20170317"/>
+      <unit id="org.eclipse.jetty.client.source" version="9.3.17.v20170317"/>
+      <unit id="org.eclipse.jetty.continuation" version="9.3.17.v20170317"/>
+      <unit id="org.eclipse.jetty.continuation.source" version="9.3.17.v20170317"/>
+      <unit id="org.eclipse.jetty.http" version="9.3.17.v20170317"/>
+      <unit id="org.eclipse.jetty.http.source" version="9.3.17.v20170317"/>
+      <unit id="org.eclipse.jetty.io" version="9.3.17.v20170317"/>
+      <unit id="org.eclipse.jetty.io.source" version="9.3.17.v20170317"/>
+      <unit id="org.eclipse.jetty.security" version="9.3.17.v20170317"/>
+      <unit id="org.eclipse.jetty.security.source" version="9.3.17.v20170317"/>
+      <unit id="org.eclipse.jetty.server" version="9.3.17.v20170317"/>
+      <unit id="org.eclipse.jetty.server.source" version="9.3.17.v20170317"/>
+      <unit id="org.eclipse.jetty.servlet" version="9.3.17.v20170317"/>
+      <unit id="org.eclipse.jetty.servlet.source" version="9.3.17.v20170317"/>
+      <unit id="org.eclipse.jetty.util" version="9.3.17.v20170317"/>
+      <unit id="org.eclipse.jetty.util.source" version="9.3.17.v20170317"/>
+      <repository id="jetty-9.3.17" location="http://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.3.17.v20170317/"/>
+    </location>
+    <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
+      <unit id="org.apache.ant" version="1.9.6.v201510161327"/>
+      <unit id="org.apache.ant.source" version="1.9.6.v201510161327"/>
+      <unit id="org.apache.commons.compress" version="1.6.0.v201310281400"/>
+      <unit id="org.apache.commons.compress.source" version="1.6.0.v201310281400"/>
+      <unit id="org.apache.commons.logging" version="1.1.1.v201101211721"/>
+      <unit id="org.apache.commons.logging.source" version="1.1.1.v201101211721"/>
+      <unit id="org.apache.httpcomponents.httpcore" version="4.3.3.v201411290715"/>
+      <unit id="org.apache.httpcomponents.httpcore.source" version="4.3.3.v201411290715"/>
+      <unit id="org.apache.httpcomponents.httpclient" version="4.3.6.v201511171540"/>
+      <unit id="org.apache.httpcomponents.httpclient.source" version="4.3.6.v201511171540"/>
+      <unit id="org.apache.log4j" version="1.2.15.v201012070815"/>
+      <unit id="org.apache.log4j.source" version="1.2.15.v201012070815"/>
+      <unit id="org.kohsuke.args4j" version="2.0.21.v201301150030"/>
+      <unit id="org.kohsuke.args4j.source" version="2.0.21.v201301150030"/>
+      <unit id="org.hamcrest.core" version="1.3.0.v201303031735"/>
+      <unit id="org.hamcrest.core.source" version="1.3.0.v201303031735"/>
+      <unit id="org.hamcrest.library" version="1.3.0.v201505072020"/>
+      <unit id="org.hamcrest.library.source" version="1.3.0.v201505072020"/>
+      <unit id="javaewah" version="1.1.6.v20160919-1400"/>
+      <unit id="javaewah.source" version="1.1.6.v20160919-1400"/>
+      <unit id="org.objenesis" version="1.0.0.v201505121915"/>
+      <unit id="org.objenesis.source" version="1.0.0.v201505121915"/>
+      <unit id="org.mockito" version="1.8.4.v201303031500"/>
+      <unit id="org.mockito.source" version="1.8.4.v201303031500"/>
+      <unit id="com.google.gson" version="2.2.4.v201311231704"/>
+      <unit id="com.jcraft.jsch" version="0.1.54.v20170116-1932"/>
+      <unit id="com.jcraft.jsch.source" version="0.1.54.v20170116-1932"/>
+      <unit id="org.junit" version="4.12.0.v201504281640"/>
+      <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.3.0.v201308270617"/>
+      <unit id="org.tukaani.xz.source" version="1.3.0.v201308270617"/>
+      <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"/>
+      <unit id="org.slf4j.impl.log4j12.source" version="1.7.2.v20131105-2200"/>
+      <repository location="http://download.eclipse.org/tools/orbit/R-builds/R20170516192513/repository"/>
+    </location>
+    <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
+      <unit id="org.eclipse.osgi" version="0.0.0"/>
+      <repository location="http://download.eclipse.org/releases/oxygen/"/>
+    </location>
+  </locations>
+</target>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.7.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.7.tpd
new file mode 100644
index 0000000..1d0e693
--- /dev/null
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.7.tpd
@@ -0,0 +1,8 @@
+target "jgit-4.7" with source configurePhase
+
+include "projects/jetty-9.3.17.tpd"
+include "orbit/R20170516192513-Oxygen.tpd"
+
+location "http://download.eclipse.org/releases/oxygen/" {
+	org.eclipse.osgi lazy
+}
\ No newline at end of file
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/R20170516192513-Oxygen.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/R20170516192513-Oxygen.tpd
new file mode 100644
index 0000000..3600628
--- /dev/null
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/R20170516192513-Oxygen.tpd
@@ -0,0 +1,42 @@
+target "R20170516192513-Oxygen" with source configurePhase
+// see http://download.eclipse.org/tools/orbit/downloads/
+
+location "http://download.eclipse.org/tools/orbit/R-builds/R20170516192513/repository" {
+	org.apache.ant [1.9.6.v201510161327,1.9.6.v201510161327]
+	org.apache.ant.source [1.9.6.v201510161327,1.9.6.v201510161327]
+	org.apache.commons.compress [1.6.0.v201310281400,1.6.0.v201310281400]
+	org.apache.commons.compress.source [1.6.0.v201310281400,1.6.0.v201310281400]
+	org.apache.commons.logging [1.1.1.v201101211721,1.1.1.v201101211721]
+	org.apache.commons.logging.source [1.1.1.v201101211721,1.1.1.v201101211721]
+	org.apache.httpcomponents.httpcore [4.3.3.v201411290715,4.3.3.v201411290715]
+	org.apache.httpcomponents.httpcore.source [4.3.3.v201411290715,4.3.3.v201411290715]
+	org.apache.httpcomponents.httpclient [4.3.6.v201511171540,4.3.6.v201511171540]
+	org.apache.httpcomponents.httpclient.source [4.3.6.v201511171540,4.3.6.v201511171540]
+	org.apache.log4j [1.2.15.v201012070815,1.2.15.v201012070815]
+	org.apache.log4j.source [1.2.15.v201012070815,1.2.15.v201012070815]
+	org.kohsuke.args4j [2.0.21.v201301150030,2.0.21.v201301150030]
+	org.kohsuke.args4j.source [2.0.21.v201301150030,2.0.21.v201301150030]
+	org.hamcrest.core [1.3.0.v201303031735,1.3.0.v201303031735]
+	org.hamcrest.core.source [1.3.0.v201303031735,1.3.0.v201303031735]
+	org.hamcrest.library [1.3.0.v201505072020,1.3.0.v201505072020]
+	org.hamcrest.library.source [1.3.0.v201505072020,1.3.0.v201505072020]
+	javaewah [1.1.6.v20160919-1400,1.1.6.v20160919-1400]
+	javaewah.source [1.1.6.v20160919-1400,1.1.6.v20160919-1400]
+	org.objenesis [1.0.0.v201505121915,1.0.0.v201505121915]
+	org.objenesis.source [1.0.0.v201505121915,1.0.0.v201505121915]
+	org.mockito [1.8.4.v201303031500,1.8.4.v201303031500]
+	org.mockito.source [1.8.4.v201303031500,1.8.4.v201303031500]
+	com.google.gson [2.2.4.v201311231704,2.2.4.v201311231704]
+	com.jcraft.jsch [0.1.54.v20170116-1932,0.1.54.v20170116-1932]
+	com.jcraft.jsch.source [0.1.54.v20170116-1932,0.1.54.v20170116-1932]
+	org.junit [4.12.0.v201504281640,4.12.0.v201504281640]
+	org.junit.source [4.12.0.v201504281640,4.12.0.v201504281640]
+	javax.servlet [3.1.0.v201410161800,3.1.0.v201410161800]
+	javax.servlet.source [3.1.0.v201410161800,3.1.0.v201410161800]
+	org.tukaani.xz [1.3.0.v201308270617,1.3.0.v201308270617]
+	org.tukaani.xz.source [1.3.0.v201308270617,1.3.0.v201308270617]
+	org.slf4j.api [1.7.2.v20121108-1250,1.7.2.v20121108-1250]
+	org.slf4j.api.source [1.7.2.v20121108-1250,1.7.2.v20121108-1250]
+	org.slf4j.impl.log4j12 [1.7.2.v20131105-2200,1.7.2.v20131105-2200]
+	org.slf4j.impl.log4j12.source [1.7.2.v20131105-2200,1.7.2.v20131105-2200]
+}
\ No newline at end of file
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/pom.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/pom.xml
index 948947f..652b122 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/pom.xml
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/pom.xml
@@ -49,7 +49,7 @@
   <parent>
     <groupId>org.eclipse.jgit</groupId>
     <artifactId>jgit.tycho.parent</artifactId>
-    <version>4.5.3-SNAPSHOT</version>
+    <version>4.6.2-SNAPSHOT</version>
   </parent>
 
   <artifactId>org.eclipse.jgit.target</artifactId>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/projects/jetty-9.2.13.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/projects/jetty-9.2.13.tpd
deleted file mode 100644
index 289a73d..0000000
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/projects/jetty-9.2.13.tpd
+++ /dev/null
@@ -1,20 +0,0 @@
-target "jetty-9.2.13" with source configurePhase
-
-location jetty-9.2.13 "http://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.2.13.v20150730/" {
-	org.eclipse.jetty.client [9.2.13.v20150730,9.2.13.v20150730]
-	org.eclipse.jetty.client.source [9.2.13.v20150730,9.2.13.v20150730]
-	org.eclipse.jetty.continuation [9.2.13.v20150730,9.2.13.v20150730]
-	org.eclipse.jetty.continuation.source [9.2.13.v20150730,9.2.13.v20150730]
-	org.eclipse.jetty.http [9.2.13.v20150730,9.2.13.v20150730]
-	org.eclipse.jetty.http.source [9.2.13.v20150730,9.2.13.v20150730]
-	org.eclipse.jetty.io [9.2.13.v20150730,9.2.13.v20150730]
-	org.eclipse.jetty.io.source [9.2.13.v20150730,9.2.13.v20150730]
-	org.eclipse.jetty.security [9.2.13.v20150730,9.2.13.v20150730]
-	org.eclipse.jetty.security.source [9.2.13.v20150730,9.2.13.v20150730]
-	org.eclipse.jetty.server [9.2.13.v20150730,9.2.13.v20150730]
-	org.eclipse.jetty.server.source [9.2.13.v20150730,9.2.13.v20150730]
-	org.eclipse.jetty.servlet [9.2.13.v20150730,9.2.13.v20150730]
-	org.eclipse.jetty.servlet.source [9.2.13.v20150730,9.2.13.v20150730]
-	org.eclipse.jetty.util [9.2.13.v20150730,9.2.13.v20150730]
-	org.eclipse.jetty.util.source [9.2.13.v20150730,9.2.13.v20150730]
-}
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/projects/jetty-9.3.17.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/projects/jetty-9.3.17.tpd
new file mode 100644
index 0000000..662df09
--- /dev/null
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/projects/jetty-9.3.17.tpd
@@ -0,0 +1,20 @@
+target "jetty-9.3.17" with source configurePhase
+
+location jetty-9.3.17 "http://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.3.17.v20170317/" {
+	org.eclipse.jetty.client [9.3.17.v20170317,9.3.17.v20170317]
+	org.eclipse.jetty.client.source [9.3.17.v20170317,9.3.17.v20170317]
+	org.eclipse.jetty.continuation [9.3.17.v20170317,9.3.17.v20170317]
+	org.eclipse.jetty.continuation.source [9.3.17.v20170317,9.3.17.v20170317]
+	org.eclipse.jetty.http [9.3.17.v20170317,9.3.17.v20170317]
+	org.eclipse.jetty.http.source [9.3.17.v20170317,9.3.17.v20170317]
+	org.eclipse.jetty.io [9.3.17.v20170317,9.3.17.v20170317]
+	org.eclipse.jetty.io.source [9.3.17.v20170317,9.3.17.v20170317]
+	org.eclipse.jetty.security [9.3.17.v20170317,9.3.17.v20170317]
+	org.eclipse.jetty.security.source [9.3.17.v20170317,9.3.17.v20170317]
+	org.eclipse.jetty.server [9.3.17.v20170317,9.3.17.v20170317]
+	org.eclipse.jetty.server.source [9.3.17.v20170317,9.3.17.v20170317]
+	org.eclipse.jetty.servlet [9.3.17.v20170317,9.3.17.v20170317]
+	org.eclipse.jetty.servlet.source [9.3.17.v20170317,9.3.17.v20170317]
+	org.eclipse.jetty.util [9.3.17.v20170317,9.3.17.v20170317]
+	org.eclipse.jetty.util.source [9.3.17.v20170317,9.3.17.v20170317]
+}
diff --git a/org.eclipse.jgit.packaging/pom.xml b/org.eclipse.jgit.packaging/pom.xml
index 4638dc5..583b128 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>4.5.3-SNAPSHOT</version>
+  <version>4.6.2-SNAPSHOT</version>
   <packaging>pom</packaging>
 
   <name>JGit Tycho Parent</name>
 
   <properties>
-    <tycho-version>0.25.0</tycho-version>
+    <tycho-version>1.0.0</tycho-version>
     <tycho-extras-version>${tycho-version}</tycho-extras-version>
     <target-platform>jgit-4.6</target-platform>
   </properties>
@@ -142,14 +142,14 @@
           <version>${tycho-version}</version>
           <configuration>
             <encoding>UTF-8</encoding>
-            <source>1.7</source>
-            <target>1.7</target>
+            <source>1.8</source>
+            <target>1.8</target>
           </configuration>
         </plugin>
         <plugin>
           <groupId>org.apache.maven.plugins</groupId>
           <artifactId>maven-resources-plugin</artifactId>
-          <version>2.7</version>
+          <version>3.0.2</version>
           <configuration>
             <encoding>ISO-8859-1</encoding>
           </configuration>
@@ -221,7 +221,7 @@
         <plugin>
           <groupId>org.codehaus.mojo</groupId>
           <artifactId>build-helper-maven-plugin</artifactId>
-          <version>1.10</version>
+          <version>1.12</version>
         </plugin>
       </plugins>
     </pluginManagement>
diff --git a/org.eclipse.jgit.pgm.test/.classpath b/org.eclipse.jgit.pgm.test/.classpath
index 30d83d8..b26f4c4 100644
--- a/org.eclipse.jgit.pgm.test/.classpath
+++ b/org.eclipse.jgit.pgm.test/.classpath
@@ -2,7 +2,7 @@
 <classpath>
 	<classpathentry kind="src" path="tst"/>
 	<classpathentry kind="src" path="src"/>
-	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7"/>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
 	<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
 	<classpathentry kind="output" path="bin"/>
 </classpath>
diff --git a/org.eclipse.jgit.pgm.test/.settings/org.eclipse.jdt.core.prefs b/org.eclipse.jgit.pgm.test/.settings/org.eclipse.jdt.core.prefs
index 87210fb..10c29d5 100644
--- a/org.eclipse.jgit.pgm.test/.settings/org.eclipse.jdt.core.prefs
+++ b/org.eclipse.jgit.pgm.test/.settings/org.eclipse.jdt.core.prefs
@@ -7,9 +7,9 @@
 org.eclipse.jdt.core.compiler.annotation.nullanalysis=disabled
 org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
 org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
-org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
 org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
-org.eclipse.jdt.core.compiler.compliance=1.7
+org.eclipse.jdt.core.compiler.compliance=1.8
 org.eclipse.jdt.core.compiler.debug.lineNumber=generate
 org.eclipse.jdt.core.compiler.debug.localVariable=generate
 org.eclipse.jdt.core.compiler.debug.sourceFile=generate
@@ -112,7 +112,7 @@
 org.eclipse.jdt.core.compiler.problem.unusedTypeParameter=ignore
 org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning
 org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=error
-org.eclipse.jdt.core.compiler.source=1.7
+org.eclipse.jdt.core.compiler.source=1.8
 org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16
 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0
diff --git a/org.eclipse.jgit.pgm.test/BUCK b/org.eclipse.jgit.pgm.test/BUCK
index a3859c9..cd15510 100644
--- a/org.eclipse.jgit.pgm.test/BUCK
+++ b/org.eclipse.jgit.pgm.test/BUCK
@@ -21,7 +21,6 @@
       '//lib:commons-compress',
       '//lib:tukaani-xz',
     ],
-    source_under_test = ['//org.eclipse.jgit.pgm:pgm'],
     vm_args = ['-Xmx256m', '-Dfile.encoding=UTF-8'],
   )
 
diff --git a/org.eclipse.jgit.pgm.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.pgm.test/META-INF/MANIFEST.MF
index 101670c..8e7d5ab 100644
--- a/org.eclipse.jgit.pgm.test/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.pgm.test/META-INF/MANIFEST.MF
@@ -2,28 +2,28 @@
 Bundle-ManifestVersion: 2
 Bundle-Name: %plugin_name
 Bundle-SymbolicName: org.eclipse.jgit.pgm.test
-Bundle-Version: 4.5.3.qualifier
+Bundle-Version: 4.6.2.qualifier
 Bundle-Vendor: %provider_name
 Bundle-Localization: plugin
 Bundle-ActivationPolicy: lazy
-Bundle-RequiredExecutionEnvironment: JavaSE-1.7
-Import-Package: org.eclipse.jgit.api;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.api.errors;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.diff;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.dircache;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.internal.storage.file;version="4.5.3",
- org.eclipse.jgit.junit;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.lib;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.merge;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.pgm;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.pgm.internal;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.pgm.opt;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.revwalk;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.storage.file;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.transport;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.treewalk;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.util;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.util.io;version="[4.5.3,4.6.0)",
+Bundle-RequiredExecutionEnvironment: JavaSE-1.8
+Import-Package: org.eclipse.jgit.api;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.api.errors;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.diff;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.dircache;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.internal.storage.file;version="4.6.2",
+ org.eclipse.jgit.junit;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.lib;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.merge;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.pgm;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.pgm.internal;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.pgm.opt;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.revwalk;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.storage.file;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.transport;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.treewalk;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.util;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.util.io;version="[4.6.2,4.7.0)",
  org.hamcrest.core;bundle-version="[1.1.0,2.0.0)",
  org.junit;version="[4.11.0,5.0.0)",
  org.junit.rules;version="[4.11.0,5.0.0)",
diff --git "a/org.eclipse.jgit.pgm.test/org.eclipse.jgit.pgm--All-Tests \050Java7\051.launch" "b/org.eclipse.jgit.pgm.test/org.eclipse.jgit.pgm--All-Tests \050Java7\051.launch"
deleted file mode 100644
index 3df0dcb..0000000
--- "a/org.eclipse.jgit.pgm.test/org.eclipse.jgit.pgm--All-Tests \050Java7\051.launch"
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<launchConfiguration type="org.eclipse.jdt.junit.launchconfig">
-<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
-<listEntry value="/org.eclipse.jgit.pgm.test/tst"/>
-</listAttribute>
-<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
-<listEntry value="2"/>
-</listAttribute>
-<booleanAttribute key="org.eclipse.debug.core.appendEnvironmentVariables" value="true"/>
-<listAttribute key="org.eclipse.debug.ui.favoriteGroups">
-<listEntry value="org.eclipse.debug.ui.launchGroup.debug"/>
-<listEntry value="org.eclipse.debug.ui.launchGroup.run"/>
-</listAttribute>
-<stringAttribute key="org.eclipse.jdt.junit.CONTAINER" value="=org.eclipse.jgit.pgm.test/tst"/>
-<booleanAttribute key="org.eclipse.jdt.junit.KEEPRUNNING_ATTR" value="false"/>
-<stringAttribute key="org.eclipse.jdt.junit.TESTNAME" value=""/>
-<stringAttribute key="org.eclipse.jdt.junit.TEST_KIND" value="org.eclipse.jdt.junit.loader.junit4"/>
-<stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7"/>
-<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value=""/>
-<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="org.eclipse.jgit.pgm.test"/>
-</launchConfiguration>
diff --git "a/org.eclipse.jgit.pgm.test/org.eclipse.jgit.pgm--All-Tests \050Java8\051 \050de\051.launch" "b/org.eclipse.jgit.pgm.test/org.eclipse.jgit.pgm--All-Tests \050Java8\051 \050de\051.launch"
index 5c137f2..e11b72f 100644
--- "a/org.eclipse.jgit.pgm.test/org.eclipse.jgit.pgm--All-Tests \050Java8\051 \050de\051.launch"
+++ "b/org.eclipse.jgit.pgm.test/org.eclipse.jgit.pgm--All-Tests \050Java8\051 \050de\051.launch"
@@ -20,7 +20,7 @@
 <stringAttribute key="org.eclipse.jdt.junit.TEST_KIND" value="org.eclipse.jdt.junit.loader.junit4"/>
 <booleanAttribute key="org.eclipse.jdt.launching.ATTR_USE_START_ON_FIRST_THREAD" value="true"/>
 <listAttribute key="org.eclipse.jdt.launching.CLASSPATH">
-<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#10;&lt;runtimeClasspathEntry containerPath=&quot;org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7&quot; path=&quot;1&quot; type=&quot;4&quot;/&gt;&#10;"/>
+<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#10;&lt;runtimeClasspathEntry containerPath=&quot;org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8&quot; path=&quot;1&quot; type=&quot;4&quot;/&gt;&#10;"/>
 <listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#10;&lt;runtimeClasspathEntry id=&quot;org.eclipse.jdt.launching.classpathentry.defaultClasspath&quot;&gt;&#10;&lt;memento exportedEntriesOnly=&quot;false&quot; project=&quot;org.eclipse.jgit.pgm.test&quot;/&gt;&#10;&lt;/runtimeClasspathEntry&gt;&#10;"/>
 </listAttribute>
 <booleanAttribute key="org.eclipse.jdt.launching.DEFAULT_CLASSPATH" value="false"/>
diff --git "a/org.eclipse.jgit.pgm.test/org.eclipse.jgit.pgm--All-Tests \050Java8\051.launch" "b/org.eclipse.jgit.pgm.test/org.eclipse.jgit.pgm--All-Tests \050Java8\051.launch"
index ce473ed..8b0452a 100644
--- "a/org.eclipse.jgit.pgm.test/org.eclipse.jgit.pgm--All-Tests \050Java8\051.launch"
+++ "b/org.eclipse.jgit.pgm.test/org.eclipse.jgit.pgm--All-Tests \050Java8\051.launch"
@@ -17,7 +17,7 @@
 <stringAttribute key="org.eclipse.jdt.junit.TEST_KIND" value="org.eclipse.jdt.junit.loader.junit4"/>
 <booleanAttribute key="org.eclipse.jdt.launching.ATTR_USE_START_ON_FIRST_THREAD" value="true"/>
 <listAttribute key="org.eclipse.jdt.launching.CLASSPATH">
-<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#10;&lt;runtimeClasspathEntry containerPath=&quot;org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7&quot; path=&quot;1&quot; type=&quot;4&quot;/&gt;&#10;"/>
+<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#10;&lt;runtimeClasspathEntry containerPath=&quot;org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8&quot; path=&quot;1&quot; type=&quot;4&quot;/&gt;&#10;"/>
 <listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#10;&lt;runtimeClasspathEntry id=&quot;org.eclipse.jdt.launching.classpathentry.defaultClasspath&quot;&gt;&#10;&lt;memento exportedEntriesOnly=&quot;false&quot; project=&quot;org.eclipse.jgit.pgm.test&quot;/&gt;&#10;&lt;/runtimeClasspathEntry&gt;&#10;"/>
 </listAttribute>
 <booleanAttribute key="org.eclipse.jdt.launching.DEFAULT_CLASSPATH" value="false"/>
diff --git a/org.eclipse.jgit.pgm.test/pom.xml b/org.eclipse.jgit.pgm.test/pom.xml
index 894bf35..c8188cb 100644
--- a/org.eclipse.jgit.pgm.test/pom.xml
+++ b/org.eclipse.jgit.pgm.test/pom.xml
@@ -50,7 +50,7 @@
   <parent>
     <groupId>org.eclipse.jgit</groupId>
     <artifactId>org.eclipse.jgit-parent</artifactId>
-    <version>4.5.3-SNAPSHOT</version>
+    <version>4.6.2-SNAPSHOT</version>
   </parent>
 
   <artifactId>org.eclipse.jgit.pgm.test</artifactId>
diff --git a/org.eclipse.jgit.pgm.test/src/org/eclipse/jgit/lib/CLIRepositoryTestCase.java b/org.eclipse.jgit.pgm.test/src/org/eclipse/jgit/lib/CLIRepositoryTestCase.java
index a6af077..b675d3c 100644
--- a/org.eclipse.jgit.pgm.test/src/org/eclipse/jgit/lib/CLIRepositoryTestCase.java
+++ b/org.eclipse.jgit.pgm.test/src/org/eclipse/jgit/lib/CLIRepositoryTestCase.java
@@ -62,15 +62,11 @@
 	/** Test repository, initialized for this test case. */
 	protected Repository db;
 
-	/** Working directory of {@link #db}. */
-	protected File trash;
-
 	@Override
 	@Before
 	public void setUp() throws Exception {
 		super.setUp();
 		db = createWorkRepository();
-		trash = db.getWorkTree();
 	}
 
 	/**
diff --git a/org.eclipse.jgit.pgm.test/src/org/eclipse/jgit/pgm/CLIGitCommand.java b/org.eclipse.jgit.pgm.test/src/org/eclipse/jgit/pgm/CLIGitCommand.java
index 3f39656..b08bc8a 100644
--- a/org.eclipse.jgit.pgm.test/src/org/eclipse/jgit/pgm/CLIGitCommand.java
+++ b/org.eclipse.jgit.pgm.test/src/org/eclipse/jgit/pgm/CLIGitCommand.java
@@ -46,7 +46,6 @@
 
 import java.io.ByteArrayOutputStream;
 import java.io.File;
-
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.util.ArrayList;
@@ -218,7 +217,7 @@
 					inquote = !inquote;
 				continue;
 			case '\\':
-				if (inquote || ip == commandLine.length())
+				if (inDblQuote || inquote || ip == commandLine.length())
 					r.append(b); // literal within a quote
 				else
 					r.append(commandLine.charAt(ip++));
diff --git a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/ArchiveTest.java b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/ArchiveTest.java
index a503ffd..35467c6 100644
--- a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/ArchiveTest.java
+++ b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/ArchiveTest.java
@@ -528,15 +528,15 @@
 
 	@Test
 	public void testArchiveWithLongFilename() throws Exception {
-		String filename = "";
+		StringBuilder filename = new StringBuilder();
 		List<String> l = new ArrayList<String>();
 		for (int i = 0; i < 20; i++) {
-			filename = filename + "1234567890/";
-			l.add(filename);
+			filename.append("1234567890/");
+			l.add(filename.toString());
 		}
-		filename = filename + "1234567890";
-		l.add(filename);
-		writeTrashFile(filename, "file with long path");
+		filename.append("1234567890");
+		l.add(filename.toString());
+		writeTrashFile(filename.toString(), "file with long path");
 		git.add().addFilepattern("1234567890").call();
 		git.commit().setMessage("file with long name").call();
 
@@ -548,15 +548,15 @@
 
 	@Test
 	public void testTarWithLongFilename() throws Exception {
-		String filename = "";
+		StringBuilder filename = new StringBuilder();
 		List<String> l = new ArrayList<String>();
 		for (int i = 0; i < 20; i++) {
-			filename = filename + "1234567890/";
-			l.add(filename);
+			filename.append("1234567890/");
+			l.add(filename.toString());
 		}
-		filename = filename + "1234567890";
-		l.add(filename);
-		writeTrashFile(filename, "file with long path");
+		filename.append("1234567890");
+		l.add(filename.toString());
+		writeTrashFile(filename.toString(), "file with long path");
 		git.add().addFilepattern("1234567890").call();
 		git.commit().setMessage("file with long name").call();
 
diff --git a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/CLIGitCommandTest.java b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/CLIGitCommandTest.java
index 24788a4..58d8e03 100644
--- a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/CLIGitCommandTest.java
+++ b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/CLIGitCommandTest.java
@@ -51,9 +51,11 @@
 
 	@Test
 	public void testSplit() throws Exception {
+		assertArrayEquals(new String[0], split(""));
 		assertArrayEquals(new String[] { "a" }, split("a"));
 		assertArrayEquals(new String[] { "a", "b" }, split("a b"));
 		assertArrayEquals(new String[] { "a", "b c" }, split("a 'b c'"));
 		assertArrayEquals(new String[] { "a", "b c" }, split("a \"b c\""));
+		assertArrayEquals(new String[] { "a", "b\\c" }, split("a \"b\\c\""));
 	}
 }
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 3651542..4b86b60 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
@@ -613,7 +613,30 @@
 	}
 
 	@Test
-	public void testCheckouSingleFile() throws Exception {
+	public void testCheckoutAllPaths() throws Exception {
+		try (Git git = new Git(db)) {
+			writeTrashFile("a", "Hello world a");
+			git.add().addFilepattern(".").call();
+			git.commit().setMessage("commit file a").call();
+			git.branchCreate().setName("branch_1").call();
+			git.checkout().setName("branch_1").call();
+			File b = writeTrashFile("b", "Hello world b");
+			git.add().addFilepattern("b").call();
+			git.commit().setMessage("commit file b").call();
+			File a = writeTrashFile("a", "New Hello world a");
+			git.add().addFilepattern(".").call();
+			git.commit().setMessage("modified a").call();
+			assertArrayEquals(new String[] { "" },
+					execute("git checkout HEAD~2 -- ."));
+			assertEquals("Hello world a", read(a));
+			assertArrayEquals(new String[] { "* branch_1", "  master", "" },
+					execute("git branch"));
+			assertEquals("Hello world b", read(b));
+		}
+	}
+
+	@Test
+	public void testCheckoutSingleFile() throws Exception {
 		try (Git git = new Git(db)) {
 			File a = writeTrashFile("a", "file a");
 			git.add().addFilepattern(".").call();
diff --git a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/CleanTest.java b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/CleanTest.java
index bbac296..82c0d98 100644
--- a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/CleanTest.java
+++ b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/CleanTest.java
@@ -42,13 +42,14 @@
  */
 package org.eclipse.jgit.pgm;
 
+import static org.eclipse.jgit.junit.JGitTestUtil.check;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
 import org.eclipse.jgit.api.Git;
 import org.eclipse.jgit.lib.CLIRepositoryTestCase;
 import org.junit.Test;
-import static org.eclipse.jgit.junit.JGitTestUtil.check;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.assertFalse;
 
 public class CleanTest extends CLIRepositoryTestCase {
 	@Test
diff --git a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/ProxyConfigTest.java b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/ProxyConfigTest.java
new file mode 100644
index 0000000..06e7a1d
--- /dev/null
+++ b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/ProxyConfigTest.java
@@ -0,0 +1,232 @@
+/*
+ * Copyright (C) 2016, Chrisian Halstrick <christian.halstrick@sap.com> and
+ * other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v1.0 which accompanies this
+ * distribution, is reproduced below, and is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.eclipse.jgit.pgm;
+
+import static org.junit.Assert.assertEquals;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
+import java.net.MalformedURLException;
+import java.util.List;
+import java.util.Map;
+
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Test how the content of the environment variables http[s]_proxy (upper- and
+ * lowercase) influence the setting of the system properties
+ * http[s].proxy[Host|Port]
+ */
+public class ProxyConfigTest {
+	private ProcessBuilder processBuilder;
+
+	private Map<String, String> environment;
+
+	@Before
+	public void setUp() {
+		String separator = System.getProperty("file.separator");
+		String classpath = System.getProperty("java.class.path");
+		String path = System.getProperty("java.home") + separator + "bin"
+				+ separator + "java";
+		processBuilder = new ProcessBuilder(path, "-cp", classpath,
+				ProxyPropertiesDumper.class.getName());
+		environment = processBuilder.environment();
+		environment.remove("http_proxy");
+		environment.remove("https_proxy");
+		environment.remove("HTTP_PROXY");
+		environment.remove("HTTPS_PROXY");
+	}
+
+	@Test
+	public void testNoSetting() throws Exception {
+		Process start = processBuilder.start();
+		start.waitFor();
+		assertEquals(
+				"http.proxyHost: null, http.proxyPort: null, https.proxyHost: null, https.proxyPort: null",
+				getOutput(start));
+	}
+
+	@Test
+	public void testHttpProxy_lowerCase() throws Exception {
+		environment.put("http_proxy", "http://xx:1234");
+		Process start = processBuilder.start();
+		start.waitFor();
+		assertEquals(
+				"http.proxyHost: xx, http.proxyPort: 1234, https.proxyHost: null, https.proxyPort: null",
+				getOutput(start));
+	}
+
+	@Test
+	public void testHttpProxy_upperCase() throws Exception {
+		environment.put("HTTP_PROXY", "http://XX:1234");
+		Process start = processBuilder.start();
+		start.waitFor();
+		assertEquals(
+				"http.proxyHost: null, http.proxyPort: null, https.proxyHost: null, https.proxyPort: null",
+				getOutput(start));
+	}
+
+	@Test
+	public void testHttpProxy_bothCases() throws Exception {
+		environment.put("http_proxy", "http://xx:1234");
+		environment.put("HTTP_PROXY", "http://XX:1234");
+		Process start = processBuilder.start();
+		start.waitFor();
+		assertEquals(
+				"http.proxyHost: xx, http.proxyPort: 1234, https.proxyHost: null, https.proxyPort: null",
+				getOutput(start));
+	}
+
+	@Test
+	public void testHttpsProxy_lowerCase() throws Exception {
+		environment.put("https_proxy", "http://xx:1234");
+		Process start = processBuilder.start();
+		start.waitFor();
+		assertEquals(
+				"http.proxyHost: null, http.proxyPort: null, https.proxyHost: xx, https.proxyPort: 1234",
+				getOutput(start));
+	}
+
+	@Test
+	public void testHttpsProxy_upperCase() throws Exception {
+		environment.put("HTTPS_PROXY", "http://XX:1234");
+		Process start = processBuilder.start();
+		start.waitFor();
+		assertEquals(
+				"http.proxyHost: null, http.proxyPort: null, https.proxyHost: XX, https.proxyPort: 1234",
+				getOutput(start));
+	}
+
+	@Test
+	public void testHttpsProxy_bothCases() throws Exception {
+		environment.put("https_proxy", "http://xx:1234");
+		environment.put("HTTPS_PROXY", "http://XX:1234");
+		Process start = processBuilder.start();
+		start.waitFor();
+		assertEquals(
+				"http.proxyHost: null, http.proxyPort: null, https.proxyHost: xx, https.proxyPort: 1234",
+				getOutput(start));
+	}
+
+	@Test
+	public void testAll() throws Exception {
+		environment.put("http_proxy", "http://xx:1234");
+		environment.put("HTTP_PROXY", "http://XX:1234");
+		environment.put("https_proxy", "http://yy:1234");
+		environment.put("HTTPS_PROXY", "http://YY:1234");
+		Process start = processBuilder.start();
+		start.waitFor();
+		assertEquals(
+				"http.proxyHost: xx, http.proxyPort: 1234, https.proxyHost: yy, https.proxyPort: 1234",
+				getOutput(start));
+	}
+
+	@Test
+	public void testDontOverwriteHttp()
+			throws IOException, InterruptedException {
+		environment.put("http_proxy", "http://xx:1234");
+		environment.put("HTTP_PROXY", "http://XX:1234");
+		environment.put("https_proxy", "http://yy:1234");
+		environment.put("HTTPS_PROXY", "http://YY:1234");
+		List<String> command = processBuilder.command();
+		command.add(1, "-Dhttp.proxyHost=gondola");
+		command.add(2, "-Dhttp.proxyPort=5678");
+		command.add("dontClearProperties");
+		Process start = processBuilder.start();
+		start.waitFor();
+		assertEquals(
+				"http.proxyHost: gondola, http.proxyPort: 5678, https.proxyHost: yy, https.proxyPort: 1234",
+				getOutput(start));
+	}
+
+	@Test
+	public void testOverwriteHttpPort()
+			throws IOException, InterruptedException {
+		environment.put("http_proxy", "http://xx:1234");
+		environment.put("HTTP_PROXY", "http://XX:1234");
+		environment.put("https_proxy", "http://yy:1234");
+		environment.put("HTTPS_PROXY", "http://YY:1234");
+		List<String> command = processBuilder.command();
+		command.add(1, "-Dhttp.proxyPort=5678");
+		command.add("dontClearProperties");
+		Process start = processBuilder.start();
+		start.waitFor();
+		assertEquals(
+				"http.proxyHost: xx, http.proxyPort: 1234, https.proxyHost: yy, https.proxyPort: 1234",
+				getOutput(start));
+	}
+
+	private static String getOutput(Process p)
+			throws IOException, UnsupportedEncodingException {
+		try (InputStream inputStream = p.getInputStream()) {
+			ByteArrayOutputStream result = new ByteArrayOutputStream();
+			byte[] buffer = new byte[1024];
+			int length;
+			while ((length = inputStream.read(buffer)) != -1) {
+				result.write(buffer, 0, length);
+			}
+			return result.toString("UTF-8");
+		}
+	}
+}
+
+class ProxyPropertiesDumper {
+	public static void main(String args[]) {
+		try {
+			if (args.length == 0 || !args[0].equals("dontClearProperties")) {
+				System.clearProperty("http.proxyHost");
+				System.clearProperty("http.proxyPort");
+				System.clearProperty("https.proxyHost");
+				System.clearProperty("https.proxyPort");
+			}
+			Main.configureHttpProxy();
+			System.out.printf(
+					"http.proxyHost: %s, http.proxyPort: %s, https.proxyHost: %s, https.proxyPort: %s",
+					System.getProperty("http.proxyHost"),
+					System.getProperty("http.proxyPort"),
+					System.getProperty("https.proxyHost"),
+					System.getProperty("https.proxyPort"));
+			System.out.flush();
+		} catch (MalformedURLException e) {
+			System.out.println("exception: " + e);
+		}
+	}
+}
diff --git a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/ResetTest.java b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/ResetTest.java
index 16c5889..44a7630 100644
--- a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/ResetTest.java
+++ b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/ResetTest.java
@@ -42,7 +42,10 @@
  */
 package org.eclipse.jgit.pgm;
 
-import static org.junit.Assert.*;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
 
 import org.eclipse.jgit.api.Git;
 import org.eclipse.jgit.lib.CLIRepositoryTestCase;
diff --git a/org.eclipse.jgit.pgm/.classpath b/org.eclipse.jgit.pgm/.classpath
index c5d5a57..e8bc977 100644
--- a/org.eclipse.jgit.pgm/.classpath
+++ b/org.eclipse.jgit.pgm/.classpath
@@ -3,7 +3,7 @@
 	<classpathentry kind="src" path="src"/>
 	<classpathentry excluding="*|resources/|resources/" including="META-INF/" kind="src" path=""/>
 	<classpathentry kind="src" path="resources"/>
-	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7"/>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
 	<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
 	<classpathentry kind="output" path="bin"/>
 </classpath>
diff --git a/org.eclipse.jgit.pgm/.settings/org.eclipse.jdt.core.prefs b/org.eclipse.jgit.pgm/.settings/org.eclipse.jdt.core.prefs
index bfaf736..4f1759f 100644
--- a/org.eclipse.jgit.pgm/.settings/org.eclipse.jdt.core.prefs
+++ b/org.eclipse.jgit.pgm/.settings/org.eclipse.jdt.core.prefs
@@ -7,9 +7,9 @@
 org.eclipse.jdt.core.compiler.annotation.nullanalysis=enabled
 org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
 org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
-org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
 org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
-org.eclipse.jdt.core.compiler.compliance=1.7
+org.eclipse.jdt.core.compiler.compliance=1.8
 org.eclipse.jdt.core.compiler.debug.lineNumber=generate
 org.eclipse.jdt.core.compiler.debug.localVariable=generate
 org.eclipse.jdt.core.compiler.debug.sourceFile=generate
@@ -112,7 +112,7 @@
 org.eclipse.jdt.core.compiler.problem.unusedTypeParameter=ignore
 org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning
 org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=error
-org.eclipse.jdt.core.compiler.source=1.7
+org.eclipse.jdt.core.compiler.source=1.8
 org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16
 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0
diff --git a/org.eclipse.jgit.pgm/BUCK b/org.eclipse.jgit.pgm/BUCK
index 47711b5..5d5e6f7 100644
--- a/org.eclipse.jgit.pgm/BUCK
+++ b/org.eclipse.jgit.pgm/BUCK
@@ -9,6 +9,7 @@
     '//org.eclipse.jgit:jgit',
     '//org.eclipse.jgit.archive:jgit-archive',
     '//org.eclipse.jgit.http.apache:http-apache',
+    '//org.eclipse.jgit.lfs:jgit-lfs',
     '//org.eclipse.jgit.lfs.server:jgit-lfs-server',
     '//org.eclipse.jgit.ui:ui',
     '//lib:args4j',
diff --git a/org.eclipse.jgit.pgm/META-INF/MANIFEST.MF b/org.eclipse.jgit.pgm/META-INF/MANIFEST.MF
index 968e8d3..5c30da7 100644
--- a/org.eclipse.jgit.pgm/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.pgm/META-INF/MANIFEST.MF
@@ -2,69 +2,71 @@
 Bundle-ManifestVersion: 2
 Bundle-Name: %plugin_name
 Bundle-SymbolicName: org.eclipse.jgit.pgm
-Bundle-Version: 4.5.3.qualifier
+Bundle-Version: 4.6.2.qualifier
 Bundle-Vendor: %provider_name
 Bundle-ActivationPolicy: lazy
 Bundle-Localization: plugin
-Bundle-RequiredExecutionEnvironment: JavaSE-1.7
+Bundle-RequiredExecutionEnvironment: JavaSE-1.8
 Import-Package: javax.servlet;version="[3.1.0,4.0.0)",
  javax.servlet.http;version="[3.1.0,4.0.0)",
  org.apache.commons.compress.archivers;version="[1.3,2.0)",
  org.apache.commons.compress.archivers.tar;version="[1.3,2.0)",
  org.apache.commons.compress.archivers.zip;version="[1.3,2.0)",
- org.eclipse.jetty.continuation;version="[9.0.0,10.0.0)",
- org.eclipse.jetty.http;version="[9.0.0,10.0.0)",
- org.eclipse.jetty.io;version="[9.0.0,10.0.0)",
- org.eclipse.jetty.security;version="[9.0.0,10.0.0)",
- org.eclipse.jetty.security.authentication;version="[9.0.0,10.0.0)",
- org.eclipse.jetty.server;version="[9.0.0,10.0.0)",
- org.eclipse.jetty.server.handler;version="[9.0.0,10.0.0)",
- org.eclipse.jetty.server.nio;version="[9.0.0,10.0.0)",
- org.eclipse.jetty.servlet;version="[9.0.0,10.0.0)",
- org.eclipse.jetty.util;version="[9.0.0,10.0.0)",
- org.eclipse.jetty.util.component;version="[9.0.0,10.0.0)",
- org.eclipse.jetty.util.log;version="[9.0.0,10.0.0)",
- org.eclipse.jetty.util.security;version="[9.0.0,10.0.0)",
- org.eclipse.jetty.util.thread;version="[9.0.0,10.0.0)",
- org.eclipse.jgit.api;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.api.errors;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.archive;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.awtui;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.blame;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.diff;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.dircache;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.errors;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.gitrepo;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.internal.ketch;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.internal.storage.file;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.internal.storage.pack;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.internal.storage.reftree;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.lfs.lib;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.lfs.server;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.lfs.server.fs;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.lfs.server.s3;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.lib;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.merge;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.nls;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.notes;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.revplot;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.revwalk;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.revwalk.filter;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.storage.file;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.storage.pack;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.transport;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.transport.http.apache;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.transport.resolver;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.treewalk;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.treewalk.filter;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.util;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.util.io;version="[4.5.3,4.6.0)",
+ org.apache.commons.logging;version="1.1.1",
+ org.eclipse.jetty.continuation;version="[9.0.0,9.4.0)",
+ org.eclipse.jetty.http;version="[9.0.0,9.4.0)",
+ org.eclipse.jetty.io;version="[9.0.0,9.4.0)",
+ org.eclipse.jetty.security;version="[9.0.0,9.4.0)",
+ org.eclipse.jetty.security.authentication;version="[9.0.0,9.4.0)",
+ org.eclipse.jetty.server;version="[9.0.0,9.4.0)",
+ org.eclipse.jetty.server.handler;version="[9.0.0,9.4.0)",
+ org.eclipse.jetty.server.nio;version="[9.0.0,9.4.0)",
+ org.eclipse.jetty.servlet;version="[9.0.0,9.4.0)",
+ org.eclipse.jetty.util;version="[9.0.0,9.4.0)",
+ org.eclipse.jetty.util.component;version="[9.0.0,9.4.0)",
+ org.eclipse.jetty.util.log;version="[9.0.0,9.4.0)",
+ org.eclipse.jetty.util.security;version="[9.0.0,9.4.0)",
+ org.eclipse.jetty.util.thread;version="[9.0.0,9.4.0)",
+ org.eclipse.jgit.api;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.api.errors;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.archive;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.awtui;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.blame;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.diff;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.dircache;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.errors;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.gitrepo;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.internal.ketch;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.internal.storage.file;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.internal.storage.pack;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.internal.storage.reftree;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.lfs;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.lfs.lib;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.lfs.server;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.lfs.server.fs;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.lfs.server.s3;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.lib;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.merge;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.nls;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.notes;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.revplot;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.revwalk;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.revwalk.filter;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.storage.file;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.storage.pack;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.transport;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.transport.http.apache;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.transport.resolver;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.treewalk;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.treewalk.filter;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.util;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.util.io;version="[4.6.2,4.7.0)",
  org.kohsuke.args4j;version="[2.0.12,2.1.0)",
  org.kohsuke.args4j.spi;version="[2.0.15,2.1.0)"
-Export-Package: org.eclipse.jgit.console;version="4.5.3";
+Export-Package: org.eclipse.jgit.console;version="4.6.2";
   uses:="org.eclipse.jgit.transport,
    org.eclipse.jgit.util",
- org.eclipse.jgit.pgm;version="4.5.3";
+ org.eclipse.jgit.pgm;version="4.6.2";
   uses:="org.eclipse.jgit.revwalk,
    org.eclipse.jgit.treewalk.filter,
    org.eclipse.jgit.pgm.opt,
@@ -75,11 +77,11 @@
    org.eclipse.jgit.treewalk,
    javax.swing,
    org.eclipse.jgit.transport",
- org.eclipse.jgit.pgm.debug;version="4.5.3";
+ org.eclipse.jgit.pgm.debug;version="4.6.2";
   uses:="org.eclipse.jgit.util.io,
    org.eclipse.jgit.pgm",
- org.eclipse.jgit.pgm.internal;version="4.5.3";x-friends:="org.eclipse.jgit.pgm.test,org.eclipse.jgit.test",
- org.eclipse.jgit.pgm.opt;version="4.5.3";
+ org.eclipse.jgit.pgm.internal;version="4.6.2";x-friends:="org.eclipse.jgit.pgm.test,org.eclipse.jgit.test",
+ org.eclipse.jgit.pgm.opt;version="4.6.2";
   uses:="org.eclipse.jgit.lib,
    org.eclipse.jgit.revwalk,
    org.kohsuke.args4j.spi,
diff --git a/org.eclipse.jgit.pgm/META-INF/SOURCE-MANIFEST.MF b/org.eclipse.jgit.pgm/META-INF/SOURCE-MANIFEST.MF
index d790bfd..443ccc8 100644
--- a/org.eclipse.jgit.pgm/META-INF/SOURCE-MANIFEST.MF
+++ b/org.eclipse.jgit.pgm/META-INF/SOURCE-MANIFEST.MF
@@ -3,5 +3,5 @@
 Bundle-Name: org.eclipse.jgit.pgm - Sources
 Bundle-SymbolicName: org.eclipse.jgit.pgm.source
 Bundle-Vendor: Eclipse.org - JGit
-Bundle-Version: 4.5.3.qualifier
-Eclipse-SourceBundle: org.eclipse.jgit.pgm;version="4.5.3.qualifier";roots="."
+Bundle-Version: 4.6.2.qualifier
+Eclipse-SourceBundle: org.eclipse.jgit.pgm;version="4.6.2.qualifier";roots="."
diff --git a/org.eclipse.jgit.pgm/pom.xml b/org.eclipse.jgit.pgm/pom.xml
index b66d035..c6f4aca 100644
--- a/org.eclipse.jgit.pgm/pom.xml
+++ b/org.eclipse.jgit.pgm/pom.xml
@@ -50,7 +50,7 @@
   <parent>
     <groupId>org.eclipse.jgit</groupId>
     <artifactId>org.eclipse.jgit-parent</artifactId>
-    <version>4.5.3-SNAPSHOT</version>
+    <version>4.6.2-SNAPSHOT</version>
   </parent>
 
   <artifactId>org.eclipse.jgit.pgm</artifactId>
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/console/ConsoleAuthenticator.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/console/ConsoleAuthenticator.java
index bdaccb0..8bf451c 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/console/ConsoleAuthenticator.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/console/ConsoleAuthenticator.java
@@ -49,9 +49,8 @@
 import java.net.PasswordAuthentication;
 import java.text.MessageFormat;
 
-import org.eclipse.jgit.util.CachedAuthenticator;
-
 import org.eclipse.jgit.pgm.internal.CLIText;
+import org.eclipse.jgit.util.CachedAuthenticator;
 
 /**
  * Basic network prompt for username/password when using the console.
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/console/ConsoleCredentialsProvider.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/console/ConsoleCredentialsProvider.java
index e805add..0aa0cf4 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/console/ConsoleCredentialsProvider.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/console/ConsoleCredentialsProvider.java
@@ -48,14 +48,13 @@
 import java.io.Console;
 
 import org.eclipse.jgit.errors.UnsupportedCredentialItem;
+import org.eclipse.jgit.pgm.internal.CLIText;
 import org.eclipse.jgit.transport.ChainingCredentialsProvider;
 import org.eclipse.jgit.transport.CredentialItem;
 import org.eclipse.jgit.transport.CredentialsProvider;
 import org.eclipse.jgit.transport.NetRCCredentialsProvider;
 import org.eclipse.jgit.transport.URIish;
 
-import org.eclipse.jgit.pgm.internal.CLIText;
-
 /**
  * Interacts with the user during authentication by using the text console.
  *
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Archive.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Archive.java
index fe2ba83..cff0bf6 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Archive.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Archive.java
@@ -52,7 +52,6 @@
 import org.eclipse.jgit.api.errors.GitAPIException;
 import org.eclipse.jgit.archive.ArchiveFormats;
 import org.eclipse.jgit.lib.ObjectId;
-import org.eclipse.jgit.pgm.TextBuiltin;
 import org.eclipse.jgit.pgm.internal.CLIText;
 import org.kohsuke.args4j.Argument;
 import org.kohsuke.args4j.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 94517db..0c3b720 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
@@ -92,8 +92,11 @@
 			CheckoutCommand command = git.checkout();
 			if (paths.size() > 0) {
 				command.setStartPoint(name);
-				for (String path : paths)
-					command.addPath(path);
+				if (paths.size() == 1 && paths.get(0).equals(".")) { //$NON-NLS-1$
+					command.setAllPaths(true);
+				} else {
+					command.addPaths(paths);
+				}
 			} else {
 				command.setCreateBranch(createBranch);
 				command.setName(name);
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/DiffTree.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/DiffTree.java
index 32adf6d..95c2132 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/DiffTree.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/DiffTree.java
@@ -47,14 +47,14 @@
 import java.util.ArrayList;
 import java.util.List;
 
-import org.kohsuke.args4j.Argument;
-import org.kohsuke.args4j.Option;
 import org.eclipse.jgit.lib.FileMode;
 import org.eclipse.jgit.pgm.opt.PathTreeFilterHandler;
 import org.eclipse.jgit.treewalk.AbstractTreeIterator;
 import org.eclipse.jgit.treewalk.TreeWalk;
 import org.eclipse.jgit.treewalk.filter.AndTreeFilter;
 import org.eclipse.jgit.treewalk.filter.TreeFilter;
+import org.kohsuke.args4j.Argument;
+import org.kohsuke.args4j.Option;
 
 @Command(usage = "usage_ShowDiffTree")
 class DiffTree extends TextBuiltin {
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Main.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Main.java
index d701f22..a0f4d06 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Main.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Main.java
@@ -57,6 +57,8 @@
 import org.eclipse.jgit.awtui.AwtAuthenticator;
 import org.eclipse.jgit.awtui.AwtCredentialsProvider;
 import org.eclipse.jgit.errors.TransportException;
+import org.eclipse.jgit.lfs.CleanFilter;
+import org.eclipse.jgit.lfs.SmudgeFilter;
 import org.eclipse.jgit.lib.Repository;
 import org.eclipse.jgit.lib.RepositoryBuilder;
 import org.eclipse.jgit.pgm.internal.CLIText;
@@ -97,6 +99,8 @@
 	 */
 	public Main() {
 		HttpTransport.setConnectionFactory(new HttpClientConnectionFactory());
+		CleanFilter.register();
+		SmudgeFilter.register();
 	}
 
 	/**
@@ -339,17 +343,28 @@
 	 * <code>https_proxy</code> environment variables as a means of specifying
 	 * an HTTP/S proxy for requests made behind a firewall. This is not natively
 	 * recognized by the JRE, so this method can be used by command line
-	 * utilities to configure the JRE before the first request is sent.
+	 * utilities to configure the JRE before the first request is sent. The
+	 * information found in the environment variables is copied to the
+	 * associated system properties. This is not done when the system properties
+	 * are already set. The default way of telling java programs about proxies
+	 * (the system properties) takes precedence over environment variables.
 	 *
 	 * @throws MalformedURLException
 	 *             the value in <code>http_proxy</code> or
 	 *             <code>https_proxy</code> is unsupportable.
 	 */
-	private static void configureHttpProxy() throws MalformedURLException {
+	static void configureHttpProxy() throws MalformedURLException {
 		for (String protocol : new String[] { "http", "https" }) { //$NON-NLS-1$ //$NON-NLS-2$
-			final String s = System.getenv(protocol + "_proxy"); //$NON-NLS-1$
-			if (s == null || s.equals("")) //$NON-NLS-1$
-				return;
+			if (System.getProperty(protocol + ".proxyHost") != null) { //$NON-NLS-1$
+				continue;
+			}
+			String s = System.getenv(protocol + "_proxy"); //$NON-NLS-1$
+			if (s == null && protocol.equals("https")) { //$NON-NLS-1$
+				s = System.getenv("HTTPS_PROXY"); //$NON-NLS-1$
+			}
+			if (s == null || s.equals("")) { //$NON-NLS-1$
+				continue;
+			}
 
 			final URL u = new URL(
 					(s.indexOf("://") == -1) ? protocol + "://" + s : s); //$NON-NLS-1$ //$NON-NLS-2$
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Merge.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Merge.java
index 485efc5..1aab748 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Merge.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Merge.java
@@ -49,8 +49,8 @@
 
 import org.eclipse.jgit.api.Git;
 import org.eclipse.jgit.api.MergeCommand;
-import org.eclipse.jgit.api.MergeResult;
 import org.eclipse.jgit.api.MergeCommand.FastForwardMode;
+import org.eclipse.jgit.api.MergeResult;
 import org.eclipse.jgit.api.errors.CheckoutConflictException;
 import org.eclipse.jgit.lib.AnyObjectId;
 import org.eclipse.jgit.lib.Constants;
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/MergeBase.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/MergeBase.java
index 29cbb53..9dcd512 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/MergeBase.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/MergeBase.java
@@ -47,10 +47,10 @@
 import java.util.ArrayList;
 import java.util.List;
 
-import org.kohsuke.args4j.Argument;
-import org.kohsuke.args4j.Option;
 import org.eclipse.jgit.revwalk.RevCommit;
 import org.eclipse.jgit.revwalk.filter.RevFilter;
+import org.kohsuke.args4j.Argument;
+import org.kohsuke.args4j.Option;
 
 @Command(usage = "usage_MergeBase")
 class MergeBase extends TextBuiltin {
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/RevParse.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/RevParse.java
index c5ecb84..6833ad3 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/RevParse.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/RevParse.java
@@ -51,13 +51,13 @@
 import java.util.List;
 import java.util.Map;
 
-import org.kohsuke.args4j.Argument;
-import org.kohsuke.args4j.CmdLineException;
-import org.kohsuke.args4j.Option;
 import org.eclipse.jgit.lib.ObjectId;
 import org.eclipse.jgit.lib.Ref;
 import org.eclipse.jgit.pgm.internal.CLIText;
 import org.eclipse.jgit.pgm.opt.CmdLineParser;
+import org.kohsuke.args4j.Argument;
+import org.kohsuke.args4j.CmdLineException;
+import org.kohsuke.args4j.Option;
 
 @Command(usage = "usage_RevParse")
 class RevParse extends TextBuiltin {
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/RevWalkTextBuiltin.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/RevWalkTextBuiltin.java
index d6063c3..1543586 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/RevWalkTextBuiltin.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/RevWalkTextBuiltin.java
@@ -49,8 +49,6 @@
 import java.util.List;
 import java.util.Map;
 
-import org.kohsuke.args4j.Argument;
-import org.kohsuke.args4j.Option;
 import org.eclipse.jgit.diff.DiffConfig;
 import org.eclipse.jgit.errors.IncorrectObjectTypeException;
 import org.eclipse.jgit.lib.Constants;
@@ -73,6 +71,8 @@
 import org.eclipse.jgit.revwalk.filter.RevFilter;
 import org.eclipse.jgit.treewalk.filter.AndTreeFilter;
 import org.eclipse.jgit.treewalk.filter.TreeFilter;
+import org.kohsuke.args4j.Argument;
+import org.kohsuke.args4j.Option;
 
 abstract class RevWalkTextBuiltin extends TextBuiltin {
 	RevWalk walk;
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Status.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Status.java
index de3df80..43b292e 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Status.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Status.java
@@ -59,10 +59,10 @@
 import org.eclipse.jgit.lib.Ref;
 import org.eclipse.jgit.lib.Repository;
 import org.eclipse.jgit.pgm.internal.CLIText;
+import org.eclipse.jgit.pgm.opt.UntrackedFilesHandler;
 import org.kohsuke.args4j.Argument;
 import org.kohsuke.args4j.Option;
 import org.kohsuke.args4j.spi.RestOfArgumentsHandler;
-import org.eclipse.jgit.pgm.opt.UntrackedFilesHandler;
 
 /**
  * Status command
@@ -70,8 +70,6 @@
 @Command(usage = "usage_Status", common = true)
 class Status extends TextBuiltin {
 
-	protected final String lineFormat = CLIText.get().lineFormat;
-
 	protected final String statusFileListFormat = CLIText.get().statusFileListFormat;
 
 	protected final String statusFileListFormatWithPrefix = CLIText.get().statusFileListFormatWithPrefix;
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/LfsStore.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/LfsStore.java
index c4d9548..52b6d19 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/LfsStore.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/LfsStore.java
@@ -64,8 +64,8 @@
 import org.eclipse.jgit.errors.ConfigInvalidException;
 import org.eclipse.jgit.lfs.server.LargeFileRepository;
 import org.eclipse.jgit.lfs.server.LfsProtocolServlet;
-import org.eclipse.jgit.lfs.server.fs.FileLfsServlet;
 import org.eclipse.jgit.lfs.server.fs.FileLfsRepository;
+import org.eclipse.jgit.lfs.server.fs.FileLfsServlet;
 import org.eclipse.jgit.lfs.server.s3.S3Config;
 import org.eclipse.jgit.lfs.server.s3.S3Repository;
 import org.eclipse.jgit.pgm.Command;
@@ -238,7 +238,7 @@
 		case S3:
 			readAWSKeys();
 			checkOptions();
-			S3Config config = new S3Config(region.toString(), bucket,
+			S3Config config = new S3Config(region, bucket,
 					storageClass.toString(), accessKey, secretKey,
 					expirationSeconds, disableSslVerify);
 			repository = new S3Repository(config);
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/AbstractTreeIteratorHandler.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/AbstractTreeIteratorHandler.java
index 6b8a61d..8f56bda 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/AbstractTreeIteratorHandler.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/AbstractTreeIteratorHandler.java
@@ -48,12 +48,6 @@
 import java.io.IOException;
 import java.text.MessageFormat;
 
-import org.kohsuke.args4j.CmdLineException;
-import org.kohsuke.args4j.CmdLineParser;
-import org.kohsuke.args4j.OptionDef;
-import org.kohsuke.args4j.spi.OptionHandler;
-import org.kohsuke.args4j.spi.Parameters;
-import org.kohsuke.args4j.spi.Setter;
 import org.eclipse.jgit.dircache.DirCache;
 import org.eclipse.jgit.dircache.DirCacheIterator;
 import org.eclipse.jgit.errors.IncorrectObjectTypeException;
@@ -66,6 +60,12 @@
 import org.eclipse.jgit.treewalk.FileTreeIterator;
 import org.eclipse.jgit.treewalk.WorkingTreeOptions;
 import org.eclipse.jgit.util.FS;
+import org.kohsuke.args4j.CmdLineException;
+import org.kohsuke.args4j.CmdLineParser;
+import org.kohsuke.args4j.OptionDef;
+import org.kohsuke.args4j.spi.OptionHandler;
+import org.kohsuke.args4j.spi.Parameters;
+import org.kohsuke.args4j.spi.Setter;
 
 /**
  * Custom argument handler {@link AbstractTreeIterator} from string values.
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/ObjectIdHandler.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/ObjectIdHandler.java
index 364809d..75ca554 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/ObjectIdHandler.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/ObjectIdHandler.java
@@ -47,14 +47,14 @@
 import java.io.IOException;
 import java.text.MessageFormat;
 
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.pgm.internal.CLIText;
 import org.kohsuke.args4j.CmdLineException;
 import org.kohsuke.args4j.CmdLineParser;
 import org.kohsuke.args4j.OptionDef;
 import org.kohsuke.args4j.spi.OptionHandler;
 import org.kohsuke.args4j.spi.Parameters;
 import org.kohsuke.args4j.spi.Setter;
-import org.eclipse.jgit.lib.ObjectId;
-import org.eclipse.jgit.pgm.internal.CLIText;
 
 /**
  * Custom argument handler {@link ObjectId} from string values.
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/PathTreeFilterHandler.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/PathTreeFilterHandler.java
index 122cce7..e468023 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/PathTreeFilterHandler.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/PathTreeFilterHandler.java
@@ -46,6 +46,10 @@
 import java.util.ArrayList;
 import java.util.List;
 
+import org.eclipse.jgit.pgm.internal.CLIText;
+import org.eclipse.jgit.treewalk.filter.PathFilter;
+import org.eclipse.jgit.treewalk.filter.PathFilterGroup;
+import org.eclipse.jgit.treewalk.filter.TreeFilter;
 import org.kohsuke.args4j.CmdLineException;
 import org.kohsuke.args4j.CmdLineParser;
 import org.kohsuke.args4j.Option;
@@ -53,10 +57,6 @@
 import org.kohsuke.args4j.spi.OptionHandler;
 import org.kohsuke.args4j.spi.Parameters;
 import org.kohsuke.args4j.spi.Setter;
-import org.eclipse.jgit.pgm.internal.CLIText;
-import org.eclipse.jgit.treewalk.filter.PathFilter;
-import org.eclipse.jgit.treewalk.filter.PathFilterGroup;
-import org.eclipse.jgit.treewalk.filter.TreeFilter;
 
 /**
  * Create a {@link TreeFilter} to patch math names.
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/RefSpecHandler.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/RefSpecHandler.java
index dae0c47..f50c7ad 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/RefSpecHandler.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/RefSpecHandler.java
@@ -43,14 +43,14 @@
 
 package org.eclipse.jgit.pgm.opt;
 
+import org.eclipse.jgit.pgm.internal.CLIText;
+import org.eclipse.jgit.transport.RefSpec;
 import org.kohsuke.args4j.CmdLineException;
 import org.kohsuke.args4j.CmdLineParser;
 import org.kohsuke.args4j.OptionDef;
 import org.kohsuke.args4j.spi.OptionHandler;
 import org.kohsuke.args4j.spi.Parameters;
 import org.kohsuke.args4j.spi.Setter;
-import org.eclipse.jgit.pgm.internal.CLIText;
-import org.eclipse.jgit.transport.RefSpec;
 
 /**
  * Custom argument handler {@link RefSpec} from string values.
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/RevCommitHandler.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/RevCommitHandler.java
index 9ae56e4..7661774 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/RevCommitHandler.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/RevCommitHandler.java
@@ -47,18 +47,18 @@
 import java.io.IOException;
 import java.text.MessageFormat;
 
-import org.kohsuke.args4j.CmdLineException;
-import org.kohsuke.args4j.CmdLineParser;
-import org.kohsuke.args4j.OptionDef;
-import org.kohsuke.args4j.spi.OptionHandler;
-import org.kohsuke.args4j.spi.Parameters;
-import org.kohsuke.args4j.spi.Setter;
 import org.eclipse.jgit.errors.IncorrectObjectTypeException;
 import org.eclipse.jgit.errors.MissingObjectException;
 import org.eclipse.jgit.lib.ObjectId;
 import org.eclipse.jgit.pgm.internal.CLIText;
 import org.eclipse.jgit.revwalk.RevCommit;
 import org.eclipse.jgit.revwalk.RevFlag;
+import org.kohsuke.args4j.CmdLineException;
+import org.kohsuke.args4j.CmdLineParser;
+import org.kohsuke.args4j.OptionDef;
+import org.kohsuke.args4j.spi.OptionHandler;
+import org.kohsuke.args4j.spi.Parameters;
+import org.kohsuke.args4j.spi.Setter;
 
 /**
  * Custom argument handler {@link RevCommit} from string values.
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/RevTreeHandler.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/RevTreeHandler.java
index e2879e0..9f1d21e 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/RevTreeHandler.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/RevTreeHandler.java
@@ -47,17 +47,17 @@
 import java.io.IOException;
 import java.text.MessageFormat;
 
+import org.eclipse.jgit.errors.IncorrectObjectTypeException;
+import org.eclipse.jgit.errors.MissingObjectException;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.pgm.internal.CLIText;
+import org.eclipse.jgit.revwalk.RevTree;
 import org.kohsuke.args4j.CmdLineException;
 import org.kohsuke.args4j.CmdLineParser;
 import org.kohsuke.args4j.OptionDef;
 import org.kohsuke.args4j.spi.OptionHandler;
 import org.kohsuke.args4j.spi.Parameters;
 import org.kohsuke.args4j.spi.Setter;
-import org.eclipse.jgit.errors.IncorrectObjectTypeException;
-import org.eclipse.jgit.errors.MissingObjectException;
-import org.eclipse.jgit.lib.ObjectId;
-import org.eclipse.jgit.pgm.internal.CLIText;
-import org.eclipse.jgit.revwalk.RevTree;
 
 /**
  * Custom argument handler {@link RevTree} from string values.
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/SubcommandHandler.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/SubcommandHandler.java
index 96f3ed0..311597e 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/SubcommandHandler.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/SubcommandHandler.java
@@ -45,16 +45,16 @@
 
 import java.text.MessageFormat;
 
+import org.eclipse.jgit.pgm.CommandCatalog;
+import org.eclipse.jgit.pgm.CommandRef;
+import org.eclipse.jgit.pgm.TextBuiltin;
+import org.eclipse.jgit.pgm.internal.CLIText;
 import org.kohsuke.args4j.CmdLineException;
 import org.kohsuke.args4j.CmdLineParser;
 import org.kohsuke.args4j.OptionDef;
 import org.kohsuke.args4j.spi.OptionHandler;
 import org.kohsuke.args4j.spi.Parameters;
 import org.kohsuke.args4j.spi.Setter;
-import org.eclipse.jgit.pgm.CommandCatalog;
-import org.eclipse.jgit.pgm.CommandRef;
-import org.eclipse.jgit.pgm.TextBuiltin;
-import org.eclipse.jgit.pgm.internal.CLIText;
 
 /**
  * Custom Argument handler for jgit command selection.
diff --git a/org.eclipse.jgit.test/.classpath b/org.eclipse.jgit.test/.classpath
index 8b81bf5..84b5052 100644
--- a/org.eclipse.jgit.test/.classpath
+++ b/org.eclipse.jgit.test/.classpath
@@ -4,7 +4,7 @@
 	<classpathentry kind="src" path="src"/>
 	<classpathentry kind="src" path="tst-rsrc"/>
 	<classpathentry kind="src" path="exttst"/>
-	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7"/>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
 	<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
 	<classpathentry kind="output" path="bin"/>
 </classpath>
diff --git a/org.eclipse.jgit.test/.settings/org.eclipse.jdt.core.prefs b/org.eclipse.jgit.test/.settings/org.eclipse.jdt.core.prefs
index 87210fb..10c29d5 100644
--- a/org.eclipse.jgit.test/.settings/org.eclipse.jdt.core.prefs
+++ b/org.eclipse.jgit.test/.settings/org.eclipse.jdt.core.prefs
@@ -7,9 +7,9 @@
 org.eclipse.jdt.core.compiler.annotation.nullanalysis=disabled
 org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
 org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
-org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
 org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
-org.eclipse.jdt.core.compiler.compliance=1.7
+org.eclipse.jdt.core.compiler.compliance=1.8
 org.eclipse.jdt.core.compiler.debug.lineNumber=generate
 org.eclipse.jdt.core.compiler.debug.localVariable=generate
 org.eclipse.jdt.core.compiler.debug.sourceFile=generate
@@ -112,7 +112,7 @@
 org.eclipse.jdt.core.compiler.problem.unusedTypeParameter=ignore
 org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning
 org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=error
-org.eclipse.jdt.core.compiler.source=1.7
+org.eclipse.jdt.core.compiler.source=1.8
 org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16
 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0
diff --git a/org.eclipse.jgit.test/BUCK b/org.eclipse.jgit.test/BUCK
index 3df3336..5b7be89 100644
--- a/org.eclipse.jgit.test/BUCK
+++ b/org.eclipse.jgit.test/BUCK
@@ -60,6 +60,7 @@
       ':tst_rsrc',
       '//org.eclipse.jgit:jgit',
       '//org.eclipse.jgit.junit:junit',
+      '//org.eclipse.jgit.lfs:jgit-lfs',
       '//lib:hamcrest-core',
       '//lib:hamcrest-library',
       '//lib:javaewah',
@@ -67,7 +68,6 @@
       '//lib:slf4j-api',
       '//lib:slf4j-simple',
     ] + DEPS.get(src, []),
-    source_under_test = ['//org.eclipse.jgit:jgit'],
     vm_args = ['-Xmx256m', '-Dfile.encoding=UTF-8'],
   )
 
diff --git a/org.eclipse.jgit.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.test/META-INF/MANIFEST.MF
index 1dcd97b..f48cae0 100644
--- a/org.eclipse.jgit.test/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.test/META-INF/MANIFEST.MF
@@ -2,57 +2,58 @@
 Bundle-ManifestVersion: 2
 Bundle-Name: %plugin_name
 Bundle-SymbolicName: org.eclipse.jgit.test
-Bundle-Version: 4.5.3.qualifier
+Bundle-Version: 4.6.2.qualifier
 Bundle-Localization: plugin
 Bundle-Vendor: %provider_name
 Bundle-ActivationPolicy: lazy
-Bundle-RequiredExecutionEnvironment: JavaSE-1.7
-Import-Package: com.googlecode.javaewah;version="[0.7.9,0.8.0)",
- org.eclipse.jgit.api;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.api.errors;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.attributes;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.awtui;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.blame;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.diff;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.dircache;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.errors;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.events;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.fnmatch;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.gitrepo;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.hooks;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.ignore;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.ignore.internal;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.internal;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.internal.storage.dfs;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.internal.storage.file;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.internal.storage.pack;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.internal.storage.reftree;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.junit;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.lib;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.merge;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.nls;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.notes;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.patch;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.pgm;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.pgm.internal;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.revplot;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.revwalk;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.revwalk.filter;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.storage.file;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.storage.pack;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.submodule;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.transport;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.transport.http;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.transport.resolver;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.treewalk;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.treewalk.filter;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.util;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.util.io;version="[4.5.3,4.6.0)",
- org.hamcrest;version="[1.1.0,2.0.0)",
+Bundle-RequiredExecutionEnvironment: JavaSE-1.8
+Import-Package: com.googlecode.javaewah;version="[1.1.6,2.0.0)",
+ org.eclipse.jgit.api;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.api.errors;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.attributes;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.awtui;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.blame;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.diff;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.dircache;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.errors;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.events;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.fnmatch;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.gitrepo;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.hooks;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.ignore;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.ignore.internal;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.internal;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.internal.storage.dfs;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.internal.storage.file;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.internal.storage.pack;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.internal.storage.reftree;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.junit;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.lfs;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.lib;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.merge;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.nls;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.notes;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.patch;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.pgm;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.pgm.internal;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.revplot;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.revwalk;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.revwalk.filter;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.storage.file;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.storage.pack;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.submodule;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.transport;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.transport.http;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.transport.resolver;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.treewalk;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.treewalk.filter;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.util;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.util.io;version="[4.6.2,4.7.0)",
  org.junit;version="[4.4.0,5.0.0)",
  org.junit.experimental.theories;version="[4.4.0,5.0.0)",
  org.junit.rules;version="[4.11.0,5.0.0)",
  org.junit.runner;version="[4.4.0,5.0.0)",
  org.junit.runners;version="[4.11.0,5.0.0)",
  org.slf4j;version="[1.7.2,2.0.0)"
-Require-Bundle: org.hamcrest.core;bundle-version="[1.1.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)"
diff --git "a/org.eclipse.jgit.test/org.eclipse.jgit.core--All-External-Tests \050Java 6\051.launch" "b/org.eclipse.jgit.test/org.eclipse.jgit.core--All-External-Tests \050Java 6\051.launch"
deleted file mode 100644
index db13a84..0000000
--- "a/org.eclipse.jgit.test/org.eclipse.jgit.core--All-External-Tests \050Java 6\051.launch"
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<launchConfiguration type="org.eclipse.jdt.junit.launchconfig">
-<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
-<listEntry value="/org.eclipse.jgit.test/exttst"/>
-</listAttribute>
-<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
-<listEntry value="2"/>
-</listAttribute>
-<booleanAttribute key="org.eclipse.debug.core.appendEnvironmentVariables" value="true"/>
-<listAttribute key="org.eclipse.debug.ui.favoriteGroups">
-<listEntry value="org.eclipse.debug.ui.launchGroup.debug"/>
-<listEntry value="org.eclipse.debug.ui.launchGroup.run"/>
-</listAttribute>
-<stringAttribute key="org.eclipse.jdt.junit.CONTAINER" value="=org.eclipse.jgit.test/exttst"/>
-<booleanAttribute key="org.eclipse.jdt.junit.KEEPRUNNING_ATTR" value="false"/>
-<stringAttribute key="org.eclipse.jdt.junit.TESTNAME" value=""/>
-<stringAttribute key="org.eclipse.jdt.junit.TEST_KIND" value="org.eclipse.jdt.junit.loader.junit4"/>
-<stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
-<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value=""/>
-<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="org.eclipse.jgit.test"/>
-</launchConfiguration>
diff --git a/org.eclipse.jgit.test/org.eclipse.jgit.core--All-External-Tests.launch b/org.eclipse.jgit.test/org.eclipse.jgit.core--All-External-Tests.launch
deleted file mode 100644
index 2adb02c..0000000
--- a/org.eclipse.jgit.test/org.eclipse.jgit.core--All-External-Tests.launch
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<launchConfiguration type="org.eclipse.jdt.junit.launchconfig">
-<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
-<listEntry value="/org.eclipse.jgit.test/exttst"/>
-</listAttribute>
-<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
-<listEntry value="2"/>
-</listAttribute>
-<booleanAttribute key="org.eclipse.debug.core.appendEnvironmentVariables" value="true"/>
-<listAttribute key="org.eclipse.debug.ui.favoriteGroups">
-<listEntry value="org.eclipse.debug.ui.launchGroup.debug"/>
-<listEntry value="org.eclipse.debug.ui.launchGroup.run"/>
-</listAttribute>
-<stringAttribute key="org.eclipse.jdt.junit.CONTAINER" value="=org.eclipse.jgit.test/exttst"/>
-<booleanAttribute key="org.eclipse.jdt.junit.KEEPRUNNING_ATTR" value="false"/>
-<stringAttribute key="org.eclipse.jdt.junit.TESTNAME" value=""/>
-<stringAttribute key="org.eclipse.jdt.junit.TEST_KIND" value="org.eclipse.jdt.junit.loader.junit4"/>
-<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value=""/>
-<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="org.eclipse.jgit.test"/>
-</launchConfiguration>
diff --git "a/org.eclipse.jgit.test/org.eclipse.jgit.core--All-Tests \050Java 6\051.launch" "b/org.eclipse.jgit.test/org.eclipse.jgit.core--All-Tests \050Java 6\051.launch"
deleted file mode 100644
index f253d59..0000000
--- "a/org.eclipse.jgit.test/org.eclipse.jgit.core--All-Tests \050Java 6\051.launch"
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<launchConfiguration type="org.eclipse.jdt.junit.launchconfig">
-<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
-<listEntry value="/org.eclipse.jgit.test/tst"/>
-</listAttribute>
-<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
-<listEntry value="2"/>
-</listAttribute>
-<booleanAttribute key="org.eclipse.debug.core.appendEnvironmentVariables" value="true"/>
-<listAttribute key="org.eclipse.debug.ui.favoriteGroups">
-<listEntry value="org.eclipse.debug.ui.launchGroup.debug"/>
-<listEntry value="org.eclipse.debug.ui.launchGroup.run"/>
-</listAttribute>
-<stringAttribute key="org.eclipse.jdt.junit.CONTAINER" value="=org.eclipse.jgit.test/tst"/>
-<booleanAttribute key="org.eclipse.jdt.junit.KEEPRUNNING_ATTR" value="false"/>
-<stringAttribute key="org.eclipse.jdt.junit.TESTNAME" value=""/>
-<stringAttribute key="org.eclipse.jdt.junit.TEST_KIND" value="org.eclipse.jdt.junit.loader.junit4"/>
-<stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
-<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value=""/>
-<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="org.eclipse.jgit.test"/>
-<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Xmx256m"/>
-</launchConfiguration>
diff --git "a/org.eclipse.jgit.test/org.eclipse.jgit.core--All-Tests \050Java 7\051 \050de\051.launch" "b/org.eclipse.jgit.test/org.eclipse.jgit.core--All-Tests \050Java 7\051 \050de\051.launch"
deleted file mode 100644
index 86446f9..0000000
--- "a/org.eclipse.jgit.test/org.eclipse.jgit.core--All-Tests \050Java 7\051 \050de\051.launch"
+++ /dev/null
@@ -1,30 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<launchConfiguration type="org.eclipse.jdt.junit.launchconfig">
-<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
-<listEntry value="/org.eclipse.jgit.test/tst"/>
-</listAttribute>
-<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
-<listEntry value="2"/>
-</listAttribute>
-<booleanAttribute key="org.eclipse.debug.core.appendEnvironmentVariables" value="true"/>
-<mapAttribute key="org.eclipse.debug.core.environmentVariables">
-<mapEntry key="LANG" value="de_DE.UTF-8"/>
-</mapAttribute>
-<listAttribute key="org.eclipse.debug.ui.favoriteGroups">
-<listEntry value="org.eclipse.debug.ui.launchGroup.debug"/>
-<listEntry value="org.eclipse.debug.ui.launchGroup.run"/>
-</listAttribute>
-<stringAttribute key="org.eclipse.jdt.junit.CONTAINER" value="=org.eclipse.jgit.test/tst"/>
-<booleanAttribute key="org.eclipse.jdt.junit.KEEPRUNNING_ATTR" value="false"/>
-<stringAttribute key="org.eclipse.jdt.junit.TESTNAME" value=""/>
-<stringAttribute key="org.eclipse.jdt.junit.TEST_KIND" value="org.eclipse.jdt.junit.loader.junit4"/>
-<listAttribute key="org.eclipse.jdt.launching.CLASSPATH">
-<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#10;&lt;runtimeClasspathEntry containerPath=&quot;org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6&quot; path=&quot;1&quot; type=&quot;4&quot;/&gt;&#10;"/>
-<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#10;&lt;runtimeClasspathEntry id=&quot;org.eclipse.jdt.launching.classpathentry.defaultClasspath&quot;&gt;&#10;&lt;memento exportedEntriesOnly=&quot;false&quot; project=&quot;org.eclipse.jgit.test&quot;/&gt;&#10;&lt;/runtimeClasspathEntry&gt;&#10;"/>
-</listAttribute>
-<booleanAttribute key="org.eclipse.jdt.launching.DEFAULT_CLASSPATH" value="false"/>
-<stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7"/>
-<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value=""/>
-<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="org.eclipse.jgit.test"/>
-<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Xmx256m"/>
-</launchConfiguration>
diff --git "a/org.eclipse.jgit.test/org.eclipse.jgit.core--All-Tests \050Java 7\051.launch" "b/org.eclipse.jgit.test/org.eclipse.jgit.core--All-Tests \050Java 7\051.launch"
deleted file mode 100644
index a83fabb..0000000
--- "a/org.eclipse.jgit.test/org.eclipse.jgit.core--All-Tests \050Java 7\051.launch"
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<launchConfiguration type="org.eclipse.jdt.junit.launchconfig">
-<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
-<listEntry value="/org.eclipse.jgit.test/tst"/>
-</listAttribute>
-<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
-<listEntry value="2"/>
-</listAttribute>
-<booleanAttribute key="org.eclipse.debug.core.appendEnvironmentVariables" value="true"/>
-<listAttribute key="org.eclipse.debug.ui.favoriteGroups">
-<listEntry value="org.eclipse.debug.ui.launchGroup.debug"/>
-<listEntry value="org.eclipse.debug.ui.launchGroup.run"/>
-</listAttribute>
-<stringAttribute key="org.eclipse.jdt.junit.CONTAINER" value="=org.eclipse.jgit.test/tst"/>
-<booleanAttribute key="org.eclipse.jdt.junit.KEEPRUNNING_ATTR" value="false"/>
-<stringAttribute key="org.eclipse.jdt.junit.TESTNAME" value=""/>
-<stringAttribute key="org.eclipse.jdt.junit.TEST_KIND" value="org.eclipse.jdt.junit.loader.junit4"/>
-<listAttribute key="org.eclipse.jdt.launching.CLASSPATH">
-<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#10;&lt;runtimeClasspathEntry containerPath=&quot;org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6&quot; path=&quot;1&quot; type=&quot;4&quot;/&gt;&#10;"/>
-<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#10;&lt;runtimeClasspathEntry id=&quot;org.eclipse.jdt.launching.classpathentry.defaultClasspath&quot;&gt;&#10;&lt;memento exportedEntriesOnly=&quot;false&quot; project=&quot;org.eclipse.jgit.test&quot;/&gt;&#10;&lt;/runtimeClasspathEntry&gt;&#10;"/>
-</listAttribute>
-<booleanAttribute key="org.eclipse.jdt.launching.DEFAULT_CLASSPATH" value="false"/>
-<stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7"/>
-<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value=""/>
-<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="org.eclipse.jgit.test"/>
-<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Xmx256m"/>
-</launchConfiguration>
diff --git a/org.eclipse.jgit.test/pom.xml b/org.eclipse.jgit.test/pom.xml
index d9e9e20..1aff289 100644
--- a/org.eclipse.jgit.test/pom.xml
+++ b/org.eclipse.jgit.test/pom.xml
@@ -52,7 +52,7 @@
   <parent>
     <groupId>org.eclipse.jgit</groupId>
     <artifactId>org.eclipse.jgit-parent</artifactId>
-    <version>4.5.3-SNAPSHOT</version>
+    <version>4.6.2-SNAPSHOT</version>
   </parent>
 
   <artifactId>org.eclipse.jgit.test</artifactId>
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/indexdiff/filerepo.txt b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/indexdiff/filerepo.txt
new file mode 100644
index 0000000..3255efb
--- /dev/null
+++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/indexdiff/filerepo.txt
@@ -0,0 +1,30 @@
+blob
+mark :1
+data 10
+äéü.txt
+blob
+mark :2
+data 8
+test.txt
+blob
+mark :3
+data 5
+Test
+
+blob
+mark :4
+data 7
+äéü
+
+reset refs/heads/master
+commit refs/heads/master
+mark :5
+author A U Thor <author@example.com> 1450727513 +0100
+committer A U Thor <author@example.com> 1450727513 +0100
+data 26
+Initial commit with links
+M 120000 :1 testfolder/aeu.txt
+M 120000 :2 testfolder/link.txt
+M 100644 :3 testfolder/test.txt
+M 100644 :4 testfolder/äéü.txt
+
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/AddCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/AddCommandTest.java
index 42601aa..5ad73f1 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/AddCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/AddCommandTest.java
@@ -57,12 +57,21 @@
 import org.eclipse.jgit.api.errors.FilterFailedException;
 import org.eclipse.jgit.api.errors.GitAPIException;
 import org.eclipse.jgit.api.errors.NoFilepatternException;
+import org.eclipse.jgit.attributes.FilterCommandRegistry;
 import org.eclipse.jgit.dircache.DirCache;
 import org.eclipse.jgit.dircache.DirCacheBuilder;
 import org.eclipse.jgit.dircache.DirCacheEntry;
 import org.eclipse.jgit.junit.JGitTestUtil;
 import org.eclipse.jgit.junit.RepositoryTestCase;
-import org.eclipse.jgit.lib.*;
+import org.eclipse.jgit.lfs.CleanFilter;
+import org.eclipse.jgit.lfs.SmudgeFilter;
+import org.eclipse.jgit.lib.ConfigConstants;
+import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.FileMode;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.ObjectInserter;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.lib.StoredConfig;
 import org.eclipse.jgit.revwalk.RevCommit;
 import org.eclipse.jgit.storage.file.FileRepositoryBuilder;
 import org.eclipse.jgit.treewalk.TreeWalk;
@@ -70,8 +79,23 @@
 import org.eclipse.jgit.util.FS;
 import org.eclipse.jgit.util.FileUtils;
 import org.junit.Test;
+import org.junit.experimental.theories.DataPoints;
+import org.junit.experimental.theories.Theories;
+import org.junit.experimental.theories.Theory;
+import org.junit.runner.RunWith;
 
+@RunWith(Theories.class)
 public class AddCommandTest extends RepositoryTestCase {
+	@DataPoints
+	public static boolean[] sleepBeforeAddOptions = { true, false };
+
+
+	@Override
+	public void setUp() throws Exception {
+		CleanFilter.register();
+		SmudgeFilter.register();
+		super.setUp();
+	}
 
 	@Test
 	public void testAddNothing() throws GitAPIException {
@@ -110,8 +134,7 @@
 	}
 
 	@Test
-	public void testCleanFilter() throws IOException,
-			GitAPIException {
+	public void testCleanFilter() throws IOException, GitAPIException {
 		writeTrashFile(".gitattributes", "*.txt filter=tstFilter");
 		writeTrashFile("src/a.tmp", "foo");
 		// Caution: we need a trailing '\n' since sed on mac always appends
@@ -134,6 +157,128 @@
 		}
 	}
 
+	@Theory
+	public void testBuiltinFilters(boolean sleepBeforeAdd)
+			throws IOException,
+			GitAPIException, InterruptedException {
+		writeTrashFile(".gitattributes", "*.txt filter=lfs");
+		writeTrashFile("src/a.tmp", "foo");
+		// Caution: we need a trailing '\n' since sed on mac always appends
+		// linefeeds if missing
+		File script = writeTempFile("sed s/o/e/g");
+		File f = writeTrashFile("src/a.txt", "foo\n");
+
+		try (Git git = new Git(db)) {
+			if (!sleepBeforeAdd) {
+				fsTick(f);
+			}
+			git.add().addFilepattern(".gitattributes").call();
+			StoredConfig config = git.getRepository().getConfig();
+			config.setString("filter", "lfs", "clean",
+					"sh " + slashify(script.getPath()));
+			config.setString("filter", "lfs", "smudge",
+					"sh " + slashify(script.getPath()));
+			config.setBoolean("filter", "lfs", "useJGitBuiltin", true);
+			config.save();
+
+			if (!sleepBeforeAdd) {
+				fsTick(f);
+			}
+			git.add().addFilepattern("src/a.txt").addFilepattern("src/a.tmp")
+					.addFilepattern(".gitattributes").call();
+
+			assertEquals(
+					"[.gitattributes, mode:100644, content:*.txt filter=lfs][src/a.tmp, mode:100644, content:foo][src/a.txt, mode:100644, content:version https://git-lfs.github.com/spec/v1\noid sha256:b5bb9d8014a0f9b1d61e21e796d78dccdf1352f23cd32812f4850b878ae4944c\nsize 4\n]",
+					indexState(CONTENT));
+
+			RevCommit c1 = git.commit().setMessage("c1").call();
+			assertTrue(git.status().call().isClean());
+			f = writeTrashFile("src/a.txt", "foobar\n");
+			if (!sleepBeforeAdd) {
+				fsTick(f);
+			}
+			git.add().addFilepattern("src/a.txt").call();
+			git.commit().setMessage("c2").call();
+			assertTrue(git.status().call().isClean());
+			assertEquals(
+					"[.gitattributes, mode:100644, content:*.txt filter=lfs][src/a.tmp, mode:100644, content:foo][src/a.txt, mode:100644, content:version https://git-lfs.github.com/spec/v1\noid sha256:aec070645fe53ee3b3763059376134f058cc337247c978add178b6ccdfb0019f\nsize 7\n]",
+					indexState(CONTENT));
+			assertEquals("foobar\n", read("src/a.txt"));
+			git.checkout().setName(c1.getName()).call();
+			assertEquals(
+					"[.gitattributes, mode:100644, content:*.txt filter=lfs][src/a.tmp, mode:100644, content:foo][src/a.txt, mode:100644, content:version https://git-lfs.github.com/spec/v1\noid sha256:b5bb9d8014a0f9b1d61e21e796d78dccdf1352f23cd32812f4850b878ae4944c\nsize 4\n]",
+					indexState(CONTENT));
+			assertEquals(
+					"foo\n", read("src/a.txt"));
+		}
+	}
+
+	@Theory
+	public void testBuiltinCleanFilter(boolean sleepBeforeAdd)
+			throws IOException, GitAPIException, InterruptedException {
+		writeTrashFile(".gitattributes", "*.txt filter=lfs");
+		writeTrashFile("src/a.tmp", "foo");
+		// Caution: we need a trailing '\n' since sed on mac always appends
+		// linefeeds if missing
+		File script = writeTempFile("sed s/o/e/g");
+		File f = writeTrashFile("src/a.txt", "foo\n");
+
+		// unregister the smudge filter. Only clean filter should be builtin
+		FilterCommandRegistry.unregister(
+				org.eclipse.jgit.lib.Constants.BUILTIN_FILTER_PREFIX
+						+ "lfs/smudge");
+
+		try (Git git = new Git(db)) {
+			if (!sleepBeforeAdd) {
+				fsTick(f);
+			}
+			git.add().addFilepattern(".gitattributes").call();
+			StoredConfig config = git.getRepository().getConfig();
+			config.setString("filter", "lfs", "clean",
+					"sh " + slashify(script.getPath()));
+			config.setString("filter", "lfs", "smudge",
+					"sh " + slashify(script.getPath()));
+			config.setBoolean("filter", "lfs", "useJGitBuiltin", true);
+			config.save();
+
+			if (!sleepBeforeAdd) {
+				fsTick(f);
+			}
+			git.add().addFilepattern("src/a.txt").addFilepattern("src/a.tmp")
+					.addFilepattern(".gitattributes").call();
+
+			assertEquals(
+					"[.gitattributes, mode:100644, content:*.txt filter=lfs][src/a.tmp, mode:100644, content:foo][src/a.txt, mode:100644, content:version https://git-lfs.github.com/spec/v1\noid sha256:b5bb9d8014a0f9b1d61e21e796d78dccdf1352f23cd32812f4850b878ae4944c\nsize 4\n]",
+					indexState(CONTENT));
+
+			RevCommit c1 = git.commit().setMessage("c1").call();
+			assertTrue(git.status().call().isClean());
+			f = writeTrashFile("src/a.txt", "foobar\n");
+			if (!sleepBeforeAdd) {
+				fsTick(f);
+			}
+			git.add().addFilepattern("src/a.txt").call();
+			git.commit().setMessage("c2").call();
+			assertTrue(git.status().call().isClean());
+			assertEquals(
+					"[.gitattributes, mode:100644, content:*.txt filter=lfs][src/a.tmp, mode:100644, content:foo][src/a.txt, mode:100644, content:version https://git-lfs.github.com/spec/v1\noid sha256:aec070645fe53ee3b3763059376134f058cc337247c978add178b6ccdfb0019f\nsize 7\n]",
+					indexState(CONTENT));
+			assertEquals("foobar\n", read("src/a.txt"));
+			git.checkout().setName(c1.getName()).call();
+			assertEquals(
+					"[.gitattributes, mode:100644, content:*.txt filter=lfs][src/a.tmp, mode:100644, content:foo][src/a.txt, mode:100644, content:version https://git-lfs.github.com/spec/v1\noid sha256:b5bb9d8014a0f9b1d61e21e796d78dccdf1352f23cd32812f4850b878ae4944c\nsize 4\n]",
+					indexState(CONTENT));
+			// due to lfs clean filter but dummy smudge filter we expect strange
+			// content. The smudge filter converts from real content to pointer
+			// file content (starting with "version ") but the smudge filter
+			// replaces 'o' by 'e' which results in a text starting with
+			// "versien "
+			assertEquals(
+					"versien https://git-lfs.github.cem/spec/v1\neid sha256:b5bb9d8014a0f9b1d61e21e796d78dccdf1352f23cd32812f4850b878ae4944c\nsize 4\n",
+					read("src/a.txt"));
+		}
+	}
+
 	@Test
 	public void testAttributesWithTreeWalkFilter()
 			throws IOException, GitAPIException {
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 0bb6610..3c19672 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
@@ -74,6 +74,8 @@
 import org.eclipse.jgit.dircache.DirCacheEntry;
 import org.eclipse.jgit.junit.JGitTestUtil;
 import org.eclipse.jgit.junit.RepositoryTestCase;
+import org.eclipse.jgit.lfs.CleanFilter;
+import org.eclipse.jgit.lfs.SmudgeFilter;
 import org.eclipse.jgit.lib.ConfigConstants;
 import org.eclipse.jgit.lib.Constants;
 import org.eclipse.jgit.lib.Ref;
@@ -87,6 +89,7 @@
 import org.eclipse.jgit.transport.RemoteConfig;
 import org.eclipse.jgit.transport.URIish;
 import org.eclipse.jgit.util.FileUtils;
+import org.eclipse.jgit.util.SystemReader;
 import org.junit.Before;
 import org.junit.Test;
 
@@ -100,6 +103,8 @@
 	@Override
 	@Before
 	public void setUp() throws Exception {
+		CleanFilter.register();
+		SmudgeFilter.register();
 		super.setUp();
 		git = new Git(db);
 		// commit something
@@ -563,11 +568,11 @@
 	public void testSmudgeFilter_modifyExisting() throws IOException, GitAPIException {
 		File script = writeTempFile("sed s/o/e/g");
 		StoredConfig config = git.getRepository().getConfig();
-		config.setString("filter", "tstFilter", "smudge",
+		config.setString("filter", "lfs", "smudge",
 				"sh " + slashify(script.getPath()));
 		config.save();
 
-		writeTrashFile(".gitattributes", "*.txt filter=tstFilter");
+		writeTrashFile(".gitattributes", "*.txt filter=lfs");
 		git.add().addFilepattern(".gitattributes").call();
 		git.commit().setMessage("add filter").call();
 
@@ -589,7 +594,7 @@
 		git.checkout().setName(content2.getName()).call();
 
 		assertEquals(
-				"[.gitattributes, mode:100644, content:*.txt filter=tstFilter][Test.txt, mode:100644, content:Some change][src/a.tmp, mode:100644, content:foo][src/a.txt, mode:100644, content:foo\n]",
+				"[.gitattributes, mode:100644, content:*.txt filter=lfs][Test.txt, mode:100644, content:Some change][src/a.tmp, mode:100644, content:foo][src/a.txt, mode:100644, content:foo\n]",
 				indexState(CONTENT));
 		assertEquals(Sets.of("src/a.txt"), git.status().call().getModified());
 		assertEquals("foo", read("src/a.tmp"));
@@ -601,7 +606,7 @@
 			throws IOException, GitAPIException {
 		File script = writeTempFile("sed s/o/e/g");
 		StoredConfig config = git.getRepository().getConfig();
-		config.setString("filter", "tstFilter", "smudge",
+		config.setString("filter", "lfs", "smudge",
 				"sh " + slashify(script.getPath()));
 		config.save();
 
@@ -609,7 +614,7 @@
 		git.add().addFilepattern("foo").call();
 		RevCommit initial = git.commit().setMessage("initial").call();
 
-		writeTrashFile(".gitattributes", "*.txt filter=tstFilter");
+		writeTrashFile(".gitattributes", "*.txt filter=lfs");
 		git.add().addFilepattern(".gitattributes").call();
 		git.commit().setMessage("add filter").call();
 
@@ -625,7 +630,7 @@
 		git.checkout().setName(content.getName()).call();
 
 		assertEquals(
-				"[.gitattributes, mode:100644, content:*.txt filter=tstFilter][Test.txt, mode:100644, content:Some change][foo, mode:100644, content:foo][src/a.tmp, mode:100644, content:foo][src/a.txt, mode:100644, content:foo\n]",
+				"[.gitattributes, mode:100644, content:*.txt filter=lfs][Test.txt, mode:100644, content:Some change][foo, mode:100644, content:foo][src/a.tmp, mode:100644, content:foo][src/a.txt, mode:100644, content:foo\n]",
 				indexState(CONTENT));
 		assertEquals("foo", read("src/a.tmp"));
 		assertEquals("fee\n", read("src/a.txt"));
@@ -636,7 +641,7 @@
 			throws IOException, GitAPIException {
 		File script = writeTempFile("sed s/o/e/g");
 		StoredConfig config = git.getRepository().getConfig();
-		config.setString("filter", "tstFilter", "smudge",
+		config.setString("filter", "lfs", "smudge",
 				"sh " + slashify(script.getPath()));
 		config.save();
 
@@ -644,7 +649,7 @@
 		git.add().addFilepattern("foo").call();
 		git.commit().setMessage("initial").call();
 
-		writeTrashFile(".gitattributes", "*.txt filter=tstFilter");
+		writeTrashFile(".gitattributes", "*.txt filter=lfs");
 		git.add().addFilepattern(".gitattributes").call();
 		git.commit().setMessage("add filter").call();
 
@@ -661,7 +666,7 @@
 				.call();
 
 		assertEquals(
-				"[.gitattributes, mode:100644, content:*.txt filter=tstFilter][Test.txt, mode:100644, content:Some change][foo, mode:100644, content:foo][src/a.tmp, mode:100644, content:foo][src/a.txt, mode:100644, content:foo\n]",
+				"[.gitattributes, mode:100644, content:*.txt filter=lfs][Test.txt, mode:100644, content:Some change][foo, mode:100644, content:foo][src/a.tmp, mode:100644, content:foo][src/a.txt, mode:100644, content:foo\n]",
 				indexState(CONTENT));
 		assertEquals("foo", read("src/a.tmp"));
 		assertEquals("fee\n", read("src/a.txt"));
@@ -672,7 +677,7 @@
 			throws IOException, GitAPIException {
 		File script = writeTempFile("sed s/o/e/g");
 		StoredConfig config = git.getRepository().getConfig();
-		config.setString("filter", "tstFilter", "smudge",
+		config.setString("filter", "lfs", "smudge",
 				"sh " + slashify(script.getPath()));
 		config.save();
 
@@ -680,7 +685,7 @@
 		git.add().addFilepattern("foo").call();
 		git.commit().setMessage("initial").call();
 
-		writeTrashFile(".gitattributes", "*.txt filter=tstFilter");
+		writeTrashFile(".gitattributes", "*.txt filter=lfs");
 		git.add().addFilepattern(".gitattributes").call();
 		git.commit().setMessage("add filter").call();
 
@@ -696,7 +701,7 @@
 		git.checkout().addPath("src/a.txt").call();
 
 		assertEquals(
-				"[.gitattributes, mode:100644, content:*.txt filter=tstFilter][Test.txt, mode:100644, content:Some change][foo, mode:100644, content:foo][src/a.tmp, mode:100644, content:foo][src/a.txt, mode:100644, content:foo\n]",
+				"[.gitattributes, mode:100644, content:*.txt filter=lfs][Test.txt, mode:100644, content:Some change][foo, mode:100644, content:foo][src/a.tmp, mode:100644, content:foo][src/a.txt, mode:100644, content:foo\n]",
 				indexState(CONTENT));
 		assertEquals("foo", read("src/a.tmp"));
 		assertEquals("fee\n", read("src/a.txt"));
@@ -707,7 +712,7 @@
 			throws IOException, GitAPIException {
 		File script = writeTempFile("sed s/o/e/g");
 		StoredConfig config = git.getRepository().getConfig();
-		config.setString("filter", "tstFilter", "smudge",
+		config.setString("filter", "lfs", "smudge",
 				"sh " + slashify(script.getPath()));
 		config.save();
 
@@ -715,7 +720,7 @@
 		git.add().addFilepattern("foo").call();
 		git.commit().setMessage("initial").call();
 
-		writeTrashFile(".gitattributes", "*.txt filter=tstFilter");
+		writeTrashFile(".gitattributes", "*.txt filter=lfs");
 		git.add().addFilepattern(".gitattributes").call();
 		git.commit().setMessage("add filter").call();
 
@@ -732,7 +737,7 @@
 				.setStartPoint(content).addPath("src/a.txt").call();
 
 		assertEquals(
-				"[.gitattributes, mode:100644, content:*.txt filter=tstFilter][Test.txt, mode:100644, content:Some change][foo, mode:100644, content:foo][src/a.tmp, mode:100644, content:foo][src/a.txt, mode:100644, content:foo\n]",
+				"[.gitattributes, mode:100644, content:*.txt filter=lfs][Test.txt, mode:100644, content:Some change][foo, mode:100644, content:foo][src/a.tmp, mode:100644, content:foo][src/a.txt, mode:100644, content:foo\n]",
 				indexState(CONTENT));
 		assertEquals("foo", read("src/a.tmp"));
 		assertEquals("fee\n", read("src/a.txt"));
@@ -745,12 +750,13 @@
 
 		try (Git git2 = new Git(db)) {
 			StoredConfig config = git.getRepository().getConfig();
-			config.setString("filter", "tstFilter", "smudge",
+			config.setString("filter", "lfs", "smudge",
 					"sh " + slashify(smudge_filter.getPath()));
-			config.setString("filter", "tstFilter", "clean",
+			config.setString("filter", "lfs", "clean",
 					"sh " + slashify(clean_filter.getPath()));
+			config.setBoolean("filter", "lfs", "useJGitBuiltin", true);
 			config.save();
-			writeTrashFile(".gitattributes", "filterTest.txt filter=tstFilter");
+			writeTrashFile(".gitattributes", "filterTest.txt filter=lfs");
 			git2.add().addFilepattern(".gitattributes").call();
 			git2.commit().setMessage("add attributes").call();
 
@@ -758,7 +764,7 @@
 			git2.add().addFilepattern("filterTest.txt").call();
 			RevCommit one = git2.commit().setMessage("add filterText.txt").call();
 			assertEquals(
-					"[.gitattributes, mode:100644, content:filterTest.txt filter=tstFilter][Test.txt, mode:100644, content:Some change][filterTest.txt, mode:100644, content:hello world, @version\n]",
+					"[.gitattributes, mode:100644, content:filterTest.txt filter=lfs][Test.txt, mode:100644, content:Some change][filterTest.txt, mode:100644, content:version https://git-lfs.github.com/spec/v1\noid sha256:7bd5d32e5c494354aa4c2473a1306d0ce7b52cc3bffeb342c03cd517ef8cf8da\nsize 16\n]",
 					indexState(CONTENT));
 
 			fsTick(writeTrashFile("filterTest.txt", "bon giorno world, V1\n"));
@@ -767,25 +773,57 @@
 
 			assertTrue(git2.status().call().isClean());
 			assertEquals(
-					"[.gitattributes, mode:100644, content:filterTest.txt filter=tstFilter][Test.txt, mode:100644, content:Some change][filterTest.txt, mode:100644, content:bon giorno world, @version\n]",
+					"[.gitattributes, mode:100644, content:filterTest.txt filter=lfs][Test.txt, mode:100644, content:Some change][filterTest.txt, mode:100644, content:version https://git-lfs.github.com/spec/v1\noid sha256:087148cccf53b0049c56475c1595113c9da4b638997c3489af8ac7108d51ef13\nsize 21\n]",
 					indexState(CONTENT));
 
 			git2.checkout().setName(one.getName()).call();
 			assertTrue(git2.status().call().isClean());
 			assertEquals(
-					"[.gitattributes, mode:100644, content:filterTest.txt filter=tstFilter][Test.txt, mode:100644, content:Some change][filterTest.txt, mode:100644, content:hello world, @version\n]",
+					"[.gitattributes, mode:100644, content:filterTest.txt filter=lfs][Test.txt, mode:100644, content:Some change][filterTest.txt, mode:100644, content:version https://git-lfs.github.com/spec/v1\noid sha256:7bd5d32e5c494354aa4c2473a1306d0ce7b52cc3bffeb342c03cd517ef8cf8da\nsize 16\n]",
 					indexState(CONTENT));
 			assertEquals("hello world, V1\n", read("filterTest.txt"));
 
 			git2.checkout().setName(two.getName()).call();
 			assertTrue(git2.status().call().isClean());
 			assertEquals(
-					"[.gitattributes, mode:100644, content:filterTest.txt filter=tstFilter][Test.txt, mode:100644, content:Some change][filterTest.txt, mode:100644, content:bon giorno world, @version\n]",
+					"[.gitattributes, mode:100644, content:filterTest.txt filter=lfs][Test.txt, mode:100644, content:Some change][filterTest.txt, mode:100644, content:version https://git-lfs.github.com/spec/v1\noid sha256:087148cccf53b0049c56475c1595113c9da4b638997c3489af8ac7108d51ef13\nsize 21\n]",
 					indexState(CONTENT));
 			assertEquals("bon giorno world, V1\n", read("filterTest.txt"));
 		}
 	}
 
+	@Test
+	public void testNonDeletableFilesOnWindows()
+			throws GitAPIException, IOException {
+		// Only on windows a FileInputStream blocks us from deleting a file
+		org.junit.Assume.assumeTrue(SystemReader.getInstance().isWindows());
+		writeTrashFile("toBeModified.txt", "a");
+		writeTrashFile("toBeDeleted.txt", "a");
+		git.add().addFilepattern(".").call();
+		RevCommit addFiles = git.commit().setMessage("add more files").call();
+
+		git.rm().setCached(false).addFilepattern("Test.txt")
+				.addFilepattern("toBeDeleted.txt").call();
+		writeTrashFile("toBeModified.txt", "b");
+		writeTrashFile("toBeCreated.txt", "a");
+		git.add().addFilepattern(".").call();
+		RevCommit crudCommit = git.commit().setMessage("delete, modify, add")
+				.call();
+		git.checkout().setName(addFiles.getName()).call();
+		try ( FileInputStream fis=new FileInputStream(new File(db.getWorkTree(), "Test.txt")) ) {
+			CheckoutCommand coCommand = git.checkout();
+			coCommand.setName(crudCommit.getName()).call();
+			CheckoutResult result = coCommand.getResult();
+			assertEquals(Status.NONDELETED, result.getStatus());
+			assertEquals("[Test.txt, toBeDeleted.txt]",
+					result.getRemovedList().toString());
+			assertEquals("[toBeCreated.txt, toBeModified.txt]",
+					result.getModifiedList().toString());
+			assertEquals("[Test.txt]", result.getUndeletedList().toString());
+			assertTrue(result.getConflictList().isEmpty());
+		}
+	}
+
 	private File writeTempFile(String body) throws IOException {
 		File f = File.createTempFile("AddCommandTest_", "");
 		JGitTestUtil.write(f, body);
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CleanCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CleanCommandTest.java
index 68f5dd1..0e1cf02 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CleanCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CleanCommandTest.java
@@ -42,10 +42,10 @@
  */
 package org.eclipse.jgit.api;
 
+import static org.eclipse.jgit.lib.Constants.DOT_GIT_MODULES;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
-import static org.eclipse.jgit.lib.Constants.DOT_GIT_MODULES;
 
 import java.io.File;
 import java.util.Set;
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitCommandTest.java
index 8a07118..473dce1 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitCommandTest.java
@@ -43,10 +43,10 @@
 package org.eclipse.jgit.api;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.fail;
 
 import java.io.File;
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/DiffCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/DiffCommandTest.java
index 4f5b50d..43c3a8c 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/DiffCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/DiffCommandTest.java
@@ -95,7 +95,7 @@
 					+ "\\ No newline at end of file\n"
 					+ "+folder change\n"
 					+ "\\ No newline at end of file\n";
-			assertEquals(expected.toString(), actual);
+			assertEquals(expected, actual);
 		}
 	}
 
@@ -130,7 +130,7 @@
 					+ "@@ -0,0 +1 @@\n"
 					+ "+folder\n"
 					+ "\\ No newline at end of file\n";
-			assertEquals(expected.toString(), actual);
+			assertEquals(expected, actual);
 		}
 	}
 
@@ -179,7 +179,7 @@
 					+ "\\ No newline at end of file\n"
 					+ "+folder change\n"
 					+ "\\ No newline at end of file\n";
-			assertEquals(expected.toString(), actual);
+			assertEquals(expected, actual);
 		}
 	}
 
@@ -201,7 +201,7 @@
 					+ "+++ new/test.txt\n" + "@@ -1 +1 @@\n" + "-test\n"
 					+ "\\ No newline at end of file\n" + "+test change\n"
 					+ "\\ No newline at end of file\n";
-			assertEquals(expected.toString(), actual);
+			assertEquals(expected, actual);
 		}
 	}
 
@@ -223,7 +223,7 @@
 					+ "index f55b5c9..c5ec8fd 100644\n" + "--- a/test.txt\n"
 					+ "+++ b/test.txt\n" + "@@ -4,3 +4,3 @@\n" + " 3\n" + "-4\n"
 					+ "+4a\n" + " 5\n";
-			assertEquals(expected.toString(), actual);
+			assertEquals(expected, actual);
 		}
 	}
 
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/EolStreamTypeUtilTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/EolStreamTypeUtilTest.java
index 8ca1b31..2ee77a0 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/EolStreamTypeUtilTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/EolStreamTypeUtilTest.java
@@ -42,8 +42,12 @@
 
 package org.eclipse.jgit.api;
 
+import static org.eclipse.jgit.lib.CoreConfig.EolStreamType.AUTO_CRLF;
+import static org.eclipse.jgit.lib.CoreConfig.EolStreamType.AUTO_LF;
+import static org.eclipse.jgit.lib.CoreConfig.EolStreamType.DIRECT;
+import static org.eclipse.jgit.lib.CoreConfig.EolStreamType.TEXT_CRLF;
+import static org.eclipse.jgit.lib.CoreConfig.EolStreamType.TEXT_LF;
 import static org.junit.Assert.assertArrayEquals;
-import static org.eclipse.jgit.lib.CoreConfig.EolStreamType.*;
 
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/NotesCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/NotesCommandTest.java
index 6ddf89c..9d15699 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/NotesCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/NotesCommandTest.java
@@ -43,6 +43,7 @@
 package org.eclipse.jgit.api;
 
 import static org.junit.Assert.assertEquals;
+
 import java.util.List;
 
 import org.eclipse.jgit.junit.RepositoryTestCase;
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/DiffFormatterTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/DiffFormatterTest.java
index 638a163..b4234dc 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/DiffFormatterTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/DiffFormatterTest.java
@@ -45,6 +45,7 @@
 
 import static org.junit.Assert.assertEquals;
 
+import java.io.BufferedOutputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.File;
 
@@ -65,7 +66,6 @@
 import org.eclipse.jgit.util.FileUtils;
 import org.eclipse.jgit.util.RawParseUtils;
 import org.eclipse.jgit.util.io.DisabledOutputStream;
-import org.eclipse.jgit.util.io.SafeBufferedOutputStream;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
@@ -381,7 +381,7 @@
 		write(new File(folder, "folder.txt"), "folder");
 		try (Git git = new Git(db);
 				ByteArrayOutputStream os = new ByteArrayOutputStream();
-				DiffFormatter dfmt = new DiffFormatter(new SafeBufferedOutputStream(os))) {
+				DiffFormatter dfmt = new DiffFormatter(new BufferedOutputStream(os))) {
 			git.add().addFilepattern(".").call();
 			git.commit().setMessage("Initial commit").call();
 			write(new File(folder, "folder.txt"), "folder change");
@@ -414,7 +414,7 @@
 		write(new File(folder, "folder.txt"), "folder");
 		try (Git git = new Git(db);
 				ByteArrayOutputStream os = new ByteArrayOutputStream();
-				DiffFormatter dfmt = new DiffFormatter(new SafeBufferedOutputStream(os))) {
+				DiffFormatter dfmt = new DiffFormatter(new BufferedOutputStream(os))) {
 			git.add().addFilepattern(".").call();
 			RevCommit commit = git.commit().setMessage("Initial commit").call();
 			write(new File(folder, "folder.txt"), "folder change");
@@ -446,7 +446,7 @@
 		write(new File(folder, "folder.txt"), "folder");
 		try (Git git = new Git(db);
 				ByteArrayOutputStream os = new ByteArrayOutputStream();
-				DiffFormatter dfmt = new DiffFormatter(new SafeBufferedOutputStream(os));) {
+				DiffFormatter dfmt = new DiffFormatter(new BufferedOutputStream(os));) {
 			git.add().addFilepattern(".").call();
 			RevCommit commit = git.commit().setMessage("Initial commit").call();
 			write(new File(folder, "folder.txt"), "folder change");
@@ -473,7 +473,7 @@
 	@Test
 	public void testDiffNullToNull() throws Exception {
 		try (ByteArrayOutputStream os = new ByteArrayOutputStream();
-				DiffFormatter dfmt = new DiffFormatter(new SafeBufferedOutputStream(os))) {
+				DiffFormatter dfmt = new DiffFormatter(new BufferedOutputStream(os))) {
 			dfmt.setRepository(db);
 			dfmt.format((AnyObjectId) null, null);
 			dfmt.flush();
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/fnmatch/FileNameMatcherTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/fnmatch/FileNameMatcherTest.java
index 1db6c80..ba78591 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/fnmatch/FileNameMatcherTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/fnmatch/FileNameMatcherTest.java
@@ -69,7 +69,7 @@
 			final boolean appendCanMatchExpected)
 			throws InvalidPatternException {
 		final FileNameMatcher matcher = new FileNameMatcher(pattern,
-				new Character(excludedCharacter));
+				Character.valueOf(excludedCharacter));
 		matcher.append(input);
 		assertEquals(matchExpected, matcher.isMatch());
 		assertEquals(appendCanMatchExpected, matcher.canAppendMatch());
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/gitrepo/ManifestParserTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/gitrepo/ManifestParserTest.java
index 30b3df1..b1138f0 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/gitrepo/ManifestParserTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/gitrepo/ManifestParserTest.java
@@ -42,8 +42,8 @@
  */
 package org.eclipse.jgit.gitrepo;
 
-import static org.junit.Assert.assertTrue;
 import static java.nio.charset.StandardCharsets.UTF_8;
+import static org.junit.Assert.assertTrue;
 
 import java.io.ByteArrayInputStream;
 import java.util.HashSet;
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/indexdiff/IndexDiffWithSymlinkTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/indexdiff/IndexDiffWithSymlinkTest.java
new file mode 100644
index 0000000..4f3b601
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/indexdiff/IndexDiffWithSymlinkTest.java
@@ -0,0 +1,234 @@
+/*
+ * Copyright (C) 2015 Thomas Wolf <thomas.wolf@paranor.ch>
+ *
+ * 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.indexdiff;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeTrue;
+
+import java.io.BufferedOutputStream;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.Writer;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Collections;
+
+import org.eclipse.jgit.junit.LocalDiskRepositoryTestCase;
+import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.IndexDiff;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.storage.file.FileRepositoryBuilder;
+import org.eclipse.jgit.treewalk.FileTreeIterator;
+import org.eclipse.jgit.treewalk.WorkingTreeIterator;
+import org.eclipse.jgit.treewalk.filter.PathFilterGroup;
+import org.eclipse.jgit.util.FS;
+import org.eclipse.jgit.util.SystemReader;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * MacOS-only test for dealing with symlinks in IndexDiff. Recreates using cgit
+ * a test repository prepared with git 2.2.1 on MacOS 10.7.5 containing some
+ * symlinks. Examines a symlink pointing to a file named "äéü.txt" (should be
+ * encoded as UTF-8 NFC), changes it through Java, examines it again to verify
+ * it's been changed to UTF-8 NFD, and finally calculates an IndexDiff.
+ */
+public class IndexDiffWithSymlinkTest extends LocalDiskRepositoryTestCase {
+
+	private static final String FILEREPO = "filerepo";
+
+	private static final String TESTFOLDER = "testfolder";
+
+	private static final String TESTTARGET = "äéü.txt";
+
+	private static final String TESTLINK = "aeu.txt";
+
+	private static final byte[] NFC = // "äéü.txt" in NFC
+	{ -61, -92, -61, -87, -61, -68, 46, 116, 120, 116 };
+
+	private static final byte[] NFD = // "äéü.txt" in NFD
+	{ 97, -52, -120, 101, -52, -127, 117, -52, -120, 46, 116, 120, 116 };
+
+	private File testRepoDir;
+
+	@Override
+	@Before
+	public void setUp() throws Exception {
+		assumeTrue(SystemReader.getInstance().isMacOS()
+				&& FS.DETECTED.supportsSymlinks());
+		super.setUp();
+		File testDir = createTempDirectory(this.getClass().getSimpleName());
+		InputStream in = this.getClass().getClassLoader().getResourceAsStream(
+				this.getClass().getPackage().getName().replace('.', '/') + '/'
+						+ FILEREPO + ".txt");
+		assertNotNull("Test repo file not found", in);
+		try {
+			testRepoDir = restoreGitRepo(in, testDir, FILEREPO);
+		} finally {
+			in.close();
+		}
+	}
+
+	private File restoreGitRepo(InputStream in, File testDir, String name)
+			throws Exception {
+		File exportedTestRepo = new File(testDir, name + ".txt");
+		copy(in, exportedTestRepo);
+		// Use CGit to restore
+		File restoreScript = new File(testDir, name + ".sh");
+		try (OutputStream out = new BufferedOutputStream(
+				new FileOutputStream(restoreScript));
+				Writer writer = new OutputStreamWriter(out,
+						StandardCharsets.UTF_8)) {
+			writer.write("echo `which git` 1>&2\n");
+			writer.write("echo `git --version` 1>&2\n");
+			writer.write("git init " + name + " && \\\n");
+			writer.write("cd ./" + name + " && \\\n");
+			writer.write("git fast-import < ../" + name + ".txt && \\\n");
+			writer.write("git checkout -f\n");
+		}
+		String[] cmd = { "/bin/sh", "./" + name + ".sh" };
+		int exitCode;
+		String stdErr;
+		Process process = Runtime.getRuntime().exec(cmd, null, testDir);
+		try (InputStream stdOutStream = process.getInputStream();
+				InputStream stdErrStream = process.getErrorStream();
+				OutputStream stdInStream = process.getOutputStream()) {
+			readStream(stdOutStream);
+			stdErr = readStream(stdErrStream);
+			process.waitFor();
+			exitCode = process.exitValue();
+		}
+		if (exitCode != 0) {
+			fail("cgit repo restore returned " + exitCode + '\n' + stdErr);
+		}
+		return new File(new File(testDir, name), Constants.DOT_GIT);
+	}
+
+	private void copy(InputStream from, File to) throws IOException {
+		try (OutputStream out = new FileOutputStream(to)) {
+			byte[] buffer = new byte[4096];
+			int n;
+			while ((n = from.read(buffer)) > 0) {
+				out.write(buffer, 0, n);
+			}
+		}
+	}
+
+	private String readStream(InputStream stream) throws IOException {
+		try (BufferedReader in = new BufferedReader(
+				new InputStreamReader(stream))) {
+			StringBuilder out = new StringBuilder();
+			String line;
+			while ((line = in.readLine()) != null) {
+				out.append(line).append('\n');
+			}
+			return out.toString();
+		}
+	}
+
+	@Test
+	public void testSymlinkWithEncodingDifference() throws Exception {
+		try (Repository testRepo = FileRepositoryBuilder.create(testRepoDir)) {
+			File workingTree = testRepo.getWorkTree();
+			File symLink = new File(new File(workingTree, TESTFOLDER),
+					TESTLINK);
+			// Read the symlink as it was created by cgit
+			Path linkTarget = Files.readSymbolicLink(symLink.toPath());
+			assertEquals("Unexpected link target", TESTTARGET,
+					linkTarget.toString());
+			byte[] raw = rawPath(linkTarget);
+			if (raw != null) {
+				assertArrayEquals("Expected an NFC link target", NFC, raw);
+			}
+			// Now re-create that symlink through Java
+			assertTrue("Could not delete symlink", symLink.delete());
+			Files.createSymbolicLink(symLink.toPath(), Paths.get(TESTTARGET));
+			// Read it again
+			linkTarget = Files.readSymbolicLink(symLink.toPath());
+			assertEquals("Unexpected link target", TESTTARGET,
+					linkTarget.toString());
+			raw = rawPath(linkTarget);
+			if (raw != null) {
+				assertArrayEquals("Expected an NFD link target", NFD, raw);
+			}
+			// Do the indexdiff
+			WorkingTreeIterator iterator = new FileTreeIterator(testRepo);
+			IndexDiff diff = new IndexDiff(testRepo, Constants.HEAD, iterator);
+			diff.setFilter(PathFilterGroup.createFromStrings(
+					Collections.singleton(TESTFOLDER + '/' + TESTLINK)));
+			diff.diff();
+			// We're testing that this does NOT throw "EOFException: Short read
+			// of block." The diff will not report any modified files -- the
+			// link modification is not visible to JGit, which always works with
+			// the Java internal NFC encoding. CGit does report the link as an
+			// unstaged modification here, though.
+		}
+	}
+
+	private byte[] rawPath(Path p) {
+		try {
+			Method method = p.getClass().getDeclaredMethod("asByteArray");
+			if (method != null) {
+				method.setAccessible(true);
+				return (byte[]) method.invoke(p);
+			}
+		} catch (NoSuchMethodException | IllegalAccessException
+				| IllegalArgumentException | InvocationTargetException e) {
+			// Ignore and fall through.
+		}
+		return null;
+	}
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsBlockCacheConfigTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsBlockCacheConfigTest.java
new file mode 100644
index 0000000..e612061
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsBlockCacheConfigTest.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2016, Philipp Marx <philippmarx@gmx.de> and
+ * other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v1.0 which accompanies this
+ * distribution, is reproduced below, and is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.internal.storage.dfs;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.is;
+
+import org.eclipse.jgit.internal.JGitText;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+public class DfsBlockCacheConfigTest {
+
+	@Rule
+	public ExpectedException thrown = ExpectedException.none();
+
+	@Test
+	public void blockSizeNotPowerOfTwoExpectsException() {
+		thrown.expect(IllegalArgumentException.class);
+		thrown.expectMessage(is(JGitText.get().blockSizeNotPowerOf2));
+
+		new DfsBlockCacheConfig().setBlockSize(1000);
+	}
+
+	@Test
+	@SuppressWarnings("boxing")
+	public void negativeBlockSizeIsConvertedToDefault() {
+		DfsBlockCacheConfig config = new DfsBlockCacheConfig();
+		config.setBlockSize(-1);
+
+		assertThat(config.getBlockSize(), is(512));
+	}
+
+	@Test
+	@SuppressWarnings("boxing")
+	public void tooSmallBlockSizeIsConvertedToDefault() {
+		DfsBlockCacheConfig config = new DfsBlockCacheConfig();
+		config.setBlockSize(10);
+
+		assertThat(config.getBlockSize(), is(512));
+	}
+
+	@Test
+	@SuppressWarnings("boxing")
+	public void validBlockSize() {
+		DfsBlockCacheConfig config = new DfsBlockCacheConfig();
+		config.setBlockSize(65536);
+
+		assertThat(config.getBlockSize(), is(65536));
+	}
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/AbbreviationTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/AbbreviationTest.java
index 9875403..ece8f67 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/AbbreviationTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/AbbreviationTest.java
@@ -50,6 +50,7 @@
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
+import java.io.BufferedOutputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.File;
 import java.io.FileOutputStream;
@@ -60,9 +61,6 @@
 import java.util.List;
 
 import org.eclipse.jgit.errors.AmbiguousObjectException;
-import org.eclipse.jgit.internal.storage.file.FileRepository;
-import org.eclipse.jgit.internal.storage.file.PackIndexWriter;
-import org.eclipse.jgit.internal.storage.file.PackIndexWriterV2;
 import org.eclipse.jgit.junit.LocalDiskRepositoryTestCase;
 import org.eclipse.jgit.junit.TestRepository;
 import org.eclipse.jgit.lib.AbbreviatedObjectId;
@@ -72,7 +70,6 @@
 import org.eclipse.jgit.revwalk.RevBlob;
 import org.eclipse.jgit.transport.PackedObjectInfo;
 import org.eclipse.jgit.util.FileUtils;
-import org.eclipse.jgit.util.io.SafeBufferedOutputStream;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
@@ -183,13 +180,10 @@
 		File idxFile = new File(packDir, packName + ".idx");
 		File packFile = new File(packDir, packName + ".pack");
 		FileUtils.mkdir(packDir, true);
-		OutputStream dst = new SafeBufferedOutputStream(new FileOutputStream(
-				idxFile));
-		try {
+		try (OutputStream dst = new BufferedOutputStream(
+				new FileOutputStream(idxFile))) {
 			PackIndexWriter writer = new PackIndexWriterV2(dst);
 			writer.write(objects, new byte[OBJECT_ID_LENGTH]);
-		} finally {
-			dst.close();
 		}
 		new FileOutputStream(packFile).close();
 
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/AutoGcTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/AutoGcTest.java
new file mode 100644
index 0000000..56994a6
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/AutoGcTest.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2016, Matthias Sohn <matthias.sohn@sap.com>
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ *   copyright notice, this list of conditions and the following
+ *   disclaimer in the documentation and/or other materials provided
+ *   with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ *   names of its contributors may be used to endorse or promote
+ *   products derived from this software without specific prior
+ *   written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.eclipse.jgit.internal.storage.file;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import org.eclipse.jgit.lib.ConfigConstants;
+import org.eclipse.jgit.storage.file.FileBasedConfig;
+import org.eclipse.jgit.test.resources.SampleDataRepositoryTestCase;
+import org.junit.Test;
+
+public class AutoGcTest extends GcTestCase {
+
+	@Test
+	public void testNotTooManyLooseObjects() {
+		assertFalse("should not find too many loose objects",
+				gc.tooManyLooseObjects());
+	}
+
+	@Test
+	public void testTooManyLooseObjects() throws Exception {
+		FileBasedConfig c = repo.getConfig();
+		c.setInt(ConfigConstants.CONFIG_GC_SECTION, null,
+				ConfigConstants.CONFIG_KEY_AUTO, 255);
+		c.save();
+		commitChain(10, 50);
+		assertTrue("should find too many loose objects",
+				gc.tooManyLooseObjects());
+	}
+
+	@Test
+	public void testNotTooManyPacks() {
+		assertFalse("should not find too many packs", gc.tooManyPacks());
+	}
+
+	@Test
+	public void testTooManyPacks() throws Exception {
+		FileBasedConfig c = repo.getConfig();
+		c.setInt(ConfigConstants.CONFIG_GC_SECTION, null,
+				ConfigConstants.CONFIG_KEY_AUTOPACKLIMIT, 1);
+		c.save();
+		SampleDataRepositoryTestCase.copyCGitTestPacks(repo);
+
+		assertTrue("should find too many packs", gc.tooManyPacks());
+	}
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/ConcurrentRepackTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/ConcurrentRepackTest.java
index 9d7a482..1d71cb3 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/ConcurrentRepackTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/ConcurrentRepackTest.java
@@ -51,6 +51,7 @@
 import static org.junit.Assert.assertNotSame;
 import static org.junit.Assert.fail;
 
+import java.io.BufferedOutputStream;
 import java.io.File;
 import java.io.FileOutputStream;
 import java.io.IOException;
@@ -71,7 +72,6 @@
 import org.eclipse.jgit.revwalk.RevWalk;
 import org.eclipse.jgit.storage.file.WindowCacheConfig;
 import org.eclipse.jgit.util.FileUtils;
-import org.eclipse.jgit.util.io.SafeBufferedOutputStream;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
@@ -235,20 +235,15 @@
 			throws IOException {
 		final long begin = files[0].getParentFile().lastModified();
 		NullProgressMonitor m = NullProgressMonitor.INSTANCE;
-		OutputStream out;
 
-		out = new SafeBufferedOutputStream(new FileOutputStream(files[0]));
-		try {
+		try (OutputStream out = new BufferedOutputStream(
+				new FileOutputStream(files[0]))) {
 			pw.writePack(m, m, out);
-		} finally {
-			out.close();
 		}
 
-		out = new SafeBufferedOutputStream(new FileOutputStream(files[1]));
-		try {
+		try (OutputStream out = new BufferedOutputStream(
+				new FileOutputStream(files[1]))) {
 			pw.writeIndex(out);
-		} finally {
-			out.close();
 		}
 
 		touch(begin, files[0].getParentFile());
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/DescriptionTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/DescriptionTest.java
new file mode 100644
index 0000000..73bd35b
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/DescriptionTest.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2016, Google Inc.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ *   copyright notice, this list of conditions and the following
+ *   disclaimer in the documentation and/or other materials provided
+ *   with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ *   names of its contributors may be used to endorse or promote
+ *   products derived from this software without specific prior
+ *   written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.internal.storage.file;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+import java.io.File;
+import java.io.IOException;
+
+import org.eclipse.jgit.junit.LocalDiskRepositoryTestCase;
+import org.eclipse.jgit.lib.Repository;
+import org.junit.Test;
+
+/** Test managing the gitweb description file. */
+public class DescriptionTest extends LocalDiskRepositoryTestCase {
+	private static final String UNCONFIGURED = "Unnamed repository; edit this file to name it for gitweb.";
+
+	@Test
+	public void description() throws IOException {
+		Repository git = createBareRepository();
+		File path = new File(git.getDirectory(), "description");
+		assertNull("description", git.getGitwebDescription());
+
+		String desc = "a test repo\nfor jgit";
+		git.setGitwebDescription(desc);
+		assertEquals(desc + '\n', read(path));
+		assertEquals(desc, git.getGitwebDescription());
+
+		git.setGitwebDescription(null);
+		assertEquals("", read(path));
+
+		desc = "foo";
+		git.setGitwebDescription(desc);
+		assertEquals(desc + '\n', read(path));
+		assertEquals(desc, git.getGitwebDescription());
+
+		git.setGitwebDescription("");
+		assertEquals("", read(path));
+
+		git.setGitwebDescription(UNCONFIGURED);
+		assertEquals(UNCONFIGURED + '\n', read(path));
+		assertNull("description", git.getGitwebDescription());
+	}
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/FileSnapshotTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/FileSnapshotTest.java
index 902416b..98a9501 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/FileSnapshotTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/FileSnapshotTest.java
@@ -42,7 +42,6 @@
  */
 package org.eclipse.jgit.internal.storage.file;
 
-import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 
 import java.io.File;
@@ -51,7 +50,6 @@
 import java.util.ArrayList;
 import java.util.List;
 
-import org.eclipse.jgit.internal.storage.file.FileSnapshot;
 import org.eclipse.jgit.util.FileUtils;
 import org.junit.After;
 import org.junit.Before;
@@ -99,22 +97,6 @@
 	}
 
 	/**
-	 * Create a file, wait long enough and verify that it has not been modified.
-	 * 3.5 seconds mean any difference between file system timestamp and system
-	 * clock should be significant.
-	 *
-	 * @throws Exception
-	 */
-	@Test
-	public void testOldFile() throws Exception {
-		File f1 = createFile("oldfile");
-		waitNextSec(f1);
-		FileSnapshot save = FileSnapshot.save(f1);
-		Thread.sleep(3500);
-		assertFalse(save.isModified(f1));
-	}
-
-	/**
 	 * Create a file, but don't wait long enough for the difference between file
 	 * system clock and system clock to be significant. Assume the file may have
 	 * been modified. It may have been, but the clock alone cannot determine
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcOrphanFilesTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcOrphanFilesTest.java
new file mode 100644
index 0000000..d9317b8
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcOrphanFilesTest.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2017 Ericsson
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ *   copyright notice, this list of conditions and the following
+ *   disclaimer in the documentation and/or other materials provided
+ *   with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ *   names of its contributors may be used to endorse or promote
+ *   products derived from this software without specific prior
+ *   written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.internal.storage.file;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.io.File;
+import java.io.IOException;
+
+import org.junit.Before;
+import org.junit.Test;
+
+public class GcOrphanFilesTest extends GcTestCase {
+	private final static String PACK = "pack";
+
+	private final static String BITMAP_File_1 = PACK + "-1.bitmap";
+
+	private final static String IDX_File_2 = PACK + "-2.idx";
+
+	private final static String IDX_File_malformed = PACK + "-1234idx";
+
+	private final static String PACK_File_2 = PACK + "-2.pack";
+
+	private final static String PACK_File_3 = PACK + "-3.pack";
+
+	private File packDir;
+
+	@Before
+	public void setUp() throws Exception {
+		super.setUp();
+		packDir = new File(repo.getObjectsDirectory(), PACK);
+	}
+
+	@Test
+	public void bitmapAndIdxDeletedButPackNot() throws Exception {
+		createFileInPackFolder(BITMAP_File_1);
+		createFileInPackFolder(IDX_File_2);
+		createFileInPackFolder(PACK_File_3);
+		gc.gc();
+		assertFalse(new File(packDir, BITMAP_File_1).exists());
+		assertFalse(new File(packDir, IDX_File_2).exists());
+		assertTrue(new File(packDir, PACK_File_3).exists());
+	}
+
+	@Test
+	public void bitmapDeletedButIdxAndPackNot() throws Exception {
+		createFileInPackFolder(BITMAP_File_1);
+		createFileInPackFolder(IDX_File_2);
+		createFileInPackFolder(PACK_File_2);
+		createFileInPackFolder(PACK_File_3);
+		gc.gc();
+		assertFalse(new File(packDir, BITMAP_File_1).exists());
+		assertTrue(new File(packDir, IDX_File_2).exists());
+		assertTrue(new File(packDir, PACK_File_2).exists());
+		assertTrue(new File(packDir, PACK_File_3).exists());
+	}
+
+	@Test
+	public void malformedIdxNotDeleted() throws Exception {
+		createFileInPackFolder(IDX_File_malformed);
+		gc.gc();
+		assertTrue(new File(packDir, IDX_File_malformed).exists());
+	}
+
+	private void createFileInPackFolder(String fileName) throws IOException {
+		if (!packDir.exists() || !packDir.isDirectory()) {
+			assertTrue(packDir.mkdirs());
+		}
+		assertTrue(new File(packDir, fileName).createNewFile());
+	}
+
+	@Test
+	public void noSuchPackFolder() throws Exception {
+		assertTrue(packDir.delete());
+		gc.gc();
+	}
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcTestCase.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcTestCase.java
index e463285..90c1152 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcTestCase.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcTestCase.java
@@ -105,6 +105,46 @@
 		return tip;
 	}
 
+	/**
+	 * Create a chain of commits of given depth with given number of added files
+	 * per commit.
+	 * <p>
+	 * Each commit contains {@code files} files as its content. The created
+	 * commit chain is referenced from any ref.
+	 * <p>
+	 * A chain will create {@code (2 + files) * depth} objects in Gits object
+	 * database. For each depth level the following objects are created: the
+	 * commit object, the top-level tree object and @code files} blobs for the
+	 * content of the file "a".
+	 *
+	 * @param depth
+	 *            the depth of the commit chain.
+	 * @param width
+	 *            number of files added per commit
+	 * @return the commit that is the tip of the commit chain
+	 * @throws Exception
+	 */
+	protected RevCommit commitChain(int depth, int width) throws Exception {
+		if (depth <= 0) {
+			throw new IllegalArgumentException("Chain depth must be > 0");
+		}
+		if (width <= 0) {
+			throw new IllegalArgumentException("Number of files per commit must be > 0");
+		}
+		CommitBuilder cb = tr.commit();
+		RevCommit tip = null;
+		do {
+			--depth;
+			for (int i=0; i < width; i++) {
+				String id = depth + "-" + i;
+				cb.add("a" + id, id).message(id);
+			}
+			tip = cb.create();
+			cb = cb.child();
+		} while (depth > 0);
+		return tip;
+	}
+
 	protected long lastModified(AnyObjectId objectId) throws IOException {
 		return repo.getFS().lastModified(
 				repo.getObjectDatabase().fileFor(objectId));
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/InflatingBitSetTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/InflatingBitSetTest.java
index 465c61b..2124b80 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/InflatingBitSetTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/InflatingBitSetTest.java
@@ -46,11 +46,10 @@
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 
-import com.googlecode.javaewah.EWAHCompressedBitmap;
-
-import org.eclipse.jgit.internal.storage.file.InflatingBitSet;
 import org.junit.Test;
 
+import com.googlecode.javaewah.EWAHCompressedBitmap;
+
 public class InflatingBitSetTest {
 
 	@Test
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/LockFileTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/LockFileTest.java
index f1bc7c8..3bfd047 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/LockFileTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/LockFileTest.java
@@ -49,7 +49,6 @@
 import org.eclipse.jgit.api.Git;
 import org.eclipse.jgit.api.errors.JGitInternalException;
 import org.eclipse.jgit.errors.LockFailedException;
-import org.eclipse.jgit.internal.storage.file.LockFile;
 import org.eclipse.jgit.junit.RepositoryTestCase;
 import org.eclipse.jgit.revwalk.RevCommit;
 import org.junit.Test;
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 923f283..87554ae 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
@@ -42,6 +42,11 @@
 
 package org.eclipse.jgit.internal.storage.file;
 
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.io.File;
+import java.io.FilenameFilter;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.concurrent.Callable;
@@ -49,10 +54,13 @@
 import java.util.concurrent.Executors;
 import java.util.concurrent.Future;
 
-import org.eclipse.jgit.internal.storage.file.ObjectDirectory;
 import org.eclipse.jgit.junit.RepositoryTestCase;
+import org.eclipse.jgit.lib.ConfigConstants;
 import org.eclipse.jgit.lib.Constants;
 import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.revwalk.RevCommit;
+import org.eclipse.jgit.storage.file.FileBasedConfig;
+import org.junit.Assume;
 import org.junit.Test;
 
 public class ObjectDirectoryTest extends RepositoryTestCase {
@@ -69,6 +77,100 @@
 		}
 	}
 
+	/**
+	 * Test packfile scanning while a gc is done from the outside (different
+	 * process or different Repository instance). This situation occurs e.g. if
+	 * a gerrit server is serving fetch requests while native git is doing a
+	 * garbage collection. The test shows that when core.trustfolderstat==true
+	 * jgit may miss to detect that a new packfile was created. This situation
+	 * is persistent until a new full rescan of the pack directory is triggered.
+	 *
+	 * The test works with two Repository instances working on the same disk
+	 * location. One (db) for all write operations (creating commits, doing gc)
+	 * and another one (receivingDB) which just reads and which in the end shows
+	 * the bug
+	 *
+	 * @throws Exception
+	 */
+	@Test
+	public void testScanningForPackfiles() throws Exception {
+		ObjectId unknownID = ObjectId
+				.fromString("c0ffee09d0b63d694bf49bc1e6847473f42d4a8c");
+		GC gc = new GC(db);
+		gc.setExpireAgeMillis(0);
+		gc.setPackExpireAgeMillis(0);
+
+		// the default repo db is used to create the objects. The receivingDB
+		// repo is used to trigger gc's
+		try (FileRepository receivingDB = new FileRepository(
+				db.getDirectory())) {
+			// set trustfolderstat to true. If set to false the test always
+			// succeeds.
+			FileBasedConfig cfg = receivingDB.getConfig();
+			cfg.setBoolean(ConfigConstants.CONFIG_CORE_SECTION, null,
+					ConfigConstants.CONFIG_KEY_TRUSTFOLDERSTAT, true);
+			cfg.save();
+
+			// setup a repo which has at least one pack file and trigger
+			// scanning of the packs directory
+			ObjectId id = commitFile("file.txt", "test", "master").getId();
+			gc.gc();
+			assertFalse(receivingDB.hasObject(unknownID));
+			assertTrue(receivingDB.getObjectDatabase().hasPackedObject(id));
+
+			// preparations
+			File packsFolder = new File(receivingDB.getObjectsDirectory(),
+					"pack");
+			// prepare creation of a temporary file in the pack folder. This
+			// simulates that a native git gc is happening starting to write
+			// temporary files but has not yet finished
+			File tmpFile = new File(packsFolder, "1.tmp");
+			RevCommit id2 = commitFile("file.txt", "test2", "master");
+			// wait until filesystem timer ticks. This raises probability that
+			// the next statements are executed in the same tick as the
+			// filesystem timer
+			fsTick(null);
+
+			// create a Temp file in the packs folder and trigger a rescan of
+			// the packs folder. This lets receivingDB think it has scanned the
+			// packs folder at the current fs timestamp t1. The following gc
+			// will create new files which have the same timestamp t1 but this
+			// will not update the mtime of the packs folder. Because of that
+			// 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));
+
+			// trigger a gc. This will create packfiles which have likely the
+			// same mtime than the packfolder
+			gc.gc();
+
+			// To deal with racy-git situations JGit's Filesnapshot class will
+			// report a file/folder potentially dirty if
+			// cachedLastReadTime-cachedLastModificationTime < 2500ms. This
+			// causes JGit to always rescan a file after modification. But:
+			// this was true only if the difference between current system time
+			// and cachedLastModification time was less than 2500ms. If the
+			// modification is more than 2500ms ago we may have reported a
+			// file/folder to be clean although it has not been rescanned. A
+			// Bug. To show the bug we sleep for more than 2500ms
+			Thread.sleep(2600);
+
+			File[] ret = packsFolder.listFiles(new FilenameFilter() {
+				@Override
+				public boolean accept(File dir, String name) {
+					return name.endsWith(".pack");
+				}
+			});
+			assertTrue(ret.length == 1);
+			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));
+		}
+	}
+
 	private Collection<Callable<ObjectId>> blobInsertersForTheSameFanOutDir(
 			final ObjectDirectory dir) {
 		Callable<ObjectId> callable = new Callable<ObjectId>() {
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackFileTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackFileTest.java
index ba07d68..1c10bb3 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackFileTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackFileTest.java
@@ -310,6 +310,27 @@
 		}
 	}
 
+	@Test
+	public void testConfigurableStreamFileThreshold() throws Exception {
+		byte[] data = getRng().nextBytes(300);
+		RevBlob id = tr.blob(data);
+		tr.branch("master").commit().add("A", id).create();
+		tr.packAndPrune();
+		assertTrue("has blob", wc.has(id));
+
+		ObjectLoader ol = wc.open(id);
+		ObjectStream in = ol.openStream();
+		assertTrue(in instanceof ObjectStream.SmallStream);
+		assertEquals(300, in.available());
+		in.close();
+
+		wc.setStreamFileThreshold(299);
+		ol = wc.open(id);
+		in = ol.openStream();
+		assertTrue(in instanceof ObjectStream.Filter);
+		assertEquals(1, in.available());
+	}
+
 	private static byte[] clone(int first, byte[] base) {
 		byte[] r = new byte[base.length];
 		System.arraycopy(base, 1, r, 1, r.length - 1);
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackIndexTestCase.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackIndexTestCase.java
index 7eeb0c0..b6aa4bc 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackIndexTestCase.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackIndexTestCase.java
@@ -52,7 +52,6 @@
 import java.util.NoSuchElementException;
 
 import org.eclipse.jgit.errors.MissingObjectException;
-import org.eclipse.jgit.internal.storage.file.PackIndex;
 import org.eclipse.jgit.internal.storage.file.PackIndex.MutableEntry;
 import org.eclipse.jgit.junit.RepositoryTestCase;
 import org.junit.Test;
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackReverseIndexTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackReverseIndexTest.java
index 2126cac..a4aa8bc 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackReverseIndexTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackReverseIndexTest.java
@@ -50,8 +50,6 @@
 import static org.junit.Assert.fail;
 
 import org.eclipse.jgit.errors.CorruptObjectException;
-import org.eclipse.jgit.internal.storage.file.PackIndex;
-import org.eclipse.jgit.internal.storage.file.PackReverseIndex;
 import org.eclipse.jgit.internal.storage.file.PackIndex.MutableEntry;
 import org.eclipse.jgit.junit.JGitTestUtil;
 import org.eclipse.jgit.junit.RepositoryTestCase;
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackWriterTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackWriterTest.java
index 3cb4c39..2e57952 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackWriterTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackWriterTest.java
@@ -43,13 +43,13 @@
 
 package org.eclipse.jgit.internal.storage.file;
 
+import static org.eclipse.jgit.internal.storage.pack.PackWriter.NONE;
 import static org.eclipse.jgit.lib.Constants.OBJ_BLOB;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
-import static org.eclipse.jgit.internal.storage.pack.PackWriter.NONE;
 
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
@@ -75,8 +75,8 @@
 import org.eclipse.jgit.lib.ObjectId;
 import org.eclipse.jgit.lib.ObjectIdSet;
 import org.eclipse.jgit.lib.ObjectInserter;
-import org.eclipse.jgit.lib.Sets;
 import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.lib.Sets;
 import org.eclipse.jgit.revwalk.DepthWalk;
 import org.eclipse.jgit.revwalk.ObjectWalk;
 import org.eclipse.jgit.revwalk.RevBlob;
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 ef5dfcd..5999acf 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
@@ -73,8 +73,8 @@
 import org.eclipse.jgit.junit.TestRepository;
 import org.eclipse.jgit.lib.AnyObjectId;
 import org.eclipse.jgit.lib.BatchRefUpdate;
-import org.eclipse.jgit.lib.ProgressMonitor;
 import org.eclipse.jgit.lib.NullProgressMonitor;
+import org.eclipse.jgit.lib.ProgressMonitor;
 import org.eclipse.jgit.lib.Ref;
 import org.eclipse.jgit.lib.Ref.Storage;
 import org.eclipse.jgit.lib.RefDatabase;
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/T0003_BasicTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/T0003_BasicTest.java
index b6ad22b..ae1e531 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/T0003_BasicTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/T0003_BasicTest.java
@@ -82,9 +82,13 @@
 import org.eclipse.jgit.storage.file.FileRepositoryBuilder;
 import org.eclipse.jgit.test.resources.SampleDataRepositoryTestCase;
 import org.eclipse.jgit.util.FileUtils;
+import org.junit.Rule;
 import org.junit.Test;
+import org.junit.rules.ExpectedException;
 
 public class T0003_BasicTest extends SampleDataRepositoryTestCase {
+	@Rule
+	public ExpectedException expectedException = ExpectedException.none();
 
 	@Test
 	public void test001_Initalize() {
@@ -326,6 +330,17 @@
 	}
 
 	@Test
+	public void test002_CreateBadTree() throws Exception {
+		// We won't create a tree entry with an empty filename
+		//
+		expectedException.expect(IllegalArgumentException.class);
+		expectedException.expectMessage(JGitText.get().invalidTreeZeroLengthName);
+		final TreeFormatter formatter = new TreeFormatter();
+		formatter.append("", FileMode.TREE,
+				ObjectId.fromString("4b825dc642cb6eb9a060e54bf8d69288fbee4904"));
+	}
+
+	@Test
 	public void test006_ReadUglyConfig() throws IOException,
 			ConfigInvalidException {
 		final File cfg = new File(db.getDirectory(), Constants.CONFIG);
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/pack/DeltaIndexTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/pack/DeltaIndexTest.java
index bb94a37..640203d 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/pack/DeltaIndexTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/pack/DeltaIndexTest.java
@@ -51,9 +51,6 @@
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 
-import org.eclipse.jgit.internal.storage.pack.BinaryDelta;
-import org.eclipse.jgit.internal.storage.pack.DeltaEncoder;
-import org.eclipse.jgit.internal.storage.pack.DeltaIndex;
 import org.eclipse.jgit.junit.JGitTestUtil;
 import org.eclipse.jgit.junit.TestRng;
 import org.eclipse.jgit.lib.Constants;
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/pack/GcCommitSelectionTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/pack/GcCommitSelectionTest.java
index 49e1f6f..20b8c51 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/pack/GcCommitSelectionTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/pack/GcCommitSelectionTest.java
@@ -55,8 +55,6 @@
 
 import org.eclipse.jgit.internal.storage.file.GcTestCase;
 import org.eclipse.jgit.internal.storage.file.PackBitmapIndexBuilder;
-import org.eclipse.jgit.internal.storage.pack.ObjectToPack;
-import org.eclipse.jgit.internal.storage.pack.PackWriterBitmapPreparer;
 import org.eclipse.jgit.internal.storage.pack.PackWriterBitmapPreparer.BitmapCommit;
 import org.eclipse.jgit.junit.TestRepository.BranchBuilder;
 import org.eclipse.jgit.junit.TestRepository.CommitBuilder;
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ConstantsEncodingTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ConstantsEncodingTest.java
index 4db6f6d..5c2fddd 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ConstantsEncodingTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ConstantsEncodingTest.java
@@ -48,6 +48,7 @@
 import static org.junit.Assert.fail;
 
 import java.io.UnsupportedEncodingException;
+
 import org.junit.Test;
 
 public class ConstantsEncodingTest {
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/DirCacheCheckoutMaliciousPathTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/DirCacheCheckoutMaliciousPathTest.java
index 59a4699..32a1ec9 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/DirCacheCheckoutMaliciousPathTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/DirCacheCheckoutMaliciousPathTest.java
@@ -366,7 +366,9 @@
 			insertId = blobId;
 			for (int i = path.length - 1; i >= 0; --i) {
 				TreeFormatter treeFormatter = new TreeFormatter();
-				treeFormatter.append(path[i], mode, insertId);
+				treeFormatter.append(path[i].getBytes(), 0,
+							path[i].getBytes().length,
+							mode, insertId, true);
 				insertId = newObjectInserter.insert(treeFormatter);
 				mode = FileMode.TREE;
 			}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ObjectIdTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ObjectIdTest.java
index 2198b87..80ece1c 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ObjectIdTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ObjectIdTest.java
@@ -50,7 +50,6 @@
 import static org.junit.Assert.assertTrue;
 
 import org.eclipse.jgit.errors.InvalidObjectIdException;
-
 import org.junit.Test;
 
 public class ObjectIdTest {
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/MergeMessageFormatterTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/MergeMessageFormatterTest.java
index 6c90f7d..f271544 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/MergeMessageFormatterTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/MergeMessageFormatterTest.java
@@ -50,9 +50,9 @@
 import org.eclipse.jgit.lib.ObjectId;
 import org.eclipse.jgit.lib.ObjectIdRef;
 import org.eclipse.jgit.lib.Ref;
-import org.eclipse.jgit.lib.SymbolicRef;
 import org.eclipse.jgit.lib.Ref.Storage;
 import org.eclipse.jgit.lib.RefUpdate;
+import org.eclipse.jgit.lib.SymbolicRef;
 import org.eclipse.jgit.test.resources.SampleDataRepositoryTestCase;
 import org.junit.Before;
 import org.junit.Test;
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/patch/PatchCcErrorTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/patch/PatchCcErrorTest.java
index 962e818..e4b4317 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/patch/PatchCcErrorTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/patch/PatchCcErrorTest.java
@@ -44,7 +44,6 @@
 package org.eclipse.jgit.patch;
 
 import static java.lang.Integer.valueOf;
-import static java.lang.Long.valueOf;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertSame;
 import static org.junit.Assert.assertTrue;
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/FooterLineTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/FooterLineTest.java
index fbd5127..87c8547 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/FooterLineTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/FooterLineTest.java
@@ -48,6 +48,7 @@
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
+
 import java.io.IOException;
 import java.util.List;
 
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/ObjectWalkFilterTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/ObjectWalkFilterTest.java
index 55117b7..75ac561 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/ObjectWalkFilterTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/ObjectWalkFilterTest.java
@@ -46,22 +46,20 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
+import java.io.IOException;
+import java.util.Set;
 
 import org.eclipse.jgit.internal.storage.dfs.DfsRepositoryDescription;
 import org.eclipse.jgit.internal.storage.dfs.InMemoryRepository;
 import org.eclipse.jgit.junit.TestRepository;
 import org.eclipse.jgit.lib.AnyObjectId;
 import org.eclipse.jgit.lib.Sets;
-import org.eclipse.jgit.revwalk.ObjectWalk;
 import org.eclipse.jgit.revwalk.filter.MessageRevFilter;
 import org.eclipse.jgit.revwalk.filter.NotRevFilter;
 import org.eclipse.jgit.revwalk.filter.ObjectFilter;
-
-import java.io.IOException;
-import java.util.Set;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
 
 public class ObjectWalkFilterTest {
 	private TestRepository<InMemoryRepository> tr;
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkMergeBaseTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkMergeBaseTest.java
index b5d4909..2451c50 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkMergeBaseTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkMergeBaseTest.java
@@ -146,4 +146,29 @@
 		assertCommit(b, rw.next());
 		assertNull(rw.next());
 	}
-}
+
+	@Test
+	public void testInconsistentCommitTimes() throws Exception {
+		// When commit times are inconsistent (a parent is younger than a child)
+		// make sure that not both, parent and child, are reported as merge
+		// base. In the following repo the merge base between C,D should be B.
+		// But when A is younger than B the MergeBaseGenerator used to generate
+		// A before it detected that B is also a merge base.
+		//
+		//   +---C
+		//  /   /
+		// A---B---D
+
+		final RevCommit a = commit(2);
+		final RevCommit b = commit(-1, a);
+		final RevCommit c = commit(2, b, a);
+		final RevCommit d = commit(1, b);
+
+		rw.setRevFilter(RevFilter.MERGE_BASE);
+		markStart(d);
+		markStart(c);
+		assertCommit(b, rw.next());
+		assertNull(rw.next());
+	}
+
+}
\ No newline at end of file
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/test/resources/SampleDataRepositoryTestCase.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/test/resources/SampleDataRepositoryTestCase.java
index 3a3b3d8..a57ef40 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/test/resources/SampleDataRepositoryTestCase.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/test/resources/SampleDataRepositoryTestCase.java
@@ -47,7 +47,9 @@
 package org.eclipse.jgit.test.resources;
 
 import java.io.File;
+import java.io.IOException;
 
+import org.eclipse.jgit.internal.storage.file.FileRepository;
 import org.eclipse.jgit.junit.JGitTestUtil;
 import org.eclipse.jgit.junit.RepositoryTestCase;
 
@@ -57,7 +59,17 @@
 	@Override
 	public void setUp() throws Exception {
 		super.setUp();
+		copyCGitTestPacks(db);
+	}
 
+	/**
+	 * Copy C Git generated pack files into given repository for testing
+	 *
+	 * @param repo
+	 *            test repository to receive packfile copies
+	 * @throws IOException
+	 */
+	public static void copyCGitTestPacks(FileRepository repo) throws IOException {
 		final String[] packs = {
 				"pack-34be9032ac282b11fa9babdc2b2a93ca996c9c2f",
 				"pack-df2982f284bbabb6bdb59ee3fcc6eb0983e20371",
@@ -67,13 +79,14 @@
 				"pack-e6d07037cbcf13376308a0a995d1fa48f8f76aaa",
 				"pack-3280af9c07ee18a87705ef50b0cc4cd20266cf12"
 		};
-		final File packDir = new File(db.getObjectDatabase().getDirectory(), "pack");
+		final File packDir = new File(repo.getObjectDatabase().getDirectory(),
+				"pack");
 		for (String n : packs) {
 			JGitTestUtil.copyTestResource(n + ".pack", new File(packDir, n + ".pack"));
 			JGitTestUtil.copyTestResource(n + ".idx", new File(packDir, n + ".idx"));
 		}
 
 		JGitTestUtil.copyTestResource("packed-refs",
-				new File(db.getDirectory(), "packed-refs"));
+				new File(repo.getDirectory(), "packed-refs"));
 	}
 }
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/SideBandOutputStreamTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/SideBandOutputStreamTest.java
index d2c3a0b..4571619 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/SideBandOutputStreamTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/SideBandOutputStreamTest.java
@@ -44,7 +44,6 @@
 package org.eclipse.jgit.transport;
 
 import static java.lang.Integer.valueOf;
-import static java.lang.Long.valueOf;
 import static org.eclipse.jgit.transport.SideBandOutputStream.CH_DATA;
 import static org.eclipse.jgit.transport.SideBandOutputStream.CH_ERROR;
 import static org.eclipse.jgit.transport.SideBandOutputStream.CH_PROGRESS;
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/WalkEncryptionTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/WalkEncryptionTest.java
index ac2bfd1..cc5870e 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/WalkEncryptionTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/WalkEncryptionTest.java
@@ -576,7 +576,7 @@
 						.forName("javax.crypto.JceSecurity")
 						.getDeclaredField("isRestricted");
 				isRestricted.setAccessible(true);
-				isRestricted.set(null, new Boolean(restrictedOn));
+				isRestricted.set(null, Boolean.valueOf(restrictedOn));
 			} catch (Throwable e) {
 				logger.info(
 						"Could not setup JCE security policy restrictions.");
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FilterCommandsTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FilterCommandsTest.java
new file mode 100644
index 0000000..0d31811
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FilterCommandsTest.java
@@ -0,0 +1,251 @@
+/*
+ * Copyright (C) 2016, Christian Halstrick <christian.halstrick@sap.com>
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ *   copyright notice, this list of conditions and the following
+ *   disclaimer in the documentation and/or other materials provided
+ *   with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ *   names of its contributors may be used to endorse or promote
+ *   products derived from this software without specific prior
+ *   written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.eclipse.jgit.util;
+
+import static org.junit.Assert.assertEquals;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import org.eclipse.jgit.api.Git;
+import org.eclipse.jgit.api.errors.GitAPIException;
+import org.eclipse.jgit.attributes.FilterCommand;
+import org.eclipse.jgit.attributes.FilterCommandFactory;
+import org.eclipse.jgit.attributes.FilterCommandRegistry;
+import org.eclipse.jgit.junit.RepositoryTestCase;
+import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.RefUpdate;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.lib.StoredConfig;
+import org.eclipse.jgit.revwalk.RevCommit;
+import org.junit.Before;
+import org.junit.Test;
+
+public class FilterCommandsTest extends RepositoryTestCase {
+	private Git git;
+
+	RevCommit initialCommit;
+
+	RevCommit secondCommit;
+
+	class TestCommandFactory implements FilterCommandFactory {
+		private int prefix;
+
+		public TestCommandFactory(int prefix) {
+			this.prefix = prefix;
+		}
+
+		@Override
+		public FilterCommand create(Repository repo, InputStream in,
+				final OutputStream out) {
+			FilterCommand cmd = new FilterCommand(in, out) {
+
+				@Override
+				public int run() throws IOException {
+					int b = in.read();
+					if (b == -1) {
+						return b;
+					}
+					out.write(prefix);
+					out.write(b);
+					return 1;
+				}
+			};
+			return cmd;
+		}
+	}
+
+	@Override
+	@Before
+	public void setUp() throws Exception {
+		super.setUp();
+		git = new Git(db);
+		// commit something
+		writeTrashFile("Test.txt", "Hello world");
+		git.add().addFilepattern("Test.txt").call();
+		initialCommit = git.commit().setMessage("Initial commit").call();
+
+		// create a master branch and switch to it
+		git.branchCreate().setName("test").call();
+		RefUpdate rup = db.updateRef(Constants.HEAD);
+		rup.link("refs/heads/test");
+
+		// commit something on the test branch
+		writeTrashFile("Test.txt", "Some change");
+		git.add().addFilepattern("Test.txt").call();
+		secondCommit = git.commit().setMessage("Second commit").call();
+	}
+
+	@Test
+	public void testBuiltinCleanFilter()
+			throws IOException, GitAPIException {
+		String builtinCommandName = "jgit://builtin/test/clean";
+		FilterCommandRegistry.register(builtinCommandName,
+				new TestCommandFactory('c'));
+		StoredConfig config = git.getRepository().getConfig();
+		config.setString("filter", "test", "clean", builtinCommandName);
+		config.save();
+
+		writeTrashFile(".gitattributes", "*.txt filter=test");
+		git.add().addFilepattern(".gitattributes").call();
+		git.commit().setMessage("add filter").call();
+
+		writeTrashFile("Test.txt", "Hello again");
+		git.add().addFilepattern("Test.txt").call();
+		assertEquals(
+				"[.gitattributes, mode:100644, content:*.txt filter=test][Test.txt, mode:100644, content:cHceclclcoc cacgcacicn]",
+				indexState(CONTENT));
+
+		writeTrashFile("Test.bin", "Hello again");
+		git.add().addFilepattern("Test.bin").call();
+		assertEquals(
+				"[.gitattributes, mode:100644, content:*.txt filter=test][Test.bin, mode:100644, content:Hello again][Test.txt, mode:100644, content:cHceclclcoc cacgcacicn]",
+				indexState(CONTENT));
+
+		config.setString("filter", "test", "clean", null);
+		config.save();
+
+		git.add().addFilepattern("Test.txt").call();
+		assertEquals(
+				"[.gitattributes, mode:100644, content:*.txt filter=test][Test.bin, mode:100644, content:Hello again][Test.txt, mode:100644, content:Hello again]",
+				indexState(CONTENT));
+
+		config.setString("filter", "test", "clean", null);
+		config.save();
+	}
+
+	@Test
+	public void testBuiltinSmudgeFilter() throws IOException, GitAPIException {
+		String builtinCommandName = "jgit://builtin/test/smudge";
+		FilterCommandRegistry.register(builtinCommandName,
+				new TestCommandFactory('s'));
+		StoredConfig config = git.getRepository().getConfig();
+		config.setString("filter", "test", "smudge", builtinCommandName);
+		config.save();
+
+		writeTrashFile(".gitattributes", "*.txt filter=test");
+		git.add().addFilepattern(".gitattributes").call();
+		git.commit().setMessage("add filter").call();
+
+		writeTrashFile("Test.txt", "Hello again");
+		git.add().addFilepattern("Test.txt").call();
+		assertEquals(
+				"[.gitattributes, mode:100644, content:*.txt filter=test][Test.txt, mode:100644, content:Hello again]",
+				indexState(CONTENT));
+		assertEquals("Hello again", read("Test.txt"));
+		deleteTrashFile("Test.txt");
+		git.checkout().addPath("Test.txt").call();
+		assertEquals("sHseslslsos sasgsasisn", read("Test.txt"));
+
+		writeTrashFile("Test.bin", "Hello again");
+		git.add().addFilepattern("Test.bin").call();
+		assertEquals(
+				"[.gitattributes, mode:100644, content:*.txt filter=test][Test.bin, mode:100644, content:Hello again][Test.txt, mode:100644, content:Hello again]",
+				indexState(CONTENT));
+		deleteTrashFile("Test.bin");
+		git.checkout().addPath("Test.bin").call();
+		assertEquals("Hello again", read("Test.bin"));
+
+		config.setString("filter", "test", "clean", null);
+		config.save();
+
+		git.add().addFilepattern("Test.txt").call();
+		assertEquals(
+				"[.gitattributes, mode:100644, content:*.txt filter=test][Test.bin, mode:100644, content:Hello again][Test.txt, mode:100644, content:sHseslslsos sasgsasisn]",
+				indexState(CONTENT));
+
+		config.setString("filter", "test", "clean", null);
+		config.save();
+	}
+
+	@Test
+	public void testBuiltinCleanAndSmudgeFilter() throws IOException, GitAPIException {
+		String builtinCommandPrefix = "jgit://builtin/test/";
+		FilterCommandRegistry.register(builtinCommandPrefix + "smudge",
+				new TestCommandFactory('s'));
+		FilterCommandRegistry.register(builtinCommandPrefix + "clean",
+				new TestCommandFactory('c'));
+		StoredConfig config = git.getRepository().getConfig();
+		config.setString("filter", "test", "smudge", builtinCommandPrefix+"smudge");
+		config.setString("filter", "test", "clean",
+				builtinCommandPrefix + "clean");
+		config.save();
+
+		writeTrashFile(".gitattributes", "*.txt filter=test");
+		git.add().addFilepattern(".gitattributes").call();
+		git.commit().setMessage("add filter").call();
+
+		writeTrashFile("Test.txt", "Hello again");
+		git.add().addFilepattern("Test.txt").call();
+		assertEquals(
+				"[.gitattributes, mode:100644, content:*.txt filter=test][Test.txt, mode:100644, content:cHceclclcoc cacgcacicn]",
+				indexState(CONTENT));
+		assertEquals("Hello again", read("Test.txt"));
+		deleteTrashFile("Test.txt");
+		git.checkout().addPath("Test.txt").call();
+		assertEquals("scsHscsescslscslscsoscs scsascsgscsascsiscsn",
+				read("Test.txt"));
+
+		writeTrashFile("Test.bin", "Hello again");
+		git.add().addFilepattern("Test.bin").call();
+		assertEquals(
+				"[.gitattributes, mode:100644, content:*.txt filter=test][Test.bin, mode:100644, content:Hello again][Test.txt, mode:100644, content:cHceclclcoc cacgcacicn]",
+				indexState(CONTENT));
+		deleteTrashFile("Test.bin");
+		git.checkout().addPath("Test.bin").call();
+		assertEquals("Hello again", read("Test.bin"));
+
+		config.setString("filter", "test", "clean", null);
+		config.save();
+
+		git.add().addFilepattern("Test.txt").call();
+		assertEquals(
+				"[.gitattributes, mode:100644, content:*.txt filter=test][Test.bin, mode:100644, content:Hello again][Test.txt, mode:100644, content:scsHscsescslscslscsoscs scsascsgscsascsiscsn]",
+				indexState(CONTENT));
+
+		config.setString("filter", "test", "clean", null);
+		config.save();
+	}
+
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/RelativeDateFormatterTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/RelativeDateFormatterTest.java
index 2901c93..76687d1 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/RelativeDateFormatterTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/RelativeDateFormatterTest.java
@@ -42,17 +42,16 @@
  */
 package org.eclipse.jgit.util;
 
-import static org.junit.Assert.assertEquals;
-import static org.eclipse.jgit.util.RelativeDateFormatter.YEAR_IN_MILLIS;
-import static org.eclipse.jgit.util.RelativeDateFormatter.SECOND_IN_MILLIS;
-import static org.eclipse.jgit.util.RelativeDateFormatter.MINUTE_IN_MILLIS;
-import static org.eclipse.jgit.util.RelativeDateFormatter.HOUR_IN_MILLIS;
 import static org.eclipse.jgit.util.RelativeDateFormatter.DAY_IN_MILLIS;
+import static org.eclipse.jgit.util.RelativeDateFormatter.HOUR_IN_MILLIS;
+import static org.eclipse.jgit.util.RelativeDateFormatter.MINUTE_IN_MILLIS;
+import static org.eclipse.jgit.util.RelativeDateFormatter.SECOND_IN_MILLIS;
+import static org.eclipse.jgit.util.RelativeDateFormatter.YEAR_IN_MILLIS;
+import static org.junit.Assert.assertEquals;
 
 import java.util.Date;
 
 import org.eclipse.jgit.junit.MockSystemReader;
-import org.eclipse.jgit.util.RelativeDateFormatter;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
diff --git a/org.eclipse.jgit.ui/.classpath b/org.eclipse.jgit.ui/.classpath
index a14ade4..110168f 100644
--- a/org.eclipse.jgit.ui/.classpath
+++ b/org.eclipse.jgit.ui/.classpath
@@ -1,6 +1,6 @@
 <?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.7"/>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
 	<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
 	<classpathentry kind="src" path="src"/>
 	<classpathentry kind="src" path="resources"/>
diff --git a/org.eclipse.jgit.ui/.settings/org.eclipse.jdt.core.prefs b/org.eclipse.jgit.ui/.settings/org.eclipse.jdt.core.prefs
index 1ce7cd0..808ec3a 100644
--- a/org.eclipse.jgit.ui/.settings/org.eclipse.jdt.core.prefs
+++ b/org.eclipse.jgit.ui/.settings/org.eclipse.jdt.core.prefs
@@ -7,9 +7,9 @@
 org.eclipse.jdt.core.compiler.annotation.nullanalysis=disabled
 org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
 org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
-org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
 org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
-org.eclipse.jdt.core.compiler.compliance=1.7
+org.eclipse.jdt.core.compiler.compliance=1.8
 org.eclipse.jdt.core.compiler.debug.lineNumber=generate
 org.eclipse.jdt.core.compiler.debug.localVariable=generate
 org.eclipse.jdt.core.compiler.debug.sourceFile=generate
@@ -112,7 +112,7 @@
 org.eclipse.jdt.core.compiler.problem.unusedTypeParameter=ignore
 org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning
 org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=error
-org.eclipse.jdt.core.compiler.source=1.7
+org.eclipse.jdt.core.compiler.source=1.8
 org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16
 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0
diff --git a/org.eclipse.jgit.ui/META-INF/MANIFEST.MF b/org.eclipse.jgit.ui/META-INF/MANIFEST.MF
index 8d2a775..667e3b2 100644
--- a/org.eclipse.jgit.ui/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.ui/META-INF/MANIFEST.MF
@@ -3,14 +3,14 @@
 Bundle-ManifestVersion: 2
 Bundle-Name: %plugin_name
 Bundle-SymbolicName: org.eclipse.jgit.ui
-Bundle-Version: 4.5.3.qualifier
+Bundle-Version: 4.6.2.qualifier
 Bundle-Vendor: %provider_name
-Bundle-RequiredExecutionEnvironment: JavaSE-1.7
-Export-Package: org.eclipse.jgit.awtui;version="4.5.3"
-Import-Package: org.eclipse.jgit.errors;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.lib;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.nls;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.revplot;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.revwalk;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.transport;version="[4.5.3,4.6.0)",
- org.eclipse.jgit.util;version="[4.5.3,4.6.0)"
+Bundle-RequiredExecutionEnvironment: JavaSE-1.8
+Export-Package: org.eclipse.jgit.awtui;version="4.6.2"
+Import-Package: org.eclipse.jgit.errors;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.lib;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.nls;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.revplot;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.revwalk;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.transport;version="[4.6.2,4.7.0)",
+ org.eclipse.jgit.util;version="[4.6.2,4.7.0)"
diff --git a/org.eclipse.jgit.ui/pom.xml b/org.eclipse.jgit.ui/pom.xml
index d8bb1ee..280399b 100644
--- a/org.eclipse.jgit.ui/pom.xml
+++ b/org.eclipse.jgit.ui/pom.xml
@@ -52,7 +52,7 @@
   <parent>
     <groupId>org.eclipse.jgit</groupId>
     <artifactId>org.eclipse.jgit-parent</artifactId>
-    <version>4.5.3-SNAPSHOT</version>
+    <version>4.6.2-SNAPSHOT</version>
   </parent>
 
   <artifactId>org.eclipse.jgit.ui</artifactId>
diff --git a/org.eclipse.jgit/.classpath b/org.eclipse.jgit/.classpath
index 04a2be7..cfcf24a 100644
--- a/org.eclipse.jgit/.classpath
+++ b/org.eclipse.jgit/.classpath
@@ -2,7 +2,7 @@
 <classpath>
 	<classpathentry kind="src" path="src"/>
 	<classpathentry kind="src" path="resources"/>
-	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7"/>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
 	<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
 	<classpathentry kind="output" path="bin"/>
 </classpath>
diff --git a/org.eclipse.jgit/.settings/org.eclipse.jdt.core.prefs b/org.eclipse.jgit/.settings/org.eclipse.jdt.core.prefs
index bfaf736..4f1759f 100644
--- a/org.eclipse.jgit/.settings/org.eclipse.jdt.core.prefs
+++ b/org.eclipse.jgit/.settings/org.eclipse.jdt.core.prefs
@@ -7,9 +7,9 @@
 org.eclipse.jdt.core.compiler.annotation.nullanalysis=enabled
 org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
 org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
-org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
 org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
-org.eclipse.jdt.core.compiler.compliance=1.7
+org.eclipse.jdt.core.compiler.compliance=1.8
 org.eclipse.jdt.core.compiler.debug.lineNumber=generate
 org.eclipse.jdt.core.compiler.debug.localVariable=generate
 org.eclipse.jdt.core.compiler.debug.sourceFile=generate
@@ -112,7 +112,7 @@
 org.eclipse.jdt.core.compiler.problem.unusedTypeParameter=ignore
 org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning
 org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=error
-org.eclipse.jdt.core.compiler.source=1.7
+org.eclipse.jdt.core.compiler.source=1.8
 org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16
 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0
diff --git a/org.eclipse.jgit/META-INF/MANIFEST.MF b/org.eclipse.jgit/META-INF/MANIFEST.MF
index 7cbedf2..701efcf 100644
--- a/org.eclipse.jgit/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit/META-INF/MANIFEST.MF
@@ -2,12 +2,12 @@
 Bundle-ManifestVersion: 2
 Bundle-Name: %plugin_name
 Bundle-SymbolicName: org.eclipse.jgit
-Bundle-Version: 4.5.3.qualifier
+Bundle-Version: 4.6.2.qualifier
 Bundle-Localization: plugin
 Bundle-Vendor: %provider_name
 Bundle-ActivationPolicy: lazy
-Export-Package: org.eclipse.jgit.annotations;version="4.5.3",
- org.eclipse.jgit.api;version="4.5.3";
+Export-Package: org.eclipse.jgit.annotations;version="4.6.2",
+ org.eclipse.jgit.api;version="4.6.2";
   uses:="org.eclipse.jgit.revwalk,
    org.eclipse.jgit.treewalk.filter,
    org.eclipse.jgit.diff,
@@ -21,60 +21,57 @@
    org.eclipse.jgit.submodule,
    org.eclipse.jgit.transport,
    org.eclipse.jgit.merge",
- org.eclipse.jgit.api.errors;version="4.5.3";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.errors",
- org.eclipse.jgit.attributes;version="4.5.3",
- org.eclipse.jgit.blame;version="4.5.3";
+ org.eclipse.jgit.api.errors;version="4.6.2";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.errors",
+ org.eclipse.jgit.attributes;version="4.6.2",
+ org.eclipse.jgit.blame;version="4.6.2";
   uses:="org.eclipse.jgit.lib,
    org.eclipse.jgit.revwalk,
    org.eclipse.jgit.treewalk.filter,
    org.eclipse.jgit.diff",
- org.eclipse.jgit.diff;version="4.5.3";
+ org.eclipse.jgit.diff;version="4.6.2";
   uses:="org.eclipse.jgit.patch,
    org.eclipse.jgit.lib,
    org.eclipse.jgit.treewalk,
    org.eclipse.jgit.revwalk,
    org.eclipse.jgit.treewalk.filter,
    org.eclipse.jgit.util",
- org.eclipse.jgit.dircache;version="4.5.3";
+ org.eclipse.jgit.dircache;version="4.6.2";
   uses:="org.eclipse.jgit.lib,
    org.eclipse.jgit.treewalk,
    org.eclipse.jgit.util,
    org.eclipse.jgit.events,
    org.eclipse.jgit.attributes",
- org.eclipse.jgit.errors;version="4.5.3";
+ org.eclipse.jgit.errors;version="4.6.2";
   uses:="org.eclipse.jgit.lib,
    org.eclipse.jgit.internal.storage.pack,
    org.eclipse.jgit.transport,
    org.eclipse.jgit.dircache",
- org.eclipse.jgit.events;version="4.5.3";uses:="org.eclipse.jgit.lib",
- org.eclipse.jgit.fnmatch;version="4.5.3",
- org.eclipse.jgit.gitrepo;version="4.5.3";
+ org.eclipse.jgit.events;version="4.6.2";uses:="org.eclipse.jgit.lib",
+ org.eclipse.jgit.fnmatch;version="4.6.2",
+ org.eclipse.jgit.gitrepo;version="4.6.2";
   uses:="org.eclipse.jgit.api,
    org.eclipse.jgit.lib,
    org.eclipse.jgit.revwalk,
    org.xml.sax.helpers,
    org.xml.sax",
- org.eclipse.jgit.gitrepo.internal;version="4.5.3";x-internal:=true,
- org.eclipse.jgit.hooks;version="4.5.3";uses:="org.eclipse.jgit.lib",
- org.eclipse.jgit.ignore;version="4.5.3",
- org.eclipse.jgit.ignore.internal;version="4.5.3";x-friends:="org.eclipse.jgit.test",
- org.eclipse.jgit.internal;version="4.5.3";x-friends:="org.eclipse.jgit.test,org.eclipse.jgit.http.test",
- org.eclipse.jgit.internal.ketch;version="4.5.3";x-friends:="org.eclipse.jgit.junit,org.eclipse.jgit.test,org.eclipse.jgit.pgm",
- org.eclipse.jgit.internal.storage.dfs;version="4.5.3";
-  x-friends:="org.eclipse.jgit.test,
-   org.eclipse.jgit.http.server,
-   org.eclipse.jgit.http.test",
- org.eclipse.jgit.internal.storage.file;version="4.5.3";
+ org.eclipse.jgit.gitrepo.internal;version="4.6.2";x-internal:=true,
+ org.eclipse.jgit.hooks;version="4.6.2";uses:="org.eclipse.jgit.lib",
+ org.eclipse.jgit.ignore;version="4.6.2",
+ org.eclipse.jgit.ignore.internal;version="4.6.2";x-friends:="org.eclipse.jgit.test",
+ org.eclipse.jgit.internal;version="4.6.2";x-friends:="org.eclipse.jgit.test,org.eclipse.jgit.http.test",
+ org.eclipse.jgit.internal.ketch;version="4.6.2";x-friends:="org.eclipse.jgit.junit,org.eclipse.jgit.test,org.eclipse.jgit.pgm",
+ org.eclipse.jgit.internal.storage.dfs;version="4.6.2";x-friends:="org.eclipse.jgit.test,org.eclipse.jgit.http.server,org.eclipse.jgit.http.test",
+ org.eclipse.jgit.internal.storage.file;version="4.6.2";
   x-friends:="org.eclipse.jgit.test,
    org.eclipse.jgit.junit,
    org.eclipse.jgit.junit.http,
    org.eclipse.jgit.http.server,
-   org.eclipse.jgit.lfs.server,
+   org.eclipse.jgit.lfs,
    org.eclipse.jgit.pgm,
    org.eclipse.jgit.pgm.test",
- org.eclipse.jgit.internal.storage.pack;version="4.5.3";x-friends:="org.eclipse.jgit.junit,org.eclipse.jgit.test,org.eclipse.jgit.pgm",
- org.eclipse.jgit.internal.storage.reftree;version="4.5.3";x-friends:="org.eclipse.jgit.junit,org.eclipse.jgit.test,org.eclipse.jgit.pgm",
- org.eclipse.jgit.lib;version="4.5.3";
+ org.eclipse.jgit.internal.storage.pack;version="4.6.2";x-friends:="org.eclipse.jgit.junit,org.eclipse.jgit.test,org.eclipse.jgit.pgm",
+ org.eclipse.jgit.internal.storage.reftree;version="4.6.2";x-friends:="org.eclipse.jgit.junit,org.eclipse.jgit.test,org.eclipse.jgit.pgm",
+ org.eclipse.jgit.lib;version="4.6.2";
   uses:="org.eclipse.jgit.revwalk,
    org.eclipse.jgit.treewalk.filter,
    org.eclipse.jgit.util,
@@ -84,32 +81,32 @@
    org.eclipse.jgit.treewalk,
    org.eclipse.jgit.transport,
    org.eclipse.jgit.submodule",
- org.eclipse.jgit.merge;version="4.5.3";
+ org.eclipse.jgit.merge;version="4.6.2";
   uses:="org.eclipse.jgit.lib,
    org.eclipse.jgit.treewalk,
    org.eclipse.jgit.revwalk,
    org.eclipse.jgit.diff,
    org.eclipse.jgit.dircache,
    org.eclipse.jgit.api",
- org.eclipse.jgit.nls;version="4.5.3",
- org.eclipse.jgit.notes;version="4.5.3";
+ org.eclipse.jgit.nls;version="4.6.2",
+ org.eclipse.jgit.notes;version="4.6.2";
   uses:="org.eclipse.jgit.lib,
    org.eclipse.jgit.treewalk,
    org.eclipse.jgit.revwalk,
    org.eclipse.jgit.merge",
- org.eclipse.jgit.patch;version="4.5.3";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.diff",
- org.eclipse.jgit.revplot;version="4.5.3";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.revwalk",
- org.eclipse.jgit.revwalk;version="4.5.3";
+ org.eclipse.jgit.patch;version="4.6.2";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.diff",
+ org.eclipse.jgit.revplot;version="4.6.2";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.revwalk",
+ org.eclipse.jgit.revwalk;version="4.6.2";
   uses:="org.eclipse.jgit.lib,
    org.eclipse.jgit.treewalk,
    org.eclipse.jgit.treewalk.filter,
    org.eclipse.jgit.diff,
    org.eclipse.jgit.revwalk.filter",
- org.eclipse.jgit.revwalk.filter;version="4.5.3";uses:="org.eclipse.jgit.revwalk,org.eclipse.jgit.lib,org.eclipse.jgit.util",
- org.eclipse.jgit.storage.file;version="4.5.3";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.util",
- org.eclipse.jgit.storage.pack;version="4.5.3";uses:="org.eclipse.jgit.lib",
- org.eclipse.jgit.submodule;version="4.5.3";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.treewalk.filter,org.eclipse.jgit.treewalk",
- org.eclipse.jgit.transport;version="4.5.3";
+ org.eclipse.jgit.revwalk.filter;version="4.6.2";uses:="org.eclipse.jgit.revwalk,org.eclipse.jgit.lib,org.eclipse.jgit.util",
+ org.eclipse.jgit.storage.file;version="4.6.2";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.util",
+ org.eclipse.jgit.storage.pack;version="4.6.2";uses:="org.eclipse.jgit.lib",
+ org.eclipse.jgit.submodule;version="4.6.2";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.treewalk.filter,org.eclipse.jgit.treewalk",
+ org.eclipse.jgit.transport;version="4.6.2";
   uses:="org.eclipse.jgit.transport.resolver,
    org.eclipse.jgit.revwalk,
    org.eclipse.jgit.internal.storage.pack,
@@ -121,24 +118,25 @@
    org.eclipse.jgit.transport.http,
    org.eclipse.jgit.errors,
    org.eclipse.jgit.storage.pack",
- org.eclipse.jgit.transport.http;version="4.5.3";uses:="javax.net.ssl",
- org.eclipse.jgit.transport.resolver;version="4.5.3";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.transport",
- org.eclipse.jgit.treewalk;version="4.5.3";
+ org.eclipse.jgit.transport.http;version="4.6.2";uses:="javax.net.ssl",
+ org.eclipse.jgit.transport.resolver;version="4.6.2";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.transport",
+ org.eclipse.jgit.treewalk;version="4.6.2";
   uses:="org.eclipse.jgit.lib,
    org.eclipse.jgit.revwalk,
    org.eclipse.jgit.attributes,
    org.eclipse.jgit.treewalk.filter,
    org.eclipse.jgit.util,
    org.eclipse.jgit.dircache",
- org.eclipse.jgit.treewalk.filter;version="4.5.3";uses:="org.eclipse.jgit.treewalk",
- org.eclipse.jgit.util;version="4.5.3";
+ org.eclipse.jgit.treewalk.filter;version="4.6.2";uses:="org.eclipse.jgit.treewalk",
+ org.eclipse.jgit.util;version="4.6.2";
   uses:="org.eclipse.jgit.lib,
    org.eclipse.jgit.transport.http,
    org.eclipse.jgit.storage.file,
    org.ietf.jgss",
- org.eclipse.jgit.util.io;version="4.5.3"
-Bundle-RequiredExecutionEnvironment: JavaSE-1.7
-Import-Package: com.googlecode.javaewah;version="[0.7.9,0.8.0)",
+ org.eclipse.jgit.util.io;version="4.6.2",
+ org.eclipse.jgit.util.time;version="4.6.2"
+Bundle-RequiredExecutionEnvironment: JavaSE-1.8
+Import-Package: com.googlecode.javaewah;version="[1.1.6,2.0.0)",
  com.jcraft.jsch;version="[0.1.37,0.2.0)",
  javax.crypto,
  javax.net.ssl,
diff --git a/org.eclipse.jgit/META-INF/SOURCE-MANIFEST.MF b/org.eclipse.jgit/META-INF/SOURCE-MANIFEST.MF
index 45a55a8..c863b04 100644
--- a/org.eclipse.jgit/META-INF/SOURCE-MANIFEST.MF
+++ b/org.eclipse.jgit/META-INF/SOURCE-MANIFEST.MF
@@ -3,5 +3,5 @@
 Bundle-Name: org.eclipse.jgit - Sources
 Bundle-SymbolicName: org.eclipse.jgit.source
 Bundle-Vendor: Eclipse.org - JGit
-Bundle-Version: 4.5.3.qualifier
-Eclipse-SourceBundle: org.eclipse.jgit;version="4.5.3.qualifier";roots="."
+Bundle-Version: 4.6.2.qualifier
+Eclipse-SourceBundle: org.eclipse.jgit;version="4.6.2.qualifier";roots="."
diff --git a/org.eclipse.jgit/pom.xml b/org.eclipse.jgit/pom.xml
index ed517be..cf935ae 100644
--- a/org.eclipse.jgit/pom.xml
+++ b/org.eclipse.jgit/pom.xml
@@ -53,7 +53,7 @@
   <parent>
     <groupId>org.eclipse.jgit</groupId>
     <artifactId>org.eclipse.jgit-parent</artifactId>
-    <version>4.5.3-SNAPSHOT</version>
+    <version>4.6.2-SNAPSHOT</version>
   </parent>
 
   <artifactId>org.eclipse.jgit</artifactId>
diff --git a/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties b/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties
index b5b04b4..992b80b 100644
--- a/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties
+++ b/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties
@@ -39,6 +39,7 @@
 blameNotCommittedYet=Not Committed Yet
 blobNotFound=Blob not found: {0}
 blobNotFoundForPath=Blob not found: {0} for path: {1}
+blockSizeNotPowerOf2=blockSize must be a power of 2
 branchNameInvalid=Branch name {0} is not allowed
 buildingBitmaps=Building bitmaps
 cachedPacksPreventsIndexCreation=Using cached packs prevents index creation
@@ -115,6 +116,7 @@
 checkoutUnexpectedResult=Checkout returned unexpected result {0}
 classCastNotA=Not a {0}
 cloneNonEmptyDirectory=Destination path "{0}" already exists and is not an empty directory
+closed=closed
 collisionOn=Collision on {0}
 commandRejectedByHook=Rejected by "{0}" hook.\n{1}
 commandWasCalledInTheWrongState=Command {0} was called in the wrong state
@@ -279,6 +281,7 @@
 expectedPktLineWithService=expected pkt-line with ''# service=-'', got ''{0}''
 expectedReceivedContentType=expected Content-Type {0}; received Content-Type {1}
 expectedReportForRefNotReceived={0}: expected report for ref {1} not received
+failedToDetermineFilterDefinition=An exception occured while determining filter definitions
 failedUpdatingRefs=failed updating refs
 failureDueToOneOfTheFollowing=Failure due to one of the following:
 failureUpdatingFETCH_HEAD=Failure updating FETCH_HEAD: {0}
@@ -366,6 +369,7 @@
 invalidTimeout=Invalid timeout: {0}
 invalidTimeUnitValue2=Invalid time unit value: {0}.{1}={2}
 invalidTimeUnitValue3=Invalid time unit value: {0}.{1}.{2}={3}
+invalidTreeZeroLengthName=Cannot append a tree entry with zero-length name
 invalidURL=Invalid URL {0}
 invalidWildcards=Invalid wildcards {0}
 invalidRefSpec=Invalid refspec {0}
@@ -463,6 +467,7 @@
 packedRefsHandleIsStale=packed-refs handle is stale, {0}. retry
 packetSizeMustBeAtLeast=packet size {0} must be >= {1}
 packetSizeMustBeAtMost=packet size {0} must be <= {1}
+packedRefsCorruptionDetected=packed-refs corruption detected: {0}
 packfileCorruptionDetected=Packfile corruption detected: {0}
 packFileInvalid=Pack file invalid: {0}
 packfileIsTruncated=Packfile {0} is truncated.
@@ -601,6 +606,7 @@
 tagNameInvalid=tag name {0} is invalid
 tagOnRepoWithoutHEADCurrentlyNotSupported=Tag on repository without HEAD currently not supported
 theFactoryMustNotBeNull=The factory must not be null
+timeIsUncertain=Time is uncertain
 timerAlreadyTerminated=Timer already terminated
 tooManyIncludeRecursions=Too many recursions; circular includes in config file(s)?
 topologicalSortRequired=Topological sort required.
@@ -670,6 +676,7 @@
 unsupportedOperationNotAddAtEnd=Not add-at-end: {0}
 unsupportedPackIndexVersion=Unsupported pack index version {0}
 unsupportedPackVersion=Unsupported pack version {0}.
+unsupportedRepositoryDescription=Repository description not supported
 updatingHeadFailed=Updating HEAD failed
 updatingReferences=Updating references
 updatingRefFailed=Updating the ref {0} to {1} failed. ReturnCode from RefUpdate.update() was {2}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/AddCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/AddCommand.java
index 1f37833..16ec146 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/AddCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/AddCommand.java
@@ -224,6 +224,11 @@
 					entry.setLength(f.getEntryLength());
 					entry.setLastModified(f.getEntryLastModified());
 					long len = f.getEntryContentLength();
+					// We read and filter the content multiple times.
+					// f.getEntryContentLength() reads and filters the input and
+					// inserter.insert(...) does it again. That's because an
+					// ObjectInserter needs to know the length before it starts
+					// inserting. TODO: Fix this by using Buffers.
 					try (InputStream in = f.openEntryStream()) {
 						ObjectId id = inserter.insert(OBJ_BLOB, len, in);
 						entry.setObjectId(id);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/BlameCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/BlameCommand.java
index d803efd..2a2e07d 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/BlameCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/BlameCommand.java
@@ -61,9 +61,9 @@
 import org.eclipse.jgit.dircache.DirCache;
 import org.eclipse.jgit.lib.AnyObjectId;
 import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.CoreConfig.AutoCRLF;
 import org.eclipse.jgit.lib.ObjectId;
 import org.eclipse.jgit.lib.Repository;
-import org.eclipse.jgit.lib.CoreConfig.AutoCRLF;
 import org.eclipse.jgit.treewalk.WorkingTreeOptions;
 import org.eclipse.jgit.util.IO;
 import org.eclipse.jgit.util.io.AutoLFInputStream;
@@ -248,11 +248,12 @@
 			rawText = new RawText(inTree);
 			break;
 		case TRUE:
-			AutoLFInputStream in = new AutoLFInputStream(
-					new FileInputStream(inTree), true);
-			// Canonicalization should lead to same or shorter length
-			// (CRLF to LF), so the file size on disk is an upper size bound
-			rawText = new RawText(toByteArray(in, (int) inTree.length()));
+			try (AutoLFInputStream in = new AutoLFInputStream(
+					new FileInputStream(inTree), true)) {
+				// Canonicalization should lead to same or shorter length
+				// (CRLF to LF), so the file size on disk is an upper size bound
+				rawText = new RawText(toByteArray(in, (int) inTree.length()));
+			}
 			break;
 		default:
 			throw new IllegalArgumentException(
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 65508ef..c17ae5c 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/CheckoutCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/CheckoutCommand.java
@@ -318,7 +318,9 @@
 
 			if (!dco.getToBeDeleted().isEmpty()) {
 				status = new CheckoutResult(Status.NONDELETED,
-						dco.getToBeDeleted());
+						dco.getToBeDeleted(),
+						new ArrayList<String>(dco.getUpdated().keySet()),
+						dco.getRemoved());
 			} else
 				status = new CheckoutResult(new ArrayList<String>(dco
 						.getUpdated().keySet()), dco.getRemoved());
@@ -365,6 +367,26 @@
 	}
 
 	/**
+	 * Add multiple slash-separated paths to the list of paths to check out. To
+	 * check out all paths, use {@link #setAllPaths(boolean)}.
+	 * <p>
+	 * If this option is set, neither the {@link #setCreateBranch(boolean)} nor
+	 * {@link #setName(String)} option is considered. In other words, these
+	 * options are exclusive.
+	 *
+	 * @param p
+	 *            paths to update in the working tree and index (with
+	 *            <code>/</code> as separator)
+	 * @return {@code this}
+	 * @since 4.6
+	 */
+	public CheckoutCommand addPaths(List<String> p) {
+		checkCallable();
+		this.paths.addAll(p);
+		return this;
+	}
+
+	/**
 	 * Set whether to checkout all paths.
 	 * <p>
 	 * This options should be used when you want to do a path checkout on the
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/CheckoutResult.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/CheckoutResult.java
index 6a1bfb8..92a67f4 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/CheckoutResult.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/CheckoutResult.java
@@ -113,6 +113,28 @@
 	 *            {@link Status#CONFLICTS} or {@link Status#NONDELETED}.
 	 */
 	CheckoutResult(Status status, List<String> fileList) {
+		this(status, fileList, null, null);
+	}
+
+	/**
+	 * Create a new fail result. If status is {@link Status#CONFLICTS},
+	 * <code>fileList</code> is a list of conflicting files, if status is
+	 * {@link Status#NONDELETED}, <code>fileList</code> is a list of not deleted
+	 * files. All other values ignore <code>fileList</code>. To create a result
+	 * for {@link Status#OK}, see {@link #CheckoutResult(List, List)}.
+	 *
+	 * @param status
+	 *            the failure status
+	 * @param fileList
+	 *            the list of files to store, status has to be either
+	 *            {@link Status#CONFLICTS} or {@link Status#NONDELETED}.
+	 * @param modified
+	 *            the modified files
+	 * @param removed
+	 *            the removed files.
+	 */
+	CheckoutResult(Status status, List<String> fileList, List<String> modified,
+			List<String> removed) {
 		myStatus = status;
 		if (status == Status.CONFLICTS)
 			this.conflictList = fileList;
@@ -123,8 +145,8 @@
 		else
 			this.undeletedList = new ArrayList<String>(0);
 
-		this.modifiedList = new ArrayList<String>(0);
-		this.removedList = new ArrayList<String>(0);
+		this.modifiedList = modified;
+		this.removedList = removed;
 	}
 
 	/**
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/CherryPickCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/CherryPickCommand.java
index e82a697..276bf96 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/CherryPickCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/CherryPickCommand.java
@@ -330,4 +330,15 @@
 		String headName = Repository.shortenRefName(targetRefName);
 		return headName;
 	}
+
+	@SuppressWarnings("nls")
+	@Override
+	public String toString() {
+		return "CherryPickCommand [repo=" + repo + ",\ncommits=" + commits
+				+ ",\nmainlineParentNumber=" + mainlineParentNumber
+				+ ", noCommit=" + noCommit + ", ourCommitName=" + ourCommitName
+				+ ", reflogPrefix=" + reflogPrefix + ", strategy=" + strategy
+				+ "]";
+	}
+
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/MergeCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/MergeCommand.java
index 38b1097..ced1863 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/MergeCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/MergeCommand.java
@@ -381,6 +381,7 @@
 									.call().getId();
 						}
 						mergeStatus = MergeStatus.MERGED;
+						getRepository().autoGC(monitor);
 					}
 					if (commit && squash) {
 						msg = JGitText.get().squashCommitNotUpdatingHEAD;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/RebaseCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/RebaseCommand.java
index 2d6a76b..d10cc3d 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/RebaseCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/RebaseCommand.java
@@ -400,8 +400,8 @@
 		boolean conflicts = false;
 		if (rebaseState.getFile(AUTOSTASH).exists()) {
 			String stash = rebaseState.readFile(AUTOSTASH);
-			try {
-				Git.wrap(repo).stashApply().setStashRef(stash)
+			try (Git git = Git.wrap(repo)) {
+				git.stashApply().setStashRef(stash)
 						.ignoreRepositoryState(true).setStrategy(strategy)
 						.call();
 			} catch (StashApplyFailureException e) {
@@ -463,8 +463,10 @@
 			String oldMessage = commitToPick.getFullMessage();
 			String newMessage = interactiveHandler
 					.modifyCommitMessage(oldMessage);
-			newHead = new Git(repo).commit().setMessage(newMessage)
-					.setAmend(true).setNoVerify(true).call();
+			try (Git git = new Git(repo)) {
+				newHead = git.commit().setMessage(newMessage).setAmend(true)
+						.setNoVerify(true).call();
+			}
 			return null;
 		case EDIT:
 			rebaseState.createFile(AMEND, commitToPick.name());
@@ -693,6 +695,7 @@
 		String headName = rebaseState.readFile(HEAD_NAME);
 		updateHead(headName, finalHead, upstreamCommit);
 		boolean stashConflicts = autoStashApply();
+		getRepository().autoGC(monitor);
 		FileUtils.delete(rebaseState.getDir(), FileUtils.RECURSIVE);
 		if (stashConflicts)
 			return RebaseResult.STASH_APPLY_CONFLICTS_RESULT;
@@ -752,12 +755,12 @@
 			GitAPIException, CheckoutConflictException {
 		Ref ref = repo.exactRef(Constants.ORIG_HEAD);
 		ObjectId orig_head = ref == null ? null : ref.getObjectId();
-		try {
-			// we have already commited the cherry-picked commit.
+		try (Git git = Git.wrap(repo)) {
+			// we have already committed the cherry-picked commit.
 			// what we need is to have changes introduced by this
 			// commit to be on the index
 			// resetting is a workaround
-			Git.wrap(repo).reset().setMode(ResetType.SOFT)
+			git.reset().setMode(ResetType.SOFT)
 					.setRef("HEAD~1").call(); //$NON-NLS-1$
 		} finally {
 			// set ORIG_HEAD back to where we started because soft
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/ResetCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/ResetCommand.java
index 3ceff84..106988d 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/ResetCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/ResetCommand.java
@@ -432,4 +432,12 @@
 		repo.writeMergeCommitMsg(null);
 	}
 
+	@SuppressWarnings("nls")
+	@Override
+	public String toString() {
+		return "ResetCommand [repo=" + repo + ", ref=" + ref + ", mode=" + mode
+				+ ", isReflogDisabled=" + isReflogDisabled + ", filepaths="
+				+ filepaths + "]";
+	}
+
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleAddCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleAddCommand.java
index fbb24c1..b0f772e 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleAddCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleAddCommand.java
@@ -133,7 +133,9 @@
 	 */
 	protected boolean submoduleExists() throws IOException {
 		TreeFilter filter = PathFilter.create(path);
-		return SubmoduleWalk.forIndex(repo).setFilter(filter).next();
+		try (SubmoduleWalk w = SubmoduleWalk.forIndex(repo)) {
+			return w.setFilter(filter).next();
+		}
 	}
 
 	/**
@@ -178,7 +180,11 @@
 		clone.setURI(resolvedUri);
 		if (monitor != null)
 			clone.setProgressMonitor(monitor);
-		Repository subRepo = clone.call().getRepository();
+		Repository subRepo = null;
+		try (Git git = clone.call()) {
+			subRepo = git.getRepository();
+			subRepo.incrementOpen();
+		}
 
 		// Save submodule URL to parent repository's config
 		StoredConfig config = repo.getConfig();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleInitCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleInitCommand.java
index 0ed02ac..1dbe368 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleInitCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleInitCommand.java
@@ -94,8 +94,7 @@
 	public Collection<String> call() throws GitAPIException {
 		checkCallable();
 
-		try {
-			SubmoduleWalk generator = SubmoduleWalk.forIndex(repo);
+		try (SubmoduleWalk generator = SubmoduleWalk.forIndex(repo)) {
 			if (!paths.isEmpty())
 				generator.setFilter(PathFilterGroup.createFromStrings(paths));
 			StoredConfig config = repo.getConfig();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleStatusCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleStatusCommand.java
index 6e89f98..a1ea790 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleStatusCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleStatusCommand.java
@@ -54,9 +54,9 @@
 import org.eclipse.jgit.lib.Constants;
 import org.eclipse.jgit.lib.ObjectId;
 import org.eclipse.jgit.lib.Repository;
-import org.eclipse.jgit.submodule.SubmoduleWalk;
 import org.eclipse.jgit.submodule.SubmoduleStatus;
 import org.eclipse.jgit.submodule.SubmoduleStatusType;
+import org.eclipse.jgit.submodule.SubmoduleWalk;
 import org.eclipse.jgit.treewalk.filter.PathFilterGroup;
 
 /**
@@ -94,8 +94,7 @@
 	public Map<String, SubmoduleStatus> call() throws GitAPIException {
 		checkCallable();
 
-		try {
-			SubmoduleWalk generator = SubmoduleWalk.forIndex(repo);
+		try (SubmoduleWalk generator = SubmoduleWalk.forIndex(repo)) {
 			if (!paths.isEmpty())
 				generator.setFilter(PathFilterGroup.createFromStrings(paths));
 			Map<String, SubmoduleStatus> statuses = new HashMap<String, SubmoduleStatus>();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleSyncCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleSyncCommand.java
index 024f0be..088eedc 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleSyncCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleSyncCommand.java
@@ -111,8 +111,7 @@
 	public Map<String, String> call() throws GitAPIException {
 		checkCallable();
 
-		try {
-			SubmoduleWalk generator = SubmoduleWalk.forIndex(repo);
+		try (SubmoduleWalk generator = SubmoduleWalk.forIndex(repo)) {
 			if (!paths.isEmpty())
 				generator.setFilter(PathFilterGroup.createFromStrings(paths));
 			Map<String, String> synced = new HashMap<String, String>();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/StashApplyFailureException.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/StashApplyFailureException.java
index 1d54f77..222c1db 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/StashApplyFailureException.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/StashApplyFailureException.java
@@ -1,7 +1,5 @@
 package org.eclipse.jgit.api.errors;
 
-import org.eclipse.jgit.api.errors.GitAPIException;
-
 /**
  * Thrown from StashApplyCommand when stash apply fails
  */
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/attributes/AttributesHandler.java b/org.eclipse.jgit/src/org/eclipse/jgit/attributes/AttributesHandler.java
index 19e4afd..3bf4179 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/attributes/AttributesHandler.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/attributes/AttributesHandler.java
@@ -54,8 +54,8 @@
 import org.eclipse.jgit.treewalk.AbstractTreeIterator;
 import org.eclipse.jgit.treewalk.CanonicalTreeParser;
 import org.eclipse.jgit.treewalk.TreeWalk;
-import org.eclipse.jgit.treewalk.WorkingTreeIterator;
 import org.eclipse.jgit.treewalk.TreeWalk.OperationType;
+import org.eclipse.jgit.treewalk.WorkingTreeIterator;
 
 /**
  * The attributes handler knows how to retrieve, parse and merge attributes from
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/attributes/FilterCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/attributes/FilterCommand.java
new file mode 100644
index 0000000..10be588
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/attributes/FilterCommand.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2016, Christian Halstrick <christian.halstrick@sap.com>
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ *   copyright notice, this list of conditions and the following
+ *   disclaimer in the documentation and/or other materials provided
+ *   with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ *   names of its contributors may be used to endorse or promote
+ *   products derived from this software without specific prior
+ *   written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.eclipse.jgit.attributes;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/**
+ * An abstraction for JGit's builtin implementations for hooks and filters.
+ * Instead of spawning an external processes to start a filter/hook and to pump
+ * data from/to stdin/stdout these builtin commmands may be used. They are
+ * constructed by {@link FilterCommandFactory}.
+ *
+ * @since 4.6
+ */
+public abstract class FilterCommand {
+	/**
+	 * The {@link InputStream} this command should read from
+	 */
+	protected InputStream in;
+
+	/**
+	 * The {@link OutputStream} this command should write to
+	 */
+	protected OutputStream out;
+
+	/**
+	 * @param in
+	 *            The {@link InputStream} this command should read from
+	 * @param out
+	 *            The {@link OutputStream} this command should write to
+	 */
+	public FilterCommand(InputStream in, OutputStream out) {
+		this.in = in;
+		this.out = out;
+	}
+
+	/**
+	 * Execute the command. The command is supposed to read data from
+	 * {@link #in} and to write the result to {@link #out}. It returns the
+	 * number of bytes it read from {@link #in}. It should be called in a loop
+	 * until it returns -1 signaling that the {@link InputStream} is completely
+	 * processed.
+	 *
+	 * @return the number of bytes read from the {@link InputStream} or -1. -1
+	 *         means that the {@link InputStream} is completely processed.
+	 * @throws IOException
+	 *             when {@link IOException} occured while reading from
+	 *             {@link #in} or writing to {@link #out}
+	 *
+	 */
+	public abstract int run() throws IOException;
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/attributes/FilterCommandFactory.java b/org.eclipse.jgit/src/org/eclipse/jgit/attributes/FilterCommandFactory.java
new file mode 100644
index 0000000..6b973da
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/attributes/FilterCommandFactory.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2016, Christian Halstrick <christian.halstrick@sap.com>
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ *   copyright notice, this list of conditions and the following
+ *   disclaimer in the documentation and/or other materials provided
+ *   with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ *   names of its contributors may be used to endorse or promote
+ *   products derived from this software without specific prior
+ *   written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.eclipse.jgit.attributes;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import org.eclipse.jgit.lib.Repository;
+
+/**
+ * The factory responsible for creating instances of {@link FilterCommand}.
+ *
+ * @since 4.6
+ */
+public interface FilterCommandFactory {
+	/**
+	 * Create a new {@link FilterCommand}.
+	 *
+	 * @param db
+	 *            the repository this command should work on
+	 * @param in
+	 *            the {@link InputStream} this command should read from
+	 * @param out
+	 *            the {@link OutputStream} this command should write to
+	 * @return the created {@link FilterCommand}
+	 * @throws IOException
+	 *             thrown when the command constructor throws an IOException
+	 */
+	public FilterCommand create(Repository db, InputStream in,
+			OutputStream out) throws IOException;
+
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/attributes/FilterCommandRegistry.java b/org.eclipse.jgit/src/org/eclipse/jgit/attributes/FilterCommandRegistry.java
new file mode 100644
index 0000000..3fbaedb
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/attributes/FilterCommandRegistry.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2016, Matthias Sohn <matthias.sohn@sap.com>
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ *   copyright notice, this list of conditions and the following
+ *   disclaimer in the documentation and/or other materials provided
+ *   with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ *   names of its contributors may be used to endorse or promote
+ *   products derived from this software without specific prior
+ *   written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.eclipse.jgit.attributes;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.eclipse.jgit.lib.Repository;
+
+/**
+ * Registry for built-in filters
+ *
+ * @since 4.6
+ */
+public class FilterCommandRegistry {
+	private static ConcurrentHashMap<String, FilterCommandFactory> filterCommandRegistry = new ConcurrentHashMap<>();
+
+	/**
+	 * Registers a {@link FilterCommandFactory} responsible for creating
+	 * {@link FilterCommand}s for a certain command name. If the factory f1 is
+	 * registered for the name "jgit://builtin/x" then a call to
+	 * <code>getCommand("jgit://builtin/x", ...)</code> will call
+	 * <code>f1(...)</code> to create a new instance of {@link FilterCommand}
+	 *
+	 * @param filterCommandName
+	 *            the command name for which this factory is registered
+	 * @param factory
+	 *            the factory responsible for creating {@link FilterCommand}s
+	 *            for the specified name
+	 * @return the previous factory associated with <tt>commandName</tt>, or
+	 *         <tt>null</tt> if there was no mapping for <tt>commandName</tt>
+	 */
+	public static FilterCommandFactory register(String filterCommandName,
+			FilterCommandFactory factory) {
+		return filterCommandRegistry.put(filterCommandName, factory);
+	}
+
+	/**
+	 * Unregisters the {@link FilterCommandFactory} registered for the given
+	 * command name
+	 *
+	 * @param filterCommandName
+	 *            the FilterCommandFactory's filter command name
+	 * @return the previous factory associated with <tt>filterCommandName</tt>,
+	 *         or <tt>null</tt> if there was no mapping for <tt>commandName</tt>
+	 */
+	public static FilterCommandFactory unregister(String filterCommandName) {
+		return filterCommandRegistry.remove(filterCommandName);
+	}
+
+	/**
+	 * Checks whether any {@link FilterCommandFactory} is registered for a given
+	 * command name
+	 *
+	 * @param filterCommandName
+	 *            the name for which the registry should be checked
+	 * @return <code>true</code> if any factory was registered for the name
+	 */
+	public static boolean isRegistered(String filterCommandName) {
+		return filterCommandRegistry.containsKey(filterCommandName);
+	}
+
+	/**
+	 * @return Set of commandNames for which a {@link FilterCommandFactory} is
+	 *         registered
+	 */
+	public static Set<String> getRegisteredFilterCommands() {
+		return filterCommandRegistry.keySet();
+	}
+
+	/**
+	 * Creates a new {@link FilterCommand} for the given name. A factory must be
+	 * registered for the name in advance.
+	 *
+	 * @param filterCommandName
+	 *            The name for which a new {@link FilterCommand} should be
+	 *            created
+	 * @param db
+	 *            the repository this command should work on
+	 * @param in
+	 *            the {@link InputStream} this {@link FilterCommand} should read
+	 *            from
+	 * @param out
+	 *            the {@link OutputStream} this {@link FilterCommand} should
+	 *            write to
+	 * @return the command if a command could be created or <code>null</code> if
+	 *         there was no factory registered for that name
+	 * @throws IOException
+	 */
+	public static FilterCommand createFilterCommand(String filterCommandName,
+			Repository db, InputStream in, OutputStream out)
+			throws IOException {
+		FilterCommandFactory cf = filterCommandRegistry.get(filterCommandName);
+		return (cf == null) ? null : cf.create(db, in, out);
+	}
+
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCache.java b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCache.java
index b9101c0..b0cf8be 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCache.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCache.java
@@ -46,6 +46,7 @@
 package org.eclipse.jgit.dircache;
 
 import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
 import java.io.EOFException;
 import java.io.File;
 import java.io.FileInputStream;
@@ -86,7 +87,6 @@
 import org.eclipse.jgit.util.MutableInteger;
 import org.eclipse.jgit.util.NB;
 import org.eclipse.jgit.util.TemporaryBuffer;
-import org.eclipse.jgit.util.io.SafeBufferedOutputStream;
 
 /**
  * Support for the Git dircache (aka index file).
@@ -634,9 +634,9 @@
 	public void write() throws IOException {
 		final LockFile tmp = myLock;
 		requireLocked(tmp);
-		try {
-			writeTo(liveFile.getParentFile(),
-					new SafeBufferedOutputStream(tmp.getOutputStream()));
+		try (OutputStream o = tmp.getOutputStream();
+				OutputStream bo = new BufferedOutputStream(o)) {
+			writeTo(liveFile.getParentFile(), bo);
 		} catch (IOException err) {
 			tmp.unlock();
 			throw err;
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 8af7e46..c318443 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java
@@ -54,6 +54,8 @@
 import java.util.Map;
 
 import org.eclipse.jgit.api.errors.FilterFailedException;
+import org.eclipse.jgit.attributes.FilterCommand;
+import org.eclipse.jgit.attributes.FilterCommandRegistry;
 import org.eclipse.jgit.errors.CheckoutConflictException;
 import org.eclipse.jgit.errors.CorruptObjectException;
 import org.eclipse.jgit.errors.IncorrectObjectTypeException;
@@ -86,11 +88,15 @@
 import org.eclipse.jgit.util.RawParseUtils;
 import org.eclipse.jgit.util.SystemReader;
 import org.eclipse.jgit.util.io.EolStreamTypeUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 /**
  * This class handles checking out one or two trees merging with the index.
  */
 public class DirCacheCheckout {
+	private static Logger LOG = LoggerFactory.getLogger(DirCacheCheckout.class);
+
 	private static final int MAX_EXCEPTION_TEXT_SIZE = 10 * 1024;
 
 	/**
@@ -1303,45 +1309,19 @@
 		} else {
 			nonNullEolStreamType = EolStreamType.DIRECT;
 		}
-		OutputStream channel = EolStreamTypeUtil.wrapOutputStream(
-				new FileOutputStream(tmpFile), nonNullEolStreamType);
-		if (checkoutMetadata.smudgeFilterCommand != null) {
-			ProcessBuilder filterProcessBuilder = fs.runInShell(
-					checkoutMetadata.smudgeFilterCommand, new String[0]);
-			filterProcessBuilder.directory(repo.getWorkTree());
-			filterProcessBuilder.environment().put(Constants.GIT_DIR_KEY,
-					repo.getDirectory().getAbsolutePath());
-			ExecutionResult result;
-			int rc;
-			try {
-				// TODO: wire correctly with AUTOCRLF
-				result = fs.execute(filterProcessBuilder, ol.openStream());
-				rc = result.getRc();
-				if (rc == 0) {
-					result.getStdout().writeTo(channel,
-							NullProgressMonitor.INSTANCE);
+		try (OutputStream channel = EolStreamTypeUtil.wrapOutputStream(
+				new FileOutputStream(tmpFile), nonNullEolStreamType)) {
+			if (checkoutMetadata.smudgeFilterCommand != null) {
+				if (FilterCommandRegistry
+						.isRegistered(checkoutMetadata.smudgeFilterCommand)) {
+					runBuiltinFilterCommand(repo, checkoutMetadata, ol,
+							channel);
+				} else {
+					runExternalFilterCommand(repo, entry, checkoutMetadata, ol,
+							fs, channel);
 				}
-			} catch (IOException | InterruptedException e) {
-				throw new IOException(new FilterFailedException(e,
-						checkoutMetadata.smudgeFilterCommand,
-						entry.getPathString()));
-
-			} finally {
-				channel.close();
-			}
-			if (rc != 0) {
-				throw new IOException(new FilterFailedException(rc,
-						checkoutMetadata.smudgeFilterCommand,
-						entry.getPathString(),
-						result.getStdout().toByteArray(MAX_EXCEPTION_TEXT_SIZE),
-						RawParseUtils.decode(result.getStderr()
-								.toByteArray(MAX_EXCEPTION_TEXT_SIZE))));
-			}
-		} else {
-			try {
+			} else {
 				ol.copyTo(channel);
-			} finally {
-				channel.close();
 			}
 		}
 		// The entry needs to correspond to the on-disk filesize. If the content
@@ -1382,6 +1362,63 @@
 		entry.setLastModified(fs.lastModified(f));
 	}
 
+	// Run an external filter command
+	private static void runExternalFilterCommand(Repository repo,
+			DirCacheEntry entry,
+			CheckoutMetadata checkoutMetadata, ObjectLoader ol, FS fs,
+			OutputStream channel) throws IOException {
+		ProcessBuilder filterProcessBuilder = fs.runInShell(
+				checkoutMetadata.smudgeFilterCommand, new String[0]);
+		filterProcessBuilder.directory(repo.getWorkTree());
+		filterProcessBuilder.environment().put(Constants.GIT_DIR_KEY,
+				repo.getDirectory().getAbsolutePath());
+		ExecutionResult result;
+		int rc;
+		try {
+			// TODO: wire correctly with AUTOCRLF
+			result = fs.execute(filterProcessBuilder, ol.openStream());
+			rc = result.getRc();
+			if (rc == 0) {
+				result.getStdout().writeTo(channel,
+						NullProgressMonitor.INSTANCE);
+			}
+		} catch (IOException | InterruptedException e) {
+			throw new IOException(new FilterFailedException(e,
+					checkoutMetadata.smudgeFilterCommand,
+					entry.getPathString()));
+		}
+		if (rc != 0) {
+			throw new IOException(new FilterFailedException(rc,
+					checkoutMetadata.smudgeFilterCommand,
+					entry.getPathString(),
+					result.getStdout().toByteArray(MAX_EXCEPTION_TEXT_SIZE),
+					RawParseUtils.decode(result.getStderr()
+							.toByteArray(MAX_EXCEPTION_TEXT_SIZE))));
+		}
+	}
+
+	// Run a builtin filter command
+	private static void runBuiltinFilterCommand(Repository repo,
+			CheckoutMetadata checkoutMetadata, ObjectLoader ol,
+			OutputStream channel) throws MissingObjectException, IOException {
+		FilterCommand command = null;
+		try {
+			command = FilterCommandRegistry.createFilterCommand(
+					checkoutMetadata.smudgeFilterCommand, repo, ol.openStream(),
+					channel);
+		} catch (IOException e) {
+			LOG.error(JGitText.get().failedToDetermineFilterDefinition, e);
+			// In case an IOException occurred during creating of the command
+			// then proceed as if there would not have been a builtin filter.
+			ol.copyTo(channel);
+		}
+		if (command != null) {
+			while (command.run() != -1) {
+				// loop as long as command.run() tells there is work to do
+			}
+		}
+	}
+
 	@SuppressWarnings("deprecation")
 	private static void checkValidPath(CanonicalTreeParser t)
 			throws InvalidPathException {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/ManifestParser.java b/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/ManifestParser.java
index 2370ae1..8a35d35 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/ManifestParser.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/ManifestParser.java
@@ -215,10 +215,13 @@
 						attributes.getValue("dest"))); //$NON-NLS-1$
 		} else if ("include".equals(qName)) { //$NON-NLS-1$
 			String name = attributes.getValue("name"); //$NON-NLS-1$
-			InputStream is = null;
 			if (includedReader != null) {
-				try {
-					is = includedReader.readIncludeFile(name);
+				try (InputStream is = includedReader.readIncludeFile(name)) {
+					if (is == null) {
+						throw new SAXException(
+								RepoText.get().errorIncludeNotImplemented);
+					}
+					read(is);
 				} catch (Exception e) {
 					throw new SAXException(MessageFormat.format(
 							RepoText.get().errorIncludeFile, name), e);
@@ -226,22 +229,13 @@
 			} else if (filename != null) {
 				int index = filename.lastIndexOf('/');
 				String path = filename.substring(0, index + 1) + name;
-				try {
-					is = new FileInputStream(path);
+				try (InputStream is = new FileInputStream(path)) {
+					read(is);
 				} catch (IOException e) {
 					throw new SAXException(MessageFormat.format(
 							RepoText.get().errorIncludeFile, path), e);
 				}
 			}
-			if (is == null) {
-				throw new SAXException(
-						RepoText.get().errorIncludeNotImplemented);
-			}
-			try {
-				read(is);
-			} catch (IOException e) {
-				throw new SAXException(e);
-			}
 		}
 	}
 
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 9b7f094..86dbabc 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoCommand.java
@@ -180,17 +180,11 @@
 		public byte[] readFile(String uri, String ref, String path)
 				throws GitAPIException, IOException {
 			File dir = FileUtils.createTempDir("jgit_", ".git", null); //$NON-NLS-1$ //$NON-NLS-2$
-			Repository repo = Git
-					.cloneRepository()
-					.setBare(true)
-					.setDirectory(dir)
-					.setURI(uri)
-					.call()
-					.getRepository();
-			try {
+			try (Git git = Git.cloneRepository().setBare(true).setDirectory(dir)
+					.setURI(uri).call();
+					Repository repo = git.getRepository()) {
 				return readFileFromRepo(repo, ref, path);
 			} finally {
-				repo.close();
 				FileUtils.delete(dir, FileUtils.RECURSIVE);
 			}
 		}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/ignore/FastIgnoreRule.java b/org.eclipse.jgit/src/org/eclipse/jgit/ignore/FastIgnoreRule.java
index eb081ad..ef67d49 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/ignore/FastIgnoreRule.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/ignore/FastIgnoreRule.java
@@ -42,10 +42,11 @@
  */
 package org.eclipse.jgit.ignore;
 
+import static org.eclipse.jgit.ignore.internal.IMatcher.NO_MATCH;
+import static org.eclipse.jgit.ignore.internal.Strings.isDirectoryPattern;
 import static org.eclipse.jgit.ignore.internal.Strings.stripTrailing;
 import static org.eclipse.jgit.ignore.internal.Strings.stripTrailingWhitespace;
-import static org.eclipse.jgit.ignore.internal.Strings.isDirectoryPattern;
-import static org.eclipse.jgit.ignore.internal.IMatcher.NO_MATCH;
+
 import org.eclipse.jgit.errors.InvalidPatternException;
 import org.eclipse.jgit.ignore.internal.IMatcher;
 import org.eclipse.jgit.ignore.internal.PathMatcher;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java
index 758f71d..ada5bf7 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java
@@ -98,6 +98,7 @@
 	/***/ public String blameNotCommittedYet;
 	/***/ public String blobNotFound;
 	/***/ public String blobNotFoundForPath;
+	/***/ public String blockSizeNotPowerOf2;
 	/***/ public String branchNameInvalid;
 	/***/ public String buildingBitmaps;
 	/***/ public String cachedPacksPreventsIndexCreation;
@@ -174,6 +175,7 @@
 	/***/ public String checkoutUnexpectedResult;
 	/***/ public String classCastNotA;
 	/***/ public String cloneNonEmptyDirectory;
+	/***/ public String closed;
 	/***/ public String collisionOn;
 	/***/ public String commandRejectedByHook;
 	/***/ public String commandWasCalledInTheWrongState;
@@ -338,6 +340,7 @@
 	/***/ public String expectedPktLineWithService;
 	/***/ public String expectedReceivedContentType;
 	/***/ public String expectedReportForRefNotReceived;
+	/***/ public String failedToDetermineFilterDefinition;
 	/***/ public String failedUpdatingRefs;
 	/***/ public String failureDueToOneOfTheFollowing;
 	/***/ public String failureUpdatingFETCH_HEAD;
@@ -424,6 +427,7 @@
 	/***/ public String invalidTimeout;
 	/***/ public String invalidTimeUnitValue2;
 	/***/ public String invalidTimeUnitValue3;
+	/***/ public String invalidTreeZeroLengthName;
 	/***/ public String invalidURL;
 	/***/ public String invalidWildcards;
 	/***/ public String invalidRefSpec;
@@ -522,6 +526,7 @@
 	/***/ public String packedRefsHandleIsStale;
 	/***/ public String packetSizeMustBeAtLeast;
 	/***/ public String packetSizeMustBeAtMost;
+	/***/ public String packedRefsCorruptionDetected;
 	/***/ public String packfileCorruptionDetected;
 	/***/ public String packFileInvalid;
 	/***/ public String packfileIsTruncated;
@@ -661,6 +666,7 @@
 	/***/ public String tagOnRepoWithoutHEADCurrentlyNotSupported;
 	/***/ public String transactionAborted;
 	/***/ public String theFactoryMustNotBeNull;
+	/***/ public String timeIsUncertain;
 	/***/ public String timerAlreadyTerminated;
 	/***/ public String tooManyIncludeRecursions;
 	/***/ public String topologicalSortRequired;
@@ -729,6 +735,7 @@
 	/***/ public String unsupportedOperationNotAddAtEnd;
 	/***/ public String unsupportedPackIndexVersion;
 	/***/ public String unsupportedPackVersion;
+	/***/ public String unsupportedRepositoryDescription;
 	/***/ public String updatingHeadFailed;
 	/***/ public String updatingReferences;
 	/***/ public String updatingRefFailed;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/ketch/ElectionRound.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/ketch/ElectionRound.java
index 014eab2..1221ddd 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/ketch/ElectionRound.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/ketch/ElectionRound.java
@@ -43,10 +43,12 @@
 
 package org.eclipse.jgit.internal.ketch;
 
+import static java.util.concurrent.TimeUnit.SECONDS;
 import static org.eclipse.jgit.internal.ketch.KetchConstants.TERM;
 
 import java.io.IOException;
 import java.util.List;
+import java.util.concurrent.TimeoutException;
 
 import org.eclipse.jgit.lib.CommitBuilder;
 import org.eclipse.jgit.lib.ObjectId;
@@ -55,6 +57,7 @@
 import org.eclipse.jgit.lib.TreeFormatter;
 import org.eclipse.jgit.revwalk.RevCommit;
 import org.eclipse.jgit.revwalk.RevWalk;
+import org.eclipse.jgit.util.time.ProposedTimestamp;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -75,9 +78,11 @@
 	void start() throws IOException {
 		ObjectId id;
 		try (Repository git = leader.openRepository();
+				ProposedTimestamp ts = getSystem().getClock().propose();
 				ObjectInserter inserter = git.newObjectInserter()) {
-			id = bumpTerm(git, inserter);
+			id = bumpTerm(git, ts, inserter);
 			inserter.flush();
+			blockUntil(ts);
 		}
 		runAsync(id);
 	}
@@ -91,12 +96,17 @@
 		return term;
 	}
 
-	private ObjectId bumpTerm(Repository git, ObjectInserter inserter)
-			throws IOException {
+	private ObjectId bumpTerm(Repository git, ProposedTimestamp ts,
+			ObjectInserter inserter) throws IOException {
 		CommitBuilder b = new CommitBuilder();
 		if (!ObjectId.zeroId().equals(acceptedOldIndex)) {
 			try (RevWalk rw = new RevWalk(git)) {
 				RevCommit c = rw.parseCommit(acceptedOldIndex);
+				if (getSystem().requireMonotonicLeaderElections()) {
+					if (ts.read(SECONDS) < c.getCommitTime()) {
+						throw new TimeIsUncertainException();
+					}
+				}
 				b.setTreeId(c.getTree());
 				b.setParentId(acceptedOldIndex);
 				term = parseTerm(c.getFooterLines(TERM)) + 1;
@@ -116,7 +126,7 @@
 			msg.append(' ').append(tag);
 		}
 
-		b.setAuthor(leader.getSystem().newCommitter());
+		b.setAuthor(leader.getSystem().newCommitter(ts));
 		b.setCommitter(b.getAuthor());
 		b.setMessage(msg.toString());
 
@@ -138,4 +148,12 @@
 		}
 		return Long.parseLong(s, 10);
 	}
+
+	private void blockUntil(ProposedTimestamp ts) throws IOException {
+		try {
+			ts.blockUntil(getSystem().getMaxWaitForMonotonicClock());
+		} catch (InterruptedException | TimeoutException e) {
+			throw new TimeIsUncertainException(e);
+		}
+	}
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/ketch/KetchSystem.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/ketch/KetchSystem.java
index 71e872e..33f526e 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/ketch/KetchSystem.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/ketch/KetchSystem.java
@@ -53,6 +53,7 @@
 import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_REMOTE;
 
 import java.net.URISyntaxException;
+import java.time.Duration;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Random;
@@ -67,6 +68,9 @@
 import org.eclipse.jgit.lib.Repository;
 import org.eclipse.jgit.transport.RemoteConfig;
 import org.eclipse.jgit.transport.URIish;
+import org.eclipse.jgit.util.time.MonotonicClock;
+import org.eclipse.jgit.util.time.MonotonicSystemClock;
+import org.eclipse.jgit.util.time.ProposedTimestamp;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -88,6 +92,7 @@
 	}
 
 	private final ScheduledExecutorService executor;
+	private final MonotonicClock clock;
 	private final String txnNamespace;
 	private final String txnAccepted;
 	private final String txnCommitted;
@@ -95,7 +100,7 @@
 
 	/** Create a default system with a thread pool of 1 thread per CPU. */
 	public KetchSystem() {
-		this(defaultExecutor(), DEFAULT_TXN_NAMESPACE);
+		this(defaultExecutor(), new MonotonicSystemClock(), DEFAULT_TXN_NAMESPACE);
 	}
 
 	/**
@@ -103,13 +108,17 @@
 	 *
 	 * @param executor
 	 *            thread pool to run background operations.
+	 * @param clock
+	 *            clock to create timestamps.
 	 * @param txnNamespace
 	 *            reference namespace for the RefTree graph and associated
 	 *            transaction state. Must begin with {@code "refs/"} and end
 	 *            with {@code '/'}, for example {@code "refs/txn/"}.
 	 */
-	public KetchSystem(ScheduledExecutorService executor, String txnNamespace) {
+	public KetchSystem(ScheduledExecutorService executor, MonotonicClock clock,
+			String txnNamespace) {
 		this.executor = executor;
+		this.clock = clock;
 		this.txnNamespace = txnNamespace;
 		this.txnAccepted = txnNamespace + ACCEPTED;
 		this.txnCommitted = txnNamespace + COMMITTED;
@@ -121,6 +130,28 @@
 		return executor;
 	}
 
+	/** @return clock to obtain timestamps from. */
+	public MonotonicClock getClock() {
+		return clock;
+	}
+
+	/**
+	 * @return how long the leader will wait for the {@link #getClock()}'s
+	 *         {@code ProposedTimestamp} used in commits proposed to the RefTree
+	 *         graph ({@link #getTxnAccepted()}). Defaults to 5 seconds.
+	 */
+	public Duration getMaxWaitForMonotonicClock() {
+		return Duration.ofSeconds(5);
+	}
+
+	/**
+	 * @return true if elections should require monotonically increasing commit
+	 *         timestamps. This requires a very good {@link MonotonicClock}.
+	 */
+	public boolean requireMonotonicLeaderElections() {
+		return false;
+	}
+
 	/**
 	 * Get the namespace used for the RefTree graph and transaction management.
 	 *
@@ -145,27 +176,32 @@
 		return txnStage;
 	}
 
-	/** @return identity line for the committer header of a RefTreeGraph. */
-	public PersonIdent newCommitter() {
+	/**
+	 * @param time
+	 *            timestamp for the committer.
+	 * @return identity line for the committer header of a RefTreeGraph.
+	 */
+	public PersonIdent newCommitter(ProposedTimestamp time) {
 		String name = "ketch"; //$NON-NLS-1$
 		String email = "ketch@system"; //$NON-NLS-1$
-		return new PersonIdent(name, email);
+		return new PersonIdent(name, email, time);
 	}
 
 	/**
 	 * Construct a random tag to identify a candidate during leader election.
 	 * <p>
 	 * Multiple processes trying to elect themselves leaders at exactly the same
-	 * time (rounded to seconds) using the same {@link #newCommitter()} identity
-	 * strings, for the same term, may generate the same ObjectId for the
-	 * election commit and falsely assume they have both won.
+	 * time (rounded to seconds) using the same
+	 * {@link #newCommitter(ProposedTimestamp)} identity strings, for the same
+	 * term, may generate the same ObjectId for the election commit and falsely
+	 * assume they have both won.
 	 * <p>
 	 * Candidates add this tag to their election ballot commit to disambiguate
 	 * the election. The tag only needs to be unique for a given triplet of
-	 * {@link #newCommitter()}, system time (rounded to seconds), and term. If
-	 * every replica in the system uses a unique {@code newCommitter} (such as
-	 * including the host name after the {@code "@"} in the email address) the
-	 * tag could be the empty string.
+	 * {@link #newCommitter(ProposedTimestamp)}, system time (rounded to
+	 * seconds), and term. If every replica in the system uses a unique
+	 * {@code newCommitter} (such as including the host name after the
+	 * {@code "@"} in the email address) the tag could be the empty string.
 	 * <p>
 	 * The default implementation generates a few bytes of random data.
 	 *
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/ketch/LocalReplica.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/ketch/LocalReplica.java
index e297bca..907eecb 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/ketch/LocalReplica.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/ketch/LocalReplica.java
@@ -64,6 +64,8 @@
 import org.eclipse.jgit.lib.Repository;
 import org.eclipse.jgit.revwalk.RevWalk;
 import org.eclipse.jgit.transport.ReceiveCommand;
+import org.eclipse.jgit.util.time.MonotonicClock;
+import org.eclipse.jgit.util.time.ProposedTimestamp;
 
 /** Ketch replica running on the same system as the {@link KetchLeader}. */
 public class LocalReplica extends KetchReplica {
@@ -119,9 +121,11 @@
 		getSystem().getExecutor().execute(new Runnable() {
 			@Override
 			public void run() {
-				try (Repository git = getLeader().openRepository()) {
+				MonotonicClock clk = getSystem().getClock();
+				try (Repository git = getLeader().openRepository();
+						ProposedTimestamp ts = clk.propose()) {
 					try {
-						update(git, req);
+						update(git, req, ts);
 						req.done(git);
 					} catch (Throwable err) {
 						req.setException(git, err);
@@ -139,8 +143,8 @@
 		throw new IOException(KetchText.get().cannotFetchFromLocalReplica);
 	}
 
-	private void update(Repository git, ReplicaPushRequest req)
-			throws IOException {
+	private void update(Repository git, ReplicaPushRequest req,
+			ProposedTimestamp ts) throws IOException {
 		RefDatabase refdb = git.getRefDatabase();
 		CommitMethod method = getCommitMethod();
 
@@ -156,7 +160,8 @@
 		}
 
 		BatchRefUpdate batch = refdb.newBatchUpdate();
-		batch.setRefLogIdent(getSystem().newCommitter());
+		batch.addProposedTimestamp(ts);
+		batch.setRefLogIdent(getSystem().newCommitter(ts));
 		batch.setRefLogMessage("ketch", false); //$NON-NLS-1$
 		batch.setAllowNonFastForwards(true);
 
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/ketch/Proposal.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/ketch/Proposal.java
index 0876eb5..12d3f4c 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/ketch/Proposal.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/ketch/Proposal.java
@@ -67,6 +67,7 @@
 import org.eclipse.jgit.revwalk.RevWalk;
 import org.eclipse.jgit.transport.PushCertificate;
 import org.eclipse.jgit.transport.ReceiveCommand;
+import org.eclipse.jgit.util.time.ProposedTimestamp;
 
 /**
  * A proposal to be applied in a Ketch system.
@@ -123,6 +124,8 @@
 	private PersonIdent author;
 	private String message;
 	private PushCertificate pushCert;
+
+	private List<ProposedTimestamp> timestamps;
 	private final List<Runnable> listeners = new CopyOnWriteArrayList<>();
 	private final AtomicReference<State> state = new AtomicReference<>(NEW);
 
@@ -223,6 +226,31 @@
 	}
 
 	/**
+	 * @return timestamps that Ketch must block for. These may have been used as
+	 *         commit times inside the objects involved in the proposal.
+	 */
+	public List<ProposedTimestamp> getProposedTimestamps() {
+		if (timestamps != null) {
+			return timestamps;
+		}
+		return Collections.emptyList();
+	}
+
+	/**
+	 * Request the proposal to wait for the affected timestamps to resolve.
+	 *
+	 * @param ts
+	 * @return {@code this}.
+	 */
+	public Proposal addProposedTimestamp(ProposedTimestamp ts) {
+		if (timestamps == null) {
+			timestamps = new ArrayList<>(4);
+		}
+		timestamps.add(ts);
+		return this;
+	}
+
+	/**
 	 * Add a callback to be invoked when the proposal is done.
 	 * <p>
 	 * A proposal is done when it has entered either {@link State#EXECUTED} or
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/ketch/ProposalRound.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/ketch/ProposalRound.java
index d34477a..ddd7059 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/ketch/ProposalRound.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/ketch/ProposalRound.java
@@ -46,12 +46,16 @@
 import static org.eclipse.jgit.internal.ketch.Proposal.State.RUNNING;
 
 import java.io.IOException;
+import java.time.Duration;
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.concurrent.TimeoutException;
+import java.util.stream.Collectors;
 
 import org.eclipse.jgit.annotations.Nullable;
 import org.eclipse.jgit.internal.storage.reftree.Command;
@@ -65,6 +69,7 @@
 import org.eclipse.jgit.revwalk.RevCommit;
 import org.eclipse.jgit.revwalk.RevWalk;
 import org.eclipse.jgit.transport.ReceiveCommand;
+import org.eclipse.jgit.util.time.ProposedTimestamp;
 
 /** A {@link Round} that aggregates and sends user {@link Proposal}s. */
 class ProposalRound extends Round {
@@ -123,8 +128,10 @@
 		}
 		try {
 			ObjectId id;
-			try (Repository git = leader.openRepository()) {
-				id = insertProposals(git);
+			try (Repository git = leader.openRepository();
+					ProposedTimestamp ts = getSystem().getClock().propose()) {
+				id = insertProposals(git, ts);
+				blockUntil(ts);
 			}
 			runAsync(id);
 		} catch (NoOp e) {
@@ -143,16 +150,16 @@
 		}
 	}
 
-	private ObjectId insertProposals(Repository git)
+	private ObjectId insertProposals(Repository git, ProposedTimestamp ts)
 			throws IOException, NoOp {
 		ObjectId id;
 		try (ObjectInserter inserter = git.newObjectInserter()) {
 			// TODO(sop) Process signed push certificates.
 
 			if (queuedTree != null) {
-				id = insertSingleProposal(git, inserter);
+				id = insertSingleProposal(git, ts, inserter);
 			} else {
-				id = insertMultiProposal(git, inserter);
+				id = insertMultiProposal(git, ts, inserter);
 			}
 
 			stageCommands = makeStageList(git, inserter);
@@ -161,7 +168,7 @@
 		return id;
 	}
 
-	private ObjectId insertSingleProposal(Repository git,
+	private ObjectId insertSingleProposal(Repository git, ProposedTimestamp ts,
 			ObjectInserter inserter) throws IOException, NoOp {
 		// Fast path: tree is passed in with all proposals applied.
 		ObjectId treeId = queuedTree.writeTree(inserter);
@@ -183,13 +190,13 @@
 		if (!ObjectId.zeroId().equals(acceptedOldIndex)) {
 			b.setParentId(acceptedOldIndex);
 		}
-		b.setCommitter(leader.getSystem().newCommitter());
+		b.setCommitter(leader.getSystem().newCommitter(ts));
 		b.setAuthor(p.getAuthor() != null ? p.getAuthor() : b.getCommitter());
 		b.setMessage(message(p));
 		return inserter.insert(b);
 	}
 
-	private ObjectId insertMultiProposal(Repository git,
+	private ObjectId insertMultiProposal(Repository git, ProposedTimestamp ts,
 			ObjectInserter inserter) throws IOException, NoOp {
 		// The tree was not passed in, or there are multiple proposals
 		// each needing their own commit. Reset the tree and replay each
@@ -208,7 +215,7 @@
 			}
 		}
 
-		PersonIdent committer = leader.getSystem().newCommitter();
+		PersonIdent committer = leader.getSystem().newCommitter(ts);
 		for (Proposal p : todo) {
 			if (!tree.apply(p.getCommands())) {
 				// This should not occur, previously during queuing the
@@ -292,6 +299,20 @@
 		return b.makeStageList(newObjs, git, inserter);
 	}
 
+	private void blockUntil(ProposedTimestamp ts)
+			throws TimeIsUncertainException {
+		List<ProposedTimestamp> times = todo.stream()
+				.flatMap(p -> p.getProposedTimestamps().stream())
+				.collect(Collectors.toCollection(ArrayList::new));
+		times.add(ts);
+
+		try {
+			Duration maxWait = getSystem().getMaxWaitForMonotonicClock();
+			ProposedTimestamp.blockUntil(times, maxWait);
+		} catch (InterruptedException | TimeoutException e) {
+			throw new TimeIsUncertainException(e);
+		}
+	}
 
 	private static class NoOp extends Exception {
 		private static final long serialVersionUID = 1L;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/ketch/RemoteGitReplica.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/ketch/RemoteGitReplica.java
index 6f4a178..396fbdd 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/ketch/RemoteGitReplica.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/ketch/RemoteGitReplica.java
@@ -44,13 +44,13 @@
 package org.eclipse.jgit.internal.ketch;
 
 import static org.eclipse.jgit.internal.ketch.KetchReplica.CommitMethod.ALL_REFS;
+import static org.eclipse.jgit.lib.Ref.Storage.NETWORK;
 import static org.eclipse.jgit.transport.ReceiveCommand.Result.LOCK_FAILURE;
 import static org.eclipse.jgit.transport.ReceiveCommand.Result.NOT_ATTEMPTED;
 import static org.eclipse.jgit.transport.ReceiveCommand.Result.OK;
 import static org.eclipse.jgit.transport.ReceiveCommand.Result.REJECTED_NODELETE;
 import static org.eclipse.jgit.transport.ReceiveCommand.Result.REJECTED_NONFASTFORWARD;
 import static org.eclipse.jgit.transport.ReceiveCommand.Result.REJECTED_OTHER_REASON;
-import static org.eclipse.jgit.lib.Ref.Storage.NETWORK;
 
 import java.io.IOException;
 import java.util.ArrayList;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/ketch/Round.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/ketch/Round.java
index 1335b85..dd8e568 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/ketch/Round.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/ketch/Round.java
@@ -75,6 +75,10 @@
 		this.acceptedOldIndex = head;
 	}
 
+	KetchSystem getSystem() {
+		return leader.getSystem();
+	}
+
 	/**
 	 * Creates a commit for {@code refs/txn/accepted} and calls
 	 * {@link #runAsync(AnyObjectId)} to begin execution of the round across
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/ketch/TimeIsUncertainException.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/ketch/TimeIsUncertainException.java
new file mode 100644
index 0000000..7223f55
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/ketch/TimeIsUncertainException.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2016, Google Inc.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ *   copyright notice, this list of conditions and the following
+ *   disclaimer in the documentation and/or other materials provided
+ *   with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ *   names of its contributors may be used to endorse or promote
+ *   products derived from this software without specific prior
+ *   written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.internal.ketch;
+
+import java.io.IOException;
+
+import org.eclipse.jgit.internal.JGitText;
+
+class TimeIsUncertainException extends IOException {
+	private static final long serialVersionUID = 1L;
+
+	TimeIsUncertainException() {
+		super(JGitText.get().timeIsUncertain);
+	}
+
+	TimeIsUncertainException(Exception e) {
+		super(JGitText.get().timeIsUncertain, e);
+	}
+}
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 ecd4b23..f7decf1 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
@@ -145,6 +145,8 @@
 	 * <p>
 	 * If a pack file has a native size, a whole multiple of the native size
 	 * will be used until it matches this size.
+	 * <p>
+	 * The value for blockSize must be a power of 2.
 	 */
 	private final int blockSize;
 
@@ -175,13 +177,14 @@
 	/** Number of bytes currently loaded in the cache. */
 	private volatile long liveBytes;
 
+	@SuppressWarnings("unchecked")
 	private DfsBlockCache(final DfsBlockCacheConfig cfg) {
 		tableSize = tableSize(cfg);
 		if (tableSize < 1)
 			throw new IllegalArgumentException(JGitText.get().tSizeMustBeGreaterOrEqual1);
 
 		table = new AtomicReferenceArray<HashEntry>(tableSize);
-		loadLocks = new ReentrantLock[32];
+		loadLocks = new ReentrantLock[cfg.getConcurrencyLevel()];
 		for (int i = 0; i < loadLocks.length; i++)
 			loadLocks[i] = new ReentrantLock(true /* fair */);
 
@@ -260,20 +263,22 @@
 		// TODO This table grows without bound. It needs to clean up
 		// entries that aren't in cache anymore, and aren't being used
 		// by a live DfsObjDatabase reference.
-		synchronized (packCache) {
-			DfsPackFile pack = packCache.get(dsc);
-			if (pack != null && pack.invalid()) {
-				packCache.remove(dsc);
-				pack = null;
-			}
-			if (pack == null) {
-				if (key == null)
-					key = new DfsPackKey();
-				pack = new DfsPackFile(this, dsc, key);
-				packCache.put(dsc, pack);
-			}
+
+		DfsPackFile pack = packCache.get(dsc);
+		if (pack != null && !pack.invalid()) {
 			return pack;
 		}
+
+		// 'pack' either didn't exist or was invalid. Compute a new
+		// entry atomically (guaranteed by ConcurrentHashMap).
+		return packCache.compute(dsc, (k, v) -> {
+			if (v != null && !v.invalid()) { // valid value added by
+				return v;                    // another thread
+			} else {
+				return new DfsPackFile(
+						this, dsc, key != null ? key : new DfsPackKey());
+			}
+		});
 	}
 
 	private int hash(int packHash, long off) {
@@ -416,6 +421,7 @@
 		clockLock.unlock();
 	}
 
+	@SuppressWarnings("unchecked")
 	private void addToClock(Ref ref, int credit) {
 		clockLock.lock();
 		try {
@@ -500,9 +506,7 @@
 	}
 
 	void remove(DfsPackFile pack) {
-		synchronized (packCache) {
-			packCache.remove(pack.getPackDescription());
-		}
+		packCache.remove(pack.getPackDescription());
 	}
 
 	private int slot(DfsPackKey pack, long position) {
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 a7d13de..089bfa4 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
@@ -47,6 +47,7 @@
 import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_DFS_SECTION;
 import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_BLOCK_LIMIT;
 import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_BLOCK_SIZE;
+import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_CONCURRENCY_LEVEL;
 import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_STREAM_RATIO;
 
 import java.text.MessageFormat;
@@ -65,12 +66,14 @@
 	private long blockLimit;
 	private int blockSize;
 	private double streamRatio;
+	private int concurrencyLevel;
 
 	/** Create a default configuration. */
 	public DfsBlockCacheConfig() {
 		setBlockLimit(32 * MB);
 		setBlockSize(64 * KB);
 		setStreamRatio(0.30);
+		setConcurrencyLevel(32);
 	}
 
 	/**
@@ -103,10 +106,38 @@
 	/**
 	 * @param newSize
 	 *            size in bytes of a single window read in from the pack file.
+	 *            The value must be a power of 2.
 	 * @return {@code this}
 	 */
 	public DfsBlockCacheConfig setBlockSize(final int newSize) {
-		blockSize = Math.max(512, newSize);
+		int size = Math.max(512, newSize);
+		if ((size & (size - 1)) != 0) {
+			throw new IllegalArgumentException(
+					JGitText.get().blockSizeNotPowerOf2);
+		}
+		blockSize = size;
+		return this;
+	}
+
+	/**
+	 * @return the estimated number of threads concurrently accessing the cache.
+	 *         <b>Default is 32.</b>
+	 * @since 4.6
+	 */
+	public int getConcurrencyLevel() {
+		return concurrencyLevel;
+	}
+
+	/**
+	 * @param newConcurrencyLevel
+	 *            the estimated number of threads concurrently accessing the
+	 *            cache.
+	 * @return {@code this}
+	 * @since 4.6
+	 */
+	public DfsBlockCacheConfig setConcurrencyLevel(
+			final int newConcurrencyLevel) {
+		concurrencyLevel = newConcurrencyLevel;
 		return this;
 	}
 
@@ -154,6 +185,12 @@
 				CONFIG_KEY_BLOCK_SIZE,
 				getBlockSize()));
 
+		setConcurrencyLevel(rc.getInt(
+				CONFIG_CORE_SECTION,
+				CONFIG_DFS_SECTION,
+				CONFIG_KEY_CONCURRENCY_LEVEL,
+				getConcurrencyLevel()));
+
 		String v = rc.getString(
 				CONFIG_CORE_SECTION,
 				CONFIG_DFS_SECTION,
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsInserter.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsInserter.java
index a5e920a..c179e77 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsInserter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsInserter.java
@@ -312,8 +312,7 @@
 		}
 
 		DfsOutputStream os = db.writeFile(pack, INDEX);
-		try {
-			CountingOutputStream cnt = new CountingOutputStream(os);
+		try (CountingOutputStream cnt = new CountingOutputStream(os)) {
 			if (buf != null)
 				buf.writeTo(cnt, null);
 			else
@@ -321,7 +320,9 @@
 			pack.addFileExt(INDEX);
 			pack.setFileSize(INDEX, cnt.getCount());
 		} finally {
-			os.close();
+			if (buf != null) {
+				buf.close();
+			}
 		}
 		return packIndex;
 	}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsReader.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsReader.java
index 2f61dea..8c93295 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsReader.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsReader.java
@@ -113,6 +113,7 @@
 
 	DfsReader(DfsObjDatabase db) {
 		this.db = db;
+		this.streamFileThreshold = db.getReaderOptions().getStreamFileThreshold();
 	}
 
 	DfsReaderOptions getOptions() {
@@ -125,10 +126,6 @@
 		return baseCache;
 	}
 
-	int getStreamFileThreshold() {
-		return getOptions().getStreamFileThreshold();
-	}
-
 	@Override
 	public ObjectReader newReader() {
 		return new DfsReader(db);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsRefUpdate.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsRefUpdate.java
index d872f97..1f26fe3 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsRefUpdate.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsRefUpdate.java
@@ -47,9 +47,9 @@
 
 import org.eclipse.jgit.lib.ObjectIdRef;
 import org.eclipse.jgit.lib.Ref;
+import org.eclipse.jgit.lib.Ref.Storage;
 import org.eclipse.jgit.lib.RefUpdate;
 import org.eclipse.jgit.lib.SymbolicRef;
-import org.eclipse.jgit.lib.Ref.Storage;
 import org.eclipse.jgit.revwalk.RevObject;
 import org.eclipse.jgit.revwalk.RevTag;
 import org.eclipse.jgit.revwalk.RevWalk;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/InMemoryRepository.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/InMemoryRepository.java
index 6f390a4..fd21397 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/InMemoryRepository.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/InMemoryRepository.java
@@ -16,6 +16,7 @@
 import java.util.concurrent.locks.ReadWriteLock;
 import java.util.concurrent.locks.ReentrantReadWriteLock;
 
+import org.eclipse.jgit.annotations.Nullable;
 import org.eclipse.jgit.internal.storage.pack.PackExt;
 import org.eclipse.jgit.lib.BatchRefUpdate;
 import org.eclipse.jgit.lib.ObjectId;
@@ -54,6 +55,7 @@
 
 	private final DfsObjDatabase objdb;
 	private final RefDatabase refdb;
+	private String gitwebDescription;
 	private boolean performsAtomicTransactions = true;
 
 	/**
@@ -94,6 +96,17 @@
 		performsAtomicTransactions = atomic;
 	}
 
+	@Override
+	@Nullable
+	public String getGitwebDescription() {
+		return gitwebDescription;
+	}
+
+	@Override
+	public void setGitwebDescription(@Nullable String d) {
+		gitwebDescription = d;
+	}
+
 	private class MemObjDatabase extends DfsObjDatabase {
 		private List<DfsPackDescription> packs = new ArrayList<DfsPackDescription>();
 
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/BasePackBitmapIndex.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/BasePackBitmapIndex.java
index 3c101e6..30e973e 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/BasePackBitmapIndex.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/BasePackBitmapIndex.java
@@ -43,11 +43,11 @@
 
 package org.eclipse.jgit.internal.storage.file;
 
-import com.googlecode.javaewah.EWAHCompressedBitmap;
-
 import org.eclipse.jgit.lib.AnyObjectId;
 import org.eclipse.jgit.lib.ObjectIdOwnerMap;
 
+import com.googlecode.javaewah.EWAHCompressedBitmap;
+
 /**
  * Base implementation of the PackBitmapIndex.
  */
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/BitSet.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/BitSet.java
index ddb5ff0..bafae87 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/BitSet.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/BitSet.java
@@ -96,7 +96,7 @@
 			}
 
 			if (lastNonEmptyWord != 0)
-				compressed.add(lastNonEmptyWord);
+				compressed.addWord(lastNonEmptyWord);
 
 			if (runningEmptyWords > 0) {
 				compressed.addStreamOfEmptyWords(false, runningEmptyWords);
@@ -107,7 +107,7 @@
 		}
 		int bitsThatMatter = 64 - Long.numberOfLeadingZeros(lastNonEmptyWord);
 		if (bitsThatMatter > 0)
-			compressed.add(lastNonEmptyWord, bitsThatMatter);
+			compressed.addWord(lastNonEmptyWord, bitsThatMatter);
 		return compressed;
 	}
 
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/BitmapIndexImpl.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/BitmapIndexImpl.java
index b27bcc4..b18a06f 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/BitmapIndexImpl.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/BitmapIndexImpl.java
@@ -47,9 +47,6 @@
 import java.util.Iterator;
 import java.util.NoSuchElementException;
 
-import com.googlecode.javaewah.EWAHCompressedBitmap;
-import com.googlecode.javaewah.IntIterator;
-
 import org.eclipse.jgit.internal.JGitText;
 import org.eclipse.jgit.lib.AnyObjectId;
 import org.eclipse.jgit.lib.BitmapIndex;
@@ -59,6 +56,9 @@
 import org.eclipse.jgit.lib.ObjectIdOwnerMap;
 import org.eclipse.jgit.util.BlockList;
 
+import com.googlecode.javaewah.EWAHCompressedBitmap;
+import com.googlecode.javaewah.IntIterator;
+
 /** A compressed bitmap representation of the entire object graph. */
 public class BitmapIndexImpl implements BitmapIndex {
 	private static final int EXTRA_BITS = 10 * 1024;
@@ -504,10 +504,10 @@
 	static final EWAHCompressedBitmap ones(int sizeInBits) {
 		EWAHCompressedBitmap mask = new EWAHCompressedBitmap();
 		mask.addStreamOfEmptyWords(
-				true, sizeInBits / EWAHCompressedBitmap.wordinbits);
-		int remaining = sizeInBits % EWAHCompressedBitmap.wordinbits;
+				true, sizeInBits / EWAHCompressedBitmap.WORD_IN_BITS);
+		int remaining = sizeInBits % EWAHCompressedBitmap.WORD_IN_BITS;
 		if (remaining > 0)
-			mask.add((1L << remaining) - 1, remaining);
+			mask.addWord((1L << remaining) - 1, remaining);
 		return mask;
 	}
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileRepository.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileRepository.java
index 53fd37e..0388acb 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileRepository.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileRepository.java
@@ -53,9 +53,13 @@
 import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.text.MessageFormat;
+import java.text.ParseException;
 import java.util.HashSet;
+import java.util.Objects;
 import java.util.Set;
 
+import org.eclipse.jgit.annotations.Nullable;
+import org.eclipse.jgit.api.errors.JGitInternalException;
 import org.eclipse.jgit.attributes.AttributesNode;
 import org.eclipse.jgit.attributes.AttributesNodeProvider;
 import org.eclipse.jgit.errors.ConfigInvalidException;
@@ -63,15 +67,16 @@
 import org.eclipse.jgit.events.ConfigChangedListener;
 import org.eclipse.jgit.events.IndexChangedEvent;
 import org.eclipse.jgit.internal.JGitText;
-import org.eclipse.jgit.internal.storage.reftree.RefTreeDatabase;
 import org.eclipse.jgit.internal.storage.file.ObjectDirectory.AlternateHandle;
 import org.eclipse.jgit.internal.storage.file.ObjectDirectory.AlternateRepository;
+import org.eclipse.jgit.internal.storage.reftree.RefTreeDatabase;
 import org.eclipse.jgit.lib.BaseRepositoryBuilder;
 import org.eclipse.jgit.lib.ConfigConstants;
 import org.eclipse.jgit.lib.Constants;
 import org.eclipse.jgit.lib.CoreConfig.HideDotFiles;
 import org.eclipse.jgit.lib.CoreConfig.SymLinks;
 import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.ProgressMonitor;
 import org.eclipse.jgit.lib.Ref;
 import org.eclipse.jgit.lib.RefDatabase;
 import org.eclipse.jgit.lib.RefUpdate;
@@ -79,8 +84,11 @@
 import org.eclipse.jgit.lib.Repository;
 import org.eclipse.jgit.storage.file.FileBasedConfig;
 import org.eclipse.jgit.storage.file.FileRepositoryBuilder;
+import org.eclipse.jgit.storage.pack.PackConfig;
 import org.eclipse.jgit.util.FS;
 import org.eclipse.jgit.util.FileUtils;
+import org.eclipse.jgit.util.IO;
+import org.eclipse.jgit.util.RawParseUtils;
 import org.eclipse.jgit.util.StringUtils;
 import org.eclipse.jgit.util.SystemReader;
 
@@ -110,16 +118,13 @@
  *
  */
 public class FileRepository extends Repository {
+	private static final String UNNAMED = "Unnamed repository; edit this file to name it for gitweb."; //$NON-NLS-1$
+
 	private final FileBasedConfig systemConfig;
-
 	private final FileBasedConfig userConfig;
-
 	private final FileBasedConfig repoConfig;
-
 	private final RefDatabase refs;
-
 	private final ObjectDirectory objectDatabase;
-
 	private FileSnapshot snapshot;
 
 	/**
@@ -177,10 +182,12 @@
 					getFS());
 		else
 			systemConfig = new FileBasedConfig(null, FS.DETECTED) {
+				@Override
 				public void load() {
 					// empty, do not load
 				}
 
+				@Override
 				public boolean isOutdated() {
 					// regular class would bomb here
 					return false;
@@ -197,6 +204,7 @@
 		loadRepoConfig();
 
 		repoConfig.addChangeListener(new ConfigChangedListener() {
+			@Override
 			public void onConfigChanged(ConfigChangedEvent event) {
 				fireEvent(event);
 			}
@@ -279,6 +287,7 @@
 	 * @throws IOException
 	 *             in case of IO problem
 	 */
+	@Override
 	public void create(boolean bare) throws IOException {
 		final FileBasedConfig cfg = getConfig();
 		if (cfg.getFile().exists()) {
@@ -376,21 +385,20 @@
 		return objectDatabase.getDirectory();
 	}
 
-	/**
-	 * @return the object database which stores this repository's data.
-	 */
+	/** @return the object database storing this repository's data. */
+	@Override
 	public ObjectDirectory getObjectDatabase() {
 		return objectDatabase;
 	}
 
 	/** @return the reference database which stores the reference namespace. */
+	@Override
 	public RefDatabase getRefDatabase() {
 		return refs;
 	}
 
-	/**
-	 * @return the configuration of this repository
-	 */
+	/** @return the configuration of this repository. */
+	@Override
 	public FileBasedConfig getConfig() {
 		if (systemConfig.isOutdated()) {
 			try {
@@ -416,6 +424,59 @@
 		return repoConfig;
 	}
 
+	@Override
+	@Nullable
+	public String getGitwebDescription() throws IOException {
+		String d;
+		try {
+			d = RawParseUtils.decode(IO.readFully(descriptionFile()));
+		} catch (FileNotFoundException err) {
+			return null;
+		}
+		if (d != null) {
+			d = d.trim();
+			if (d.isEmpty() || UNNAMED.equals(d)) {
+				return null;
+			}
+		}
+		return d;
+	}
+
+	@Override
+	public void setGitwebDescription(@Nullable String description)
+			throws IOException {
+		String old = getGitwebDescription();
+		if (Objects.equals(old, description)) {
+			return;
+		}
+
+		File path = descriptionFile();
+		LockFile lock = new LockFile(path);
+		if (!lock.lock()) {
+			throw new IOException(MessageFormat.format(JGitText.get().lockError,
+					path.getAbsolutePath()));
+		}
+		try {
+			String d = description;
+			if (d != null) {
+				d = d.trim();
+				if (!d.isEmpty()) {
+					d += '\n';
+				}
+			} else {
+				d = ""; //$NON-NLS-1$
+			}
+			lock.write(Constants.encode(d));
+			lock.commit();
+		} finally {
+			lock.unlock();
+		}
+	}
+
+	private File descriptionFile() {
+		return new File(getDirectory(), "description"); //$NON-NLS-1$
+	}
+
 	/**
 	 * Objects known to exist but not expressed by {@link #getAllRefs()}.
 	 * <p>
@@ -426,6 +487,7 @@
 	 *
 	 * @return unmodifiable collection of other known objects.
 	 */
+	@Override
 	public Set<ObjectId> getAdditionalHaves() {
 		HashSet<ObjectId> r = new HashSet<ObjectId>();
 		for (AlternateHandle d : objectDatabase.myAlternates()) {
@@ -464,9 +526,7 @@
 		detectIndexChanges();
 	}
 
-	/**
-	 * Detect index changes.
-	 */
+	/** Detect index changes. */
 	private void detectIndexChanges() {
 		if (isBare())
 			return;
@@ -490,6 +550,7 @@
 	 *         named ref does not exist.
 	 * @throws IOException the ref could not be accessed.
 	 */
+	@Override
 	public ReflogReader getReflogReader(String refName) throws IOException {
 		Ref ref = findRef(refName);
 		if (ref != null)
@@ -527,6 +588,7 @@
 			globalAttributesNode = new GlobalAttributesNode(repo);
 		}
 
+		@Override
 		public AttributesNode getInfoAttributesNode() throws IOException {
 			if (infoAttributesNode instanceof InfoAttributesNode)
 				infoAttributesNode = ((InfoAttributesNode) infoAttributesNode)
@@ -534,6 +596,7 @@
 			return infoAttributesNode;
 		}
 
+		@Override
 		public AttributesNode getGlobalAttributesNode() throws IOException {
 			if (globalAttributesNode instanceof GlobalAttributesNode)
 				globalAttributesNode = ((GlobalAttributesNode) globalAttributesNode)
@@ -555,4 +618,16 @@
 
 	}
 
+	@Override
+	public void autoGC(ProgressMonitor monitor) {
+		GC gc = new GC(this);
+		gc.setPackConfig(new PackConfig(this));
+		gc.setProgressMonitor(monitor);
+		gc.setAuto(true);
+		try {
+			gc.gc();
+		} catch (ParseException | IOException e) {
+			throw new JGitInternalException(JGitText.get().gcFailed, e);
+		}
+	}
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileSnapshot.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileSnapshot.java
index 8926d79..97f3b57 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileSnapshot.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileSnapshot.java
@@ -264,12 +264,6 @@
 			return false;
 		}
 
-		// Our lastRead flag may be old, refresh and retry
-		lastRead = System.currentTimeMillis();
-		if (notRacyClean(lastRead)) {
-			return false;
-		}
-
 		// We last read this path too close to its last observed
 		// modification time. We may have missed a modification.
 		// Scan again, to ensure we still see the same state.
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 a3e9430..b608416 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
@@ -52,6 +52,10 @@
 import java.io.OutputStream;
 import java.nio.channels.Channels;
 import java.nio.channels.FileChannel;
+import java.nio.file.DirectoryStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
 import java.nio.file.StandardCopyOption;
 import java.text.MessageFormat;
 import java.text.ParseException;
@@ -62,12 +66,16 @@
 import java.util.Date;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
 import java.util.Set;
 import java.util.TreeMap;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
 
 import org.eclipse.jgit.annotations.NonNull;
 import org.eclipse.jgit.dircache.DirCacheIterator;
@@ -100,6 +108,8 @@
 import org.eclipse.jgit.util.FileUtils;
 import org.eclipse.jgit.util.GitDateParser;
 import org.eclipse.jgit.util.SystemReader;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 /**
  * A garbage collector for git {@link FileRepository}. Instances of this class
@@ -109,10 +119,27 @@
  * adapted to FileRepositories.
  */
 public class GC {
+	private final static Logger LOG = LoggerFactory
+			.getLogger(GC.class);
+
 	private static final String PRUNE_EXPIRE_DEFAULT = "2.weeks.ago"; //$NON-NLS-1$
 
 	private static final String PRUNE_PACK_EXPIRE_DEFAULT = "1.hour.ago"; //$NON-NLS-1$
 
+	private static final Pattern PATTERN_LOOSE_OBJECT = Pattern
+			.compile("[0-9a-fA-F]{38}"); //$NON-NLS-1$
+
+	private static final String PACK_EXT = "." + PackExt.PACK.getExtension();//$NON-NLS-1$
+
+	private static final String BITMAP_EXT = "." //$NON-NLS-1$
+			+ PackExt.BITMAP_INDEX.getExtension();
+
+	private static final String INDEX_EXT = "." + PackExt.INDEX.getExtension(); //$NON-NLS-1$
+
+	private static final int DEFAULT_AUTOPACKLIMIT = 50;
+
+	private static final int DEFAULT_AUTOLIMIT = 6700;
+
 	private final FileRepository repo;
 
 	private ProgressMonitor pm;
@@ -143,6 +170,11 @@
 	private long lastRepackTime;
 
 	/**
+	 * Whether gc should do automatic housekeeping
+	 */
+	private boolean automatic;
+
+	/**
 	 * Creates a new garbage collector with default values. An expirationTime of
 	 * two weeks and <code>null</code> as progress monitor will be used.
 	 *
@@ -163,6 +195,10 @@
 	 * <li>prune all loose objects which are now reachable by packs</li>
 	 * </ul>
 	 *
+	 * If {@link #setAuto(boolean)} was set to {@code true} {@code gc} will
+	 * first check whether any housekeeping is required; if not, it exits
+	 * without performing any work.
+	 *
 	 * @return the collection of {@link PackFile}'s which are newly created
 	 * @throws IOException
 	 * @throws ParseException
@@ -170,6 +206,9 @@
 	 *             parsed
 	 */
 	public Collection<PackFile> gc() throws IOException, ParseException {
+		if (automatic && !needGc()) {
+			return Collections.emptyList();
+		}
 		pm.start(6 /* tasks */);
 		packRefs();
 		// TODO: implement reflog_expire(pm, repo);
@@ -325,45 +364,48 @@
 		Set<ObjectId> indexObjects = null;
 		File objects = repo.getObjectsDirectory();
 		String[] fanout = objects.list();
-		if (fanout != null && fanout.length > 0) {
-			pm.beginTask(JGitText.get().pruneLooseUnreferencedObjects,
-					fanout.length);
-			try {
-				for (String d : fanout) {
-					pm.update(1);
-					if (d.length() != 2)
+		if (fanout == null || fanout.length == 0) {
+			return;
+		}
+		pm.beginTask(JGitText.get().pruneLooseUnreferencedObjects,
+				fanout.length);
+		try {
+			for (String d : fanout) {
+				pm.update(1);
+				if (d.length() != 2)
+					continue;
+				File[] entries = new File(objects, d).listFiles();
+				if (entries == null)
+					continue;
+				for (File f : entries) {
+					String fName = f.getName();
+					if (fName.length() != Constants.OBJECT_ID_STRING_LENGTH - 2)
 						continue;
-					File[] entries = new File(objects, d).listFiles();
-					if (entries == null)
+					if (repo.getFS().lastModified(f) >= expireDate)
 						continue;
-					for (File f : entries) {
-						String fName = f.getName();
-						if (fName.length() != Constants.OBJECT_ID_STRING_LENGTH - 2)
+					try {
+						ObjectId id = ObjectId.fromString(d + fName);
+						if (objectsToKeep.contains(id))
 							continue;
-						if (repo.getFS().lastModified(f) >= expireDate)
+						if (indexObjects == null)
+							indexObjects = listNonHEADIndexObjects();
+						if (indexObjects.contains(id))
 							continue;
-						try {
-							ObjectId id = ObjectId.fromString(d + fName);
-							if (objectsToKeep.contains(id))
-								continue;
-							if (indexObjects == null)
-								indexObjects = listNonHEADIndexObjects();
-							if (indexObjects.contains(id))
-								continue;
-							deletionCandidates.put(id, f);
-						} catch (IllegalArgumentException notAnObject) {
-							// ignoring the file that does not represent loose
-							// object
-							continue;
-						}
+						deletionCandidates.put(id, f);
+					} catch (IllegalArgumentException notAnObject) {
+						// ignoring the file that does not represent loose
+						// object
+						continue;
 					}
 				}
-			} finally {
-				pm.endTask();
 			}
+		} finally {
+			pm.endTask();
 		}
-		if (deletionCandidates.isEmpty())
+
+		if (deletionCandidates.isEmpty()) {
 			return;
+		}
 
 		// From the set of current refs remove all those which have been handled
 		// during last repack(). Only those refs will survive which have been
@@ -433,12 +475,19 @@
 		// loose objects. Make a last check, though, to avoid deleting objects
 		// that could have been referenced while the candidates list was being
 		// built (by an incoming push, for example).
+		Set<File> touchedFanout = new HashSet<>();
 		for (File f : deletionCandidates.values()) {
 			if (f.lastModified() < expireDate) {
 				f.delete();
+				touchedFanout.add(f.getParentFile());
 			}
 		}
 
+		for (File f : touchedFanout) {
+			FileUtils.delete(f,
+					FileUtils.EMPTY_DIRECTORIES_ONLY | FileUtils.IGNORE_ERRORS);
+		}
+
 		repo.getObjectDatabase().close();
 	}
 
@@ -625,6 +674,7 @@
 			throw new IOException(e);
 		}
 		prunePacked();
+		deleteOrphans();
 
 		lastPackedRefs = refsBefore;
 		lastRepackTime = time;
@@ -632,6 +682,48 @@
 	}
 
 	/**
+	 * Deletes orphans
+	 * <p>
+	 * A file is considered an orphan if it is either a "bitmap" or an index
+	 * file, and its corresponding pack file is missing in the list.
+	 * </p>
+	 */
+	private void deleteOrphans() {
+		Path packDir = Paths.get(repo.getObjectsDirectory().getAbsolutePath(),
+				"pack"); //$NON-NLS-1$
+		List<String> fileNames = null;
+		try (Stream<Path> files = Files.list(packDir)) {
+			fileNames = files.map(path -> path.getFileName().toString())
+					.filter(name -> {
+						return (name.endsWith(PACK_EXT)
+								|| name.endsWith(BITMAP_EXT)
+								|| name.endsWith(INDEX_EXT));
+					}).sorted(Collections.reverseOrder())
+					.collect(Collectors.toList());
+		} catch (IOException e1) {
+			// ignore
+		}
+		if (fileNames == null) {
+			return;
+		}
+
+		String base = null;
+		for (String n : fileNames) {
+			if (n.endsWith(PACK_EXT)) {
+				base = n.substring(0, n.lastIndexOf('.'));
+			} else {
+				if (base == null || !n.startsWith(base)) {
+					try {
+						Files.delete(new File(packDir.toFile(), n).toPath());
+					} catch (IOException e) {
+						LOG.error(e.getMessage(), e);
+					}
+				}
+			}
+		}
+	}
+
+	/**
 	 * @param ref
 	 *            the ref which log should be inspected
 	 * @param minTime only reflog entries not older then this time are processed
@@ -1081,4 +1173,114 @@
 		this.packExpire = packExpire;
 		packExpireAgeMillis = -1;
 	}
+
+	/**
+	 * Set the {@code gc --auto} option.
+	 *
+	 * With this option, gc checks whether any housekeeping is required; if not,
+	 * it exits without performing any work. Some JGit commands run
+	 * {@code gc --auto} after performing operations that could create many
+	 * loose objects.
+	 * <p/>
+	 * Housekeeping is required if there are too many loose objects or too many
+	 * packs in the repository. If the number of loose objects exceeds the value
+	 * of the gc.auto option JGit GC consolidates all existing packs into a
+	 * single pack (equivalent to {@code -A} option), whereas git-core would
+	 * combine all loose objects into a single pack using {@code repack -d -l}.
+	 * Setting the value of {@code gc.auto} to 0 disables automatic packing of
+	 * loose objects.
+	 * <p/>
+	 * If the number of packs exceeds the value of {@code gc.autoPackLimit},
+	 * then existing packs (except those marked with a .keep file) are
+	 * consolidated into a single pack by using the {@code -A} option of repack.
+	 * Setting {@code gc.autoPackLimit} to 0 disables automatic consolidation of
+	 * packs.
+	 * <p/>
+	 * Like git the following jgit commands run auto gc:
+	 * <ul>
+	 * <li>fetch</li>
+	 * <li>merge</li>
+	 * <li>rebase</li>
+	 * <li>receive-pack</li>
+	 * </ul>
+	 * The auto gc for receive-pack can be suppressed by setting the config
+	 * option {@code receive.autogc = false}
+	 *
+	 * @param auto
+	 *            defines whether gc should do automatic housekeeping
+	 * @since 4.5
+	 */
+	public void setAuto(boolean auto) {
+		this.automatic = auto;
+	}
+
+	private boolean needGc() {
+		if (tooManyPacks()) {
+			addRepackAllOption();
+		} else if (!tooManyLooseObjects()) {
+			return false;
+		}
+		// TODO run pre-auto-gc hook, if it fails return false
+		return true;
+	}
+
+	private void addRepackAllOption() {
+		// TODO: if JGit GC is enhanced to support repack's option -l this
+		// method needs to be implemented
+	}
+
+	/**
+	 * @return {@code true} if number of packs > gc.autopacklimit (default 50)
+	 */
+	boolean tooManyPacks() {
+		int autopacklimit = repo.getConfig().getInt(
+				ConfigConstants.CONFIG_GC_SECTION,
+				ConfigConstants.CONFIG_KEY_AUTOPACKLIMIT,
+				DEFAULT_AUTOPACKLIMIT);
+		if (autopacklimit <= 0) {
+			return false;
+		}
+		// JGit always creates two packfiles, one for the objects reachable from
+		// branches, and another one for the rest
+		return repo.getObjectDatabase().getPacks().size() > (autopacklimit + 1);
+	}
+
+	/**
+	 * Quickly estimate number of loose objects, SHA1 is distributed evenly so
+	 * counting objects in one directory (bucket 17) is sufficient
+	 *
+	 * @return {@code true} if number of loose objects > gc.auto (default 6700)
+	 */
+	boolean tooManyLooseObjects() {
+		int auto = repo.getConfig().getInt(ConfigConstants.CONFIG_GC_SECTION,
+				ConfigConstants.CONFIG_KEY_AUTO, DEFAULT_AUTOLIMIT);
+		if (auto <= 0) {
+			return false;
+		}
+		int n = 0;
+		int threshold = (auto + 255) / 256;
+		Path dir = repo.getObjectsDirectory().toPath().resolve("17"); //$NON-NLS-1$
+		if (!Files.exists(dir)) {
+			return false;
+		}
+		try (DirectoryStream<Path> stream = Files.newDirectoryStream(dir,
+				new DirectoryStream.Filter<Path>() {
+
+					public boolean accept(Path file) throws IOException {
+						return Files.isRegularFile(file) && PATTERN_LOOSE_OBJECT
+								.matcher(file.getFileName().toString())
+								.matches();
+					}
+				})) {
+			for (Iterator<Path> iter = stream.iterator(); iter.hasNext();
+					iter.next()) {
+				if (++n > threshold) {
+					return true;
+				}
+			}
+		} catch (IOException e) {
+			LOG.error(e.getMessage(), e);
+		}
+		return false;
+	}
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackBitmapIndex.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackBitmapIndex.java
index e743cb4..7fb8e6d 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackBitmapIndex.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackBitmapIndex.java
@@ -49,13 +49,13 @@
 import java.io.InputStream;
 import java.text.MessageFormat;
 
-import com.googlecode.javaewah.EWAHCompressedBitmap;
-
 import org.eclipse.jgit.errors.CorruptObjectException;
 import org.eclipse.jgit.internal.JGitText;
 import org.eclipse.jgit.lib.AnyObjectId;
 import org.eclipse.jgit.lib.ObjectId;
 
+import com.googlecode.javaewah.EWAHCompressedBitmap;
+
 /**
  * Logical representation of the bitmap data stored in the pack index.
  * {@link ObjectId}s are encoded as a single integer in the range [0,
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackBitmapIndexBuilder.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackBitmapIndexBuilder.java
index 4ff09a1..956e8de 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackBitmapIndexBuilder.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackBitmapIndexBuilder.java
@@ -50,8 +50,6 @@
 import java.util.List;
 import java.util.NoSuchElementException;
 
-import com.googlecode.javaewah.EWAHCompressedBitmap;
-
 import org.eclipse.jgit.internal.JGitText;
 import org.eclipse.jgit.internal.storage.file.BitmapIndexImpl.CompressedBitmap;
 import org.eclipse.jgit.internal.storage.pack.ObjectToPack;
@@ -63,6 +61,8 @@
 import org.eclipse.jgit.lib.ObjectIdOwnerMap;
 import org.eclipse.jgit.util.BlockList;
 
+import com.googlecode.javaewah.EWAHCompressedBitmap;
+
 /**
  * Helper for constructing {@link PackBitmapIndex}es.
  */
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackBitmapIndexRemapper.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackBitmapIndexRemapper.java
index 7cd68b6..2c462a7 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackBitmapIndexRemapper.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackBitmapIndexRemapper.java
@@ -47,15 +47,15 @@
 import java.util.Iterator;
 import java.util.NoSuchElementException;
 
-import com.googlecode.javaewah.EWAHCompressedBitmap;
-import com.googlecode.javaewah.IntIterator;
-
 import org.eclipse.jgit.internal.storage.file.BasePackBitmapIndex.StoredBitmap;
 import org.eclipse.jgit.lib.AnyObjectId;
 import org.eclipse.jgit.lib.BitmapIndex;
 import org.eclipse.jgit.lib.ObjectId;
 import org.eclipse.jgit.lib.ObjectIdOwnerMap;
 
+import com.googlecode.javaewah.EWAHCompressedBitmap;
+import com.googlecode.javaewah.IntIterator;
+
 /**
  * A PackBitmapIndex that remaps the bitmaps in the previous index to the
  * positions in the new pack index. Note, unlike typical PackBitmapIndex
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackBitmapIndexV1.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackBitmapIndexV1.java
index a7ab00d..9d2c70b 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackBitmapIndexV1.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackBitmapIndexV1.java
@@ -49,8 +49,6 @@
 import java.text.MessageFormat;
 import java.util.Arrays;
 
-import com.googlecode.javaewah.EWAHCompressedBitmap;
-
 import org.eclipse.jgit.internal.JGitText;
 import org.eclipse.jgit.lib.AnyObjectId;
 import org.eclipse.jgit.lib.Constants;
@@ -59,6 +57,8 @@
 import org.eclipse.jgit.util.IO;
 import org.eclipse.jgit.util.NB;
 
+import com.googlecode.javaewah.EWAHCompressedBitmap;
+
 /**
  * Support for the pack bitmap index v1 format.
  *
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackBitmapIndexWriterV1.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackBitmapIndexWriterV1.java
index 8325e2e..f8f02e9 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackBitmapIndexWriterV1.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackBitmapIndexWriterV1.java
@@ -50,12 +50,11 @@
 import java.security.DigestOutputStream;
 import java.text.MessageFormat;
 
-import com.googlecode.javaewah.EWAHCompressedBitmap;
-
 import org.eclipse.jgit.internal.JGitText;
 import org.eclipse.jgit.internal.storage.file.PackBitmapIndexBuilder.StoredEntry;
 import org.eclipse.jgit.lib.Constants;
-import org.eclipse.jgit.util.io.SafeBufferedOutputStream;
+
+import com.googlecode.javaewah.EWAHCompressedBitmap;
 
 /**
  * Creates the version 1 pack bitmap index files.
@@ -74,7 +73,7 @@
 	 */
 	public PackBitmapIndexWriterV1(final OutputStream dst) {
 		out = new DigestOutputStream(dst instanceof BufferedOutputStream ? dst
-				: new SafeBufferedOutputStream(dst),
+				: new BufferedOutputStream(dst),
 				Constants.newMessageDigest());
 		dataOutput = new SimpleDataOutput(out);
 	}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackIndexWriter.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackIndexWriter.java
index 6dfe74b..5153911 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackIndexWriter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackIndexWriter.java
@@ -56,7 +56,6 @@
 import org.eclipse.jgit.lib.ObjectId;
 import org.eclipse.jgit.transport.PackedObjectInfo;
 import org.eclipse.jgit.util.NB;
-import org.eclipse.jgit.util.io.SafeBufferedOutputStream;
 
 /**
  * Creates a table of contents to support random access by {@link PackFile}.
@@ -183,7 +182,7 @@
 	 */
 	protected PackIndexWriter(final OutputStream dst) {
 		out = new DigestOutputStream(dst instanceof BufferedOutputStream ? dst
-				: new SafeBufferedOutputStream(dst),
+				: new BufferedOutputStream(dst),
 				Constants.newMessageDigest());
 		tmp = new byte[4 + Constants.OBJECT_ID_LENGTH];
 	}
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 1080659..e3d0d61 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
@@ -843,6 +843,11 @@
 			}
 
 			int sp = p.indexOf(' ');
+			if (sp < 0) {
+				throw new IOException(MessageFormat.format(
+						JGitText.get().packedRefsCorruptionDetected,
+						packedRefsFile.getAbsolutePath()));
+			}
 			ObjectId id = ObjectId.fromString(p.substring(0, sp));
 			String name = copy(p, sp + 1, p.length());
 			ObjectIdRef cur;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/WindowCursor.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/WindowCursor.java
index a2c0561..a742d17 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/WindowCursor.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/WindowCursor.java
@@ -94,12 +94,14 @@
 	WindowCursor(FileObjectDatabase db) {
 		this.db = db;
 		this.createdFromInserter = null;
+		this.streamFileThreshold = WindowCache.getStreamFileThreshold();
 	}
 
 	WindowCursor(FileObjectDatabase db,
 			@Nullable ObjectDirectoryInserter createdFromInserter) {
 		this.db = db;
 		this.createdFromInserter = createdFromInserter;
+		this.streamFileThreshold = WindowCache.getStreamFileThreshold();
 	}
 
 	DeltaBaseCache getDeltaBaseCache() {
@@ -337,10 +339,6 @@
 		}
 	}
 
-	int getStreamFileThreshold() {
-		return WindowCache.getStreamFileThreshold();
-	}
-
 	@Override
 	@Nullable
 	public ObjectInserter getCreatedFromInserter() {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackOutputStream.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackOutputStream.java
index be1e3d4..59166e6 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackOutputStream.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackOutputStream.java
@@ -183,7 +183,7 @@
 	public final void writeHeader(ObjectToPack otp, long rawLength)
 			throws IOException {
 		ObjectToPack b = otp.getDeltaBase();
-		if (b != null && (b.isWritten() & ofsDelta)) {
+		if (b != null && (b.isWritten() & ofsDelta)) { // Non-short-circuit logic is intentional
 			int n = objectHeader(rawLength, OBJ_OFS_DELTA, headerBuffer);
 			n = ofsDelta(count - b.getOffset(), headerBuffer, n);
 			write(headerBuffer, 0, n);
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 691867a..8b4d2e6 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
@@ -1597,14 +1597,15 @@
 			}
 		}
 
-		TemporaryBuffer.Heap delta = delta(otp);
-		out.writeHeader(otp, delta.length());
+		try (TemporaryBuffer.Heap delta = delta(otp)) {
+			out.writeHeader(otp, delta.length());
 
-		Deflater deflater = deflater();
-		deflater.reset();
-		DeflaterOutputStream dst = new DeflaterOutputStream(out, deflater);
-		delta.writeTo(dst, null);
-		dst.finish();
+			Deflater deflater = deflater();
+			deflater.reset();
+			DeflaterOutputStream dst = new DeflaterOutputStream(out, deflater);
+			delta.writeTo(dst, null);
+			dst.finish();
+		}
 		typeStats.cntDeltas++;
 		typeStats.deltaBytes += out.length() - otp.getOffset();
 	}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackWriterBitmapWalker.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackWriterBitmapWalker.java
index d9ac9ef..2ec4d56 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackWriterBitmapWalker.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackWriterBitmapWalker.java
@@ -49,11 +49,11 @@
 import org.eclipse.jgit.errors.IncorrectObjectTypeException;
 import org.eclipse.jgit.errors.MissingObjectException;
 import org.eclipse.jgit.lib.BitmapIndex;
+import org.eclipse.jgit.lib.BitmapIndex.Bitmap;
+import org.eclipse.jgit.lib.BitmapIndex.BitmapBuilder;
 import org.eclipse.jgit.lib.Constants;
 import org.eclipse.jgit.lib.NullProgressMonitor;
 import org.eclipse.jgit.lib.ObjectId;
-import org.eclipse.jgit.lib.BitmapIndex.Bitmap;
-import org.eclipse.jgit.lib.BitmapIndex.BitmapBuilder;
 import org.eclipse.jgit.lib.ProgressMonitor;
 import org.eclipse.jgit.revwalk.ObjectWalk;
 import org.eclipse.jgit.revwalk.RevCommit;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftree/Scanner.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftree/Scanner.java
index d383abf..2ef0f20 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftree/Scanner.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftree/Scanner.java
@@ -43,7 +43,6 @@
 
 package org.eclipse.jgit.internal.storage.reftree;
 
-import static org.eclipse.jgit.lib.RefDatabase.MAX_SYMBOLIC_REF_DEPTH;
 import static org.eclipse.jgit.lib.Constants.OBJ_BLOB;
 import static org.eclipse.jgit.lib.Constants.R_REFS;
 import static org.eclipse.jgit.lib.Constants.encode;
@@ -52,6 +51,7 @@
 import static org.eclipse.jgit.lib.FileMode.TYPE_TREE;
 import static org.eclipse.jgit.lib.Ref.Storage.NEW;
 import static org.eclipse.jgit.lib.Ref.Storage.PACKED;
+import static org.eclipse.jgit.lib.RefDatabase.MAX_SYMBOLIC_REF_DEPTH;
 
 import java.io.IOException;
 
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/BatchRefUpdate.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/BatchRefUpdate.java
index 8550ec3..653c9f6 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/BatchRefUpdate.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/BatchRefUpdate.java
@@ -49,18 +49,21 @@
 
 import java.io.IOException;
 import java.text.MessageFormat;
+import java.time.Duration;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
+import java.util.concurrent.TimeoutException;
 
 import org.eclipse.jgit.internal.JGitText;
 import org.eclipse.jgit.lib.RefUpdate.Result;
 import org.eclipse.jgit.revwalk.RevWalk;
 import org.eclipse.jgit.transport.PushCertificate;
 import org.eclipse.jgit.transport.ReceiveCommand;
+import org.eclipse.jgit.util.time.ProposedTimestamp;
 
 /**
  * Batch of reference updates to be applied to a repository.
@@ -69,6 +72,17 @@
  * server is making changes to more than one reference at a time.
  */
 public class BatchRefUpdate {
+	/**
+	 * Maximum delay the calling thread will tolerate while waiting for a
+	 * {@code MonotonicClock} to resolve associated {@link ProposedTimestamp}s.
+	 * <p>
+	 * A default of 5 seconds was chosen by guessing. A common assumption is
+	 * clock skew between machines on the same LAN using an NTP server also on
+	 * the same LAN should be under 5 seconds. 5 seconds is also not that long
+	 * for a large `git push` operation to complete.
+	 */
+	private static final Duration MAX_WAIT = Duration.ofSeconds(5);
+
 	private final RefDatabase refdb;
 
 	/** Commands to apply during this batch. */
@@ -95,6 +109,9 @@
 	/** Push options associated with this update. */
 	private List<String> pushOptions;
 
+	/** Associated timestamps that should be blocked on before update. */
+	private List<ProposedTimestamp> timestamps;
+
 	/**
 	 * Initialize a new batch update.
 	 *
@@ -314,6 +331,32 @@
 	}
 
 	/**
+	 * @return list of timestamps the batch must wait for.
+	 * @since 4.6
+	 */
+	public List<ProposedTimestamp> getProposedTimestamps() {
+		if (timestamps != null) {
+			return Collections.unmodifiableList(timestamps);
+		}
+		return Collections.emptyList();
+	}
+
+	/**
+	 * Request the batch to wait for the affected timestamps to resolve.
+	 *
+	 * @param ts
+	 * @return {@code this}.
+	 * @since 4.6
+	 */
+	public BatchRefUpdate addProposedTimestamp(ProposedTimestamp ts) {
+		if (timestamps == null) {
+			timestamps = new ArrayList<>(4);
+		}
+		timestamps.add(ts);
+		return this;
+	}
+
+	/**
 	 * Execute this batch update.
 	 * <p>
 	 * The default implementation of this method performs a sequential reference
@@ -348,6 +391,9 @@
 			}
 			return;
 		}
+		if (!blockUntilTimestamps(MAX_WAIT)) {
+			return;
+		}
 
 		if (options != null) {
 			pushOptions = options;
@@ -433,6 +479,33 @@
 	}
 
 	/**
+	 * Wait for timestamps to be in the past, aborting commands on timeout.
+	 *
+	 * @param maxWait
+	 *            maximum amount of time to wait for timestamps to resolve.
+	 * @return true if timestamps were successfully waited for; false if
+	 *         commands were aborted.
+	 * @since 4.6
+	 */
+	protected boolean blockUntilTimestamps(Duration maxWait) {
+		if (timestamps == null) {
+			return true;
+		}
+		try {
+			ProposedTimestamp.blockUntil(timestamps, maxWait);
+			return true;
+		} catch (TimeoutException | InterruptedException e) {
+			String msg = JGitText.get().timeIsUncertain;
+			for (ReceiveCommand c : commands) {
+				if (c.getResult() == NOT_ATTEMPTED) {
+					c.setResult(REJECTED_OTHER_REASON, msg);
+				}
+			}
+			return false;
+		}
+	}
+
+	/**
 	 * Execute this batch update without option strings.
 	 *
 	 * @param walk
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java
index 9e3e0b7..cde41c2 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java
@@ -65,6 +65,12 @@
 	/** The "dfs" section */
 	public static final String CONFIG_DFS_SECTION = "dfs";
 
+	/**
+	 * The "receive" section
+	 * @since 4.6
+	 */
+	public static final String CONFIG_RECEIVE_SECTION = "receive";
+
 	/** The "user" section */
 	public static final String CONFIG_USER_SECTION = "user";
 
@@ -101,6 +107,12 @@
 	 */
 	public static final String CONFIG_PULL_SECTION = "pull";
 
+	/**
+	 * The "filter" section
+	 * @since 4.6
+	 */
+	public static final String CONFIG_FILTER_SECTION = "filter";
+
 	/** The "algorithm" key */
 	public static final String CONFIG_KEY_ALGORITHM = "algorithm";
 
@@ -108,6 +120,24 @@
 	public static final String CONFIG_KEY_AUTOCRLF = "autocrlf";
 
 	/**
+	 * The "auto" key
+	 * @since 4.6
+	 */
+	public static final String CONFIG_KEY_AUTO = "auto";
+
+	/**
+	 * The "autogc" key
+	 * @since 4.6
+	 */
+	public static final String CONFIG_KEY_AUTOGC = "autogc";
+
+	/**
+	 * The "autopacklimit" key
+	 * @since 4.6
+	 */
+	public static final String CONFIG_KEY_AUTOPACKLIMIT = "autopacklimit";
+
+	/**
 	 * The "eol" key
 	 *
 	 * @since 4.3
@@ -145,6 +175,13 @@
 	/** The "blockSize" key */
 	public static final String CONFIG_KEY_BLOCK_SIZE = "blockSize";
 
+	/**
+	 * The "concurrencyLevel" key
+	 *
+	 * @since 4.6
+	 */
+	public static final String CONFIG_KEY_CONCURRENCY_LEVEL = "concurrencyLevel";
+
 	/** The "deltaBaseCacheLimit" key */
 	public static final String CONFIG_KEY_DELTA_BASE_CACHE_LIMIT = "deltaBaseCacheLimit";
 
@@ -330,4 +367,11 @@
 	 * @since 4.0
 	 */
 	public static final String CONFIG_KEY_STREAM_RATIO = "streamRatio";
+
+	/**
+	 * Flag in the filter section whether to use JGit's implementations of
+	 * filters and hooks
+	 * @since 4.6
+	 */
+	public static final String CONFIG_KEY_USEJGITBUILTIN = "useJGitBuiltin";
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Constants.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Constants.java
index d30edaf..ff80672 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Constants.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Constants.java
@@ -391,6 +391,13 @@
 	 */
 	public static final String ATTR_FILTER_TYPE_SMUDGE = "smudge";
 
+	/**
+	 * Builtin filter commands start with this prefix
+	 *
+	 * @since 4.6
+	 */
+	public static final String BUILTIN_FILTER_PREFIX = "jgit://builtin/";
+
 	/** Name of the ignore file */
 	public static final String DOT_GIT_IGNORE = ".gitignore";
 
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/IndexDiff.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/IndexDiff.java
index 9e474f8..af6a4fb 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/IndexDiff.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/IndexDiff.java
@@ -65,7 +65,6 @@
 import org.eclipse.jgit.errors.MissingObjectException;
 import org.eclipse.jgit.errors.StopWalkException;
 import org.eclipse.jgit.internal.JGitText;
-import org.eclipse.jgit.revwalk.RevTree;
 import org.eclipse.jgit.revwalk.RevWalk;
 import org.eclipse.jgit.submodule.SubmoduleWalk;
 import org.eclipse.jgit.submodule.SubmoduleWalk.IgnoreSubmoduleMode;
@@ -73,8 +72,8 @@
 import org.eclipse.jgit.treewalk.EmptyTreeIterator;
 import org.eclipse.jgit.treewalk.FileTreeIterator;
 import org.eclipse.jgit.treewalk.TreeWalk;
-import org.eclipse.jgit.treewalk.WorkingTreeIterator;
 import org.eclipse.jgit.treewalk.TreeWalk.OperationType;
+import org.eclipse.jgit.treewalk.WorkingTreeIterator;
 import org.eclipse.jgit.treewalk.filter.AndTreeFilter;
 import org.eclipse.jgit.treewalk.filter.IndexDiffFilter;
 import org.eclipse.jgit.treewalk.filter.SkipWorkTreeFilter;
@@ -248,7 +247,7 @@
 
 	private final Repository repository;
 
-	private final RevTree tree;
+	private final AnyObjectId tree;
 
 	private TreeFilter filter = null;
 
@@ -311,10 +310,13 @@
 	public IndexDiff(Repository repository, ObjectId objectId,
 			WorkingTreeIterator workingTreeIterator) throws IOException {
 		this.repository = repository;
-		if (objectId != null)
-			tree = new RevWalk(repository).parseTree(objectId);
-		else
+		if (objectId != null) {
+			try (RevWalk rw = new RevWalk(repository)) {
+				tree = rw.parseTree(objectId);
+			}
+		} else {
 			tree = null;
+		}
 		this.initialWorkingTreeIterator = workingTreeIterator;
 	}
 
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectChecker.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectChecker.java
index 0b5efd7..feecbd8 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectChecker.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectChecker.java
@@ -709,11 +709,12 @@
 		return ptr;
 	}
 
-	@SuppressWarnings("resource")
 	@Nullable
 	private ObjectId idFor(int objType, byte[] raw) {
 		if (skipList != null) {
-			return new ObjectInserter.Formatter().idFor(objType, raw);
+			try (ObjectInserter.Formatter fmt = new ObjectInserter.Formatter()) {
+				return fmt.idFor(objType, raw);
+			}
 		}
 		return null;
 	}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectId.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectId.java
index 4edb38c..2a2d67d 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectId.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectId.java
@@ -44,15 +44,15 @@
 
 package org.eclipse.jgit.lib;
 
-import org.eclipse.jgit.errors.InvalidObjectIdException;
-import org.eclipse.jgit.util.NB;
-import org.eclipse.jgit.util.RawParseUtils;
-
 import java.io.IOException;
 import java.io.ObjectInputStream;
 import java.io.ObjectOutputStream;
 import java.io.Serializable;
 
+import org.eclipse.jgit.errors.InvalidObjectIdException;
+import org.eclipse.jgit.util.NB;
+import org.eclipse.jgit.util.RawParseUtils;
+
 /**
  * A SHA-1 abstraction.
  */
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectIdOwnerMap.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectIdOwnerMap.java
index 442261c..95cb976 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectIdOwnerMap.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectIdOwnerMap.java
@@ -143,6 +143,7 @@
 	 *            object to find.
 	 * @return true if the mapping exists for this object; false otherwise.
 	 */
+	@Override
 	public boolean contains(final AnyObjectId toFind) {
 		return get(toFind) != null;
 	}
@@ -219,20 +220,20 @@
 		return size == 0;
 	}
 
+	@Override
 	public Iterator<V> iterator() {
 		return new Iterator<V>() {
 			private int found;
-
 			private int dirIdx;
-
 			private int tblIdx;
-
 			private V next;
 
+			@Override
 			public boolean hasNext() {
 				return found < size;
 			}
 
+			@Override
 			public V next() {
 				if (next != null)
 					return found(next);
@@ -261,6 +262,7 @@
 				return v;
 			}
 
+			@Override
 			public void remove() {
 				throw new UnsupportedOperationException();
 			}
@@ -341,7 +343,7 @@
 
 	/** Type of entry stored in the {@link ObjectIdOwnerMap}. */
 	public static abstract class Entry extends ObjectId {
-		Entry next;
+		transient Entry next;
 
 		/**
 		 * Initialize this entry with a specific ObjectId.
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectReader.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectReader.java
index b23145d..372da98 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectReader.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectReader.java
@@ -66,6 +66,13 @@
 	public static final int OBJ_ANY = -1;
 
 	/**
+	 * The threshold at which a file will be streamed rather than loaded
+	 * entirely into memory.
+	 * @since 4.6
+	 */
+	protected int streamFileThreshold;
+
+	/**
 	 * Construct a new reader from the same data.
 	 * <p>
 	 * Applications can use this method to build a new reader from the same data
@@ -445,6 +452,29 @@
 	public abstract void close();
 
 	/**
+	 * Sets the threshold at which a file will be streamed rather than loaded
+	 * entirely into memory
+	 *
+	 * @param threshold
+	 *            the new threshold
+	 * @since 4.6
+	 */
+	public void setStreamFileThreshold(int threshold) {
+		streamFileThreshold = threshold;
+	}
+
+	/**
+	 * Returns the threshold at which a file will be streamed rather than loaded
+	 * entirely into memory
+	 *
+	 * @return the threshold in bytes
+	 * @since 4.6
+	 */
+	public int getStreamFileThreshold() {
+		return streamFileThreshold;
+	}
+
+	/**
 	 * Wraps a delegate ObjectReader.
 	 *
 	 * @since 4.4
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/PersonIdent.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/PersonIdent.java
index e08a985..627ccaa 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/PersonIdent.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/PersonIdent.java
@@ -53,6 +53,7 @@
 
 import org.eclipse.jgit.internal.JGitText;
 import org.eclipse.jgit.util.SystemReader;
+import org.eclipse.jgit.util.time.ProposedTimestamp;
 
 /**
  * A combination of a person identity and time in Git.
@@ -189,6 +190,19 @@
 	}
 
 	/**
+	 * Construct a new {@link PersonIdent} with current time.
+	 *
+	 * @param aName
+	 * @param aEmailAddress
+	 * @param when
+	 * @since 4.6
+	 */
+	public PersonIdent(String aName, String aEmailAddress,
+			ProposedTimestamp when) {
+		this(aName, aEmailAddress, when.millis());
+	}
+
+	/**
 	 * Copy a PersonIdent, but alter the clone's time stamp
 	 *
 	 * @param pi
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/RebaseTodoFile.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/RebaseTodoFile.java
index 4ebe5fe..75a3592 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/RebaseTodoFile.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/RebaseTodoFile.java
@@ -43,6 +43,7 @@
 
 package org.eclipse.jgit.lib;
 
+import java.io.BufferedOutputStream;
 import java.io.File;
 import java.io.FileOutputStream;
 import java.io.IOException;
@@ -53,7 +54,6 @@
 import org.eclipse.jgit.lib.RebaseTodoLine.Action;
 import org.eclipse.jgit.util.IO;
 import org.eclipse.jgit.util.RawParseUtils;
-import org.eclipse.jgit.util.io.SafeBufferedOutputStream;
 
 /**
  * Offers methods to read and write files formatted like the git-rebase-todo
@@ -216,9 +216,8 @@
 	 */
 	public void writeRebaseTodoFile(String path, List<RebaseTodoLine> steps,
 			boolean append) throws IOException {
-		OutputStream fw = new SafeBufferedOutputStream(new FileOutputStream(
-				new File(repo.getDirectory(), path), append));
-		try {
+		try (OutputStream fw = new BufferedOutputStream(new FileOutputStream(
+				new File(repo.getDirectory(), path), append))) {
 			StringBuilder sb = new StringBuilder();
 			for (RebaseTodoLine step : steps) {
 				sb.setLength(0);
@@ -234,8 +233,6 @@
 				sb.append('\n');
 				fw.write(Constants.encode(sb.toString()));
 			}
-		} finally {
-			fw.close();
 		}
 	}
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ReflogEntry.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ReflogEntry.java
index e2102e5..0504646 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ReflogEntry.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ReflogEntry.java
@@ -42,9 +42,6 @@
  */
 package org.eclipse.jgit.lib;
 
-import org.eclipse.jgit.lib.ObjectId;
-import org.eclipse.jgit.lib.PersonIdent;
-
 /**
  * Parsed reflog entry
  *
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 aba5242..c5b2ef8 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Repository.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Repository.java
@@ -52,6 +52,7 @@
 import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
 import java.io.IOException;
+import java.io.OutputStream;
 import java.net.URISyntaxException;
 import java.text.MessageFormat;
 import java.util.Collection;
@@ -80,6 +81,7 @@
 import org.eclipse.jgit.events.ListenerList;
 import org.eclipse.jgit.events.RepositoryEvent;
 import org.eclipse.jgit.internal.JGitText;
+import org.eclipse.jgit.internal.storage.file.GC;
 import org.eclipse.jgit.revwalk.RevBlob;
 import org.eclipse.jgit.revwalk.RevCommit;
 import org.eclipse.jgit.revwalk.RevObject;
@@ -93,7 +95,6 @@
 import org.eclipse.jgit.util.IO;
 import org.eclipse.jgit.util.RawParseUtils;
 import org.eclipse.jgit.util.SystemReader;
-import org.eclipse.jgit.util.io.SafeBufferedOutputStream;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -106,8 +107,7 @@
  * This class is thread-safe.
  */
 public abstract class Repository implements AutoCloseable {
-	private static Logger LOG = LoggerFactory.getLogger(Repository.class);
-
+	private static final Logger LOG = LoggerFactory.getLogger(Repository.class);
 	private static final ListenerList globalListeners = new ListenerList();
 
 	/** @return the global listener list observing all events in this JVM. */
@@ -245,7 +245,6 @@
 	@NonNull
 	public abstract AttributesNodeProvider createAttributesNodeProvider();
 
-
 	/**
 	 * @return the used file system abstraction, or or {@code null} if
 	 *         repository isn't local.
@@ -653,7 +652,10 @@
 							// detached
 							name = Constants.HEAD;
 						if (!Repository.isValidRefName("x/" + name)) //$NON-NLS-1$
-							throw new RevisionSyntaxException(revstr);
+							throw new RevisionSyntaxException(MessageFormat
+									.format(JGitText.get().invalidRefName,
+											name),
+									revstr);
 						Ref ref = getRef(name);
 						name = null;
 						if (ref == null)
@@ -703,7 +705,10 @@
 						if (name.equals("")) //$NON-NLS-1$
 							name = Constants.HEAD;
 						if (!Repository.isValidRefName("x/" + name)) //$NON-NLS-1$
-							throw new RevisionSyntaxException(revstr);
+							throw new RevisionSyntaxException(MessageFormat
+									.format(JGitText.get().invalidRefName,
+											name),
+									revstr);
 						Ref ref = getRef(name);
 						name = null;
 						if (ref == null)
@@ -752,7 +757,9 @@
 			return null;
 		name = revstr.substring(done);
 		if (!Repository.isValidRefName("x/" + name)) //$NON-NLS-1$
-			throw new RevisionSyntaxException(revstr);
+			throw new RevisionSyntaxException(
+					MessageFormat.format(JGitText.get().invalidRefName, name),
+					revstr);
 		if (getRef(name) != null)
 			return name;
 		return resolveSimple(name);
@@ -869,6 +876,7 @@
 	}
 
 	/** Decrement the use count, and maybe close resources. */
+	@Override
 	public void close() {
 		int newCount = useCnt.decrementAndGet();
 		if (newCount == 0) {
@@ -902,8 +910,9 @@
 		getRefDatabase().close();
 	}
 
-	@NonNull
 	@SuppressWarnings("nls")
+	@Override
+	@NonNull
 	public String toString() {
 		String desc;
 		File directory = getDirectory();
@@ -1175,7 +1184,7 @@
 		// we want DirCache to inform us so that we can inform registered
 		// listeners about index changes
 		IndexChangedListener l = new IndexChangedListener() {
-
+			@Override
 			public void onIndexChanged(IndexChangedEvent event) {
 				notifyIndexChanged();
 			}
@@ -1183,15 +1192,6 @@
 		return DirCache.lock(this, l);
 	}
 
-	static byte[] gitInternalSlash(byte[] bytes) {
-		if (File.separatorChar == '/')
-			return bytes;
-		for (int i=0; i<bytes.length; ++i)
-			if (bytes[i] == File.separatorChar)
-				bytes[i] = '/';
-		return bytes;
-	}
-
 	/**
 	 * @return an important state
 	 */
@@ -1445,6 +1445,33 @@
 	}
 
 	/**
+	 * Read the {@code GIT_DIR/description} file for gitweb.
+	 *
+	 * @return description text; null if no description has been configured.
+	 * @throws IOException
+	 *             description cannot be accessed.
+	 * @since 4.6
+	 */
+	@Nullable
+	public String getGitwebDescription() throws IOException {
+		return null;
+	}
+
+	/**
+	 * Set the {@code GIT_DIR/description} file for gitweb.
+	 *
+	 * @param description
+	 *            new description; null to clear the description.
+	 * @throws IOException
+	 *             description cannot be persisted.
+	 * @since 4.6
+	 */
+	public void setGitwebDescription(@Nullable String description)
+			throws IOException {
+		throw new IOException(JGitText.get().unsupportedRepositoryDescription);
+	}
+
+	/**
 	 * @param refName
 	 * @return a {@link ReflogReader} for the supplied refname, or {@code null}
 	 *         if the named ref does not exist.
@@ -1781,15 +1808,12 @@
 			throws FileNotFoundException, IOException {
 		File headsFile = new File(getDirectory(), filename);
 		if (heads != null) {
-			BufferedOutputStream bos = new SafeBufferedOutputStream(
-					new FileOutputStream(headsFile));
-			try {
+			try (OutputStream bos = new BufferedOutputStream(
+					new FileOutputStream(headsFile))) {
 				for (ObjectId id : heads) {
 					id.copyTo(bos);
 					bos.write('\n');
 				}
-			} finally {
-				bos.close();
 			}
 		} else {
 			FileUtils.delete(headsFile, FileUtils.SKIP_MISSING);
@@ -1845,4 +1869,22 @@
 		return getConfig()
 				.getSubsections(ConfigConstants.CONFIG_REMOTE_SECTION);
 	}
+
+	/**
+	 * Check whether any housekeeping is required; if yes, run garbage
+	 * collection; if not, exit without performing any work. Some JGit commands
+	 * run autoGC after performing operations that could create many loose
+	 * objects.
+	 * <p/>
+	 * Currently this option is supported for repositories of type
+	 * {@code FileRepository} only. See {@link GC#setAuto(boolean)} for
+	 * configuration details.
+	 *
+	 * @param monitor
+	 *            to report progress
+	 * @since 4.6
+	 */
+	public void autoGC(ProgressMonitor monitor) {
+		// default does nothing
+	}
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/RepositoryCache.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/RepositoryCache.java
index 7a8d246..2f1a9e1 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/RepositoryCache.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/RepositoryCache.java
@@ -45,12 +45,8 @@
 
 import java.io.File;
 import java.io.IOException;
-import java.lang.ref.Reference;
-import java.lang.ref.SoftReference;
 import java.util.ArrayList;
 import java.util.Collection;
-import java.util.Iterator;
-import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ScheduledFuture;
 import java.util.concurrent.ScheduledThreadPoolExecutor;
@@ -150,7 +146,7 @@
 	public static void close(@NonNull final Repository db) {
 		if (db.getDirectory() != null) {
 			FileKey key = FileKey.exact(db.getDirectory(), db.getFS());
-			cache.unregisterAndCloseRepository(key, db);
+			cache.unregisterAndCloseRepository(key);
 		}
 	}
 
@@ -202,8 +198,7 @@
 			return false;
 		}
 		FileKey key = new FileKey(gitDir, repo.getFS());
-		Reference<Repository> repoRef = cache.cacheMap.get(key);
-		return repoRef != null && repoRef.get() == repo;
+		return cache.cacheMap.get(key) == repo;
 	}
 
 	/** Unregister all repositories from the cache. */
@@ -219,7 +214,7 @@
 		cache.configureEviction(repositoryCacheConfig);
 	}
 
-	private final ConcurrentHashMap<Key, Reference<Repository>> cacheMap;
+	private final ConcurrentHashMap<Key, Repository> cacheMap;
 
 	private final Lock[] openLocks;
 
@@ -228,7 +223,7 @@
 	private volatile long expireAfter;
 
 	private RepositoryCache() {
-		cacheMap = new ConcurrentHashMap<Key, Reference<Repository>>();
+		cacheMap = new ConcurrentHashMap<>();
 		openLocks = new Lock[4];
 		for (int i = 0; i < openLocks.length; i++) {
 			openLocks[i] = new Lock();
@@ -261,19 +256,15 @@
 		}
 	}
 
-	@SuppressWarnings("resource")
 	private Repository openRepository(final Key location,
 			final boolean mustExist) throws IOException {
-		Reference<Repository> ref = cacheMap.get(location);
-		Repository db = ref != null ? ref.get() : null;
+		Repository db = cacheMap.get(location);
 		if (db == null) {
 			synchronized (lockFor(location)) {
-				ref = cacheMap.get(location);
-				db = ref != null ? ref.get() : null;
+				db = cacheMap.get(location);
 				if (db == null) {
 					db = location.open(mustExist);
-					ref = new SoftReference<Repository>(db);
-					cacheMap.put(location, ref);
+					cacheMap.put(location, db);
 				} else {
 					db.incrementOpen();
 				}
@@ -285,16 +276,13 @@
 	}
 
 	private void registerRepository(final Key location, final Repository db) {
-		SoftReference<Repository> newRef = new SoftReference<Repository>(db);
-		Reference<Repository> oldRef = cacheMap.put(location, newRef);
-		Repository oldDb = oldRef != null ? oldRef.get() : null;
+		Repository oldDb = cacheMap.put(location, db);
 		if (oldDb != null)
 			oldDb.close();
 	}
 
 	private Repository unregisterRepository(final Key location) {
-		Reference<Repository> oldRef = cacheMap.remove(location);
-		return oldRef != null ? oldRef.get() : null;
+		return cacheMap.remove(location);
 	}
 
 	private boolean isExpired(Repository db) {
@@ -302,8 +290,7 @@
 			&& (System.currentTimeMillis() - db.closedAt.get() > expireAfter);
 	}
 
-	private void unregisterAndCloseRepository(final Key location,
-			Repository db) {
+	private void unregisterAndCloseRepository(final Key location) {
 		synchronized (lockFor(location)) {
 			Repository oldDb = unregisterRepository(location);
 			if (oldDb != null) {
@@ -317,8 +304,7 @@
 	}
 
 	private void clearAllExpired() {
-		for (Reference<Repository> ref : cacheMap.values()) {
-			Repository db = ref.get();
+		for (Repository db : cacheMap.values()) {
 			if (isExpired(db)) {
 				RepositoryCache.close(db);
 			}
@@ -326,9 +312,8 @@
 	}
 
 	private void clearAll() {
-		for (Iterator<Map.Entry<Key, Reference<Repository>>> i = cacheMap
-				.entrySet().iterator(); i.hasNext();) {
-			unregisterAndCloseRepository(i.next().getKey(), null);
+		for (Key k : cacheMap.keySet()) {
+			unregisterAndCloseRepository(k);
 		}
 	}
 
@@ -442,6 +427,7 @@
 			return path;
 		}
 
+		@Override
 		public Repository open(final boolean mustExist) throws IOException {
 			if (mustExist && !isGitRepository(path, fs))
 				throw new RepositoryNotFoundException(path);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/RepositoryCacheConfig.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/RepositoryCacheConfig.java
index 428dea3..28cdaae 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/RepositoryCacheConfig.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/RepositoryCacheConfig.java
@@ -53,8 +53,8 @@
 
 	/**
 	 * Set cleanupDelayMillis to this value in order to switch off time-based
-	 * cache eviction. The JVM can still expire cache entries when heap memory
-	 * runs low.
+	 * cache eviction. Expired cache entries will only be evicted when
+	 * RepositoryCache.clearExpired or RepositoryCache.clear are called.
 	 */
 	public static final long NO_CLEANUP = 0;
 
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/TreeFormatter.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/TreeFormatter.java
index 065b8f4..777ce94 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/TreeFormatter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/TreeFormatter.java
@@ -53,6 +53,7 @@
 import java.io.IOException;
 
 import org.eclipse.jgit.errors.CorruptObjectException;
+import org.eclipse.jgit.internal.JGitText;
 import org.eclipse.jgit.revwalk.RevBlob;
 import org.eclipse.jgit.revwalk.RevCommit;
 import org.eclipse.jgit.revwalk.RevTree;
@@ -193,6 +194,34 @@
 	 */
 	public void append(byte[] nameBuf, int namePos, int nameLen, FileMode mode,
 			AnyObjectId id) {
+		append(nameBuf, namePos, nameLen, mode, id, false);
+	}
+
+	/**
+	 * Append any entry to the tree.
+	 *
+	 * @param nameBuf
+	 *            buffer holding the name of the entry. The name should be UTF-8
+	 *            encoded, but file name encoding is not a well defined concept
+	 *            in Git.
+	 * @param namePos
+	 *            first position within {@code nameBuf} of the name data.
+	 * @param nameLen
+	 *            number of bytes from {@code nameBuf} to use as the name.
+	 * @param mode
+	 *            mode describing the treatment of {@code id}.
+	 * @param id
+	 *            the ObjectId to store in this entry.
+	 * @param allowEmptyName
+	 *            allow an empty filename (creating a corrupt tree)
+	 * @since 4.6
+	 */
+	public void append(byte[] nameBuf, int namePos, int nameLen, FileMode mode,
+			AnyObjectId id, boolean allowEmptyName) {
+		if (nameLen == 0 && !allowEmptyName) {
+			throw new IllegalArgumentException(
+					JGitText.get().invalidTreeZeroLengthName);
+		}
 		if (fmtBuf(nameBuf, namePos, nameLen, mode)) {
 			id.copyRawTo(buf, ptr);
 			ptr += OBJECT_ID_LENGTH;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeConfig.java b/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeConfig.java
index 9125ddf..83b143b 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeConfig.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeConfig.java
@@ -46,8 +46,8 @@
 
 import org.eclipse.jgit.api.MergeCommand.FastForwardMode;
 import org.eclipse.jgit.lib.Config;
-import org.eclipse.jgit.lib.ConfigConstants;
 import org.eclipse.jgit.lib.Config.SectionParser;
+import org.eclipse.jgit.lib.ConfigConstants;
 import org.eclipse.jgit.lib.Repository;
 
 /**
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/patch/Patch.java b/org.eclipse.jgit/src/org/eclipse/jgit/patch/Patch.java
index 383c1f8..40ea77e 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/patch/Patch.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/patch/Patch.java
@@ -44,9 +44,9 @@
 package org.eclipse.jgit.patch;
 
 import static org.eclipse.jgit.lib.Constants.encodeASCII;
-import static org.eclipse.jgit.patch.FileHeader.isHunkHdr;
 import static org.eclipse.jgit.patch.FileHeader.NEW_NAME;
 import static org.eclipse.jgit.patch.FileHeader.OLD_NAME;
+import static org.eclipse.jgit.patch.FileHeader.isHunkHdr;
 import static org.eclipse.jgit.util.RawParseUtils.match;
 import static org.eclipse.jgit.util.RawParseUtils.nextLF;
 
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revplot/PlotCommit.java b/org.eclipse.jgit/src/org/eclipse/jgit/revplot/PlotCommit.java
index 2e8aab8..98bcd1a 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revplot/PlotCommit.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revplot/PlotCommit.java
@@ -44,8 +44,8 @@
 package org.eclipse.jgit.revplot;
 
 import org.eclipse.jgit.lib.AnyObjectId;
-import org.eclipse.jgit.revwalk.RevCommit;
 import org.eclipse.jgit.lib.Ref;
+import org.eclipse.jgit.revwalk.RevCommit;
 
 /**
  * A commit reference to a commit in the DAG.
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/MergeBaseGenerator.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/MergeBaseGenerator.java
index f1d7dc8..3609d46 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/MergeBaseGenerator.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/MergeBaseGenerator.java
@@ -45,6 +45,7 @@
 
 import java.io.IOException;
 import java.text.MessageFormat;
+import java.util.LinkedList;
 
 import org.eclipse.jgit.errors.IncorrectObjectTypeException;
 import org.eclipse.jgit.errors.MissingObjectException;
@@ -85,12 +86,15 @@
 
 	private int recarryMask;
 
+	private int mergeBaseAncestor = -1;
+	private LinkedList<RevCommit> ret = new LinkedList<RevCommit>();
+
 	MergeBaseGenerator(final RevWalk w) {
 		walker = w;
 		pending = new DateRevQueue();
 	}
 
-	void init(final AbstractRevQueue p) {
+	void init(final AbstractRevQueue p) throws IOException {
 		try {
 			for (;;) {
 				final RevCommit c = p.next();
@@ -98,17 +102,25 @@
 					break;
 				add(c);
 			}
-		} finally {
-			// Always free the flags immediately. This ensures the flags
-			// will be available for reuse when the walk resets.
-			//
-			walker.freeFlag(branchMask);
-
 			// Setup the condition used by carryOntoOne to detect a late
 			// merge base and produce it on the next round.
 			//
 			recarryTest = branchMask | POPPED;
 			recarryMask = branchMask | POPPED | MERGE_BASE;
+			mergeBaseAncestor = walker.allocFlag();
+
+			for (;;) {
+				RevCommit c = _next();
+				if (c == null) {
+					break;
+				}
+				ret.add(c);
+			}
+		} finally {
+			// Always free the flags immediately. This ensures the flags
+			// will be available for reuse when the walk resets.
+			//
+			walker.freeFlag(branchMask | mergeBaseAncestor);
 		}
 	}
 
@@ -131,8 +143,7 @@
 		return 0;
 	}
 
-	@Override
-	RevCommit next() throws MissingObjectException,
+	private RevCommit _next() throws MissingObjectException,
 			IncorrectObjectTypeException, IOException {
 		for (;;) {
 			final RevCommit c = pending.next();
@@ -156,7 +167,7 @@
 				// also flagged as being popped, so that they do not
 				// generate to the caller.
 				//
-				carry |= MERGE_BASE;
+				carry |= MERGE_BASE | mergeBaseAncestor;
 			}
 			carryOntoHistory(c, carry);
 
@@ -179,6 +190,18 @@
 		}
 	}
 
+	@Override
+	RevCommit next() throws MissingObjectException,
+			IncorrectObjectTypeException, IOException {
+		while (!ret.isEmpty()) {
+			RevCommit commit = ret.remove();
+			if ((commit.flags & mergeBaseAncestor) == 0) {
+				return commit;
+			}
+		}
+		return null;
+	}
+
 	private void carryOntoHistory(RevCommit c, final int carry) {
 		for (;;) {
 			final RevCommit[] pList = c.parents;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/storage/file/FileBasedConfig.java b/org.eclipse.jgit/src/org/eclipse/jgit/storage/file/FileBasedConfig.java
index 4b4822c..38a0fa2 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/storage/file/FileBasedConfig.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/storage/file/FileBasedConfig.java
@@ -55,8 +55,8 @@
 import java.io.IOException;
 import java.text.MessageFormat;
 
-import org.eclipse.jgit.errors.LockFailedException;
 import org.eclipse.jgit.errors.ConfigInvalidException;
+import org.eclipse.jgit.errors.LockFailedException;
 import org.eclipse.jgit.internal.JGitText;
 import org.eclipse.jgit.internal.storage.file.FileSnapshot;
 import org.eclipse.jgit.internal.storage.file.LockFile;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/AmazonS3.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/AmazonS3.java
index 4069a64..1aebadd 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/AmazonS3.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/AmazonS3.java
@@ -529,21 +529,29 @@
 				Integer.valueOf(HttpSupport.response(c)),
 				c.getResponseMessage()));
 		final InputStream errorStream = c.getErrorStream();
-		if (errorStream == null)
+		if (errorStream == null) {
 			return err;
-
-		final ByteArrayOutputStream b = new ByteArrayOutputStream();
-		byte[] buf = new byte[2048];
-		for (;;) {
-			final int n = errorStream.read(buf);
-			if (n < 0)
-				break;
-			if (n > 0)
-				b.write(buf, 0, n);
 		}
-		buf = b.toByteArray();
-		if (buf.length > 0)
-			err.initCause(new IOException("\n" + new String(buf))); //$NON-NLS-1$
+
+		try {
+			final ByteArrayOutputStream b = new ByteArrayOutputStream();
+			byte[] buf = new byte[2048];
+			for (;;) {
+				final int n = errorStream.read(buf);
+				if (n < 0) {
+					break;
+				}
+				if (n > 0) {
+					b.write(buf, 0, n);
+				}
+			}
+			buf = b.toByteArray();
+			if (buf.length > 0) {
+				err.initCause(new IOException("\n" + new String(buf))); //$NON-NLS-1$
+			}
+		} finally {
+			errorStream.close();
+		}
 		return err;
 	}
 
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackFetchConnection.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackFetchConnection.java
index 754cf36..0dd907f 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackFetchConnection.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackFetchConnection.java
@@ -71,7 +71,6 @@
 import org.eclipse.jgit.lib.ObjectInserter;
 import org.eclipse.jgit.lib.ProgressMonitor;
 import org.eclipse.jgit.lib.Ref;
-import org.eclipse.jgit.transport.GitProtocolConstants.MultiAck;
 import org.eclipse.jgit.revwalk.RevCommit;
 import org.eclipse.jgit.revwalk.RevCommitList;
 import org.eclipse.jgit.revwalk.RevFlag;
@@ -80,6 +79,7 @@
 import org.eclipse.jgit.revwalk.RevWalk;
 import org.eclipse.jgit.revwalk.filter.CommitTimeRevFilter;
 import org.eclipse.jgit.revwalk.filter.RevFilter;
+import org.eclipse.jgit.transport.GitProtocolConstants.MultiAck;
 import org.eclipse.jgit.transport.PacketLineIn.AckNackResult;
 import org.eclipse.jgit.util.TemporaryBuffer;
 
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 0724eac..4d0803a 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BaseReceivePack.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BaseReceivePack.java
@@ -69,6 +69,7 @@
 import java.util.Set;
 import java.util.concurrent.TimeUnit;
 
+import org.eclipse.jgit.annotations.Nullable;
 import org.eclipse.jgit.errors.InvalidObjectIdException;
 import org.eclipse.jgit.errors.MissingObjectException;
 import org.eclipse.jgit.errors.PackProtocolException;
@@ -268,6 +269,7 @@
 	private PushCertificateParser pushCertificateParser;
 	private SignedPushConfig signedPushConfig;
 	private PushCertificate pushCert;
+	private ReceivedPackStatistics stats;
 
 	/**
 	 * Get the push certificate used to verify the pusher's identity.
@@ -1115,6 +1117,18 @@
 	}
 
 	/**
+	 * Returns the statistics on the received pack if available. This should be
+	 * called after {@link #receivePack} is called.
+	 *
+	 * @return ReceivedPackStatistics
+	 * @since 4.6
+	 */
+	@Nullable
+	public ReceivedPackStatistics getReceivedPackStatistics() {
+		return stats;
+	}
+
+	/**
 	 * Receive a list of commands from the input.
 	 *
 	 * @throws IOException
@@ -1307,6 +1321,7 @@
 			parser.setMaxObjectSizeLimit(maxObjectSizeLimit);
 			packLock = parser.parse(receiving, resolving);
 			packSize = Long.valueOf(parser.getPackSize());
+			stats = parser.getReceivedPackStatistics();
 			ins.flush();
 		}
 
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/DaemonClient.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/DaemonClient.java
index 22f3438..23e3379 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/DaemonClient.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/DaemonClient.java
@@ -44,6 +44,7 @@
 package org.eclipse.jgit.transport;
 
 import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
@@ -52,7 +53,6 @@
 
 import org.eclipse.jgit.transport.resolver.ServiceNotAuthorizedException;
 import org.eclipse.jgit.transport.resolver.ServiceNotEnabledException;
-import org.eclipse.jgit.util.io.SafeBufferedOutputStream;
 
 /** Active network client of {@link Daemon}. */
 public class DaemonClient {
@@ -95,7 +95,7 @@
 	void execute(final Socket sock) throws IOException,
 			ServiceNotEnabledException, ServiceNotAuthorizedException {
 		rawIn = new BufferedInputStream(sock.getInputStream());
-		rawOut = new SafeBufferedOutputStream(sock.getOutputStream());
+		rawOut = new BufferedOutputStream(sock.getOutputStream());
 
 		if (0 < daemon.getTimeout())
 			sock.setSoTimeout(daemon.getTimeout() * 1000);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/DaemonService.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/DaemonService.java
index 4e7e123..ec6f242 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/DaemonService.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/DaemonService.java
@@ -47,8 +47,8 @@
 import java.io.IOException;
 
 import org.eclipse.jgit.lib.Config;
-import org.eclipse.jgit.lib.Repository;
 import org.eclipse.jgit.lib.Config.SectionParser;
+import org.eclipse.jgit.lib.Repository;
 import org.eclipse.jgit.transport.resolver.ServiceNotAuthorizedException;
 import org.eclipse.jgit.transport.resolver.ServiceNotEnabledException;
 
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/HMACSHA1NonceGenerator.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/HMACSHA1NonceGenerator.java
index 622680a..319ae1e 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/HMACSHA1NonceGenerator.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/HMACSHA1NonceGenerator.java
@@ -52,7 +52,6 @@
 
 import org.eclipse.jgit.internal.storage.dfs.DfsRepository;
 import org.eclipse.jgit.lib.Repository;
-import org.eclipse.jgit.transport.NonceGenerator;
 import org.eclipse.jgit.transport.PushCertificate.NonceStatus;
 
 /**
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/InsecureCipherFactory.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/InsecureCipherFactory.java
new file mode 100644
index 0000000..73384a1
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/InsecureCipherFactory.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2016, Google Inc.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ *   copyright notice, this list of conditions and the following
+ *   disclaimer in the documentation and/or other materials provided
+ *   with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ *   names of its contributors may be used to endorse or promote
+ *   products derived from this software without specific prior
+ *   written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.transport;
+
+import java.security.NoSuchAlgorithmException;
+
+import javax.crypto.Cipher;
+import javax.crypto.NoSuchPaddingException;
+
+/**
+ * <b>DO NOT USE</b> Factory to create any cipher.
+ * <p>
+ * This is a hack for {@link WalkEncryption} to create any cipher configured by
+ * the end-user. Using this class allows JGit to violate ErrorProne's security
+ * recommendations (<a
+ * href="http://errorprone.info/bugpattern/InsecureCryptoUsage"
+ * >InsecureCryptoUsage</a>), which is not secure.
+ */
+class InsecureCipherFactory {
+	static Cipher create(String algo)
+			throws NoSuchAlgorithmException, NoSuchPaddingException {
+		return Cipher.getInstance(algo);
+	}
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/JschSession.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/JschSession.java
index 1dfe5d9..fa27bfc 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/JschSession.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/JschSession.java
@@ -48,15 +48,14 @@
 
 package org.eclipse.jgit.transport;
 
+import java.io.BufferedOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
-import java.io.PipedInputStream;
-import java.io.PipedOutputStream;
 
 import org.eclipse.jgit.errors.TransportException;
 import org.eclipse.jgit.internal.JGitText;
-import org.eclipse.jgit.util.io.StreamCopyThread;
+import org.eclipse.jgit.util.io.IsolatedOutputStream;
 
 import com.jcraft.jsch.Channel;
 import com.jcraft.jsch.ChannelExec;
@@ -178,33 +177,12 @@
 			// that we spawn a background thread to shuttle data through a pipe,
 			// as we can issue an interrupted write out of that. Its slower, so
 			// we only use this route if there is a timeout.
-			final OutputStream out = channel.getOutputStream();
+			OutputStream out = channel.getOutputStream();
 			if (timeout <= 0) {
 				outputStream = out;
 			} else {
-				final PipedInputStream pipeIn = new PipedInputStream();
-				final StreamCopyThread copier = new StreamCopyThread(pipeIn,
-						out);
-				final PipedOutputStream pipeOut = new PipedOutputStream(pipeIn) {
-					@Override
-					public void flush() throws IOException {
-						super.flush();
-						copier.flush();
-					}
-
-					@Override
-					public void close() throws IOException {
-						super.close();
-						try {
-							copier.join(timeout * 1000);
-						} catch (InterruptedException e) {
-							// Just wake early, the thread will terminate
-							// anyway.
-						}
-					}
-				};
-				copier.start();
-				outputStream = pipeOut;
+				IsolatedOutputStream i = new IsolatedOutputStream(out);
+				outputStream = new BufferedOutputStream(i, 16 * 1024);
 			}
 
 			errStream = channel.getErrStream();
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 b96fe88..4bbe3f8 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PackParser.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PackParser.java
@@ -186,6 +186,9 @@
 	/** Git object size limit */
 	private long maxObjectSizeLimit;
 
+	private final ReceivedPackStatistics.Builder stats =
+			new ReceivedPackStatistics.Builder();
+
 	/**
 	 * Initialize a pack parser.
 	 *
@@ -455,8 +458,8 @@
 	}
 
 	/**
-	 * Get the size of the parsed pack.
-	 *
+	 * Get the size of the newly created pack.
+	 * <p>
 	 * This will also include the pack index size if an index was created. This
 	 * method should only be called after pack parsing is finished.
 	 *
@@ -469,6 +472,18 @@
 	}
 
 	/**
+	 * Returns the statistics of the parsed pack.
+	 * <p>
+	 * This should only be called after pack parsing is finished.
+	 *
+	 * @return {@link ReceivedPackStatistics}
+	 * @since 4.6
+	 */
+	public ReceivedPackStatistics getReceivedPackStatistics() {
+		return stats.build();
+	}
+
+	/**
 	 * Parse the pack stream.
 	 *
 	 * @param progress
@@ -626,6 +641,7 @@
 	private void resolveDeltas(DeltaVisit visit, final int type,
 			ObjectTypeAndSize info, ProgressMonitor progress)
 			throws IOException {
+		stats.addDeltaObject(type);
 		do {
 			progress.update(1);
 			info = openDatabase(visit.delta, info);
@@ -919,6 +935,7 @@
 
 	// Cleanup all resources associated with our input parsing.
 	private void endInput() {
+		stats.setNumBytesRead(streamPosition());
 		in = null;
 	}
 
@@ -947,12 +964,14 @@
 		case Constants.OBJ_TREE:
 		case Constants.OBJ_BLOB:
 		case Constants.OBJ_TAG:
+			stats.addWholeObject(typeCode);
 			onBeginWholeObject(streamPosition, typeCode, sz);
 			onObjectHeader(Source.INPUT, hdrBuf, 0, hdrPtr);
 			whole(streamPosition, typeCode, sz);
 			break;
 
 		case Constants.OBJ_OFS_DELTA: {
+			stats.addOffsetDelta();
 			c = readFrom(Source.INPUT);
 			hdrBuf[hdrPtr++] = (byte) c;
 			long ofs = c & 127;
@@ -975,6 +994,7 @@
 		}
 
 		case Constants.OBJ_REF_DELTA: {
+			stats.addRefDelta();
 			c = fill(Source.INPUT, 20);
 			final ObjectId base = ObjectId.fromRaw(buf, c);
 			System.arraycopy(buf, c, hdrBuf, hdrPtr, 20);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PushCertificateIdent.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PushCertificateIdent.java
index 871a6f7..4c8acd2 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PushCertificateIdent.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PushCertificateIdent.java
@@ -44,7 +44,6 @@
 package org.eclipse.jgit.transport;
 
 import static java.nio.charset.StandardCharsets.UTF_8;
-
 import static org.eclipse.jgit.util.RawParseUtils.lastIndexOfTrim;
 
 import java.text.SimpleDateFormat;
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 cc20d50..393e25a 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceivePack.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceivePack.java
@@ -56,7 +56,9 @@
 
 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.Repository;
 import org.eclipse.jgit.transport.ReceiveCommand.Result;
 import org.eclipse.jgit.transport.RefAdvertiser.PacketLineOutRefAdvertiser;
@@ -307,9 +309,19 @@
 				throw new UnpackException(unpackError);
 			}
 			postReceive.onPostReceive(this, filterCommands(Result.OK));
+			autoGc();
 		}
 	}
 
+	private void autoGc() {
+		Repository repo = getRepository();
+		if (!repo.getConfig().getBoolean(ConfigConstants.CONFIG_RECEIVE_SECTION,
+				ConfigConstants.CONFIG_KEY_AUTOGC, true)) {
+			return;
+		}
+		repo.autoGC(NullProgressMonitor.INSTANCE);
+	}
+
 	@Override
 	protected String getLockMessageProcessName() {
 		return "jgit receive-pack"; //$NON-NLS-1$
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceivedPackStatistics.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceivedPackStatistics.java
new file mode 100644
index 0000000..052d550
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceivedPackStatistics.java
@@ -0,0 +1,231 @@
+/*
+ * Copyright (C) 2016, Google Inc.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ *   copyright notice, this list of conditions and the following
+ *   disclaimer in the documentation and/or other materials provided
+ *   with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ *   names of its contributors may be used to endorse or promote
+ *   products derived from this software without specific prior
+ *   written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.transport;
+
+import org.eclipse.jgit.lib.Constants;
+
+/**
+ * Statistics about {@link PackParser}.
+ *
+ * @since 4.6
+ */
+public class ReceivedPackStatistics {
+	private long numBytesRead;
+
+	private long numWholeCommit;
+	private long numWholeTree;
+	private long numWholeBlob;
+	private long numWholeTag;
+	private long numOfsDelta;
+	private long numRefDelta;
+
+	private long numDeltaCommit;
+	private long numDeltaTree;
+	private long numDeltaBlob;
+	private long numDeltaTag;
+
+	/** @return number of bytes read from the input stream */
+	public long getNumBytesRead() {
+		return numBytesRead;
+	}
+
+	/** @return number of whole commit objects in the pack */
+	public long getNumWholeCommit() {
+		return numWholeCommit;
+	}
+
+	/** @return number of whole tree objects in the pack */
+	public long getNumWholeTree() {
+		return numWholeTree;
+	}
+
+	/** @return number of whole blob objects in the pack */
+	public long getNumWholeBlob() {
+		return numWholeBlob;
+	}
+
+	/** @return number of whole tag objects in the pack */
+	public long getNumWholeTag() {
+		return numWholeTag;
+	}
+
+	/** @return number of offset delta objects in the pack */
+	public long getNumOfsDelta() {
+		return numOfsDelta;
+	}
+
+	/** @return number of ref delta objects in the pack */
+	public long getNumRefDelta() {
+		return numRefDelta;
+	}
+
+	/** @return number of delta commit objects in the pack */
+	public long getNumDeltaCommit() {
+		return numDeltaCommit;
+	}
+
+	/** @return number of delta tree objects in the pack */
+	public long getNumDeltaTree() {
+		return numDeltaTree;
+	}
+
+	/** @return number of delta blob objects in the pack */
+	public long getNumDeltaBlob() {
+		return numDeltaBlob;
+	}
+
+	/** @return number of delta tag objects in the pack */
+	public long getNumDeltaTag() {
+		return numDeltaTag;
+	}
+
+	/** A builder for {@link ReceivedPackStatistics}. */
+	public static class Builder {
+		private long numBytesRead;
+
+		private long numWholeCommit;
+		private long numWholeTree;
+		private long numWholeBlob;
+		private long numWholeTag;
+		private long numOfsDelta;
+		private long numRefDelta;
+
+		private long numDeltaCommit;
+		private long numDeltaTree;
+		private long numDeltaBlob;
+		private long numDeltaTag;
+
+		/**
+		 * @param numBytesRead number of bytes read from the input stream
+		 * @return this
+		 */
+		public Builder setNumBytesRead(long numBytesRead) {
+			this.numBytesRead = numBytesRead;
+			return this;
+		}
+
+		/**
+		 * Increment a whole object count.
+		 *
+		 * @param type OBJ_COMMIT, OBJ_TREE, OBJ_BLOB, or OBJ_TAG
+		 * @return this
+		 */
+		public Builder addWholeObject(int type) {
+			switch (type) {
+				case Constants.OBJ_COMMIT:
+					numWholeCommit++;
+					break;
+				case Constants.OBJ_TREE:
+					numWholeTree++;
+					break;
+				case Constants.OBJ_BLOB:
+					numWholeBlob++;
+					break;
+				case Constants.OBJ_TAG:
+					numWholeTag++;
+					break;
+				default:
+					throw new IllegalArgumentException(
+							type + " cannot be a whole object"); //$NON-NLS-1$
+			}
+			return this;
+		}
+
+		/** @return this */
+		public Builder addOffsetDelta() {
+			numOfsDelta++;
+			return this;
+		}
+
+		/** @return this */
+		public Builder addRefDelta() {
+			numRefDelta++;
+			return this;
+		}
+
+		/**
+		 * Increment a delta object count.
+		 *
+		 * @param type OBJ_COMMIT, OBJ_TREE, OBJ_BLOB, or OBJ_TAG
+		 * @return this
+		 */
+		public Builder addDeltaObject(int type) {
+			switch (type) {
+				case Constants.OBJ_COMMIT:
+					numDeltaCommit++;
+					break;
+				case Constants.OBJ_TREE:
+					numDeltaTree++;
+					break;
+				case Constants.OBJ_BLOB:
+					numDeltaBlob++;
+					break;
+				case Constants.OBJ_TAG:
+					numDeltaTag++;
+					break;
+				default:
+					throw new IllegalArgumentException(
+							"delta should be a delta to a whole object. " + //$NON-NLS-1$
+							type + " cannot be a whole object"); //$NON-NLS-1$
+			}
+			return this;
+		}
+
+		ReceivedPackStatistics build() {
+			ReceivedPackStatistics s = new ReceivedPackStatistics();
+			s.numBytesRead = numBytesRead;
+			s.numWholeCommit = numWholeCommit;
+			s.numWholeTree = numWholeTree;
+			s.numWholeBlob = numWholeBlob;
+			s.numWholeTag = numWholeTag;
+			s.numOfsDelta = numOfsDelta;
+			s.numRefDelta = numRefDelta;
+			s.numDeltaCommit = numDeltaCommit;
+			s.numDeltaTree = numDeltaTree;
+			s.numDeltaBlob = numDeltaBlob;
+			s.numDeltaTag = numDeltaTag;
+			return s;
+		}
+	}
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/ServiceMayNotContinueException.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/ServiceMayNotContinueException.java
index ce5ccaa..81c5da3 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/ServiceMayNotContinueException.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/ServiceMayNotContinueException.java
@@ -44,6 +44,7 @@
 package org.eclipse.jgit.transport;
 
 import java.io.IOException;
+
 import javax.servlet.http.HttpServletResponse;
 
 import org.eclipse.jgit.internal.JGitText;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/Transport.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/Transport.java
index bc4843a..df86069 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/Transport.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/Transport.java
@@ -1199,6 +1199,9 @@
 
 		final FetchResult result = new FetchResult();
 		new FetchProcess(this, toFetch).execute(monitor, result);
+
+		local.autoGC(monitor);
+
 		return result;
 	}
 
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportBundleFile.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportBundleFile.java
index bbc0d0a..9b08341 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportBundleFile.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportBundleFile.java
@@ -94,7 +94,7 @@
 		public Transport open(URIish uri, Repository local, String remoteName)
 				throws NotSupportedException, TransportException {
 			if ("bundle".equals(uri.getScheme())) { //$NON-NLS-1$
-				File path = local.getFS().resolve(new File("."), uri.getPath()); //$NON-NLS-1$
+				File path = FS.DETECTED.resolve(new File("."), uri.getPath()); //$NON-NLS-1$
 				return new TransportBundleFile(local, uri, path);
 			}
 
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportGitAnon.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportGitAnon.java
index a7f42fd..c6e4c50 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportGitAnon.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportGitAnon.java
@@ -46,6 +46,7 @@
 package org.eclipse.jgit.transport;
 
 import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
@@ -62,7 +63,6 @@
 import org.eclipse.jgit.errors.TransportException;
 import org.eclipse.jgit.internal.JGitText;
 import org.eclipse.jgit.lib.Repository;
-import org.eclipse.jgit.util.io.SafeBufferedOutputStream;
 
 /**
  * Transport through a git-daemon waiting for anonymous TCP connections.
@@ -182,7 +182,7 @@
 				OutputStream sOut = sock.getOutputStream();
 
 				sIn = new BufferedInputStream(sIn);
-				sOut = new SafeBufferedOutputStream(sOut);
+				sOut = new BufferedOutputStream(sOut);
 
 				init(sIn, sOut);
 				service("git-upload-pack", pckOut); //$NON-NLS-1$
@@ -221,7 +221,7 @@
 				OutputStream sOut = sock.getOutputStream();
 
 				sIn = new BufferedInputStream(sIn);
-				sOut = new SafeBufferedOutputStream(sOut);
+				sOut = new BufferedOutputStream(sOut);
 
 				init(sIn, sOut);
 				service("git-receive-pack", pckOut); //$NON-NLS-1$
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportGitSsh.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportGitSsh.java
index 52f0f04..da98e8c 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportGitSsh.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportGitSsh.java
@@ -64,11 +64,11 @@
 import org.eclipse.jgit.internal.JGitText;
 import org.eclipse.jgit.lib.Constants;
 import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.util.FS;
 import org.eclipse.jgit.util.QuotedString;
 import org.eclipse.jgit.util.SystemReader;
 import org.eclipse.jgit.util.io.MessageWriter;
 import org.eclipse.jgit.util.io.StreamCopyThread;
-import org.eclipse.jgit.util.FS;
 
 /**
  * Transport through an SSH tunnel.
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportHttp.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportHttp.java
index 1166080..96a6fe1 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportHttp.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportHttp.java
@@ -45,7 +45,9 @@
 
 package org.eclipse.jgit.transport;
 
+import static org.eclipse.jgit.lib.Constants.HEAD;
 import static org.eclipse.jgit.util.HttpSupport.ENCODING_GZIP;
+import static org.eclipse.jgit.util.HttpSupport.ENCODING_X_GZIP;
 import static org.eclipse.jgit.util.HttpSupport.HDR_ACCEPT;
 import static org.eclipse.jgit.util.HttpSupport.HDR_ACCEPT_ENCODING;
 import static org.eclipse.jgit.util.HttpSupport.HDR_CONTENT_ENCODING;
@@ -128,6 +130,25 @@
 
 	private static final String SVC_RECEIVE_PACK = "git-receive-pack"; //$NON-NLS-1$
 
+	/**
+	 * Accept-Encoding header in the HTTP request
+	 * (https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html).
+	 *
+	 * @since 4.6
+	 */
+	public enum AcceptEncoding {
+		/**
+		 * Do not specify an Accept-Encoding header. In most servers this
+		 * results in the content being transmitted as-is.
+		 */
+		UNSPECIFIED,
+
+		/**
+		 * Accept gzip content encoding.
+		 */
+		GZIP
+	}
+
 	static final TransportProtocol PROTO_HTTP = new TransportProtocol() {
 		private final String[] schemeNames = { "http", "https" }; //$NON-NLS-1$ //$NON-NLS-2$
 
@@ -324,12 +345,15 @@
 			br.close();
 		}
 
-		if (!refs.containsKey(Constants.HEAD)) {
+		if (!refs.containsKey(HEAD)) {
 			// If HEAD was not published in the info/refs file (it usually
 			// is not there) download HEAD by itself as a loose file and do
 			// the resolution by hand.
 			//
-			HttpConnection conn = httpOpen(new URL(baseUrl, Constants.HEAD));
+			HttpConnection conn = httpOpen(
+					METHOD_GET,
+					new URL(baseUrl, HEAD),
+					AcceptEncoding.GZIP);
 			int status = HttpSupport.response(conn);
 			switch (status) {
 			case HttpConnection.HTTP_OK: {
@@ -341,11 +365,11 @@
 						Ref r = refs.get(target);
 						if (r == null)
 							r = new ObjectIdRef.Unpeeled(Ref.Storage.NEW, target, null);
-						r = new SymbolicRef(Constants.HEAD, r);
+						r = new SymbolicRef(HEAD, r);
 						refs.put(r.getName(), r);
 					} else if (line != null && ObjectId.isId(line)) {
 						Ref r = new ObjectIdRef.Unpeeled(Ref.Storage.NETWORK,
-								Constants.HEAD, ObjectId.fromString(line));
+								HEAD, ObjectId.fromString(line));
 						refs.put(r.getName(), r);
 					}
 				} finally {
@@ -455,7 +479,7 @@
 		Collection<Type> ignoreTypes = null;
 		for (;;) {
 			try {
-				final HttpConnection conn = httpOpen(u);
+				final HttpConnection conn = httpOpen(METHOD_GET, u, AcceptEncoding.GZIP);
 				if (useSmartHttp) {
 					String exp = "application/x-" + service + "-advertisement"; //$NON-NLS-1$ //$NON-NLS-2$
 					conn.setRequestProperty(HDR_ACCEPT, exp + ", */*"); //$NON-NLS-1$
@@ -529,21 +553,37 @@
 		}
 	}
 
-	final HttpConnection httpOpen(URL u) throws IOException {
-		return httpOpen(METHOD_GET, u);
+	/**
+	 * Open an HTTP connection, setting the accept-encoding request header to gzip.
+	 *
+	 * @param method HTTP request method
+	 * @param u url of the HTTP connection
+	 * @return the HTTP connection
+	 * @throws IOException
+	 * @since 3.3
+	 * @deprecated use {@link #httpOpen(String, URL, AcceptEncoding)} instead.
+	 */
+	@Deprecated
+	protected HttpConnection httpOpen(String method, URL u) throws IOException {
+		return httpOpen(method, u, AcceptEncoding.GZIP);
 	}
 
 	/**
 	 * Open an HTTP connection.
 	 *
-	 * @param method
-	 * @param u
-	 * @return the connection
+	 * @param method HTTP request method
+	 * @param u url of the HTTP connection
+	 * @param acceptEncoding accept-encoding header option
+	 * @return the HTTP connection
 	 * @throws IOException
-	 * @since 3.3
+	 * @since 4.6
 	 */
-	protected HttpConnection httpOpen(String method, URL u)
-			throws IOException {
+	protected HttpConnection httpOpen(String method, URL u,
+			AcceptEncoding acceptEncoding) throws IOException {
+		if (method == null || u == null || acceptEncoding == null) {
+			throw new NullPointerException();
+		}
+
 		final Proxy proxy = HttpSupport.proxyFor(proxySelector, u);
 		HttpConnection conn = connectionFactory.create(u, proxy);
 
@@ -553,7 +593,9 @@
 
 		conn.setRequestMethod(method);
 		conn.setUseCaches(false);
-		conn.setRequestProperty(HDR_ACCEPT_ENCODING, ENCODING_GZIP);
+		if (acceptEncoding == AcceptEncoding.GZIP) {
+			conn.setRequestProperty(HDR_ACCEPT_ENCODING, ENCODING_GZIP);
+		}
 		conn.setRequestProperty(HDR_PRAGMA, "no-cache"); //$NON-NLS-1$
 		if (UserAgent.get() != null) {
 			conn.setRequestProperty(HDR_USER_AGENT, UserAgent.get());
@@ -575,7 +617,7 @@
 	final InputStream openInputStream(HttpConnection conn)
 			throws IOException {
 		InputStream input = conn.getInputStream();
-		if (ENCODING_GZIP.equals(conn.getHeaderField(HDR_CONTENT_ENCODING)))
+		if (isGzipContent(conn))
 			input = new GZIPInputStream(input);
 		return input;
 	}
@@ -591,6 +633,11 @@
 		return expType.equals(actType);
 	}
 
+	private boolean isGzipContent(final HttpConnection c) {
+		return ENCODING_GZIP.equals(c.getHeaderField(HDR_CONTENT_ENCODING))
+				|| ENCODING_X_GZIP.equals(c.getHeaderField(HDR_CONTENT_ENCODING));
+	}
+
 	private void readSmartHeaders(final InputStream in, final String service)
 			throws IOException {
 		// A smart reply will have a '#' after the first 4 bytes, but
@@ -655,6 +702,14 @@
 		}
 
 		@Override
+		BufferedReader openReader(String path) throws IOException {
+			// Line oriented readable content is likely to compress well.
+			// Request gzip encoding.
+			InputStream is = open(path, AcceptEncoding.GZIP).in;
+			return new BufferedReader(new InputStreamReader(is, Constants.CHARSET));
+		}
+
+		@Override
 		Collection<String> getPackNames() throws IOException {
 			final Collection<String> packs = new ArrayList<String>();
 			try {
@@ -679,14 +734,25 @@
 
 		@Override
 		FileStream open(final String path) throws IOException {
+			return open(path, AcceptEncoding.UNSPECIFIED);
+		}
+
+		FileStream open(String path, AcceptEncoding acceptEncoding)
+				throws IOException {
 			final URL base = httpObjectsUrl;
 			final URL u = new URL(base, path);
-			final HttpConnection c = httpOpen(u);
+			final HttpConnection c = httpOpen(METHOD_GET, u, acceptEncoding);
 			switch (HttpSupport.response(c)) {
 			case HttpConnection.HTTP_OK:
 				final InputStream in = openInputStream(c);
-				final int len = c.getContentLength();
-				return new FileStream(in, len);
+				// If content is being gzipped and then transferred, the content
+				// length in the header is the zipped content length, not the
+				// actual content length.
+				if (!isGzipContent(c)) {
+					final int len = c.getContentLength();
+					return new FileStream(in, len);
+				}
+				return new FileStream(in);
 			case HttpConnection.HTTP_NOT_FOUND:
 				throw new FileNotFoundException(u.toString());
 			default:
@@ -832,7 +898,10 @@
 		}
 
 		void openStream() throws IOException {
-			conn = httpOpen(METHOD_POST, new URL(baseUrl, serviceName));
+			conn = httpOpen(
+					METHOD_POST,
+					new URL(baseUrl, serviceName),
+					AcceptEncoding.GZIP);
 			conn.setInstanceFollowRedirects(false);
 			conn.setDoOutput(true);
 			conn.setRequestProperty(HDR_CONTENT_TYPE, requestType);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportLocal.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportLocal.java
index 292ba7e..1528c71 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportLocal.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportLocal.java
@@ -48,6 +48,7 @@
 package org.eclipse.jgit.transport;
 
 import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
 import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
@@ -67,7 +68,6 @@
 import org.eclipse.jgit.transport.resolver.UploadPackFactory;
 import org.eclipse.jgit.util.FS;
 import org.eclipse.jgit.util.io.MessageWriter;
-import org.eclipse.jgit.util.io.SafeBufferedOutputStream;
 import org.eclipse.jgit.util.io.StreamCopyThread;
 
 /**
@@ -258,7 +258,7 @@
 			OutputStream upOut = uploadPack.getOutputStream();
 
 			upIn = new BufferedInputStream(upIn);
-			upOut = new SafeBufferedOutputStream(upOut);
+			upOut = new BufferedOutputStream(upOut);
 
 			init(upIn, upOut);
 			readAdvertisedRefs();
@@ -311,7 +311,7 @@
 			OutputStream rpOut = receivePack.getOutputStream();
 
 			rpIn = new BufferedInputStream(rpIn);
-			rpOut = new SafeBufferedOutputStream(rpOut);
+			rpOut = new BufferedOutputStream(rpOut);
 
 			init(rpIn, rpOut);
 			readAdvertisedRefs();
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 d1fd67e..201fb18 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java
@@ -45,8 +45,8 @@
 
 import static org.eclipse.jgit.lib.RefDatabase.ALL;
 import static org.eclipse.jgit.transport.GitProtocolConstants.OPTION_AGENT;
-import static org.eclipse.jgit.transport.GitProtocolConstants.OPTION_ALLOW_TIP_SHA1_IN_WANT;
 import static org.eclipse.jgit.transport.GitProtocolConstants.OPTION_ALLOW_REACHABLE_SHA1_IN_WANT;
+import static org.eclipse.jgit.transport.GitProtocolConstants.OPTION_ALLOW_TIP_SHA1_IN_WANT;
 import static org.eclipse.jgit.transport.GitProtocolConstants.OPTION_INCLUDE_TAG;
 import static org.eclipse.jgit.transport.GitProtocolConstants.OPTION_MULTI_ACK;
 import static org.eclipse.jgit.transport.GitProtocolConstants.OPTION_MULTI_ACK_DETAILED;
@@ -313,6 +313,7 @@
 
 	private PackStatistics statistics;
 
+	@SuppressWarnings("deprecation")
 	private UploadPackLogger logger = UploadPackLogger.NULL;
 
 	/**
@@ -1428,6 +1429,7 @@
 		}
 	}
 
+	@SuppressWarnings("deprecation")
 	private void sendPack(final boolean sideband) throws IOException {
 		ProgressMonitor pm = NullProgressMonitor.INSTANCE;
 		OutputStream packOut = rawOut;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPackLogger.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPackLogger.java
index 85ebecc..0588634 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPackLogger.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPackLogger.java
@@ -56,7 +56,7 @@
  * @deprecated use {@link PostUploadHook} instead
  */
 @Deprecated
-public interface UploadPackLogger {
+public interface UploadPackLogger { // TODO remove in JGit 5.0
 	/** A simple no-op logger. */
 	public static final UploadPackLogger NULL = new UploadPackLogger() {
 		public void onPackStatistics(PackWriter.Statistics stats) {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/WalkEncryption.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/WalkEncryption.java
index fe03bdc..4c3fdd8 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/WalkEncryption.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/WalkEncryption.java
@@ -143,35 +143,6 @@
 		}
 	}
 
-	// PBEParameterSpec factory for Java (version <= 7).
-	// Does not support AlgorithmParameterSpec.
-	static PBEParameterSpec java7PBEParameterSpec(byte[] salt,
-			int iterationCount) {
-		return new PBEParameterSpec(salt, iterationCount);
-	}
-
-	// PBEParameterSpec factory for Java (version >= 8).
-	// Adds support for AlgorithmParameterSpec.
-	static PBEParameterSpec java8PBEParameterSpec(byte[] salt,
-			int iterationCount, AlgorithmParameterSpec paramSpec) {
-		try {
-			@SuppressWarnings("boxing")
-			PBEParameterSpec instance = PBEParameterSpec.class
-					.getConstructor(byte[].class, int.class,
-							AlgorithmParameterSpec.class)
-					.newInstance(salt, iterationCount, paramSpec);
-			return instance;
-		} catch (Exception e) {
-			throw new RuntimeException(e);
-		}
-	}
-
-	// Current runtime version.
-	// https://docs.oracle.com/javase/7/docs/technotes/guides/versioning/spec/versioning2.html
-	static double javaVersion() {
-		return Double.parseDouble(System.getProperty("java.specification.version")); //$NON-NLS-1$
-	}
-
 	/**
 	 * JetS3t compatibility reference: <a href=
 	 * "https://bitbucket.org/jmurty/jets3t/src/156c00eb160598c2e9937fd6873f00d3190e28ca/src/org/jets3t/service/security/EncryptionUtil.java">
@@ -204,7 +175,7 @@
 		// Size 16, see com.sun.crypto.provider.AESConstants.AES_BLOCK_SIZE
 		static final byte[] ZERO_AES_IV = new byte[16];
 
-		private static final String cryptoVer = VERSION;
+		private static final String CRYPTO_VER = VERSION;
 
 		private final String cryptoAlg;
 
@@ -217,7 +188,7 @@
 			cryptoAlg = algo;
 
 			// Verify if cipher is present.
-			Cipher cipher = Cipher.getInstance(cryptoAlg);
+			Cipher cipher = InsecureCipherFactory.create(cryptoAlg);
 
 			// Standard names are not case-sensitive.
 			// http://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html
@@ -233,9 +204,7 @@
 			boolean useIV = cryptoName.contains("AES"); //$NON-NLS-1$
 
 			// PBEParameterSpec algorithm parameters are supported from Java 8.
-			boolean isJava8 = javaVersion() >= 1.8;
-
-			if (useIV && isJava8) {
+			if (useIV) {
 				// Support IV where possible:
 				// * since JCE provider uses random IV for PBE/AES
 				// * and there is no place to store dynamic IV in JetS3t V2
@@ -245,34 +214,33 @@
 				// https://bitbucket.org/jmurty/jets3t/raw/156c00eb160598c2e9937fd6873f00d3190e28ca/src/org/jets3t/service/security/EncryptionUtil.java
 				// http://cr.openjdk.java.net/~mullan/webrevs/ascarpin/webrev.00/raw_files/new/src/share/classes/com/sun/crypto/provider/PBES2Core.java
 				IvParameterSpec paramIV = new IvParameterSpec(ZERO_AES_IV);
-				paramSpec = java8PBEParameterSpec(SALT, ITERATIONS, paramIV);
+				paramSpec = new PBEParameterSpec(SALT, ITERATIONS, paramIV);
 			} else {
 				// Strict legacy JetS3t V2 compatibility, with no IV support.
-				paramSpec = java7PBEParameterSpec(SALT, ITERATIONS);
+				paramSpec = new PBEParameterSpec(SALT, ITERATIONS);
 			}
 
 			// Verify if cipher + key are allowed by policy.
 			cipher.init(Cipher.ENCRYPT_MODE, secretKey, paramSpec);
 			cipher.doFinal();
-
 		}
 
 		@Override
 		void request(final HttpURLConnection u, final String prefix) {
-			u.setRequestProperty(prefix + JETS3T_CRYPTO_VER, cryptoVer);
+			u.setRequestProperty(prefix + JETS3T_CRYPTO_VER, CRYPTO_VER);
 			u.setRequestProperty(prefix + JETS3T_CRYPTO_ALG, cryptoAlg);
 		}
 
 		@Override
 		void validate(final HttpURLConnection u, final String prefix)
 				throws IOException {
-			validateImpl(u, prefix, cryptoVer, cryptoAlg);
+			validateImpl(u, prefix, CRYPTO_VER, cryptoAlg);
 		}
 
 		@Override
 		OutputStream encrypt(final OutputStream os) throws IOException {
 			try {
-				final Cipher cipher = Cipher.getInstance(cryptoAlg);
+				final Cipher cipher = InsecureCipherFactory.create(cryptoAlg);
 				cipher.init(Cipher.ENCRYPT_MODE, secretKey, paramSpec);
 				return new CipherOutputStream(os, cipher);
 			} catch (GeneralSecurityException e) {
@@ -283,7 +251,7 @@
 		@Override
 		InputStream decrypt(final InputStream in) throws IOException {
 			try {
-				final Cipher cipher = Cipher.getInstance(cryptoAlg);
+				final Cipher cipher = InsecureCipherFactory.create(cryptoAlg);
 				cipher.init(Cipher.DECRYPT_MODE, secretKey, paramSpec);
 				return new CipherInputStream(in, cipher);
 			} catch (GeneralSecurityException e) {
@@ -374,7 +342,7 @@
 			String keySalt = props.getProperty(profile + X_KEY_SALT, DEFAULT_KEY_SALT);
 
 			// Verify if cipher is present.
-			Cipher cipher = Cipher.getInstance(cipherAlgo);
+			Cipher cipher = InsecureCipherFactory.create(cipherAlgo);
 
 			// Verify if key factory is present.
 			SecretKeyFactory factory = SecretKeyFactory.getInstance(keyAlgo);
@@ -432,7 +400,7 @@
 		@Override
 		OutputStream encrypt(OutputStream output) throws IOException {
 			try {
-				Cipher cipher = Cipher.getInstance(cipherAlgo);
+				Cipher cipher = InsecureCipherFactory.create(cipherAlgo);
 				cipher.init(Cipher.ENCRYPT_MODE, secretKey);
 				AlgorithmParameters params = cipher.getParameters();
 				if (params == null) {
@@ -489,7 +457,7 @@
 						JGitText.get().unsupportedEncryptionVersion, vers));
 			}
 			try {
-				decryptCipher = Cipher.getInstance(cipherAlgo);
+				decryptCipher = InsecureCipherFactory.create(cipherAlgo);
 				if (cont.isEmpty()) {
 					decryptCipher.init(Cipher.DECRYPT_MODE, secretKey);
 				} else {
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 17edfdc..13d4a24 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/WalkFetchConnection.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/WalkFetchConnection.java
@@ -195,7 +195,7 @@
 		local = wt.local;
 		objCheck = wt.getObjectChecker();
 		inserter = local.newObjectInserter();
-		reader = local.newObjectReader();
+		reader = inserter.newReader();
 
 		remotes = new ArrayList<WalkRemoteObjectDatabase>();
 		remotes.add(w);
@@ -240,6 +240,12 @@
 				downloadObject(monitor, id);
 			process(id);
 		}
+
+		try {
+			inserter.flush();
+		} catch (IOException e) {
+			throw new TransportException(e.getMessage(), e);
+		}
 	}
 
 	public Collection<PackLock> getPackLocks() {
@@ -652,7 +658,6 @@
 					Constants.typeString(type),
 					Integer.valueOf(compressed.length)));
 		}
-		inserter.flush();
 	}
 
 	private Collection<WalkRemoteObjectDatabase> expandOneAlternate(
@@ -876,14 +881,17 @@
 		void downloadPack(final ProgressMonitor monitor) throws IOException {
 			String name = "pack/" + packName; //$NON-NLS-1$
 			WalkRemoteObjectDatabase.FileStream s = connection.open(name);
-			PackParser parser = inserter.newPackParser(s.in);
-			parser.setAllowThin(false);
-			parser.setObjectChecker(objCheck);
-			parser.setLockMessage(lockMessage);
-			PackLock lock = parser.parse(monitor);
-			if (lock != null)
-				packLocks.add(lock);
-			inserter.flush();
+			try {
+				PackParser parser = inserter.newPackParser(s.in);
+				parser.setAllowThin(false);
+				parser.setObjectChecker(objCheck);
+				parser.setLockMessage(lockMessage);
+				PackLock lock = parser.parse(monitor);
+				if (lock != null)
+					packLocks.add(lock);
+			} finally {
+				s.in.close();
+			}
 		}
 	}
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/WalkPushConnection.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/WalkPushConnection.java
index 4eaf3f9..7b449c7 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/WalkPushConnection.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/WalkPushConnection.java
@@ -45,6 +45,7 @@
 
 import static org.eclipse.jgit.transport.WalkRemoteObjectDatabase.ROOT_DIR;
 
+import java.io.BufferedOutputStream;
 import java.io.IOException;
 import java.io.OutputStream;
 import java.util.ArrayList;
@@ -69,7 +70,6 @@
 import org.eclipse.jgit.lib.RefWriter;
 import org.eclipse.jgit.lib.Repository;
 import org.eclipse.jgit.transport.RemoteRefUpdate.Status;
-import org.eclipse.jgit.util.io.SafeBufferedOutputStream;
 
 /**
  * Generic push support for dumb transport protocols.
@@ -262,21 +262,15 @@
 			// Write the pack file, then the index, as readers look the
 			// other direction (index, then pack file).
 			//
-			final String wt = "Put " + base.substring(0, 12); //$NON-NLS-1$
-			OutputStream os = dest.writeFile(pathPack, monitor, wt + "..pack"); //$NON-NLS-1$
-			try {
-				os = new SafeBufferedOutputStream(os);
+			String wt = "Put " + base.substring(0, 12); //$NON-NLS-1$
+			try (OutputStream os = new BufferedOutputStream(
+					dest.writeFile(pathPack, monitor, wt + "..pack"))) { //$NON-NLS-1$
 				writer.writePack(monitor, monitor, os);
-			} finally {
-				os.close();
 			}
 
-			os = dest.writeFile(pathIdx, monitor, wt + "..idx"); //$NON-NLS-1$
-			try {
-				os = new SafeBufferedOutputStream(os);
+			try (OutputStream os = new BufferedOutputStream(
+					dest.writeFile(pathIdx, monitor, wt + "..idx"))) { //$NON-NLS-1$
 				writer.writeIndex(os);
-			} finally {
-				os.close();
 			}
 
 			// Record the pack at the start of the pack info list. This
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 e47913e..24f30ed 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/WalkRemoteObjectDatabase.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/WalkRemoteObjectDatabase.java
@@ -133,6 +133,9 @@
 	 * Callers such as {@link WalkFetchConnection} are prepared to handle this
 	 * by validating the content received, and assuming content that fails to
 	 * match its hash is an incorrectly phrased FileNotFoundException.
+	 * <p>
+	 * This method is recommended for already compressed files like loose objects
+	 * and pack files. For text files, see {@link #openReader(String)}.
 	 *
 	 * @param path
 	 *            location of the file to read, relative to this objects
@@ -346,8 +349,8 @@
 	/**
 	 * Open a buffered reader around a file.
 	 * <p>
-	 * This is shorthand for calling {@link #open(String)} and then wrapping it
-	 * in a reader suitable for line oriented files like the alternates list.
+	 * This method is suitable for 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.
 	 * @param path
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/AbstractTreeIterator.java b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/AbstractTreeIterator.java
index 07fc829..6d4c342 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/AbstractTreeIterator.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/AbstractTreeIterator.java
@@ -49,8 +49,8 @@
 import java.nio.ByteBuffer;
 import java.nio.CharBuffer;
 
-import org.eclipse.jgit.attributes.AttributesNode;
 import org.eclipse.jgit.attributes.AttributesHandler;
+import org.eclipse.jgit.attributes.AttributesNode;
 import org.eclipse.jgit.dircache.DirCacheCheckout;
 import org.eclipse.jgit.errors.CorruptObjectException;
 import org.eclipse.jgit.errors.IncorrectObjectTypeException;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/FileTreeIterator.java b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/FileTreeIterator.java
index db81e1a..afa2ed9 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/FileTreeIterator.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/FileTreeIterator.java
@@ -426,4 +426,9 @@
 	protected byte[] idSubmodule(final Entry e) {
 		return idSubmodule(getDirectory(), e);
 	}
+
+	@Override
+	protected String readSymlinkTarget(Entry entry) throws IOException {
+		return fs.readSymLink(getEntryFile());
+	}
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/TreeWalk.java b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/TreeWalk.java
index 911b7ff..5dfebe9 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/TreeWalk.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/TreeWalk.java
@@ -53,10 +53,11 @@
 import org.eclipse.jgit.api.errors.JGitInternalException;
 import org.eclipse.jgit.attributes.Attribute;
 import org.eclipse.jgit.attributes.Attributes;
+import org.eclipse.jgit.attributes.AttributesHandler;
 import org.eclipse.jgit.attributes.AttributesNodeProvider;
 import org.eclipse.jgit.attributes.AttributesProvider;
+import org.eclipse.jgit.attributes.FilterCommandRegistry;
 import org.eclipse.jgit.dircache.DirCacheBuildIterator;
-import org.eclipse.jgit.attributes.AttributesHandler;
 import org.eclipse.jgit.dircache.DirCacheIterator;
 import org.eclipse.jgit.errors.CorruptObjectException;
 import org.eclipse.jgit.errors.IncorrectObjectTypeException;
@@ -64,6 +65,7 @@
 import org.eclipse.jgit.errors.StopWalkException;
 import org.eclipse.jgit.lib.AnyObjectId;
 import org.eclipse.jgit.lib.Config;
+import org.eclipse.jgit.lib.ConfigConstants;
 import org.eclipse.jgit.lib.Constants;
 import org.eclipse.jgit.lib.CoreConfig.EolStreamType;
 import org.eclipse.jgit.lib.FileMode;
@@ -313,6 +315,8 @@
 
 	private Config config;
 
+	private Set<String> filterCommands;
+
 	/**
 	 * Create a new tree walker for a given repository.
 	 *
@@ -357,6 +361,8 @@
 		if (repo != null) {
 			config = repo.getConfig();
 			attributesNodeProvider = repo.createAttributesNodeProvider();
+			filterCommands = FilterCommandRegistry
+					.getRegisteredFilterCommands();
 		} else {
 			config = null;
 			attributesNodeProvider = null;
@@ -1367,10 +1373,22 @@
 		String filterCommand = filterCommandsByNameDotType.get(key);
 		if (filterCommand != null)
 			return filterCommand;
-		filterCommand = config.getString(Constants.ATTR_FILTER,
+		filterCommand = config.getString(ConfigConstants.CONFIG_FILTER_SECTION,
 				filterDriverName, filterCommandType);
-		if (filterCommand != null)
+		boolean useBuiltin = config.getBoolean(
+				ConfigConstants.CONFIG_FILTER_SECTION,
+				filterDriverName, ConfigConstants.CONFIG_KEY_USEJGITBUILTIN, false);
+		if (useBuiltin) {
+			String builtinFilterCommand = Constants.BUILTIN_FILTER_PREFIX
+					+ filterDriverName + '/' + filterCommandType;
+			if (filterCommands != null
+					&& filterCommands.contains(builtinFilterCommand)) {
+				filterCommand = builtinFilterCommand;
+			}
+		}
+		if (filterCommand != null) {
 			filterCommandsByNameDotType.put(key, filterCommand);
+		}
 		return filterCommand;
 	}
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeIterator.java b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeIterator.java
index 9a3fa80..52477cb 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeIterator.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeIterator.java
@@ -65,6 +65,8 @@
 import org.eclipse.jgit.api.errors.FilterFailedException;
 import org.eclipse.jgit.attributes.AttributesNode;
 import org.eclipse.jgit.attributes.AttributesRule;
+import org.eclipse.jgit.attributes.FilterCommand;
+import org.eclipse.jgit.attributes.FilterCommandRegistry;
 import org.eclipse.jgit.diff.RawText;
 import org.eclipse.jgit.dircache.DirCache;
 import org.eclipse.jgit.dircache.DirCacheEntry;
@@ -93,6 +95,8 @@
 import org.eclipse.jgit.util.IO;
 import org.eclipse.jgit.util.Paths;
 import org.eclipse.jgit.util.RawParseUtils;
+import org.eclipse.jgit.util.TemporaryBuffer;
+import org.eclipse.jgit.util.TemporaryBuffer.LocalFile;
 import org.eclipse.jgit.util.io.AutoLFInputStream;
 import org.eclipse.jgit.util.io.EolStreamTypeUtil;
 
@@ -263,7 +267,6 @@
 			// If there is a matching DirCacheIterator, we can reuse
 			// its idBuffer, but only if we appear to be clean against
 			// the cached index information for the path.
-			//
 			DirCacheIterator i = state.walk.getTree(state.dirCacheTree,
 							DirCacheIterator.class);
 			if (i != null) {
@@ -393,15 +396,9 @@
 
 		if (len <= MAXIMUM_FILE_SIZE_TO_READ_FULLY) {
 			ByteBuffer rawbuf = IO.readWholeStream(is, (int) len);
-			byte[] raw = rawbuf.array();
-			int n = rawbuf.limit();
-			if (!isBinary(raw, n)) {
-				rawbuf = filterClean(raw, n, opType);
-				raw = rawbuf.array();
-				n = rawbuf.limit();
-			}
-			canonLen = n;
-			return new ByteArrayInputStream(raw, 0, n);
+			rawbuf = filterClean(rawbuf.array(), rawbuf.limit(), opType);
+			canonLen = rawbuf.limit();
+			return new ByteArrayInputStream(rawbuf.array(), 0, (int) canonLen);
 		}
 
 		if (getCleanFilterCommand() == null && isBinary(e)) {
@@ -429,10 +426,6 @@
 		}
 	}
 
-	private static boolean isBinary(byte[] content, int sz) {
-		return RawText.isBinary(content, sz);
-	}
-
 	private static boolean isBinary(Entry entry) throws IOException {
 		InputStream in = entry.openInputStream();
 		try {
@@ -461,6 +454,16 @@
 		in = handleAutoCRLF(in, opType);
 		String filterCommand = getCleanFilterCommand();
 		if (filterCommand != null) {
+			if (FilterCommandRegistry.isRegistered(filterCommand)) {
+				LocalFile buffer = new TemporaryBuffer.LocalFile(null);
+				FilterCommand command = FilterCommandRegistry
+						.createFilterCommand(filterCommand, repository, in,
+								buffer);
+				while (command.run() != -1) {
+					// loop as long as command.run() tells there is work to do
+				}
+				return buffer.openInputStream();
+			}
 			FS fs = repository.getFS();
 			ProcessBuilder filterProcessBuilder = fs.runInShell(filterCommand,
 					new String[0]);
@@ -1005,10 +1008,10 @@
 
 			return false;
 		} else {
-			if (mode == FileMode.SYMLINK.getBits())
-				return !new File(readContentAsNormalizedString(current()))
-						.equals(new File((readContentAsNormalizedString(entry,
-								reader))));
+			if (mode == FileMode.SYMLINK.getBits()) {
+				return !new File(readSymlinkTarget(current())).equals(
+						new File(readContentAsNormalizedString(entry, reader)));
+			}
 			// Content differs: that's a real change, perhaps
 			if (reader == null) // deprecated use, do no further checks
 				return true;
@@ -1054,12 +1057,30 @@
 		return FS.detect().normalize(RawParseUtils.decode(cachedBytes));
 	}
 
-	private static String readContentAsNormalizedString(Entry entry) throws IOException {
+	/**
+	 * Reads the target of a symlink as a string. This default implementation
+	 * fully reads the entry's input stream and converts it to a normalized
+	 * string. Subclasses may override to provide more specialized
+	 * implementations.
+	 *
+	 * @param entry
+	 *            to read
+	 * @return the entry's content as a normalized string
+	 * @throws IOException
+	 *             if the entry cannot be read or does not denote a symlink
+	 * @since 4.6
+	 */
+	protected String readSymlinkTarget(Entry entry) throws IOException {
+		if (!entry.getMode().equals(FileMode.SYMLINK)) {
+			throw new java.nio.file.NotLinkException(entry.getName());
+		}
 		long length = entry.getLength();
 		byte[] content = new byte[(int) length];
-		InputStream is = entry.openInputStream();
-		IO.readFully(is, content, 0, (int) length);
-		return FS.detect().normalize(RawParseUtils.decode(content));
+		try (InputStream is = entry.openInputStream()) {
+			int bytesRead = IO.readFully(is, content, 0);
+			return FS.detect()
+					.normalize(RawParseUtils.decode(content, 0, bytesRead));
+		}
 	}
 
 	private static long computeLength(InputStream in) throws IOException {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeOptions.java b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeOptions.java
index dea07c1..112ce8f 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeOptions.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeOptions.java
@@ -44,8 +44,8 @@
 package org.eclipse.jgit.treewalk;
 
 import org.eclipse.jgit.lib.Config;
-import org.eclipse.jgit.lib.ConfigConstants;
 import org.eclipse.jgit.lib.Config.SectionParser;
+import org.eclipse.jgit.lib.ConfigConstants;
 import org.eclipse.jgit.lib.CoreConfig.AutoCRLF;
 import org.eclipse.jgit.lib.CoreConfig.CheckStat;
 import org.eclipse.jgit.lib.CoreConfig.EOL;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/ChangeIdUtil.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/ChangeIdUtil.java
index e14096e..f1f6053 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/ChangeIdUtil.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/ChangeIdUtil.java
@@ -45,8 +45,8 @@
 import java.util.regex.Pattern;
 
 import org.eclipse.jgit.lib.Constants;
-import org.eclipse.jgit.lib.ObjectInserter;
 import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.ObjectInserter;
 import org.eclipse.jgit.lib.PersonIdent;
 
 /**
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/FS.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/FS.java
index a55b5c0..dcd7970 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/FS.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/FS.java
@@ -164,7 +164,7 @@
 	/** The auto-detected implementation selected for this operating system and JRE. */
 	public static final FS DETECTED = detect();
 
-	private static FSFactory factory;
+	private volatile static FSFactory factory;
 
 	/**
 	 * Auto-detect the appropriate file system abstraction.
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/HttpSupport.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/HttpSupport.java
index 202645b..251381a 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/HttpSupport.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/HttpSupport.java
@@ -144,6 +144,12 @@
 	/** The {@code gzip} encoding value for {@link #HDR_ACCEPT_ENCODING}. */
 	public static final String ENCODING_GZIP = "gzip"; //$NON-NLS-1$
 
+	/**
+	 * The {@code x-gzip} encoding value for {@link #HDR_ACCEPT_ENCODING}.
+	 * @since 4.6
+	 */
+	public static final String ENCODING_X_GZIP = "x-gzip"; //$NON-NLS-1$
+
 	/** The standard {@code text/plain} MIME type. */
 	public static final String TEXT_PLAIN = "text/plain"; //$NON-NLS-1$
 
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/SystemReader.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/SystemReader.java
index 9860ef0..b36fc23 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/SystemReader.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/SystemReader.java
@@ -56,10 +56,12 @@
 import java.util.Locale;
 import java.util.TimeZone;
 
-import org.eclipse.jgit.storage.file.FileBasedConfig;
 import org.eclipse.jgit.errors.CorruptObjectException;
 import org.eclipse.jgit.lib.Config;
 import org.eclipse.jgit.lib.ObjectChecker;
+import org.eclipse.jgit.storage.file.FileBasedConfig;
+import org.eclipse.jgit.util.time.MonotonicClock;
+import org.eclipse.jgit.util.time.MonotonicSystemClock;
 
 /**
  * Interface to read values from the system.
@@ -231,6 +233,14 @@
 	public abstract long getCurrentTime();
 
 	/**
+	 * @return clock instance preferred by this system.
+	 * @since 4.6
+	 */
+	public MonotonicClock getClock() {
+		return new MonotonicSystemClock();
+	}
+
+	/**
 	 * @param when TODO
 	 * @return the local time zone
 	 */
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/TemporaryBuffer.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/TemporaryBuffer.java
index 3cd5929..57bcfbd 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/TemporaryBuffer.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/TemporaryBuffer.java
@@ -56,7 +56,6 @@
 import org.eclipse.jgit.internal.JGitText;
 import org.eclipse.jgit.lib.NullProgressMonitor;
 import org.eclipse.jgit.lib.ProgressMonitor;
-import org.eclipse.jgit.util.io.SafeBufferedOutputStream;
 
 /**
  * A fully buffered output stream.
@@ -360,7 +359,7 @@
 			overflow.write(b.buffer, 0, b.count);
 		blocks = null;
 
-		overflow = new SafeBufferedOutputStream(overflow, Block.SZ);
+		overflow = new BufferedOutputStream(overflow, Block.SZ);
 		overflow.write(last.buffer, 0, last.count);
 	}
 
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/IsolatedOutputStream.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/IsolatedOutputStream.java
new file mode 100644
index 0000000..3598a7b
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/IsolatedOutputStream.java
@@ -0,0 +1,243 @@
+/*
+ * Copyright (C) 2016, Google Inc.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ *   copyright notice, this list of conditions and the following
+ *   disclaimer in the documentation and/or other materials provided
+ *   with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ *   names of its contributors may be used to endorse or promote
+ *   products derived from this software without specific prior
+ *   written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.util.io;
+
+import java.io.IOException;
+import java.io.InterruptedIOException;
+import java.io.OutputStream;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Future;
+import java.util.concurrent.RejectedExecutionException;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.eclipse.jgit.internal.JGitText;
+
+/**
+ * OutputStream isolated from interrupts.
+ * <p>
+ * Wraps an OutputStream to prevent interrupts during writes from being made
+ * visible to that stream instance. This works around buggy or difficult
+ * OutputStream implementations like JSch that cannot gracefully handle an
+ * interrupt during write.
+ * <p>
+ * Every write (or flush) requires a context switch to another thread. Callers
+ * should wrap this stream with {@code BufferedOutputStream} using a suitable
+ * buffer size to amortize the cost of context switches.
+ *
+ * @since 4.6
+ */
+public class IsolatedOutputStream extends OutputStream {
+	private final OutputStream dst;
+	private final ExecutorService copier;
+	private Future<Void> pending;
+
+	/**
+	 * Wraps an OutputStream.
+	 *
+	 * @param out
+	 *            stream to send all writes to.
+	 */
+	public IsolatedOutputStream(OutputStream out) {
+		dst = out;
+		copier = new ThreadPoolExecutor(1, 1, 0, TimeUnit.MILLISECONDS,
+				new ArrayBlockingQueue<Runnable>(1), new NamedThreadFactory());
+	}
+
+	@Override
+	public void write(int ch) throws IOException {
+		write(new byte[] { (byte) ch }, 0, 1);
+	}
+
+	@Override
+	public void write(final byte[] buf, final int pos, final int cnt)
+			throws IOException {
+		checkClosed();
+		execute(new Callable<Void>() {
+			@Override
+			public Void call() throws IOException {
+				dst.write(buf, pos, cnt);
+				return null;
+			}
+		});
+	}
+
+	@Override
+	public void flush() throws IOException {
+		checkClosed();
+		execute(new Callable<Void>() {
+			@Override
+			public Void call() throws IOException {
+				dst.flush();
+				return null;
+			}
+		});
+	}
+
+	@Override
+	public void close() throws IOException {
+		if (!copier.isShutdown()) {
+			try {
+				if (pending == null || tryCleanClose()) {
+					cleanClose();
+				} else {
+					dirtyClose();
+				}
+			} finally {
+				copier.shutdown();
+			}
+		}
+	}
+
+	private boolean tryCleanClose() {
+		/*
+		 * If the caller stopped waiting for a prior write or flush, they could
+		 * be trying to close a stream that is still in-use. Check if the prior
+		 * operation ended in a predictable way.
+		 */
+		try {
+			pending.get(0, TimeUnit.MILLISECONDS);
+			pending = null;
+			return true;
+		} catch (TimeoutException | InterruptedException e) {
+			return false;
+		} catch (ExecutionException e) {
+			pending = null;
+			return true;
+		}
+	}
+
+	private void cleanClose() throws IOException {
+		execute(new Callable<Void>() {
+			@Override
+			public Void call() throws IOException {
+				dst.close();
+				return null;
+			}
+		});
+	}
+
+	private void dirtyClose() throws IOException {
+		/*
+		 * Interrupt any still pending write or flush operation. This may cause
+		 * massive failures inside of the stream, but its going to be closed as
+		 * the next step.
+		 */
+		pending.cancel(true);
+
+		Future<Void> close;
+		try {
+			close = copier.submit(new Callable<Void>() {
+				@Override
+				public Void call() throws IOException {
+					dst.close();
+					return null;
+				}
+			});
+		} catch (RejectedExecutionException e) {
+			throw new IOException(e);
+		}
+		try {
+			close.get(200, TimeUnit.MILLISECONDS);
+		} catch (InterruptedException | TimeoutException e) {
+			close.cancel(true);
+			throw new IOException(e);
+		} catch (ExecutionException e) {
+			throw new IOException(e.getCause());
+		}
+	}
+
+	private void checkClosed() throws IOException {
+		if (copier.isShutdown()) {
+			throw new IOException(JGitText.get().closed);
+		}
+	}
+
+	private void execute(Callable<Void> task) throws IOException {
+		if (pending != null) {
+			// Check (and rethrow) any prior failed operation.
+			checkedGet(pending);
+		}
+		try {
+			pending = copier.submit(task);
+		} catch (RejectedExecutionException e) {
+			throw new IOException(e);
+		}
+		checkedGet(pending);
+		pending = null;
+	}
+
+	private static void checkedGet(Future<Void> future) throws IOException {
+		try {
+			future.get();
+		} catch (InterruptedException e) {
+			throw interrupted(e);
+		} catch (ExecutionException e) {
+			throw new IOException(e.getCause());
+		}
+	}
+
+	private static InterruptedIOException interrupted(InterruptedException c) {
+		InterruptedIOException e = new InterruptedIOException();
+		e.initCause(c);
+		return e;
+	}
+
+	private static class NamedThreadFactory implements ThreadFactory {
+		private static final AtomicInteger cnt = new AtomicInteger();
+
+		@Override
+		public Thread newThread(Runnable r) {
+			int n = cnt.incrementAndGet();
+			String name = IsolatedOutputStream.class.getSimpleName() + '-' + n;
+			return new Thread(r, name);
+		}
+	}
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/SafeBufferedOutputStream.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/SafeBufferedOutputStream.java
index 68f250d..84c3398 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/SafeBufferedOutputStream.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/SafeBufferedOutputStream.java
@@ -43,20 +43,13 @@
 package org.eclipse.jgit.util.io;
 
 import java.io.BufferedOutputStream;
-import java.io.IOException;
 import java.io.OutputStream;
 
 /**
- * A BufferedOutputStream that throws an error if the final flush fails on
- * close.
- * <p>
- * Java's BufferedOutputStream swallows errors that occur when the output stream
- * tries to write the final bytes to the output during close. This may result in
- * corrupted files without notice.
- * </p>
+ * @deprecated use BufferedOutputStream in Java 8 and later.
  */
+@Deprecated
 public class SafeBufferedOutputStream extends BufferedOutputStream {
-
 	/**
 	 * @see BufferedOutputStream#BufferedOutputStream(OutputStream)
 	 * @param out
@@ -76,13 +69,4 @@
 	public SafeBufferedOutputStream(OutputStream out, int size) {
 		super(out, size);
 	}
-
-	@Override
-	public void close() throws IOException {
-		try {
-			flush();
-		} finally {
-			super.close();
-		}
-	}
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/StreamCopyThread.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/StreamCopyThread.java
index 8d39a22..7aba0a5 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/StreamCopyThread.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/StreamCopyThread.java
@@ -47,7 +47,6 @@
 import java.io.InputStream;
 import java.io.InterruptedIOException;
 import java.io.OutputStream;
-import java.util.concurrent.atomic.AtomicInteger;
 
 /** Thread to copy from an input stream to an output stream. */
 public class StreamCopyThread extends Thread {
@@ -59,7 +58,8 @@
 
 	private volatile boolean done;
 
-	private final AtomicInteger flushCount = new AtomicInteger(0);
+	/** Lock held by flush to avoid interrupting a write. */
+	private final Object writeLock;
 
 	/**
 	 * Create a thread to copy data from an input stream to an output stream.
@@ -75,6 +75,7 @@
 		setName(Thread.currentThread().getName() + "-StreamCopy"); //$NON-NLS-1$
 		src = i;
 		dst = o;
+		writeLock = new Object();
 	}
 
 	/**
@@ -84,9 +85,11 @@
 	 * happen at some future point in time, when the thread wakes up to process
 	 * the request.
 	 */
+	@Deprecated
 	public void flush() {
-		flushCount.incrementAndGet();
-		interrupt();
+		synchronized (writeLock) {
+			interrupt();
+		}
 	}
 
 	/**
@@ -113,25 +116,23 @@
 	public void run() {
 		try {
 			final byte[] buf = new byte[BUFFER_SIZE];
-			int flushCountBeforeRead = 0;
 			boolean readInterrupted = false;
 			for (;;) {
 				try {
 					if (readInterrupted) {
-						dst.flush();
-						readInterrupted = false;
-						if (!flushCount.compareAndSet(flushCountBeforeRead, 0)) {
-							// There was a flush() call since last blocked read.
-							// Set interrupt status, so next blocked read will throw
-							// an InterruptedIOException and we will flush again.
-							interrupt();
+						synchronized (writeLock) {
+							boolean interruptedAgain = Thread.interrupted();
+							dst.flush();
+							if (interruptedAgain) {
+								interrupt();
+							}
 						}
+						readInterrupted = false;
 					}
 
 					if (done)
 						break;
 
-					flushCountBeforeRead = flushCount.get();
 					final int n;
 					try {
 						n = src.read(buf);
@@ -142,20 +143,12 @@
 					if (n < 0)
 						break;
 
-					boolean writeInterrupted = false;
-					for (;;) {
-						try {
-							dst.write(buf, 0, n);
-						} catch (InterruptedIOException wakey) {
-							writeInterrupted = true;
-							continue;
-						}
-
-						// set interrupt status, which will be checked
-						// when we block in src.read
-						if (writeInterrupted || flushCount.get() > 0)
+					synchronized (writeLock) {
+						boolean writeInterrupted = Thread.interrupted();
+						dst.write(buf, 0, n);
+						if (writeInterrupted) {
 							interrupt();
-						break;
+						}
 					}
 				} catch (IOException e) {
 					break;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/time/MonotonicClock.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/time/MonotonicClock.java
new file mode 100644
index 0000000..794d851
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/time/MonotonicClock.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2016, Google Inc.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ *   copyright notice, this list of conditions and the following
+ *   disclaimer in the documentation and/or other materials provided
+ *   with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ *   names of its contributors may be used to endorse or promote
+ *   products derived from this software without specific prior
+ *   written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.util.time;
+
+import java.time.Duration;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * A provider of time.
+ * <p>
+ * Clocks should provide wall clock time, obtained from a reasonable clock
+ * source, such as the local system clock.
+ * <p>
+ * MonotonicClocks provide the following behavior, with the assertion always
+ * being true if {@link ProposedTimestamp#blockUntil(Duration)} is used:
+ *
+ * <pre>
+ *   MonotonicClock clk = ...;
+ *   long r1;
+ *   try (ProposedTimestamp t1 = clk.propose()) {
+ *   	r1 = t1.millis();
+ *   	t1.blockUntil(...);
+ *   }
+ *
+ *   try (ProposedTimestamp t2 = clk.propose()) {
+ *   	assert t2.millis() > r1;
+ *   }
+ * </pre>
+ *
+ * @since 4.6
+ */
+public interface MonotonicClock {
+	/**
+	 * Obtain a timestamp close to "now".
+	 * <p>
+	 * Proposed times are close to "now", but may not yet be certainly in the
+	 * past. This allows the calling thread to interleave other useful work
+	 * while waiting for the clock instance to create an assurance it will never
+	 * in the future propose a time earlier than the returned time.
+	 * <p>
+	 * A hypothetical implementation could read the local system clock (managed
+	 * by NTP) and return that proposal, concurrently sending network messages
+	 * to closely collaborating peers in the same cluster to also ensure their
+	 * system clocks are ahead of this time. In such an implementation the
+	 * {@link ProposedTimestamp#blockUntil(Duration)} method would wait for
+	 * replies from the peers indicating their own system clocks have moved past
+	 * the proposed time.
+	 *
+	 * @return "now". The value can be immediately accessed by
+	 *         {@link ProposedTimestamp#read(TimeUnit)} and friends, but the
+	 *         caller must use {@link ProposedTimestamp#blockUntil(Duration)} to
+	 *         ensure ordering holds.
+	 */
+	ProposedTimestamp propose();
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/time/MonotonicSystemClock.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/time/MonotonicSystemClock.java
new file mode 100644
index 0000000..a9f4830
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/time/MonotonicSystemClock.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2016, Google Inc.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ *   copyright notice, this list of conditions and the following
+ *   disclaimer in the documentation and/or other materials provided
+ *   with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ *   names of its contributors may be used to endorse or promote
+ *   products derived from this software without specific prior
+ *   written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.util.time;
+
+import static java.util.concurrent.TimeUnit.MICROSECONDS;
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
+
+import java.time.Duration;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicLong;
+
+/**
+ * A {@link MonotonicClock} based on {@code System.currentTimeMillis}.
+ *
+ * @since 4.6
+ */
+public class MonotonicSystemClock implements MonotonicClock {
+	private static final AtomicLong before = new AtomicLong();
+
+	private static long nowMicros() {
+		long now = MILLISECONDS.toMicros(System.currentTimeMillis());
+		for (;;) {
+			long o = before.get();
+			long n = Math.max(o + 1, now);
+			if (before.compareAndSet(o, n)) {
+				return n;
+			}
+		}
+	}
+
+	@Override
+	public ProposedTimestamp propose() {
+		final long u = nowMicros();
+		return new ProposedTimestamp() {
+			@Override
+			public long read(TimeUnit unit) {
+				return unit.convert(u, MICROSECONDS);
+			}
+
+			@Override
+			public void blockUntil(Duration maxWait) {
+				// Assume system clock never goes backwards.
+			}
+		};
+	}
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/time/ProposedTimestamp.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/time/ProposedTimestamp.java
new file mode 100644
index 0000000..c09ab32
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/time/ProposedTimestamp.java
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2016, Google Inc.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ *   copyright notice, this list of conditions and the following
+ *   disclaimer in the documentation and/or other materials provided
+ *   with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ *   names of its contributors may be used to endorse or promote
+ *   products derived from this software without specific prior
+ *   written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.util.time;
+
+import static java.util.concurrent.TimeUnit.MICROSECONDS;
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
+
+import java.sql.Timestamp;
+import java.time.Duration;
+import java.time.Instant;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+/**
+ * A timestamp generated by {@link MonotonicClock#propose()}.
+ * <p>
+ * ProposedTimestamp implements AutoCloseable so that implementations can
+ * release resources associated with obtaining certainty about time elapsing.
+ * For example the constructing MonotonicClock may start network IO with peers
+ * when creating the ProposedTimestamp, and {@link #close()} can ensure those
+ * network resources are released in a timely fashion.
+ *
+ * @since 4.6
+ */
+public abstract class ProposedTimestamp implements AutoCloseable {
+	/**
+	 * Wait for several timestamps.
+	 *
+	 * @param times
+	 *            timestamps to wait on.
+	 * @param maxWait
+	 *            how long to wait for the timestamps.
+	 * @throws InterruptedException
+	 *             current thread was interrupted before the waiting process
+	 *             completed normally.
+	 * @throws TimeoutException
+	 *             the timeout was reached without the proposed timestamp become
+	 *             certainly in the past.
+	 */
+	public static void blockUntil(Iterable<ProposedTimestamp> times,
+			Duration maxWait) throws TimeoutException, InterruptedException {
+		Iterator<ProposedTimestamp> itr = times.iterator();
+		if (!itr.hasNext()) {
+			return;
+		}
+
+		long now = System.currentTimeMillis();
+		long deadline = now + maxWait.toMillis();
+		for (;;) {
+			long w = deadline - now;
+			if (w < 0) {
+				throw new TimeoutException();
+			}
+			itr.next().blockUntil(Duration.ofMillis(w));
+			if (itr.hasNext()) {
+				now = System.currentTimeMillis();
+			} else {
+				break;
+			}
+		}
+	}
+
+	/**
+	 * Read the timestamp as {@code unit} since the epoch.
+	 * <p>
+	 * The timestamp value for a specific {@code ProposedTimestamp} object never
+	 * changes, and can be read before {@link #blockUntil(Duration)}.
+	 *
+	 * @param unit
+	 *            what unit to return the timestamp in. The timestamp will be
+	 *            rounded if the unit is bigger than the clock's granularity.
+	 * @return {@code unit} since the epoch.
+	 */
+	public abstract long read(TimeUnit unit);
+
+	/**
+	 * Wait for this proposed timestamp to be certainly in the recent past.
+	 * <p>
+	 * This method forces the caller to wait up to {@code timeout} for
+	 * {@code this} to pass sufficiently into the past such that the creating
+	 * {@link MonotonicClock} instance will not create an earlier timestamp.
+	 *
+	 * @param maxWait
+	 *            how long the implementation may block the caller.
+	 * @throws InterruptedException
+	 *             current thread was interrupted before the waiting process
+	 *             completed normally.
+	 * @throws TimeoutException
+	 *             the timeout was reached without the proposed timestamp
+	 *             becoming certainly in the past.
+	 */
+	public abstract void blockUntil(Duration maxWait)
+			throws InterruptedException, TimeoutException;
+
+	/** @return milliseconds since epoch; {@code read(MILLISECONDS}). */
+	public long millis() {
+		return read(MILLISECONDS);
+	}
+
+	/** @return microseconds since epoch; {@code read(MICROSECONDS}). */
+	public long micros() {
+		return read(MICROSECONDS);
+	}
+
+	/** @return time since epoch, with up to microsecond resolution. */
+	public Instant instant() {
+		long usec = micros();
+		long secs = usec / 1000000L;
+		long nanos = (usec % 1000000L) * 1000L;
+		return Instant.ofEpochSecond(secs, nanos);
+	}
+
+	/** @return time since epoch, with up to microsecond resolution. */
+	public Timestamp timestamp() {
+		return Timestamp.from(instant());
+	}
+
+	/** @return time since epoch, with up to millisecond resolution. */
+	public Date date() {
+		return new Date(millis());
+	}
+
+	/** Release resources allocated by this timestamp. */
+	@Override
+	public void close() {
+		// Do nothing by default.
+	}
+
+	@Override
+	public String toString() {
+		return instant().toString();
+	}
+}
diff --git a/pom.xml b/pom.xml
index 55370ad..b8154c1 100644
--- a/pom.xml
+++ b/pom.xml
@@ -51,7 +51,7 @@
   <groupId>org.eclipse.jgit</groupId>
   <artifactId>org.eclipse.jgit-parent</artifactId>
   <packaging>pom</packaging>
-  <version>4.5.3-SNAPSHOT</version>
+  <version>4.6.2-SNAPSHOT</version>
 
   <name>JGit - Parent</name>
   <url>${jgit-url}</url>
@@ -190,25 +190,23 @@
     <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
     <maven.build.timestamp.format>yyyyMMddHHmm</maven.build.timestamp.format>
     <bundle-manifest>${project.build.directory}/META-INF/MANIFEST.MF</bundle-manifest>
-    <!-- set JDK_HOME to JAVA_HOME path of JDK7 installation in order to compile against JDK 7 class library -->
-    <JDK_HOME>${JAVA_HOME}</JDK_HOME>
 
     <jgit-last-release-version>4.2.0.201601211800-r</jgit-last-release-version>
     <jsch-version>0.1.53</jsch-version>
-    <javaewah-version>0.7.9</javaewah-version>
+    <javaewah-version>1.1.6</javaewah-version>
     <junit-version>4.12</junit-version>
     <test-fork-count>1C</test-fork-count>
     <args4j-version>2.0.15</args4j-version>
     <commons-compress-version>1.6</commons-compress-version>
     <osgi-core-version>4.3.1</osgi-core-version>
     <servlet-api-version>3.1.0</servlet-api-version>
-    <jetty-version>9.2.13.v20150730</jetty-version>
+    <jetty-version>9.3.17.v20170317</jetty-version>
     <japicmp-version>0.5.3</japicmp-version>
     <httpclient-version>4.3.6</httpclient-version>
     <slf4j-version>1.7.2</slf4j-version>
     <log4j-version>1.2.15</log4j-version>
-    <maven-javadoc-plugin-version>2.10.3</maven-javadoc-plugin-version>
-    <tycho-extras-version>0.25.0</tycho-extras-version>
+    <maven-javadoc-plugin-version>2.10.4</maven-javadoc-plugin-version>
+    <tycho-extras-version>0.26.0</tycho-extras-version>
     <gson-version>2.2.4</gson-version>
 
     <!-- Properties to enable jacoco code coverage analysis -->
@@ -241,7 +239,7 @@
         <plugin>
           <groupId>org.apache.maven.plugins</groupId>
           <artifactId>maven-jar-plugin</artifactId>
-          <version>2.6</version>
+          <version>3.0.2</version>
           <configuration>
             <archive>
               <manifestEntries>
@@ -260,15 +258,59 @@
 
         <plugin>
           <artifactId>maven-compiler-plugin</artifactId>
-          <version>3.5.1</version>
+          <version>3.6.0</version>
           <configuration>
             <encoding>UTF-8</encoding>
-            <source>1.7</source>
-            <target>1.7</target>
-            <compilerArguments>
-              <bootclasspath>${JDK_HOME}${file.separator}jre${file.separator}lib${file.separator}rt.jar${path.separator}${JDK_HOME}${file.separator}jre${file.separator}lib${file.separator}jsse.jar${path.separator}${JDK_HOME}${file.separator}jre${file.separator}lib${file.separator}jce.jar</bootclasspath>
-            </compilerArguments>
+            <source>1.8</source>
+            <target>1.8</target>
           </configuration>
+          <executions>
+            <execution>
+              <id>default-compile</id>
+              <phase>compile</phase>
+              <goals>
+                <goal>compile</goal>
+              </goals>
+              <configuration>
+                <includes>
+                  <include>org/eclipse/jgit/transport/InsecureCipherFactory.java</include>
+                </includes>
+              </configuration>
+            </execution>
+            <execution>
+              <id>compile-with-errorprone</id>
+              <phase>compile</phase>
+              <goals>
+                <goal>compile</goal>
+              </goals>
+              <configuration>
+                <compilerId>javac-with-errorprone</compilerId>
+                <forceJavacCompilerUse>true</forceJavacCompilerUse>
+                <excludes>
+                  <exclude>org/eclipse/jgit/transport/InsecureCipherFactory.java</exclude>
+                </excludes>
+              </configuration>
+            </execution>
+          </executions>
+          <dependencies>
+            <dependency>
+              <groupId>org.codehaus.plexus</groupId>
+              <artifactId>plexus-compiler-javac</artifactId>
+              <version>2.8.1</version>
+            </dependency>
+            <dependency>
+              <groupId>org.codehaus.plexus</groupId>
+              <artifactId>plexus-compiler-javac-errorprone</artifactId>
+              <version>2.8.1</version>
+            </dependency>
+            <!-- override plexus-compiler-javac-errorprone's dependency on
+                 Error Prone with the latest version -->
+            <dependency>
+              <groupId>com.google.errorprone</groupId>
+              <artifactId>error_prone_core</artifactId>
+              <version>2.0.15</version>
+            </dependency>
+          </dependencies>
         </plugin>
 
         <plugin>
@@ -291,13 +333,13 @@
         <plugin>
           <groupId>org.apache.maven.plugins</groupId>
           <artifactId>maven-dependency-plugin</artifactId>
-          <version>2.10</version>
+          <version>3.0.0</version>
         </plugin>
 
         <plugin>
           <groupId>org.apache.maven.plugins</groupId>
           <artifactId>maven-source-plugin</artifactId>
-          <version>3.0.0</version>
+          <version>3.0.1</version>
         </plugin>
 
         <plugin>
@@ -319,13 +361,13 @@
         <plugin>
           <groupId>org.codehaus.mojo</groupId>
           <artifactId>build-helper-maven-plugin</artifactId>
-          <version>1.10</version>
+          <version>1.12</version>
         </plugin>
 
         <plugin>
           <groupId>org.codehaus.mojo</groupId>
           <artifactId>findbugs-maven-plugin</artifactId>
-          <version>3.0.3</version>
+          <version>3.0.4</version>
           <configuration>
             <findbugsXmlOutput>true</findbugsXmlOutput>
             <failOnError>false</failOnError>
@@ -342,11 +384,11 @@
         <plugin>
           <groupId>org.apache.maven.plugins</groupId>
           <artifactId>maven-pmd-plugin</artifactId>
-          <version>3.6</version>
+          <version>3.7</version>
           <configuration>
             <sourceEncoding>utf-8</sourceEncoding>
             <minimumTokens>100</minimumTokens>
-            <targetJdk>1.7</targetJdk>
+            <targetJdk>1.8</targetJdk>
             <format>xml</format>
             <failOnViolation>false</failOnViolation>
           </configuration>
@@ -377,12 +419,12 @@
         <plugin>
           <groupId>org.jacoco</groupId>
           <artifactId>jacoco-maven-plugin</artifactId>
-          <version>0.7.6.201602180812</version>
+          <version>0.7.8</version>
         </plugin>
         <plugin>
           <groupId>org.apache.maven.plugins</groupId>
           <artifactId>maven-site-plugin</artifactId>
-          <version>3.5.1</version>
+          <version>3.6</version>
           <dependencies>
             <dependency><!-- add support for ssh/scp -->
               <groupId>org.apache.maven.wagon</groupId>
@@ -459,7 +501,7 @@
           <quiet>true</quiet>
           <excludePackageNames>org.eclipse.jgit.http.test</excludePackageNames>
           <links>
-            <link>http://docs.oracle.com/javase/7/docs/api</link>
+            <link>http://docs.oracle.com/javase/8/docs/api</link>
           </links>
         </configuration>
         <executions>
@@ -668,12 +710,6 @@
 
   <profiles>
     <profile>
-      <id>jgit.java7</id>
-      <activation>
-        <jdk>[1.7,)</jdk>
-      </activation>
-    </profile>
-    <profile>
       <id>jgit.java8</id>
       <activation>
         <jdk>[1.8,)</jdk>
diff --git a/tools/eclipse-JGit-Format.xml b/tools/eclipse-JGit-Format.xml
index 278b449..490758a 100644
--- a/tools/eclipse-JGit-Format.xml
+++ b/tools/eclipse-JGit-Format.xml
@@ -45,7 +45,7 @@
 <setting id="org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk" value="1"/>
 <setting id="org.eclipse.jdt.core.formatter.insert_space_before_binary_operator" value="insert"/>
 <setting id="org.eclipse.jdt.core.formatter.blank_lines_before_package" value="0"/>
-<setting id="org.eclipse.jdt.core.compiler.source" value="1.7"/>
+<setting id="org.eclipse.jdt.core.compiler.source" value="1.8"/>
 <setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration" value="do not insert"/>
 <setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments" value="insert"/>
 <setting id="org.eclipse.jdt.core.formatter.comment.format_line_comments" value="true"/>
@@ -156,7 +156,7 @@
 <setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference" value="do not insert"/>
 <setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression" value="16"/>
 <setting id="org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter" value="insert"/>
-<setting id="org.eclipse.jdt.core.compiler.compliance" value="1.7"/>
+<setting id="org.eclipse.jdt.core.compiler.compliance" value="1.8"/>
 <setting id="org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer" value="2"/>
 <setting id="org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration" value="insert"/>
 <setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression" value="do not insert"/>
@@ -227,7 +227,7 @@
 <setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws" value="insert"/>
 <setting id="org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration" value="16"/>
 <setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer" value="insert"/>
-<setting id="org.eclipse.jdt.core.compiler.codegen.targetPlatform" value="1.7"/>
+<setting id="org.eclipse.jdt.core.compiler.codegen.targetPlatform" value="1.8"/>
 <setting id="org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations" value="false"/>
 <setting id="org.eclipse.jdt.core.formatter.comment.format_header" value="false"/>
 <setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_member" value="insert"/>