1 #define USE_THE_REPOSITORY_VARIABLE
2 #define DISABLE_SIGN_COMPARE_WARNINGS
4 #include "git-compat-util.h"
8 #include "string-list.h"
16 * Parses the provided refspec 'refspec' and populates the refspec_item 'item'.
17 * Returns 1 if successful and 0 if the refspec is invalid.
19 static int parse_refspec(struct refspec_item
*item
, const char *refspec
, int fetch
)
23 const char *lhs
, *rhs
;
32 } else if (*lhs
== '^') {
37 rhs
= strrchr(lhs
, ':');
39 /* negative refspecs only have one side */
40 if (item
->negative
&& rhs
)
44 * Before going on, special case ":" (or "+:") as a refspec
45 * for pushing matching refs.
47 if (!fetch
&& rhs
== lhs
&& rhs
[1] == '\0') {
53 size_t rlen
= strlen(++rhs
);
54 is_glob
= (1 <= rlen
&& strchr(rhs
, '*'));
55 item
->dst
= xstrndup(rhs
, rlen
);
60 llen
= (rhs
? (rhs
- lhs
- 1) : strlen(lhs
));
61 if (1 <= llen
&& memchr(lhs
, '*', llen
)) {
62 if ((rhs
&& !is_glob
) || (!rhs
&& !item
->negative
&& fetch
))
65 } else if (rhs
&& is_glob
) {
69 item
->pattern
= is_glob
;
70 if (llen
== 1 && *lhs
== '@')
71 item
->src
= xstrdup("HEAD");
73 item
->src
= xstrndup(lhs
, llen
);
74 flags
= REFNAME_ALLOW_ONELEVEL
| (is_glob
? REFNAME_REFSPEC_PATTERN
: 0);
77 struct object_id unused
;
80 * Negative refspecs only have a LHS, which indicates a ref
81 * (or pattern of refs) to exclude from other matches. This
82 * can either be a simple ref, or a glob pattern. Exact sha1
83 * match is not currently supported.
86 return 0; /* negative refspecs must not be empty */
87 else if (llen
== the_hash_algo
->hexsz
&& !get_oid_hex(item
->src
, &unused
))
88 return 0; /* negative refpsecs cannot be exact sha1 */
89 else if (!check_refname_format(item
->src
, flags
))
90 ; /* valid looking ref is ok */
94 /* the other rules below do not apply to negative refspecs */
99 struct object_id unused
;
103 ; /* empty is ok; it means "HEAD" */
104 else if (llen
== the_hash_algo
->hexsz
&& !get_oid_hex(item
->src
, &unused
))
105 item
->exact_sha1
= 1; /* ok */
106 else if (!check_refname_format(item
->src
, flags
))
107 ; /* valid looking ref is ok */
112 ; /* missing is ok; it is the same as empty */
113 else if (!*item
->dst
)
114 ; /* empty is ok; it means "do not store" */
115 else if (!check_refname_format(item
->dst
, flags
))
116 ; /* valid looking ref is ok */
122 * - empty is allowed; it means delete.
123 * - when wildcarded, it must be a valid looking ref.
124 * - otherwise, it must be an extended SHA-1, but
125 * there is no existing way to validate this.
130 if (check_refname_format(item
->src
, flags
))
134 ; /* anything goes, for now */
137 * - missing is allowed, but LHS then must be a
139 * - empty is not allowed.
140 * - otherwise it must be a valid looking ref.
143 if (check_refname_format(item
->src
, flags
))
145 } else if (!*item
->dst
) {
148 if (check_refname_format(item
->dst
, flags
))
156 static int refspec_item_init(struct refspec_item
*item
, const char *refspec
,
159 memset(item
, 0, sizeof(*item
));
160 item
->raw
= xstrdup(refspec
);
161 return parse_refspec(item
, refspec
, fetch
);
164 int refspec_item_init_fetch(struct refspec_item
*item
, const char *refspec
)
166 return refspec_item_init(item
, refspec
, 1);
169 int refspec_item_init_push(struct refspec_item
*item
, const char *refspec
)
171 return refspec_item_init(item
, refspec
, 0);
174 void refspec_item_clear(struct refspec_item
*item
)
176 FREE_AND_NULL(item
->src
);
177 FREE_AND_NULL(item
->dst
);
178 FREE_AND_NULL(item
->raw
);
182 item
->exact_sha1
= 0;
185 void refspec_init_fetch(struct refspec
*rs
)
187 struct refspec blank
= REFSPEC_INIT_FETCH
;
188 memcpy(rs
, &blank
, sizeof(*rs
));
191 void refspec_init_push(struct refspec
*rs
)
193 struct refspec blank
= REFSPEC_INIT_PUSH
;
194 memcpy(rs
, &blank
, sizeof(*rs
));
197 void refspec_append(struct refspec
*rs
, const char *refspec
)
199 struct refspec_item item
;
203 ret
= refspec_item_init_fetch(&item
, refspec
);
205 ret
= refspec_item_init_push(&item
, refspec
);
207 die(_("invalid refspec '%s'"), refspec
);
209 ALLOC_GROW(rs
->items
, rs
->nr
+ 1, rs
->alloc
);
210 rs
->items
[rs
->nr
] = item
;
215 void refspec_appendf(struct refspec
*rs
, const char *fmt
, ...)
221 buf
= xstrvfmt(fmt
, ap
);
224 refspec_append(rs
, buf
);
228 void refspec_appendn(struct refspec
*rs
, const char **refspecs
, int nr
)
231 for (i
= 0; i
< nr
; i
++)
232 refspec_append(rs
, refspecs
[i
]);
235 void refspec_clear(struct refspec
*rs
)
239 for (i
= 0; i
< rs
->nr
; i
++)
240 refspec_item_clear(&rs
->items
[i
]);
242 FREE_AND_NULL(rs
->items
);
249 int valid_fetch_refspec(const char *fetch_refspec_str
)
251 struct refspec_item refspec
;
252 int ret
= refspec_item_init_fetch(&refspec
, fetch_refspec_str
);
253 refspec_item_clear(&refspec
);
257 void refspec_ref_prefixes(const struct refspec
*rs
,
258 struct strvec
*ref_prefixes
)
261 for (i
= 0; i
< rs
->nr
; i
++) {
262 const struct refspec_item
*item
= &rs
->items
[i
];
263 const char *prefix
= NULL
;
269 if (item
->exact_sha1
)
274 * Pushes can have an explicit destination like
275 * "foo:bar", or can implicitly use the src for both
276 * ("foo" is the same as "foo:foo").
280 else if (item
->src
&& !item
->exact_sha1
)
288 const char *glob
= strchr(prefix
, '*');
289 strvec_pushf(ref_prefixes
, "%.*s",
290 (int)(glob
- prefix
),
293 expand_ref_prefix(ref_prefixes
, prefix
);
298 int match_refname_with_pattern(const char *pattern
, const char *refname
,
299 const char *replacement
, char **result
)
301 const char *kstar
= strchr(pattern
, '*');
307 die(_("pattern '%s' has no '*'"), pattern
);
308 klen
= kstar
- pattern
;
309 ksuffixlen
= strlen(kstar
+ 1);
310 namelen
= strlen(refname
);
311 ret
= !strncmp(refname
, pattern
, klen
) && namelen
>= klen
+ ksuffixlen
&&
312 !memcmp(refname
+ namelen
- ksuffixlen
, kstar
+ 1, ksuffixlen
);
313 if (ret
&& replacement
) {
314 struct strbuf sb
= STRBUF_INIT
;
315 const char *vstar
= strchr(replacement
, '*');
317 die(_("replacement '%s' has no '*'"), replacement
);
318 strbuf_add(&sb
, replacement
, vstar
- replacement
);
319 strbuf_add(&sb
, refname
+ klen
, namelen
- klen
- ksuffixlen
);
320 strbuf_addstr(&sb
, vstar
+ 1);
321 *result
= strbuf_detach(&sb
, NULL
);
326 static int refspec_match(const struct refspec_item
*refspec
,
329 if (refspec
->pattern
)
330 return match_refname_with_pattern(refspec
->src
, name
, NULL
, NULL
);
332 return !strcmp(refspec
->src
, name
);
335 int refname_matches_negative_refspec_item(const char *refname
, struct refspec
*rs
)
339 for (i
= 0; i
< rs
->nr
; i
++) {
340 if (rs
->items
[i
].negative
&& refspec_match(&rs
->items
[i
], refname
))
346 static int refspec_find_negative_match(struct refspec
*rs
, struct refspec_item
*query
)
348 int i
, matched_negative
= 0;
349 int find_src
= !query
->src
;
350 struct string_list reversed
= STRING_LIST_INIT_DUP
;
351 const char *needle
= find_src
? query
->dst
: query
->src
;
354 * Check whether the queried ref matches any negative refpsec. If so,
355 * then we should ultimately treat this as not matching the query at
358 * Note that negative refspecs always match the source, but the query
359 * item uses the destination. To handle this, we apply pattern
360 * refspecs in reverse to figure out if the query source matches any
361 * of the negative refspecs.
363 * The first loop finds and expands all positive refspecs
364 * matched by the queried ref.
366 * The second loop checks if any of the results of the first loop
367 * match any negative refspec.
369 for (i
= 0; i
< rs
->nr
; i
++) {
370 struct refspec_item
*refspec
= &rs
->items
[i
];
373 if (refspec
->negative
)
376 /* Note the reversal of src and dst */
377 if (refspec
->pattern
) {
378 const char *key
= refspec
->dst
? refspec
->dst
: refspec
->src
;
379 const char *value
= refspec
->src
;
381 if (match_refname_with_pattern(key
, needle
, value
, &expn_name
))
382 string_list_append_nodup(&reversed
, expn_name
);
383 } else if (refspec
->matching
) {
384 /* For the special matching refspec, any query should match */
385 string_list_append(&reversed
, needle
);
386 } else if (!refspec
->src
) {
387 BUG("refspec->src should not be null here");
388 } else if (!strcmp(needle
, refspec
->src
)) {
389 string_list_append(&reversed
, refspec
->src
);
393 for (i
= 0; !matched_negative
&& i
< reversed
.nr
; i
++) {
394 if (refname_matches_negative_refspec_item(reversed
.items
[i
].string
, rs
))
395 matched_negative
= 1;
398 string_list_clear(&reversed
, 0);
400 return matched_negative
;
403 void refspec_find_all_matches(struct refspec
*rs
,
404 struct refspec_item
*query
,
405 struct string_list
*results
)
408 int find_src
= !query
->src
;
410 if (find_src
&& !query
->dst
)
411 BUG("refspec_find_all_matches: need either src or dst");
413 if (refspec_find_negative_match(rs
, query
))
416 for (i
= 0; i
< rs
->nr
; i
++) {
417 struct refspec_item
*refspec
= &rs
->items
[i
];
418 const char *key
= find_src
? refspec
->dst
: refspec
->src
;
419 const char *value
= find_src
? refspec
->src
: refspec
->dst
;
420 const char *needle
= find_src
? query
->dst
: query
->src
;
421 char **result
= find_src
? &query
->src
: &query
->dst
;
423 if (!refspec
->dst
|| refspec
->negative
)
425 if (refspec
->pattern
) {
426 if (match_refname_with_pattern(key
, needle
, value
, result
))
427 string_list_append_nodup(results
, *result
);
428 } else if (!strcmp(needle
, key
)) {
429 string_list_append(results
, value
);
434 int refspec_find_match(struct refspec
*rs
, struct refspec_item
*query
)
437 int find_src
= !query
->src
;
438 const char *needle
= find_src
? query
->dst
: query
->src
;
439 char **result
= find_src
? &query
->src
: &query
->dst
;
441 if (find_src
&& !query
->dst
)
442 BUG("refspec_find_match: need either src or dst");
444 if (refspec_find_negative_match(rs
, query
))
447 for (i
= 0; i
< rs
->nr
; i
++) {
448 struct refspec_item
*refspec
= &rs
->items
[i
];
449 const char *key
= find_src
? refspec
->dst
: refspec
->src
;
450 const char *value
= find_src
? refspec
->src
: refspec
->dst
;
452 if (!refspec
->dst
|| refspec
->negative
)
454 if (refspec
->pattern
) {
455 if (match_refname_with_pattern(key
, needle
, value
, result
)) {
456 query
->force
= refspec
->force
;
459 } else if (!strcmp(needle
, key
)) {
460 *result
= xstrdup(value
);
461 query
->force
= refspec
->force
;
468 struct ref
*apply_negative_refspecs(struct ref
*ref_map
, struct refspec
*rs
)
472 for (tail
= &ref_map
; *tail
; ) {
473 struct ref
*ref
= *tail
;
475 if (refname_matches_negative_refspec_item(ref
->name
, rs
)) {
486 char *apply_refspecs(struct refspec
*rs
, const char *name
)
488 struct refspec_item query
;
490 memset(&query
, 0, sizeof(struct refspec_item
));
491 query
.src
= (char *)name
;
493 if (refspec_find_match(rs
, &query
))