Skip to content

Commit

Permalink
rebase -i: reread the todo list if exec touched it
Browse files Browse the repository at this point in the history
In the scripted version of the interactive rebase, there was no internal
representation of the todo list; it was re-read before every command.
That allowed the hack that an `exec` command could append (or even
completely rewrite) the todo list.

This hack was broken by the partial conversion of the interactive rebase
to C, and this patch reinstates it.

We also add a small test to verify that this fix does not regress in the
future.

Signed-off-by: Stephen Hicks <[email protected]>
Signed-off-by: Johannes Schindelin <[email protected]>
Signed-off-by: Junio C Hamano <[email protected]>
  • Loading branch information
shicks authored and gitster committed Apr 27, 2017
1 parent e2cb6ab commit 54fd324
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 0 deletions.
22 changes: 22 additions & 0 deletions sequencer.c
Original file line number Diff line number Diff line change
Expand Up @@ -1200,6 +1200,7 @@ struct todo_list {
struct todo_item *items;
int nr, alloc, current;
int done_nr, total_nr;
struct stat_data stat;
};

#define TODO_LIST_INIT { STRBUF_INIT }
Expand Down Expand Up @@ -1330,6 +1331,7 @@ static int count_commands(struct todo_list *todo_list)
static int read_populate_todo(struct todo_list *todo_list,
struct replay_opts *opts)
{
struct stat st;
const char *todo_file = get_todo_path(opts);
int fd, res;

Expand All @@ -1343,6 +1345,11 @@ static int read_populate_todo(struct todo_list *todo_list,
}
close(fd);

res = stat(todo_file, &st);
if (res)
return error(_("could not stat '%s'"), todo_file);
fill_stat_data(&todo_list->stat, &st);

res = parse_insn_buffer(todo_list->buf.buf, todo_list);
if (res) {
if (is_rebase_i(opts))
Expand Down Expand Up @@ -2028,10 +2035,25 @@ static int pick_commits(struct todo_list *todo_list, struct replay_opts *opts)
} else if (item->command == TODO_EXEC) {
char *end_of_arg = (char *)(item->arg + item->arg_len);
int saved = *end_of_arg;
struct stat st;

*end_of_arg = '\0';
res = do_exec(item->arg);
*end_of_arg = saved;

/* Reread the todo file if it has changed. */
if (res)
; /* fall through */
else if (stat(get_todo_path(opts), &st))
res = error_errno(_("could not stat '%s'"),
get_todo_path(opts));
else if (match_stat_data(&todo_list->stat, &st)) {
todo_list_release(todo_list);
if (read_populate_todo(todo_list, opts))
res = -1; /* message was printed */
/* `current` will be incremented below */
todo_list->current = -1;
}
} else if (!is_noop(item->command))
return error(_("unknown command %d"), item->command);

Expand Down
14 changes: 14 additions & 0 deletions t/t3429-rebase-edit-todo.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#!/bin/sh

test_description='rebase should reread the todo file if an exec modifies it'

. ./test-lib.sh

test_expect_success 'rebase exec modifies rebase-todo' '
test_commit initial &&
todo=.git/rebase-merge/git-rebase-todo &&
git rebase HEAD -x "echo exec touch F >>$todo" &&
test -e F
'

test_done

0 comments on commit 54fd324

Please sign in to comment.