* [PATCH (resend) 0/3] Minor f-e-r enhacements @ 2013-10-31 9:46 Ramkumar Ramachandra 2013-10-31 9:46 ` [PATCH 1/3] for-each-ref: introduce %C(...) for color Ramkumar Ramachandra ` (2 more replies) 0 siblings, 3 replies; 25+ messages in thread From: Ramkumar Ramachandra @ 2013-10-31 9:46 UTC (permalink / raw) To: Git List Hi, I've been running git with these patches applied locally for a long time. Although I've sent them to the list before, they've been overlooked. Thanks. Ramkumar Ramachandra (3): for-each-ref: introduce %C(...) for color for-each-ref: introduce %(HEAD) asterisk marker for-each-ref: introduce %(upstream:track[short]) Documentation/git-for-each-ref.txt | 14 ++++++- builtin/for-each-ref.c | 75 ++++++++++++++++++++++++++++++++++---- 2 files changed, 79 insertions(+), 10 deletions(-) -- 1.8.5.rc0.3.gb488857 ^ permalink raw reply [flat|nested] 25+ messages in thread
* [PATCH 1/3] for-each-ref: introduce %C(...) for color 2013-10-31 9:46 [PATCH (resend) 0/3] Minor f-e-r enhacements Ramkumar Ramachandra @ 2013-10-31 9:46 ` Ramkumar Ramachandra 2013-10-31 20:50 ` Junio C Hamano 2013-10-31 9:46 ` [PATCH 2/3] for-each-ref: introduce %(HEAD) asterisk marker Ramkumar Ramachandra 2013-10-31 9:46 ` [PATCH 3/3] for-each-ref: introduce %(upstream:track[short]) Ramkumar Ramachandra 2 siblings, 1 reply; 25+ messages in thread From: Ramkumar Ramachandra @ 2013-10-31 9:46 UTC (permalink / raw) To: Git List Enhance 'git for-each-ref' with color formatting options. You can now use the following format in for-each-ref: %C(green)%(refname:short)%C(reset) Signed-off-by: Ramkumar Ramachandra <artagnon@gmail.com> --- Documentation/git-for-each-ref.txt | 4 +++- builtin/for-each-ref.c | 23 +++++++++++++++++++---- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt index f2e08d1..6fa4464 100644 --- a/Documentation/git-for-each-ref.txt +++ b/Documentation/git-for-each-ref.txt @@ -45,7 +45,9 @@ OPTIONS It also interpolates `%%` to `%`, and `%xx` where `xx` are hex digits interpolates to character with hex code `xx`; for example `%00` interpolates to `\0` (NUL), - `%09` to `\t` (TAB) and `%0a` to `\n` (LF). + `%09` to `\t` (TAB) and `%0a` to `\n` (LF). Additionally, + colors can be specified using `%C(...)`, with names + described in color.branch.*. <pattern>...:: If one or more patterns are given, only refs are shown that diff --git a/builtin/for-each-ref.c b/builtin/for-each-ref.c index 1d4083c..6da2903 100644 --- a/builtin/for-each-ref.c +++ b/builtin/for-each-ref.c @@ -9,6 +9,7 @@ #include "quote.h" #include "parse-options.h" #include "remote.h" +#include "color.h" /* Quoting styles */ #define QUOTE_NONE 0 @@ -155,10 +156,13 @@ static const char *find_next(const char *cp) while (*cp) { if (*cp == '%') { /* + * %C( is the start of a color; * %( is the start of an atom; * %% is a quoted per-cent. */ - if (cp[1] == '(') + if (cp[1] == 'C' && cp[2] == '(') + return cp; + else if (cp[1] == '(') return cp; else if (cp[1] == '%') cp++; /* skip over two % */ @@ -180,8 +184,11 @@ static int verify_format(const char *format) const char *ep = strchr(sp, ')'); if (!ep) return error("malformed format string %s", sp); - /* sp points at "%(" and ep points at the closing ")" */ - parse_atom(sp + 2, ep); + /* Ignore color specifications: %C( + * sp points at "%(" and ep points at the closing ")" + */ + if (prefixcmp(sp, "%C(")) + parse_atom(sp + 2, ep); cp = ep + 1; } return 0; @@ -933,12 +940,20 @@ static void emit(const char *cp, const char *ep) static void show_ref(struct refinfo *info, const char *format, int quote_style) { const char *cp, *sp, *ep; + char color[COLOR_MAXLEN] = ""; for (cp = format; *cp && (sp = find_next(cp)); cp = ep + 1) { ep = strchr(sp, ')'); if (cp < sp) emit(cp, sp); - print_value(info, parse_atom(sp + 2, ep), quote_style); + + /* Do we have a color specification? */ + if (!prefixcmp(sp, "%C(")) + color_parse_mem(sp + 3, ep - sp - 3, "--format", color); + else { + printf("%s", color); + print_value(info, parse_atom(sp + 2, ep), quote_style); + } } if (*cp) { sp = cp + strlen(cp); -- 1.8.5.rc0.3.gb488857 ^ permalink raw reply related [flat|nested] 25+ messages in thread
* Re: [PATCH 1/3] for-each-ref: introduce %C(...) for color 2013-10-31 9:46 ` [PATCH 1/3] for-each-ref: introduce %C(...) for color Ramkumar Ramachandra @ 2013-10-31 20:50 ` Junio C Hamano 2013-11-01 8:37 ` Ramkumar Ramachandra 0 siblings, 1 reply; 25+ messages in thread From: Junio C Hamano @ 2013-10-31 20:50 UTC (permalink / raw) To: Ramkumar Ramachandra; +Cc: Git List Ramkumar Ramachandra <artagnon@gmail.com> writes: > Enhance 'git for-each-ref' with color formatting options. You can now > use the following format in for-each-ref: > > %C(green)%(refname:short)%C(reset) So far, every magic for-each-ref takes were of form %(...); was there a reason why this had to be %C(...), not %(color=blah), or something more in-line with the existing other magic? > > Signed-off-by: Ramkumar Ramachandra <artagnon@gmail.com> > --- > Documentation/git-for-each-ref.txt | 4 +++- > builtin/for-each-ref.c | 23 +++++++++++++++++++---- > 2 files changed, 22 insertions(+), 5 deletions(-) > > diff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt > index f2e08d1..6fa4464 100644 > --- a/Documentation/git-for-each-ref.txt > +++ b/Documentation/git-for-each-ref.txt > @@ -45,7 +45,9 @@ OPTIONS > It also interpolates `%%` to `%`, and `%xx` where `xx` > are hex digits interpolates to character with hex code > `xx`; for example `%00` interpolates to `\0` (NUL), > - `%09` to `\t` (TAB) and `%0a` to `\n` (LF). > + `%09` to `\t` (TAB) and `%0a` to `\n` (LF). Additionally, > + colors can be specified using `%C(...)`, with names > + described in color.branch.*. > > <pattern>...:: > If one or more patterns are given, only refs are shown that > diff --git a/builtin/for-each-ref.c b/builtin/for-each-ref.c > index 1d4083c..6da2903 100644 > --- a/builtin/for-each-ref.c > +++ b/builtin/for-each-ref.c > @@ -9,6 +9,7 @@ > #include "quote.h" > #include "parse-options.h" > #include "remote.h" > +#include "color.h" > > /* Quoting styles */ > #define QUOTE_NONE 0 > @@ -155,10 +156,13 @@ static const char *find_next(const char *cp) > while (*cp) { > if (*cp == '%') { > /* > + * %C( is the start of a color; > * %( is the start of an atom; > * %% is a quoted per-cent. > */ > - if (cp[1] == '(') > + if (cp[1] == 'C' && cp[2] == '(') > + return cp; > + else if (cp[1] == '(') > return cp; > else if (cp[1] == '%') > cp++; /* skip over two % */ > @@ -180,8 +184,11 @@ static int verify_format(const char *format) > const char *ep = strchr(sp, ')'); > if (!ep) > return error("malformed format string %s", sp); > - /* sp points at "%(" and ep points at the closing ")" */ > - parse_atom(sp + 2, ep); > + /* Ignore color specifications: %C( > + * sp points at "%(" and ep points at the closing ")" > + */ > + if (prefixcmp(sp, "%C(")) > + parse_atom(sp + 2, ep); > cp = ep + 1; > } > return 0; > @@ -933,12 +940,20 @@ static void emit(const char *cp, const char *ep) > static void show_ref(struct refinfo *info, const char *format, int quote_style) > { > const char *cp, *sp, *ep; > + char color[COLOR_MAXLEN] = ""; > > for (cp = format; *cp && (sp = find_next(cp)); cp = ep + 1) { > ep = strchr(sp, ')'); > if (cp < sp) > emit(cp, sp); > - print_value(info, parse_atom(sp + 2, ep), quote_style); > + > + /* Do we have a color specification? */ > + if (!prefixcmp(sp, "%C(")) > + color_parse_mem(sp + 3, ep - sp - 3, "--format", color); > + else { > + printf("%s", color); > + print_value(info, parse_atom(sp + 2, ep), quote_style); > + } > } > if (*cp) { > sp = cp + strlen(cp); ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH 1/3] for-each-ref: introduce %C(...) for color 2013-10-31 20:50 ` Junio C Hamano @ 2013-11-01 8:37 ` Ramkumar Ramachandra 2013-11-01 15:05 ` Junio C Hamano 0 siblings, 1 reply; 25+ messages in thread From: Ramkumar Ramachandra @ 2013-11-01 8:37 UTC (permalink / raw) To: Junio C Hamano; +Cc: Git List Junio C Hamano wrote: > Ramkumar Ramachandra <artagnon@gmail.com> writes: > >> Enhance 'git for-each-ref' with color formatting options. You can now >> use the following format in for-each-ref: >> >> %C(green)%(refname:short)%C(reset) > > So far, every magic for-each-ref takes were of form %(...); was > there a reason why this had to be %C(...), not %(color=blah), or > something more in-line with the existing other magic? It is in-line with the color specification in pretty-formats. Would you strongly prefer something else? ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH 1/3] for-each-ref: introduce %C(...) for color 2013-11-01 8:37 ` Ramkumar Ramachandra @ 2013-11-01 15:05 ` Junio C Hamano 2013-11-02 6:02 ` Ramkumar Ramachandra 0 siblings, 1 reply; 25+ messages in thread From: Junio C Hamano @ 2013-11-01 15:05 UTC (permalink / raw) To: Ramkumar Ramachandra; +Cc: Git List Ramkumar Ramachandra <artagnon@gmail.com> writes: > Junio C Hamano wrote: >> Ramkumar Ramachandra <artagnon@gmail.com> writes: >> >>> Enhance 'git for-each-ref' with color formatting options. You can now >>> use the following format in for-each-ref: >>> >>> %C(green)%(refname:short)%C(reset) >> >> So far, every magic for-each-ref takes were of form %(...); was >> there a reason why this had to be %C(...), not %(color=blah), or >> something more in-line with the existing other magic? > > It is in-line with the color specification in pretty-formats. Would > you strongly prefer something else? This patch is about for-each-ref and your series does not seem to aim to unify it in any way with pretty-formats, so I would have expected an enhancement in line with the former, not the latter. ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH 1/3] for-each-ref: introduce %C(...) for color 2013-11-01 15:05 ` Junio C Hamano @ 2013-11-02 6:02 ` Ramkumar Ramachandra 2013-11-04 18:17 ` Junio C Hamano 0 siblings, 1 reply; 25+ messages in thread From: Ramkumar Ramachandra @ 2013-11-02 6:02 UTC (permalink / raw) To: Junio C Hamano; +Cc: Git List Junio C Hamano wrote: > This patch is about for-each-ref and your series does not seem to > aim to unify it in any way with pretty-formats, so I would have > expected an enhancement in line with the former, not the latter. While I might never attempt a unification again, there's no harm in getting the formats to resemble each other in part; it's likely that users of f-e-r format will be familiar with pretty-formats. ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH 1/3] for-each-ref: introduce %C(...) for color 2013-11-02 6:02 ` Ramkumar Ramachandra @ 2013-11-04 18:17 ` Junio C Hamano 2013-11-07 6:36 ` Ramkumar Ramachandra 0 siblings, 1 reply; 25+ messages in thread From: Junio C Hamano @ 2013-11-04 18:17 UTC (permalink / raw) To: Ramkumar Ramachandra; +Cc: Git List Ramkumar Ramachandra <artagnon@gmail.com> writes: > Junio C Hamano wrote: >> This patch is about for-each-ref and your series does not seem to >> aim to unify it in any way with pretty-formats, so I would have >> expected an enhancement in line with the former, not the latter. > > While I might never attempt a unification again, there's no harm in > getting the formats to resemble each other in part. Yes, but... > it's likely that > users of f-e-r format will be familiar with pretty-formats. ... users of for-each-ref format will be _more_ familiar with formats used by for-each-ref, and it would make a lot more sense to keep the syntactic resemblance between existing features to show magic things in for-each-ref and the new feature to show color (which is merely one new "magic" to the vocabulary in the context of for-each-ref), no? ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH 1/3] for-each-ref: introduce %C(...) for color 2013-11-04 18:17 ` Junio C Hamano @ 2013-11-07 6:36 ` Ramkumar Ramachandra 2013-11-07 18:02 ` Junio C Hamano 0 siblings, 1 reply; 25+ messages in thread From: Ramkumar Ramachandra @ 2013-11-07 6:36 UTC (permalink / raw) To: Junio C Hamano; +Cc: Git List Junio C Hamano wrote: > ... users of for-each-ref format will be _more_ familiar with > formats used by for-each-ref, and it would make a lot more sense to > keep the syntactic resemblance between existing features to show > magic things in for-each-ref and the new feature to show color > (which is merely one new "magic" to the vocabulary in the context of > for-each-ref), no? Okay, so what do you suggest in place of %C(...)? ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH 1/3] for-each-ref: introduce %C(...) for color 2013-11-07 6:36 ` Ramkumar Ramachandra @ 2013-11-07 18:02 ` Junio C Hamano 2013-11-08 12:14 ` Ramkumar Ramachandra 0 siblings, 1 reply; 25+ messages in thread From: Junio C Hamano @ 2013-11-07 18:02 UTC (permalink / raw) To: Ramkumar Ramachandra; +Cc: Git List Ramkumar Ramachandra <artagnon@gmail.com> writes: > Junio C Hamano wrote: >> ... users of for-each-ref format will be _more_ familiar with >> formats used by for-each-ref, and it would make a lot more sense to >> keep the syntactic resemblance between existing features to show >> magic things in for-each-ref and the new feature to show color >> (which is merely one new "magic" to the vocabulary in the context of >> for-each-ref), no? > > Okay, so what do you suggest in place of %C(...)? If %(authordate) is "I want to see the author date here", and %(authordate:short) is "I want to see the author date here in the short form", you would expect "I want colored output in green" to be spelled as %(color:green), or something, perhaps? ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH 1/3] for-each-ref: introduce %C(...) for color 2013-11-07 18:02 ` Junio C Hamano @ 2013-11-08 12:14 ` Ramkumar Ramachandra 2013-11-08 17:30 ` Junio C Hamano 0 siblings, 1 reply; 25+ messages in thread From: Ramkumar Ramachandra @ 2013-11-08 12:14 UTC (permalink / raw) To: Junio C Hamano; +Cc: Git List Junio C Hamano wrote: > If %(authordate) is "I want to see the author date here", and > %(authordate:short) is "I want to see the author date here in the > short form", you would expect "I want colored output in green" to be > spelled as %(color:green), or something, perhaps? Last time, we almost managed a unification: tokens like %authordate in f-e-r correspond to tokens like %ae in pretty-formats; %C(...) is different in that it doesn't actually output anything, but changes the color of tokens following it. While I'm not opposed to %(color:...), I would prefer a color syntax that is different from other-token syntax, like in pretty-formats. ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH 1/3] for-each-ref: introduce %C(...) for color 2013-11-08 12:14 ` Ramkumar Ramachandra @ 2013-11-08 17:30 ` Junio C Hamano 2013-11-12 3:38 ` Ramkumar Ramachandra 0 siblings, 1 reply; 25+ messages in thread From: Junio C Hamano @ 2013-11-08 17:30 UTC (permalink / raw) To: Ramkumar Ramachandra; +Cc: Git List Ramkumar Ramachandra <artagnon@gmail.com> writes: > ... %C(...) is > different in that it doesn't actually output anything, but changes the > color of tokens following it. While I'm not opposed to %(color:...), I > would prefer a color syntax that is different from other-token syntax, > like in pretty-formats. You may prefer it, but I do not see why users prefer to memorize that a magic that consumes no display output columns uses a syntax different from all the other magic introducers that follows %(name of the magic with string after colon to give more specifics to the magic) syntax. In all honesty, the %XY mnemonic syntax in pretty-format is a syntactic disaster. It is perfectly OK to have a set of often used shorthand, but because we started without a consistent long-hand, we ended up with %Cred and %C(yellow), leading us to a nonsense like this (try it yourself and weep): $ git show -s --format='%CredAnd%CyellowAreNotTheSameColor' It would have been much saner if we started from %(color:yellow), %(subject), etc., i.e. have a single long-hand magic introducer %(...), and added a set of often-used short-hands like %s. I am not opposed to unify the internal implementations and the external interfaces of pretty, for-each-ref and friends, but modelling the external UI after the "mnemonic only with ad hoc additions" mess the pretty-format uses is a huge mistake. ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH 1/3] for-each-ref: introduce %C(...) for color 2013-11-08 17:30 ` Junio C Hamano @ 2013-11-12 3:38 ` Ramkumar Ramachandra 0 siblings, 0 replies; 25+ messages in thread From: Ramkumar Ramachandra @ 2013-11-12 3:38 UTC (permalink / raw) To: Junio C Hamano; +Cc: Git List Junio C Hamano <gitster@pobox.com> wrote: > $ git show -s --format='%CredAnd%CyellowAreNotTheSameColor' Ouch, this is quite a disaster. > It would have been much saner if we started from %(color:yellow), > %(subject), etc., i.e. have a single long-hand magic introducer > %(...), and added a set of often-used short-hands like %s. > > I am not opposed to unify the internal implementations and the > external interfaces of pretty, for-each-ref and friends, but > modelling the external UI after the "mnemonic only with ad hoc > additions" mess the pretty-format uses is a huge mistake. Okay, I'm convinced; I'll rework the series to do %(color:...) and resubmit shortly. Thanks. ^ permalink raw reply [flat|nested] 25+ messages in thread
* [PATCH 2/3] for-each-ref: introduce %(HEAD) asterisk marker 2013-10-31 9:46 [PATCH (resend) 0/3] Minor f-e-r enhacements Ramkumar Ramachandra 2013-10-31 9:46 ` [PATCH 1/3] for-each-ref: introduce %C(...) for color Ramkumar Ramachandra @ 2013-10-31 9:46 ` Ramkumar Ramachandra 2013-10-31 9:46 ` [PATCH 3/3] for-each-ref: introduce %(upstream:track[short]) Ramkumar Ramachandra 2 siblings, 0 replies; 25+ messages in thread From: Ramkumar Ramachandra @ 2013-10-31 9:46 UTC (permalink / raw) To: Git List 'git branch' shows which branch you are currently on with an '*', but 'git for-each-ref' misses this feature. So, extend its format with %(HEAD) for the same effect. Now you can use the following format in for-each-ref: %C(red)%(HEAD)%C(reset) %(refname:short) to display a red asterisk next to the current ref. Signed-off-by: Ramkumar Ramachandra <artagnon@gmail.com> --- Documentation/git-for-each-ref.txt | 4 ++++ builtin/for-each-ref.c | 13 +++++++++++-- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt index 6fa4464..bb9c4c1 100644 --- a/Documentation/git-for-each-ref.txt +++ b/Documentation/git-for-each-ref.txt @@ -95,6 +95,10 @@ upstream:: from the displayed ref. Respects `:short` in the same way as `refname` above. +HEAD:: + Used to indicate the currently checked out branch. Is '*' if + HEAD points to the current ref, and ' ' otherwise. + In addition to the above, for commit and tag objects, the header field names (`tree`, `parent`, `object`, `type`, and `tag`) can be used to specify the value in the header field. diff --git a/builtin/for-each-ref.c b/builtin/for-each-ref.c index 6da2903..b841545 100644 --- a/builtin/for-each-ref.c +++ b/builtin/for-each-ref.c @@ -76,6 +76,7 @@ static struct { { "upstream" }, { "symref" }, { "flag" }, + { "HEAD" }, }; /* @@ -682,8 +683,16 @@ static void populate_value(struct refinfo *ref) v->s = xstrdup(buf + 1); } continue; - } - else + } else if (!strcmp(name, "HEAD")) { + const char *head; + unsigned char sha1[20]; + head = resolve_ref_unsafe("HEAD", sha1, 1, NULL); + if (!strcmp(ref->refname, head)) + v->s = "*"; + else + v->s = " "; + continue; + } else continue; formatp = strchr(name, ':'); -- 1.8.5.rc0.3.gb488857 ^ permalink raw reply related [flat|nested] 25+ messages in thread
* [PATCH 3/3] for-each-ref: introduce %(upstream:track[short]) 2013-10-31 9:46 [PATCH (resend) 0/3] Minor f-e-r enhacements Ramkumar Ramachandra 2013-10-31 9:46 ` [PATCH 1/3] for-each-ref: introduce %C(...) for color Ramkumar Ramachandra 2013-10-31 9:46 ` [PATCH 2/3] for-each-ref: introduce %(HEAD) asterisk marker Ramkumar Ramachandra @ 2013-10-31 9:46 ` Ramkumar Ramachandra 2013-11-01 17:17 ` Junio C Hamano 2 siblings, 1 reply; 25+ messages in thread From: Ramkumar Ramachandra @ 2013-10-31 9:46 UTC (permalink / raw) To: Git List Introduce %(upstream:track) to display "[ahead M, behind N]" and %(upstream:trackshort) to display "=", ">", "<", or "<>" appropriately (inspired by contrib/completion/git-prompt.sh). Now you can use the following format in for-each-ref: %C(green)%(refname:short)%C(reset)%(upstream:trackshort) to display refs with terse tracking information. Note that :track and :trackshort only work with "upstream", and error out when used with anything else. Signed-off-by: Ramkumar Ramachandra <artagnon@gmail.com> --- Documentation/git-for-each-ref.txt | 6 +++++- builtin/for-each-ref.c | 39 ++++++++++++++++++++++++++++++++++++-- 2 files changed, 42 insertions(+), 3 deletions(-) diff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt index bb9c4c1..3ef6aa8 100644 --- a/Documentation/git-for-each-ref.txt +++ b/Documentation/git-for-each-ref.txt @@ -93,7 +93,11 @@ objectname:: upstream:: The name of a local ref which can be considered ``upstream'' from the displayed ref. Respects `:short` in the same way as - `refname` above. + `refname` above. Additionally respects `:track` to show + "[ahead N, behind M]" and `:trackshort` to show the terse + version (like the prompt) ">", "<", "<>", or "=". Has no + effect if the ref does not have tracking information + associated with it. HEAD:: Used to indicate the currently checked out branch. Is '*' if diff --git a/builtin/for-each-ref.c b/builtin/for-each-ref.c index b841545..7d5c174 100644 --- a/builtin/for-each-ref.c +++ b/builtin/for-each-ref.c @@ -648,6 +648,7 @@ static void populate_value(struct refinfo *ref) int deref = 0; const char *refname; const char *formatp; + struct branch *branch; if (*name == '*') { deref = 1; @@ -659,7 +660,6 @@ static void populate_value(struct refinfo *ref) else if (!prefixcmp(name, "symref")) refname = ref->symref ? ref->symref : ""; else if (!prefixcmp(name, "upstream")) { - struct branch *branch; /* only local branches may have an upstream */ if (prefixcmp(ref->refname, "refs/heads/")) continue; @@ -686,6 +686,7 @@ static void populate_value(struct refinfo *ref) } else if (!strcmp(name, "HEAD")) { const char *head; unsigned char sha1[20]; + head = resolve_ref_unsafe("HEAD", sha1, 1, NULL); if (!strcmp(ref->refname, head)) v->s = "*"; @@ -698,11 +699,45 @@ static void populate_value(struct refinfo *ref) formatp = strchr(name, ':'); /* look for "short" refname format */ if (formatp) { + int num_ours, num_theirs; + formatp++; if (!strcmp(formatp, "short")) refname = shorten_unambiguous_ref(refname, warn_ambiguous_refs); - else + else if (!strcmp(formatp, "track") && + !prefixcmp(name, "upstream")) { + char buf[40]; + + stat_tracking_info(branch, &num_ours, &num_theirs); + if (!num_ours && !num_theirs) + v->s = ""; + else if (!num_ours) { + sprintf(buf, "[behind %d]", num_theirs); + v->s = xstrdup(buf); + } else if (!num_theirs) { + sprintf(buf, "[ahead %d]", num_ours); + v->s = xstrdup(buf); + } else { + sprintf(buf, "[ahead %d, behind %d]", + num_ours, num_theirs); + v->s = xstrdup(buf); + } + continue; + } else if (!strcmp(formatp, "trackshort") && + !prefixcmp(name, "upstream")) { + + stat_tracking_info(branch, &num_ours, &num_theirs); + if (!num_ours && !num_theirs) + v->s = "="; + else if (!num_ours) + v->s = "<"; + else if (!num_theirs) + v->s = ">"; + else + v->s = "<>"; + continue; + } else die("unknown %.*s format %s", (int)(formatp - name), name, formatp); } -- 1.8.5.rc0.3.gb488857 ^ permalink raw reply related [flat|nested] 25+ messages in thread
* Re: [PATCH 3/3] for-each-ref: introduce %(upstream:track[short]) 2013-10-31 9:46 ` [PATCH 3/3] for-each-ref: introduce %(upstream:track[short]) Ramkumar Ramachandra @ 2013-11-01 17:17 ` Junio C Hamano 0 siblings, 0 replies; 25+ messages in thread From: Junio C Hamano @ 2013-11-01 17:17 UTC (permalink / raw) To: Ramkumar Ramachandra; +Cc: Git List This patch needed on top of 3/3 for me to pass gcc cleanly. -- >8 -- Subject: [PATCH] fixup! for-each-ref: introduce %(upstream:track[short]) The condition !prefixcmp(name, "upstream") must be true for the variable "branch" to be reused, so the variable should be always set when it gets used, but GCC does not seem to realize this fact. --- builtin/for-each-ref.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/builtin/for-each-ref.c b/builtin/for-each-ref.c index 7d5c174..871d86c 100644 --- a/builtin/for-each-ref.c +++ b/builtin/for-each-ref.c @@ -648,7 +648,7 @@ static void populate_value(struct refinfo *ref) int deref = 0; const char *refname; const char *formatp; - struct branch *branch; + struct branch *branch = NULL; if (*name == '*') { deref = 1; @@ -727,6 +727,7 @@ static void populate_value(struct refinfo *ref) } else if (!strcmp(formatp, "trackshort") && !prefixcmp(name, "upstream")) { + assert(branch != NULL); stat_tracking_info(branch, &num_ours, &num_theirs); if (!num_ours && !num_theirs) v->s = "="; -- 1.8.5-rc0-205-g5b7460b ^ permalink raw reply related [flat|nested] 25+ messages in thread
* [PATCH 0/3] Juggling between hot branches @ 2013-09-27 12:10 Ramkumar Ramachandra 2013-09-27 12:10 ` [PATCH 3/3] for-each-ref: introduce %(upstream:track[short]) Ramkumar Ramachandra 0 siblings, 1 reply; 25+ messages in thread From: Ramkumar Ramachandra @ 2013-09-27 12:10 UTC (permalink / raw) To: Git List; +Cc: Jonathan Nieder Hi, I juggle between several hot branches, and an alphabetical listing from 'git branch' doesn't cut it for me. I've chosen to enhance for-each-ref so that I get output like (with color): $ git hot um-build> perf-manifest= * master= sparse= ia32-asm-cleanup> menuconfig-jk<> perf-build= perf-completion< where hot is the following alias: for-each-ref --format='%C(red)%(HEAD)%C(reset) %C(green)%(refname:short)%C(reset)%(upstream:trackshort)' --count 10 --sort='-committerdate' refs/heads While the alias might look a bit horrendous, I get the desired output. The last time I tried to get this feature merged, there was some confusion about unifying the format of for-each-ref with pretty-formats, and enhacing git-branch while at it. I tried going down that road, but got no reviews; everyone was generally more unhappy due to the added complexity. Months have passed since, and we still don't have this feature. Let's keep it simple and stupid. A terse +84,-10 (with documentation) for this wonderful feature now. Let's get it merged, and defer the kitchen-sink-unification efforts. Thanks. Ramkumar Ramachandra (3): for-each-ref: introduce %C(...) for color for-each-ref: introduce %(HEAD) asterisk marker for-each-ref: introduce %(upstream:track[short]) Documentation/git-for-each-ref.txt | 14 ++++++- builtin/for-each-ref.c | 80 ++++++++++++++++++++++++++++++++++---- 2 files changed, 84 insertions(+), 10 deletions(-) -- 1.8.4.478.g55109e3 ^ permalink raw reply [flat|nested] 25+ messages in thread
* [PATCH 3/3] for-each-ref: introduce %(upstream:track[short]) 2013-09-27 12:10 [PATCH 0/3] Juggling between hot branches Ramkumar Ramachandra @ 2013-09-27 12:10 ` Ramkumar Ramachandra 2013-09-27 14:03 ` Phil Hord ` (2 more replies) 0 siblings, 3 replies; 25+ messages in thread From: Ramkumar Ramachandra @ 2013-09-27 12:10 UTC (permalink / raw) To: Git List; +Cc: Jonathan Nieder Introduce %(upstream:track) to display "[ahead M, behind N]" and %(upstream:trackshort) to display "=", ">", "<", or "<>" appropriately (inspired by contrib/completion/git-prompt.sh). Now you can use the following format in for-each-ref: %C(green)%(refname:short)%C(reset)%(upstream:trackshort) to display refs with terse tracking information. Note that :track and :trackshort only work with "upstream", and error out when used with anything else. Signed-off-by: Ramkumar Ramachandra <artagnon@gmail.com> --- Documentation/git-for-each-ref.txt | 6 +++++- builtin/for-each-ref.c | 44 ++++++++++++++++++++++++++++++++++++-- 2 files changed, 47 insertions(+), 3 deletions(-) diff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt index f1d4e9e..682eaa8 100644 --- a/Documentation/git-for-each-ref.txt +++ b/Documentation/git-for-each-ref.txt @@ -93,7 +93,11 @@ objectname:: upstream:: The name of a local ref which can be considered ``upstream'' from the displayed ref. Respects `:short` in the same way as - `refname` above. + `refname` above. Additionally respects `:track` to show + "[ahead N, behind M]" and `:trackshort` to show the terse + version (like the prompt) ">", "<", "<>", or "=". Has no + effect if the ref does not have tracking information + associated with it. HEAD:: Used to indicate the currently checked out branch. Is '*' if diff --git a/builtin/for-each-ref.c b/builtin/for-each-ref.c index e54b5d8..10843bb 100644 --- a/builtin/for-each-ref.c +++ b/builtin/for-each-ref.c @@ -631,6 +631,7 @@ static void populate_value(struct refinfo *ref) int eaten, i; unsigned long size; const unsigned char *tagged; + int upstream_present = 0; ref->value = xcalloc(sizeof(struct atom_value), used_atom_cnt); @@ -648,6 +649,7 @@ static void populate_value(struct refinfo *ref) int deref = 0; const char *refname; const char *formatp; + struct branch *branch; if (*name == '*') { deref = 1; @@ -659,7 +661,6 @@ static void populate_value(struct refinfo *ref) else if (!prefixcmp(name, "symref")) refname = ref->symref ? ref->symref : ""; else if (!prefixcmp(name, "upstream")) { - struct branch *branch; /* only local branches may have an upstream */ if (prefixcmp(ref->refname, "refs/heads/")) continue; @@ -669,6 +670,7 @@ static void populate_value(struct refinfo *ref) !branch->merge[0]->dst) continue; refname = branch->merge[0]->dst; + upstream_present = 1; } else if (!strcmp(name, "flag")) { char buf[256], *cp = buf; @@ -686,6 +688,7 @@ static void populate_value(struct refinfo *ref) } else if (!strcmp(name, "HEAD")) { const char *head; unsigned char sha1[20]; + head = resolve_ref_unsafe("HEAD", sha1, 1, NULL); if (!strcmp(ref->refname, head)) v->s = "*"; @@ -698,11 +701,48 @@ static void populate_value(struct refinfo *ref) formatp = strchr(name, ':'); /* look for "short" refname format */ if (formatp) { + int num_ours, num_theirs; + formatp++; if (!strcmp(formatp, "short")) refname = shorten_unambiguous_ref(refname, warn_ambiguous_refs); - else + else if (!strcmp(formatp, "track") && + !prefixcmp(name, "upstream")) { + char buf[40]; + + if (!upstream_present) + continue; + stat_tracking_info(branch, &num_ours, &num_theirs); + if (!num_ours && !num_theirs) + v->s = ""; + else if (!num_ours) { + sprintf(buf, "[behind %d]", num_theirs); + v->s = xstrdup(buf); + } else if (!num_theirs) { + sprintf(buf, "[ahead %d]", num_ours); + v->s = xstrdup(buf); + } else { + sprintf(buf, "[ahead %d, behind %d]", + num_ours, num_theirs); + v->s = xstrdup(buf); + } + continue; + } else if (!strcmp(formatp, "trackshort") && + !prefixcmp(name, "upstream")) { + if (!upstream_present) + continue; + stat_tracking_info(branch, &num_ours, &num_theirs); + if (!num_ours && !num_theirs) + v->s = "="; + else if (!num_ours) + v->s = "<"; + else if (!num_theirs) + v->s = ">"; + else + v->s = "<>"; + continue; + } else die("unknown %.*s format %s", (int)(formatp - name), name, formatp); } -- 1.8.4.478.g55109e3 ^ permalink raw reply related [flat|nested] 25+ messages in thread
* Re: [PATCH 3/3] for-each-ref: introduce %(upstream:track[short]) 2013-09-27 12:10 ` [PATCH 3/3] for-each-ref: introduce %(upstream:track[short]) Ramkumar Ramachandra @ 2013-09-27 14:03 ` Phil Hord 2013-09-27 14:27 ` Ramkumar Ramachandra 2013-09-27 14:25 ` Johannes Sixt 2013-09-27 16:06 ` Philip Oakley 2 siblings, 1 reply; 25+ messages in thread From: Phil Hord @ 2013-09-27 14:03 UTC (permalink / raw) To: Ramkumar Ramachandra; +Cc: Git List, Jonathan Nieder On Fri, Sep 27, 2013 at 8:10 AM, Ramkumar Ramachandra <artagnon@gmail.com> wrote: > Introduce %(upstream:track) to display "[ahead M, behind N]" and > %(upstream:trackshort) to display "=", ">", "<", or "<>" > appropriately (inspired by contrib/completion/git-prompt.sh). > > Now you can use the following format in for-each-ref: > > %C(green)%(refname:short)%C(reset)%(upstream:trackshort) > > to display refs with terse tracking information. Thanks. I like this. > > Note that :track and :trackshort only work with "upstream", and error > out when used with anything else. I think I would like to use %(refname:track) myself, but this does not detract from this change. > > Signed-off-by: Ramkumar Ramachandra <artagnon@gmail.com> > --- > Documentation/git-for-each-ref.txt | 6 +++++- > builtin/for-each-ref.c | 44 ++++++++++++++++++++++++++++++++++++-- > 2 files changed, 47 insertions(+), 3 deletions(-) > > diff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt > index f1d4e9e..682eaa8 100644 > --- a/Documentation/git-for-each-ref.txt > +++ b/Documentation/git-for-each-ref.txt > @@ -93,7 +93,11 @@ objectname:: > upstream:: > The name of a local ref which can be considered ``upstream'' > from the displayed ref. Respects `:short` in the same way as > - `refname` above. > + `refname` above. Additionally respects `:track` to show > + "[ahead N, behind M]" and `:trackshort` to show the terse > + version (like the prompt) ">", "<", "<>", or "=". Has no > + effect if the ref does not have tracking information > + associated with it. > > HEAD:: > Used to indicate the currently checked out branch. Is '*' if > diff --git a/builtin/for-each-ref.c b/builtin/for-each-ref.c > index e54b5d8..10843bb 100644 > --- a/builtin/for-each-ref.c > +++ b/builtin/for-each-ref.c > @@ -631,6 +631,7 @@ static void populate_value(struct refinfo *ref) > int eaten, i; > unsigned long size; > const unsigned char *tagged; > + int upstream_present = 0; This flag is out of place. It should be in the same scope as 'branch' since the code which depends on this flag also depends on '!!branch'. However, I don't think it is even necessary. The only way to reach the places where this flag is tested is when (name="upstream") and (upstream exists). In all other cases, the parser loops before reaching the track/trackshort code or else it doesn't enter it. > > ref->value = xcalloc(sizeof(struct atom_value), used_atom_cnt); > > @@ -648,6 +649,7 @@ static void populate_value(struct refinfo *ref) > int deref = 0; > const char *refname; > const char *formatp; > + struct branch *branch; > > if (*name == '*') { > deref = 1; > @@ -659,7 +661,6 @@ static void populate_value(struct refinfo *ref) > else if (!prefixcmp(name, "symref")) > refname = ref->symref ? ref->symref : ""; > else if (!prefixcmp(name, "upstream")) { > - struct branch *branch; > /* only local branches may have an upstream */ > if (prefixcmp(ref->refname, "refs/heads/")) > continue; > @@ -669,6 +670,7 @@ static void populate_value(struct refinfo *ref) > !branch->merge[0]->dst) > continue; > refname = branch->merge[0]->dst; > + upstream_present = 1; > } > else if (!strcmp(name, "flag")) { > char buf[256], *cp = buf; > @@ -686,6 +688,7 @@ static void populate_value(struct refinfo *ref) > } else if (!strcmp(name, "HEAD")) { > const char *head; > unsigned char sha1[20]; > + > head = resolve_ref_unsafe("HEAD", sha1, 1, NULL); > if (!strcmp(ref->refname, head)) > v->s = "*"; > @@ -698,11 +701,48 @@ static void populate_value(struct refinfo *ref) > formatp = strchr(name, ':'); > /* look for "short" refname format */ > if (formatp) { > + int num_ours, num_theirs; > + > formatp++; > if (!strcmp(formatp, "short")) > refname = shorten_unambiguous_ref(refname, > warn_ambiguous_refs); > - else > + else if (!strcmp(formatp, "track") && > + !prefixcmp(name, "upstream")) { > + char buf[40]; > + > + if (!upstream_present) > + continue; > + stat_tracking_info(branch, &num_ours, &num_theirs); > + if (!num_ours && !num_theirs) > + v->s = ""; Is this the same as 'continue'? > + else if (!num_ours) { > + sprintf(buf, "[behind %d]", num_theirs); > + v->s = xstrdup(buf); > + } else if (!num_theirs) { > + sprintf(buf, "[ahead %d]", num_ours); > + v->s = xstrdup(buf); > + } else { > + sprintf(buf, "[ahead %d, behind %d]", > + num_ours, num_theirs); > + v->s = xstrdup(buf); > + } > + continue; > + } else if (!strcmp(formatp, "trackshort") && > + !prefixcmp(name, "upstream")) { > + if (!upstream_present) > + continue; > + stat_tracking_info(branch, &num_ours, &num_theirs); > + if (!num_ours && !num_theirs) > + v->s = "="; > + else if (!num_ours) > + v->s = "<"; > + else if (!num_theirs) > + v->s = ">"; > + else > + v->s = "<>"; > + continue; > + } else > die("unknown %.*s format %s", > (int)(formatp - name), name, formatp); > } > -- > 1.8.4.478.g55109e3 > > -- > To unsubscribe from this list: send the line "unsubscribe git" in > the body of a message to majordomo@vger.kernel.org > More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH 3/3] for-each-ref: introduce %(upstream:track[short]) 2013-09-27 14:03 ` Phil Hord @ 2013-09-27 14:27 ` Ramkumar Ramachandra 0 siblings, 0 replies; 25+ messages in thread From: Ramkumar Ramachandra @ 2013-09-27 14:27 UTC (permalink / raw) To: Phil Hord; +Cc: Git List, Jonathan Nieder Phil Hord wrote: >> --- a/builtin/for-each-ref.c >> +++ b/builtin/for-each-ref.c >> @@ -631,6 +631,7 @@ static void populate_value(struct refinfo *ref) >> int eaten, i; >> unsigned long size; >> const unsigned char *tagged; >> + int upstream_present = 0; > > This flag is out of place. It should be in the same scope as 'branch' > since the code which depends on this flag also depends on '!!branch'. Agreed. Fixed. > However, I don't think it is even necessary. The only way to reach > the places where this flag is tested is when (name="upstream") and > (upstream exists). In all other cases, the parser loops before > reaching the track/trackshort code or else it doesn't enter it. Yeah, you're right. I was setting upstream_present in this snippet: else if (!prefixcmp(name, "upstream")) { /* only local branches may have an upstream */ if (prefixcmp(ref->refname, "refs/heads/")) continue; If the refname doesn't begin with "refs/heads" in the first place (which is what I was guarding against), the code will loop and never reach the track[short] code anyway. upstream_present factored out now. >> @@ -698,11 +701,48 @@ static void populate_value(struct refinfo *ref) >> formatp = strchr(name, ':'); >> /* look for "short" refname format */ >> if (formatp) { >> + int num_ours, num_theirs; >> + >> formatp++; >> if (!strcmp(formatp, "short")) >> refname = shorten_unambiguous_ref(refname, >> warn_ambiguous_refs); >> - else >> + else if (!strcmp(formatp, "track") && >> + !prefixcmp(name, "upstream")) { >> + char buf[40]; >> + >> + if (!upstream_present) >> + continue; >> + stat_tracking_info(branch, &num_ours, &num_theirs); >> + if (!num_ours && !num_theirs) >> + v->s = ""; > > Is this the same as 'continue'? I'll leave this as it is for readability reasons. Thanks for the review. ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH 3/3] for-each-ref: introduce %(upstream:track[short]) 2013-09-27 12:10 ` [PATCH 3/3] for-each-ref: introduce %(upstream:track[short]) Ramkumar Ramachandra 2013-09-27 14:03 ` Phil Hord @ 2013-09-27 14:25 ` Johannes Sixt 2013-09-27 14:33 ` Ramkumar Ramachandra 2013-09-27 22:18 ` Jonathan Nieder 2013-09-27 16:06 ` Philip Oakley 2 siblings, 2 replies; 25+ messages in thread From: Johannes Sixt @ 2013-09-27 14:25 UTC (permalink / raw) To: Ramkumar Ramachandra; +Cc: Git List, Jonathan Nieder Am 9/27/2013 14:10, schrieb Ramkumar Ramachandra: > + else if (!strcmp(formatp, "track") && > + !prefixcmp(name, "upstream")) { > + char buf[40]; > + > + if (!upstream_present) > + continue; > + stat_tracking_info(branch, &num_ours, &num_theirs); > + if (!num_ours && !num_theirs) > + v->s = ""; > + else if (!num_ours) { > + sprintf(buf, "[behind %d]", num_theirs); > + v->s = xstrdup(buf); > + } else if (!num_theirs) { > + sprintf(buf, "[ahead %d]", num_ours); > + v->s = xstrdup(buf); > + } else { > + sprintf(buf, "[ahead %d, behind %d]", > + num_ours, num_theirs); > + v->s = xstrdup(buf); > + } These strdupped strings are leaked, right? > + continue; > + } else if (!strcmp(formatp, "trackshort") && > + !prefixcmp(name, "upstream")) { > + if (!upstream_present) > + continue; > + stat_tracking_info(branch, &num_ours, &num_theirs); > + if (!num_ours && !num_theirs) > + v->s = "="; > + else if (!num_ours) > + v->s = "<"; > + else if (!num_theirs) > + v->s = ">"; > + else > + v->s = "<>"; > + continue; > + } else > die("unknown %.*s format %s", > (int)(formatp - name), name, formatp); > } > -- Hannes ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH 3/3] for-each-ref: introduce %(upstream:track[short]) 2013-09-27 14:25 ` Johannes Sixt @ 2013-09-27 14:33 ` Ramkumar Ramachandra 2013-09-27 22:18 ` Jonathan Nieder 1 sibling, 0 replies; 25+ messages in thread From: Ramkumar Ramachandra @ 2013-09-27 14:33 UTC (permalink / raw) To: Johannes Sixt; +Cc: Git List, Jonathan Nieder Johannes Sixt wrote: >> + else if (!num_ours) { >> + sprintf(buf, "[behind %d]", num_theirs); >> + v->s = xstrdup(buf); >> + } else if (!num_theirs) { >> + sprintf(buf, "[ahead %d]", num_ours); >> + v->s = xstrdup(buf); >> + } else { >> + sprintf(buf, "[ahead %d, behind %d]", >> + num_ours, num_theirs); >> + v->s = xstrdup(buf); >> + } > > These strdupped strings are leaked, right? Yes, there's a minor leakage; there are quite a few instances of this in the rest of the file. Do you see an easy fix? ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH 3/3] for-each-ref: introduce %(upstream:track[short]) 2013-09-27 14:25 ` Johannes Sixt 2013-09-27 14:33 ` Ramkumar Ramachandra @ 2013-09-27 22:18 ` Jonathan Nieder 1 sibling, 0 replies; 25+ messages in thread From: Jonathan Nieder @ 2013-09-27 22:18 UTC (permalink / raw) To: Johannes Sixt; +Cc: Ramkumar Ramachandra, Git List Johannes Sixt wrote: > Am 9/27/2013 14:10, schrieb Ramkumar Ramachandra: >> + v->s = xstrdup(buf); >> + } > > These strdupped strings are leaked, right? The convention seems to be that each refinfo owns its atom_value, which owns its string that is kept on the heap. Except when it isn't (e.g., "v->s = typename(obj->type);"). So at least this patch doesn't make the muddle any worse. ;-) A nice followup would be to consistently allocate atom_value.s on the heap, check for a GIT_FREE_AT_EXIT envvar, and free the refinfos if that envvar is set at exit. That would make sure that the code is careful enough with memory to some day free some refinfo earlier when there are many refs. Until that's ready, I think continuing to mix and match like this (constant strings left as is, dynamically generated strings on the heap) is the best we can do. Thanks, Jonathan ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH 3/3] for-each-ref: introduce %(upstream:track[short]) 2013-09-27 12:10 ` [PATCH 3/3] for-each-ref: introduce %(upstream:track[short]) Ramkumar Ramachandra 2013-09-27 14:03 ` Phil Hord 2013-09-27 14:25 ` Johannes Sixt @ 2013-09-27 16:06 ` Philip Oakley 2013-09-27 16:10 ` Ramkumar Ramachandra 2 siblings, 1 reply; 25+ messages in thread From: Philip Oakley @ 2013-09-27 16:06 UTC (permalink / raw) To: Ramkumar Ramachandra, Git List; +Cc: Jonathan Nieder ----- Original Message ----- From: "Ramkumar Ramachandra" <artagnon@gmail.com> Sent: Friday, September 27, 2013 1:10 PM > Introduce %(upstream:track) to display "[ahead M, behind N]" and > %(upstream:trackshort) to display "=", ">", "<", or "<>" > appropriately (inspired by contrib/completion/git-prompt.sh). > > Now you can use the following format in for-each-ref: > > %C(green)%(refname:short)%C(reset)%(upstream:trackshort) > > to display refs with terse tracking information. > > Note that :track and :trackshort only work with "upstream", and error > out when used with anything else. > > Signed-off-by: Ramkumar Ramachandra <artagnon@gmail.com> > --- > Documentation/git-for-each-ref.txt | 6 +++++- > builtin/for-each-ref.c | 44 > ++++++++++++++++++++++++++++++++++++-- > 2 files changed, 47 insertions(+), 3 deletions(-) > > diff --git a/Documentation/git-for-each-ref.txt > b/Documentation/git-for-each-ref.txt > index f1d4e9e..682eaa8 100644 > --- a/Documentation/git-for-each-ref.txt > +++ b/Documentation/git-for-each-ref.txt > @@ -93,7 +93,11 @@ objectname:: > upstream:: > The name of a local ref which can be considered ``upstream'' > from the displayed ref. Respects `:short` in the same way as > - `refname` above. > + `refname` above. Additionally respects `:track` to show > + "[ahead N, behind M]" and `:trackshort` to show the terse > + version (like the prompt) ">", "<", "<>", or "=". Has no > + effect if the ref does not have tracking information > + associated with it. > "=" and "<>" I can easily understand (binary choice), but ">" and "<" will need to be clear which way they indicate in terms of matching the "[ahead N]" and "[behind M]" options. Otherwise a good idea. Philip > HEAD:: > Used to indicate the currently checked out branch. Is '*' if > diff --git a/builtin/for-each-ref.c b/builtin/for-each-ref.c > index e54b5d8..10843bb 100644 > --- a/builtin/for-each-ref.c > +++ b/builtin/for-each-ref.c > @@ -631,6 +631,7 @@ static void populate_value(struct refinfo *ref) > int eaten, i; > unsigned long size; > const unsigned char *tagged; > + int upstream_present = 0; > > ref->value = xcalloc(sizeof(struct atom_value), used_atom_cnt); > > @@ -648,6 +649,7 @@ static void populate_value(struct refinfo *ref) > int deref = 0; > const char *refname; > const char *formatp; > + struct branch *branch; > > if (*name == '*') { > deref = 1; > @@ -659,7 +661,6 @@ static void populate_value(struct refinfo *ref) > else if (!prefixcmp(name, "symref")) > refname = ref->symref ? ref->symref : ""; > else if (!prefixcmp(name, "upstream")) { > - struct branch *branch; > /* only local branches may have an upstream */ > if (prefixcmp(ref->refname, "refs/heads/")) > continue; > @@ -669,6 +670,7 @@ static void populate_value(struct refinfo *ref) > !branch->merge[0]->dst) > continue; > refname = branch->merge[0]->dst; > + upstream_present = 1; > } > else if (!strcmp(name, "flag")) { > char buf[256], *cp = buf; > @@ -686,6 +688,7 @@ static void populate_value(struct refinfo *ref) > } else if (!strcmp(name, "HEAD")) { > const char *head; > unsigned char sha1[20]; > + > head = resolve_ref_unsafe("HEAD", sha1, 1, NULL); > if (!strcmp(ref->refname, head)) > v->s = "*"; > @@ -698,11 +701,48 @@ static void populate_value(struct refinfo *ref) > formatp = strchr(name, ':'); > /* look for "short" refname format */ > if (formatp) { > + int num_ours, num_theirs; > + > formatp++; > if (!strcmp(formatp, "short")) > refname = shorten_unambiguous_ref(refname, > warn_ambiguous_refs); > - else > + else if (!strcmp(formatp, "track") && > + !prefixcmp(name, "upstream")) { > + char buf[40]; > + > + if (!upstream_present) > + continue; > + stat_tracking_info(branch, &num_ours, &num_theirs); > + if (!num_ours && !num_theirs) > + v->s = ""; > + else if (!num_ours) { > + sprintf(buf, "[behind %d]", num_theirs); > + v->s = xstrdup(buf); > + } else if (!num_theirs) { > + sprintf(buf, "[ahead %d]", num_ours); > + v->s = xstrdup(buf); > + } else { > + sprintf(buf, "[ahead %d, behind %d]", > + num_ours, num_theirs); > + v->s = xstrdup(buf); > + } > + continue; > + } else if (!strcmp(formatp, "trackshort") && > + !prefixcmp(name, "upstream")) { > + if (!upstream_present) > + continue; > + stat_tracking_info(branch, &num_ours, &num_theirs); > + if (!num_ours && !num_theirs) > + v->s = "="; > + else if (!num_ours) > + v->s = "<"; > + else if (!num_theirs) > + v->s = ">"; > + else > + v->s = "<>"; > + continue; > + } else > die("unknown %.*s format %s", > (int)(formatp - name), name, formatp); > } > -- > 1.8.4.478.g55109e3 > > -- ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH 3/3] for-each-ref: introduce %(upstream:track[short]) 2013-09-27 16:06 ` Philip Oakley @ 2013-09-27 16:10 ` Ramkumar Ramachandra 2013-09-27 17:07 ` Philip Oakley 0 siblings, 1 reply; 25+ messages in thread From: Ramkumar Ramachandra @ 2013-09-27 16:10 UTC (permalink / raw) To: Philip Oakley; +Cc: Git List, Jonathan Nieder Philip Oakley wrote: > "=" and "<>" I can easily understand (binary choice), but ">" and "<" will > need to be clear which way they indicate in terms of matching > the "[ahead N]" and "[behind M]" options. The ">" corresponds to ahead, while "<" is behind. You'll get used to it pretty quickly :) ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH 3/3] for-each-ref: introduce %(upstream:track[short]) 2013-09-27 16:10 ` Ramkumar Ramachandra @ 2013-09-27 17:07 ` Philip Oakley 0 siblings, 0 replies; 25+ messages in thread From: Philip Oakley @ 2013-09-27 17:07 UTC (permalink / raw) To: Ramkumar Ramachandra; +Cc: Git List, Jonathan Nieder From: "Ramkumar Ramachandra" <artagnon@gmail.com> > Philip Oakley wrote: >> "=" and "<>" I can easily understand (binary choice), but ">" and "<" >> will >> need to be clear which way they indicate in terms of matching >> the "[ahead N]" and "[behind M]" options. > > The ">" corresponds to ahead, while "<" is behind. You'll get used to > it pretty quickly :) > But this documentation section could say ;-) >>> diff --git a/Documentation/git-for-each-ref.txt >>> b/Documentation/git-for-each-ref.txt regards Philip ^ permalink raw reply [flat|nested] 25+ messages in thread
* [PATCH v2 0/3] Towards a useable git-branch @ 2013-05-24 14:19 Ramkumar Ramachandra 2013-05-24 14:19 ` [PATCH 3/3] for-each-ref: introduce %(upstream:track[short]) Ramkumar Ramachandra 0 siblings, 1 reply; 25+ messages in thread From: Ramkumar Ramachandra @ 2013-05-24 14:19 UTC (permalink / raw) To: Git List; +Cc: Junio C Hamano, Nguyễn Thái Ngọc Duy So, while investigating alignment operators in pretty-formats, I found out that it's way too much effort and totally not worth it (atleast not immediately; we can add it later if we want). What I want now is a useable git-branch output. And I think I can say that I've achieved it. I currently have hot aliased to for-each-ref --format='%C(red)%(HEAD)%C(reset) %C(green)%(refname:short)%C(reset)%(upstream:trackshort)' --count 10 --sort='-committerdate' refs/heads and it works beautifully for me. Sample output: % git hot * hot-branch<> pickaxe-doc> publish-rev= publish-rev-test upstream-error= push-current-head= master= prompt= autostash-stash= rebase.autostash= The asterisk is red, the branch names are in green, and the tracking marker is white. I'm very happy with the implementation too: 1. color only kicks in at the parsing layer. 2. HEAD is a new atom. 3. :track[short] is a formatp like :short. There is no need to use a hammer and coerce everything into an atom, or throw everything out the window and start from scratch to conform to pretty-formats perfectly. Let's extend the existing format to be _useful_ sensibly. Thanks. Ramkumar Ramachandra (3): for-each-ref: introduce %C(...) for color for-each-ref: introduce %(HEAD) marker for-each-ref: introduce %(upstream:track[short]) builtin/for-each-ref.c | 81 +++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 73 insertions(+), 8 deletions(-) -- 1.8.3.rc3.2.g99b8f3f.dirty ^ permalink raw reply [flat|nested] 25+ messages in thread
* [PATCH 3/3] for-each-ref: introduce %(upstream:track[short]) 2013-05-24 14:19 [PATCH v2 0/3] Towards a useable git-branch Ramkumar Ramachandra @ 2013-05-24 14:19 ` Ramkumar Ramachandra 0 siblings, 0 replies; 25+ messages in thread From: Ramkumar Ramachandra @ 2013-05-24 14:19 UTC (permalink / raw) To: Git List; +Cc: Junio C Hamano, Nguyễn Thái Ngọc Duy Introduce %(upstream:track) to display "[ahead M, behind N]" and %(upstream:trackshort) to display "=", ">", "<", or "<>" appropriately (inspired by the contrib/completion/git-prompt.sh). Now you can use the following format in for-each-ref: %C(red)%(HEAD)%C(reset) %C(green)%(refname:short)%C(reset)%(upstream:trackshort) to display refs with terse tracking information. Note that :track and :trackshort only works with upstream, and errors out when used with anything else. Signed-off-by: Ramkumar Ramachandra <artagnon@gmail.com> --- builtin/for-each-ref.c | 42 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 40 insertions(+), 2 deletions(-) diff --git a/builtin/for-each-ref.c b/builtin/for-each-ref.c index 63d3a85..838b125 100644 --- a/builtin/for-each-ref.c +++ b/builtin/for-each-ref.c @@ -632,6 +632,7 @@ static void populate_value(struct refinfo *ref) int eaten, i; unsigned long size; const unsigned char *tagged; + int upstream_present = 0; ref->value = xcalloc(sizeof(struct atom_value), used_atom_cnt); @@ -649,6 +650,7 @@ static void populate_value(struct refinfo *ref) int deref = 0; const char *refname; const char *formatp; + struct branch *branch; if (*name == '*') { deref = 1; @@ -660,7 +662,6 @@ static void populate_value(struct refinfo *ref) else if (!prefixcmp(name, "symref")) refname = ref->symref ? ref->symref : ""; else if (!prefixcmp(name, "upstream")) { - struct branch *branch; /* only local branches may have an upstream */ if (prefixcmp(ref->refname, "refs/heads/")) continue; @@ -670,6 +671,7 @@ static void populate_value(struct refinfo *ref) !branch->merge[0]->dst) continue; refname = branch->merge[0]->dst; + upstream_present = 1; } else if (!strcmp(name, "flag")) { char buf[256], *cp = buf; @@ -687,6 +689,7 @@ static void populate_value(struct refinfo *ref) } else if (!strcmp(name, "HEAD")) { const char *head; unsigned char sha1[20]; + head = resolve_ref_unsafe("HEAD", sha1, 1, NULL); if (!strcmp(ref->refname, head)) v->s = "*"; @@ -699,11 +702,46 @@ static void populate_value(struct refinfo *ref) formatp = strchr(name, ':'); /* look for "short" refname format */ if (formatp) { + int num_ours, num_theirs; + formatp++; if (!strcmp(formatp, "short")) refname = shorten_unambiguous_ref(refname, warn_ambiguous_refs); - else + else if (!strcmp(formatp, "track") && + !prefixcmp(name, "upstream")) { + char buf[40]; + + if (!upstream_present) + continue; + if (!stat_tracking_info(branch, &num_ours, &num_theirs)) + v->s = ""; + else if (!num_ours) { + sprintf(buf, "[behind %d]", num_theirs); + v->s = xstrdup(buf); + } else if (!num_theirs) { + sprintf(buf, "[ahead %d]", num_ours); + v->s = xstrdup(buf); + } else { + sprintf(buf, "[ahead %d, behind %d]", + num_ours, num_theirs); + v->s = xstrdup(buf); + } + continue; + } else if (!strcmp(formatp, "trackshort") && + !prefixcmp(name, "upstream")) { + if (!upstream_present) + continue; + if (!stat_tracking_info(branch, &num_ours, &num_theirs)) + v->s = "="; + else if (!num_ours) + v->s = "<"; + else if (!num_theirs) + v->s = ">"; + else + v->s = "<>"; + continue; + } else die("unknown %.*s format %s", (int)(formatp - name), name, formatp); } -- 1.8.3.rc3.2.g99b8f3f.dirty ^ permalink raw reply related [flat|nested] 25+ messages in thread
end of thread, other threads:[~2013-11-12 3:39 UTC | newest] Thread overview: 25+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2013-10-31 9:46 [PATCH (resend) 0/3] Minor f-e-r enhacements Ramkumar Ramachandra 2013-10-31 9:46 ` [PATCH 1/3] for-each-ref: introduce %C(...) for color Ramkumar Ramachandra 2013-10-31 20:50 ` Junio C Hamano 2013-11-01 8:37 ` Ramkumar Ramachandra 2013-11-01 15:05 ` Junio C Hamano 2013-11-02 6:02 ` Ramkumar Ramachandra 2013-11-04 18:17 ` Junio C Hamano 2013-11-07 6:36 ` Ramkumar Ramachandra 2013-11-07 18:02 ` Junio C Hamano 2013-11-08 12:14 ` Ramkumar Ramachandra 2013-11-08 17:30 ` Junio C Hamano 2013-11-12 3:38 ` Ramkumar Ramachandra 2013-10-31 9:46 ` [PATCH 2/3] for-each-ref: introduce %(HEAD) asterisk marker Ramkumar Ramachandra 2013-10-31 9:46 ` [PATCH 3/3] for-each-ref: introduce %(upstream:track[short]) Ramkumar Ramachandra 2013-11-01 17:17 ` Junio C Hamano -- strict thread matches above, loose matches on Subject: below -- 2013-09-27 12:10 [PATCH 0/3] Juggling between hot branches Ramkumar Ramachandra 2013-09-27 12:10 ` [PATCH 3/3] for-each-ref: introduce %(upstream:track[short]) Ramkumar Ramachandra 2013-09-27 14:03 ` Phil Hord 2013-09-27 14:27 ` Ramkumar Ramachandra 2013-09-27 14:25 ` Johannes Sixt 2013-09-27 14:33 ` Ramkumar Ramachandra 2013-09-27 22:18 ` Jonathan Nieder 2013-09-27 16:06 ` Philip Oakley 2013-09-27 16:10 ` Ramkumar Ramachandra 2013-09-27 17:07 ` Philip Oakley 2013-05-24 14:19 [PATCH v2 0/3] Towards a useable git-branch Ramkumar Ramachandra 2013-05-24 14:19 ` [PATCH 3/3] for-each-ref: introduce %(upstream:track[short]) Ramkumar Ramachandra
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).