mirror of
https://github.com/git/git.git
synced 2026-02-02 22:12:23 +00:00
sequencer: prepare for rebase -i's commit functionality
In interactive rebases, we commit a little bit differently than the sequencer did so far: we heed the "author-script", the "message" and the "amend" files in the .git/rebase-merge/ subdirectory. Likewise, we may want to edit the commit message *even* when providing a file containing the suggested commit message. Therefore we change the code to not even provide a default message when we do not want any, and to call the editor explicitly. As interactive rebase's GPG settings are configured differently from how cherry-pick (and therefore sequencer) handles them, we will leave support for that to the next commit. Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
This commit is contained in:
97
sequencer.c
97
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();
|
||||
@@ -377,20 +390,76 @@ static int is_index_unchanged(void)
|
||||
return !hashcmp(active_cache_tree->sha1, head_commit->tree->object.oid.hash);
|
||||
}
|
||||
|
||||
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 sequencer_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 sequencer_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 case, 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");
|
||||
@@ -399,14 +468,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");
|
||||
@@ -414,8 +482,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;
|
||||
}
|
||||
|
||||
@@ -664,7 +735,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 = sequencer_commit(opts->edit ? NULL : git_path_merge_msg(),
|
||||
opts, allow);
|
||||
|
||||
leave:
|
||||
free_message(commit, &msg);
|
||||
@@ -877,6 +949,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;
|
||||
/*
|
||||
|
||||
@@ -53,6 +53,9 @@ int sequencer_continue(struct replay_opts *opts);
|
||||
int sequencer_rollback(struct replay_opts *opts);
|
||||
int sequencer_remove_state(struct replay_opts *opts);
|
||||
|
||||
int sequencer_commit(const char *defmsg, struct replay_opts *opts,
|
||||
int allow_empty);
|
||||
|
||||
extern const char sign_off_header[];
|
||||
|
||||
void append_signoff(struct strbuf *msgbuf, int ignore_footer, unsigned flag);
|
||||
|
||||
Reference in New Issue
Block a user