diff options
Diffstat (limited to 'third_party/git/refspec.c')
-rw-r--r-- | third_party/git/refspec.c | 62 |
1 files changed, 53 insertions, 9 deletions
diff --git a/third_party/git/refspec.c b/third_party/git/refspec.c index 9a9bf21934af..8af357a0a35d 100644 --- a/third_party/git/refspec.c +++ b/third_party/git/refspec.c @@ -1,5 +1,5 @@ #include "cache.h" -#include "argv-array.h" +#include "strvec.h" #include "refs.h" #include "refspec.h" @@ -8,6 +8,7 @@ static struct refspec_item s_tag_refspec = { 1, 0, 0, + 0, "refs/tags/*", "refs/tags/*" }; @@ -32,10 +33,17 @@ static int parse_refspec(struct refspec_item *item, const char *refspec, int fet if (*lhs == '+') { item->force = 1; lhs++; + } else if (*lhs == '^') { + item->negative = 1; + lhs++; } rhs = strrchr(lhs, ':'); + /* negative refspecs only have one side */ + if (item->negative && rhs) + return 0; + /* * Before going on, special case ":" (or "+:") as a refspec * for pushing matching refs. @@ -55,7 +63,7 @@ static int parse_refspec(struct refspec_item *item, const char *refspec, int fet llen = (rhs ? (rhs - lhs - 1) : strlen(lhs)); if (1 <= llen && memchr(lhs, '*', llen)) { - if ((rhs && !is_glob) || (!rhs && fetch)) + if ((rhs && !is_glob) || (!rhs && !item->negative && fetch)) return 0; is_glob = 1; } else if (rhs && is_glob) { @@ -66,6 +74,28 @@ static int parse_refspec(struct refspec_item *item, const char *refspec, int fet item->src = xstrndup(lhs, llen); flags = REFNAME_ALLOW_ONELEVEL | (is_glob ? REFNAME_REFSPEC_PATTERN : 0); + if (item->negative) { + struct object_id unused; + + /* + * Negative refspecs only have a LHS, which indicates a ref + * (or pattern of refs) to exclude from other matches. This + * can either be a simple ref, or a glob pattern. Exact sha1 + * match is not currently supported. + */ + if (!*item->src) + return 0; /* negative refspecs must not be empty */ + else if (llen == the_hash_algo->hexsz && !get_oid_hex(item->src, &unused)) + return 0; /* negative refpsecs cannot be exact sha1 */ + else if (!check_refname_format(item->src, flags)) + ; /* valid looking ref is ok */ + else + return 0; + + /* the other rules below do not apply to negative refspecs */ + return 1; + } + if (fetch) { struct object_id unused; @@ -153,7 +183,7 @@ void refspec_init(struct refspec *rs, int fetch) rs->fetch = fetch; } -void refspec_append(struct refspec *rs, const char *refspec) +static void refspec_append_nodup(struct refspec *rs, char *refspec) { struct refspec_item item; @@ -163,7 +193,21 @@ void refspec_append(struct refspec *rs, const char *refspec) rs->items[rs->nr++] = item; ALLOC_GROW(rs->raw, rs->raw_nr + 1, rs->raw_alloc); - rs->raw[rs->raw_nr++] = xstrdup(refspec); + rs->raw[rs->raw_nr++] = refspec; +} + +void refspec_append(struct refspec *rs, const char *refspec) +{ + refspec_append_nodup(rs, xstrdup(refspec)); +} + +void refspec_appendf(struct refspec *rs, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + refspec_append_nodup(rs, xstrvfmt(fmt, ap)); + va_end(ap); } void refspec_appendn(struct refspec *rs, const char **refspecs, int nr) @@ -202,14 +246,14 @@ int valid_fetch_refspec(const char *fetch_refspec_str) } void refspec_ref_prefixes(const struct refspec *rs, - struct argv_array *ref_prefixes) + struct strvec *ref_prefixes) { int i; for (i = 0; i < rs->nr; i++) { const struct refspec_item *item = &rs->items[i]; const char *prefix = NULL; - if (item->exact_sha1) + if (item->exact_sha1 || item->negative) continue; if (rs->fetch == REFSPEC_FETCH) prefix = item->src; @@ -221,9 +265,9 @@ void refspec_ref_prefixes(const struct refspec *rs, if (prefix) { if (item->pattern) { const char *glob = strchr(prefix, '*'); - argv_array_pushf(ref_prefixes, "%.*s", - (int)(glob - prefix), - prefix); + strvec_pushf(ref_prefixes, "%.*s", + (int)(glob - prefix), + prefix); } else { expand_ref_prefix(ref_prefixes, prefix); } |