summaryrefslogtreecommitdiffstatsabout
diff options
context:
space:
mode:
authorRobin Stocker2012-09-22 19:57:20 (EDT)
committer Chris Aniszczyk2012-11-16 13:31:32 (EST)
commitcdaded26b0711bfd99cc2990db25b4562540c3b5 (patch)
treee036b301f6d625f19115c6602fbec7adf7d19740
parent20c829838ac101cf595ee9d4575d6b95a6d2c99d (diff)
downloadjgit-cdaded26b0711bfd99cc2990db25b4562540c3b5.zip
jgit-cdaded26b0711bfd99cc2990db25b4562540c3b5.tar.gz
jgit-cdaded26b0711bfd99cc2990db25b4562540c3b5.tar.bz2
CheckoutCommand: Support checking out ours and theirsrefs/changes/84/7884/5
The checkoutPaths body is split into two implementations, depending on whether we are checking out the index or a branch. This improves readability, as in the index case we now also need to have access to DirCacheIterator. Bug: 390147 Change-Id: I99fd599b25b2ace9bdd84535a56565286a3cb7f1 Signed-off-by: Chris Aniszczyk <zx@twitter.com>
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/api/PathCheckoutCommandTest.java48
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/api/CheckoutCommand.java176
2 files changed, 179 insertions, 45 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 d37f572..43b632d 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
@@ -47,6 +47,7 @@ import static org.junit.Assert.assertEquals;
import java.io.File;
import java.io.IOException;
+import org.eclipse.jgit.api.CheckoutCommand.Stage;
import org.eclipse.jgit.api.errors.JGitInternalException;
import org.eclipse.jgit.dircache.DirCache;
import org.eclipse.jgit.dircache.DirCacheEntry;
@@ -246,10 +247,41 @@ public class PathCheckoutCommandTest extends RepositoryTestCase {
assertEquals("a", read(test2));
}
+
@Test(expected = JGitInternalException.class)
public void testCheckoutOfConflictingFileShouldThrow()
throws Exception {
- // Setup
+ setupConflictingState();
+
+ git.checkout().addPath(FILE1).call();
+ }
+
+ @Test
+ public void testCheckoutOurs() throws Exception {
+ setupConflictingState();
+
+ git.checkout().setStage(Stage.OURS).addPath(FILE1).call();
+
+ assertEquals("3", read(FILE1));
+ assertStageOneToThree(FILE1);
+ }
+
+ @Test
+ public void testCheckoutTheirs() throws Exception {
+ setupConflictingState();
+
+ git.checkout().setStage(Stage.THEIRS).addPath(FILE1).call();
+
+ assertEquals("Conflicting", read(FILE1));
+ assertStageOneToThree(FILE1);
+ }
+
+ @Test(expected = IllegalStateException.class)
+ public void testStageNotPossibleWithBranch() throws Exception {
+ git.checkout().setStage(Stage.OURS).setStartPoint("master").call();
+ }
+
+ private void setupConflictingState() throws Exception {
git.checkout().setCreateBranch(true).setName("conflict")
.setStartPoint(initialCommit).call();
writeTrashFile(FILE1, "Conflicting");
@@ -260,8 +292,18 @@ public class PathCheckoutCommandTest extends RepositoryTestCase {
git.merge().include(conflict).call();
assertEquals(RepositoryState.MERGING, db.getRepositoryState());
+ assertStageOneToThree(FILE1);
+ }
- // Now check out the conflicting path
- git.checkout().addPath(FILE1).call();
+ private void assertStageOneToThree(String name) throws Exception {
+ DirCache cache = DirCache.read(db.getIndexFile(), db.getFS());
+ int i = cache.findEntry(name);
+ DirCacheEntry stage1 = cache.getEntry(i);
+ DirCacheEntry stage2 = cache.getEntry(i + 1);
+ DirCacheEntry stage3 = cache.getEntry(i + 2);
+
+ assertEquals(DirCacheEntry.STAGE_1, stage1.getStage());
+ assertEquals(DirCacheEntry.STAGE_2, stage2.getStage());
+ assertEquals(DirCacheEntry.STAGE_3, stage3.getStage());
}
}
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 9d3bf56..ef227dc 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/CheckoutCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/CheckoutCommand.java
@@ -125,6 +125,33 @@ import org.eclipse.jgit.util.FileUtils;
* >Git documentation about Checkout</a>
*/
public class CheckoutCommand extends GitCommand<Ref> {
+
+ /**
+ * Stage to check out, see {@link CheckoutCommand#setStage(Stage)}.
+ */
+ public static enum Stage {
+ /**
+ * Base stage (#1)
+ */
+ BASE(DirCacheEntry.STAGE_1),
+
+ /**
+ * Ours stage (#2)
+ */
+ OURS(DirCacheEntry.STAGE_2),
+
+ /**
+ * Theirs stage (#3)
+ */
+ THEIRS(DirCacheEntry.STAGE_3);
+
+ private final int number;
+
+ private Stage(int number) {
+ this.number = number;
+ }
+ }
+
private String name;
private boolean force = false;
@@ -137,6 +164,8 @@ public class CheckoutCommand extends GitCommand<Ref> {
private RevCommit startCommit;
+ private Stage checkoutStage = null;
+
private CheckoutResult status;
private List<String> paths;
@@ -327,52 +356,19 @@ public class CheckoutCommand extends GitCommand<Ref> {
RevWalk revWalk = new RevWalk(repo);
DirCache dc = repo.lockDirCache();
try {
- DirCacheEditor editor = dc.editor();
- TreeWalk startWalk = new TreeWalk(revWalk.getObjectReader());
- startWalk.setRecursive(true);
+ TreeWalk treeWalk = new TreeWalk(revWalk.getObjectReader());
+ treeWalk.setRecursive(true);
if (!checkoutAllPaths)
- startWalk.setFilter(PathFilterGroup.createFromStrings(paths));
- final boolean checkoutIndex = startCommit == null
- && startPoint == null;
- if (!checkoutIndex)
- startWalk.addTree(revWalk.parseCommit(getStartPoint())
- .getTree());
- else
- startWalk.addTree(new DirCacheIterator(dc));
-
- final File workTree = repo.getWorkTree();
- final ObjectReader r = repo.getObjectDatabase().newReader();
+ treeWalk.setFilter(PathFilterGroup.createFromStrings(paths));
try {
- while (startWalk.next()) {
- final ObjectId blobId = startWalk.getObjectId(0);
- final FileMode mode = startWalk.getFileMode(0);
- editor.add(new PathEdit(startWalk.getPathString()) {
- public void apply(DirCacheEntry ent) {
- if (checkoutIndex
- && ent.getStage() > DirCacheEntry.STAGE_0) {
- UnmergedPathException e = new UnmergedPathException(ent);
- throw new JGitInternalException(e.getMessage(), e);
- }
- ent.setObjectId(blobId);
- ent.setFileMode(mode);
- File file = new File(workTree, ent.getPathString());
- File parentDir = file.getParentFile();
- try {
- FileUtils.mkdirs(parentDir, true);
- DirCacheCheckout.checkoutEntry(repo, file, ent, r);
- } catch (IOException e) {
- throw new JGitInternalException(
- MessageFormat.format(
- JGitText.get().checkoutConflictWithFile,
- ent.getPathString()), e);
- }
- }
- });
+ if (isCheckoutIndex())
+ checkoutPathsFromIndex(treeWalk, dc);
+ else {
+ RevCommit commit = revWalk.parseCommit(getStartPoint());
+ checkoutPathsFromCommit(treeWalk, dc, commit);
}
- editor.commit();
} finally {
- startWalk.release();
- r.release();
+ treeWalk.release();
}
} finally {
dc.unlock();
@@ -381,6 +377,75 @@ public class CheckoutCommand extends GitCommand<Ref> {
return this;
}
+ private void checkoutPathsFromIndex(TreeWalk treeWalk, DirCache dc)
+ throws IOException {
+ DirCacheIterator dci = new DirCacheIterator(dc);
+ treeWalk.addTree(dci);
+
+ final ObjectReader r = treeWalk.getObjectReader();
+ DirCacheEditor editor = dc.editor();
+ while (treeWalk.next()) {
+ DirCacheEntry entry = dci.getDirCacheEntry();
+ // Only add one edit per path
+ if (entry != null && entry.getStage() > DirCacheEntry.STAGE_1)
+ continue;
+ editor.add(new PathEdit(treeWalk.getPathString()) {
+ public void apply(DirCacheEntry ent) {
+ int stage = ent.getStage();
+ if (stage > DirCacheEntry.STAGE_0) {
+ if (checkoutStage != null) {
+ if (stage == checkoutStage.number)
+ checkoutPath(ent, r);
+ } else {
+ UnmergedPathException e = new UnmergedPathException(
+ ent);
+ throw new JGitInternalException(e.getMessage(), e);
+ }
+ } else {
+ checkoutPath(ent, r);
+ }
+ }
+ });
+ }
+ editor.commit();
+ }
+
+ private void checkoutPathsFromCommit(TreeWalk treeWalk, DirCache dc,
+ RevCommit commit) throws IOException {
+ treeWalk.addTree(commit.getTree());
+ final ObjectReader r = treeWalk.getObjectReader();
+ DirCacheEditor editor = dc.editor();
+ while (treeWalk.next()) {
+ final ObjectId blobId = treeWalk.getObjectId(0);
+ final FileMode mode = treeWalk.getFileMode(0);
+ editor.add(new PathEdit(treeWalk.getPathString()) {
+ public void apply(DirCacheEntry ent) {
+ ent.setObjectId(blobId);
+ ent.setFileMode(mode);
+ checkoutPath(ent, r);
+ }
+ });
+ }
+ editor.commit();
+ }
+
+ private void checkoutPath(DirCacheEntry entry, ObjectReader reader) {
+ File file = new File(repo.getWorkTree(), entry.getPathString());
+ File parentDir = file.getParentFile();
+ try {
+ FileUtils.mkdirs(parentDir, true);
+ DirCacheCheckout.checkoutEntry(repo, file, entry, reader);
+ } catch (IOException e) {
+ throw new JGitInternalException(MessageFormat.format(
+ JGitText.get().checkoutConflictWithFile,
+ entry.getPathString()), e);
+ }
+ }
+
+ private boolean isCheckoutIndex() {
+ return startCommit == null && startPoint == null;
+ }
+
private ObjectId getStartPoint() throws AmbiguousObjectException,
RefNotFoundException, IOException {
if (startCommit != null)
@@ -483,6 +548,7 @@ public class CheckoutCommand extends GitCommand<Ref> {
checkCallable();
this.startPoint = startPoint;
this.startCommit = null;
+ checkOptions();
return this;
}
@@ -503,6 +569,7 @@ public class CheckoutCommand extends GitCommand<Ref> {
checkCallable();
this.startCommit = startCommit;
this.startPoint = null;
+ checkOptions();
return this;
}
@@ -523,6 +590,24 @@ public class CheckoutCommand extends GitCommand<Ref> {
}
/**
+ * When checking out the index, check out the specified stage (ours or
+ * theirs) for unmerged paths.
+ * <p>
+ * This can not be used when checking out a branch, only when checking out
+ * the index.
+ *
+ * @param stage
+ * the stage to check out
+ * @return this
+ */
+ public CheckoutCommand setStage(Stage stage) {
+ checkCallable();
+ this.checkoutStage = stage;
+ checkOptions();
+ return this;
+ }
+
+ /**
* @return the result, never <code>null</code>
*/
public CheckoutResult getResult() {
@@ -530,4 +615,11 @@ public class CheckoutCommand extends GitCommand<Ref> {
return CheckoutResult.NOT_TRIED_RESULT;
return status;
}
+
+ private void checkOptions() {
+ if (checkoutStage != null && !isCheckoutIndex())
+ throw new IllegalStateException(
+ "Checking out ours/theirs is only possible when checking out index, "
+ + "not when switching branches.");
+ }
}