diff options
Diffstat (limited to 'builtin/remote.c')
| -rw-r--r-- | builtin/remote.c | 679 |
1 files changed, 408 insertions, 271 deletions
diff --git a/builtin/remote.c b/builtin/remote.c index 79b0326446..729f6f3643 100644 --- a/builtin/remote.c +++ b/builtin/remote.c @@ -6,16 +6,18 @@ #include "string-list.h" #include "strbuf.h" #include "run-command.h" +#include "rebase.h" #include "refs.h" #include "refspec.h" #include "object-store.h" -#include "argv-array.h" +#include "strvec.h" #include "commit-reach.h" +#include "progress.h" static const char * const builtin_remote_usage[] = { - N_("git remote [-v | --verbose]"), + "git remote [-v | --verbose]", N_("git remote add [-t <branch>] [-m <master>] [-f] [--tags | --no-tags] [--mirror=<fetch|push>] <name> <url>"), - N_("git remote rename <old> <new>"), + N_("git remote rename [--[no-]progress] <old> <new>"), N_("git remote remove <name>"), N_("git remote set-head <name> (-a | --auto | -d | --delete | <branch>)"), N_("git remote [-v | --verbose] show [-n] <name>"), @@ -35,7 +37,7 @@ static const char * const builtin_remote_add_usage[] = { }; static const char * const builtin_remote_rename_usage[] = { - N_("git remote rename <old> <new>"), + N_("git remote rename [--[no-]progress] <old> <new>"), NULL }; @@ -90,13 +92,15 @@ static int verbose; static int fetch_remote(const char *name) { - const char *argv[] = { "fetch", name, NULL, NULL }; - if (verbose) { - argv[1] = "-v"; - argv[2] = name; - } + struct child_process cmd = CHILD_PROCESS_INIT; + + strvec_push(&cmd.args, "fetch"); + if (verbose) + strvec_push(&cmd.args, "-v"); + strvec_push(&cmd.args, name); + cmd.git_cmd = 1; printf_ln(_("Updating %s"), name); - if (run_command_v_opt(argv, RUN_GIT_CMD)) + if (run_command(&cmd)) return error(_("Could not fetch %s"), name); return 0; } @@ -148,7 +152,7 @@ static int parse_mirror_opt(const struct option *opt, const char *arg, int not) return 0; } -static int add(int argc, const char **argv) +static int add(int argc, const char **argv, const char *prefix) { int fetch = 0, fetch_tags = TAGS_DEFAULT; unsigned mirror = MIRROR_NONE; @@ -169,14 +173,14 @@ static int add(int argc, const char **argv) OPT_STRING_LIST('t', "track", &track, N_("branch"), N_("branch(es) to track")), OPT_STRING('m', "master", &master, N_("branch"), N_("master branch")), - { OPTION_CALLBACK, 0, "mirror", &mirror, N_("push|fetch"), + OPT_CALLBACK_F(0, "mirror", &mirror, "(push|fetch)", N_("set up remote as a mirror to push to or fetch from"), - PARSE_OPT_OPTARG | PARSE_OPT_COMP_ARG, parse_mirror_opt }, + PARSE_OPT_OPTARG | PARSE_OPT_COMP_ARG, parse_mirror_opt), OPT_END() }; - argc = parse_options(argc, argv, NULL, options, builtin_remote_add_usage, - 0); + argc = parse_options(argc, argv, prefix, options, + builtin_remote_add_usage, 0); if (argc != 2) usage_with_options(builtin_remote_add_usage, options); @@ -190,11 +194,12 @@ static int add(int argc, const char **argv) url = argv[1]; remote = remote_get(name); - if (remote_is_configured(remote, 1)) - die(_("remote %s already exists."), name); + if (remote_is_configured(remote, 1)) { + error(_("remote %s already exists."), name); + exit(3); + } - strbuf_addf(&buf2, "refs/heads/test:refs/remotes/%s/test", name); - if (!valid_fetch_refspec(buf2.buf)) + if (!valid_remote_name(name)) die(_("'%s' is not a valid remote name"), name); strbuf_addf(&buf, "remote.%s.url", name); @@ -219,7 +224,7 @@ static int add(int argc, const char **argv) if (fetch_tags != TAGS_DEFAULT) { strbuf_reset(&buf); - strbuf_addf(&buf, "remote.%s.tagopt", name); + strbuf_addf(&buf, "remote.%s.tagOpt", name); git_config_set(buf.buf, fetch_tags == TAGS_SET ? "--tags" : "--no-tags"); } @@ -248,9 +253,8 @@ static int add(int argc, const char **argv) struct branch_info { char *remote_name; struct string_list merge; - enum { - NO_REBASE, NORMAL_REBASE, INTERACTIVE_REBASE, REBASE_MERGES - } rebase; + enum rebase_type rebase; + char *push_remote_name; }; static struct string_list branch_list = STRING_LIST_INIT_NODUP; @@ -262,61 +266,75 @@ static const char *abbrev_ref(const char *name, const char *prefix) } #define abbrev_branch(name) abbrev_ref((name), "refs/heads/") -static int config_read_branches(const char *key, const char *value, void *cb) +static int config_read_branches(const char *key, const char *value, + void *data UNUSED) { - if (starts_with(key, "branch.")) { - const char *orig_key = key; - char *name; - struct string_list_item *item; - struct branch_info *info; - enum { REMOTE, MERGE, REBASE } type; - size_t key_len; - - key += 7; - if (strip_suffix(key, ".remote", &key_len)) { - name = xmemdupz(key, key_len); - type = REMOTE; - } else if (strip_suffix(key, ".merge", &key_len)) { - name = xmemdupz(key, key_len); - type = MERGE; - } else if (strip_suffix(key, ".rebase", &key_len)) { - name = xmemdupz(key, key_len); - type = REBASE; - } else - return 0; + const char *orig_key = key; + char *name; + struct string_list_item *item; + struct branch_info *info; + enum { REMOTE, MERGE, REBASE, PUSH_REMOTE } type; + size_t key_len; - item = string_list_insert(&branch_list, name); + if (!starts_with(key, "branch.")) + return 0; - if (!item->util) - item->util = xcalloc(1, sizeof(struct branch_info)); - info = item->util; - if (type == REMOTE) { - if (info->remote_name) - warning(_("more than one %s"), orig_key); - info->remote_name = xstrdup(value); - } else if (type == MERGE) { - char *space = strchr(value, ' '); - value = abbrev_branch(value); - while (space) { - char *merge; - merge = xstrndup(value, space - value); - string_list_append(&info->merge, merge); - value = abbrev_branch(space + 1); - space = strchr(value, ' '); - } - string_list_append(&info->merge, xstrdup(value)); - } else { - int v = git_parse_maybe_bool(value); - if (v >= 0) - info->rebase = v; - else if (!strcmp(value, "preserve")) - info->rebase = NORMAL_REBASE; - else if (!strcmp(value, "merges")) - info->rebase = REBASE_MERGES; - else if (!strcmp(value, "interactive")) - info->rebase = INTERACTIVE_REBASE; + key += strlen("branch."); + if (strip_suffix(key, ".remote", &key_len)) + type = REMOTE; + else if (strip_suffix(key, ".merge", &key_len)) + type = MERGE; + else if (strip_suffix(key, ".rebase", &key_len)) + type = REBASE; + else if (strip_suffix(key, ".pushremote", &key_len)) + type = PUSH_REMOTE; + else + return 0; + name = xmemdupz(key, key_len); + + item = string_list_insert(&branch_list, name); + + if (!item->util) + item->util = xcalloc(1, sizeof(struct branch_info)); + info = item->util; + switch (type) { + case REMOTE: + if (info->remote_name) + warning(_("more than one %s"), orig_key); + info->remote_name = xstrdup(value); + break; + case MERGE: { + char *space = strchr(value, ' '); + value = abbrev_branch(value); + while (space) { + char *merge; + merge = xstrndup(value, space - value); + string_list_append(&info->merge, merge); + value = abbrev_branch(space + 1); + space = strchr(value, ' '); } + string_list_append(&info->merge, xstrdup(value)); + break; + } + case REBASE: + /* + * Consider invalid values as false and check the + * truth value with >= REBASE_TRUE. + */ + info->rebase = rebase_parse_value(value); + if (info->rebase == REBASE_INVALID) + warning(_("unhandled branch.%s.rebase=%s; assuming " + "'true'"), name, value); + break; + case PUSH_REMOTE: + if (info->push_remote_name) + warning(_("more than one %s"), orig_key); + info->push_remote_name = xstrdup(value); + break; + default: + BUG("unexpected type=%d", type); } + return 0; } @@ -329,10 +347,19 @@ static void read_branches(void) struct ref_states { struct remote *remote; - struct string_list new_refs, stale, tracked, heads, push; + struct string_list new_refs, skipped, stale, tracked, heads, push; int queried; }; +#define REF_STATES_INIT { \ + .new_refs = STRING_LIST_INIT_DUP, \ + .skipped = STRING_LIST_INIT_DUP, \ + .stale = STRING_LIST_INIT_DUP, \ + .tracked = STRING_LIST_INIT_DUP, \ + .heads = STRING_LIST_INIT_DUP, \ + .push = STRING_LIST_INIT_DUP, \ +} + static int get_ref_states(const struct ref *remote_refs, struct ref_states *states) { struct ref *fetch_map = NULL, **tail = &fetch_map; @@ -344,11 +371,10 @@ static int get_ref_states(const struct ref *remote_refs, struct ref_states *stat die(_("Could not get fetch map for refspec %s"), states->remote->fetch.raw[i]); - states->new_refs.strdup_strings = 1; - states->tracked.strdup_strings = 1; - states->stale.strdup_strings = 1; for (ref = fetch_map; ref; ref = ref->next) { - if (!ref->peer_ref || !ref_exists(ref->peer_ref->name)) + if (omit_name_by_refspec(ref->name, &states->remote->fetch)) + string_list_append(&states->skipped, abbrev_branch(ref->name)); + else if (!ref->peer_ref || !ref_exists(ref->peer_ref->name)) string_list_append(&states->new_refs, abbrev_branch(ref->name)); else string_list_append(&states->tracked, abbrev_branch(ref->name)); @@ -363,6 +389,7 @@ static int get_ref_states(const struct ref *remote_refs, struct ref_states *stat free_refs(fetch_map); string_list_sort(&states->new_refs); + string_list_sort(&states->skipped); string_list_sort(&states->tracked); string_list_sort(&states->stale); @@ -395,7 +422,6 @@ static int get_push_ref_states(const struct ref *remote_refs, match_push_refs(local_refs, &push_map, &remote->push, MATCH_REFS_NONE); - states->push.strdup_strings = 1; for (ref = push_map; ref; ref = ref->next) { struct string_list_item *item; struct push_info *info; @@ -413,7 +439,7 @@ static int get_push_ref_states(const struct ref *remote_refs, if (is_null_oid(&ref->new_oid)) { info->status = PUSH_STATUS_DELETE; - } else if (!oidcmp(&ref->old_oid, &ref->new_oid)) + } else if (oideq(&ref->old_oid, &ref->new_oid)) info->status = PUSH_STATUS_UPTODATE; else if (is_null_oid(&ref->old_oid)) info->status = PUSH_STATUS_CREATE; @@ -438,7 +464,6 @@ static int get_push_ref_states_noquery(struct ref_states *states) if (remote->mirror) return 0; - states->push.strdup_strings = 1; if (!remote->push.nr) { item = string_list_append(&states->push, _("(matching)")); info = item->util = xcalloc(1, sizeof(struct push_info)); @@ -468,10 +493,10 @@ static int get_head_names(const struct ref *remote_refs, struct ref_states *stat struct ref *fetch_map = NULL, **fetch_map_tail = &fetch_map; struct refspec_item refspec; + memset(&refspec, 0, sizeof(refspec)); refspec.force = 0; refspec.pattern = 1; refspec.src = refspec.dst = "refs/heads/*"; - states->heads.strdup_strings = 1; get_fetch_map(remote_refs, &refspec, &fetch_map_tail, 0); matches = guess_remote_head(find_ref_by_name(remote_refs, "HEAD"), fetch_map, 1); @@ -516,7 +541,8 @@ struct branches_for_remote { }; static int add_branch_for_removal(const char *refname, - const struct object_id *oid, int flags, void *cb_data) + const struct object_id *oid UNUSED, + int flags UNUSED, void *cb_data) { struct branches_for_remote *branches = cb_data; struct refspec_item refspec; @@ -554,10 +580,12 @@ struct rename_info { const char *old_name; const char *new_name; struct string_list *remote_branches; + uint32_t symrefs_nr; }; static int read_remote_branches(const char *refname, - const struct object_id *oid, int flags, void *cb_data) + const struct object_id *oid UNUSED, + int flags UNUSED, void *cb_data) { struct rename_info *rename = cb_data; struct strbuf buf = STRBUF_INIT; @@ -567,13 +595,15 @@ static int read_remote_branches(const char *refname, strbuf_addf(&buf, "refs/remotes/%s/", rename->old_name); if (starts_with(refname, buf.buf)) { - item = string_list_append(rename->remote_branches, xstrdup(refname)); + item = string_list_append(rename->remote_branches, refname); symref = resolve_ref_unsafe(refname, RESOLVE_REF_READING, NULL, &flag); - if (symref && (flag & REF_ISSYMREF)) + if (symref && (flag & REF_ISSYMREF)) { item->util = xstrdup(symref); - else + rename->symrefs_nr++; + } else { item->util = NULL; + } } strbuf_release(&buf); @@ -605,70 +635,131 @@ static int migrate_file(struct remote *remote) return 0; } -static int mv(int argc, const char **argv) +struct push_default_info +{ + const char *old_name; + enum config_scope scope; + struct strbuf origin; + int linenr; +}; + +static int config_read_push_default(const char *key, const char *value, + void *cb) { + struct push_default_info* info = cb; + if (strcmp(key, "remote.pushdefault") || + !value || strcmp(value, info->old_name)) + return 0; + + info->scope = current_config_scope(); + strbuf_reset(&info->origin); + strbuf_addstr(&info->origin, current_config_name()); + info->linenr = current_config_line(); + + return 0; +} + +static void handle_push_default(const char* old_name, const char* new_name) +{ + struct push_default_info push_default = { + old_name, CONFIG_SCOPE_UNKNOWN, STRBUF_INIT, -1 }; + git_config(config_read_push_default, &push_default); + if (push_default.scope >= CONFIG_SCOPE_COMMAND) + ; /* pass */ + else if (push_default.scope >= CONFIG_SCOPE_LOCAL) { + int result = git_config_set_gently("remote.pushDefault", + new_name); + if (new_name && result && result != CONFIG_NOTHING_SET) + die(_("could not set '%s'"), "remote.pushDefault"); + else if (!new_name && result && result != CONFIG_NOTHING_SET) + die(_("could not unset '%s'"), "remote.pushDefault"); + } else if (push_default.scope >= CONFIG_SCOPE_SYSTEM) { + /* warn */ + warning(_("The %s configuration remote.pushDefault in:\n" + "\t%s:%d\n" + "now names the non-existent remote '%s'"), + config_scope_name(push_default.scope), + push_default.origin.buf, push_default.linenr, + old_name); + } +} + + +static int mv(int argc, const char **argv, const char *prefix) +{ + int show_progress = isatty(2); struct option options[] = { + OPT_BOOL(0, "progress", &show_progress, N_("force progress reporting")), OPT_END() }; struct remote *oldremote, *newremote; struct strbuf buf = STRBUF_INIT, buf2 = STRBUF_INIT, buf3 = STRBUF_INIT, old_remote_context = STRBUF_INIT; - struct string_list remote_branches = STRING_LIST_INIT_NODUP; + struct string_list remote_branches = STRING_LIST_INIT_DUP; struct rename_info rename; - int i, refspec_updated = 0; + int i, refs_renamed_nr = 0, refspec_updated = 0; + struct progress *progress = NULL; - if (argc != 3) + argc = parse_options(argc, argv, prefix, options, + builtin_remote_rename_usage, 0); + + if (argc != 2) usage_with_options(builtin_remote_rename_usage, options); - rename.old_name = argv[1]; - rename.new_name = argv[2]; + rename.old_name = argv[0]; + rename.new_name = argv[1]; rename.remote_branches = &remote_branches; + rename.symrefs_nr = 0; oldremote = remote_get(rename.old_name); - if (!remote_is_configured(oldremote, 1)) - die(_("No such remote: %s"), rename.old_name); + if (!remote_is_configured(oldremote, 1)) { + error(_("No such remote: '%s'"), rename.old_name); + exit(2); + } if (!strcmp(rename.old_name, rename.new_name) && oldremote->origin != REMOTE_CONFIG) return migrate_file(oldremote); newremote = remote_get(rename.new_name); - if (remote_is_configured(newremote, 1)) - die(_("remote %s already exists."), rename.new_name); + if (remote_is_configured(newremote, 1)) { + error(_("remote %s already exists."), rename.new_name); + exit(3); + } - strbuf_addf(&buf, "refs/heads/test:refs/remotes/%s/test", rename.new_name); - if (!valid_fetch_refspec(buf.buf)) + if (!valid_remote_name(rename.new_name)) die(_("'%s' is not a valid remote name"), rename.new_name); - strbuf_reset(&buf); strbuf_addf(&buf, "remote.%s", rename.old_name); strbuf_addf(&buf2, "remote.%s", rename.new_name); if (git_config_rename_section(buf.buf, buf2.buf) < 1) return error(_("Could not rename config section '%s' to '%s'"), buf.buf, buf2.buf); - strbuf_reset(&buf); - strbuf_addf(&buf, "remote.%s.fetch", rename.new_name); - git_config_set_multivar(buf.buf, NULL, NULL, 1); - strbuf_addf(&old_remote_context, ":refs/remotes/%s/", rename.old_name); - for (i = 0; i < oldremote->fetch.raw_nr; i++) { - char *ptr; - - strbuf_reset(&buf2); - strbuf_addstr(&buf2, oldremote->fetch.raw[i]); - ptr = strstr(buf2.buf, old_remote_context.buf); - if (ptr) { - refspec_updated = 1; - strbuf_splice(&buf2, - ptr-buf2.buf + strlen(":refs/remotes/"), - strlen(rename.old_name), rename.new_name, - strlen(rename.new_name)); - } else - warning(_("Not updating non-default fetch refspec\n" - "\t%s\n" - "\tPlease update the configuration manually if necessary."), - buf2.buf); - - git_config_set_multivar(buf.buf, buf2.buf, "^$", 0); + if (oldremote->fetch.raw_nr) { + strbuf_reset(&buf); + strbuf_addf(&buf, "remote.%s.fetch", rename.new_name); + git_config_set_multivar(buf.buf, NULL, NULL, CONFIG_FLAGS_MULTI_REPLACE); + strbuf_addf(&old_remote_context, ":refs/remotes/%s/", rename.old_name); + for (i = 0; i < oldremote->fetch.raw_nr; i++) { + char *ptr; + + strbuf_reset(&buf2); + strbuf_addstr(&buf2, oldremote->fetch.raw[i]); + ptr = strstr(buf2.buf, old_remote_context.buf); + if (ptr) { + refspec_updated = 1; + strbuf_splice(&buf2, + ptr-buf2.buf + strlen(":refs/remotes/"), + strlen(rename.old_name), rename.new_name, + strlen(rename.new_name)); + } else + warning(_("Not updating non-default fetch refspec\n" + "\t%s\n" + "\tPlease update the configuration manually if necessary."), + buf2.buf); + + git_config_set_multivar(buf.buf, buf2.buf, "^$", 0); + } } read_branches(); @@ -680,6 +771,11 @@ static int mv(int argc, const char **argv) strbuf_addf(&buf, "branch.%s.remote", item->string); git_config_set(buf.buf, rename.new_name); } + if (info->push_remote_name && !strcmp(info->push_remote_name, rename.old_name)) { + strbuf_reset(&buf); + strbuf_addf(&buf, "branch.%s.pushRemote", item->string); + git_config_set(buf.buf, rename.new_name); + } } if (!refspec_updated) @@ -690,16 +786,26 @@ static int mv(int argc, const char **argv) * the new symrefs. */ for_each_ref(read_remote_branches, &rename); + if (show_progress) { + /* + * Count symrefs twice, since "renaming" them is done by + * deleting and recreating them in two separate passes. + */ + progress = start_progress(_("Renaming remote references"), + rename.remote_branches->nr + rename.symrefs_nr); + } for (i = 0; i < remote_branches.nr; i++) { struct string_list_item *item = remote_branches.items + i; - int flag = 0; - struct object_id oid; + struct strbuf referent = STRBUF_INIT; - read_ref_full(item->string, RESOLVE_REF_READING, &oid, &flag); - if (!(flag & REF_ISSYMREF)) + if (refs_read_symbolic_ref(get_main_ref_store(the_repository), item->string, + &referent)) continue; if (delete_ref(NULL, item->string, NULL, REF_NO_DEREF)) die(_("deleting '%s' failed"), item->string); + + strbuf_release(&referent); + display_progress(progress, ++refs_renamed_nr); } for (i = 0; i < remote_branches.nr; i++) { struct string_list_item *item = remote_branches.items + i; @@ -715,6 +821,7 @@ static int mv(int argc, const char **argv) item->string, buf.buf); if (rename_ref(item->string, buf.buf, buf2.buf)) die(_("renaming '%s' failed"), item->string); + display_progress(progress, ++refs_renamed_nr); } for (i = 0; i < remote_branches.nr; i++) { struct string_list_item *item = remote_branches.items + i; @@ -734,11 +841,17 @@ static int mv(int argc, const char **argv) item->string, buf.buf); if (create_symref(buf.buf, buf2.buf, buf3.buf)) die(_("creating '%s' failed"), buf.buf); + display_progress(progress, ++refs_renamed_nr); } + stop_progress(&progress); + string_list_clear(&remote_branches, 1); + + handle_push_default(rename.old_name, rename.new_name); + return 0; } -static int rm(int argc, const char **argv) +static int rm(int argc, const char **argv, const char *prefix) { struct option options[] = { OPT_END() @@ -756,12 +869,16 @@ static int rm(int argc, const char **argv) cb_data.skipped = &skipped; cb_data.keep = &known_remotes; - if (argc != 2) + argc = parse_options(argc, argv, prefix, options, + builtin_remote_rm_usage, 0); + if (argc != 1) usage_with_options(builtin_remote_rm_usage, options); - remote = remote_get(argv[1]); - if (!remote_is_configured(remote, 1)) - die(_("No such remote: %s"), argv[1]); + remote = remote_get(argv[0]); + if (!remote_is_configured(remote, 1)) { + error(_("No such remote: '%s'"), argv[0]); + exit(2); + } known_remotes.to_delete = remote; for_each_remote(add_known_remote, &known_remotes); @@ -781,6 +898,13 @@ static int rm(int argc, const char **argv) die(_("could not unset '%s'"), buf.buf); } } + if (info->push_remote_name && !strcmp(info->push_remote_name, remote->name)) { + strbuf_reset(&buf); + strbuf_addf(&buf, "branch.%s.pushremote", item->string); + result = git_config_set_gently(buf.buf, NULL); + if (result && result != CONFIG_NOTHING_SET) + die(_("could not unset '%s'"), buf.buf); + } } /* @@ -813,12 +937,14 @@ static int rm(int argc, const char **argv) strbuf_addf(&buf, "remote.%s", remote->name); if (git_config_rename_section(buf.buf, NULL) < 1) return error(_("Could not remove config section '%s'"), buf.buf); + + handle_push_default(remote->name, NULL); } return result; } -static void clear_push_info(void *util, const char *string) +static void clear_push_info(void *util, const char *string UNUSED) { struct push_info *info = util; free(info->dest); @@ -828,6 +954,7 @@ static void clear_push_info(void *util, const char *string) static void free_remote_ref_states(struct ref_states *states) { string_list_clear(&states->new_refs, 0); + string_list_clear(&states->skipped, 0); string_list_clear(&states->stale, 1); string_list_clear(&states->tracked, 0); string_list_clear(&states->heads, 0); @@ -835,7 +962,8 @@ static void free_remote_ref_states(struct ref_states *states) } static int append_ref_to_tracked_list(const char *refname, - const struct object_id *oid, int flags, void *cb_data) + const struct object_id *oid UNUSED, + int flags, void *cb_data) { struct ref_states *states = cb_data; struct refspec_item refspec; @@ -855,20 +983,19 @@ static int get_remote_ref_states(const char *name, struct ref_states *states, int query) { - struct transport *transport; - const struct ref *remote_refs; - states->remote = remote_get(name); if (!states->remote) - return error(_("No such remote: %s"), name); + return error(_("No such remote: '%s'"), name); read_branches(); if (query) { + struct transport *transport; + const struct ref *remote_refs; + transport = transport_get(states->remote, states->remote->url_nr > 0 ? states->remote->url[0] : NULL); remote_refs = transport_get_remote_refs(transport, NULL); - transport_disconnect(transport); states->queried = 1; if (query & GET_REF_STATES) @@ -877,6 +1004,7 @@ static int get_remote_ref_states(const char *name, get_head_names(remote_refs, states); if (query & GET_PUSH_REF_STATES) get_push_ref_states(remote_refs, states); + transport_disconnect(transport); } else { for_each_ref(append_ref_to_tracked_list, states); string_list_sort(&states->tracked); @@ -887,26 +1015,31 @@ static int get_remote_ref_states(const char *name, } struct show_info { - struct string_list *list; - struct ref_states *states; + struct string_list list; + struct ref_states states; int width, width2; int any_rebase; }; +#define SHOW_INFO_INIT { \ + .list = STRING_LIST_INIT_DUP, \ + .states = REF_STATES_INIT, \ +} + static int add_remote_to_show_info(struct string_list_item *item, void *cb_data) { struct show_info *info = cb_data; int n = strlen(item->string); if (n > info->width) info->width = n; - string_list_insert(info->list, item->string); + string_list_insert(&info->list, item->string); return 0; } static int show_remote_info_item(struct string_list_item *item, void *cb_data) { struct show_info *info = cb_data; - struct ref_states *states = info->states; + struct ref_states *states = &info->states; const char *name = item->string; if (states->queried) { @@ -917,6 +1050,8 @@ static int show_remote_info_item(struct string_list_item *item, void *cb_data) arg = states->remote->name; } else if (string_list_has_string(&states->tracked, name)) arg = _(" tracked"); + else if (string_list_has_string(&states->skipped, name)) + arg = _(" skipped"); else if (string_list_has_string(&states->stale, name)) arg = _(" stale (use 'git remote prune' to remove)"); else @@ -933,7 +1068,7 @@ static int show_remote_info_item(struct string_list_item *item, void *cb_data) static int add_local_to_show_info(struct string_list_item *branch_item, void *cb_data) { struct show_info *show_info = cb_data; - struct ref_states *states = show_info->states; + struct ref_states *states = &show_info->states; struct branch_info *branch_info = branch_item->util; struct string_list_item *item; int n; @@ -943,10 +1078,10 @@ static int add_local_to_show_info(struct string_list_item *branch_item, void *cb return 0; if ((n = strlen(branch_item->string)) > show_info->width) show_info->width = n; - if (branch_info->rebase) + if (branch_info->rebase >= REBASE_TRUE) show_info->any_rebase = 1; - item = string_list_insert(show_info->list, branch_item->string); + item = string_list_insert(&show_info->list, branch_item->string); item->util = branch_info; return 0; @@ -960,16 +1095,16 @@ static int show_local_info_item(struct string_list_item *item, void *cb_data) int width = show_info->width + 4; int i; - if (branch_info->rebase && branch_info->merge.nr > 1) { + if (branch_info->rebase >= REBASE_TRUE && branch_info->merge.nr > 1) { error(_("invalid branch.%s.merge; cannot rebase onto > 1 branch"), item->string); return 0; } printf(" %-*s ", show_info->width, item->string); - if (branch_info->rebase) { + if (branch_info->rebase >= REBASE_TRUE) { const char *msg; - if (branch_info->rebase == INTERACTIVE_REBASE) + if (branch_info->rebase == REBASE_INTERACTIVE) msg = _("rebases interactively onto remote %s"); else if (branch_info->rebase == REBASE_MERGES) msg = _("rebases interactively (with merges) onto " @@ -1001,7 +1136,7 @@ static int add_push_to_show_info(struct string_list_item *push_item, void *cb_da show_info->width = n; if ((n = strlen(push_info->dest)) > show_info->width2) show_info->width2 = n; - item = string_list_append(show_info->list, push_item->string); + item = string_list_append(&show_info->list, push_item->string); item->util = push_item->util; return 0; } @@ -1067,14 +1202,22 @@ static int show_push_info_item(struct string_list_item *item, void *cb_data) static int get_one_entry(struct remote *remote, void *priv) { struct string_list *list = priv; - struct strbuf url_buf = STRBUF_INIT; + struct strbuf remote_info_buf = STRBUF_INIT; const char **url; int i, url_nr; if (remote->url_nr > 0) { - strbuf_addf(&url_buf, "%s (fetch)", remote->url[0]); + struct strbuf promisor_config = STRBUF_INIT; + const char *partial_clone_filter = NULL; + + strbuf_addf(&promisor_config, "remote.%s.partialclonefilter", remote->name); + strbuf_addf(&remote_info_buf, "%s (fetch)", remote->url[0]); + if (!git_config_get_string_tmp(promisor_config.buf, &partial_clone_filter)) + strbuf_addf(&remote_info_buf, " [%s]", partial_clone_filter); + + strbuf_release(&promisor_config); string_list_append(list, remote->name)->util = - strbuf_detach(&url_buf, NULL); + strbuf_detach(&remote_info_buf, NULL); } else string_list_append(list, remote->name)->util = NULL; if (remote->pushurl_nr) { @@ -1086,9 +1229,9 @@ static int get_one_entry(struct remote *remote, void *priv) } for (i = 0; i < url_nr; i++) { - strbuf_addf(&url_buf, "%s (push)", url[i]); + strbuf_addf(&remote_info_buf, "%s (push)", url[i]); string_list_append(list, remote->name)->util = - strbuf_detach(&url_buf, NULL); + strbuf_detach(&remote_info_buf, NULL); } return 0; @@ -1096,10 +1239,9 @@ static int get_one_entry(struct remote *remote, void *priv) static int show_all(void) { - struct string_list list = STRING_LIST_INIT_NODUP; + struct string_list list = STRING_LIST_INIT_DUP; int result; - list.strdup_strings = 1; result = for_each_remote(get_one_entry, &list); if (!result) { @@ -1122,18 +1264,17 @@ static int show_all(void) return result; } -static int show(int argc, const char **argv) +static int show(int argc, const char **argv, const char *prefix) { int no_query = 0, result = 0, query_flag = 0; struct option options[] = { OPT_BOOL('n', NULL, &no_query, N_("do not query remotes")), OPT_END() }; - struct ref_states states; - struct string_list info_list = STRING_LIST_INIT_NODUP; - struct show_info info; + struct show_info info = SHOW_INFO_INIT; - argc = parse_options(argc, argv, NULL, options, builtin_remote_show_usage, + argc = parse_options(argc, argv, prefix, options, + builtin_remote_show_usage, 0); if (argc < 1) @@ -1142,26 +1283,22 @@ static int show(int argc, const char **argv) if (!no_query) query_flag = (GET_REF_STATES | GET_HEAD_NAMES | GET_PUSH_REF_STATES); - memset(&states, 0, sizeof(states)); - memset(&info, 0, sizeof(info)); - info.states = &states; - info.list = &info_list; for (; argc; argc--, argv++) { int i; const char **url; int url_nr; - get_remote_ref_states(*argv, &states, query_flag); + get_remote_ref_states(*argv, &info.states, query_flag); printf_ln(_("* remote %s"), *argv); - printf_ln(_(" Fetch URL: %s"), states.remote->url_nr > 0 ? - states.remote->url[0] : _("(no URL)")); - if (states.remote->pushurl_nr) { - url = states.remote->pushurl; - url_nr = states.remote->pushurl_nr; + printf_ln(_(" Fetch URL: %s"), info.states.remote->url_nr > 0 ? + info.states.remote->url[0] : _("(no URL)")); + if (info.states.remote->pushurl_nr) { + url = info.states.remote->pushurl; + url_nr = info.states.remote->pushurl_nr; } else { - url = states.remote->url; - url_nr = states.remote->url_nr; + url = info.states.remote->url; + url_nr = info.states.remote->url_nr; } for (i = 0; i < url_nr; i++) /* @@ -1174,63 +1311,64 @@ static int show(int argc, const char **argv) printf_ln(_(" Push URL: %s"), _("(no URL)")); if (no_query) printf_ln(_(" HEAD branch: %s"), _("(not queried)")); - else if (!states.heads.nr) + else if (!info.states.heads.nr) printf_ln(_(" HEAD branch: %s"), _("(unknown)")); - else if (states.heads.nr == 1) - printf_ln(_(" HEAD branch: %s"), states.heads.items[0].string); + else if (info.states.heads.nr == 1) + printf_ln(_(" HEAD branch: %s"), info.states.heads.items[0].string); else { printf(_(" HEAD branch (remote HEAD is ambiguous," " may be one of the following):\n")); - for (i = 0; i < states.heads.nr; i++) - printf(" %s\n", states.heads.items[i].string); + for (i = 0; i < info.states.heads.nr; i++) + printf(" %s\n", info.states.heads.items[i].string); } /* remote branch info */ info.width = 0; - for_each_string_list(&states.new_refs, add_remote_to_show_info, &info); - for_each_string_list(&states.tracked, add_remote_to_show_info, &info); - for_each_string_list(&states.stale, add_remote_to_show_info, &info); - if (info.list->nr) + for_each_string_list(&info.states.new_refs, add_remote_to_show_info, &info); + for_each_string_list(&info.states.skipped, add_remote_to_show_info, &info); + for_each_string_list(&info.states.tracked, add_remote_to_show_info, &info); + for_each_string_list(&info.states.stale, add_remote_to_show_info, &info); + if (info.list.nr) printf_ln(Q_(" Remote branch:%s", " Remote branches:%s", - info.list->nr), + info.list.nr), no_query ? _(" (status not queried)") : ""); - for_each_string_list(info.list, show_remote_info_item, &info); - string_list_clear(info.list, 0); + for_each_string_list(&info.list, show_remote_info_item, &info); + string_list_clear(&info.list, 0); /* git pull info */ info.width = 0; info.any_rebase = 0; for_each_string_list(&branch_list, add_local_to_show_info, &info); - if (info.list->nr) + if (info.list.nr) printf_ln(Q_(" Local branch configured for 'git pull':", " Local branches configured for 'git pull':", - info.list->nr)); - for_each_string_list(info.list, show_local_info_item, &info); - string_list_clear(info.list, 0); + info.list.nr)); + for_each_string_list(&info.list, show_local_info_item, &info); + string_list_clear(&info.list, 0); /* git push info */ - if (states.remote->mirror) + if (info.states.remote->mirror) printf_ln(_(" Local refs will be mirrored by 'git push'")); info.width = info.width2 = 0; - for_each_string_list(&states.push, add_push_to_show_info, &info); - QSORT(info.list->items, info.list->nr, cmp_string_with_push); - if (info.list->nr) + for_each_string_list(&info.states.push, add_push_to_show_info, &info); + QSORT(info.list.items, info.list.nr, cmp_string_with_push); + if (info.list.nr) printf_ln(Q_(" Local ref configured for 'git push'%s:", " Local refs configured for 'git push'%s:", - info.list->nr), + info.list.nr), no_query ? _(" (status not queried)") : ""); - for_each_string_list(info.list, show_push_info_item, &info); - string_list_clear(info.list, 0); + for_each_string_list(&info.list, show_push_info_item, &info); + string_list_clear(&info.list, 0); - free_remote_ref_states(&states); + free_remote_ref_states(&info.states); } return result; } -static int set_head(int argc, const char **argv) +static int set_head(int argc, const char **argv, const char *prefix) { int i, opt_a = 0, opt_d = 0, result = 0; struct strbuf buf = STRBUF_INIT, buf2 = STRBUF_INIT; @@ -1243,16 +1381,15 @@ static int set_head(int argc, const char **argv) N_("delete refs/remotes/<name>/HEAD")), OPT_END() }; - argc = parse_options(argc, argv, NULL, options, builtin_remote_sethead_usage, - 0); + argc = parse_options(argc, argv, prefix, options, + builtin_remote_sethead_usage, 0); if (argc) strbuf_addf(&buf, "refs/remotes/%s/HEAD", argv[0]); if (!opt_a && !opt_d && argc == 2) { head_name = xstrdup(argv[1]); } else if (opt_a && !opt_d && argc == 1) { - struct ref_states states; - memset(&states, 0, sizeof(states)); + struct ref_states states = REF_STATES_INIT; get_remote_ref_states(argv[0], &states, GET_HEAD_NAMES); if (!states.heads.nr) result |= error(_("Cannot determine remote HEAD")); @@ -1278,7 +1415,7 @@ static int set_head(int argc, const char **argv) result |= error(_("Not a valid ref: %s"), buf2.buf); else if (create_symref(buf.buf, buf2.buf, "remote set-head")) result |= error(_("Could not setup %s"), buf.buf); - if (opt_a) + else if (opt_a) printf("%s/HEAD set to %s\n", argv[0], head_name); free(head_name); } @@ -1291,14 +1428,13 @@ static int set_head(int argc, const char **argv) static int prune_remote(const char *remote, int dry_run) { int result = 0; - struct ref_states states; + struct ref_states states = REF_STATES_INIT; struct string_list refs_to_prune = STRING_LIST_INIT_NODUP; struct string_list_item *item; const char *dangling_msg = dry_run ? _(" %s will become dangling!") : _(" %s has become dangling!"); - memset(&states, 0, sizeof(states)); get_remote_ref_states(remote, &states, GET_REF_STATES); if (!states.stale.nr) { @@ -1337,7 +1473,7 @@ static int prune_remote(const char *remote, int dry_run) return result; } -static int prune(int argc, const char **argv) +static int prune(int argc, const char **argv, const char *prefix) { int dry_run = 0, result = 0; struct option options[] = { @@ -1345,8 +1481,8 @@ static int prune(int argc, const char **argv) OPT_END() }; - argc = parse_options(argc, argv, NULL, options, builtin_remote_prune_usage, - 0); + argc = parse_options(argc, argv, prefix, options, + builtin_remote_prune_usage, 0); if (argc < 1) usage_with_options(builtin_remote_prune_usage, options); @@ -1357,7 +1493,7 @@ static int prune(int argc, const char **argv) return result; } -static int get_remote_default(const char *key, const char *value, void *priv) +static int get_remote_default(const char *key, const char *value UNUSED, void *priv) { if (strcmp(key, "remotes.default") == 0) { int *found = priv; @@ -1366,7 +1502,7 @@ static int get_remote_default(const char *key, const char *value, void *priv) return 0; } -static int update(int argc, const char **argv) +static int update(int argc, const char **argv, const char *prefix) { int i, prune = -1; struct option options[] = { @@ -1374,41 +1510,41 @@ static int update(int argc, const char **argv) N_("prune remotes after fetching")), OPT_END() }; - struct argv_array fetch_argv = ARGV_ARRAY_INIT; + struct child_process cmd = CHILD_PROCESS_INIT; int default_defined = 0; - int retval; - argc = parse_options(argc, argv, NULL, options, builtin_remote_update_usage, + argc = parse_options(argc, argv, prefix, options, + builtin_remote_update_usage, PARSE_OPT_KEEP_ARGV0); - argv_array_push(&fetch_argv, "fetch"); + strvec_push(&cmd.args, "fetch"); if (prune != -1) - argv_array_push(&fetch_argv, prune ? "--prune" : "--no-prune"); + strvec_push(&cmd.args, prune ? "--prune" : "--no-prune"); if (verbose) - argv_array_push(&fetch_argv, "-v"); - argv_array_push(&fetch_argv, "--multiple"); + strvec_push(&cmd.args, "-v"); + strvec_push(&cmd.args, "--multiple"); if (argc < 2) - argv_array_push(&fetch_argv, "default"); + strvec_push(&cmd.args, "default"); for (i = 1; i < argc; i++) - argv_array_push(&fetch_argv, argv[i]); + strvec_push(&cmd.args, argv[i]); - if (strcmp(fetch_argv.argv[fetch_argv.argc-1], "default") == 0) { + if (strcmp(cmd.args.v[cmd.args.nr-1], "default") == 0) { git_config(get_remote_default, &default_defined); if (!default_defined) { - argv_array_pop(&fetch_argv); - argv_array_push(&fetch_argv, "--all"); + strvec_pop(&cmd.args); + strvec_push(&cmd.args, "--all"); } } - retval = run_command_v_opt(fetch_argv.argv, RUN_GIT_CMD); - argv_array_clear(&fetch_argv); - return retval; + cmd.git_cmd = 1; + return run_command(&cmd); } -static int remove_all_fetch_refspecs(const char *remote, const char *key) +static int remove_all_fetch_refspecs(const char *key) { - return git_config_set_multivar_gently(key, NULL, NULL, 1); + return git_config_set_multivar_gently(key, NULL, NULL, + CONFIG_FLAGS_MULTI_REPLACE); } static void add_branches(struct remote *remote, const char **branches, @@ -1433,10 +1569,12 @@ static int set_remote_branches(const char *remotename, const char **branches, strbuf_addf(&key, "remote.%s.fetch", remotename); remote = remote_get(remotename); - if (!remote_is_configured(remote, 1)) - die(_("No such remote '%s'"), remotename); + if (!remote_is_configured(remote, 1)) { + error(_("No such remote '%s'"), remotename); + exit(2); + } - if (!add_mode && remove_all_fetch_refspecs(remotename, key.buf)) { + if (!add_mode && remove_all_fetch_refspecs(key.buf)) { strbuf_release(&key); return 1; } @@ -1446,7 +1584,7 @@ static int set_remote_branches(const char *remotename, const char **branches, return 0; } -static int set_branches(int argc, const char **argv) +static int set_branches(int argc, const char **argv, const char *prefix) { int add_mode = 0; struct option options[] = { @@ -1454,7 +1592,7 @@ static int set_branches(int argc, const char **argv) OPT_END() }; - argc = parse_options(argc, argv, NULL, options, + argc = parse_options(argc, argv, prefix, options, builtin_remote_setbranches_usage, 0); if (argc == 0) { error(_("no remote specified")); @@ -1465,7 +1603,7 @@ static int set_branches(int argc, const char **argv) return set_remote_branches(argv[0], argv + 1, add_mode); } -static int get_url(int argc, const char **argv) +static int get_url(int argc, const char **argv, const char *prefix) { int i, push_mode = 0, all_mode = 0; const char *remotename = NULL; @@ -1479,7 +1617,8 @@ static int get_url(int argc, const char **argv) N_("return all URLs")), OPT_END() }; - argc = parse_options(argc, argv, NULL, options, builtin_remote_geturl_usage, 0); + argc = parse_options(argc, argv, prefix, options, + builtin_remote_geturl_usage, 0); if (argc != 1) usage_with_options(builtin_remote_geturl_usage, options); @@ -1487,8 +1626,10 @@ static int get_url(int argc, const char **argv) remotename = argv[0]; remote = remote_get(remotename); - if (!remote_is_configured(remote, 1)) - die(_("No such remote '%s'"), remotename); + if (!remote_is_configured(remote, 1)) { + error(_("No such remote '%s'"), remotename); + exit(2); + } url_nr = 0; if (push_mode) { @@ -1516,7 +1657,7 @@ static int get_url(int argc, const char **argv) return 0; } -static int set_url(int argc, const char **argv) +static int set_url(int argc, const char **argv, const char *prefix) { int i, push_mode = 0, add_mode = 0, delete_mode = 0; int matches = 0, negative_matches = 0; @@ -1537,7 +1678,8 @@ static int set_url(int argc, const char **argv) N_("delete URLs")), OPT_END() }; - argc = parse_options(argc, argv, NULL, options, builtin_remote_seturl_usage, + argc = parse_options(argc, argv, prefix, options, + builtin_remote_seturl_usage, PARSE_OPT_KEEP_ARGV0); if (add_mode && delete_mode) @@ -1555,8 +1697,10 @@ static int set_url(int argc, const char **argv) oldurl = newurl; remote = remote_get(remotename); - if (!remote_is_configured(remote, 1)) - die(_("No such remote '%s'"), remotename); + if (!remote_is_configured(remote, 1)) { + error(_("No such remote '%s'"), remotename); + exit(2); + } if (push_mode) { strbuf_addf(&name_buf, "remote.%s.pushurl", remotename); @@ -1597,7 +1741,8 @@ static int set_url(int argc, const char **argv) if (!delete_mode) git_config_set_multivar(name_buf.buf, newurl, oldurl, 0); else - git_config_set_multivar(name_buf.buf, NULL, oldurl, 1); + git_config_set_multivar(name_buf.buf, NULL, oldurl, + CONFIG_FLAGS_MULTI_REPLACE); out: strbuf_release(&name_buf); return 0; @@ -1605,41 +1750,33 @@ out: int cmd_remote(int argc, const char **argv, const char *prefix) { + parse_opt_subcommand_fn *fn = NULL; struct option options[] = { OPT__VERBOSE(&verbose, N_("be verbose; must be placed before a subcommand")), + OPT_SUBCOMMAND("add", &fn, add), + OPT_SUBCOMMAND("rename", &fn, mv), + OPT_SUBCOMMAND_F("rm", &fn, rm, PARSE_OPT_NOCOMPLETE), + OPT_SUBCOMMAND("remove", &fn, rm), + OPT_SUBCOMMAND("set-head", &fn, set_head), + OPT_SUBCOMMAND("set-branches", &fn, set_branches), + OPT_SUBCOMMAND("get-url", &fn, get_url), + OPT_SUBCOMMAND("set-url", &fn, set_url), + OPT_SUBCOMMAND("show", &fn, show), + OPT_SUBCOMMAND("prune", &fn, prune), + OPT_SUBCOMMAND("update", &fn, update), OPT_END() }; - int result; argc = parse_options(argc, argv, prefix, options, builtin_remote_usage, - PARSE_OPT_STOP_AT_NON_OPTION); + PARSE_OPT_SUBCOMMAND_OPTIONAL); - if (argc < 1) - result = show_all(); - else if (!strcmp(argv[0], "add")) - result = add(argc, argv); - else if (!strcmp(argv[0], "rename")) - result = mv(argc, argv); - else if (!strcmp(argv[0], "rm") || !strcmp(argv[0], "remove")) - result = rm(argc, argv); - else if (!strcmp(argv[0], "set-head")) - result = set_head(argc, argv); - else if (!strcmp(argv[0], "set-branches")) - result = set_branches(argc, argv); - else if (!strcmp(argv[0], "get-url")) - result = get_url(argc, argv); - else if (!strcmp(argv[0], "set-url")) - result = set_url(argc, argv); - else if (!strcmp(argv[0], "show")) - result = show(argc, argv); - else if (!strcmp(argv[0], "prune")) - result = prune(argc, argv); - else if (!strcmp(argv[0], "update")) - result = update(argc, argv); - else { - error(_("Unknown subcommand: %s"), argv[0]); - usage_with_options(builtin_remote_usage, options); + if (fn) { + return !!fn(argc, argv, prefix); + } else { + if (argc) { + error(_("unknown subcommand: `%s'"), argv[0]); + usage_with_options(builtin_remote_usage, options); + } + return !!show_all(); } - - return result ? 1 : 0; } |
