diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Log.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Log.java index ae0c95415..048526ee8 100644 --- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Log.java +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Log.java @@ -272,7 +272,7 @@ class Log extends RevWalkTextBuiltin { if (showNotes(c)) outw.println(); - if (c.getParentCount() == 1 && (showNameAndStatusOnly || showPatch)) + if (c.getParentCount() <= 1 && (showNameAndStatusOnly || showPatch)) showDiff(c); outw.flush(); } @@ -345,7 +345,8 @@ class Log extends RevWalkTextBuiltin { } 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(); if (showNameAndStatusOnly) diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/DiffFormatterTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/DiffFormatterTest.java index 60b746022..91498e7df 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/DiffFormatterTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/DiffFormatterTest.java @@ -53,11 +53,13 @@ import org.eclipse.jgit.diff.DiffEntry.ChangeType; import org.eclipse.jgit.dircache.DirCacheIterator; import org.eclipse.jgit.junit.RepositoryTestCase; import org.eclipse.jgit.junit.TestRepository; +import org.eclipse.jgit.lib.AnyObjectId; import org.eclipse.jgit.lib.FileMode; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.patch.FileHeader; import org.eclipse.jgit.patch.HunkHeader; +import org.eclipse.jgit.revwalk.RevCommit; import org.eclipse.jgit.treewalk.FileTreeIterator; import org.eclipse.jgit.treewalk.filter.PathFilter; import org.eclipse.jgit.util.FileUtils; @@ -341,6 +343,82 @@ public class DiffFormatterTest extends RepositoryTestCase { 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, ObjectId aId, ObjectId bId) { diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/diff/DiffFormatter.java b/org.eclipse.jgit/src/org/eclipse/jgit/diff/DiffFormatter.java index 8b1c023c5..a4b6ab127 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/diff/DiffFormatter.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/diff/DiffFormatter.java @@ -67,6 +67,7 @@ import org.eclipse.jgit.diff.DiffEntry.ChangeType; import org.eclipse.jgit.dircache.DirCacheIterator; import org.eclipse.jgit.errors.AmbiguousObjectException; import org.eclipse.jgit.errors.CorruptObjectException; +import org.eclipse.jgit.errors.IncorrectObjectTypeException; import org.eclipse.jgit.errors.LargeObjectException; import org.eclipse.jgit.errors.MissingObjectException; import org.eclipse.jgit.internal.JGitText; @@ -89,6 +90,7 @@ import org.eclipse.jgit.revwalk.RevWalk; import org.eclipse.jgit.storage.pack.PackConfig; import org.eclipse.jgit.treewalk.AbstractTreeIterator; import org.eclipse.jgit.treewalk.CanonicalTreeParser; +import org.eclipse.jgit.treewalk.EmptyTreeIterator; import org.eclipse.jgit.treewalk.TreeWalk; import org.eclipse.jgit.treewalk.WorkingTreeIterator; import org.eclipse.jgit.treewalk.filter.AndTreeFilter; @@ -391,11 +393,14 @@ public class DiffFormatter { * returned. Callers may choose to format these paths themselves, or convert * them into {@link FileHeader} instances with a complete edit list by * calling {@link #toFileHeader(DiffEntry)}. + *

+ * Either side may be null to indicate that the tree has beed added or + * removed. The diff will be computed against nothing. * * @param a - * the old (or previous) side. + * the old (or previous) side or null * @param b - * the new (or updated) side. + * the new (or updated) side or null * @return the paths that are different. * @throws IOException * trees cannot be read or file contents cannot be read. @@ -405,7 +410,9 @@ public class DiffFormatter { assertHaveRepository(); 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 class DiffFormatter { * returned. Callers may choose to format these paths themselves, or convert * them into {@link FileHeader} instances with a complete edit list by * calling {@link #toFileHeader(DiffEntry)}. + *

+ * Either side may be null to indicate that the tree has beed added or + * removed. The diff will be computed against nothing. * * @param a - * the old (or previous) side. + * the old (or previous) side or null * @param b - * the new (or updated) side. + * the new (or updated) side or null * @return the paths that are different. * @throws IOException * trees cannot be read or file contents cannot be read. @@ -427,13 +437,19 @@ public class DiffFormatter { public List scan(RevTree a, RevTree b) throws IOException { assertHaveRepository(); - CanonicalTreeParser aParser = new CanonicalTreeParser(); - CanonicalTreeParser bParser = new CanonicalTreeParser(); - - aParser.reset(reader, a); - bParser.reset(reader, b); + AbstractTreeIterator aIterator = makeIteratorFromTreeOrNull(a); + AbstractTreeIterator bIterator = makeIteratorFromTreeOrNull(b); + return scan(aIterator, bIterator); + } - return scan(aParser, bParser); + private AbstractTreeIterator makeIteratorFromTreeOrNull(RevTree tree) + throws IncorrectObjectTypeException, IOException { + if (tree != null) { + CanonicalTreeParser parser = new CanonicalTreeParser(); + parser.reset(reader, tree); + return parser; + } else + return new EmptyTreeIterator(); } /** @@ -553,11 +569,14 @@ public class DiffFormatter { * * The patch is expressed as instructions to modify {@code a} to make it * {@code b}. + *

+ * Either side may be null to indicate that the tree has beed added or + * removed. The diff will be computed against nothing. * * @param a - * the old (or previous) side. + * the old (or previous) side or null * @param b - * the new (or updated) side. + * the new (or updated) side or null * @throws IOException * trees cannot be read, file contents cannot be read, or the * patch cannot be output. @@ -572,10 +591,14 @@ public class DiffFormatter { * The patch is expressed as instructions to modify {@code a} to make it * {@code b}. * + *

+ * Either side may be null to indicate that the tree has beed added or + * removed. The diff will be computed against nothing. + * * @param a - * the old (or previous) side. + * the old (or previous) side or null * @param b - * the new (or updated) side. + * the new (or updated) side or null * @throws IOException * trees cannot be read, file contents cannot be read, or the * patch cannot be output. @@ -589,11 +612,14 @@ public class DiffFormatter { * * The patch is expressed as instructions to modify {@code a} to make it * {@code b}. + *

+ * Either side may be null to indicate that the tree has beed added or + * removed. The diff will be computed against nothing. * * @param a - * the old (or previous) side. + * the old (or previous) side or null * @param b - * the new (or updated) side. + * the new (or updated) side or null * @throws IOException * trees cannot be read, file contents cannot be read, or the * patch cannot be output.