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>
Karthik Nayak committed
Jan 10, 2017 at 14:19 UTC
1a34728e6bb469083dd46ff35362fdfc6e489d07
3 files changed
+81
-21
Documentation/git-for-each-ref.txt
+23
-19
@@ -95,13 +95,15 @@ refname::
95
The name of the ref (the part after $GIT_DIR/).
96
For a non-ambiguous short name of the ref append `:short`.
97
The option core.warnAmbiguousRefs is used to select the strict
98
- abbreviation mode. If `lstrip=<N>` is appended, strips `<N>`
99
- slash-separated path components from the front of the refname
100
- (e.g. `%(refname:lstrip=2)` turns `refs/tags/foo` into `foo`.
98
+ abbreviation mode. If `lstrip=<N>` (`rstrip=<N>`) is appended, strips `<N>`
99
+ slash-separated path components from the front (back) of the refname
100
+ (e.g. `%(refname:lstrip=2)` turns `refs/tags/foo` into `foo` and
101
+ `%(refname:rstrip=2)` turns `refs/tags/foo` into `refs`).
102
If `<N>` is a negative number, strip as many path components as
102
- necessary from the left to leave `-<N>` path components
103
+ necessary from the specified end to leave `-<N>` path components
104
(e.g. `%(refname:lstrip=-2)` turns
104
- `refs/tags/foo` into `tags/foo`). When the ref does not have
105
+ `refs/tags/foo` into `tags/foo` and `%(refname:rstrip=-1)`
106
+ turns `refs/tags/foo` into `refs`). When the ref does not have
107
enough components, the result becomes an empty string if
108
stripping with positive <N>, or it becomes the full refname if
109
stripping with negative <N>. Neither is an error.
@@ -121,22 +123,23 @@ objectname::
123
124
upstream::
125
The name of a local ref which can be considered ``upstream''
124
- from the displayed ref. Respects `:short` and `:lstrip` in the
125
- same way as `refname` above. Additionally respects `:track`
126
- to show "[ahead N, behind M]" and `:trackshort` to show the
127
- terse version: ">" (ahead), "<" (behind), "<>" (ahead and
128
- behind), or "=" (in sync). `:track` also prints "[gone]"
129
- whenever unknown upstream ref is encountered. Append
130
- `:track,nobracket` to show tracking information without
131
- brackets (i.e "ahead N, behind M"). Has no effect if the ref
132
- does not have tracking information associated with it. All
133
- the options apart from `nobracket` are mutually exclusive, but
134
- if used together the last option is selected.
126
+ from the displayed ref. Respects `:short`, `:lstrip` and
127
+ `:rstrip` in the same way as `refname` above. Additionally
128
+ respects `:track` to show "[ahead N, behind M]" and
129
+ `:trackshort` to show the terse version: ">" (ahead), "<"
130
+ (behind), "<>" (ahead and behind), or "=" (in sync). `:track`
131
+ also prints "[gone]" whenever unknown upstream ref is
132
+ encountered. Append `:track,nobracket` to show tracking
133
+ information without brackets (i.e "ahead N, behind M"). Has
134
+ no effect if the ref does not have tracking information
135
+ associated with it. All the options apart from `nobracket`
136
+ are mutually exclusive, but if used together the last option
137
+ is selected.
138
139
push::
140
The name of a local ref which represents the `@{push}`
141
location for the displayed ref. Respects `:short`, `:lstrip`,
139
- `:track`, and `:trackshort` options as `upstream`
142
+ `:rstrip`, `:track`, and `:trackshort` options as `upstream`
143
does. Produces an empty string if no `@{push}` ref is
144
configured.
145
@@ -178,8 +181,9 @@ if::
181
182
symref::
183
The ref which the given symbolic ref refers to. If not a
181
- symbolic ref, nothing is printed. Respects the `:short` and
182
- `:lstrip` options in the same way as `refname` above.
184
+ symbolic ref, nothing is printed. Respects the `:short`,
185
+ `:lstrip` and `:rstrip` options in the same way as `refname`
186
+ above.
187
188
In addition to the above, for commit and tag objects, the header
189
field names (`tree`, `parent`, `object`, `type`, and `tag`) can
ref-filter.c
+39
-2
@@ -33,8 +33,8 @@ struct if_then_else {
33
};
34
35
struct refname_atom {
36
- enum { R_NORMAL, R_SHORT, R_LSTRIP } option;
37
- int lstrip;
36
+ enum { R_NORMAL, R_SHORT, R_LSTRIP, R_RSTRIP } option;
37
+ int lstrip, rstrip;
38
};
39
40
/*
@@ -95,6 +95,10 @@ static void refname_atom_parser_internal(struct refname_atom *atom,
95
atom->option = R_LSTRIP;
96
if (strtol_i(arg, 10, &atom->lstrip))
97
die(_("Integer value expected refname:lstrip=%s"), arg);
98
+ } else if (skip_prefix(arg, "rstrip=", &arg)) {
99
+ atom->option = R_RSTRIP;
100
+ if (strtol_i(arg, 10, &atom->rstrip))
101
+ die(_("Integer value expected refname:rstrip=%s"), arg);
102
} else
103
die(_("unrecognized %%(%s) argument: %s"), name, arg);
104
}
@@ -1125,12 +1129,45 @@ static const char *lstrip_ref_components(const char *refname, int len)
1129
return start;
1130
}
1131
1132
+static const char *rstrip_ref_components(const char *refname, int len)
1133
+{
1134
+ long remaining = len;
1135
+ char *start = xstrdup(refname);
1136
+
1137
+ if (len < 0) {
1138
+ int i;
1139
+ const char *p = refname;
1140
+
1141
+ /* Find total no of '/' separated path-components */
1142
+ for (i = 0; p[i]; p[i] == '/' ? i++ : *p++)
1143
+ ;
1144
+ /*
1145
+ * The number of components we need to strip is now
1146
+ * the total minus the components to be left (Plus one
1147
+ * because we count the number of '/', but the number
1148
+ * of components is one more than the no of '/').
1149
+ */
1150
+ remaining = i + len + 1;
1151
+ }
1152
+
1153
+ while (remaining-- > 0) {
1154
+ char *p = strrchr(start, '/');
1155
+ if (p == NULL)
1156
+ return "";
1157
+ else
1158
+ p[0] = '\0';
1159
+ }
1160
+ return start;
1161
+}
1162
+
1163
static const char *show_ref(struct refname_atom *atom, const char *refname)
1164
{
1165
if (atom->option == R_SHORT)
1166
return shorten_unambiguous_ref(refname, warn_ambiguous_refs);
1167
else if (atom->option == R_LSTRIP)
1168
return lstrip_ref_components(refname, atom->lstrip);
1169
+ else if (atom->option == R_RSTRIP)
1170
+ return rstrip_ref_components(refname, atom->rstrip);
1171
else
1172
return refname;
1173
}
t/t6300-for-each-ref.sh
+19
@@ -55,14 +55,22 @@ test_atom head refname:lstrip=1 heads/master
55
test_atom head refname:lstrip=2 master
56
test_atom head refname:lstrip=-1 master
57
test_atom head refname:lstrip=-2 heads/master
58
+test_atom head refname:rstrip=1 refs/heads
59
+test_atom head refname:rstrip=2 refs
60
+test_atom head refname:rstrip=-1 refs
61
+test_atom head refname:rstrip=-2 refs/heads
62
test_atom head upstream refs/remotes/origin/master
63
test_atom head upstream:short origin/master
64
test_atom head upstream:lstrip=2 origin/master
65
test_atom head upstream:lstrip=-2 origin/master
66
+test_atom head upstream:rstrip=2 refs/remotes
67
+test_atom head upstream:rstrip=-2 refs/remotes
68
test_atom head push refs/remotes/myfork/master
69
test_atom head push:short myfork/master
70
test_atom head push:lstrip=1 remotes/myfork/master
71
test_atom head push:lstrip=-1 master
72
+test_atom head push:rstrip=1 refs/remotes/myfork
73
+test_atom head push:rstrip=-1 refs
74
test_atom head objecttype commit
75
test_atom head objectsize 171
76
test_atom head objectname $(git rev-parse refs/heads/master)
@@ -631,4 +639,15 @@ test_expect_success 'Verify usage of %(symref:lstrip) atom' '
639
test_cmp expected actual
640
'
641
642
+cat >expected <<EOF
643
+refs
644
+refs/heads
645
+EOF
646
+
647
+test_expect_success 'Verify usage of %(symref:rstrip) atom' '
648
+ git for-each-ref --format="%(symref:rstrip=2)" refs/heads/sym > actual &&
649
+ git for-each-ref --format="%(symref:rstrip=-2)" refs/heads/sym >> actual &&
650
+ test_cmp expected actual
651
+'
652
+
653
test_done