Merge branch 'kh/keep-tag-editmsg-upon-failure'

"git tag" learned to leave the "$GIT_DIR/TAG_EDITMSG" file when the
command failed, so that the user can salvage what they typed.

* kh/keep-tag-editmsg-upon-failure:
  tag: keep the message file in case ref transaction fails
  t/t7004-tag: add regression test for successful tag creation
  doc: tag: document `TAG_EDITMSG`
This commit is contained in:
Junio C Hamano 2023-06-13 12:29:44 -07:00
commit 6d2a88c728
3 changed files with 44 additions and 9 deletions

View file

@ -381,6 +381,16 @@ $ GIT_COMMITTER_DATE="2006-10-02 10:31" git tag -s v1.0.1
include::date-formats.txt[]
FILES
-----
`$GIT_DIR/TAG_EDITMSG`::
This file contains the message of an in-progress annotated
tag. If `git tag` exits due to an error before creating an
annotated tag then the tag message that has been provided by the
user in an editor session will be available in this file, but
may be overwritten by the next invocation of `git tag`.
NOTES
-----

View file

@ -271,11 +271,10 @@ static const char message_advice_nested_tag[] =
static void create_tag(const struct object_id *object, const char *object_ref,
const char *tag,
struct strbuf *buf, struct create_tag_options *opt,
struct object_id *prev, struct object_id *result)
struct object_id *prev, struct object_id *result, char *path)
{
enum object_type type;
struct strbuf header = STRBUF_INIT;
char *path = NULL;
type = oid_object_info(the_repository, object, NULL);
if (type <= OBJ_NONE)
@ -299,7 +298,6 @@ static void create_tag(const struct object_id *object, const char *object_ref,
int fd;
/* write the template message before editing: */
path = git_pathdup("TAG_EDITMSG");
fd = xopen(path, O_CREAT | O_TRUNC | O_WRONLY, 0600);
if (opt->message_given) {
@ -341,10 +339,6 @@ static void create_tag(const struct object_id *object, const char *object_ref,
path);
exit(128);
}
if (path) {
unlink_or_warn(path);
free(path);
}
}
static void create_reflog_msg(const struct object_id *oid, struct strbuf *sb)
@ -495,6 +489,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
};
int ret = 0;
const char *only_in_list = NULL;
char *path = NULL;
setup_ref_filter_porcelain_msg();
@ -629,7 +624,9 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
if (create_tag_object) {
if (force_sign_annotate && !annotate)
opt.sign = 1;
create_tag(&object, object_ref, tag, &buf, &opt, &prev, &object);
path = git_pathdup("TAG_EDITMSG");
create_tag(&object, object_ref, tag, &buf, &opt, &prev, &object,
path);
}
transaction = ref_transaction_begin(&err);
@ -637,8 +634,17 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
ref_transaction_update(transaction, ref.buf, &object, &prev,
create_reflog ? REF_FORCE_CREATE_REFLOG : 0,
reflog_msg.buf, &err) ||
ref_transaction_commit(transaction, &err))
ref_transaction_commit(transaction, &err)) {
if (path)
fprintf(stderr,
_("The tag message has been left in %s\n"),
path);
die("%s", err.buf);
}
if (path) {
unlink_or_warn(path);
free(path);
}
ref_transaction_free(transaction);
if (force && !is_null_oid(&prev) && !oideq(&prev, &object))
printf(_("Updated tag '%s' (was %s)\n"), tag,

View file

@ -2188,4 +2188,23 @@ test_expect_success 'Does --[no-]contains stop at commits? Yes!' '
test_cmp expected actual
'
test_expect_success 'If tag is created then tag message file is unlinked' '
test_when_finished "git tag -d foo" &&
write_script fakeeditor <<-\EOF &&
echo Message >.git/TAG_EDITMSG
EOF
GIT_EDITOR=./fakeeditor git tag -a foo &&
test_path_is_missing .git/TAG_EDITMSG
'
test_expect_success 'If tag cannot be created then tag message file is not unlinked' '
test_when_finished "git tag -d foo/bar && rm .git/TAG_EDITMSG" &&
write_script fakeeditor <<-\EOF &&
echo Message >.git/TAG_EDITMSG
EOF
git tag foo/bar &&
test_must_fail env GIT_EDITOR=./fakeeditor git tag -a foo &&
test_path_exists .git/TAG_EDITMSG
'
test_done