IndexDiff: Provide stage state for conflicting entries
Adds a new method getConflictingStageStates() which returns a Map<String, StageState> (path to stage state). StageState is an enum for all possible stage combinations (BOTH_DELETED, ADDED_BY_US, ...). This can be used to implement the conflict text for unmerged paths in output of "git status" or in EGit for decorations/hints. Bug: 403697 Change-Id: Ib461640a43111b7df4a0debe92ff69b82171329c Signed-off-by: Chris Aniszczyk <zx@twitter.com>
This commit is contained in:
parent
1c40d83f52
commit
1080cc5a0d
|
@ -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.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 void testConflicting() throws Exception {
|
|||
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 void testConflictingDeletedAndModified() throws Exception {
|
|||
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 void testAssumeUnchanged() throws Exception {
|
|||
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();
|
||||
|
|
|
@ -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.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 @@
|
|||
*/
|
||||
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 TreeFilter clone() {
|
|||
|
||||
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,11 +397,15 @@ public boolean diff(final ProgressMonitor monitor, int estWorkTreeSize,
|
|||
if (dirCacheIterator != null) {
|
||||
final DirCacheEntry dirCacheEntry = dirCacheIterator
|
||||
.getDirCacheEntry();
|
||||
if (dirCacheEntry != null && dirCacheEntry.getStage() > 0) {
|
||||
conflicts.add(treeWalk.getPathString());
|
||||
if (dirCacheEntry != null) {
|
||||
int stage = dirCacheEntry.getStage();
|
||||
if (stage > 0) {
|
||||
String path = treeWalk.getPathString();
|
||||
addConflict(path, stage);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (treeIterator != null) {
|
||||
if (dirCacheIterator != null) {
|
||||
|
@ -355,6 +461,18 @@ public boolean diff(final ProgressMonitor monitor, int estWorkTreeSize,
|
|||
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 Set<String> getUntracked() {
|
|||
}
|
||||
|
||||
/**
|
||||
* @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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue