Merge branch 'stable-3.5'

* stable-3.5:
  Prepare 3.5.3-SNAPSHOT builds
  JGit v3.5.2.201411120430-r
  Don't use SSL anymore to avoid POODLE attack

Change-Id: Icc8404a94512aae36da83baafb8b10422b7bbf7b
Signed-off-by: Matthias Sohn <matthias.sohn@sap.com>
diff --git a/org.eclipse.jgit.ant.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.ant.test/META-INF/MANIFEST.MF
index ea3b8af..6ea67f0 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: 3.5.3.qualifier
+Bundle-Version: 3.6.0.qualifier
 Bundle-ActivationPolicy: lazy
 Bundle-RequiredExecutionEnvironment: J2SE-1.5
 Import-Package: org.apache.tools.ant,
- org.eclipse.jgit.ant.tasks;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.internal.storage.file;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.junit;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.lib;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.util;version="[3.5.3,3.6.0)",
+ org.eclipse.jgit.ant.tasks;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.internal.storage.file;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.junit;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.lib;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.util;version="[3.6.0,3.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/pom.xml b/org.eclipse.jgit.ant.test/pom.xml
index f58390d..dcae4b1 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>3.5.3-SNAPSHOT</version>
+    <version>3.6.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>org.eclipse.jgit.ant.test</artifactId>
diff --git a/org.eclipse.jgit.ant/META-INF/MANIFEST.MF b/org.eclipse.jgit.ant/META-INF/MANIFEST.MF
index 5e7fd81..6ea680b 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: 3.5.3.qualifier
+Bundle-Version: 3.6.0.qualifier
 Bundle-RequiredExecutionEnvironment: J2SE-1.5
 Import-Package: org.apache.tools.ant,
-  org.eclipse.jgit.storage.file;version="[3.5.3,3.6.0)"
+  org.eclipse.jgit.storage.file;version="[3.6.0,3.7.0)"
 Bundle-Localization: plugin
 Bundle-Vendor: %Provider-Name
-Export-Package: org.eclipse.jgit.ant.tasks;version="3.5.3";
+Export-Package: org.eclipse.jgit.ant.tasks;version="3.6.0";
  uses:="org.apache.tools.ant.types,org.apache.tools.ant"
diff --git a/org.eclipse.jgit.ant/pom.xml b/org.eclipse.jgit.ant/pom.xml
index c2fe4b0..f22ff58 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>3.5.3-SNAPSHOT</version>
+		<version>3.6.0-SNAPSHOT</version>
 	</parent>
 
 	<artifactId>org.eclipse.jgit.ant</artifactId>
diff --git a/org.eclipse.jgit.archive/META-INF/MANIFEST.MF b/org.eclipse.jgit.archive/META-INF/MANIFEST.MF
index c9697ee..0cb8150 100644
--- a/org.eclipse.jgit.archive/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.archive/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@
 Bundle-ManifestVersion: 2
 Bundle-Name: %plugin_name
 Bundle-SymbolicName: org.eclipse.jgit.archive
-Bundle-Version: 3.5.3.qualifier
+Bundle-Version: 3.6.0.qualifier
 Bundle-Vendor: %provider_name
 Bundle-Localization: plugin
 Bundle-RequiredExecutionEnvironment: J2SE-1.5
@@ -12,13 +12,13 @@
  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="[3.5.3,3.6.0)",
- org.eclipse.jgit.lib;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.nls;version="[3.5.3,3.6.0)",
+ org.eclipse.jgit.api;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.lib;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.nls;version="[3.6.0,3.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="3.5.3";
+Export-Package: org.eclipse.jgit.archive;version="3.6.0";
   uses:="org.eclipse.jgit.lib,
    org.eclipse.jgit.api,
    org.apache.commons.compress.archivers,
diff --git a/org.eclipse.jgit.archive/META-INF/SOURCE-MANIFEST.MF b/org.eclipse.jgit.archive/META-INF/SOURCE-MANIFEST.MF
index c4f2e87..b1d2399 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: 3.5.3.qualifier
-Eclipse-SourceBundle: org.eclipse.jgit.archive;version="3.5.3.qualifier";roots="."
+Bundle-Version: 3.6.0.qualifier
+Eclipse-SourceBundle: org.eclipse.jgit.archive;version="3.6.0.qualifier";roots="."
diff --git a/org.eclipse.jgit.archive/pom.xml b/org.eclipse.jgit.archive/pom.xml
index e10c7fb..41d71c6 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>3.5.3-SNAPSHOT</version>
+    <version>3.6.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>org.eclipse.jgit.archive</artifactId>
diff --git a/org.eclipse.jgit.console/META-INF/MANIFEST.MF b/org.eclipse.jgit.console/META-INF/MANIFEST.MF
index 2f2b057..a1f4bbb 100644
--- a/org.eclipse.jgit.console/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.console/META-INF/MANIFEST.MF
@@ -3,11 +3,11 @@
 Bundle-ManifestVersion: 2
 Bundle-Name: %plugin_name
 Bundle-SymbolicName: org.eclipse.jgit.console
-Bundle-Version: 3.5.3.qualifier
+Bundle-Version: 3.6.0.qualifier
 Bundle-Vendor: %provider_name
 Bundle-RequiredExecutionEnvironment: JavaSE-1.6
-Export-Package: org.eclipse.jgit.console;version="3.5.3"
-Import-Package: org.eclipse.jgit.errors;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.nls;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.transport;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.util;version="[3.5.3,3.6.0)"
+Export-Package: org.eclipse.jgit.console;version="3.6.0"
+Import-Package: org.eclipse.jgit.errors;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.nls;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.transport;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.util;version="[3.6.0,3.7.0)"
diff --git a/org.eclipse.jgit.console/pom.xml b/org.eclipse.jgit.console/pom.xml
index 2e3de84..84a8dc5 100644
--- a/org.eclipse.jgit.console/pom.xml
+++ b/org.eclipse.jgit.console/pom.xml
@@ -52,7 +52,7 @@
   <parent>
     <groupId>org.eclipse.jgit</groupId>
     <artifactId>org.eclipse.jgit-parent</artifactId>
-    <version>3.5.3-SNAPSHOT</version>
+    <version>3.6.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>org.eclipse.jgit.console</artifactId>
diff --git a/org.eclipse.jgit.http.apache/META-INF/MANIFEST.MF b/org.eclipse.jgit.http.apache/META-INF/MANIFEST.MF
index 389cfd4..1ea6612 100644
--- a/org.eclipse.jgit.http.apache/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.http.apache/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@
 Bundle-ManifestVersion: 2
 Bundle-Name: %Bundle-Name
 Bundle-SymbolicName: org.eclipse.jgit.http.apache
-Bundle-Version: 3.5.3.qualifier
+Bundle-Version: 3.6.0.qualifier
 Bundle-RequiredExecutionEnvironment: J2SE-1.5
 Bundle-Localization: plugin
 Bundle-Vendor: %Provider-Name
@@ -18,10 +18,10 @@
  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="[3.5.3,3.6.0)",
- org.eclipse.jgit.transport.http;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.util;version="[3.5.3,3.6.0)"
-Export-Package: org.eclipse.jgit.transport.http.apache;version="3.5.3";
+ org.eclipse.jgit.nls;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.transport.http;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.util;version="[3.6.0,3.7.0)"
+Export-Package: org.eclipse.jgit.transport.http.apache;version="3.6.0";
   uses:="org.eclipse.jgit.transport.http,
    javax.net.ssl,
    org.apache.http.client,
diff --git a/org.eclipse.jgit.http.apache/pom.xml b/org.eclipse.jgit.http.apache/pom.xml
index 3075044..4e30569 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>3.5.3-SNAPSHOT</version>
+		<version>3.6.0-SNAPSHOT</version>
 	</parent>
 
 	<artifactId>org.eclipse.jgit.http.apache</artifactId>
diff --git a/org.eclipse.jgit.http.server/META-INF/MANIFEST.MF b/org.eclipse.jgit.http.server/META-INF/MANIFEST.MF
index a14f41a..832a958 100644
--- a/org.eclipse.jgit.http.server/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.http.server/META-INF/MANIFEST.MF
@@ -2,14 +2,14 @@
 Bundle-ManifestVersion: 2
 Bundle-Name: %plugin_name
 Bundle-SymbolicName: org.eclipse.jgit.http.server
-Bundle-Version: 3.5.3.qualifier
+Bundle-Version: 3.6.0.qualifier
 Bundle-Localization: plugin
 Bundle-Vendor: %provider_name
 Export-Package: 
- org.eclipse.jgit.http.server;version="3.5.3",
- org.eclipse.jgit.http.server.glue;version="3.5.3";
+ org.eclipse.jgit.http.server;version="3.6.0",
+ org.eclipse.jgit.http.server.glue;version="3.6.0";
   uses:="javax.servlet,javax.servlet.http",
- org.eclipse.jgit.http.server.resolver;version="3.5.3";
+ org.eclipse.jgit.http.server.resolver;version="3.6.0";
   uses:="org.eclipse.jgit.transport.resolver,
    org.eclipse.jgit.lib,
    org.eclipse.jgit.transport,
@@ -18,11 +18,11 @@
 Bundle-RequiredExecutionEnvironment: J2SE-1.5
 Import-Package: javax.servlet;version="[2.5.0,3.0.0)",
  javax.servlet.http;version="[2.5.0,3.0.0)",
- org.eclipse.jgit.errors;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.internal.storage.file;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.lib;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.nls;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.revwalk;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.transport;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.transport.resolver;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.util;version="[3.5.3,3.6.0)"
+ org.eclipse.jgit.errors;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.internal.storage.file;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.lib;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.nls;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.revwalk;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.transport;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.transport.resolver;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.util;version="[3.6.0,3.7.0)"
diff --git a/org.eclipse.jgit.http.server/pom.xml b/org.eclipse.jgit.http.server/pom.xml
index ed49c53..7eb2998 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>3.5.3-SNAPSHOT</version>
+    <version>3.6.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>org.eclipse.jgit.http.server</artifactId>
diff --git a/org.eclipse.jgit.http.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.http.test/META-INF/MANIFEST.MF
index 58c42fc..a95a1bd 100644
--- a/org.eclipse.jgit.http.test/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.http.test/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@
 Bundle-ManifestVersion: 2
 Bundle-Name: %plugin_name
 Bundle-SymbolicName: org.eclipse.jgit.http.test
-Bundle-Version: 3.5.3.qualifier
+Bundle-Version: 3.6.0.qualifier
 Bundle-Vendor: %provider_name
 Bundle-Localization: plugin
 Bundle-RequiredExecutionEnvironment: J2SE-1.5
@@ -22,23 +22,23 @@
  org.eclipse.jetty.util.log;version="[7.6.0,8.0.0)",
  org.eclipse.jetty.util.security;version="[7.6.0,8.0.0)",
  org.eclipse.jetty.util.thread;version="[7.6.0,8.0.0)",
- org.eclipse.jgit.errors;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.http.server;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.http.server.glue;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.http.server.resolver;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.internal;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.internal.storage.file;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.junit;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.junit.http;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.lib;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.nls;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.revwalk;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.storage.file;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.transport;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.transport.http;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.transport.http.apache;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.transport.resolver;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.util;version="[3.5.3,3.6.0)",
+ org.eclipse.jgit.errors;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.http.server;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.http.server.glue;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.http.server.resolver;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.internal;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.internal.storage.file;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.junit;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.junit.http;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.lib;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.nls;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.revwalk;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.storage.file;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.transport;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.transport.http;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.transport.http.apache;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.transport.resolver;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.util;version="[3.6.0,3.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 30c513e..48f98a5 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>3.5.3-SNAPSHOT</version>
+    <version>3.6.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>org.eclipse.jgit.http.test</artifactId>
diff --git a/org.eclipse.jgit.java7.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.java7.test/META-INF/MANIFEST.MF
index 875df85..f6a7d83 100644
--- a/org.eclipse.jgit.java7.test/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.java7.test/META-INF/MANIFEST.MF
@@ -2,17 +2,17 @@
 Bundle-ManifestVersion: 2
 Bundle-Name: %plugin_name
 Bundle-SymbolicName: org.eclipse.jgit.java7.test
-Bundle-Version: 3.5.3.qualifier
+Bundle-Version: 3.6.0.qualifier
 Bundle-Vendor: %provider_name
 Bundle-RequiredExecutionEnvironment: JavaSE-1.7
-Import-Package: org.eclipse.jgit.api;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.diff;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.dircache;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.internal.storage.file;version="3.5.3",
- org.eclipse.jgit.junit;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.lib;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.revwalk;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.storage.file;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.treewalk;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.util;version="[3.5.3,3.6.0)",
+Import-Package: org.eclipse.jgit.api;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.diff;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.dircache;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.internal.storage.file;version="3.6.0",
+ org.eclipse.jgit.junit;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.lib;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.revwalk;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.storage.file;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.treewalk;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.util;version="[3.6.0,3.7.0)",
  org.junit;version="[4.11.0,5.0.0)"
diff --git a/org.eclipse.jgit.java7.test/pom.xml b/org.eclipse.jgit.java7.test/pom.xml
index 056e0c0..7acd3f5 100644
--- a/org.eclipse.jgit.java7.test/pom.xml
+++ b/org.eclipse.jgit.java7.test/pom.xml
@@ -50,7 +50,7 @@
   <parent>
     <groupId>org.eclipse.jgit</groupId>
     <artifactId>org.eclipse.jgit-parent</artifactId>
-    <version>3.5.3-SNAPSHOT</version>
+    <version>3.6.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>org.eclipse.jgit.java7.test</artifactId>
diff --git a/org.eclipse.jgit.java7/META-INF/MANIFEST.MF b/org.eclipse.jgit.java7/META-INF/MANIFEST.MF
index 4d5c7be..43bdf6a 100644
--- a/org.eclipse.jgit.java7/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.java7/META-INF/MANIFEST.MF
@@ -3,8 +3,8 @@
 Fragment-Host: org.eclipse.jgit;bundle-version="3.1.1"
 Bundle-Name: %plugin_name
 Bundle-SymbolicName: org.eclipse.jgit.java7
-Bundle-Version: 3.5.3.qualifier
+Bundle-Version: 3.6.0.qualifier
 Bundle-Localization: plugin
 Bundle-Vendor: %provider_name
 Bundle-RequiredExecutionEnvironment: JavaSE-1.7
-Export-Package: org.eclipse.jgit.util;version="3.5.3"
+Export-Package: org.eclipse.jgit.util;version="3.6.0"
diff --git a/org.eclipse.jgit.java7/META-INF/SOURCE-MANIFEST.MF b/org.eclipse.jgit.java7/META-INF/SOURCE-MANIFEST.MF
index 8f26d99..1143db4 100644
--- a/org.eclipse.jgit.java7/META-INF/SOURCE-MANIFEST.MF
+++ b/org.eclipse.jgit.java7/META-INF/SOURCE-MANIFEST.MF
@@ -3,6 +3,6 @@
 Bundle-Name: org.eclipse.jgit.java7 - Sources
 Bundle-SymbolicName: org.eclipse.jgit.java7.source
 Bundle-Vendor: Eclipse.org - JGit
-Bundle-Version: 3.5.3.qualifier
-Eclipse-SourceBundle: org.eclipse.jgit.java7;version="3.5.3.qualifier";roots="."
+Bundle-Version: 3.6.0.qualifier
+Eclipse-SourceBundle: org.eclipse.jgit.java7;version="3.6.0.qualifier";roots="."
 
diff --git a/org.eclipse.jgit.java7/pom.xml b/org.eclipse.jgit.java7/pom.xml
index 9c8d28e..0d046ec 100644
--- a/org.eclipse.jgit.java7/pom.xml
+++ b/org.eclipse.jgit.java7/pom.xml
@@ -50,7 +50,7 @@
   <parent>
     <groupId>org.eclipse.jgit</groupId>
     <artifactId>org.eclipse.jgit-parent</artifactId>
-    <version>3.5.3-SNAPSHOT</version>
+    <version>3.6.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>org.eclipse.jgit.java7</artifactId>
diff --git a/org.eclipse.jgit.junit.http/META-INF/MANIFEST.MF b/org.eclipse.jgit.junit.http/META-INF/MANIFEST.MF
index 2164ddb..a0a0dcd 100644
--- a/org.eclipse.jgit.junit.http/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.junit.http/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@
 Bundle-ManifestVersion: 2
 Bundle-Name: %plugin_name
 Bundle-SymbolicName: org.eclipse.jgit.junit.http
-Bundle-Version: 3.5.3.qualifier
+Bundle-Version: 3.6.0.qualifier
 Bundle-Localization: plugin
 Bundle-Vendor: %provider_name
 Bundle-ActivationPolicy: lazy
@@ -20,13 +20,13 @@
  org.eclipse.jetty.util.component;version="[7.6.0,8.0.0)",
  org.eclipse.jetty.util.log;version="[7.6.0,8.0.0)",
  org.eclipse.jetty.util.security;version="[7.6.0,8.0.0)",
- org.eclipse.jgit.errors;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.http.server;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.internal.storage.file;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.junit;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.lib;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.revwalk;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.transport;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.transport.resolver;version="[3.5.3,3.6.0)",
+ org.eclipse.jgit.errors;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.http.server;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.internal.storage.file;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.junit;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.lib;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.revwalk;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.transport;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.transport.resolver;version="[3.6.0,3.7.0)",
  org.junit;version="[4.0.0,5.0.0)"
-Export-Package: org.eclipse.jgit.junit.http;version="3.5.3"
+Export-Package: org.eclipse.jgit.junit.http;version="3.6.0"
diff --git a/org.eclipse.jgit.junit.http/pom.xml b/org.eclipse.jgit.junit.http/pom.xml
index d2097d3..96cfa05 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>3.5.3-SNAPSHOT</version>
+    <version>3.6.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>org.eclipse.jgit.junit.http</artifactId>
diff --git a/org.eclipse.jgit.junit/META-INF/MANIFEST.MF b/org.eclipse.jgit.junit/META-INF/MANIFEST.MF
index 06ebfa2..d2f285a 100644
--- a/org.eclipse.jgit.junit/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.junit/META-INF/MANIFEST.MF
@@ -2,23 +2,23 @@
 Bundle-ManifestVersion: 2
 Bundle-Name: %plugin_name
 Bundle-SymbolicName: org.eclipse.jgit.junit
-Bundle-Version: 3.5.3.qualifier
+Bundle-Version: 3.6.0.qualifier
 Bundle-Localization: plugin
 Bundle-Vendor: %provider_name
 Bundle-ActivationPolicy: lazy
 Bundle-RequiredExecutionEnvironment: J2SE-1.5
-Import-Package: org.eclipse.jgit.api;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.api.errors;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.dircache;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.errors;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.internal.storage.file;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.internal.storage.pack;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.lib;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.revwalk;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.storage.file;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.treewalk;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.treewalk.filter;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.util;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.util.io;version="[3.5.3,3.6.0)",
+Import-Package: org.eclipse.jgit.api;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.api.errors;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.dircache;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.errors;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.internal.storage.file;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.internal.storage.pack;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.lib;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.revwalk;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.storage.file;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.treewalk;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.treewalk.filter;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.util;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.util.io;version="[3.6.0,3.7.0)",
  org.junit;version="[4.0.0,5.0.0)"
-Export-Package: org.eclipse.jgit.junit;version="3.5.3"
+Export-Package: org.eclipse.jgit.junit;version="3.6.0"
diff --git a/org.eclipse.jgit.junit/pom.xml b/org.eclipse.jgit.junit/pom.xml
index be91ae7..676638e 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>3.5.3-SNAPSHOT</version>
+    <version>3.6.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>org.eclipse.jgit.junit</artifactId>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.feature/feature.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.feature/feature.xml
index 0663319..4cf2d71 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="3.5.3.qualifier"
+      version="3.6.0.qualifier"
       provider-name="%providerName">
 
    <description url="http://www.eclipse.org/jgit/">
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.feature/pom.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.feature/pom.xml
index 2f8e1b5..f3e0e18 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>3.5.3-SNAPSHOT</version>
+    <version>3.6.0-SNAPSHOT</version>
   </parent>
 
   <groupId>org.eclipse.jgit.feature</groupId>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.http.apache.feature/feature.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.http.apache.feature/feature.xml
index f61b3fd..26fbd32 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="3.5.3.qualifier"
+      version="3.6.0.qualifier"
       provider-name="%providerName">
 
    <description url="http://www.eclipse.org/jgit/">
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.http.apache.feature/pom.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.http.apache.feature/pom.xml
index a49bb57..5ecf11c 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>3.5.3-SNAPSHOT</version>
+    <version>3.6.0-SNAPSHOT</version>
   </parent>
 
   <groupId>org.eclipse.jgit.feature</groupId>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.java7.feature/feature.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.java7.feature/feature.xml
index 0413b14..f0b518d 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.java7.feature/feature.xml
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.java7.feature/feature.xml
@@ -2,7 +2,7 @@
 <feature
       id="org.eclipse.jgit.java7"
       label="%featureName"
-      version="3.5.3.qualifier"
+      version="3.6.0.qualifier"
       provider-name="%providerName">
 
    <description url="http://www.eclipse.org/jgit/">
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.java7.feature/pom.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.java7.feature/pom.xml
index 1dc1dcb..fc03522 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.java7.feature/pom.xml
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.java7.feature/pom.xml
@@ -50,7 +50,7 @@
   <parent>
     <groupId>org.eclipse.jgit</groupId>
     <artifactId>jgit.tycho.parent</artifactId>
-    <version>3.5.3-SNAPSHOT</version>
+    <version>3.6.0-SNAPSHOT</version>
   </parent>
 
   <groupId>org.eclipse.jgit.feature</groupId>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.junit.feature/feature.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.junit.feature/feature.xml
index 58e04f7..f85e320 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="3.5.3.qualifier"
+      version="3.6.0.qualifier"
       provider-name="%providerName">
 
    <description url="http://www.eclipse.org/jgit/">
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.junit.feature/pom.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.junit.feature/pom.xml
index 43306a7..234d99d 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>3.5.3-SNAPSHOT</version>
+    <version>3.6.0-SNAPSHOT</version>
   </parent>
 
   <groupId>org.eclipse.jgit.feature</groupId>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.feature/feature.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.feature/feature.xml
index 66287b4..21c754a 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="3.5.3.qualifier"
+      version="3.6.0.qualifier"
       provider-name="%providerName">
 
    <description url="http://www.eclipse.org/jgit/">
@@ -27,7 +27,7 @@
          version="0.0.0"/>
 
    <requires>
-      <import feature="org.eclipse.jgit" version="3.5.0" match="equivalent"/>
+      <import feature="org.eclipse.jgit" version="3.6.0" match="equivalent"/>
    </requires>
 
    <plugin
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.feature/pom.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.feature/pom.xml
index 9c76531..a8ea568 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>3.5.3-SNAPSHOT</version>
+    <version>3.6.0-SNAPSHOT</version>
   </parent>
 
   <groupId>org.eclipse.jgit.feature</groupId>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.source.feature/feature.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.source.feature/feature.xml
index fc4d752..1bf44cf 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="3.5.3.qualifier"
+      version="3.6.0.qualifier"
       provider-name="%providerName">
 
    <description url="http://www.eclipse.org/jgit/">
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.source.feature/pom.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.source.feature/pom.xml
index e1b92df..8a50785 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>3.5.3-SNAPSHOT</version>
+    <version>3.6.0-SNAPSHOT</version>
   </parent>
 
   <groupId>org.eclipse.jgit.feature</groupId>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.repository/pom.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.repository/pom.xml
index c34503a..19fa24c 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>3.5.3-SNAPSHOT</version>
+    <version>3.6.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>org.eclipse.jgit.repository</artifactId>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.source.feature/feature.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.source.feature/feature.xml
index 8ef3027..f84365a 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="3.5.3.qualifier"
+      version="3.6.0.qualifier"
       provider-name="%providerName">
 
    <description url="http://www.eclipse.org/jgit/">
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.source.feature/pom.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.source.feature/pom.xml
index 82c800d..a7872d8 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>3.5.3-SNAPSHOT</version>
+    <version>3.6.0-SNAPSHOT</version>
   </parent>
 
   <groupId>org.eclipse.jgit.feature</groupId>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/META-INF/MANIFEST.MF b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/META-INF/MANIFEST.MF
index e63cc22..9dbb69d 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: 3.5.3.qualifier
+Bundle-Version: 3.6.0.qualifier
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
index 17db411..2645b16 100644
--- 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
@@ -63,7 +63,7 @@
       <unit id="org.tukaani.xz.source" version="1.3.0.v201308270617"/>
     </location>
     <location includeAllPlatforms="false" includeConfigurePhase="true" includeMode="slicer" includeSource="true" type="InstallableUnit">
-      <repository location="http://download.eclipse.org/releases/juno/"/>
+      <repository location="http://download.eclipse.org/releases/luna/"/>
       <unit id="org.eclipse.osgi" version="0.0.0"/>
     </location>
   </locations>
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
new file mode 100644
index 0000000..1ba9122
--- /dev/null
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.5.target
@@ -0,0 +1,70 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!--
+   Copyright (C) 2014 Matthias Sohn <matthias.sohn@sap.com>
+
+   All rights reserved. This program and the accompanying materials
+   are made available under the terms of the Eclipse Public License v1.0
+   which accompanies this distribution, and is available at
+   http://www.eclipse.org/legal/epl-v10.html
+-->
+<?pde version="3.6"?>
+<target name="jgit.target" sequenceNumber="1">
+  <locations>
+    <location includeAllPlatforms="false" includeConfigurePhase="true" includeMode="slicer" includeSource="true" type="InstallableUnit">
+      <repository location="http://download.eclipse.org/jetty/updates/jetty-bundles-7.x/7.6.14.v20131031/"/>
+      <unit id="org.eclipse.jetty.client" version="7.6.14.v20131031"/>
+      <unit id="org.eclipse.jetty.client.source" version="7.6.14.v20131031"/>
+      <unit id="org.eclipse.jetty.continuation" version="7.6.14.v20131031"/>
+      <unit id="org.eclipse.jetty.continuation.source" version="7.6.14.v20131031"/>
+      <unit id="org.eclipse.jetty.http" version="7.6.14.v20131031"/>
+      <unit id="org.eclipse.jetty.http.source" version="7.6.14.v20131031"/>
+      <unit id="org.eclipse.jetty.io" version="7.6.14.v20131031"/>
+      <unit id="org.eclipse.jetty.io.source" version="7.6.14.v20131031"/>
+      <unit id="org.eclipse.jetty.security" version="7.6.14.v20131031"/>
+      <unit id="org.eclipse.jetty.security.source" version="7.6.14.v20131031"/>
+      <unit id="org.eclipse.jetty.server" version="7.6.14.v20131031"/>
+      <unit id="org.eclipse.jetty.server.source" version="7.6.14.v20131031"/>
+      <unit id="org.eclipse.jetty.servlet" version="7.6.14.v20131031"/>
+      <unit id="org.eclipse.jetty.servlet.source" version="7.6.14.v20131031"/>
+      <unit id="org.eclipse.jetty.util" version="7.6.14.v20131031"/>
+      <unit id="org.eclipse.jetty.util.source" version="7.6.14.v20131031"/>
+    </location>
+    <location includeAllPlatforms="false" includeConfigurePhase="true" includeMode="slicer" includeSource="true" type="InstallableUnit">
+      <repository location="http://download.eclipse.org/tools/orbit/downloads/drops/S20141023165154/repository/"/>
+      <unit id="org.apache.ant.source" version="1.9.4.v201410062020"/>
+      <unit id="org.apache.ant" version="1.9.4.v201410062020"/>
+      <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.1.4.v201203221030"/>
+      <unit id="org.apache.httpcomponents.httpcore.source" version="4.1.4.v201203221030"/>
+      <unit id="org.apache.httpcomponents.httpclient" version="4.1.3.v201209201135"/>
+      <unit id="org.apache.httpcomponents.httpclient.source" version="4.1.3.v201209201135"/>
+      <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.jcraft.jsch" version="0.1.51.v201410231640"/>
+      <unit id="com.jcraft.jsch.source" version="0.1.51.v201410231640"/>
+      <unit id="org.junit" version="4.11.0.v201303080030"/>
+      <unit id="org.junit.source" version="4.11.0.v201303080030"/>
+      <unit id="javax.servlet" version="2.5.0.v201103041518"/>
+      <unit id="javax.servlet.source" version="2.5.0.v201103041518"/>
+      <unit id="org.tukaani.xz" version="1.3.0.v201308270617"/>
+      <unit id="org.tukaani.xz.source" version="1.3.0.v201308270617"/>
+    </location>
+    <location includeAllPlatforms="false" includeConfigurePhase="true" includeMode="slicer" includeSource="true" type="InstallableUnit">
+      <repository location="http://download.eclipse.org/releases/mars/"/>
+      <unit id="org.eclipse.osgi" version="0.0.0"/>
+    </location>
+  </locations>
+</target>
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 a71f62c..47d6c1b 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>3.5.3-SNAPSHOT</version>
+    <version>3.6.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>org.eclipse.jgit.target</artifactId>
diff --git a/org.eclipse.jgit.packaging/pom.xml b/org.eclipse.jgit.packaging/pom.xml
index bee3d33..6ed0761 100644
--- a/org.eclipse.jgit.packaging/pom.xml
+++ b/org.eclipse.jgit.packaging/pom.xml
@@ -53,7 +53,7 @@
 
   <groupId>org.eclipse.jgit</groupId>
   <artifactId>jgit.tycho.parent</artifactId>
-  <version>3.5.3-SNAPSHOT</version>
+  <version>3.6.0-SNAPSHOT</version>
   <packaging>pom</packaging>
 
   <name>JGit Tycho Parent</name>
@@ -253,6 +253,18 @@
       </properties>
     </profile>
     <profile>
+      <id>platform-mars</id>
+      <activation>
+        <property>
+          <name>platform-version-name</name>
+          <value>mars</value>
+        </property>
+      </activation>
+      <properties>
+        <target-platform>jgit-4.5</target-platform>
+      </properties>
+    </profile>
+    <profile>
       <id>eclipse-sign</id>
       <build>
         <plugins>
@@ -377,4 +389,3 @@
     </profile>
   </profiles>
 </project>
-
diff --git a/org.eclipse.jgit.pgm.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.pgm.test/META-INF/MANIFEST.MF
index f7356c4..b2173c5 100644
--- a/org.eclipse.jgit.pgm.test/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.pgm.test/META-INF/MANIFEST.MF
@@ -2,27 +2,27 @@
 Bundle-ManifestVersion: 2
 Bundle-Name: %plugin_name
 Bundle-SymbolicName: org.eclipse.jgit.pgm.test
-Bundle-Version: 3.5.3.qualifier
+Bundle-Version: 3.6.0.qualifier
 Bundle-Vendor: %provider_name
 Bundle-Localization: plugin
 Bundle-ActivationPolicy: lazy
 Bundle-RequiredExecutionEnvironment: J2SE-1.5
-Import-Package: org.eclipse.jgit.api;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.api.errors;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.diff;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.dircache;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.junit;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.lib;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.merge;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.pgm;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.pgm.internal;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.pgm.opt;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.revwalk;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.storage.file;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.transport;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.treewalk;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.util;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.util.io;version="[3.5.3,3.6.0)",
+Import-Package: org.eclipse.jgit.api;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.api.errors;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.diff;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.dircache;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.junit;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.lib;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.merge;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.pgm;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.pgm.internal;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.pgm.opt;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.revwalk;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.storage.file;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.transport;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.treewalk;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.util;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.util.io;version="[3.6.0,3.7.0)",
  org.hamcrest.core;bundle-version="[1.1.0,2.0.0)",
  org.junit;version="[4.4.0,5.0.0)",
  org.kohsuke.args4j;version="[2.0.12,2.1.0)"
diff --git a/org.eclipse.jgit.pgm.test/pom.xml b/org.eclipse.jgit.pgm.test/pom.xml
index a46a648..cf6cac7 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>3.5.3-SNAPSHOT</version>
+    <version>3.6.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>org.eclipse.jgit.pgm.test</artifactId>
diff --git a/org.eclipse.jgit.pgm/META-INF/MANIFEST.MF b/org.eclipse.jgit.pgm/META-INF/MANIFEST.MF
index a37a389..e4628b0 100644
--- a/org.eclipse.jgit.pgm/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.pgm/META-INF/MANIFEST.MF
@@ -2,43 +2,43 @@
 Bundle-ManifestVersion: 2
 Bundle-Name: %plugin_name
 Bundle-SymbolicName: org.eclipse.jgit.pgm
-Bundle-Version: 3.5.3.qualifier
+Bundle-Version: 3.6.0.qualifier
 Bundle-Vendor: %provider_name
 Bundle-Localization: plugin
 Bundle-RequiredExecutionEnvironment: J2SE-1.5
 Import-Package: 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.jgit.api;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.api.errors;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.archive;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.awtui;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.blame;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.diff;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.dircache;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.errors;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.gitrepo;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.internal.storage.file;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.internal.storage.pack;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.lib;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.merge;version="3.5.3",
- org.eclipse.jgit.nls;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.notes;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.revplot;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.revwalk;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.revwalk.filter;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.storage.file;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.storage.pack;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.transport;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.transport.resolver;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.treewalk;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.treewalk.filter;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.util;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.util.io;version="[3.5.3,3.6.0)",
+ org.eclipse.jgit.api;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.api.errors;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.archive;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.awtui;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.blame;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.diff;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.dircache;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.errors;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.gitrepo;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.internal.storage.file;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.internal.storage.pack;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.lib;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.merge;version="3.6.0",
+ org.eclipse.jgit.nls;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.notes;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.revplot;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.revwalk;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.revwalk.filter;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.storage.file;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.storage.pack;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.transport;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.transport.resolver;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.treewalk;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.treewalk.filter;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.util;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.util.io;version="[3.6.0,3.7.0)",
  org.kohsuke.args4j;version="[2.0.12,2.1.0)",
  org.kohsuke.args4j.spi;version="[2.0.12,2.1.0)"
 Bundle-ActivationPolicy: lazy
-Export-Package: org.eclipse.jgit.pgm;version="3.5.3";
+Export-Package: org.eclipse.jgit.pgm;version="3.6.0";
   uses:="org.eclipse.jgit.revwalk,
    org.eclipse.jgit.treewalk.filter,
    org.eclipse.jgit.pgm.opt,
@@ -49,10 +49,10 @@
    org.eclipse.jgit.treewalk,
    javax.swing,
    org.eclipse.jgit.transport",
- org.eclipse.jgit.pgm.debug;version="3.5.3";
+ org.eclipse.jgit.pgm.debug;version="3.6.0";
   uses:="org.eclipse.jgit.pgm",
- org.eclipse.jgit.pgm.internal;version="3.5.3";x-friends:="org.eclipse.jgit.pgm.test,org.eclipse.jgit.test",
- org.eclipse.jgit.pgm.opt;version="3.5.3";
+ org.eclipse.jgit.pgm.internal;version="3.6.0";x-friends:="org.eclipse.jgit.pgm.test,org.eclipse.jgit.test",
+ org.eclipse.jgit.pgm.opt;version="3.6.0";
   uses:="org.eclipse.jgit.lib,
    org.eclipse.jgit.revwalk,
    org.kohsuke.args4j.spi,
diff --git a/org.eclipse.jgit.pgm/META-INF/SOURCE-MANIFEST.MF b/org.eclipse.jgit.pgm/META-INF/SOURCE-MANIFEST.MF
index c81f62f..29bcf8e 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: 3.5.3.qualifier
-Eclipse-SourceBundle: org.eclipse.jgit.pgm;version="3.5.3.qualifier";roots="."
+Bundle-Version: 3.6.0.qualifier
+Eclipse-SourceBundle: org.eclipse.jgit.pgm;version="3.6.0.qualifier";roots="."
diff --git a/org.eclipse.jgit.pgm/pom.xml b/org.eclipse.jgit.pgm/pom.xml
index e1b33f6..f52d1a6 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>3.5.3-SNAPSHOT</version>
+    <version>3.6.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>org.eclipse.jgit.pgm</artifactId>
diff --git a/org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/internal/CLIText.properties b/org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/internal/CLIText.properties
index 574981d..bdf05e9 100644
--- a/org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/internal/CLIText.properties
+++ b/org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/internal/CLIText.properties
@@ -184,6 +184,7 @@
 unsupportedOperation=Unsupported operation: {0}
 untrackedFiles=Untracked files:
 updating=Updating {0}..{1}
+usage_Aggressive=This option will cause gc to more aggressively optimize the repository at the expense of taking much more time
 usage_Blame=Show what revision and author last modified each line
 usage_CommandLineClientForamazonsS3Service=Command line client for Amazon's S3 service
 usage_CommitAll=commit all modified and deleted files
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Gc.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Gc.java
index 58813bc..aa5c905 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Gc.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Gc.java
@@ -43,16 +43,19 @@
 
 package org.eclipse.jgit.pgm;
 
-import org.eclipse.jgit.internal.storage.file.FileRepository;
-import org.eclipse.jgit.internal.storage.file.GC;
+import org.eclipse.jgit.api.Git;
 import org.eclipse.jgit.lib.TextProgressMonitor;
+import org.kohsuke.args4j.Option;
 
 @Command(common = true, usage = "usage_Gc")
 class Gc extends TextBuiltin {
+	@Option(name = "--aggressive", usage = "usage_Aggressive")
+	private boolean aggressive;
+
 	@Override
 	protected void run() throws Exception {
-		GC gc = new GC((FileRepository) db);
-		gc.setProgressMonitor(new TextProgressMonitor());
-		gc.gc();
+		Git git = Git.wrap(db);
+		git.gc().setAggressive(aggressive)
+				.setProgressMonitor(new TextProgressMonitor()).call();
 	}
 }
diff --git a/org.eclipse.jgit.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.test/META-INF/MANIFEST.MF
index 9957659..7b9bd64 100644
--- a/org.eclipse.jgit.test/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.test/META-INF/MANIFEST.MF
@@ -2,50 +2,52 @@
 Bundle-ManifestVersion: 2
 Bundle-Name: %plugin_name
 Bundle-SymbolicName: org.eclipse.jgit.test
-Bundle-Version: 3.5.3.qualifier
+Bundle-Version: 3.6.0.qualifier
 Bundle-Localization: plugin
 Bundle-Vendor: %provider_name
 Bundle-ActivationPolicy: lazy
 Bundle-RequiredExecutionEnvironment: J2SE-1.5
 Import-Package: com.googlecode.javaewah;version="[0.7.9,0.8.0)",
- org.eclipse.jgit.api;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.api.errors;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.awtui;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.blame;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.console;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.diff;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.dircache;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.errors;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.events;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.fnmatch;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.gitrepo;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.ignore;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.internal;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.internal.storage.dfs;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.internal.storage.file;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.internal.storage.pack;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.junit;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.lib;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.merge;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.nls;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.notes;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.patch;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.pgm;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.pgm.internal;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.revplot;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.revwalk;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.revwalk.filter;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.storage.file;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.storage.pack;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.submodule;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.transport;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.transport.http;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.treewalk;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.treewalk.filter;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.util;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.util.io;version="[3.5.3,3.6.0)",
+ org.eclipse.jgit.api;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.api.errors;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.awtui;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.blame;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.console;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.diff;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.dircache;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.errors;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.events;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.fnmatch;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.gitrepo;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.ignore;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.ignore.internal;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.internal;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.internal.storage.dfs;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.internal.storage.file;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.internal.storage.pack;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.junit;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.lib;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.merge;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.nls;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.notes;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.patch;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.pgm;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.pgm.internal;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.revplot;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.revwalk;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.revwalk.filter;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.storage.file;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.storage.pack;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.submodule;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.transport;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.transport.http;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.treewalk;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.treewalk.filter;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.util;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.util.io;version="[3.6.0,3.7.0)",
  org.hamcrest;version="[1.1.0,2.0.0)",
  org.junit;version="[4.4.0,5.0.0)",
  org.junit.experimental.theories;version="[4.4.0,5.0.0)",
- org.junit.runner;version="[4.4.0,5.0.0)"
+ org.junit.runner;version="[4.4.0,5.0.0)",
+ org.junit.runners;version="[4.11.0,5.0.0)"
 Require-Bundle: org.hamcrest.core;bundle-version="[1.1.0,2.0.0)"
diff --git a/org.eclipse.jgit.test/pom.xml b/org.eclipse.jgit.test/pom.xml
index 8bbdbf2..07883eb 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>3.5.3-SNAPSHOT</version>
+    <version>3.6.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>org.eclipse.jgit.test</artifactId>
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/ArchiveCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/ArchiveCommandTest.java
index d85fb54..8cdf6a6 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/ArchiveCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/ArchiveCommandTest.java
@@ -45,6 +45,14 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNull;
 
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
 import org.eclipse.jgit.api.errors.GitAPIException;
 import org.eclipse.jgit.junit.RepositoryTestCase;
 import org.eclipse.jgit.lib.FileMode;
@@ -54,10 +62,6 @@
 import org.junit.Before;
 import org.junit.Test;
 
-import java.io.IOException;
-import java.io.OutputStream;
-import java.util.*;
-
 public class ArchiveCommandTest extends RepositoryTestCase {
 
 	private static final String UNEXPECTED_ARCHIVE_SIZE  = "Unexpected archive size";
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/ResetCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/ResetCommandTest.java
index 8224976..c48b412 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/ResetCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/ResetCommandTest.java
@@ -425,6 +425,21 @@
 	}
 
 	@Test
+	public void testResetDefaultMode() throws Exception {
+		git = new Git(db);
+		writeTrashFile("a.txt", "content");
+		git.add().addFilepattern("a.txt").call();
+		writeTrashFile("a.txt", "modified");
+		// should use default mode MIXED
+		git.reset().call();
+
+		DirCache cache = db.readDirCache();
+		DirCacheEntry aEntry = cache.getEntry("a.txt");
+		assertNull(aEntry);
+		assertEquals("modified", read("a.txt"));
+	}
+
+	@Test
 	public void testHardResetOnTag() throws Exception {
 		setupRepository();
 		String tagName = "initialtag";
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/ignore/BasicRuleTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/ignore/BasicRuleTest.java
new file mode 100644
index 0000000..d8a6174
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/ignore/BasicRuleTest.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2014, Andrey Loskutov <loskutov@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.ignore;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+
+public class BasicRuleTest {
+
+	@Test
+	public void test() {
+		FastIgnoreRule rule1 = new FastIgnoreRule("/hello/[a]/");
+		FastIgnoreRule rule2 = new FastIgnoreRule("/hello/[a]/");
+		FastIgnoreRule rule3 = new FastIgnoreRule("!/hello/[a]/");
+		FastIgnoreRule rule4 = new FastIgnoreRule("/hello/[a]");
+		assertTrue(rule1.dirOnly());
+		assertTrue(rule3.dirOnly());
+		assertFalse(rule4.dirOnly());
+		assertFalse(rule1.getNegation());
+		assertTrue(rule3.getNegation());
+		assertNotEquals(rule1, null);
+		assertEquals(rule1, rule1);
+		assertEquals(rule1, rule2);
+		assertNotEquals(rule1, rule3);
+		assertNotEquals(rule1, rule4);
+		assertEquals(rule1.hashCode(), rule2.hashCode());
+		assertNotEquals(rule1.hashCode(), rule3.hashCode());
+		assertEquals(rule1.toString(), rule2.toString());
+		assertNotEquals(rule1.toString(), rule3.toString());
+	}
+
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/ignore/FastIgnoreRuleTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/ignore/FastIgnoreRuleTest.java
new file mode 100644
index 0000000..656ba44
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/ignore/FastIgnoreRuleTest.java
@@ -0,0 +1,563 @@
+/*
+ * Copyright (C) 2014, Andrey Loskutov <loskutov@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.ignore;
+
+import static org.eclipse.jgit.ignore.internal.Strings.split;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeFalse;
+import static org.junit.Assume.assumeTrue;
+
+import java.util.Arrays;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+@SuppressWarnings("deprecation")
+@RunWith(Parameterized.class)
+public class FastIgnoreRuleTest {
+
+	@Parameters(name = "JGit? {0}")
+	public static Iterable<Boolean[]> data() {
+		return Arrays.asList(new Boolean[][] { { Boolean.FALSE },
+				{ Boolean.TRUE } });
+	}
+
+	@Parameter
+	public Boolean useJGitRule;
+
+	@Test
+	public void testSimpleCharClass() {
+		assertMatched("[a]", "a");
+		assertMatched("[a]", "a/");
+		assertMatched("[a]", "a/b");
+
+		assertMatched("[a]", "b/a");
+		assertMatched("[a]", "b/a/");
+		assertMatched("[a]", "b/a/b");
+
+		assertMatched("[a]", "/a/");
+		assertMatched("[a]", "/a/b");
+
+		assertMatched("[a]", "c/a/b");
+		assertMatched("[a]", "c/b/a");
+
+		assertMatched("/[a]", "a");
+		assertMatched("/[a]", "a/");
+		assertMatched("/[a]", "a/b");
+		assertMatched("/[a]", "/a");
+		assertMatched("/[a]", "/a/");
+		assertMatched("/[a]", "/a/b");
+
+		assertMatched("[a]/", "a/");
+		assertMatched("[a]/", "a/b");
+		assertMatched("[a]/", "/a/");
+		assertMatched("[a]/", "/a/b");
+
+		assertMatched("/[a]/", "a/");
+		assertMatched("/[a]/", "a/b");
+		assertMatched("/[a]/", "/a/");
+		assertMatched("/[a]/", "/a/b");
+	}
+
+	@Test
+	public void testCharClass() {
+		assertMatched("[v-z]", "x");
+		assertMatched("[v-z]", "x/");
+		assertMatched("[v-z]", "x/b");
+
+		assertMatched("[v-z]", "b/x");
+		assertMatched("[v-z]", "b/x/");
+		assertMatched("[v-z]", "b/x/b");
+
+		assertMatched("[v-z]", "/x/");
+		assertMatched("[v-z]", "/x/b");
+
+		assertMatched("[v-z]", "c/x/b");
+		assertMatched("[v-z]", "c/b/x");
+
+		assertMatched("/[v-z]", "x");
+		assertMatched("/[v-z]", "x/");
+		assertMatched("/[v-z]", "x/b");
+		assertMatched("/[v-z]", "/x");
+		assertMatched("/[v-z]", "/x/");
+		assertMatched("/[v-z]", "/x/b");
+
+		assertMatched("[v-z]/", "x/");
+		assertMatched("[v-z]/", "x/b");
+		assertMatched("[v-z]/", "/x/");
+		assertMatched("[v-z]/", "/x/b");
+
+		assertMatched("/[v-z]/", "x/");
+		assertMatched("/[v-z]/", "x/b");
+		assertMatched("/[v-z]/", "/x/");
+		assertMatched("/[v-z]/", "/x/b");
+	}
+
+	@Test
+	public void testAsteriskDot() {
+		assertMatched("*.a", ".a");
+		assertMatched("*.a", "/.a");
+		assertMatched("*.a", "a.a");
+		assertMatched("*.a", "/b.a");
+		assertMatched("*.a", "b.a");
+		assertMatched("*.a", "/a/b.a");
+		assertMatched("*.a", "/b/.a");
+	}
+
+	@Test
+	public void testAsteriskDotDoNotMatch() {
+		assertNotMatched("*.a", ".ab");
+		assertNotMatched("*.a", "/.ab");
+		assertNotMatched("*.a", "/b.ba");
+		assertNotMatched("*.a", "a.ab");
+		assertNotMatched("*.a", "/b.ab");
+		assertNotMatched("*.a", "b.ab");
+		assertNotMatched("*.a", "/a/b.ab");
+		assertNotMatched("*.a", "/b/.ab");
+	}
+
+	@Test
+	public void testDotAsteriskMatch() {
+		assertMatched("a.*", "a.");
+		assertMatched("a.*", "a./");
+		assertMatched("a.*", "a.b");
+
+		assertMatched("a.*", "b/a.b");
+		assertMatched("a.*", "b/a.b/");
+		assertMatched("a.*", "b/a.b/b");
+
+		assertMatched("a.*", "/a.b/");
+		assertMatched("a.*", "/a.b/b");
+
+		assertMatched("a.*", "c/a.b/b");
+		assertMatched("a.*", "c/b/a.b");
+
+		assertMatched("/a.*", "a.b");
+		assertMatched("/a.*", "a.b/");
+		assertMatched("/a.*", "a.b/b");
+		assertMatched("/a.*", "/a.b");
+		assertMatched("/a.*", "/a.b/");
+		assertMatched("/a.*", "/a.b/b");
+
+		assertMatched("/a.*/b", "a.b/b");
+		assertMatched("/a.*/b", "/a.b/b");
+		assertMatched("/a.*/b", "/a.bc/b");
+		assertMatched("/a.*/b", "/a./b");
+	}
+
+	@Test
+	public void testAsterisk() {
+		assertMatched("a*", "a");
+		assertMatched("a*", "a/");
+		assertMatched("a*", "ab");
+
+		assertMatched("a*", "b/ab");
+		assertMatched("a*", "b/ab/");
+		assertMatched("a*", "b/ab/b");
+
+		assertMatched("a*", "b/abc");
+		assertMatched("a*", "b/abc/");
+		assertMatched("a*", "b/abc/b");
+
+		assertMatched("a*", "/abc/");
+		assertMatched("a*", "/abc/b");
+
+		assertMatched("a*", "c/abc/b");
+		assertMatched("a*", "c/b/abc");
+
+		assertMatched("/a*", "abc");
+		assertMatched("/a*", "abc/");
+		assertMatched("/a*", "abc/b");
+		assertMatched("/a*", "/abc");
+		assertMatched("/a*", "/abc/");
+		assertMatched("/a*", "/abc/b");
+
+		assertMatched("/a*/b", "abc/b");
+		assertMatched("/a*/b", "/abc/b");
+		assertMatched("/a*/b", "/abcd/b");
+		assertMatched("/a*/b", "/a/b");
+	}
+
+	@Test
+	public void testQuestionmark() {
+		assertMatched("a?", "ab");
+		assertMatched("a?", "ab/");
+
+		assertMatched("a?", "b/ab");
+		assertMatched("a?", "b/ab/");
+		assertMatched("a?", "b/ab/b");
+
+		assertMatched("a?", "/ab/");
+		assertMatched("a?", "/ab/b");
+
+		assertMatched("a?", "c/ab/b");
+		assertMatched("a?", "c/b/ab");
+
+		assertMatched("/a?", "ab");
+		assertMatched("/a?", "ab/");
+		assertMatched("/a?", "ab/b");
+		assertMatched("/a?", "/ab");
+		assertMatched("/a?", "/ab/");
+		assertMatched("/a?", "/ab/b");
+
+		assertMatched("/a?/b", "ab/b");
+		assertMatched("/a?/b", "/ab/b");
+	}
+
+	@Test
+	public void testQuestionmarkDoNotMatch() {
+		assertNotMatched("a?", "a/");
+		assertNotMatched("a?", "abc");
+		assertNotMatched("a?", "abc/");
+
+		assertNotMatched("a?", "b/abc");
+		assertNotMatched("a?", "b/abc/");
+
+		assertNotMatched("a?", "/abc/");
+		assertNotMatched("a?", "/abc/b");
+
+		assertNotMatched("a?", "c/abc/b");
+		assertNotMatched("a?", "c/b/abc");
+
+		assertNotMatched("/a?", "abc");
+		assertNotMatched("/a?", "abc/");
+		assertNotMatched("/a?", "abc/b");
+		assertNotMatched("/a?", "/abc");
+		assertNotMatched("/a?", "/abc/");
+		assertNotMatched("/a?", "/abc/b");
+
+		assertNotMatched("/a?/b", "abc/b");
+		assertNotMatched("/a?/b", "/abc/b");
+		assertNotMatched("/a?/b", "/a/b");
+	}
+
+	@Test
+	public void testSimplePatterns() {
+		assertMatched("a", "a");
+		assertMatched("a", "a/");
+		assertMatched("a", "a/b");
+
+		assertMatched("a", "b/a");
+		assertMatched("a", "b/a/");
+		assertMatched("a", "b/a/b");
+
+		assertMatched("a", "/a/");
+		assertMatched("a", "/a/b");
+
+		assertMatched("a", "c/a/b");
+		assertMatched("a", "c/b/a");
+
+		assertMatched("/a", "a");
+		assertMatched("/a", "a/");
+		assertMatched("/a", "a/b");
+		assertMatched("/a", "/a");
+		assertMatched("/a", "/a/");
+		assertMatched("/a", "/a/b");
+
+		assertMatched("a/", "a/");
+		assertMatched("a/", "a/b");
+		assertMatched("a/", "/a/");
+		assertMatched("a/", "/a/b");
+
+		assertMatched("/a/", "a/");
+		assertMatched("/a/", "a/b");
+		assertMatched("/a/", "/a/");
+		assertMatched("/a/", "/a/b");
+
+	}
+
+	@Test
+	public void testSimplePatternsDoNotMatch() {
+		assertNotMatched("ab", "a");
+		assertNotMatched("abc", "a/");
+		assertNotMatched("abc", "a/b");
+
+		assertNotMatched("a", "ab");
+		assertNotMatched("a", "ba");
+		assertNotMatched("a", "aa");
+
+		assertNotMatched("a", "b/ab");
+		assertNotMatched("a", "b/ba");
+
+		assertNotMatched("a", "b/ba");
+		assertNotMatched("a", "b/ab");
+
+		assertNotMatched("a", "b/ba/");
+		assertNotMatched("a", "b/ba/b");
+
+		assertNotMatched("a", "/aa");
+		assertNotMatched("a", "aa/");
+		assertNotMatched("a", "/aa/");
+
+		assertNotMatched("/a", "b/a");
+		assertNotMatched("/a", "/b/a/");
+
+		assertNotMatched("a/", "a");
+		assertNotMatched("a/", "b/a");
+
+		assertNotMatched("/a/", "a");
+		assertNotMatched("/a/", "/a");
+		assertNotMatched("/a/", "b/a");
+	}
+
+	@Test
+	public void testSegments() {
+		assertMatched("/a/b", "a/b");
+		assertMatched("/a/b", "/a/b");
+		assertMatched("/a/b", "/a/b/");
+		assertMatched("/a/b", "/a/b/c");
+
+		assertMatched("a/b", "a/b");
+		assertMatched("a/b", "/a/b");
+		assertMatched("a/b", "/a/b/");
+		assertMatched("a/b", "/a/b/c");
+
+		assertMatched("a/b/", "a/b/");
+		assertMatched("a/b/", "/a/b/");
+		assertMatched("a/b/", "/a/b/c");
+	}
+
+	@Test
+	public void testSegmentsDoNotMatch() {
+		assertNotMatched("a/b", "/a/bb");
+		assertNotMatched("a/b", "/aa/b");
+		assertNotMatched("a/b", "a/bb");
+		assertNotMatched("a/b", "aa/b");
+		assertNotMatched("a/b", "c/aa/b");
+		assertNotMatched("a/b", "c/a/bb");
+		assertNotMatched("a/b/", "/a/b");
+		assertNotMatched("/a/b/", "/a/b");
+		assertNotMatched("/a/b", "c/a/b");
+		assertNotMatched("/a/b/", "c/a/b");
+		assertNotMatched("/a/b/", "c/a/b/");
+
+		// XXX why is it like this????
+		assertNotMatched("a/b", "c/a/b");
+		assertNotMatched("a/b", "c/a/b/");
+		assertNotMatched("a/b", "c/a/b/c");
+		assertNotMatched("a/b/", "c/a/b/");
+		assertNotMatched("a/b/", "c/a/b/c");
+	}
+
+	@SuppressWarnings("boxing")
+	@Test
+	public void testWildmatch() {
+		if (useJGitRule)
+			System.err
+					.println("IgnoreRule can't understand wildmatch rules, skipping testWildmatch!");
+
+		Boolean assume = useJGitRule;
+		assertMatched("**/a/b", "a/b", assume);
+		assertMatched("**/a/b", "c/a/b", assume);
+		assertMatched("**/a/b", "c/d/a/b", assume);
+		assertMatched("**/**/a/b", "c/d/a/b", assume);
+
+		assertMatched("/**/a/b", "a/b", assume);
+		assertMatched("/**/a/b", "c/a/b", assume);
+		assertMatched("/**/a/b", "c/d/a/b", assume);
+		assertMatched("/**/**/a/b", "c/d/a/b", assume);
+
+		assertMatched("a/b/**", "a/b", assume);
+		assertMatched("a/b/**", "a/b/c", assume);
+		assertMatched("a/b/**", "a/b/c/d/", assume);
+		assertMatched("a/b/**/**", "a/b/c/d", assume);
+
+		assertMatched("**/a/**/b", "c/d/a/b", assume);
+		assertMatched("**/a/**/b", "c/d/a/e/b", assume);
+		assertMatched("**/**/a/**/**/b", "c/d/a/e/b", assume);
+
+		assertMatched("/**/a/**/b", "c/d/a/b", assume);
+		assertMatched("/**/a/**/b", "c/d/a/e/b", assume);
+		assertMatched("/**/**/a/**/**/b", "c/d/a/e/b", assume);
+
+		assertMatched("a/**/b", "a/b", assume);
+		assertMatched("a/**/b", "a/c/b", assume);
+		assertMatched("a/**/b", "a/c/d/b", assume);
+		assertMatched("a/**/**/b", "a/c/d/b", assume);
+
+		assertMatched("a/**/b/**/c", "a/c/b/d/c", assume);
+		assertMatched("a/**/**/b/**/**/c", "a/c/b/d/c", assume);
+	}
+
+	@SuppressWarnings("boxing")
+	@Test
+	public void testWildmatchDoNotMatch() {
+		if (useJGitRule)
+			System.err
+					.println("IgnoreRule can't understand wildmatch rules, skipping testWildmatchDoNotMatch!");
+
+		Boolean assume = useJGitRule;
+		assertNotMatched("**/a/b", "a/c/b", assume);
+		assertNotMatched("!/**/*.zip", "c/a/b.zip", assume);
+		assertNotMatched("!**/*.zip", "c/a/b.zip", assume);
+		assertNotMatched("a/**/b", "a/c/bb", assume);
+	}
+
+	@SuppressWarnings("unused")
+	@Test
+	public void testSimpleRules() {
+		try {
+			new FastIgnoreRule(null);
+			fail("Illegal input allowed!");
+		} catch (IllegalArgumentException e) {
+			// expected
+		}
+		assertFalse(new FastIgnoreRule("/").isMatch("/", false));
+		assertFalse(new FastIgnoreRule("//").isMatch("//", false));
+		assertFalse(new FastIgnoreRule("#").isMatch("#", false));
+		assertFalse(new FastIgnoreRule("").isMatch("", false));
+		assertFalse(new FastIgnoreRule(" ").isMatch(" ", false));
+	}
+
+	@Test
+	public void testSplit() {
+		try {
+			split("/", '/').toArray();
+			fail("should not allow single slash");
+		} catch (IllegalStateException e) {
+			// expected
+		}
+
+		assertArrayEquals(new String[] { "a", "b" }, split("a/b", '/')
+				.toArray());
+		assertArrayEquals(new String[] { "a", "b/" }, split("a/b/", '/')
+				.toArray());
+		assertArrayEquals(new String[] { "/a", "b" }, split("/a/b", '/')
+				.toArray());
+		assertArrayEquals(new String[] { "/a", "b/" }, split("/a/b/", '/')
+				.toArray());
+		assertArrayEquals(new String[] { "/a", "b", "c" }, split("/a/b/c", '/')
+				.toArray());
+		assertArrayEquals(new String[] { "/a", "b", "c/" },
+				split("/a/b/c/", '/').toArray());
+	}
+
+	public void assertMatched(String pattern, String path, Boolean... assume) {
+		boolean match = match(pattern, path);
+		String result = path + " is " + (match ? "ignored" : "not ignored")
+				+ " via '" + pattern + "' rule";
+		if (!match)
+			System.err.println(result);
+		if (assume.length == 0 || !assume[0].booleanValue())
+			assertTrue("Expected a match for: " + pattern + " with: " + path,
+					match);
+		else
+			assumeTrue("Expected a match for: " + pattern + " with: " + path,
+					match);
+
+		if (pattern.startsWith("!"))
+			pattern = pattern.substring(1);
+		else
+			pattern = "!" + pattern;
+		match = match(pattern, path);
+		if (assume.length == 0 || !assume[0].booleanValue())
+			assertFalse("Expected no match for: " + pattern + " with: " + path,
+					match);
+		else
+			assumeFalse("Expected no match for: " + pattern + " with: " + path,
+					match);
+	}
+
+	public void assertNotMatched(String pattern, String path, Boolean... assume) {
+		boolean match = match(pattern, path);
+		String result = path + " is " + (match ? "ignored" : "not ignored")
+				+ " via '" + pattern + "' rule";
+		if (match)
+			System.err.println(result);
+		if (assume.length == 0 || !assume[0].booleanValue())
+			assertFalse("Expected no match for: " + pattern + " with: " + path,
+					match);
+		else
+			assumeFalse("Expected no match for: " + pattern + " with: " + path,
+					match);
+
+		if (pattern.startsWith("!"))
+			pattern = pattern.substring(1);
+		else
+			pattern = "!" + pattern;
+		match = match(pattern, path);
+		if (assume.length == 0 || !assume[0].booleanValue())
+			assertTrue("Expected a match for: " + pattern + " with: " + path,
+					match);
+		else
+			assumeTrue("Expected a match for: " + pattern + " with: " + path,
+					match);
+	}
+
+	/**
+	 * Check for a match. If target ends with "/", match will assume that the
+	 * target is meant to be a directory.
+	 *
+	 * @param pattern
+	 *            Pattern as it would appear in a .gitignore file
+	 * @param target
+	 *            Target file path relative to repository's GIT_DIR
+	 * @return Result of {@link FastIgnoreRule#isMatch(String, boolean)}
+	 */
+	private boolean match(String pattern, String target) {
+		boolean isDirectory = target.endsWith("/");
+		if (useJGitRule.booleanValue()) {
+			IgnoreRule r = new IgnoreRule(pattern);
+			// If speed of this test is ever an issue, we can use a presetRule
+			// field
+			// to avoid recompiling a pattern each time.
+			boolean match = r.isMatch(target, isDirectory);
+			if (r.getNegation())
+				match = !match;
+			return match;
+		}
+		FastIgnoreRule r = new FastIgnoreRule(pattern);
+		// If speed of this test is ever an issue, we can use a presetRule field
+		// to avoid recompiling a pattern each time.
+		boolean match = r.isMatch(target, isDirectory);
+		if (r.getNegation())
+			match = !match;
+		return match;
+	}
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/ignore/IgnoreMatcherParametrizedTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/ignore/IgnoreMatcherParametrizedTest.java
new file mode 100644
index 0000000..48649d6
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/ignore/IgnoreMatcherParametrizedTest.java
@@ -0,0 +1,370 @@
+/*
+ * Copyright (C) 2010, Red Hat 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.ignore;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Arrays;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+/**
+ * Tests ignore pattern matches
+ */
+@SuppressWarnings("deprecation")
+@RunWith(Parameterized.class)
+public class IgnoreMatcherParametrizedTest {
+
+	@Parameters(name = "JGit? {0}")
+	public static Iterable<Boolean[]> data() {
+		return Arrays.asList(new Boolean[][] { { Boolean.FALSE },
+				{ Boolean.TRUE } });
+	}
+
+	@Parameter
+	public Boolean useJGitRule;
+
+	@Test
+	public void testBasic() {
+		String pattern = "/test.stp";
+		assertMatched(pattern, "/test.stp");
+
+		pattern = "#/test.stp";
+		assertNotMatched(pattern, "/test.stp");
+	}
+
+	@Test
+	public void testFileNameWildcards() {
+		// Test basic * and ? for any pattern + any character
+		String pattern = "*.st?";
+		assertMatched(pattern, "/test.stp");
+		assertMatched(pattern, "/anothertest.stg");
+		assertMatched(pattern, "/anothertest.st0");
+		assertNotMatched(pattern, "/anothertest.sta1");
+		// Check that asterisk does not expand to "/"
+		assertNotMatched(pattern, "/another/test.sta1");
+
+		// Same as above, with a leading slash to ensure that doesn't cause
+		// problems
+		pattern = "/*.st?";
+		assertMatched(pattern, "/test.stp");
+		assertMatched(pattern, "/anothertest.stg");
+		assertMatched(pattern, "/anothertest.st0");
+		assertNotMatched(pattern, "/anothertest.sta1");
+		// Check that asterisk does not expand to "/"
+		assertNotMatched(pattern, "/another/test.sta1");
+
+		// Test for numbers
+		pattern = "*.sta[0-5]";
+		assertMatched(pattern, "/test.sta5");
+		assertMatched(pattern, "/test.sta4");
+		assertMatched(pattern, "/test.sta3");
+		assertMatched(pattern, "/test.sta2");
+		assertMatched(pattern, "/test.sta1");
+		assertMatched(pattern, "/test.sta0");
+		assertMatched(pattern, "/anothertest.sta2");
+		assertNotMatched(pattern, "test.stag");
+		assertNotMatched(pattern, "test.sta6");
+
+		// Test for letters
+		pattern = "/[tv]est.sta[a-d]";
+		assertMatched(pattern, "/test.staa");
+		assertMatched(pattern, "/test.stab");
+		assertMatched(pattern, "/test.stac");
+		assertMatched(pattern, "/test.stad");
+		assertMatched(pattern, "/vest.stac");
+		assertNotMatched(pattern, "test.stae");
+		assertNotMatched(pattern, "test.sta9");
+
+		// Test child directory/file is matched
+		pattern = "/src/ne?";
+		assertMatched(pattern, "/src/new/");
+		assertMatched(pattern, "/src/new");
+		assertMatched(pattern, "/src/new/a.c");
+		assertMatched(pattern, "/src/new/a/a.c");
+		assertNotMatched(pattern, "/src/new.c");
+
+		// Test name-only fnmatcher matches
+		pattern = "ne?";
+		assertMatched(pattern, "/src/new/");
+		assertMatched(pattern, "/src/new");
+		assertMatched(pattern, "/src/new/a.c");
+		assertMatched(pattern, "/src/new/a/a.c");
+		assertMatched(pattern, "/neb");
+		assertNotMatched(pattern, "/src/new.c");
+	}
+
+	@Test
+	public void testTargetWithoutLeadingSlash() {
+		// Test basic * and ? for any pattern + any character
+		String pattern = "/*.st?";
+		assertMatched(pattern, "test.stp");
+		assertMatched(pattern, "anothertest.stg");
+		assertMatched(pattern, "anothertest.st0");
+		assertNotMatched(pattern, "anothertest.sta1");
+		// Check that asterisk does not expand to ""
+		assertNotMatched(pattern, "another/test.sta1");
+
+		// Same as above, with a leading slash to ensure that doesn't cause
+		// problems
+		pattern = "/*.st?";
+		assertMatched(pattern, "test.stp");
+		assertMatched(pattern, "anothertest.stg");
+		assertMatched(pattern, "anothertest.st0");
+		assertNotMatched(pattern, "anothertest.sta1");
+		// Check that asterisk does not expand to ""
+		assertNotMatched(pattern, "another/test.sta1");
+
+		// Test for numbers
+		pattern = "/*.sta[0-5]";
+		assertMatched(pattern, "test.sta5");
+		assertMatched(pattern, "test.sta4");
+		assertMatched(pattern, "test.sta3");
+		assertMatched(pattern, "test.sta2");
+		assertMatched(pattern, "test.sta1");
+		assertMatched(pattern, "test.sta0");
+		assertMatched(pattern, "anothertest.sta2");
+		assertNotMatched(pattern, "test.stag");
+		assertNotMatched(pattern, "test.sta6");
+
+		// Test for letters
+		pattern = "/[tv]est.sta[a-d]";
+		assertMatched(pattern, "test.staa");
+		assertMatched(pattern, "test.stab");
+		assertMatched(pattern, "test.stac");
+		assertMatched(pattern, "test.stad");
+		assertMatched(pattern, "vest.stac");
+		assertNotMatched(pattern, "test.stae");
+		assertNotMatched(pattern, "test.sta9");
+
+		// Test child directory/file is matched
+		pattern = "/src/ne?";
+		assertMatched(pattern, "src/new/");
+		assertMatched(pattern, "src/new");
+		assertMatched(pattern, "src/new/a.c");
+		assertMatched(pattern, "src/new/a/a.c");
+		assertNotMatched(pattern, "src/new.c");
+
+		// Test name-only fnmatcher matches
+		pattern = "ne?";
+		assertMatched(pattern, "src/new/");
+		assertMatched(pattern, "src/new");
+		assertMatched(pattern, "src/new/a.c");
+		assertMatched(pattern, "src/new/a/a.c");
+		assertMatched(pattern, "neb");
+		assertNotMatched(pattern, "src/new.c");
+	}
+
+	@Test
+	public void testParentDirectoryGitIgnores() {
+		// Contains git ignore patterns such as might be seen in a parent
+		// directory
+
+		// Test for wildcards
+		String pattern = "/*/*.c";
+		assertMatched(pattern, "/file/a.c");
+		assertMatched(pattern, "/src/a.c");
+		assertNotMatched(pattern, "/src/new/a.c");
+
+		// Test child directory/file is matched
+		pattern = "/src/new";
+		assertMatched(pattern, "/src/new/");
+		assertMatched(pattern, "/src/new");
+		assertMatched(pattern, "/src/new/a.c");
+		assertMatched(pattern, "/src/new/a/a.c");
+		assertNotMatched(pattern, "/src/new.c");
+
+		// Test child directory is matched, slash after name
+		pattern = "/src/new/";
+		assertMatched(pattern, "/src/new/");
+		assertMatched(pattern, "/src/new/a.c");
+		assertMatched(pattern, "/src/new/a/a.c");
+		assertNotMatched(pattern, "/src/new");
+		assertNotMatched(pattern, "/src/new.c");
+
+		// Test directory is matched by name only
+		pattern = "b1";
+		assertMatched(pattern, "/src/new/a/b1/a.c");
+		assertNotMatched(pattern, "/src/new/a/b2/file.c");
+		assertNotMatched(pattern, "/src/new/a/bb1/file.c");
+		assertNotMatched(pattern, "/src/new/a/file.c");
+	}
+
+	@Test
+	public void testTrailingSlash() {
+		String pattern = "/src/";
+		assertMatched(pattern, "/src/");
+		assertMatched(pattern, "/src/new");
+		assertMatched(pattern, "/src/new/a.c");
+		assertMatched(pattern, "/src/a.c");
+		assertNotMatched(pattern, "/src");
+		assertNotMatched(pattern, "/srcA/");
+	}
+
+	@Test
+	public void testNameOnlyMatches() {
+		/*
+		 * Name-only matches do not contain any path separators
+		 */
+		// Test matches for file extension
+		String pattern = "*.stp";
+		assertMatched(pattern, "/test.stp");
+		assertMatched(pattern, "/src/test.stp");
+		assertNotMatched(pattern, "/test.stp1");
+		assertNotMatched(pattern, "/test.astp");
+
+		// Test matches for name-only, applies to file name or folder name
+		pattern = "src";
+		assertMatched(pattern, "/src");
+		assertMatched(pattern, "/src/");
+		assertMatched(pattern, "/src/a.c");
+		assertMatched(pattern, "/src/new/a.c");
+		assertMatched(pattern, "/new/src/a.c");
+		assertMatched(pattern, "/file/src");
+
+		// Test matches for name-only, applies only to folder names
+		pattern = "src/";
+		assertMatched(pattern, "/src/");
+		assertMatched(pattern, "/src/a.c");
+		assertMatched(pattern, "/src/new/a.c");
+		assertMatched(pattern, "/new/src/a.c");
+		assertNotMatched(pattern, "/src");
+		assertNotMatched(pattern, "/file/src");
+
+		// Test matches for name-only, applies to file name or folder name
+		// With a small wildcard
+		pattern = "?rc";
+		assertMatched(pattern, "/src/a.c");
+		assertMatched(pattern, "/src/new/a.c");
+		assertMatched(pattern, "/new/src/a.c");
+		assertMatched(pattern, "/file/src");
+		assertMatched(pattern, "/src/");
+
+		// Test matches for name-only, applies to file name or folder name
+		// With a small wildcard
+		pattern = "?r[a-c]";
+		assertMatched(pattern, "/src/a.c");
+		assertMatched(pattern, "/src/new/a.c");
+		assertMatched(pattern, "/new/src/a.c");
+		assertMatched(pattern, "/file/src");
+		assertMatched(pattern, "/src/");
+		assertMatched(pattern, "/srb/a.c");
+		assertMatched(pattern, "/grb/new/a.c");
+		assertMatched(pattern, "/new/crb/a.c");
+		assertMatched(pattern, "/file/3rb");
+		assertMatched(pattern, "/xrb/");
+		assertMatched(pattern, "/3ra/a.c");
+		assertMatched(pattern, "/5ra/new/a.c");
+		assertMatched(pattern, "/new/1ra/a.c");
+		assertMatched(pattern, "/file/dra");
+		assertMatched(pattern, "/era/");
+		assertNotMatched(pattern, "/crg");
+		assertNotMatched(pattern, "/cr3");
+	}
+
+	@Test
+	public void testNegation() {
+		String pattern = "!/test.stp";
+		assertMatched(pattern, "/test.stp");
+	}
+
+	/**
+	 * Check for a match. If target ends with "/", match will assume that the
+	 * target is meant to be a directory.
+	 *
+	 * @param pattern
+	 *            Pattern as it would appear in a .gitignore file
+	 * @param target
+	 *            Target file path relative to repository's GIT_DIR
+	 */
+	public void assertMatched(String pattern, String target) {
+		boolean value = match(pattern, target);
+		assertTrue("Expected a match for: " + pattern + " with: " + target,
+				value);
+	}
+
+	/**
+	 * Check for a match. If target ends with "/", match will assume that the
+	 * target is meant to be a directory.
+	 *
+	 * @param pattern
+	 *            Pattern as it would appear in a .gitignore file
+	 * @param target
+	 *            Target file path relative to repository's GIT_DIR
+	 */
+	public void assertNotMatched(String pattern, String target) {
+		boolean value = match(pattern, target);
+		assertFalse("Expected no match for: " + pattern + " with: " + target,
+				value);
+	}
+
+	/**
+	 * Check for a match. If target ends with "/", match will assume that the
+	 * target is meant to be a directory.
+	 *
+	 * @param pattern
+	 *            Pattern as it would appear in a .gitignore file
+	 * @param target
+	 *            Target file path relative to repository's GIT_DIR
+	 * @return Result of {@link FastIgnoreRule#isMatch(String, boolean)}
+	 */
+	private boolean match(String pattern, String target) {
+		boolean isDirectory = target.endsWith("/");
+		if (useJGitRule.booleanValue()) {
+			IgnoreRule r = new IgnoreRule(pattern);
+			// If speed of this test is ever an issue, we can use a presetRule
+			// field
+			// to avoid recompiling a pattern each time.
+			return r.isMatch(target, isDirectory);
+		}
+		FastIgnoreRule r = new FastIgnoreRule(pattern);
+		// If speed of this test is ever an issue, we can use a presetRule field
+		// to avoid recompiling a pattern each time.
+		return r.isMatch(target, isDirectory);
+	}
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/ignore/IgnoreMatcherTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/ignore/IgnoreMatcherTest.java
index aa98696..0713b1a 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/ignore/IgnoreMatcherTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/ignore/IgnoreMatcherTest.java
@@ -52,6 +52,7 @@
 /**
  * Tests ignore pattern matches
  */
+@SuppressWarnings("deprecation")
 public class IgnoreMatcherTest {
 
 	@Test
@@ -383,12 +384,12 @@
 	/**
 	 * Check for a match. If target ends with "/", match will assume that the
 	 * target is meant to be a directory.
+	 *
 	 * @param pattern
-	 * 			  Pattern as it would appear in a .gitignore file
+	 *            Pattern as it would appear in a .gitignore file
 	 * @param target
-	 * 			  Target file path relative to repository's GIT_DIR
-	 * @return
-	 * 			  Result of {@link IgnoreRule#isMatch(String, boolean)}
+	 *            Target file path relative to repository's GIT_DIR
+	 * @return Result of IgnoreRule.isMatch(String, boolean)
 	 */
 	private static boolean match(String pattern, String target) {
 		IgnoreRule r = new IgnoreRule(pattern);
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/ignore/IgnoreRuleSpecialCasesTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/ignore/IgnoreRuleSpecialCasesTest.java
new file mode 100644
index 0000000..109f28d
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/ignore/IgnoreRuleSpecialCasesTest.java
@@ -0,0 +1,902 @@
+/*
+ * Copyright (C) 2008, Florian Koeberle <florianskarten@web.de>
+ * Copyright (C) 2008, Florian Köberle <florianskarten@web.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.ignore;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assume.assumeTrue;
+
+import java.util.Arrays;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+@SuppressWarnings({ "deprecation", "boxing" })
+public class IgnoreRuleSpecialCasesTest {
+
+	@Parameters(name = "JGit? {0}")
+	public static Iterable<Boolean[]> data() {
+		return Arrays.asList(new Boolean[][] { { Boolean.FALSE },
+				{ Boolean.TRUE } });
+	}
+
+	@Parameter
+	public Boolean useJGitRule;
+
+	private void assertMatch(final String pattern, final String input,
+			final boolean matchExpected, Boolean... assume) {
+		boolean assumeDir = input.endsWith("/");
+		if (useJGitRule.booleanValue()) {
+			final IgnoreRule matcher = new IgnoreRule(pattern);
+			if (assume.length == 0 || !assume[0].booleanValue())
+				assertEquals(matchExpected, matcher.isMatch(input, assumeDir));
+			else
+				assumeTrue(matchExpected == matcher.isMatch(input, assumeDir));
+		} else {
+			FastIgnoreRule matcher = new FastIgnoreRule(pattern);
+			if (assume.length == 0 || !assume[0].booleanValue())
+				assertEquals(matchExpected, matcher.isMatch(input, assumeDir));
+			else
+				assumeTrue(matchExpected == matcher.isMatch(input, assumeDir));
+		}
+	}
+
+	private void assertFileNameMatch(final String pattern, final String input,
+			final boolean matchExpected) {
+		boolean assumeDir = input.endsWith("/");
+		if (useJGitRule.booleanValue()) {
+			final IgnoreRule matcher = new IgnoreRule(pattern);
+			assertEquals(matchExpected, matcher.isMatch(input, assumeDir));
+		} else {
+			FastIgnoreRule matcher = new FastIgnoreRule(pattern);
+			assertEquals(matchExpected, matcher.isMatch(input, assumeDir));
+		}
+	}
+
+	@Test
+	public void testVerySimplePatternCase0() throws Exception {
+		if (useJGitRule)
+			System.err
+					.println("IgnoreRule can't understand blank lines, skipping");
+		Boolean assume = useJGitRule;
+		assertMatch("", "", false, assume);
+	}
+
+	@Test
+	public void testVerySimplePatternCase1() throws Exception {
+		assertMatch("ab", "a", false);
+	}
+
+	@Test
+	public void testVerySimplePatternCase2() throws Exception {
+		assertMatch("ab", "ab", true);
+	}
+
+	@Test
+	public void testVerySimplePatternCase3() throws Exception {
+		assertMatch("ab", "ac", false);
+	}
+
+	@Test
+	public void testVerySimplePatternCase4() throws Exception {
+		assertMatch("ab", "abc", false);
+	}
+
+	@Test
+	public void testVerySimpleWildcardCase0() throws Exception {
+		assertMatch("?", "a", true);
+	}
+
+	@Test
+	public void testVerySimpleWildCardCase1() throws Exception {
+		assertMatch("??", "a", false);
+	}
+
+	@Test
+	public void testVerySimpleWildCardCase2() throws Exception {
+		assertMatch("??", "ab", true);
+	}
+
+	@Test
+	public void testVerySimpleWildCardCase3() throws Exception {
+		assertMatch("??", "abc", false);
+	}
+
+	@Test
+	public void testVerySimpleStarCase0() throws Exception {
+		// can't happen, but blank lines should never match
+		assertMatch("*", "", false);
+	}
+
+	@Test
+	public void testVerySimpleStarCase1() throws Exception {
+		assertMatch("*", "a", true);
+	}
+
+	@Test
+	public void testVerySimpleStarCase2() throws Exception {
+		assertMatch("*", "ab", true);
+	}
+
+	@Test
+	public void testSimpleStarCase0() throws Exception {
+		assertMatch("a*b", "a", false);
+	}
+
+	@Test
+	public void testSimpleStarCase1() throws Exception {
+		assertMatch("a*c", "ac", true);
+	}
+
+	@Test
+	public void testSimpleStarCase2() throws Exception {
+		assertMatch("a*c", "ab", false);
+	}
+
+	@Test
+	public void testSimpleStarCase3() throws Exception {
+		assertMatch("a*c", "abc", true);
+	}
+
+	@Test
+	public void testManySolutionsCase0() throws Exception {
+		assertMatch("a*a*a", "aaa", true);
+	}
+
+	@Test
+	public void testManySolutionsCase1() throws Exception {
+		assertMatch("a*a*a", "aaaa", true);
+	}
+
+	@Test
+	public void testManySolutionsCase2() throws Exception {
+		assertMatch("a*a*a", "ababa", true);
+	}
+
+	@Test
+	public void testManySolutionsCase3() throws Exception {
+		assertMatch("a*a*a", "aaaaaaaa", true);
+	}
+
+	@Test
+	public void testManySolutionsCase4() throws Exception {
+		assertMatch("a*a*a", "aaaaaaab", false);
+	}
+
+	@Test
+	public void testVerySimpleGroupCase0() throws Exception {
+		assertMatch("[ab]", "a", true);
+	}
+
+	@Test
+	public void testVerySimpleGroupCase1() throws Exception {
+		assertMatch("[ab]", "b", true);
+	}
+
+	@Test
+	public void testVerySimpleGroupCase2() throws Exception {
+		assertMatch("[ab]", "ab", false);
+	}
+
+	@Test
+	public void testVerySimpleGroupRangeCase0() throws Exception {
+		assertMatch("[b-d]", "a", false);
+	}
+
+	@Test
+	public void testVerySimpleGroupRangeCase1() throws Exception {
+		assertMatch("[b-d]", "b", true);
+	}
+
+	@Test
+	public void testVerySimpleGroupRangeCase2() throws Exception {
+		assertMatch("[b-d]", "c", true);
+	}
+
+	@Test
+	public void testVerySimpleGroupRangeCase3() throws Exception {
+		assertMatch("[b-d]", "d", true);
+	}
+
+	@Test
+	public void testVerySimpleGroupRangeCase4() throws Exception {
+		assertMatch("[b-d]", "e", false);
+	}
+
+	@Test
+	public void testVerySimpleGroupRangeCase5() throws Exception {
+		assertMatch("[b-d]", "-", false);
+	}
+
+	@Test
+	public void testTwoGroupsCase0() throws Exception {
+		assertMatch("[b-d][ab]", "bb", true);
+	}
+
+	@Test
+	public void testTwoGroupsCase1() throws Exception {
+		assertMatch("[b-d][ab]", "ca", true);
+	}
+
+	@Test
+	public void testTwoGroupsCase2() throws Exception {
+		assertMatch("[b-d][ab]", "fa", false);
+	}
+
+	@Test
+	public void testTwoGroupsCase3() throws Exception {
+		assertMatch("[b-d][ab]", "bc", false);
+	}
+
+	@Test
+	public void testTwoRangesInOneGroupCase0() throws Exception {
+		assertMatch("[b-ce-e]", "a", false);
+	}
+
+	@Test
+	public void testTwoRangesInOneGroupCase1() throws Exception {
+		assertMatch("[b-ce-e]", "b", true);
+	}
+
+	@Test
+	public void testTwoRangesInOneGroupCase2() throws Exception {
+		assertMatch("[b-ce-e]", "c", true);
+	}
+
+	@Test
+	public void testTwoRangesInOneGroupCase3() throws Exception {
+		assertMatch("[b-ce-e]", "d", false);
+	}
+
+	@Test
+	public void testTwoRangesInOneGroupCase4() throws Exception {
+		assertMatch("[b-ce-e]", "e", true);
+	}
+
+	@Test
+	public void testTwoRangesInOneGroupCase5() throws Exception {
+		assertMatch("[b-ce-e]", "f", false);
+	}
+
+	@Test
+	public void testIncompleteRangesInOneGroupCase0() throws Exception {
+		assertMatch("a[b-]", "ab", true);
+	}
+
+	@Test
+	public void testIncompleteRangesInOneGroupCase1() throws Exception {
+		assertMatch("a[b-]", "ac", false);
+	}
+
+	@Test
+	public void testIncompleteRangesInOneGroupCase2() throws Exception {
+		assertMatch("a[b-]", "a-", true);
+	}
+
+	@Test
+	public void testCombinedRangesInOneGroupCase0() throws Exception {
+		assertMatch("[a-c-e]", "b", true);
+	}
+
+	/**
+	 * The c belongs to the range a-c. "-e" is no valid range so d should not
+	 * match.
+	 *
+	 * @throws Exception
+	 *             for some reasons
+	 */
+	@Test
+	public void testCombinedRangesInOneGroupCase1() throws Exception {
+		assertMatch("[a-c-e]", "d", false);
+	}
+
+	@Test
+	public void testCombinedRangesInOneGroupCase2() throws Exception {
+		assertMatch("[a-c-e]", "e", true);
+	}
+
+	@Test
+	public void testInversedGroupCase0() throws Exception {
+		assertMatch("[!b-c]", "a", true);
+	}
+
+	@Test
+	public void testInversedGroupCase1() throws Exception {
+		assertMatch("[!b-c]", "b", false);
+	}
+
+	@Test
+	public void testInversedGroupCase2() throws Exception {
+		assertMatch("[!b-c]", "c", false);
+	}
+
+	@Test
+	public void testInversedGroupCase3() throws Exception {
+		assertMatch("[!b-c]", "d", true);
+	}
+
+	@Test
+	public void testAlphaGroupCase0() throws Exception {
+		assertMatch("[[:alpha:]]", "d", true);
+	}
+
+	@Test
+	public void testAlphaGroupCase1() throws Exception {
+		assertMatch("[[:alpha:]]", ":", false);
+	}
+
+	@Test
+	public void testAlphaGroupCase2() throws Exception {
+		// \u00f6 = 'o' with dots on it
+		assertMatch("[[:alpha:]]", "\u00f6", true);
+	}
+
+	@Test
+	public void test2AlphaGroupsCase0() throws Exception {
+		// \u00f6 = 'o' with dots on it
+		assertMatch("[[:alpha:]][[:alpha:]]", "a\u00f6", true);
+		assertMatch("[[:alpha:]][[:alpha:]]", "a1", false);
+	}
+
+	@Test
+	public void testAlnumGroupCase0() throws Exception {
+		assertMatch("[[:alnum:]]", "a", true);
+	}
+
+	@Test
+	public void testAlnumGroupCase1() throws Exception {
+		assertMatch("[[:alnum:]]", "1", true);
+	}
+
+	@Test
+	public void testAlnumGroupCase2() throws Exception {
+		assertMatch("[[:alnum:]]", ":", false);
+	}
+
+	@Test
+	public void testBlankGroupCase0() throws Exception {
+		assertMatch("[[:blank:]]", " ", true);
+	}
+
+	@Test
+	public void testBlankGroupCase1() throws Exception {
+		assertMatch("[[:blank:]]", "\t", true);
+	}
+
+	@Test
+	public void testBlankGroupCase2() throws Exception {
+		assertMatch("[[:blank:]]", "\r", false);
+	}
+
+	@Test
+	public void testBlankGroupCase3() throws Exception {
+		assertMatch("[[:blank:]]", "\n", false);
+	}
+
+	@Test
+	public void testBlankGroupCase4() throws Exception {
+		assertMatch("[[:blank:]]", "a", false);
+	}
+
+	@Test
+	public void testCntrlGroupCase0() throws Exception {
+		assertMatch("[[:cntrl:]]", "a", false);
+	}
+
+	@Test
+	public void testCntrlGroupCase1() throws Exception {
+		assertMatch("[[:cntrl:]]", String.valueOf((char) 7), true);
+	}
+
+	@Test
+	public void testDigitGroupCase0() throws Exception {
+		assertMatch("[[:digit:]]", "0", true);
+	}
+
+	@Test
+	public void testDigitGroupCase1() throws Exception {
+		assertMatch("[[:digit:]]", "5", true);
+	}
+
+	@Test
+	public void testDigitGroupCase2() throws Exception {
+		assertMatch("[[:digit:]]", "9", true);
+	}
+
+	@Test
+	public void testDigitGroupCase3() throws Exception {
+		// \u06f9 = EXTENDED ARABIC-INDIC DIGIT NINE
+		assertMatch("[[:digit:]]", "\u06f9", true);
+	}
+
+	@Test
+	public void testDigitGroupCase4() throws Exception {
+		assertMatch("[[:digit:]]", "a", false);
+	}
+
+	@Test
+	public void testDigitGroupCase5() throws Exception {
+		assertMatch("[[:digit:]]", "]", false);
+	}
+
+	@Test
+	public void testGraphGroupCase0() throws Exception {
+		assertMatch("[[:graph:]]", "]", true);
+	}
+
+	@Test
+	public void testGraphGroupCase1() throws Exception {
+		assertMatch("[[:graph:]]", "a", true);
+	}
+
+	@Test
+	public void testGraphGroupCase2() throws Exception {
+		assertMatch("[[:graph:]]", ".", true);
+	}
+
+	@Test
+	public void testGraphGroupCase3() throws Exception {
+		assertMatch("[[:graph:]]", "0", true);
+	}
+
+	@Test
+	public void testGraphGroupCase4() throws Exception {
+		assertMatch("[[:graph:]]", " ", false);
+	}
+
+	@Test
+	public void testGraphGroupCase5() throws Exception {
+		// \u00f6 = 'o' with dots on it
+		assertMatch("[[:graph:]]", "\u00f6", true);
+	}
+
+	@Test
+	public void testLowerGroupCase0() throws Exception {
+		assertMatch("[[:lower:]]", "a", true);
+	}
+
+	@Test
+	public void testLowerGroupCase1() throws Exception {
+		assertMatch("[[:lower:]]", "h", true);
+	}
+
+	@Test
+	public void testLowerGroupCase2() throws Exception {
+		assertMatch("[[:lower:]]", "A", false);
+	}
+
+	@Test
+	public void testLowerGroupCase3() throws Exception {
+		assertMatch("[[:lower:]]", "H", false);
+	}
+
+	@Test
+	public void testLowerGroupCase4() throws Exception {
+		// \u00e4 = small 'a' with dots on it
+		assertMatch("[[:lower:]]", "\u00e4", true);
+	}
+
+	@Test
+	public void testLowerGroupCase5() throws Exception {
+		assertMatch("[[:lower:]]", ".", false);
+	}
+
+	@Test
+	public void testPrintGroupCase0() throws Exception {
+		assertMatch("[[:print:]]", "]", true);
+	}
+
+	@Test
+	public void testPrintGroupCase1() throws Exception {
+		assertMatch("[[:print:]]", "a", true);
+	}
+
+	@Test
+	public void testPrintGroupCase2() throws Exception {
+		assertMatch("[[:print:]]", ".", true);
+	}
+
+	@Test
+	public void testPrintGroupCase3() throws Exception {
+		assertMatch("[[:print:]]", "0", true);
+	}
+
+	@Test
+	public void testPrintGroupCase4() throws Exception {
+		assertMatch("[[:print:]]", " ", true);
+	}
+
+	@Test
+	public void testPrintGroupCase5() throws Exception {
+		// \u00f6 = 'o' with dots on it
+		assertMatch("[[:print:]]", "\u00f6", true);
+	}
+
+	@Test
+	public void testPunctGroupCase0() throws Exception {
+		assertMatch("[[:punct:]]", ".", true);
+	}
+
+	@Test
+	public void testPunctGroupCase1() throws Exception {
+		assertMatch("[[:punct:]]", "@", true);
+	}
+
+	@Test
+	public void testPunctGroupCase2() throws Exception {
+		assertMatch("[[:punct:]]", " ", false);
+	}
+
+	@Test
+	public void testPunctGroupCase3() throws Exception {
+		assertMatch("[[:punct:]]", "a", false);
+	}
+
+	@Test
+	public void testSpaceGroupCase0() throws Exception {
+		assertMatch("[[:space:]]", " ", true);
+	}
+
+	@Test
+	public void testSpaceGroupCase1() throws Exception {
+		assertMatch("[[:space:]]", "\t", true);
+	}
+
+	@Test
+	public void testSpaceGroupCase2() throws Exception {
+		assertMatch("[[:space:]]", "\r", true);
+	}
+
+	@Test
+	public void testSpaceGroupCase3() throws Exception {
+		assertMatch("[[:space:]]", "\n", true);
+	}
+
+	@Test
+	public void testSpaceGroupCase4() throws Exception {
+		assertMatch("[[:space:]]", "a", false);
+	}
+
+	@Test
+	public void testUpperGroupCase0() throws Exception {
+		assertMatch("[[:upper:]]", "a", false);
+	}
+
+	@Test
+	public void testUpperGroupCase1() throws Exception {
+		assertMatch("[[:upper:]]", "h", false);
+	}
+
+	@Test
+	public void testUpperGroupCase2() throws Exception {
+		assertMatch("[[:upper:]]", "A", true);
+	}
+
+	@Test
+	public void testUpperGroupCase3() throws Exception {
+		assertMatch("[[:upper:]]", "H", true);
+	}
+
+	@Test
+	public void testUpperGroupCase4() throws Exception {
+		// \u00c4 = 'A' with dots on it
+		assertMatch("[[:upper:]]", "\u00c4", true);
+	}
+
+	@Test
+	public void testUpperGroupCase5() throws Exception {
+		assertMatch("[[:upper:]]", ".", false);
+	}
+
+	@Test
+	public void testXDigitGroupCase0() throws Exception {
+		assertMatch("[[:xdigit:]]", "a", true);
+	}
+
+	@Test
+	public void testXDigitGroupCase1() throws Exception {
+		assertMatch("[[:xdigit:]]", "d", true);
+	}
+
+	@Test
+	public void testXDigitGroupCase2() throws Exception {
+		assertMatch("[[:xdigit:]]", "f", true);
+	}
+
+	@Test
+	public void testXDigitGroupCase3() throws Exception {
+		assertMatch("[[:xdigit:]]", "0", true);
+	}
+
+	@Test
+	public void testXDigitGroupCase4() throws Exception {
+		assertMatch("[[:xdigit:]]", "5", true);
+	}
+
+	@Test
+	public void testXDigitGroupCase5() throws Exception {
+		assertMatch("[[:xdigit:]]", "9", true);
+	}
+
+	@Test
+	public void testXDigitGroupCase6() throws Exception {
+		assertMatch("[[:xdigit:]]", "Û¹", false);
+	}
+
+	@Test
+	public void testXDigitGroupCase7() throws Exception {
+		assertMatch("[[:xdigit:]]", ".", false);
+	}
+
+	@Test
+	public void testWordGroupCase0() throws Exception {
+		assertMatch("[[:word:]]", "g", true);
+	}
+
+	@Test
+	public void testWordGroupCase1() throws Exception {
+		// \u00f6 = 'o' with dots on it
+		assertMatch("[[:word:]]", "\u00f6", true);
+	}
+
+	@Test
+	public void testWordGroupCase2() throws Exception {
+		assertMatch("[[:word:]]", "5", true);
+	}
+
+	@Test
+	public void testWordGroupCase3() throws Exception {
+		assertMatch("[[:word:]]", "_", true);
+	}
+
+	@Test
+	public void testWordGroupCase4() throws Exception {
+		assertMatch("[[:word:]]", " ", false);
+	}
+
+	@Test
+	public void testWordGroupCase5() throws Exception {
+		assertMatch("[[:word:]]", ".", false);
+	}
+
+	@Test
+	public void testMixedGroupCase0() throws Exception {
+		assertMatch("[A[:lower:]C3-5]", "A", true);
+	}
+
+	@Test
+	public void testMixedGroupCase1() throws Exception {
+		assertMatch("[A[:lower:]C3-5]", "C", true);
+	}
+
+	@Test
+	public void testMixedGroupCase2() throws Exception {
+		assertMatch("[A[:lower:]C3-5]", "e", true);
+	}
+
+	@Test
+	public void testMixedGroupCase3() throws Exception {
+		assertMatch("[A[:lower:]C3-5]", "3", true);
+	}
+
+	@Test
+	public void testMixedGroupCase4() throws Exception {
+		assertMatch("[A[:lower:]C3-5]", "4", true);
+	}
+
+	@Test
+	public void testMixedGroupCase5() throws Exception {
+		assertMatch("[A[:lower:]C3-5]", "5", true);
+	}
+
+	@Test
+	public void testMixedGroupCase6() throws Exception {
+		assertMatch("[A[:lower:]C3-5]", "B", false);
+	}
+
+	@Test
+	public void testMixedGroupCase7() throws Exception {
+		assertMatch("[A[:lower:]C3-5]", "2", false);
+	}
+
+	@Test
+	public void testMixedGroupCase8() throws Exception {
+		assertMatch("[A[:lower:]C3-5]", "6", false);
+	}
+
+	@Test
+	public void testMixedGroupCase9() throws Exception {
+		assertMatch("[A[:lower:]C3-5]", ".", false);
+	}
+
+	@Test
+	public void testSpecialGroupCase0() throws Exception {
+		assertMatch("[[]", "[", true);
+	}
+
+	@Test
+	public void testSpecialGroupCase1() throws Exception {
+		assertMatch("[]]", "]", true);
+	}
+
+	@Test
+	public void testSpecialGroupCase2() throws Exception {
+		assertMatch("[]a]", "]", true);
+	}
+
+	@Test
+	public void testSpecialGroupCase3() throws Exception {
+		assertMatch("[a[]", "[", true);
+	}
+
+	@Test
+	public void testSpecialGroupCase4() throws Exception {
+		assertMatch("[a[]", "a", true);
+	}
+
+	@Test
+	public void testSpecialGroupCase5() throws Exception {
+		assertMatch("[!]]", "]", false);
+	}
+
+	@Test
+	public void testSpecialGroupCase6() throws Exception {
+		assertMatch("[!]]", "x", true);
+	}
+
+	@Test
+	public void testSpecialGroupCase7() throws Exception {
+		assertMatch("[:]]", ":]", true);
+	}
+
+	@Test
+	public void testSpecialGroupCase8() throws Exception {
+		assertMatch("[:]]", ":", false);
+	}
+
+	@Test
+	public void testSpecialGroupCase9() throws Exception {
+		if (useJGitRule)
+			System.err.println("IgnoreRule can't understand [[:], skipping");
+		Boolean assume = useJGitRule;
+		// Second bracket is threated literally, so both [ and : should match
+		assertMatch("[[:]", ":", true, assume);
+		assertMatch("[[:]", "[", true, assume);
+	}
+
+	@Test
+	public void testUnsupportedGroupCase0() throws Exception {
+		assertMatch("[[=a=]]", "a", false);
+		assertMatch("[[=a=]]", "=", false);
+		assertMatch("[=a=]", "a", true);
+		assertMatch("[=a=]", "=", true);
+	}
+
+	@Test
+	public void testUnsupportedGroupCase01() throws Exception {
+		assertMatch("[.a.]*[.a.]", "aha", true);
+	}
+
+	@Test
+	public void testUnsupportedGroupCase1() throws Exception {
+		assertMatch("[[.a.]]", "a", false);
+		assertMatch("[[.a.]]", ".", false);
+		assertMatch("[.a.]", "a", true);
+		assertMatch("[.a.]", ".", true);
+	}
+
+	@Test
+	public void testEscapedBracket1() throws Exception {
+		assertMatch("\\[", "[", true);
+	}
+
+	@Test
+	public void testEscapedBracket2() throws Exception {
+		assertMatch("\\[[a]", "[", false);
+	}
+
+	@Test
+	public void testEscapedBracket3() throws Exception {
+		assertMatch("\\[[a]", "a", false);
+	}
+
+	@Test
+	public void testEscapedBracket4() throws Exception {
+		assertMatch("\\[[a]", "[a", true);
+	}
+
+	@Test
+	public void testEscapedBracket5() throws Exception {
+		assertMatch("[a\\]]", "]", true);
+	}
+
+	@Test
+	public void testEscapedBracket6() throws Exception {
+		assertMatch("[a\\]]", "a", true);
+	}
+
+	@Test
+	public void testEscapedBackslash() throws Exception {
+		if (useJGitRule)
+			System.err
+					.println("IgnoreRule can't understand escaped backslashes, skipping");
+		Boolean assume = useJGitRule;
+		// In Git CLI a\\b matches a\b file
+		assertMatch("a\\\\b", "a\\b", true, assume);
+	}
+
+	@Test
+	public void testMultipleEscapedCharacters1() throws Exception {
+		assertMatch("\\]a?c\\*\\[d\\?\\]", "]abc*[d?]", true);
+	}
+
+	@Test
+	public void testFilePathSimpleCase() throws Exception {
+		assertFileNameMatch("a/b", "a/b", true);
+	}
+
+	@Test
+	public void testFilePathCase0() throws Exception {
+		assertFileNameMatch("a*b", "a/b", false);
+	}
+
+	@Test
+	public void testFilePathCase1() throws Exception {
+		assertFileNameMatch("a?b", "a/b", false);
+	}
+
+	@Test
+	public void testFilePathCase2() throws Exception {
+		assertFileNameMatch("a*b", "a\\b", true);
+	}
+
+	@Test
+	public void testFilePathCase3() throws Exception {
+		assertFileNameMatch("a?b", "a\\b", true);
+	}
+
+}
\ No newline at end of file
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcBasicPackingTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcBasicPackingTest.java
index 0f27099..0742504 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcBasicPackingTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcBasicPackingTest.java
@@ -51,21 +51,32 @@
 
 import org.eclipse.jgit.junit.TestRepository.BranchBuilder;
 import org.eclipse.jgit.revwalk.RevCommit;
-import org.junit.Test;
+import org.eclipse.jgit.storage.pack.PackConfig;
+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 GcBasicPackingTest extends GcTestCase {
-	@Test
-	public void repackEmptyRepo_noPackCreated() throws IOException {
+	@DataPoints
+	public static boolean[] aggressiveValues = { true, false };
+
+	@Theory
+	public void repackEmptyRepo_noPackCreated(boolean aggressive)
+			throws IOException {
+		configureGc(gc, aggressive);
 		gc.repack();
 		assertEquals(0, repo.getObjectDatabase().getPacks().size());
 	}
 
-	@Test
-	public void testPackRepoWithNoRefs() throws Exception {
+	@Theory
+	public void testPackRepoWithNoRefs(boolean aggressive) throws Exception {
 		tr.commit().add("A", "A").add("B", "B").create();
 		stats = gc.getStatistics();
 		assertEquals(4, stats.numberOfLooseObjects);
 		assertEquals(0, stats.numberOfPackedObjects);
+		configureGc(gc, aggressive);
 		gc.gc();
 		stats = gc.getStatistics();
 		assertEquals(4, stats.numberOfLooseObjects);
@@ -73,8 +84,8 @@
 		assertEquals(0, stats.numberOfPackFiles);
 	}
 
-	@Test
-	public void testPack2Commits() throws Exception {
+	@Theory
+	public void testPack2Commits(boolean aggressive) throws Exception {
 		BranchBuilder bb = tr.branch("refs/heads/master");
 		bb.commit().add("A", "A").add("B", "B").create();
 		bb.commit().add("A", "A2").add("B", "B2").create();
@@ -82,6 +93,7 @@
 		stats = gc.getStatistics();
 		assertEquals(8, stats.numberOfLooseObjects);
 		assertEquals(0, stats.numberOfPackedObjects);
+		configureGc(gc, aggressive);
 		gc.gc();
 		stats = gc.getStatistics();
 		assertEquals(0, stats.numberOfLooseObjects);
@@ -89,13 +101,15 @@
 		assertEquals(1, stats.numberOfPackFiles);
 	}
 
-	@Test
-	public void testPackAllObjectsInOnePack() throws Exception {
+	@Theory
+	public void testPackAllObjectsInOnePack(boolean aggressive)
+			throws Exception {
 		tr.branch("refs/heads/master").commit().add("A", "A").add("B", "B")
 				.create();
 		stats = gc.getStatistics();
 		assertEquals(4, stats.numberOfLooseObjects);
 		assertEquals(0, stats.numberOfPackedObjects);
+		configureGc(gc, aggressive);
 		gc.gc();
 		stats = gc.getStatistics();
 		assertEquals(0, stats.numberOfLooseObjects);
@@ -110,8 +124,8 @@
 		assertEquals(1, stats.numberOfPackFiles);
 	}
 
-	@Test
-	public void testPackCommitsAndLooseOne() throws Exception {
+	@Theory
+	public void testPackCommitsAndLooseOne(boolean aggressive) throws Exception {
 		BranchBuilder bb = tr.branch("refs/heads/master");
 		RevCommit first = bb.commit().add("A", "A").add("B", "B").create();
 		bb.commit().add("A", "A2").add("B", "B2").create();
@@ -120,6 +134,7 @@
 		stats = gc.getStatistics();
 		assertEquals(8, stats.numberOfLooseObjects);
 		assertEquals(0, stats.numberOfPackedObjects);
+		configureGc(gc, aggressive);
 		gc.gc();
 		stats = gc.getStatistics();
 		assertEquals(0, stats.numberOfLooseObjects);
@@ -127,8 +142,8 @@
 		assertEquals(2, stats.numberOfPackFiles);
 	}
 
-	@Test
-	public void testNotPackTwice() throws Exception {
+	@Theory
+	public void testNotPackTwice(boolean aggressive) throws Exception {
 		BranchBuilder bb = tr.branch("refs/heads/master");
 		RevCommit first = bb.commit().message("M").add("M", "M").create();
 		bb.commit().message("B").add("B", "Q").create();
@@ -146,6 +161,7 @@
 
 		gc.setExpireAgeMillis(0);
 		fsTick();
+		configureGc(gc, aggressive);
 		gc.gc();
 		stats = gc.getStatistics();
 		assertEquals(0, stats.numberOfLooseObjects);
@@ -159,4 +175,15 @@
 			assertEquals(9, pIt.next().getObjectCount());
 		}
 	}
+
+	private void configureGc(GC myGc, boolean aggressive) {
+		PackConfig pconfig = new PackConfig(repo);
+		if (aggressive) {
+			pconfig.setDeltaSearchWindowSize(250);
+			pconfig.setMaxDeltaDepth(250);
+			pconfig.setReuseObjects(false);
+		} else
+			pconfig = new PackConfig(repo);
+		myGc.setPackConfig(pconfig);
+	}
 }
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/StoredBitmapTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/StoredBitmapTest.java
index 0adf3e4..18c9ba5 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/StoredBitmapTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/StoredBitmapTest.java
@@ -43,14 +43,14 @@
 
 package org.eclipse.jgit.internal.storage.file;
 
-import static org.junit.Assert.*;
-
-import com.googlecode.javaewah.EWAHCompressedBitmap;
+import static org.junit.Assert.assertEquals;
 
 import org.eclipse.jgit.internal.storage.file.BasePackBitmapIndex.StoredBitmap;
 import org.eclipse.jgit.lib.ObjectId;
 import org.junit.Test;
 
+import com.googlecode.javaewah.EWAHCompressedBitmap;
+
 public class StoredBitmapTest {
 
 	@Test
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/DirCacheCheckoutTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/DirCacheCheckoutTest.java
index f7e6fa9..48debae 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/DirCacheCheckoutTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/DirCacheCheckoutTest.java
@@ -986,6 +986,38 @@
 	}
 
 	@Test
+	public void testOverwriteUntrackedIgnoredFile() throws IOException,
+			GitAPIException {
+		String fname="file.txt";
+		Git git = Git.wrap(db);
+
+		// Add a file
+		writeTrashFile(fname, "a");
+		git.add().addFilepattern(fname).call();
+		git.commit().setMessage("create file").call();
+
+		// Create branch
+		git.branchCreate().setName("side").call();
+
+		// Modify file
+		writeTrashFile(fname, "b");
+		git.add().addFilepattern(fname).call();
+		git.commit().setMessage("modify file").call();
+
+		// Switch branches
+		git.checkout().setName("side").call();
+		git.rm().addFilepattern(fname).call();
+		writeTrashFile(".gitignore", fname);
+		git.add().addFilepattern(".gitignore").call();
+		git.commit().setMessage("delete and ignore file").call();
+
+		writeTrashFile(fname, "Something different");
+		git.checkout().setName("master").call();
+		assertWorkDir(mkmap(fname, "b"));
+		assertTrue(git.status().call().isClean());
+	}
+
+	@Test
 	public void testFileModeChangeWithNoContentChangeUpdate() throws Exception {
 		if (!FS.DETECTED.supportsExecute())
 			return;
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/IndexDiffSubmoduleTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/IndexDiffSubmoduleTest.java
new file mode 100644
index 0000000..8003824
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/IndexDiffSubmoduleTest.java
@@ -0,0 +1,211 @@
+/*
+ * Copyright (C) 2014, 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.lib;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.io.File;
+import java.io.IOException;
+
+import org.eclipse.jgit.api.Git;
+import org.eclipse.jgit.api.errors.GitAPIException;
+import org.eclipse.jgit.errors.NoWorkTreeException;
+import org.eclipse.jgit.internal.storage.file.FileRepository;
+import org.eclipse.jgit.junit.JGitTestUtil;
+import org.eclipse.jgit.junit.RepositoryTestCase;
+import org.eclipse.jgit.submodule.SubmoduleWalk.IgnoreSubmoduleMode;
+import org.eclipse.jgit.treewalk.FileTreeIterator;
+import org.junit.Before;
+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 IndexDiffSubmoduleTest extends RepositoryTestCase {
+	/** a submodule repository inside a root repository */
+	protected FileRepository submodule_db;
+
+	/** Working directory of the submodule repository */
+	protected File submodule_trash;
+
+	@DataPoints
+	public static IgnoreSubmoduleMode allModes[] = IgnoreSubmoduleMode.values();
+
+	@Override
+	@Before
+	public void setUp() throws Exception {
+		super.setUp();
+		FileRepository submoduleStandalone = createWorkRepository();
+		JGitTestUtil.writeTrashFile(submoduleStandalone, "fileInSubmodule",
+				"submodule");
+		Git submoduleStandaloneGit = Git.wrap(submoduleStandalone);
+		submoduleStandaloneGit.add().addFilepattern("fileInSubmodule").call();
+		submoduleStandaloneGit.commit().setMessage("add file to submodule")
+				.call();
+
+		submodule_db = (FileRepository) Git.wrap(db).submoduleAdd()
+				.setPath("submodule")
+				.setURI(submoduleStandalone.getDirectory().toURI().toString())
+				.call();
+		submodule_trash = submodule_db.getWorkTree();
+		writeTrashFile("fileInRoot", "root");
+		Git rootGit = Git.wrap(db);
+		rootGit.add().addFilepattern("fileInRoot").call();
+		rootGit.commit().setMessage("add submodule and root file").call();
+	}
+
+	@Theory
+	public void testInitiallyClean(IgnoreSubmoduleMode mode)
+			throws IOException {
+		IndexDiff indexDiff = new IndexDiff(db, Constants.HEAD,
+				new FileTreeIterator(db));
+		indexDiff.setIgnoreSubmoduleMode(mode);
+		assertFalse(indexDiff.diff());
+	}
+
+	@Theory
+	public void testDirtyRootWorktree(IgnoreSubmoduleMode mode)
+			throws IOException {
+		writeTrashFile("fileInRoot", "2");
+
+		IndexDiff indexDiff = new IndexDiff(db, Constants.HEAD,
+				new FileTreeIterator(db));
+		indexDiff.setIgnoreSubmoduleMode(mode);
+		assertTrue(indexDiff.diff());
+	}
+
+	@Theory
+	public void testDirtySubmoduleWorktree(IgnoreSubmoduleMode mode)
+			throws IOException {
+		JGitTestUtil.writeTrashFile(submodule_db, "fileInSubmodule", "2");
+		IndexDiff indexDiff = new IndexDiff(db, Constants.HEAD,
+				new FileTreeIterator(db));
+		indexDiff.setIgnoreSubmoduleMode(mode);
+		if (mode.equals(IgnoreSubmoduleMode.ALL)
+				|| mode.equals(IgnoreSubmoduleMode.DIRTY))
+			assertFalse("diff should be false with mode=" + mode,
+					indexDiff.diff());
+		else
+			assertTrue("diff should be true with mode=" + mode,
+					indexDiff.diff());
+	}
+
+	@Theory
+	public void testDirtySubmoduleHEAD(IgnoreSubmoduleMode mode)
+			throws IOException, GitAPIException {
+		JGitTestUtil.writeTrashFile(submodule_db, "fileInSubmodule", "2");
+		Git submoduleGit = Git.wrap(submodule_db);
+		submoduleGit.add().addFilepattern("fileInSubmodule").call();
+		submoduleGit.commit().setMessage("Modified fileInSubmodule").call();
+
+		IndexDiff indexDiff = new IndexDiff(db, Constants.HEAD,
+				new FileTreeIterator(db));
+		indexDiff.setIgnoreSubmoduleMode(mode);
+		if (mode.equals(IgnoreSubmoduleMode.ALL))
+			assertFalse("diff should be false with mode=" + mode,
+					indexDiff.diff());
+		else
+			assertTrue("diff should be true with mode=" + mode,
+					indexDiff.diff());
+	}
+
+	@Theory
+	public void testDirtySubmoduleIndex(IgnoreSubmoduleMode mode)
+			throws IOException, GitAPIException {
+		JGitTestUtil.writeTrashFile(submodule_db, "fileInSubmodule", "2");
+		Git submoduleGit = Git.wrap(submodule_db);
+		submoduleGit.add().addFilepattern("fileInSubmodule").call();
+
+		IndexDiff indexDiff = new IndexDiff(db, Constants.HEAD,
+				new FileTreeIterator(db));
+		indexDiff.setIgnoreSubmoduleMode(mode);
+		if (mode.equals(IgnoreSubmoduleMode.ALL)
+				|| mode.equals(IgnoreSubmoduleMode.DIRTY))
+			assertFalse("diff should be false with mode=" + mode,
+					indexDiff.diff());
+		else
+			assertTrue("diff should be true with mode=" + mode,
+					indexDiff.diff());
+	}
+
+	@Theory
+	public void testDirtySubmoduleIndexAndWorktree(IgnoreSubmoduleMode mode)
+			throws IOException, GitAPIException, NoWorkTreeException {
+		JGitTestUtil.writeTrashFile(submodule_db, "fileInSubmodule", "2");
+		Git submoduleGit = Git.wrap(submodule_db);
+		submoduleGit.add().addFilepattern("fileInSubmodule").call();
+		JGitTestUtil.writeTrashFile(submodule_db, "fileInSubmodule", "3");
+
+		IndexDiff indexDiff = new IndexDiff(db, Constants.HEAD,
+				new FileTreeIterator(db));
+		indexDiff.setIgnoreSubmoduleMode(mode);
+		if (mode.equals(IgnoreSubmoduleMode.ALL)
+				|| mode.equals(IgnoreSubmoduleMode.DIRTY))
+			assertFalse("diff should be false with mode=" + mode,
+					indexDiff.diff());
+		else
+			assertTrue("diff should be true with mode=" + mode,
+					indexDiff.diff());
+	}
+
+	@Theory
+	public void testDirtySubmoduleWorktreeUntracked(IgnoreSubmoduleMode mode)
+			throws IOException {
+		JGitTestUtil.writeTrashFile(submodule_db, "additionalFileInSubmodule",
+				"2");
+		IndexDiff indexDiff = new IndexDiff(db, Constants.HEAD,
+				new FileTreeIterator(db));
+		indexDiff.setIgnoreSubmoduleMode(mode);
+		if (mode.equals(IgnoreSubmoduleMode.ALL)
+				|| mode.equals(IgnoreSubmoduleMode.DIRTY)
+				|| mode.equals(IgnoreSubmoduleMode.UNTRACKED))
+			assertFalse("diff should be false with mode=" + mode,
+					indexDiff.diff());
+		else
+			assertTrue("diff should be true with mode=" + mode,
+					indexDiff.diff());
+	}
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkShallowTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkShallowTest.java
index 3e45d2e..6df36e7 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkShallowTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkShallowTest.java
@@ -43,14 +43,14 @@
 
 package org.eclipse.jgit.revwalk;
 
+import static org.junit.Assert.assertNull;
+
 import java.io.File;
 import java.io.IOException;
 
 import org.eclipse.jgit.junit.JGitTestUtil;
-import org.eclipse.jgit.lib.*;
-import org.junit.*;
-
-import static org.junit.Assert.*;
+import org.eclipse.jgit.lib.ObjectId;
+import org.junit.Test;
 
 public class RevWalkShallowTest extends RevWalkTestCase {
 
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleWalkTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleWalkTest.java
index 383ff50..251938f 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleWalkTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleWalkTest.java
@@ -56,11 +56,15 @@
 import java.io.FileWriter;
 import java.io.IOException;
 
+import org.eclipse.jgit.api.Git;
+import org.eclipse.jgit.api.Status;
+import org.eclipse.jgit.api.errors.GitAPIException;
 import org.eclipse.jgit.dircache.DirCache;
 import org.eclipse.jgit.dircache.DirCacheEditor;
 import org.eclipse.jgit.dircache.DirCacheEditor.PathEdit;
 import org.eclipse.jgit.dircache.DirCacheEntry;
 import org.eclipse.jgit.errors.ConfigInvalidException;
+import org.eclipse.jgit.errors.NoWorkTreeException;
 import org.eclipse.jgit.junit.RepositoryTestCase;
 import org.eclipse.jgit.junit.TestRepository;
 import org.eclipse.jgit.lib.Config;
@@ -98,7 +102,7 @@
 
 	@Test
 	public void repositoryWithRootLevelSubmodule() throws IOException,
-			ConfigInvalidException {
+			ConfigInvalidException, NoWorkTreeException, GitAPIException {
 		final ObjectId id = ObjectId
 				.fromString("abcd1234abcd1234abcd1234abcd1234abcd1234");
 		final String path = "sub";
@@ -124,6 +128,8 @@
 		assertNull(gen.getModulesUpdate());
 		assertNull(gen.getModulesUrl());
 		assertNull(gen.getRepository());
+		Status status = Git.wrap(db).status().call();
+		assertTrue(!status.isClean());
 		assertFalse(gen.next());
 	}
 
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/BundleWriterTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/BundleWriterTest.java
index efc3834..24cee0a 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/BundleWriterTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/BundleWriterTest.java
@@ -73,20 +73,19 @@
 public class BundleWriterTest extends SampleDataRepositoryTestCase {
 
 	@Test
-	public void testWrite0() throws Exception {
+	public void testWriteSingleRef() throws Exception {
 		// Create a tiny bundle, (well one of) the first commits only
 		final byte[] bundle = makeBundle("refs/heads/firstcommit",
 				"42e4e7c5e507e113ebbb7801b16b52cf867b7ce1", null);
 
 		// Then we clone a new repo from that bundle and do a simple test. This
-		// makes sure
-		// we could read the bundle we created.
+		// makes sure we could read the bundle we created.
 		Repository newRepo = createBareRepository();
 		FetchResult fetchResult = fetchFromBundle(newRepo, bundle);
 		Ref advertisedRef = fetchResult
 				.getAdvertisedRef("refs/heads/firstcommit");
 
-		// We expect firstcommit to appear by id
+		// We expect first commit to appear by id
 		assertEquals("42e4e7c5e507e113ebbb7801b16b52cf867b7ce1", advertisedRef
 				.getObjectId().name());
 		// ..and by name as the bundle created a new ref
@@ -94,13 +93,21 @@
 				.resolve("refs/heads/firstcommit").name());
 	}
 
-	/**
-	 * Incremental bundle test
-	 *
-	 * @throws Exception
-	 */
 	@Test
-	public void testWrite1() throws Exception {
+	public void testWriteHEAD() throws Exception {
+		byte[] bundle = makeBundle("HEAD",
+				"42e4e7c5e507e113ebbb7801b16b52cf867b7ce1", null);
+
+		Repository newRepo = createBareRepository();
+		FetchResult fetchResult = fetchFromBundle(newRepo, bundle);
+		Ref advertisedRef = fetchResult.getAdvertisedRef("HEAD");
+
+		assertEquals("42e4e7c5e507e113ebbb7801b16b52cf867b7ce1", advertisedRef
+				.getObjectId().name());
+	}
+
+	@Test
+	public void testIncrementalBundle() throws Exception {
 		byte[] bundle;
 
 		// Create a small bundle, an early commit
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/FileTreeIteratorTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/FileTreeIteratorTest.java
index 51110b1..ab45790 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/FileTreeIteratorTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/FileTreeIteratorTest.java
@@ -145,6 +145,43 @@
 	}
 
 	@Test
+	public void testEmptyIteratorOnEmptyDirectory() throws Exception {
+		String nonExistingFileName = "not-existing-file";
+		final File r = new File(trash, nonExistingFileName);
+		assertFalse(r.exists());
+		FileUtils.mkdir(r);
+
+		final FileTreeIterator parent = new FileTreeIterator(db);
+
+		while (!parent.getEntryPathString().equals(nonExistingFileName))
+			parent.next(1);
+
+		final FileTreeIterator childIter = new FileTreeIterator(parent, r,
+				db.getFS());
+		assertTrue(childIter.first());
+		assertTrue(childIter.eof());
+
+		String parentPath = parent.getEntryPathString();
+		assertEquals(nonExistingFileName, parentPath);
+
+		// must be "not-existing-file/", but getEntryPathString() was broken by
+		// 445363 too
+		String childPath = childIter.getEntryPathString();
+
+		// in bug 445363 the iterator wrote garbage to the parent "path" field
+		EmptyTreeIterator e = childIter.createEmptyTreeIterator();
+		assertNotNull(e);
+
+		// check if parent path is not overridden by empty iterator (bug 445363)
+		// due bug 445363 this was "/ot-existing-file" instead of
+		// "not-existing-file"
+		assertEquals(parentPath, parent.getEntryPathString());
+		assertEquals(parentPath + "/", childPath);
+		assertEquals(parentPath + "/", childIter.getEntryPathString());
+		assertEquals(childPath + "/", e.getEntryPathString());
+	}
+
+	@Test
 	public void testSimpleIterate() throws Exception {
 		final FileTreeIterator top = new FileTreeIterator(trash, db.getFS(),
 				db.getConfig().get(WorkingTreeOptions.KEY));
diff --git a/org.eclipse.jgit.ui/META-INF/MANIFEST.MF b/org.eclipse.jgit.ui/META-INF/MANIFEST.MF
index 67f95f9..498fe10 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: 3.5.3.qualifier
+Bundle-Version: 3.6.0.qualifier
 Bundle-Vendor: %provider_name
 Bundle-RequiredExecutionEnvironment: J2SE-1.5
-Export-Package: org.eclipse.jgit.awtui;version="3.5.3"
-Import-Package: org.eclipse.jgit.errors;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.lib;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.nls;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.revplot;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.revwalk;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.transport;version="[3.5.3,3.6.0)",
- org.eclipse.jgit.util;version="[3.5.3,3.6.0)"
+Export-Package: org.eclipse.jgit.awtui;version="3.6.0"
+Import-Package: org.eclipse.jgit.errors;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.lib;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.nls;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.revplot;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.revwalk;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.transport;version="[3.6.0,3.7.0)",
+ org.eclipse.jgit.util;version="[3.6.0,3.7.0)"
diff --git a/org.eclipse.jgit.ui/pom.xml b/org.eclipse.jgit.ui/pom.xml
index 5715ede..4e98132 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>3.5.3-SNAPSHOT</version>
+    <version>3.6.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>org.eclipse.jgit.ui</artifactId>
diff --git a/org.eclipse.jgit/META-INF/MANIFEST.MF b/org.eclipse.jgit/META-INF/MANIFEST.MF
index 2139636..80399f6 100644
--- a/org.eclipse.jgit/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit/META-INF/MANIFEST.MF
@@ -2,10 +2,10 @@
 Bundle-ManifestVersion: 2
 Bundle-Name: %plugin_name
 Bundle-SymbolicName: org.eclipse.jgit
-Bundle-Version: 3.5.3.qualifier
+Bundle-Version: 3.6.0.qualifier
 Bundle-Localization: plugin
 Bundle-Vendor: %provider_name
-Export-Package: org.eclipse.jgit.api;version="3.5.3";
+Export-Package: org.eclipse.jgit.api;version="3.6.0";
   uses:="org.eclipse.jgit.revwalk,
    org.eclipse.jgit.treewalk.filter,
    org.eclipse.jgit.diff,
@@ -18,49 +18,50 @@
    org.eclipse.jgit.blame,
    org.eclipse.jgit.transport,
    org.eclipse.jgit.merge",
- org.eclipse.jgit.api.errors;version="3.5.3";
+ org.eclipse.jgit.api.errors;version="3.6.0";
   uses:="org.eclipse.jgit.lib,org.eclipse.jgit.errors",
- org.eclipse.jgit.blame;version="3.5.3";
+ org.eclipse.jgit.blame;version="3.6.0";
   uses:="org.eclipse.jgit.lib,
    org.eclipse.jgit.revwalk,
    org.eclipse.jgit.treewalk.filter,
    org.eclipse.jgit.diff",
- org.eclipse.jgit.diff;version="3.5.3";
+ org.eclipse.jgit.diff;version="3.6.0";
   uses:="org.eclipse.jgit.patch,
    org.eclipse.jgit.lib,
    org.eclipse.jgit.treewalk,
    org.eclipse.jgit.revwalk,
    org.eclipse.jgit.treewalk.filter,
    org.eclipse.jgit.util",
- org.eclipse.jgit.dircache;version="3.5.3";
+ org.eclipse.jgit.dircache;version="3.6.0";
   uses:="org.eclipse.jgit.lib,
    org.eclipse.jgit.treewalk,
    org.eclipse.jgit.util,
    org.eclipse.jgit.events",
- org.eclipse.jgit.errors;version="3.5.3";
+ org.eclipse.jgit.errors;version="3.6.0";
   uses:="org.eclipse.jgit.lib,
    org.eclipse.jgit.internal.storage.pack,
    org.eclipse.jgit.transport,
    org.eclipse.jgit.dircache",
- org.eclipse.jgit.events;version="3.5.3";
+ org.eclipse.jgit.events;version="3.6.0";
   uses:="org.eclipse.jgit.lib",
- org.eclipse.jgit.fnmatch;version="3.5.3",
- org.eclipse.jgit.gitrepo;version="3.5.3";
+ org.eclipse.jgit.fnmatch;version="3.6.0",
+ org.eclipse.jgit.gitrepo;version="3.6.0";
   uses:="org.eclipse.jgit.api,
    org.eclipse.jgit.lib",
- org.eclipse.jgit.gitrepo.internal;version="3.5.3";x-internal:=true,
- org.eclipse.jgit.ignore;version="3.5.3",
- org.eclipse.jgit.internal;version="3.5.3";x-friends:="org.eclipse.jgit.test,org.eclipse.jgit.http.test",
- org.eclipse.jgit.internal.storage.dfs;version="3.5.3";x-friends:="org.eclipse.jgit.test",
- org.eclipse.jgit.internal.storage.file;version="3.5.3";
+ org.eclipse.jgit.gitrepo.internal;version="3.6.0";x-internal:=true,
+ org.eclipse.jgit.ignore;version="3.6.0",
+ org.eclipse.jgit.ignore.internal;version="3.6.0";x-friends:="org.eclipse.jgit.test",
+ org.eclipse.jgit.internal;version="3.6.0";x-friends:="org.eclipse.jgit.test,org.eclipse.jgit.http.test",
+ org.eclipse.jgit.internal.storage.dfs;version="3.6.0";x-friends:="org.eclipse.jgit.test",
+ org.eclipse.jgit.internal.storage.file;version="3.6.0";
   x-friends:="org.eclipse.jgit.test,
    org.eclipse.jgit.junit,
    org.eclipse.jgit.junit.http,
    org.eclipse.jgit.http.server,
    org.eclipse.jgit.java7.test,
    org.eclipse.jgit.pgm",
- org.eclipse.jgit.internal.storage.pack;version="3.5.3";x-friends:="org.eclipse.jgit.junit,org.eclipse.jgit.test,org.eclipse.jgit.pgm",
- org.eclipse.jgit.lib;version="3.5.3";
+ org.eclipse.jgit.internal.storage.pack;version="3.6.0";x-friends:="org.eclipse.jgit.junit,org.eclipse.jgit.test,org.eclipse.jgit.pgm",
+ org.eclipse.jgit.lib;version="3.6.0";
   uses:="org.eclipse.jgit.revwalk,
    org.eclipse.jgit.treewalk.filter,
    org.eclipse.jgit.util,
@@ -69,37 +70,37 @@
    org.eclipse.jgit.internal.storage.file,
    org.eclipse.jgit.treewalk,
    org.eclipse.jgit.transport",
- org.eclipse.jgit.merge;version="3.5.3";
+ org.eclipse.jgit.merge;version="3.6.0";
   uses:="org.eclipse.jgit.lib,
    org.eclipse.jgit.treewalk,
    org.eclipse.jgit.revwalk,
    org.eclipse.jgit.diff,
    org.eclipse.jgit.dircache",
- org.eclipse.jgit.nls;version="3.5.3",
- org.eclipse.jgit.notes;version="3.5.3";
+ org.eclipse.jgit.nls;version="3.6.0",
+ org.eclipse.jgit.notes;version="3.6.0";
   uses:="org.eclipse.jgit.lib,
    org.eclipse.jgit.treewalk,
    org.eclipse.jgit.revwalk,
    org.eclipse.jgit.merge",
- org.eclipse.jgit.patch;version="3.5.3";
+ org.eclipse.jgit.patch;version="3.6.0";
   uses:="org.eclipse.jgit.lib,org.eclipse.jgit.diff",
- org.eclipse.jgit.revplot;version="3.5.3";
+ org.eclipse.jgit.revplot;version="3.6.0";
   uses:="org.eclipse.jgit.lib,org.eclipse.jgit.revwalk",
- org.eclipse.jgit.revwalk;version="3.5.3";
+ org.eclipse.jgit.revwalk;version="3.6.0";
   uses:="org.eclipse.jgit.lib,
    org.eclipse.jgit.treewalk,
    org.eclipse.jgit.treewalk.filter,
    org.eclipse.jgit.diff,
    org.eclipse.jgit.revwalk.filter",
- org.eclipse.jgit.revwalk.filter;version="3.5.3";
+ org.eclipse.jgit.revwalk.filter;version="3.6.0";
   uses:="org.eclipse.jgit.revwalk,org.eclipse.jgit.util",
- org.eclipse.jgit.storage.file;version="3.5.3";
+ org.eclipse.jgit.storage.file;version="3.6.0";
   uses:="org.eclipse.jgit.lib,org.eclipse.jgit.util",
- org.eclipse.jgit.storage.pack;version="3.5.3";
+ org.eclipse.jgit.storage.pack;version="3.6.0";
   uses:="org.eclipse.jgit.lib",
- org.eclipse.jgit.submodule;version="3.5.3";
+ org.eclipse.jgit.submodule;version="3.6.0";
   uses:="org.eclipse.jgit.lib,org.eclipse.jgit.treewalk,org.eclipse.jgit.treewalk.filter",
- org.eclipse.jgit.transport;version="3.5.3";
+ org.eclipse.jgit.transport;version="3.6.0";
   uses:="org.eclipse.jgit.transport.resolver,
    org.eclipse.jgit.revwalk,
    org.eclipse.jgit.internal.storage.pack,
@@ -111,21 +112,21 @@
    org.eclipse.jgit.transport.http,
    org.eclipse.jgit.errors,
    org.eclipse.jgit.storage.pack",
- org.eclipse.jgit.transport.http;version="3.5.3";
+ org.eclipse.jgit.transport.http;version="3.6.0";
   uses:="javax.net.ssl",
- org.eclipse.jgit.transport.resolver;version="3.5.3";
+ org.eclipse.jgit.transport.resolver;version="3.6.0";
   uses:="org.eclipse.jgit.lib,org.eclipse.jgit.transport",
- org.eclipse.jgit.treewalk;version="3.5.3";
+ org.eclipse.jgit.treewalk;version="3.6.0";
   uses:="org.eclipse.jgit.lib,
    org.eclipse.jgit.revwalk,
    org.eclipse.jgit.treewalk.filter,
    org.eclipse.jgit.util,
    org.eclipse.jgit.dircache",
- org.eclipse.jgit.treewalk.filter;version="3.5.3";
+ org.eclipse.jgit.treewalk.filter;version="3.6.0";
   uses:="org.eclipse.jgit.treewalk",
- org.eclipse.jgit.util;version="3.5.3";
+ org.eclipse.jgit.util;version="3.6.0";
   uses:="org.eclipse.jgit.lib,org.eclipse.jgit.transport.http,org.eclipse.jgit.storage.file",
- org.eclipse.jgit.util.io;version="3.5.3"
+ org.eclipse.jgit.util.io;version="3.6.0"
 Bundle-ActivationPolicy: lazy
 Bundle-RequiredExecutionEnvironment: J2SE-1.5
 Require-Bundle: com.jcraft.jsch;bundle-version="[0.1.37,0.2.0)"
diff --git a/org.eclipse.jgit/META-INF/SOURCE-MANIFEST.MF b/org.eclipse.jgit/META-INF/SOURCE-MANIFEST.MF
index 5fb5842..3954fc2 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: 3.5.3.qualifier
-Eclipse-SourceBundle: org.eclipse.jgit;version="3.5.3.qualifier";roots="."
+Bundle-Version: 3.6.0.qualifier
+Eclipse-SourceBundle: org.eclipse.jgit;version="3.6.0.qualifier";roots="."
diff --git a/org.eclipse.jgit/pom.xml b/org.eclipse.jgit/pom.xml
index d9387f2..33cd02d 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>3.5.3-SNAPSHOT</version>
+    <version>3.6.0-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 45021e8..524aa3e 100644
--- a/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties
+++ b/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties
@@ -500,6 +500,7 @@
 theFactoryMustNotBeNull=The factory must not be null
 timerAlreadyTerminated=Timer already terminated
 topologicalSortRequired=Topological sort required.
+transactionAborted=transaction aborted
 transportExceptionBadRef=Empty ref: {0}: {1}
 transportExceptionEmptyRef=Empty ref: {0}
 transportExceptionInvalid=Invalid {0} {1}:{2}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/DescribeCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/DescribeCommand.java
index 2ca8422..08e41e4 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/DescribeCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/DescribeCommand.java
@@ -42,17 +42,7 @@
  */
 package org.eclipse.jgit.api;
 
-import org.eclipse.jgit.api.errors.GitAPIException;
-import org.eclipse.jgit.api.errors.JGitInternalException;
-import org.eclipse.jgit.api.errors.RefNotFoundException;
-import org.eclipse.jgit.errors.IncorrectObjectTypeException;
-import org.eclipse.jgit.errors.MissingObjectException;
-import org.eclipse.jgit.internal.JGitText;
-import org.eclipse.jgit.lib.Constants;
-import org.eclipse.jgit.lib.ObjectId;
-import org.eclipse.jgit.lib.Ref;
-import org.eclipse.jgit.lib.Repository;
-import org.eclipse.jgit.revwalk.*;
+import static org.eclipse.jgit.lib.Constants.R_TAGS;
 
 import java.io.IOException;
 import java.text.MessageFormat;
@@ -63,7 +53,20 @@
 import java.util.List;
 import java.util.Map;
 
-import static org.eclipse.jgit.lib.Constants.R_TAGS;
+import org.eclipse.jgit.api.errors.GitAPIException;
+import org.eclipse.jgit.api.errors.JGitInternalException;
+import org.eclipse.jgit.api.errors.RefNotFoundException;
+import org.eclipse.jgit.errors.IncorrectObjectTypeException;
+import org.eclipse.jgit.errors.MissingObjectException;
+import org.eclipse.jgit.internal.JGitText;
+import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.Ref;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.revwalk.RevCommit;
+import org.eclipse.jgit.revwalk.RevFlag;
+import org.eclipse.jgit.revwalk.RevFlagSet;
+import org.eclipse.jgit.revwalk.RevWalk;
 
 /**
  * Given a commit, show the most recent tag that is reachable from a commit.
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/GarbageCollectCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/GarbageCollectCommand.java
index 77b84d3..2f7a3ed 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/GarbageCollectCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/GarbageCollectCommand.java
@@ -54,8 +54,11 @@
 import org.eclipse.jgit.internal.storage.file.FileRepository;
 import org.eclipse.jgit.internal.storage.file.GC;
 import org.eclipse.jgit.internal.storage.file.GC.RepoStatistics;
+import org.eclipse.jgit.lib.ConfigConstants;
 import org.eclipse.jgit.lib.ProgressMonitor;
 import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.lib.StoredConfig;
+import org.eclipse.jgit.storage.pack.PackConfig;
 import org.eclipse.jgit.util.GitDateParser;
 
 /**
@@ -63,17 +66,34 @@
  * supported options and arguments of this command and a {@link #call()} method
  * to finally execute the command. Each instance of this class should only be
  * used for one invocation of the command (means: one call to {@link #call()})
- * 
+ *
  * @since 2.2
  * @see <a href="http://www.kernel.org/pub/software/scm/git/docs/git-gc.html"
  *      >Git documentation about gc</a>
  */
 public class GarbageCollectCommand extends GitCommand<Properties> {
+	/**
+	 * Default value of maximum delta chain depth during aggressive garbage
+	 * collection: {@value}
+	 *
+	 * @since 3.6
+	 */
+	public static final int DEFAULT_GC_AGGRESSIVE_DEPTH = 250;
+
+	/**
+	 * Default window size during packing during aggressive garbage collection:
+	 * * {@value}
+	 *
+	 * @since 3.6
+	 */
+	public static final int DEFAULT_GC_AGGRESSIVE_WINDOW = 250;
 
 	private ProgressMonitor monitor;
 
 	private Date expire;
 
+	private PackConfig pconfig;
+
 	/**
 	 * @param repo
 	 */
@@ -82,6 +102,7 @@
 		if (!(repo instanceof FileRepository))
 			throw new UnsupportedOperationException(MessageFormat.format(
 					JGitText.get().unsupportedGC, repo.getClass().toString()));
+		pconfig = new PackConfig(repo);
 	}
 
 	/**
@@ -110,11 +131,41 @@
 		return this;
 	}
 
+	/**
+	 * Whether to use aggressive mode or not. If set to true JGit behaves more
+	 * similar to native git's "git gc --aggressive". If set to
+	 * <code>true</code> compressed objects found in old packs are not reused
+	 * but every object is compressed again. Configuration variables
+	 * pack.window and pack.depth are set to 250 for this GC.
+	 *
+	 * @since 3.6
+	 * @param aggressive
+	 *            whether to turn on or off aggressive mode
+	 * @return this instance
+	 */
+	public GarbageCollectCommand setAggressive(boolean aggressive) {
+		if (aggressive) {
+			StoredConfig repoConfig = repo.getConfig();
+			pconfig.setDeltaSearchWindowSize(repoConfig.getInt(
+					ConfigConstants.CONFIG_GC_SECTION,
+					ConfigConstants.CONFIG_KEY_AGGRESSIVE_WINDOW,
+					DEFAULT_GC_AGGRESSIVE_WINDOW));
+			pconfig.setMaxDeltaDepth(repoConfig.getInt(
+					ConfigConstants.CONFIG_GC_SECTION,
+					ConfigConstants.CONFIG_KEY_AGGRESSIVE_DEPTH,
+					DEFAULT_GC_AGGRESSIVE_DEPTH));
+			pconfig.setReuseObjects(false);
+		} else
+			pconfig = new PackConfig(repo);
+		return this;
+	}
+
 	@Override
 	public Properties call() throws GitAPIException {
 		checkCallable();
 
 		GC gc = new GC((FileRepository) repo);
+		gc.setPackConfig(pconfig);
 		gc.setProgressMonitor(monitor);
 		if (this.expire != null)
 			gc.setExpire(expire);
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 7cc682e..47424a9 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/RebaseCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/RebaseCommand.java
@@ -99,6 +99,7 @@
 import org.eclipse.jgit.revwalk.RevCommit;
 import org.eclipse.jgit.revwalk.RevWalk;
 import org.eclipse.jgit.revwalk.filter.RevFilter;
+import org.eclipse.jgit.submodule.SubmoduleWalk.IgnoreSubmoduleMode;
 import org.eclipse.jgit.treewalk.TreeWalk;
 import org.eclipse.jgit.treewalk.filter.TreeFilter;
 import org.eclipse.jgit.util.FileUtils;
@@ -294,7 +295,7 @@
 								walk.parseCommit(repo.resolve(Constants.HEAD)),
 								upstreamCommit)) {
 					org.eclipse.jgit.api.Status status = Git.wrap(repo)
-							.status().call();
+							.status().setIgnoreSubmodules(IgnoreSubmoduleMode.ALL).call();
 					if (status.hasUncommittedChanges()) {
 						List<String> list = new ArrayList<String>();
 						list.addAll(status.getUncommittedChanges());
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 7c2192d..17b1242 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/ResetCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/ResetCommand.java
@@ -195,6 +195,9 @@
 				result = repo.getRef(Constants.HEAD);
 			}
 
+			if (mode == null)
+				mode = ResetType.MIXED;
+
 			switch (mode) {
 				case HARD:
 					checkoutIndex(commitTree);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/StatusCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/StatusCommand.java
index dee0a31..9752195 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/StatusCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/StatusCommand.java
@@ -53,6 +53,7 @@
 import org.eclipse.jgit.lib.IndexDiff;
 import org.eclipse.jgit.lib.ProgressMonitor;
 import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.submodule.SubmoduleWalk.IgnoreSubmoduleMode;
 import org.eclipse.jgit.treewalk.FileTreeIterator;
 import org.eclipse.jgit.treewalk.WorkingTreeIterator;
 import org.eclipse.jgit.treewalk.filter.PathFilterGroup;
@@ -72,6 +73,8 @@
 	private List<String> paths = null;
 	private ProgressMonitor progressMonitor = null;
 
+	private IgnoreSubmoduleMode ignoreSubmoduleMode = null;
+
 	/**
 	 * @param repo
 	 */
@@ -80,6 +83,16 @@
 	}
 
 	/**
+	 * @param mode
+	 * @return {@code this}
+	 * @since 3.6
+	 */
+	public StatusCommand setIgnoreSubmodules(IgnoreSubmoduleMode mode) {
+		ignoreSubmoduleMode = mode;
+		return this;
+	}
+
+	/**
 	 * Show only the status of files which match the given paths. The path must
 	 * either name a file or a directory exactly. All paths are always relative
 	 * to the repository root. If a directory is specified all files recursively
@@ -127,6 +140,8 @@
 
 		try {
 			IndexDiff diff = new IndexDiff(repo, Constants.HEAD, workingTreeIt);
+			if (ignoreSubmoduleMode != null)
+				diff.setIgnoreSubmoduleMode(ignoreSubmoduleMode);
 			if (paths != null)
 				diff.setFilter(PathFilterGroup.createFromStrings(paths));
 			if (progressMonitor == null)
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 4b0d586..9f340c1 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java
@@ -698,7 +698,7 @@
 			// Nothing in Index
 			// At least one of Head, Index, Merge is not empty
 			// make sure not to overwrite untracked files
-			if (f != null) {
+			if (f != null && !f.isEntryIgnored()) {
 				// A submodule is not a file. We should ignore it
 				if (!FileMode.GITLINK.equals(mMode)) {
 					// a dirty worktree: the index is empty but we have a
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/ignore/FastIgnoreRule.java b/org.eclipse.jgit/src/org/eclipse/jgit/ignore/FastIgnoreRule.java
new file mode 100644
index 0000000..02863bd
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/ignore/FastIgnoreRule.java
@@ -0,0 +1,229 @@
+/*
+ * Copyright (C) 2014, Andrey Loskutov <loskutov@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.ignore;
+
+import static org.eclipse.jgit.ignore.internal.Strings.stripTrailing;
+
+import org.eclipse.jgit.errors.InvalidPatternException;
+import org.eclipse.jgit.ignore.internal.IMatcher;
+import org.eclipse.jgit.ignore.internal.PathMatcher;
+
+/**
+ * "Fast" (compared with IgnoreRule) git ignore rule implementation supporting
+ * also double star <code>**<code> pattern.
+ * <p>
+ * This class is immutable and thread safe.
+ *
+ * @since 3.6
+ */
+public class FastIgnoreRule {
+
+	/**
+	 * Character used as default path separator for ignore entries
+	 */
+	public static final char PATH_SEPARATOR = '/';
+
+	private static final NoResultMatcher NO_MATCH = new NoResultMatcher();
+
+	private final IMatcher matcher;
+
+	private final boolean inverse;
+
+	private final boolean dirOnly;
+
+	/**
+	 *
+	 * @param pattern
+	 *            ignore pattern as described in <a href=
+	 *            "https://www.kernel.org/pub/software/scm/git/docs/gitignore.html"
+	 *            >git manual</a>. If pattern is invalid or is not a pattern
+	 *            (comment), this rule doesn't match anything.
+	 */
+	public FastIgnoreRule(String pattern) {
+		if (pattern == null)
+			throw new IllegalArgumentException("Pattern must not be null!"); //$NON-NLS-1$
+		if (pattern.length() == 0) {
+			dirOnly = false;
+			inverse = false;
+			this.matcher = NO_MATCH;
+			return;
+		}
+		inverse = pattern.charAt(0) == '!';
+		if (inverse) {
+			pattern = pattern.substring(1);
+			if (pattern.length() == 0) {
+				dirOnly = false;
+				this.matcher = NO_MATCH;
+				return;
+			}
+		}
+		if (pattern.charAt(0) == '#') {
+			this.matcher = NO_MATCH;
+			dirOnly = false;
+		} else {
+			dirOnly = pattern.charAt(pattern.length() - 1) == PATH_SEPARATOR;
+			if (dirOnly) {
+				pattern = stripTrailing(pattern, PATH_SEPARATOR);
+				if (pattern.length() == 0) {
+					this.matcher = NO_MATCH;
+					return;
+				}
+			}
+			IMatcher m;
+			try {
+				m = PathMatcher.createPathMatcher(pattern,
+						Character.valueOf(PATH_SEPARATOR), dirOnly);
+			} catch (InvalidPatternException e) {
+				m = NO_MATCH;
+			}
+			this.matcher = m;
+		}
+	}
+
+	/**
+	 * Returns true if a match was made. <br>
+	 * This function does NOT return the actual ignore status of the target!
+	 * Please consult {@link #getResult()} for the negation status. The actual
+	 * ignore status may be true or false depending on whether this rule is an
+	 * ignore rule or a negation rule.
+	 *
+	 * @param path
+	 *            Name pattern of the file, relative to the base directory of
+	 *            this rule
+	 * @param directory
+	 *            Whether the target file is a directory or not
+	 * @return True if a match was made. This does not necessarily mean that the
+	 *         target is ignored. Call {@link #getResult() getResult()} for the
+	 *         result.
+	 */
+	public boolean isMatch(String path, boolean directory) {
+		if (path == null)
+			return false;
+		if (path.length() == 0)
+			return false;
+		boolean match = matcher.matches(path, directory);
+		return match;
+	}
+
+	/**
+	 * @return True if the pattern is just a file name and not a path
+	 */
+	public boolean getNameOnly() {
+		return !(matcher instanceof PathMatcher);
+	}
+
+	/**
+	 *
+	 * @return True if the pattern should match directories only
+	 */
+	public boolean dirOnly() {
+		return dirOnly;
+	}
+
+	/**
+	 * Indicates whether the rule is non-negation or negation.
+	 *
+	 * @return True if the pattern had a "!" in front of it
+	 */
+	public boolean getNegation() {
+		return inverse;
+	}
+
+	/**
+	 * Indicates whether the rule is non-negation or negation.
+	 *
+	 * @return True if the target is to be ignored, false otherwise.
+	 */
+	public boolean getResult() {
+		return !inverse;
+	}
+
+	@Override
+	public String toString() {
+		StringBuilder sb = new StringBuilder();
+		if (inverse)
+			sb.append('!');
+		sb.append(matcher);
+		if (dirOnly)
+			sb.append(PATH_SEPARATOR);
+		return sb.toString();
+
+	}
+
+	@Override
+	public int hashCode() {
+		final int prime = 31;
+		int result = 1;
+		result = prime * result + (inverse ? 1231 : 1237);
+		result = prime * result + (dirOnly ? 1231 : 1237);
+		result = prime * result + ((matcher == null) ? 0 : matcher.hashCode());
+		return result;
+	}
+
+	@Override
+	public boolean equals(Object obj) {
+		if (this == obj)
+			return true;
+		if (!(obj instanceof FastIgnoreRule))
+			return false;
+
+		FastIgnoreRule other = (FastIgnoreRule) obj;
+		if (inverse != other.inverse)
+			return false;
+		if (dirOnly != other.dirOnly)
+			return false;
+		return matcher.equals(other.matcher);
+	}
+
+	static final class NoResultMatcher implements IMatcher {
+
+		public boolean matches(String path, boolean assumeDirectory) {
+			return false;
+		}
+
+		public boolean matches(String segment, int startIncl, int endExcl,
+				boolean assumeDirectory) {
+			return false;
+		}
+	}
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/ignore/IgnoreNode.java b/org.eclipse.jgit/src/org/eclipse/jgit/ignore/IgnoreNode.java
index 2cddddb..ff74f7c 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/ignore/IgnoreNode.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/ignore/IgnoreNode.java
@@ -71,11 +71,11 @@
 	}
 
 	/** The rules that have been parsed into this node. */
-	private final List<IgnoreRule> rules;
+	private final List<FastIgnoreRule> rules;
 
 	/** Create an empty ignore node with no rules. */
 	public IgnoreNode() {
-		rules = new ArrayList<IgnoreRule>();
+		rules = new ArrayList<FastIgnoreRule>();
 	}
 
 	/**
@@ -84,7 +84,7 @@
 	 * @param rules
 	 *            list of rules.
 	 **/
-	public IgnoreNode(List<IgnoreRule> rules) {
+	public IgnoreNode(List<FastIgnoreRule> rules) {
 		this.rules = rules;
 	}
 
@@ -103,7 +103,7 @@
 		while ((txt = br.readLine()) != null) {
 			txt = txt.trim();
 			if (txt.length() > 0 && !txt.startsWith("#") && !txt.equals("/")) //$NON-NLS-1$ //$NON-NLS-2$
-				rules.add(new IgnoreRule(txt));
+				rules.add(new FastIgnoreRule(txt));
 		}
 	}
 
@@ -112,7 +112,7 @@
 	}
 
 	/** @return list of all ignore rules held by this node. */
-	public List<IgnoreRule> getRules() {
+	public List<FastIgnoreRule> getRules() {
 		return Collections.unmodifiableList(rules);
 	}
 
@@ -133,7 +133,7 @@
 
 		// Parse rules in the reverse order that they were read
 		for (int i = rules.size() - 1; i > -1; i--) {
-			IgnoreRule rule = rules.get(i);
+			FastIgnoreRule rule = rules.get(i);
 			if (rule.isMatch(entryPath, isDirectory)) {
 				if (rule.getResult())
 					return MatchResult.IGNORED;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/ignore/IgnoreRule.java b/org.eclipse.jgit/src/org/eclipse/jgit/ignore/IgnoreRule.java
index 42bbd9e..f14d1bd 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/ignore/IgnoreRule.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/ignore/IgnoreRule.java
@@ -46,11 +46,16 @@
 import org.eclipse.jgit.fnmatch.FileNameMatcher;
 
 /**
- * A single ignore rule corresponding to one line in a .gitignore or
- * ignore file. Parses the ignore pattern
+ * A single ignore rule corresponding to one line in a .gitignore or ignore
+ * file. Parses the ignore pattern
  *
  * Inspiration from: Ferry Huberts
+ *
+ * @deprecated this rule does not support double star pattern and is slow
+ *             parsing glob expressions. Consider to use {@link FastIgnoreRule}
+ *             instead. See https://bugs.eclipse.org/bugs/show_bug.cgi?id=440732
  */
+@Deprecated
 public class IgnoreRule {
 	private String pattern;
 	private boolean negation;
@@ -270,4 +275,4 @@
 	public String toString() {
 		return pattern;
 	}
-}
\ No newline at end of file
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/AbstractMatcher.java b/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/AbstractMatcher.java
new file mode 100644
index 0000000..4e90d8c
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/AbstractMatcher.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2014, Andrey Loskutov <loskutov@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.ignore.internal;
+
+/**
+ * Base class for default methods as {@link #toString()} and such.
+ * <p>
+ * This class is immutable and thread safe.
+ *
+ * @since 3.6
+ */
+public abstract class AbstractMatcher implements IMatcher {
+
+	final boolean dirOnly;
+
+	final String pattern;
+
+	/**
+	 * @param pattern
+	 *            string to parse
+	 * @param dirOnly
+	 *            true if this matcher should match only directories
+	 */
+	AbstractMatcher(String pattern, boolean dirOnly) {
+		this.pattern = pattern;
+		this.dirOnly = dirOnly;
+	}
+
+	@Override
+	public String toString() {
+		return pattern;
+	}
+
+	@Override
+	public int hashCode() {
+		return pattern.hashCode();
+	}
+
+	@Override
+	public boolean equals(Object obj) {
+		if (this == obj)
+			return true;
+		if (!(obj instanceof AbstractMatcher))
+			return false;
+		AbstractMatcher other = (AbstractMatcher) obj;
+		return dirOnly == other.dirOnly && pattern.equals(other.pattern);
+	}
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/IMatcher.java b/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/IMatcher.java
new file mode 100644
index 0000000..10b5e49
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/IMatcher.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2014, Andrey Loskutov <loskutov@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.ignore.internal;
+
+/**
+ * Generic string matcher
+ *
+ * @since 3.6
+ */
+public interface IMatcher {
+
+	/**
+	 * Matches entire given string
+	 *
+	 * @param path
+	 *            string which is not null, but might be empty
+	 * @param assumeDirectory
+	 *            true to assume this path as directory (even if it doesn't end
+	 *            with a slash)
+	 * @return true if this matcher pattern matches given string
+	 */
+	boolean matches(String path, boolean assumeDirectory);
+
+	/**
+	 * Matches only part of given string
+	 *
+	 * @param segment
+	 *            string which is not null, but might be empty
+	 * @param startIncl
+	 *            start index, inclusive
+	 * @param endExcl
+	 *            end index, exclusive
+	 * @param assumeDirectory
+	 *            true to assume this path as directory (even if it doesn't end
+	 *            with a slash)
+	 * @return true if this matcher pattern matches given string
+	 */
+	boolean matches(String segment, int startIncl, int endExcl,
+			boolean assumeDirectory);
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/NameMatcher.java b/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/NameMatcher.java
new file mode 100644
index 0000000..6c4c809
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/NameMatcher.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2014, Andrey Loskutov <loskutov@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.ignore.internal;
+
+import static org.eclipse.jgit.ignore.internal.Strings.getPathSeparator;
+
+/**
+ * Matcher built from patterns for file names (single path segments). This class
+ * is immutable and thread safe.
+ *
+ * @since 3.6
+ */
+public class NameMatcher extends AbstractMatcher {
+
+	final boolean beginning;
+
+	final char slash;
+
+	final String subPattern;
+
+	NameMatcher(String pattern, Character pathSeparator, boolean dirOnly) {
+		super(pattern, dirOnly);
+		slash = getPathSeparator(pathSeparator);
+		beginning = pattern.length() == 0 ? false : pattern.charAt(0) == slash;
+		if (!beginning)
+			this.subPattern = pattern;
+		else
+			this.subPattern = pattern.substring(1);
+	}
+
+	public boolean matches(String path, boolean assumeDirectory) {
+		int end = 0;
+		int firstChar = 0;
+		do {
+			firstChar = getFirstNotSlash(path, end);
+			end = getFirstSlash(path, firstChar);
+			boolean match = matches(path, firstChar, end, assumeDirectory);
+			if (match)
+				// make sure the directory matches: either if we are done with
+				// segment and there is next one, or if the directory is assumed
+				return !dirOnly ? true : (end > 0 && end != path.length())
+						|| assumeDirectory;
+		} while (!beginning && end != path.length());
+		return false;
+	}
+
+	public boolean matches(String segment, int startIncl, int endExcl,
+			boolean assumeDirectory) {
+		// faster local access, same as in string.indexOf()
+		String s = subPattern;
+		if (s.length() != (endExcl - startIncl))
+			return false;
+		for (int i = 0; i < s.length(); i++) {
+			char c1 = s.charAt(i);
+			char c2 = segment.charAt(i + startIncl);
+			if (c1 != c2)
+				return false;
+		}
+		return true;
+	}
+
+	private int getFirstNotSlash(String s, int start) {
+		int slashIdx = s.indexOf(slash, start);
+		return slashIdx == start ? start + 1 : start;
+	}
+
+	private int getFirstSlash(String s, int start) {
+		int slashIdx = s.indexOf(slash, start);
+		return slashIdx == -1 ? s.length() : slashIdx;
+	}
+
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/PathMatcher.java b/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/PathMatcher.java
new file mode 100644
index 0000000..830aab1
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/PathMatcher.java
@@ -0,0 +1,243 @@
+/*
+ * Copyright (C) 2014, Andrey Loskutov <loskutov@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.ignore.internal;
+
+import static org.eclipse.jgit.ignore.internal.Strings.count;
+import static org.eclipse.jgit.ignore.internal.Strings.getPathSeparator;
+import static org.eclipse.jgit.ignore.internal.Strings.isWildCard;
+import static org.eclipse.jgit.ignore.internal.Strings.split;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.jgit.errors.InvalidPatternException;
+import org.eclipse.jgit.ignore.FastIgnoreRule;
+
+/**
+ * Matcher built by patterns consists of multiple path segments.
+ * <p>
+ * This class is immutable and thread safe.
+ *
+ * @since 3.6
+ */
+public class PathMatcher extends AbstractMatcher {
+
+	private static final WildMatcher WILD = WildMatcher.INSTANCE;
+
+	private final List<IMatcher> matchers;
+
+	private final char slash;
+
+	private boolean beginning;
+
+	PathMatcher(String pattern, Character pathSeparator, boolean dirOnly)
+			throws InvalidPatternException {
+		super(pattern, dirOnly);
+		slash = getPathSeparator(pathSeparator);
+		beginning = pattern.indexOf(slash) == 0;
+		if (isSimplePathWithSegments(pattern))
+			matchers = null;
+		else
+			matchers = createMatchers(split(pattern, slash), pathSeparator,
+					dirOnly);
+	}
+
+	private boolean isSimplePathWithSegments(String path) {
+		return !isWildCard(path) && count(path, slash, true) > 0;
+	}
+
+	static private List<IMatcher> createMatchers(List<String> segments,
+			Character pathSeparator, boolean dirOnly)
+			throws InvalidPatternException {
+		List<IMatcher> matchers = new ArrayList<IMatcher>(segments.size());
+		for (int i = 0; i < segments.size(); i++) {
+			String segment = segments.get(i);
+			IMatcher matcher = createNameMatcher0(segment, pathSeparator,
+					dirOnly);
+			if (matcher == WILD && i > 0
+					&& matchers.get(matchers.size() - 1) == WILD)
+				// collapse wildmatchers **/** is same as **
+				continue;
+			matchers.add(matcher);
+		}
+		return matchers;
+	}
+
+	/**
+	 *
+	 * @param pattern
+	 * @param pathSeparator
+	 *            if this parameter isn't null then this character will not
+	 *            match at wildcards(* and ? are wildcards).
+	 * @param dirOnly
+	 * @return never null
+	 * @throws InvalidPatternException
+	 */
+	public static IMatcher createPathMatcher(String pattern,
+			Character pathSeparator, boolean dirOnly)
+			throws InvalidPatternException {
+		pattern = pattern.trim();
+		char slash = Strings.getPathSeparator(pathSeparator);
+		// ignore possible leading and trailing slash
+		int slashIdx = pattern.indexOf(slash, 1);
+		if (slashIdx > 0 && slashIdx < pattern.length() - 1)
+			return new PathMatcher(pattern, pathSeparator, dirOnly);
+		return createNameMatcher0(pattern, pathSeparator, dirOnly);
+	}
+
+	private static IMatcher createNameMatcher0(String segment,
+			Character pathSeparator, boolean dirOnly)
+			throws InvalidPatternException {
+		// check if we see /** or ** segments => double star pattern
+		if (WildMatcher.WILDMATCH.equals(segment)
+				|| WildMatcher.WILDMATCH2.equals(segment))
+			return WILD;
+		if (isWildCard(segment))
+			return new WildCardMatcher(segment, pathSeparator, dirOnly);
+		return new NameMatcher(segment, pathSeparator, dirOnly);
+	}
+
+	public boolean matches(String path, boolean assumeDirectory) {
+		if (matchers == null)
+			return simpleMatch(path, assumeDirectory);
+		return iterate(path, 0, path.length(), assumeDirectory);
+	}
+
+	/*
+	 * Stupid but fast string comparison: the case where we don't have to match
+	 * wildcards or single segments (mean: this is multi-segment path which must
+	 * be at the beginning of the another string)
+	 */
+	private boolean simpleMatch(String path, boolean assumeDirectory) {
+		boolean hasSlash = path.indexOf(slash) == 0;
+		if (beginning && !hasSlash)
+			path = slash + path;
+
+		if (!beginning && hasSlash)
+			path = path.substring(1);
+
+		if (path.equals(pattern))
+			// Exact match
+			if (dirOnly && !assumeDirectory)
+				// Directory expectations not met
+				return false;
+			else
+				// Directory expectations met
+				return true;
+
+		/*
+		 * Add slashes for startsWith check. This avoids matching e.g.
+		 * "/src/new" to /src/newfile" but allows "/src/new" to match
+		 * "/src/new/newfile", as is the git standard
+		 */
+		if (path.startsWith(pattern + FastIgnoreRule.PATH_SEPARATOR))
+			return true;
+
+		return false;
+	}
+
+	public boolean matches(String segment, int startIncl, int endExcl,
+			boolean assumeDirectory) {
+		throw new UnsupportedOperationException(
+				"Path matcher works only on entire paths"); //$NON-NLS-1$
+	}
+
+	boolean iterate(final String path, final int startIncl, final int endExcl,
+			boolean assumeDirectory) {
+		int matcher = 0;
+		int right = startIncl;
+		boolean match = false;
+		int lastWildmatch = -1;
+		while (true) {
+			int left = right;
+			right = path.indexOf(slash, right);
+			if (right == -1) {
+				if (left < endExcl)
+					match = matches(matcher, path, left, endExcl,
+							assumeDirectory);
+				if (match) {
+					if (matcher == matchers.size() - 2
+							&& matchers.get(matcher + 1) == WILD)
+						// ** can match *nothing*: a/b/** match also a/b
+						return true;
+					if (matcher < matchers.size() - 1
+							&& matchers.get(matcher) == WILD) {
+						// ** can match *nothing*: a/**/b match also a/b
+						matcher++;
+						match = matches(matcher, path, left, endExcl,
+								assumeDirectory);
+					} else if (dirOnly)
+						return false;
+				}
+				return match && matcher + 1 == matchers.size();
+			}
+			if (right - left > 0)
+				match = matches(matcher, path, left, right, assumeDirectory);
+			else {
+				// path starts with slash???
+				right++;
+				continue;
+			}
+			if (match) {
+				if (matchers.get(matcher) == WILD) {
+					lastWildmatch = matcher;
+					// ** can match *nothing*: a/**/b match also a/b
+					right = left - 1;
+				}
+				matcher++;
+				if (matcher == matchers.size())
+					return true;
+			} else if (lastWildmatch != -1)
+				matcher = lastWildmatch + 1;
+			else
+				return false;
+			right++;
+		}
+	}
+
+	boolean matches(int matcherIdx, String path, int startIncl, int endExcl,
+			boolean assumeDirectory) {
+		IMatcher matcher = matchers.get(matcherIdx);
+		return matcher.matches(path, startIncl, endExcl, assumeDirectory);
+	}
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/Strings.java b/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/Strings.java
new file mode 100644
index 0000000..c694a14
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/Strings.java
@@ -0,0 +1,375 @@
+/*
+ * Copyright (C) 2014, Andrey Loskutov <loskutov@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.ignore.internal;
+
+import static java.lang.Character.isLetter;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.regex.Pattern;
+
+import org.eclipse.jgit.errors.InvalidPatternException;
+import org.eclipse.jgit.ignore.FastIgnoreRule;
+
+/**
+ * Various {@link String} related utility methods, written mostly to avoid
+ * generation of new String objects (e.g. via splitting Strings etc).
+ *
+ * @since 3.6
+ */
+public class Strings {
+
+	static char getPathSeparator(Character pathSeparator) {
+		return pathSeparator == null ? FastIgnoreRule.PATH_SEPARATOR
+				: pathSeparator.charValue();
+	}
+
+	/**
+	 * @param pattern
+	 *            non null
+	 * @param c
+	 *            character to remove
+	 * @return new string with all trailing characters removed
+	 */
+	public static String stripTrailing(String pattern, char c) {
+		while (pattern.length() > 0
+				&& pattern.charAt(pattern.length() - 1) == c)
+			pattern = pattern.substring(0, pattern.length() - 1);
+		return pattern;
+	}
+
+	static int count(String s, char c, boolean ignoreFirstLast) {
+		int start = 0;
+		int count = 0;
+		while (true) {
+			start = s.indexOf(c, start);
+			if (start == -1)
+				break;
+			if (!ignoreFirstLast || (start != 0 && start != s.length()))
+				count++;
+			start++;
+		}
+		return count;
+	}
+
+	/**
+	 * Splits given string to substrings by given separator
+	 *
+	 * @param pattern
+	 *            non null
+	 * @param slash
+	 *            separator char
+	 * @return list of substrings
+	 */
+	public static List<String> split(String pattern, char slash) {
+		int count = count(pattern, slash, true);
+		if (count < 1)
+			throw new IllegalStateException(
+					"Pattern must have at least two segments: " + pattern); //$NON-NLS-1$
+		List<String> segments = new ArrayList<String>(count);
+		int right = 0;
+		while (true) {
+			int left = right;
+			right = pattern.indexOf(slash, right);
+			if (right == -1) {
+				if (left < pattern.length())
+					segments.add(pattern.substring(left));
+				break;
+			}
+			if (right - left > 0)
+				if (left == 1)
+					// leading slash should remain by the first pattern
+					segments.add(pattern.substring(left - 1, right));
+				else if (right == pattern.length() - 1)
+					// trailing slash should remain too
+					segments.add(pattern.substring(left, right + 1));
+				else
+					segments.add(pattern.substring(left, right));
+			right++;
+		}
+		return segments;
+	}
+
+	static boolean isWildCard(String pattern) {
+		return pattern.indexOf('*') != -1 || pattern.indexOf('?') != -1
+				|| pattern.indexOf('[') != -1
+				// required to match escaped backslashes '\\\\'
+				|| pattern.indexOf('\\') != -1 || pattern.indexOf(']') != -1;
+	}
+
+	final static List<String> POSIX_CHAR_CLASSES = Arrays.asList(
+			"alnum", "alpha", "blank", "cntrl", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
+			// [:alnum:] [:alpha:] [:blank:] [:cntrl:]
+			"digit", "graph", "lower", "print", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
+			// [:digit:] [:graph:] [:lower:] [:print:]
+			"punct", "space", "upper", "xdigit", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
+			// [:punct:] [:space:] [:upper:] [:xdigit:]
+			"word" //$NON-NLS-1$
+	// [:word:] XXX I don't see it in
+	// http://man7.org/linux/man-pages/man7/glob.7.html
+	// but this was in org.eclipse.jgit.fnmatch.GroupHead.java ???
+			);
+
+	private static final String DL = "\\p{javaDigit}\\p{javaLetter}"; //$NON-NLS-1$
+
+	final static List<String> JAVA_CHAR_CLASSES = Arrays
+			.asList("\\p{Alnum}", "\\p{javaLetter}", "\\p{Blank}", "\\p{Cntrl}", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
+					// [:alnum:] [:alpha:] [:blank:] [:cntrl:]
+					"\\p{javaDigit}", "[\\p{Graph}" + DL + "]", "\\p{Ll}", "[\\p{Print}" + DL + "]", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$
+					// [:digit:] [:graph:] [:lower:] [:print:]
+					"\\p{Punct}", "\\p{Space}", "\\p{Lu}", "\\p{XDigit}", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
+					// [:punct:] [:space:] [:upper:] [:xdigit:]
+					"[" + DL + "_]" //$NON-NLS-1$ //$NON-NLS-2$
+							// [:word:]
+			);
+
+	// Collating symbols [[.a.]] or equivalence class expressions [[=a=]] are
+	// not supported by CLI git (at least not by 1.9.1)
+	final static Pattern UNSUPPORTED = Pattern
+			.compile("\\[\\[[.=]\\w+[.=]\\]\\]"); //$NON-NLS-1$
+
+	/**
+	 * Conversion from glob to Java regex following two sources: <li>
+	 * http://man7.org/linux/man-pages/man7/glob.7.html <li>
+	 * org.eclipse.jgit.fnmatch.FileNameMatcher.java Seems that there are
+	 * various ways to define what "glob" can be.
+	 *
+	 * @param pattern
+	 *            non null pattern
+	 *
+	 * @return Java regex pattern corresponding to given glob pattern
+	 * @throws InvalidPatternException
+	 */
+	static Pattern convertGlob(String pattern) throws InvalidPatternException {
+		if (UNSUPPORTED.matcher(pattern).find())
+			throw new InvalidPatternException(
+					"Collating symbols [[.a.]] or equivalence class expressions [[=a=]] are not supported", //$NON-NLS-1$
+					pattern);
+
+		StringBuilder sb = new StringBuilder(pattern.length());
+
+		int in_brackets = 0;
+		boolean seenEscape = false;
+		boolean ignoreLastBracket = false;
+		boolean in_char_class = false;
+		// 6 is the length of the longest posix char class "xdigit"
+		char[] charClass = new char[6];
+
+		for (int i = 0; i < pattern.length(); i++) {
+			char c = pattern.charAt(i);
+			switch (c) {
+
+			case '*':
+				if (seenEscape || in_brackets > 0)
+					sb.append(c);
+				else
+					sb.append('.').append(c);
+				break;
+
+			case '.':
+				if (seenEscape)
+					sb.append(c);
+				else
+					sb.append('\\').append('.');
+				break;
+
+			case '?':
+				if (seenEscape || in_brackets > 0)
+					sb.append(c);
+				else
+					sb.append('.');
+				break;
+
+			case ':':
+				if (in_brackets > 0)
+					if (lookBehind(sb) == '['
+							&& isLetter(lookAhead(pattern, i)))
+						in_char_class = true;
+				sb.append(':');
+				break;
+
+			case '-':
+				if (in_brackets > 0) {
+					if (lookAhead(pattern, i) == ']')
+						sb.append('\\').append(c);
+					else
+						sb.append(c);
+				} else
+					sb.append('-');
+				break;
+
+			case '\\':
+				if (in_brackets > 0) {
+					char lookAhead = lookAhead(pattern, i);
+					if (lookAhead == ']' || lookAhead == '[')
+						ignoreLastBracket = true;
+				}
+				sb.append(c);
+				break;
+
+			case '[':
+				if (in_brackets > 0) {
+					sb.append('\\').append('[');
+					ignoreLastBracket = true;
+				} else {
+					if (!seenEscape) {
+						in_brackets++;
+						ignoreLastBracket = false;
+					}
+					sb.append('[');
+				}
+				break;
+
+			case ']':
+				if (seenEscape) {
+					sb.append(']');
+					ignoreLastBracket = true;
+					break;
+				}
+				if (in_brackets <= 0) {
+					sb.append('\\').append(']');
+					ignoreLastBracket = true;
+					break;
+				}
+				char lookBehind = lookBehind(sb);
+				if ((lookBehind == '[' && !ignoreLastBracket)
+						|| lookBehind == '^') {
+					sb.append('\\');
+					sb.append(']');
+					ignoreLastBracket = true;
+				} else {
+					ignoreLastBracket = false;
+					if (!in_char_class) {
+						in_brackets--;
+						sb.append(']');
+					} else {
+						in_char_class = false;
+						String charCl = checkPosixCharClass(charClass);
+						// delete last \[:: chars and set the pattern
+						if (charCl != null) {
+							sb.setLength(sb.length() - 4);
+							sb.append(charCl);
+						}
+						reset(charClass);
+					}
+				}
+				break;
+
+			case '!':
+				if (in_brackets > 0) {
+					if (lookBehind(sb) == '[')
+						sb.append('^');
+					else
+						sb.append(c);
+				} else
+					sb.append(c);
+				break;
+
+			default:
+				if (in_char_class)
+					setNext(charClass, c);
+				else
+					sb.append(c);
+				break;
+			} // end switch
+
+			seenEscape = c == '\\';
+
+		} // end for
+
+		if (in_brackets > 0)
+			throw new InvalidPatternException("Not closed bracket?", pattern); //$NON-NLS-1$
+		return Pattern.compile(sb.toString());
+	}
+
+	/**
+	 * @param buffer
+	 * @return zero of the buffer is empty, otherwise the last character from
+	 *         buffer
+	 */
+	private static char lookBehind(StringBuilder buffer) {
+		return buffer.length() > 0 ? buffer.charAt(buffer.length() - 1) : 0;
+	}
+
+	/**
+	 * @param pattern
+	 * @param i
+	 *            current pointer in the pattern
+	 * @return zero of the index is out of range, otherwise the next character
+	 *         from given position
+	 */
+	private static char lookAhead(String pattern, int i) {
+		int idx = i + 1;
+		return idx >= pattern.length() ? 0 : pattern.charAt(idx);
+	}
+
+	private static void setNext(char[] buffer, char c) {
+		for (int i = 0; i < buffer.length; i++)
+			if (buffer[i] == 0) {
+				buffer[i] = c;
+				break;
+			}
+	}
+
+	private static void reset(char[] buffer) {
+		for (int i = 0; i < buffer.length; i++)
+			buffer[i] = 0;
+	}
+
+	private static String checkPosixCharClass(char[] buffer) {
+		for (int i = 0; i < POSIX_CHAR_CLASSES.size(); i++) {
+			String clazz = POSIX_CHAR_CLASSES.get(i);
+			boolean match = true;
+			for (int j = 0; j < clazz.length(); j++)
+				if (buffer[j] != clazz.charAt(j)) {
+					match = false;
+					break;
+				}
+			if (match)
+				return JAVA_CHAR_CLASSES.get(i);
+		}
+		return null;
+	}
+
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/WildCardMatcher.java b/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/WildCardMatcher.java
new file mode 100644
index 0000000..7d12b0d
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/WildCardMatcher.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2014, Andrey Loskutov <loskutov@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.ignore.internal;
+
+import static org.eclipse.jgit.ignore.internal.Strings.convertGlob;
+
+import java.util.regex.Pattern;
+
+import org.eclipse.jgit.errors.InvalidPatternException;
+
+/**
+ * Matcher built from path segments containing wildcards. This matcher converts
+ * glob wildcards to Java {@link Pattern}'s.
+ * <p>
+ * This class is immutable and thread safe.
+ *
+ * @since 3.6
+ */
+public class WildCardMatcher extends NameMatcher {
+
+	final Pattern p;
+
+	WildCardMatcher(String pattern, Character pathSeparator, boolean dirOnly)
+			throws InvalidPatternException {
+		super(pattern, pathSeparator, dirOnly);
+		p = convertGlob(subPattern);
+	}
+
+	@Override
+	public boolean matches(String segment, int startIncl, int endExcl,
+			boolean assumeDirectory) {
+		return p.matcher(segment.substring(startIncl, endExcl)).matches();
+	}
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/WildMatcher.java b/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/WildMatcher.java
new file mode 100644
index 0000000..d578654
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/WildMatcher.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2014, Andrey Loskutov <loskutov@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.ignore.internal;
+
+/**
+ * Wildmatch matcher for "double star" (<code>**</code>) pattern only. This
+ * matcher matches any path.
+ * <p>
+ * This class is immutable and thread safe.
+ *
+ * @since 3.6
+ */
+public final class WildMatcher extends AbstractMatcher {
+
+	static final String WILDMATCH = "**"; //$NON-NLS-1$
+
+	// double star for the beginning of pattern
+	static final String WILDMATCH2 = "/**"; //$NON-NLS-1$
+
+	static final WildMatcher INSTANCE = new WildMatcher();
+
+	private WildMatcher() {
+		super(WILDMATCH, false);
+	}
+
+	public final boolean matches(String path, boolean assumeDirectory) {
+		return true;
+	}
+
+	public final boolean matches(String segment, int startIncl, int endExcl,
+			boolean assumeDirectory) {
+		return true;
+	}
+
+}
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 f2a1b94..dd1be0d 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java
@@ -556,6 +556,7 @@
 	/***/ public String tagAlreadyExists;
 	/***/ public String tagNameInvalid;
 	/***/ public String tagOnRepoWithoutHEADCurrentlyNotSupported;
+	/***/ public String transactionAborted;
 	/***/ public String theFactoryMustNotBeNull;
 	/***/ public String timerAlreadyTerminated;
 	/***/ public String topologicalSortRequired;
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 3cc4e7b..48335e4 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
@@ -93,6 +93,7 @@
 import org.eclipse.jgit.revwalk.ObjectWalk;
 import org.eclipse.jgit.revwalk.RevObject;
 import org.eclipse.jgit.revwalk.RevWalk;
+import org.eclipse.jgit.storage.pack.PackConfig;
 import org.eclipse.jgit.treewalk.TreeWalk;
 import org.eclipse.jgit.treewalk.filter.TreeFilter;
 import org.eclipse.jgit.util.FileUtils;
@@ -117,6 +118,8 @@
 
 	private Date expire;
 
+	private PackConfig pconfig = null;
+
 	/**
 	 * the refs which existed during the last call to {@link #repack()}. This is
 	 * needed during {@link #prune(Set)} where we can optimize by looking at the
@@ -686,7 +689,7 @@
 					}
 
 				});
-		PackWriter pw = new PackWriter(repo);
+		PackWriter pw = new PackWriter((pconfig == null) ? new PackConfig(repo) : pconfig, repo.newObjectReader());
 		try {
 			// prepare the PackWriter
 			pw.setDeltaBaseAsOffset(true);
@@ -948,6 +951,19 @@
 	}
 
 	/**
+	 * Set the PackConfig used when (re-)writing packfiles. This allows to
+	 * influence how packs are written and to implement something similar to
+	 * "git gc --aggressive"
+	 *
+	 * @since 3.6
+	 * @param pconfig
+	 *            the {@link PackConfig} used when writing packs
+	 */
+	public void setPackConfig(PackConfig pconfig) {
+		this.pconfig = pconfig;
+	}
+
+	/**
 	 * During gc() or prune() each unreferenced, loose object which has been
 	 * created or modified after or at <code>expire</code> will not be pruned.
 	 * Only older objects may be pruned. If set to null then every object is a
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectory.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectory.java
index 882f5c8..48a6b9d 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectory.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectory.java
@@ -72,6 +72,7 @@
 import org.eclipse.jgit.lib.AbbreviatedObjectId;
 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.ObjectDatabase;
 import org.eclipse.jgit.lib.ObjectId;
@@ -130,6 +131,14 @@
 
 	private Set<ObjectId> shallowCommitsIds;
 
+	// Whether to trust the pack folder's modification time. If set
+	// to false we will always scan the .git/objects/pack folder to
+	// check for new pack files. If set to true (default) we use the
+	// lastmodified attribute of the folder and assume that no new
+	// pack files can be in this folder if his modification time has
+	// not changed.
+	private boolean trustFolderStat = true;
+
 	/**
 	 * Initialize a reference to an on-disk object directory.
 	 *
@@ -152,6 +161,9 @@
 			File[] alternatePaths, FS fs, File shallowFile) throws IOException {
 		config = cfg;
 		objects = dir;
+		trustFolderStat = config.getBoolean(
+				ConfigConstants.CONFIG_CORE_SECTION,
+				ConfigConstants.CONFIG_KEY_TRUSTFOLDERSTAT, true);
 		infoDirectory = new File(objects, "info"); //$NON-NLS-1$
 		packDirectory = new File(objects, "pack"); //$NON-NLS-1$
 		alternatesFile = new File(infoDirectory, "alternates"); //$NON-NLS-1$
@@ -606,7 +618,8 @@
 	}
 
 	private boolean searchPacksAgain(PackList old) {
-		return old.snapshot.isModified(packDirectory) && old != scanPacks(old);
+		return ((!trustFolderStat) || old.snapshot.isModified(packDirectory))
+				&& old != scanPacks(old);
 	}
 
 	Config getConfig() {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackIndexV1.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackIndexV1.java
index 2d574d8..ab3297a 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackIndexV1.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackIndexV1.java
@@ -54,6 +54,7 @@
 import java.util.Set;
 
 import org.eclipse.jgit.errors.CorruptObjectException;
+import org.eclipse.jgit.internal.JGitText;
 import org.eclipse.jgit.lib.AbbreviatedObjectId;
 import org.eclipse.jgit.lib.AnyObjectId;
 import org.eclipse.jgit.lib.Constants;
@@ -88,7 +89,11 @@
 				n = (int) (idxHeader[k] - idxHeader[k - 1]);
 			}
 			if (n > 0) {
-				idxdata[k] = new byte[n * (Constants.OBJECT_ID_LENGTH + 4)];
+				final long len = n * (Constants.OBJECT_ID_LENGTH + 4);
+				if (len > Integer.MAX_VALUE - 8) // http://stackoverflow.com/a/8381338
+					throw new IOException(JGitText.get().indexFileIsTooLargeForJgit);
+
+				idxdata[k] = new byte[(int) len];
 				IO.readFully(fd, idxdata[k], 0, idxdata[k].length);
 			}
 		}
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 76e0b35..1649347 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
@@ -1029,43 +1029,44 @@
 		stats.totalObjects = objCnt;
 		beginPhase(PackingPhase.WRITING, writeMonitor, objCnt);
 		long writeStart = System.currentTimeMillis();
+		try {
+			out.writeFileHeader(PACK_VERSION_GENERATED, objCnt);
+			out.flush();
 
-		out.writeFileHeader(PACK_VERSION_GENERATED, objCnt);
-		out.flush();
+			writeObjects(out);
+			if (!edgeObjects.isEmpty() || !cachedPacks.isEmpty()) {
+				for (Statistics.ObjectType typeStat : stats.objectTypes) {
+					if (typeStat == null)
+						continue;
+					stats.thinPackBytes += typeStat.bytes;
+				}
+			}
 
-		writeObjects(out);
-		if (!edgeObjects.isEmpty() || !cachedPacks.isEmpty()) {
+			stats.reusedPacks = Collections.unmodifiableList(cachedPacks);
+			for (CachedPack pack : cachedPacks) {
+				long deltaCnt = pack.getDeltaCount();
+				stats.reusedObjects += pack.getObjectCount();
+				stats.reusedDeltas += deltaCnt;
+				stats.totalDeltas += deltaCnt;
+				reuseSupport.copyPackAsIs(out, pack, reuseValidate);
+			}
+			writeChecksum(out);
+			out.flush();
+		} finally {
+			stats.timeWriting = System.currentTimeMillis() - writeStart;
+			stats.depth = depth;
+
 			for (Statistics.ObjectType typeStat : stats.objectTypes) {
 				if (typeStat == null)
 					continue;
-				stats.thinPackBytes += typeStat.bytes;
+				typeStat.cntDeltas += typeStat.reusedDeltas;
+				stats.reusedObjects += typeStat.reusedObjects;
+				stats.reusedDeltas += typeStat.reusedDeltas;
+				stats.totalDeltas += typeStat.cntDeltas;
 			}
 		}
 
-		for (CachedPack pack : cachedPacks) {
-			long deltaCnt = pack.getDeltaCount();
-			stats.reusedObjects += pack.getObjectCount();
-			stats.reusedDeltas += deltaCnt;
-			stats.totalDeltas += deltaCnt;
-			reuseSupport.copyPackAsIs(out, pack, reuseValidate);
-		}
-		writeChecksum(out);
-		out.flush();
-		stats.timeWriting = System.currentTimeMillis() - writeStart;
 		stats.totalBytes = out.length();
-		stats.reusedPacks = Collections.unmodifiableList(cachedPacks);
-		stats.depth = depth;
-
-		for (Statistics.ObjectType typeStat : stats.objectTypes) {
-			if (typeStat == null)
-				continue;
-			typeStat.cntDeltas += typeStat.reusedDeltas;
-
-			stats.reusedObjects += typeStat.reusedObjects;
-			stats.reusedDeltas += typeStat.reusedDeltas;
-			stats.totalDeltas += typeStat.cntDeltas;
-		}
-
 		reader.release();
 		endPhase(writeMonitor);
 	}
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 378d91c..ccbfed7 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java
@@ -79,7 +79,6 @@
 
 	/**
 	 * The "rebase" section
-	 *
 	 * @since 3.2
 	 */
 	public static final String CONFIG_REBASE_SECTION = "rebase";
@@ -92,14 +91,12 @@
 
 	/**
 	 * The "fetch" section
-	 *
 	 * @since 3.3
 	 */
 	public static final String CONFIG_FETCH_SECTION = "fetch";
 
 	/**
 	 * The "pull" section
-	 *
 	 * @since 3.5
 	 */
 	public static final String CONFIG_PULL_SECTION = "pull";
@@ -139,7 +136,6 @@
 
 	/**
 	 * The "symlinks" key
-	 *
 	 * @since 3.3
 	 */
 	public static final String CONFIG_KEY_SYMLINKS = "symlinks";
@@ -167,7 +163,6 @@
 
 	/**
 	 * The "autostash" key
-	 *
 	 * @since 3.2
 	 */
 	public static final String CONFIG_KEY_AUTOSTASH = "autostash";
@@ -208,6 +203,12 @@
 	/** The "update" key */
 	public static final String CONFIG_KEY_UPDATE = "update";
 
+	/**
+	 * The "ignore" key
+	 * @since 3.6
+	 */
+	public static final String CONFIG_KEY_IGNORE = "ignore";
+
 	/** The "compression" key */
 	public static final String CONFIG_KEY_COMPRESSION = "compression";
 
@@ -226,6 +227,18 @@
 	/** The "pruneexpire" key */
 	public static final String CONFIG_KEY_PRUNEEXPIRE = "pruneexpire";
 
+	/**
+	 * The "aggressiveDepth" key
+	 * @since 3.6
+	 */
+	public static final String CONFIG_KEY_AGGRESSIVE_DEPTH = "aggressiveDepth";
+
+	/**
+	 * The "aggressiveWindow" key
+	 * @since 3.6
+	 */
+	public static final String CONFIG_KEY_AGGRESSIVE_WINDOW = "aggressiveWindow";
+
 	/** The "mergeoptions" key */
 	public static final String CONFIG_KEY_MERGEOPTIONS = "mergeoptions";
 
@@ -239,38 +252,43 @@
 	public static final String CONFIG_KEY_CHECKSTAT = "checkstat";
 
 	/**
-         * The "renamelimit" key in the "diff section"
-         * @since 3.0
-         */
+	 * The "renamelimit" key in the "diff section"
+	 * @since 3.0
+	 */
 	public static final String CONFIG_KEY_RENAMELIMIT = "renamelimit";
 
 	/**
-         * The "noprefix" key in the "diff section"
-         * @since 3.0
-         */
+	 * The "trustfolderstat" key in the "core section"
+	 * @since 3.6
+	 */
+	public static final String CONFIG_KEY_TRUSTFOLDERSTAT = "trustfolderstat";
+
+	/**
+	 * The "noprefix" key in the "diff section"
+	 * @since 3.0
+	 */
 	public static final String CONFIG_KEY_NOPREFIX = "noprefix";
 
 	/**
-         * A "renamelimit" value in the "diff section"
-         * @since 3.0
-         */
+	 * A "renamelimit" value in the "diff section"
+	 * @since 3.0
+	 */
 	public static final String CONFIG_RENAMELIMIT_COPY = "copy";
 
 	/**
-         * A "renamelimit" value in the "diff section"
-         * @since 3.0
-         */
+	 * A "renamelimit" value in the "diff section"
+	 * @since 3.0
+	 */
 	public static final String CONFIG_RENAMELIMIT_COPIES = "copies";
 
 	/**
-         * The "renames" key in the "diff section"
-         * @since 3.0
-         */
+	 * The "renames" key in the "diff section"
+	 * @since 3.0
+	 */
 	public static final String CONFIG_KEY_RENAMES = "renames";
 
 	/**
 	 * The "prune" key
-	 *
 	 * @since 3.3
 	 */
 	public static final String CONFIG_KEY_PRUNE = "prune";
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 8eb0333..d62b1f5 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/IndexDiff.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/IndexDiff.java
@@ -3,6 +3,7 @@
  * Copyright (C) 2007-2008, Robin Rosenberg <robin.rosenberg@dewire.com>
  * Copyright (C) 2010, Jens Baumgart <jens.baumgart@sap.com>
  * Copyright (C) 2013, Robin Stocker <robin@nibor.org>
+ * Copyright (C) 2014, Axel Richard <axel.richard@obeo.fr>
  * and other copyright owners as documented in the project's IP log.
  *
  * This program and the accompanying materials are made available
@@ -58,13 +59,17 @@
 import org.eclipse.jgit.dircache.DirCache;
 import org.eclipse.jgit.dircache.DirCacheEntry;
 import org.eclipse.jgit.dircache.DirCacheIterator;
+import org.eclipse.jgit.errors.ConfigInvalidException;
 import org.eclipse.jgit.errors.IncorrectObjectTypeException;
 import org.eclipse.jgit.errors.MissingObjectException;
 import org.eclipse.jgit.errors.StopWalkException;
 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;
 import org.eclipse.jgit.treewalk.AbstractTreeIterator;
 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.filter.AndTreeFilter;
@@ -227,7 +232,7 @@
 		@Override
 		public TreeFilter clone() {
 			throw new IllegalStateException(
-					"Do not clone this kind of filter: "
+					"Do not clone this kind of filter: " //$NON-NLS-1$
 							+ getClass().getName());
 		}
 	}
@@ -268,6 +273,12 @@
 
 	private IndexDiffFilter indexDiffFilter;
 
+	private Map<String, IndexDiff> submoduleIndexDiffs = new HashMap<String, IndexDiff>();
+
+	private IgnoreSubmoduleMode ignoreSubmoduleMode = null;
+
+	private Map<FileMode, Set<String>> fileModes = new HashMap<FileMode, Set<String>>();
+
 	/**
 	 * Construct an IndexDiff
 	 *
@@ -281,13 +292,7 @@
 	 */
 	public IndexDiff(Repository repository, String revstr,
 			WorkingTreeIterator workingTreeIterator) throws IOException {
-		this.repository = repository;
-		ObjectId objectId = repository.resolve(revstr);
-		if (objectId != null)
-			tree = new RevWalk(repository).parseTree(objectId);
-		else
-			tree = null;
-		this.initialWorkingTreeIterator = workingTreeIterator;
+		this(repository, repository.resolve(revstr), workingTreeIterator);
 	}
 
 	/**
@@ -311,6 +316,43 @@
 	}
 
 	/**
+	 * @param mode
+	 *            defines how modifications in submodules are treated
+	 * @since 3.6
+	 */
+	public void setIgnoreSubmoduleMode(IgnoreSubmoduleMode mode) {
+		this.ignoreSubmoduleMode = mode;
+	}
+
+	/**
+	 * A factory to producing WorkingTreeIterators
+	 * @since 3.6
+	 */
+	public interface WorkingTreeIteratorFactory {
+		/**
+		 * @param repo
+		 * @return a WorkingTreeIterator for repo
+		 */
+		public WorkingTreeIterator getWorkingTreeIterator(Repository repo);
+	}
+
+	private WorkingTreeIteratorFactory wTreeIt = new WorkingTreeIteratorFactory() {
+		public WorkingTreeIterator getWorkingTreeIterator(Repository repo) {
+			return new FileTreeIterator(repo);
+		}
+	};
+
+	/**
+	 * Allows higher layers to set the factory for WorkingTreeIterators.
+	 *
+	 * @param wTreeIt
+	 * @since 3.6
+	 */
+	public void setWorkingTreeItFactory(WorkingTreeIteratorFactory wTreeIt) {
+		this.wTreeIt = wTreeIt;
+	}
+
+	/**
 	 * Sets a filter. Can be used e.g. for restricting the tree walk to a set of
 	 * files.
 	 *
@@ -386,6 +428,7 @@
 		indexDiffFilter = new IndexDiffFilter(INDEX, WORKDIR);
 		filters.add(indexDiffFilter);
 		treeWalk.setFilter(AndTreeFilter.create(filters));
+		fileModes.clear();
 		while (treeWalk.next()) {
 			AbstractTreeIterator treeIterator = treeWalk.getTree(TREE,
 					AbstractTreeIterator.class);
@@ -413,18 +456,25 @@
 							|| treeIterator.getEntryRawMode()
 							!= dirCacheIterator.getEntryRawMode()) {
 						// in repo, in index, content diff => changed
-						changed.add(treeWalk.getPathString());
+						if (!isEntryGitLink(treeIterator)
+								|| !isEntryGitLink(dirCacheIterator)
+								|| ignoreSubmoduleMode != IgnoreSubmoduleMode.ALL)
+							changed.add(treeWalk.getPathString());
 					}
 				} else {
 					// in repo, not in index => removed
-					removed.add(treeWalk.getPathString());
+					if (!isEntryGitLink(treeIterator)
+							|| ignoreSubmoduleMode != IgnoreSubmoduleMode.ALL)
+						removed.add(treeWalk.getPathString());
 					if (workingTreeIterator != null)
 						untracked.add(treeWalk.getPathString());
 				}
 			} else {
 				if (dirCacheIterator != null) {
 					// not in repo, in index => added
-					added.add(treeWalk.getPathString());
+					if (!isEntryGitLink(dirCacheIterator)
+							|| ignoreSubmoduleMode != IgnoreSubmoduleMode.ALL)
+						added.add(treeWalk.getPathString());
 				} else {
 					// not in repo, not in index => untracked
 					if (workingTreeIterator != null
@@ -437,16 +487,78 @@
 			if (dirCacheIterator != null) {
 				if (workingTreeIterator == null) {
 					// in index, not in workdir => missing
-					missing.add(treeWalk.getPathString());
+					if (!isEntryGitLink(dirCacheIterator)
+							|| ignoreSubmoduleMode != IgnoreSubmoduleMode.ALL)
+						missing.add(treeWalk.getPathString());
 				} else {
 					if (workingTreeIterator.isModified(
 							dirCacheIterator.getDirCacheEntry(), true,
 							treeWalk.getObjectReader())) {
 						// in index, in workdir, content differs => modified
-						modified.add(treeWalk.getPathString());
+						if (!isEntryGitLink(dirCacheIterator) || !isEntryGitLink(workingTreeIterator)
+								|| (ignoreSubmoduleMode != IgnoreSubmoduleMode.ALL && ignoreSubmoduleMode != IgnoreSubmoduleMode.DIRTY))
+							modified.add(treeWalk.getPathString());
 					}
 				}
 			}
+
+			for (int i = 0; i < treeWalk.getTreeCount(); i++) {
+				Set<String> values = fileModes.get(treeWalk.getFileMode(i));
+				String path = treeWalk.getPathString();
+				if (path != null) {
+					if (values == null)
+						values = new HashSet<String>();
+					values.add(path);
+					fileModes.put(treeWalk.getFileMode(i), values);
+				}
+			}
+		}
+
+		if (ignoreSubmoduleMode != IgnoreSubmoduleMode.ALL) {
+			IgnoreSubmoduleMode localIgnoreSubmoduleMode = ignoreSubmoduleMode;
+			SubmoduleWalk smw = SubmoduleWalk.forIndex(repository);
+			while (smw.next()) {
+				try {
+					if (localIgnoreSubmoduleMode == null)
+						localIgnoreSubmoduleMode = smw.getModulesIgnore();
+					if (IgnoreSubmoduleMode.ALL
+							.equals(localIgnoreSubmoduleMode))
+						continue;
+				} catch (ConfigInvalidException e) {
+					IOException e1 = new IOException(
+							"Found invalid ignore param for submodule "
+									+ smw.getPath());
+					e1.initCause(e);
+					throw e1;
+				}
+				Repository subRepo = smw.getRepository();
+				if (subRepo != null) {
+					ObjectId subHead = subRepo.resolve("HEAD"); //$NON-NLS-1$
+					if (subHead != null && !subHead.equals(smw.getObjectId()))
+						modified.add(smw.getPath());
+					else if (ignoreSubmoduleMode != IgnoreSubmoduleMode.DIRTY) {
+						IndexDiff smid = submoduleIndexDiffs.get(smw.getPath());
+						if (smid == null) {
+							smid = new IndexDiff(subRepo, smw.getObjectId(),
+									wTreeIt.getWorkingTreeIterator(subRepo));
+							submoduleIndexDiffs.put(smw.getPath(), smid);
+						}
+						if (smid.diff()) {
+							if (ignoreSubmoduleMode == IgnoreSubmoduleMode.UNTRACKED
+									&& smid.getAdded().isEmpty()
+									&& smid.getChanged().isEmpty()
+									&& smid.getConflicting().isEmpty()
+									&& smid.getMissing().isEmpty()
+									&& smid.getModified().isEmpty()
+									&& smid.getRemoved().isEmpty()) {
+								continue;
+							}
+							modified.add(smw.getPath());
+						}
+					}
+				}
+			}
+
 		}
 
 		// consume the remaining work
@@ -462,6 +574,11 @@
 			return true;
 	}
 
+	private boolean isEntryGitLink(AbstractTreeIterator ti) {
+		return ((ti != null) && (ti.getEntryRawMode() == FileMode.GITLINK
+				.getBits()));
+	}
+
 	private void addConflict(String path, int stage) {
 		StageState existingStageStates = conflicts.get(path);
 		byte stageMask = 0;
@@ -578,4 +695,20 @@
 		final DirCacheEntry entry = dirCache.getEntry(path);
 		return entry != null ? entry.getFileMode() : FileMode.MISSING;
 	}
+
+	/**
+	 * Get the list of paths that IndexDiff has detected to differ and have the
+	 * given file mode
+	 *
+	 * @param mode
+	 * @return the list of paths that IndexDiff has detected to differ and have
+	 *         the given file mode
+	 * @since 3.6
+	 */
+	public Set<String> getPathsWithIndexMode(final FileMode mode) {
+		Set<String> paths = fileModes.get(mode);
+		if (paths == null)
+			paths = new HashSet<String>();
+		return paths;
+	}
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefDatabase.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefDatabase.java
index 682cac1..7fea880 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefDatabase.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefDatabase.java
@@ -197,6 +197,15 @@
 	}
 
 	/**
+	 * @return if the database performs {@code newBatchUpdate()} as an atomic
+	 *         transaction.
+	 * @since 3.6
+	 */
+	public boolean performsAtomicTransactions() {
+		return false;
+	}
+
+	/**
 	 * Read a single reference.
 	 * <p>
 	 * Aside from taking advantage of {@link #SEARCH_PATH}, this method may be
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevWalk.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevWalk.java
index 79cc42d..d19e467 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevWalk.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevWalk.java
@@ -174,6 +174,7 @@
 
 	private int delayFreeFlags;
 
+	private int retainOnReset;
 	int carryFlags = UNINTERESTING;
 
 	final ArrayList<RevCommit> roots;
@@ -1093,6 +1094,47 @@
 	}
 
 	/**
+	 * Preserve a RevFlag during all {@code reset} methods.
+	 * <p>
+	 * Calling {@code retainOnReset(flag)} avoids needing to pass the flag
+	 * during each {@code resetRetain()} invocation on this instance.
+	 * <p>
+	 * Clearing flags marked retainOnReset requires disposing of the flag with
+	 * {@code #disposeFlag(RevFlag)} or disposing of the entire RevWalk by
+	 * {@code #dispose()}.
+	 *
+	 * @param flag
+	 *            the flag to retain during all resets.
+	 * @since 3.6
+	 */
+	public final void retainOnReset(RevFlag flag) {
+		if ((freeFlags & flag.mask) != 0)
+			throw new IllegalArgumentException(MessageFormat.format(JGitText.get().flagIsDisposed, flag.name));
+		if (flag.walker != this)
+			throw new IllegalArgumentException(MessageFormat.format(JGitText.get().flagNotFromThis, flag.name));
+		retainOnReset |= flag.mask;
+	}
+
+	/**
+	 * Preserve a set of RevFlags during all {@code reset} methods.
+	 * <p>
+	 * Calling {@code retainOnReset(set)} avoids needing to pass the flags
+	 * during each {@code resetRetain()} invocation on this instance.
+	 * <p>
+	 * Clearing flags marked retainOnReset requires disposing of the flag with
+	 * {@code #disposeFlag(RevFlag)} or disposing of the entire RevWalk by
+	 * {@code #dispose()}.
+	 *
+	 * @param flags
+	 *            the flags to retain during all resets.
+	 * @since 3.6
+	 */
+	public final void retainOnReset(Collection<RevFlag> flags) {
+		for (RevFlag f : flags)
+			retainOnReset(f);
+	}
+
+	/**
 	 * Allow a flag to be recycled for a different use.
 	 * <p>
 	 * Recycled flags always come back as a different Java object instance when
@@ -1110,6 +1152,7 @@
 	}
 
 	void freeFlag(final int mask) {
+		retainOnReset &= ~mask;
 		if (isNotStarted()) {
 			freeFlags |= mask;
 			carryFlags &= ~mask;
@@ -1158,6 +1201,9 @@
 	 * Unlike {@link #dispose()} previously acquired RevObject (and RevCommit)
 	 * instances are not invalidated. RevFlag instances are not invalidated, but
 	 * are removed from all RevObjects.
+	 * <p>
+	 * See {@link #retainOnReset(RevFlag)} for an alternative that does not
+	 * require passing the flags during each reset.
 	 *
 	 * @param retainFlags
 	 *            application flags that should <b>not</b> be cleared from
@@ -1183,7 +1229,7 @@
 	 */
 	protected void reset(int retainFlags) {
 		finishDelayedFreeFlags();
-		retainFlags |= PARSED;
+		retainFlags |= PARSED | retainOnReset;
 		final int clearFlags = ~retainFlags;
 
 		final FIFORevQueue q = new FIFORevQueue();
@@ -1227,6 +1273,7 @@
 		reader.release();
 		freeFlags = APP_FLAGS;
 		delayFreeFlags = 0;
+		retainOnReset = 0;
 		carryFlags = UNINTERESTING;
 		objects.clear();
 		reader.release();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/submodule/SubmoduleWalk.java b/org.eclipse.jgit/src/org/eclipse/jgit/submodule/SubmoduleWalk.java
index c31ffd1..5db3378 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/submodule/SubmoduleWalk.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/submodule/SubmoduleWalk.java
@@ -79,6 +79,33 @@
 public class SubmoduleWalk {
 
 	/**
+	 * The values for the config param submodule.<name>.ignore
+	 *
+	 * @since 3.6
+	 */
+	public enum IgnoreSubmoduleMode {
+		/**
+		 * Ignore all modifications to submodules
+		 */
+		ALL,
+
+		/**
+		 * Ignore changes to the working tree of a submodule
+		 */
+		DIRTY,
+
+		/**
+		 * Ignore changes to untracked files in the working tree of a submodule
+		 */
+		UNTRACKED,
+
+		/**
+		 * Ignore nothing. That's the default
+		 */
+		NONE;
+	}
+
+	/**
 	 * Create a generator to walk over the submodule entries currently in the
 	 * index
 	 *
@@ -426,6 +453,29 @@
 		return this;
 	}
 
+	/**
+	 * Checks whether the working tree (or the index in case of a bare repo)
+	 * contains a .gitmodules file. That's a hint that the repo contains
+	 * submodules.
+	 *
+	 * @param repository
+	 *            the repository to check
+	 * @return <code>true</code> if the repo contains a .gitmodules file
+	 * @throws IOException
+	 * @throws CorruptObjectException
+	 * @since 3.6
+	 */
+	public static boolean containsGitModulesFile(Repository repository)
+			throws IOException {
+		if (repository.isBare()) {
+			DirCache dc = repository.readDirCache();
+			return (dc.findEntry(Constants.DOT_GIT_MODULES) >= 0);
+		}
+		File modulesFile = new File(repository.getWorkTree(),
+				Constants.DOT_GIT_MODULES);
+		return (modulesFile.exists());
+	}
+
 	private void lazyLoadModulesConfig() throws IOException, ConfigInvalidException {
 		if (modulesConfig == null)
 			loadModulesConfig();
@@ -600,6 +650,26 @@
 	}
 
 	/**
+	 * Get the configured ignore field for the current entry. This will be the
+	 * value from the .gitmodules file in the current repository's working tree.
+	 *
+	 * @return ignore value
+	 * @throws ConfigInvalidException
+	 * @throws IOException
+	 * @since 3.6
+	 */
+	public IgnoreSubmoduleMode getModulesIgnore() throws IOException,
+			ConfigInvalidException {
+		lazyLoadModulesConfig();
+		String name = modulesConfig.getString(
+				ConfigConstants.CONFIG_SUBMODULE_SECTION, path,
+				ConfigConstants.CONFIG_KEY_IGNORE);
+		if (name == null)
+			return null;
+		return IgnoreSubmoduleMode.valueOf(name.trim().toUpperCase());
+	}
+
+	/**
 	 * Get repository for current submodule entry
 	 *
 	 * @return repository or null if non-existent
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 72c1697..83d063e 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BaseReceivePack.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BaseReceivePack.java
@@ -43,6 +43,7 @@
 
 package org.eclipse.jgit.transport;
 
+import static org.eclipse.jgit.transport.GitProtocolConstants.CAPABILITY_ATOMIC;
 import static org.eclipse.jgit.transport.GitProtocolConstants.CAPABILITY_DELETE_REFS;
 import static org.eclipse.jgit.transport.GitProtocolConstants.CAPABILITY_OFS_DELTA;
 import static org.eclipse.jgit.transport.GitProtocolConstants.CAPABILITY_REPORT_STATUS;
@@ -908,6 +909,8 @@
 		adv.advertiseCapability(CAPABILITY_SIDE_BAND_64K);
 		adv.advertiseCapability(CAPABILITY_DELETE_REFS);
 		adv.advertiseCapability(CAPABILITY_REPORT_STATUS);
+		if (db.getRefDatabase().performsAtomicTransactions())
+			adv.advertiseCapability(CAPABILITY_ATOMIC);
 		if (allowOfsDelta)
 			adv.advertiseCapability(CAPABILITY_OFS_DELTA);
 		adv.send(getAdvertisedOrDefaultRefs());
@@ -1252,6 +1255,29 @@
 	}
 
 	/**
+	 * @return if any commands have been rejected so far.
+	 * @since 3.6
+	 */
+	protected boolean anyRejects() {
+		for (ReceiveCommand cmd : commands) {
+			if (cmd.getResult() != Result.NOT_ATTEMPTED && cmd.getResult() != Result.OK)
+				return true;
+		}
+		return false;
+	}
+
+	/**
+	 * Set the result to fail for any command that was not processed yet.
+	 * @since 3.6
+	 */
+	protected void failPendingCommands() {
+		for (ReceiveCommand cmd : commands) {
+			if (cmd.getResult() == Result.NOT_ATTEMPTED)
+				cmd.setResult(Result.REJECTED_OTHER_REASON, JGitText.get().transactionAborted);
+		}
+	}
+
+	/**
 	 * Filter the list of commands according to result.
 	 *
 	 * @param want
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BundleWriter.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BundleWriter.java
index 4f5cda7..d0f005c 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BundleWriter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BundleWriter.java
@@ -128,7 +128,8 @@
 	 *            object to pack. Multiple refs may point to the same object.
 	 */
 	public void include(final String name, final AnyObjectId id) {
-		if (!Repository.isValidRefName(name))
+		boolean validRefName = Repository.isValidRefName(name) || Constants.HEAD.equals(name);
+		if (!validRefName)
 			throw new IllegalArgumentException(MessageFormat.format(JGitText.get().invalidRefName, name));
 		if (include.containsKey(name))
 			throw new IllegalStateException(JGitText.get().duplicateRef + name);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/GitProtocolConstants.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/GitProtocolConstants.java
index c0a70d0..43fd079 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/GitProtocolConstants.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/GitProtocolConstants.java
@@ -130,6 +130,14 @@
 	public static final String OPTION_ALLOW_TIP_SHA1_IN_WANT = "allow-tip-sha1-in-want"; //$NON-NLS-1$
 
 	/**
+	 * The client supports atomic pushes. If this option is used, the server
+	 * will update all refs within one atomic transaction.
+	 *
+	 * @since 3.6
+	 */
+	public static final String CAPABILITY_ATOMIC = "atomic-push"; //$NON-NLS-1$
+
+	/**
 	 * The client expects a status report after the server processes the pack.
 	 *
 	 * @since 3.2
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 4d931dd..e5eb822 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceivePack.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceivePack.java
@@ -43,6 +43,7 @@
 
 package org.eclipse.jgit.transport;
 
+import static org.eclipse.jgit.transport.GitProtocolConstants.CAPABILITY_ATOMIC;
 import static org.eclipse.jgit.transport.GitProtocolConstants.CAPABILITY_REPORT_STATUS;
 
 import java.io.IOException;
@@ -199,8 +200,14 @@
 			}
 
 			if (unpackError == null) {
+				boolean atomic = isCapabilityEnabled(CAPABILITY_ATOMIC);
 				validateCommands();
+				if (atomic && anyRejects())
+					failPendingCommands();
+
 				preReceive.onPreReceive(this, filterCommands(Result.NOT_ATTEMPTED));
+				if (atomic && anyRejects())
+					failPendingCommands();
 				executeCommands();
 			}
 			unlockPack();
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 9eb4285..cc5ef18 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeIterator.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeIterator.java
@@ -70,8 +70,8 @@
 import org.eclipse.jgit.errors.CorruptObjectException;
 import org.eclipse.jgit.errors.MissingObjectException;
 import org.eclipse.jgit.errors.NoWorkTreeException;
+import org.eclipse.jgit.ignore.FastIgnoreRule;
 import org.eclipse.jgit.ignore.IgnoreNode;
-import org.eclipse.jgit.ignore.IgnoreRule;
 import org.eclipse.jgit.internal.JGitText;
 import org.eclipse.jgit.lib.Constants;
 import org.eclipse.jgit.lib.CoreConfig;
@@ -668,6 +668,8 @@
 		ptr = 0;
 		if (!eof())
 			parseEntry();
+		else if (pathLen == 0) // see bug 445363
+			pathLen = pathOffset;
 	}
 
 	/**
@@ -1130,7 +1132,7 @@
 		final Entry entry;
 
 		PerDirectoryIgnoreNode(Entry entry) {
-			super(Collections.<IgnoreRule> emptyList());
+			super(Collections.<FastIgnoreRule> emptyList());
 			this.entry = entry;
 		}
 
diff --git a/pom.xml b/pom.xml
index 7c93674..c9fe147 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>3.5.3-SNAPSHOT</version>
+  <version>3.6.0-SNAPSHOT</version>
 
   <name>JGit - Parent</name>
   <url>${jgit-url}</url>
@@ -176,7 +176,7 @@
     <maven.build.timestamp.format>yyyyMMddHHmm</maven.build.timestamp.format>
     <bundle-manifest>${project.build.directory}/META-INF/MANIFEST.MF</bundle-manifest>
 
-    <jgit-last-release-version>3.4.1.201406201815-r</jgit-last-release-version>
+    <jgit-last-release-version>v3.5.0.201409260305-r</jgit-last-release-version>
     <jsch-version>0.1.50</jsch-version>
     <javaewah-version>0.7.9</javaewah-version>
     <junit-version>4.11</junit-version>
@@ -199,9 +199,8 @@
   <repositories>
     <repository>
       <id>jgit-repository</id>
-      <url>http://download.eclipse.org/jgit/maven</url>
+      <url>https://repo.eclipse.org/content/repositories/jgit-releases/</url>
     </repository>
-
   </repositories>
 
   <pluginRepositories>