git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH v2 3/3] tag: keep the message file in case ref transaction fails

From
Kristoffer Haugsbakk <code@khaugsbakk.name>
Date
May 15, 2023, 20:29 UTC
Message-ID
<e67b6416b7ee05c3b39fad9ab74d4fb0bec4a1b4.1684181855.git.code@khaugsbakk.name>
In-Reply-To
<cover.1684181855.git.code@khaugsbakk.name>

The ref transaction can fail after the user has written their tag message. In particular, if there exists a tag `foo/bar` and `git tag -a foo` is said then the command will only fail once it tries to write `refs/tags/foo`, which is after the file has been unlinked.

Hold on to the message file for a little longer so that it is not unlinked before the fatal error occurs.

Cc: Jeff King <peff@peff.net>
Signed-off-by: Kristoffer Haugsbakk <code@khaugsbakk.name>
---
Notes (series):
    I duplicated this message (this isn’t obvious in the diff):
    
        fprintf(stderr,
                _("The tag message has been left in %s\n"),
                path);
    
    Should this be factored into a static function instead?
    
    § Changes from previous round
    
    Squash (combine) the update to `tag.c` with the test so that the fix and
    the regression test is added in one step.
    
    This makes more sense than what I was going for since the test suite
    would fail on patch 2/3 of the previous round.
    
    Link: https://lore.kernel.org/git/xmqq4joeaxgw.fsf@gitster.g/T/#u
 builtin/tag.c  | 24 +++++++++++++++---------
 t/t7004-tag.sh | 10 ++++++++++
 2 files changed, 25 insertions(+), 9 deletions(-)
diff --git a/builtin/tag.c b/builtin/tag.c
index d428c45dc8..7df9c143ac 100644
--- a/builtin/tag.c
+++ b/builtin/tag.c
@@ -266,11 +266,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)
@@ -294,7 +293,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) {
@@ -336,10 +334,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)
@@ -487,6 +481,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();
 
@@ -621,7 +616,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);
@@ -629,8 +626,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,
diff --git a/t/t7004-tag.sh b/t/t7004-tag.sh
index cd454acfed..37bfa63fe8 100755
--- a/t/t7004-tag.sh
+++ b/t/t7004-tag.sh
@@ -2136,4 +2136,14 @@ test_expect_success 'If tag is created then tag message file is unlinked' '
 	! test_path_exists .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
-- 
2.40.1
Previous: Kristoffer HaugsbakkNext: Junio C Hamano
Message 14 of 26 in “tag: keep the message file in case ref transaction fails”
  1. 0/3 tag: keep the message file in case ref transaction failsKristoffer Haugsbakk, May 14, 2023
  2. 1/3 t/t7004-tag: add regression test for existing behaviorKristoffer Haugsbakk, May 14, 2023
  3. Junio C HamanoMay 15, 2023
  4. 2/3 t/t7004-tag: add failing tag message file testKristoffer Haugsbakk, May 14, 2023
  5. Junio C HamanoMay 15, 2023
  6. Junio C HamanoMay 15, 2023
  7. Kristoffer HaugsbakkMay 15, 2023
  8. 3/3 tag: keep the message file in case ref transaction failsKristoffer Haugsbakk, May 14, 2023
  9. Junio C HamanoMay 15, 2023
  10. 0/3 tag: keep the message file in case ref transaction failsKristoffer Haugsbakk, May 15, 2023
  11. 1/3 doc: tag: document `TAG_EDITMSG`Kristoffer Haugsbakk, May 15, 2023
  12. Junio C HamanoMay 15, 2023
  13. 2/3 t/t7004-tag: add regression test for successful tag creationKristoffer Haugsbakk, May 15, 2023
  14. 3/3 tag: keep the message file in case ref transaction failsKristoffer Haugsbakk, May 15, 2023
  15. Junio C HamanoMay 15, 2023
  16. 0/3 tag: keep the message file in case ref transaction failsKristoffer Haugsbakk, May 16, 2023
  17. 1/3 doc: tag: document `TAG_EDITMSG`Kristoffer Haugsbakk, May 16, 2023
  18. 2/3 t/t7004-tag: add regression test for successful tag creationKristoffer Haugsbakk, May 16, 2023
  19. 3/3 tag: keep the message file in case ref transaction failsKristoffer Haugsbakk, May 16, 2023
  20. Junio C HamanoMay 16, 2023
  21. Jeff KingMay 17, 2023
  22. Junio C HamanoMay 17, 2023
  23. Jeff KingMay 17, 2023
  24. Eric SunshineMay 17, 2023
  25. Kristoffer HaugsbakkMay 17, 2023
  26. Kristoffer HaugsbakkMay 17, 2023

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.