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>
Johannes Schindelin committed
Jan 2, 2017 at 16:26 UTC
311af5266b27523742e8be9d8297ea475137cfb5
1 file changed
+57
sequencer.c
+57
@@ -18,6 +18,7 @@
18
#include "quote.h"
19
#include "trailer.h"
20
#include "log-tree.h"
21
+#include "wt-status.h"
22
23
#define GIT_REFLOG_ACTION "GIT_REFLOG_ACTION"
24
@@ -632,6 +633,8 @@ enum todo_command {
633
TODO_PICK = 0,
634
TODO_REVERT,
635
TODO_EDIT,
636
+ /* commands that do something else than handling a single commit */
637
+ TODO_EXEC,
638
/* commands that do nothing but are counted for reporting progress */
639
TODO_NOOP
640
};
@@ -640,6 +643,7 @@ static const char *todo_command_strings[] = {
643
"pick",
644
"revert",
645
"edit",
646
+ "exec",
647
"noop"
648
};
649
@@ -938,6 +942,12 @@ static int parse_insn_line(struct todo_item *item, const char *bol, char *eol)
942
return -1;
943
bol += padding;
944
945
+ if (item->command == TODO_EXEC) {
946
+ item->arg = bol;
947
+ item->arg_len = (int)(eol - bol);
948
+ return 0;
949
+ }
950
+
951
end_of_object_name = (char *) bol + strcspn(bol, " \t\n");
952
saved = *end_of_object_name;
953
*end_of_object_name = '\0';
@@ -1397,6 +1407,46 @@ static int error_with_patch(struct commit *commit,
1407
return exit_code;
1408
}
1409
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
+
1450
static int pick_commits(struct todo_list *todo_list, struct replay_opts *opts)
1451
{
1452
int res = 0;
@@ -1425,6 +1475,13 @@ static int pick_commits(struct todo_list *todo_list, struct replay_opts *opts)
1475
item->arg, item->arg_len, opts, res,
1476
!res);
1477
}
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;
1485
} else if (!is_noop(item->command))
1486
return error(_("unknown command %d"), item->command);
1487