diff options
-rw-r--r-- | org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/IndexDiffTest.java | 48 | ||||
-rw-r--r-- | org.eclipse.jgit/src/org/eclipse/jgit/lib/IndexDiff.java | 138 |
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; } |