Merge branch 'jk/no-looking-at-dotgit-outside-repo'
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)
Update "git diff --no-index" codepath not to try to peek into .git/
directory that happens to be under the current directory, when we
know we are operating outside any repository.

* jk/no-looking-at-dotgit-outside-repo:
diff: handle sha1 abbreviations outside of repository
diff_aligned_abbrev: use "struct oid"
diff_unique_abbrev: rename to diff_aligned_abbrev
find_unique_abbrev: use 4-buffer ring
test-*-cache-tree: setup git dir
read info/{attributes,exclude} only when in repository

1  2 
cache.h
diff.c
sha1_name.c
diff --combined cache.h
index b7f34b4ae610380b1fc950ff5c8ccf16f93a8268,607fe6ed30f6003009217ec22de13873e57589b4..1be6526d14fd66f2c854cdb01d0ef20d9151d6e1
+++ b/cache.h
@@@ -903,8 -903,8 +903,8 @@@ extern char *sha1_pack_index_name(cons
   * The result will be at least `len` characters long, and will be NUL
   * terminated.
   *
-  * The non-`_r` version returns a static buffer which will be overwritten by
-  * subsequent calls.
+  * The non-`_r` version returns a static buffer which remains valid until 4
+  * more calls to find_unique_abbrev are made.
   *
   * The `_r` variant writes to a buffer supplied by the caller, which must be at
   * least `GIT_SHA1_HEXSZ + 1` bytes. The return value is the number of bytes
@@@ -1190,9 -1190,6 +1190,9 @@@ static inline int hex2chr(const char *s
  #define MINIMUM_ABBREV minimum_abbrev
  #define DEFAULT_ABBREV default_abbrev
  
 +/* used when the code does not know or care what the default abbrev is */
 +#define FALLBACK_DEFAULT_ABBREV 7
 +
  struct object_context {
        unsigned char tree[20];
        char path[PATH_MAX];
@@@ -1493,12 -1490,6 +1493,12 @@@ extern void prepare_packed_git(void)
  extern void reprepare_packed_git(void);
  extern void install_packed_git(struct packed_git *pack);
  
 +/*
 + * Give a rough count of objects in the repository. This sacrifices accuracy
 + * for speed.
 + */
 +unsigned long approximate_object_count(void);
 +
  extern struct packed_git *find_sha1_pack(const unsigned char *sha1,
                                         struct packed_git *packs);
  
diff --combined diff.c
index 5a4e9b31efd5ba6ab43e715effe4d97b13ef2a07,4c47bb3a2d23d2f747b416669895744c331f3dd5..4c09314cc7970788382a01c6ff839563d4563241
--- 1/diff.c
--- 2/diff.c
+++ b/diff.c
@@@ -3096,6 -3096,19 +3096,21 @@@ static int similarity_index(struct diff
        return p->score * 100 / MAX_SCORE;
  }
  
 -              if (abbrev < 0 || abbrev > GIT_SHA1_HEXSZ)
+ static const char *diff_abbrev_oid(const struct object_id *oid, int abbrev)
+ {
+       if (startup_info->have_repository)
+               return find_unique_abbrev(oid->hash, abbrev);
+       else {
+               char *hex = oid_to_hex(oid);
++              if (abbrev < 0)
++                      abbrev = FALLBACK_DEFAULT_ABBREV;
++              if (abbrev > GIT_SHA1_HEXSZ)
+                       die("BUG: oid abbreviation out of range: %d", abbrev);
+               hex[abbrev] = '\0';
+               return hex;
+       }
+ }
  static void fill_metainfo(struct strbuf *msg,
                          const char *name,
                          const char *other,
                            (!fill_mmfile(&mf, two) && diff_filespec_is_binary(two)))
                                abbrev = 40;
                }
-               strbuf_addf(msg, "%s%sindex %s..", line_prefix, set,
-                           find_unique_abbrev(one->oid.hash, abbrev));
-               strbuf_add_unique_abbrev(msg, two->oid.hash, abbrev);
+               strbuf_addf(msg, "%s%sindex %s..%s", line_prefix, set,
+                           diff_abbrev_oid(&one->oid, abbrev),
+                           diff_abbrev_oid(&two->oid, abbrev));
                if (one->mode == two->mode)
                        strbuf_addf(msg, " %06o", one->mode);
                strbuf_addf(msg, "%s\n", reset);
@@@ -3468,7 -3481,7 +3483,7 @@@ void diff_setup_done(struct diff_option
                         */
                        read_cache();
        }
 -      if (options->abbrev <= 0 || 40 < options->abbrev)
 +      if (40 < options->abbrev)
                options->abbrev = 40; /* full */
  
        /*
@@@ -4157,18 -4170,15 +4172,15 @@@ void diff_free_filepair(struct diff_fil
        free(p);
  }
  
- /*
-  * This is different from find_unique_abbrev() in that
-  * it stuffs the result with dots for alignment.
-  */
- const char *diff_unique_abbrev(const unsigned char *sha1, int len)
+ const char *diff_aligned_abbrev(const struct object_id *oid, int len)
  {
        int abblen;
        const char *abbrev;
-       if (len == 40)
-               return sha1_to_hex(sha1);
  
-       abbrev = find_unique_abbrev(sha1, len);
+       if (len == GIT_SHA1_HEXSZ)
+               return oid_to_hex(oid);
+       abbrev = diff_abbrev_oid(oid, len);
        abblen = strlen(abbrev);
  
        /*
         * the automatic sizing is supposed to give abblen that ensures
         * uniqueness across all objects (statistically speaking).
         */
-       if (abblen < 37) {
-               static char hex[41];
+       if (abblen < GIT_SHA1_HEXSZ - 3) {
+               static char hex[GIT_SHA1_HEXSZ + 1];
                if (len < abblen && abblen <= len + 2)
                        xsnprintf(hex, sizeof(hex), "%s%.*s", abbrev, len+3-abblen, "..");
                else
                        xsnprintf(hex, sizeof(hex), "%s...", abbrev);
                return hex;
        }
-       return sha1_to_hex(sha1);
+       return oid_to_hex(oid);
  }
  
  static void diff_flush_raw(struct diff_filepair *p, struct diff_options *opt)
        fprintf(opt->file, "%s", diff_line_prefix(opt));
        if (!(opt->output_format & DIFF_FORMAT_NAME_STATUS)) {
                fprintf(opt->file, ":%06o %06o %s ", p->one->mode, p->two->mode,
-                       diff_unique_abbrev(p->one->oid.hash, opt->abbrev));
+                       diff_aligned_abbrev(&p->one->oid, opt->abbrev));
                fprintf(opt->file, "%s ",
-                       diff_unique_abbrev(p->two->oid.hash, opt->abbrev));
+                       diff_aligned_abbrev(&p->two->oid, opt->abbrev));
        }
        if (p->score) {
                fprintf(opt->file, "%c%03d%c", p->status, similarity_index(p),
diff --combined sha1_name.c
index c71fc172f55dcfed6cda15220151231557f4e5a6,36ce9b9f45041c6e17e763cee259c284312dc42c..06409a38451971121e6cf6abd4a8af5bffd231c1
@@@ -448,46 -448,10 +448,46 @@@ int for_each_abbrev(const char *prefix
        return ret;
  }
  
 +/*
 + * Return the slot of the most-significant bit set in "val". There are various
 + * ways to do this quickly with fls() or __builtin_clzl(), but speed is
 + * probably not a big deal here.
 + */
 +static unsigned msb(unsigned long val)
 +{
 +      unsigned r = 0;
 +      while (val >>= 1)
 +              r++;
 +      return r;
 +}
 +
  int find_unique_abbrev_r(char *hex, const unsigned char *sha1, int len)
  {
        int status, exists;
  
 +      if (len < 0) {
 +              unsigned long count = approximate_object_count();
 +              /*
 +               * Add one because the MSB only tells us the highest bit set,
 +               * not including the value of all the _other_ bits (so "15"
 +               * is only one off of 2^4, but the MSB is the 3rd bit.
 +               */
 +              len = msb(count) + 1;
 +              /*
 +               * We now know we have on the order of 2^len objects, which
 +               * expects a collision at 2^(len/2). But we also care about hex
 +               * chars, not bits, and there are 4 bits per hex. So all
 +               * together we need to divide by 2; but we also want to round
 +               * odd numbers up, hence adding one before dividing.
 +               */
 +              len = (len + 1) / 2;
 +              /*
 +               * For very small repos, we stick with our regular fallback.
 +               */
 +              if (len < FALLBACK_DEFAULT_ABBREV)
 +                      len = FALLBACK_DEFAULT_ABBREV;
 +      }
 +
        sha1_to_hex_r(hex, sha1);
        if (len == 40 || !len)
                return 40;
  
  const char *find_unique_abbrev(const unsigned char *sha1, int len)
  {
-       static char hex[GIT_SHA1_HEXSZ + 1];
+       static int bufno;
+       static char hexbuffer[4][GIT_SHA1_HEXSZ + 1];
+       char *hex = hexbuffer[3 & ++bufno];
        find_unique_abbrev_r(hex, sha1, len);
        return hex;
  }