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

[PATCH 4/5] Make sequencer abort safer

From
Stephan Beyer <s-beyer@gmx.net>
Date
Dec 7, 2016, 21:51 UTC
Message-ID
<20161207215133.13433-4-s-beyer@gmx.net>
In-Reply-To
<20161207215133.13433-1-s-beyer@gmx.net>

In contrast to "git am --abort", a sequencer abort did not check whether the current HEAD is the one that is expected. This can lead to loss of work (when not spotted and resolved using reflog before the garbage collector chimes in).

This behavior is now changed by mimicking "git am --abort": the abortion is done but HEAD is not changed when the current HEAD is not the expected HEAD.

A new file "sequencer/current" is added to save the expected HEAD.

The new behavior is only active when --abort is invoked on multiple picks. The problem does not occur for the single-pick case because it is handled differently.

Signed-off-by: Stephan Beyer <s-beyer@gmx.net>
---
 sequencer.c | 49 +++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 49 insertions(+)
diff --git a/sequencer.c b/sequencer.c
index 30b10ba14..c9b560ac1 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -27,6 +27,7 @@ GIT_PATH_FUNC(git_path_seq_dir, "sequencer")
 static GIT_PATH_FUNC(git_path_todo_file, "sequencer/todo")
 static GIT_PATH_FUNC(git_path_opts_file, "sequencer/opts")
 static GIT_PATH_FUNC(git_path_head_file, "sequencer/head")
+static GIT_PATH_FUNC(git_path_curr_file, "sequencer/current")
 
 /*
  * A script to set the GIT_AUTHOR_NAME, GIT_AUTHOR_EMAIL, and
@@ -310,6 +311,20 @@ static int error_dirty_index(struct replay_opts *opts)
 	return -1;
 }
 
+static void update_curr_file()
+{
+	struct object_id head;
+
+	/* Do nothing on a single-pick */
+	if (!file_exists(git_path_seq_dir()))
+		return;
+
+	if (!get_oid("HEAD", &head))
+		write_file(git_path_curr_file(), "%s", oid_to_hex(&head));
+	else
+		write_file(git_path_curr_file(), "%s", "");
+}
+
 static int fast_forward_to(const unsigned char *to, const unsigned char *from,
 			int unborn, struct replay_opts *opts)
 {
@@ -339,6 +354,7 @@ static int fast_forward_to(const unsigned char *to, const unsigned char *from,
 	strbuf_release(&sb);
 	strbuf_release(&err);
 	ref_transaction_free(transaction);
+	update_curr_file();
 	return 0;
 }
 
@@ -813,6 +829,7 @@ static int do_pick_commit(enum todo_command command, struct commit *commit,
 
 leave:
 	free_message(commit, &msg);
+	update_curr_file();
 
 	return res;
 }
@@ -1132,9 +1149,34 @@ static int save_head(const char *head)
 	return 0;
 }
 
+static int rollback_is_safe()
+{
+	struct strbuf sb = STRBUF_INIT;
+	struct object_id expected_head, actual_head;
+
+	if (strbuf_read_file(&sb, git_path_curr_file(), 0) >= 0) {
+		strbuf_trim(&sb);
+		if (get_oid_hex(sb.buf, &expected_head)) {
+			strbuf_release(&sb);
+			die(_("could not parse %s"), git_path_curr_file());
+		}
+		strbuf_release(&sb);
+	}
+	else if (errno == ENOENT)
+		oidclr(&expected_head);
+	else
+		die_errno(_("could not read '%s'"), git_path_curr_file());
+
+	if (get_oid("HEAD", &actual_head))
+		oidclr(&actual_head);
+
+	return !oidcmp(&actual_head, &expected_head);
+}
+
 static int reset_for_rollback(const unsigned char *sha1)
 {
 	const char *argv[4];	/* reset --merge <arg> + NULL */
+
 	argv[0] = "reset";
 	argv[1] = "--merge";
 	argv[2] = sha1_to_hex(sha1);
@@ -1189,6 +1231,12 @@ int sequencer_rollback(struct replay_opts *opts)
 		error(_("cannot abort from a branch yet to be born"));
 		goto fail;
 	}
+
+	if (!rollback_is_safe()) {
+		/* Do not error, just do not rollback */
+		warning(_("You seem to have moved HEAD. "
+			  "Not rewinding, check your HEAD!"));
+	} else
 	if (reset_for_rollback(sha1))
 		goto fail;
 	strbuf_release(&buf);
@@ -1393,6 +1441,7 @@ int sequencer_pick_revisions(struct replay_opts *opts)
 		return -1;
 	if (save_opts(opts))
 		return -1;
+	update_curr_file();
 	res = pick_commits(&todo_list, opts);
 	todo_list_release(&todo_list);
 	return res;
-- 
2.11.0.27.g4eed97c
Previous: Stephan BeyerNext: Johannes Schindelin
Message 2 of 18 in “am: Fix filename in safe_to_abort() error message”
  1. 1/5 am: Fix filename in safe_to_abort() error messageStephan Beyer, Dec 7, 2016
  2. 4/5 Make sequencer abort saferStephan Beyer, Dec 7, 2016
  3. Johannes SchindelinDec 8, 2016
  4. Junio C HamanoDec 8, 2016
  5. Stephan BeyerDec 8, 2016
  6. Junio C HamanoDec 9, 2016
  7. 1/5 am: Fix filename in safe_to_abort() error messageStephan Beyer, Dec 9, 2016
  8. 3/5 Add test that cherry-pick --abort does not unsafely change HEADStephan Beyer, Dec 9, 2016
  9. 2/5 am: Change safe_to_abort()'s not rewinding error into a warningStephan Beyer, Dec 9, 2016
  10. 4/5 Make sequencer abort saferStephan Beyer, Dec 9, 2016
  11. Christian CouderDec 10, 2016
  12. Jeff KingDec 10, 2016
  13. Stephan BeyerDec 10, 2016
  14. 5/5 sequencer: Remove useless get_dir() functionStephan Beyer, Dec 9, 2016
  15. 2/5 am: Change safe_to_abort()'s not rewinding error into a warningStephan Beyer, Dec 7, 2016
  16. 3/5 Add test that cherry-pick --abort does not unsafely change HEADStephan Beyer, Dec 7, 2016
  17. 5/5 sequencer: Remove useless get_dir() functionStephan Beyer, Dec 7, 2016
  18. Paul TanDec 8, 2016

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.