]> source.dussan.org Git - jgit.git/commitdiff
Add setContains to ListBranchCommand (branch --contains) 19/20619/1
authorRobin Stocker <robin@nibor.org>
Tue, 14 Jan 2014 16:38:40 +0000 (17:38 +0100)
committerRobin Stocker <robin@nibor.org>
Tue, 14 Jan 2014 16:45:50 +0000 (17:45 +0100)
To correspond to the behavior of "git branch", also return HEAD in case
it is detached.

Bug: 425678
Change-Id: Ie615731434d70b99bd18c7a02e832c0a2c3ceef3
Signed-off-by: Robin Stocker <robin@nibor.org>
org.eclipse.jgit.test/tst/org/eclipse/jgit/api/BranchCommandTest.java
org.eclipse.jgit/src/org/eclipse/jgit/api/ListBranchCommand.java

index 91ced0a596f6cfac5dac97ac999b07da66a48aa0..c0e2e2ca8aa3e546c0e8af39e0f04494ca55d431 100644 (file)
@@ -196,6 +196,20 @@ public class BranchCommandTest extends RepositoryTestCase {
                git.branchList().setListMode(ListMode.ALL).call();
        }
 
+       @Test
+       public void testListBranchesWithContains() throws Exception {
+               git.branchCreate().setName("foo").setStartPoint(secondCommit).call();
+
+               List<Ref> refs = git.branchList().call();
+               assertEquals(2, refs.size());
+
+               List<Ref> refsContainingSecond = git.branchList()
+                               .setContains(secondCommit.name()).call();
+               assertEquals(1, refsContainingSecond.size());
+               // master is on initial commit, so it should not be returned
+               assertEquals("refs/heads/foo", refsContainingSecond.get(0).getName());
+       }
+
        @Test
        public void testCreateFromCommit() throws Exception {
                Ref branch = git.branchCreate().setName("FromInitial").setStartPoint(
index ea6f34b414fa131aefbe36f02affce06cfa00e61..32ee651485cebd6b52a32391752eb6c4b0b3869e 100644 (file)
@@ -1,6 +1,7 @@
 /*
  * Copyright (C) 2010, Mathias Kinzler <mathias.kinzler@sap.com>
  * Copyright (C) 2010, Chris Aniszczyk <caniszczyk@gmail.com>
+ * Copyright (C) 2014, Robin Stocker <robin@nibor.org>
  * and other copyright owners as documented in the project's IP log.
  *
  * This program and the accompanying materials are made available
 package org.eclipse.jgit.api;
 
 import java.io.IOException;
+import java.text.MessageFormat;
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.Comparator;
-import java.util.HashMap;
 import java.util.List;
-import java.util.Map;
 
 import org.eclipse.jgit.api.errors.GitAPIException;
 import org.eclipse.jgit.api.errors.JGitInternalException;
+import org.eclipse.jgit.api.errors.RefNotFoundException;
+import org.eclipse.jgit.internal.JGitText;
 import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.ObjectId;
 import org.eclipse.jgit.lib.Ref;
 import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.revwalk.RevCommit;
+import org.eclipse.jgit.revwalk.RevWalk;
+import org.eclipse.jgit.revwalk.RevWalkUtils;
 
 /**
  * Used to obtain a list of branches.
+ * <p>
+ * In case HEAD is detached (it points directly to a commit), it is also
+ * returned in the results.
  *
  * @see <a
  *      href="http://www.kernel.org/pub/software/scm/git/docs/git-branch.html"
@@ -67,6 +77,8 @@ import org.eclipse.jgit.lib.Repository;
 public class ListBranchCommand extends GitCommand<List<Ref>> {
        private ListMode listMode;
 
+       private String containsCommitish;
+
        /**
         * The modes available for listing branches (corresponding to the -r and -a
         * options)
@@ -91,23 +103,28 @@ public class ListBranchCommand extends GitCommand<List<Ref>> {
 
        public List<Ref> call() throws GitAPIException {
                checkCallable();
-               Map<String, Ref> refList;
+               List<Ref> resultRefs;
                try {
+                       Collection<Ref> refs = new ArrayList<Ref>();
+
+                       // Also return HEAD if it's detached
+                       Ref head = repo.getRef(Constants.HEAD);
+                       if (head != null && head.getLeaf().getName().equals(Constants.HEAD))
+                               refs.add(head);
+
                        if (listMode == null) {
-                               refList = repo.getRefDatabase().getRefs(Constants.R_HEADS);
+                               refs.addAll(getRefs(Constants.R_HEADS));
                        } else if (listMode == ListMode.REMOTE) {
-                               refList = repo.getRefDatabase().getRefs(Constants.R_REMOTES);
+                               refs.addAll(getRefs(Constants.R_REMOTES));
                        } else {
-                               refList = new HashMap<String,Ref>(repo.getRefDatabase().getRefs(
-                                               Constants.R_HEADS));
-                               refList.putAll(repo.getRefDatabase().getRefs(
-                                               Constants.R_REMOTES));
+                               refs.addAll(getRefs(Constants.R_HEADS));
+                               refs.addAll(getRefs(Constants.R_REMOTES));
                        }
+                       resultRefs = new ArrayList<Ref>(filterRefs(refs));
                } catch (IOException e) {
                        throw new JGitInternalException(e.getMessage(), e);
                }
-               List<Ref> resultRefs = new ArrayList<Ref>();
-               resultRefs.addAll(refList.values());
+
                Collections.sort(resultRefs, new Comparator<Ref>() {
                        public int compare(Ref o1, Ref o2) {
                                return o1.getName().compareTo(o2.getName());
@@ -117,6 +134,26 @@ public class ListBranchCommand extends GitCommand<List<Ref>> {
                return resultRefs;
        }
 
+       private Collection<Ref> filterRefs(Collection<Ref> refs)
+                       throws RefNotFoundException, IOException {
+               if (containsCommitish == null)
+                       return refs;
+
+               RevWalk walk = new RevWalk(repo);
+               try {
+                       ObjectId resolved = repo.resolve(containsCommitish);
+                       if (resolved == null)
+                               throw new RefNotFoundException(MessageFormat.format(
+                                               JGitText.get().refNotResolved, containsCommitish));
+
+                       RevCommit containsCommit = walk.parseCommit(resolved);
+                       return RevWalkUtils.findBranchesReachableFrom(containsCommit, walk,
+                                       refs);
+               } finally {
+                       walk.release();
+               }
+       }
+
        /**
         * @param listMode
         *            optional: corresponds to the -r/-a options; by default, only
@@ -128,4 +165,23 @@ public class ListBranchCommand extends GitCommand<List<Ref>> {
                this.listMode = listMode;
                return this;
        }
+
+       /**
+        * If this is set, only the branches that contain the specified commit-ish
+        * as an ancestor are returned.
+        *
+        * @param containsCommitish
+        *            a commit ID or ref name
+        * @return this instance
+        * @since 3.3
+        */
+       public ListBranchCommand setContains(String containsCommitish) {
+               checkCallable();
+               this.containsCommitish = containsCommitish;
+               return this;
+       }
+
+       private Collection<Ref> getRefs(String prefix) throws IOException {
+               return repo.getRefDatabase().getRefs(prefix).values();
+       }
 }