]> git.ipfire.org Git - thirdparty/git.git/blobdiff - remote.c
submodules: fix of regression on fetching of non-init subsub-repo
[thirdparty/git.git] / remote.c
index eafc14cbe759ed98096e68ce196013a3b026c67a..8be67f0892b47d0f31f9f1579c80ad6420721a7b 100644 (file)
--- a/remote.c
+++ b/remote.c
@@ -682,6 +682,91 @@ static int match_name_with_pattern(const char *key, const char *name,
        return ret;
 }
 
+static int refspec_match(const struct refspec_item *refspec,
+                        const char *name)
+{
+       if (refspec->pattern)
+               return match_name_with_pattern(refspec->src, name, NULL, NULL);
+
+       return !strcmp(refspec->src, name);
+}
+
+static int omit_name_by_refspec(const char *name, struct refspec *rs)
+{
+       int i;
+
+       for (i = 0; i < rs->nr; i++) {
+               if (rs->items[i].negative && refspec_match(&rs->items[i], name))
+                       return 1;
+       }
+       return 0;
+}
+
+struct ref *apply_negative_refspecs(struct ref *ref_map, struct refspec *rs)
+{
+       struct ref **tail;
+
+       for (tail = &ref_map; *tail; ) {
+               struct ref *ref = *tail;
+
+               if (omit_name_by_refspec(ref->name, rs)) {
+                       *tail = ref->next;
+                       free(ref->peer_ref);
+                       free(ref);
+               } else
+                       tail = &ref->next;
+       }
+
+       return ref_map;
+}
+
+static int query_matches_negative_refspec(struct refspec *rs, struct refspec_item *query)
+{
+       int i, matched_negative = 0;
+       int find_src = !query->src;
+       struct string_list reversed = STRING_LIST_INIT_NODUP;
+       const char *needle = find_src ? query->dst : query->src;
+
+       /*
+        * Check whether the queried ref matches any negative refpsec. If so,
+        * then we should ultimately treat this as not matching the query at
+        * all.
+        *
+        * Note that negative refspecs always match the source, but the query
+        * item uses the destination. To handle this, we apply pattern
+        * refspecs in reverse to figure out if the query source matches any
+        * of the negative refspecs.
+        */
+       for (i = 0; i < rs->nr; i++) {
+               struct refspec_item *refspec = &rs->items[i];
+               char *expn_name;
+
+               if (refspec->negative)
+                       continue;
+
+               /* Note the reversal of src and dst */
+               if (refspec->pattern) {
+                       const char *key = refspec->dst ? refspec->dst : refspec->src;
+                       const char *value = refspec->src;
+
+                       if (match_name_with_pattern(key, needle, value, &expn_name))
+                               string_list_append_nodup(&reversed, expn_name);
+               } else {
+                       if (!strcmp(needle, refspec->src))
+                               string_list_append(&reversed, refspec->src);
+               }
+       }
+
+       for (i = 0; !matched_negative && i < reversed.nr; i++) {
+               if (omit_name_by_refspec(reversed.items[i].string, rs))
+                       matched_negative = 1;
+       }
+
+       string_list_clear(&reversed, 0);
+
+       return matched_negative;
+}
+
 static void query_refspecs_multiple(struct refspec *rs,
                                    struct refspec_item *query,
                                    struct string_list *results)
@@ -692,6 +777,9 @@ static void query_refspecs_multiple(struct refspec *rs,
        if (find_src && !query->dst)
                BUG("query_refspecs_multiple: need either src or dst");
 
+       if (query_matches_negative_refspec(rs, query))
+               return;
+
        for (i = 0; i < rs->nr; i++) {
                struct refspec_item *refspec = &rs->items[i];
                const char *key = find_src ? refspec->dst : refspec->src;
@@ -699,7 +787,7 @@ static void query_refspecs_multiple(struct refspec *rs,
                const char *needle = find_src ? query->dst : query->src;
                char **result = find_src ? &query->src : &query->dst;
 
-               if (!refspec->dst)
+               if (!refspec->dst || refspec->negative)
                        continue;
                if (refspec->pattern) {
                        if (match_name_with_pattern(key, needle, value, result))
@@ -720,12 +808,15 @@ int query_refspecs(struct refspec *rs, struct refspec_item *query)
        if (find_src && !query->dst)
                BUG("query_refspecs: need either src or dst");
 
+       if (query_matches_negative_refspec(rs, query))
+               return -1;
+
        for (i = 0; i < rs->nr; i++) {
                struct refspec_item *refspec = &rs->items[i];
                const char *key = find_src ? refspec->dst : refspec->src;
                const char *value = find_src ? refspec->src : refspec->dst;
 
-               if (!refspec->dst)
+               if (!refspec->dst || refspec->negative)
                        continue;
                if (refspec->pattern) {
                        if (match_name_with_pattern(key, needle, value, result)) {
@@ -1054,7 +1145,7 @@ static int match_explicit(struct ref *src, struct ref *dst,
        const char *dst_value = rs->dst;
        char *dst_guess;
 
-       if (rs->pattern || rs->matching)
+       if (rs->pattern || rs->matching || rs->negative)
                return 0;
 
        matched_src = matched_dst = NULL;
@@ -1130,6 +1221,10 @@ static char *get_ref_match(const struct refspec *rs, const struct ref *ref,
        int matching_refs = -1;
        for (i = 0; i < rs->nr; i++) {
                const struct refspec_item *item = &rs->items[i];
+
+               if (item->negative)
+                       continue;
+
                if (item->matching &&
                    (matching_refs == -1 || item->force)) {
                        matching_refs = i;
@@ -1335,7 +1430,7 @@ int check_push_refs(struct ref *src, struct refspec *rs)
        for (i = 0; i < rs->nr; i++) {
                struct refspec_item *item = &rs->items[i];
 
-               if (item->pattern || item->matching)
+               if (item->pattern || item->matching || item->negative)
                        continue;
 
                ret |= match_explicit_lhs(src, item, NULL, NULL);
@@ -1437,6 +1532,8 @@ int match_push_refs(struct ref *src, struct ref **dst,
                string_list_clear(&src_ref_index, 0);
        }
 
+       *dst = apply_negative_refspecs(*dst, rs);
+
        if (errs)
                return -1;
        return 0;
@@ -1806,6 +1903,9 @@ int get_fetch_map(const struct ref *remote_refs,
 {
        struct ref *ref_map, **rmp;
 
+       if (refspec->negative)
+               return 0;
+
        if (refspec->pattern) {
                ref_map = get_expanded_map(remote_refs, refspec);
        } else {