ref-filter: add an 'rstrip=<N>' option to atoms which deal with refnames

Complimenting the existing 'lstrip=<N>' option, add an 'rstrip=<N>'
option which strips `<N>` slash-separated path components from the end
of the refname (e.g., `%(refname:rstrip=2)` turns `refs/tags/foo` into
`refs`).

Signed-off-by: Karthik Nayak <Karthik.188@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Karthik Nayak
2017-01-10 14:19:49 +05:30
committed by Junio C Hamano
parent 1a0ca5e358
commit 1a34728e6b
3 changed files with 81 additions and 21 deletions

View File

@ -95,13 +95,15 @@ refname::
The name of the ref (the part after $GIT_DIR/). The name of the ref (the part after $GIT_DIR/).
For a non-ambiguous short name of the ref append `:short`. For a non-ambiguous short name of the ref append `:short`.
The option core.warnAmbiguousRefs is used to select the strict The option core.warnAmbiguousRefs is used to select the strict
abbreviation mode. If `lstrip=<N>` is appended, strips `<N>` abbreviation mode. If `lstrip=<N>` (`rstrip=<N>`) is appended, strips `<N>`
slash-separated path components from the front of the refname slash-separated path components from the front (back) of the refname
(e.g. `%(refname:lstrip=2)` turns `refs/tags/foo` into `foo`. (e.g. `%(refname:lstrip=2)` turns `refs/tags/foo` into `foo` and
`%(refname:rstrip=2)` turns `refs/tags/foo` into `refs`).
If `<N>` is a negative number, strip as many path components as If `<N>` is a negative number, strip as many path components as
necessary from the left to leave `-<N>` path components necessary from the specified end to leave `-<N>` path components
(e.g. `%(refname:lstrip=-2)` turns (e.g. `%(refname:lstrip=-2)` turns
`refs/tags/foo` into `tags/foo`). When the ref does not have `refs/tags/foo` into `tags/foo` and `%(refname:rstrip=-1)`
turns `refs/tags/foo` into `refs`). When the ref does not have
enough components, the result becomes an empty string if enough components, the result becomes an empty string if
stripping with positive <N>, or it becomes the full refname if stripping with positive <N>, or it becomes the full refname if
stripping with negative <N>. Neither is an error. stripping with negative <N>. Neither is an error.
@ -121,22 +123,23 @@ objectname::
upstream:: upstream::
The name of a local ref which can be considered ``upstream'' The name of a local ref which can be considered ``upstream''
from the displayed ref. Respects `:short` and `:lstrip` in the from the displayed ref. Respects `:short`, `:lstrip` and
same way as `refname` above. Additionally respects `:track` `:rstrip` in the same way as `refname` above. Additionally
to show "[ahead N, behind M]" and `:trackshort` to show the respects `:track` to show "[ahead N, behind M]" and
terse version: ">" (ahead), "<" (behind), "<>" (ahead and `:trackshort` to show the terse version: ">" (ahead), "<"
behind), or "=" (in sync). `:track` also prints "[gone]" (behind), "<>" (ahead and behind), or "=" (in sync). `:track`
whenever unknown upstream ref is encountered. Append also prints "[gone]" whenever unknown upstream ref is
`:track,nobracket` to show tracking information without encountered. Append `:track,nobracket` to show tracking
brackets (i.e "ahead N, behind M"). Has no effect if the ref information without brackets (i.e "ahead N, behind M"). Has
does not have tracking information associated with it. All no effect if the ref does not have tracking information
the options apart from `nobracket` are mutually exclusive, but associated with it. All the options apart from `nobracket`
if used together the last option is selected. are mutually exclusive, but if used together the last option
is selected.
push:: push::
The name of a local ref which represents the `@{push}` The name of a local ref which represents the `@{push}`
location for the displayed ref. Respects `:short`, `:lstrip`, location for the displayed ref. Respects `:short`, `:lstrip`,
`:track`, and `:trackshort` options as `upstream` `:rstrip`, `:track`, and `:trackshort` options as `upstream`
does. Produces an empty string if no `@{push}` ref is does. Produces an empty string if no `@{push}` ref is
configured. configured.
@ -178,8 +181,9 @@ if::
symref:: symref::
The ref which the given symbolic ref refers to. If not a The ref which the given symbolic ref refers to. If not a
symbolic ref, nothing is printed. Respects the `:short` and symbolic ref, nothing is printed. Respects the `:short`,
`:lstrip` options in the same way as `refname` above. `:lstrip` and `:rstrip` options in the same way as `refname`
above.
In addition to the above, for commit and tag objects, the header In addition to the above, for commit and tag objects, the header
field names (`tree`, `parent`, `object`, `type`, and `tag`) can field names (`tree`, `parent`, `object`, `type`, and `tag`) can

View File

@ -33,8 +33,8 @@ struct if_then_else {
}; };
struct refname_atom { struct refname_atom {
enum { R_NORMAL, R_SHORT, R_LSTRIP } option; enum { R_NORMAL, R_SHORT, R_LSTRIP, R_RSTRIP } option;
int lstrip; int lstrip, rstrip;
}; };
/* /*
@ -95,6 +95,10 @@ static void refname_atom_parser_internal(struct refname_atom *atom,
atom->option = R_LSTRIP; atom->option = R_LSTRIP;
if (strtol_i(arg, 10, &atom->lstrip)) if (strtol_i(arg, 10, &atom->lstrip))
die(_("Integer value expected refname:lstrip=%s"), arg); die(_("Integer value expected refname:lstrip=%s"), arg);
} else if (skip_prefix(arg, "rstrip=", &arg)) {
atom->option = R_RSTRIP;
if (strtol_i(arg, 10, &atom->rstrip))
die(_("Integer value expected refname:rstrip=%s"), arg);
} else } else
die(_("unrecognized %%(%s) argument: %s"), name, arg); die(_("unrecognized %%(%s) argument: %s"), name, arg);
} }
@ -1125,12 +1129,45 @@ static const char *lstrip_ref_components(const char *refname, int len)
return start; return start;
} }
static const char *rstrip_ref_components(const char *refname, int len)
{
long remaining = len;
char *start = xstrdup(refname);
if (len < 0) {
int i;
const char *p = refname;
/* Find total no of '/' separated path-components */
for (i = 0; p[i]; p[i] == '/' ? i++ : *p++)
;
/*
* The number of components we need to strip is now
* the total minus the components to be left (Plus one
* because we count the number of '/', but the number
* of components is one more than the no of '/').
*/
remaining = i + len + 1;
}
while (remaining-- > 0) {
char *p = strrchr(start, '/');
if (p == NULL)
return "";
else
p[0] = '\0';
}
return start;
}
static const char *show_ref(struct refname_atom *atom, const char *refname) static const char *show_ref(struct refname_atom *atom, const char *refname)
{ {
if (atom->option == R_SHORT) if (atom->option == R_SHORT)
return shorten_unambiguous_ref(refname, warn_ambiguous_refs); return shorten_unambiguous_ref(refname, warn_ambiguous_refs);
else if (atom->option == R_LSTRIP) else if (atom->option == R_LSTRIP)
return lstrip_ref_components(refname, atom->lstrip); return lstrip_ref_components(refname, atom->lstrip);
else if (atom->option == R_RSTRIP)
return rstrip_ref_components(refname, atom->rstrip);
else else
return refname; return refname;
} }

View File

@ -55,14 +55,22 @@ test_atom head refname:lstrip=1 heads/master
test_atom head refname:lstrip=2 master test_atom head refname:lstrip=2 master
test_atom head refname:lstrip=-1 master test_atom head refname:lstrip=-1 master
test_atom head refname:lstrip=-2 heads/master test_atom head refname:lstrip=-2 heads/master
test_atom head refname:rstrip=1 refs/heads
test_atom head refname:rstrip=2 refs
test_atom head refname:rstrip=-1 refs
test_atom head refname:rstrip=-2 refs/heads
test_atom head upstream refs/remotes/origin/master test_atom head upstream refs/remotes/origin/master
test_atom head upstream:short origin/master test_atom head upstream:short origin/master
test_atom head upstream:lstrip=2 origin/master test_atom head upstream:lstrip=2 origin/master
test_atom head upstream:lstrip=-2 origin/master test_atom head upstream:lstrip=-2 origin/master
test_atom head upstream:rstrip=2 refs/remotes
test_atom head upstream:rstrip=-2 refs/remotes
test_atom head push refs/remotes/myfork/master test_atom head push refs/remotes/myfork/master
test_atom head push:short myfork/master test_atom head push:short myfork/master
test_atom head push:lstrip=1 remotes/myfork/master test_atom head push:lstrip=1 remotes/myfork/master
test_atom head push:lstrip=-1 master test_atom head push:lstrip=-1 master
test_atom head push:rstrip=1 refs/remotes/myfork
test_atom head push:rstrip=-1 refs
test_atom head objecttype commit test_atom head objecttype commit
test_atom head objectsize 171 test_atom head objectsize 171
test_atom head objectname $(git rev-parse refs/heads/master) test_atom head objectname $(git rev-parse refs/heads/master)
@ -631,4 +639,15 @@ test_expect_success 'Verify usage of %(symref:lstrip) atom' '
test_cmp expected actual test_cmp expected actual
' '
cat >expected <<EOF
refs
refs/heads
EOF
test_expect_success 'Verify usage of %(symref:rstrip) atom' '
git for-each-ref --format="%(symref:rstrip=2)" refs/heads/sym > actual &&
git for-each-ref --format="%(symref:rstrip=-2)" refs/heads/sym >> actual &&
test_cmp expected actual
'
test_done test_done