diff options
64 files changed, 1848 insertions, 361 deletions
@@ -118,8 +118,6 @@ There are some missing features: - gitattributes support -- Recursive merge strategy - Support ------- diff --git a/org.eclipse.jgit.ant.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.ant.test/META-INF/MANIFEST.MF index 4c955b01a5..0f08a05a07 100644 --- a/org.eclipse.jgit.ant.test/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.ant.test/META-INF/MANIFEST.MF @@ -3,15 +3,15 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %plugin_name Bundle-SymbolicName: org.eclipse.jgit.ant.test -Bundle-Version: 2.3.0.qualifier +Bundle-Version: 2.4.0.qualifier Bundle-ActivationPolicy: lazy Bundle-RequiredExecutionEnvironment: J2SE-1.5 Import-Package: org.apache.tools.ant, org.apache.tools.ant.types, - org.eclipse.jgit.ant.tasks;version="2.3.0", + org.eclipse.jgit.ant.tasks;version="2.4.0", org.eclipse.jgit.junit, - org.eclipse.jgit.lib;version="2.3.0", - org.eclipse.jgit.storage.file;version="2.3.0", - org.eclipse.jgit.util;version="2.3.0", + org.eclipse.jgit.lib;version="2.4.0", + org.eclipse.jgit.storage.file;version="2.4.0", + org.eclipse.jgit.util;version="2.4.0", org.hamcrest;version="1.1.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 42a26c4a33..fc80e7f2f0 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>2.3.0-SNAPSHOT</version> + <version>2.4.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 e1ac42ff60..52e8551c35 100644 --- a/org.eclipse.jgit.ant/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.ant/META-INF/MANIFEST.MF @@ -2,9 +2,9 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %Bundle-Name Bundle-SymbolicName: org.eclipse.jgit.ant -Bundle-Version: 2.3.0.qualifier +Bundle-Version: 2.4.0.qualifier Bundle-RequiredExecutionEnvironment: J2SE-1.5 Import-Package: org.apache.tools.ant Bundle-Localization: plugin Bundle-Vendor: %Provider-Name -Export-Package: org.eclipse.jgit.ant.tasks;version="2.3.0" +Export-Package: org.eclipse.jgit.ant.tasks;version="2.4.0" diff --git a/org.eclipse.jgit.ant/pom.xml b/org.eclipse.jgit.ant/pom.xml index 3a959846b7..43555c57f3 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>2.3.0-SNAPSHOT</version> + <version>2.4.0-SNAPSHOT</version> </parent> <artifactId>org.eclipse.jgit.ant</artifactId> diff --git a/org.eclipse.jgit.console/META-INF/MANIFEST.MF b/org.eclipse.jgit.console/META-INF/MANIFEST.MF index 775f0fd5e5..d30dd2d382 100644 --- a/org.eclipse.jgit.console/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.console/META-INF/MANIFEST.MF @@ -3,12 +3,12 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %plugin_name Bundle-SymbolicName: org.eclipse.jgit.console -Bundle-Version: 2.3.0.qualifier +Bundle-Version: 2.4.0.qualifier Bundle-Vendor: %provider_name Bundle-RequiredExecutionEnvironment: JavaSE-1.6 -Export-Package: org.eclipse.jgit.console;version="2.3.0" -Import-Package: org.eclipse.jgit.errors;version="[2.3.0,2.4.0)", - org.eclipse.jgit.nls;version="[2.3.0,2.4.0)", - org.eclipse.jgit.transport;version="[2.3.0,2.4.0)", - org.eclipse.jgit.util;version="[2.3.0,2.4.0)" +Export-Package: org.eclipse.jgit.console;version="2.4.0" +Import-Package: org.eclipse.jgit.errors;version="[2.4.0,2.5.0)", + org.eclipse.jgit.nls;version="[2.4.0,2.5.0)", + org.eclipse.jgit.transport;version="[2.4.0,2.5.0)", + org.eclipse.jgit.util;version="[2.4.0,2.5.0)" Require-Bundle: com.jcraft.jsch;bundle-version="[0.1.37,0.2.0)" diff --git a/org.eclipse.jgit.console/pom.xml b/org.eclipse.jgit.console/pom.xml index de5854f5e3..3d8163625d 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>2.3.0-SNAPSHOT</version> + <version>2.4.0-SNAPSHOT</version> </parent> <artifactId>org.eclipse.jgit.console</artifactId> diff --git a/org.eclipse.jgit.http.server/META-INF/MANIFEST.MF b/org.eclipse.jgit.http.server/META-INF/MANIFEST.MF index 074c7badc0..42028d7f88 100644 --- a/org.eclipse.jgit.http.server/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.http.server/META-INF/MANIFEST.MF @@ -2,23 +2,23 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %plugin_name Bundle-SymbolicName: org.eclipse.jgit.http.server -Bundle-Version: 2.3.0.qualifier +Bundle-Version: 2.4.0.qualifier Bundle-Localization: plugin Bundle-Vendor: %provider_name Export-Package: - org.eclipse.jgit.http.server;version="2.3.0", - org.eclipse.jgit.http.server.glue;version="2.3.0", - org.eclipse.jgit.http.server.resolver;version="2.3.0" + org.eclipse.jgit.http.server;version="2.4.0", + org.eclipse.jgit.http.server.glue;version="2.4.0", + org.eclipse.jgit.http.server.resolver;version="2.4.0" Bundle-ActivationPolicy: lazy 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="[2.3.0,2.4.0)", - org.eclipse.jgit.lib;version="[2.3.0,2.4.0)", - org.eclipse.jgit.nls;version="[2.3.0,2.4.0)", - org.eclipse.jgit.revwalk;version="[2.3.0,2.4.0)", - org.eclipse.jgit.storage.file;version="[2.3.0,2.4.0)", - org.eclipse.jgit.transport;version="[2.3.0,2.4.0)", - org.eclipse.jgit.transport.resolver;version="[2.3.0,2.4.0)", - org.eclipse.jgit.util;version="[2.3.0,2.4.0)", - org.eclipse.jgit.util.io;version="[2.3.0,2.4.0)" + org.eclipse.jgit.errors;version="[2.4.0,2.5.0)", + org.eclipse.jgit.lib;version="[2.4.0,2.5.0)", + org.eclipse.jgit.nls;version="[2.4.0,2.5.0)", + org.eclipse.jgit.revwalk;version="[2.4.0,2.5.0)", + org.eclipse.jgit.storage.file;version="[2.4.0,2.5.0)", + org.eclipse.jgit.transport;version="[2.4.0,2.5.0)", + org.eclipse.jgit.transport.resolver;version="[2.4.0,2.5.0)", + org.eclipse.jgit.util;version="[2.4.0,2.5.0)", + org.eclipse.jgit.util.io;version="[2.4.0,2.5.0)" diff --git a/org.eclipse.jgit.http.server/pom.xml b/org.eclipse.jgit.http.server/pom.xml index 34b6264357..9597c31abc 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>2.3.0-SNAPSHOT</version> + <version>2.4.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 bf1328ec0a..67a3dce332 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 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %plugin_name Bundle-SymbolicName: org.eclipse.jgit.http.test -Bundle-Version: 2.3.0.qualifier +Bundle-Version: 2.4.0.qualifier Bundle-Vendor: %provider_name Bundle-Localization: plugin Bundle-RequiredExecutionEnvironment: J2SE-1.5 @@ -22,19 +22,19 @@ Import-Package: javax.servlet;version="[2.5.0,3.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.jetty.util.thread;version="[7.6.0,8.0.0)", - org.eclipse.jgit.errors;version="[2.3.0,2.4.0)", - org.eclipse.jgit.http.server;version="[2.3.0,2.4.0)", - org.eclipse.jgit.http.server.glue;version="[2.3.0,2.4.0)", - org.eclipse.jgit.http.server.resolver;version="[2.3.0,2.4.0)", - org.eclipse.jgit.internal;version="[2.3.0,2.4.0)", - org.eclipse.jgit.junit;version="[2.3.0,2.4.0)", - org.eclipse.jgit.junit.http;version="[2.3.0,2.4.0)", - org.eclipse.jgit.lib;version="[2.3.0,2.4.0)", - org.eclipse.jgit.nls;version="[2.3.0,2.4.0)", - org.eclipse.jgit.revwalk;version="[2.3.0,2.4.0)", - org.eclipse.jgit.storage.file;version="[2.3.0,2.4.0)", - org.eclipse.jgit.transport;version="[2.3.0,2.4.0)", - org.eclipse.jgit.transport.resolver;version="[2.3.0,2.4.0)", - org.eclipse.jgit.util;version="[2.3.0,2.4.0)", + org.eclipse.jgit.errors;version="[2.4.0,2.5.0)", + org.eclipse.jgit.http.server;version="[2.4.0,2.5.0)", + org.eclipse.jgit.http.server.glue;version="[2.4.0,2.5.0)", + org.eclipse.jgit.http.server.resolver;version="[2.4.0,2.5.0)", + org.eclipse.jgit.internal;version="[2.4.0,2.5.0)", + org.eclipse.jgit.junit;version="[2.4.0,2.5.0)", + org.eclipse.jgit.junit.http;version="[2.4.0,2.5.0)", + org.eclipse.jgit.lib;version="[2.4.0,2.5.0)", + org.eclipse.jgit.nls;version="[2.4.0,2.5.0)", + org.eclipse.jgit.revwalk;version="[2.4.0,2.5.0)", + org.eclipse.jgit.storage.file;version="[2.4.0,2.5.0)", + org.eclipse.jgit.transport;version="[2.4.0,2.5.0)", + org.eclipse.jgit.transport.resolver;version="[2.4.0,2.5.0)", + org.eclipse.jgit.util;version="[2.4.0,2.5.0)", org.hamcrest.core;version="[1.1.0,2.0.0)", org.junit;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 0b5e0cd533..febfc4f1d1 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>2.3.0-SNAPSHOT</version> + <version>2.4.0-SNAPSHOT</version> </parent> <artifactId>org.eclipse.jgit.http.test</artifactId> diff --git a/org.eclipse.jgit.junit.http/META-INF/MANIFEST.MF b/org.eclipse.jgit.junit.http/META-INF/MANIFEST.MF index 43f5819fc6..e3cf724260 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 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %plugin_name Bundle-SymbolicName: org.eclipse.jgit.junit.http -Bundle-Version: 2.3.0.qualifier +Bundle-Version: 2.4.0.qualifier Bundle-Localization: plugin Bundle-Vendor: %provider_name Bundle-ActivationPolicy: lazy @@ -22,14 +22,14 @@ Import-Package: javax.servlet;version="[2.5.0,3.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.jetty.util.thread;version="[7.6.0,8.0.0)", - org.eclipse.jgit.errors;version="[2.3.0,2.4.0)", - org.eclipse.jgit.http.server;version="[2.3.0,2.4.0)", - org.eclipse.jgit.http.server.resolver;version="[2.3.0,2.4.0)", - org.eclipse.jgit.junit;version="[2.3.0,2.4.0)", - org.eclipse.jgit.lib;version="[2.3.0,2.4.0)", - org.eclipse.jgit.revwalk;version="[2.3.0,2.4.0)", - org.eclipse.jgit.storage.file;version="[2.3.0,2.4.0)", - org.eclipse.jgit.transport;version="[2.3.0,2.4.0)", - org.eclipse.jgit.transport.resolver;version="[2.3.0,2.4.0)", + org.eclipse.jgit.errors;version="[2.4.0,2.5.0)", + org.eclipse.jgit.http.server;version="[2.4.0,2.5.0)", + org.eclipse.jgit.http.server.resolver;version="[2.4.0,2.5.0)", + org.eclipse.jgit.junit;version="[2.4.0,2.5.0)", + org.eclipse.jgit.lib;version="[2.4.0,2.5.0)", + org.eclipse.jgit.revwalk;version="[2.4.0,2.5.0)", + org.eclipse.jgit.storage.file;version="[2.4.0,2.5.0)", + org.eclipse.jgit.transport;version="[2.4.0,2.5.0)", + org.eclipse.jgit.transport.resolver;version="[2.4.0,2.5.0)", org.junit;version="[4.0.0,5.0.0)" -Export-Package: org.eclipse.jgit.junit.http;version="2.3.0" +Export-Package: org.eclipse.jgit.junit.http;version="2.4.0" diff --git a/org.eclipse.jgit.junit.http/pom.xml b/org.eclipse.jgit.junit.http/pom.xml index 7b4601b55b..2e13f63fc9 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>2.3.0-SNAPSHOT</version>
+ <version>2.4.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 21db4579a4..a266d73392 100644 --- a/org.eclipse.jgit.junit/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.junit/META-INF/MANIFEST.MF @@ -2,30 +2,30 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %plugin_name Bundle-SymbolicName: org.eclipse.jgit.junit -Bundle-Version: 2.3.0.qualifier +Bundle-Version: 2.4.0.qualifier Bundle-Localization: plugin Bundle-Vendor: %provider_name Bundle-ActivationPolicy: lazy Bundle-RequiredExecutionEnvironment: J2SE-1.5 -Import-Package: org.eclipse.jgit.api;version="[2.3.0,2.4.0)", - org.eclipse.jgit.api.errors;version="[2.3.0,2.4.0)", - org.eclipse.jgit.diff;version="[2.3.0,2.4.0)", - org.eclipse.jgit.dircache;version="[2.3.0,2.4.0)", - org.eclipse.jgit.errors;version="[2.3.0,2.4.0)", - org.eclipse.jgit.fnmatch;version="[2.3.0,2.4.0)", - org.eclipse.jgit.lib;version="[2.3.0,2.4.0)", - org.eclipse.jgit.merge;version="[2.3.0,2.4.0)", - org.eclipse.jgit.patch;version="[2.3.0,2.4.0)", - org.eclipse.jgit.revplot;version="[2.3.0,2.4.0)", - org.eclipse.jgit.revwalk;version="[2.3.0,2.4.0)", - org.eclipse.jgit.revwalk.filter;version="[2.3.0,2.4.0)", - org.eclipse.jgit.storage.file;version="[2.3.0,2.4.0)", - org.eclipse.jgit.storage.pack;version="[2.3.0,2.4.0)", - org.eclipse.jgit.transport;version="[2.3.0,2.4.0)", - org.eclipse.jgit.treewalk;version="[2.3.0,2.4.0)", - org.eclipse.jgit.treewalk.filter;version="[2.3.0,2.4.0)", - org.eclipse.jgit.util;version="[2.3.0,2.4.0)", - org.eclipse.jgit.util.io;version="[2.3.0,2.4.0)", +Import-Package: org.eclipse.jgit.api;version="[2.4.0,2.5.0)", + org.eclipse.jgit.api.errors;version="[2.4.0,2.5.0)", + org.eclipse.jgit.diff;version="[2.4.0,2.5.0)", + org.eclipse.jgit.dircache;version="[2.4.0,2.5.0)", + org.eclipse.jgit.errors;version="[2.4.0,2.5.0)", + org.eclipse.jgit.fnmatch;version="[2.4.0,2.5.0)", + org.eclipse.jgit.lib;version="[2.4.0,2.5.0)", + org.eclipse.jgit.merge;version="[2.4.0,2.5.0)", + org.eclipse.jgit.patch;version="[2.4.0,2.5.0)", + org.eclipse.jgit.revplot;version="[2.4.0,2.5.0)", + org.eclipse.jgit.revwalk;version="[2.4.0,2.5.0)", + org.eclipse.jgit.revwalk.filter;version="[2.4.0,2.5.0)", + org.eclipse.jgit.storage.file;version="[2.4.0,2.5.0)", + org.eclipse.jgit.storage.pack;version="[2.4.0,2.5.0)", + org.eclipse.jgit.transport;version="[2.4.0,2.5.0)", + org.eclipse.jgit.treewalk;version="[2.4.0,2.5.0)", + org.eclipse.jgit.treewalk.filter;version="[2.4.0,2.5.0)", + org.eclipse.jgit.util;version="[2.4.0,2.5.0)", + org.eclipse.jgit.util.io;version="[2.4.0,2.5.0)", org.junit;version="[4.0.0,5.0.0)" -Export-Package: org.eclipse.jgit.junit;version="2.3.0" +Export-Package: org.eclipse.jgit.junit;version="2.4.0" Require-Bundle: com.jcraft.jsch;bundle-version="[0.1.37,0.2.0)" diff --git a/org.eclipse.jgit.junit/pom.xml b/org.eclipse.jgit.junit/pom.xml index be36651d16..b043949721 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>2.3.0-SNAPSHOT</version> + <version>2.4.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 78d28e0e96..35be618a07 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="2.3.0.qualifier" + version="2.4.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 2d80a2b6f7..822982f4d5 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>2.3.0-SNAPSHOT</version> + <version>2.4.0-SNAPSHOT</version> </parent> <groupId>org.eclipse.jgit.feature</groupId> @@ -63,7 +63,7 @@ <dependency> <groupId>org.eclipse.jgit</groupId> <artifactId>org.eclipse.jgit</artifactId> - <version>2.3.0-SNAPSHOT</version> + <version>${project.version}</version> </dependency> </dependencies> 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 0c47e7e36d..5d72f7f617 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="2.3.0.qualifier"
+ version="2.4.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 3eacb67049..9c91f124af 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>2.3.0-SNAPSHOT</version> + <version>2.4.0-SNAPSHOT</version> </parent> <groupId>org.eclipse.jgit.feature</groupId> @@ -63,17 +63,17 @@ <dependency> <groupId>org.eclipse.jgit</groupId> <artifactId>org.eclipse.jgit.junit</artifactId> - <version>2.3.0-SNAPSHOT</version> + <version>${project.version}</version> </dependency> <dependency> <groupId>org.eclipse.jgit</groupId> <artifactId>org.eclipse.jgit.junit.http</artifactId> - <version>2.3.0-SNAPSHOT</version> + <version>${project.version}</version> </dependency> <dependency> <groupId>org.eclipse.jgit</groupId> <artifactId>org.eclipse.jgit.http.server</artifactId> - <version>2.3.0-SNAPSHOT</version> + <version>${project.version}</version> </dependency> </dependencies> 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 85d5d355c1..3a153e793b 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="2.3.0.qualifier" + version="2.4.0.qualifier" provider-name="%providerName"> <description url="http://www.eclipse.org/jgit/"> @@ -23,7 +23,7 @@ </url> <requires> - <import feature="org.eclipse.jgit" version="2.3.0" match="equivalent"/> + <import feature="org.eclipse.jgit" version="2.4.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 68101521d1..8ee7b0124b 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>2.3.0-SNAPSHOT</version> + <version>2.4.0-SNAPSHOT</version> </parent> <groupId>org.eclipse.jgit.feature</groupId> @@ -64,19 +64,19 @@ <dependency> <groupId>org.eclipse.jgit</groupId> <artifactId>org.eclipse.jgit</artifactId> - <version>2.3.0-SNAPSHOT</version> + <version>${project.version}</version> </dependency> <dependency> <groupId>org.eclipse.jgit</groupId> <artifactId>org.eclipse.jgit.pgm</artifactId> - <version>2.3.0-SNAPSHOT</version> + <version>${project.version}</version> </dependency> <dependency> <groupId>org.eclipse.jgit</groupId> <artifactId>org.eclipse.jgit.ui</artifactId> - <version>2.3.0-SNAPSHOT</version> + <version>${project.version}</version> </dependency> </dependencies> 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 44a74f3e63..dc1abe21a9 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="2.3.0.qualifier" + version="2.4.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 1247e3ed28..4afd9fdceb 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>2.3.0-SNAPSHOT</version> + <version>2.4.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 2c86857876..34b2a371f4 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>2.3.0-SNAPSHOT</version> + <version>2.4.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 6175629536..b02fe240b0 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="2.3.0.qualifier" + version="2.4.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 db1df66a7f..fcc8399d93 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>2.3.0-SNAPSHOT</version> + <version>2.4.0-SNAPSHOT</version> </parent> <groupId>org.eclipse.jgit.feature</groupId> diff --git a/org.eclipse.jgit.packaging/pom.xml b/org.eclipse.jgit.packaging/pom.xml index f00be89b0a..cf8e646215 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>2.3.0-SNAPSHOT</version> + <version>2.4.0-SNAPSHOT</version> <packaging>pom</packaging> <name>JGit Tycho Parent</name> @@ -94,12 +94,26 @@ </repository> </repositories> + <distributionManagement> + <repository> + <id>repo.eclipse.org</id> + <name>JGit Maven Repository - Releases</name> + <url>https://repo.eclipse.org/content/repositories/jgit-releases/</url> + </repository> + <snapshotRepository> + <id>repo.eclipse.org</id> + <name>JGit Maven Repository - Snapshots</name> + <url>https://repo.eclipse.org/content/repositories/jgit-snapshots/</url> + <uniqueVersion>true</uniqueVersion> + </snapshotRepository> + </distributionManagement> + <dependencies> <!-- sources artifacts so that we can place them in the features --> <dependency> <groupId>org.eclipse.jgit</groupId> <artifactId>org.eclipse.jgit</artifactId> - <version>2.3.0-SNAPSHOT</version> + <version>${project.version}</version> <classifier>sources</classifier> </dependency> <dependency> diff --git a/org.eclipse.jgit.pgm.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.pgm.test/META-INF/MANIFEST.MF index b1fbe92c5b..045660dcbf 100644 --- a/org.eclipse.jgit.pgm.test/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.pgm.test/META-INF/MANIFEST.MF @@ -2,22 +2,22 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %plugin_name Bundle-SymbolicName: org.eclipse.jgit.pgm.test -Bundle-Version: 2.3.0.qualifier +Bundle-Version: 2.4.0.qualifier Bundle-Vendor: %provider_name Bundle-Localization: plugin Bundle-ActivationPolicy: lazy Bundle-RequiredExecutionEnvironment: J2SE-1.5 -Import-Package: org.eclipse.jgit.api;version="[2.3.0,2.4.0)", - org.eclipse.jgit.dircache;version="[2.3.0,2.4.0)", - org.eclipse.jgit.junit;version="[2.3.0,2.4.0)", - org.eclipse.jgit.lib;version="[2.3.0,2.4.0)", - org.eclipse.jgit.merge;version="[2.3.0,2.4.0)", - org.eclipse.jgit.pgm;version="[2.3.0,2.4.0)", - org.eclipse.jgit.pgm.opt;version="[2.3.0,2.4.0)", - org.eclipse.jgit.revwalk;version="[2.3.0,2.4.0)", - org.eclipse.jgit.storage.file;version="[2.3.0,2.4.0)", - org.eclipse.jgit.util;version="[2.3.0,2.4.0)", - org.eclipse.jgit.util.io;version="[2.3.0,2.4.0)", +Import-Package: org.eclipse.jgit.api;version="[2.4.0,2.5.0)", + org.eclipse.jgit.dircache;version="[2.4.0,2.5.0)", + org.eclipse.jgit.junit;version="[2.4.0,2.5.0)", + org.eclipse.jgit.lib;version="[2.4.0,2.5.0)", + org.eclipse.jgit.merge;version="[2.4.0,2.5.0)", + org.eclipse.jgit.pgm;version="[2.4.0,2.5.0)", + org.eclipse.jgit.pgm.opt;version="[2.4.0,2.5.0)", + org.eclipse.jgit.revwalk;version="[2.4.0,2.5.0)", + org.eclipse.jgit.storage.file;version="[2.4.0,2.5.0)", + org.eclipse.jgit.util;version="[2.4.0,2.5.0)", + org.eclipse.jgit.util.io;version="[2.4.0,2.5.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 6e5a7e962d..6de3c8895a 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>2.3.0-SNAPSHOT</version> + <version>2.4.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 3f971e319f..8025fe3046 100644 --- a/org.eclipse.jgit.pgm/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.pgm/META-INF/MANIFEST.MF @@ -2,39 +2,39 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %plugin_name Bundle-SymbolicName: org.eclipse.jgit.pgm -Bundle-Version: 2.3.0.qualifier +Bundle-Version: 2.4.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="[2.3.0,2.4.0)", - org.eclipse.jgit.api.errors;version="[2.3.0,2.4.0)", - org.eclipse.jgit.awtui;version="[2.3.0,2.4.0)", - org.eclipse.jgit.blame;version="[2.3.0,2.4.0)", - org.eclipse.jgit.diff;version="[2.3.0,2.4.0)", - org.eclipse.jgit.dircache;version="[2.3.0,2.4.0)", - org.eclipse.jgit.errors;version="[2.3.0,2.4.0)", - org.eclipse.jgit.lib;version="[2.3.0,2.4.0)", - org.eclipse.jgit.merge;version="2.3.0", - org.eclipse.jgit.nls;version="[2.3.0,2.4.0)", - org.eclipse.jgit.notes;version="[2.3.0,2.4.0)", - org.eclipse.jgit.revplot;version="[2.3.0,2.4.0)", - org.eclipse.jgit.revwalk;version="[2.3.0,2.4.0)", - org.eclipse.jgit.revwalk.filter;version="[2.3.0,2.4.0)", - org.eclipse.jgit.storage.file;version="[2.3.0,2.4.0)", - org.eclipse.jgit.storage.pack;version="[2.3.0,2.4.0)", - org.eclipse.jgit.transport;version="[2.3.0,2.4.0)", - org.eclipse.jgit.transport.resolver;version="[2.3.0,2.4.0)", - org.eclipse.jgit.treewalk;version="[2.3.0,2.4.0)", - org.eclipse.jgit.treewalk.filter;version="[2.3.0,2.4.0)", - org.eclipse.jgit.util;version="[2.3.0,2.4.0)", - org.eclipse.jgit.util.io;version="[2.3.0,2.4.0)", + org.eclipse.jgit.api;version="[2.4.0,2.5.0)", + org.eclipse.jgit.api.errors;version="[2.4.0,2.5.0)", + org.eclipse.jgit.awtui;version="[2.4.0,2.5.0)", + org.eclipse.jgit.blame;version="[2.4.0,2.5.0)", + org.eclipse.jgit.diff;version="[2.4.0,2.5.0)", + org.eclipse.jgit.dircache;version="[2.4.0,2.5.0)", + org.eclipse.jgit.errors;version="[2.4.0,2.5.0)", + org.eclipse.jgit.lib;version="[2.4.0,2.5.0)", + org.eclipse.jgit.merge;version="2.4.0", + org.eclipse.jgit.nls;version="[2.4.0,2.5.0)", + org.eclipse.jgit.notes;version="[2.4.0,2.5.0)", + org.eclipse.jgit.revplot;version="[2.4.0,2.5.0)", + org.eclipse.jgit.revwalk;version="[2.4.0,2.5.0)", + org.eclipse.jgit.revwalk.filter;version="[2.4.0,2.5.0)", + org.eclipse.jgit.storage.file;version="[2.4.0,2.5.0)", + org.eclipse.jgit.storage.pack;version="[2.4.0,2.5.0)", + org.eclipse.jgit.transport;version="[2.4.0,2.5.0)", + org.eclipse.jgit.transport.resolver;version="[2.4.0,2.5.0)", + org.eclipse.jgit.treewalk;version="[2.4.0,2.5.0)", + org.eclipse.jgit.treewalk.filter;version="[2.4.0,2.5.0)", + org.eclipse.jgit.util;version="[2.4.0,2.5.0)", + org.eclipse.jgit.util.io;version="[2.4.0,2.5.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="2.3.0"; +Export-Package: org.eclipse.jgit.pgm;version="2.4.0"; uses:="org.eclipse.jgit.lib, org.eclipse.jgit.nls, org.eclipse.jgit.treewalk, @@ -43,7 +43,7 @@ Export-Package: org.eclipse.jgit.pgm;version="2.3.0"; org.eclipse.jgit.pgm.opt, org.eclipse.jgit.awtui, org.eclipse.jgit.transport", - org.eclipse.jgit.pgm.debug;version="2.3.0", - org.eclipse.jgit.pgm.opt;version="2.3.0" + org.eclipse.jgit.pgm.debug;version="2.4.0", + org.eclipse.jgit.pgm.opt;version="2.4.0" Main-Class: org.eclipse.jgit.pgm.Main Implementation-Title: JGit Command Line Interface diff --git a/org.eclipse.jgit.pgm/META-INF/SOURCE-MANIFEST.MF b/org.eclipse.jgit.pgm/META-INF/SOURCE-MANIFEST.MF index 1b6990397e..34f69c1b00 100644 --- a/org.eclipse.jgit.pgm/META-INF/SOURCE-MANIFEST.MF +++ b/org.eclipse.jgit.pgm/META-INF/SOURCE-MANIFEST.MF @@ -3,6 +3,6 @@ Bundle-ManifestVersion: 2 Bundle-Name: org.eclipse.jgit.pgm - Sources Bundle-SymbolicName: org.eclipse.jgit.pgm.source;singleton:=true Bundle-Vendor: Eclipse.org - JGit -Bundle-Version: 2.3.0.qualifier -Eclipse-SourceBundle: org.eclipse.jgit.pgm;version="2.3.0";roots="." +Bundle-Version: 2.4.0.qualifier +Eclipse-SourceBundle: org.eclipse.jgit.pgm;version="2.4.0";roots="." diff --git a/org.eclipse.jgit.pgm/pom.xml b/org.eclipse.jgit.pgm/pom.xml index 17ed092dc4..6948746c24 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>2.3.0-SNAPSHOT</version> + <version>2.4.0-SNAPSHOT</version> </parent> <artifactId>org.eclipse.jgit.pgm</artifactId> diff --git a/org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/CLIText.properties b/org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/CLIText.properties index 0a4d90b088..d9684054c1 100644 --- a/org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/CLIText.properties +++ b/org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/CLIText.properties @@ -13,8 +13,8 @@ averageMSPerRead=average {0} ms/read branchAlreadyExists=A branch named ''{0}'' already exists. branchCreatedFrom=branch: Created from {0} branchDetachedHEAD=detached HEAD -branchIsNotAnAncestorOfYourCurrentHEAD=The branch '{0}' is not an ancestor of your current HEAD.\nIf you are sure you want to delete it, run 'jgit branch -D {0}'. -branchNotFound=branch '{0}' not found. +branchIsNotAnAncestorOfYourCurrentHEAD=The branch ''{0}'' is not an ancestor of your current HEAD.\nIf you are sure you want to delete it, run ''jgit branch -D {0}''. +branchNotFound=branch ''{0}'' not found. cacheTreePathInfo="{0}": {1} entries, {2} children cannotBeRenamed={0} cannot be renamed cannotChekoutNoHeadsAdvertisedByRemote=cannot checkout; no HEAD advertised by remote @@ -23,7 +23,7 @@ cannotCreateCommand=Cannot create command {0} cannotCreateOutputStream=cannot create output stream cannotDeatchHEAD=Cannot detach HEAD cannotDeleteFile=error: The following file could not be deleted: -cannotDeleteTheBranchWhichYouAreCurrentlyOn=Cannot delete the branch '{0}' which you are currently on. +cannotDeleteTheBranchWhichYouAreCurrentlyOn=Cannot delete the branch ''{0}'' which you are currently on. cannotGuessLocalNameFrom=cannot guess local name from {0} cannotLock=Cannot lock {0} cannotMergeDetachedHead=Cannot merge into detached HEAD @@ -76,6 +76,7 @@ metaVar_author=AUTHOR metaVar_base=base metaVar_blameL=START,END metaVar_blameReverse=START..END +metaVar_branchName=branch metaVar_bucket=BUCKET metaVar_command=command metaVar_commandDetail=DETAIL @@ -116,11 +117,12 @@ mostCommonlyUsedCommandsAre=The most commonly used commands are: needApprovalToDestroyCurrentRepository=Need approval to destroy current repository noGitRepositoryConfigured=No Git repository configured. noSuchFile=no such file: {0} +noSuchRemoteRef=no such remote ref: ''{0}'' noTREESectionInIndex=no 'TREE' section in index nonFastForward=non-fast forward notABranch={0} is not a branch notACommit={0} is not a commit -notAGitRepository='{0}' not a git repository +notAGitRepository=''{0}'' not a git repository notAJgitCommand={0} is not a jgit command notARevision=Not a revision: {0} notATagVersionIsRequired={0} is not a tag, --version is required @@ -144,7 +146,7 @@ remoteMessage=remote: {0} remoteRefObjectChangedIsNotExpectedOne=remote ref object changed - is not expected one {0} remoteSideDoesNotSupportDeletingRefs=remote side does not support deleting refs repaint=Repaint -serviceNotSupported=Service '{0}' not supported +serviceNotSupported=Service ''{0}'' not supported skippingObject=skipping {0} {1} statusFileListFormat=\t%1$s statusFileListFormatWithPrefix=\t%1$-11s %2$s @@ -274,5 +276,6 @@ usage_symbolicVersionForTheProject=Symbolic version for the project usage_tagMessage=tag message usage_updateRemoteRefsFromAnotherRepository=Update remote refs from another repository usage_useNameInsteadOfOriginToTrackUpstream=use <name> instead of 'origin' to track upstream +usage_checkoutBranchAfterClone=checkout named branch instead of remotes's HEAD usage_viewCommitHistory=View commit history warningNoCommitGivenOnCommandLine=warning: No commit given on command line, assuming {0} diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/CLIText.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/CLIText.java index 552629eba1..807fe39db9 100644 --- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/CLIText.java +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/CLIText.java @@ -180,6 +180,7 @@ public class CLIText extends TranslationBundle { /***/ public String needApprovalToDestroyCurrentRepository; /***/ public String noGitRepositoryConfigured; /***/ public String noSuchFile; + /***/ public String noSuchRemoteRef; /***/ public String noTREESectionInIndex; /***/ public String nonFastForward; /***/ public String notABranch; diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Clone.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Clone.java index 5406527a68..898203da29 100644 --- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Clone.java +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Clone.java @@ -47,9 +47,6 @@ import java.io.File; import java.io.IOException; import java.net.URISyntaxException; import java.text.MessageFormat; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; import org.eclipse.jgit.dircache.DirCache; import org.eclipse.jgit.dircache.DirCacheCheckout; @@ -57,7 +54,6 @@ import org.eclipse.jgit.errors.IncorrectObjectTypeException; import org.eclipse.jgit.errors.MissingObjectException; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.Ref; -import org.eclipse.jgit.lib.RefComparator; import org.eclipse.jgit.lib.RefUpdate; import org.eclipse.jgit.lib.TextProgressMonitor; import org.eclipse.jgit.revwalk.RevCommit; @@ -78,6 +74,9 @@ class Clone extends AbstractFetchCommand { @Option(name = "--origin", aliases = { "-o" }, metaVar = "metaVar_remoteName", usage = "usage_useNameInsteadOfOriginToTrackUpstream") private String remoteName = Constants.DEFAULT_REMOTE_NAME; + @Option(name = "--branch", aliases = { "-b" }, metaVar = "metaVar_branchName", usage = "usage_checkoutBranchAfterClone") + private String branch; + @Argument(index = 0, required = true, metaVar = "metaVar_uriish") private String sourceUri; @@ -121,8 +120,16 @@ class Clone extends AbstractFetchCommand { saveRemote(uri); final FetchResult r = runFetch(); - final Ref branch = guessHEAD(r); - doCheckout(branch); + final Ref checkoutRef; + if (branch == null) + checkoutRef = guessHEAD(r); + else { + checkoutRef = r.getAdvertisedRef(Constants.R_HEADS + branch); + if (checkoutRef == null) + throw die(MessageFormat.format(CLIText.get().noSuchRemoteRef, + branch)); + } + doCheckout(checkoutRef); } private void saveRemote(final URIish uri) throws URISyntaxException, @@ -152,19 +159,16 @@ class Clone extends AbstractFetchCommand { private static Ref guessHEAD(final FetchResult result) { final Ref idHEAD = result.getAdvertisedRef(Constants.HEAD); - final List<Ref> availableRefs = new ArrayList<Ref>(); Ref head = null; for (final Ref r : result.getAdvertisedRefs()) { final String n = r.getName(); if (!n.startsWith(Constants.R_HEADS)) continue; - availableRefs.add(r); if (idHEAD == null || head != null) continue; if (r.getObjectId().equals(idHEAD.getObjectId())) head = r; } - Collections.sort(availableRefs, RefComparator.INSTANCE); if (idHEAD != null && head == null) head = idHEAD; return head; diff --git a/org.eclipse.jgit.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.test/META-INF/MANIFEST.MF index 7ea0fa2f79..4de17bdcb9 100644 --- a/org.eclipse.jgit.test/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.test/META-INF/MANIFEST.MF @@ -2,41 +2,41 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %plugin_name Bundle-SymbolicName: org.eclipse.jgit.test -Bundle-Version: 2.3.0.qualifier +Bundle-Version: 2.4.0.qualifier Bundle-Localization: plugin Bundle-Vendor: %provider_name Bundle-ActivationPolicy: lazy Bundle-RequiredExecutionEnvironment: J2SE-1.5 -Import-Package: org.eclipse.jgit.api;version="[2.3.0,2.4.0)", - org.eclipse.jgit.api.errors;version="[2.3.0,2.4.0)", - org.eclipse.jgit.awtui;version="[2.3.0,2.4.0)", - org.eclipse.jgit.blame;version="[2.3.0,2.4.0)", - org.eclipse.jgit.console;version="[2.3.0,2.4.0)", - org.eclipse.jgit.diff;version="[2.3.0,2.4.0)", - org.eclipse.jgit.dircache;version="[2.3.0,2.4.0)", - org.eclipse.jgit.errors;version="[2.3.0,2.4.0)", - org.eclipse.jgit.events;version="[2.3.0,2.4.0)", - org.eclipse.jgit.fnmatch;version="[2.3.0,2.4.0)", - org.eclipse.jgit.ignore;version="[2.3.0,2.4.0)", - org.eclipse.jgit.internal;version="[2.3.0,2.4.0)", - org.eclipse.jgit.junit;version="[2.3.0,2.4.0)", - org.eclipse.jgit.lib;version="[2.3.0,2.4.0)", - org.eclipse.jgit.merge;version="[2.3.0,2.4.0)", - org.eclipse.jgit.nls;version="[2.3.0,2.4.0)", - org.eclipse.jgit.notes;version="[2.3.0,2.4.0)", - org.eclipse.jgit.patch;version="[2.3.0,2.4.0)", - org.eclipse.jgit.pgm;version="[2.3.0,2.4.0)", - org.eclipse.jgit.revplot;version="[2.3.0,2.4.0)", - org.eclipse.jgit.revwalk;version="[2.3.0,2.4.0)", - org.eclipse.jgit.revwalk.filter;version="[2.3.0,2.4.0)", - org.eclipse.jgit.storage.file;version="[2.3.0,2.4.0)", - org.eclipse.jgit.storage.pack;version="[2.3.0,2.4.0)", - org.eclipse.jgit.submodule;version="[2.3.0,2.4.0)", - org.eclipse.jgit.transport;version="[2.3.0,2.4.0)", - org.eclipse.jgit.treewalk;version="[2.3.0,2.4.0)", - org.eclipse.jgit.treewalk.filter;version="[2.3.0,2.4.0)", - org.eclipse.jgit.util;version="[2.3.0,2.4.0)", - org.eclipse.jgit.util.io;version="[2.3.0,2.4.0)", +Import-Package: org.eclipse.jgit.api;version="[2.4.0,2.5.0)", + org.eclipse.jgit.api.errors;version="[2.4.0,2.5.0)", + org.eclipse.jgit.awtui;version="[2.4.0,2.5.0)", + org.eclipse.jgit.blame;version="[2.4.0,2.5.0)", + org.eclipse.jgit.console;version="[2.4.0,2.5.0)", + org.eclipse.jgit.diff;version="[2.4.0,2.5.0)", + org.eclipse.jgit.dircache;version="[2.4.0,2.5.0)", + org.eclipse.jgit.errors;version="[2.4.0,2.5.0)", + org.eclipse.jgit.events;version="[2.4.0,2.5.0)", + org.eclipse.jgit.fnmatch;version="[2.4.0,2.5.0)", + org.eclipse.jgit.ignore;version="[2.4.0,2.5.0)", + org.eclipse.jgit.internal;version="[2.4.0,2.5.0)", + org.eclipse.jgit.junit;version="[2.4.0,2.5.0)", + org.eclipse.jgit.lib;version="[2.4.0,2.5.0)", + org.eclipse.jgit.merge;version="[2.4.0,2.5.0)", + org.eclipse.jgit.nls;version="[2.4.0,2.5.0)", + org.eclipse.jgit.notes;version="[2.4.0,2.5.0)", + org.eclipse.jgit.patch;version="[2.4.0,2.5.0)", + org.eclipse.jgit.pgm;version="[2.4.0,2.5.0)", + org.eclipse.jgit.revplot;version="[2.4.0,2.5.0)", + org.eclipse.jgit.revwalk;version="[2.4.0,2.5.0)", + org.eclipse.jgit.revwalk.filter;version="[2.4.0,2.5.0)", + org.eclipse.jgit.storage.file;version="[2.4.0,2.5.0)", + org.eclipse.jgit.storage.pack;version="[2.4.0,2.5.0)", + org.eclipse.jgit.submodule;version="[2.4.0,2.5.0)", + org.eclipse.jgit.transport;version="[2.4.0,2.5.0)", + org.eclipse.jgit.treewalk;version="[2.4.0,2.5.0)", + org.eclipse.jgit.treewalk.filter;version="[2.4.0,2.5.0)", + org.eclipse.jgit.util;version="[2.4.0,2.5.0)", + org.eclipse.jgit.util.io;version="[2.4.0,2.5.0)", org.hamcrest;version="[1.1.0,2.0.0)", org.hamcrest.text.pattern;version="[1.1.0,2.0.0)", org.junit;version="[4.4.0,5.0.0)", @@ -44,4 +44,4 @@ Import-Package: org.eclipse.jgit.api;version="[2.3.0,2.4.0)", org.junit.runner;version="[4.4.0,5.0.0)" Require-Bundle: com.jcraft.jsch;bundle-version="[0.1.37,0.2.0)", org.hamcrest.core;bundle-version="[1.1.0,2.0.0)" -Export-Package: org.eclipse.jgit.lib +Export-Package: org.eclipse.jgit.lib;version="2.4.0" diff --git a/org.eclipse.jgit.test/pom.xml b/org.eclipse.jgit.test/pom.xml index 5019ca1eee..5f5659f45b 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>2.3.0-SNAPSHOT</version> + <version>2.4.0-SNAPSHOT</version> </parent> <artifactId>org.eclipse.jgit.test</artifactId> diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/RecursiveMergerTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/RecursiveMergerTest.java new file mode 100644 index 0000000000..9860d304f3 --- /dev/null +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/RecursiveMergerTest.java @@ -0,0 +1,578 @@ +/* + * Copyright (C) 2012, 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.merge; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStreamReader; + +import org.eclipse.jgit.api.Git; +import org.eclipse.jgit.dircache.DirCache; +import org.eclipse.jgit.dircache.DirCacheEditor; +import org.eclipse.jgit.dircache.DirCacheEntry; +import org.eclipse.jgit.errors.MissingObjectException; +import org.eclipse.jgit.errors.NoMergeBaseException; +import org.eclipse.jgit.errors.NoMergeBaseException.MergeBaseFailureReason; +import org.eclipse.jgit.junit.RepositoryTestCase; +import org.eclipse.jgit.junit.TestRepository; +import org.eclipse.jgit.junit.TestRepository.BranchBuilder; +import org.eclipse.jgit.lib.AnyObjectId; +import org.eclipse.jgit.lib.Constants; +import org.eclipse.jgit.lib.FileMode; +import org.eclipse.jgit.lib.ObjectId; +import org.eclipse.jgit.lib.ObjectLoader; +import org.eclipse.jgit.lib.ObjectReader; +import org.eclipse.jgit.lib.Repository; +import org.eclipse.jgit.revwalk.RevBlob; +import org.eclipse.jgit.revwalk.RevCommit; +import org.eclipse.jgit.storage.file.FileRepository; +import org.eclipse.jgit.treewalk.FileTreeIterator; +import org.eclipse.jgit.treewalk.TreeWalk; +import org.eclipse.jgit.treewalk.filter.PathFilter; +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 RecursiveMergerTest extends RepositoryTestCase { + static int counter = 0; + + @DataPoints + public static MergeStrategy[] strategiesUnderTest = new MergeStrategy[] { + MergeStrategy.RECURSIVE, MergeStrategy.RESOLVE }; + + public enum IndexState { + Bare, Missing, SameAsHead, SameAsOther, SameAsWorkTree, DifferentFromHeadAndOtherAndWorktree + } + + @DataPoints + public static IndexState[] indexStates = IndexState.values(); + + public enum WorktreeState { + Bare, Missing, SameAsHead, DifferentFromHeadAndOther, SameAsOther; + } + + @DataPoints + public static WorktreeState[] worktreeStates = WorktreeState.values(); + + private TestRepository<FileRepository> db_t; + + @Override + @Before + public void setUp() throws Exception { + super.setUp(); + db_t = new TestRepository<FileRepository>(db); + } + + @Theory + /** + * Merging m2,s2 from the following topology. In master and side different + * files are touched. No need to do a real content merge. + * + * <pre> + * m0--m1--m2 + * \ \/ + * \ /\ + * s1--s2 + * </pre> + */ + public void crissCrossMerge(MergeStrategy strategy, IndexState indexState, + WorktreeState worktreeState) throws Exception { + if (!validateStates(indexState, worktreeState)) + return; + // fill the repo + BranchBuilder master = db_t.branch("master"); + RevCommit m0 = master.commit().add("m", ",m0").message("m0").create(); + RevCommit m1 = master.commit().add("m", "m1").message("m1").create(); + db_t.getRevWalk().parseCommit(m1); + + BranchBuilder side = db_t.branch("side"); + RevCommit s1 = side.commit().parent(m0).add("s", "s1").message("s1") + .create(); + RevCommit s2 = side.commit().parent(m1).add("m", "m1") + .message("s2(merge)").create(); + RevCommit m2 = master.commit().parent(s1).add("s", "s1") + .message("m2(merge)").create(); + + Git git = Git.wrap(db); + git.checkout().setName("master").call(); + modifyWorktree(worktreeState, "m", "side"); + modifyWorktree(worktreeState, "s", "side"); + modifyIndex(indexState, "m", "side"); + modifyIndex(indexState, "s", "side"); + + ResolveMerger merger = (ResolveMerger) strategy.newMerger(db, + worktreeState == WorktreeState.Bare); + if (worktreeState != WorktreeState.Bare) + merger.setWorkingTreeIterator(new FileTreeIterator(db)); + try { + boolean expectSuccess = true; + if (!(indexState == IndexState.Bare + || indexState == IndexState.Missing + || indexState == IndexState.SameAsHead || indexState == IndexState.SameAsOther)) + // index is dirty + expectSuccess = false; + + assertEquals(Boolean.valueOf(expectSuccess), + Boolean.valueOf(merger.merge(new RevCommit[] { m2, s2 }))); + assertEquals(MergeStrategy.RECURSIVE, strategy); + assertEquals("m1", + contentAsString(db, merger.getResultTreeId(), "m")); + assertEquals("s1", + contentAsString(db, merger.getResultTreeId(), "s")); + } catch (NoMergeBaseException e) { + assertEquals(MergeStrategy.RESOLVE, strategy); + assertEquals(e.getReason(), + MergeBaseFailureReason.MULTIPLE_MERGE_BASES_NOT_SUPPORTED); + } + } + + @Theory + /** + * Merging m2,s2 from the following topology. The same file is modified + * in both branches. The modifications should be mergeable. m2 and s2 + * contain branch specific conflict resolutions. Therefore m2 and don't contain the same content. + * + * <pre> + * m0--m1--m2 + * \ \/ + * \ /\ + * s1--s2 + * </pre> + */ + public void crissCrossMerge_mergeable(MergeStrategy strategy, + IndexState indexState, WorktreeState worktreeState) + throws Exception { + if (!validateStates(indexState, worktreeState)) + return; + + BranchBuilder master = db_t.branch("master"); + RevCommit m0 = master.commit().add("f", "1\n2\n3\n4\n5\n6\n7\n8\n9\n") + .message("m0").create(); + RevCommit m1 = master.commit() + .add("f", "1-master\n2\n3\n4\n5\n6\n7\n8\n9\n").message("m1") + .create(); + db_t.getRevWalk().parseCommit(m1); + + BranchBuilder side = db_t.branch("side"); + RevCommit s1 = side.commit().parent(m0) + .add("f", "1\n2\n3\n4\n5\n6\n7\n8\n9-side\n").message("s1") + .create(); + RevCommit s2 = side.commit().parent(m1) + .add("f", "1-master\n2\n3\n4\n5\n6\n7-res(side)\n8\n9-side\n") + .message("s2(merge)").create(); + RevCommit m2 = master + .commit() + .parent(s1) + .add("f", "1-master\n2\n3-res(master)\n4\n5\n6\n7\n8\n9-side\n") + .message("m2(merge)").create(); + + Git git = Git.wrap(db); + git.checkout().setName("master").call(); + modifyWorktree(worktreeState, "f", "side"); + modifyIndex(indexState, "f", "side"); + + ResolveMerger merger = (ResolveMerger) strategy.newMerger(db, + worktreeState == WorktreeState.Bare); + if (worktreeState != WorktreeState.Bare) + merger.setWorkingTreeIterator(new FileTreeIterator(db)); + try { + boolean expectSuccess = true; + if (!(indexState == IndexState.Bare + || indexState == IndexState.Missing || indexState == IndexState.SameAsHead)) + // index is dirty + expectSuccess = false; + else if (worktreeState == WorktreeState.DifferentFromHeadAndOther + || worktreeState == WorktreeState.SameAsOther) + expectSuccess = false; + assertEquals(Boolean.valueOf(expectSuccess), + Boolean.valueOf(merger.merge(new RevCommit[] { m2, s2 }))); + assertEquals(MergeStrategy.RECURSIVE, strategy); + if (!expectSuccess) + // if the merge was not successful skip testing the state of index and workingtree + return; + assertEquals( + "1-master\n2\n3-res(master)\n4\n5\n6\n7-res(side)\n8\n9-side", + contentAsString(db, merger.getResultTreeId(), "f")); + if (indexState != IndexState.Bare) + assertEquals( + "[f, mode:100644, content:1-master\n2\n3-res(master)\n4\n5\n6\n7-res(side)\n8\n9-side\n]", + indexState(RepositoryTestCase.CONTENT)); + if (worktreeState != WorktreeState.Bare + && worktreeState != WorktreeState.Missing) + assertEquals( + "1-master\n2\n3-res(master)\n4\n5\n6\n7-res(side)\n8\n9-side\n", + read("f")); + } catch (NoMergeBaseException e) { + assertEquals(MergeStrategy.RESOLVE, strategy); + assertEquals(e.getReason(), + MergeBaseFailureReason.MULTIPLE_MERGE_BASES_NOT_SUPPORTED); + } + } + + @Theory + /** + * Merging m2,s2 from the following topology. The same file is modified + * in both branches. The modifications are not automatically + * mergeable. m2 and s2 contain branch specific conflict resolutions. + * Therefore m2 and s2 don't contain the same content. + * + * <pre> + * m0--m1--m2 + * \ \/ + * \ /\ + * s1--s2 + * </pre> + */ + public void crissCrossMerge_nonmergeable(MergeStrategy strategy, + IndexState indexState, WorktreeState worktreeState) + throws Exception { + if (!validateStates(indexState, worktreeState)) + return; + + BranchBuilder master = db_t.branch("master"); + RevCommit m0 = master.commit().add("f", "1\n2\n3\n4\n5\n6\n7\n8\n9\n") + .message("m0").create(); + RevCommit m1 = master.commit() + .add("f", "1-master\n2\n3\n4\n5\n6\n7\n8\n9\n").message("m1") + .create(); + db_t.getRevWalk().parseCommit(m1); + + BranchBuilder side = db_t.branch("side"); + RevCommit s1 = side.commit().parent(m0) + .add("f", "1\n2\n3\n4\n5\n6\n7\n8\n9-side\n").message("s1") + .create(); + RevCommit s2 = side.commit().parent(m1) + .add("f", "1-master\n2\n3\n4\n5\n6\n7-res(side)\n8\n9-side\n") + .message("s2(merge)").create(); + RevCommit m2 = master.commit().parent(s1) + .add("f", "1-master\n2\n3\n4\n5\n6\n7-conflict\n8\n9-side\n") + .message("m2(merge)").create(); + + Git git = Git.wrap(db); + git.checkout().setName("master").call(); + modifyWorktree(worktreeState, "f", "side"); + modifyIndex(indexState, "f", "side"); + + ResolveMerger merger = (ResolveMerger) strategy.newMerger(db, + worktreeState == WorktreeState.Bare); + if (worktreeState != WorktreeState.Bare) + merger.setWorkingTreeIterator(new FileTreeIterator(db)); + try { + assertFalse(merger.merge(new RevCommit[] { m2, s2 })); + assertEquals(MergeStrategy.RECURSIVE, strategy); + if (indexState == IndexState.SameAsHead + && worktreeState == WorktreeState.SameAsHead) { + assertEquals( + "[f, mode:100644, stage:1, content:1-master\n2\n3\n4\n5\n6\n7\n8\n9-side\n]" + + "[f, mode:100644, stage:2, content:1-master\n2\n3\n4\n5\n6\n7-conflict\n8\n9-side\n]" + + "[f, mode:100644, stage:3, content:1-master\n2\n3\n4\n5\n6\n7-res(side)\n8\n9-side\n]", + indexState(RepositoryTestCase.CONTENT)); + assertEquals( + "1-master\n2\n3\n4\n5\n6\n<<<<<<< OURS\n7-conflict\n=======\n7-res(side)\n>>>>>>> THEIRS\n8\n9-side\n", + read("f")); + } + } catch (NoMergeBaseException e) { + assertEquals(MergeStrategy.RESOLVE, strategy); + assertEquals(e.getReason(), + MergeBaseFailureReason.MULTIPLE_MERGE_BASES_NOT_SUPPORTED); + } + } + + @Theory + /** + * Merging m2,s2 which have three common predecessors.The same file is modified + * in all branches. The modifications should be mergeable. m2 and s2 + * contain branch specific conflict resolutions. Therefore m2 and s2 + * don't contain the same content. + * + * <pre> + * m1-----m2 + * / \/ / + * / /\ / + * m0--o1 x + * \ \/ \ + * \ /\ \ + * s1-----s2 + * </pre> + */ + public void crissCrossMerge_ThreeCommonPredecessors(MergeStrategy strategy, + IndexState indexState, WorktreeState worktreeState) + throws Exception { + if (!validateStates(indexState, worktreeState)) + return; + + BranchBuilder master = db_t.branch("master"); + RevCommit m0 = master.commit().add("f", "1\n2\n3\n4\n5\n6\n7\n8\n9\n") + .message("m0").create(); + RevCommit m1 = master.commit() + .add("f", "1-master\n2\n3\n4\n5\n6\n7\n8\n9\n").message("m1") + .create(); + BranchBuilder side = db_t.branch("side"); + RevCommit s1 = side.commit().parent(m0) + .add("f", "1\n2\n3\n4\n5\n6\n7\n8\n9-side\n").message("s1") + .create(); + BranchBuilder other = db_t.branch("other"); + RevCommit o1 = other.commit().parent(m0) + .add("f", "1\n2\n3\n4\n5-other\n6\n7\n8\n9\n").message("o1") + .create(); + + RevCommit m2 = master + .commit() + .parent(s1) + .parent(o1) + .add("f", + "1-master\n2\n3-res(master)\n4\n5-other\n6\n7\n8\n9-side\n") + .message("m2(merge)").create(); + + RevCommit s2 = side + .commit() + .parent(m1) + .parent(o1) + .add("f", + "1-master\n2\n3\n4\n5-other\n6\n7-res(side)\n8\n9-side\n") + .message("s2(merge)").create(); + + Git git = Git.wrap(db); + git.checkout().setName("master").call(); + modifyWorktree(worktreeState, "f", "side"); + modifyIndex(indexState, "f", "side"); + + ResolveMerger merger = (ResolveMerger) strategy.newMerger(db, + worktreeState == WorktreeState.Bare); + if (worktreeState != WorktreeState.Bare) + merger.setWorkingTreeIterator(new FileTreeIterator(db)); + try { + boolean expectSuccess = true; + if (!(indexState == IndexState.Bare + || indexState == IndexState.Missing || indexState == IndexState.SameAsHead)) + // index is dirty + expectSuccess = false; + else if (worktreeState == WorktreeState.DifferentFromHeadAndOther + || worktreeState == WorktreeState.SameAsOther) + // workingtree is dirty + expectSuccess = false; + + assertEquals(Boolean.valueOf(expectSuccess), + Boolean.valueOf(merger.merge(new RevCommit[] { m2, s2 }))); + assertEquals(MergeStrategy.RECURSIVE, strategy); + if (!expectSuccess) + // if the merge was not successful skip testing the state of index and workingtree + return; + assertEquals( + "1-master\n2\n3-res(master)\n4\n5-other\n6\n7-res(side)\n8\n9-side", + contentAsString(db, merger.getResultTreeId(), "f")); + if (indexState != IndexState.Bare) + assertEquals( + "[f, mode:100644, content:1-master\n2\n3-res(master)\n4\n5-other\n6\n7-res(side)\n8\n9-side\n]", + indexState(RepositoryTestCase.CONTENT)); + if (worktreeState != WorktreeState.Bare + && worktreeState != WorktreeState.Missing) + assertEquals( + "1-master\n2\n3-res(master)\n4\n5-other\n6\n7-res(side)\n8\n9-side\n", + read("f")); + } catch (NoMergeBaseException e) { + assertEquals(MergeStrategy.RESOLVE, strategy); + assertEquals(e.getReason(), + MergeBaseFailureReason.MULTIPLE_MERGE_BASES_NOT_SUPPORTED); + } + } + + void modifyIndex(IndexState indexState, String path, String other) + throws Exception { + RevBlob blob; + switch (indexState) { + case Missing: + setIndex(null, path); + break; + case SameAsHead: + setIndex(contentId(Constants.HEAD, path), path); + break; + case SameAsOther: + setIndex(contentId(other, path), path); + break; + case SameAsWorkTree: + blob = db_t.blob(read(path)); + setIndex(blob, path); + break; + case DifferentFromHeadAndOtherAndWorktree: + blob = db_t.blob(Integer.toString(counter++)); + setIndex(blob, path); + break; + case Bare: + File file = new File(db.getDirectory(), "index"); + if (!file.exists()) + return; + db.close(); + file.delete(); + db = new FileRepository(db.getDirectory()); + db_t = new TestRepository<FileRepository>(db); + break; + } + } + + private void setIndex(final ObjectId id, String path) + throws MissingObjectException, IOException { + DirCache lockedDircache; + DirCacheEditor dcedit; + + lockedDircache = db.lockDirCache(); + dcedit = lockedDircache.editor(); + try { + if (id != null) { + final ObjectLoader contLoader = db.newObjectReader().open(id); + dcedit.add(new DirCacheEditor.PathEdit(path) { + @Override + public void apply(DirCacheEntry ent) { + ent.setFileMode(FileMode.REGULAR_FILE); + ent.setLength(contLoader.getSize()); + ent.setObjectId(id); + } + }); + } else + dcedit.add(new DirCacheEditor.DeletePath(path)); + } finally { + dcedit.commit(); + } + } + + private ObjectId contentId(String revName, String path) throws Exception { + RevCommit headCommit = db_t.getRevWalk().parseCommit( + db.resolve(revName)); + db_t.parseBody(headCommit); + return db_t.get(headCommit.getTree(), path).getId(); + } + + void modifyWorktree(WorktreeState worktreeState, String path, String other) + throws Exception { + FileOutputStream fos = null; + ObjectId bloblId; + + try { + switch (worktreeState) { + case Missing: + new File(db.getWorkTree(), path).delete(); + break; + case DifferentFromHeadAndOther: + write(new File(db.getWorkTree(), path), + Integer.toString(counter++)); + break; + case SameAsHead: + bloblId = contentId(Constants.HEAD, path); + fos = new FileOutputStream(new File(db.getWorkTree(), path)); + db.newObjectReader().open(bloblId).copyTo(fos); + break; + case SameAsOther: + bloblId = contentId(other, path); + fos = new FileOutputStream(new File(db.getWorkTree(), path)); + db.newObjectReader().open(bloblId).copyTo(fos); + break; + case Bare: + if (db.isBare()) + return; + File workTreeFile = db.getWorkTree(); + db.getConfig().setBoolean("core", null, "bare", true); + db.getDirectory().renameTo(new File(workTreeFile, "test.git")); + db = new FileRepository(new File(workTreeFile, "test.git")); + db_t = new TestRepository<FileRepository>(db); + } + } finally { + if (fos != null) + fos.close(); + } + } + + private boolean validateStates(IndexState indexState, + WorktreeState worktreeState) { + if (worktreeState == WorktreeState.Bare + && indexState != IndexState.Bare) + return false; + if (worktreeState != WorktreeState.Bare + && indexState == IndexState.Bare) + return false; + if (worktreeState != WorktreeState.DifferentFromHeadAndOther + && indexState == IndexState.SameAsWorkTree) + // would be a duplicate: the combination WorktreeState.X and + // IndexState.X already covered this + return false; + return true; + } + + private String contentAsString(Repository r, ObjectId treeId, String path) + throws MissingObjectException, IOException { + TreeWalk tw = new TreeWalk(r); + tw.addTree(treeId); + tw.setFilter(PathFilter.create(path)); + tw.setRecursive(true); + if (!tw.next()) + return null; + AnyObjectId blobId = tw.getObjectId(0); + + StringBuilder result = new StringBuilder(); + BufferedReader br = null; + ObjectReader or = r.newObjectReader(); + try { + br = new BufferedReader(new InputStreamReader(or.open(blobId) + .openStream())); + String line; + boolean first = true; + while ((line = br.readLine()) != null) { + if (!first) + result.append('\n'); + result.append(line); + first = false; + } + return result.toString(); + } finally { + if (br != null) + br.close(); + } + } +} diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/ResolveMergerTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/ResolveMergerTest.java index 8c10c731c2..d8ef2dd6ba 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/ResolveMergerTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/ResolveMergerTest.java @@ -54,7 +54,10 @@ import org.eclipse.jgit.api.Git; import org.eclipse.jgit.api.MergeResult; import org.eclipse.jgit.api.MergeResult.MergeStatus; import org.eclipse.jgit.api.errors.CheckoutConflictException; +import org.eclipse.jgit.api.errors.JGitInternalException; import org.eclipse.jgit.dircache.DirCache; +import org.eclipse.jgit.errors.NoMergeBaseException; +import org.eclipse.jgit.errors.NoMergeBaseException.MergeBaseFailureReason; import org.eclipse.jgit.junit.RepositoryTestCase; import org.eclipse.jgit.merge.ResolveMerger.MergeFailureReason; import org.eclipse.jgit.revwalk.RevCommit; @@ -72,6 +75,9 @@ public class ResolveMergerTest extends RepositoryTestCase { @DataPoint public static MergeStrategy resolve = MergeStrategy.RESOLVE; + @DataPoint + public static MergeStrategy recursive = MergeStrategy.RECURSIVE; + @Theory public void failingPathsShouldNotResultInOKReturnValue( MergeStrategy strategy) throws Exception { @@ -396,6 +402,66 @@ public class ResolveMergerTest extends RepositoryTestCase { } } + /** + * Merging after criss-cross merges. In this case we merge together two + * commits which have two equally good common ancestors + * + * @param strategy + * @throws Exception + */ + @Theory + public void checkMergeCrissCross(MergeStrategy strategy) throws Exception { + Git git = Git.wrap(db); + + writeTrashFile("1", "1\n2\n3"); + git.add().addFilepattern("1").call(); + RevCommit first = git.commit().setMessage("added 1").call(); + + writeTrashFile("1", "1master\n2\n3"); + RevCommit masterCommit = git.commit().setAll(true) + .setMessage("modified 1 on master").call(); + + writeTrashFile("1", "1master2\n2\n3"); + git.commit().setAll(true) + .setMessage("modified 1 on master again").call(); + + git.checkout().setCreateBranch(true).setStartPoint(first) + .setName("side").call(); + writeTrashFile("1", "1\n2\na\nb\nc\n3side"); + RevCommit sideCommit = git.commit().setAll(true) + .setMessage("modified 1 on side").call(); + + writeTrashFile("1", "1\n2\n3side2"); + git.commit().setAll(true) + .setMessage("modified 1 on side again").call(); + + MergeResult result = git.merge().setStrategy(strategy) + .include(masterCommit).call(); + assertEquals(MergeStatus.MERGED, result.getMergeStatus()); + result.getNewHead(); + git.checkout().setName("master").call(); + result = git.merge().setStrategy(strategy).include(sideCommit).call(); + assertEquals(MergeStatus.MERGED, result.getMergeStatus()); + + // we have two branches which are criss-cross merged. Try to merge the + // tips. This should succeed with RecursiveMerge and fail with + // ResolveMerge + try { + MergeResult mergeResult = git.merge().setStrategy(strategy) + .include(git.getRepository().getRef("refs/heads/side")) + .call(); + assertEquals(MergeStrategy.RECURSIVE, strategy); + assertEquals(MergeResult.MergeStatus.MERGED, + mergeResult.getMergeStatus()); + assertEquals("1master2\n2\n3side2\n", read("1")); + } catch (JGitInternalException e) { + assertEquals(MergeStrategy.RESOLVE, strategy); + assertTrue(e.getCause() instanceof NoMergeBaseException); + assertEquals(((NoMergeBaseException) e.getCause()).getReason(), + MergeBaseFailureReason.MULTIPLE_MERGE_BASES_NOT_SUPPORTED); + } + } + @Theory public void checkLockedFilesToBeDeleted(MergeStrategy strategy) throws Exception { diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/filter/PathFilterGroupTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/filter/PathFilterGroupTest.java index 5267e81a15..8038206e9b 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/filter/PathFilterGroupTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/filter/PathFilterGroupTest.java @@ -135,6 +135,19 @@ public class PathFilterGroupTest { } @Test + public void testLongPaths() throws MissingObjectException, + IncorrectObjectTypeException, IOException { + TreeFilter longPathFilter = PathFilterGroup + .createFromStrings( + "tst/org/eclipse/jgit/treewalk/filter/PathFilterGroupTest.java", + "tst/org/eclipse/jgit/treewalk/filter/PathFilterGroupTest2.java"); + assertFalse(longPathFilter + .include(fakeWalk("tst/org/eclipse/jgit/treewalk/FileTreeIteratorTest.java"))); + assertFalse(longPathFilter.include(fakeWalk("tst/a-other-in-same"))); + assertFalse(longPathFilter.include(fakeWalk("a-nothing-in-common"))); + } + + @Test public void testStopWalk() throws MissingObjectException, IncorrectObjectTypeException, IOException { // Obvious diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/ChangeIdUtilTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/ChangeIdUtilTest.java index 54f3114c6d..66649b1006 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/ChangeIdUtilTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/ChangeIdUtilTest.java @@ -642,29 +642,58 @@ public class ChangeIdUtilTest { assertEquals(3, ChangeIdUtil.indexOfChangeId("x\n" + "\n" + "Change-Id: I3b7e4e16b503ce00f07ba6ad01d97a356dad7701\n", "\n")); + assertEquals(3, ChangeIdUtil.indexOfChangeId("x\n" + "\n" + + "Change-Id: I3b7e4e16b503ce00f07ba6ad01d97a356dad7701\n\n\n", + "\n")); + assertEquals(3, ChangeIdUtil.indexOfChangeId("x\n" + "\n" + + "Change-Id: I3b7e4e16b503ce00f07ba6ad01d97a356dad7701\n \n \n", + "\n")); + assertEquals(3, ChangeIdUtil.indexOfChangeId("x\n" + "\n" + + "Change-Id: I3b7e4e16b503ce00f07ba6ad01d97a356dad7701\n", + "\n")); + + // leading whitespace is rejected by Gerrit + assertEquals(-1, ChangeIdUtil.indexOfChangeId("x\n" + "\n" + + " Change-Id: I3b7e4e16b503ce00f07ba6ad01d97a356dad7701\n", + "\n")); + assertEquals(-1, ChangeIdUtil.indexOfChangeId("x\n" + "\n" + + "\t Change-Id: I3b7e4e16b503ce00f07ba6ad01d97a356dad7701\n", + "\n")); + + assertEquals(-1, ChangeIdUtil.indexOfChangeId("x\n" + "\n" + + "Change-Id: \n", "\n")); + assertEquals(3, ChangeIdUtil.indexOfChangeId("x\n" + "\n" + + "Change-Id: I3b7e4e16b503ce00f07ba6ad01d97a356dad7701 \n", + "\n")); + assertEquals(12, ChangeIdUtil.indexOfChangeId("x\n" + "\n" + + "Bug 4711\n" + + "Change-Id: I3b7e4e16b503ce00f07ba6ad01d97a356dad7701\n", + "\n")); + assertEquals(56, ChangeIdUtil.indexOfChangeId("x\n" + + "Change-Id: I3b7e4e16b503ce00f07ba6ad01d97a356dad7701\n" + + "\n" + + "Change-Id: I3b7e4e16b503ce00f07ba6ad01d97a356dad7701\n", + "\n")); + assertEquals(-1, ChangeIdUtil.indexOfChangeId("x\n" + + "Change-Id: I3b7e4e16b503ce00f07ba6ad01d97a356dad7701\n" + + "\n" + "x\n", "\n")); + assertEquals(-1, ChangeIdUtil.indexOfChangeId("x\n\n" + + "Change-Id: I3b7e4e16b503ce00f07ba6ad01d97a356dad7701\n" + + "\n" + "x\n", "\n")); assertEquals(5, ChangeIdUtil.indexOfChangeId("x\r\n" + "\r\n" + "Change-Id: I3b7e4e16b503ce00f07ba6ad01d97a356dad7701\r\n", "\r\n")); assertEquals(3, ChangeIdUtil.indexOfChangeId("x\r" + "\r" + "Change-Id: I3b7e4e16b503ce00f07ba6ad01d97a356dad7701\r", "\r")); + assertEquals(3, ChangeIdUtil.indexOfChangeId("x\r" + "\r" + + "Change-Id: I3b7e4e16b503ce00f07ba6ad01d97a356dad7701\r", + "\r")); assertEquals(8, ChangeIdUtil.indexOfChangeId("x\ny\n\nz\n" + "\n" + "Change-Id: I3b7e4e16b503ce00f07ba6ad01d97a356dad7701\n", "\n")); } - @Test - public void testIndexOfFirstFooterLine() { - assertEquals( - 2, - ChangeIdUtil.indexOfFirstFooterLine(new String[] { "a", "", - "Bug: 42", "Signed-Off-By: j.developer@a.com" })); - assertEquals( - 3, - ChangeIdUtil.indexOfFirstFooterLine(new String[] { "a", - "Bug: 42", "", "Signed-Off-By: j.developer@a.com" })); - } - private void hookDoesNotModify(final String in) throws Exception { assertEquals(in, call(in)); } diff --git a/org.eclipse.jgit.ui/META-INF/MANIFEST.MF b/org.eclipse.jgit.ui/META-INF/MANIFEST.MF index 684f23cd77..97230df851 100644 --- a/org.eclipse.jgit.ui/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.ui/META-INF/MANIFEST.MF @@ -3,15 +3,15 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %plugin_name Bundle-SymbolicName: org.eclipse.jgit.ui -Bundle-Version: 2.3.0.qualifier +Bundle-Version: 2.4.0.qualifier Bundle-Vendor: %provider_name Bundle-RequiredExecutionEnvironment: J2SE-1.5 -Export-Package: org.eclipse.jgit.awtui;version="2.3.0" -Import-Package: org.eclipse.jgit.errors;version="[2.3.0,2.4.0)", - org.eclipse.jgit.lib;version="[2.3.0,2.4.0)", - org.eclipse.jgit.nls;version="[2.3.0,2.4.0)", - org.eclipse.jgit.revplot;version="[2.3.0,2.4.0)", - org.eclipse.jgit.revwalk;version="[2.3.0,2.4.0)", - org.eclipse.jgit.transport;version="[2.3.0,2.4.0)", - org.eclipse.jgit.util;version="[2.3.0,2.4.0)" +Export-Package: org.eclipse.jgit.awtui;version="2.4.0" +Import-Package: org.eclipse.jgit.errors;version="[2.4.0,2.5.0)", + org.eclipse.jgit.lib;version="[2.4.0,2.5.0)", + org.eclipse.jgit.nls;version="[2.4.0,2.5.0)", + org.eclipse.jgit.revplot;version="[2.4.0,2.5.0)", + org.eclipse.jgit.revwalk;version="[2.4.0,2.5.0)", + org.eclipse.jgit.transport;version="[2.4.0,2.5.0)", + org.eclipse.jgit.util;version="[2.4.0,2.5.0)" Require-Bundle: com.jcraft.jsch;bundle-version="[0.1.37,0.2.0)" diff --git a/org.eclipse.jgit.ui/pom.xml b/org.eclipse.jgit.ui/pom.xml index 8c70c54fee..bb3f49f123 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>2.3.0-SNAPSHOT</version> + <version>2.4.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 095068fd5d..30f2be1cf8 100644 --- a/org.eclipse.jgit/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit/META-INF/MANIFEST.MF @@ -2,37 +2,37 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %plugin_name Bundle-SymbolicName: org.eclipse.jgit -Bundle-Version: 2.3.0.qualifier +Bundle-Version: 2.4.0.qualifier Bundle-Localization: plugin Bundle-Vendor: %provider_name -Export-Package: org.eclipse.jgit.api;version="2.3.0", - org.eclipse.jgit.api.errors;version="2.3.0", - org.eclipse.jgit.blame;version="2.3.0", - org.eclipse.jgit.diff;version="2.3.0", - org.eclipse.jgit.dircache;version="2.3.0", - org.eclipse.jgit.errors;version="2.3.0", - org.eclipse.jgit.events;version="2.3.0", - org.eclipse.jgit.fnmatch;version="2.3.0", - org.eclipse.jgit.ignore;version="2.3.0", - org.eclipse.jgit.internal;version="2.3.0";x-friends:="org.eclipse.jgit.test,org.eclipse.jgit.http.test", - org.eclipse.jgit.lib;version="2.3.0", - org.eclipse.jgit.merge;version="2.3.0", - org.eclipse.jgit.nls;version="2.3.0", - org.eclipse.jgit.notes;version="2.3.0", - org.eclipse.jgit.patch;version="2.3.0", - org.eclipse.jgit.revplot;version="2.3.0", - org.eclipse.jgit.revwalk;version="2.3.0", - org.eclipse.jgit.revwalk.filter;version="2.3.0", - org.eclipse.jgit.storage.dfs;version="2.3.0", - org.eclipse.jgit.storage.file;version="2.3.0", - org.eclipse.jgit.storage.pack;version="2.3.0", - org.eclipse.jgit.submodule;version="2.3.0", - org.eclipse.jgit.transport;version="2.3.0", - org.eclipse.jgit.transport.resolver;version="2.3.0", - org.eclipse.jgit.treewalk;version="2.3.0", - org.eclipse.jgit.treewalk.filter;version="2.3.0", - org.eclipse.jgit.util;version="2.3.0", - org.eclipse.jgit.util.io;version="2.3.0" +Export-Package: org.eclipse.jgit.api;version="2.4.0", + org.eclipse.jgit.api.errors;version="2.4.0", + org.eclipse.jgit.blame;version="2.4.0", + org.eclipse.jgit.diff;version="2.4.0", + org.eclipse.jgit.dircache;version="2.4.0", + org.eclipse.jgit.errors;version="2.4.0", + org.eclipse.jgit.events;version="2.4.0", + org.eclipse.jgit.fnmatch;version="2.4.0", + org.eclipse.jgit.ignore;version="2.4.0", + org.eclipse.jgit.internal;version="2.4.0";x-friends:="org.eclipse.jgit.test,org.eclipse.jgit.http.test", + org.eclipse.jgit.lib;version="2.4.0", + org.eclipse.jgit.merge;version="2.4.0", + org.eclipse.jgit.nls;version="2.4.0", + org.eclipse.jgit.notes;version="2.4.0", + org.eclipse.jgit.patch;version="2.4.0", + org.eclipse.jgit.revplot;version="2.4.0", + org.eclipse.jgit.revwalk;version="2.4.0", + org.eclipse.jgit.revwalk.filter;version="2.4.0", + org.eclipse.jgit.storage.dfs;version="2.4.0", + org.eclipse.jgit.storage.file;version="2.4.0", + org.eclipse.jgit.storage.pack;version="2.4.0", + org.eclipse.jgit.submodule;version="2.4.0", + org.eclipse.jgit.transport;version="2.4.0", + org.eclipse.jgit.transport.resolver;version="2.4.0", + org.eclipse.jgit.treewalk;version="2.4.0", + org.eclipse.jgit.treewalk.filter;version="2.4.0", + org.eclipse.jgit.util;version="2.4.0", + org.eclipse.jgit.util.io;version="2.4.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 12ef8a5e56..764b68b326 100644 --- a/org.eclipse.jgit/META-INF/SOURCE-MANIFEST.MF +++ b/org.eclipse.jgit/META-INF/SOURCE-MANIFEST.MF @@ -3,6 +3,6 @@ Bundle-ManifestVersion: 2 Bundle-Name: org.eclipse.jgit - Sources Bundle-SymbolicName: org.eclipse.jgit.source;singleton:=true Bundle-Vendor: Eclipse.org - JGit -Bundle-Version: 2.3.0.qualifier -Eclipse-SourceBundle: org.eclipse.jgit;version="2.3.0";roots="." +Bundle-Version: 2.4.0.qualifier +Eclipse-SourceBundle: org.eclipse.jgit;version="2.4.0";roots="." diff --git a/org.eclipse.jgit/pom.xml b/org.eclipse.jgit/pom.xml index 41640d55ff..a4167292d9 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>2.3.0-SNAPSHOT</version> + <version>2.4.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 b3ef62ad04..cc0b766231 100644 --- a/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties +++ b/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties @@ -288,6 +288,8 @@ mergeConflictOnNotes=Merge conflict on note {0}. base = {1}, ours = {2}, theirs mergeStrategyAlreadyExistsAsDefault=Merge strategy "{0}" already exists as a default strategy mergeStrategyDoesNotSupportHeads=merge strategy {0} does not support {1} heads to be merged into HEAD mergeUsingStrategyResultedInDescription=Merge of revisions {0} with base {1} using strategy {2} resulted in: {3}. {4} +mergeRecursiveReturnedNoCommit=Merge returned no commit:\n Depth {0}\n Head one {1}\n Head two {2} +mergeRecursiveTooManyMergeBasesFor = "More than {0} merge bases for:\n a {1}\n b {2} found:\n count {3}" minutesAgo={0} minutes ago missingAccesskey=Missing accesskey. missingConfigurationForKey=No value for key {0} found in configuration @@ -313,6 +315,7 @@ noApplyInDelete=No apply in delete noClosingBracket=No closing {0} found for {1} at index {2}. noHEADExistsAndNoExplicitStartingRevisionWasSpecified=No HEAD exists and no explicit starting revision was specified noHMACsupport=No {0} support: {1} +noMergeBase=No merge base could be determined. Reason={0}. {1} noMergeHeadSpecified=No merge head specified noSuchRef=no such ref notABoolean=Not a boolean: {0} 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 7629de6434..292206e539 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java @@ -683,6 +683,8 @@ public class DirCacheCheckout { } if (i == null) { + // Nothing in Index + // At least one of Head, Index, Merge is not empty // make sure not to overwrite untracked files if (f != null) { // A submodule is not a file. We should ignore it @@ -711,17 +713,37 @@ public class DirCacheCheckout { */ if (h == null) + // Nothing in Head + // Nothing in Index + // At least one of Head, Index, Merge is not empty + // -> only Merge contains something for this path. Use it! + // Potentially update the file update(name, mId, mMode); // 1 else if (m == null) + // Nothing in Merge + // Something in Head + // Nothing in Index + // -> only Head contains something for this path and it should + // be deleted. Potentially removes the file! remove(name); // 2 else { // 3 + // Something in Merge + // Something in Head + // Nothing in Index + // -> Head and Merge contain something (maybe not the same) and + // in the index there is nothing (e.g. 'git rm ...' was + // called before). Ignore the cached deletion and use what we + // find in Merge. Potentially updates the file. if (equalIdAndMode(hId, hMode, mId, mMode)) keep(dce); else conflict(name, dce, h, m); } } else { + // Something in Index if (h == null) { + // Nothing in Head + // Something in Index /** * <pre> * clean I==H I==M H M Result @@ -737,17 +759,54 @@ public class DirCacheCheckout { */ if (m == null || equalIdAndMode(mId, mMode, iId, iMode)) { + // Merge contains nothing or the same as Index + // Nothing in Head + // Something in Index if (m==null && walk.isDirectoryFileConflict()) { + // Nothing in Merge and current path is part of + // File/Folder conflict + // Nothing in Head + // Something in Index if (dce != null && (f == null || f.isModified(dce, true))) + // No file or file is dirty + // Nothing in Merge and current path is part of + // File/Folder conflict + // Nothing in Head + // Something in Index + // -> File folder conflict and Merge wants this + // path to be removed. Since the file is dirty + // report a conflict conflict(name, dce, h, m); else + // A file is present and file is not dirty + // Nothing in Merge and current path is part of + // File/Folder conflict + // Nothing in Head + // Something in Index + // -> File folder conflict and Merge wants this path + // to be removed. Since the file is not dirty remove + // file and index entry remove(name); } else + // Something in Merge or current path is not part of + // File/Folder conflict + // Merge contains nothing or the same as Index + // Nothing in Head + // Something in Index + // -> Merge contains nothing new. Keep the index. keep(dce); } else + // Merge contains something and it is not the same as Index + // Nothing in Head + // Something in Index + // -> Index contains something new (different from Head) + // and Merge is different from Index. Report a conflict conflict(name, dce, h, m); } else if (m == null) { + // Nothing in Merge + // Something in Head + // Something in Index /** * <pre> @@ -761,36 +820,115 @@ public class DirCacheCheckout { */ if (iMode == FileMode.GITLINK) { + // A submodule in Index + // Nothing in Merge + // Something in Head // Submodules that disappear from the checkout must // be removed from the index, but not deleted from disk. remove(name); } else { + // Something different from a submodule in Index + // Nothing in Merge + // Something in Head if (equalIdAndMode(hId, hMode, iId, iMode)) { + // Index contains the same as Head + // Something different from a submodule in Index + // Nothing in Merge + // Something in Head if (f == null || f.isModified(dce, true)) + // file is dirty + // Index contains the same as Head + // Something different from a submodule in Index + // Nothing in Merge + // Something in Head + // -> file is dirty but is should be removed. That's + // a conflict conflict(name, dce, h, m); else + // file doesn't exist or is clean + // Index contains the same as Head + // Something different from a submodule in Index + // Nothing in Merge + // Something in Head + // -> Remove from index and delete the file remove(name); } else + // Index contains something different from Head + // Something different from a submodule in Index + // Nothing in Merge + // Something in Head + // -> Something new is in index (and maybe even on the + // filesystem). But Merge wants the path to be removed. + // Report a conflict conflict(name, dce, h, m); } } else { + // Something in Merge + // Something in Head + // Something in Index if (!equalIdAndMode(hId, hMode, mId, mMode) && !equalIdAndMode(hId, hMode, iId, iMode) && !equalIdAndMode(mId, mMode, iId, iMode)) + // All three contents in Head, Merge, Index differ from each + // other + // -> All contents differ. Report a conflict. conflict(name, dce, h, m); - else if (equalIdAndMode(hId, hMode, iId, iMode) + else + // At least two of the contents of Head, Index, Merge + // are the same + // Something in Merge + // Something in Head + // Something in Index + + if (equalIdAndMode(hId, hMode, iId, iMode) && !equalIdAndMode(mId, mMode, iId, iMode)) { + // Head contains the same as Index. Merge differs + // Something in Merge + // For submodules just update the index with the new SHA-1 if (dce != null && FileMode.GITLINK.equals(dce.getFileMode())) { + // Index and Head contain the same submodule. Merge + // differs + // Something in Merge + // -> Nothing new in index. Move to merge. + // Potentially updates the file + + // TODO check that we don't overwrite some unsaved + // file content update(name, mId, mMode); } else if (dce != null && (f == null || f.isModified(dce, true))) { + // File doesn't exist or is dirty + // Head and Index don't contain a submodule + // Head contains the same as Index. Merge differs + // Something in Merge + // -> Merge wants the index and file to be updated + // but the file is dirty. Report a conflict conflict(name, dce, h, m); } else { + // File exists and is clean + // Head and Index don't contain a submodule + // Head contains the same as Index. Merge differs + // Something in Merge + // -> Standard case when switching between branches: + // Nothing new in index but something different in + // Merge. Update index and file update(name, mId, mMode); } } else { + // Head differs from index or merge is same as index + // At least two of the contents of Head, Index, Merge + // are the same + // Something in Merge + // Something in Head + // Something in Index + + // Can be formulated as: Either all three states are + // equal or Merge is equal to Head or Index and differs + // to the other one. + // -> In all three cases we don't touch index and file. + keep(dce); } } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/errors/NoMergeBaseException.java b/org.eclipse.jgit/src/org/eclipse/jgit/errors/NoMergeBaseException.java new file mode 100644 index 0000000000..df90e69009 --- /dev/null +++ b/org.eclipse.jgit/src/org/eclipse/jgit/errors/NoMergeBaseException.java @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2013, 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.errors; + +import java.io.IOException; +import java.text.MessageFormat; + +import org.eclipse.jgit.internal.JGitText; +import org.eclipse.jgit.merge.RecursiveMerger; + +/** + * Exception thrown if a merge fails because no merge base could be determined. + */ +public class NoMergeBaseException extends IOException { + private static final long serialVersionUID = 1L; + + private MergeBaseFailureReason reason; + + /** + * An enum listing the different reason why no merge base could be + * determined. + */ + public static enum MergeBaseFailureReason { + /** + * Multiple merge bases have been found (e.g. the commits to be merged + * have multiple common predecessors) but the merge strategy doesn't + * support this (e.g. ResolveMerge) + */ + MULTIPLE_MERGE_BASES_NOT_SUPPORTED, + + /** + * The number of merge bases exceeds {@link RecursiveMerger#MAX_BASES} + */ + TOO_MANY_MERGE_BASES, + + /** + * In order to find a single merge base it may required to merge + * together multiple common predecessors. If during these merges + * conflicts occur the merge fails with this reason + */ + CONFLICTS_DURING_MERGE_BASE_CALCULATION + } + + + /** + * Construct a NoMergeBase exception + * + * @param reason + * the reason why no merge base could be found + * @param message + * a text describing the problem + */ + public NoMergeBaseException(MergeBaseFailureReason reason, String message) { + super(MessageFormat.format(JGitText.get().noMergeBase, + reason.toString(), message)); + this.reason = reason; + } + + /** + * Construct a NoMergeBase exception + * + * @param reason + * the reason why no merge base could be found + * @param message + * a text describing the problem + * @param why + * an exception causing this error + */ + public NoMergeBaseException(MergeBaseFailureReason reason, String message, + Throwable why) { + super(MessageFormat.format(JGitText.get().noMergeBase, + reason.toString(), message)); + this.reason = reason; + initCause(why); + } + + /** + * @return the reason why no merge base could be found + */ + public MergeBaseFailureReason getReason() { + return reason; + } +} 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 d032bbc88b..f8ea5ff932 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java @@ -1,5 +1,6 @@ /* * Copyright (C) 2010, 2013 Sasa Zivkov <sasa.zivkov@sap.com> + * Copyright (C) 2012, Research In Motion Limited * and other copyright owners as documented in the project's IP log. * * This program and the accompanying materials are made available @@ -349,6 +350,8 @@ public class JGitText extends TranslationBundle { /***/ public String mergeStrategyAlreadyExistsAsDefault; /***/ public String mergeStrategyDoesNotSupportHeads; /***/ public String mergeUsingStrategyResultedInDescription; + /***/ public String mergeRecursiveReturnedNoCommit; + /***/ public String mergeRecursiveTooManyMergeBasesFor; /***/ public String minutesAgo; /***/ public String missingAccesskey; /***/ public String missingConfigurationForKey; @@ -374,6 +377,7 @@ public class JGitText extends TranslationBundle { /***/ public String noClosingBracket; /***/ public String noHEADExistsAndNoExplicitStartingRevisionWasSpecified; /***/ public String noHMACsupport; + /***/ public String noMergeBase; /***/ public String noMergeHeadSpecified; /***/ public String noSuchRef; /***/ public String notABoolean; 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 8fd84c8938..88d274147f 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java @@ -1,6 +1,7 @@ /* * Copyright (C) 2010, Mathias Kinzler <mathias.kinzler@sap.com> * Copyright (C) 2010, Chris Aniszczyk <caniszczyk@gmail.com> + * Copyright (C) 2012-2013, Robin Rosenberg * and other copyright owners as documented in the project's IP log. * * This program and the accompanying materials are made available @@ -194,4 +195,7 @@ public class ConfigConstants { /** The "ff" key */ public static final String CONFIG_KEY_FF = "ff"; + + /** The "checkstat" key */ + public static final String CONFIG_KEY_CHECKSTAT = "checkstat"; } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/CoreConfig.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/CoreConfig.java index 23aca37948..982cbc84e1 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/CoreConfig.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/CoreConfig.java @@ -74,6 +74,25 @@ public class CoreConfig { INPUT; } + /** + * Permissible values for {@code core.checkstat} + * + * @since 2.3 + */ + public static enum CheckStat { + /** + * Only check the size and whole second part of time stamp when + * comparing the stat info in the dircache with actual file stat info. + */ + MINIMAL, + + /** + * Check as much of the dircache stat info as possible. Implementation + * limits may apply. + */ + DEFAULT + } + private final int compression; private final int packIndexVersion; diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeStrategy.java b/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeStrategy.java index 2e6fc41378..3b64ddd361 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeStrategy.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeStrategy.java @@ -1,6 +1,7 @@ /* * Copyright (C) 2008-2009, Google Inc. * Copyright (C) 2009, Matthias Sohn <matthias.sohn@sap.com> + * Copyright (C) 2012, Research In Motion Limited * and other copyright owners as documented in the project's IP log. * * This program and the accompanying materials are made available @@ -66,9 +67,18 @@ public abstract class MergeStrategy { /** Simple strategy to merge paths, without simultaneous edits. */ public static final ThreeWayMergeStrategy SIMPLE_TWO_WAY_IN_CORE = new StrategySimpleTwoWayInCore(); - /** Simple strategy to merge paths. It tries to merge also contents. Multiple merge bases are not supported */ + /** + * Simple strategy to merge paths. It tries to merge also contents. Multiple + * merge bases are not supported + */ public static final ThreeWayMergeStrategy RESOLVE = new StrategyResolve(); + /** + * Recursive strategy to merge paths. It tries to merge also contents. + * Multiple merge bases are supported + */ + public static final ThreeWayMergeStrategy RECURSIVE = new StrategyRecursive(); + private static final HashMap<String, MergeStrategy> STRATEGIES = new HashMap<String, MergeStrategy>(); static { @@ -76,6 +86,7 @@ public abstract class MergeStrategy { register(THEIRS); register(SIMPLE_TWO_WAY_IN_CORE); register(RESOLVE); + register(RECURSIVE); } /** @@ -103,7 +114,8 @@ public abstract class MergeStrategy { public static synchronized void register(final String name, final MergeStrategy imp) { if (STRATEGIES.containsKey(name)) - throw new IllegalArgumentException(MessageFormat.format(JGitText.get().mergeStrategyAlreadyExistsAsDefault, name)); + throw new IllegalArgumentException(MessageFormat.format( + JGitText.get().mergeStrategyAlreadyExistsAsDefault, name)); STRATEGIES.put(name, imp); } @@ -146,7 +158,7 @@ public abstract class MergeStrategy { /** * Create a new merge instance. - * + * * @param db * repository database the merger will read from, and eventually * write results back to. diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/merge/Merger.java b/org.eclipse.jgit/src/org/eclipse/jgit/merge/Merger.java index fd94cfb23f..04c29e6e83 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/merge/Merger.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/merge/Merger.java @@ -47,6 +47,8 @@ import java.io.IOException; import java.text.MessageFormat; import org.eclipse.jgit.errors.IncorrectObjectTypeException; +import org.eclipse.jgit.errors.NoMergeBaseException; +import org.eclipse.jgit.errors.NoMergeBaseException.MergeBaseFailureReason; import org.eclipse.jgit.internal.JGitText; import org.eclipse.jgit.lib.AnyObjectId; import org.eclipse.jgit.lib.Constants; @@ -186,19 +188,19 @@ public abstract class Merger { /** * Create an iterator to walk the merge base of two commits. * - * @param aIdx - * index of the first commit in {@link #sourceObjects}. - * @param bIdx - * index of the second commit in {@link #sourceObjects}. + * @param a + * the first commit in {@link #sourceObjects}. + * @param b + * the second commit in {@link #sourceObjects}. * @return the new iterator * @throws IncorrectObjectTypeException * one of the input objects is not a commit. * @throws IOException * objects are missing or multiple merge bases were found. */ - protected AbstractTreeIterator mergeBase(final int aIdx, final int bIdx) + protected AbstractTreeIterator mergeBase(RevCommit a, RevCommit b) throws IOException { - RevCommit base = getBaseCommit(aIdx, bIdx); + RevCommit base = getBaseCommit(a, b); return (base == null) ? new EmptyTreeIterator() : openTree(base.getTree()); } @@ -224,18 +226,38 @@ public abstract class Merger { if (sourceCommits[bIdx] == null) throw new IncorrectObjectTypeException(sourceObjects[bIdx], Constants.TYPE_COMMIT); + return getBaseCommit(sourceCommits[aIdx], sourceCommits[bIdx]); + } + + /** + * Return the merge base of two commits. + * + * @param a + * the first commit in {@link #sourceObjects}. + * @param b + * the second commit in {@link #sourceObjects}. + * @return the merge base of two commits + * @throws IncorrectObjectTypeException + * one of the input objects is not a commit. + * @throws IOException + * objects are missing or multiple merge bases were found. + */ + protected RevCommit getBaseCommit(RevCommit a, RevCommit b) + throws IncorrectObjectTypeException, IOException { walk.reset(); walk.setRevFilter(RevFilter.MERGE_BASE); - walk.markStart(sourceCommits[aIdx]); - walk.markStart(sourceCommits[bIdx]); + walk.markStart(a); + walk.markStart(b); final RevCommit base = walk.next(); if (base == null) return null; final RevCommit base2 = walk.next(); if (base2 != null) { - throw new IOException(MessageFormat.format(JGitText.get().multipleMergeBasesFor - , sourceCommits[aIdx].name(), sourceCommits[bIdx].name() - , base.name(), base2.name())); + throw new NoMergeBaseException( + MergeBaseFailureReason.MULTIPLE_MERGE_BASES_NOT_SUPPORTED, + MessageFormat.format( + JGitText.get().multipleMergeBasesFor, a.name(), b.name(), + base.name(), base2.name())); } return base; } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/merge/RecursiveMerger.java b/org.eclipse.jgit/src/org/eclipse/jgit/merge/RecursiveMerger.java new file mode 100644 index 0000000000..d68be35403 --- /dev/null +++ b/org.eclipse.jgit/src/org/eclipse/jgit/merge/RecursiveMerger.java @@ -0,0 +1,274 @@ +/* + * Copyright (C) 2012, Research In Motion Limited + * Copyright (C) 2012, 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. + */ + +/* + * Contributors: + * George Young - initial API and implementation + * Christian Halstrick - initial API and implementation + */ +package org.eclipse.jgit.merge; + +import java.io.IOException; +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.List; +import java.util.logging.Logger; + +import org.eclipse.jgit.dircache.DirCache; +import org.eclipse.jgit.dircache.DirCacheBuilder; +import org.eclipse.jgit.dircache.DirCacheEntry; +import org.eclipse.jgit.errors.IncorrectObjectTypeException; +import org.eclipse.jgit.errors.NoMergeBaseException; +import org.eclipse.jgit.internal.JGitText; +import org.eclipse.jgit.lib.CommitBuilder; +import org.eclipse.jgit.lib.ObjectId; +import org.eclipse.jgit.lib.ObjectInserter; +import org.eclipse.jgit.lib.PersonIdent; +import org.eclipse.jgit.lib.Repository; +import org.eclipse.jgit.revwalk.RevCommit; +import org.eclipse.jgit.revwalk.filter.RevFilter; +import org.eclipse.jgit.treewalk.TreeWalk; +import org.eclipse.jgit.treewalk.WorkingTreeIterator; + +/** + * A three-way merger performing a content-merge if necessary across multiple + * bases using recursion + * + * This merger extends the resolve merger and does several things differently: + * + * - allow more than one merge base, up to a maximum + * + * - uses "Lists" instead of Arrays for chained types + * + * - recursively merges the merge bases together to compute a usable base + * + */ + +public class RecursiveMerger extends ResolveMerger { + static Logger log = Logger.getLogger(RecursiveMerger.class.toString()); + + /** + * The maximum number of merge bases. This merge will stop when the number + * of merge bases exceeds this value + */ + public final int MAX_BASES = 200; + + private PersonIdent ident = new PersonIdent(db); + + /** + * Normal recursive merge when you want a choice of DirCache placement + * inCore + * + * @param local + * @param inCore + */ + protected RecursiveMerger(Repository local, boolean inCore) { + super(local, inCore); + } + + /** + * Normal recursive merge, implies not inCore + * + * @param local + */ + protected RecursiveMerger(Repository local) { + this(local, false); + } + + /** + * Get a single base commit for two given commits. If the two source commits + * have more than one base commit recursively merge the base commits + * together until you end up with a single base commit. + * + * @throws IOException + * @throws IncorrectObjectTypeException + */ + @Override + protected RevCommit getBaseCommit(RevCommit a, RevCommit b) + throws IncorrectObjectTypeException, IOException { + return getBaseCommit(a, b, 0); + } + + /** + * Get a single base commit for two given commits. If the two source commits + * have more than one base commit recursively merge the base commits + * together until a virtual common base commit has been found. + * + * @param a + * the first commit to be merged + * @param b + * the second commit to be merged + * @param callDepth + * the callDepth when this method is called recursively + * @return the merge base of two commits + * @throws IOException + * @throws IncorrectObjectTypeException + * one of the input objects is not a commit. + * @throws NoMergeBaseException + * too many merge bases are found or the computation of a common + * merge base failed (e.g. because of a conflict). + */ + protected RevCommit getBaseCommit(RevCommit a, RevCommit b, int callDepth) + throws IOException { + ArrayList<RevCommit> baseCommits = new ArrayList<RevCommit>(); + walk.reset(); + walk.setRevFilter(RevFilter.MERGE_BASE); + walk.markStart(a); + walk.markStart(b); + RevCommit c; + while ((c = walk.next()) != null) + baseCommits.add(c); + + if (baseCommits.isEmpty()) + return null; + if (baseCommits.size() == 1) + return baseCommits.get(0); + if (baseCommits.size() >= MAX_BASES) + throw new NoMergeBaseException(NoMergeBaseException.MergeBaseFailureReason.TOO_MANY_MERGE_BASES, MessageFormat.format( + JGitText.get().mergeRecursiveTooManyMergeBasesFor, + Integer.valueOf(MAX_BASES), a.name(), b.name(), + Integer.valueOf(baseCommits.size()))); + + // We know we have more than one base commit. We have to do merges now + // to determine a single base commit. We don't want to spoil the current + // dircache and working tree with the results of this intermediate + // merges. Therefore set the dircache to a new in-memory dircache and + // disable that we update the working-tree. We set this back to the + // original values once a single base commit is created. + RevCommit currentBase = baseCommits.get(0); + DirCache oldDircache = dircache; + boolean oldIncore = inCore; + WorkingTreeIterator oldWTreeIt = workingTreeIterator; + workingTreeIterator = null; + try { + dircache = dircacheFromTree(currentBase.getTree()); + inCore = true; + + List<RevCommit> parents = new ArrayList<RevCommit>(); + parents.add(currentBase); + for (int commitIdx = 1; commitIdx < baseCommits.size(); commitIdx++) { + RevCommit nextBase = baseCommits.get(commitIdx); + if (commitIdx >= MAX_BASES) + throw new NoMergeBaseException( + NoMergeBaseException.MergeBaseFailureReason.TOO_MANY_MERGE_BASES, + MessageFormat.format( + JGitText.get().mergeRecursiveTooManyMergeBasesFor, + Integer.valueOf(MAX_BASES), a.name(), b.name(), + Integer.valueOf(baseCommits.size()))); + parents.add(nextBase); + if (mergeTrees( + openTree(getBaseCommit(currentBase, nextBase, + callDepth + 1).getTree()), + currentBase.getTree(), + nextBase.getTree())) + currentBase = createCommitForTree(resultTree, parents); + else + throw new NoMergeBaseException( + NoMergeBaseException.MergeBaseFailureReason.CONFLICTS_DURING_MERGE_BASE_CALCULATION, + MessageFormat.format( + JGitText.get().mergeRecursiveTooManyMergeBasesFor, + Integer.valueOf(MAX_BASES), a.name(), + b.name(), + Integer.valueOf(baseCommits.size()))); + } + } finally { + inCore = oldIncore; + dircache = oldDircache; + workingTreeIterator = oldWTreeIt; + } + return currentBase; + } + + /** + * Create a new commit by explicitly specifying the content tree and the + * parents. The commit message is not set and author/committer are set to + * the current user. + * + * @param tree + * the tree this commit should capture + * @param parents + * the list of parent commits + * @return a new (persisted) commit + * @throws IOException + */ + private RevCommit createCommitForTree(ObjectId tree, List<RevCommit> parents) + throws IOException { + CommitBuilder c = new CommitBuilder(); + c.setParentIds(parents); + c.setTreeId(tree); + c.setAuthor(ident); + c.setCommitter(ident); + ObjectInserter odi = db.newObjectInserter(); + ObjectId newCommitId = odi.insert(c); + odi.flush(); + RevCommit ret = walk.lookupCommit(newCommitId); + walk.parseHeaders(ret); + return ret; + } + + /** + * Create a new in memory dircache which has the same content as a given + * tree. + * + * @param treeId + * the tree which should be used to fill the dircache + * @return a new in memory dircache + * @throws IOException + */ + private DirCache dircacheFromTree(ObjectId treeId) throws IOException { + DirCache ret = DirCache.newInCore(); + DirCacheBuilder builder = ret.builder(); + TreeWalk tw = new TreeWalk(db); + tw.addTree(treeId); + tw.setRecursive(true); + while (tw.next()) { + DirCacheEntry e = new DirCacheEntry(tw.getRawPath()); + e.setFileMode(tw.getFileMode(0)); + e.setObjectId(tw.getObjectId(0)); + builder.add(e); + } + builder.finish(); + return ret; + } +} diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java b/org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java index 433458a273..bea2119333 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java @@ -1,6 +1,7 @@ /* * Copyright (C) 2010, Christian Halstrick <christian.halstrick@sap.com>, * Copyright (C) 2010-2012, Matthias Sohn <matthias.sohn@sap.com> + * Copyright (C) 2012, Research In Motion Limited * and other copyright owners as documented in the project's IP log. * * This program and the accompanying materials are made available @@ -80,6 +81,8 @@ import org.eclipse.jgit.lib.FileMode; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.ObjectReader; import org.eclipse.jgit.lib.Repository; +import org.eclipse.jgit.revwalk.RevTree; +import org.eclipse.jgit.treewalk.AbstractTreeIterator; import org.eclipse.jgit.treewalk.CanonicalTreeParser; import org.eclipse.jgit.treewalk.NameConflictTreeWalk; import org.eclipse.jgit.treewalk.WorkingTreeIterator; @@ -104,7 +107,10 @@ public class ResolveMerger extends ThreeWayMerger { private NameConflictTreeWalk tw; - private String commitNames[]; + /** + * string versions of a list of commit SHA1s + */ + protected String commitNames[]; private static final int T_BASE = 0; @@ -118,7 +124,10 @@ public class ResolveMerger extends ThreeWayMerger { private DirCacheBuilder builder; - private ObjectId resultTree; + /** + * merge result as tree + */ + protected ObjectId resultTree; private List<String> unmergedPaths = new ArrayList<String>(); @@ -134,13 +143,38 @@ public class ResolveMerger extends ThreeWayMerger { private boolean enterSubtree; - private boolean inCore; + /** + * Set to true if this merge should work in-memory. The repos dircache and + * workingtree are not touched by this method. Eventually needed files are + * created as temporary files and a new empty, in-memory dircache will be + * used instead the repo's one. Often used for bare repos where the repo + * doesn't even have a workingtree and dircache. + */ + protected boolean inCore; + + /** + * Set to true if this merger should use the default dircache of the + * repository and should handle locking and unlocking of the dircache. If + * this merger should work in-core or if an explicit dircache was specified + * during construction then this field is set to false. + */ + protected boolean implicitDirCache; - private DirCache dircache; + /** + * Directory cache + */ + protected DirCache dircache; - private WorkingTreeIterator workingTreeIterator; + /** + * The iterator to access the working tree. If set to <code>null</code> this + * merger will not touch the working tree. + */ + protected WorkingTreeIterator workingTreeIterator; - private MergeAlgorithm mergeAlgorithm; + /** + * our merge algorithm + */ + protected MergeAlgorithm mergeAlgorithm; /** * @param local @@ -153,11 +187,14 @@ public class ResolveMerger extends ThreeWayMerger { ConfigConstants.CONFIG_KEY_ALGORITHM, SupportedAlgorithm.HISTOGRAM); mergeAlgorithm = new MergeAlgorithm(DiffAlgorithm.getAlgorithm(diffAlg)); - commitNames = new String[] { "BASE", "OURS", "THEIRS" }; + commitNames = new String[] { "BASE", "OURS", "THEIRS" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ this.inCore = inCore; if (inCore) { + implicitDirCache = false; dircache = DirCache.newInCore(); + } else { + implicitDirCache = true; } } @@ -170,67 +207,11 @@ public class ResolveMerger extends ThreeWayMerger { @Override protected boolean mergeImpl() throws IOException { - boolean implicitDirCache = false; - - if (dircache == null) { + if (implicitDirCache) dircache = getRepository().lockDirCache(); - implicitDirCache = true; - } try { - builder = dircache.builder(); - DirCacheBuildIterator buildIt = new DirCacheBuildIterator(builder); - - tw = new NameConflictTreeWalk(db); - tw.addTree(mergeBase()); - tw.addTree(sourceTrees[0]); - tw.addTree(sourceTrees[1]); - tw.addTree(buildIt); - if (workingTreeIterator != null) - tw.addTree(workingTreeIterator); - - while (tw.next()) { - if (!processEntry( - tw.getTree(T_BASE, CanonicalTreeParser.class), - tw.getTree(T_OURS, CanonicalTreeParser.class), - tw.getTree(T_THEIRS, CanonicalTreeParser.class), - tw.getTree(T_INDEX, DirCacheBuildIterator.class), - (workingTreeIterator == null) ? null : tw.getTree(T_FILE, WorkingTreeIterator.class))) { - cleanUp(); - return false; - } - if (tw.isSubtree() && enterSubtree) - tw.enterSubtree(); - } - - if (!inCore) { - // No problem found. The only thing left to be done is to - // checkout all files from "theirs" which have been selected to - // go into the new index. - checkout(); - - // All content-merges are successfully done. If we can now write the - // new index we are on quite safe ground. Even if the checkout of - // files coming from "theirs" fails the user can work around such - // failures by checking out the index again. - if (!builder.commit()) { - cleanUp(); - throw new IndexWriteException(); - } - builder = null; - - } else { - builder.finish(); - builder = null; - } - - if (getUnmergedPaths().isEmpty() && !failed()) { - resultTree = dircache.writeTree(getObjectInserter()); - return true; - } else { - resultTree = null; - return false; - } + return mergeTrees(mergeBase(), sourceTrees[0], sourceTrees[1]); } finally { if (implicitDirCache) dircache.unlock(); @@ -279,14 +260,15 @@ public class ResolveMerger extends ThreeWayMerger { /** * Reverts the worktree after an unsuccessful merge. We know that for all * modified files the old content was in the old index and the index - * contained only stage 0. In case if inCore operation just clear - * the history of modified files. + * contained only stage 0. In case if inCore operation just clear the + * history of modified files. * * @throws IOException * @throws CorruptObjectException * @throws NoWorkTreeException */ - private void cleanUp() throws NoWorkTreeException, CorruptObjectException, IOException { + private void cleanUp() throws NoWorkTreeException, CorruptObjectException, + IOException { if (inCore) { modifiedFiles.clear(); return; @@ -298,7 +280,10 @@ public class ResolveMerger extends ThreeWayMerger { while(mpathsIt.hasNext()) { String mpath=mpathsIt.next(); DirCacheEntry entry = dc.getEntry(mpath); - FileOutputStream fos = new FileOutputStream(new File(db.getWorkTree(), mpath)); + if (entry == null) + continue; + FileOutputStream fos = new FileOutputStream(new File( + db.getWorkTree(), mpath)); try { or.open(entry.getObjectId()).copyTo(fos); } finally { @@ -610,6 +595,9 @@ public class ResolveMerger extends ThreeWayMerger { } private boolean isIndexDirty() { + if (inCore) + return false; + final int modeI = tw.getRawMode(T_INDEX); final int modeO = tw.getRawMode(T_OURS); @@ -623,7 +611,7 @@ public class ResolveMerger extends ThreeWayMerger { } private boolean isWorktreeDirty(WorkingTreeIterator work) { - if (inCore || work == null) + if (work == null) return false; final int modeF = tw.getRawMode(T_FILE); @@ -862,19 +850,20 @@ public class ResolveMerger extends ThreeWayMerger { /** * Sets the DirCache which shall be used by this merger. If the DirCache is - * not set explicitly this merger will implicitly get and lock a default - * DirCache. If the DirCache is explicitly set the caller is responsible to - * lock it in advance. Finally the merger will call - * {@link DirCache#commit()} which requires that the DirCache is locked. If - * the {@link #mergeImpl()} returns without throwing an exception the lock - * will be released. In case of exceptions the caller is responsible to - * release the lock. + * not set explicitly and if this merger doesn't work in-core, this merger + * will implicitly get and lock a default DirCache. If the DirCache is + * explicitly set the caller is responsible to lock it in advance. Finally + * the merger will call {@link DirCache#commit()} which requires that the + * DirCache is locked. If the {@link #mergeImpl()} returns without throwing + * an exception the lock will be released. In case of exceptions the caller + * is responsible to release the lock. * * @param dc * the DirCache to set */ public void setDirCache(DirCache dc) { this.dircache = dc; + implicitDirCache = false; } /** @@ -891,4 +880,73 @@ public class ResolveMerger extends ThreeWayMerger { public void setWorkingTreeIterator(WorkingTreeIterator workingTreeIterator) { this.workingTreeIterator = workingTreeIterator; } + + + /** + * The resolve conflict way of three way merging + * + * @param baseTree + * @param headTree + * @param mergeTree + * @return whether the trees merged cleanly + * @throws IOException + */ + protected boolean mergeTrees(AbstractTreeIterator baseTree, + RevTree headTree, RevTree mergeTree) throws IOException { + + builder = dircache.builder(); + DirCacheBuildIterator buildIt = new DirCacheBuildIterator(builder); + + tw = new NameConflictTreeWalk(db); + tw.addTree(baseTree); + tw.addTree(headTree); + tw.addTree(mergeTree); + tw.addTree(buildIt); + if (workingTreeIterator != null) + tw.addTree(workingTreeIterator); + + while (tw.next()) { + if (!processEntry( + tw.getTree(T_BASE, CanonicalTreeParser.class), + tw.getTree(T_OURS, CanonicalTreeParser.class), + tw.getTree(T_THEIRS, CanonicalTreeParser.class), + tw.getTree(T_INDEX, DirCacheBuildIterator.class), + (workingTreeIterator == null) ? null : tw.getTree(T_FILE, + WorkingTreeIterator.class))) { + cleanUp(); + return false; + } + if (tw.isSubtree() && enterSubtree) + tw.enterSubtree(); + } + + if (!inCore) { + // No problem found. The only thing left to be done is to + // checkout all files from "theirs" which have been selected to + // go into the new index. + checkout(); + + // All content-merges are successfully done. If we can now write the + // new index we are on quite safe ground. Even if the checkout of + // files coming from "theirs" fails the user can work around such + // failures by checking out the index again. + if (!builder.commit()) { + cleanUp(); + throw new IndexWriteException(); + } + builder = null; + + } else { + builder.finish(); + builder = null; + } + + if (getUnmergedPaths().isEmpty() && !failed()) { + resultTree = dircache.writeTree(getObjectInserter()); + return true; + } else { + resultTree = null; + return false; + } + } } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/merge/StrategyRecursive.java b/org.eclipse.jgit/src/org/eclipse/jgit/merge/StrategyRecursive.java new file mode 100644 index 0000000000..11c8bca5dd --- /dev/null +++ b/org.eclipse.jgit/src/org/eclipse/jgit/merge/StrategyRecursive.java @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2012, Research In Motion Limited + * 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.merge; + +import org.eclipse.jgit.lib.Repository; + +/** + * A three-way merge strategy performing a content-merge if necessary + */ +public class StrategyRecursive extends StrategyResolve { + + @Override + public ThreeWayMerger newMerger(Repository db) { + return new RecursiveMerger(db, false); + } + + @Override + public ThreeWayMerger newMerger(Repository db, boolean inCore) { + return new RecursiveMerger(db, inCore); + } + + @Override + public String getName() { + return "recursive"; + } +} diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/merge/ThreeWayMerger.java b/org.eclipse.jgit/src/org/eclipse/jgit/merge/ThreeWayMerger.java index 521f8963a4..1ad791bb79 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/merge/ThreeWayMerger.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/merge/ThreeWayMerger.java @@ -1,5 +1,6 @@ /* * Copyright (C) 2009, Google Inc. + * Copyright (C) 2012, Research In Motion Limited * and other copyright owners as documented in the project's IP log. * * This program and the accompanying materials are made available @@ -118,6 +119,6 @@ public abstract class ThreeWayMerger extends Merger { protected AbstractTreeIterator mergeBase() throws IOException { if (baseTree != null) return openTree(baseTree); - return mergeBase(0, 1); + return mergeBase(sourceCommits[0], sourceCommits[1]); } } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/storage/file/PackReverseIndex.java b/org.eclipse.jgit/src/org/eclipse/jgit/storage/file/PackReverseIndex.java index 990106b934..7eeb028339 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/storage/file/PackReverseIndex.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/storage/file/PackReverseIndex.java @@ -108,7 +108,7 @@ public class PackReverseIndex { int i64 = 0; for (final MutableEntry me : index) { final long o = me.getOffset(); - if (o < Integer.MAX_VALUE) + if (o <= Integer.MAX_VALUE) offsets32[i32++] = (int) o; else offsets64[i64++] = o; @@ -120,7 +120,7 @@ public class PackReverseIndex { int nth = 0; for (final MutableEntry me : index) { final long o = me.getOffset(); - if (o < Integer.MAX_VALUE) + if (o <= Integer.MAX_VALUE) nth32[Arrays.binarySearch(offsets32, (int) o)] = nth++; else nth64[Arrays.binarySearch(offsets64, o)] = nth++; 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 1858626cdf..9a7db888c6 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeIterator.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeIterator.java @@ -2,6 +2,7 @@ * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org> * Copyright (C) 2010, Christian Halstrick <christian.halstrick@sap.com> * Copyright (C) 2010, Matthias Sohn <matthias.sohn@sap.com> + * Copyright (C) 2012-2013, Robin Rosenberg * and other copyright owners as documented in the project's IP log. * * This program and the accompanying materials are made available @@ -75,6 +76,7 @@ import org.eclipse.jgit.lib.CoreConfig; import org.eclipse.jgit.lib.FileMode; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.Repository; +import org.eclipse.jgit.lib.CoreConfig.CheckStat; import org.eclipse.jgit.submodule.SubmoduleWalk; import org.eclipse.jgit.util.FS; import org.eclipse.jgit.util.IO; @@ -754,15 +756,23 @@ public abstract class WorkingTreeIterator extends AbstractTreeIterator { // Git under windows only stores seconds so we round the timestamp // Java gives us if it looks like the timestamp in index is seconds - // only. Otherwise we compare the timestamp at millisecond precision. + // only. Otherwise we compare the timestamp at millisecond precision, + // unless core.checkstat is set to "minimal", in which case we only + // compare the whole second part. long cacheLastModified = entry.getLastModified(); long fileLastModified = getEntryLastModified(); - if (cacheLastModified % 1000 == 0) - fileLastModified = fileLastModified - fileLastModified % 1000; + long lastModifiedMillis = fileLastModified % 1000; + long cacheMillis = cacheLastModified % 1000; + if (getOptions().getCheckStat() == CheckStat.MINIMAL) { + fileLastModified = fileLastModified - lastModifiedMillis; + cacheLastModified = cacheLastModified - cacheMillis; + } else if (cacheMillis == 0) + fileLastModified = fileLastModified - lastModifiedMillis; // Some Java version on Linux return whole seconds only even when // the file systems supports more precision. - else if (fileLastModified % 1000 == 0) - cacheLastModified = cacheLastModified - cacheLastModified % 1000; + else if (lastModifiedMillis == 0) + cacheLastModified = cacheLastModified - cacheMillis; + if (fileLastModified != cacheLastModified) return MetadataDiff.DIFFER_BY_TIMESTAMP; else if (!entry.isSmudged()) diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeOptions.java b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeOptions.java index dafb3a1517..93590fd222 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeOptions.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeOptions.java @@ -1,5 +1,6 @@ /* * Copyright (C) 2010, Marc Strapetz <marc.strapetz@syntevo.com> + * Copyright (C) 2012-2013, Robin Rosenberg * and other copyright owners as documented in the project's IP log. * * This program and the accompanying materials are made available @@ -46,6 +47,7 @@ import org.eclipse.jgit.lib.Config; import org.eclipse.jgit.lib.ConfigConstants; import org.eclipse.jgit.lib.Config.SectionParser; import org.eclipse.jgit.lib.CoreConfig.AutoCRLF; +import org.eclipse.jgit.lib.CoreConfig.CheckStat; /** Options used by the {@link WorkingTreeIterator}. */ public class WorkingTreeOptions { @@ -60,11 +62,15 @@ public class WorkingTreeOptions { private final AutoCRLF autoCRLF; + private final CheckStat checkStat; + private WorkingTreeOptions(final Config rc) { fileMode = rc.getBoolean(ConfigConstants.CONFIG_CORE_SECTION, ConfigConstants.CONFIG_KEY_FILEMODE, true); autoCRLF = rc.getEnum(ConfigConstants.CONFIG_CORE_SECTION, null, ConfigConstants.CONFIG_KEY_AUTOCRLF, AutoCRLF.FALSE); + checkStat = rc.getEnum(ConfigConstants.CONFIG_CORE_SECTION, null, + ConfigConstants.CONFIG_KEY_CHECKSTAT, CheckStat.DEFAULT); } /** @return true if the execute bit on working files should be trusted. */ @@ -76,4 +82,12 @@ public class WorkingTreeOptions { public AutoCRLF getAutoCRLF() { return autoCRLF; } + + /** + * @return how stat data is compared + * @since 2.3 + */ + public CheckStat getCheckStat() { + return checkStat; + } } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/filter/ByteArraySet.java b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/filter/ByteArraySet.java index 0df24af24f..5a35359821 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/filter/ByteArraySet.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/filter/ByteArraySet.java @@ -88,7 +88,7 @@ class ByteArraySet { } private static boolean equals(byte[] a, byte[] b, int length) { - if (a.length < length || b.length < length) + if (a.length != length || b.length < length) return false; for (int i = 0; i < length; ++i) { if (a[i] != b[i]) diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/ChangeIdUtil.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/ChangeIdUtil.java index 41bb4cc7eb..7487f0d2b9 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/util/ChangeIdUtil.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/ChangeIdUtil.java @@ -125,9 +125,14 @@ public class ChangeIdUtil { private static final Pattern footerPattern = Pattern .compile("(^[a-zA-Z0-9-]+:(?!//).*$)"); //$NON-NLS-1$ + private static final Pattern changeIdPattern = Pattern + .compile("(^" + CHANGE_ID + " *I[a-f0-9]{40}$)"); //$NON-NLS-1$ //$NON-NLS-2$ + private static final Pattern includeInFooterPattern = Pattern .compile("^[ \\[].*$"); //$NON-NLS-1$ + private static final Pattern trailingWhitespace = Pattern.compile("\\s+$"); + /** * Find the right place to insert a Change-Id and return it. * <p> @@ -209,8 +214,11 @@ public class ChangeIdUtil { } /** - * Find the index in the String {@code} message} where the Change-Id entry - * begins + * Return the index in the String {@code message} where the Change-Id entry + * in the footer begins. If there are more than one entries matching the + * pattern, return the index of the last one in the last section. Because of + * Bug: 400818 we release the constraint here that a footer must contain + * only lines matching {@code footerPattern}. * * @param message * @param delimiter @@ -221,14 +229,32 @@ public class ChangeIdUtil { */ public static int indexOfChangeId(String message, String delimiter) { String[] lines = message.split(delimiter); - int footerFirstLine = indexOfFirstFooterLine(lines); - if (footerFirstLine == lines.length) - return -1; + int indexOfChangeIdLine = 0; + boolean inFooter = false; + for (int i = lines.length - 1; i >= 0; --i) { + if (!inFooter && isEmptyLine(lines[i])) + continue; + inFooter = true; + if (changeIdPattern.matcher(trimRight(lines[i])).matches()) { + indexOfChangeIdLine = i; + break; + } else if (isEmptyLine(lines[i]) || i == 0) + return -1; + } + int indexOfChangeIdLineinString = 0; + for (int i = 0; i < indexOfChangeIdLine; ++i) + indexOfChangeIdLineinString += lines[i].length() + + delimiter.length(); + return indexOfChangeIdLineinString + + lines[indexOfChangeIdLine].indexOf(CHANGE_ID); + } + + private static boolean isEmptyLine(String line) { + return line.trim().length() == 0; + } - int indexOfFooter = 0; - for (int i = 0; i < footerFirstLine; ++i) - indexOfFooter += lines[i].length() + delimiter.length(); - return message.indexOf(CHANGE_ID, indexOfFooter); + private static String trimRight(String s) { + return trailingWhitespace.matcher(s).replaceAll(""); //$NON-NLS-1$ } /** @@ -51,7 +51,7 @@ <groupId>org.eclipse.jgit</groupId> <artifactId>org.eclipse.jgit-parent</artifactId> <packaging>pom</packaging> - <version>2.3.0-SNAPSHOT</version> + <version>2.4.0-SNAPSHOT</version> <name>JGit - Parent</name> <url>${jgit-url}</url> @@ -175,7 +175,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>2.1.0.201209190230-r</jgit-last-release-version> + <jgit-last-release-version>2.3.1.201302201838-r</jgit-last-release-version> <jsch-version>0.1.46</jsch-version> <junit-version>4.5</junit-version> <!-- TODO: update Maven dependency for args4j to 2.0.21 as soon as available on Maven Central --> @@ -438,10 +438,15 @@ </dependencyManagement> <distributionManagement> + <repository> + <id>repo.eclipse.org</id> + <name>JGit Maven Repository - Releases</name> + <url>https://repo.eclipse.org/content/repositories/jgit-releases/</url> + </repository> <snapshotRepository> - <id>jgit-maven-snapshot</id> - <name>JGit Maven Repository</name> - <url>dav:https://egit.googlecode.com/svn/maven/</url> + <id>repo.eclipse.org</id> + <name>JGit Maven Repository - Snapshots</name> + <url>https://repo.eclipse.org/content/repositories/jgit-snapshots/</url> <uniqueVersion>true</uniqueVersion> </snapshotRepository> </distributionManagement> |