]> git.ipfire.org Git - thirdparty/git.git/blobdiff - sequencer.c
sequencer (rebase -i): implement the 'exec' command
[thirdparty/git.git] / sequencer.c
index b138a3906cf386d3335aba01beadcdb447cd8721..e9c10d7fe55057d6f1791ac3e7595a8192954ee1 100644 (file)
@@ -18,6 +18,7 @@
 #include "quote.h"
 #include "trailer.h"
 #include "log-tree.h"
+#include "wt-status.h"
 
 #define GIT_REFLOG_ACTION "GIT_REFLOG_ACTION"
 
@@ -632,6 +633,8 @@ enum todo_command {
        TODO_PICK = 0,
        TODO_REVERT,
        TODO_EDIT,
+       /* commands that do something else than handling a single commit */
+       TODO_EXEC,
        /* commands that do nothing but are counted for reporting progress */
        TODO_NOOP
 };
@@ -640,6 +643,7 @@ static const char *todo_command_strings[] = {
        "pick",
        "revert",
        "edit",
+       "exec",
        "noop"
 };
 
@@ -938,6 +942,12 @@ static int parse_insn_line(struct todo_item *item, const char *bol, char *eol)
                return -1;
        bol += padding;
 
+       if (item->command == TODO_EXEC) {
+               item->arg = bol;
+               item->arg_len = (int)(eol - bol);
+               return 0;
+       }
+
        end_of_object_name = (char *) bol + strcspn(bol, " \t\n");
        saved = *end_of_object_name;
        *end_of_object_name = '\0';
@@ -1397,6 +1407,46 @@ static int error_with_patch(struct commit *commit,
        return exit_code;
 }
 
+static int do_exec(const char *command_line)
+{
+       const char *child_argv[] = { NULL, NULL };
+       int dirty, status;
+
+       fprintf(stderr, "Executing: %s\n", command_line);
+       child_argv[0] = command_line;
+       status = run_command_v_opt(child_argv, RUN_USING_SHELL);
+
+       /* force re-reading of the cache */
+       if (discard_cache() < 0 || read_cache() < 0)
+               return error(_("could not read index"));
+
+       dirty = require_clean_work_tree("rebase", NULL, 1, 1);
+
+       if (status) {
+               warning(_("execution failed: %s\n%s"
+                         "You can fix the problem, and then run\n"
+                         "\n"
+                         "  git rebase --continue\n"
+                         "\n"),
+                       command_line,
+                       dirty ? N_("and made changes to the index and/or the "
+                               "working tree\n") : "");
+               if (status == 127)
+                       /* command not found */
+                       status = 1;
+       } else if (dirty) {
+               warning(_("execution succeeded: %s\nbut "
+                         "left changes to the index and/or the working tree\n"
+                         "Commit or stash your changes, and then run\n"
+                         "\n"
+                         "  git rebase --continue\n"
+                         "\n"), command_line);
+               status = 1;
+       }
+
+       return status;
+}
+
 static int pick_commits(struct todo_list *todo_list, struct replay_opts *opts)
 {
        int res = 0;
@@ -1425,6 +1475,13 @@ static int pick_commits(struct todo_list *todo_list, struct replay_opts *opts)
                                        item->arg, item->arg_len, opts, res,
                                        !res);
                        }
+               } else if (item->command == TODO_EXEC) {
+                       char *end_of_arg = (char *)(item->arg + item->arg_len);
+                       int saved = *end_of_arg;
+
+                       *end_of_arg = '\0';
+                       res = do_exec(item->arg);
+                       *end_of_arg = saved;
                } else if (!is_noop(item->command))
                        return error(_("unknown command %d"), item->command);