Handle diff formatting when there is nothing to compare with

DiffFormatter now suports either side being null and the log program
will output the diff for the first commit.

Bug: 395791
Change-Id: I378957b57e9ad1f7195ba416f402178453f0ebd3
This commit is contained in:
Robin Rosenberg 2014-06-29 22:31:26 +02:00
parent 71c18201c1
commit 89ad10ec27
3 changed files with 124 additions and 19 deletions

View File

@ -272,7 +272,7 @@ protected void show(final RevCommit c) throws Exception {
if (showNotes(c)) if (showNotes(c))
outw.println(); outw.println();
if (c.getParentCount() == 1 && (showNameAndStatusOnly || showPatch)) if (c.getParentCount() <= 1 && (showNameAndStatusOnly || showPatch))
showDiff(c); showDiff(c);
outw.flush(); outw.flush();
} }
@ -345,7 +345,8 @@ private boolean showNotes(RevCommit c, NoteMap map, String label,
} }
private void showDiff(RevCommit c) throws IOException { private void showDiff(RevCommit c) throws IOException {
final RevTree a = c.getParent(0).getTree(); final RevTree a = c.getParentCount() > 0 ? c.getParent(0).getTree()
: null;
final RevTree b = c.getTree(); final RevTree b = c.getTree();
if (showNameAndStatusOnly) if (showNameAndStatusOnly)

View File

@ -53,11 +53,13 @@
import org.eclipse.jgit.dircache.DirCacheIterator; import org.eclipse.jgit.dircache.DirCacheIterator;
import org.eclipse.jgit.junit.RepositoryTestCase; import org.eclipse.jgit.junit.RepositoryTestCase;
import org.eclipse.jgit.junit.TestRepository; import org.eclipse.jgit.junit.TestRepository;
import org.eclipse.jgit.lib.AnyObjectId;
import org.eclipse.jgit.lib.FileMode; import org.eclipse.jgit.lib.FileMode;
import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.patch.FileHeader; import org.eclipse.jgit.patch.FileHeader;
import org.eclipse.jgit.patch.HunkHeader; import org.eclipse.jgit.patch.HunkHeader;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.treewalk.FileTreeIterator; import org.eclipse.jgit.treewalk.FileTreeIterator;
import org.eclipse.jgit.treewalk.filter.PathFilter; import org.eclipse.jgit.treewalk.filter.PathFilter;
import org.eclipse.jgit.util.FileUtils; import org.eclipse.jgit.util.FileUtils;
@ -341,6 +343,82 @@ public void testDiff() throws Exception {
assertEquals(expected, actual); assertEquals(expected, actual);
} }
@Test
public void testDiffRootNullToTree() throws Exception {
write(new File(db.getDirectory().getParent(), "test.txt"), "test");
File folder = new File(db.getDirectory().getParent(), "folder");
FileUtils.mkdir(folder);
write(new File(folder, "folder.txt"), "folder");
Git git = new Git(db);
git.add().addFilepattern(".").call();
RevCommit commit = git.commit().setMessage("Initial commit").call();
write(new File(folder, "folder.txt"), "folder change");
ByteArrayOutputStream os = new ByteArrayOutputStream();
DiffFormatter dfmt = new DiffFormatter(new SafeBufferedOutputStream(os));
dfmt.setRepository(db);
dfmt.setPathFilter(PathFilter.create("folder"));
dfmt.format(null, commit.getTree().getId());
dfmt.flush();
String actual = os.toString("UTF-8");
String expected = "diff --git a/folder/folder.txt b/folder/folder.txt\n"
+ "new file mode 100644\n"
+ "index 0000000..0119635\n"
+ "--- /dev/null\n"
+ "+++ b/folder/folder.txt\n"
+ "@@ -0,0 +1 @@\n"
+ "+folder\n"
+ "\\ No newline at end of file\n";
assertEquals(expected, actual);
}
@Test
public void testDiffRootTreeToNull() throws Exception {
write(new File(db.getDirectory().getParent(), "test.txt"), "test");
File folder = new File(db.getDirectory().getParent(), "folder");
FileUtils.mkdir(folder);
write(new File(folder, "folder.txt"), "folder");
Git git = new Git(db);
git.add().addFilepattern(".").call();
RevCommit commit = git.commit().setMessage("Initial commit").call();
write(new File(folder, "folder.txt"), "folder change");
ByteArrayOutputStream os = new ByteArrayOutputStream();
DiffFormatter dfmt = new DiffFormatter(new SafeBufferedOutputStream(os));
dfmt.setRepository(db);
dfmt.setPathFilter(PathFilter.create("folder"));
dfmt.format(commit.getTree().getId(), null);
dfmt.flush();
String actual = os.toString("UTF-8");
String expected = "diff --git a/folder/folder.txt b/folder/folder.txt\n"
+ "deleted file mode 100644\n"
+ "index 0119635..0000000\n"
+ "--- a/folder/folder.txt\n"
+ "+++ /dev/null\n"
+ "@@ -1 +0,0 @@\n"
+ "-folder\n"
+ "\\ No newline at end of file\n";
assertEquals(expected, actual);
}
@Test
public void testDiffNullToNull() throws Exception {
ByteArrayOutputStream os = new ByteArrayOutputStream();
DiffFormatter dfmt = new DiffFormatter(new SafeBufferedOutputStream(os));
dfmt.setRepository(db);
dfmt.format((AnyObjectId) null, null);
dfmt.flush();
String actual = os.toString("UTF-8");
String expected = "";
assertEquals(expected, actual);
}
private static String makeDiffHeader(String pathA, String pathB, private static String makeDiffHeader(String pathA, String pathB,
ObjectId aId, ObjectId aId,
ObjectId bId) { ObjectId bId) {

View File

@ -67,6 +67,7 @@
import org.eclipse.jgit.dircache.DirCacheIterator; import org.eclipse.jgit.dircache.DirCacheIterator;
import org.eclipse.jgit.errors.AmbiguousObjectException; import org.eclipse.jgit.errors.AmbiguousObjectException;
import org.eclipse.jgit.errors.CorruptObjectException; import org.eclipse.jgit.errors.CorruptObjectException;
import org.eclipse.jgit.errors.IncorrectObjectTypeException;
import org.eclipse.jgit.errors.LargeObjectException; import org.eclipse.jgit.errors.LargeObjectException;
import org.eclipse.jgit.errors.MissingObjectException; import org.eclipse.jgit.errors.MissingObjectException;
import org.eclipse.jgit.internal.JGitText; import org.eclipse.jgit.internal.JGitText;
@ -89,6 +90,7 @@
import org.eclipse.jgit.storage.pack.PackConfig; import org.eclipse.jgit.storage.pack.PackConfig;
import org.eclipse.jgit.treewalk.AbstractTreeIterator; import org.eclipse.jgit.treewalk.AbstractTreeIterator;
import org.eclipse.jgit.treewalk.CanonicalTreeParser; import org.eclipse.jgit.treewalk.CanonicalTreeParser;
import org.eclipse.jgit.treewalk.EmptyTreeIterator;
import org.eclipse.jgit.treewalk.TreeWalk; import org.eclipse.jgit.treewalk.TreeWalk;
import org.eclipse.jgit.treewalk.WorkingTreeIterator; import org.eclipse.jgit.treewalk.WorkingTreeIterator;
import org.eclipse.jgit.treewalk.filter.AndTreeFilter; import org.eclipse.jgit.treewalk.filter.AndTreeFilter;
@ -391,11 +393,14 @@ public void release() {
* returned. Callers may choose to format these paths themselves, or convert * returned. Callers may choose to format these paths themselves, or convert
* them into {@link FileHeader} instances with a complete edit list by * them into {@link FileHeader} instances with a complete edit list by
* calling {@link #toFileHeader(DiffEntry)}. * calling {@link #toFileHeader(DiffEntry)}.
* <p>
* Either side may be null to indicate that the tree has beed added or
* removed. The diff will be computed against nothing.
* *
* @param a * @param a
* the old (or previous) side. * the old (or previous) side or null
* @param b * @param b
* the new (or updated) side. * the new (or updated) side or null
* @return the paths that are different. * @return the paths that are different.
* @throws IOException * @throws IOException
* trees cannot be read or file contents cannot be read. * trees cannot be read or file contents cannot be read.
@ -405,7 +410,9 @@ public List<DiffEntry> scan(AnyObjectId a, AnyObjectId b)
assertHaveRepository(); assertHaveRepository();
RevWalk rw = new RevWalk(reader); RevWalk rw = new RevWalk(reader);
return scan(rw.parseTree(a), rw.parseTree(b)); RevTree aTree = a != null ? rw.parseTree(a) : null;
RevTree bTree = b != null ? rw.parseTree(b) : null;
return scan(aTree, bTree);
} }
/** /**
@ -415,11 +422,14 @@ public List<DiffEntry> scan(AnyObjectId a, AnyObjectId b)
* returned. Callers may choose to format these paths themselves, or convert * returned. Callers may choose to format these paths themselves, or convert
* them into {@link FileHeader} instances with a complete edit list by * them into {@link FileHeader} instances with a complete edit list by
* calling {@link #toFileHeader(DiffEntry)}. * calling {@link #toFileHeader(DiffEntry)}.
* <p>
* Either side may be null to indicate that the tree has beed added or
* removed. The diff will be computed against nothing.
* *
* @param a * @param a
* the old (or previous) side. * the old (or previous) side or null
* @param b * @param b
* the new (or updated) side. * the new (or updated) side or null
* @return the paths that are different. * @return the paths that are different.
* @throws IOException * @throws IOException
* trees cannot be read or file contents cannot be read. * trees cannot be read or file contents cannot be read.
@ -427,13 +437,19 @@ public List<DiffEntry> scan(AnyObjectId a, AnyObjectId b)
public List<DiffEntry> scan(RevTree a, RevTree b) throws IOException { public List<DiffEntry> scan(RevTree a, RevTree b) throws IOException {
assertHaveRepository(); assertHaveRepository();
CanonicalTreeParser aParser = new CanonicalTreeParser(); AbstractTreeIterator aIterator = makeIteratorFromTreeOrNull(a);
CanonicalTreeParser bParser = new CanonicalTreeParser(); AbstractTreeIterator bIterator = makeIteratorFromTreeOrNull(b);
return scan(aIterator, bIterator);
}
aParser.reset(reader, a); private AbstractTreeIterator makeIteratorFromTreeOrNull(RevTree tree)
bParser.reset(reader, b); throws IncorrectObjectTypeException, IOException {
if (tree != null) {
return scan(aParser, bParser); CanonicalTreeParser parser = new CanonicalTreeParser();
parser.reset(reader, tree);
return parser;
} else
return new EmptyTreeIterator();
} }
/** /**
@ -553,11 +569,14 @@ private static boolean isRename(DiffEntry ent) {
* *
* The patch is expressed as instructions to modify {@code a} to make it * The patch is expressed as instructions to modify {@code a} to make it
* {@code b}. * {@code b}.
* <p>
* Either side may be null to indicate that the tree has beed added or
* removed. The diff will be computed against nothing.
* *
* @param a * @param a
* the old (or previous) side. * the old (or previous) side or null
* @param b * @param b
* the new (or updated) side. * the new (or updated) side or null
* @throws IOException * @throws IOException
* trees cannot be read, file contents cannot be read, or the * trees cannot be read, file contents cannot be read, or the
* patch cannot be output. * patch cannot be output.
@ -572,10 +591,14 @@ public void format(AnyObjectId a, AnyObjectId b) throws IOException {
* The patch is expressed as instructions to modify {@code a} to make it * The patch is expressed as instructions to modify {@code a} to make it
* {@code b}. * {@code b}.
* *
* <p>
* Either side may be null to indicate that the tree has beed added or
* removed. The diff will be computed against nothing.
*
* @param a * @param a
* the old (or previous) side. * the old (or previous) side or null
* @param b * @param b
* the new (or updated) side. * the new (or updated) side or null
* @throws IOException * @throws IOException
* trees cannot be read, file contents cannot be read, or the * trees cannot be read, file contents cannot be read, or the
* patch cannot be output. * patch cannot be output.
@ -589,11 +612,14 @@ public void format(RevTree a, RevTree b) throws IOException {
* *
* The patch is expressed as instructions to modify {@code a} to make it * The patch is expressed as instructions to modify {@code a} to make it
* {@code b}. * {@code b}.
* <p>
* Either side may be null to indicate that the tree has beed added or
* removed. The diff will be computed against nothing.
* *
* @param a * @param a
* the old (or previous) side. * the old (or previous) side or null
* @param b * @param b
* the new (or updated) side. * the new (or updated) side or null
* @throws IOException * @throws IOException
* trees cannot be read, file contents cannot be read, or the * trees cannot be read, file contents cannot be read, or the
* patch cannot be output. * patch cannot be output.