Skip to content

Commit ac8763b

Browse files
committed
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. Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
1 parent 8e28f2a commit ac8763b

2 files changed

Lines changed: 80 additions & 5 deletions

File tree

sequencer.c

Lines changed: 77 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,17 @@ static GIT_PATH_FUNC(git_path_rebase_dir, "rebase-merge")
3737
* file and written to the tail of 'done'.
3838
*/
3939
static GIT_PATH_FUNC(git_path_rebase_todo, "rebase-merge/git-rebase-todo")
40+
/*
41+
* The commit message that is planned to be used for any changes that
42+
* need to be committed following a user interaction.
43+
*/
44+
static GIT_PATH_FUNC(git_path_rebase_msg, "rebase-merge/message")
45+
/*
46+
* A script to set the GIT_AUTHOR_NAME, GIT_AUTHOR_EMAIL, and
47+
* GIT_AUTHOR_DATE that will be used for the commit that is currently
48+
* being rebased.
49+
*/
50+
static GIT_PATH_FUNC(author_script, "rebase-merge/author-script")
4051
/*
4152
* When an "edit" rebase command is being processed, the SHA1 of the
4253
* commit to be edited is recorded in this file. When "git rebase
@@ -401,20 +412,76 @@ static int is_index_unchanged(void)
401412
return !hashcmp(active_cache_tree->sha1, head_commit->tree->object.oid.hash);
402413
}
403414

415+
static char **read_author_script()
416+
{
417+
struct strbuf script = STRBUF_INIT;
418+
int i, count = 0;
419+
char *p, *p2, **env;
420+
size_t env_size;
421+
422+
if (strbuf_read_file(&script, author_script(), 256) <= 0)
423+
return NULL;
424+
425+
for (p = script.buf; *p; p++)
426+
if (skip_prefix(p, "'\\\\''", (const char **)&p2))
427+
strbuf_splice(&script, p - script.buf, p2 - p, "'", 1);
428+
else if (*p == '\'')
429+
strbuf_splice(&script, p-- - script.buf, 1, "", 0);
430+
else if (*p == '\n') {
431+
*p = '\0';
432+
count++;
433+
}
434+
435+
env_size = (count + 1) * sizeof(*env);
436+
strbuf_grow(&script, env_size);
437+
memmove(script.buf + env_size, script.buf, script.len);
438+
p = script.buf + env_size;
439+
env = (char **)strbuf_detach(&script, NULL);
440+
441+
for (i = 0; i < count; i++) {
442+
env[i] = p;
443+
p += strlen(p) + 1;
444+
}
445+
env[count] = NULL;
446+
447+
return env;
448+
}
449+
404450
/*
405451
* If we are cherry-pick, and if the merge did not result in
406452
* hand-editing, we will hit this commit and inherit the original
407453
* author date and name.
408454
* If we are revert, or if our cherry-pick results in a hand merge,
409-
* we had better say that the current user is responsible for that.
455+
* we had better say that the current user is responsible for that
456+
* (except, of course, while running an interactive rebase).
410457
*/
411-
static int run_git_commit(const char *defmsg, struct replay_opts *opts,
458+
int sequencer_commit(const char *defmsg, struct replay_opts *opts,
412459
int allow_empty)
413460
{
461+
char **env = NULL;
414462
struct argv_array array;
415463
int rc;
416464
const char *value;
417465

466+
if (IS_REBASE_I()) {
467+
if (!defmsg)
468+
defmsg = git_path_rebase_msg();
469+
470+
env = read_author_script();
471+
if (!env)
472+
/* TODO: gpg_sign_opt */
473+
return error("You have staged changes in your working "
474+
"tree. If these changes are meant to be\n"
475+
"squashed into the previous commit, run:\n\n"
476+
" git commit --amend $gpg_sign_opt_quoted\n\n"
477+
"If they are meant to go into a new commit, "
478+
"run:\n\n"
479+
" git commit $gpg_sign_opt_quoted\n\n"
480+
"In both case, once you're done, continue "
481+
"with:\n\n"
482+
" git rebase --continue\n");
483+
}
484+
418485
argv_array_init(&array);
419486
argv_array_push(&array, "commit");
420487
argv_array_push(&array, "-n");
@@ -423,23 +490,28 @@ static int run_git_commit(const char *defmsg, struct replay_opts *opts,
423490
argv_array_pushf(&array, "-S%s", opts->gpg_sign);
424491
if (opts->signoff)
425492
argv_array_push(&array, "-s");
426-
if (!opts->edit) {
493+
if (!opts->edit || IS_REBASE_I()) {
427494
argv_array_push(&array, "-F");
428495
argv_array_push(&array, defmsg);
429496
if (!opts->signoff &&
430497
!opts->record_origin &&
431498
git_config_get_value("commit.cleanup", &value))
432499
argv_array_push(&array, "--cleanup=verbatim");
433500
}
501+
if (opts->edit && IS_REBASE_I())
502+
argv_array_push(&array, "-e");
434503

435504
if (allow_empty)
436505
argv_array_push(&array, "--allow-empty");
437506

438507
if (opts->allow_empty_message)
439508
argv_array_push(&array, "--allow-empty-message");
440509

441-
rc = run_command_v_opt(array.argv, RUN_GIT_CMD);
510+
rc = run_command_v_opt_cd_env(array.argv, RUN_GIT_CMD, NULL,
511+
(const char *const *)env);
442512
argv_array_clear(&array);
513+
free(env);
514+
443515
return rc;
444516
}
445517

@@ -693,7 +765,7 @@ static int do_pick_commit(enum todo_command command, struct commit *commit,
693765
goto leave;
694766
}
695767
if (!opts->no_commit)
696-
res = run_git_commit(git_path_merge_msg(), opts, allow);
768+
res = sequencer_commit(git_path_merge_msg(), opts, allow);
697769

698770
leave:
699771
free_message(commit, &msg);

sequencer.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,9 @@ int sequencer_continue(struct replay_opts *opts);
4444
int sequencer_rollback(struct replay_opts *opts);
4545
int sequencer_remove_state(struct replay_opts *opts);
4646

47+
int sequencer_commit(const char *defmsg, struct replay_opts *opts,
48+
int allow_empty);
49+
4750
extern const char sign_off_header[];
4851

4952
void append_signoff(struct strbuf *msgbuf, int ignore_footer, unsigned flag);

0 commit comments

Comments
 (0)