diff options
Diffstat (limited to 'builtin/fetch.c')
| -rw-r--r-- | builtin/fetch.c | 124 |
1 files changed, 89 insertions, 35 deletions
diff --git a/builtin/fetch.c b/builtin/fetch.c index 4b5a89839b..d784b2e694 100644 --- a/builtin/fetch.c +++ b/builtin/fetch.c @@ -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(¬e, "%s ", kind); strbuf_addf(¬e, "'%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(¬e); if (ref) { @@ -568,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; } @@ -587,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; @@ -633,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 @@ -690,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); @@ -710,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); @@ -721,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); @@ -733,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 */ @@ -776,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) @@ -959,6 +996,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 +1010,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 +1078,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; } |
