{"thread":{"id":"22266","subject":"[PATCH v2] rev-parse --namespace","startedAt":"2010-01-18T07:15:52Z","lastAt":"2010-01-20T07:29:03Z","messageCount":14,"participants":["Ilari Liusvaara","Junio C Hamano","Jeff King","Thomas Rast","Johannes Sixt"],"isPatch":true,"patchVersion":2,"patchTotal":null},"messages":[{"id":"132020","messageId":"1263798952-27624-1-git-send-email-ilari.liusvaara@elisanet.fi","threadId":"22266","inReplyTo":null,"subject":"[PATCH v2] rev-parse --namespace","fromName":"Ilari Liusvaara","fromEmail":"ilari.liusvaara@elisanet.fi","sentAt":"2010-01-18T07:15:52Z","receivedAt":"2010-01-18T07:15:52Z","isPatch":true,"sender":{"key":"ilari.liusvaara@elisanet.fi","avatar":null},"body":"Add --namespace=<namespace> option to rev-parse and everything that\naccepts its options. This option matches all refs in some subnamespace\nof refs hierarchy.\n\nExample:\n\n'git log --branches --not --namespace=remotes/origin'\n\nTo show what you have that origin doesn't.\n\nSigned-off-by: Ilari Liusvaara <ilari.liusvaara@elisanet.fi>\n---\nChanges from v1:\n- Get rid of global variable for namespace.\n- Use strbuf API to build the namespace\n- Test rev-list/rev-parse outputs up to permutation, not just line\n  count.\n- Add example to commit message and to git log manual page.\n\nI left renaming the option (more opinions on that?) and changing the\ndescription in manpage (the other similar entries should be fixed too\nthen) for later iteration (if these are to be done).\n\n Documentation/git-rev-list.txt     |    1 +\n Documentation/git-rev-parse.txt    |    4 +\n Documentation/rev-list-options.txt |    6 ++\n builtin-rev-parse.c                |    8 +++\n refs.c                             |   18 ++++++\n refs.h                             |   13 ++++\n revision.c                         |   20 ++++++-\n t/t6018-rev-list-namespace.sh      |  112 ++++++++++++++++++++++++++++++++++++\n 8 files changed, 180 insertions(+), 2 deletions(-)\n create mode 100755 t/t6018-rev-list-namespace.sh\n\ndiff --git a/Documentation/git-rev-list.txt b/Documentation/git-rev-list.txt\nindex 3341d1b..a8f8f22 100644\n--- a/Documentation/git-rev-list.txt\n+++ b/Documentation/git-rev-list.txt\n@@ -24,6 +24,7 @@ SYNOPSIS\n \t     [ \\--branches ]\n \t     [ \\--tags ]\n \t     [ \\--remotes ]\n+\t     [ \\--namespace=namespace-prefix ]\n \t     [ \\--stdin ]\n \t     [ \\--quiet ]\n \t     [ \\--topo-order ]\ndiff --git a/Documentation/git-rev-parse.txt b/Documentation/git-rev-parse.txt\nindex 82045a2..af4605a 100644\n--- a/Documentation/git-rev-parse.txt\n+++ b/Documentation/git-rev-parse.txt\n@@ -112,6 +112,10 @@ OPTIONS\n --remotes::\n \tShow tag refs found in `$GIT_DIR/refs/remotes`.\n \n+--namespace=namespace-prefix::\n+\tShow refs found in `$GIT_DIR/namespace-prefix`. If namespace\n+\tspecified lacks leading 'refs/', it is automatically prepended.\n+\n --show-prefix::\n \tWhen the command is invoked from a subdirectory, show the\n \tpath of the current directory relative to the top-level\ndiff --git a/Documentation/rev-list-options.txt b/Documentation/rev-list-options.txt\nindex 1f57aed..c824a7b 100644\n--- a/Documentation/rev-list-options.txt\n+++ b/Documentation/rev-list-options.txt\n@@ -243,6 +243,12 @@ endif::git-rev-list[]\n \tPretend as if all the refs in `$GIT_DIR/refs/remotes` are listed\n \ton the command line as '<commit>'.\n \n+--namespace=namespace-prefix::\n+\tPretend as if all the refs in `$GIT_DIR/namespace-prefix` are\n+\tlisted on the command line as '<commit>'. Leading 'refs/', it\n+\tis automatically prepended if missing.\n+\n+\n ifndef::git-rev-list[]\n --bisect::\n \ndiff --git a/builtin-rev-parse.c b/builtin-rev-parse.c\nindex 37d0233..255191d 100644\n--- a/builtin-rev-parse.c\n+++ b/builtin-rev-parse.c\n@@ -52,6 +52,7 @@ static int is_rev_argument(const char *arg)\n \t\t\"--parents\",\n \t\t\"--pretty\",\n \t\t\"--remotes\",\n+\t\t\"--namespace=\",\n \t\t\"--sparse\",\n \t\t\"--tags\",\n \t\t\"--topo-order\",\n@@ -577,6 +578,13 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)\n \t\t\t\tfor_each_tag_ref(show_reference, NULL);\n \t\t\t\tcontinue;\n \t\t\t}\n+\t\t\tif (!prefixcmp(arg, \"--namespace=\")) {\n+\t\t\t\tstruct for_each_namespace_request req;\n+\t\t\t\treq.req_namespace = arg + 12;\n+\t\t\t\treq.req_opaque = NULL;\n+\t\t\t\tfor_each_namespace_ref(show_reference, &req);\n+\t\t\t\tcontinue;\n+\t\t\t}\n \t\t\tif (!strcmp(arg, \"--remotes\")) {\n \t\t\t\tfor_each_remote_ref(show_reference, NULL);\n \t\t\t\tcontinue;\ndiff --git a/refs.c b/refs.c\nindex 3e73a0a..c7162d1 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -7,6 +7,7 @@\n /* ISSYMREF=01 and ISPACKED=02 are public interfaces */\n #define REF_KNOWS_PEELED 04\n \n+/* Current prefix namespace in use. NULL means none. */\n struct ref_list {\n \tstruct ref_list *next;\n \tunsigned char flag; /* ISSYMREF? ISPACKED? */\n@@ -674,6 +675,23 @@ int for_each_replace_ref(each_ref_fn fn, void *cb_data)\n \treturn do_for_each_ref(\"refs/replace/\", fn, 13, 0, cb_data);\n }\n \n+int for_each_namespace_ref(each_ref_fn fn, void *cb_data)\n+{\n+\tstruct for_each_namespace_request *req = cb_data;\n+\tstruct strbuf real_prefix = STRBUF_INIT;\n+\tint ret;\n+\n+\tif (prefixcmp(req->req_namespace, \"refs/\"))\n+\t\tstrbuf_addstr(&real_prefix, \"refs/\");\n+\tstrbuf_addstr(&real_prefix, req->req_namespace);\n+\tif (real_prefix.buf[real_prefix.len - 1] != '/')\n+\t\tstrbuf_addch(&real_prefix, '/');\n+\n+\tret = for_each_ref_in(real_prefix.buf, fn, req->req_opaque);\n+\tstrbuf_release(&real_prefix);\n+\treturn ret;\n+}\n+\n int for_each_rawref(each_ref_fn fn, void *cb_data)\n {\n \treturn do_for_each_ref(\"refs/\", fn, 0,\ndiff --git a/refs.h b/refs.h\nindex e141991..4bb63b0 100644\n--- a/refs.h\n+++ b/refs.h\n@@ -13,6 +13,18 @@ struct ref_lock {\n #define REF_ISSYMREF 01\n #define REF_ISPACKED 02\n \n+/* Opaque request for for_each_namespace_ref */\n+struct for_each_namespace_request\n+{\n+\t/*\n+\t * The limiting namespace. 'refs/' and '/' are autoprepended /\n+\t * autoappended if missing.\n+\t */\n+\tconst char *req_namespace;\n+\t/* The real opaque data for callback function. */\n+\tvoid *req_opaque;\n+};\n+\n /*\n  * Calls the specified function for each ref file until it returns nonzero,\n  * and returns the value\n@@ -25,6 +37,7 @@ extern int for_each_tag_ref(each_ref_fn, void *);\n extern int for_each_branch_ref(each_ref_fn, void *);\n extern int for_each_remote_ref(each_ref_fn, void *);\n extern int for_each_replace_ref(each_ref_fn, void *);\n+extern int for_each_namespace_ref(each_ref_fn, void *);\n \n /* can be used to learn about broken ref and symref */\n extern int for_each_rawref(each_ref_fn, void *);\ndiff --git a/revision.c b/revision.c\nindex 25fa14d..ff9484f 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -699,12 +699,18 @@ static int handle_one_ref(const char *path, const unsigned char *sha1, int flag,\n \treturn 0;\n }\n \n+static void init_all_refs_cb(struct all_refs_cb *cb, struct rev_info *revs,\n+\tunsigned flags)\n+{\n+\tcb->all_revs = revs;\n+\tcb->all_flags = flags;\n+}\n+\n static void handle_refs(struct rev_info *revs, unsigned flags,\n \t\tint (*for_each)(each_ref_fn, void *))\n {\n \tstruct all_refs_cb cb;\n-\tcb.all_revs = revs;\n-\tcb.all_flags = flags;\n+\tinit_all_refs_cb(&cb, revs, flags);\n \tfor_each(handle_one_ref, &cb);\n }\n \n@@ -1352,6 +1358,16 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch\n \t\t\t\thandle_refs(revs, flags, for_each_remote_ref);\n \t\t\t\tcontinue;\n \t\t\t}\n+\t\t\tif (!prefixcmp(arg, \"--namespace=\")) {\n+\t\t\t\tstruct for_each_namespace_request req;\n+\t\t\t\tstruct all_refs_cb cb;\n+\n+\t\t\t\tinit_all_refs_cb(&cb, revs, flags);\n+\t\t\t\treq.req_namespace = arg + 12;\n+\t\t\t\treq.req_opaque = &cb;\n+\t\t\t\tfor_each_namespace_ref(handle_one_ref, &req);\n+\t\t\t\tcontinue;\n+\t\t\t}\n \t\t\tif (!strcmp(arg, \"--reflog\")) {\n \t\t\t\thandle_reflog(revs, flags);\n \t\t\t\tcontinue;\ndiff --git a/t/t6018-rev-list-namespace.sh b/t/t6018-rev-list-namespace.sh\nnew file mode 100755\nindex 0000000..6bb562a\n--- /dev/null\n+++ b/t/t6018-rev-list-namespace.sh\n@@ -0,0 +1,112 @@\n+#!/bin/sh\n+\n+test_description='rev-list/rev-parse --namespace'\n+\n+. ./test-lib.sh\n+\n+\n+commit () {\n+\ttest_tick &&\n+\techo $1 > foo &&\n+\tgit add foo &&\n+\tgit commit -m \"$1\"\n+}\n+\n+compare () {\n+\t# Split arguments on whitespace.\n+\tgit $1 $2 | sort >expected &&\n+\tgit $1 $3 | sort >actual &&\n+\tcmp expected actual\n+}\n+\n+test_expect_success 'setup' '\n+\n+\tcommit master &&\n+\tgit checkout -b subspace/one master\n+\tcommit one &&\n+\tgit checkout -b subspace/two master\n+\tcommit two &&\n+\tgit checkout -b subspace-x master\n+\tcommit subspace-x &&\n+\tgit checkout -b other/three master\n+\tcommit three &&\n+\tgit checkout -b someref master\n+\tcommit some &&\n+\tgit checkout master &&\n+\tcommit master2\n+'\n+\n+test_expect_success 'rev-parse --namespace=refs/heads/subspace/' '\n+\n+\tcompare rev-parse \"subspace/one subspace/two\" \"--namespace=refs/heads/subspace/\"\n+\n+'\n+\n+test_expect_success 'rev-parse --namespace=refs/heads/subspace' '\n+\n+\tcompare rev-parse \"subspace/one subspace/two\" \"--namespace=refs/heads/subspace\"\n+\n+'\n+\n+test_expect_success 'rev-parse --namespace=heads/subspace' '\n+\n+\tcompare rev-parse \"subspace/one subspace/two\" \"--namespace=heads/subspace\"\n+\n+'\n+\n+test_expect_success 'rev-parse --namespace=heads/subspace --namespace=heads/other' '\n+\n+\tcompare rev-parse \"subspace/one subspace/two other/three\" \"--namespace=heads/subspace --namespace=heads/other\"\n+\n+'\n+\n+test_expect_success 'rev-parse --namespace=heads/someref master' '\n+\n+\tcompare rev-parse \"master\" \"--namespace=heads/someref master\"\n+\n+'\n+\n+test_expect_success 'rev-parse --namespace=heads' '\n+\n+\tcompare rev-parse \"subspace/one subspace/two other/three subspace-x master someref\" \"--namespace=heads\"\n+\n+'\n+\n+test_expect_success 'rev-list --namespace=refs/heads/subspace/' '\n+\n+\tcompare rev-list \"subspace/one subspace/two\" \"--namespace=refs/heads/subspace/\"\n+\n+'\n+\n+test_expect_success 'rev-list --namespace=refs/heads/subspace' '\n+\n+\tcompare rev-list \"subspace/one subspace/two\" \"--namespace=refs/heads/subspace\"\n+\n+'\n+\n+test_expect_success 'rev-list --namespace=heads/subspace' '\n+\n+\tcompare rev-list \"subspace/one subspace/two\" \"--namespace=heads/subspace\"\n+\n+'\n+\n+test_expect_success 'rev-list --namespace=heads/someref master' '\n+\n+\tcompare rev-parse \"master\" \"--namespace=heads/someref master\"\n+\n+'\n+\n+test_expect_success 'rev-list --namespace=heads/subspace --namespace=heads/other' '\n+\n+\tcompare rev-parse \"subspace/one subspace/two other/three\" \"--namespace=heads/subspace --namespace=heads/other\"\n+\n+'\n+\n+test_expect_success 'rev-list --namespace=heads' '\n+\n+\tcompare rev-parse \"subspace/one subspace/two other/three subspace-x master someref\" \"--namespace=heads\"\n+\n+'\n+\n+\n+test_done\n-- \n1.6.6.199.gff4b0\n"},{"id":"132021","messageId":"7vk4vfsv64.fsf@alter.siamese.dyndns.org","threadId":"22266","inReplyTo":"1263798952-27624-1-git-send-email-ilari.liusvaara@elisanet.fi","subject":"Re: [PATCH v2] rev-parse --namespace","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2010-01-18T07:56:35Z","receivedAt":"2010-01-18T07:56:35Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ilari Liusvaara <ilari.liusvaara@elisanet.fi> writes:\n\n> Add --namespace=<namespace> option to rev-parse and everything that\n> accepts its options. This option matches all refs in some subnamespace\n> of refs hierarchy.\n>\n> Example:\n>\n> 'git log --branches --not --namespace=remotes/origin'\n>\n> To show what you have that origin doesn't.\n>\n> Signed-off-by: Ilari Liusvaara <ilari.liusvaara@elisanet.fi>\n\nThanks.\n\n> @@ -577,6 +578,13 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)\n>  \t\t\t\tfor_each_tag_ref(show_reference, NULL);\n>  \t\t\t\tcontinue;\n>  \t\t\t}\n> +\t\t\tif (!prefixcmp(arg, \"--namespace=\")) {\n> +\t\t\t\tstruct for_each_namespace_request req;\n> +\t\t\t\treq.req_namespace = arg + 12;\n> +\t\t\t\treq.req_opaque = NULL;\n\nIf the structure variable is often named after \"request\", there is not\nmuch point naming its fields (which are most likely all related to\nrequest) with \"req_\" prefix.  IOW, wouldn't this be much easier to read?\n\n\tstruct for_each_namespace_request req;\n\tmemset(&req, 0, sizeof(req));\n        req.namespace = arg + 12;\n\nBut please don't worry about this part too much, as I'll suggest getting\nrid of the struct altogether shortly (read on).\n\n> diff --git a/refs.c b/refs.c\n> index 3e73a0a..c7162d1 100644\n> --- a/refs.c\n> +++ b/refs.c\n> @@ -7,6 +7,7 @@\n>  /* ISSYMREF=01 and ISPACKED=02 are public interfaces */\n>  #define REF_KNOWS_PEELED 04\n>  \n> +/* Current prefix namespace in use. NULL means none. */\n>  struct ref_list {\n>  \tstruct ref_list *next;\n>  \tunsigned char flag; /* ISSYMREF? ISPACKED? */\n\nIs the above new comment really about what this structure type is?\n\n> diff --git a/refs.h b/refs.h\n> index e141991..4bb63b0 100644\n> --- a/refs.h\n> +++ b/refs.h\n> @@ -25,6 +37,7 @@ extern int for_each_tag_ref(each_ref_fn, void *);\n>  extern int for_each_branch_ref(each_ref_fn, void *);\n>  extern int for_each_remote_ref(each_ref_fn, void *);\n>  extern int for_each_replace_ref(each_ref_fn, void *);\n> +extern int for_each_namespace_ref(each_ref_fn, void *);\n\nI know somebody in the review discussion thought that the second parameter\nfor this should be void * for whatever reason, but I don't see the point.\n\nWhy cannot this be\n\n\tfor_each_namespace_ref(each_ref_fn, const char *, void *)\n\nwhere the second one specifies the \"namespace prefix\"?\n\nThe caller of for_each_namespace_ref() with v2 interface needs to be aware\nof that for_each_namespace_request structure anyway, so there is nothing\n\"void *\" about it.  You can have a function pointer that can point at\nfor_each_{branch,remote,replace}_ref and indirectly call one of the\nfunctions via that pointer to grab different set of refs, but this new\nfunction for_each_namespace_ref cannot play together with them, as its\ncb_data must be of different shape for the request to make sense; having\nthe same function signature as others wouldn't help.\n\nIf the callback \"each_ref_fn\" function learns what ns-prefix was given for\nit to be called (iow, it gets the whole for_each_namespace_request,\ninstead of just its req_opaque member), then I might be talked into\nbelieving that it _could_ be useful in some situations, but the way the\ncallback is called is just the usual \"this ref points at this object name,\nby the way here is the message my caller told me to give it to you\".  And\nif the caller really wanted to tell the namespace prefix to the callback\nfunction, it can be made part of the application specific cbdata.\n\nSo in short, I simply don't see the point of using this new \"request\"\nstructure.  Here is a suggested update that can be squashed on top of v2.\n\nAm I missing some subtle issues?\n\n builtin-rev-parse.c |    5 +----\n refs.c              |   10 ++++------\n refs.h              |   14 +-------------\n revision.c          |    5 +----\n 4 files changed, 7 insertions(+), 27 deletions(-)\n\ndiff --git a/builtin-rev-parse.c b/builtin-rev-parse.c\nindex 255191d..34af347 100644\n--- a/builtin-rev-parse.c\n+++ b/builtin-rev-parse.c\n@@ -579,10 +579,7 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)\n \t\t\t\tcontinue;\n \t\t\t}\n \t\t\tif (!prefixcmp(arg, \"--namespace=\")) {\n-\t\t\t\tstruct for_each_namespace_request req;\n-\t\t\t\treq.req_namespace = arg + 12;\n-\t\t\t\treq.req_opaque = NULL;\n-\t\t\t\tfor_each_namespace_ref(show_reference, &req);\n+\t\t\t\tfor_each_namespace_ref(show_reference, arg + 12, NULL);\n \t\t\t\tcontinue;\n \t\t\t}\n \t\t\tif (!strcmp(arg, \"--remotes\")) {\ndiff --git a/refs.c b/refs.c\nindex c7162d1..2bf8755 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -7,7 +7,6 @@\n /* ISSYMREF=01 and ISPACKED=02 are public interfaces */\n #define REF_KNOWS_PEELED 04\n \n-/* Current prefix namespace in use. NULL means none. */\n struct ref_list {\n \tstruct ref_list *next;\n \tunsigned char flag; /* ISSYMREF? ISPACKED? */\n@@ -675,19 +674,18 @@ int for_each_replace_ref(each_ref_fn fn, void *cb_data)\n \treturn do_for_each_ref(\"refs/replace/\", fn, 13, 0, cb_data);\n }\n \n-int for_each_namespace_ref(each_ref_fn fn, void *cb_data)\n+int for_each_namespace_ref(each_ref_fn fn, const char *ns_prefix, void *cb_data)\n {\n-\tstruct for_each_namespace_request *req = cb_data;\n \tstruct strbuf real_prefix = STRBUF_INIT;\n \tint ret;\n \n-\tif (prefixcmp(req->req_namespace, \"refs/\"))\n+\tif (prefixcmp(ns_prefix, \"refs/\"))\n \t\tstrbuf_addstr(&real_prefix, \"refs/\");\n-\tstrbuf_addstr(&real_prefix, req->req_namespace);\n+\tstrbuf_addstr(&real_prefix, ns_prefix);\n \tif (real_prefix.buf[real_prefix.len - 1] != '/')\n \t\tstrbuf_addch(&real_prefix, '/');\n \n-\tret = for_each_ref_in(real_prefix.buf, fn, req->req_opaque);\n+\tret = for_each_ref_in(real_prefix.buf, fn, cb_data);\n \tstrbuf_release(&real_prefix);\n \treturn ret;\n }\ndiff --git a/refs.h b/refs.h\nindex 4bb63b0..a1d7378 100644\n--- a/refs.h\n+++ b/refs.h\n@@ -13,18 +13,6 @@ struct ref_lock {\n #define REF_ISSYMREF 01\n #define REF_ISPACKED 02\n \n-/* Opaque request for for_each_namespace_ref */\n-struct for_each_namespace_request\n-{\n-\t/*\n-\t * The limiting namespace. 'refs/' and '/' are autoprepended /\n-\t * autoappended if missing.\n-\t */\n-\tconst char *req_namespace;\n-\t/* The real opaque data for callback function. */\n-\tvoid *req_opaque;\n-};\n-\n /*\n  * Calls the specified function for each ref file until it returns nonzero,\n  * and returns the value\n@@ -37,7 +25,7 @@ extern int for_each_tag_ref(each_ref_fn, void *);\n extern int for_each_branch_ref(each_ref_fn, void *);\n extern int for_each_remote_ref(each_ref_fn, void *);\n extern int for_each_replace_ref(each_ref_fn, void *);\n-extern int for_each_namespace_ref(each_ref_fn, void *);\n+extern int for_each_namespace_ref(each_ref_fn, const char *, void *);\n \n /* can be used to learn about broken ref and symref */\n extern int for_each_rawref(each_ref_fn, void *);\ndiff --git a/revision.c b/revision.c\nindex ff9484f..ec63fa0 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -1359,13 +1359,10 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch\n \t\t\t\tcontinue;\n \t\t\t}\n \t\t\tif (!prefixcmp(arg, \"--namespace=\")) {\n-\t\t\t\tstruct for_each_namespace_request req;\n \t\t\t\tstruct all_refs_cb cb;\n \n \t\t\t\tinit_all_refs_cb(&cb, revs, flags);\n-\t\t\t\treq.req_namespace = arg + 12;\n-\t\t\t\treq.req_opaque = &cb;\n-\t\t\t\tfor_each_namespace_ref(handle_one_ref, &req);\n+\t\t\t\tfor_each_namespace_ref(handle_one_ref, arg + 12, &cb);\n \t\t\t\tcontinue;\n \t\t\t}\n \t\t\tif (!strcmp(arg, \"--reflog\")) {\n"},{"id":"132025","messageId":"1263808296-30756-1-git-send-email-ilari.liusvaara@elisanet.fi","threadId":"22266","inReplyTo":"7vk4vfsv64.fsf@alter.siamese.dyndns.org","subject":"[PATCH v3] rev-parse --namespace","fromName":"Ilari Liusvaara","fromEmail":"ilari.liusvaara@elisanet.fi","sentAt":"2010-01-18T09:51:36Z","receivedAt":"2010-01-18T09:51:36Z","isPatch":true,"sender":{"key":"ilari.liusvaara@elisanet.fi","avatar":null},"body":"Add --namespace=<namespace> option to rev-parse and everything that\naccepts its options. This option matches all refs in some subnamespace\nof refs hierarchy.\n\nExample:\n\n'git log --branches --not --namespace=remotes/origin'\n\nTo show what you have that origin doesn't.\n\nSigned-off-by: Ilari Liusvaara <ilari.liusvaara@elisanet.fi>\n---\nChanges from v2:\n- Actually include updated git log examples (oops).\n- Get rid of for_each_namespace_request, use parameters instead.\n- Get rid of extraneous comment.\n\n Documentation/git-log.txt          |    6 ++\n Documentation/git-rev-list.txt     |    1 +\n Documentation/git-rev-parse.txt    |    4 +\n Documentation/rev-list-options.txt |    6 ++\n builtin-rev-parse.c                |    5 ++\n refs.c                             |   16 +++++\n refs.h                             |    1 +\n revision.c                         |   16 +++++-\n t/t6018-rev-list-namespace.sh      |  112 ++++++++++++++++++++++++++++++++++++\n 9 files changed, 165 insertions(+), 2 deletions(-)\n create mode 100755 t/t6018-rev-list-namespace.sh\n\ndiff --git a/Documentation/git-log.txt b/Documentation/git-log.txt\nindex 3d79de1..d84660c 100644\n--- a/Documentation/git-log.txt\n+++ b/Documentation/git-log.txt\n@@ -107,6 +107,12 @@ git log --follow builtin-rev-list.c::\n \tthose commits that occurred before the file was given its\n \tpresent name.\n \n+git log --branches --not --namespace=remotes/origin::\n+\n+\tShows all commits that are in any of local branches but not in\n+\tany of remote tracking branches for 'origin' (what you have that\n+\torigin doesn't).\n+\n Discussion\n ----------\n \ndiff --git a/Documentation/git-rev-list.txt b/Documentation/git-rev-list.txt\nindex 3341d1b..a8f8f22 100644\n--- a/Documentation/git-rev-list.txt\n+++ b/Documentation/git-rev-list.txt\n@@ -24,6 +24,7 @@ SYNOPSIS\n \t     [ \\--branches ]\n \t     [ \\--tags ]\n \t     [ \\--remotes ]\n+\t     [ \\--namespace=namespace-prefix ]\n \t     [ \\--stdin ]\n \t     [ \\--quiet ]\n \t     [ \\--topo-order ]\ndiff --git a/Documentation/git-rev-parse.txt b/Documentation/git-rev-parse.txt\nindex 82045a2..af4605a 100644\n--- a/Documentation/git-rev-parse.txt\n+++ b/Documentation/git-rev-parse.txt\n@@ -112,6 +112,10 @@ OPTIONS\n --remotes::\n \tShow tag refs found in `$GIT_DIR/refs/remotes`.\n \n+--namespace=namespace-prefix::\n+\tShow refs found in `$GIT_DIR/namespace-prefix`. If namespace\n+\tspecified lacks leading 'refs/', it is automatically prepended.\n+\n --show-prefix::\n \tWhen the command is invoked from a subdirectory, show the\n \tpath of the current directory relative to the top-level\ndiff --git a/Documentation/rev-list-options.txt b/Documentation/rev-list-options.txt\nindex 1f57aed..c824a7b 100644\n--- a/Documentation/rev-list-options.txt\n+++ b/Documentation/rev-list-options.txt\n@@ -243,6 +243,12 @@ endif::git-rev-list[]\n \tPretend as if all the refs in `$GIT_DIR/refs/remotes` are listed\n \ton the command line as '<commit>'.\n \n+--namespace=namespace-prefix::\n+\tPretend as if all the refs in `$GIT_DIR/namespace-prefix` are\n+\tlisted on the command line as '<commit>'. Leading 'refs/', it\n+\tis automatically prepended if missing.\n+\n+\n ifndef::git-rev-list[]\n --bisect::\n \ndiff --git a/builtin-rev-parse.c b/builtin-rev-parse.c\nindex 37d0233..34af347 100644\n--- a/builtin-rev-parse.c\n+++ b/builtin-rev-parse.c\n@@ -52,6 +52,7 @@ static int is_rev_argument(const char *arg)\n \t\t\"--parents\",\n \t\t\"--pretty\",\n \t\t\"--remotes\",\n+\t\t\"--namespace=\",\n \t\t\"--sparse\",\n \t\t\"--tags\",\n \t\t\"--topo-order\",\n@@ -577,6 +578,10 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)\n \t\t\t\tfor_each_tag_ref(show_reference, NULL);\n \t\t\t\tcontinue;\n \t\t\t}\n+\t\t\tif (!prefixcmp(arg, \"--namespace=\")) {\n+\t\t\t\tfor_each_namespace_ref(show_reference, arg + 12, NULL);\n+\t\t\t\tcontinue;\n+\t\t\t}\n \t\t\tif (!strcmp(arg, \"--remotes\")) {\n \t\t\t\tfor_each_remote_ref(show_reference, NULL);\n \t\t\t\tcontinue;\ndiff --git a/refs.c b/refs.c\nindex 3e73a0a..5583f4b 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -674,6 +674,22 @@ int for_each_replace_ref(each_ref_fn fn, void *cb_data)\n \treturn do_for_each_ref(\"refs/replace/\", fn, 13, 0, cb_data);\n }\n \n+int for_each_namespace_ref(each_ref_fn fn, const char *ns_name, void *cb_data)\n+{\n+\tstruct strbuf real_prefix = STRBUF_INIT;\n+\tint ret;\n+\n+\tif (prefixcmp(ns_name, \"refs/\"))\n+\t\tstrbuf_addstr(&real_prefix, \"refs/\");\n+\tstrbuf_addstr(&real_prefix, ns_name);\n+\tif (real_prefix.buf[real_prefix.len - 1] != '/')\n+\t\tstrbuf_addch(&real_prefix, '/');\n+\n+\tret = for_each_ref_in(real_prefix.buf, fn, cb_data);\n+\tstrbuf_release(&real_prefix);\n+\treturn ret;\n+}\n+\n int for_each_rawref(each_ref_fn fn, void *cb_data)\n {\n \treturn do_for_each_ref(\"refs/\", fn, 0,\ndiff --git a/refs.h b/refs.h\nindex e141991..b26c3a8 100644\n--- a/refs.h\n+++ b/refs.h\n@@ -25,6 +25,7 @@ extern int for_each_tag_ref(each_ref_fn, void *);\n extern int for_each_branch_ref(each_ref_fn, void *);\n extern int for_each_remote_ref(each_ref_fn, void *);\n extern int for_each_replace_ref(each_ref_fn, void *);\n+extern int for_each_namespace_ref(each_ref_fn, const char* ns_name, void *);\n \n /* can be used to learn about broken ref and symref */\n extern int for_each_rawref(each_ref_fn, void *);\ndiff --git a/revision.c b/revision.c\nindex 25fa14d..7328201 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -699,12 +699,18 @@ static int handle_one_ref(const char *path, const unsigned char *sha1, int flag,\n \treturn 0;\n }\n \n+static void init_all_refs_cb(struct all_refs_cb *cb, struct rev_info *revs,\n+\tunsigned flags)\n+{\n+\tcb->all_revs = revs;\n+\tcb->all_flags = flags;\n+}\n+\n static void handle_refs(struct rev_info *revs, unsigned flags,\n \t\tint (*for_each)(each_ref_fn, void *))\n {\n \tstruct all_refs_cb cb;\n-\tcb.all_revs = revs;\n-\tcb.all_flags = flags;\n+\tinit_all_refs_cb(&cb, revs, flags);\n \tfor_each(handle_one_ref, &cb);\n }\n \n@@ -1352,6 +1358,12 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch\n \t\t\t\thandle_refs(revs, flags, for_each_remote_ref);\n \t\t\t\tcontinue;\n \t\t\t}\n+\t\t\tif (!prefixcmp(arg, \"--namespace=\")) {\n+\t\t\t\tstruct all_refs_cb cb;\n+\t\t\t\tinit_all_refs_cb(&cb, revs, flags);\n+\t\t\t\tfor_each_namespace_ref(handle_one_ref, arg + 12, &cb);\n+\t\t\t\tcontinue;\n+\t\t\t}\n \t\t\tif (!strcmp(arg, \"--reflog\")) {\n \t\t\t\thandle_reflog(revs, flags);\n \t\t\t\tcontinue;\ndiff --git a/t/t6018-rev-list-namespace.sh b/t/t6018-rev-list-namespace.sh\nnew file mode 100755\nindex 0000000..6bb562a\n--- /dev/null\n+++ b/t/t6018-rev-list-namespace.sh\n@@ -0,0 +1,112 @@\n+#!/bin/sh\n+\n+test_description='rev-list/rev-parse --namespace'\n+\n+. ./test-lib.sh\n+\n+\n+commit () {\n+\ttest_tick &&\n+\techo $1 > foo &&\n+\tgit add foo &&\n+\tgit commit -m \"$1\"\n+}\n+\n+compare () {\n+\t# Split arguments on whitespace.\n+\tgit $1 $2 | sort >expected &&\n+\tgit $1 $3 | sort >actual &&\n+\tcmp expected actual\n+}\n+\n+test_expect_success 'setup' '\n+\n+\tcommit master &&\n+\tgit checkout -b subspace/one master\n+\tcommit one &&\n+\tgit checkout -b subspace/two master\n+\tcommit two &&\n+\tgit checkout -b subspace-x master\n+\tcommit subspace-x &&\n+\tgit checkout -b other/three master\n+\tcommit three &&\n+\tgit checkout -b someref master\n+\tcommit some &&\n+\tgit checkout master &&\n+\tcommit master2\n+'\n+\n+test_expect_success 'rev-parse --namespace=refs/heads/subspace/' '\n+\n+\tcompare rev-parse \"subspace/one subspace/two\" \"--namespace=refs/heads/subspace/\"\n+\n+'\n+\n+test_expect_success 'rev-parse --namespace=refs/heads/subspace' '\n+\n+\tcompare rev-parse \"subspace/one subspace/two\" \"--namespace=refs/heads/subspace\"\n+\n+'\n+\n+test_expect_success 'rev-parse --namespace=heads/subspace' '\n+\n+\tcompare rev-parse \"subspace/one subspace/two\" \"--namespace=heads/subspace\"\n+\n+'\n+\n+test_expect_success 'rev-parse --namespace=heads/subspace --namespace=heads/other' '\n+\n+\tcompare rev-parse \"subspace/one subspace/two other/three\" \"--namespace=heads/subspace --namespace=heads/other\"\n+\n+'\n+\n+test_expect_success 'rev-parse --namespace=heads/someref master' '\n+\n+\tcompare rev-parse \"master\" \"--namespace=heads/someref master\"\n+\n+'\n+\n+test_expect_success 'rev-parse --namespace=heads' '\n+\n+\tcompare rev-parse \"subspace/one subspace/two other/three subspace-x master someref\" \"--namespace=heads\"\n+\n+'\n+\n+test_expect_success 'rev-list --namespace=refs/heads/subspace/' '\n+\n+\tcompare rev-list \"subspace/one subspace/two\" \"--namespace=refs/heads/subspace/\"\n+\n+'\n+\n+test_expect_success 'rev-list --namespace=refs/heads/subspace' '\n+\n+\tcompare rev-list \"subspace/one subspace/two\" \"--namespace=refs/heads/subspace\"\n+\n+'\n+\n+test_expect_success 'rev-list --namespace=heads/subspace' '\n+\n+\tcompare rev-list \"subspace/one subspace/two\" \"--namespace=heads/subspace\"\n+\n+'\n+\n+test_expect_success 'rev-list --namespace=heads/someref master' '\n+\n+\tcompare rev-parse \"master\" \"--namespace=heads/someref master\"\n+\n+'\n+\n+test_expect_success 'rev-list --namespace=heads/subspace --namespace=heads/other' '\n+\n+\tcompare rev-parse \"subspace/one subspace/two other/three\" \"--namespace=heads/subspace --namespace=heads/other\"\n+\n+'\n+\n+test_expect_success 'rev-list --namespace=heads' '\n+\n+\tcompare rev-parse \"subspace/one subspace/two other/three subspace-x master someref\" \"--namespace=heads\"\n+\n+'\n+\n+\n+test_done\n-- \n1.6.6.199.gff4b0\n"},{"id":"132080","messageId":"20100119065609.GB3946@coredump.intra.peff.net","threadId":"22266","inReplyTo":"1263808296-30756-1-git-send-email-ilari.liusvaara@elisanet.fi","subject":"Re: [PATCH v3] rev-parse --namespace","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2010-01-19T06:56:09Z","receivedAt":"2010-01-19T06:56:09Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Mon, Jan 18, 2010 at 11:51:36AM +0200, Ilari Liusvaara wrote:\n\n> Add --namespace=<namespace> option to rev-parse and everything that\n> accepts its options. This option matches all refs in some subnamespace\n> of refs hierarchy.\n\nThanks, I think the code in this version looks good, but:\n\n> --- /dev/null\n> +++ b/t/t6018-rev-list-namespace.sh\n> [...]\n> +compare () {\n> +\t# Split arguments on whitespace.\n> +\tgit $1 $2 | sort >expected &&\n> +\tgit $1 $3 | sort >actual &&\n> +\tcmp expected actual\n> +}\n\nPlease use test_cmp instead of regular cmp.\n\nAlso, do you really need to sort? The internal ref code keeps the ref\nlists sorted by name, and we merge-sort the packed and loose lists in\ndo_for_each_ref. So your --namespace should always operate on the refs\nin sorted order, producing predictable results.\n\n> +test_expect_success 'setup' '\n> +\n> +\tcommit master &&\n> +\tgit checkout -b subspace/one master\n> +\tcommit one &&\n> +\tgit checkout -b subspace/two master\n> +\tcommit two &&\n> +\tgit checkout -b subspace-x master\n> +\tcommit subspace-x &&\n> +\tgit checkout -b other/three master\n> +\tcommit three &&\n> +\tgit checkout -b someref master\n> +\tcommit some &&\n> +\tgit checkout master &&\n> +\tcommit master2\n> +'\n\nYou are still missing some '&&' here to detect setup failures.\n\n-Peff\n"},{"id":"132090","messageId":"1263893748-23327-1-git-send-email-ilari.liusvaara@elisanet.fi","threadId":"22266","inReplyTo":"20100119065609.GB3946@coredump.intra.peff.net","subject":"[PATCH] Fix errors in t6018","fromName":"Ilari Liusvaara","fromEmail":"ilari.liusvaara@elisanet.fi","sentAt":"2010-01-19T09:35:48Z","receivedAt":"2010-01-19T09:35:48Z","isPatch":true,"sender":{"key":"ilari.liusvaara@elisanet.fi","avatar":null},"body":"Fix errors and shortcomings in t6018 (the rev-parse --namespace test):\n1) Some tests were missing &&'s, leading too possibly missing failures\n2) Some tests used incorrect commands (didn't test what they were\nsuppoed to)\n3) Some test used 'cmp' instead of 'test_cmp'\n4) Tests only tested output up to permutation\n\nFix these errors in t6018.\n\nSigned-off-by: Ilari Liusvaara <ilari.liusvaara@elisanet.fi>\n---\nThis can be appiled on top of rev-parse --namespace patch v3 or this\ncan be squashed to that patch.\n\n t/t6018-rev-list-namespace.sh |   24 ++++++++++++------------\n 1 files changed, 12 insertions(+), 12 deletions(-)\n\ndiff --git a/t/t6018-rev-list-namespace.sh b/t/t6018-rev-list-namespace.sh\nindex 6bb562a..70c8a83 100755\n--- a/t/t6018-rev-list-namespace.sh\n+++ b/t/t6018-rev-list-namespace.sh\n@@ -14,23 +14,23 @@ commit () {\n \n compare () {\n \t# Split arguments on whitespace.\n-\tgit $1 $2 | sort >expected &&\n-\tgit $1 $3 | sort >actual &&\n-\tcmp expected actual\n+\tgit $1 $2 >expected &&\n+\tgit $1 $3 >actual &&\n+\ttest_cmp expected actual\n }\n \n test_expect_success 'setup' '\n \n \tcommit master &&\n-\tgit checkout -b subspace/one master\n+\tgit checkout -b subspace/one master &&\n \tcommit one &&\n-\tgit checkout -b subspace/two master\n+\tgit checkout -b subspace/two master &&\n \tcommit two &&\n-\tgit checkout -b subspace-x master\n+\tgit checkout -b subspace-x master &&\n \tcommit subspace-x &&\n-\tgit checkout -b other/three master\n+\tgit checkout -b other/three master &&\n \tcommit three &&\n-\tgit checkout -b someref master\n+\tgit checkout -b someref master &&\n \tcommit some &&\n \tgit checkout master &&\n \tcommit master2\n@@ -68,7 +68,7 @@ test_expect_success 'rev-parse --namespace=heads/someref master' '\n \n test_expect_success 'rev-parse --namespace=heads' '\n \n-\tcompare rev-parse \"subspace/one subspace/two other/three subspace-x master someref\" \"--namespace=heads\"\n+\tcompare rev-parse \"master other/three someref subspace-x subspace/one subspace/two\" \"--namespace=heads\"\n \n '\n \n@@ -92,19 +92,19 @@ test_expect_success 'rev-list --namespace=heads/subspace' '\n \n test_expect_success 'rev-list --namespace=heads/someref master' '\n \n-\tcompare rev-parse \"master\" \"--namespace=heads/someref master\"\n+\tcompare rev-list \"master\" \"--namespace=heads/someref master\"\n \n '\n \n test_expect_success 'rev-list --namespace=heads/subspace --namespace=heads/other' '\n \n-\tcompare rev-parse \"subspace/one subspace/two other/three\" \"--namespace=heads/subspace --namespace=heads/other\"\n+\tcompare rev-list \"subspace/one subspace/two other/three\" \"--namespace=heads/subspace --namespace=heads/other\"\n \n '\n \n test_expect_success 'rev-list --namespace=heads' '\n \n-\tcompare rev-parse \"subspace/one subspace/two other/three subspace-x master someref\" \"--namespace=heads\"\n+\tcompare rev-list \"master other/three someref subspace-x subspace/one subspace/two\" \"--namespace=heads\"\n \n '\n \n-- \n1.6.6.199.gff4b0\n"},{"id":"132123","messageId":"201001191839.27090.trast@student.ethz.ch","threadId":"22266","inReplyTo":"1263798952-27624-1-git-send-email-ilari.liusvaara@elisanet.fi","subject":"Re: [PATCH v2] rev-parse --namespace","fromName":"Thomas Rast","fromEmail":"trast@student.ethz.ch","sentAt":"2010-01-19T17:39:25Z","receivedAt":"2010-01-19T17:39:25Z","isPatch":true,"sender":{"key":"tr@thomasrast.ch","avatar":"https://avatars.githubusercontent.com/u/153510?v=4"},"body":"Ilari Liusvaara wrote:\n> Add --namespace=<namespace> option to rev-parse and everything that\n> accepts its options. This option matches all refs in some subnamespace\n> of refs hierarchy.\n> \n> Example:\n> \n> 'git log --branches --not --namespace=remotes/origin'\n> \n> To show what you have that origin doesn't.\n\nSorry for being so late to this discussion, but... wouldn't it be\nnicer to give it some globbing powers and the same semantics as\n'fetch' lines?  That way spelling \"all master branches of my remotes\"\nand other such things would be easy.\n\n-- \nThomas Rast\ntrast@{inf,student}.ethz.ch\n"},{"id":"132127","messageId":"20100119183736.GA24204@Knoppix","threadId":"22266","inReplyTo":"201001191839.27090.trast@student.ethz.ch","subject":"Re: [PATCH v2] rev-parse --namespace","fromName":"Ilari Liusvaara","fromEmail":"ilari.liusvaara@elisanet.fi","sentAt":"2010-01-19T18:37:36Z","receivedAt":"2010-01-19T18:37:36Z","isPatch":true,"sender":{"key":"ilari.liusvaara@elisanet.fi","avatar":null},"body":"On Tue, Jan 19, 2010 at 06:39:25PM +0100, Thomas Rast wrote:\n> Ilari Liusvaara wrote:\n> \n> Sorry for being so late to this discussion, but... wouldn't it be\n> nicer to give it some globbing powers and the same semantics as\n> 'fetch' lines?  That way spelling \"all master branches of my remotes\"\n> and other such things would be easy.\n\nUnfortunately doesn't seem to be easy to do, as push and fetch have\ntheir own refspec logic. In fact, if matching power would be extended,\nprobably the easiest extension would be full-blown extended regular\nexpressions.\n\n-Ilari\n"},{"id":"132137","messageId":"7v3a21amh7.fsf@alter.siamese.dyndns.org","threadId":"22266","inReplyTo":"20100119183736.GA24204@Knoppix","subject":"Re: [PATCH v2] rev-parse --namespace","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2010-01-19T20:06:12Z","receivedAt":"2010-01-19T20:06:12Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ilari Liusvaara <ilari.liusvaara@elisanet.fi> writes:\n\n> ..., if matching power would be extended,\n> probably the easiest extension would be full-blown extended regular\n> expressions.\n\nAs refs behave like a filesystem path and we try to use fnmatch() for\nanything that behave like a filesystem path, that would break consistency.\n\nBut a patch to add fnmatch() shouldn't be too bad; something like this\n(not even compile tested)?\n\n refs.c |   45 +++++++++++++++++++++++++++++++++++++--------\n 1 files changed, 37 insertions(+), 8 deletions(-)\n\ndiff --git a/refs.c b/refs.c\nindex 5583f4b..0494c75 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -674,19 +674,48 @@ int for_each_replace_ref(each_ref_fn fn, void *cb_data)\n \treturn do_for_each_ref(\"refs/replace/\", fn, 13, 0, cb_data);\n }\n \n+struct ref_glob_filter {\n+\teach_ref_fn *user_callback;\n+\tvoid *user_cb_data;\n+\tconst char *pattern;\n+\tint pattern_len;\n+};\n+\n+static int ref_glob_filter_cb(const char *refname,\n+\t\t\t      const unsigned char *sha1,\n+\t\t\t      int flags, void *cb_data)\n+{\n+\tstruct ref_glob_filter *cb = cb_data;\n+\n+\t/*\n+\t * Reject if it does not produce a prefix match and\n+\t * it doesn't pass fnmatch().\n+\t */\n+\tif (!(cb->pattern_len <= strlen(refname)\n+\t      && !memcmp(cb->pattern, refname, cb->pattern_len)) &&\n+\t    fnmatch(cb->pattern, refname, 0))\n+\t\treturn 0;\n+\treturn cb->user_callback(refname, sha1, flags, cb->user_cb_data);\n+}\n+\n int for_each_namespace_ref(each_ref_fn fn, const char *ns_name, void *cb_data)\n {\n-\tstruct strbuf real_prefix = STRBUF_INIT;\n+\tstruct ref_glob_filter filter;\n+\tstruct strbuf pattern = STRBUF_INIT;\n \tint ret;\n \n \tif (prefixcmp(ns_name, \"refs/\"))\n-\t\tstrbuf_addstr(&real_prefix, \"refs/\");\n-\tstrbuf_addstr(&real_prefix, ns_name);\n-\tif (real_prefix.buf[real_prefix.len - 1] != '/')\n-\t\tstrbuf_addch(&real_prefix, '/');\n-\n-\tret = for_each_ref_in(real_prefix.buf, fn, cb_data);\n-\tstrbuf_release(&real_prefix);\n+\t\tstrbuf_addstr(&pattern, \"refs/\");\n+\tstrbuf_addstr(&pattern, ns_name);\n+\tif (pattern.buf[pattern.len - 1] != '/')\n+\t\tstrbuf_addch(&pattern, '/');\n+\tfilter.pattern = pattern.buf;\n+\tfilter.pattern_len = pattern.len;\n+\tfilter.user_callback = fn;\n+\tfilter.user_cb_data = cb_data;\n+\n+\tret = for_each_ref(ref_glob_filter_cb, &filter);\n+\tstrbuf_release(&pattern);\n \treturn ret;\n }\n \n"},{"id":"132138","messageId":"7vtyuh970t.fsf@alter.siamese.dyndns.org","threadId":"22266","inReplyTo":"1263893748-23327-1-git-send-email-ilari.liusvaara@elisanet.fi","subject":"Re: [PATCH] Fix errors in t6018","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2010-01-19T20:25:22Z","receivedAt":"2010-01-19T20:25:22Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Thanks, both of you, for being careful.\n"},{"id":"132140","messageId":"20100119214400.GA24911@Knoppix","threadId":"22266","inReplyTo":"7v3a21amh7.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH v2] rev-parse --namespace","fromName":"Ilari Liusvaara","fromEmail":"ilari.liusvaara@elisanet.fi","sentAt":"2010-01-19T21:44:00Z","receivedAt":"2010-01-19T21:44:00Z","isPatch":true,"sender":{"key":"ilari.liusvaara@elisanet.fi","avatar":null},"body":"On Tue, Jan 19, 2010 at 12:06:12PM -0800, Junio C Hamano wrote:\n> Ilari Liusvaara <ilari.liusvaara@elisanet.fi> writes:\n> \n> > ..., if matching power would be extended,\n> > probably the easiest extension would be full-blown extended regular\n> > expressions.\n> \n> As refs behave like a filesystem path and we try to use fnmatch() for\n> anything that behave like a filesystem path, that would break consistency.\n\nEh, remind me what commands take refs and shell-glob them? The only\n'globbing' of refs I'm aware of is in refspecs, and that definitely isn't\nshell globbing...\n\n-Ilari\n"},{"id":"132141","messageId":"201001192246.53453.trast@student.ethz.ch","threadId":"22266","inReplyTo":"20100119214400.GA24911@Knoppix","subject":"Re: [PATCH v2] rev-parse --namespace","fromName":"Thomas Rast","fromEmail":"trast@student.ethz.ch","sentAt":"2010-01-19T21:46:51Z","receivedAt":"2010-01-19T21:46:51Z","isPatch":true,"sender":{"key":"tr@thomasrast.ch","avatar":"https://avatars.githubusercontent.com/u/153510?v=4"},"body":"Ilari Liusvaara wrote:\n> On Tue, Jan 19, 2010 at 12:06:12PM -0800, Junio C Hamano wrote:\n> > As refs behave like a filesystem path and we try to use fnmatch() for\n> > anything that behave like a filesystem path, that would break consistency.\n> \n> Eh, remind me what commands take refs and shell-glob them? The only\n> 'globbing' of refs I'm aware of is in refspecs, and that definitely isn't\n> shell globbing...\n\nfetchspecs?\n\n-- \nThomas Rast\ntrast@{inf,student}.ethz.ch\n"},{"id":"132143","messageId":"20100119221258.GA25210@Knoppix","threadId":"22266","inReplyTo":"201001192246.53453.trast@student.ethz.ch","subject":"Re: [PATCH v2] rev-parse --namespace","fromName":"Ilari Liusvaara","fromEmail":"ilari.liusvaara@elisanet.fi","sentAt":"2010-01-19T22:12:59Z","receivedAt":"2010-01-19T22:12:59Z","isPatch":true,"sender":{"key":"ilari.liusvaara@elisanet.fi","avatar":null},"body":"On Tue, Jan 19, 2010 at 10:46:51PM +0100, Thomas Rast wrote:\n> Ilari Liusvaara wrote:\n> > \n> > Eh, remind me what commands take refs and shell-glob them? The only\n> > 'globbing' of refs I'm aware of is in refspecs, and that definitely isn't\n> > shell globbing...\n> \n> fetchspecs?\n\nAh, found one: 'ls-remote'. Documentation of that doesn't say what format\npatterns are in... \n\nAny others? \n\n-Ilari\n"},{"id":"132144","messageId":"7vd41590xq.fsf@alter.siamese.dyndns.org","threadId":"22266","inReplyTo":"20100119221258.GA25210@Knoppix","subject":"Re: [PATCH v2] rev-parse --namespace","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2010-01-19T22:36:49Z","receivedAt":"2010-01-19T22:36:49Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ilari Liusvaara <ilari.liusvaara@elisanet.fi> writes:\n\n> On Tue, Jan 19, 2010 at 10:46:51PM +0100, Thomas Rast wrote:\n>> Ilari Liusvaara wrote:\n>> > \n>> > Eh, remind me what commands take refs and shell-glob them? The only\n>> > 'globbing' of refs I'm aware of is in refspecs, and that definitely isn't\n>> > shell globbing...\n>> \n>> fetchspecs?\n>\n> Ah, found one: 'ls-remote'. Documentation of that doesn't say what format\n> patterns are in... \n>\n> Any others? \n\nWhat I gave you was \"Please don't use regexp, because matching refs with\nfnmatch() is the design guideline we follow\".  It was not \"please follow\nthe precedence of existing commands\".  IOW, even if there was no command\nthat matched refs with globs, it is not an excuse to use regexp.  You\ndidn't even have to find any single example.  But here are some others, if\nyou are interested.\n\n$ git grep fnmatch builtin-{for-each-ref,reflog,name-rev,show-branch,tag}.c\n\nYou find the design guideline to make refs behave as paths in a lot more\nfundamental places, such as \"if you have 'master' branch, you don't have\nmaster/foo branch\", and \"you cannot use '?' in ref name because it is a\nspecial character in globbing\".\n"},{"id":"132167","messageId":"4B56B0BF.6020102@viscovery.net","threadId":"22266","inReplyTo":"1263798952-27624-1-git-send-email-ilari.liusvaara@elisanet.fi","subject":"Re: [PATCH v2] rev-parse --namespace","fromName":"Johannes Sixt","fromEmail":"j.sixt@viscovery.net","sentAt":"2010-01-20T07:29:03Z","receivedAt":"2010-01-20T07:29:03Z","isPatch":true,"sender":{"key":"j6t@kdbg.org","avatar":"https://avatars.githubusercontent.com/u/14810926?v=4"},"body":"I've implemented --remotes=foo on top of your patch because I needed it,\nand --namespace=remotes/foo was too much to type. Are you interested in\nintegrating this in your series in some way?\n\nI only needed the --remotes=foo part; the --branches=foo is only\n\"because we can\". Note that 'foo' is always a complete path component,\nbecause it is the name of a remote (the trailing slash is implied), e.g.,\n'--remotes=origin'.\n\n--- 8< ---\nFrom: Johannes Sixt <j6t@kdbg.org>\nSubject: [PATCH] revision options --remotes=prefix and --branches=prefix\n\nSigned-off-by: Johannes Sixt <j6t@kdbg.org>\n---\n builtin-rev-parse.c |    2 ++\n revision.c          |   23 +++++++++++++++++++++++\n 2 files changed, 25 insertions(+), 0 deletions(-)\n\ndiff --git a/builtin-rev-parse.c b/builtin-rev-parse.c\nindex 34af347..08b0555 100644\n--- a/builtin-rev-parse.c\n+++ b/builtin-rev-parse.c\n@@ -42,6 +42,7 @@ static int is_rev_argument(const char *arg)\n \t\t\"--bisect\",\n \t\t\"--dense\",\n \t\t\"--branches\",\n+\t\t\"--branches=\",\n \t\t\"--header\",\n \t\t\"--max-age=\",\n \t\t\"--max-count=\",\n@@ -52,6 +53,7 @@ static int is_rev_argument(const char *arg)\n \t\t\"--parents\",\n \t\t\"--pretty\",\n \t\t\"--remotes\",\n+\t\t\"--remotes=\",\n \t\t\"--namespace=\",\n \t\t\"--sparse\",\n \t\t\"--tags\",\ndiff --git a/revision.c b/revision.c\nindex ec63fa0..68e251b 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -714,6 +714,21 @@ static void handle_refs(struct rev_info *revs, unsigned flags,\n \tfor_each(handle_one_ref, &cb);\n }\n\n+static void handle_ref_subset(struct rev_info *revs, unsigned flags,\n+\t\t\t      const char *prefix, const char *postfix)\n+{\n+\tstruct strbuf name = STRBUF_INIT;\n+\tstruct all_refs_cb cb;\n+\n+\tstrbuf_addstr(&name, prefix);\n+\tstrbuf_addstr(&name, postfix);\n+\tif (name.buf[name.len - 1] != '/')\n+\t\tstrbuf_addch(&name, '/');\n+\tinit_all_refs_cb(&cb, revs, flags);\n+\tfor_each_ref_in(name.buf, handle_one_ref, &cb);\n+\tstrbuf_release(&name);\n+}\n+\n static void handle_one_reflog_commit(unsigned char *sha1, void *cb_data)\n {\n \tstruct all_refs_cb *cb = cb_data;\n@@ -1344,6 +1359,10 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch\n \t\t\t\thandle_refs(revs, flags, for_each_branch_ref);\n \t\t\t\tcontinue;\n \t\t\t}\n+\t\t\tif (!prefixcmp(arg, \"--branches=\")) {\n+\t\t\t\thandle_ref_subset(revs, flags, \"refs/heads/\", arg + 11);\n+\t\t\t\tcontinue;\n+\t\t\t}\n \t\t\tif (!strcmp(arg, \"--bisect\")) {\n \t\t\t\thandle_refs(revs, flags, for_each_bad_bisect_ref);\n \t\t\t\thandle_refs(revs, flags ^ UNINTERESTING, for_each_good_bisect_ref);\n@@ -1358,6 +1377,10 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch\n \t\t\t\thandle_refs(revs, flags, for_each_remote_ref);\n \t\t\t\tcontinue;\n \t\t\t}\n+\t\t\tif (!prefixcmp(arg, \"--remotes=\")) {\n+\t\t\t\thandle_ref_subset(revs, flags, \"refs/remotes/\", arg + 10);\n+\t\t\t\tcontinue;\n+\t\t\t}\n \t\t\tif (!prefixcmp(arg, \"--namespace=\")) {\n \t\t\t\tstruct all_refs_cb cb;\n\n-- \n1.6.6.1301.g354d\n"}]}