Merge branch 'jc/abbrev-auto'
authorJunio C Hamano <gitster@pobox.com>
Thu, 27 Oct 2016 21:58:48 +0000 (14:58 -0700)
committerJunio C Hamano <gitster@pobox.com>
Thu, 27 Oct 2016 21:58:48 +0000 (14:58 -0700)
"git push" and "git fetch" reports from what old object to what new
object each ref was updated, using abbreviated refnames, and they
attempt to align the columns for this and other pieces of
information. The way these codepaths compute how many display
columns to allocate for the object names portion of this output has
been updated to match the recent "auto scale the default
abbreviation length" change.

* jc/abbrev-auto:
transport: compute summary-width dynamically
transport: allow summary-width to be computed dynamically
fetch: pass summary_width down the callchain
transport: pass summary_width down the callchain

1  2 
builtin/fetch.c
transport.c
transport.h
diff --combined builtin/fetch.c
index b2e113d387af821355c66d32642351db6bf0ccd1,09813cd826cbe0dfd196cb4ef120394f9b2a84a6..b6a5597cbf332fc56b5feabfd29d03c98d4d6686
@@@ -17,9 -17,6 +17,6 @@@
  #include "argv-array.h"
  #include "utf8.h"
  
- #define TRANSPORT_SUMMARY(x) \
-       (int)(TRANSPORT_SUMMARY_WIDTH + strlen(x) - gettext_width(x)), (x)
  static const char * const builtin_fetch_usage[] = {
        N_("git fetch [<options>] [<repository> [<refspec>...]]"),
        N_("git fetch [<options>] <group>"),
@@@ -38,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;
@@@ -122,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 by 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 },
@@@ -244,10 -233,9 +241,10 @@@ static void find_non_local_tags(struct 
                 * as one to ignore by setting util to NULL.
                 */
                if (ends_with(ref->name, "^{}")) {
 -                      if (item && !has_object_file(&ref->old_oid) &&
 +                      if (item &&
 +                          !has_object_file_with_flags(&ref->old_oid, HAS_SHA1_QUICK) &&
                            !will_fetch(head, ref->old_oid.hash) &&
 -                          !has_sha1_file(item->util) &&
 +                          !has_sha1_file_with_flags(item->util, HAS_SHA1_QUICK) &&
                            !will_fetch(head, item->util))
                                item->util = NULL;
                        item = NULL;
                 * to check if it is a lightweight tag that we want to
                 * fetch.
                 */
 -              if (item && !has_sha1_file(item->util) &&
 +              if (item &&
 +                  !has_sha1_file_with_flags(item->util, HAS_SHA1_QUICK) &&
                    !will_fetch(head, item->util))
                        item->util = NULL;
  
         * We may have a final lightweight tag that needs to be
         * checked to see if it needs fetching.
         */
 -      if (item && !has_sha1_file(item->util) &&
 +      if (item &&
 +          !has_sha1_file_with_flags(item->util, HAS_SHA1_QUICK) &&
            !will_fetch(head, item->util))
                item->util = NULL;
  
@@@ -580,9 -566,12 +577,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;
        }
  }
@@@ -732,6 -722,7 +733,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 -881,7 +892,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,6 -906,7 +917,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);
@@@ -997,7 -991,7 +1002,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) {
@@@ -1252,7 -1227,7 +1257,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 */
@@@ -1312,13 -1287,6 +1317,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 transport.c
index 079499dbafd749aaaebcac96d717893c8919ef23,2af1109920db78f01b6bdc1ef1b9027073224315..d57e8dec28d6890ce981a8422e9b8b60b697ecd6
@@@ -151,15 -151,6 +151,15 @@@ static int set_git_option(struct git_tr
                                die(_("transport: invalid depth option '%s'"), value);
                }
                return 0;
 +      } else if (!strcmp(name, TRANS_OPT_DEEPEN_SINCE)) {
 +              opts->deepen_since = value;
 +              return 0;
 +      } else if (!strcmp(name, TRANS_OPT_DEEPEN_NOT)) {
 +              opts->deepen_not = (const struct string_list *)value;
 +              return 0;
 +      } else if (!strcmp(name, TRANS_OPT_DEEPEN_RELATIVE)) {
 +              opts->deepen_relative = !!value;
 +              return 0;
        }
        return 1;
  }
@@@ -220,9 -211,6 +220,9 @@@ static int fetch_refs_via_pack(struct t
        args.quiet = (transport->verbose < 0);
        args.no_progress = !transport->progress;
        args.depth = data->options.depth;
 +      args.deepen_since = data->options.deepen_since;
 +      args.deepen_not = data->options.deepen_not;
 +      args.deepen_relative = data->options.deepen_relative;
        args.check_self_contained_and_connected =
                data->options.check_self_contained_and_connected;
        args.cloning = transport->cloning;
@@@ -307,7 -295,9 +307,9 @@@ void transport_update_tracking_ref(stru
        }
  }
  
- static void print_ref_status(char flag, const char *summary, struct ref *to, struct ref *from, const char *msg, int porcelain)
+ static void print_ref_status(char flag, const char *summary,
+                            struct ref *to, struct ref *from, const char *msg,
+                            int porcelain, int summary_width)
  {
        if (porcelain) {
                if (from)
                else
                        fprintf(stdout, "%s\n", summary);
        } else {
-               fprintf(stderr, " %c %-*s ", flag, TRANSPORT_SUMMARY_WIDTH, summary);
+               fprintf(stderr, " %c %-*s ", flag, summary_width, summary);
                if (from)
                        fprintf(stderr, "%s -> %s", prettify_refname(from->name), prettify_refname(to->name));
                else
        }
  }
  
- static void print_ok_ref_status(struct ref *ref, int porcelain)
+ static void print_ok_ref_status(struct ref *ref, int porcelain, int summary_width)
  {
        if (ref->deletion)
-               print_ref_status('-', "[deleted]", ref, NULL, NULL, porcelain);
+               print_ref_status('-', "[deleted]", ref, NULL, NULL,
+                                porcelain, summary_width);
        else if (is_null_oid(&ref->old_oid))
                print_ref_status('*',
                        (starts_with(ref->name, "refs/tags/") ? "[new tag]" :
                        "[new branch]"),
-                       ref, ref->peer_ref, NULL, porcelain);
+                       ref, ref->peer_ref, NULL, porcelain, summary_width);
        else {
                struct strbuf quickref = STRBUF_INIT;
                char type;
                strbuf_add_unique_abbrev(&quickref, ref->new_oid.hash,
                                         DEFAULT_ABBREV);
  
-               print_ref_status(type, quickref.buf, ref, ref->peer_ref, msg, porcelain);
+               print_ref_status(type, quickref.buf, ref, ref->peer_ref, msg,
+                                porcelain, summary_width);
                strbuf_release(&quickref);
        }
  }
  
- static int print_one_push_status(struct ref *ref, const char *dest, int count, int porcelain)
+ static int print_one_push_status(struct ref *ref, const char *dest, int count,
+                                int porcelain, int summary_width)
  {
        if (!count) {
                char *url = transport_anonymize_url(dest);
  
        switch(ref->status) {
        case REF_STATUS_NONE:
-               print_ref_status('X', "[no match]", ref, NULL, NULL, porcelain);
+               print_ref_status('X', "[no match]", ref, NULL, NULL,
+                                porcelain, summary_width);
                break;
        case REF_STATUS_REJECT_NODELETE:
                print_ref_status('!', "[rejected]", ref, NULL,
-                                                "remote does not support deleting refs", porcelain);
+                                "remote does not support deleting refs",
+                                porcelain, summary_width);
                break;
        case REF_STATUS_UPTODATE:
                print_ref_status('=', "[up to date]", ref,
-                                                ref->peer_ref, NULL, porcelain);
+                                ref->peer_ref, NULL, porcelain, summary_width);
                break;
        case REF_STATUS_REJECT_NONFASTFORWARD:
                print_ref_status('!', "[rejected]", ref, ref->peer_ref,
-                                                "non-fast-forward", porcelain);
+                                "non-fast-forward", porcelain, summary_width);
                break;
        case REF_STATUS_REJECT_ALREADY_EXISTS:
                print_ref_status('!', "[rejected]", ref, ref->peer_ref,
-                                                "already exists", porcelain);
+                                "already exists", porcelain, summary_width);
                break;
        case REF_STATUS_REJECT_FETCH_FIRST:
                print_ref_status('!', "[rejected]", ref, ref->peer_ref,
-                                                "fetch first", porcelain);
+                                "fetch first", porcelain, summary_width);
                break;
        case REF_STATUS_REJECT_NEEDS_FORCE:
                print_ref_status('!', "[rejected]", ref, ref->peer_ref,
-                                                "needs force", porcelain);
+                                "needs force", porcelain, summary_width);
                break;
        case REF_STATUS_REJECT_STALE:
                print_ref_status('!', "[rejected]", ref, ref->peer_ref,
-                                                "stale info", porcelain);
+                                "stale info", porcelain, summary_width);
                break;
        case REF_STATUS_REJECT_SHALLOW:
                print_ref_status('!', "[rejected]", ref, ref->peer_ref,
-                                                "new shallow roots not allowed", porcelain);
+                                "new shallow roots not allowed",
+                                porcelain, summary_width);
                break;
        case REF_STATUS_REMOTE_REJECT:
                print_ref_status('!', "[remote rejected]", ref,
-                                                ref->deletion ? NULL : ref->peer_ref,
-                                                ref->remote_status, porcelain);
+                                ref->deletion ? NULL : ref->peer_ref,
+                                ref->remote_status, porcelain, summary_width);
                break;
        case REF_STATUS_EXPECTING_REPORT:
                print_ref_status('!', "[remote failure]", ref,
-                                                ref->deletion ? NULL : ref->peer_ref,
-                                                "remote failed to report status", porcelain);
+                                ref->deletion ? NULL : ref->peer_ref,
+                                "remote failed to report status",
+                                porcelain, summary_width);
                break;
        case REF_STATUS_ATOMIC_PUSH_FAILED:
                print_ref_status('!', "[rejected]", ref, ref->peer_ref,
-                                                "atomic push failed", porcelain);
+                                "atomic push failed", porcelain, summary_width);
                break;
        case REF_STATUS_OK:
-               print_ok_ref_status(ref, porcelain);
+               print_ok_ref_status(ref, porcelain, summary_width);
                break;
        }
  
        return 1;
  }
  
+ static int measure_abbrev(const struct object_id *oid, int sofar)
+ {
+       char hex[GIT_SHA1_HEXSZ + 1];
+       int w = find_unique_abbrev_r(hex, oid->hash, DEFAULT_ABBREV);
+       return (w < sofar) ? sofar : w;
+ }
+ int transport_summary_width(const struct ref *refs)
+ {
+       int maxw = -1;
+       for (; refs; refs = refs->next) {
+               maxw = measure_abbrev(&refs->old_oid, maxw);
+               maxw = measure_abbrev(&refs->new_oid, maxw);
+       }
+       if (maxw < 0)
+               maxw = FALLBACK_DEFAULT_ABBREV;
+       return (2 * maxw + 3);
+ }
  void transport_print_push_status(const char *dest, struct ref *refs,
                                  int verbose, int porcelain, unsigned int *reject_reasons)
  {
        int n = 0;
        unsigned char head_sha1[20];
        char *head;
+       int summary_width = transport_summary_width(refs);
  
        head = resolve_refdup("HEAD", RESOLVE_REF_READING, head_sha1, NULL);
  
        if (verbose) {
                for (ref = refs; ref; ref = ref->next)
                        if (ref->status == REF_STATUS_UPTODATE)
-                               n += print_one_push_status(ref, dest, n, porcelain);
+                               n += print_one_push_status(ref, dest, n,
+                                                          porcelain, summary_width);
        }
  
        for (ref = refs; ref; ref = ref->next)
                if (ref->status == REF_STATUS_OK)
-                       n += print_one_push_status(ref, dest, n, porcelain);
+                       n += print_one_push_status(ref, dest, n,
+                                                  porcelain, summary_width);
  
        *reject_reasons = 0;
        for (ref = refs; ref; ref = ref->next) {
                if (ref->status != REF_STATUS_NONE &&
                    ref->status != REF_STATUS_UPTODATE &&
                    ref->status != REF_STATUS_OK)
-                       n += print_one_push_status(ref, dest, n, porcelain);
+                       n += print_one_push_status(ref, dest, n,
+                                                  porcelain, summary_width);
                if (ref->status == REF_STATUS_REJECT_NONFASTFORWARD) {
                        if (head != NULL && !strcmp(head, ref->name))
                                *reject_reasons |= REJECT_NON_FF_HEAD;
@@@ -1096,7 -1118,9 +1130,7 @@@ static int refs_from_alternate_cb(struc
        const struct ref *extra;
        struct alternate_refs_data *cb = data;
  
 -      e->name[-1] = '\0';
 -      other = xstrdup(real_path(e->base));
 -      e->name[-1] = '/';
 +      other = xstrdup(real_path(e->path));
        len = strlen(other);
  
        while (other[len-1] == '/')
diff --combined transport.h
index 5624c0218c5d8175c3187d1c89cc603cd3f1d2cf,706d99e8183a87f825b7e54c02b69f611b3664cf..b8e4ee8099260a74e5207048cf2837c9fd686568
@@@ -5,8 -5,6 +5,8 @@@
  #include "run-command.h"
  #include "remote.h"
  
 +struct string_list;
 +
  struct git_transport_options {
        unsigned thin : 1;
        unsigned keep : 1;
        unsigned check_self_contained_and_connected : 1;
        unsigned self_contained_and_connected : 1;
        unsigned update_shallow : 1;
 +      unsigned deepen_relative : 1;
        int depth;
 +      const char *deepen_since;
 +      const struct string_list *deepen_not;
        const char *uploadpack;
        const char *receivepack;
        struct push_cas_option *cas;
@@@ -147,7 -142,7 +147,7 @@@ struct transport 
  #define TRANSPORT_PUSH_ATOMIC 8192
  #define TRANSPORT_PUSH_OPTIONS 16384
  
- #define TRANSPORT_SUMMARY_WIDTH (2 * FALLBACK_DEFAULT_ABBREV + 3)
+ extern int transport_summary_width(const struct ref *refs);
  
  /* Returns a transport suitable for the url */
  struct transport *transport_get(struct remote *, const char *);
@@@ -190,15 -185,6 +190,15 @@@ int transport_restrict_protocols(void)
  /* Limit the depth of the fetch if not null */
  #define TRANS_OPT_DEPTH "depth"
  
 +/* Limit the depth of the fetch based on time if not null */
 +#define TRANS_OPT_DEEPEN_SINCE "deepen-since"
 +
 +/* Limit the depth of the fetch based on revs if not null */
 +#define TRANS_OPT_DEEPEN_NOT "deepen-not"
 +
 +/* Limit the deepen of the fetch if not null */
 +#define TRANS_OPT_DEEPEN_RELATIVE "deepen-relative"
 +
  /* Aggressively fetch annotated tags if possible */
  #define TRANS_OPT_FOLLOWTAGS "followtags"