Merge branch 'js/prepare-sequencer'

Update of the sequencer codebase to make it reusable to reimplement
"rebase -i" continues.

* js/prepare-sequencer: (27 commits)
  sequencer: mark all error messages for translation
  sequencer: start error messages consistently with lower case
  sequencer: quote filenames in error messages
  sequencer: mark action_name() for translation
  sequencer: remove overzealous assumption in rebase -i mode
  sequencer: teach write_message() to append an optional LF
  sequencer: refactor write_message() to take a pointer/length
  sequencer: roll back lock file if write_message() failed
  sequencer: stop releasing the strbuf in write_message()
  sequencer: left-trim lines read from the script
  sequencer: support cleaning up commit messages
  sequencer: support amending commits
  sequencer: allow editing the commit message on a case-by-case basis
  sequencer: introduce a helper to read files written by scripts
  sequencer: prepare for rebase -i's commit functionality
  sequencer: remember the onelines when parsing the todo file
  sequencer: get rid of the subcommand field
  sequencer: avoid completely different messages for different actions
  sequencer: strip CR from the todo script
  sequencer: completely revamp the "todo" script parsing
  ...
This commit is contained in:
Junio C Hamano 2016-10-27 14:58:50 -07:00
commit cca3be6ea1
5 changed files with 493 additions and 262 deletions

View File

@ -183,7 +183,7 @@ static void determine_whence(struct wt_status *s)
whence = FROM_MERGE; whence = FROM_MERGE;
else if (file_exists(git_path_cherry_pick_head())) { else if (file_exists(git_path_cherry_pick_head())) {
whence = FROM_CHERRY_PICK; whence = FROM_CHERRY_PICK;
if (file_exists(git_path(SEQ_DIR))) if (file_exists(git_path_seq_dir()))
sequencer_in_use = 1; sequencer_in_use = 1;
} }
else else

View File

@ -71,7 +71,7 @@ static void verify_opt_compatible(const char *me, const char *base_opt, ...)
die(_("%s: %s cannot be used with %s"), me, this_opt, base_opt); die(_("%s: %s cannot be used with %s"), me, this_opt, base_opt);
} }
static void parse_args(int argc, const char **argv, struct replay_opts *opts) static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)
{ {
const char * const * usage_str = revert_or_cherry_pick_usage(opts); const char * const * usage_str = revert_or_cherry_pick_usage(opts);
const char *me = action_name(opts); const char *me = action_name(opts);
@ -115,25 +115,15 @@ static void parse_args(int argc, const char **argv, struct replay_opts *opts)
if (opts->keep_redundant_commits) if (opts->keep_redundant_commits)
opts->allow_empty = 1; opts->allow_empty = 1;
/* Set the subcommand */
if (cmd == 'q')
opts->subcommand = REPLAY_REMOVE_STATE;
else if (cmd == 'c')
opts->subcommand = REPLAY_CONTINUE;
else if (cmd == 'a')
opts->subcommand = REPLAY_ROLLBACK;
else
opts->subcommand = REPLAY_NONE;
/* Check for incompatible command line arguments */ /* Check for incompatible command line arguments */
if (opts->subcommand != REPLAY_NONE) { if (cmd) {
char *this_operation; char *this_operation;
if (opts->subcommand == REPLAY_REMOVE_STATE) if (cmd == 'q')
this_operation = "--quit"; this_operation = "--quit";
else if (opts->subcommand == REPLAY_CONTINUE) else if (cmd == 'c')
this_operation = "--continue"; this_operation = "--continue";
else { else {
assert(opts->subcommand == REPLAY_ROLLBACK); assert(cmd == 'a');
this_operation = "--abort"; this_operation = "--abort";
} }
@ -156,7 +146,7 @@ static void parse_args(int argc, const char **argv, struct replay_opts *opts)
"--edit", opts->edit, "--edit", opts->edit,
NULL); NULL);
if (opts->subcommand != REPLAY_NONE) { if (cmd) {
opts->revs = NULL; opts->revs = NULL;
} else { } else {
struct setup_revision_opt s_r_opt; struct setup_revision_opt s_r_opt;
@ -174,20 +164,30 @@ static void parse_args(int argc, const char **argv, struct replay_opts *opts)
if (argc > 1) if (argc > 1)
usage_with_options(usage_str, options); usage_with_options(usage_str, options);
/* These option values will be free()d */
opts->gpg_sign = xstrdup_or_null(opts->gpg_sign);
opts->strategy = xstrdup_or_null(opts->strategy);
if (cmd == 'q')
return sequencer_remove_state(opts);
if (cmd == 'c')
return sequencer_continue(opts);
if (cmd == 'a')
return sequencer_rollback(opts);
return sequencer_pick_revisions(opts);
} }
int cmd_revert(int argc, const char **argv, const char *prefix) int cmd_revert(int argc, const char **argv, const char *prefix)
{ {
struct replay_opts opts; struct replay_opts opts = REPLAY_OPTS_INIT;
int res; int res;
memset(&opts, 0, sizeof(opts));
if (isatty(0)) if (isatty(0))
opts.edit = 1; opts.edit = 1;
opts.action = REPLAY_REVERT; opts.action = REPLAY_REVERT;
git_config(git_default_config, NULL); git_config(git_default_config, NULL);
parse_args(argc, argv, &opts); res = run_sequencer(argc, argv, &opts);
res = sequencer_pick_revisions(&opts);
if (res < 0) if (res < 0)
die(_("revert failed")); die(_("revert failed"));
return res; return res;
@ -195,14 +195,12 @@ int cmd_revert(int argc, const char **argv, const char *prefix)
int cmd_cherry_pick(int argc, const char **argv, const char *prefix) int cmd_cherry_pick(int argc, const char **argv, const char *prefix)
{ {
struct replay_opts opts; struct replay_opts opts = REPLAY_OPTS_INIT;
int res; int res;
memset(&opts, 0, sizeof(opts));
opts.action = REPLAY_PICK; opts.action = REPLAY_PICK;
git_config(git_default_config, NULL); git_config(git_default_config, NULL);
parse_args(argc, argv, &opts); res = run_sequencer(argc, argv, &opts);
res = sequencer_pick_revisions(&opts);
if (res < 0) if (res < 0)
die(_("cherry-pick failed")); die(_("cherry-pick failed"));
return res; return res;

File diff suppressed because it is too large Load Diff

View File

@ -1,10 +1,7 @@
#ifndef SEQUENCER_H #ifndef SEQUENCER_H
#define SEQUENCER_H #define SEQUENCER_H
#define SEQ_DIR "sequencer" const char *git_path_seq_dir(void);
#define SEQ_HEAD_FILE "sequencer/head"
#define SEQ_TODO_FILE "sequencer/todo"
#define SEQ_OPTS_FILE "sequencer/opts"
#define APPEND_SIGNOFF_DEDUP (1u << 0) #define APPEND_SIGNOFF_DEDUP (1u << 0)
@ -13,16 +10,8 @@ enum replay_action {
REPLAY_PICK REPLAY_PICK
}; };
enum replay_subcommand {
REPLAY_NONE,
REPLAY_REMOVE_STATE,
REPLAY_CONTINUE,
REPLAY_ROLLBACK
};
struct replay_opts { struct replay_opts {
enum replay_action action; enum replay_action action;
enum replay_subcommand subcommand;
/* Boolean options */ /* Boolean options */
int edit; int edit;
@ -37,18 +26,22 @@ struct replay_opts {
int mainline; int mainline;
const char *gpg_sign; char *gpg_sign;
/* Merge strategy */ /* Merge strategy */
const char *strategy; char *strategy;
const char **xopts; char **xopts;
size_t xopts_nr, xopts_alloc; size_t xopts_nr, xopts_alloc;
/* Only used by REPLAY_NONE */ /* Only used by REPLAY_NONE */
struct rev_info *revs; struct rev_info *revs;
}; };
#define REPLAY_OPTS_INIT { -1 }
int sequencer_pick_revisions(struct replay_opts *opts); int sequencer_pick_revisions(struct replay_opts *opts);
int sequencer_continue(struct replay_opts *opts);
int sequencer_rollback(struct replay_opts *opts);
int sequencer_remove_state(struct replay_opts *opts);
extern const char sign_off_header[]; extern const char sign_off_header[];

View File

@ -96,7 +96,7 @@ test_expect_success 'revert forbidden on dirty working tree' '
echo content >extra_file && echo content >extra_file &&
git add extra_file && git add extra_file &&
test_must_fail git revert HEAD 2>errors && test_must_fail git revert HEAD 2>errors &&
test_i18ngrep "Your local changes would be overwritten by " errors test_i18ngrep "your local changes would be overwritten by " errors
' '