diff options
6 files changed, 129 insertions, 9 deletions
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/PathCheckoutCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/PathCheckoutCommandTest.java index e0a1c1d61b..f52b715d39 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/PathCheckoutCommandTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/PathCheckoutCommandTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011, Kevin Sawicki <kevin@github.com> and others + * Copyright (C) 2011, 2020 Kevin Sawicki <kevin@github.com> and others * * This program and the accompanying materials are made available under the * terms of the Eclipse Distribution License v. 1.0 which is available at @@ -24,6 +24,7 @@ import org.eclipse.jgit.dircache.DirCacheEntry; import org.eclipse.jgit.errors.NoWorkTreeException; import org.eclipse.jgit.junit.RepositoryTestCase; import org.eclipse.jgit.lib.ConfigConstants; +import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.ObjectReader; import org.eclipse.jgit.lib.RepositoryState; import org.eclipse.jgit.lib.StoredConfig; @@ -310,6 +311,16 @@ public class PathCheckoutCommandTest extends RepositoryTestCase { } @Test + public void testCheckoutFileWithConflict() throws Exception { + setupConflictingState(); + assertEquals('[' + FILE1 + ']', + git.status().call().getConflicting().toString()); + git.checkout().setStartPoint(Constants.HEAD).addPath(FILE1).call(); + assertEquals("3", read(FILE1)); + assertTrue(git.status().call().isClean()); + } + + @Test public void testCheckoutOursWhenNoBase() throws Exception { String file = "added.txt"; 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 5477f565f4..8e84dfa318 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 @@ -242,6 +242,46 @@ public class DirCacheEntryTest { } @Test + public void testSetStage() { + DirCacheEntry e = new DirCacheEntry("some/path", DirCacheEntry.STAGE_1); + e.setAssumeValid(true); + e.setCreationTime(2L); + e.setFileMode(FileMode.EXECUTABLE_FILE); + e.setLastModified(EPOCH.plusMillis(3L)); + e.setLength(100L); + e.setObjectId(ObjectId + .fromString("0123456789012345678901234567890123456789")); + e.setUpdateNeeded(true); + e.setStage(DirCacheEntry.STAGE_2); + + assertTrue(e.isAssumeValid()); + assertEquals(2L, e.getCreationTime()); + assertEquals( + ObjectId.fromString("0123456789012345678901234567890123456789"), + e.getObjectId()); + assertEquals(FileMode.EXECUTABLE_FILE, e.getFileMode()); + assertEquals(EPOCH.plusMillis(3L), e.getLastModifiedInstant()); + assertEquals(100L, e.getLength()); + assertEquals(DirCacheEntry.STAGE_2, e.getStage()); + assertTrue(e.isUpdateNeeded()); + assertEquals("some/path", e.getPathString()); + + e.setStage(DirCacheEntry.STAGE_0); + + assertTrue(e.isAssumeValid()); + assertEquals(2L, e.getCreationTime()); + assertEquals( + ObjectId.fromString("0123456789012345678901234567890123456789"), + e.getObjectId()); + assertEquals(FileMode.EXECUTABLE_FILE, e.getFileMode()); + assertEquals(EPOCH.plusMillis(3L), e.getLastModifiedInstant()); + assertEquals(100L, e.getLength()); + assertEquals(DirCacheEntry.STAGE_0, e.getStage()); + assertTrue(e.isUpdateNeeded()); + assertEquals("some/path", e.getPathString()); + } + + @Test public void testCopyMetaDataWithStage() { copyMetaDataHelper(false); } diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCachePathEditTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCachePathEditTest.java index 39a1f01803..5778d28d6f 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCachePathEditTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCachePathEditTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011, Robin Rosenberg and others + * Copyright (C) 2011, 2020 Robin Rosenberg and others * * This program and the accompanying materials are made available under the * terms of the Eclipse Distribution License v. 1.0 which is available at @@ -124,6 +124,32 @@ public class DirCachePathEditTest { } @Test + public void testPathEditWithStagesAndReset() throws Exception { + DirCache dc = DirCache.newInCore(); + DirCacheBuilder builder = new DirCacheBuilder(dc, 3); + builder.add(createEntry("a", DirCacheEntry.STAGE_1)); + builder.add(createEntry("a", DirCacheEntry.STAGE_2)); + builder.add(createEntry("a", DirCacheEntry.STAGE_3)); + builder.finish(); + + DirCacheEditor editor = dc.editor(); + PathEdit edit = new PathEdit("a") { + + @Override + public void apply(DirCacheEntry ent) { + ent.setStage(DirCacheEntry.STAGE_0); + } + }; + editor.add(edit); + editor.finish(); + + assertEquals(1, dc.getEntryCount()); + DirCacheEntry entry = dc.getEntry(0); + assertEquals("a", entry.getPathString()); + assertEquals(DirCacheEntry.STAGE_0, entry.getStage()); + } + + @Test public void testFileReplacesTree() throws Exception { DirCache dc = DirCache.newInCore(); DirCacheEditor editor = dc.editor(); diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/CheckoutCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/CheckoutCommand.java index 0dc5d5e7f7..847ab0a9a8 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/CheckoutCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/CheckoutCommand.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2010, Chris Aniszczyk <caniszczyk@gmail.com> - * Copyright (C) 2011, Matthias Sohn <matthias.sohn@sap.com> and others + * Copyright (C) 2011, 2020 Matthias Sohn <matthias.sohn@sap.com> and others * * This program and the accompanying materials are made available under the * terms of the Eclipse Distribution License v. 1.0 which is available at @@ -503,6 +503,11 @@ public class CheckoutCommand extends GitCommand<Ref> { editor.add(new PathEdit(path) { @Override public void apply(DirCacheEntry ent) { + if (ent.getStage() != DirCacheEntry.STAGE_0) { + // A checkout on a conflicting file stages the checked + // out file and resolves the conflict. + ent.setStage(DirCacheEntry.STAGE_0); + } ent.setObjectId(blobId); ent.setFileMode(mode); checkoutPath(ent, r, diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheEditor.java b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheEditor.java index 73d2807eaf..8c342e267d 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheEditor.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheEditor.java @@ -1,6 +1,6 @@ /* - * Copyright (C) 2008-2009, Google Inc. - * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org> and others + * Copyright (C) 2008, 2009, Google Inc. + * Copyright (C) 2008, 2020 Shawn O. Pearce <spearce@spearce.org> and others * * This program and the accompanying materials are made available under the * terms of the Eclipse Distribution License v. 1.0 which is available at @@ -139,10 +139,28 @@ public class DirCacheEditor extends BaseDirCacheEditor { : eIdx; fastAdd(ent); } else { - // Apply to all entries of the current path (different stages) lastIdx = cache.nextEntry(eIdx); - for (int i = eIdx; i < lastIdx; i++) { - final DirCacheEntry ent = cache.getEntry(i); + if (lastIdx > eIdx + 1) { + // Apply to all entries of the current path (different + // stages). If any apply() resets the stage to STAGE_0, take + // only that entry and omit all others. + DirCacheEntry[] tmp = new DirCacheEntry[lastIdx - eIdx]; + int n = 0; + for (int i = eIdx; i < lastIdx; i++) { + DirCacheEntry ent = cache.getEntry(i); + e.apply(ent); + if (ent.getStage() == DirCacheEntry.STAGE_0) { + fastAdd(ent); + n = 0; + break; + } + tmp[n++] = ent; + } + for (int i = 0; i < n; i++) { + fastAdd(tmp[i]); + } + } else { + DirCacheEntry ent = cache.getEntry(eIdx); e.apply(ent); fastAdd(ent); } @@ -257,7 +275,9 @@ public class DirCacheEditor extends BaseDirCacheEditor { * {@link #apply(DirCacheEntry)} method. The editor will invoke apply once * for each record in the index which matches the path name. If there are * multiple records (for example in stages 1, 2 and 3), the edit instance - * will be called multiple times, once for each stage. + * will be called multiple times, once for each stage. If any of these calls + * resets the stage to 0, only this entry will be taken and entries for + * other stages are discarded. */ public abstract static class PathEdit { final byte[] path; 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 dcb84825fe..67edf50f44 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheEntry.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheEntry.java @@ -542,6 +542,24 @@ public class DirCacheEntry { } /** + * Sets the stage of an entry. + * + * @param stage + * to set, in the range [0..3] + * @throws IllegalArgumentException + * if the stage is outside the range [0..3] + * @since 5.10 + */ + public void setStage(int stage) { + if ((stage & ~0x3) != 0) { + throw new IllegalArgumentException( + "Invalid stage, must be in range [0..3]"); //$NON-NLS-1$ + } + byte flags = info[infoOffset + P_FLAGS]; + info[infoOffset + P_FLAGS] = (byte) ((flags & 0xCF) | (stage << 4)); + } + + /** * Returns whether this entry should be skipped from the working tree. * * @return true if this entry should be skipepd. |