Globbing for ignored branches?
I would like to ignore branches that match a certain pattern, e.g.:
markus@x4 gcc % git branch -a
gcc-4.8
* master
remotes/origin/HEAD -> origin/master
remotes/origin/aldyh/cilk-in-gomp
...
remotes/origin/hjl/arch
remotes/origin/hjl/asan
...
remotes/origin/hjl/x86/m16
remotes/origin/ifunc
remotes/origin/jason/4.6-cxx0x
remotes/origin/jason/alias-decl
remotes/origin/jason/comdat-debug
remotes/origin/lw-ipo
remotes/origin/master
...
Is it possible to ignore all branches that match "hjl"?
Signature · 1 line
Markus
Quoted 6 lines
-----Original Message-----
Behalf Of Markus Trippelsdorf
Sent: Friday, January 24, 2014 1:01 AM
Subject: Globbing for ignored branches?I would like to ignore branches that match a certain pattern, e.g.:
[snip]
Quoted 2 lines
Is it possible to ignore all branches that match "hjl"?
If you mean ignore them when you do "git branch -a", then
git branch -a |grep -v hjl
If you mean "ignore" in some other scenario you need to be more specific about what you want.
Quoted 11 lines · Jim Garrison
Quoted 6 lines
-----Original Message-----
Behalf Of Markus Trippelsdorf
Sent: Friday, January 24, 2014 1:01 AM
Subject: Globbing for ignored branches?I would like to ignore branches that match a certain pattern, e.g.:
[snip]
Quoted 2 lines
Is it possible to ignore all branches that match "hjl"?
Quoted 6 lines
If you mean ignore them when you do "git branch -a", then
git branch -a |grep -v hjl
If you mean "ignore" in some other scenario you need to be more specific about what you want.
I want to them when I run "git pull".
Signature · 1 line
Markus
Quoted 12 lines · Markus Trippelsdorf
Quoted 11 lines · Jim Garrison
Quoted 6 lines
-----Original Message-----
Behalf Of Markus Trippelsdorf
Sent: Friday, January 24, 2014 1:01 AM
Subject: Globbing for ignored branches?I would like to ignore branches that match a certain pattern, e.g.:
[snip]
Quoted 2 lines
Is it possible to ignore all branches that match "hjl"?
Quoted 8 lines
Quoted 6 lines
If you mean ignore them when you do "git branch -a", then
git branch -a |grep -v hjl
If you mean "ignore" in some other scenario you need to be more specific about what you want.
I want to them when I run "git pull".
ignore
Signature · 1 line
Markus
Quoted 5 lines · Markus Trippelsdorf
Quoted 4 lines
Quoted 2 lines
If you mean "ignore" in some other scenario you need to be more specific about what you want.
I want to them when I run "git pull".
ignore
I assume you mean that you do not want to fetch them at all, not that you want to avoid merging them. The set of branches that git fetches is configured by the fetch "refspec" in your config file. It usually looks like this:
$ git config remote.origin.fetch +refs/heads/*:refs/remotes/origin/*
But you can specify a specific list of branches you want to fetch instead:
$ git config --unset remote.origin.fetch
$ for i in master other-branch; do
git config --add remote.origin.fetch \
+refs/heads/$i:refs/remotes/origin/$i
doneHowever, you do have to specify each branch individually. You probably want to say "all branches except X", and you cannot currently specify a negative refspec like that.
-Peff
Quoted 25 lines · Jeff King
Quoted 5 lines · Markus Trippelsdorf
Quoted 4 lines
Quoted 2 lines
If you mean "ignore" in some other scenario you need to be more specific about what you want.
I want to them when I run "git pull".
ignore
I assume you mean that you do not want to fetch them at all, not that you want to avoid merging them. The set of branches that git fetches is configured by the fetch "refspec" in your config file. It usually looks like this:
$ git config remote.origin.fetch +refs/heads/*:refs/remotes/origin/*But you can specify a specific list of branches you want to fetch instead:
$ git config --unset remote.origin.fetch $ for i in master other-branch; do git config --add remote.origin.fetch \ +refs/heads/$i:refs/remotes/origin/$i done
Quoted 3 lines
However, you do have to specify each branch individually. You probably want to say "all branches except X", and you cannot currently specify a negative refspec like that.
Thanks.
Yes, that was the question I wanted to ask (, sorry for not formulating it more clearly).
Is this "negative refspec for branches" a feature that is planned for the future?
Signature · 1 line
Markus
Quoted 8 lines · Markus Trippelsdorf
Quoted 3 lines
However, you do have to specify each branch individually. You probably want to say "all branches except X", and you cannot currently specify a negative refspec like that.
Yes, that was the question I wanted to ask (, sorry for not formulating it more clearly).
Is this "negative refspec for branches" a feature that is planned for the future?
It is something that has been talked about before, but I do not think anybody is actively working on. It would probably not be too hard a feature if you are interested in getting your feet wet in git development. :)
-Peff
Quoted 11 lines · Jeff King
Quoted 8 lines · Markus Trippelsdorf
Quoted 3 lines
However, you do have to specify each branch individually. You probably want to say "all branches except X", and you cannot currently specify a negative refspec like that.
Yes, that was the question I wanted to ask (, sorry for not formulating it more clearly).
Is this "negative refspec for branches" a feature that is planned for the future?
Quoted 4 lines
It is something that has been talked about before, but I do not think anybody is actively working on. It would probably not be too hard a feature if you are interested in getting your feet wet in git development. :)
The end result might be not so hard in the mechanical sense, but designing the interface would be hard. I do not offhand think of a good way to do this.
Quoted 13 lines · Junio C Hamano
Quoted 11 lines · Jeff King
Quoted 8 lines · Markus Trippelsdorf
Quoted 3 lines
However, you do have to specify each branch individually. You probably want to say "all branches except X", and you cannot currently specify a negative refspec like that.
Yes, that was the question I wanted to ask (, sorry for not formulating it more clearly).
Is this "negative refspec for branches" a feature that is planned for the future?
Quoted 8 lines
Quoted 4 lines
It is something that has been talked about before, but I do not think anybody is actively working on. It would probably not be too hard a feature if you are interested in getting your feet wet in git development. :)
The end result might be not so hard in the mechanical sense, but designing the interface would be hard. I do not offhand think of a good way to do this.
I don't know if the in-tree regex engine supports negative lookaheads. If it does, then something like the following should work (to use my "hjl" example):
^(.(?!hjl))*
Signature · 1 line
Markus
Quoted 23 lines · Markus Trippelsdorf
Quoted 13 lines · Junio C Hamano
Quoted 11 lines · Jeff King
Quoted 8 lines · Markus Trippelsdorf
Quoted 3 lines
However, you do have to specify each branch individually. You probably want to say "all branches except X", and you cannot currently specify a negative refspec like that.
Yes, that was the question I wanted to ask (, sorry for not formulating it more clearly).
Is this "negative refspec for branches" a feature that is planned for the future?Quoted 8 lines
Quoted 4 lines
It is something that has been talked about before, but I do not think anybody is actively working on. It would probably not be too hard a feature if you are interested in getting your feet wet in git development. :)
The end result might be not so hard in the mechanical sense, but designing the interface would be hard. I do not offhand think of a good way to do this.
Quoted 5 lines
I don't know if the in-tree regex engine supports negative lookaheads. If it does, then something like the following should work (to use my "hjl" example):
^(.(?!hjl))*
refspec wildcards are *NOT* regular expressions.
Quoted 25 lines · Junio C Hamano
Quoted 23 lines · Markus Trippelsdorf
Quoted 21 lines · Junio C Hamano
Quoted 11 lines · Jeff King
Quoted 8 lines · Markus Trippelsdorf
Quoted 3 lines
However, you do have to specify each branch individually. You probably want to say "all branches except X", and you cannot currently specify a negative refspec like that.
Yes, that was the question I wanted to ask (, sorry for not formulating it more clearly).
Is this "negative refspec for branches" a feature that is planned for the future?Quoted 4 lines
It is something that has been talked about before, but I do not think anybody is actively working on. It would probably not be too hard a feature if you are interested in getting your feet wet in git development. :)
The end result might be not so hard in the mechanical sense, but designing the interface would be hard. I do not offhand think of a good way to do this.
Quoted 7 lines
Quoted 5 lines
I don't know if the in-tree regex engine supports negative lookaheads. If it does, then something like the following should work (to use my "hjl" example):
^(.(?!hjl))*
refspec wildcards are *NOT* regular expressions.
Yes, but that's the point. If they were, the "negative refspec" interface issue would be solved.
Signature · 1 line
Markus
Quoted 11 lines · Junio C Hamano
Quoted 5 lines · Jeff King
Quoted 3 lines · Markus Trippelsdorf
Quoted 3 lines
However, you do have to specify each branch individually. You probably want to say "all branches except X", and you cannot currently specify a negative refspec like that.
[...]
The end result might be not so hard in the mechanical sense, but designing the interface would be hard. I do not offhand think of a good way to do this.
I had imagined a "not" token at the front of the refspec, like:
git fetch origin +refs/heads/*:refs/remotes/origin/* ^refs/heads/foo
In this case, a colon in the refspec would be an error. An alternative would be:
git fetch origin +refs/heads/*:refs/remotes/origin/* refs/heads/foo:
I.e., to say "put foo to nowhere". But generally refspecs do not affect each other. So "refs/heads/foo:refs/heads/bar" would generally work _in addition_ to the other refspec. Making the "null destination" work differently might be confusing.
I dunno. I have not thought very hard on the topic, so maybe there are some subtle cases I am missing.
-Peff
Quoted 11 lines · Jeff King
I had imagined a "not" token at the front of the refspec, like:
git fetch origin +refs/heads/*:refs/remotes/origin/* ^refs/heads/foo
In this case, a colon in the refspec would be an error. An alternative would be:
git fetch origin +refs/heads/*:refs/remotes/origin/* refs/heads/foo:
I.e., to say "put foo to nowhere". But generally refspecs do not affect each other.
Not really. You do not have to view it as "'not refs/heads/foo' is affecting the previous '+refs/heads/*:refs/remotes/origin/*'".
You can think of two refspecs "refs/heads/foo refs/heads/bar" are both affecting the "end result"; so far we only had a single way for multiple refspecs to affect the end result and that was a "union". Introducing "subtract" as another mode of combining is not too bad, I would think, at the conceptual level.
Quoted 2 lines
... Making the "null destination" work
differently might be confusing.
I tend to agree that "refs/heads/foo:" is being too cute and may be confusing, at least if it will be the only way to express this in the end-user-facing UI. Even some people were confused enough on a very sensible "push nothing to ref means deletion" to make us add another explicit way, "push --delete", to ask for the same thing.
Quoted 8 lines · Junio C Hamano
Not really. You do not have to view it as "'not refs/heads/foo' is affecting the previous '+refs/heads/*:refs/remotes/origin/*'".
You can think of two refspecs "refs/heads/foo refs/heads/bar" are both affecting the "end result"; so far we only had a single way for multiple refspecs to affect the end result and that was a "union". Introducing "subtract" as another mode of combining is not too bad, I would think, at the conceptual level.
OK, I buy that line of reasoning. I assume that ordering should not matter (that is, we would apply all positive refspecs, and then subtract all negative refspecs).
I took a quick look at the refspec code, and how bad it would be to implement this feature. It's rather a bit of a mess. It looks like there are three separate code paths to apply refspecs:
- fetch uses get_ref_map, which calls get_fetch_map for each refspec; each refspec than expands into 0, 1, or multiple refs (if it's a pattern). You can mention a ref multiple times on the LHS of a refspec, and it may be fetched multiple times. After we have the whole list, we detect duplicate destinations, and either drop the duplicates (if all sources are the same) or complain (if there are different sources).
- push uses match_push_refs, which calls get_ref_match for each ref (not refspec). So the loop is inside-out from fetch, and it looks like we do weird things with multiple matches. We seem to handle multiple explicit matches like:
$ git push --dry-run tmp master:foo master:bar To tmp
* [new branch] master -> foo
* [new branch] master -> bar
but we don't seem to do the same for pattern matches:
$ git push --dry-run tmp refs/heads/*:refs/foo/* \
refs/heads/*:refs/bar/*
To tmp
* [new branch] master -> refs/foo/master
we just take the first match, even though the two did not conflict. I doubt this comes up that much, but I do not see any reason this should not be doing the same as fetch: apply all refspecs to come up with a complete list, then cull duplicates.
- @{upstream} uses apply_refspecs to convert a single name. This is also used by transport-helper's fetch_with_import and push_with_import. Which makes me think they do not handle overlapping refspecs at all, unlike the builtin counterparts.
There is also query_refspecs, which underlies apply_refspecs. I'm not even sure I understand all of the uses there.
The patch below implements negative refspecs for fetch, but does nothing for push and apply_refspecs (in fact, it probably makes them worse, because they've learned to parse negative refspecs, but not handle them properly).
The helpers in the patch could probably be used to build support for the other code paths, but it really seems like there could stand to be some refactoring. I'm not sure if I have the time/stomach for it at the moment. But I'll post this here anyway in case somebody else is interested.
Quoted 5 lines
I tend to agree that "refs/heads/foo:" is being too cute and may be confusing, at least if it will be the only way to express this in the end-user-facing UI. Even some people were confused enough on a very sensible "push nothing to ref means deletion" to make us add another explicit way, "push --delete", to ask for the same thing.
Agreed. I went with "^refs/heads/master" in the patch below, but I am open to other suggestions.
---
builtin/fetch.c +2 -0
@@ -363,6 +363,8 @@ static struct ref *get_ref_map(struct transport *transport, tail = &rm->next; } + ref_map =apply_negative_refspecs (ref_map, refspecs, refspec_count); +return ref_remove_duplicates (ref_map); }
remote.c +52 -0
78 lines not on this page · raw message
remote.h +5 -0
@@ -67,6 +67,7 @@ struct refspec { unsigned pattern : 1; unsigned matching : 1; unsigned exact_sha1 : 1; + unsigned negative : 1;char *src;char *dst;
@@ -157,6 +158,10 @@ int ref_newer(const unsigned char *new_sha1, const unsigned char *old_sha1);*/ struct ref *ref_remove_duplicates (struct ref *ref_map); +struct ref *apply_negative_refspecs (struct ref *ref_map, +const struct refspec *refspecs, +int nr_refspecs); +int valid_fetch_refspec (const char *refspec);struct refspec *parse_fetch_refspec (int nr_refspec,const char **refspec);
Quoted 11 lines · Jeff King
Quoted 8 lines · Junio C Hamano
Not really. You do not have to view it as "'not refs/heads/foo' is affecting the previous '+refs/heads/*:refs/remotes/origin/*'".
You can think of two refspecs "refs/heads/foo refs/heads/bar" are both affecting the "end result"; so far we only had a single way for multiple refspecs to affect the end result and that was a "union". Introducing "subtract" as another mode of combining is not too bad, I would think, at the conceptual level.
Quoted 8 lines
Quoted 5 lines
I tend to agree that "refs/heads/foo:" is being too cute and may be confusing, at least if it will be the only way to express this in the end-user-facing UI. Even some people were confused enough on a very sensible "push nothing to ref means deletion" to make us add another explicit way, "push --delete", to ask for the same thing.
Agreed. I went with "^refs/heads/master" in the patch below, but I am open to other suggestions.
Many thanks for the patch. It seems to work as advertised, but only if the negative refspec appears on a separate line. For example:
[remote "origin"]
url = git://gcc.gnu.org/git/gcc.git
fetch = +refs/heads/*:refs/remotes/origin/* fetch = ^refs/remotes/hjl
works fine, but:
[remote "origin"]
url = git://gcc.gnu.org/git/gcc.git
fetch = +refs/heads/*:refs/remotes/origin/* ^refs/remotes/hjl
doesn't. (I think this happens because bad_ref_char in refs.c checks for '^'.)
Signature · 1 line
Markus
Quoted 18 lines · Markus Trippelsdorf
Quoted 17 lines · Jeff King
Quoted 14 lines · Junio C Hamano
Not really. You do not have to view it as "'not refs/heads/foo' is affecting the previous '+refs/heads/*:refs/remotes/origin/*'".
You can think of two refspecs "refs/heads/foo refs/heads/bar" are both affecting the "end result"; so far we only had a single way for multiple refspecs to affect the end result and that was a "union". Introducing "subtract" as another mode of combining is not too bad, I would think, at the conceptual level.
I tend to agree that "refs/heads/foo:" is being too cute and may be confusing, at least if it will be the only way to express this in the end-user-facing UI. Even some people were confused enough on a very sensible "push nothing to ref means deletion" to make us add another explicit way, "push --delete", to ask for the same thing.
Quoted 5 lines
Quoted 2 lines
Agreed. I went with "^refs/heads/master" in the patch below, but I am open to other suggestions.
Many thanks for the patch. It seems to work as advertised, but only if the negative refspec appears on a separate line. For example:
I've posted a wrong negative refspec. Sorry. Correction below.
Quoted 4 lines
[remote "origin"]
url =git://gcc.gnu.org/git/gcc.git
fetch = +refs/heads/*:refs/remotes/origin/* fetch = ^refs/remotes/hjl
fetch = ^refs/remotes/origin/hjl
Quoted 5 lines
works fine, but:
[remote "origin"]
url =git://gcc.gnu.org/git/gcc.git
fetch = +refs/heads/*:refs/remotes/origin/* ^refs/remotes/hjl
fetch = +refs/heads/*:refs/remotes/origin/* ^refs/remotes/origin/hjl
Quoted 1 line
doesn't. (I think this happens because
bad_ref_charinrefs.cchecks for '^'.)
Signature · 1 line
Markus
Quoted 8 lines · Markus Trippelsdorf
Many thanks for the patch. It seems to work as advertised, but only if the negative refspec appears on a separate line. For example:
[remote "origin"]
url =git://gcc.gnu.org/git/gcc.git
fetch = +refs/heads/*:refs/remotes/origin/* fetch = ^refs/remotes/hjl
Quoted 5 lines
works fine, but:
[remote "origin"]
url =git://gcc.gnu.org/git/gcc.git
fetch = +refs/heads/*:refs/remotes/origin/* ^refs/remotes/hjl
That does not have anything to do with the negative refspec. The config format is one refspec per "fetch" key, but you may have as many keys as you like. Doing:
[remote "origin"]
fetch = refs/heads/a:refs/heads/a refs/heads/b:refs/heads/b
is similarly wrong. You need to do:
[remote "origin"]
fetch = refs/heads/a:refs/heads/a
fetch = refs/heads/b:refs/heads/b
instead. I believe that since space is forbidden in refnames, it should also be forbidden in refspecs, which means that we could interpret the first one as you expected without losing backwards compatibility. But I do not think there is any real advantage to doing so, aside from being more forgiving. I suspect the documentation in that area could be improved, though.
-Peff