Skip to content

Commit 54fd324

Browse files
shicksgitster
authored andcommitted
rebase -i: reread the todo list if exec touched it
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]>
1 parent e2cb6ab commit 54fd324

File tree

2 files changed

+36
-0
lines changed

2 files changed

+36
-0
lines changed

sequencer.c

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1200,6 +1200,7 @@ struct todo_list {
12001200
struct todo_item *items;
12011201
int nr, alloc, current;
12021202
int done_nr, total_nr;
1203+
struct stat_data stat;
12031204
};
12041205

12051206
#define TODO_LIST_INIT { STRBUF_INIT }
@@ -1330,6 +1331,7 @@ static int count_commands(struct todo_list *todo_list)
13301331
static int read_populate_todo(struct todo_list *todo_list,
13311332
struct replay_opts *opts)
13321333
{
1334+
struct stat st;
13331335
const char *todo_file = get_todo_path(opts);
13341336
int fd, res;
13351337

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

1348+
res = stat(todo_file, &st);
1349+
if (res)
1350+
return error(_("could not stat '%s'"), todo_file);
1351+
fill_stat_data(&todo_list->stat, &st);
1352+
13461353
res = parse_insn_buffer(todo_list->buf.buf, todo_list);
13471354
if (res) {
13481355
if (is_rebase_i(opts))
@@ -2028,10 +2035,25 @@ static int pick_commits(struct todo_list *todo_list, struct replay_opts *opts)
20282035
} else if (item->command == TODO_EXEC) {
20292036
char *end_of_arg = (char *)(item->arg + item->arg_len);
20302037
int saved = *end_of_arg;
2038+
struct stat st;
20312039

20322040
*end_of_arg = '\0';
20332041
res = do_exec(item->arg);
20342042
*end_of_arg = saved;
2043+
2044+
/* Reread the todo file if it has changed. */
2045+
if (res)
2046+
; /* fall through */
2047+
else if (stat(get_todo_path(opts), &st))
2048+
res = error_errno(_("could not stat '%s'"),
2049+
get_todo_path(opts));
2050+
else if (match_stat_data(&todo_list->stat, &st)) {
2051+
todo_list_release(todo_list);
2052+
if (read_populate_todo(todo_list, opts))
2053+
res = -1; /* message was printed */
2054+
/* `current` will be incremented below */
2055+
todo_list->current = -1;
2056+
}
20352057
} else if (!is_noop(item->command))
20362058
return error(_("unknown command %d"), item->command);
20372059

t/t3429-rebase-edit-todo.sh

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#!/bin/sh
2+
3+
test_description='rebase should reread the todo file if an exec modifies it'
4+
5+
. ./test-lib.sh
6+
7+
test_expect_success 'rebase exec modifies rebase-todo' '
8+
test_commit initial &&
9+
todo=.git/rebase-merge/git-rebase-todo &&
10+
git rebase HEAD -x "echo exec touch F >>$todo" &&
11+
test -e F
12+
'
13+
14+
test_done

0 commit comments

Comments
 (0)