diff --git a/org.eclipse.jgit.ant/pom.xml b/org.eclipse.jgit.ant/pom.xml
index fcd6f8918..9a55466f4 100644
--- a/org.eclipse.jgit.ant/pom.xml
+++ b/org.eclipse.jgit.ant/pom.xml
@@ -110,6 +110,25 @@
UTF-8
+
+
+ org.codehaus.mojo
+ clirr-maven-plugin
+
+
+
+
+
+ org.codehaus.mojo
+ clirr-maven-plugin
+ ${clirr-version}
+
+ ${jgit-last-release-version}
+ info
+
+
+
+
diff --git a/org.eclipse.jgit.console/pom.xml b/org.eclipse.jgit.console/pom.xml
index c5573c54d..bd99d39cd 100644
--- a/org.eclipse.jgit.console/pom.xml
+++ b/org.eclipse.jgit.console/pom.xml
@@ -108,6 +108,25 @@
UTF-8
+
+
+ org.codehaus.mojo
+ clirr-maven-plugin
+
+
+
+
+
+ org.codehaus.mojo
+ clirr-maven-plugin
+ ${clirr-version}
+
+ ${jgit-last-release-version}
+ info
+
+
+
+
diff --git a/org.eclipse.jgit.http.server/pom.xml b/org.eclipse.jgit.http.server/pom.xml
index 94479ccf6..d4fc39eff 100644
--- a/org.eclipse.jgit.http.server/pom.xml
+++ b/org.eclipse.jgit.http.server/pom.xml
@@ -125,6 +125,25 @@
+
+
+ org.codehaus.mojo
+ clirr-maven-plugin
+
+
+
+
+
+ org.codehaus.mojo
+ clirr-maven-plugin
+ ${clirr-version}
+
+ ${jgit-last-release-version}
+ info
+
+
+
+
diff --git a/org.eclipse.jgit.storage.dht/pom.xml b/org.eclipse.jgit.storage.dht/pom.xml
index 83c1b857c..06ca61d95 100644
--- a/org.eclipse.jgit.storage.dht/pom.xml
+++ b/org.eclipse.jgit.storage.dht/pom.xml
@@ -157,6 +157,25 @@
+
+
+ org.codehaus.mojo
+ clirr-maven-plugin
+
+
+
+
+
+ org.codehaus.mojo
+ clirr-maven-plugin
+ ${clirr-version}
+
+ ${jgit-last-release-version}
+ info
+
+
+
+
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/MergeCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/MergeCommandTest.java
index bb9058891..30a94520d 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/MergeCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/MergeCommandTest.java
@@ -60,6 +60,7 @@ import org.eclipse.jgit.lib.RepositoryTestCase;
import org.eclipse.jgit.merge.MergeStrategy;
import org.eclipse.jgit.merge.ResolveMerger.MergeFailureReason;
import org.eclipse.jgit.revwalk.RevCommit;
+import org.eclipse.jgit.util.FS;
import org.eclipse.jgit.util.FileUtils;
import org.junit.Test;
import org.junit.experimental.theories.DataPoints;
@@ -1023,6 +1024,88 @@ public class MergeCommandTest extends RepositoryTestCase {
assertFalse(folder2.exists());
}
+ @Test
+ public void testFileModeMerge() throws Exception {
+ if (!FS.DETECTED.supportsExecute())
+ return;
+ // Only Java6
+ Git git = new Git(db);
+
+ writeTrashFile("mergeableMode", "a");
+ setExecutable(git, "mergeableMode", false);
+ writeTrashFile("conflictingModeWithBase", "a");
+ setExecutable(git, "conflictingModeWithBase", false);
+ RevCommit initialCommit = addAllAndCommit(git);
+
+ // switch branch
+ createBranch(initialCommit, "refs/heads/side");
+ checkoutBranch("refs/heads/side");
+ setExecutable(git, "mergeableMode", true);
+ writeTrashFile("conflictingModeNoBase", "b");
+ setExecutable(git, "conflictingModeNoBase", true);
+ RevCommit sideCommit = addAllAndCommit(git);
+
+ // switch branch
+ createBranch(initialCommit, "refs/heads/side2");
+ checkoutBranch("refs/heads/side2");
+ setExecutable(git, "mergeableMode", false);
+ assertFalse(new File(git.getRepository().getWorkTree(),
+ "conflictingModeNoBase").exists());
+ writeTrashFile("conflictingModeNoBase", "b");
+ setExecutable(git, "conflictingModeNoBase", false);
+ addAllAndCommit(git);
+
+ // merge
+ MergeResult result = git.merge().include(sideCommit.getId())
+ .setStrategy(MergeStrategy.RESOLVE).call();
+ assertEquals(MergeStatus.CONFLICTING, result.getMergeStatus());
+ assertTrue(canExecute(git, "mergeableMode"));
+ assertFalse(canExecute(git, "conflictingModeNoBase"));
+ }
+
+ @Test
+ public void testFileModeMergeWithDirtyWorkTree() throws Exception {
+ if (!FS.DETECTED.supportsExecute())
+ return;
+ // Only Java6 (or set x bit in index)
+
+ Git git = new Git(db);
+
+ writeTrashFile("mergeableButDirty", "a");
+ setExecutable(git, "mergeableButDirty", false);
+ RevCommit initialCommit = addAllAndCommit(git);
+
+ // switch branch
+ createBranch(initialCommit, "refs/heads/side");
+ checkoutBranch("refs/heads/side");
+ setExecutable(git, "mergeableButDirty", true);
+ RevCommit sideCommit = addAllAndCommit(git);
+
+ // switch branch
+ createBranch(initialCommit, "refs/heads/side2");
+ checkoutBranch("refs/heads/side2");
+ setExecutable(git, "mergeableButDirty", false);
+ addAllAndCommit(git);
+
+ writeTrashFile("mergeableButDirty", "b");
+
+ // merge
+ MergeResult result = git.merge().include(sideCommit.getId())
+ .setStrategy(MergeStrategy.RESOLVE).call();
+ assertEquals(MergeStatus.FAILED, result.getMergeStatus());
+ assertFalse(canExecute(git, "mergeableButDirty"));
+ }
+
+ private void setExecutable(Git git, String path, boolean executable) {
+ FS.DETECTED.setExecute(
+ new File(git.getRepository().getWorkTree(), path), executable);
+ }
+
+ private boolean canExecute(Git git, String path) {
+ return FS.DETECTED.canExecute(new File(git.getRepository()
+ .getWorkTree(), path));
+ }
+
private RevCommit addAllAndCommit(final Git git) throws Exception {
git.add().addFilepattern(".").call();
return git.commit().setMessage("message").call();
diff --git a/org.eclipse.jgit/pom.xml b/org.eclipse.jgit/pom.xml
index b77a17a7a..92f39acbe 100644
--- a/org.eclipse.jgit/pom.xml
+++ b/org.eclipse.jgit/pom.xml
@@ -142,7 +142,13 @@
+
+
+ org.codehaus.mojo
+ clirr-maven-plugin
+
+
@@ -155,4 +161,18 @@
+
+
+
+
+ org.codehaus.mojo
+ clirr-maven-plugin
+ ${clirr-version}
+
+ ${jgit-last-release-version}
+ info
+
+
+
+
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 b76356895..8211780ca 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java
@@ -51,6 +51,7 @@ import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
@@ -378,12 +379,46 @@ public class ResolveMerger extends ThreeWayMerger {
if (isIndexDirty())
return false;
- if (nonTree(modeO) && modeO == modeT && tw.idEqual(T_OURS, T_THEIRS)) {
- // OURS and THEIRS are equal: it doesn't matter which one we choose.
- // OURS is chosen.
- add(tw.getRawPath(), ours, DirCacheEntry.STAGE_0);
- // no checkout needed!
- return true;
+ if (nonTree(modeO) && nonTree(modeT) && tw.idEqual(T_OURS, T_THEIRS)) {
+ // OURS and THEIRS have equal content. Check the file mode
+ if (modeO == modeT) {
+ // content and mode of OURS and THEIRS are equal: it doesn't
+ // matter which one we choose. OURS is chosen.
+ add(tw.getRawPath(), ours, DirCacheEntry.STAGE_0);
+ // no checkout needed!
+ return true;
+ } else {
+ // same content but different mode on OURS and THEIRS.
+ // Try to merge the mode and report an error if this is
+ // not possible.
+ int newMode = mergeFileModes(modeB, modeO, modeT);
+ if (newMode != FileMode.MISSING.getBits()) {
+ if (newMode == modeO)
+ // ours version is preferred
+ add(tw.getRawPath(), ours, DirCacheEntry.STAGE_0);
+ else {
+ // the preferred version THEIRS has a different mode
+ // than ours. Check it out!
+ if (isWorktreeDirty())
+ return false;
+ DirCacheEntry e = add(tw.getRawPath(), theirs,
+ DirCacheEntry.STAGE_0);
+ toBeCheckedOut.put(tw.getPathString(), e);
+ }
+ return true;
+ } else {
+ // FileModes are not mergeable. We found a conflict on modes
+ add(tw.getRawPath(), base, DirCacheEntry.STAGE_1);
+ add(tw.getRawPath(), ours, DirCacheEntry.STAGE_2);
+ add(tw.getRawPath(), theirs, DirCacheEntry.STAGE_3);
+ unmergedPaths.add(tw.getPathString());
+ mergeResults.put(
+ tw.getPathString(),
+ new MergeResult(Collections
+ . emptyList()));
+ }
+ return true;
+ }
}
if (nonTree(modeO) && modeB == modeT && tw.idEqual(T_BASE, T_THEIRS)) {
@@ -582,7 +617,12 @@ public class ResolveMerger extends ThreeWayMerger {
// no conflict occurred, the file will contain fully merged content.
// the index will be populated with the new merged version
DirCacheEntry dce = new DirCacheEntry(tw.getPathString());
- dce.setFileMode(tw.getFileMode(0));
+ int newMode = mergeFileModes(tw.getRawMode(0), tw.getRawMode(1),
+ tw.getRawMode(2));
+ // set the mode for the new content. Fall back to REGULAR_FILE if
+ // you can't merge modes of OURS and THEIRS
+ dce.setFileMode((newMode == FileMode.MISSING.getBits()) ? FileMode.REGULAR_FILE
+ : FileMode.fromBits(newMode));
dce.setLastModified(of.lastModified());
dce.setLength((int) of.length());
InputStream is = new FileInputStream(of);
@@ -599,6 +639,34 @@ public class ResolveMerger extends ThreeWayMerger {
}
}
+ /**
+ * Try to merge filemodes. If only ours or theirs have changed the mode
+ * (compared to base) we choose that one. If ours and theirs have equal
+ * modes return that one. If also that is not the case the modes are not
+ * mergeable. Return {@link FileMode#MISSING} int that case.
+ *
+ * @param modeB
+ * filemode found in BASE
+ * @param modeO
+ * filemode found in OURS
+ * @param modeT
+ * filemode found in THEIRS
+ *
+ * @return the merged filemode or {@link FileMode#MISSING} in case of a
+ * conflict
+ */
+ private int mergeFileModes(int modeB, int modeO, int modeT) {
+ if (modeO == modeT)
+ return modeO;
+ if (modeB == modeO)
+ // Base equal to Ours -> chooses Theirs if that is not missing
+ return (modeT == FileMode.MISSING.getBits()) ? modeO : modeT;
+ if (modeB == modeT)
+ // Base equal to Theirs -> chooses Ours if that is not missing
+ return (modeO == FileMode.MISSING.getBits()) ? modeT : modeO;
+ return FileMode.MISSING.getBits();
+ }
+
private static RawText getRawText(ObjectId id, Repository db)
throws IOException {
if (id.equals(ObjectId.zeroId()))
diff --git a/pom.xml b/pom.xml
index 15365b097..b74db9ddc 100644
--- a/pom.xml
+++ b/pom.xml
@@ -130,14 +130,23 @@
yyyyMMddHHmm
${project.build.directory}/META-INF/MANIFEST.MF
+ 1.1.0.201109151100-r
0.1.44-1
4.5
2.0.12
2.5
7.1.6.v20100715
2.4.0a
+ 2.3
+
+
+ jgit-repository
+ http://download.eclipse.org/jgit/maven
+
+
+
@@ -246,6 +255,16 @@
+
+
+ org.codehaus.mojo
+ clirr-maven-plugin
+ ${clirr-version}
+
+ ${jgit-last-release-version}
+ info
+
+