Merge branch 'nd/warn-ambiguous-object-name' into jk/cat-file-batch-optim
authorJunio C Hamano <gitster@pobox.com>
Fri, 12 Jul 2013 17:09:50 +0000 (10:09 -0700)
committerJunio C Hamano <gitster@pobox.com>
Fri, 12 Jul 2013 17:09:50 +0000 (10:09 -0700)
* nd/warn-ambiguous-object-name:
get_sha1: warn about full or short object names that look like refs

1  2 
advice.c
advice.h
sha1_name.c
diff --combined advice.c
index a8deee6e6419a1e867e06e90a70300cd2e01b556,22abde9bc4edc5d90fa8e12e5e27654948955b23..54315cbd0a554bdeb1ace160a5df7cf6c485e559
+++ b/advice.c
@@@ -8,12 -8,11 +8,13 @@@ int advice_push_already_exists = 1
  int advice_push_fetch_first = 1;
  int advice_push_needs_force = 1;
  int advice_status_hints = 1;
 +int advice_status_u_option = 1;
  int advice_commit_before_merge = 1;
  int advice_resolve_conflict = 1;
  int advice_implicit_identity = 1;
  int advice_detached_head = 1;
 +int advice_set_upstream_failure = 1;
+ int advice_object_name_warning = 1;
  
  static struct {
        const char *name;
        { "pushfetchfirst", &advice_push_fetch_first },
        { "pushneedsforce", &advice_push_needs_force },
        { "statushints", &advice_status_hints },
 +      { "statusuoption", &advice_status_u_option },
        { "commitbeforemerge", &advice_commit_before_merge },
        { "resolveconflict", &advice_resolve_conflict },
        { "implicitidentity", &advice_implicit_identity },
        { "detachedhead", &advice_detached_head },
 +      { "setupstreamfailure", &advice_set_upstream_failure },
+       { "object_name_warning", &advice_object_name_warning },
  
        /* make this an alias for backward compatibility */
        { "pushnonfastforward", &advice_push_update_rejected }
diff --combined advice.h
index 94caa32f9213f59a627176ec8b4aea022f6b0f8f,24d5420b7add56e6b19ce58918bf8d2fbde8ed8d..fefe39ac5caf5a1e8b95683a4c8dcc443df16d32
+++ b/advice.h
@@@ -11,12 -11,11 +11,13 @@@ extern int advice_push_already_exists
  extern int advice_push_fetch_first;
  extern int advice_push_needs_force;
  extern int advice_status_hints;
 +extern int advice_status_u_option;
  extern int advice_commit_before_merge;
  extern int advice_resolve_conflict;
  extern int advice_implicit_identity;
  extern int advice_detached_head;
 +extern int advice_set_upstream_failure;
+ extern int advice_object_name_warning;
  
  int git_default_advice_config(const char *var, const char *value);
  void advise(const char *advice, ...);
diff --combined sha1_name.c
index 3820f28ae757cce54a95014629ade4f7feb56efc,502d107a5e427f61374a97d36ebc392f9619f3ad..a1e0f804dc1844a0df936bc48bcdc4839c612566
@@@ -435,12 -435,31 +435,31 @@@ static int get_sha1_1(const char *name
  static int get_sha1_basic(const char *str, int len, unsigned char *sha1)
  {
        static const char *warn_msg = "refname '%.*s' is ambiguous.";
+       static const char *object_name_msg = N_(
+       "Git normally never creates a ref that ends with 40 hex characters\n"
+       "because it will be ignored when you just specify 40-hex. These refs\n"
+       "may be created by mistake. For example,\n"
+       "\n"
+       "  git checkout -b $br $(git rev-parse ...)\n"
+       "\n"
+       "where \"$br\" is somehow empty and a 40-hex ref is created. Please\n"
+       "examine these refs and maybe delete them. Turn this message off by\n"
+       "running \"git config advice.object_name_warning false\"");
+       unsigned char tmp_sha1[20];
        char *real_ref = NULL;
        int refs_found = 0;
        int at, reflog_len;
  
-       if (len == 40 && !get_sha1_hex(str, sha1))
+       if (len == 40 && !get_sha1_hex(str, sha1)) {
+               refs_found = dwim_ref(str, len, tmp_sha1, &real_ref);
+               if (refs_found > 0 && warn_ambiguous_refs) {
+                       warning(warn_msg, len, str);
+                       if (advice_object_name_warning)
+                               fprintf(stderr, "%s\n", _(object_name_msg));
+               }
+               free(real_ref);
                return 0;
+       }
  
        /* basic@{time or number or -number} format to query ref-log */
        reflog_len = at = 0;
        if (!refs_found)
                return -1;
  
-       if (warn_ambiguous_refs && refs_found > 1)
+       if (warn_ambiguous_refs &&
+           (refs_found > 1 ||
+            !get_short_sha1(str, len, tmp_sha1, GET_SHA1_QUIETLY)))
                warning(warn_msg, len, str);
  
        if (reflog_len) {
@@@ -594,7 -615,7 +615,7 @@@ struct object *peel_to_type(const char 
        while (1) {
                if (!o || (!o->parsed && !parse_object(o->sha1)))
                        return NULL;
 -              if (o->type == expected_type)
 +              if (expected_type == OBJ_ANY || o->type == expected_type)
                        return o;
                if (o->type == OBJ_TAG)
                        o = ((struct tag*) o)->tagged;
@@@ -645,8 -666,6 +666,8 @@@ static int peel_onion(const char *name
                expected_type = OBJ_TREE;
        else if (!strncmp(blob_type, sp, 4) && sp[4] == '}')
                expected_type = OBJ_BLOB;
 +      else if (!prefixcmp(sp, "object}"))
 +              expected_type = OBJ_ANY;
        else if (sp[0] == '}')
                expected_type = OBJ_NONE;
        else if (sp[0] == '/')
  
        if (expected_type == OBJ_COMMIT)
                lookup_flags = GET_SHA1_COMMITTISH;
 +      else if (expected_type == OBJ_TREE)
 +              lookup_flags = GET_SHA1_TREEISH;
  
        if (get_sha1_1(name, sp - name - 2, outer, lookup_flags))
                return -1;
@@@ -860,8 -877,8 +881,8 @@@ static int get_sha1_oneline(const char 
  }
  
  struct grab_nth_branch_switch_cbdata {
 -      long cnt, alloc;
 -      struct strbuf *buf;
 +      int remaining;
 +      struct strbuf buf;
  };
  
  static int grab_nth_branch_switch(unsigned char *osha1, unsigned char *nsha1,
        struct grab_nth_branch_switch_cbdata *cb = cb_data;
        const char *match = NULL, *target = NULL;
        size_t len;
 -      int nth;
  
        if (!prefixcmp(message, "checkout: moving from ")) {
                match = message + strlen("checkout: moving from ");
  
        if (!match || !target)
                return 0;
 -
 -      len = target - match;
 -      nth = cb->cnt++ % cb->alloc;
 -      strbuf_reset(&cb->buf[nth]);
 -      strbuf_add(&cb->buf[nth], match, len);
 +      if (--(cb->remaining) == 0) {
 +              len = target - match;
 +              strbuf_reset(&cb->buf);
 +              strbuf_add(&cb->buf, match, len);
 +              return 1; /* we are done */
 +      }
        return 0;
  }
  
  static int interpret_nth_prior_checkout(const char *name, struct strbuf *buf)
  {
        long nth;
 -      int i, retval;
 +      int retval;
        struct grab_nth_branch_switch_cbdata cb;
        const char *brace;
        char *num_end;
        brace = strchr(name, '}');
        if (!brace)
                return -1;
 -      nth = strtol(name+3, &num_end, 10);
 +      nth = strtol(name + 3, &num_end, 10);
        if (num_end != brace)
                return -1;
        if (nth <= 0)
                return -1;
 -      cb.alloc = nth;
 -      cb.buf = xmalloc(nth * sizeof(struct strbuf));
 -      for (i = 0; i < nth; i++)
 -              strbuf_init(&cb.buf[i], 20);
 -      cb.cnt = 0;
 +      cb.remaining = nth;
 +      strbuf_init(&cb.buf, 20);
 +
        retval = 0;
 -      for_each_recent_reflog_ent("HEAD", grab_nth_branch_switch, 40960, &cb);
 -      if (cb.cnt < nth) {
 -              cb.cnt = 0;
 -              for_each_reflog_ent("HEAD", grab_nth_branch_switch, &cb);
 +      if (0 < for_each_reflog_ent_reverse("HEAD", grab_nth_branch_switch, &cb)) {
 +              strbuf_reset(buf);
 +              strbuf_add(buf, cb.buf.buf, cb.buf.len);
 +              retval = brace - name + 1;
        }
 -      if (cb.cnt < nth)
 -              goto release_return;
 -      i = cb.cnt % nth;
 -      strbuf_reset(buf);
 -      strbuf_add(buf, cb.buf[i].buf, cb.buf[i].len);
 -      retval = brace-name+1;
 -
 -release_return:
 -      for (i = 0; i < nth; i++)
 -              strbuf_release(&cb.buf[i]);
 -      free(cb.buf);
  
 +      strbuf_release(&cb.buf);
        return retval;
  }
  
@@@ -1129,8 -1158,7 +1150,8 @@@ int get_sha1_blob(const char *name, uns
  static void diagnose_invalid_sha1_path(const char *prefix,
                                       const char *filename,
                                       const unsigned char *tree_sha1,
 -                                     const char *object_name)
 +                                     const char *object_name,
 +                                     int object_name_len)
  {
        struct stat st;
        unsigned char sha1[20];
                prefix = "";
  
        if (!lstat(filename, &st))
 -              die("Path '%s' exists on disk, but not in '%s'.",
 -                  filename, object_name);
 +              die("Path '%s' exists on disk, but not in '%.*s'.",
 +                  filename, object_name_len, object_name);
        if (errno == ENOENT || errno == ENOTDIR) {
                char *fullname = xmalloc(strlen(filename)
                                             + strlen(prefix) + 1);
                if (!get_tree_entry(tree_sha1, fullname,
                                    sha1, &mode)) {
                        die("Path '%s' exists, but not '%s'.\n"
 -                          "Did you mean '%s:%s' aka '%s:./%s'?",
 +                          "Did you mean '%.*s:%s' aka '%.*s:./%s'?",
                            fullname,
                            filename,
 -                          object_name,
 +                          object_name_len, object_name,
                            fullname,
 -                          object_name,
 +                          object_name_len, object_name,
                            filename);
                }
 -              die("Path '%s' does not exist in '%s'",
 -                  filename, object_name);
 +              die("Path '%s' does not exist in '%.*s'",
 +                  filename, object_name_len, object_name);
        }
  }
  
@@@ -1325,8 -1353,13 +1346,8 @@@ static int get_sha1_with_context_1(cons
        }
        if (*cp == ':') {
                unsigned char tree_sha1[20];
 -              char *object_name = NULL;
 -              if (only_to_die) {
 -                      object_name = xmalloc(cp-name+1);
 -                      strncpy(object_name, name, cp-name);
 -                      object_name[cp-name] = '\0';
 -              }
 -              if (!get_sha1_1(name, cp-name, tree_sha1, GET_SHA1_TREEISH)) {
 +              int len = cp - name;
 +              if (!get_sha1_1(name, len, tree_sha1, GET_SHA1_TREEISH)) {
                        const char *filename = cp+1;
                        char *new_filename = NULL;
  
                        ret = get_tree_entry(tree_sha1, filename, sha1, &oc->mode);
                        if (ret && only_to_die) {
                                diagnose_invalid_sha1_path(prefix, filename,
 -                                                         tree_sha1, object_name);
 -                              free(object_name);
 +                                                         tree_sha1,
 +                                                         name, len);
                        }
                        hashcpy(oc->tree, tree_sha1);
                        strncpy(oc->path, filename,
                        return ret;
                } else {
                        if (only_to_die)
 -                              die("Invalid object name '%s'.", object_name);
 +                              die("Invalid object name '%.*s'.", len, name);
                }
        }
        return ret;