On 02/13/2012 07:37 AM, Junio C Hamano wrote: > Michael Haggerty <mhagger@xxxxxxxxxxxx> writes: > >> Of *course* they operate on different namespaces. But part of the way >> that revisions are selected using rev-list is by *selecting or excluding >> refnames* from which it should crawl. > > I am appalled if that is truly the understanding of yours, after having > taken more than a few patches from you to fairly core parts of Git. > > "rev-list A ^B" does not say "include A and exclude B from which rev-list > should crawl" AT ALL. We _actively_ crawl from both A and B. It is that > what are reachable from B is painted in a color different from the color > in which we paint what are reachable from A. Please read my emails more carefully before insulting me. It is perfectly clear to me that there are two types of exclusion that we are talking about. And *both* of them are (or should be) relevant to rev-parse. Take the following repository with three branches: o---o---o---o A \ \ \ o---o C \ o---o B If I do "git rev-list A B ^C" then I get the commits marked "*" in the following diagram o---o---o---* A \ \ \ o---o C \ *---* B By excluding C I have necessarily excluded a part of the history of A and B. If we assume that the proposed feature is implemented and I do "git rev-list $(git for-each-ref --format='%(refname)' A B ^C)", then I get something different: *---*---*---* A \ \ \ o---o C \ *---* B I argue that this is a useful selection. For example, maybe I want to remove the clutter of branch C from my view, but I still want to see the *whole* history of branches A and B. The middle selection doesn't do it. Obviously this is not really necessary if there are only three branches, but if there are dozens, and if A, B, and C are patterns rather than literal branch names, then it can be very convenient. For example, suppose I want to see the status of all of my submissions in your repository in the context of your main branches plus my local branches. It would be great to be able to type gitk --with-branch='refs/heads/*' \ --with-branch='remotes/gitster/*' \ --without-branch='remotes/gitster/*/**' \ --with-branch='remotes/gitster/mh/*' I don't know of a way to do that now. > A better pair you could have mentioned would be for-each-ref vs rev-parse > (not rev-list). What Tom wanted with "do not show the refs that match the > pattern" he originally wanted to give to "tag --list" would be > > for-each-ref A ^B > > that is "show ref that matches A but do not show if it also matches B", > while what you want to say is "I want to paint A in positive color and > paint B in negative color, and I want to get a canonical notation to do > so", it is spelled with rev-parse, not for-each-ref, like this: > > rev-parse A ^B That's not what I want; see above. > In other words, > > git rev-list $(git rev-parse A ^B) > > would be the equivalent to "git rev-list A ^B". > > Maybe you are troubled that there are multiple concepts of negation, which > ultimately comes from the undeniable fact that for-each-ref and rev-parse > operate on entities in different concept domain (refnames and objects)? > And if we decide to use "^", then these two different concepts of negation > are both expressed with the same operator "prefix ^", leading to > confusion? Not only that, but also that both concepts of negation are interesting and useful within "git rev-list", and therefore we should make them *combinable*. To be very explicit, I advocate: 1. Implement an explicit syntax for "do not include references matching this pattern in a list of references". Implement this syntax in for-each-ref; something like --with-ref=PATTERN / --without-ref=PATTERN --with-branch=PATTERN / --without-branch=PATTERN --with-tag=PATTERN / --without-tag=PATTERN --with-remote=PATTERN / --without-remote=PATTERN The point of having multiple with/without pairs would be that the first would match full refnames explicitly (i.e., the pattern would usually start with "refs/"), whereas the other pairs would implicitly prepend "refs/heads/", "refs/tags/", or "refs/remotes/", respectively, to the pattern for convenience. There should also be an "--all" option that is equivalent to "--with-ref=**". The output from for-each-ref would essentially be a *list of positive references* matching the criteria. In other words, "--without-branch=foo" would cause "refs/heads/foo" to be *excluded* from the output altogether, *not* included as "^refs/heads/foo". The order of the options should be significant, with the last matching pattern winning. 2. The pattern matching of refnames should be like fnmatch, with the addition of "**" as a wildcard meaning "any characters, including '/'". 3. Other reference-listing commands should take the same options as appropriate; for example, "git branch --list" would take --with(out)?-branch and --with(out)?-remote (and maybe --with(out)?-ref); "git tag --list" would take --with(out)?-tag (and maybe --with(out)?-ref), etc. 4. The *exact same options* should be added to rev-list, and would effectively be expanded into a list of positive references; e.g., git rev-list --with-branch=A --with-branch=B --without-branch=C would be equivalent to git rev-list $(git for-each-ref --format='%(refname)' --with-branch=A --with-branch=B --without-branch=C) If A, B, and C happen to be branch names rather than patterns, the above would be equivalent to git rev-list refs/heads/A refs/heads/B Note that this *differs* (in a useful way!) from git rev-list refs/heads/A refs/heads/B --not refs/heads/C or git rev-list refs/heads/A refs/heads/B ^refs/heads/C which are useful in other scenarios and whose meanings we would of course retain. If "--not" is used in git-rev-list, it would demarcate groups of options that are passed separately to for-each-ref; for example, git rev-list --all --with-branch=A --without-branch=B \ --not --with-branch=C --without-branch=D would be equivalent to git rev-list $(git for-each-ref --format='%(refname)' --all --with-branch=A --without-branch=B)\ --not $(git for-each-ref --format='%(refname)' --with-branch=C --without-branch=D) Michael -- Michael Haggerty mhagger@xxxxxxxxxxxx http://softwareswirl.blogspot.com/ -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html