summaryrefslogtreecommitdiff
path: root/sequencer.c
diff options
context:
space:
mode:
Diffstat (limited to 'sequencer.c')
-rw-r--r--sequencer.c99
1 files changed, 89 insertions, 10 deletions
diff --git a/sequencer.c b/sequencer.c
index 3d1fdacc54..6d5fe9485a 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -27,6 +27,19 @@ static GIT_PATH_FUNC(git_path_todo_file, "sequencer/todo")
static GIT_PATH_FUNC(git_path_opts_file, "sequencer/opts")
static GIT_PATH_FUNC(git_path_head_file, "sequencer/head")
+/*
+ * A script to set the GIT_AUTHOR_NAME, GIT_AUTHOR_EMAIL, and
+ * GIT_AUTHOR_DATE that will be used for the commit that is currently
+ * being rebased.
+ */
+static GIT_PATH_FUNC(rebase_path_author_script, "rebase-merge/author-script")
+
+/* We will introduce the 'interactive rebase' mode later */
+static inline int is_rebase_i(const struct replay_opts *opts)
+{
+ return 0;
+}
+
static const char *get_dir(const struct replay_opts *opts)
{
return git_path_seq_dir();
@@ -370,19 +383,79 @@ static int is_index_unchanged(void)
}
/*
+ * Read the author-script file into an environment block, ready for use in
+ * run_command(), that can be free()d afterwards.
+ */
+static char **read_author_script(void)
+{
+ struct strbuf script = STRBUF_INIT;
+ int i, count = 0;
+ char *p, *p2, **env;
+ size_t env_size;
+
+ if (strbuf_read_file(&script, rebase_path_author_script(), 256) <= 0)
+ return NULL;
+
+ for (p = script.buf; *p; p++)
+ if (skip_prefix(p, "'\\\\''", (const char **)&p2))
+ strbuf_splice(&script, p - script.buf, p2 - p, "'", 1);
+ else if (*p == '\'')
+ strbuf_splice(&script, p-- - script.buf, 1, "", 0);
+ else if (*p == '\n') {
+ *p = '\0';
+ count++;
+ }
+
+ env_size = (count + 1) * sizeof(*env);
+ strbuf_grow(&script, env_size);
+ memmove(script.buf + env_size, script.buf, script.len);
+ p = script.buf + env_size;
+ env = (char **)strbuf_detach(&script, NULL);
+
+ for (i = 0; i < count; i++) {
+ env[i] = p;
+ p += strlen(p) + 1;
+ }
+ env[count] = NULL;
+
+ return env;
+}
+
+/*
* If we are cherry-pick, and if the merge did not result in
* hand-editing, we will hit this commit and inherit the original
* author date and name.
+ *
* If we are revert, or if our cherry-pick results in a hand merge,
* we had better say that the current user is responsible for that.
+ *
+ * An exception is when run_git_commit() is called during an
+ * interactive rebase: in that case, we will want to retain the
+ * author metadata.
*/
static int run_git_commit(const char *defmsg, struct replay_opts *opts,
int allow_empty)
{
+ char **env = NULL;
struct argv_array array;
int rc;
const char *value;
+ if (is_rebase_i(opts)) {
+ env = read_author_script();
+ if (!env)
+ return error("You have staged changes in your working "
+ "tree. If these changes are meant to be\n"
+ "squashed into the previous commit, run:\n\n"
+ " git commit --amend $gpg_sign_opt_quoted\n\n"
+ "If they are meant to go into a new commit, "
+ "run:\n\n"
+ " git commit $gpg_sign_opt_quoted\n\n"
+ "In both cases, once you're done, continue "
+ "with:\n\n"
+ " git rebase --continue\n");
+ }
+
argv_array_init(&array);
argv_array_push(&array, "commit");
argv_array_push(&array, "-n");
@@ -391,14 +464,13 @@ static int run_git_commit(const char *defmsg, struct replay_opts *opts,
argv_array_pushf(&array, "-S%s", opts->gpg_sign);
if (opts->signoff)
argv_array_push(&array, "-s");
- if (!opts->edit) {
- argv_array_push(&array, "-F");
- argv_array_push(&array, defmsg);
- if (!opts->signoff &&
- !opts->record_origin &&
- git_config_get_value("commit.cleanup", &value))
- argv_array_push(&array, "--cleanup=verbatim");
- }
+ if (defmsg)
+ argv_array_pushl(&array, "-F", defmsg, NULL);
+ if (opts->edit)
+ argv_array_push(&array, "-e");
+ else if (!opts->signoff && !opts->record_origin &&
+ git_config_get_value("commit.cleanup", &value))
+ argv_array_push(&array, "--cleanup=verbatim");
if (allow_empty)
argv_array_push(&array, "--allow-empty");
@@ -406,8 +478,11 @@ static int run_git_commit(const char *defmsg, struct replay_opts *opts,
if (opts->allow_empty_message)
argv_array_push(&array, "--allow-empty-message");
- rc = run_command_v_opt(array.argv, RUN_GIT_CMD);
+ rc = run_command_v_opt_cd_env(array.argv, RUN_GIT_CMD, NULL,
+ (const char *const *)env);
argv_array_clear(&array);
+ free(env);
+
return rc;
}
@@ -657,7 +732,8 @@ static int do_pick_commit(enum todo_command command, struct commit *commit,
goto leave;
}
if (!opts->no_commit)
- res = run_git_commit(git_path_merge_msg(), opts, allow);
+ res = run_git_commit(opts->edit ? NULL : git_path_merge_msg(),
+ opts, allow);
leave:
free_message(commit, &msg);
@@ -879,6 +955,9 @@ static int populate_opts_cb(const char *key, const char *value, void *data)
static int read_populate_opts(struct replay_opts *opts)
{
+ if (is_rebase_i(opts))
+ return 0;
+
if (!file_exists(git_path_opts_file()))
return 0;
/*