summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/IndexDiffTest.java48
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/lib/IndexDiff.java138
2 files changed, 181 insertions, 5 deletions
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/IndexDiffTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/IndexDiffTest.java
index 6040dfed78..51ba5f13ea 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/IndexDiffTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/IndexDiffTest.java
@@ -2,6 +2,7 @@
* Copyright (C) 2007, Dave Watson <dwatson@mimvista.com>
* Copyright (C) 2008, Robin Rosenberg <robin.rosenberg@dewire.com>
* Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org>
+ * Copyright (C) 2013, Robin Stocker <robin@nibor.org>
* and other copyright owners as documented in the project's IP log.
*
* This program and the accompanying materials are made available
@@ -46,6 +47,7 @@
package org.eclipse.jgit.lib;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import java.io.File;
@@ -61,10 +63,12 @@ import org.eclipse.jgit.api.MergeResult;
import org.eclipse.jgit.api.MergeResult.MergeStatus;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.dircache.DirCache;
+import org.eclipse.jgit.dircache.DirCacheBuilder;
import org.eclipse.jgit.dircache.DirCacheEditor;
import org.eclipse.jgit.dircache.DirCacheEditor.PathEdit;
import org.eclipse.jgit.dircache.DirCacheEntry;
import org.eclipse.jgit.junit.RepositoryTestCase;
+import org.eclipse.jgit.lib.IndexDiff.StageState;
import org.eclipse.jgit.merge.MergeStrategy;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.treewalk.FileTreeIterator;
@@ -212,6 +216,8 @@ public class IndexDiffTest extends RepositoryTestCase {
assertEquals("[]", diff.getMissing().toString());
assertEquals("[]", diff.getModified().toString());
assertEquals("[a]", diff.getConflicting().toString());
+ assertEquals(StageState.BOTH_MODIFIED,
+ diff.getConflictingStageStates().get("a"));
assertEquals(Collections.EMPTY_SET, diff.getUntrackedFolders());
}
@@ -251,6 +257,8 @@ public class IndexDiffTest extends RepositoryTestCase {
assertEquals("[]", diff.getMissing().toString());
assertEquals("[]", diff.getModified().toString());
assertEquals("[a]", diff.getConflicting().toString());
+ assertEquals(StageState.DELETED_BY_THEM,
+ diff.getConflictingStageStates().get("a"));
assertEquals(Collections.EMPTY_SET, diff.getUntrackedFolders());
}
@@ -500,6 +508,46 @@ public class IndexDiffTest extends RepositoryTestCase {
assertEquals(Collections.EMPTY_SET, diff.getUntrackedFolders());
}
+ @Test
+ public void testStageState() throws IOException {
+ final int base = DirCacheEntry.STAGE_1;
+ final int ours = DirCacheEntry.STAGE_2;
+ final int theirs = DirCacheEntry.STAGE_3;
+ verifyStageState(StageState.BOTH_DELETED, base);
+ verifyStageState(StageState.DELETED_BY_THEM, ours, base);
+ verifyStageState(StageState.DELETED_BY_US, base, theirs);
+ verifyStageState(StageState.BOTH_MODIFIED, base, ours, theirs);
+ verifyStageState(StageState.ADDED_BY_US, ours);
+ verifyStageState(StageState.BOTH_ADDED, ours, theirs);
+ verifyStageState(StageState.ADDED_BY_THEM, theirs);
+
+ assertTrue(StageState.BOTH_DELETED.hasBase());
+ assertFalse(StageState.BOTH_DELETED.hasOurs());
+ assertFalse(StageState.BOTH_DELETED.hasTheirs());
+ assertFalse(StageState.BOTH_ADDED.hasBase());
+ assertTrue(StageState.BOTH_ADDED.hasOurs());
+ assertTrue(StageState.BOTH_ADDED.hasTheirs());
+ }
+
+ private void verifyStageState(StageState expected, int... stages)
+ throws IOException {
+ DirCacheBuilder builder = db.lockDirCache().builder();
+ for (int stage : stages) {
+ DirCacheEntry entry = createEntry("a", FileMode.REGULAR_FILE,
+ stage, "content");
+ builder.add(entry);
+ }
+ builder.commit();
+
+ IndexDiff diff = new IndexDiff(db, Constants.HEAD,
+ new FileTreeIterator(db));
+ diff.diff();
+
+ assertEquals(
+ "Conflict for entries in stages " + Arrays.toString(stages),
+ expected, diff.getConflictingStageStates().get("a"));
+ }
+
private void removeFromIndex(String path) throws IOException {
final DirCache dirc = db.lockDirCache();
final DirCacheEditor edit = dirc.editor();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/IndexDiff.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/IndexDiff.java
index d32eb99792..33654447ae 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/IndexDiff.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/IndexDiff.java
@@ -2,6 +2,7 @@
* Copyright (C) 2007, Dave Watson <dwatson@mimvista.com>
* Copyright (C) 2007-2008, Robin Rosenberg <robin.rosenberg@dewire.com>
* Copyright (C) 2010, Jens Baumgart <jens.baumgart@sap.com>
+ * Copyright (C) 2013, Robin Stocker <robin@nibor.org>
* and other copyright owners as documented in the project's IP log.
*
* This program and the accompanying materials are made available
@@ -49,7 +50,9 @@ import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
+import java.util.HashMap;
import java.util.HashSet;
+import java.util.Map;
import java.util.Set;
import org.eclipse.jgit.dircache.DirCache;
@@ -85,6 +88,105 @@ import org.eclipse.jgit.treewalk.filter.TreeFilter;
*/
public class IndexDiff {
+ /**
+ * Represents the state of the index for a certain path regarding the stages
+ * - which stages exist for a path and which not (base, ours, theirs).
+ * <p>
+ * This is used for figuring out what kind of conflict occurred.
+ *
+ * @see IndexDiff#getConflictingStageStates()
+ * @since 3.0
+ */
+ public static enum StageState {
+ /**
+ * Exists in base, but neither in ours nor in theirs.
+ */
+ BOTH_DELETED(1),
+
+ /**
+ * Only exists in ours.
+ */
+ ADDED_BY_US(2),
+
+ /**
+ * Exists in base and ours, but no in theirs.
+ */
+ DELETED_BY_THEM(3),
+
+ /**
+ * Only exists in theirs.
+ */
+ ADDED_BY_THEM(4),
+
+ /**
+ * Exists in base and theirs, but not in ours.
+ */
+ DELETED_BY_US(5),
+
+ /**
+ * Exists in ours and theirs, but not in base.
+ */
+ BOTH_ADDED(6),
+
+ /**
+ * Exists in all stages, content conflict.
+ */
+ BOTH_MODIFIED(7);
+
+ private final int stageMask;
+
+ private StageState(int stageMask) {
+ this.stageMask = stageMask;
+ }
+
+ int getStageMask() {
+ return stageMask;
+ }
+
+ /**
+ * @return whether there is a "base" stage entry
+ */
+ public boolean hasBase() {
+ return (stageMask & 1) != 0;
+ }
+
+ /**
+ * @return whether there is an "ours" stage entry
+ */
+ public boolean hasOurs() {
+ return (stageMask & 2) != 0;
+ }
+
+ /**
+ * @return whether there is a "theirs" stage entry
+ */
+ public boolean hasTheirs() {
+ return (stageMask & 4) != 0;
+ }
+
+ static StageState fromMask(int stageMask) {
+ // bits represent: theirs, ours, base
+ switch (stageMask) {
+ case 1: // 0b001
+ return BOTH_DELETED;
+ case 2: // 0b010
+ return ADDED_BY_US;
+ case 3: // 0b011
+ return DELETED_BY_THEM;
+ case 4: // 0b100
+ return ADDED_BY_THEM;
+ case 5: // 0b101
+ return DELETED_BY_US;
+ case 6: // 0b110
+ return BOTH_ADDED;
+ case 7: // 0b111
+ return BOTH_MODIFIED;
+ default:
+ return null;
+ }
+ }
+ }
+
private static final class ProgressReportingFilter extends TreeFilter {
private final ProgressMonitor monitor;
@@ -156,7 +258,7 @@ public class IndexDiff {
private Set<String> untracked = new HashSet<String>();
- private Set<String> conflicts = new HashSet<String>();
+ private Map<String, StageState> conflicts = new HashMap<String, StageState>();
private Set<String> ignored;
@@ -295,9 +397,13 @@ public class IndexDiff {
if (dirCacheIterator != null) {
final DirCacheEntry dirCacheEntry = dirCacheIterator
.getDirCacheEntry();
- if (dirCacheEntry != null && dirCacheEntry.getStage() > 0) {
- conflicts.add(treeWalk.getPathString());
- continue;
+ if (dirCacheEntry != null) {
+ int stage = dirCacheEntry.getStage();
+ if (stage > 0) {
+ String path = treeWalk.getPathString();
+ addConflict(path, stage);
+ continue;
+ }
}
}
@@ -355,6 +461,18 @@ public class IndexDiff {
return true;
}
+ private void addConflict(String path, int stage) {
+ StageState existingStageStates = conflicts.get(path);
+ byte stageMask = 0;
+ if (existingStageStates != null)
+ stageMask |= existingStageStates.getStageMask();
+ // stage 1 (base) should be shifted 0 times
+ int shifts = stage - 1;
+ stageMask |= (1 << shifts);
+ StageState stageState = StageState.fromMask(stageMask);
+ conflicts.put(path, stageState);
+ }
+
/**
* @return list of files added to the index, not in the tree
*/
@@ -398,9 +516,19 @@ public class IndexDiff {
}
/**
- * @return list of files that are in conflict
+ * @return list of files that are in conflict, corresponds to the keys of
+ * {@link #getConflictingStageStates()}
*/
public Set<String> getConflicting() {
+ return conflicts.keySet();
+ }
+
+ /**
+ * @return the map from each path of {@link #getConflicting()} to its
+ * corresponding {@link StageState}
+ * @since 3.0
+ */
+ public Map<String, StageState> getConflictingStageStates() {
return conflicts;
}