Skip to content

Commit 1a0ca5e

Browse files
KarthikNayakgitster
authored andcommitted
ref-filter: modify the 'lstrip=<N>' option to work with negative '<N>'
Currently the 'lstrip=<N>' option only takes a positive value '<N>' and strips '<N>' slash-separated path components from the left. Modify the 'lstrip' option to also take a negative number '<N>' which would strip from the left as necessary and _leave_ behind only 'N' slash-separated path components from the right-most end. For e.g. %(refname:lstrip=-1) would make 'foo/goo/abc' into 'abc'. Add documentation and tests for the same. Signed-off-by: Karthik Nayak <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 3a42980 commit 1a0ca5e

File tree

3 files changed

+36
-13
lines changed

3 files changed

+36
-13
lines changed

Documentation/git-for-each-ref.txt

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,8 +97,14 @@ refname::
9797
The option core.warnAmbiguousRefs is used to select the strict
9898
abbreviation mode. If `lstrip=<N>` is appended, strips `<N>`
9999
slash-separated path components from the front of the refname
100-
(e.g., `%(refname:lstrip=2)` turns `refs/tags/foo` into `foo`.
101-
`<N>` must be a positive integer.
100+
(e.g. `%(refname:lstrip=2)` turns `refs/tags/foo` into `foo`.
101+
If `<N>` is a negative number, strip as many path components as
102+
necessary from the left to leave `-<N>` path components
103+
(e.g. `%(refname:lstrip=-2)` turns
104+
`refs/tags/foo` into `tags/foo`). When the ref does not have
105+
enough components, the result becomes an empty string if
106+
stripping with positive <N>, or it becomes the full refname if
107+
stripping with negative <N>. Neither is an error.
102108

103109
objecttype::
104110
The type of the object (`blob`, `tree`, `commit`, `tag`).

ref-filter.c

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ struct if_then_else {
3434

3535
struct refname_atom {
3636
enum { R_NORMAL, R_SHORT, R_LSTRIP } option;
37-
unsigned int lstrip;
37+
int lstrip;
3838
};
3939

4040
/*
@@ -93,8 +93,8 @@ static void refname_atom_parser_internal(struct refname_atom *atom,
9393
atom->option = R_SHORT;
9494
else if (skip_prefix(arg, "lstrip=", &arg)) {
9595
atom->option = R_LSTRIP;
96-
if (strtoul_ui(arg, 10, &atom->lstrip) || atom->lstrip <= 0)
97-
die(_("positive value expected refname:lstrip=%s"), arg);
96+
if (strtol_i(arg, 10, &atom->lstrip))
97+
die(_("Integer value expected refname:lstrip=%s"), arg);
9898
} else
9999
die(_("unrecognized %%(%s) argument: %s"), name, arg);
100100
}
@@ -1091,12 +1091,28 @@ static inline char *copy_advance(char *dst, const char *src)
10911091
return dst;
10921092
}
10931093

1094-
static const char *lstrip_ref_components(const char *refname, unsigned int len)
1094+
static const char *lstrip_ref_components(const char *refname, int len)
10951095
{
10961096
long remaining = len;
10971097
const char *start = refname;
10981098

1099-
while (remaining) {
1099+
if (len < 0) {
1100+
int i;
1101+
const char *p = refname;
1102+
1103+
/* Find total no of '/' separated path-components */
1104+
for (i = 0; p[i]; p[i] == '/' ? i++ : *p++)
1105+
;
1106+
/*
1107+
* The number of components we need to strip is now
1108+
* the total minus the components to be left (Plus one
1109+
* because we count the number of '/', but the number
1110+
* of components is one more than the no of '/').
1111+
*/
1112+
remaining = i + len + 1;
1113+
}
1114+
1115+
while (remaining > 0) {
11001116
switch (*start++) {
11011117
case '\0':
11021118
return "";
@@ -1105,6 +1121,7 @@ static const char *lstrip_ref_components(const char *refname, unsigned int len)
11051121
break;
11061122
}
11071123
}
1124+
11081125
return start;
11091126
}
11101127

t/t6300-for-each-ref.sh

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -53,12 +53,16 @@ test_atom head refname refs/heads/master
5353
test_atom head refname:short master
5454
test_atom head refname:lstrip=1 heads/master
5555
test_atom head refname:lstrip=2 master
56+
test_atom head refname:lstrip=-1 master
57+
test_atom head refname:lstrip=-2 heads/master
5658
test_atom head upstream refs/remotes/origin/master
5759
test_atom head upstream:short origin/master
5860
test_atom head upstream:lstrip=2 origin/master
61+
test_atom head upstream:lstrip=-2 origin/master
5962
test_atom head push refs/remotes/myfork/master
6063
test_atom head push:short myfork/master
6164
test_atom head push:lstrip=1 remotes/myfork/master
65+
test_atom head push:lstrip=-1 master
6266
test_atom head objecttype commit
6367
test_atom head objectsize 171
6468
test_atom head objectname $(git rev-parse refs/heads/master)
@@ -141,12 +145,6 @@ test_expect_success 'Check invalid atoms names are errors' '
141145
test_must_fail git for-each-ref --format="%(INVALID)" refs/heads
142146
'
143147

144-
test_expect_success 'arguments to :lstrip must be positive integers' '
145-
test_must_fail git for-each-ref --format="%(refname:lstrip=0)" &&
146-
test_must_fail git for-each-ref --format="%(refname:lstrip=-1)" &&
147-
test_must_fail git for-each-ref --format="%(refname:lstrip=foo)"
148-
'
149-
150148
test_expect_success 'Check format specifiers are ignored in naming date atoms' '
151149
git for-each-ref --format="%(authordate)" refs/heads &&
152150
git for-each-ref --format="%(authordate:default) %(authordate)" refs/heads &&
@@ -624,10 +622,12 @@ test_expect_success 'Verify usage of %(symref:short) atom' '
624622

625623
cat >expected <<EOF
626624
master
625+
heads/master
627626
EOF
628627

629628
test_expect_success 'Verify usage of %(symref:lstrip) atom' '
630629
git for-each-ref --format="%(symref:lstrip=2)" refs/heads/sym > actual &&
630+
git for-each-ref --format="%(symref:lstrip=-2)" refs/heads/sym >> actual &&
631631
test_cmp expected actual
632632
'
633633

0 commit comments

Comments
 (0)