* 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
#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];
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);
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);
*/
read_cache();
}
- if (options->abbrev <= 0 || 40 < options->abbrev)
+ if (40 < options->abbrev)
options->abbrev = 40; /* full */
/*
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),
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;
}