Skip to content

Commit 311af52

Browse files
dschogitster
authored andcommitted
sequencer (rebase -i): implement the 'exec' command
The 'exec' command is a little special among rebase -i's commands, as it does *not* have a SHA-1 as first parameter. Instead, everything after the `exec` command is treated as command-line to execute. Let's reuse the arg/arg_len fields of the todo_item structure (which hold the oneline for pick/edit commands) to point to the command-line. Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
1 parent 56dc3ab commit 311af52

File tree

1 file changed

+57
-0
lines changed

1 file changed

+57
-0
lines changed

sequencer.c

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include "quote.h"
1919
#include "trailer.h"
2020
#include "log-tree.h"
21+
#include "wt-status.h"
2122

2223
#define GIT_REFLOG_ACTION "GIT_REFLOG_ACTION"
2324

@@ -632,6 +633,8 @@ enum todo_command {
632633
TODO_PICK = 0,
633634
TODO_REVERT,
634635
TODO_EDIT,
636+
/* commands that do something else than handling a single commit */
637+
TODO_EXEC,
635638
/* commands that do nothing but are counted for reporting progress */
636639
TODO_NOOP
637640
};
@@ -640,6 +643,7 @@ static const char *todo_command_strings[] = {
640643
"pick",
641644
"revert",
642645
"edit",
646+
"exec",
643647
"noop"
644648
};
645649

@@ -938,6 +942,12 @@ static int parse_insn_line(struct todo_item *item, const char *bol, char *eol)
938942
return -1;
939943
bol += padding;
940944

945+
if (item->command == TODO_EXEC) {
946+
item->arg = bol;
947+
item->arg_len = (int)(eol - bol);
948+
return 0;
949+
}
950+
941951
end_of_object_name = (char *) bol + strcspn(bol, " \t\n");
942952
saved = *end_of_object_name;
943953
*end_of_object_name = '\0';
@@ -1397,6 +1407,46 @@ static int error_with_patch(struct commit *commit,
13971407
return exit_code;
13981408
}
13991409

1410+
static int do_exec(const char *command_line)
1411+
{
1412+
const char *child_argv[] = { NULL, NULL };
1413+
int dirty, status;
1414+
1415+
fprintf(stderr, "Executing: %s\n", command_line);
1416+
child_argv[0] = command_line;
1417+
status = run_command_v_opt(child_argv, RUN_USING_SHELL);
1418+
1419+
/* force re-reading of the cache */
1420+
if (discard_cache() < 0 || read_cache() < 0)
1421+
return error(_("could not read index"));
1422+
1423+
dirty = require_clean_work_tree("rebase", NULL, 1, 1);
1424+
1425+
if (status) {
1426+
warning(_("execution failed: %s\n%s"
1427+
"You can fix the problem, and then run\n"
1428+
"\n"
1429+
" git rebase --continue\n"
1430+
"\n"),
1431+
command_line,
1432+
dirty ? N_("and made changes to the index and/or the "
1433+
"working tree\n") : "");
1434+
if (status == 127)
1435+
/* command not found */
1436+
status = 1;
1437+
} else if (dirty) {
1438+
warning(_("execution succeeded: %s\nbut "
1439+
"left changes to the index and/or the working tree\n"
1440+
"Commit or stash your changes, and then run\n"
1441+
"\n"
1442+
" git rebase --continue\n"
1443+
"\n"), command_line);
1444+
status = 1;
1445+
}
1446+
1447+
return status;
1448+
}
1449+
14001450
static int pick_commits(struct todo_list *todo_list, struct replay_opts *opts)
14011451
{
14021452
int res = 0;
@@ -1425,6 +1475,13 @@ static int pick_commits(struct todo_list *todo_list, struct replay_opts *opts)
14251475
item->arg, item->arg_len, opts, res,
14261476
!res);
14271477
}
1478+
} else if (item->command == TODO_EXEC) {
1479+
char *end_of_arg = (char *)(item->arg + item->arg_len);
1480+
int saved = *end_of_arg;
1481+
1482+
*end_of_arg = '\0';
1483+
res = do_exec(item->arg);
1484+
*end_of_arg = saved;
14281485
} else if (!is_noop(item->command))
14291486
return error(_("unknown command %d"), item->command);
14301487

0 commit comments

Comments
 (0)