tag: generate useful reflog message

When tags are created with `--create-reflog` or with the option `core.logAllRefUpdates` set to 'always', a reflog is created for them. So far, the description of reflog entries for tags was empty, making the reflog hard to understand. For example: 6e3a7b3 refs/tags/test@{0}: Now, a reflog message is generated when creating a tag, following the pattern "tag: tagging <short-sha1> (<description>)". If GIT_REFLOG_ACTION is set, the message becomes "$GIT_REFLOG_ACTION (<description>)" instead. If the tag references a commit object, the description is set to the subject line of the commit, followed by its commit date. For example: 6e3a7b3 refs/tags/test@{0}: tag: tagging 6e3a7b3398 (Git 2.12-rc0, 2017-02-03) If the tag points to a tree/blob/tag objects, the following static strings are taken as description: - "tree object" - "blob object" - "other tag object" Signed-off-by: Cornelius Weig <cornelius.weig@tngtech.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Cornelius Weig committed Feb 8, 2017 at 23:41 UTC df8512ede80888505b15ab92efc70f2f20f3cba8
2 files changed +70 -2
builtin/tag.c
+53 -1
@@ -288,6 +288,54 @@ static void create_tag(const unsigned char *object, const char *tag,
288 }
289 }
290
291 +static void create_reflog_msg(const unsigned char *sha1, struct strbuf *sb)
292 +{
293 + enum object_type type;
294 + struct commit *c;
295 + char *buf;
296 + unsigned long size;
297 + int subject_len = 0;
298 + const char *subject_start;
299 +
300 + char *rla = getenv("GIT_REFLOG_ACTION");
301 + if (rla) {
302 + strbuf_addstr(sb, rla);
303 + } else {
304 + strbuf_addstr(sb, _("tag: tagging "));
305 + strbuf_add_unique_abbrev(sb, sha1, DEFAULT_ABBREV);
306 + }
307 +
308 + strbuf_addstr(sb, " (");
309 + type = sha1_object_info(sha1, NULL);
310 + switch (type) {
311 + default:
312 + strbuf_addstr(sb, _("object of unknown type"));
313 + break;
314 + case OBJ_COMMIT:
315 + if ((buf = read_sha1_file(sha1, &type, &size)) != NULL) {
316 + subject_len = find_commit_subject(buf, &subject_start);
317 + strbuf_insert(sb, sb->len, subject_start, subject_len);
318 + } else {
319 + strbuf_addstr(sb, _("commit object"));
320 + }
321 + free(buf);
322 +
323 + if ((c = lookup_commit_reference(sha1)) != NULL)
324 + strbuf_addf(sb, ", %s", show_date(c->date, 0, DATE_MODE(SHORT)));
325 + break;
326 + case OBJ_TREE:
327 + strbuf_addstr(sb, _("tree object"));
328 + break;
329 + case OBJ_BLOB:
330 + strbuf_addstr(sb, _("blob object"));
331 + break;
332 + case OBJ_TAG:
333 + strbuf_addstr(sb, _("other tag object"));
334 + break;
335 + }
336 + strbuf_addch(sb, ')');
337 +}
338 +
339 struct msg_arg {
340 int given;
341 struct strbuf buf;
@@ -321,6 +369,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
369 {
370 struct strbuf buf = STRBUF_INIT;
371 struct strbuf ref = STRBUF_INIT;
372 + struct strbuf reflog_msg = STRBUF_INIT;
373 unsigned char object[20], prev[20];
374 const char *object_ref, *tag;
375 struct create_tag_options opt;
@@ -473,6 +522,8 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
522 else
523 die(_("Invalid cleanup mode %s"), cleanup_arg);
524
525 + create_reflog_msg(object, &reflog_msg);
526 +
527 if (create_tag_object) {
528 if (force_sign_annotate && !annotate)
529 opt.sign = 1;
@@ -483,7 +534,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
534 if (!transaction ||
535 ref_transaction_update(transaction, ref.buf, object, prev,
536 create_reflog ? REF_FORCE_CREATE_REFLOG : 0,
486 - NULL, &err) ||
537 + reflog_msg.buf, &err) ||
538 ref_transaction_commit(transaction, &err))
539 die("%s", err.buf);
540 ref_transaction_free(transaction);
@@ -493,5 +544,6 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
544 strbuf_release(&err);
545 strbuf_release(&buf);
546 strbuf_release(&ref);
547 + strbuf_release(&reflog_msg);
548 return 0;
549 }
t/t7004-tag.sh
+17 -1
@@ -56,9 +56,25 @@ test_expect_success 'creating a tag using default HEAD should succeed' '
56 '
57
58 test_expect_success 'creating a tag with --create-reflog should create reflog' '
59 + git log -1 \
60 + --format="format:tag: tagging %h (%s, %cd)%n" \
61 + --date=format:%Y-%m-%d >expected &&
62 test_when_finished "git tag -d tag_with_reflog" &&
63 git tag --create-reflog tag_with_reflog &&
61 - git reflog exists refs/tags/tag_with_reflog
64 + git reflog exists refs/tags/tag_with_reflog &&
65 + sed -e "s/^.* //" .git/logs/refs/tags/tag_with_reflog >actual &&
66 + test_cmp expected actual
67 +'
68 +
69 +test_expect_success 'annotated tag with --create-reflog has correct message' '
70 + git log -1 \
71 + --format="format:tag: tagging %h (%s, %cd)%n" \
72 + --date=format:%Y-%m-%d >expected &&
73 + test_when_finished "git tag -d tag_with_reflog" &&
74 + git tag -m "annotated tag" --create-reflog tag_with_reflog &&
75 + git reflog exists refs/tags/tag_with_reflog &&
76 + sed -e "s/^.* //" .git/logs/refs/tags/tag_with_reflog >actual &&
77 + test_cmp expected actual
78 '
79
80 test_expect_success '--create-reflog does not create reflog on failure' '