diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheEntryTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheEntryTest.java index 7c90f25b5..7ba7ca052 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheEntryTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheEntryTest.java @@ -51,6 +51,7 @@ import static org.junit.Assert.fail; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.FileMode; +import org.eclipse.jgit.lib.ObjectId; import org.junit.Test; public class DirCacheEntryTest { @@ -164,4 +165,53 @@ public class DirCacheEntryTest { assertEquals("Invalid mode 40000 for path a", err.getMessage()); } } + + @Test + public void testCopyMetaDataWithStage() { + copyMetaDataHelper(false); + } + + @Test + public void testCopyMetaDataWithoutStage() { + copyMetaDataHelper(true); + } + + private void copyMetaDataHelper(final boolean keepStage) { + DirCacheEntry e = new DirCacheEntry("some/path", DirCacheEntry.STAGE_2); + e.setAssumeValid(false); + e.setCreationTime(2L); + e.setFileMode(FileMode.EXECUTABLE_FILE); + e.setLastModified(3L); + e.setLength(100L); + e.setObjectId(ObjectId + .fromString("0123456789012345678901234567890123456789")); + e.setUpdateNeeded(true); + + DirCacheEntry f = new DirCacheEntry("someother/path", + DirCacheEntry.STAGE_1); + f.setAssumeValid(true); + f.setCreationTime(10L); + f.setFileMode(FileMode.SYMLINK); + f.setLastModified(20L); + f.setLength(100000000L); + f.setObjectId(ObjectId + .fromString("1234567890123456789012345678901234567890")); + f.setUpdateNeeded(true); + + e.copyMetaData(f, keepStage); + assertTrue(e.isAssumeValid()); + assertEquals(10L, e.getCreationTime()); + assertEquals( + ObjectId.fromString("1234567890123456789012345678901234567890"), + e.getObjectId()); + assertEquals(FileMode.SYMLINK, e.getFileMode()); + assertEquals(20L, e.getLastModified()); + assertEquals(100000000L, e.getLength()); + if (keepStage) + assertEquals(DirCacheEntry.STAGE_2, e.getStage()); + else + assertEquals(DirCacheEntry.STAGE_1, e.getStage()); + assertTrue(e.isUpdateNeeded()); + assertEquals("some/path", e.getPathString()); + } } 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 fa2904231..859f61173 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java @@ -795,7 +795,7 @@ public class DirCacheCheckout { DirCacheEntry entry; if (e != null) { entry = new DirCacheEntry(e.getPathString(), DirCacheEntry.STAGE_1); - entry.copyMetaData(e); + entry.copyMetaData(e, true); builder.add(entry); } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheEntry.java b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheEntry.java index 71d9c4bdf..85df340d3 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheEntry.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheEntry.java @@ -641,10 +641,33 @@ public class DirCacheEntry { * the entry to copy ObjectId and meta fields from. */ public void copyMetaData(final DirCacheEntry src) { - final int pLen = NB.decodeUInt16(info, infoOffset + P_FLAGS) & NAME_MASK; + copyMetaData(src, false); + } + + /** + * Copy the ObjectId and other meta fields from an existing entry. + *
+ * This method copies everything except the path and possibly stage from one + * entry to another, supporting renaming. + * + * @param src + * the entry to copy ObjectId and meta fields from. + * @param keepStage + * if true, the stage attribute will not be copied + */ + void copyMetaData(final DirCacheEntry src, boolean keepStage) { + int origflags = NB.decodeUInt16(info, infoOffset + P_FLAGS); + int newflags = NB.decodeUInt16(src.info, src.infoOffset + P_FLAGS); System.arraycopy(src.info, src.infoOffset, info, infoOffset, INFO_LEN); - NB.encodeInt16(info, infoOffset + P_FLAGS, pLen - | NB.decodeUInt16(info, infoOffset + P_FLAGS) & ~NAME_MASK); + final int pLen = origflags & NAME_MASK; + final int SHIFTED_STAGE_MASK = 0x3 << 12; + final int pStageShifted; + if (keepStage) + pStageShifted = origflags & SHIFTED_STAGE_MASK; + else + pStageShifted = newflags & SHIFTED_STAGE_MASK; + NB.encodeInt16(info, infoOffset + P_FLAGS, pStageShifted | pLen + | (newflags & ~NAME_MASK & ~SHIFTED_STAGE_MASK)); } /**