[RFC] branch: list branches by single remote

Subsystems: the rest

8 messages, 3 authors, 2016-06-15 · open the first message on its own page

[RFC] branch: list branches by single remote

From: Michael Schubert <hidden>
Date: 2016-06-15 22:51:43

I've always missed some option for "git branch" to limit the output to a single
remote. What's the right place to filter the output? The code below doesn't
look very smart..

---
 builtin/branch.c |   16 +++++++++++++---
 1 files changed, 13 insertions(+), 3 deletions(-)
diff --git a/builtin/branch.c b/builtin/branch.c
index 3142daa..22e6be2 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -17,7 +17,7 @@
 #include "revision.h"
 
 static const char * const builtin_branch_usage[] = {
-	"git branch [options] [-r | -a] [--merged | --no-merged]",
+	"git branch [options] [-r | -a] [-R <remote>] [--merged | --no-merged]",
 	"git branch [options] [-l] [-f] <branchname> [<start-point>]",
 	"git branch [options] [-r] (-d | -D) <branchname>...",
 	"git branch [options] (-m | -M) [<oldbranch>] <newbranch>",
@@ -260,6 +260,7 @@ static char *resolve_symref(const char *src, const char *prefix)
 
 struct append_ref_cb {
 	struct ref_list *ref_list;
+	const char *remote;
 	int ret;
 };
 
@@ -297,6 +298,9 @@ static int append_ref(const char *refname, const unsigned char *sha1, int flags,
 	if ((kind & ref_list->kinds) == 0)
 		return 0;
 
+	if (cb->remote && strncmp(cb->remote, refname, strlen(cb->remote)))
+		return 0;
+
 	commit = NULL;
 	if (ref_list->verbose || ref_list->with_commit || merge_filter != NO_FILTER) {
 		commit = lookup_commit_reference_gently(sha1, 1);
@@ -492,7 +496,7 @@ static void show_detached(struct ref_list *ref_list)
 	}
 }
 
-static int print_ref_list(int kinds, int detached, int verbose, int abbrev, struct commit_list *with_commit)
+static int print_ref_list(int kinds, int detached, int verbose, int abbrev, struct commit_list *with_commit, const char *only)
 {
 	int i;
 	struct append_ref_cb cb;
@@ -506,6 +510,7 @@ static int print_ref_list(int kinds, int detached, int verbose, int abbrev, stru
 	if (merge_filter != NO_FILTER)
 		init_revisions(&ref_list.revs, NULL);
 	cb.ref_list = &ref_list;
+	cb.remote = only;
 	cb.ret = 0;
 	for_each_rawref(append_ref, &cb);
 	if (merge_filter != NO_FILTER) {
@@ -618,6 +623,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
 	enum branch_track track;
 	int kinds = REF_LOCAL_BRANCH;
 	struct commit_list *with_commit = NULL;
+	char *single_remote = NULL;
 
 	struct option options[] = {
 		OPT_GROUP("Generic options"),
@@ -647,6 +653,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
 		OPT_GROUP("Specific git-branch actions:"),
 		OPT_SET_INT('a', NULL, &kinds, "list both remote-tracking and local branches",
 			REF_REMOTE_BRANCH | REF_LOCAL_BRANCH),
+		OPT_STRING('R', NULL, &single_remote, "remote", "list only branches by remote"),
 		OPT_BIT('d', NULL, &delete, "delete fully merged branch", 1),
 		OPT_BIT('D', NULL, &delete, "delete branch (even if not merged)", 2),
 		OPT_BIT('m', NULL, &rename, "move/rename a branch and its reflog", 1),
@@ -696,10 +703,13 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
 	if (!!delete + !!rename + !!force_create > 1)
 		usage_with_options(builtin_branch_usage, options);
 
+	if (single_remote)
+		kinds = REF_REMOTE_BRANCH;
+
 	if (delete)
 		return delete_branches(argc, argv, delete > 1, kinds);
 	else if (argc == 0)
-		return print_ref_list(kinds, detached, verbose, abbrev, with_commit);
+		return print_ref_list(kinds, detached, verbose, abbrev, with_commit, single_remote);
 	else if (rename && (argc == 1))
 		rename_branch(head, argv[0], rename > 1);
 	else if (rename && (argc == 2))
-- 
1.7.6.396.ge0613.dirty

Re: [RFC] branch: list branches by single remote

From: Jeff King <hidden>
Date: 2016-06-15 22:51:44

On Tue, Aug 02, 2011 at 07:17:38PM +0200, Michael Schubert wrote:
quoted hunk
@@ -297,6 +298,9 @@ static int append_ref(const char *refname, const unsigned char *sha1, int flags,
 	if ((kind & ref_list->kinds) == 0)
 		return 0;
 
+	if (cb->remote && strncmp(cb->remote, refname, strlen(cb->remote)))
+		return 0;
+
This isn't right. You are assuming that a remote called "foo" will have
all of its branches in refs/remotes/foo. That's true under the default
configuration, but technically speaking, the remote tracking branches of
"foo" are defined by the right-hand side of foo's fetch refspecs.

So I think you want something more like this:

  int i;
  struct remote *remote = remote_get("foo");

  for (i = 0; i < remote->fetch_refspec_nr; i++) {
          struct refspec *rs = remote->fetch + i;

          /* if it's not a wildcard, then take the rhs verbatim */
          if (!rs->pattern)
                  append_ref(rs->dst);
          else {
                  /* it's a wildcard like refs/remotes/foo/*; glob in
                   * the ref list appropriately. Or we can cheat, noting
                   * that git's only allowed wildcard is "/*" at the
                   * end, and do this: */
                  char *prefix = xstrndup(rs->dst, strlen(rs->dst) - 1);
                  for_each_ref_in(prefix, append_ref, NULL);
          }
  }

instead of the call to "for_each_rawref(append_ref, ...)" that would
normally be used. You could even pretty easily allow selecting branches
from multiple remotes, too, though I don't know if that is actually
useful.

-Peff

Re: [RFC] branch: list branches by single remote

From: Michael J Gruber <hidden>
Date: 2016-06-15 22:51:49

Jeff King venit, vidit, dixit 04.08.2011 06:06:
On Tue, Aug 02, 2011 at 07:17:38PM +0200, Michael Schubert wrote:
quoted
@@ -297,6 +298,9 @@ static int append_ref(const char *refname, const unsigned char *sha1, int flags,
 	if ((kind & ref_list->kinds) == 0)
 		return 0;
 
+	if (cb->remote && strncmp(cb->remote, refname, strlen(cb->remote)))
+		return 0;
+
This isn't right. You are assuming that a remote called "foo" will have
all of its branches in refs/remotes/foo. That's true under the default
configuration, but technically speaking, the remote tracking branches of
"foo" are defined by the right-hand side of foo's fetch refspecs.
You are 100% right here, but...
So I think you want something more like this:
...the op still might want to filter simply by the remote name.

Reminds me that I have to resurrect my patterns-with-branches series....

Michael

Re: [RFC] branch: list branches by single remote

From: Michael Schubert <hidden>
Date: 2016-06-15 22:51:49

On 08/16/2011 03:37 PM, Michael J Gruber wrote:
Jeff King venit, vidit, dixit 04.08.2011 06:06:
quoted
On Tue, Aug 02, 2011 at 07:17:38PM +0200, Michael Schubert wrote:
quoted
@@ -297,6 +298,9 @@ static int append_ref(const char *refname, const unsigned char *sha1, int flags,
 	if ((kind & ref_list->kinds) == 0)
 		return 0;
 
+	if (cb->remote && strncmp(cb->remote, refname, strlen(cb->remote)))
+		return 0;
+
This isn't right. You are assuming that a remote called "foo" will have
all of its branches in refs/remotes/foo. That's true under the default
configuration, but technically speaking, the remote tracking branches of
"foo" are defined by the right-hand side of foo's fetch refspecs.
You are 100% right here, but...
quoted
So I think you want something more like this:
...the op still might want to filter simply by the remote name.
There's an interesting discussion related to the subject:

http://thread.gmane.org/gmane.comp.version-control.git/178960

Re: [RFC] branch: list branches by single remote

From: Jeff King <hidden>
Date: 2016-06-15 22:51:49

On Tue, Aug 16, 2011 at 03:37:33PM +0200, Michael J Gruber wrote:
quoted
This isn't right. You are assuming that a remote called "foo" will have
all of its branches in refs/remotes/foo. That's true under the default
configuration, but technically speaking, the remote tracking branches of
"foo" are defined by the right-hand side of foo's fetch refspecs.
You are 100% right here, but...
quoted
So I think you want something more like this:
...the op still might want to filter simply by the remote name.
That is a perfectly reasonable approach. It just should be called
"--glob" or something, and not "remote".  git-tag allows patterns to an
explicit "tag -l", but "-l" is already taken for git-branch.
Reminds me that I have to resurrect my patterns-with-branches series....
Please do. I think it's a much simpler and more versatile solution to
the same problem.

-Peff

Re: [RFC] branch: list branches by single remote

From: Michael Schubert <hidden>
Date: 2016-06-15 22:51:54

On 08/16/2011 05:14 PM, Jeff King wrote:
On Tue, Aug 16, 2011 at 03:37:33PM +0200, Michael J Gruber wrote:
quoted
quoted
This isn't right. You are assuming that a remote called "foo" will have
all of its branches in refs/remotes/foo. That's true under the default
configuration, but technically speaking, the remote tracking branches of
"foo" are defined by the right-hand side of foo's fetch refspecs.
You are 100% right here, but...
quoted
So I think you want something more like this:
...the op still might want to filter simply by the remote name.
That is a perfectly reasonable approach. It just should be called
"--glob" or something, and not "remote".  git-tag allows patterns to an
explicit "tag -l", but "-l" is already taken for git-branch.
As suggested, I've just called it "--glob" for now.
--- 8< ---
Subject: [PATCH] branch: add option "glob" to filter listed branches

When calling "git branch" with either "-r" or "-a", there is no way to
further limit the output. Add an option "--glob=<pattern>" to allow
limiting the output to matching branch names.

Signed-off-by: Michael Schubert <redacted>
---
 Documentation/git-branch.txt |    8 ++++++--
 builtin/branch.c             |   13 ++++++++++---
 2 files changed, 16 insertions(+), 5 deletions(-)
diff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt
index c50f189..5de3c79 100644
--- a/Documentation/git-branch.txt
+++ b/Documentation/git-branch.txt
@@ -8,7 +8,7 @@ git-branch - List, create, or delete branches
 SYNOPSIS
 --------
 [verse]
-'git branch' [--color[=<when>] | --no-color] [-r | -a]
+'git branch' [--color[=<when>] | --no-color] [(-r | -a) [--glob=<pattern>]]
 	[-v [--abbrev=<length> | --no-abbrev]]
 	[(--merged | --no-merged | --contains) [<commit>]]
 'git branch' [--set-upstream | --track | --no-track] [-l] [-f] <branchname> [<start-point>]
@@ -20,7 +20,8 @@ DESCRIPTION
 
 With no arguments, existing branches are listed and the current branch will
 be highlighted with an asterisk.  Option `-r` causes the remote-tracking
-branches to be listed, and option `-a` shows both.
+branches to be listed, option `-a` shows both and `--glob` limits the
+output to branches matching <pattern>.
 
 With `--contains`, shows only the branches that contain the named commit
 (in other words, the branches whose tip commits are descendants of the
@@ -105,6 +106,9 @@ OPTIONS
 -a::
 	List both remote-tracking branches and local branches.
 
+--glob=<pattern>::
+	List only branches matching pattern.
+
 -v::
 --verbose::
 	Show sha1 and commit subject line for each head, along with
diff --git a/builtin/branch.c b/builtin/branch.c
index 3142daa..74730ad 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -17,7 +17,7 @@
 #include "revision.h"
 
 static const char * const builtin_branch_usage[] = {
-	"git branch [options] [-r | -a] [--merged | --no-merged]",
+	"git branch [options] [(-r | -a) [--glob=<pattern>]] [--merged | --no-merged]",
 	"git branch [options] [-l] [-f] <branchname> [<start-point>]",
 	"git branch [options] [-r] (-d | -D) <branchname>...",
 	"git branch [options] (-m | -M) [<oldbranch>] <newbranch>",
@@ -260,6 +260,7 @@ static char *resolve_symref(const char *src, const char *prefix)
 
 struct append_ref_cb {
 	struct ref_list *ref_list;
+	const char *glob;
 	int ret;
 };
 
@@ -297,6 +298,9 @@ static int append_ref(const char *refname, const unsigned char *sha1, int flags,
 	if ((kind & ref_list->kinds) == 0)
 		return 0;
 
+	if (cb->glob && fnmatch(cb->glob, refname, 0))
+		return 0;
+
 	commit = NULL;
 	if (ref_list->verbose || ref_list->with_commit || merge_filter != NO_FILTER) {
 		commit = lookup_commit_reference_gently(sha1, 1);
@@ -492,7 +496,7 @@ static void show_detached(struct ref_list *ref_list)
 	}
 }
 
-static int print_ref_list(int kinds, int detached, int verbose, int abbrev, struct commit_list *with_commit)
+static int print_ref_list(int kinds, int detached, int verbose, int abbrev, struct commit_list *with_commit, const char *glob)
 {
 	int i;
 	struct append_ref_cb cb;
@@ -506,6 +510,7 @@ static int print_ref_list(int kinds, int detached, int verbose, int abbrev, stru
 	if (merge_filter != NO_FILTER)
 		init_revisions(&ref_list.revs, NULL);
 	cb.ref_list = &ref_list;
+	cb.glob = glob;
 	cb.ret = 0;
 	for_each_rawref(append_ref, &cb);
 	if (merge_filter != NO_FILTER) {
@@ -618,6 +623,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
 	enum branch_track track;
 	int kinds = REF_LOCAL_BRANCH;
 	struct commit_list *with_commit = NULL;
+	char *glob = NULL;
 
 	struct option options[] = {
 		OPT_GROUP("Generic options"),
@@ -647,6 +653,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
 		OPT_GROUP("Specific git-branch actions:"),
 		OPT_SET_INT('a', NULL, &kinds, "list both remote-tracking and local branches",
 			REF_REMOTE_BRANCH | REF_LOCAL_BRANCH),
+		OPT_STRING(0, "glob", &glob, "pattern", "list only branches matching the pattern"),
 		OPT_BIT('d', NULL, &delete, "delete fully merged branch", 1),
 		OPT_BIT('D', NULL, &delete, "delete branch (even if not merged)", 2),
 		OPT_BIT('m', NULL, &rename, "move/rename a branch and its reflog", 1),
@@ -699,7 +706,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
 	if (delete)
 		return delete_branches(argc, argv, delete > 1, kinds);
 	else if (argc == 0)
-		return print_ref_list(kinds, detached, verbose, abbrev, with_commit);
+		return print_ref_list(kinds, detached, verbose, abbrev, with_commit, glob);
 	else if (rename && (argc == 1))
 		rename_branch(head, argv[0], rename > 1);
 	else if (rename && (argc == 2))
-- 
1.7.6.577.g8d918.dirty

Re: [RFC] branch: list branches by single remote

From: Michael J Gruber <hidden>
Date: 2016-06-15 22:51:54

Michael Schubert venit, vidit, dixit 24.08.2011 17:14:
On 08/16/2011 05:14 PM, Jeff King wrote:
quoted
On Tue, Aug 16, 2011 at 03:37:33PM +0200, Michael J Gruber wrote:
quoted
quoted
This isn't right. You are assuming that a remote called "foo" will have
all of its branches in refs/remotes/foo. That's true under the default
configuration, but technically speaking, the remote tracking branches of
"foo" are defined by the right-hand side of foo's fetch refspecs.
You are 100% right here, but...
quoted
So I think you want something more like this:
...the op still might want to filter simply by the remote name.
That is a perfectly reasonable approach. It just should be called
"--glob" or something, and not "remote".  git-tag allows patterns to an
explicit "tag -l", but "-l" is already taken for git-branch.
As suggested, I've just called it "--glob" for now.
Well, again, what's the point in replicating

http://permalink.gmane.org/gmane.comp.version-control.git/172228

and how is it different?

As I've mentioned, I've been in the middle of polishing that up. You can
follow it if you like:

http://repo.or.cz/w/git/mjg.git/shortlog/refs/heads/branch-list-pattern

Also, again: git branch is much more like git tag than it is like git
log, so I think the pattern matching options should be, too.

Michael

Re: [RFC] branch: list branches by single remote

From: Michael Schubert <hidden>
Date: 2016-06-15 22:51:54

On 08/24/2011 05:37 PM, Michael J Gruber wrote:
Michael Schubert venit, vidit, dixit 24.08.2011 17:14:
quoted
On 08/16/2011 05:14 PM, Jeff King wrote:
quoted
On Tue, Aug 16, 2011 at 03:37:33PM +0200, Michael J Gruber wrote:
quoted
quoted
This isn't right. You are assuming that a remote called "foo" will have
all of its branches in refs/remotes/foo. That's true under the default
configuration, but technically speaking, the remote tracking branches of
"foo" are defined by the right-hand side of foo's fetch refspecs.
You are 100% right here, but...
quoted
So I think you want something more like this:
...the op still might want to filter simply by the remote name.
That is a perfectly reasonable approach. It just should be called
"--glob" or something, and not "remote".  git-tag allows patterns to an
explicit "tag -l", but "-l" is already taken for git-branch.
As suggested, I've just called it "--glob" for now.
Well, again, what's the point in replicating

http://permalink.gmane.org/gmane.comp.version-control.git/172228

and how is it different?
While I just haven't seen this,
As I've mentioned, I've been in the middle of polishing that up. You can
follow it if you like:

http://repo.or.cz/w/git/mjg.git/shortlog/refs/heads/branch-list-pattern
I thought I just send it out not knowing you're actually into resurrecting
the "patterns-with-branches series".

Thanks.
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help