summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRonald Bhuleskar <funronald@google.com>2022-08-03 16:41:43 -0700
committerRonald Bhuleskar <funronald@google.com>2022-08-16 21:32:25 -0700
commit6297491e8adb85e43d60ffe75fb71f335e733449 (patch)
tree2b0e16f7108eef11d9b92f152db9b53e5669b691
parentab3799be37834a0ab9ac394eae1fe7c2766ee516 (diff)
downloadjgit-6297491e8adb85e43d60ffe75fb71f335e733449.tar.gz
jgit-6297491e8adb85e43d60ffe75fb71f335e733449.zip
Adds FilteredRevCommit that can overwrites its parents in the DAG.
Change-Id: I1ea63a3b56074099688fc45d6a22943a8ae3c2ae
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/FilteredRevCommitTest.java135
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/FilteredRevWalkTest.java121
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/FirstParentRevWalkTest.java53
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkFollowFilterTest.java15
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkPathFilter1Test.java102
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/revwalk/FilteredRevCommit.java95
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevCommit.java18
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RewriteGenerator.java37
8 files changed, 523 insertions, 53 deletions
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/FilteredRevCommitTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/FilteredRevCommitTest.java
new file mode 100644
index 0000000000..49ce47ef42
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/FilteredRevCommitTest.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2022, Google LLC.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0 which is available at
+ * https://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * @since 6.3
+ */
+package org.eclipse.jgit.revwalk;
+
+import static java.nio.charset.StandardCharsets.UTF_8;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertSame;
+
+import java.util.Arrays;
+
+import org.eclipse.jgit.internal.storage.dfs.DfsRepositoryDescription;
+import org.eclipse.jgit.internal.storage.dfs.InMemoryRepository;
+import org.eclipse.jgit.junit.TestRepository;
+import org.eclipse.jgit.lib.AnyObjectId;
+import org.eclipse.jgit.lib.ObjectLoader;
+import org.junit.Before;
+import org.junit.Test;
+
+public class FilteredRevCommitTest {
+ private TestRepository<InMemoryRepository> tr;
+
+ private RevWalk rw;
+
+ @Before
+ public void setUp() throws Exception {
+ tr = new TestRepository<>(
+ new InMemoryRepository(new DfsRepositoryDescription("test")));
+ rw = tr.getRevWalk();
+ }
+
+ @Test
+ public void testParseHeaders_noParent() 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();
+ FilteredRevCommit filteredRevCommit = new FilteredRevCommit(orig);
+ filteredRevCommit.parseHeaders(rw);
+ tr.branch("master").update(filteredRevCommit);
+ assertEquals("foo contents", blobAsString(filteredRevCommit, "foo"));
+ assertEquals("bar contents", blobAsString(filteredRevCommit, "bar"));
+ assertEquals("baz contents",
+ blobAsString(filteredRevCommit, "dir/baz"));
+ }
+
+ @Test
+ public void testParents() throws Exception {
+ RevCommit commit1 = tr.commit().add("foo", "foo contents\n").create();
+ RevCommit commit2 = tr.commit().parent(commit1)
+ .message("original message").add("bar", "bar contents")
+ .create();
+ RevCommit commit3 = tr.commit().parent(commit2).message("commit3")
+ .add("foo", "foo contents\n new line\n").create();
+
+ FilteredRevCommit filteredCommitHead = new FilteredRevCommit(commit3,
+ commit1);
+
+ assertEquals(commit1, Arrays.stream(filteredCommitHead.getParents())
+ .findFirst().get());
+ assertEquals("commit3", filteredCommitHead.getFullMessage());
+ assertEquals("foo contents\n new line\n",
+ blobAsString(filteredCommitHead, "foo"));
+ assertEquals(filteredCommitHead.getTree(), commit3.getTree());
+
+ }
+
+ @Test
+ public void testFlag() 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();
+
+ FilteredRevCommit filteredRevCommit = new FilteredRevCommit(orig, root);
+ assertEquals(RevObject.PARSED, orig.flags);
+ assertEquals(RevObject.PARSED, filteredRevCommit.flags);
+ }
+
+ @Test
+ public void testCommitState() 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();
+
+ FilteredRevCommit filteredRevCommit = new FilteredRevCommit(orig, root);
+ assertEquals(filteredRevCommit.getParentCount(), 1);
+ assertSame(filteredRevCommit.getRawBuffer(), orig.getRawBuffer());
+ assertSame(filteredRevCommit.getTree(), orig.getTree());
+ assertEquals(filteredRevCommit.getFullMessage(), orig.getFullMessage());
+ assertEquals(filteredRevCommit.commitTime, orig.commitTime);
+ assertSame(filteredRevCommit.parents, RevCommit.NO_PARENTS);
+ }
+
+ @Test
+ public void testParseCommit_withParents_parsesRealParents()
+ throws Exception {
+ RevCommit commit1 = tr.commit().add("foo", "foo contents\n").create();
+ RevCommit commit2 = tr.commit().parent(commit1)
+ .message("original message").add("bar", "bar contents")
+ .create();
+ RevCommit commit3 = tr.commit().parent(commit2).message("commit3")
+ .add("foo", "foo contents\n new line\n").create();
+
+ FilteredRevCommit filteredCommitHead = new FilteredRevCommit(commit3,
+ commit1);
+
+ RevCommit parsedCommit = rw.parseCommit(filteredCommitHead.getId());
+ assertEquals(filteredCommitHead.getId(), commit3.getId());
+ // This is an intended behavior as revWalk#parseCommit doesn't parse
+ // through the overridden parents rather uses the real parents.
+ assertNotEquals(
+ Arrays.stream(parsedCommit.getParents()).findFirst().get(),
+ Arrays.stream(filteredCommitHead.getParents()).findFirst()
+ .get());
+ }
+
+ 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);
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/FilteredRevWalkTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/FilteredRevWalkTest.java
new file mode 100644
index 0000000000..b1f8c0c0e9
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/FilteredRevWalkTest.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2022, Google LLC.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0 which is available at
+ * https://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+package org.eclipse.jgit.revwalk;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+
+import org.eclipse.jgit.internal.storage.file.FileRepository;
+import org.eclipse.jgit.junit.TestRepository;
+import org.junit.Before;
+import org.junit.Test;
+
+public class FilteredRevWalkTest extends RevWalkTestCase {
+ private TestRepository<FileRepository> repository;
+
+ @Override
+ @Before
+ public void setUp() throws Exception {
+ super.setUp();
+ repository = new TestRepository<>(db);
+ }
+
+ @Test
+ public void testWalk() throws Exception {
+ writeTrashFile("a.txt", "content");
+ repository.git().add().addFilepattern("a.txt").call();
+ RevCommit c1 = repository.git().commit().setMessage("first commit")
+ .call();
+
+ writeTrashFile("b.txt", "new file added");
+ repository.git().add().addFilepattern("b.txt").call();
+ repository.git().commit().setMessage("second commit").call();
+
+ writeTrashFile("a.txt", "content added");
+ repository.git().add().addFilepattern("a.txt").call();
+ RevCommit c3 = repository.git().commit().setMessage("third commit")
+ .call();
+
+ RevWalk revWalk = repository.getRevWalk();
+ FilteredRevCommit filteredRevCommit = new FilteredRevCommit(c3, c1);
+
+ revWalk.markStart(filteredRevCommit);
+ assertEquals(c3, revWalk.next());
+ assertEquals(c1, revWalk.next());
+ }
+
+ @Test
+ public void testParseBody() throws Exception {
+ writeTrashFile("a.txt", "content");
+ repository.git().add().addFilepattern("a.txt").call();
+ RevCommit c1 = repository.git().commit().setMessage("first commit")
+ .call();
+
+ writeTrashFile("b.txt", "new file added");
+ repository.git().add().addFilepattern("b.txt").call();
+ repository.git().commit().setMessage("second commit").call();
+
+ writeTrashFile("a.txt", "content added");
+ repository.git().add().addFilepattern("a.txt").call();
+ RevCommit c3 = repository.git().commit().setMessage("third commit")
+ .call();
+
+ FilteredRevCommit filteredRevCommit = new FilteredRevCommit(c3, c1);
+ filteredRevCommit.disposeBody();
+
+ RevWalk revWalk = repository.getRevWalk();
+
+ revWalk.parseBody(filteredRevCommit);
+ assertEquals(filteredRevCommit.getFullMessage(), c3.getFullMessage());
+ assertEquals(filteredRevCommit.getShortMessage(), c3.getShortMessage());
+ assertEquals(filteredRevCommit.commitTime, c3.commitTime);
+ assertSame(filteredRevCommit.getTree(), c3.getTree());
+ assertSame(filteredRevCommit.parents, RevCommit.NO_PARENTS);
+
+ }
+
+ /**
+ * Test that the uninteresting flag is carried over correctly. Every commit
+ * should have the uninteresting flag resulting in a RevWalk returning no
+ * commit.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void testRevWalkCarryUninteresting() throws Exception {
+ writeTrashFile("a.txt", "content");
+ repository.git().add().addFilepattern("a.txt").call();
+ RevCommit c1 = repository.git().commit().setMessage("first commit")
+ .call();
+
+ writeTrashFile("b.txt", "new file added");
+ repository.git().add().addFilepattern("b.txt").call();
+ RevCommit c2 = repository.git().commit().setMessage("second commit")
+ .call();
+
+ writeTrashFile("a.txt", "content added");
+ repository.git().add().addFilepattern("a.txt").call();
+ RevCommit c3 = repository.git().commit().setMessage("third commit")
+ .call();
+
+ RevWalk revWalk = repository.getRevWalk();
+ FilteredRevCommit filteredCommit1 = new FilteredRevCommit(c1);
+ FilteredRevCommit filteredCommit2 = new FilteredRevCommit(c2,
+ filteredCommit1);
+ FilteredRevCommit filteredCommit3 = new FilteredRevCommit(c3,
+ filteredCommit2);
+
+ revWalk.markStart(filteredCommit2);
+ markUninteresting(filteredCommit3);
+ assertNull("Found an unexpected commit", rw.next());
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/FirstParentRevWalkTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/FirstParentRevWalkTest.java
index c8256b89c0..146d16953c 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/FirstParentRevWalkTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/FirstParentRevWalkTest.java
@@ -12,6 +12,7 @@ package org.eclipse.jgit.revwalk;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.revwalk.filter.MessageRevFilter;
@@ -423,9 +424,41 @@ public class FirstParentRevWalkTest extends RevWalkTestCase {
rw.sort(RevSort.TOPO, true);
rw.setTreeFilter(PathFilterGroup.createFromStrings("0"));
markStart(d);
- assertCommit(d, rw.next());
- assertCommit(c, rw.next());
- assertCommit(b, rw.next());
+
+ assertEquals(d, rw.next());
+ assertEquals(c, rw.next());
+ assertEquals(b, rw.next());
+ assertNull(rw.next());
+ }
+
+ @Test
+ public void testWithTopoSortAndTreeFilter_shouldUseFilteredRevCommits()
+ throws Exception {
+ RevCommit a = commit();
+ RevCommit b = commit(tree(file("0", blob("b"))), a);
+ RevCommit c = commit(tree(file("0", blob("c"))), b, a);
+ RevCommit d = commit(tree(file("0", blob("d"))), c);
+
+ rw.reset();
+ rw.setFirstParent(true);
+ rw.sort(RevSort.TOPO, true);
+ rw.setTreeFilter(PathFilterGroup.createFromStrings("0"));
+ markStart(d);
+
+ RevCommit x = rw.next();
+ assertTrue(x instanceof FilteredRevCommit);
+ assertEquals(1, x.getParentCount());
+ assertEquals(c, x.getParent(0));
+
+ RevCommit y = rw.next();
+ assertTrue(y instanceof FilteredRevCommit);
+ assertEquals(1, y.getParentCount());
+ assertEquals(b, y.getParent(0));
+
+ RevCommit z = rw.next();
+ assertTrue(z instanceof FilteredRevCommit);
+ assertEquals(0, z.getParentCount());
+
assertNull(rw.next());
}
@@ -441,8 +474,8 @@ public class FirstParentRevWalkTest extends RevWalkTestCase {
rw.sort(RevSort.TOPO, true);
rw.setTreeFilter(PathFilterGroup.createFromStrings("0"));
markStart(d);
- assertCommit(d, rw.next());
- assertCommit(c, rw.next());
+ assertEquals(d, rw.next());
+ assertEquals(c, rw.next());
assertNull(rw.next());
}
@@ -458,9 +491,9 @@ public class FirstParentRevWalkTest extends RevWalkTestCase {
rw.sort(RevSort.TOPO_KEEP_BRANCH_TOGETHER, true);
rw.setTreeFilter(PathFilterGroup.createFromStrings("0"));
markStart(d);
- assertCommit(d, rw.next());
- assertCommit(c, rw.next());
- assertCommit(b, rw.next());
+ assertEquals(d, rw.next());
+ assertEquals(c, rw.next());
+ assertEquals(b, rw.next());
assertNull(rw.next());
}
@@ -476,8 +509,8 @@ public class FirstParentRevWalkTest extends RevWalkTestCase {
rw.sort(RevSort.TOPO_KEEP_BRANCH_TOGETHER, true);
rw.setTreeFilter(PathFilterGroup.createFromStrings("0"));
markStart(d);
- assertCommit(d, rw.next());
- assertCommit(c, rw.next());
+ assertEquals(d, rw.next());
+ assertEquals(c, rw.next());
assertNull(rw.next());
}
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkFollowFilterTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkFollowFilterTest.java
index c62136e64d..20478ef709 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkFollowFilterTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkFollowFilterTest.java
@@ -9,6 +9,7 @@
*/
package org.eclipse.jgit.revwalk;
+import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import java.util.ArrayList;
@@ -55,7 +56,7 @@ public class RevWalkFollowFilterTest extends RevWalkTestCase {
final RevCommit a = commit(tree(file("0", blob("0"))));
follow("0");
markStart(a);
- assertCommit(a, rw.next());
+ assertEquals(a, rw.next());
assertNull(rw.next());
assertNoRenames();
@@ -72,8 +73,8 @@ public class RevWalkFollowFilterTest extends RevWalkTestCase {
follow("b");
markStart(renameCommit);
- assertCommit(renameCommit, rw.next());
- assertCommit(a, rw.next());
+ assertEquals(renameCommit, rw.next());
+ assertEquals(a, rw.next());
assertNull(rw.next());
assertRenames("a->b");
@@ -101,10 +102,10 @@ public class RevWalkFollowFilterTest extends RevWalkTestCase {
follow("a");
markStart(renameCommit3);
- assertCommit(renameCommit3, rw.next());
- assertCommit(renameCommit2, rw.next());
- assertCommit(renameCommit1, rw.next());
- assertCommit(a, rw.next());
+ assertEquals(renameCommit3, rw.next());
+ assertEquals(renameCommit2, rw.next());
+ assertEquals(renameCommit1, rw.next());
+ assertEquals(a, rw.next());
assertNull(rw.next());
assertRenames("c->a", "b->c", "a->b");
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkPathFilter1Test.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkPathFilter1Test.java
index 5cce11aa1f..d933a6fc72 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkPathFilter1Test.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkPathFilter1Test.java
@@ -11,6 +11,7 @@
package org.eclipse.jgit.revwalk;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import java.util.Collections;
@@ -23,8 +24,8 @@ import org.junit.Test;
public class RevWalkPathFilter1Test extends RevWalkTestCase {
protected void filter(String path) {
- rw.setTreeFilter(AndTreeFilter.create(PathFilterGroup
- .createFromStrings(Collections.singleton(path)),
+ rw.setTreeFilter(AndTreeFilter.create(
+ PathFilterGroup.createFromStrings(Collections.singleton(path)),
TreeFilter.ANY_DIFF));
}
@@ -49,7 +50,7 @@ public class RevWalkPathFilter1Test extends RevWalkTestCase {
final RevCommit a = commit(tree(file("0", blob("0"))));
filter("0");
markStart(a);
- assertCommit(a, rw.next());
+ assertEquals(a, rw.next());
assertNull(rw.next());
}
@@ -72,10 +73,10 @@ public class RevWalkPathFilter1Test extends RevWalkTestCase {
final RevCommit d = commit(tree(file("0", blob("d"))), c);
filter("0");
markStart(d);
- assertCommit(d, rw.next());
- assertCommit(c, rw.next());
- assertCommit(b, rw.next());
- assertCommit(a, rw.next());
+ assertEquals(d, rw.next());
+ assertEquals(c, rw.next());
+ assertEquals(b, rw.next());
+ assertEquals(a, rw.next());
assertNull(rw.next());
}
@@ -87,11 +88,11 @@ public class RevWalkPathFilter1Test extends RevWalkTestCase {
filter("d/f");
markStart(c);
- assertCommit(c, rw.next());
+ assertEquals(c, rw.next());
assertEquals(1, c.getParentCount());
- assertCommit(a, c.getParent(0)); // b was skipped
+ assertEquals(a, c.getParent(0)); // b was skipped
- assertCommit(a, rw.next());
+ assertEquals(a, rw.next());
assertEquals(0, a.getParentCount());
assertNull(rw.next());
}
@@ -106,11 +107,11 @@ public class RevWalkPathFilter1Test extends RevWalkTestCase {
markStart(c);
rw.setRewriteParents(false);
- assertCommit(c, rw.next());
+ assertEquals(c, rw.next());
assertEquals(1, c.getParentCount());
- assertCommit(b, c.getParent(0));
+ assertEquals(b, c.getParent(0));
- assertCommit(a, rw.next()); // b was skipped
+ assertEquals(a, rw.next()); // b was skipped
assertEquals(0, a.getParentCount());
assertNull(rw.next());
}
@@ -125,18 +126,18 @@ public class RevWalkPathFilter1Test extends RevWalkTestCase {
markStart(d);
// d was skipped
- assertCommit(c, rw.next());
+ assertEquals(c, rw.next());
assertEquals(1, c.getParentCount());
- assertCommit(a, c.getParent(0)); // b was skipped
+ assertEquals(a, c.getParent(0)); // b was skipped
- assertCommit(a, rw.next());
+ assertEquals(a, rw.next());
assertEquals(0, a.getParentCount());
assertNull(rw.next());
}
@Test
public void testStringOfPearls_FilePath2_NoParentRewriting()
- throws Exception {
+ throws Exception {
final RevCommit a = commit(tree(file("d/f", blob("a"))));
final RevCommit b = commit(tree(file("d/f", blob("a"))), a);
final RevCommit c = commit(tree(file("d/f", blob("b"))), b);
@@ -146,12 +147,12 @@ public class RevWalkPathFilter1Test extends RevWalkTestCase {
rw.setRewriteParents(false);
// d was skipped
- assertCommit(c, rw.next());
+ assertEquals(c, rw.next());
assertEquals(1, c.getParentCount());
- assertCommit(b, c.getParent(0));
+ assertEquals(b, c.getParent(0));
// b was skipped
- assertCommit(a, rw.next());
+ assertEquals(a, rw.next());
assertEquals(0, a.getParentCount());
assertNull(rw.next());
}
@@ -166,11 +167,11 @@ public class RevWalkPathFilter1Test extends RevWalkTestCase {
markStart(d);
// d was skipped
- assertCommit(c, rw.next());
+ assertEquals(c, rw.next());
assertEquals(1, c.getParentCount());
- assertCommit(a, c.getParent(0)); // b was skipped
+ assertEquals(a, c.getParent(0)); // b was skipped
- assertCommit(a, rw.next());
+ assertEquals(a, rw.next());
assertEquals(0, a.getParentCount());
assertNull(rw.next());
}
@@ -211,15 +212,15 @@ public class RevWalkPathFilter1Test extends RevWalkTestCase {
filter("d/f");
markStart(i);
- assertCommit(i, rw.next());
+ assertEquals(i, rw.next());
assertEquals(1, i.getParentCount());
- assertCommit(c, i.getParent(0)); // h..d was skipped
+ assertEquals(c, i.getParent(0)); // h..d was skipped
- assertCommit(c, rw.next());
+ assertEquals(c, rw.next());
assertEquals(1, c.getParentCount());
- assertCommit(a, c.getParent(0)); // b was skipped
+ assertEquals(a, c.getParent(0)); // b was skipped
- assertCommit(a, rw.next());
+ assertEquals(a, rw.next());
assertEquals(0, a.getParentCount());
assertNull(rw.next());
}
@@ -273,4 +274,49 @@ public class RevWalkPathFilter1Test extends RevWalkTestCase {
assertCommit(b, rw.next());
assertCommit(a, rw.next());
}
+
+ @Test
+ public void testCommitHeaders_rewrittenParents() throws Exception {
+ final RevCommit a = commit(tree(file("d/f", blob("a"))));
+ final RevCommit b = commit(tree(file("d/f", blob("a"))), a);
+ final RevCommit c = commit(tree(file("d/f", blob("b"))), b);
+ filter("d/f");
+ markStart(c);
+
+ RevCommit cBar = rw.next();
+ assertNotNull(cBar.getShortMessage());
+ assertEquals(cBar.getCommitTime(), c.getCommitTime());
+
+ RevCommit aBar = rw.next();
+ assertNotNull(aBar.getShortMessage());
+ assertEquals(aBar.getCommitTime(), a.getCommitTime());
+
+ assertNull(rw.next());
+ }
+
+ @Test
+ public void testFlags_rewrittenParents() throws Exception {
+ final RevCommit a = commit(tree(file("d/f", blob("a"))));
+ final RevCommit b = commit(tree(file("d/f", blob("a"))), a);
+ final RevCommit c = commit(tree(file("d/f", blob("b"))), b);
+
+ final RevFlag flag1 = rw.newFlag("flag1");
+ final RevFlag flag2 = rw.newFlag("flag2");
+
+ a.add(flag1);
+ c.add(flag2);
+
+ filter("d/f");
+ markStart(c);
+
+ RevCommit cBar = rw.next();
+ assertEquals(cBar.flags & RevObject.PARSED, 1);
+ assertEquals(cBar.flags & flag2.mask, flag2.mask);
+
+ RevCommit aBar = rw.next();
+ assertEquals(aBar.flags & RevObject.PARSED, 1);
+ assertEquals(aBar.flags & flag1.mask, flag1.mask);
+
+ assertNull(rw.next());
+ }
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/FilteredRevCommit.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/FilteredRevCommit.java
new file mode 100644
index 0000000000..16beac3903
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/FilteredRevCommit.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2022, Google LLC.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0 which is available at
+ * https://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+package org.eclipse.jgit.revwalk;
+
+/**
+ * A filtered commit reference that overrides its parent in the DAG.
+ *
+ * @since 6.3
+ */
+public class FilteredRevCommit extends RevCommit {
+ private RevCommit[] overriddenParents;
+
+ /**
+ * Create a new commit reference wrapping an underlying commit reference.
+ *
+ * @param commit
+ * commit that is being wrapped
+ */
+ public FilteredRevCommit(RevCommit commit) {
+ this(commit, NO_PARENTS);
+ }
+
+ /**
+ * Create a new commit reference wrapping an underlying commit reference.
+ *
+ * @param commit
+ * commit that is being wrapped
+ * @param parents
+ * overridden parents for the commit
+ */
+ public FilteredRevCommit(RevCommit commit, RevCommit... parents) {
+ super(commit);
+ this.overriddenParents = parents;
+ this.parents = NO_PARENTS;
+ }
+
+ /**
+ * Update parents on the commit
+ *
+ * @param overriddenParents
+ * parents to be overwritten
+ */
+ public void setParents(RevCommit... overriddenParents) {
+ this.overriddenParents = overriddenParents;
+ }
+
+ /**
+ * Get the number of parent commits listed in this commit.
+ *
+ * @return number of parents; always a positive value but can be 0 if it has
+ * no parents.
+ */
+ @Override
+ public int getParentCount() {
+ return overriddenParents.length;
+ }
+
+ /**
+ * Get the nth parent from this commit's parent list.
+ *
+ * @param nth
+ * parent index to obtain. Must be in the range 0 through
+ * {@link #getParentCount()}-1.
+ * @return the specified parent.
+ * @throws java.lang.ArrayIndexOutOfBoundsException
+ * an invalid parent index was specified.
+ */
+ @Override
+ public RevCommit getParent(int nth) {
+ return overriddenParents[nth];
+ }
+
+ /**
+ * Obtain an array of all parents (<b>NOTE - THIS IS NOT A COPY</b>).
+ *
+ * <p>
+ * This method is exposed only to provide very fast, efficient access to
+ * this commit's parent list. Applications relying on this list should be
+ * very careful to ensure they do not modify its contents during their use
+ * of it.
+ *
+ * @return the array of parents.
+ */
+ @Override
+ public RevCommit[] getParents() {
+ return overriddenParents;
+ }
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevCommit.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevCommit.java
index 70490eec79..7f1e887074 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevCommit.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevCommit.java
@@ -109,7 +109,7 @@ public class RevCommit extends RevObject {
*
* @since 6.3
*/
- protected RevCommit[] parents;
+ RevCommit[] parents;
int commitTime; // An int here for performance, overflows in 2038
@@ -127,6 +127,22 @@ public class RevCommit extends RevObject {
super(id);
}
+ /**
+ * Create a new commit reference.
+ *
+ * @param orig
+ * commit to be copied from.
+ */
+ RevCommit(RevCommit orig) {
+ super(orig.getId());
+ this.buffer = orig.buffer;
+ this.commitTime = orig.commitTime;
+ this.flags = orig.flags;
+ this.parents = orig.parents;
+ this.tree = orig.tree;
+ this.inDegree = orig.inDegree;
+ }
+
@Override
void parseHeaders(RevWalk walk) throws MissingObjectException,
IncorrectObjectTypeException, IOException {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RewriteGenerator.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RewriteGenerator.java
index 2c88bb872e..9ec331b697 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RewriteGenerator.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RewriteGenerator.java
@@ -11,6 +11,8 @@
package org.eclipse.jgit.revwalk;
import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
import org.eclipse.jgit.errors.IncorrectObjectTypeException;
import org.eclipse.jgit.errors.MissingObjectException;
@@ -38,10 +40,13 @@ class RewriteGenerator extends Generator {
private final FIFORevQueue pending;
+ private final Map<RevCommit, FilteredRevCommit> transformedCommits;
+
RewriteGenerator(Generator s) {
super(s.firstParent);
source = s;
pending = new FIFORevQueue(s.firstParent);
+ transformedCommits = new HashMap<>();
}
@Override
@@ -58,10 +63,10 @@ class RewriteGenerator extends Generator {
@Override
RevCommit next() throws MissingObjectException,
IncorrectObjectTypeException, IOException {
- RevCommit c = pending.next();
+ FilteredRevCommit c = (FilteredRevCommit) pending.next();
if (c == null) {
- c = source.next();
+ c = transform(source.next());
if (c == null) {
// We are done: Both the source generator and our internal list
// are completely exhausted.
@@ -79,9 +84,9 @@ class RewriteGenerator extends Generator {
final RevCommit newp = rewrite(oldp);
if (firstParent) {
if (newp == null) {
- c.parents = RevCommit.NO_PARENTS;
+ c.setParents(RevCommit.NO_PARENTS);
} else {
- c.parents = new RevCommit[] { newp };
+ c.setParents(newp);
}
return c;
}
@@ -91,7 +96,7 @@ class RewriteGenerator extends Generator {
}
}
if (rewrote) {
- c.parents = cleanup(pList);
+ c.setParents(cleanup(pList));
}
return c;
}
@@ -111,7 +116,7 @@ class RewriteGenerator extends Generator {
for (RevCommit parent : c.getParents()) {
while ((parent.flags & RevWalk.TREE_REV_FILTER_APPLIED) == 0) {
- RevCommit n = source.next();
+ FilteredRevCommit n = transform(source.next());
if (n != null) {
pending.add(n);
@@ -130,6 +135,8 @@ class RewriteGenerator extends Generator {
IncorrectObjectTypeException, IOException {
for (;;) {
+ p = transform(p);
+
if (p.getParentCount() > 1) {
// This parent is a merge, so keep it.
//
@@ -158,9 +165,25 @@ class RewriteGenerator extends Generator {
}
applyFilterToParents(p.getParent(0));
- p = p.getParent(0);
+ p = transform(p.getParent(0));
+
+ }
+ }
+ private FilteredRevCommit transform(RevCommit c) {
+ if (c == null) {
+ return null;
}
+
+ if (c instanceof FilteredRevCommit) {
+ return (FilteredRevCommit) c;
+ }
+
+ if (!transformedCommits.containsKey(c)) {
+ transformedCommits.put(c, new FilteredRevCommit(c, c.getParents()));
+ }
+
+ return transformedCommits.get(c);
}
private RevCommit[] cleanup(RevCommit[] oldList) {