Skip to content

Commit 424d04f

Browse files
author
Git for Windows Build Agent
committed
Merge branch 'interactive-rebase'
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]>
2 parents e5abd67 + bfe70d6 commit 424d04f

18 files changed

+2258
-699
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@
114114
/git-read-tree
115115
/git-rebase
116116
/git-rebase--am
117+
/git-rebase--helper
117118
/git-rebase--interactive
118119
/git-rebase--merge
119120
/git-receive-pack

Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -924,6 +924,7 @@ BUILTIN_OBJS += builtin/prune.o
924924
BUILTIN_OBJS += builtin/pull.o
925925
BUILTIN_OBJS += builtin/push.o
926926
BUILTIN_OBJS += builtin/read-tree.o
927+
BUILTIN_OBJS += builtin/rebase--helper.o
927928
BUILTIN_OBJS += builtin/receive-pack.o
928929
BUILTIN_OBJS += builtin/reflog.o
929930
BUILTIN_OBJS += builtin/remote.o

builtin.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ extern int cmd_prune_packed(int argc, const char **argv, const char *prefix);
102102
extern int cmd_pull(int argc, const char **argv, const char *prefix);
103103
extern int cmd_push(int argc, const char **argv, const char *prefix);
104104
extern int cmd_read_tree(int argc, const char **argv, const char *prefix);
105+
extern int cmd_rebase__helper(int argc, const char **argv, const char *prefix);
105106
extern int cmd_receive_pack(int argc, const char **argv, const char *prefix);
106107
extern int cmd_reflog(int argc, const char **argv, const char *prefix);
107108
extern int cmd_remote(int argc, const char **argv, const char *prefix);

builtin/commit.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ static void determine_whence(struct wt_status *s)
183183
whence = FROM_MERGE;
184184
else if (file_exists(git_path_cherry_pick_head())) {
185185
whence = FROM_CHERRY_PICK;
186-
if (file_exists(git_path(SEQ_DIR)))
186+
if (file_exists(git_path_seq_dir()))
187187
sequencer_in_use = 1;
188188
}
189189
else

builtin/pull.c

Lines changed: 3 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "revision.h"
1818
#include "tempfile.h"
1919
#include "lockfile.h"
20+
#include "wt-status.h"
2021

2122
enum rebase_type {
2223
REBASE_INVALID = -1,
@@ -325,73 +326,6 @@ static int git_pull_config(const char *var, const char *value, void *cb)
325326
return git_default_config(var, value, cb);
326327
}
327328

328-
/**
329-
* Returns 1 if there are unstaged changes, 0 otherwise.
330-
*/
331-
static int has_unstaged_changes(const char *prefix)
332-
{
333-
struct rev_info rev_info;
334-
int result;
335-
336-
init_revisions(&rev_info, prefix);
337-
DIFF_OPT_SET(&rev_info.diffopt, IGNORE_SUBMODULES);
338-
DIFF_OPT_SET(&rev_info.diffopt, QUICK);
339-
diff_setup_done(&rev_info.diffopt);
340-
result = run_diff_files(&rev_info, 0);
341-
return diff_result_code(&rev_info.diffopt, result);
342-
}
343-
344-
/**
345-
* Returns 1 if there are uncommitted changes, 0 otherwise.
346-
*/
347-
static int has_uncommitted_changes(const char *prefix)
348-
{
349-
struct rev_info rev_info;
350-
int result;
351-
352-
if (is_cache_unborn())
353-
return 0;
354-
355-
init_revisions(&rev_info, prefix);
356-
DIFF_OPT_SET(&rev_info.diffopt, IGNORE_SUBMODULES);
357-
DIFF_OPT_SET(&rev_info.diffopt, QUICK);
358-
add_head_to_pending(&rev_info);
359-
diff_setup_done(&rev_info.diffopt);
360-
result = run_diff_index(&rev_info, 1);
361-
return diff_result_code(&rev_info.diffopt, result);
362-
}
363-
364-
/**
365-
* If the work tree has unstaged or uncommitted changes, dies with the
366-
* appropriate message.
367-
*/
368-
static void die_on_unclean_work_tree(const char *prefix)
369-
{
370-
struct lock_file *lock_file = xcalloc(1, sizeof(*lock_file));
371-
int do_die = 0;
372-
373-
hold_locked_index(lock_file, 0);
374-
refresh_cache(REFRESH_QUIET);
375-
update_index_if_able(&the_index, lock_file);
376-
rollback_lock_file(lock_file);
377-
378-
if (has_unstaged_changes(prefix)) {
379-
error(_("Cannot pull with rebase: You have unstaged changes."));
380-
do_die = 1;
381-
}
382-
383-
if (has_uncommitted_changes(prefix)) {
384-
if (do_die)
385-
error(_("Additionally, your index contains uncommitted changes."));
386-
else
387-
error(_("Cannot pull with rebase: Your index contains uncommitted changes."));
388-
do_die = 1;
389-
}
390-
391-
if (do_die)
392-
exit(1);
393-
}
394-
395329
/**
396330
* Appends merge candidates from FETCH_HEAD that are not marked not-for-merge
397331
* into merge_heads.
@@ -875,7 +809,8 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
875809
die(_("Updating an unborn branch with changes added to the index."));
876810

877811
if (!autostash)
878-
die_on_unclean_work_tree(prefix);
812+
require_clean_work_tree(N_("pull with rebase"),
813+
"Please commit or stash them.", 1, 0);
879814

880815
if (get_rebase_fork_point(rebase_fork_point, repo, *refspecs))
881816
hashclr(rebase_fork_point);

builtin/rebase--helper.c

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
#include "builtin.h"
2+
#include "cache.h"
3+
#include "parse-options.h"
4+
#include "sequencer.h"
5+
6+
static const char * const builtin_rebase_helper_usage[] = {
7+
N_("git rebase--helper [<options>]"),
8+
NULL
9+
};
10+
11+
int cmd_rebase__helper(int argc, const char **argv, const char *prefix)
12+
{
13+
struct replay_opts opts = REPLAY_OPTS_INIT;
14+
int keep_empty = 0;
15+
enum {
16+
CONTINUE = 1, ABORT, MAKE_SCRIPT, SHORTEN_SHA1S, EXPAND_SHA1S,
17+
CHECK_TODO_LIST, SKIP_UNNECESSARY_PICKS, REARRANGE_SQUASH
18+
} command = 0;
19+
struct option options[] = {
20+
OPT_BOOL(0, "ff", &opts.allow_ff, N_("allow fast-forward")),
21+
OPT_BOOL(0, "keep-empty", &keep_empty, N_("keep empty commits")),
22+
OPT_CMDMODE(0, "continue", &command, N_("continue rebase"),
23+
CONTINUE),
24+
OPT_CMDMODE(0, "abort", &command, N_("abort rebase"),
25+
ABORT),
26+
OPT_CMDMODE(0, "make-script", &command,
27+
N_("make rebase script"), MAKE_SCRIPT),
28+
OPT_CMDMODE(0, "shorten-sha1s", &command,
29+
N_("shorten SHA-1s in the todo list"), SHORTEN_SHA1S),
30+
OPT_CMDMODE(0, "expand-sha1s", &command,
31+
N_("expand SHA-1s in the todo list"), EXPAND_SHA1S),
32+
OPT_CMDMODE(0, "check-todo-list", &command,
33+
N_("check the todo list"), CHECK_TODO_LIST),
34+
OPT_CMDMODE(0, "skip-unnecessary-picks", &command,
35+
N_("skip unnecessary picks"), SKIP_UNNECESSARY_PICKS),
36+
OPT_CMDMODE(0, "rearrange-squash", &command,
37+
N_("rearrange fixup/squash lines"), REARRANGE_SQUASH),
38+
OPT_END()
39+
};
40+
41+
git_config(git_default_config, NULL);
42+
43+
opts.action = REPLAY_INTERACTIVE_REBASE;
44+
opts.allow_ff = 1;
45+
opts.allow_empty = 1;
46+
47+
argc = parse_options(argc, argv, NULL, options,
48+
builtin_rebase_helper_usage, PARSE_OPT_KEEP_ARGV0);
49+
50+
if (command == CONTINUE && argc == 1)
51+
return !!sequencer_continue(&opts);
52+
if (command == ABORT && argc == 1)
53+
return !!sequencer_remove_state(&opts);
54+
if (command == MAKE_SCRIPT && argc > 1)
55+
return !!sequencer_make_script(keep_empty, stdout, argc, argv);
56+
if (command == SHORTEN_SHA1S && argc == 1)
57+
return !!transform_todo_ids(1);
58+
if (command == EXPAND_SHA1S && argc == 1)
59+
return !!transform_todo_ids(0);
60+
if (command == CHECK_TODO_LIST && argc == 1)
61+
return !!check_todo_list();
62+
if (command == SKIP_UNNECESSARY_PICKS && argc == 1)
63+
return !!skip_unnecessary_picks();
64+
if (command == REARRANGE_SQUASH && argc == 1)
65+
return !!rearrange_squash();
66+
usage_with_options(builtin_rebase_helper_usage, options);
67+
}

builtin/revert.c

Lines changed: 18 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ static void verify_opt_compatible(const char *me, const char *base_opt, ...)
7171
die(_("%s: %s cannot be used with %s"), me, this_opt, base_opt);
7272
}
7373

74-
static void parse_args(int argc, const char **argv, struct replay_opts *opts)
74+
static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)
7575
{
7676
const char * const * usage_str = revert_or_cherry_pick_usage(opts);
7777
const char *me = action_name(opts);
@@ -115,25 +115,15 @@ static void parse_args(int argc, const char **argv, struct replay_opts *opts)
115115
if (opts->keep_redundant_commits)
116116
opts->allow_empty = 1;
117117

118-
/* Set the subcommand */
119-
if (cmd == 'q')
120-
opts->subcommand = REPLAY_REMOVE_STATE;
121-
else if (cmd == 'c')
122-
opts->subcommand = REPLAY_CONTINUE;
123-
else if (cmd == 'a')
124-
opts->subcommand = REPLAY_ROLLBACK;
125-
else
126-
opts->subcommand = REPLAY_NONE;
127-
128118
/* Check for incompatible command line arguments */
129-
if (opts->subcommand != REPLAY_NONE) {
119+
if (cmd) {
130120
char *this_operation;
131-
if (opts->subcommand == REPLAY_REMOVE_STATE)
121+
if (cmd == 'q')
132122
this_operation = "--quit";
133-
else if (opts->subcommand == REPLAY_CONTINUE)
123+
else if (cmd == 'c')
134124
this_operation = "--continue";
135125
else {
136-
assert(opts->subcommand == REPLAY_ROLLBACK);
126+
assert(cmd == 'a');
137127
this_operation = "--abort";
138128
}
139129

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

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

175165
if (argc > 1)
176166
usage_with_options(usage_str, options);
167+
168+
if (cmd == 'q')
169+
return sequencer_remove_state(opts);
170+
if (cmd == 'c')
171+
return sequencer_continue(opts);
172+
if (cmd == 'a')
173+
return sequencer_rollback(opts);
174+
return sequencer_pick_revisions(opts);
177175
}
178176

179177
int cmd_revert(int argc, const char **argv, const char *prefix)
180178
{
181-
struct replay_opts opts;
179+
struct replay_opts opts = REPLAY_OPTS_INIT;
182180
int res;
183181

184-
memset(&opts, 0, sizeof(opts));
185182
if (isatty(0))
186183
opts.edit = 1;
187184
opts.action = REPLAY_REVERT;
188185
git_config(git_default_config, NULL);
189-
parse_args(argc, argv, &opts);
190-
res = sequencer_pick_revisions(&opts);
186+
res = run_sequencer(argc, argv, &opts);
191187
if (res < 0)
192188
die(_("revert failed"));
193189
return res;
194190
}
195191

196192
int cmd_cherry_pick(int argc, const char **argv, const char *prefix)
197193
{
198-
struct replay_opts opts;
194+
struct replay_opts opts = REPLAY_OPTS_INIT;
199195
int res;
200196

201-
memset(&opts, 0, sizeof(opts));
202197
opts.action = REPLAY_PICK;
203198
git_config(git_default_config, NULL);
204-
parse_args(argc, argv, &opts);
205-
res = sequencer_pick_revisions(&opts);
199+
res = run_sequencer(argc, argv, &opts);
206200
if (res < 0)
207201
die(_("cherry-pick failed"));
208202
return res;

0 commit comments

Comments
 (0)