Skip to content

Commit

Permalink
Merge branch 'interactive-rebase'
Browse files Browse the repository at this point in the history
This series of branches introduces the git-rebase--helper, a builtin
helping to accelerate the interactive rebase dramatically.

Signed-off-by: Johannes Schindelin <[email protected]>
  • Loading branch information
dscho committed Aug 31, 2016
2 parents 751c7f6 + 0282bc6 commit c465e11
Show file tree
Hide file tree
Showing 19 changed files with 2,225 additions and 707 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@
/git-read-tree
/git-rebase
/git-rebase--am
/git-rebase--helper
/git-rebase--interactive
/git-rebase--merge
/git-receive-pack
Expand Down
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -919,6 +919,7 @@ BUILTIN_OBJS += builtin/prune.o
BUILTIN_OBJS += builtin/pull.o
BUILTIN_OBJS += builtin/push.o
BUILTIN_OBJS += builtin/read-tree.o
BUILTIN_OBJS += builtin/rebase--helper.o
BUILTIN_OBJS += builtin/receive-pack.o
BUILTIN_OBJS += builtin/reflog.o
BUILTIN_OBJS += builtin/remote.o
Expand Down
1 change: 1 addition & 0 deletions builtin.h
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ extern int cmd_prune_packed(int argc, const char **argv, const char *prefix);
extern int cmd_pull(int argc, const char **argv, const char *prefix);
extern int cmd_push(int argc, const char **argv, const char *prefix);
extern int cmd_read_tree(int argc, const char **argv, const char *prefix);
extern int cmd_rebase__helper(int argc, const char **argv, const char *prefix);
extern int cmd_receive_pack(int argc, const char **argv, const char *prefix);
extern int cmd_reflog(int argc, const char **argv, const char *prefix);
extern int cmd_remote(int argc, const char **argv, const char *prefix);
Expand Down
2 changes: 1 addition & 1 deletion builtin/commit.c
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ static void determine_whence(struct wt_status *s)
whence = FROM_MERGE;
else if (file_exists(git_path_cherry_pick_head())) {
whence = FROM_CHERRY_PICK;
if (file_exists(git_path(SEQ_DIR)))
if (file_exists(git_path_seq_dir()))
sequencer_in_use = 1;
}
else
Expand Down
71 changes: 3 additions & 68 deletions builtin/pull.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include "revision.h"
#include "tempfile.h"
#include "lockfile.h"
#include "wt-status.h"

enum rebase_type {
REBASE_INVALID = -1,
Expand Down Expand Up @@ -325,73 +326,6 @@ static int git_pull_config(const char *var, const char *value, void *cb)
return git_default_config(var, value, cb);
}

/**
* Returns 1 if there are unstaged changes, 0 otherwise.
*/
static int has_unstaged_changes(const char *prefix)
{
struct rev_info rev_info;
int result;

init_revisions(&rev_info, prefix);
DIFF_OPT_SET(&rev_info.diffopt, IGNORE_SUBMODULES);
DIFF_OPT_SET(&rev_info.diffopt, QUICK);
diff_setup_done(&rev_info.diffopt);
result = run_diff_files(&rev_info, 0);
return diff_result_code(&rev_info.diffopt, result);
}

/**
* Returns 1 if there are uncommitted changes, 0 otherwise.
*/
static int has_uncommitted_changes(const char *prefix)
{
struct rev_info rev_info;
int result;

if (is_cache_unborn())
return 0;

init_revisions(&rev_info, prefix);
DIFF_OPT_SET(&rev_info.diffopt, IGNORE_SUBMODULES);
DIFF_OPT_SET(&rev_info.diffopt, QUICK);
add_head_to_pending(&rev_info);
diff_setup_done(&rev_info.diffopt);
result = run_diff_index(&rev_info, 1);
return diff_result_code(&rev_info.diffopt, result);
}

/**
* If the work tree has unstaged or uncommitted changes, dies with the
* appropriate message.
*/
static void die_on_unclean_work_tree(const char *prefix)
{
struct lock_file *lock_file = xcalloc(1, sizeof(*lock_file));
int do_die = 0;

hold_locked_index(lock_file, 0);
refresh_cache(REFRESH_QUIET);
update_index_if_able(&the_index, lock_file);
rollback_lock_file(lock_file);

if (has_unstaged_changes(prefix)) {
error(_("Cannot pull with rebase: You have unstaged changes."));
do_die = 1;
}

if (has_uncommitted_changes(prefix)) {
if (do_die)
error(_("Additionally, your index contains uncommitted changes."));
else
error(_("Cannot pull with rebase: Your index contains uncommitted changes."));
do_die = 1;
}

if (do_die)
exit(1);
}

/**
* Appends merge candidates from FETCH_HEAD that are not marked not-for-merge
* into merge_heads.
Expand Down Expand Up @@ -875,7 +809,8 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
die(_("Updating an unborn branch with changes added to the index."));

if (!autostash)
die_on_unclean_work_tree(prefix);
require_clean_work_tree("pull with rebase",
"Please commit or stash them.", 1, 0);

if (get_rebase_fork_point(rebase_fork_point, repo, *refspecs))
hashclr(rebase_fork_point);
Expand Down
67 changes: 67 additions & 0 deletions builtin/rebase--helper.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
#include "builtin.h"
#include "cache.h"
#include "parse-options.h"
#include "sequencer.h"

static const char * const builtin_rebase_helper_usage[] = {
N_("git rebase--helper [<options>]"),
NULL
};

int cmd_rebase__helper(int argc, const char **argv, const char *prefix)
{
struct replay_opts opts = REPLAY_OPTS_INIT;
int keep_empty = 0;
enum {
CONTINUE = 1, ABORT, MAKE_SCRIPT, SHORTEN_SHA1S, EXPAND_SHA1S,
CHECK_TODO_LIST, SKIP_UNNECESSARY_PICKS, REARRANGE_SQUASH
} command = 0;
struct option options[] = {
OPT_BOOL(0, "ff", &opts.allow_ff, N_("allow fast-forward")),
OPT_BOOL(0, "keep-empty", &keep_empty, N_("keep empty commits")),
OPT_CMDMODE(0, "continue", &command, N_("continue rebase"),
CONTINUE),
OPT_CMDMODE(0, "abort", &command, N_("abort rebase"),
ABORT),
OPT_CMDMODE(0, "make-script", &command,
N_("make rebase script"), MAKE_SCRIPT),
OPT_CMDMODE(0, "shorten-sha1s", &command,
N_("shorten SHA-1s in the todo list"), SHORTEN_SHA1S),
OPT_CMDMODE(0, "expand-sha1s", &command,
N_("expand SHA-1s in the todo list"), EXPAND_SHA1S),
OPT_CMDMODE(0, "check-todo-list", &command,
N_("check the todo list"), CHECK_TODO_LIST),
OPT_CMDMODE(0, "skip-unnecessary-picks", &command,
N_("skip unnecessary picks"), SKIP_UNNECESSARY_PICKS),
OPT_CMDMODE(0, "rearrange-squash", &command,
N_("rearrange fixup/squash lines"), REARRANGE_SQUASH),
OPT_END()
};

git_config(git_default_config, NULL);

opts.action = REPLAY_INTERACTIVE_REBASE;
opts.allow_ff = 1;
opts.allow_empty = 1;

argc = parse_options(argc, argv, NULL, options,
builtin_rebase_helper_usage, PARSE_OPT_KEEP_ARGV0);

if (command == CONTINUE && argc == 1)
return !!sequencer_continue(&opts);
if (command == ABORT && argc == 1)
return !!sequencer_remove_state(&opts);
if (command == MAKE_SCRIPT && argc > 1)
return !!sequencer_make_script(keep_empty, stdout, argc, argv);
if (command == SHORTEN_SHA1S && argc == 1)
return !!transform_todo_ids(1);
if (command == EXPAND_SHA1S && argc == 1)
return !!transform_todo_ids(0);
if (command == CHECK_TODO_LIST && argc == 1)
return !!check_todo_list();
if (command == SKIP_UNNECESSARY_PICKS && argc == 1)
return !!skip_unnecessary_picks();
if (command == REARRANGE_SQUASH && argc == 1)
return !!rearrange_squash();
usage_with_options(builtin_rebase_helper_usage, options);
}
42 changes: 18 additions & 24 deletions builtin/revert.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

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 *me = action_name(opts);
Expand Down Expand Up @@ -115,25 +115,15 @@ static void parse_args(int argc, const char **argv, struct replay_opts *opts)
if (opts->keep_redundant_commits)
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 */
if (opts->subcommand != REPLAY_NONE) {
if (cmd) {
char *this_operation;
if (opts->subcommand == REPLAY_REMOVE_STATE)
if (cmd == 'q')
this_operation = "--quit";
else if (opts->subcommand == REPLAY_CONTINUE)
else if (cmd == 'c')
this_operation = "--continue";
else {
assert(opts->subcommand == REPLAY_ROLLBACK);
assert(cmd == 'a');
this_operation = "--abort";
}

Expand All @@ -156,7 +146,7 @@ static void parse_args(int argc, const char **argv, struct replay_opts *opts)
"--edit", opts->edit,
NULL);

if (opts->subcommand != REPLAY_NONE) {
if (cmd) {
opts->revs = NULL;
} else {
struct setup_revision_opt s_r_opt;
Expand All @@ -174,35 +164,39 @@ static void parse_args(int argc, const char **argv, struct replay_opts *opts)

if (argc > 1)
usage_with_options(usage_str, options);

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)
{
struct replay_opts opts;
struct replay_opts opts = REPLAY_OPTS_INIT;
int res;

memset(&opts, 0, sizeof(opts));
if (isatty(0))
opts.edit = 1;
opts.action = REPLAY_REVERT;
git_config(git_default_config, NULL);
parse_args(argc, argv, &opts);
res = sequencer_pick_revisions(&opts);
res = run_sequencer(argc, argv, &opts);
if (res < 0)
die(_("revert failed"));
return res;
}

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;

memset(&opts, 0, sizeof(opts));
opts.action = REPLAY_PICK;
git_config(git_default_config, NULL);
parse_args(argc, argv, &opts);
res = sequencer_pick_revisions(&opts);
res = run_sequencer(argc, argv, &opts);
if (res < 0)
die(_("cherry-pick failed"));
return res;
Expand Down
Loading

2 comments on commit c465e11

@nalla
Copy link

@nalla nalla commented on c465e11 Sep 1, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dscho OOC, is this rebase -i rewrite windows only for the time being? Are you planning to add this upstream as well?

@dscho
Copy link
Member Author

@dscho dscho commented on c465e11 Sep 1, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nalla The rebase--helper is pushed into Git for Windows v2.10.0 before it arrives in upstream Git, that is true.

But the (15 or 16) patch series of which this work consists have been mostly merged, and the last batch (but for the last two patch series) are under review.

So at some stage, this will hopefully make it upstream, although I have no idea when.

Please sign in to comment.