archive: support filtering paths with glob
[gitweb.git] / remote.c
index a89efab5b766ba9374c3a09656b2d56593884c8e..ebed40dcb65df55ac81facbf5df59ddc28451872 100644 (file)
--- a/remote.c
+++ b/remote.c
@@ -49,6 +49,7 @@ static int branches_nr;
 
 static struct branch *current_branch;
 static const char *default_remote_name;
+static const char *branch_pushremote_name;
 static const char *pushremote_name;
 static int explicit_default_remote_name;
 
@@ -352,7 +353,7 @@ static int handle_config(const char *key, const char *value, void *cb)
                        }
                } else if (!strcmp(subkey, ".pushremote")) {
                        if (branch == current_branch)
-                               if (git_config_string(&pushremote_name, key, value))
+                               if (git_config_string(&branch_pushremote_name, key, value))
                                        return -1;
                } else if (!strcmp(subkey, ".merge")) {
                        if (!value)
@@ -492,6 +493,10 @@ static void read_config(void)
                        make_branch(head_ref + strlen("refs/heads/"), 0);
        }
        git_config(handle_config, NULL);
+       if (branch_pushremote_name) {
+               free((char *)pushremote_name);
+               pushremote_name = branch_pushremote_name;
+       }
        alias_all_urls();
 }
 
@@ -852,6 +857,32 @@ static int match_name_with_pattern(const char *key, const char *name,
        return ret;
 }
 
+static void query_refspecs_multiple(struct refspec *refs, int ref_count, struct refspec *query, struct string_list *results)
+{
+       int i;
+       int find_src = !query->src;
+
+       if (find_src && !query->dst)
+               error("query_refspecs_multiple: need either src or dst");
+
+       for (i = 0; i < ref_count; i++) {
+               struct refspec *refspec = &refs[i];
+               const char *key = find_src ? refspec->dst : refspec->src;
+               const char *value = find_src ? refspec->src : refspec->dst;
+               const char *needle = find_src ? query->dst : query->src;
+               char **result = find_src ? &query->src : &query->dst;
+
+               if (!refspec->dst)
+                       continue;
+               if (refspec->pattern) {
+                       if (match_name_with_pattern(key, needle, value, result))
+                               string_list_append_nodup(results, *result);
+               } else if (!strcmp(needle, key)) {
+                       string_list_append(results, value);
+               }
+       }
+}
+
 int query_refspecs(struct refspec *refs, int ref_count, struct refspec *query)
 {
        int i;
@@ -1000,7 +1031,7 @@ int count_refspec_match(const char *pattern,
                char *name = refs->name;
                int namelen = strlen(name);
 
-               if (!refname_match(pattern, name, ref_rev_parse_rules))
+               if (!refname_match(pattern, name))
                        continue;
 
                /* A match is "weak" if it is with refs outside
@@ -1404,7 +1435,7 @@ int match_push_refs(struct ref *src, struct ref **dst,
                                /*
                                 * Remote doesn't have it, and we have no
                                 * explicit pattern, and we don't have
-                                * --all nor --mirror.
+                                * --all or --mirror.
                                 */
                                goto free_name;
 
@@ -1571,7 +1602,7 @@ int branch_merge_matches(struct branch *branch,
 {
        if (!branch || i < 0 || i >= branch->merge_nr)
                return 0;
-       return refname_match(branch->merge[i]->src, refname, ref_fetch_rules);
+       return refname_match(branch->merge[i]->src, refname);
 }
 
 static int ignore_symref_update(const char *refname)
@@ -1624,7 +1655,7 @@ static const struct ref *find_ref_by_name_abbrev(const struct ref *refs, const c
 {
        const struct ref *ref;
        for (ref = refs; ref; ref = ref->next) {
-               if (refname_match(name, ref->name, ref_fetch_rules))
+               if (refname_match(name, ref->name))
                        return ref;
        }
        return NULL;
@@ -1992,25 +2023,37 @@ static int get_stale_heads_cb(const char *refname,
        const unsigned char *sha1, int flags, void *cb_data)
 {
        struct stale_heads_info *info = cb_data;
+       struct string_list matches = STRING_LIST_INIT_DUP;
        struct refspec query;
+       int i, stale = 1;
        memset(&query, 0, sizeof(struct refspec));
        query.dst = (char *)refname;
 
-       if (query_refspecs(info->refs, info->ref_count, &query))
-               return 0; /* No matches */
+       query_refspecs_multiple(info->refs, info->ref_count, &query, &matches);
+       if (matches.nr == 0)
+               goto clean_exit; /* No matches */
 
        /*
         * If we did find a suitable refspec and it's not a symref and
         * it's not in the list of refs that currently exist in that
-        * remote we consider it to be stale.
+        * remote, we consider it to be stale. In order to deal with
+        * overlapping refspecs, we need to go over all of the
+        * matching refs.
         */
-       if (!((flags & REF_ISSYMREF) ||
-             string_list_has_string(info->ref_names, query.src))) {
+       if (flags & REF_ISSYMREF)
+               goto clean_exit;
+
+       for (i = 0; stale && i < matches.nr; i++)
+               if (string_list_has_string(info->ref_names, matches.items[i].string))
+                       stale = 0;
+
+       if (stale) {
                struct ref *ref = make_linked_ref(refname, &info->stale_refs_tail);
                hashcpy(ref->new_sha1, sha1);
        }
 
-       free(query.src);
+clean_exit:
+       string_list_clear(&matches, 0);
        return 0;
 }
 
@@ -2121,7 +2164,7 @@ static void apply_cas(struct push_cas_option *cas,
        /* Find an explicit --<option>=<name>[:<value>] entry */
        for (i = 0; i < cas->nr; i++) {
                struct push_cas *entry = &cas->entry[i];
-               if (!refname_match(entry->refname, ref->name, ref_rev_parse_rules))
+               if (!refname_match(entry->refname, ref->name))
                        continue;
                ref->expect_old_sha1 = 1;
                if (!entry->use_tracking)