{"thread":{"id":"27658","subject":"[PATCH/RFC] branch: add optional parameter to -r to specify remote","startedAt":"2011-06-19T19:19:08Z","lastAt":"2011-06-20T19:12:41Z","messageCount":12,"participants":["Boris Faure","Junio C Hamano","Johannes Sixt","Jeff King","Michael J Gruber"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"170256","messageId":"1308511149-10933-1-git-send-email-billiob@gmail.com","threadId":"27658","inReplyTo":null,"subject":"[PATCH/RFC] branch: add optional parameter to -r to specify remote","fromName":"Boris Faure","fromEmail":"billiob@gmail.com","sentAt":"2011-06-19T19:19:08Z","receivedAt":"2011-06-19T19:19:08Z","isPatch":true,"sender":{"key":"billiob@gmail.com","avatar":"https://avatars.githubusercontent.com/u/27988?v=4"},"body":"The following patch adds an optional parameter to branch -r to use as\n-r=<remote> in order to list branches on a particular remote.\n\n'git branch -d -r one/another' can also be done with\n'git branch -d -r=one another'.\n\nI haven't found tests specially crafted for 'git branch -r -d <branch>'. I\nhope the tests I have added are in the correct places.\n"},{"id":"170257","messageId":"1308511149-10933-2-git-send-email-billiob@gmail.com","threadId":"27658","inReplyTo":"1308511149-10933-1-git-send-email-billiob@gmail.com","subject":"[PATCH/RFC] branch: add optional parameter to -r to specify remote","fromName":"Boris Faure","fromEmail":"billiob@gmail.com","sentAt":"2011-06-19T19:19:09Z","receivedAt":"2011-06-19T19:19:09Z","isPatch":true,"sender":{"key":"billiob@gmail.com","avatar":"https://avatars.githubusercontent.com/u/27988?v=4"},"body":"add '--remote' as long version for '-r'\nupdate documentation\nadd tests\n---\n Documentation/git-branch.txt |   10 +++--\n builtin/branch.c             |   72 ++++++++++++++++++++++++++++++++----------\n t/t3200-branch.sh            |   34 ++++++++++++++++++++\n t/t3203-branch-output.sh     |   59 ++++++++++++++++++++++++++++++++++\n 4 files changed, 154 insertions(+), 21 deletions(-)\n\ndiff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt\nindex c50f189..242da9c 100644\n--- a/Documentation/git-branch.txt\n+++ b/Documentation/git-branch.txt\n@@ -8,12 +8,12 @@ git-branch - List, create, or delete branches\n SYNOPSIS\n --------\n [verse]\n-'git branch' [--color[=<when>] | --no-color] [-r | -a]\n+'git branch' [--color[=<when>] | --no-color] [-r[=<remote>] | -a]\n \t[-v [--abbrev=<length> | --no-abbrev]]\n \t[(--merged | --no-merged | --contains) [<commit>]]\n 'git branch' [--set-upstream | --track | --no-track] [-l] [-f] <branchname> [<start-point>]\n 'git branch' (-m | -M) [<oldbranch>] <newbranch>\n-'git branch' (-d | -D) [-r] <branchname>...\n+'git branch' (-d | -D) [-r[=<remote>]] <branchname>...\n \n DESCRIPTION\n -----------\n@@ -99,8 +99,10 @@ OPTIONS\n \tdefault to color output.\n \tSame as `--color=never`.\n \n--r::\n-\tList or delete (if used with -d) the remote-tracking branches.\n+-r[=<remote>]::\n+--remote[=<remote>]::\n+\tList or delete (if used with -d) the remote-tracking branches from\n+\t<remote> if specified.\n \n -a::\n \tList both remote-tracking branches and local branches.\ndiff --git a/builtin/branch.c b/builtin/branch.c\nindex d6ab93b..52dff04 100644\n--- a/builtin/branch.c\n+++ b/builtin/branch.c\n@@ -17,15 +17,18 @@\n #include \"revision.h\"\n \n static const char * const builtin_branch_usage[] = {\n-\t\"git branch [options] [-r | -a] [--merged | --no-merged]\",\n+\t\"git branch [options] [-r[=<remote>] | -a] [--merged | --no-merged]\",\n \t\"git branch [options] [-l] [-f] <branchname> [<start-point>]\",\n-\t\"git branch [options] [-r] (-d | -D) <branchname>\",\n+\t\"git branch [options] [-r[=<remote>]] (-d | -D) <branchname>\",\n \t\"git branch [options] (-m | -M) [<oldbranch>] <newbranch>\",\n \tNULL\n };\n \n #define REF_LOCAL_BRANCH    0x01\n #define REF_REMOTE_BRANCH   0x02\n+static int kinds = REF_LOCAL_BRANCH;\n+\n+static const char *remote = NULL;\n \n static const char *head;\n static unsigned char head_sha1[20];\n@@ -144,12 +147,12 @@ static int branch_merged(int kind, const char *name,\n \treturn merged;\n }\n \n-static int delete_branches(int argc, const char **argv, int force, int kinds)\n+static int delete_branches(int argc, const char **argv, int force)\n {\n \tstruct commit *rev, *head_rev = NULL;\n \tunsigned char sha1[20];\n \tchar *name = NULL;\n-\tconst char *fmt, *remote;\n+\tconst char *fmt, *remote_trans;\n \tint i;\n \tint ret = 0;\n \tstruct strbuf bname = STRBUF_INIT;\n@@ -158,12 +161,12 @@ static int delete_branches(int argc, const char **argv, int force, int kinds)\n \tcase REF_REMOTE_BRANCH:\n \t\tfmt = \"refs/remotes/%s\";\n \t\t/* TRANSLATORS: This is \"remote \" in \"remote branch '%s' not found\" */\n-\t\tremote = _(\"remote \");\n+\t\tremote_trans = _(\"remote \");\n \t\tforce = 1;\n \t\tbreak;\n \tcase REF_LOCAL_BRANCH:\n \t\tfmt = \"refs/heads/%s\";\n-\t\tremote = \"\";\n+\t\tremote_trans = \"\";\n \t\tbreak;\n \tdefault:\n \t\tdie(_(\"cannot use -a with -d\"));\n@@ -175,7 +178,16 @@ static int delete_branches(int argc, const char **argv, int force, int kinds)\n \t\t\tdie(_(\"Couldn't look up commit object for HEAD\"));\n \t}\n \tfor (i = 0; i < argc; i++, strbuf_release(&bname)) {\n-\t\tstrbuf_branchname(&bname, argv[i]);\n+\t\tif (kinds == REF_REMOTE_BRANCH && remote) {\n+\t\t\tstruct strbuf buf = STRBUF_INIT;\n+\t\t\tstrbuf_addstr(&buf, remote);\n+\t\t\tstrbuf_addch(&buf, '/');\n+\t\t\tstrbuf_addstr(&buf, argv[i]);\n+\t\t\tstrbuf_branchname(&bname, buf.buf);\n+\t\t\tstrbuf_release(&buf);\n+\t\t} else {\n+\t\t\tstrbuf_branchname(&bname, argv[i]);\n+\t\t}\n \t\tif (kinds == REF_LOCAL_BRANCH && !strcmp(head, bname.buf)) {\n \t\t\terror(_(\"Cannot delete the branch '%s' \"\n \t\t\t      \"which you are currently on.\"), bname.buf);\n@@ -188,7 +200,7 @@ static int delete_branches(int argc, const char **argv, int force, int kinds)\n \t\tname = xstrdup(mkpath(fmt, bname.buf));\n \t\tif (!resolve_ref(name, sha1, 1, NULL)) {\n \t\t\terror(_(\"%sbranch '%s' not found.\"),\n-\t\t\t\t\tremote, bname.buf);\n+\t\t\t      remote_trans, bname.buf);\n \t\t\tret = 1;\n \t\t\tcontinue;\n \t\t}\n@@ -209,12 +221,13 @@ static int delete_branches(int argc, const char **argv, int force, int kinds)\n \t\t}\n \n \t\tif (delete_ref(name, sha1, 0)) {\n-\t\t\terror(_(\"Error deleting %sbranch '%s'\"), remote,\n+\t\t\terror(_(\"Error deleting %sbranch '%s'\"), remote_trans,\n \t\t\t      bname.buf);\n \t\t\tret = 1;\n \t\t} else {\n \t\t\tstruct strbuf buf = STRBUF_INIT;\n-\t\t\tprintf(_(\"Deleted %sbranch %s (was %s).\\n\"), remote,\n+\t\t\tprintf(_(\"Deleted %sbranch %s (was %s).\\n\"),\n+\t\t\t       remote_trans,\n \t\t\t       bname.buf,\n \t\t\t       find_unique_abbrev(sha1, DEFAULT_ABBREV));\n \t\t\tstrbuf_addf(&buf, \"branch.%s\", bname.buf);\n@@ -492,7 +505,7 @@ static void show_detached(struct ref_list *ref_list)\n \t}\n }\n \n-static int print_ref_list(int kinds, int detached, int verbose, int abbrev, struct commit_list *with_commit)\n+static int print_ref_list(int detached, int verbose, int abbrev, struct commit_list *with_commit)\n {\n \tint i;\n \tstruct append_ref_cb cb;\n@@ -533,6 +546,14 @@ static int print_ref_list(int kinds, int detached, int verbose, int abbrev, stru\n \t\tchar *prefix = (kinds != REF_REMOTE_BRANCH &&\n \t\t\t\tref_list.list[i].kind == REF_REMOTE_BRANCH)\n \t\t\t\t? \"remotes/\" : \"\";\n+\t\tif (kinds == REF_REMOTE_BRANCH && remote &&\n+\t\t    ref_list.list[i].kind == REF_REMOTE_BRANCH &&\n+\t\t    ref_list.list[i].name) {\n+\t\t\tint remote_len = strlen(remote);\n+\t\t\tif (strncmp(remote, ref_list.list[i].name, strlen(remote)) ||\n+\t\t\t       ref_list.list[i].name[remote_len] != '/')\n+\t\t\t\tcontinue;\n+\t\t}\n \t\tprint_ref_item(&ref_list.list[i], ref_list.maxwidth, verbose,\n \t\t\t       abbrev, current, prefix);\n \t}\n@@ -610,13 +631,28 @@ static int opt_parse_merge_filter(const struct option *opt, const char *arg, int\n \treturn 0;\n }\n \n+static int parse_opt_remote_cb(const struct option *opt, const char *arg,\n+\t\t\t       int unset)\n+{\n+\tkinds = REF_REMOTE_BRANCH;\n+\tif (unset)\n+\t\tkinds = REF_LOCAL_BRANCH;\n+\tif (arg) {\n+\t\tif ( *arg == '=')\n+\t\t\tremote = arg + 1; /* skip '=' */\n+\t\telse\n+\t\t\tremote = arg;\n+\t} else\n+\t\tremote = NULL;\n+\treturn 0;\n+}\n+\n int cmd_branch(int argc, const char **argv, const char *prefix)\n {\n \tint delete = 0, rename = 0, force_create = 0;\n \tint verbose = 0, abbrev = DEFAULT_ABBREV, detached = 0;\n \tint reflog = 0;\n \tenum branch_track track;\n-\tint kinds = REF_LOCAL_BRANCH;\n \tstruct commit_list *with_commit = NULL;\n \n \tstruct option options[] = {\n@@ -628,8 +664,11 @@ int cmd_branch(int argc, const char **argv, const char *prefix)\n \t\tOPT_SET_INT( 0, \"set-upstream\",  &track, \"change upstream info\",\n \t\t\tBRANCH_TRACK_OVERRIDE),\n \t\tOPT__COLOR(&branch_use_color, \"use colored output\"),\n-\t\tOPT_SET_INT('r', NULL,     &kinds, \"act on remote-tracking branches\",\n-\t\t\tREF_REMOTE_BRANCH),\n+\t\t{\n+\t\t\tOPTION_CALLBACK, 'r', \"remote\", &kinds, \"remote\",\n+\t\t\t\"act on remote-tracking branches\",\n+\t\t\tPARSE_OPT_OPTARG, parse_opt_remote_cb, 0\n+\t\t},\n \t\t{\n \t\t\tOPTION_CALLBACK, 0, \"contains\", &with_commit, \"commit\",\n \t\t\t\"print only branches that contain the commit\",\n@@ -695,11 +734,10 @@ int cmd_branch(int argc, const char **argv, const char *prefix)\n \t\t\t     0);\n \tif (!!delete + !!rename + !!force_create > 1)\n \t\tusage_with_options(builtin_branch_usage, options);\n-\n \tif (delete)\n-\t\treturn delete_branches(argc, argv, delete > 1, kinds);\n+\t\treturn delete_branches(argc, argv, delete > 1);\n \telse if (argc == 0)\n-\t\treturn print_ref_list(kinds, detached, verbose, abbrev, with_commit);\n+\t\treturn print_ref_list(detached, verbose, abbrev, with_commit);\n \telse if (rename && (argc == 1))\n \t\trename_branch(head, argv[0], rename > 1);\n \telse if (rename && (argc == 2))\ndiff --git a/t/t3200-branch.sh b/t/t3200-branch.sh\nindex 9e69c8c..df2f0f8 100755\n--- a/t/t3200-branch.sh\n+++ b/t/t3200-branch.sh\n@@ -10,6 +10,23 @@ handled.  Specifically, that a bogus branch is not created.\n '\n . ./test-lib.sh\n \n+setup_repository () {\n+\tmkdir \"$1\" && (\n+\tcd \"$1\" &&\n+\tgit init &&\n+\t>file &&\n+\tgit add file &&\n+\ttest_tick &&\n+\tgit commit -m \"Initial\" &&\n+\tgit checkout -b side &&\n+\t>elif &&\n+\tgit add elif &&\n+\ttest_tick &&\n+\tgit commit -m \"Second\" &&\n+\tgit checkout master\n+\t)\n+}\n+\n test_expect_success \\\n     'prepare a trivial repository' \\\n     'echo Hello > A &&\n@@ -542,4 +559,21 @@ test_expect_success 'attempt to delete a branch merged to its base' '\n \ttest_must_fail git branch -d my10\n '\n \n+test_expect_success 'git branch -d -r=one another should delete another branch from remote one' '\n+\tsetup_repository one &&\n+\tsetup_repository onelong &&\n+\t(\n+\t\tcd one && git branch another\n+\t) &&\n+\tgit remote add -f one one &&\n+\tgit remote add -f onelong onelong &&\n+\tgit branch -d -r=one another &&\n+\ttest ! -f .git/refs/remotes/one/another &&\n+\ttest ! -f .git/logs/refs/remotes/one/another'\n+\n+test_expect_success 'git branch -d --remote=one master should delete master branch from remote one' '\n+\tgit branch -d --remote=one master &&\n+\ttest ! -f .git/refs/remotes/one/master &&\n+\ttest ! -f .git/logs/refs/remotes/one/master'\n+\n test_done\ndiff --git a/t/t3203-branch-output.sh b/t/t3203-branch-output.sh\nindex 6b7c118..aa8cba6 100755\n--- a/t/t3203-branch-output.sh\n+++ b/t/t3203-branch-output.sh\n@@ -3,6 +3,23 @@\n test_description='git branch display tests'\n . ./test-lib.sh\n \n+setup_repository () {\n+\tmkdir \"$1\" && (\n+\tcd \"$1\" &&\n+\tgit init &&\n+\t>file &&\n+\tgit add file &&\n+\ttest_tick &&\n+\tgit commit -m \"Initial\" &&\n+\tgit checkout -b side &&\n+\t>elif &&\n+\tgit add elif &&\n+\ttest_tick &&\n+\tgit commit -m \"Second\" &&\n+\tgit checkout master\n+\t)\n+}\n+\n test_expect_success 'make commits' '\n \techo content >file &&\n \tgit add file &&\n@@ -43,6 +60,26 @@ test_expect_success 'git branch -r shows remote branches' '\n '\n \n cat >expect <<'EOF'\n+  origin/HEAD -> origin/branch-one\n+  origin/branch-one\n+  origin/branch-two\n+EOF\n+test_expect_success 'git branch -r=origin shows remote branches from origin' '\n+\tgit branch -r=origin >actual &&\n+\ttest_cmp expect actual\n+'\n+\n+cat >expect <<'EOF'\n+  origin/HEAD -> origin/branch-one\n+  origin/branch-one\n+  origin/branch-two\n+EOF\n+test_expect_success 'git branch --remote=origin shows remote branches from origin' '\n+\tgit branch --remote=origin >actual &&\n+\ttest_cmp expect actual\n+'\n+\n+cat >expect <<'EOF'\n   branch-one\n   branch-two\n * master\n@@ -78,4 +115,26 @@ test_expect_success 'git branch shows detached HEAD properly' '\n \ttest_i18ncmp expect actual\n '\n \n+\n+cat >expect <<'EOF'\n+  one/another\n+  one/master\n+  one/side\n+EOF\n+\n+test_expect_success 'git branch -r=one shows only branches from remote one' '\n+\tsetup_repository one &&\n+\tsetup_repository onelong &&\n+\t(\n+\t\tcd one && git branch another\n+\t) &&\n+\tgit remote add -f one one &&\n+\tgit remote add -f onelong onelong &&\n+\tgit branch -r=one >actual &&\n+\ttest_cmp expect actual'\n+\n+test_expect_success 'git branch --remote=one shows only branches from remote one' '\n+\tgit branch --remote=one >actual &&\n+\ttest_cmp expect actual'\n+\n test_done\n-- \n1.7.6.rc2.4.g36bfb.dirty\n"},{"id":"170264","messageId":"7vtyble9k8.fsf@alter.siamese.dyndns.org","threadId":"27658","inReplyTo":"1308511149-10933-2-git-send-email-billiob@gmail.com","subject":"Re: [PATCH/RFC] branch: add optional parameter to -r to specify remote","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2011-06-19T22:32:55Z","receivedAt":"2011-06-19T22:32:55Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Boris Faure <billiob@gmail.com> writes:\n\n> add '--remote' as long version for '-r'\n> update documentation\n> add tests\n\n(style) Sentences begin with a capital letter and ends with a period.\n\nThis commit does a lot more than the above, no? It adds an optional remote\nname parameter to the existing \"-r\" option and limits the output to the\nremote tracking branches of the remote when it is specified.\n\n> ---\n\nSign-off?\n\n> diff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt\n> index c50f189..242da9c 100644\n> --- a/Documentation/git-branch.txt\n> +++ b/Documentation/git-branch.txt\n> ...\n> @@ -99,8 +99,10 @@ OPTIONS\n>  \tdefault to color output.\n>  \tSame as `--color=never`.\n>  \n> --r::\n> -\tList or delete (if used with -d) the remote-tracking branches.\n> +-r[=<remote>]::\n> +--remote[=<remote>]::\n> +\tList or delete (if used with -d) the remote-tracking branches from\n> +\t<remote> if specified.\n\nIt is now unspecified what the command would do when the optional <remote>\nis left unspecified.\n\n> diff --git a/builtin/branch.c b/builtin/branch.c\n> index d6ab93b..52dff04 100644\n> --- a/builtin/branch.c\n> +++ b/builtin/branch.c\n> @@ -17,15 +17,18 @@\n>  #include \"revision.h\"\n>  \n>  static const char * const builtin_branch_usage[] = {\n> -\t\"git branch [options] [-r | -a] [--merged | --no-merged]\",\n> +\t\"git branch [options] [-r[=<remote>] | -a] [--merged | --no-merged]\",\n>  \t\"git branch [options] [-l] [-f] <branchname> [<start-point>]\",\n> -\t\"git branch [options] [-r] (-d | -D) <branchname>\",\n> +\t\"git branch [options] [-r[=<remote>]] (-d | -D) <branchname>\",\n>  \t\"git branch [options] (-m | -M) [<oldbranch>] <newbranch>\",\n>  \tNULL\n>  };\n>  \n>  #define REF_LOCAL_BRANCH    0x01\n>  #define REF_REMOTE_BRANCH   0x02\n> +static int kinds = REF_LOCAL_BRANCH;\n\nThis used to be nicely scoped out of global space and got passed around as\nparameter, but now it has become a global? I do not see a good reason for\nthis change.\n\n> +static const char *remote = NULL;\n\nTwo issues.\n\n 1. Presumably you wanted to have this change because you have too many\n    remotes, way more than two, and wanted to filter the output from\n    remotes that you are not interested in. Is it entirely implausible\n    that you might be interested in not just one, but two remotes out of\n    many remotes you have? A single string variable would not suffice for\n    that but you should be able to make this an array of strings.\n\n 2. The name suck for a global variable (same for the \"kinds\" that is now\n    global), and caused the patch to become unnecessarily big by renaming\n    concisely named \"remote\" to ugly \"remote_trans\" in delete_branches()\n    function. In general, local variables are scoped narrower and readers\n    can rely on the context to tell what the variable is _for_, so it is\n    easy for them to see a variable called \"remote\" and understand what\n    aspects of \"remote\" the variable is trying to express. On the other\n    hand, global variables are used in wider context and has to have more\n    descriptive names.  This is about \"filtering\" set of remote tracking\n    branches we deal with to the subset specified by this variable, so it\n    at least has to have \"filter\" or \"limit\" or something to that effect\n    in its name.\n\n> @@ -144,12 +147,12 @@ static int branch_merged(int kind, const char *name,\n>  \treturn merged;\n>  }\n>  \n> -static int delete_branches(int argc, const char **argv, int force, int kinds)\n> +static int delete_branches(int argc, const char **argv, int force)\n>  {\n>  \tstruct commit *rev, *head_rev = NULL;\n>  \tunsigned char sha1[20];\n>  \tchar *name = NULL;\n> -\tconst char *fmt, *remote;\n> +\tconst char *fmt, *remote_trans;\n\nUnwarranted change caused by a poor choice of the new global variable\nabove.\n\n> @@ -610,13 +631,28 @@ static int opt_parse_merge_filter(const struct option *opt, const char *arg, int\n>  \treturn 0;\n>  }\n>  \n> +static int parse_opt_remote_cb(const struct option *opt, const char *arg,\n> +\t\t\t       int unset)\n> +{\n> +\tkinds = REF_REMOTE_BRANCH;\n> +\tif (unset)\n> +\t\tkinds = REF_LOCAL_BRANCH;\n\nWhat is this \"unset\" check about? Wouldn't that be an error if the command\nline said \"--no-remote\"?\n\nAnd you do not return but proceed to look at \"arg\", presumably to handle a\ncase where the command line said \"--no-remote=foobar\"?\n\n> +\tif (arg) {\n> +\t\tif ( *arg == '=')\n\n(style) Unwanted SP after an open parenthesis.\n\n> +\t\t\tremote = arg + 1; /* skip '=' */\n\n(style) It is clear enough what this does without the extra comment.\n\nDoes this forbid remote names that begin with a \"=\"?  I.e.\n\n\t$ git branch -r =temporary\n\nAs to the design of the new feature, I see you tried to make it possible\nto perform what\n\n\t$ git branch -d -r origin/master\n\ndoes with\n\n\t$ git branch -d --remote=origin master\n\nI do not think it is particularly a good idea. Adding yet another way to\ndo the same thing, unless that new way is vastly superiour (e.g. easier to\nuse, easier to explain, more efficient to perform, etc.), does not add\nmuch value to the system.\n\nIt would make much more sense to restrict this feature to the \"listing\"\nside of the branches.  It would be nice if you can do:\n\n\t$ git branch -r --match alice --match bob\n\nto show only remote tracking branches under refs/remotes/{alice,bob}\nand also\n\n\t$ git branch --match \"jk/*\"\n\nto show only local topic branches whose names match the given blob.\n"},{"id":"170279","messageId":"4DFEEB60.5000005@viscovery.net","threadId":"27658","inReplyTo":"7vtyble9k8.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH/RFC] branch: add optional parameter to -r to specify remote","fromName":"Johannes Sixt","fromEmail":"j.sixt@viscovery.net","sentAt":"2011-06-20T06:40:32Z","receivedAt":"2011-06-20T06:40:32Z","isPatch":true,"sender":{"key":"j6t@kdbg.org","avatar":"https://avatars.githubusercontent.com/u/14810926?v=4"},"body":"Am 6/20/2011 0:32, schrieb Junio C Hamano:\n> It would make much more sense to restrict this feature to the \"listing\"\n> side of the branches.  It would be nice if you can do:\n\nI agree with everything you said earlier and the first sentence above. And\nI would have needed the possibility to limit the branch listing to a\nparticular remote a lot in the past. But...\n\n> \t$ git branch -r --match alice --match bob\n> \n> to show only remote tracking branches under refs/remotes/{alice,bob}\n> and also\n> \n> \t$ git branch --match \"jk/*\"\n> \n> to show only local topic branches whose names match the given blob.\n\nI would hate having to learn a new syntax '--match \"jk/*\"' when we can\nalready say\n\n    $ git log --remotes\n    $ git log --remotes=alice --remotes=bob\n    $ git log --remotes=\"jk/*\"\n\nIMO, it is the right approach to have a long option --remotes with an\noptional argument.\n\n-- Hannes\n"},{"id":"170281","messageId":"20110620070316.GA15246@sigill.intra.peff.net","threadId":"27658","inReplyTo":"4DFEEB60.5000005@viscovery.net","subject":"Re: [PATCH/RFC] branch: add optional parameter to -r to specify remote","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2011-06-20T07:03:16Z","receivedAt":"2011-06-20T07:03:16Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Mon, Jun 20, 2011 at 08:40:32AM +0200, Johannes Sixt wrote:\n\n> > \t$ git branch --match \"jk/*\"\n> > \n> > to show only local topic branches whose names match the given blob.\n> \n> I would hate having to learn a new syntax '--match \"jk/*\"' when we can\n> already say\n> \n>     $ git log --remotes\n>     $ git log --remotes=alice --remotes=bob\n>     $ git log --remotes=\"jk/*\"\n> \n> IMO, it is the right approach to have a long option --remotes with an\n> optional argument.\n\nFor that matter, --match should be spelled \"--glob\", as we already have:\n\n  $ git log --glob='jk/*'\n\nI think having the ref-selection for \"git branch\" match that of the\nrevision walker makes sense.\n\n-Peff\n"},{"id":"170292","messageId":"4DFF2A1D.3060206@drmicha.warpmail.net","threadId":"27658","inReplyTo":"20110620070316.GA15246@sigill.intra.peff.net","subject":"Re: [PATCH/RFC] branch: add optional parameter to -r to specify remote","fromName":"Michael J Gruber","fromEmail":"git@drmicha.warpmail.net","sentAt":"2011-06-20T11:08:13Z","receivedAt":"2011-06-20T11:08:13Z","isPatch":true,"sender":{"key":"git@grubix.eu","avatar":"https://avatars.githubusercontent.com/u/233215?v=4"},"body":"Jeff King venit, vidit, dixit 20.06.2011 09:03:\n> On Mon, Jun 20, 2011 at 08:40:32AM +0200, Johannes Sixt wrote:\n> \n>>> \t$ git branch --match \"jk/*\"\n>>>\n>>> to show only local topic branches whose names match the given blob.\n>>\n>> I would hate having to learn a new syntax '--match \"jk/*\"' when we can\n>> already say\n>>\n>>     $ git log --remotes\n>>     $ git log --remotes=alice --remotes=bob\n>>     $ git log --remotes=\"jk/*\"\n>>\n>> IMO, it is the right approach to have a long option --remotes with an\n>> optional argument.\n> \n> For that matter, --match should be spelled \"--glob\", as we already have:\n> \n>   $ git log --glob='jk/*'\n> \n> I think having the ref-selection for \"git branch\" match that of the\n> revision walker makes sense.\n> \n> -Peff\n\nWell, \"branch\" is about refs, and \"log\" about revs. I'd rather have\n\"branch\" similar to \"tag\" in that respect (i.e. '-l'). I'm still meaning\nto revive that series:\n\nhttp://permalink.gmane.org/gmane.comp.version-control.git/172228\n\nI've reworked a few more things compared to the RFC from back then but\nwas caught by lack of time and the rc phase. I'll send what I have asap.\n\nMichael\n"},{"id":"170295","messageId":"20110620130945.GA19011@sigill.intra.peff.net","threadId":"27658","inReplyTo":"4DFF2A1D.3060206@drmicha.warpmail.net","subject":"Re: [PATCH/RFC] branch: add optional parameter to -r to specify remote","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2011-06-20T13:09:45Z","receivedAt":"2011-06-20T13:09:45Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Mon, Jun 20, 2011 at 01:08:13PM +0200, Michael J Gruber wrote:\n\n> > For that matter, --match should be spelled \"--glob\", as we already have:\n> > \n> >   $ git log --glob='jk/*'\n> > \n> > I think having the ref-selection for \"git branch\" match that of the\n> > revision walker makes sense.\n> \n> Well, \"branch\" is about refs, and \"log\" about revs.\n\nSure, and I wouldn't expect \"git branch --list 1234abcd\" to do anything\nuseful. But naming refs is a subset of naming revs. Certainly it seems\nworth it to make the shorthands like \"--remotes\" behave the same way\nwhere applicable.\n\nI do agree that \"git branch -l 'jk/*'\" is less typing than \"--glob\"; it\nmay be worth supporting both forms to provide the least surprise to the\nuser (i.e., even though it may not be the shortest, users may expect the\nsame syntax to work in both places, and it costs us very little to\naccept either).\n\n> I'd rather have\n> \"branch\" similar to \"tag\" in that respect (i.e. '-l'). I'm still meaning\n> to revive that series:\n> \n> http://permalink.gmane.org/gmane.comp.version-control.git/172228\n\nModulo Junio's comments on the \"-l\" transition, I like the idea. One\nthing jumped out at me:\n\n> -       else if (argc == 0)\n> -               return print_ref_list(kinds, detached, verbose, abbrev, with_commit);\n> +       else if (argc == 0 || (verbose && argc == 1))\n> +               return print_ref_list(kinds, detached, verbose, abbrev, with_commit, argc ?  argv[0] : NULL);\n\nIs there any reason not to accept:\n\n  git branch --list jk/* mg/*\n\n? For \"tag -l\", we seem to silently ignore any arguments past the first:\n\n  $ git tag -l 'v1.7.4.*' 'v1.7.5.*'\n  v1.7.4.1\n  v1.7.4.2\n  v1.7.4.3\n  v1.7.4.4\n  v1.7.4.5\n\nWe should at least warn and say \"your second argument is being ignored\"\nor show the usage message.  But perhaps it is even friendlier to accept\na list of patterns.\n\n-Peff\n"},{"id":"170301","messageId":"7v62o0eckx.fsf@alter.siamese.dyndns.org","threadId":"27658","inReplyTo":"20110620070316.GA15246@sigill.intra.peff.net","subject":"Re: [PATCH/RFC] branch: add optional parameter to -r to specify remote","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2011-06-20T15:39:58Z","receivedAt":"2011-06-20T15:39:58Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jeff King <peff@peff.net> writes:\n\n> On Mon, Jun 20, 2011 at 08:40:32AM +0200, Johannes Sixt wrote:\n>\n>> > \t$ git branch --match \"jk/*\"\n>> > \n>> > to show only local topic branches whose names match the given blob.\n>> \n>> I would hate having to learn a new syntax '--match \"jk/*\"' when we can\n>> already say\n>> \n>>     $ git log --remotes\n>>     $ git log --remotes=alice --remotes=bob\n>>     $ git log --remotes=\"jk/*\"\n>> \n>> IMO, it is the right approach to have a long option --remotes with an\n>> optional argument.\n\nYeah, it was just me being sloppy. I didn't mean to suggest a brand new\noption name \"--match\"; I was merely saying that it should be something\nthat specifies filtering.  Except for the last one, if you are naming\nremotes, that also would make sense.\n\nBut not the last one at least in the context of the example I gave in my\nmessage. I wanted to see local topic branches whose names match jk/* so\nusing --remotes is actively wrong.\n\n> For that matter, --match should be spelled \"--glob\", as we already have:\n>\n>   $ git log --glob='jk/*'\n>\n> I think having the ref-selection for \"git branch\" match that of the\n> revision walker makes sense.\n\nYes, again I was just being sloppy and did not mean to introduce a brand\nnew --match; --glob indeed is a lot more appropriate in the examples I\ngave in the message.\n\nHere are two other examples of \"listing\" mode of the branch command:\n\n\t$ git branch --no-merged --glob=\"jc/*\" pu\n\t$ git branch --with jc/some-topic --glob=\"maint-*\" --glob=maint\n\nI sometimes wish if they had such filtering.\n"},{"id":"170302","messageId":"7v1uyoecgn.fsf@alter.siamese.dyndns.org","threadId":"27658","inReplyTo":"20110620130945.GA19011@sigill.intra.peff.net","subject":"Re: [PATCH/RFC] branch: add optional parameter to -r to specify remote","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2011-06-20T15:42:32Z","receivedAt":"2011-06-20T15:42:32Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jeff King <peff@peff.net> writes:\n\n> ? For \"tag -l\", we seem to silently ignore any arguments past the first:\n>\n>   $ git tag -l 'v1.7.4.*' 'v1.7.5.*'\n>   v1.7.4.1\n>   v1.7.4.2\n>   v1.7.4.3\n>   v1.7.4.4\n>   v1.7.4.5\n>\n> We should at least warn and say \"your second argument is being ignored\"\n> or show the usage message.\n\nI think it is just a bug; no need for \"being ignored\" warning.\n\n> But perhaps it is even friendlier to accept\n> a list of patterns.\n\nYes indeed; please make it so ;-)\n"},{"id":"170303","messageId":"7vwrggcxl6.fsf@alter.siamese.dyndns.org","threadId":"27658","inReplyTo":"4DFF2A1D.3060206@drmicha.warpmail.net","subject":"Re: [PATCH/RFC] branch: add optional parameter to -r to specify remote","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2011-06-20T15:49:09Z","receivedAt":"2011-06-20T15:49:09Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Michael J Gruber <git@drmicha.warpmail.net> writes:\n\n>> For that matter, --match should be spelled \"--glob\", as we already have:\n>> \n>>   $ git log --glob='jk/*'\n>> \n>> I think having the ref-selection for \"git branch\" match that of the\n>> revision walker makes sense.\n>> \n>> -Peff\n>\n> Well, \"branch\" is about refs, and \"log\" about revs.\n\nNot really. What \"log\" output by traversing is about revisions, but we are\ndiscussing how the command line argument discover the set of refs to feed\ninto the underlying machinery that does different things in each of the\ncommand (branch just lists them without any traversal, log shows history\nleading to the commits). So I do not see any difference and I think it\nwould be appropriate if we can use the same notation to specify both \"I\nwant to see all branches that match this pattern\" and \"I want to see\nhistory leading to all refs that match this pattern\".\n\n> I'd rather have\n> \"branch\" similar to \"tag\" in that respect (i.e. '-l').\n\nAnd \"tag --glob='*'\" also falls into the same class from that point of\nview: \"I want to see all tags that match this pattern\".\n\nThanks.\n"},{"id":"170308","messageId":"20110620165928.GA20887@sigill.intra.peff.net","threadId":"27658","inReplyTo":"7v1uyoecgn.fsf@alter.siamese.dyndns.org","subject":"[PATCH] tag: accept multiple patterns for --list","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2011-06-20T16:59:28Z","receivedAt":"2011-06-20T16:59:28Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Mon, Jun 20, 2011 at 08:42:32AM -0700, Junio C Hamano wrote:\n\n> Jeff King <peff@peff.net> writes:\n> \n> > ? For \"tag -l\", we seem to silently ignore any arguments past the first:\n> >\n> >   $ git tag -l 'v1.7.4.*' 'v1.7.5.*'\n> >   v1.7.4.1\n> >   v1.7.4.2\n> >   v1.7.4.3\n> >   v1.7.4.4\n> >   v1.7.4.5\n> >\n> > We should at least warn and say \"your second argument is being ignored\"\n> > or show the usage message.\n> \n> I think it is just a bug; no need for \"being ignored\" warning.\n> \n> > But perhaps it is even friendlier to accept\n> > a list of patterns.\n> \n> Yes indeed; please make it so ;-)\n\nHere's a patch.\n\n-- >8 --\nSubject: [PATCH] tag: accept multiple patterns for --list\n\nUntil now, \"git tag -l foo* bar*\" would silently ignore the\nsecond argument, showing only refs starting with \"foo\". It's\nnot just unfriendly not to take a second pattern; we\nactually generated subtly wrong results (from the user's\nperspective) because some of the requested tags were\nomitted.\n\nThis patch allows an arbitrary number of patterns on the\ncommand line; if any of them matches, the ref is shown.\n\nWhile we're tweaking the documentation, let's also make it\nclear that the pattern is fnmatch.\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\n Documentation/git-tag.txt |    9 ++++++---\n builtin/tag.c             |   26 +++++++++++++++++---------\n t/t7004-tag.sh            |    5 +++++\n 3 files changed, 28 insertions(+), 12 deletions(-)\n\ndiff --git a/Documentation/git-tag.txt b/Documentation/git-tag.txt\nindex d82f621..fb1c0ac 100644\n--- a/Documentation/git-tag.txt\n+++ b/Documentation/git-tag.txt\n@@ -12,7 +12,7 @@ SYNOPSIS\n 'git tag' [-a | -s | -u <key-id>] [-f] [-m <msg> | -F <file>]\n \t<tagname> [<commit> | <object>]\n 'git tag' -d <tagname>...\n-'git tag' [-n[<num>]] -l [--contains <commit>] [<pattern>]\n+'git tag' [-n[<num>]] -l [--contains <commit>] [<pattern>...]\n 'git tag' -v <tagname>...\n \n DESCRIPTION\n@@ -69,8 +69,11 @@ OPTIONS\n \tIf the tag is not annotated, the commit message is displayed instead.\n \n -l <pattern>::\n-\tList tags with names that match the given pattern (or all if no pattern is given).\n-\tTyping \"git tag\" without arguments, also lists all tags.\n+\tList tags with names that match the given pattern (or all if no\n+\tpattern is given).  Running \"git tag\" without arguments also\n+\tlists all tags. The pattern is a shell wildcard (i.e., matched\n+\tusing fnmatch(3)).  Multiple patterns may be given; if any of\n+\tthem matches, the tag is shown.\n \n --contains <commit>::\n \tOnly list tags which contain the specified commit.\ndiff --git a/builtin/tag.c b/builtin/tag.c\nindex ec926fc..cef2726 100644\n--- a/builtin/tag.c\n+++ b/builtin/tag.c\n@@ -16,7 +16,7 @@\n static const char * const git_tag_usage[] = {\n \t\"git tag [-a|-s|-u <key-id>] [-f] [-m <msg>|-F <file>] <tagname> [<head>]\",\n \t\"git tag -d <tagname>...\",\n-\t\"git tag -l [-n[<num>]] [<pattern>]\",\n+\t\"git tag -l [-n[<num>]] [<pattern>...]\",\n \t\"git tag -v <tagname>...\",\n \tNULL\n };\n@@ -24,17 +24,28 @@ static const char * const git_tag_usage[] = {\n static char signingkey[1000];\n \n struct tag_filter {\n-\tconst char *pattern;\n+\tconst char **patterns;\n \tint lines;\n \tstruct commit_list *with_commit;\n };\n \n+static int match_pattern(const char **patterns, const char *ref)\n+{\n+\t/* no pattern means match everything */\n+\tif (!*patterns)\n+\t\treturn 1;\n+\tfor (; *patterns; patterns++)\n+\t\tif (!fnmatch(*patterns, ref, 0))\n+\t\t\treturn 1;\n+\treturn 0;\n+}\n+\n static int show_reference(const char *refname, const unsigned char *sha1,\n \t\t\t  int flag, void *cb_data)\n {\n \tstruct tag_filter *filter = cb_data;\n \n-\tif (!fnmatch(filter->pattern, refname, 0)) {\n+\tif (match_pattern(filter->patterns, refname)) {\n \t\tint i;\n \t\tunsigned long size;\n \t\tenum object_type type;\n@@ -88,15 +99,12 @@ static int show_reference(const char *refname, const unsigned char *sha1,\n \treturn 0;\n }\n \n-static int list_tags(const char *pattern, int lines,\n+static int list_tags(const char **patterns, int lines,\n \t\t\tstruct commit_list *with_commit)\n {\n \tstruct tag_filter filter;\n \n-\tif (pattern == NULL)\n-\t\tpattern = \"*\";\n-\n-\tfilter.pattern = pattern;\n+\tfilter.patterns = patterns;\n \tfilter.lines = lines;\n \tfilter.with_commit = with_commit;\n \n@@ -425,7 +433,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix)\n \tif (list + delete + verify > 1)\n \t\tusage_with_options(git_tag_usage, options);\n \tif (list)\n-\t\treturn list_tags(argv[0], lines == -1 ? 0 : lines,\n+\t\treturn list_tags(argv, lines == -1 ? 0 : lines,\n \t\t\t\t with_commit);\n \tif (lines != -1)\n \t\tdie(_(\"-n option is only allowed with -l.\"));\ndiff --git a/t/t7004-tag.sh b/t/t7004-tag.sh\nindex 2ac1c66..097ce2b 100755\n--- a/t/t7004-tag.sh\n+++ b/t/t7004-tag.sh\n@@ -257,6 +257,11 @@ test_expect_success \\\n \ttest_cmp expect actual\n '\n \n+test_expect_success 'tag -l can accept multiple patterns' '\n+\tgit tag -l \"v1*\" \"v0*\" >actual &&\n+\ttest_cmp expect actual\n+'\n+\n # creating and verifying lightweight tags:\n \n test_expect_success \\\n-- \n1.7.6.rc1.38.g97f64.dirty\n"},{"id":"170315","messageId":"BANLkTikWvkLdiF1hvbwL9ep3vyEtmN8uqw@mail.gmail.com","threadId":"27658","inReplyTo":"7vtyble9k8.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH/RFC] branch: add optional parameter to -r to specify remote","fromName":"Boris Faure","fromEmail":"billiob@gmail.com","sentAt":"2011-06-20T19:12:41Z","receivedAt":"2011-06-20T19:12:41Z","isPatch":true,"sender":{"key":"billiob@gmail.com","avatar":"https://avatars.githubusercontent.com/u/27988?v=4"},"body":"On Mon, Jun 20, 2011 at 00:32, Junio C Hamano <gitster@pobox.com> wrote:\n> Boris Faure <billiob@gmail.com> writes:\n>\n>> add '--remote' as long version for '-r'\n>> update documentation\n>> add tests\n>\n> (style) Sentences begin with a capital letter and ends with a period.\n>\n> This commit does a lot more than the above, no? It adds an optional remote\n> name parameter to the existing \"-r\" option and limits the output to the\n> remote tracking branches of the remote when it is specified.\n>\n>> ---\n>\n> Sign-off?\n\nI missed it.\n\n>> diff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt\n>> index c50f189..242da9c 100644\n>> --- a/Documentation/git-branch.txt\n>> +++ b/Documentation/git-branch.txt\n>> ...\n>> @@ -99,8 +99,10 @@ OPTIONS\n>>       default to color output.\n>>       Same as `--color=never`.\n>>\n>> --r::\n>> -     List or delete (if used with -d) the remote-tracking branches.\n>> +-r[=<remote>]::\n>> +--remote[=<remote>]::\n>> +     List or delete (if used with -d) the remote-tracking branches from\n>> +     <remote> if specified.\n>\n> It is now unspecified what the command would do when the optional <remote>\n> is left unspecified.\n\nMy english is not excellent and for sure a better wording can be found.\n\n\n>>  #define REF_LOCAL_BRANCH    0x01\n>>  #define REF_REMOTE_BRANCH   0x02\n>> +static int kinds = REF_LOCAL_BRANCH;\n>\n> This used to be nicely scoped out of global space and got passed around as\n> parameter, but now it has become a global? I do not see a good reason for\n> this change.\n>\n>> +static const char *remote = NULL;\n\nI put those variables in global space in order to access them within the\nparse_opt callback.\n\n\n> Two issues.\n>\n>  1. Presumably you wanted to have this change because you have too many\n>    remotes, way more than two, and wanted to filter the output from\n>    remotes that you are not interested in. Is it entirely implausible\n>    that you might be interested in not just one, but two remotes out of\n>    many remotes you have? A single string variable would not suffice for\n>    that but you should be able to make this an array of strings.\n\nI wanted to replace a git branch -r | grep 'someRemoteName' to filter\nin fact one remote in particular.\n\n>> +static int parse_opt_remote_cb(const struct option *opt, const char *arg,\n>> +                            int unset)\n>> +{\n>> +     kinds = REF_REMOTE_BRANCH;\n>> +     if (unset)\n>> +             kinds = REF_LOCAL_BRANCH;\n>\n> What is this \"unset\" check about? Wouldn't that be an error if the command\n> line said \"--no-remote\"?\n>\n> And you do not return but proceed to look at \"arg\", presumably to handle a\n> case where the command line said \"--no-remote=foobar\"?\n\nIt's just a missing return.\n\n>> +     if (arg) {\n>> +             if ( *arg == '=')\n>\n> (style) Unwanted SP after an open parenthesis.\n>\n>> +                     remote = arg + 1; /* skip '=' */\n>\n> (style) It is clear enough what this does without the extra comment.\n>\n> Does this forbid remote names that begin with a \"=\"?  I.e.\n>\n>        $ git branch -r =temporary\n\narg is '=temporary' if called with git branch -r=temporary but 'temporary'\nif called with git branch --remote=temporary. I didn't know to check whether\nthe option triggered was from the long or the short version and skip '='\naccordingly.\n\n> As to the design of the new feature, I see you tried to make it possible\n> to perform what\n>\n>        $ git branch -d -r origin/master\n>\n> does with\n>\n>        $ git branch -d --remote=origin master\n>\n> I do not think it is particularly a good idea. Adding yet another way to\n> do the same thing, unless that new way is vastly superiour (e.g. easier to\n> use, easier to explain, more efficient to perform, etc.), does not add\n> much value to the system.\n>\n> It would make much more sense to restrict this feature to the \"listing\"\n> side of the branches.  It would be nice if you can do:\n>\n>        $ git branch -r --match alice --match bob\n>\n> to show only remote tracking branches under refs/remotes/{alice,bob}\n> and also\n>\n>        $ git branch --match \"jk/*\"\n>\n> to show only local topic branches whose names match the given blob.\n\nI agree that it doesn't make much sense with -d option. I added the feature\nwith '-r=<remote>' so that it works with '-d'.\nI would have preferred to just list branches from a given remote 'aa' with\n'git branch -r aa' but I'll see where the discussion ends up.\n\n-- \nBoris Faure\n"}]}