Merge branch 'rr/rebase-autostash'
[gitweb.git] / builtin / fetch.c
index 4b5a89839b66f201bda42f06cabdf781d44f0192..d15a7343d8384d05784aa5739dc758262f750a25 100644 (file)
@@ -32,7 +32,7 @@ enum {
 
 static int all, append, dry_run, force, keep, multiple, prune, update_head_ok, verbosity;
 static int progress = -1, recurse_submodules = RECURSE_SUBMODULES_DEFAULT;
-static int tags = TAGS_DEFAULT;
+static int tags = TAGS_DEFAULT, unshallow;
 static const char *depth;
 static const char *upload_pack;
 static struct strbuf default_rla = STRBUF_INIT;
@@ -82,6 +82,9 @@ static struct option builtin_fetch_options[] = {
        OPT_BOOL(0, "progress", &progress, N_("force progress reporting")),
        OPT_STRING(0, "depth", &depth, N_("depth"),
                   N_("deepen history of shallow clone")),
+       { OPTION_SET_INT, 0, "unshallow", &unshallow, NULL,
+                  N_("convert to a complete repository"),
+                  PARSE_OPT_NONEG | PARSE_OPT_NOARG, NULL, 1 },
        { OPTION_STRING, 0, "submodule-prefix", &submodule_prefix, N_("dir"),
                   N_("prepend this to submodule path output"), PARSE_OPT_HIDDEN },
        { OPTION_STRING, 0, "recurse-submodules-default",
@@ -116,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;
                        }
                }
@@ -137,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;
        }
 }
 
@@ -157,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])
@@ -164,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;
@@ -183,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
@@ -199,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;
                }
        }
@@ -386,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)
@@ -404,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) {
@@ -462,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) {
@@ -959,6 +991,9 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
        struct string_list list = STRING_LIST_INIT_NODUP;
        struct remote *remote;
        int result = 0;
+       static const char *argv_gc_auto[] = {
+               "gc", "--auto", NULL,
+       };
 
        packet_trace_identity("fetch");
 
@@ -970,6 +1005,18 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
        argc = parse_options(argc, argv, prefix,
                             builtin_fetch_options, builtin_fetch_usage, 0);
 
+       if (unshallow) {
+               if (depth)
+                       die(_("--depth and --unshallow cannot be used together"));
+               else if (!is_repository_shallow())
+                       die(_("--unshallow on a complete repository does not make sense"));
+               else {
+                       static char inf_depth[12];
+                       sprintf(inf_depth, "%d", INFINITE_DEPTH);
+                       depth = inf_depth;
+               }
+       }
+
        if (recurse_submodules != RECURSE_SUBMODULES_OFF) {
                if (recurse_submodules_default) {
                        int arg = parse_fetch_recurse_submodules_arg("--recurse-submodules-default", recurse_submodules_default);
@@ -1026,5 +1073,7 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
        list.strdup_strings = 1;
        string_list_clear(&list, 0);
 
+       run_command_v_opt(argv_gc_auto, RUN_GIT_CMD);
+
        return result;
 }