Merge branch 'js/remote-rename-with-half-configured-remote'
authorJunio C Hamano <gitster@pobox.com>
Tue, 31 Jan 2017 21:14:59 +0000 (13:14 -0800)
committerJunio C Hamano <gitster@pobox.com>
Tue, 31 Jan 2017 21:14:59 +0000 (13:14 -0800)
With anticipatory tweaking for remotes defined in ~/.gitconfig
(e.g. "remote.origin.prune" set to true, even though there may or
may not actually be "origin" remote defined in a particular Git
repository), "git remote rename" and other commands misinterpreted
and behaved as if such a non-existing remote actually existed.

* js/remote-rename-with-half-configured-remote:
remote rename: more carefully determine whether a remote is configured
remote rename: demonstrate a bogus "remote exists" bug

1  2 
builtin/fetch.c
builtin/remote.c
remote.c
diff --combined builtin/fetch.c
index f1570e346434e8695e80ba568c28b1363b2c0cb5,44de68564ac4d526b51fa4cac732e57e63eb69ad..b5ad09d0460cc7a51f35a56a4304e6a1fb26d26e
@@@ -35,15 -35,13 +35,15 @@@ static int fetch_prune_config = -1; /* 
  static int prune = -1; /* unspecified */
  #define PRUNE_BY_DEFAULT 0 /* do we prune by default? */
  
 -static int all, append, dry_run, force, keep, multiple, update_head_ok, verbosity;
 +static int all, append, dry_run, force, keep, multiple, update_head_ok, verbosity, deepen_relative;
  static int progress = -1, recurse_submodules = RECURSE_SUBMODULES_DEFAULT;
 -static int tags = TAGS_DEFAULT, unshallow, update_shallow;
 +static int tags = TAGS_DEFAULT, unshallow, update_shallow, deepen;
  static int max_children = -1;
  static enum transport_family family;
  static const char *depth;
 +static const char *deepen_since;
  static const char *upload_pack;
 +static struct string_list deepen_not = STRING_LIST_INIT_NODUP;
  static struct strbuf default_rla = STRBUF_INIT;
  static struct transport *gtransport;
  static struct transport *gsecondary;
@@@ -119,12 -117,6 +119,12 @@@ static struct option builtin_fetch_opti
        OPT_BOOL(0, "progress", &progress, N_("force progress reporting")),
        OPT_STRING(0, "depth", &depth, N_("depth"),
                   N_("deepen history of shallow clone")),
 +      OPT_STRING(0, "shallow-since", &deepen_since, N_("time"),
 +                 N_("deepen history of shallow repository based on time")),
 +      OPT_STRING_LIST(0, "shallow-exclude", &deepen_not, N_("revision"),
 +                      N_("deepen history of shallow clone, excluding rev")),
 +      OPT_INTEGER(0, "deepen", &deepen_relative,
 +                  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 },
@@@ -359,6 -351,9 +359,6 @@@ static struct ref *get_ref_map(struct t
  
                for (i = 0; i < fetch_refspec_nr; i++)
                        get_fetch_map(ref_map, &fetch_refspec[i], &oref_tail, 1);
 -
 -              if (tags == TAGS_SET)
 -                      get_fetch_map(remote_refs, tag_refspec, &tail, 0);
        } else if (refmap_array) {
                die("--refmap option is only meaningful with command-line refspec(s).");
        } else {
@@@ -574,12 -569,9 +574,12 @@@ static void print_compact(struct strbu
  
  static void format_display(struct strbuf *display, char code,
                           const char *summary, const char *error,
 -                         const char *remote, const char *local)
 +                         const char *remote, const char *local,
 +                         int summary_width)
  {
 -      strbuf_addf(display, "%c %-*s ", code, TRANSPORT_SUMMARY(summary));
 +      int width = (summary_width + strlen(summary) - gettext_width(summary));
 +
 +      strbuf_addf(display, "%c %-*s ", code, width, summary);
        if (!compact_format)
                print_remote_to_local(display, remote, local);
        else
  static int update_local_ref(struct ref *ref,
                            const char *remote,
                            const struct ref *remote_ref,
 -                          struct strbuf *display)
 +                          struct strbuf *display,
 +                          int summary_width)
  {
        struct commit *current = NULL, *updated;
        enum object_type type;
        if (!oidcmp(&ref->old_oid, &ref->new_oid)) {
                if (verbosity > 0)
                        format_display(display, '=', _("[up to date]"), NULL,
 -                                     remote, pretty_ref);
 +                                     remote, pretty_ref, summary_width);
                return 0;
        }
  
                 */
                format_display(display, '!', _("[rejected]"),
                               _("can't fetch in current branch"),
 -                             remote, pretty_ref);
 +                             remote, pretty_ref, summary_width);
                return 1;
        }
  
                r = s_update_ref("updating tag", ref, 0);
                format_display(display, r ? '!' : 't', _("[tag update]"),
                               r ? _("unable to update local ref") : NULL,
 -                             remote, pretty_ref);
 +                             remote, pretty_ref, summary_width);
                return r;
        }
  
                r = s_update_ref(msg, ref, 0);
                format_display(display, r ? '!' : '*', what,
                               r ? _("unable to update local ref") : NULL,
 -                             remote, pretty_ref);
 +                             remote, pretty_ref, summary_width);
                return r;
        }
  
                r = s_update_ref("fast-forward", ref, 1);
                format_display(display, r ? '!' : ' ', quickref.buf,
                               r ? _("unable to update local ref") : NULL,
 -                             remote, pretty_ref);
 +                             remote, pretty_ref, summary_width);
                strbuf_release(&quickref);
                return r;
        } else if (force || ref->force) {
                r = s_update_ref("forced-update", ref, 1);
                format_display(display, r ? '!' : '+', quickref.buf,
                               r ? _("unable to update local ref") : _("forced update"),
 -                             remote, pretty_ref);
 +                             remote, pretty_ref, summary_width);
                strbuf_release(&quickref);
                return r;
        } else {
                format_display(display, '!', _("[rejected]"), _("non-fast-forward"),
 -                             remote, pretty_ref);
 +                             remote, pretty_ref, summary_width);
                return 1;
        }
  }
@@@ -730,7 -721,6 +730,7 @@@ static int store_updated_refs(const cha
        char *url;
        const char *filename = dry_run ? "/dev/null" : git_path_fetch_head();
        int want_status;
 +      int summary_width = transport_summary_width(ref_map);
  
        fp = fopen(filename, "a");
        if (!fp)
  
                        strbuf_reset(&note);
                        if (ref) {
 -                              rc |= update_local_ref(ref, what, rm, &note);
 +                              rc |= update_local_ref(ref, what, rm, &note,
 +                                                     summary_width);
                                free(ref);
                        } else
                                format_display(&note, '*',
                                               *kind ? kind : "branch", NULL,
                                               *what ? what : "HEAD",
 -                                             "FETCH_HEAD");
 +                                             "FETCH_HEAD", summary_width);
                        if (note.len) {
                                if (verbosity >= 0 && !shown_url) {
                                        fprintf(stderr, _("From %.*s\n"),
@@@ -889,7 -878,7 +889,7 @@@ static int quickfetch(struct ref *ref_m
         * really need to perform.  Claiming failure now will ensure
         * we perform the network exchange to deepen our history.
         */
 -      if (depth)
 +      if (deepen)
                return -1;
        opt.quiet = 1;
        return check_connected(iterate_ref_map, &rm, &opt);
@@@ -914,7 -903,6 +914,7 @@@ static int prune_refs(struct refspec *r
        int url_len, i, result = 0;
        struct ref *ref, *stale_refs = get_stale_heads(refs, ref_count, ref_map);
        char *url;
 +      int summary_width = transport_summary_width(stale_refs);
        const char *dangling_msg = dry_run
                ? _("   (%s will become dangling)")
                : _("   (%s has become dangling)");
                                shown_url = 1;
                        }
                        format_display(&sb, '-', _("[deleted]"), NULL,
 -                                     _("(none)"), prettify_refname(ref->name));
 +                                     _("(none)"), prettify_refname(ref->name),
 +                                     summary_width);
                        fprintf(stderr, " %s\n",sb.buf);
                        strbuf_release(&sb);
                        warn_dangling_symref(stderr, dangling_msg, ref->name);
@@@ -999,7 -986,7 +999,7 @@@ static void set_option(struct transpor
                        name, transport->url);
  }
  
 -static struct transport *prepare_transport(struct remote *remote)
 +static struct transport *prepare_transport(struct remote *remote, int deepen)
  {
        struct transport *transport;
        transport = transport_get(remote, NULL);
                set_option(transport, TRANS_OPT_KEEP, "yes");
        if (depth)
                set_option(transport, TRANS_OPT_DEPTH, depth);
 +      if (deepen && deepen_since)
 +              set_option(transport, TRANS_OPT_DEEPEN_SINCE, deepen_since);
 +      if (deepen && deepen_not.nr)
 +              set_option(transport, TRANS_OPT_DEEPEN_NOT,
 +                         (const char *)&deepen_not);
 +      if (deepen_relative)
 +              set_option(transport, TRANS_OPT_DEEPEN_RELATIVE, "yes");
        if (update_shallow)
                set_option(transport, TRANS_OPT_UPDATE_SHALLOW, "yes");
        return transport;
  
  static void backfill_tags(struct transport *transport, struct ref *ref_map)
  {
 -      if (transport->cannot_reuse) {
 -              gsecondary = prepare_transport(transport->remote);
 +      int cannot_reuse;
 +
 +      /*
 +       * Once we have set TRANS_OPT_DEEPEN_SINCE, we can't unset it
 +       * when remote helper is used (setting it to an empty string
 +       * is not unsetting). We could extend the remote helper
 +       * protocol for that, but for now, just force a new connection
 +       * without deepen-since. Similar story for deepen-not.
 +       */
 +      cannot_reuse = transport->cannot_reuse ||
 +              deepen_since || deepen_not.nr;
 +      if (cannot_reuse) {
 +              gsecondary = prepare_transport(transport->remote, 0);
                transport = gsecondary;
        }
  
        transport_set_option(transport, TRANS_OPT_FOLLOWTAGS, NULL);
        transport_set_option(transport, TRANS_OPT_DEPTH, "0");
 +      transport_set_option(transport, TRANS_OPT_DEEPEN_RELATIVE, NULL);
        fetch_refs(transport, ref_map);
  
        if (gsecondary) {
@@@ -1177,7 -1145,7 +1177,7 @@@ static int add_remote_or_group(const ch
        git_config(get_remote_group, &g);
        if (list->nr == prev_nr) {
                struct remote *remote = remote_get(name);
-               if (!remote_is_configured(remote))
+               if (!remote_is_configured(remote, 0))
                        return 0;
                string_list_append(list, remote->name);
        }
@@@ -1254,7 -1222,7 +1254,7 @@@ static int fetch_one(struct remote *rem
                die(_("No remote repository specified.  Please, specify either a URL or a\n"
                    "remote name from which new revisions should be fetched."));
  
 -      gtransport = prepare_transport(remote);
 +      gtransport = prepare_transport(remote, 1);
  
        if (prune < 0) {
                /* no command line request */
@@@ -1314,13 -1282,6 +1314,13 @@@ int cmd_fetch(int argc, const char **ar
        argc = parse_options(argc, argv, prefix,
                             builtin_fetch_options, builtin_fetch_usage, 0);
  
 +      if (deepen_relative) {
 +              if (deepen_relative < 0)
 +                      die(_("Negative depth in --deepen is not supported"));
 +              if (depth)
 +                      die(_("--deepen and --depth are mutually exclusive"));
 +              depth = xstrfmt("%d", deepen_relative);
 +      }
        if (unshallow) {
                if (depth)
                        die(_("--depth and --unshallow cannot be used together"));
        /* no need to be strict, transport_set_option() will validate it again */
        if (depth && atoi(depth) < 1)
                die(_("depth %s is not a positive number"), depth);
 +      if (depth || deepen_since || deepen_not.nr)
 +              deepen = 1;
  
        if (recurse_submodules != RECURSE_SUBMODULES_OFF) {
                if (recurse_submodules_default) {
diff --combined builtin/remote.c
index e52cf3925b2388008221de6f7cbedeecd6cdd010,be1b62683aad76c2657af946bc212cbfdf2a2f21..5339ed6ad17bb0c83e05d3e60d654c4f0632ee50
@@@ -186,7 -186,7 +186,7 @@@ static int add(int argc, const char **a
        url = argv[1];
  
        remote = remote_get(name);
-       if (remote_is_configured(remote))
+       if (remote_is_configured(remote, 1))
                die(_("remote %s already exists."), name);
  
        strbuf_addf(&buf2, "refs/heads/test:refs/remotes/%s/test", name);
@@@ -618,14 -618,14 +618,14 @@@ static int mv(int argc, const char **ar
        rename.remote_branches = &remote_branches;
  
        oldremote = remote_get(rename.old);
-       if (!remote_is_configured(oldremote))
+       if (!remote_is_configured(oldremote, 1))
                die(_("No such remote: %s"), rename.old);
  
        if (!strcmp(rename.old, rename.new) && oldremote->origin != REMOTE_CONFIG)
                return migrate_file(oldremote);
  
        newremote = remote_get(rename.new);
-       if (remote_is_configured(newremote))
+       if (remote_is_configured(newremote, 1))
                die(_("remote %s already exists."), rename.new);
  
        strbuf_addf(&buf, "refs/heads/test:refs/remotes/%s/test", rename.new);
@@@ -753,7 -753,7 +753,7 @@@ static int rm(int argc, const char **ar
                usage_with_options(builtin_remote_rm_usage, options);
  
        remote = remote_get(argv[1]);
-       if (!remote_is_configured(remote))
+       if (!remote_is_configured(remote, 1))
                die(_("No such remote: %s"), argv[1]);
  
        known_remotes.to_delete = remote;
@@@ -1197,7 -1197,8 +1197,7 @@@ static int show(int argc, const char **
  
                info.width = info.width2 = 0;
                for_each_string_list(&states.push, add_push_to_show_info, &info);
 -              qsort(info.list->items, info.list->nr,
 -                      sizeof(*info.list->items), cmp_string_with_push);
 +              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:",
@@@ -1415,7 -1416,7 +1415,7 @@@ static int set_remote_branches(const ch
        strbuf_addf(&key, "remote.%s.fetch", remotename);
  
        remote = remote_get(remotename);
-       if (!remote_is_configured(remote))
+       if (!remote_is_configured(remote, 1))
                die(_("No such remote '%s'"), remotename);
  
        if (!add_mode && remove_all_fetch_refspecs(remotename, key.buf)) {
@@@ -1469,7 -1470,7 +1469,7 @@@ static int get_url(int argc, const cha
        remotename = argv[0];
  
        remote = remote_get(remotename);
-       if (!remote_is_configured(remote))
+       if (!remote_is_configured(remote, 1))
                die(_("No such remote '%s'"), remotename);
  
        url_nr = 0;
@@@ -1537,7 -1538,7 +1537,7 @@@ static int set_url(int argc, const cha
                oldurl = newurl;
  
        remote = remote_get(remotename);
-       if (!remote_is_configured(remote))
+       if (!remote_is_configured(remote, 1))
                die(_("No such remote '%s'"), remotename);
  
        if (push_mode) {
diff --combined remote.c
index d5eaec73742e74738c522cdc36ba9bf811b158b2,8524135de4286a079519068be17f0fe6fe7632f9..bf1bf2309128bf886eac16959b8162b9990c98d7
+++ b/remote.c
@@@ -255,6 -255,7 +255,7 @@@ static void read_remotes_file(struct re
  
        if (!f)
                return;
+       remote->configured_in_repo = 1;
        remote->origin = REMOTE_REMOTES;
        while (strbuf_getline(&buf, f) != EOF) {
                const char *v;
@@@ -289,6 -290,7 +290,7 @@@ static void read_branches_file(struct r
                return;
        }
  
+       remote->configured_in_repo = 1;
        remote->origin = REMOTE_BRANCHES;
  
        /*
@@@ -371,6 -373,8 +373,8 @@@ static int handle_config(const char *ke
        }
        remote = make_remote(name, namelen);
        remote->origin = REMOTE_CONFIG;
+       if (current_config_scope() == CONFIG_SCOPE_REPO)
+               remote->configured_in_repo = 1;
        if (!strcmp(subkey, "mirror"))
                remote->mirror = git_config_bool(key, value);
        else if (!strcmp(subkey, "skipdefaultupdate"))
@@@ -714,9 -718,13 +718,13 @@@ struct remote *pushremote_get(const cha
        return remote_get_1(name, pushremote_for_branch);
  }
  
- int remote_is_configured(struct remote *remote)
+ int remote_is_configured(struct remote *remote, int in_repo)
  {
-       return remote && remote->origin;
+       if (!remote)
+               return 0;
+       if (in_repo)
+               return remote->configured_in_repo;
+       return !!remote->origin;
  }
  
  int for_each_remote(each_remote_fn fn, void *priv)
@@@ -1716,6 -1724,9 +1724,6 @@@ static const char *branch_get_push_1(st
  {
        struct remote *remote;
  
 -      if (!branch)
 -              return error_buf(err, _("HEAD does not point to a branch"));
 -
        remote = remote_get(pushremote_for_branch(branch, NULL));
        if (!remote)
                return error_buf(err,
  
  const char *branch_get_push(struct branch *branch, struct strbuf *err)
  {
 +      if (!branch)
 +              return error_buf(err, _("HEAD does not point to a branch"));
 +
        if (!branch->push_tracking_ref)
                branch->push_tracking_ref = branch_get_push_1(branch, err);
        return branch->push_tracking_ref;