{"thread":{"id":"35726","subject":"Globbing for ignored branches?","startedAt":"2014-01-24T09:01:04Z","lastAt":"2014-01-25T20:02:17Z","messageCount":17,"participants":["Markus Trippelsdorf","Jim Garrison","Jeff King","Junio C Hamano"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"233680","messageId":"20140124090104.GA396@x4","threadId":"35726","inReplyTo":null,"subject":"Globbing for ignored branches?","fromName":"Markus Trippelsdorf","fromEmail":"markus@trippelsdorf.de","sentAt":"2014-01-24T09:01:04Z","receivedAt":"2014-01-24T09:01:04Z","isPatch":false,"sender":{"key":"markus@trippelsdorf.de","avatar":null},"body":"I would like to ignore branches that match a certain pattern, e.g.:\n\nmarkus@x4 gcc % git branch -a\n  gcc-4.8\n* master\n  remotes/origin/HEAD -> origin/master\n  remotes/origin/aldyh/cilk-in-gomp\n...\n  remotes/origin/hjl/arch\n  remotes/origin/hjl/asan\n...\n  remotes/origin/hjl/x86/m16\n  remotes/origin/ifunc\n  remotes/origin/jason/4.6-cxx0x\n  remotes/origin/jason/alias-decl\n  remotes/origin/jason/comdat-debug\n  remotes/origin/lw-ipo\n  remotes/origin/master\n...\n\nIs it possible to ignore all branches that match \"hjl\"?\n\n-- \nMarkus\n"},{"id":"233696","messageId":"0C723FEB5B4E5642B25B451BA57E273075148284@S1P5DAG3C.EXCHPROD.USA.NET","threadId":"35726","inReplyTo":"20140124090104.GA396@x4","subject":"RE: Globbing for ignored branches?","fromName":"Jim Garrison","fromEmail":"jim.garrison@nwea.org","sentAt":"2014-01-24T16:37:41Z","receivedAt":"2014-01-24T16:37:41Z","isPatch":false,"sender":{"key":"jim.garrison@nwea.org","avatar":null},"body":"> -----Original Message-----\n> Behalf Of Markus Trippelsdorf\n> Sent: Friday, January 24, 2014 1:01 AM\n> Subject: Globbing for ignored branches?\n> \n> I would like to ignore branches that match a certain pattern, e.g.:\n[snip]\n> \n> Is it possible to ignore all branches that match \"hjl\"?\n \n\nIf you mean ignore them when you do \"git branch -a\", then\n\ngit branch -a |grep -v hjl\n\nIf you mean \"ignore\" in some other scenario you need to be more specific about what you want.\n"},{"id":"233698","messageId":"20140124170739.GC396@x4","threadId":"35726","inReplyTo":"0C723FEB5B4E5642B25B451BA57E273075148284@S1P5DAG3C.EXCHPROD.USA.NET","subject":"Re: Globbing for ignored branches?","fromName":"Markus Trippelsdorf","fromEmail":"markus@trippelsdorf.de","sentAt":"2014-01-24T17:07:39Z","receivedAt":"2014-01-24T17:07:39Z","isPatch":false,"sender":{"key":"markus@trippelsdorf.de","avatar":null},"body":"On 2014.01.24 at 16:37 +0000, Jim Garrison wrote:\n> > -----Original Message-----\n> > Behalf Of Markus Trippelsdorf\n> > Sent: Friday, January 24, 2014 1:01 AM\n> > Subject: Globbing for ignored branches?\n> > \n> > I would like to ignore branches that match a certain pattern, e.g.:\n> [snip]\n> > \n> > Is it possible to ignore all branches that match \"hjl\"?\n>  \n> \n> If you mean ignore them when you do \"git branch -a\", then\n> \n> git branch -a |grep -v hjl\n> \n> If you mean \"ignore\" in some other scenario you need to be more\n> specific about what you want.\n\nI want to them when I run \"git pull\".\n\n-- \nMarkus\n"},{"id":"233699","messageId":"20140124170909.GD396@x4","threadId":"35726","inReplyTo":"20140124170739.GC396@x4","subject":"Re: Globbing for ignored branches?","fromName":"Markus Trippelsdorf","fromEmail":"markus@trippelsdorf.de","sentAt":"2014-01-24T17:09:09Z","receivedAt":"2014-01-24T17:09:09Z","isPatch":false,"sender":{"key":"markus@trippelsdorf.de","avatar":null},"body":"On 2014.01.24 at 18:07 +0100, Markus Trippelsdorf wrote:\n> On 2014.01.24 at 16:37 +0000, Jim Garrison wrote:\n> > > -----Original Message-----\n> > > Behalf Of Markus Trippelsdorf\n> > > Sent: Friday, January 24, 2014 1:01 AM\n> > > Subject: Globbing for ignored branches?\n> > > \n> > > I would like to ignore branches that match a certain pattern, e.g.:\n> > [snip]\n> > > \n> > > Is it possible to ignore all branches that match \"hjl\"?\n> >  \n> > \n> > If you mean ignore them when you do \"git branch -a\", then\n> > \n> > git branch -a |grep -v hjl\n> > \n> > If you mean \"ignore\" in some other scenario you need to be more\n> > specific about what you want.\n> \n> I want to them when I run \"git pull\".\n           ignore\n-- \nMarkus\n"},{"id":"233701","messageId":"20140124182341.GB8202@sigill.intra.peff.net","threadId":"35726","inReplyTo":"20140124170909.GD396@x4","subject":"Re: Globbing for ignored branches?","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2014-01-24T18:23:41Z","receivedAt":"2014-01-24T18:23:41Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Fri, Jan 24, 2014 at 06:09:09PM +0100, Markus Trippelsdorf wrote:\n\n> > > If you mean \"ignore\" in some other scenario you need to be more\n> > > specific about what you want.\n> > \n> > I want to them when I run \"git pull\".\n>            ignore\n\nI assume you mean that you do not want to fetch them at all, not that\nyou want to avoid merging them. The set of branches that git fetches is\nconfigured by the fetch \"refspec\" in your config file. It usually looks\nlike this:\n\n  $ git config remote.origin.fetch\n  +refs/heads/*:refs/remotes/origin/*\n\nBut you can specify a specific list of branches you want to fetch\ninstead:\n\n  $ git config --unset remote.origin.fetch\n  $ for i in master other-branch; do\n      git config --add remote.origin.fetch \\\n                       +refs/heads/$i:refs/remotes/origin/$i\n    done\n\nHowever, you do have to specify each branch individually. You probably\nwant to say \"all branches except X\", and you cannot currently specify\na negative refspec like that.\n\n-Peff\n"},{"id":"233702","messageId":"20140124183222.GE396@x4","threadId":"35726","inReplyTo":"20140124182341.GB8202@sigill.intra.peff.net","subject":"Re: Globbing for ignored branches?","fromName":"Markus Trippelsdorf","fromEmail":"markus@trippelsdorf.de","sentAt":"2014-01-24T18:32:22Z","receivedAt":"2014-01-24T18:32:22Z","isPatch":false,"sender":{"key":"markus@trippelsdorf.de","avatar":null},"body":"On 2014.01.24 at 13:23 -0500, Jeff King wrote:\n> On Fri, Jan 24, 2014 at 06:09:09PM +0100, Markus Trippelsdorf wrote:\n> \n> > > > If you mean \"ignore\" in some other scenario you need to be more\n> > > > specific about what you want.\n> > > \n> > > I want to them when I run \"git pull\".\n> >            ignore\n> \n> I assume you mean that you do not want to fetch them at all, not that\n> you want to avoid merging them. The set of branches that git fetches is\n> configured by the fetch \"refspec\" in your config file. It usually looks\n> like this:\n> \n>   $ git config remote.origin.fetch\n>   +refs/heads/*:refs/remotes/origin/*\n> \n> But you can specify a specific list of branches you want to fetch\n> instead:\n> \n>   $ git config --unset remote.origin.fetch\n>   $ for i in master other-branch; do\n>       git config --add remote.origin.fetch \\\n>                        +refs/heads/$i:refs/remotes/origin/$i\n>     done\n> \n> However, you do have to specify each branch individually. You probably\n> want to say \"all branches except X\", and you cannot currently specify\n> a negative refspec like that.\n\nThanks.\nYes, that was the question I wanted to ask (, sorry for not formulating\nit more clearly). \nIs this \"negative refspec for branches\" a feature that is planned for\nthe future?\n\n-- \nMarkus\n"},{"id":"233703","messageId":"20140124185538.GA9836@sigill.intra.peff.net","threadId":"35726","inReplyTo":"20140124183222.GE396@x4","subject":"Re: Globbing for ignored branches?","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2014-01-24T18:55:38Z","receivedAt":"2014-01-24T18:55:38Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Fri, Jan 24, 2014 at 07:32:22PM +0100, Markus Trippelsdorf wrote:\n\n> > However, you do have to specify each branch individually. You probably\n> > want to say \"all branches except X\", and you cannot currently specify\n> > a negative refspec like that.\n> \n> Yes, that was the question I wanted to ask (, sorry for not formulating\n> it more clearly). \n> Is this \"negative refspec for branches\" a feature that is planned for\n> the future?\n\nIt is something that has been talked about before, but I do not think\nanybody is actively working on. It would probably not be too hard a\nfeature if you are interested in getting your feet wet in git\ndevelopment. :)\n\n-Peff\n"},{"id":"233708","messageId":"xmqq4n4trvzj.fsf@gitster.dls.corp.google.com","threadId":"35726","inReplyTo":"20140124185538.GA9836@sigill.intra.peff.net","subject":"Re: Globbing for ignored branches?","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2014-01-24T20:00:16Z","receivedAt":"2014-01-24T20:00:16Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jeff King <peff@peff.net> writes:\n\n> On Fri, Jan 24, 2014 at 07:32:22PM +0100, Markus Trippelsdorf wrote:\n>\n>> > However, you do have to specify each branch individually. You probably\n>> > want to say \"all branches except X\", and you cannot currently specify\n>> > a negative refspec like that.\n>> \n>> Yes, that was the question I wanted to ask (, sorry for not formulating\n>> it more clearly). \n>> Is this \"negative refspec for branches\" a feature that is planned for\n>> the future?\n>\n> It is something that has been talked about before, but I do not think\n> anybody is actively working on. It would probably not be too hard a\n> feature if you are interested in getting your feet wet in git\n> development. :)\n\nThe end result might be not so hard in the mechanical sense, but\ndesigning the interface would be hard.  I do not offhand think of a\ngood way to do this.\n"},{"id":"233716","messageId":"20140124203312.GF396@x4","threadId":"35726","inReplyTo":"xmqq4n4trvzj.fsf@gitster.dls.corp.google.com","subject":"Re: Globbing for ignored branches?","fromName":"Markus Trippelsdorf","fromEmail":"markus@trippelsdorf.de","sentAt":"2014-01-24T20:33:12Z","receivedAt":"2014-01-24T20:33:12Z","isPatch":false,"sender":{"key":"markus@trippelsdorf.de","avatar":null},"body":"On 2014.01.24 at 12:00 -0800, Junio C Hamano wrote:\n> Jeff King <peff@peff.net> writes:\n> \n> > On Fri, Jan 24, 2014 at 07:32:22PM +0100, Markus Trippelsdorf wrote:\n> >\n> >> > However, you do have to specify each branch individually. You probably\n> >> > want to say \"all branches except X\", and you cannot currently specify\n> >> > a negative refspec like that.\n> >> \n> >> Yes, that was the question I wanted to ask (, sorry for not formulating\n> >> it more clearly). \n> >> Is this \"negative refspec for branches\" a feature that is planned for\n> >> the future?\n> >\n> > It is something that has been talked about before, but I do not think\n> > anybody is actively working on. It would probably not be too hard a\n> > feature if you are interested in getting your feet wet in git\n> > development. :)\n> \n> The end result might be not so hard in the mechanical sense, but\n> designing the interface would be hard.  I do not offhand think of a\n> good way to do this.\n\nI don't know if the in-tree regex engine supports negative lookaheads.\nIf it does, then something like the following should work (to use my\n\"hjl\" example):\n\n^(.(?!hjl))*\n\n-- \nMarkus\n"},{"id":"233718","messageId":"xmqqmwilqfcl.fsf@gitster.dls.corp.google.com","threadId":"35726","inReplyTo":"20140124203312.GF396@x4","subject":"Re: Globbing for ignored branches?","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2014-01-24T20:44:58Z","receivedAt":"2014-01-24T20:44:58Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Markus Trippelsdorf <markus@trippelsdorf.de> writes:\n\n> On 2014.01.24 at 12:00 -0800, Junio C Hamano wrote:\n>> Jeff King <peff@peff.net> writes:\n>> \n>> > On Fri, Jan 24, 2014 at 07:32:22PM +0100, Markus Trippelsdorf wrote:\n>> >\n>> >> > However, you do have to specify each branch individually. You probably\n>> >> > want to say \"all branches except X\", and you cannot currently specify\n>> >> > a negative refspec like that.\n>> >> \n>> >> Yes, that was the question I wanted to ask (, sorry for not formulating\n>> >> it more clearly). \n>> >> Is this \"negative refspec for branches\" a feature that is planned for\n>> >> the future?\n>> >\n>> > It is something that has been talked about before, but I do not think\n>> > anybody is actively working on. It would probably not be too hard a\n>> > feature if you are interested in getting your feet wet in git\n>> > development. :)\n>> \n>> The end result might be not so hard in the mechanical sense, but\n>> designing the interface would be hard.  I do not offhand think of a\n>> good way to do this.\n>\n> I don't know if the in-tree regex engine supports negative lookaheads.\n> If it does, then something like the following should work (to use my\n> \"hjl\" example):\n>\n> ^(.(?!hjl))*\n\nrefspec wildcards are *NOT* regular expressions.\n"},{"id":"233719","messageId":"20140124204825.GA17167@sigill.intra.peff.net","threadId":"35726","inReplyTo":"xmqq4n4trvzj.fsf@gitster.dls.corp.google.com","subject":"Re: Globbing for ignored branches?","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2014-01-24T20:48:25Z","receivedAt":"2014-01-24T20:48:25Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Fri, Jan 24, 2014 at 12:00:16PM -0800, Junio C Hamano wrote:\n\n> Jeff King <peff@peff.net> writes:\n> \n> > On Fri, Jan 24, 2014 at 07:32:22PM +0100, Markus Trippelsdorf wrote:\n> >\n> >> > However, you do have to specify each branch individually. You probably\n> >> > want to say \"all branches except X\", and you cannot currently specify\n> >> > a negative refspec like that.\n> [...]\n> The end result might be not so hard in the mechanical sense, but\n> designing the interface would be hard.  I do not offhand think of a\n> good way to do this.\n\nI had imagined a \"not\" token at the front of the refspec, like:\n\n  git fetch origin +refs/heads/*:refs/remotes/origin/* ^refs/heads/foo\n\nIn this case, a colon in the refspec would be an error. An alternative\nwould be:\n\n  git fetch origin +refs/heads/*:refs/remotes/origin/* refs/heads/foo:\n\nI.e., to say \"put foo to nowhere\". But generally refspecs do not affect\neach other. So \"refs/heads/foo:refs/heads/bar\" would generally work _in\naddition_ to the other refspec. Making the \"null destination\" work\ndifferently might be confusing.\n\nI dunno. I have not thought very hard on the topic, so maybe there are\nsome subtle cases I am missing.\n\n-Peff\n"},{"id":"233720","messageId":"20140124205207.GG396@x4","threadId":"35726","inReplyTo":"xmqqmwilqfcl.fsf@gitster.dls.corp.google.com","subject":"Re: Globbing for ignored branches?","fromName":"Markus Trippelsdorf","fromEmail":"markus@trippelsdorf.de","sentAt":"2014-01-24T20:52:07Z","receivedAt":"2014-01-24T20:52:07Z","isPatch":false,"sender":{"key":"markus@trippelsdorf.de","avatar":null},"body":"On 2014.01.24 at 12:44 -0800, Junio C Hamano wrote:\n> Markus Trippelsdorf <markus@trippelsdorf.de> writes:\n> \n> > On 2014.01.24 at 12:00 -0800, Junio C Hamano wrote:\n> >> Jeff King <peff@peff.net> writes:\n> >> \n> >> > On Fri, Jan 24, 2014 at 07:32:22PM +0100, Markus Trippelsdorf wrote:\n> >> >\n> >> >> > However, you do have to specify each branch individually. You probably\n> >> >> > want to say \"all branches except X\", and you cannot currently specify\n> >> >> > a negative refspec like that.\n> >> >> \n> >> >> Yes, that was the question I wanted to ask (, sorry for not formulating\n> >> >> it more clearly). \n> >> >> Is this \"negative refspec for branches\" a feature that is planned for\n> >> >> the future?\n> >> >\n> >> > It is something that has been talked about before, but I do not think\n> >> > anybody is actively working on. It would probably not be too hard a\n> >> > feature if you are interested in getting your feet wet in git\n> >> > development. :)\n> >> \n> >> The end result might be not so hard in the mechanical sense, but\n> >> designing the interface would be hard.  I do not offhand think of a\n> >> good way to do this.\n> >\n> > I don't know if the in-tree regex engine supports negative lookaheads.\n> > If it does, then something like the following should work (to use my\n> > \"hjl\" example):\n> >\n> > ^(.(?!hjl))*\n> \n> refspec wildcards are *NOT* regular expressions.\n\nYes, but that's the point. If they were, the \"negative refspec\"\ninterface issue would be solved.\n\n-- \nMarkus\n"},{"id":"233724","messageId":"xmqqeh3xqe91.fsf@gitster.dls.corp.google.com","threadId":"35726","inReplyTo":"20140124204825.GA17167@sigill.intra.peff.net","subject":"Re: Globbing for ignored branches?","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2014-01-24T21:08:42Z","receivedAt":"2014-01-24T21:08:42Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jeff King <peff@peff.net> writes:\n\n> I had imagined a \"not\" token at the front of the refspec, like:\n>\n>   git fetch origin +refs/heads/*:refs/remotes/origin/* ^refs/heads/foo\n>\n> In this case, a colon in the refspec would be an error. An alternative\n> would be:\n>\n>   git fetch origin +refs/heads/*:refs/remotes/origin/* refs/heads/foo:\n>\n> I.e., to say \"put foo to nowhere\". But generally refspecs do not affect\n> each other.\n\nNot really.  You do not have to view it as \"'not refs/heads/foo' is\naffecting the previous '+refs/heads/*:refs/remotes/origin/*'\".\n\nYou can think of two refspecs \"refs/heads/foo refs/heads/bar\" are\nboth affecting the \"end result\"; so far we only had a single way for\nmultiple refspecs to affect the end result and that was a \"union\".\nIntroducing \"subtract\" as another mode of combining is not too bad,\nI would think, at the conceptual level.\n\n> ... Making the \"null destination\" work\n> differently might be confusing.\n\nI tend to agree that \"refs/heads/foo:\" is being too cute and may be\nconfusing, at least if it will be the only way to express this in\nthe end-user-facing UI.  Even some people were confused enough on a\nvery sensible \"push nothing to ref means deletion\" to make us add\nanother explicit way, \"push --delete\", to ask for the same thing.\n"},{"id":"233739","messageId":"20140125013433.GA22336@sigill.intra.peff.net","threadId":"35726","inReplyTo":"xmqqeh3xqe91.fsf@gitster.dls.corp.google.com","subject":"Re: Globbing for ignored branches?","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2014-01-25T01:34:33Z","receivedAt":"2014-01-25T01:34:33Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Fri, Jan 24, 2014 at 01:08:42PM -0800, Junio C Hamano wrote:\n\n> Not really.  You do not have to view it as \"'not refs/heads/foo' is\n> affecting the previous '+refs/heads/*:refs/remotes/origin/*'\".\n> \n> You can think of two refspecs \"refs/heads/foo refs/heads/bar\" are\n> both affecting the \"end result\"; so far we only had a single way for\n> multiple refspecs to affect the end result and that was a \"union\".\n> Introducing \"subtract\" as another mode of combining is not too bad,\n> I would think, at the conceptual level.\n\nOK, I buy that line of reasoning. I assume that ordering should not\nmatter (that is, we would apply all positive refspecs, and then subtract\nall negative refspecs).\n\nI took a quick look at the refspec code, and how bad it would be to\nimplement this feature. It's rather a bit of a mess. It looks like there\nare three separate code paths to apply refspecs:\n\n  - fetch uses get_ref_map, which calls get_fetch_map for each refspec;\n    each refspec than expands into 0, 1, or multiple refs (if it's a\n    pattern). You can mention a ref multiple times on the LHS of a\n    refspec, and it may be fetched multiple times. After we have the\n    whole list, we detect duplicate destinations, and either drop the\n    duplicates (if all sources are the same) or complain (if there are\n    different sources).\n\n  - push uses match_push_refs, which calls get_ref_match for each ref\n    (not refspec). So the loop is inside-out from fetch, and it looks\n    like we do weird things with multiple matches. We seem to handle\n    multiple explicit matches like:\n\n      $ git push --dry-run tmp master:foo master:bar\n      To tmp\n       * [new branch]      master -> foo\n       * [new branch]      master -> bar\n\n    but we don't seem to do the same for pattern matches:\n\n      $ git push --dry-run tmp refs/heads/*:refs/foo/* \\\n                               refs/heads/*:refs/bar/*\n      To tmp\n       * [new branch]      master -> refs/foo/master\n\n    we just take the first match, even though the two did not conflict.\n    I doubt this comes up that much, but I do not see any reason this\n    should not be doing the same as fetch: apply all refspecs to come up\n    with a complete list, then cull duplicates.\n\n  - @{upstream} uses apply_refspecs to convert a single name. This is\n    also used by transport-helper's fetch_with_import and\n    push_with_import. Which makes me think they do not handle\n    overlapping refspecs at all, unlike the builtin counterparts.\n\n    There is also query_refspecs, which underlies apply_refspecs. I'm\n    not even sure I understand all of the uses there.\n\nThe patch below implements negative refspecs for fetch, but does nothing\nfor push and apply_refspecs (in fact, it probably makes them worse,\nbecause they've learned to parse negative refspecs, but not handle them\nproperly).\n\nThe helpers in the patch could probably be used to build support for the\nother code paths, but it really seems like there could stand to be some\nrefactoring. I'm not sure if I have the time/stomach for it at the\nmoment. But I'll post this here anyway in case somebody else is\ninterested.\n\n> I tend to agree that \"refs/heads/foo:\" is being too cute and may be\n> confusing, at least if it will be the only way to express this in\n> the end-user-facing UI.  Even some people were confused enough on a\n> very sensible \"push nothing to ref means deletion\" to make us add\n> another explicit way, \"push --delete\", to ask for the same thing.\n\nAgreed. I went with \"^refs/heads/master\" in the patch below, but I am\nopen to other suggestions.\n\n---\ndiff --git a/builtin/fetch.c b/builtin/fetch.c\nindex 025bc3e..47f25e9 100644\n--- a/builtin/fetch.c\n+++ b/builtin/fetch.c\n@@ -363,6 +363,8 @@ static struct ref *get_ref_map(struct transport *transport,\n \t\ttail = &rm->next;\n \t}\n \n+\tref_map = apply_negative_refspecs(ref_map, refspecs, refspec_count);\n+\n \treturn ref_remove_duplicates(ref_map);\n }\n \ndiff --git a/remote.c b/remote.c\nindex a89efab..b7b20de 100644\n--- a/remote.c\n+++ b/remote.c\n@@ -16,6 +16,7 @@ static struct refspec s_tag_refspec = {\n \t1,\n \t0,\n \t0,\n+\t0,\n \t\"refs/tags/*\",\n \t\"refs/tags/*\"\n };\n@@ -533,8 +534,14 @@ static struct refspec *parse_refspec_internal(int nr_refspec, const char **refsp\n \t\t\trs[i].force = 1;\n \t\t\tlhs++;\n \t\t}\n+\t\telse if (*lhs == '^') {\n+\t\t\trs[i].negative = 1;\n+\t\t\tlhs++;\n+\t\t}\n \n \t\trhs = strrchr(lhs, ':');\n+\t\tif (rs[i].negative && rhs)\n+\t\t\tgoto invalid;\n \n \t\t/*\n \t\t * Before going on, special case \":\" (or \"+:\") as a refspec\n@@ -1663,6 +1670,9 @@ int get_fetch_map(const struct ref *remote_refs,\n {\n \tstruct ref *ref_map, **rmp;\n \n+\tif (refspec->negative)\n+\t\treturn 0;\n+\n \tif (refspec->pattern) {\n \t\tref_map = get_expanded_map(remote_refs, refspec);\n \t} else {\n@@ -1705,6 +1715,48 @@ int get_fetch_map(const struct ref *remote_refs,\n \treturn 0;\n }\n \n+static int refspec_match(const struct refspec *refspec,\n+\t\t\t const char *name)\n+{\n+\tif (refspec->pattern)\n+\t\treturn match_name_with_pattern(refspec->src, name, NULL, NULL);\n+\n+\treturn !strcmp(refspec->src, name);\n+}\n+\n+static int omit_name_by_refspec(const char *name,\n+\t\t\t\tconst struct refspec *refspecs,\n+\t\t\t\tint nr_refspec)\n+{\n+\tint i;\n+\n+\tfor (i = 0; i < nr_refspec; i++) {\n+\t\tif (refspecs[i].negative && refspec_match(&refspecs[i], name))\n+\t\t\treturn 1;\n+\t}\n+\treturn 0;\n+}\n+\n+struct ref *apply_negative_refspecs(struct ref *ref_map,\n+\t\t\t\t    const struct refspec *refspecs,\n+\t\t\t\t    int nr_refspec)\n+{\n+\tstruct ref **tail;\n+\n+\tfor (tail = &ref_map; *tail; ) {\n+\t\tstruct ref *ref = *tail;\n+\n+\t\tif (omit_name_by_refspec(ref->name, refspecs, nr_refspec)) {\n+\t\t\t*tail = ref->next;\n+\t\t\tfree(ref->peer_ref);\n+\t\t\tfree(ref);\n+\t\t} else\n+\t\t\ttail = &ref->next;\n+\t}\n+\n+\treturn ref_map;\n+}\n+\n int resolve_remote_symref(struct ref *ref, struct ref *list)\n {\n \tif (!ref->symref)\ndiff --git a/remote.h b/remote.h\nindex fb7647f..534d365 100644\n--- a/remote.h\n+++ b/remote.h\n@@ -67,6 +67,7 @@ struct refspec {\n \tunsigned pattern : 1;\n \tunsigned matching : 1;\n \tunsigned exact_sha1 : 1;\n+\tunsigned negative : 1;\n \n \tchar *src;\n \tchar *dst;\n@@ -157,6 +158,10 @@ int ref_newer(const unsigned char *new_sha1, const unsigned char *old_sha1);\n  */\n struct ref *ref_remove_duplicates(struct ref *ref_map);\n \n+struct ref *apply_negative_refspecs(struct ref *ref_map,\n+\t\t\t\t    const struct refspec *refspecs,\n+\t\t\t\t    int nr_refspecs);\n+\n int valid_fetch_refspec(const char *refspec);\n struct refspec *parse_fetch_refspec(int nr_refspec, const char **refspec);\n \n"},{"id":"233750","messageId":"20140125141542.GA402@x4","threadId":"35726","inReplyTo":"20140125013433.GA22336@sigill.intra.peff.net","subject":"Re: Globbing for ignored branches?","fromName":"Markus Trippelsdorf","fromEmail":"markus@trippelsdorf.de","sentAt":"2014-01-25T14:15:42Z","receivedAt":"2014-01-25T14:15:42Z","isPatch":false,"sender":{"key":"markus@trippelsdorf.de","avatar":null},"body":"On 2014.01.24 at 20:34 -0500, Jeff King wrote:\n> On Fri, Jan 24, 2014 at 01:08:42PM -0800, Junio C Hamano wrote:\n> \n> > Not really.  You do not have to view it as \"'not refs/heads/foo' is\n> > affecting the previous '+refs/heads/*:refs/remotes/origin/*'\".\n> > \n> > You can think of two refspecs \"refs/heads/foo refs/heads/bar\" are\n> > both affecting the \"end result\"; so far we only had a single way for\n> > multiple refspecs to affect the end result and that was a \"union\".\n> > Introducing \"subtract\" as another mode of combining is not too bad,\n> > I would think, at the conceptual level.\n> \n> > I tend to agree that \"refs/heads/foo:\" is being too cute and may be\n> > confusing, at least if it will be the only way to express this in\n> > the end-user-facing UI.  Even some people were confused enough on a\n> > very sensible \"push nothing to ref means deletion\" to make us add\n> > another explicit way, \"push --delete\", to ask for the same thing.\n> \n> Agreed. I went with \"^refs/heads/master\" in the patch below, but I am\n> open to other suggestions.\n\nMany thanks for the patch. It seems to work as advertised, but only if\nthe negative refspec appears on a separate line. For example:\n\n[remote \"origin\"]\n        url = git://gcc.gnu.org/git/gcc.git\n        fetch = +refs/heads/*:refs/remotes/origin/*\n        fetch = ^refs/remotes/hjl\n\nworks fine, but:\n\n[remote \"origin\"]\n        url = git://gcc.gnu.org/git/gcc.git\n        fetch = +refs/heads/*:refs/remotes/origin/* ^refs/remotes/hjl \n\ndoesn't. (I think this happens because bad_ref_char in refs.c checks for '^'.)\n\n-- \nMarkus\n"},{"id":"233751","messageId":"20140125171548.GB402@x4","threadId":"35726","inReplyTo":"20140125141542.GA402@x4","subject":"Re: Globbing for ignored branches?","fromName":"Markus Trippelsdorf","fromEmail":"markus@trippelsdorf.de","sentAt":"2014-01-25T17:15:48Z","receivedAt":"2014-01-25T17:15:48Z","isPatch":false,"sender":{"key":"markus@trippelsdorf.de","avatar":null},"body":"On 2014.01.25 at 15:15 +0100, Markus Trippelsdorf wrote:\n> On 2014.01.24 at 20:34 -0500, Jeff King wrote:\n> > On Fri, Jan 24, 2014 at 01:08:42PM -0800, Junio C Hamano wrote:\n> > \n> > > Not really.  You do not have to view it as \"'not refs/heads/foo' is\n> > > affecting the previous '+refs/heads/*:refs/remotes/origin/*'\".\n> > > \n> > > You can think of two refspecs \"refs/heads/foo refs/heads/bar\" are\n> > > both affecting the \"end result\"; so far we only had a single way for\n> > > multiple refspecs to affect the end result and that was a \"union\".\n> > > Introducing \"subtract\" as another mode of combining is not too bad,\n> > > I would think, at the conceptual level.\n> > \n> > > I tend to agree that \"refs/heads/foo:\" is being too cute and may be\n> > > confusing, at least if it will be the only way to express this in\n> > > the end-user-facing UI.  Even some people were confused enough on a\n> > > very sensible \"push nothing to ref means deletion\" to make us add\n> > > another explicit way, \"push --delete\", to ask for the same thing.\n> > \n> > Agreed. I went with \"^refs/heads/master\" in the patch below, but I am\n> > open to other suggestions.\n> \n> Many thanks for the patch. It seems to work as advertised, but only if\n> the negative refspec appears on a separate line. For example:\n\nI've posted a wrong negative refspec. Sorry. Correction below.\n\n> [remote \"origin\"]\n>         url = git://gcc.gnu.org/git/gcc.git\n>         fetch = +refs/heads/*:refs/remotes/origin/*\n>         fetch = ^refs/remotes/hjl\n          fetch = ^refs/remotes/origin/hjl\n\n> works fine, but:\n> \n> [remote \"origin\"]\n>         url = git://gcc.gnu.org/git/gcc.git\n>         fetch = +refs/heads/*:refs/remotes/origin/* ^refs/remotes/hjl \n          fetch = +refs/heads/*:refs/remotes/origin/* ^refs/remotes/origin/hjl\n\n> doesn't. (I think this happens because bad_ref_char in refs.c checks for '^'.)\n\n-- \nMarkus\n"},{"id":"233756","messageId":"20140125200217.GA5608@sigill.intra.peff.net","threadId":"35726","inReplyTo":"20140125141542.GA402@x4","subject":"Re: Globbing for ignored branches?","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2014-01-25T20:02:17Z","receivedAt":"2014-01-25T20:02:17Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Sat, Jan 25, 2014 at 03:15:42PM +0100, Markus Trippelsdorf wrote:\n\n> Many thanks for the patch. It seems to work as advertised, but only if\n> the negative refspec appears on a separate line. For example:\n> \n> [remote \"origin\"]\n>         url = git://gcc.gnu.org/git/gcc.git\n>         fetch = +refs/heads/*:refs/remotes/origin/*\n>         fetch = ^refs/remotes/hjl\n> \n> works fine, but:\n> \n> [remote \"origin\"]\n>         url = git://gcc.gnu.org/git/gcc.git\n>         fetch = +refs/heads/*:refs/remotes/origin/* ^refs/remotes/hjl \n\nThat does not have anything to do with the negative refspec. The config\nformat is one refspec per \"fetch\" key, but you may have as many keys as\nyou like. Doing:\n\n  [remote \"origin\"]\n  fetch = refs/heads/a:refs/heads/a refs/heads/b:refs/heads/b\n\nis similarly wrong. You need to do:\n\n  [remote \"origin\"]\n  fetch = refs/heads/a:refs/heads/a\n  fetch = refs/heads/b:refs/heads/b\n\ninstead.  I believe that since space is forbidden in refnames, it should\nalso be forbidden in refspecs, which means that we could interpret the\nfirst one as you expected without losing backwards compatibility. But I\ndo not think there is any real advantage to doing so, aside from being\nmore forgiving. I suspect the documentation in that area could be\nimproved, though.\n\n-Peff\n"}]}