]> git.ipfire.org Git - thirdparty/git.git/blobdiff - refspec.c
strmap: enable allocations to come from a mem_pool
[thirdparty/git.git] / refspec.c
index 8d0affc34a6b8c6c22a43e18e5cd40c8c0055a26..8af357a0a35d15267fb217337b3957be18577459 100644 (file)
--- a/refspec.c
+++ b/refspec.c
@@ -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;
 
@@ -223,7 +253,7 @@ void refspec_ref_prefixes(const struct refspec *rs,
                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;