Git fork
at reftables-rust 722 lines 20 kB view raw
1/* 2 * Builtin "git tag" 3 * 4 * Copyright (c) 2007 Kristian Høgsberg <krh@redhat.com>, 5 * Carlos Rica <jasampler@gmail.com> 6 * Based on git-tag.sh and mktag.c by Linus Torvalds. 7 */ 8 9#define USE_THE_REPOSITORY_VARIABLE 10#define DISABLE_SIGN_COMPARE_WARNINGS 11 12#include "builtin.h" 13#include "advice.h" 14#include "config.h" 15#include "editor.h" 16#include "environment.h" 17#include "gettext.h" 18#include "hex.h" 19#include "refs.h" 20#include "object-file.h" 21#include "object-name.h" 22#include "odb.h" 23#include "path.h" 24#include "tag.h" 25#include "parse-options.h" 26#include "diff.h" 27#include "revision.h" 28#include "gpg-interface.h" 29#include "oid-array.h" 30#include "column.h" 31#include "ref-filter.h" 32#include "date.h" 33#include "write-or-die.h" 34#include "object-file-convert.h" 35#include "trailer.h" 36 37static const char * const git_tag_usage[] = { 38 N_("git tag [-a | -s | -u <key-id>] [-f] [-m <msg> | -F <file>] [-e]\n" 39 " [(--trailer <token>[(=|:)<value>])...]\n" 40 " <tagname> [<commit> | <object>]"), 41 N_("git tag -d <tagname>..."), 42 N_("git tag [-n[<num>]] -l [--contains <commit>] [--no-contains <commit>]\n" 43 " [--points-at <object>] [--column[=<options>] | --no-column]\n" 44 " [--create-reflog] [--sort=<key>] [--format=<format>]\n" 45 " [--merged <commit>] [--no-merged <commit>] [<pattern>...]"), 46 N_("git tag -v [--format=<format>] <tagname>..."), 47 NULL 48}; 49 50static unsigned int colopts; 51static int force_sign_annotate; 52static int config_sign_tag = -1; /* unspecified */ 53 54static int list_tags(struct ref_filter *filter, struct ref_sorting *sorting, 55 struct ref_format *format) 56{ 57 char *to_free = NULL; 58 59 if (filter->lines == -1) 60 filter->lines = 0; 61 62 if (!format->format) { 63 if (filter->lines) { 64 to_free = xstrfmt("%s %%(contents:lines=%d)", 65 "%(align:15)%(refname:lstrip=2)%(end)", 66 filter->lines); 67 format->format = to_free; 68 } else 69 format->format = "%(refname:lstrip=2)"; 70 } 71 72 if (verify_ref_format(format)) 73 die(_("unable to parse format string")); 74 filter->with_commit_tag_algo = 1; 75 filter_and_format_refs(filter, FILTER_REFS_TAGS, sorting, format); 76 77 free(to_free); 78 79 return 0; 80} 81 82typedef int (*each_tag_name_fn)(const char *name, const char *ref, 83 const struct object_id *oid, void *cb_data); 84 85static int for_each_tag_name(const char **argv, each_tag_name_fn fn, 86 void *cb_data) 87{ 88 const char **p; 89 struct strbuf ref = STRBUF_INIT; 90 int had_error = 0; 91 struct object_id oid; 92 93 for (p = argv; *p; p++) { 94 strbuf_reset(&ref); 95 strbuf_addf(&ref, "refs/tags/%s", *p); 96 if (refs_read_ref(get_main_ref_store(the_repository), ref.buf, &oid)) { 97 error(_("tag '%s' not found."), *p); 98 had_error = 1; 99 continue; 100 } 101 if (fn(*p, ref.buf, &oid, cb_data)) 102 had_error = 1; 103 } 104 strbuf_release(&ref); 105 return had_error; 106} 107 108static int collect_tags(const char *name UNUSED, const char *ref, 109 const struct object_id *oid, void *cb_data) 110{ 111 struct string_list *ref_list = cb_data; 112 113 string_list_append(ref_list, ref); 114 ref_list->items[ref_list->nr - 1].util = oiddup(oid); 115 return 0; 116} 117 118static int delete_tags(const char **argv) 119{ 120 int result; 121 struct string_list refs_to_delete = STRING_LIST_INIT_DUP; 122 struct string_list_item *item; 123 124 result = for_each_tag_name(argv, collect_tags, (void *)&refs_to_delete); 125 if (refs_delete_refs(get_main_ref_store(the_repository), NULL, &refs_to_delete, REF_NO_DEREF)) 126 result = 1; 127 128 for_each_string_list_item(item, &refs_to_delete) { 129 const char *name = item->string; 130 struct object_id *oid = item->util; 131 if (!refs_ref_exists(get_main_ref_store(the_repository), name)) 132 printf(_("Deleted tag '%s' (was %s)\n"), 133 item->string + 10, 134 repo_find_unique_abbrev(the_repository, oid, DEFAULT_ABBREV)); 135 136 free(oid); 137 } 138 string_list_clear(&refs_to_delete, 0); 139 return result; 140} 141 142static int verify_tag(const char *name, const char *ref UNUSED, 143 const struct object_id *oid, void *cb_data) 144{ 145 int flags; 146 struct ref_format *format = cb_data; 147 flags = GPG_VERIFY_VERBOSE; 148 149 if (format->format) 150 flags = GPG_VERIFY_OMIT_STATUS; 151 152 if (gpg_verify_tag(oid, name, flags)) 153 return -1; 154 155 if (format->format) 156 pretty_print_ref(name, oid, format); 157 158 return 0; 159} 160 161static int do_sign(struct strbuf *buffer, struct object_id **compat_oid, 162 struct object_id *compat_oid_buf) 163{ 164 const struct git_hash_algo *compat = the_repository->compat_hash_algo; 165 struct strbuf sig = STRBUF_INIT, compat_sig = STRBUF_INIT; 166 struct strbuf compat_buf = STRBUF_INIT; 167 char *keyid = get_signing_key(); 168 int ret = -1; 169 170 if (sign_buffer(buffer, &sig, keyid)) 171 goto out; 172 173 if (compat) { 174 const struct git_hash_algo *algo = the_repository->hash_algo; 175 176 if (convert_object_file(the_repository ,&compat_buf, algo, compat, 177 buffer->buf, buffer->len, OBJ_TAG, 1)) 178 goto out; 179 if (sign_buffer(&compat_buf, &compat_sig, keyid)) 180 goto out; 181 add_header_signature(&compat_buf, &sig, algo); 182 strbuf_addbuf(&compat_buf, &compat_sig); 183 hash_object_file(compat, compat_buf.buf, compat_buf.len, 184 OBJ_TAG, compat_oid_buf); 185 *compat_oid = compat_oid_buf; 186 } 187 188 if (compat_sig.len) 189 add_header_signature(buffer, &compat_sig, compat); 190 191 strbuf_addbuf(buffer, &sig); 192 ret = 0; 193out: 194 strbuf_release(&sig); 195 strbuf_release(&compat_sig); 196 strbuf_release(&compat_buf); 197 free(keyid); 198 return ret; 199} 200 201static const char tag_template[] = 202 N_("\nWrite a message for tag:\n %s\n" 203 "Lines starting with '%s' will be ignored.\n"); 204 205static const char tag_template_nocleanup[] = 206 N_("\nWrite a message for tag:\n %s\n" 207 "Lines starting with '%s' will be kept; you may remove them" 208 " yourself if you want to.\n"); 209 210static int git_tag_config(const char *var, const char *value, 211 const struct config_context *ctx, void *cb) 212{ 213 if (!strcmp(var, "tag.gpgsign")) { 214 config_sign_tag = git_config_bool(var, value); 215 return 0; 216 } 217 218 if (!strcmp(var, "tag.sort")) { 219 if (!value) 220 return config_error_nonbool(var); 221 string_list_append(cb, value); 222 return 0; 223 } 224 225 if (!strcmp(var, "tag.forcesignannotated")) { 226 force_sign_annotate = git_config_bool(var, value); 227 return 0; 228 } 229 230 if (starts_with(var, "column.")) 231 return git_column_config(var, value, "tag", &colopts); 232 233 if (git_color_config(var, value, cb) < 0) 234 return -1; 235 236 return git_default_config(var, value, ctx, cb); 237} 238 239static void write_tag_body(int fd, const struct object_id *oid) 240{ 241 unsigned long size; 242 enum object_type type; 243 char *buf, *sp, *orig; 244 struct strbuf payload = STRBUF_INIT; 245 struct strbuf signature = STRBUF_INIT; 246 247 orig = buf = odb_read_object(the_repository->objects, oid, &type, &size); 248 if (!buf) 249 return; 250 if (parse_signature(buf, size, &payload, &signature)) { 251 buf = payload.buf; 252 size = payload.len; 253 } 254 /* skip header */ 255 sp = strstr(buf, "\n\n"); 256 257 if (!sp || !size || type != OBJ_TAG) { 258 free(buf); 259 return; 260 } 261 sp += 2; /* skip the 2 LFs */ 262 write_or_die(fd, sp, buf + size - sp); 263 264 free(orig); 265 strbuf_release(&payload); 266 strbuf_release(&signature); 267} 268 269static int build_tag_object(struct strbuf *buf, int sign, struct object_id *result) 270{ 271 struct object_id *compat_oid = NULL, compat_oid_buf; 272 if (sign && do_sign(buf, &compat_oid, &compat_oid_buf) < 0) 273 return error(_("unable to sign the tag")); 274 if (odb_write_object_ext(the_repository->objects, buf->buf, 275 buf->len, OBJ_TAG, result, compat_oid, 0) < 0) 276 return error(_("unable to write tag file")); 277 return 0; 278} 279 280struct create_tag_options { 281 unsigned int message_given:1; 282 unsigned int use_editor:1; 283 unsigned int sign; 284 enum { 285 CLEANUP_NONE, 286 CLEANUP_SPACE, 287 CLEANUP_ALL 288 } cleanup_mode; 289}; 290 291static const char message_advice_nested_tag[] = 292 N_("You have created a nested tag. The object referred to by your new tag is\n" 293 "already a tag. If you meant to tag the object that it points to, use:\n" 294 "\n" 295 "\tgit tag -f %s %s^{}"); 296 297static void create_tag(const struct object_id *object, const char *object_ref, 298 const char *tag, 299 struct strbuf *buf, struct create_tag_options *opt, 300 struct object_id *prev, struct object_id *result, 301 struct strvec *trailer_args, char *path) 302{ 303 enum object_type type; 304 struct strbuf header = STRBUF_INIT; 305 int should_edit; 306 307 type = odb_read_object_info(the_repository->objects, object, NULL); 308 if (type <= OBJ_NONE) 309 die(_("bad object type.")); 310 311 if (type == OBJ_TAG) 312 advise_if_enabled(ADVICE_NESTED_TAG, _(message_advice_nested_tag), 313 tag, object_ref); 314 315 strbuf_addf(&header, 316 "object %s\n" 317 "type %s\n" 318 "tag %s\n" 319 "tagger %s\n\n", 320 oid_to_hex(object), 321 type_name(type), 322 tag, 323 git_committer_info(IDENT_STRICT)); 324 325 should_edit = opt->use_editor || !opt->message_given; 326 if (should_edit || trailer_args->nr) { 327 int fd; 328 329 /* write the template message before editing: */ 330 fd = xopen(path, O_CREAT | O_TRUNC | O_WRONLY, 0600); 331 332 if (opt->message_given && buf->len) { 333 strbuf_complete(buf, '\n'); 334 write_or_die(fd, buf->buf, buf->len); 335 strbuf_reset(buf); 336 } else if (!is_null_oid(prev)) { 337 write_tag_body(fd, prev); 338 } else { 339 struct strbuf buf = STRBUF_INIT; 340 strbuf_addch(&buf, '\n'); 341 if (opt->cleanup_mode == CLEANUP_ALL) 342 strbuf_commented_addf(&buf, comment_line_str, 343 _(tag_template), tag, comment_line_str); 344 else 345 strbuf_commented_addf(&buf, comment_line_str, 346 _(tag_template_nocleanup), tag, comment_line_str); 347 write_or_die(fd, buf.buf, buf.len); 348 strbuf_release(&buf); 349 } 350 close(fd); 351 352 if (trailer_args->nr && amend_file_with_trailers(path, trailer_args)) 353 die(_("unable to pass trailers to --trailers")); 354 355 if (should_edit) { 356 if (launch_editor(path, buf, NULL)) { 357 fprintf(stderr, 358 _("Please supply the message using either -m or -F option.\n")); 359 exit(1); 360 } 361 } else if (trailer_args->nr) { 362 strbuf_reset(buf); 363 if (strbuf_read_file(buf, path, 0) < 0) 364 die_errno(_("failed to read '%s'"), path); 365 } 366 } 367 368 if (opt->cleanup_mode != CLEANUP_NONE) 369 strbuf_stripspace(buf, 370 opt->cleanup_mode == CLEANUP_ALL ? comment_line_str : NULL); 371 372 if (!opt->message_given && !buf->len) 373 die(_("no tag message?")); 374 375 strbuf_insert(buf, 0, header.buf, header.len); 376 strbuf_release(&header); 377 378 if (build_tag_object(buf, opt->sign, result) < 0) { 379 if (path) 380 fprintf(stderr, _("The tag message has been left in %s\n"), 381 path); 382 exit(128); 383 } 384} 385 386static void create_reflog_msg(const struct object_id *oid, struct strbuf *sb) 387{ 388 enum object_type type; 389 struct commit *c; 390 char *buf; 391 unsigned long size; 392 int subject_len = 0; 393 const char *subject_start; 394 395 char *rla = getenv("GIT_REFLOG_ACTION"); 396 if (rla) { 397 strbuf_addstr(sb, rla); 398 } else { 399 strbuf_addstr(sb, "tag: tagging "); 400 strbuf_add_unique_abbrev(sb, oid, DEFAULT_ABBREV); 401 } 402 403 strbuf_addstr(sb, " ("); 404 type = odb_read_object_info(the_repository->objects, oid, NULL); 405 switch (type) { 406 default: 407 strbuf_addstr(sb, "object of unknown type"); 408 break; 409 case OBJ_COMMIT: 410 if ((buf = odb_read_object(the_repository->objects, oid, &type, &size))) { 411 subject_len = find_commit_subject(buf, &subject_start); 412 strbuf_insert(sb, sb->len, subject_start, subject_len); 413 } else { 414 strbuf_addstr(sb, "commit object"); 415 } 416 free(buf); 417 418 if ((c = lookup_commit_reference(the_repository, oid))) 419 strbuf_addf(sb, ", %s", show_date(c->date, 0, DATE_MODE(SHORT))); 420 break; 421 case OBJ_TREE: 422 strbuf_addstr(sb, "tree object"); 423 break; 424 case OBJ_BLOB: 425 strbuf_addstr(sb, "blob object"); 426 break; 427 case OBJ_TAG: 428 strbuf_addstr(sb, "other tag object"); 429 break; 430 } 431 strbuf_addch(sb, ')'); 432} 433 434struct msg_arg { 435 int given; 436 struct strbuf buf; 437}; 438 439static int parse_msg_arg(const struct option *opt, const char *arg, int unset) 440{ 441 struct msg_arg *msg = opt->value; 442 443 BUG_ON_OPT_NEG(unset); 444 445 if (!arg) 446 return -1; 447 if (msg->buf.len) 448 strbuf_addstr(&(msg->buf), "\n\n"); 449 strbuf_addstr(&(msg->buf), arg); 450 msg->given = 1; 451 return 0; 452} 453 454int cmd_tag(int argc, 455 const char **argv, 456 const char *prefix, 457 struct repository *repo UNUSED) 458{ 459 struct strbuf buf = STRBUF_INIT; 460 struct strbuf ref = STRBUF_INIT; 461 struct strbuf reflog_msg = STRBUF_INIT; 462 struct object_id object, prev; 463 const char *object_ref, *tag; 464 struct create_tag_options opt; 465 char *cleanup_arg = NULL; 466 int create_reflog = 0; 467 int annotate = 0, force = 0; 468 int cmdmode = 0, create_tag_object = 0; 469 char *msgfile = NULL; 470 const char *keyid = NULL; 471 struct msg_arg msg = { .buf = STRBUF_INIT }; 472 struct ref_transaction *transaction; 473 struct strbuf err = STRBUF_INIT; 474 struct ref_filter filter = REF_FILTER_INIT; 475 struct ref_sorting *sorting; 476 struct string_list sorting_options = STRING_LIST_INIT_DUP; 477 struct ref_format format = REF_FORMAT_INIT; 478 struct strvec trailer_args = STRVEC_INIT; 479 int icase = 0; 480 int edit_flag = 0; 481 struct option options[] = { 482 OPT_CMDMODE('l', "list", &cmdmode, N_("list tag names"), 'l'), 483 { 484 .type = OPTION_INTEGER, 485 .short_name = 'n', 486 .value = &filter.lines, 487 .precision = sizeof(filter.lines), 488 .argh = N_("n"), 489 .help = N_("print <n> lines of each tag message"), 490 .flags = PARSE_OPT_OPTARG, 491 .defval = 1, 492 }, 493 OPT_CMDMODE('d', "delete", &cmdmode, N_("delete tags"), 'd'), 494 OPT_CMDMODE('v', "verify", &cmdmode, N_("verify tags"), 'v'), 495 496 OPT_GROUP(N_("Tag creation options")), 497 OPT_BOOL('a', "annotate", &annotate, 498 N_("annotated tag, needs a message")), 499 OPT_CALLBACK_F('m', "message", &msg, N_("message"), 500 N_("tag message"), PARSE_OPT_NONEG, parse_msg_arg), 501 OPT_FILENAME('F', "file", &msgfile, N_("read message from file")), 502 OPT_PASSTHRU_ARGV(0, "trailer", &trailer_args, N_("trailer"), 503 N_("add custom trailer(s)"), PARSE_OPT_NONEG), 504 OPT_BOOL('e', "edit", &edit_flag, N_("force edit of tag message")), 505 OPT_BOOL('s', "sign", &opt.sign, N_("annotated and GPG-signed tag")), 506 OPT_CLEANUP(&cleanup_arg), 507 OPT_STRING('u', "local-user", &keyid, N_("key-id"), 508 N_("use another key to sign the tag")), 509 OPT__FORCE(&force, N_("replace the tag if exists"), 0), 510 OPT_BOOL(0, "create-reflog", &create_reflog, N_("create a reflog")), 511 512 OPT_GROUP(N_("Tag listing options")), 513 OPT_COLUMN(0, "column", &colopts, N_("show tag list in columns")), 514 OPT_CONTAINS(&filter.with_commit, N_("print only tags that contain the commit")), 515 OPT_NO_CONTAINS(&filter.no_commit, N_("print only tags that don't contain the commit")), 516 OPT_WITH(&filter.with_commit, N_("print only tags that contain the commit")), 517 OPT_WITHOUT(&filter.no_commit, N_("print only tags that don't contain the commit")), 518 OPT_MERGED(&filter, N_("print only tags that are merged")), 519 OPT_NO_MERGED(&filter, N_("print only tags that are not merged")), 520 OPT_BOOL(0, "omit-empty", &format.array_opts.omit_empty, 521 N_("do not output a newline after empty formatted refs")), 522 OPT_REF_SORT(&sorting_options), 523 { 524 .type = OPTION_CALLBACK, 525 .long_name = "points-at", 526 .value = &filter.points_at, 527 .argh = N_("object"), 528 .help = N_("print only tags of the object"), 529 .flags = PARSE_OPT_LASTARG_DEFAULT, 530 .callback = parse_opt_object_name, 531 .defval = (intptr_t) "HEAD", 532 }, 533 OPT_STRING( 0 , "format", &format.format, N_("format"), 534 N_("format to use for the output")), 535 OPT__COLOR(&format.use_color, N_("respect format colors")), 536 OPT_BOOL('i', "ignore-case", &icase, N_("sorting and filtering are case insensitive")), 537 OPT_END() 538 }; 539 int ret = 0; 540 const char *only_in_list = NULL; 541 char *path = NULL; 542 543 setup_ref_filter_porcelain_msg(); 544 545 /* 546 * Try to set sort keys from config. If config does not set any, 547 * fall back on default (refname) sorting. 548 */ 549 repo_config(the_repository, git_tag_config, &sorting_options); 550 if (!sorting_options.nr) 551 string_list_append(&sorting_options, "refname"); 552 553 memset(&opt, 0, sizeof(opt)); 554 filter.lines = -1; 555 opt.sign = -1; 556 557 argc = parse_options(argc, argv, prefix, options, git_tag_usage, 0); 558 559 if (!cmdmode) { 560 if (argc == 0) 561 cmdmode = 'l'; 562 else if (filter.with_commit || filter.no_commit || 563 filter.reachable_from || filter.unreachable_from || 564 filter.points_at.nr || filter.lines != -1) 565 cmdmode = 'l'; 566 } 567 568 if (cmdmode == 'l') 569 setup_auto_pager("tag", 1); 570 571 if (opt.sign == -1) 572 opt.sign = cmdmode ? 0 : config_sign_tag > 0; 573 574 if (keyid) { 575 opt.sign = 1; 576 set_signing_key(keyid); 577 } 578 create_tag_object = (opt.sign || annotate || msg.given || msgfile || 579 edit_flag || trailer_args.nr); 580 581 if ((create_tag_object || force) && (cmdmode != 0)) 582 usage_with_options(git_tag_usage, options); 583 584 finalize_colopts(&colopts, -1); 585 if (cmdmode == 'l' && filter.lines != -1) { 586 if (explicitly_enable_column(colopts)) 587 die(_("options '%s' and '%s' cannot be used together"), "--column", "-n"); 588 colopts = 0; 589 } 590 sorting = ref_sorting_options(&sorting_options); 591 ref_sorting_set_sort_flags_all(sorting, REF_SORTING_ICASE, icase); 592 filter.ignore_case = icase; 593 if (cmdmode == 'l') { 594 if (column_active(colopts)) { 595 struct column_options copts; 596 memset(&copts, 0, sizeof(copts)); 597 copts.padding = 2; 598 if (run_column_filter(colopts, &copts)) 599 die(_("could not start 'git column'")); 600 } 601 filter.name_patterns = argv; 602 ret = list_tags(&filter, sorting, &format); 603 if (column_active(colopts)) 604 stop_column_filter(); 605 goto cleanup; 606 } 607 if (filter.lines != -1) 608 only_in_list = "-n"; 609 else if (filter.with_commit) 610 only_in_list = "--contains"; 611 else if (filter.no_commit) 612 only_in_list = "--no-contains"; 613 else if (filter.points_at.nr) 614 only_in_list = "--points-at"; 615 else if (filter.reachable_from) 616 only_in_list = "--merged"; 617 else if (filter.unreachable_from) 618 only_in_list = "--no-merged"; 619 if (only_in_list) 620 die(_("the '%s' option is only allowed in list mode"), only_in_list); 621 if (cmdmode == 'd') { 622 ret = delete_tags(argv); 623 goto cleanup; 624 } 625 if (cmdmode == 'v') { 626 if (format.format && verify_ref_format(&format)) 627 usage_with_options(git_tag_usage, options); 628 ret = for_each_tag_name(argv, verify_tag, &format); 629 goto cleanup; 630 } 631 632 if (msg.given || msgfile) { 633 if (msg.given && msgfile) 634 die(_("options '%s' and '%s' cannot be used together"), "-F", "-m"); 635 if (msg.given) 636 strbuf_addbuf(&buf, &(msg.buf)); 637 else { 638 if (!strcmp(msgfile, "-")) { 639 if (strbuf_read(&buf, 0, 1024) < 0) 640 die_errno(_("cannot read '%s'"), msgfile); 641 } else { 642 if (strbuf_read_file(&buf, msgfile, 1024) < 0) 643 die_errno(_("could not open or read '%s'"), 644 msgfile); 645 } 646 } 647 } 648 649 tag = argv[0]; 650 651 object_ref = argc == 2 ? argv[1] : "HEAD"; 652 if (argc > 2) 653 die(_("too many arguments")); 654 655 if (repo_get_oid(the_repository, object_ref, &object)) 656 die(_("Failed to resolve '%s' as a valid ref."), object_ref); 657 658 if (check_tag_ref(&ref, tag)) 659 die(_("'%s' is not a valid tag name."), tag); 660 661 if (refs_read_ref(get_main_ref_store(the_repository), ref.buf, &prev)) 662 oidclr(&prev, the_repository->hash_algo); 663 else if (!force) 664 die(_("tag '%s' already exists"), tag); 665 666 opt.message_given = msg.given || msgfile; 667 opt.use_editor = edit_flag; 668 669 if (!cleanup_arg || !strcmp(cleanup_arg, "strip")) 670 opt.cleanup_mode = CLEANUP_ALL; 671 else if (!strcmp(cleanup_arg, "verbatim")) 672 opt.cleanup_mode = CLEANUP_NONE; 673 else if (!strcmp(cleanup_arg, "whitespace")) 674 opt.cleanup_mode = CLEANUP_SPACE; 675 else 676 die(_("Invalid cleanup mode %s"), cleanup_arg); 677 678 create_reflog_msg(&object, &reflog_msg); 679 680 if (create_tag_object) { 681 if (force_sign_annotate && !annotate) 682 opt.sign = 1; 683 path = repo_git_path(the_repository, "TAG_EDITMSG"); 684 create_tag(&object, object_ref, tag, &buf, &opt, &prev, &object, 685 &trailer_args, path); 686 } 687 688 transaction = ref_store_transaction_begin(get_main_ref_store(the_repository), 689 0, &err); 690 if (!transaction || 691 ref_transaction_update(transaction, ref.buf, &object, &prev, 692 NULL, NULL, 693 create_reflog ? REF_FORCE_CREATE_REFLOG : 0, 694 reflog_msg.buf, &err) || 695 ref_transaction_commit(transaction, &err)) { 696 if (path) 697 fprintf(stderr, 698 _("The tag message has been left in %s\n"), 699 path); 700 die("%s", err.buf); 701 } 702 if (path) { 703 unlink_or_warn(path); 704 free(path); 705 } 706 ref_transaction_free(transaction); 707 if (force && !is_null_oid(&prev) && !oideq(&prev, &object)) 708 printf(_("Updated tag '%s' (was %s)\n"), tag, 709 repo_find_unique_abbrev(the_repository, &prev, DEFAULT_ABBREV)); 710 711cleanup: 712 ref_sorting_release(sorting); 713 ref_filter_clear(&filter); 714 strbuf_release(&buf); 715 strbuf_release(&ref); 716 strbuf_release(&reflog_msg); 717 strbuf_release(&msg.buf); 718 strbuf_release(&err); 719 strvec_clear(&trailer_args); 720 free(msgfile); 721 return ret; 722}