TestRepository: Add methods to amend commits or refs

Change-Id: I47082416f6e281262b160ba15272258f9109abd1
This commit is contained in:
Dave Borowitz 2015-03-11 12:04:10 -07:00
parent d79cadb3cf
commit da85ca73ff
2 changed files with 192 additions and 13 deletions

View File

@ -435,6 +435,72 @@ public RevCommit update(String ref, CommitBuilder to) throws Exception {
return update(ref, to.create());
}
/**
* Amend an existing ref.
*
* @param ref
* the name of the reference to amend, which must already exist.
* If {@code ref} does not start with {@code refs/} and is not the
* magic names {@code HEAD} {@code FETCH_HEAD} or {@code
* MERGE_HEAD}, then {@code refs/heads/} will be prefixed in front
* of the given name, thereby assuming it is a branch.
* @return commit builder that amends the branch on commit.
* @throws Exception
*/
public CommitBuilder amendRef(String ref) throws Exception {
String name = normalizeRef(ref);
Ref r = db.getRef(name);
if (r == null)
throw new IOException("Not a ref: " + ref);
return amend(pool.parseCommit(r.getObjectId()), branch(name).commit());
}
/**
* Amend an existing commit.
*
* @param id
* the id of the commit to amend.
* @return commit builder.
* @throws Exception
*/
public CommitBuilder amend(AnyObjectId id) throws Exception {
return amend(pool.parseCommit(id), commit());
}
private CommitBuilder amend(RevCommit old, CommitBuilder b) throws Exception {
pool.parseBody(old);
b.author(old.getAuthorIdent());
b.committer(old.getCommitterIdent());
b.message(old.getFullMessage());
// Use the committer name from the old commit, but update it after ticking
// the clock in CommitBuilder#create().
b.updateCommitterTime = true;
// Reset parents to original parents.
b.noParents();
for (int i = 0; i < old.getParentCount(); i++)
b.parent(old.getParent(i));
// Reset tree to original tree; resetting parents reset tree contents to the
// first parent.
b.tree.clear();
try (TreeWalk tw = new TreeWalk(db)) {
tw.reset(old.getTree());
tw.setRecursive(true);
while (tw.next()) {
b.edit(new PathEdit(tw.getPathString()) {
@Override
public void apply(DirCacheEntry ent) {
ent.setFileMode(tw.getFileMode(0));
ent.setObjectId(tw.getObjectId(0));
}
});
}
}
return b;
}
/**
* Update a reference to point to an object.
*
@ -452,17 +518,7 @@ public RevCommit update(String ref, CommitBuilder to) throws Exception {
* @throws Exception
*/
public <T extends AnyObjectId> T update(String ref, T obj) throws Exception {
if (Constants.HEAD.equals(ref)) {
// nothing
} else if ("FETCH_HEAD".equals(ref)) {
// nothing
} else if ("MERGE_HEAD".equals(ref)) {
// nothing
} else if (ref.startsWith(Constants.R_REFS)) {
// nothing
} else
ref = Constants.R_HEADS + ref;
ref = normalizeRef(ref);
RefUpdate u = db.updateRef(ref);
u.setNewObjectId(obj);
switch (u.forceUpdate()) {
@ -478,6 +534,20 @@ public <T extends AnyObjectId> T update(String ref, T obj) throws Exception {
}
}
private static String normalizeRef(String ref) {
if (Constants.HEAD.equals(ref)) {
// nothing
} else if ("FETCH_HEAD".equals(ref)) {
// nothing
} else if ("MERGE_HEAD".equals(ref)) {
// nothing
} else if (ref.startsWith(Constants.R_REFS)) {
// nothing
} else
ref = Constants.R_HEADS + ref;
return ref;
}
/**
* Soft-reset HEAD to a detached state.
* <p>
@ -807,6 +877,8 @@ public class CommitBuilder {
private boolean insertChangeId;
private boolean updateCommitterTime;
CommitBuilder() {
branch = null;
}
@ -930,8 +1002,11 @@ public RevCommit create() throws Exception {
setAuthorAndCommitter(c);
if (author != null)
c.setAuthor(author);
if (committer != null)
if (committer != null) {
if (updateCommitterTime)
committer = new PersonIdent(committer, new Date(now));
c.setCommitter(committer);
}
ObjectId commitId;
try (ObjectInserter ins = inserter) {

View File

@ -43,19 +43,29 @@
package org.eclipse.jgit.junit;
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import java.util.Date;
import java.util.regex.Pattern;
import org.eclipse.jgit.internal.storage.dfs.DfsRepositoryDescription;
import org.eclipse.jgit.internal.storage.dfs.InMemoryRepository;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.AnyObjectId;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.ObjectLoader;
import org.eclipse.jgit.lib.PersonIdent;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.revwalk.RevBlob;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevObject;
import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.treewalk.TreeWalk;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
@ -76,7 +86,7 @@ public void setUp() throws Exception {
@After
public void tearDown() {
rw.close();
tr.getRepository().close();
repo.close();
}
@Test
@ -168,4 +178,98 @@ public void resetFromDetachedHead() throws Exception {
assertEquals(detached, head.getObjectId());
assertFalse(head.isSymbolic());
}
@Test
public void amendRef() throws Exception {
RevCommit root = tr.commit()
.add("todelete", "to be deleted")
.create();
RevCommit orig = tr.commit().parent(root)
.rm("todelete")
.add("foo", "foo contents")
.add("bar", "bar contents")
.add("dir/baz", "baz contents")
.create();
rw.parseBody(orig);
tr.branch("master").update(orig);
assertEquals("foo contents", blobAsString(orig, "foo"));
assertEquals("bar contents", blobAsString(orig, "bar"));
assertEquals("baz contents", blobAsString(orig, "dir/baz"));
RevCommit amended = tr.amendRef("master")
.tick(3)
.add("bar", "fixed bar contents")
.create();
assertEquals(amended, repo.getRef("refs/heads/master").getObjectId());
rw.parseBody(amended);
assertEquals(1, amended.getParentCount());
assertEquals(root, amended.getParent(0));
assertEquals(orig.getFullMessage(), amended.getFullMessage());
assertEquals(orig.getAuthorIdent(), amended.getAuthorIdent());
// Committer name/email is the same, but time was incremented.
assertEquals(new PersonIdent(orig.getCommitterIdent(), new Date(0)),
new PersonIdent(amended.getCommitterIdent(), new Date(0)));
assertTrue(orig.getCommitTime() < amended.getCommitTime());
assertEquals("foo contents", blobAsString(amended, "foo"));
assertEquals("fixed bar contents", blobAsString(amended, "bar"));
assertEquals("baz contents", blobAsString(amended, "dir/baz"));
assertNull(TreeWalk.forPath(repo, "todelete", amended.getTree()));
}
@Test
public void amendHead() throws Exception {
repo.updateRef("HEAD").link("refs/heads/master");
RevCommit root = tr.commit()
.add("foo", "foo contents")
.create();
RevCommit orig = tr.commit().parent(root)
.message("original message")
.add("bar", "bar contents")
.create();
tr.branch("master").update(orig);
RevCommit amended = tr.amendRef("HEAD")
.add("foo", "fixed foo contents")
.create();
Ref head = repo.getRef(Constants.HEAD);
assertEquals(amended, head.getObjectId());
assertTrue(head.isSymbolic());
assertEquals("refs/heads/master", head.getTarget().getName());
rw.parseBody(amended);
assertEquals("original message", amended.getFullMessage());
assertEquals("fixed foo contents", blobAsString(amended, "foo"));
assertEquals("bar contents", blobAsString(amended, "bar"));
}
@Test
public void amendCommit() throws Exception {
RevCommit root = tr.commit()
.add("foo", "foo contents")
.create();
RevCommit orig = tr.commit().parent(root)
.message("original message")
.add("bar", "bar contents")
.create();
RevCommit amended = tr.amend(orig.copy())
.add("foo", "fixed foo contents")
.create();
rw.parseBody(amended);
assertEquals("original message", amended.getFullMessage());
assertEquals("fixed foo contents", blobAsString(amended, "foo"));
assertEquals("bar contents", blobAsString(amended, "bar"));
}
private String blobAsString(AnyObjectId treeish, String path)
throws Exception {
RevObject obj = tr.get(rw.parseTree(treeish), path);
assertSame(RevBlob.class, obj.getClass());
ObjectLoader loader = rw.getObjectReader().open(obj);
return new String(loader.getCachedBytes(), UTF_8);
}
}