CommitBuilder should check for duplicate parents

When setting the parents of a commit with setParentIds() or
addParentId() it should be checked that we don't have duplicate parents.
An IllegalArgumentException should be thrown in this case.

Change-Id: I9fa9f31149b7732071b304bca232f037146de454
Signed-off-by: Christian Halstrick <christian.halstrick@sap.com>
This commit is contained in:
Christian Halstrick 2012-07-04 15:08:13 +02:00 committed by Matthias Sohn
parent 9041fbc958
commit 6bc48cdc62
5 changed files with 147 additions and 33 deletions

View File

@ -47,16 +47,22 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import org.eclipse.jgit.dircache.DirCache;
import org.eclipse.jgit.dircache.DirCacheBuilder;
import org.eclipse.jgit.lib.AnyObjectId;
import org.eclipse.jgit.lib.CommitBuilder;
import org.eclipse.jgit.lib.FileMode;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectInserter;
import org.eclipse.jgit.lib.PersonIdent;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.test.resources.SampleDataRepositoryTestCase;
import org.eclipse.jgit.treewalk.TreeWalk;
import org.junit.Test;
@ -87,6 +93,81 @@ public void testTrivialTwoWay() throws IOException {
assertEquals("02ba32d3649e510002c21651936b7077aa75ffa9",ourMerger.getResultTreeId().name());
}
@Test
public void testDuplicateParents() throws Exception {
ObjectId commitId;
RevCommit newCommit;
final ObjectInserter ow = db.newObjectInserter();
RevWalk rw = new RevWalk(db);
ObjectId parentA = db.resolve("a");
ObjectId parentB = db.resolve("b");
ObjectId[] parentIds_AA = new ObjectId[] { parentA, parentA };
ObjectId[] parentIds_AB = new ObjectId[] { parentA, parentB };
ObjectId[] parentIds_BA = new ObjectId[] { parentB, parentA };
ObjectId[] parentIds_BBAB = new ObjectId[] { parentB, parentB, parentA,
parentB };
try {
commitId = commit(ow, db.readDirCache(), parentA, parentA);
fail("an expected exception did not occur");
} catch (IllegalArgumentException e) {
//
}
commitId = commit(ow, db.readDirCache(), parentA, parentB);
newCommit = rw.parseCommit(commitId);
assertEquals(2, newCommit.getParentCount());
commitId = commit(ow, db.readDirCache(), parentB, parentA);
newCommit = rw.parseCommit(commitId);
assertEquals(2, newCommit.getParentCount());
try {
commitId = commit(ow, db.readDirCache(), parentIds_AA);
fail("an expected exception did not occur");
} catch (IllegalArgumentException e) {
//
}
commitId = commit(ow, db.readDirCache(), parentIds_AB);
newCommit = rw.parseCommit(commitId);
assertEquals(2, newCommit.getParentCount());
commitId = commit(ow, db.readDirCache(), parentIds_BA);
newCommit = rw.parseCommit(commitId);
assertEquals(2, newCommit.getParentCount());
try {
commitId = commit(ow, db.readDirCache(), parentIds_BBAB);
fail("an expected exception did not occur");
} catch (IllegalArgumentException e) {
//
}
try {
commitId = commit(ow, db.readDirCache(),
Arrays.asList(parentIds_AA));
fail("an expected exception did not occur");
} catch (IllegalArgumentException e) {
//
}
commitId = commit(ow, db.readDirCache(), parentIds_AB);
newCommit = rw.parseCommit(commitId);
assertEquals(2, newCommit.getParentCount());
commitId = commit(ow, db.readDirCache(), parentIds_BA);
newCommit = rw.parseCommit(commitId);
assertEquals(2, newCommit.getParentCount());
try {
commitId = commit(ow, db.readDirCache(), parentIds_BBAB);
fail("an expected exception did not occur");
} catch (IllegalArgumentException e) {
//
}
}
@Test
public void testTrivialTwoWay_disjointhistories() throws IOException {
Merger ourMerger = MergeStrategy.SIMPLE_TWO_WAY_IN_CORE.newMerger(db);
@ -391,4 +472,31 @@ private static ObjectId commit(final ObjectInserter odi,
odi.flush();
return id;
}
private ObjectId commit(final ObjectInserter odi, final DirCache treeB,
final AnyObjectId parentId1, final AnyObjectId parentId2)
throws Exception {
final CommitBuilder c = new CommitBuilder();
c.setTreeId(treeB.writeTree(odi));
c.setAuthor(new PersonIdent("A U Thor", "a.u.thor", 1L, 0));
c.setCommitter(c.getAuthor());
c.setParentIds(parentId1, parentId2);
c.setMessage("Tree " + c.getTreeId().name());
ObjectId id = odi.insert(c);
odi.flush();
return id;
}
private ObjectId commit(final ObjectInserter odi, final DirCache treeB,
List<ObjectId> parents) throws Exception {
final CommitBuilder c = new CommitBuilder();
c.setTreeId(treeB.writeTree(odi));
c.setAuthor(new PersonIdent("A U Thor", "a.u.thor", 1L, 0));
c.setCommitter(c.getAuthor());
c.setParentIds(parents);
c.setMessage("Tree " + c.getTreeId().name());
ObjectId id = odi.insert(c);
odi.flush();
return id;
}
}

View File

@ -393,32 +393,6 @@ public void testEgitHistory() throws Exception {
test.noMoreCommits();
}
// test a history where a merge commit has two time the same parent
@Test
public void testDuplicateParents() throws Exception {
final RevCommit m1 = commit();
final RevCommit m2 = commit(m1);
final RevCommit m3 = commit(m2, m2);
final RevCommit s1 = commit(m2);
final RevCommit s2 = commit(s1);
PlotWalk pw = new PlotWalk(db);
pw.markStart(pw.lookupCommit(m3));
pw.markStart(pw.lookupCommit(s2));
PlotCommitList<PlotLane> pcl = new PlotCommitList<PlotLane>();
pcl.source(pw);
pcl.fillTo(Integer.MAX_VALUE);
CommitListAssert test = new CommitListAssert(pcl);
test.commit(s2).nrOfPassingLanes(0);
test.commit(s1).nrOfPassingLanes(0);
test.commit(m3).nrOfPassingLanes(1);
test.commit(m2).nrOfPassingLanes(0);
test.commit(m1).nrOfPassingLanes(0);
test.noMoreCommits();
}
/**
* The graph shows the problematic original positioning. Due to this some
* lanes are no straight lines here, but they are with the new layout code)

View File

@ -173,6 +173,7 @@ doesNotHandleMode=Does not handle mode {0} ({1})
downloadCancelled=Download cancelled
downloadCancelledDuringIndexing=Download cancelled during indexing
duplicateAdvertisementsOf=duplicate advertisements of {0}
duplicateParents=The following parent was specified multiple times: {0}
duplicateRef=Duplicate ref: {0}
duplicateRemoteRefUpdateIsIllegal=Duplicate remote ref update is illegal. Affected remote name: {0}
duplicateStagesNotAllowed=Duplicate stages not allowed

View File

@ -232,6 +232,7 @@ public static JGitText get() {
/***/ public String downloadCancelled;
/***/ public String downloadCancelledDuringIndexing;
/***/ public String duplicateAdvertisementsOf;
/***/ public String duplicateParents;
/***/ public String duplicateRef;
/***/ public String duplicateRemoteRefUpdateIsIllegal;
/***/ public String duplicateStagesNotAllowed;

View File

@ -50,8 +50,11 @@
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import java.text.MessageFormat;
import java.util.List;
import org.eclipse.jgit.internal.JGitText;
/**
* Mutable builder to construct a commit recording the state of a project.
*
@ -166,7 +169,11 @@ public void setParentId(AnyObjectId newParent) {
* branch being merged into the current branch.
*/
public void setParentIds(AnyObjectId parent1, AnyObjectId parent2) {
parentIds = new ObjectId[] { parent1.copy(), parent2.copy() };
if (!parent1.equals(parent2))
parentIds = new ObjectId[] { parent1.copy(), parent2.copy() };
else
throw new IllegalArgumentException(MessageFormat.format(
JGitText.get().duplicateParents, parent1.getName()));
}
/**
@ -176,9 +183,18 @@ public void setParentIds(AnyObjectId parent1, AnyObjectId parent2) {
* the entire list of parents for this commit.
*/
public void setParentIds(ObjectId... newParents) {
parentIds = new ObjectId[newParents.length];
for (int i = 0; i < newParents.length; i++)
parentIds[i] = newParents[i].copy();
ObjectId[] tmpIds = new ObjectId[newParents.length];
int newParentCount = 0;
for (int i = 0; i < newParents.length; i++) {
for (int j = 0; j < newParentCount; j++)
if (tmpIds[j].equals(newParents[i]))
throw new IllegalArgumentException(MessageFormat.format(
JGitText.get().duplicateParents,
tmpIds[j].getName()));
tmpIds[newParentCount++] = newParents[i].copy();
}
parentIds = tmpIds;
}
/**
@ -188,9 +204,18 @@ public void setParentIds(ObjectId... newParents) {
* the entire list of parents for this commit.
*/
public void setParentIds(List<? extends AnyObjectId> newParents) {
parentIds = new ObjectId[newParents.size()];
for (int i = 0; i < newParents.size(); i++)
parentIds[i] = newParents.get(i).copy();
ObjectId[] tmpIds = new ObjectId[newParents.size()];
int newParentCount = 0;
for (AnyObjectId newId : newParents) {
for (int j = 0; j < newParentCount; j++)
if (tmpIds[j].equals(newId))
throw new IllegalArgumentException(MessageFormat.format(
JGitText.get().duplicateParents,
tmpIds[j].getName()));
tmpIds[newParentCount++] = newId.copy();
}
parentIds = tmpIds;
}
/**
@ -203,6 +228,11 @@ public void addParentId(AnyObjectId additionalParent) {
if (parentIds.length == 0) {
setParentId(additionalParent);
} else {
for (int i = 0; i < parentIds.length; i++)
if (parentIds[i].equals(additionalParent))
throw new IllegalArgumentException(MessageFormat.format(
JGitText.get().duplicateParents,
parentIds[i].getName()));
ObjectId[] newParents = new ObjectId[parentIds.length + 1];
System.arraycopy(parentIds, 0, newParents, 0, parentIds.length);
newParents[parentIds.length] = additionalParent.copy();