find_unique_abbrev: use 4-buffer ring

Some code paths want to format multiple abbreviated sha1s in the same output line. Because we use a single static buffer for our return value, they have to either break their output into several calls or allocate their own arrays and use find_unique_abbrev_r(). Intead, let's mimic sha1_to_hex() and use a ring of several buffers, so that the return value stays valid through multiple calls. This shortens some of the callers, and makes it harder to for them to make a silly mistake. Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Jeff King committed Oct 20, 2016 at 02:19 UTC ef2ed5013c4160284d9de18903bd4f7d0542d810
4 files changed +16 -19
builtin/merge.c
+5 -6
@@ -1374,12 +1374,11 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
1374 struct commit *commit;
1375
1376 if (verbosity >= 0) {
1377 - char from[GIT_SHA1_HEXSZ + 1], to[GIT_SHA1_HEXSZ + 1];
1378 - find_unique_abbrev_r(from, head_commit->object.oid.hash,
1379 - DEFAULT_ABBREV);
1380 - find_unique_abbrev_r(to, remoteheads->item->object.oid.hash,
1381 - DEFAULT_ABBREV);
1382 - printf(_("Updating %s..%s\n"), from, to);
1377 + printf(_("Updating %s..%s\n"),
1378 + find_unique_abbrev(head_commit->object.oid.hash,
1379 + DEFAULT_ABBREV),
1380 + find_unique_abbrev(remoteheads->item->object.oid.hash,
1381 + DEFAULT_ABBREV));
1382 }
1383 strbuf_addstr(&msg, "Fast-forward");
1384 if (have_message)
builtin/receive-pack.c
+6 -10
@@ -1163,10 +1163,6 @@ static void check_aliased_update(struct command *cmd, struct string_list *list)
1163 struct string_list_item *item;
1164 struct command *dst_cmd;
1165 unsigned char sha1[GIT_SHA1_RAWSZ];
1166 - char cmd_oldh[GIT_SHA1_HEXSZ + 1],
1167 - cmd_newh[GIT_SHA1_HEXSZ + 1],
1168 - dst_oldh[GIT_SHA1_HEXSZ + 1],
1169 - dst_newh[GIT_SHA1_HEXSZ + 1];
1166 int flag;
1167
1168 strbuf_addf(&buf, "%s%s", get_git_namespace(), cmd->ref_name);
@@ -1197,14 +1193,14 @@ static void check_aliased_update(struct command *cmd, struct string_list *list)
1193
1194 dst_cmd->skip_update = 1;
1195
1200 - find_unique_abbrev_r(cmd_oldh, cmd->old_sha1, DEFAULT_ABBREV);
1201 - find_unique_abbrev_r(cmd_newh, cmd->new_sha1, DEFAULT_ABBREV);
1202 - find_unique_abbrev_r(dst_oldh, dst_cmd->old_sha1, DEFAULT_ABBREV);
1203 - find_unique_abbrev_r(dst_newh, dst_cmd->new_sha1, DEFAULT_ABBREV);
1196 rp_error("refusing inconsistent update between symref '%s' (%s..%s) and"
1197 " its target '%s' (%s..%s)",
1206 - cmd->ref_name, cmd_oldh, cmd_newh,
1207 - dst_cmd->ref_name, dst_oldh, dst_newh);
1198 + cmd->ref_name,
1199 + find_unique_abbrev(cmd->old_sha1, DEFAULT_ABBREV),
1200 + find_unique_abbrev(cmd->new_sha1, DEFAULT_ABBREV),
1201 + dst_cmd->ref_name,
1202 + find_unique_abbrev(dst_cmd->old_sha1, DEFAULT_ABBREV),
1203 + find_unique_abbrev(dst_cmd->new_sha1, DEFAULT_ABBREV));
1204
1205 cmd->error_string = dst_cmd->error_string =
1206 "inconsistent aliased update";
cache.h
+2 -2
@@ -903,8 +903,8 @@ extern char *sha1_pack_index_name(const unsigned char *sha1);
903 * The result will be at least `len` characters long, and will be NUL
904 * terminated.
905 *
906 - * The non-`_r` version returns a static buffer which will be overwritten by
907 - * subsequent calls.
906 + * The non-`_r` version returns a static buffer which remains valid until 4
907 + * more calls to find_unique_abbrev are made.
908 *
909 * The `_r` variant writes to a buffer supplied by the caller, which must be at
910 * least `GIT_SHA1_HEXSZ + 1` bytes. The return value is the number of bytes
sha1_name.c
+3 -1
@@ -472,7 +472,9 @@ int find_unique_abbrev_r(char *hex, const unsigned char *sha1, int len)
472
473 const char *find_unique_abbrev(const unsigned char *sha1, int len)
474 {
475 - static char hex[GIT_SHA1_HEXSZ + 1];
475 + static int bufno;
476 + static char hexbuffer[4][GIT_SHA1_HEXSZ + 1];
477 + char *hex = hexbuffer[3 & ++bufno];
478 find_unique_abbrev_r(hex, sha1, len);
479 return hex;
480 }