Skip to content

Commit dc84ad2

Browse files
committed
sequencer (rebase -i): implement the 'edit' command
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
1 parent 1321c05 commit dc84ad2

1 file changed

Lines changed: 91 additions & 2 deletions

File tree

sequencer.c

Lines changed: 91 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include "merge-recursive.h"
1616
#include "refs.h"
1717
#include "argv-array.h"
18+
#include "log-tree.h"
1819

1920
#define GIT_REFLOG_ACTION "GIT_REFLOG_ACTION"
2021

@@ -35,6 +36,20 @@ static GIT_PATH_FUNC(git_path_rebase_dir, "rebase-merge")
3536
* file and written to the tail of 'done'.
3637
*/
3738
static GIT_PATH_FUNC(git_path_rebase_todo, "rebase-merge/git-rebase-todo")
39+
/*
40+
* When an "edit" rebase command is being processed, the SHA1 of the
41+
* commit to be edited is recorded in this file. When "git rebase
42+
* --continue" is executed, if there are any staged changes then they
43+
* will be amended to the HEAD commit, but only provided the HEAD
44+
* commit is still the commit to be edited. When any other rebase
45+
* command is processed, this file is deleted.
46+
*/
47+
static GIT_PATH_FUNC(git_path_rebase_amend, "rebase-merge/amend")
48+
/*
49+
* When we stop at a given patch via the "edit" command, this file contains
50+
* the long commit name of the corresponding patch.
51+
*/
52+
static GIT_PATH_FUNC(stopped_sha, "rebase-merge/stopped-sha")
3853

3954
#define IS_REBASE_I() (opts->action == REPLAY_INTERACTIVE_REBASE)
4055

@@ -488,12 +503,14 @@ static int allow_empty(struct replay_opts *opts, struct commit *commit)
488503
enum todo_command {
489504
TODO_PICK,
490505
TODO_REVERT,
506+
TODO_EDIT,
491507
TODO_NOOP
492508
};
493509

494510
static const char *todo_command_strings[] = {
495511
"pick",
496512
"revert",
513+
"edit",
497514
"noop"
498515
};
499516

@@ -1065,10 +1082,67 @@ static int save_opts(struct replay_opts *opts)
10651082
return res;
10661083
}
10671084

1068-
static int pick_commits(struct todo_list *todo_list, struct replay_opts *opts)
1085+
static int make_patch(struct commit *commit, struct replay_opts *opts)
10691086
{
1087+
struct strbuf buf = STRBUF_INIT;
1088+
struct rev_info log_tree_opt;
1089+
const char *commit_buffer = get_commit_buffer(commit, NULL), *subject;
10701090
int res;
10711091

1092+
write_file(stopped_sha(), "%s\n", short_commit_name(commit));
1093+
1094+
strbuf_addf(&buf, "%s/patch", get_dir(opts));
1095+
freopen(buf.buf, "w", stdout);
1096+
memset(&log_tree_opt, 0, sizeof(log_tree_opt));
1097+
init_revisions(&log_tree_opt, NULL);
1098+
log_tree_opt.abbrev = 0;
1099+
log_tree_opt.diff = 1;
1100+
log_tree_opt.diffopt.output_format = DIFF_FORMAT_PATCH;
1101+
log_tree_opt.disable_stdin = 1;
1102+
log_tree_opt.no_commit_id = 1;
1103+
res = log_tree_commit(&log_tree_opt, commit);
1104+
strbuf_reset(&buf);
1105+
1106+
strbuf_addf(&buf, "%s/message", get_dir(opts));
1107+
if (!file_exists(buf.buf)) {
1108+
find_commit_subject(commit_buffer, &subject);
1109+
write_file(buf.buf, "%s\n", subject);
1110+
unuse_commit_buffer(commit, commit_buffer);
1111+
}
1112+
strbuf_release(&buf);
1113+
1114+
return res;
1115+
}
1116+
1117+
static int error_with_patch(struct commit *commit,
1118+
struct replay_opts *opts, int exit_code)
1119+
{
1120+
unsigned char head[20];
1121+
1122+
if (get_sha1("HEAD", head))
1123+
return error("Cannot read HEAD");
1124+
1125+
if (make_patch(commit, opts))
1126+
return -1;
1127+
1128+
write_file(git_path_rebase_amend(),
1129+
"%s\n", sha1_to_hex(head));
1130+
1131+
fprintf(stderr, "You can amend the commit now, with\n"
1132+
"\n"
1133+
" git commit --amend\n" /* TODO: $gpg_sign_opt_quoted */
1134+
"\n"
1135+
"Once you are satisfied with your changes, run\n"
1136+
"\n"
1137+
" git rebase --continue\n");
1138+
1139+
return exit_code;
1140+
}
1141+
1142+
static int pick_commits(struct todo_list *todo_list, struct replay_opts *opts)
1143+
{
1144+
int res = 0;
1145+
10721146
setenv(GIT_REFLOG_ACTION, action_name(opts), 0);
10731147
if (opts->allow_ff)
10741148
assert(!(opts->signoff || opts->no_commit ||
@@ -1080,9 +1154,18 @@ static int pick_commits(struct todo_list *todo_list, struct replay_opts *opts)
10801154
struct todo_item *item = todo_list->items + todo_list->current;
10811155
if (save_todo(todo_list, opts))
10821156
return -1;
1083-
if (item->command <= TODO_REVERT)
1157+
if (item->command <= TODO_EDIT) {
10841158
res = do_pick_commit(item->command, item->commit,
10851159
opts);
1160+
if (item->command == TODO_EDIT) {
1161+
struct commit *commit = item->commit;
1162+
if (!res)
1163+
warning("Stopped at %s... %.*s",
1164+
short_commit_name(commit),
1165+
item->arg_len, item->arg);
1166+
return error_with_patch(commit, opts, res);
1167+
}
1168+
}
10861169
else if (item->command != TODO_NOOP)
10871170
return error("Unknown command %d", item->command);
10881171

@@ -1091,6 +1174,12 @@ static int pick_commits(struct todo_list *todo_list, struct replay_opts *opts)
10911174
return res;
10921175
}
10931176

1177+
if (IS_REBASE_I()) {
1178+
/* Stopped in the middle, as planned? */
1179+
if (todo_list->current < todo_list->nr)
1180+
return 0;
1181+
}
1182+
10941183
/*
10951184
* Sequence of picks finished successfully; cleanup by
10961185
* removing the .git/sequencer directory

0 commit comments

Comments
 (0)