summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/RepositoryTestCase.java12
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkMergedIntoTest.java81
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevWalk.java114
3 files changed, 207 insertions, 0 deletions
diff --git a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/RepositoryTestCase.java b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/RepositoryTestCase.java
index 64556acc1c..5622108dcd 100644
--- a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/RepositoryTestCase.java
+++ b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/RepositoryTestCase.java
@@ -25,6 +25,7 @@ import java.io.InputStreamReader;
import java.io.Reader;
import java.nio.file.Path;
import java.time.Instant;
+import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
@@ -39,6 +40,7 @@ import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.FileMode;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectInserter;
+import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.RefUpdate;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit;
@@ -386,6 +388,16 @@ public abstract class RepositoryTestCase extends LocalDiskRepositoryTestCase {
}
/**
+ * Get all Refs
+ *
+ * @return list of refs
+ * @throws IOException
+ */
+ public List<Ref> getRefs() throws IOException {
+ return db.getRefDatabase().getRefs();
+ }
+
+ /**
* Checkout a branch
*
* @param branchName
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkMergedIntoTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkMergedIntoTest.java
index 2c21eb60d3..2f16aa49e8 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkMergedIntoTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkMergedIntoTest.java
@@ -11,6 +11,9 @@ package org.eclipse.jgit.revwalk;
import static org.junit.Assert.assertTrue;
+import java.util.List;
+import java.util.stream.Collectors;
+import org.eclipse.jgit.lib.Ref;
import org.junit.Test;
public class RevWalkMergedIntoTest extends RevWalkTestCase {
@@ -44,4 +47,82 @@ public class RevWalkMergedIntoTest extends RevWalkTestCase {
final RevCommit t = commit(n, o);
assertTrue(rw.isMergedInto(b, t));
}
+
+ @Test
+ public void testGetMergedInto() throws Exception {
+ /*
+ * i
+ * / \
+ * A o
+ * / \ \
+ * o1 o2 E
+ * / \ / \
+ * B C D
+ */
+ String b = "refs/heads/b";
+ String c = "refs/heads/c";
+ String d = "refs/heads/d";
+ String e = "refs/heads/e";
+ final RevCommit i = commit();
+ final RevCommit a = commit(i);
+ final RevCommit o1 = commit(a);
+ final RevCommit o2 = commit(a);
+ createBranch(commit(o1), b);
+ createBranch(commit(o1, o2), c);
+ createBranch(commit(o2), d);
+ createBranch(commit(commit(i)), e);
+
+ List<String> modifiedResult = rw.getMergedInto(a, getRefs())
+ .stream().map(Ref::getName).collect(Collectors.toList());
+
+ assertTrue(modifiedResult.size() == 3);
+ assertTrue(modifiedResult.contains(b));
+ assertTrue(modifiedResult.contains(c));
+ assertTrue(modifiedResult.contains(d));
+ }
+
+ @Test
+ public void testIsMergedIntoAny() throws Exception {
+ /*
+ * i
+ * / \
+ * A o
+ * / \
+ * o C
+ * /
+ * B
+ */
+ String b = "refs/heads/b";
+ String c = "refs/heads/c";
+ final RevCommit i = commit();
+ final RevCommit a = commit(i);
+ createBranch(commit(commit(a)), b);
+ createBranch(commit(commit(i)), c);
+
+ assertTrue( rw.isMergedIntoAny(a, getRefs()));
+ }
+
+ @Test
+ public void testIsMergedIntoAll() throws Exception {
+ /*
+ *
+ * A
+ * / \
+ * o1 o2
+ * / \ / \
+ * B C D
+ */
+
+ String b = "refs/heads/b";
+ String c = "refs/heads/c";
+ String d = "refs/heads/c";
+ final RevCommit a = commit();
+ final RevCommit o1 = commit(a);
+ final RevCommit o2 = commit(a);
+ createBranch(commit(o1), b);
+ createBranch(commit(o1, o2), c);
+ createBranch(commit(o2), d);
+
+ assertTrue(rw.isMergedIntoAll(a, getRefs()));
+ }
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevWalk.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevWalk.java
index 631d861c0d..3ca2ff6033 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevWalk.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevWalk.java
@@ -36,6 +36,7 @@ import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectIdOwnerMap;
import org.eclipse.jgit.lib.ObjectLoader;
import org.eclipse.jgit.lib.ObjectReader;
+import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.filter.RevFilter;
import org.eclipse.jgit.treewalk.filter.TreeFilter;
@@ -181,6 +182,12 @@ public class RevWalk implements Iterable<RevCommit>, AutoCloseable {
boolean shallowCommitsInitialized;
+ private enum GetMergedIntoStrategy {
+ RETURN_ON_FIRST_FOUND,
+ RETURN_ON_FIRST_NOT_FOUND,
+ EVALUATE_ALL
+ }
+
/**
* Create a new revision walker for a given repository.
*
@@ -425,6 +432,113 @@ public class RevWalk implements Iterable<RevCommit>, AutoCloseable {
}
/**
+ * Determine the Refs into which a commit is merged.
+ * <p>
+ * A commit is merged into a ref if we can find a path of commits that leads
+ * from that specific ref and ends at <code>commit</code>.
+ * <p>
+ *
+ * @param commit
+ * commit the caller thinks is reachable from <code>refs</code>.
+ * @param refs
+ * refs to start iteration from, and which is most likely a
+ * descendant (child) of <code>commit</code>.
+ * @return list of refs that are reachable from <code>commit</code>.
+ * @throws java.io.IOException
+ * a pack file or loose object could not be read.
+ * @since 5.12
+ */
+ public List<Ref> getMergedInto(RevCommit commit, Collection<Ref> refs)
+ throws IOException{
+ return getMergedInto(commit, refs, GetMergedIntoStrategy.EVALUATE_ALL);
+ }
+
+ /**
+ * Determine if a <code>commit</code> is merged into any of the given
+ * <code>refs</code>.
+ *
+ * @param commit
+ * commit the caller thinks is reachable from <code>refs</code>.
+ * @param refs
+ * refs to start iteration from, and which is most likely a
+ * descendant (child) of <code>commit</code>.
+ * @return true if commit is merged into any of the refs; false otherwise.
+ * @throws java.io.IOException
+ * a pack file or loose object could not be read.
+ * @since 5.12
+ */
+ public boolean isMergedIntoAny(RevCommit commit, Collection<Ref> refs)
+ throws IOException {
+ return getMergedInto(commit, refs,
+ GetMergedIntoStrategy.RETURN_ON_FIRST_FOUND).size() > 0;
+ }
+
+ /**
+ * Determine if a <code>commit</code> is merged into all of the given
+ * <code>refs</code>.
+ *
+ * @param commit
+ * commit the caller thinks is reachable from <code>refs</code>.
+ * @param refs
+ * refs to start iteration from, and which is most likely a
+ * descendant (child) of <code>commit</code>.
+ * @return true if commit is merged into all of the refs; false otherwise.
+ * @throws java.io.IOException
+ * a pack file or loose object could not be read.
+ * @since 5.12
+ */
+ public boolean isMergedIntoAll(RevCommit commit, Collection<Ref> refs)
+ throws IOException {
+ return getMergedInto(commit, refs,
+ GetMergedIntoStrategy.RETURN_ON_FIRST_NOT_FOUND).size()
+ == refs.size();
+ }
+
+ private List<Ref> getMergedInto(RevCommit needle, Collection<Ref> haystacks,
+ Enum returnStrategy) throws IOException {
+ List<Ref> result = new ArrayList<>();
+ RevFilter oldRF = filter;
+ TreeFilter oldTF = treeFilter;
+ try {
+ finishDelayedFreeFlags();
+ filter = RevFilter.ALL;
+ treeFilter = TreeFilter.ALL;
+ for (Ref r: haystacks) {
+ RevObject o = parseAny(r.getObjectId());
+ if (!(o instanceof RevCommit)) {
+ continue;
+ }
+ RevCommit c = (RevCommit) o;
+ resetRetain(RevFlag.UNINTERESTING);
+ markStart(c);
+ boolean commitFound = false;
+ RevCommit next;
+ while ((next = next()) != null) {
+ if (References.isSameObject(next, needle)) {
+ result.add(r);
+ if (returnStrategy == GetMergedIntoStrategy.RETURN_ON_FIRST_FOUND) {
+ return result;
+ }
+ commitFound = true;
+ break;
+ }
+ }
+ if(!commitFound){
+ markUninteresting(c);
+ if (returnStrategy == GetMergedIntoStrategy.RETURN_ON_FIRST_NOT_FOUND) {
+ return result;
+ }
+ }
+ }
+ } finally {
+ reset(~freeFlags & APP_FLAGS);
+ filter = oldRF;
+ treeFilter = oldTF;
+ }
+ return result;
+ }
+
+ /**
* Pop the next most recent commit.
*
* @return next most recent commit; null if traversal is over.