From: Junio C Hamano Date: Thu, 27 Oct 2016 21:58:48 +0000 (-0700) Subject: Merge branch 'jk/no-looking-at-dotgit-outside-repo' X-Git-Tag: v2.11.0-rc0~21 X-Git-Url: https://git.lorimer.id.au/gitweb.git/diff_plain/0d9c527d5963fca098ea4964f4129511bd5d82d8?ds=inline;hp=-c Merge branch 'jk/no-looking-at-dotgit-outside-repo' 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 --- 0d9c527d5963fca098ea4964f4129511bd5d82d8 diff --combined cache.h index b7f34b4ae6,607fe6ed30..1be6526d14 --- a/cache.h +++ 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 5a4e9b31ef,4c47bb3a2d..4c09314cc7 --- a/diff.c +++ b/diff.c @@@ -3096,6 -3096,19 +3096,21 @@@ static int similarity_index(struct diff return p->score * 100 / MAX_SCORE; } + 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 > GIT_SHA1_HEXSZ) ++ 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, @@@ -3154,9 -3167,9 +3169,9 @@@ (!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); /* @@@ -4190,15 -4200,16 +4202,16 @@@ * 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) @@@ -4209,9 -4220,9 +4222,9 @@@ 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 c71fc172f5,36ce9b9f45..06409a3845 --- a/sha1_name.c +++ b/sha1_name.c @@@ -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; @@@ -508,7 -472,9 +508,9 @@@ 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; }