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 + +