Merge branch 'js/test-ln-s-add'
[gitweb.git] / builtin / fetch.c
index 4b6b1dfe66952a7e3fb1516e7e14473febde3d2d..d784b2e6947f1b5ace0016d92258e29377e9d1a7 100644 (file)
@@ -119,7 +119,7 @@ static void add_merge_config(struct ref **head,
 
                for (rm = *head; rm; rm = rm->next) {
                        if (branch_merge_matches(branch, i, rm->name)) {
-                               rm->merge = 1;
+                               rm->fetch_head_status = FETCH_HEAD_MERGE;
                                break;
                        }
                }
@@ -140,7 +140,7 @@ static void add_merge_config(struct ref **head,
                refspec.src = branch->merge[i]->src;
                get_fetch_map(remote_refs, &refspec, tail, 1);
                for (rm = *old_tail; rm; rm = rm->next)
-                       rm->merge = 1;
+                       rm->fetch_head_status = FETCH_HEAD_MERGE;
        }
 }
 
@@ -160,6 +160,8 @@ static struct ref *get_ref_map(struct transport *transport,
        const struct ref *remote_refs = transport_get_remote_refs(transport);
 
        if (ref_count || tags == TAGS_SET) {
+               struct ref **old_tail;
+
                for (i = 0; i < ref_count; i++) {
                        get_fetch_map(remote_refs, &refs[i], &tail, 0);
                        if (refs[i].dst && refs[i].dst[0])
@@ -167,9 +169,23 @@ static struct ref *get_ref_map(struct transport *transport,
                }
                /* Merge everything on the command line, but not --tags */
                for (rm = ref_map; rm; rm = rm->next)
-                       rm->merge = 1;
+                       rm->fetch_head_status = FETCH_HEAD_MERGE;
                if (tags == TAGS_SET)
                        get_fetch_map(remote_refs, tag_refspec, &tail, 0);
+
+               /*
+                * For any refs that we happen to be fetching via command-line
+                * arguments, take the opportunity to update their configured
+                * counterparts. However, we do not want to mention these
+                * entries in FETCH_HEAD at all, as they would simply be
+                * duplicates of existing entries.
+                */
+               old_tail = tail;
+               for (i = 0; i < transport->remote->fetch_refspec_nr; i++)
+                       get_fetch_map(ref_map, &transport->remote->fetch[i],
+                                     &tail, 1);
+               for (rm = *old_tail; rm; rm = rm->next)
+                       rm->fetch_head_status = FETCH_HEAD_IGNORE;
        } else {
                /* Use the defaults */
                struct remote *remote = transport->remote;
@@ -186,7 +202,7 @@ static struct ref *get_ref_map(struct transport *transport,
                                        *autotags = 1;
                                if (!i && !has_merge && ref_map &&
                                    !remote->fetch[0].pattern)
-                                       ref_map->merge = 1;
+                                       ref_map->fetch_head_status = FETCH_HEAD_MERGE;
                        }
                        /*
                         * if the remote we're fetching from is the same
@@ -202,7 +218,7 @@ static struct ref *get_ref_map(struct transport *transport,
                        ref_map = get_remote_ref(remote_refs, "HEAD");
                        if (!ref_map)
                                die(_("Couldn't find remote ref HEAD"));
-                       ref_map->merge = 1;
+                       ref_map->fetch_head_status = FETCH_HEAD_MERGE;
                        tail = &ref_map->next;
                }
        }
@@ -389,7 +405,7 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
        const char *what, *kind;
        struct ref *rm;
        char *url, *filename = dry_run ? "/dev/null" : git_path("FETCH_HEAD");
-       int want_merge;
+       int want_status;
 
        fp = fopen(filename, "a");
        if (!fp)
@@ -407,19 +423,22 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
        }
 
        /*
-        * The first pass writes objects to be merged and then the
-        * second pass writes the rest, in order to allow using
-        * FETCH_HEAD as a refname to refer to the ref to be merged.
+        * We do a pass for each fetch_head_status type in their enum order, so
+        * merged entries are written before not-for-merge. That lets readers
+        * use FETCH_HEAD as a refname to refer to the ref to be merged.
         */
-       for (want_merge = 1; 0 <= want_merge; want_merge--) {
+       for (want_status = FETCH_HEAD_MERGE;
+            want_status <= FETCH_HEAD_IGNORE;
+            want_status++) {
                for (rm = ref_map; rm; rm = rm->next) {
                        struct ref *ref = NULL;
+                       const char *merge_status_marker = "";
 
                        commit = lookup_commit_reference_gently(rm->old_sha1, 1);
                        if (!commit)
-                               rm->merge = 0;
+                               rm->fetch_head_status = FETCH_HEAD_NOT_FOR_MERGE;
 
-                       if (rm->merge != want_merge)
+                       if (rm->fetch_head_status != want_status)
                                continue;
 
                        if (rm->peer_ref) {
@@ -465,16 +484,26 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
                                        strbuf_addf(&note, "%s ", kind);
                                strbuf_addf(&note, "'%s' of ", what);
                        }
-                       fprintf(fp, "%s\t%s\t%s",
-                               sha1_to_hex(rm->old_sha1),
-                               rm->merge ? "" : "not-for-merge",
-                               note.buf);
-                       for (i = 0; i < url_len; ++i)
-                               if ('\n' == url[i])
-                                       fputs("\\n", fp);
-                               else
-                                       fputc(url[i], fp);
-                       fputc('\n', fp);
+                       switch (rm->fetch_head_status) {
+                       case FETCH_HEAD_NOT_FOR_MERGE:
+                               merge_status_marker = "not-for-merge";
+                               /* fall-through */
+                       case FETCH_HEAD_MERGE:
+                               fprintf(fp, "%s\t%s\t%s",
+                                       sha1_to_hex(rm->old_sha1),
+                                       merge_status_marker,
+                                       note.buf);
+                               for (i = 0; i < url_len; ++i)
+                                       if ('\n' == url[i])
+                                               fputs("\\n", fp);
+                                       else
+                                               fputc(url[i], fp);
+                               fputc('\n', fp);
+                               break;
+                       default:
+                               /* do not write anything to FETCH_HEAD */
+                               break;
+                       }
 
                        strbuf_reset(&note);
                        if (ref) {
@@ -571,7 +600,8 @@ static int add_existing(const char *refname, const unsigned char *sha1,
 {
        struct string_list *list = (struct string_list *)cbdata;
        struct string_list_item *item = string_list_insert(list, refname);
-       item->util = (void *)sha1;
+       item->util = xmalloc(20);
+       hashcpy(item->util, sha1);
        return 0;
 }
 
@@ -590,7 +620,7 @@ static void find_non_local_tags(struct transport *transport,
                        struct ref **head,
                        struct ref ***tail)
 {
-       struct string_list existing_refs = STRING_LIST_INIT_NODUP;
+       struct string_list existing_refs = STRING_LIST_INIT_DUP;
        struct string_list remote_refs = STRING_LIST_INIT_NODUP;
        const struct ref *ref;
        struct string_list_item *item = NULL;
@@ -636,7 +666,7 @@ static void find_non_local_tags(struct transport *transport,
                item = string_list_insert(&remote_refs, ref->name);
                item->util = (void *)ref->old_sha1;
        }
-       string_list_clear(&existing_refs, 0);
+       string_list_clear(&existing_refs, 1);
 
        /*
         * We may have a final lightweight tag that needs to be
@@ -693,11 +723,11 @@ static int truncate_fetch_head(void)
 static int do_fetch(struct transport *transport,
                    struct refspec *refs, int ref_count)
 {
-       struct string_list existing_refs = STRING_LIST_INIT_NODUP;
-       struct string_list_item *peer_item = NULL;
+       struct string_list existing_refs = STRING_LIST_INIT_DUP;
        struct ref *ref_map;
        struct ref *rm;
        int autotags = (transport->remote->fetch_tags == 1);
+       int retcode = 0;
 
        for_each_ref(add_existing, &existing_refs);
 
@@ -713,9 +743,9 @@ static int do_fetch(struct transport *transport,
 
        /* if not appending, truncate FETCH_HEAD */
        if (!append && !dry_run) {
-               int errcode = truncate_fetch_head();
-               if (errcode)
-                       return errcode;
+               retcode = truncate_fetch_head();
+               if (retcode)
+                       goto cleanup;
        }
 
        ref_map = get_ref_map(transport, refs, ref_count, tags, &autotags);
@@ -724,8 +754,9 @@ static int do_fetch(struct transport *transport,
 
        for (rm = ref_map; rm; rm = rm->next) {
                if (rm->peer_ref) {
-                       peer_item = string_list_lookup(&existing_refs,
-                                                      rm->peer_ref->name);
+                       struct string_list_item *peer_item =
+                               string_list_lookup(&existing_refs,
+                                                  rm->peer_ref->name);
                        if (peer_item)
                                hashcpy(rm->peer_ref->old_sha1,
                                        peer_item->util);
@@ -736,7 +767,8 @@ static int do_fetch(struct transport *transport,
                transport_set_option(transport, TRANS_OPT_FOLLOWTAGS, "1");
        if (fetch_refs(transport, ref_map)) {
                free_refs(ref_map);
-               return 1;
+               retcode = 1;
+               goto cleanup;
        }
        if (prune) {
                /* If --tags was specified, pretend the user gave us the canonical tags refspec */
@@ -779,7 +811,9 @@ static int do_fetch(struct transport *transport,
                free_refs(ref_map);
        }
 
-       return 0;
+ cleanup:
+       string_list_clear(&existing_refs, 1);
+       return retcode;
 }
 
 static void set_option(const char *name, const char *value)