Skip to content

Commit b5a6704

Browse files
dschogitster
authored andcommitted
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. Also, in "interactive rebase" mode we want to skip reading the options in the state directory of the cherry-pick/revert commands. Finally, 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 <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent c22f7df commit b5a6704

File tree

1 file changed

+89
-10
lines changed

1 file changed

+89
-10
lines changed

sequencer.c

Lines changed: 89 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,19 @@ static GIT_PATH_FUNC(git_path_todo_file, "sequencer/todo")
2727
static GIT_PATH_FUNC(git_path_opts_file, "sequencer/opts")
2828
static GIT_PATH_FUNC(git_path_head_file, "sequencer/head")
2929

30+
/*
31+
* A script to set the GIT_AUTHOR_NAME, GIT_AUTHOR_EMAIL, and
32+
* GIT_AUTHOR_DATE that will be used for the commit that is currently
33+
* being rebased.
34+
*/
35+
static GIT_PATH_FUNC(rebase_path_author_script, "rebase-merge/author-script")
36+
37+
/* We will introduce the 'interactive rebase' mode later */
38+
static inline int is_rebase_i(const struct replay_opts *opts)
39+
{
40+
return 0;
41+
}
42+
3043
static const char *get_dir(const struct replay_opts *opts)
3144
{
3245
return git_path_seq_dir();
@@ -369,20 +382,80 @@ static int is_index_unchanged(void)
369382
return !hashcmp(active_cache_tree->sha1, head_commit->tree->object.oid.hash);
370383
}
371384

385+
/*
386+
* Read the author-script file into an environment block, ready for use in
387+
* run_command(), that can be free()d afterwards.
388+
*/
389+
static char **read_author_script(void)
390+
{
391+
struct strbuf script = STRBUF_INIT;
392+
int i, count = 0;
393+
char *p, *p2, **env;
394+
size_t env_size;
395+
396+
if (strbuf_read_file(&script, rebase_path_author_script(), 256) <= 0)
397+
return NULL;
398+
399+
for (p = script.buf; *p; p++)
400+
if (skip_prefix(p, "'\\\\''", (const char **)&p2))
401+
strbuf_splice(&script, p - script.buf, p2 - p, "'", 1);
402+
else if (*p == '\'')
403+
strbuf_splice(&script, p-- - script.buf, 1, "", 0);
404+
else if (*p == '\n') {
405+
*p = '\0';
406+
count++;
407+
}
408+
409+
env_size = (count + 1) * sizeof(*env);
410+
strbuf_grow(&script, env_size);
411+
memmove(script.buf + env_size, script.buf, script.len);
412+
p = script.buf + env_size;
413+
env = (char **)strbuf_detach(&script, NULL);
414+
415+
for (i = 0; i < count; i++) {
416+
env[i] = p;
417+
p += strlen(p) + 1;
418+
}
419+
env[count] = NULL;
420+
421+
return env;
422+
}
423+
372424
/*
373425
* If we are cherry-pick, and if the merge did not result in
374426
* hand-editing, we will hit this commit and inherit the original
375427
* author date and name.
428+
*
376429
* If we are revert, or if our cherry-pick results in a hand merge,
377430
* we had better say that the current user is responsible for that.
431+
*
432+
* An exception is when run_git_commit() is called during an
433+
* interactive rebase: in that case, we will want to retain the
434+
* author metadata.
378435
*/
379436
static int run_git_commit(const char *defmsg, struct replay_opts *opts,
380437
int allow_empty)
381438
{
439+
char **env = NULL;
382440
struct argv_array array;
383441
int rc;
384442
const char *value;
385443

444+
if (is_rebase_i(opts)) {
445+
env = read_author_script();
446+
if (!env)
447+
return error("You have staged changes in your working "
448+
"tree. If these changes are meant to be\n"
449+
"squashed into the previous commit, run:\n\n"
450+
" git commit --amend $gpg_sign_opt_quoted\n\n"
451+
"If they are meant to go into a new commit, "
452+
"run:\n\n"
453+
" git commit $gpg_sign_opt_quoted\n\n"
454+
"In both cases, once you're done, continue "
455+
"with:\n\n"
456+
" git rebase --continue\n");
457+
}
458+
386459
argv_array_init(&array);
387460
argv_array_push(&array, "commit");
388461
argv_array_push(&array, "-n");
@@ -391,23 +464,25 @@ static int run_git_commit(const char *defmsg, struct replay_opts *opts,
391464
argv_array_pushf(&array, "-S%s", opts->gpg_sign);
392465
if (opts->signoff)
393466
argv_array_push(&array, "-s");
394-
if (!opts->edit) {
395-
argv_array_push(&array, "-F");
396-
argv_array_push(&array, defmsg);
397-
if (!opts->signoff &&
398-
!opts->record_origin &&
399-
git_config_get_value("commit.cleanup", &value))
400-
argv_array_push(&array, "--cleanup=verbatim");
401-
}
467+
if (defmsg)
468+
argv_array_pushl(&array, "-F", defmsg, NULL);
469+
if (opts->edit)
470+
argv_array_push(&array, "-e");
471+
else if (!opts->signoff && !opts->record_origin &&
472+
git_config_get_value("commit.cleanup", &value))
473+
argv_array_push(&array, "--cleanup=verbatim");
402474

403475
if (allow_empty)
404476
argv_array_push(&array, "--allow-empty");
405477

406478
if (opts->allow_empty_message)
407479
argv_array_push(&array, "--allow-empty-message");
408480

409-
rc = run_command_v_opt(array.argv, RUN_GIT_CMD);
481+
rc = run_command_v_opt_cd_env(array.argv, RUN_GIT_CMD, NULL,
482+
(const char *const *)env);
410483
argv_array_clear(&array);
484+
free(env);
485+
411486
return rc;
412487
}
413488

@@ -657,7 +732,8 @@ static int do_pick_commit(enum todo_command command, struct commit *commit,
657732
goto leave;
658733
}
659734
if (!opts->no_commit)
660-
res = run_git_commit(git_path_merge_msg(), opts, allow);
735+
res = run_git_commit(opts->edit ? NULL : git_path_merge_msg(),
736+
opts, allow);
661737

662738
leave:
663739
free_message(commit, &msg);
@@ -879,6 +955,9 @@ static int populate_opts_cb(const char *key, const char *value, void *data)
879955

880956
static int read_populate_opts(struct replay_opts *opts)
881957
{
958+
if (is_rebase_i(opts))
959+
return 0;
960+
882961
if (!file_exists(git_path_opts_file()))
883962
return 0;
884963
/*

0 commit comments

Comments
 (0)