From: Junio C Hamano Date: Thu, 7 Feb 2019 06:05:20 +0000 (-0800) Subject: Merge branch 'en/rebase-merge-on-sequencer' X-Git-Tag: v2.21.0-rc0~29 X-Git-Url: https://git.lorimer.id.au/gitweb.git/diff_plain/8fe9c3f21dff?hp=-c Merge branch 'en/rebase-merge-on-sequencer' "git rebase --merge" as been reimplemented by reusing the internal machinery used for "git rebase -i". * en/rebase-merge-on-sequencer: rebase: implement --merge via the interactive machinery rebase: define linearization ordering and enforce it git-legacy-rebase: simplify unnecessary triply-nested if git-rebase, sequencer: extend --quiet option for the interactive machinery am, rebase--merge: do not overlook --skip'ed commits with post-rewrite t5407: add a test demonstrating how interactive handles --skip differently rebase: fix incompatible options error message rebase: make builtin and legacy script error messages the same --- 8fe9c3f21dff206acb464d86cbd3bf4dbbb94f38 diff --combined .gitignore index 8bcf153ed9,910b1d2d2f..6fd61c7272 --- a/.gitignore +++ b/.gitignore @@@ -1,4 -1,3 +1,4 @@@ +/fuzz-commit-graph /fuzz_corpora /fuzz-pack-headers /fuzz-pack-idx @@@ -125,7 -124,6 +125,6 @@@ /git-rebase--am /git-rebase--common /git-rebase--interactive - /git-rebase--merge /git-rebase--preserve-merges /git-receive-pack /git-reflog diff --combined Documentation/git-rebase.txt index 4dd5853d6e,8bfa36a185..7e695b30e4 --- a/Documentation/git-rebase.txt +++ b/Documentation/git-rebase.txt @@@ -462,12 -462,6 +462,12 @@@ without an explicit `--interactive` + See also INCOMPATIBLE OPTIONS below. +-y :: + This is the same as passing `--reschedule-failed-exec` before + `-x `, i.e. it appends the specified `exec` command and + turns on the mode where failed `exec` commands are automatically + rescheduled. + --root:: Rebase all commits reachable from , instead of limiting them with an . This allows you to rebase @@@ -507,23 -501,10 +507,15 @@@ See also INCOMPATIBLE OPTIONS below with care: the final stash application after a successful rebase might result in non-trivial conflicts. +--reschedule-failed-exec:: +--no-reschedule-failed-exec:: + Automatically reschedule `exec` commands that failed. This only makes + sense in interactive mode (or when an `--exec` option was provided). + INCOMPATIBLE OPTIONS -------------------- - git-rebase has many flags that are incompatible with each other, - predominantly due to the fact that it has three different underlying - implementations: - - * one based on linkgit:git-am[1] (the default) - * one based on git-merge-recursive (merge backend) - * one based on linkgit:git-cherry-pick[1] (interactive backend) - - Flags only understood by the am backend: + The following options: * --committer-date-is-author-date * --ignore-date @@@ -531,15 -512,12 +523,12 @@@ * --ignore-whitespace * -C - Flags understood by both merge and interactive backends: + are incompatible with the following options: * --merge * --strategy * --strategy-option * --allow-empty-message - - Flags only understood by the interactive backend: - * --[no-]autosquash * --rebase-merges * --preserve-merges @@@ -550,7 -528,7 +539,7 @@@ * --edit-todo * --root when used in combination with --onto - Other incompatible flag pairs: + In addition, the following pairs of options are incompatible: * --preserve-merges and --interactive * --preserve-merges and --signoff @@@ -581,9 -559,8 +570,9 @@@ it to keep commits that started empty Directory rename detection ~~~~~~~~~~~~~~~~~~~~~~~~~~ -The merge and interactive backends work fine with -directory rename detection. The am backend sometimes does not. +Directory rename heuristics are enabled in the merge and interactive +backends. Due to the lack of accurate tree information, directory +rename detection is disabled in the am backend. include::merge-strategies.txt[] @@@ -991,7 -968,7 +980,7 @@@ when the merge operation did not even s At this time, the `merge` command will *always* use the `recursive` merge strategy for regular merges, and `octopus` for octopus merges, -strategy, with no way to choose a different one. To work around +with no way to choose a different one. To work around this, an `exec` command can be used to call `git merge` explicitly, using the fact that the labels are worktree-local refs (the ref `refs/rewritten/onto` would correspond to the label `onto`, for example). diff --combined Makefile index 28ee1799d1,82e1eb1a4a..afa411d727 --- a/Makefile +++ b/Makefile @@@ -186,12 -186,6 +186,12 @@@ all: # in one call to the platform's SHA1_Update(). e.g. APPLE_COMMON_CRYPTO # wants 'SHA1_MAX_BLOCK_SIZE=1024L*1024L*1024L' defined. # +# Define BLK_SHA256 to use the built-in SHA-256 routines. +# +# Define GCRYPT_SHA256 to use the SHA-256 routines in libgcrypt. +# +# Define OPENSSL_SHA256 to use the SHA-256 routines in OpenSSL. +# # Define NEEDS_CRYPTO_WITH_SSL if you need -lcrypto when using -lssl (Darwin). # # Define NEEDS_SSL_WITH_CRYPTO if you need -lssl when using -lcrypto (Darwin). @@@ -634,7 -628,6 +634,6 @@@ SCRIPT_LIB += git-parse-remot SCRIPT_LIB += git-rebase--am SCRIPT_LIB += git-rebase--common SCRIPT_LIB += git-rebase--preserve-merges - SCRIPT_LIB += git-rebase--merge SCRIPT_LIB += git-sh-setup SCRIPT_LIB += git-sh-i18n @@@ -690,7 -683,6 +689,7 @@@ SCRIPTS = $(SCRIPT_SH_INS) ETAGS_TARGET = TAGS +FUZZ_OBJS += fuzz-commit-graph.o FUZZ_OBJS += fuzz-pack-headers.o FUZZ_OBJS += fuzz-pack-idx.o @@@ -731,9 -723,7 +730,9 @@@ TEST_BUILTINS_OBJS += test-dump-split-i TEST_BUILTINS_OBJS += test-dump-untracked-cache.o TEST_BUILTINS_OBJS += test-example-decorate.o TEST_BUILTINS_OBJS += test-genrandom.o +TEST_BUILTINS_OBJS += test-hash.o TEST_BUILTINS_OBJS += test-hashmap.o +TEST_BUILTINS_OBJS += test-hash-speed.o TEST_BUILTINS_OBJS += test-index-version.o TEST_BUILTINS_OBJS += test-json-writer.o TEST_BUILTINS_OBJS += test-lazy-init-name-hash.o @@@ -756,7 -746,6 +755,7 @@@ TEST_BUILTINS_OBJS += test-run-command. TEST_BUILTINS_OBJS += test-scrap-cache-tree.o TEST_BUILTINS_OBJS += test-sha1.o TEST_BUILTINS_OBJS += test-sha1-array.o +TEST_BUILTINS_OBJS += test-sha256.o TEST_BUILTINS_OBJS += test-sigchain.o TEST_BUILTINS_OBJS += test-strcmp-offset.o TEST_BUILTINS_OBJS += test-string-list.o @@@ -1656,19 -1645,6 +1655,19 @@@ endi endif endif +ifdef OPENSSL_SHA256 + EXTLIBS += $(LIB_4_CRYPTO) + BASIC_CFLAGS += -DSHA256_OPENSSL +else +ifdef GCRYPT_SHA256 + BASIC_CFLAGS += -DSHA256_GCRYPT + EXTLIBS += -lgcrypt +else + LIB_OBJS += sha256/block/sha256.o + BASIC_CFLAGS += -DSHA256_BLK +endif +endif + ifdef SHA1_MAX_BLOCK_SIZE LIB_OBJS += compat/sha1-chunked.o BASIC_CFLAGS += -DSHA1_MAX_BLOCK_SIZE="$(SHA1_MAX_BLOCK_SIZE)" @@@ -3126,7 -3102,7 +3125,7 @@@ cover_db_html: cover_d # An example command to build against libFuzzer from LLVM 4.0.0: # # make CC=clang CXX=clang++ \ -# FUZZ_CXXFLAGS="-fsanitize-coverage=trace-pc-guard -fsanitize=address" \ +# CFLAGS="-fsanitize-coverage=trace-pc-guard -fsanitize=address" \ # LIB_FUZZING_ENGINE=/usr/lib/llvm-4.0/lib/libFuzzer.a \ # fuzz-all # diff --combined builtin/am.c index 95370313b6,af9d034838..6d1c6d3da9 --- a/builtin/am.c +++ b/builtin/am.c @@@ -1970,7 -1970,7 +1970,7 @@@ static int clean_index(const struct obj if (merge_tree(remote_tree)) return -1; - remove_branch_state(); + remove_branch_state(the_repository); return 0; } @@@ -1981,7 -1981,7 +1981,7 @@@ static void am_rerere_clear(void) { struct string_list merge_rr = STRING_LIST_INIT_DUP; - rerere_clear(&merge_rr); + rerere_clear(the_repository, &merge_rr); string_list_clear(&merge_rr, 1); } @@@ -2000,6 -2000,15 +2000,15 @@@ static void am_skip(struct am_state *st if (clean_index(&head, &head)) die(_("failed to clean index")); + if (state->rebasing) { + FILE *fp = xfopen(am_path(state, "rewritten"), "a"); + + assert(!is_null_oid(&state->orig_commit)); + fprintf(fp, "%s ", oid_to_hex(&state->orig_commit)); + fprintf(fp, "%s\n", oid_to_hex(&head)); + fclose(fp); + } + am_next(state); am_load(state); am_run(state, 0); diff --combined builtin/rebase.c index fdeb41e899,d95843a8d4..3f9b26f729 --- a/builtin/rebase.c +++ b/builtin/rebase.c @@@ -104,7 -104,6 +104,7 @@@ struct rebase_options int rebase_merges, rebase_cousins; char *strategy, *strategy_opts; struct strbuf git_format_patch_opt; + int reschedule_failed_exec; }; static int is_interactive(struct rebase_options *opts) @@@ -123,7 -122,7 +123,7 @@@ static void imply_interactive(struct re case REBASE_PRESERVE_MERGES: break; case REBASE_MERGE: - /* we silently *upgrade* --merge to --interactive if needed */ + /* we now implement --merge via --interactive */ default: opts->type = REBASE_INTERACTIVE; /* implied */ break; @@@ -186,10 -185,7 +186,7 @@@ static int read_basic_state(struct reba if (get_oid(buf.buf, &opts->orig_head)) return error(_("invalid orig-head: '%s'"), buf.buf); - strbuf_reset(&buf); - if (read_one(state_dir_path("quiet", opts), &buf)) - return -1; - if (buf.len) + if (file_exists(state_dir_path("quiet", opts))) opts->flags &= ~REBASE_NO_QUIET; else opts->flags |= REBASE_NO_QUIET; @@@ -355,8 -351,7 +352,8 @@@ static int run_specific_rebase(struct r argv_array_pushf(&child.env_array, "GIT_CHERRY_PICK_HELP=%s", resolvemsg); if (!(opts->flags & REBASE_INTERACTIVE_EXPLICIT)) { - argv_array_push(&child.env_array, "GIT_EDITOR=:"); + argv_array_push(&child.env_array, + "GIT_SEQUENCE_EDITOR=:"); opts->autosquash = 0; } @@@ -417,8 -412,6 +414,8 @@@ argv_array_push(&child.args, opts->gpg_sign_opt); if (opts->signoff) argv_array_push(&child.args, "--signoff"); + if (opts->reschedule_failed_exec) + argv_array_push(&child.args, "--reschedule-failed-exec"); status = run_command(&child); goto finished_rebase; @@@ -479,7 -472,7 +476,7 @@@ if (is_interactive(opts) && !(opts->flags & REBASE_INTERACTIVE_EXPLICIT)) { strbuf_addstr(&script_snippet, - "GIT_EDITOR=:; export GIT_EDITOR; "); + "GIT_SEQUENCE_EDITOR=:; export GIT_SEQUENCE_EDITOR; "); opts->autosquash = 0; } @@@ -488,10 -481,6 +485,6 @@@ backend = "git-rebase--am"; backend_func = "git_rebase__am"; break; - case REBASE_MERGE: - backend = "git-rebase--merge"; - backend_func = "git_rebase__merge"; - break; case REBASE_PRESERVE_MERGES: backend = "git-rebase--preserve-merges"; backend_func = "git_rebase__preserve_merges"; @@@ -534,7 -523,6 +527,7 @@@ finished_rebase #define RESET_HEAD_DETACH (1<<0) #define RESET_HEAD_HARD (1<<1) +#define RESET_HEAD_RUN_POST_CHECKOUT_HOOK (1<<2) static int reset_head(struct object_id *oid, const char *action, const char *switch_to_branch, unsigned flags, @@@ -542,7 -530,6 +535,7 @@@ { unsigned detach_head = flags & RESET_HEAD_DETACH; unsigned reset_hard = flags & RESET_HEAD_HARD; + unsigned run_hook = flags & RESET_HEAD_RUN_POST_CHECKOUT_HOOK; struct object_id head_oid; struct tree_desc desc[2] = { { NULL }, { NULL } }; struct lock_file lock = LOCK_INIT; @@@ -604,7 -591,7 +597,7 @@@ } tree = parse_tree_indirect(oid); - prime_cache_tree(the_repository->index, tree); + prime_cache_tree(the_repository, the_repository->index, tree); if (write_locked_index(the_repository->index, &lock, COMMIT_LOCK) < 0) { ret = error(_("could not write index")); @@@ -642,10 -629,6 +635,10 @@@ ret = update_ref(reflog_head, "HEAD", oid, NULL, 0, UPDATE_REFS_MSG_ON_ERR); } + if (run_hook) + run_hook_le(NULL, "post-checkout", + oid_to_hex(orig ? orig : &null_oid), + oid_to_hex(oid), "1", NULL); leave_reset_head: strbuf_release(&msg); @@@ -684,11 -667,6 +677,11 @@@ static int rebase_config(const char *va return 0; } + if (!strcmp(var, "rebase.reschedulefailedexec")) { + opts->reschedule_failed_exec = git_config_bool(var, value); + return 0; + } + return git_default_config(var, value, data); } @@@ -761,23 -739,6 +754,23 @@@ static int parse_opt_interactive(const return 0; } +struct opt_y { + struct string_list *list; + struct rebase_options *options; +}; + +static int parse_opt_y(const struct option *opt, const char *arg, int unset) +{ + struct opt_y *o = opt->value; + + if (unset || !arg) + return -1; + + o->options->reschedule_failed_exec = 1; + string_list_append(o->list, arg); + return 0; +} + static void NORETURN error_on_missing_default_upstream(void) { struct branch *current_branch = branch_get(NULL); @@@ -858,7 -819,6 +851,7 @@@ int cmd_rebase(int argc, const char **a struct string_list strategy_options = STRING_LIST_INIT_NODUP; struct object_id squash_onto; char *squash_onto_name = NULL; + struct opt_y opt_y = { .list = &exec, .options = &options }; struct option builtin_rebase_options[] = { OPT_STRING(0, "onto", &options.onto_name, N_("revision"), @@@ -936,9 -896,6 +929,9 @@@ OPT_STRING_LIST('x', "exec", &exec, N_("exec"), N_("add exec lines after each commit of the " "editable list")), + { OPTION_CALLBACK, 'y', NULL, &opt_y, N_(""), + N_("same as --reschedule-failed-exec -x "), + PARSE_OPT_NONEG, parse_opt_y }, OPT_BOOL(0, "allow-empty-message", &options.allow_empty_message, N_("allow rebasing commits with empty messages")), @@@ -956,9 -913,6 +949,9 @@@ "strategy")), OPT_BOOL(0, "root", &options.root, N_("rebase all reachable commits up to the root(s)")), + OPT_BOOL(0, "reschedule-failed-exec", + &options.reschedule_failed_exec, + N_("automatically re-schedule any `exec` that fails")), OPT_END(), }; int i; @@@ -1063,7 -1017,7 +1056,7 @@@ &lock_file); rollback_lock_file(&lock_file); - if (has_unstaged_changes(1)) { + if (has_unstaged_changes(the_repository, 1)) { puts(_("You must edit all merge conflicts and then\n" "mark them as resolved using git add")); exit(1); @@@ -1078,13 -1032,13 +1071,13 @@@ options.action = "skip"; set_reflog_action(&options); - rerere_clear(&merge_rr); + rerere_clear(the_repository, &merge_rr); string_list_clear(&merge_rr, 1); if (reset_head(NULL, "reset", NULL, RESET_HEAD_HARD, NULL, NULL) < 0) die(_("could not discard worktree changes")); - remove_branch_state(); + remove_branch_state(the_repository); if (read_basic_state(&options)) exit(1); goto run_rebase; @@@ -1094,7 -1048,7 +1087,7 @@@ options.action = "abort"; set_reflog_action(&options); - rerere_clear(&merge_rr); + rerere_clear(the_repository, &merge_rr); string_list_clear(&merge_rr, 1); if (read_basic_state(&options)) @@@ -1104,7 -1058,7 +1097,7 @@@ NULL, NULL) < 0) die(_("could not move back to %s"), oid_to_hex(&options.orig_head)); - remove_branch_state(); + remove_branch_state(the_repository); ret = finish_rebase(&options); goto cleanup; } @@@ -1233,6 -1187,9 +1226,9 @@@ } } + if (options.type == REBASE_MERGE) + imply_interactive(&options, "--merge"); + if (options.root && !options.onto_name) imply_interactive(&options, "--root without --onto"); @@@ -1255,9 -1212,6 +1251,9 @@@ break; } + if (options.reschedule_failed_exec && !is_interactive(&options)) + die(_("--reschedule-failed-exec requires an interactive rebase")); + if (options.git_am_opts.argc) { /* all am options except -q are compatible only with --am */ for (i = options.git_am_opts.argc - 1; i >= 0; i--) @@@ -1265,14 -1219,8 +1261,8 @@@ break; if (is_interactive(&options) && i >= 0) - die(_("error: cannot combine interactive options " - "(--interactive, --exec, --rebase-merges, " - "--preserve-merges, --keep-empty, --root + " - "--onto) with am options (%s)"), buf.buf); - if (options.type == REBASE_MERGE && i >= 0) - die(_("error: cannot combine merge options (--merge, " - "--strategy, --strategy-option) with am options " - "(%s)"), buf.buf); + die(_("cannot combine am options with either " + "interactive or merge options")); } if (options.signoff) { @@@ -1283,27 -1231,22 +1273,27 @@@ options.flags |= REBASE_FORCE; } - if (options.type == REBASE_PRESERVE_MERGES) + if (options.type == REBASE_PRESERVE_MERGES) { /* * Note: incompatibility with --signoff handled in signoff block above * Note: incompatibility with --interactive is just a strong warning; * git-rebase.txt caveats with "unless you know what you are doing" */ if (options.rebase_merges) - die(_("error: cannot combine '--preserve-merges' with " + die(_("cannot combine '--preserve-merges' with " "'--rebase-merges'")); + if (options.reschedule_failed_exec) + die(_("error: cannot combine '--preserve-merges' with " + "'--reschedule-failed-exec'")); + } + if (options.rebase_merges) { if (strategy_options.nr) - die(_("error: cannot combine '--rebase-merges' with " + die(_("cannot combine '--rebase-merges' with " "'--strategy-option'")); if (options.strategy) - die(_("error: cannot combine '--rebase-merges' with " + die(_("cannot combine '--rebase-merges' with " "'--strategy'")); } @@@ -1428,8 -1371,7 +1418,8 @@@ update_index_if_able(&the_index, &lock_file); rollback_lock_file(&lock_file); - if (has_unstaged_changes(1) || has_uncommitted_changes(1)) { + if (has_unstaged_changes(the_repository, 1) || + has_uncommitted_changes(the_repository, 1)) { const char *autostash = state_dir_path("autostash", &options); struct child_process stash = CHILD_PROCESS_INIT; @@@ -1475,7 -1417,7 +1465,7 @@@ } } - if (require_clean_work_tree("rebase", + if (require_clean_work_tree(the_repository, "rebase", _("Please commit or stash them."), 1, 1)) { ret = 1; goto cleanup; @@@ -1513,8 -1455,7 +1503,8 @@@ getenv(GIT_REFLOG_ACTION_ENVIRONMENT), options.switch_to); if (reset_head(&oid, "checkout", - options.head_name, 0, + options.head_name, + RESET_HEAD_RUN_POST_CHECKOUT_HOOK, NULL, buf.buf) < 0) { ret = !!error(_("could not switch to " "%s"), @@@ -1588,8 -1529,7 +1578,8 @@@ strbuf_addf(&msg, "%s: checkout %s", getenv(GIT_REFLOG_ACTION_ENVIRONMENT), options.onto_name); if (reset_head(&options.onto->object.oid, "checkout", NULL, - RESET_HEAD_DETACH, NULL, msg.buf)) + RESET_HEAD_DETACH | RESET_HEAD_RUN_POST_CHECKOUT_HOOK, + NULL, msg.buf)) die(_("Could not detach HEAD")); strbuf_release(&msg); diff --combined git-legacy-rebase.sh index f03ca6c49a,0c9c19bc60..8d6c9aca65 --- a/git-legacy-rebase.sh +++ b/git-legacy-rebase.sh @@@ -26,7 -26,6 +26,7 @@@ f,force-rebase! cherry-pick all comm m,merge! use merging strategies to rebase i,interactive! let the user edit the list of commits to rebase x,exec=! add exec lines after each commit of the editable list +y=! same as --reschedule-failed-exec -x k,keep-empty preserve empty commits during rebase allow-empty-message allow rebasing commits with empty messages stat! display a diffstat of what changed upstream @@@ -49,7 -48,6 +49,7 @@@ skip! skip current patch a edit-todo! edit the todo list during an interactive rebase quit! abort but keep HEAD where it is show-current-patch! show the patch file being applied or merged +reschedule-failed-exec automatically reschedule failed exec commands " . git-sh-setup set_reflog_action rebase @@@ -94,14 -92,11 +94,14 @@@ autosquash keep_empty= allow_empty_message=--allow-empty-message signoff= +reschedule_failed_exec= test "$(git config --bool rebase.autosquash)" = "true" && autosquash=t case "$(git config --bool commit.gpgsign)" in true) gpg_sign_opt=-S ;; *) gpg_sign_opt= ;; esac +test "$(git config --bool rebase.reschedulefailedexec)" = "true" && +reschedule_failed_exec=--reschedule-failed-exec . git-rebase--common read_basic_state () { @@@ -118,7 -113,7 +118,7 @@@ else orig_head=$(cat "$state_dir"/head) fi && - GIT_QUIET=$(cat "$state_dir"/quiet) && + test -f "$state_dir"/quiet && GIT_QUIET=t test -f "$state_dir"/verbose && verbose=t test -f "$state_dir"/strategy && strategy="$(cat "$state_dir"/strategy)" test -f "$state_dir"/strategy_opts && @@@ -131,8 -126,6 +131,8 @@@ signoff="$(cat "$state_dir"/signoff)" force_rebase=t } + test -f "$state_dir"/reschedule-failed-exec && + reschedule_failed_exec=t } finish_rebase () { @@@ -170,14 -163,13 +170,14 @@@ run_interactive () "$allow_empty_message" "$autosquash" "$verbose" \ "$force_rebase" "$onto_name" "$head_name" "$strategy" \ "$strategy_opts" "$cmd" "$switch_to" \ - "$allow_rerere_autoupdate" "$gpg_sign_opt" "$signoff" + "$allow_rerere_autoupdate" "$gpg_sign_opt" "$signoff" \ + "$reschedule_failed_exec" } run_specific_rebase () { if [ "$interactive_rebase" = implied ]; then - GIT_EDITOR=: - export GIT_EDITOR + GIT_SEQUENCE_EDITOR=: + export GIT_SEQUENCE_EDITOR autosquash= fi @@@ -226,6 -218,7 +226,7 @@@ the state_dir="$apply_dir" elif test -d "$merge_dir" then + type=interactive if test -d "$merge_dir"/rewritten then type=preserve-merges @@@ -233,10 -226,7 +234,7 @@@ preserve_merges=t elif test -f "$merge_dir"/interactive then - type=interactive interactive_rebase=explicit - else - type=merge fi state_dir="$merge_dir" fi @@@ -263,11 -253,6 +261,11 @@@ d cmd="${cmd}exec ${1#--exec=}${LF}" test -z "$interactive_rebase" && interactive_rebase=implied ;; + -y*) + reschedule_failed_exec=--reschedule-failed-exec + cmd="${cmd}exec ${1#-y}${LF}" + test -z "$interactive_rebase" && interactive_rebase=implied + ;; --interactive) interactive_rebase=explicit ;; @@@ -391,12 -376,6 +389,12 @@@ --gpg-sign=*) gpg_sign_opt="-S${1#--gpg-sign=}" ;; + --reschedule-failed-exec) + reschedule_failed_exec=--reschedule-failed-exec + ;; + --no-reschedule-failed-exec) + reschedule_failed_exec= + ;; --) shift break @@@ -496,6 -475,7 +494,7 @@@ the test -z "$interactive_rebase" && interactive_rebase=implied fi + actually_interactive= if test -n "$interactive_rebase" then if test -z "$preserve_merges" @@@ -504,11 -484,12 +503,12 @@@ else type=preserve-merges fi - + actually_interactive=t state_dir="$merge_dir" elif test -n "$do_merge" then - type=merge + interactive_rebase=implied + type=interactive state_dir="$merge_dir" else type=am @@@ -520,28 -501,20 +520,20 @@@ the git_format_patch_opt="$git_format_patch_opt --progress" fi - if test -n "$git_am_opt"; then - incompatible_opts=$(echo " $git_am_opt " | \ - sed -e 's/ -q / /g' -e 's/^ \(.*\) $/\1/') - if test -n "$interactive_rebase" + incompatible_opts=$(echo " $git_am_opt " | \ + sed -e 's/ -q / /g' -e 's/^ \(.*\) $/\1/') + if test -n "$incompatible_opts" + then + if test -n "$actually_interactive" || test "$do_merge" then - if test -n "$incompatible_opts" - then - die "$(gettext "error: cannot combine interactive options (--interactive, --exec, --rebase-merges, --preserve-merges, --keep-empty, --root + --onto) with am options ($incompatible_opts)")" - fi - fi - if test -n "$do_merge"; then - if test -n "$incompatible_opts" - then - die "$(gettext "error: cannot combine merge options (--merge, --strategy, --strategy-option) with am options ($incompatible_opts)")" - fi + die "$(gettext "fatal: cannot combine am options with either interactive or merge options")" fi fi if test -n "$signoff" then test -n "$preserve_merges" && - die "$(gettext "error: cannot combine '--signoff' with '--preserve-merges'")" + die "$(gettext "fatal: cannot combine '--signoff' with '--preserve-merges'")" git_am_opt="$git_am_opt $signoff" force_rebase=t fi @@@ -552,18 -525,15 +544,18 @@@ the # Note: incompatibility with --interactive is just a strong warning; # git-rebase.txt caveats with "unless you know what you are doing" test -n "$rebase_merges" && - die "$(gettext "error: cannot combine '--preserve-merges' with '--rebase-merges'")" + die "$(gettext "fatal: cannot combine '--preserve-merges' with '--rebase-merges'")" + + test -n "$reschedule_failed_exec" && + die "$(gettext "error: cannot combine '--preserve-merges' with '--reschedule-failed-exec'")" fi if test -n "$rebase_merges" then test -n "$strategy_opts" && - die "$(gettext "error: cannot combine '--rebase-merges' with '--strategy-option'")" + die "$(gettext "fatal: cannot combine '--rebase-merges' with '--strategy-option'")" test -n "$strategy" && - die "$(gettext "error: cannot combine '--rebase-merges' with '--strategy'")" + die "$(gettext "fatal: cannot combine '--rebase-merges' with '--strategy'")" fi if test -z "$rebase_root" @@@ -702,7 -672,7 +694,7 @@@ require_clean_work_tree "rebase" "$(get # but this should be done only when upstream and onto are the same # and if this is not an interactive rebase. mb=$(git merge-base "$onto" "$orig_head") - if test -z "$interactive_rebase" && test "$upstream" = "$onto" && + if test -z "$actually_interactive" && test "$upstream" = "$onto" && test "$mb" = "$onto" && test -z "$restrict_revision" && # linear history? ! (git rev-list --parents "$onto".."$orig_head" | sane_grep " .* ") > /dev/null @@@ -752,6 -722,19 +744,19 @@@ the GIT_PAGER='' git diff --stat --summary "$mb_tree" "$onto" fi + if test -z "$actually_interactive" && test "$mb" = "$orig_head" + then + say "$(eval_gettext "Fast-forwarded \$branch_name to \$onto_name.")" + GIT_REFLOG_ACTION="$GIT_REFLOG_ACTION: checkout $onto_name" \ + git checkout -q "$onto^0" || die "could not detach HEAD" + # If the $onto is a proper descendant of the tip of the branch, then + # we just fast-forwarded. + git update-ref ORIG_HEAD $orig_head + move_to_original_branch + finish_rebase + exit 0 + fi + test -n "$interactive_rebase" && run_specific_rebase # Detach HEAD and reset the tree @@@ -761,16 -744,6 +766,6 @@@ GIT_REFLOG_ACTION="$GIT_REFLOG_ACTION: git checkout -q "$onto^0" || die "could not detach HEAD" git update-ref ORIG_HEAD $orig_head - # If the $onto is a proper descendant of the tip of the branch, then - # we just fast-forwarded. - if test "$mb" = "$orig_head" - then - say "$(eval_gettext "Fast-forwarded \$branch_name to \$onto_name.")" - move_to_original_branch - finish_rebase - exit 0 - fi - if test -n "$rebase_root" then revisions="$onto..$orig_head" diff --combined git-rebase--common.sh index a8a44608e0,dc18c682fa..f00e13e5d0 --- a/git-rebase--common.sh +++ b/git-rebase--common.sh @@@ -10,7 -10,7 +10,7 @@@ write_basic_state () echo "$head_name" > "$state_dir"/head-name && echo "$onto" > "$state_dir"/onto && echo "$orig_head" > "$state_dir"/orig-head && - echo "$GIT_QUIET" > "$state_dir"/quiet && + test t = "$GIT_QUIET" && : > "$state_dir"/quiet test t = "$verbose" && : > "$state_dir"/verbose test -n "$strategy" && echo "$strategy" > "$state_dir"/strategy test -n "$strategy_opts" && echo "$strategy_opts" > \ @@@ -19,7 -19,6 +19,7 @@@ "$state_dir"/allow_rerere_autoupdate test -n "$gpg_sign_opt" && echo "$gpg_sign_opt" > "$state_dir"/gpg_sign_opt test -n "$signoff" && echo "$signoff" >"$state_dir"/signoff + test -n "$reschedule_failed_exec" && : > "$state_dir"/reschedule-failed-exec } apply_autostash () { diff --combined sequencer.c index 213815dbfc,bc25615050..a6333abd39 --- a/sequencer.c +++ b/sequencer.c @@@ -150,6 -150,7 +150,7 @@@ static GIT_PATH_FUNC(rebase_path_refs_t static GIT_PATH_FUNC(rebase_path_gpg_sign_opt, "rebase-merge/gpg_sign_opt") static GIT_PATH_FUNC(rebase_path_orig_head, "rebase-merge/orig-head") static GIT_PATH_FUNC(rebase_path_verbose, "rebase-merge/verbose") + static GIT_PATH_FUNC(rebase_path_quiet, "rebase-merge/quiet") static GIT_PATH_FUNC(rebase_path_signoff, "rebase-merge/signoff") static GIT_PATH_FUNC(rebase_path_head_name, "rebase-merge/head-name") static GIT_PATH_FUNC(rebase_path_onto, "rebase-merge/onto") @@@ -157,8 -158,6 +158,7 @@@ static GIT_PATH_FUNC(rebase_path_autost static GIT_PATH_FUNC(rebase_path_strategy, "rebase-merge/strategy") static GIT_PATH_FUNC(rebase_path_strategy_opts, "rebase-merge/strategy_opts") static GIT_PATH_FUNC(rebase_path_allow_rerere_autoupdate, "rebase-merge/allow_rerere_autoupdate") - static GIT_PATH_FUNC(rebase_path_quiet, "rebase-merge/quiet") +static GIT_PATH_FUNC(rebase_path_reschedule_failed_exec, "rebase-merge/reschedule-failed-exec") static int git_sequencer_config(const char *k, const char *v, void *cb) { @@@ -357,8 -356,7 +357,8 @@@ static void free_message(struct commit unuse_commit_buffer(commit, msg->message); } -static void print_advice(int show_hint, struct replay_opts *opts) +static void print_advice(struct repository *r, int show_hint, + struct replay_opts *opts) { char *msg = getenv("GIT_CHERRY_PICK_HELP"); @@@ -369,7 -367,7 +369,7 @@@ * (typically rebase --interactive) wants to take care * of the commit itself so remove CHERRY_PICK_HEAD */ - unlink(git_path_cherry_pick_head(the_repository)); + unlink(git_path_cherry_pick_head(r)); return; } @@@ -442,14 -440,14 +442,14 @@@ static int read_oneliner(struct strbuf return 1; } -static struct tree *empty_tree(void) +static struct tree *empty_tree(struct repository *r) { - return lookup_tree(the_repository, the_repository->hash_algo->empty_tree); + return lookup_tree(r, the_hash_algo->empty_tree); } -static int error_dirty_index(struct replay_opts *opts) +static int error_dirty_index(struct index_state *istate, struct replay_opts *opts) { - if (read_cache_unmerged()) + if (read_index_unmerged(istate)) return error_resolve_conflict(_(action_name(opts))); error(_("your local changes would be overwritten by %s."), @@@ -474,18 -472,15 +474,18 @@@ static void update_abort_safety_file(vo write_file(git_path_abort_safety_file(), "%s", ""); } -static int fast_forward_to(const struct object_id *to, const struct object_id *from, - int unborn, struct replay_opts *opts) +static int fast_forward_to(struct repository *r, + const struct object_id *to, + const struct object_id *from, + int unborn, + struct replay_opts *opts) { struct ref_transaction *transaction; struct strbuf sb = STRBUF_INIT; struct strbuf err = STRBUF_INIT; - read_index(&the_index); - if (checkout_fast_forward(the_repository, from, to, 1)) + read_index(r->index); + if (checkout_fast_forward(r, from, to, 1)) return -1; /* the callee should have complained already */ strbuf_addf(&sb, _("%s: fast-forward"), _(action_name(opts))); @@@ -511,26 -506,24 +511,26 @@@ return 0; } -void append_conflicts_hint(struct strbuf *msgbuf) +void append_conflicts_hint(struct index_state *istate, + struct strbuf *msgbuf) { int i; strbuf_addch(msgbuf, '\n'); strbuf_commented_addf(msgbuf, "Conflicts:\n"); - for (i = 0; i < active_nr;) { - const struct cache_entry *ce = active_cache[i++]; + for (i = 0; i < istate->cache_nr;) { + const struct cache_entry *ce = istate->cache[i++]; if (ce_stage(ce)) { strbuf_commented_addf(msgbuf, "\t%s\n", ce->name); - while (i < active_nr && !strcmp(ce->name, - active_cache[i]->name)) + while (i < istate->cache_nr && + !strcmp(ce->name, istate->cache[i]->name)) i++; } } } -static int do_recursive_merge(struct commit *base, struct commit *next, +static int do_recursive_merge(struct repository *r, + struct commit *base, struct commit *next, const char *base_label, const char *next_label, struct object_id *head, struct strbuf *msgbuf, struct replay_opts *opts) @@@ -544,7 -537,7 +544,7 @@@ if (hold_locked_index(&index_lock, LOCK_REPORT_ON_ERROR) < 0) return -1; - read_cache(); + read_index(r->index); init_merge_options(&o); o.ancestor = base ? base_label : "(empty tree)"; @@@ -555,8 -548,8 +555,8 @@@ o.show_rename_progress = 1; head_tree = parse_tree_indirect(head); - next_tree = next ? get_commit_tree(next) : empty_tree(); - base_tree = base ? get_commit_tree(base) : empty_tree(); + next_tree = next ? get_commit_tree(next) : empty_tree(r); + base_tree = base ? get_commit_tree(base) : empty_tree(r); for (xopt = opts->xopts; xopt != opts->xopts + opts->xopts_nr; xopt++) parse_merge_opt(&o, *xopt); @@@ -573,7 -566,7 +573,7 @@@ return clean; } - if (write_locked_index(&the_index, &index_lock, + if (write_locked_index(r->index, &index_lock, COMMIT_LOCK | SKIP_IF_UNCHANGED)) /* * TRANSLATORS: %s will be "revert", "cherry-pick" or @@@ -583,35 -576,34 +583,35 @@@ _(action_name(opts))); if (!clean) - append_conflicts_hint(msgbuf); + append_conflicts_hint(r->index, msgbuf); return !clean; } -static struct object_id *get_cache_tree_oid(void) +static struct object_id *get_cache_tree_oid(struct index_state *istate) { - if (!active_cache_tree) - active_cache_tree = cache_tree(); + if (!istate->cache_tree) + istate->cache_tree = cache_tree(); - if (!cache_tree_fully_valid(active_cache_tree)) - if (cache_tree_update(&the_index, 0)) { + if (!cache_tree_fully_valid(istate->cache_tree)) + if (cache_tree_update(istate, 0)) { error(_("unable to update cache tree")); return NULL; } - return &active_cache_tree->oid; + return &istate->cache_tree->oid; } -static int is_index_unchanged(void) +static int is_index_unchanged(struct repository *r) { struct object_id head_oid, *cache_tree_oid; struct commit *head_commit; + struct index_state *istate = r->index; if (!resolve_ref_unsafe("HEAD", RESOLVE_REF_READING, &head_oid, NULL)) return error(_("could not resolve HEAD commit")); - head_commit = lookup_commit(the_repository, &head_oid); + head_commit = lookup_commit(r, &head_oid); /* * If head_commit is NULL, check_commit, called from @@@ -624,7 -616,7 +624,7 @@@ if (parse_commit(head_commit)) return -1; - if (!(cache_tree_oid = get_cache_tree_oid())) + if (!(cache_tree_oid = get_cache_tree_oid(istate))) return -1; return oideq(cache_tree_oid, get_commit_tree_oid(head_commit)); @@@ -896,9 -888,7 +896,9 @@@ static int run_command_silent_on_succes * interactive rebase: in that case, we will want to retain the * author metadata. */ -static int run_git_commit(const char *defmsg, struct replay_opts *opts, +static int run_git_commit(struct repository *r, + const char *defmsg, + struct replay_opts *opts, unsigned int flags) { struct child_process cmd = CHILD_PROCESS_INIT; @@@ -921,7 -911,7 +921,7 @@@ if (!defmsg) BUG("root commit without message"); - if (!(cache_tree_oid = get_cache_tree_oid())) + if (!(cache_tree_oid = get_cache_tree_oid(r->index))) res = -1; if (!res) @@@ -1130,9 -1120,7 +1130,9 @@@ void commit_post_rewrite(const struct c run_rewrite_hook(&old_head->object.oid, new_head); } -static int run_prepare_commit_msg_hook(struct strbuf *msg, const char *commit) +static int run_prepare_commit_msg_hook(struct repository *r, + struct strbuf *msg, + const char *commit) { struct argv_array hook_env = ARGV_ARRAY_INIT; int ret; @@@ -1142,7 -1130,7 +1142,7 @@@ if (write_message(msg->buf, msg->len, name, 0)) return -1; - argv_array_pushf(&hook_env, "GIT_INDEX_FILE=%s", get_index_file()); + argv_array_pushf(&hook_env, "GIT_INDEX_FILE=%s", r->index_file); argv_array_push(&hook_env, "GIT_EDITOR=:"); if (commit) ret = run_hook_le(hook_env.argv, "prepare-commit-msg", name, @@@ -1198,9 -1186,7 +1198,9 @@@ static const char *implicit_ident_advic } -void print_commit_summary(const char *prefix, const struct object_id *oid, +void print_commit_summary(struct repository *r, + const char *prefix, + const struct object_id *oid, unsigned int flags) { struct rev_info rev; @@@ -1211,7 -1197,7 +1211,7 @@@ struct strbuf author_ident = STRBUF_INIT; struct strbuf committer_ident = STRBUF_INIT; - commit = lookup_commit(the_repository, oid); + commit = lookup_commit(r, oid); if (!commit) die(_("couldn't look up newly created commit")); if (parse_commit(commit)) @@@ -1244,7 -1230,7 +1244,7 @@@ strbuf_release(&author_ident); strbuf_release(&committer_ident); - repo_init_revisions(the_repository, &rev, prefix); + repo_init_revisions(r, &rev, prefix); setup_revisions(0, NULL, &rev, NULL); rev.diff = 1; @@@ -1278,7 -1264,7 +1278,7 @@@ strbuf_release(&format); } -static int parse_head(struct commit **head) +static int parse_head(struct repository *r, struct commit **head) { struct commit *current_head; struct object_id oid; @@@ -1286,7 -1272,7 +1286,7 @@@ if (get_oid("HEAD", &oid)) { current_head = NULL; } else { - current_head = lookup_commit_reference(the_repository, &oid); + current_head = lookup_commit_reference(r, &oid); if (!current_head) return error(_("could not parse HEAD")); if (!oideq(&oid, ¤t_head->object.oid)) { @@@ -1310,8 -1296,7 +1310,8 @@@ * 0 - success * 1 - run 'git commit' */ -static int try_to_commit(struct strbuf *msg, const char *author, +static int try_to_commit(struct repository *r, + struct strbuf *msg, const char *author, struct replay_opts *opts, unsigned int flags, struct object_id *oid) { @@@ -1326,7 -1311,7 +1326,7 @@@ enum commit_msg_cleanup_mode cleanup; int res = 0; - if (parse_head(¤t_head)) + if (parse_head(r, ¤t_head)) return -1; if (flags & AMEND_MSG) { @@@ -1355,7 -1340,7 +1355,7 @@@ commit_list_insert(current_head, &parents); } - if (write_index_as_tree(&tree, &the_index, get_index_file(), 0, NULL)) { + if (write_index_as_tree(&tree, r->index, r->index_file, 0, NULL)) { res = error(_("git write-tree failed to write a tree")); goto out; } @@@ -1368,7 -1353,7 +1368,7 @@@ } if (find_hook("prepare-commit-msg")) { - res = run_prepare_commit_msg_hook(msg, hook_commit); + res = run_prepare_commit_msg_hook(r, msg, hook_commit); if (res) goto out; if (strbuf_read_file(&commit_msg, git_path_commit_editmsg(), @@@ -1417,8 -1402,7 +1417,8 @@@ out return res; } -static int do_commit(const char *msg_file, const char *author, +static int do_commit(struct repository *r, + const char *msg_file, const char *author, struct replay_opts *opts, unsigned int flags) { int res = 1; @@@ -1433,20 -1417,20 +1433,20 @@@ "from '%s'"), msg_file); - res = try_to_commit(msg_file ? &sb : NULL, author, opts, flags, - &oid); + res = try_to_commit(r, msg_file ? &sb : NULL, + author, opts, flags, &oid); strbuf_release(&sb); if (!res) { - unlink(git_path_cherry_pick_head(the_repository)); - unlink(git_path_merge_msg(the_repository)); + unlink(git_path_cherry_pick_head(r)); + unlink(git_path_merge_msg(r)); if (!is_rebase_i(opts)) - print_commit_summary(NULL, &oid, + print_commit_summary(r, NULL, &oid, SUMMARY_SHOW_AUTHOR_DATE); return res; } } if (res == 1) - return run_git_commit(msg_file, opts, flags); + return run_git_commit(r, msg_file, opts, flags); return res; } @@@ -1474,9 -1458,7 +1474,9 @@@ static int is_original_commit_empty(str /* * Do we run "git commit" with "--allow-empty"? */ -static int allow_empty(struct replay_opts *opts, struct commit *commit) +static int allow_empty(struct repository *r, + struct replay_opts *opts, + struct commit *commit) { int index_unchanged, empty_commit; @@@ -1493,7 -1475,7 +1493,7 @@@ if (!opts->allow_empty) return 0; /* let "git commit" barf as necessary */ - index_unchanged = is_index_unchanged(); + index_unchanged = is_index_unchanged(r); if (index_unchanged < 0) return index_unchanged; if (!index_unchanged) @@@ -1597,10 -1579,8 +1597,10 @@@ static int is_pick_or_similar(enum todo } } -static int update_squash_messages(enum todo_command command, - struct commit *commit, struct replay_opts *opts) +static int update_squash_messages(struct repository *r, + enum todo_command command, + struct commit *commit, + struct replay_opts *opts) { struct strbuf buf = STRBUF_INIT; int res; @@@ -1629,7 -1609,7 +1629,7 @@@ if (get_oid("HEAD", &head)) return error(_("need a HEAD to fixup")); - if (!(head_commit = lookup_commit_reference(the_repository, &head))) + if (!(head_commit = lookup_commit_reference(r, &head))) return error(_("could not read HEAD")); if (!(head_message = get_commit_buffer(head_commit, NULL))) return error(_("could not read HEAD's commit message")); @@@ -1690,8 -1670,7 +1690,8 @@@ return res; } -static void flush_rewritten_pending(void) { +static void flush_rewritten_pending(void) +{ struct strbuf buf = STRBUF_INIT; struct object_id newoid; FILE *out; @@@ -1716,8 -1695,7 +1716,8 @@@ } static void record_in_rewritten(struct object_id *oid, - enum todo_command next_command) { + enum todo_command next_command) +{ FILE *out = fopen_or_warn(rebase_path_rewritten_pending(), "a"); if (!out) @@@ -1730,14 -1708,11 +1730,14 @@@ flush_rewritten_pending(); } -static int do_pick_commit(enum todo_command command, struct commit *commit, - struct replay_opts *opts, int final_fixup) +static int do_pick_commit(struct repository *r, + enum todo_command command, + struct commit *commit, + struct replay_opts *opts, + int final_fixup) { unsigned int flags = opts->edit ? EDIT_MSG : 0; - const char *msg_file = opts->edit ? NULL : git_path_merge_msg(the_repository); + const char *msg_file = opts->edit ? NULL : git_path_merge_msg(r); struct object_id head; struct commit *base, *next, *parent; const char *base_label, *next_label; @@@ -1753,7 -1728,7 +1753,7 @@@ * that represents the "current" state for merge-recursive * to work on. */ - if (write_index_as_tree(&head, &the_index, get_index_file(), 0, NULL)) + if (write_index_as_tree(&head, r->index, r->index_file, 0, NULL)) return error(_("your index file is unmerged.")); } else { unborn = get_oid("HEAD", &head); @@@ -1766,11 -1741,11 +1766,11 @@@ unborn = 1; } else if (unborn) oidcpy(&head, the_hash_algo->empty_tree); - if (index_differs_from(unborn ? empty_tree_oid_hex() : "HEAD", + if (index_differs_from(r, unborn ? empty_tree_oid_hex() : "HEAD", NULL, 0)) - return error_dirty_index(opts); + return error_dirty_index(r->index, opts); } - discard_cache(); + discard_index(r->index); if (!commit->parents) parent = NULL; @@@ -1791,13 -1766,9 +1791,13 @@@ return error(_("commit %s does not have parent %d"), oid_to_hex(&commit->object.oid), opts->mainline); parent = p->item; - } else if (0 < opts->mainline) - return error(_("mainline was specified but commit %s is not a merge."), - oid_to_hex(&commit->object.oid)); + } else if (1 < opts->mainline) + /* + * Non-first parent explicitly specified as mainline for + * non-merge commit + */ + return error(_("commit %s does not have parent %d"), + oid_to_hex(&commit->object.oid), opts->mainline); else parent = commit->parents->item; @@@ -1810,7 -1781,7 +1810,7 @@@ (!parent && unborn))) { if (is_rebase_i(opts)) write_author_script(msg.message); - res = fast_forward_to(&commit->object.oid, &head, unborn, + res = fast_forward_to(r, &commit->object.oid, &head, unborn, opts); if (res || command != TODO_REWORD) goto leave; @@@ -1874,7 -1845,7 +1874,7 @@@ if (command == TODO_REWORD) flags |= EDIT_MSG | VERIFY_MSG; else if (is_fixup(command)) { - if (update_squash_messages(command, commit, opts)) + if (update_squash_messages(r, command, commit, opts)) return -1; flags |= AMEND_MSG; if (!final_fixup) @@@ -1883,12 -1854,12 +1883,12 @@@ flags |= CLEANUP_MSG; msg_file = rebase_path_fixup_msg(); } else { - const char *dest = git_path_squash_msg(the_repository); + const char *dest = git_path_squash_msg(r); unlink(dest); if (copy_file(dest, rebase_path_squash_msg(), 0666)) return error(_("could not rename '%s' to '%s'"), rebase_path_squash_msg(), dest); - unlink(git_path_merge_msg(the_repository)); + unlink(git_path_merge_msg(r)); msg_file = dest; flags |= EDIT_MSG; } @@@ -1900,23 -1871,23 +1900,23 @@@ if (is_rebase_i(opts) && write_author_script(msg.message) < 0) res = -1; else if (!opts->strategy || !strcmp(opts->strategy, "recursive") || command == TODO_REVERT) { - res = do_recursive_merge(base, next, base_label, next_label, + res = do_recursive_merge(r, base, next, base_label, next_label, &head, &msgbuf, opts); if (res < 0) goto leave; res |= write_message(msgbuf.buf, msgbuf.len, - git_path_merge_msg(the_repository), 0); + git_path_merge_msg(r), 0); } else { struct commit_list *common = NULL; struct commit_list *remotes = NULL; res = write_message(msgbuf.buf, msgbuf.len, - git_path_merge_msg(the_repository), 0); + git_path_merge_msg(r), 0); commit_list_insert(base, &common); commit_list_insert(next, &remotes); - res |= try_merge_command(the_repository, opts->strategy, + res |= try_merge_command(r, opts->strategy, opts->xopts_nr, (const char **)opts->xopts, common, oid_to_hex(&head), remotes); free_commit_list(common); @@@ -1944,12 -1915,12 +1944,12 @@@ ? _("could not revert %s... %s") : _("could not apply %s... %s"), short_commit_name(commit), msg.subject); - print_advice(res == 1, opts); - repo_rerere(the_repository, opts->allow_rerere_auto); + print_advice(r, res == 1, opts); + repo_rerere(r, opts->allow_rerere_auto); goto leave; } - allow = allow_empty(opts, commit); + allow = allow_empty(r, opts, commit); if (allow < 0) { res = allow; goto leave; @@@ -1958,7 -1929,7 +1958,7 @@@ if (!opts->no_commit) { fast_forward_edit: if (author || command == TODO_REVERT || (flags & AMEND_MSG)) - res = do_commit(msg_file, author, opts, flags); + res = do_commit(r, msg_file, author, opts, flags); else res = error(_("unable to parse commit author")); } @@@ -1994,19 -1965,18 +1994,19 @@@ static int prepare_revs(struct replay_o return 0; } -static int read_and_refresh_cache(struct replay_opts *opts) +static int read_and_refresh_cache(struct repository *r, + struct replay_opts *opts) { struct lock_file index_lock = LOCK_INIT; int index_fd = hold_locked_index(&index_lock, 0); - if (read_index(&the_index) < 0) { + if (read_index(r->index) < 0) { rollback_lock_file(&index_lock); return error(_("git %s: failed to read the index"), _(action_name(opts))); } - refresh_index(&the_index, REFRESH_QUIET|REFRESH_UNMERGED, NULL, NULL, NULL); + refresh_index(r->index, REFRESH_QUIET|REFRESH_UNMERGED, NULL, NULL, NULL); if (index_fd >= 0) { - if (write_locked_index(&the_index, &index_lock, + if (write_locked_index(r->index, &index_lock, COMMIT_LOCK | SKIP_IF_UNCHANGED)) { return error(_("git %s: failed to refresh the index"), _(action_name(opts))); @@@ -2051,8 -2021,7 +2051,8 @@@ static struct todo_item *append_new_tod return todo_list->items + todo_list->nr++; } -static int parse_insn_line(struct todo_item *item, const char *bol, char *eol) +static int parse_insn_line(struct repository *r, struct todo_item *item, + const char *bol, char *eol) { struct object_id commit_oid; char *end_of_object_name; @@@ -2137,12 -2106,11 +2137,12 @@@ if (status < 0) return -1; - item->commit = lookup_commit_reference(the_repository, &commit_oid); + item->commit = lookup_commit_reference(r, &commit_oid); return !item->commit; } -static int parse_insn_buffer(char *buf, struct todo_list *todo_list) +static int parse_insn_buffer(struct repository *r, char *buf, + struct todo_list *todo_list) { struct todo_item *item; char *p = buf, *next_p; @@@ -2158,7 -2126,7 +2158,7 @@@ item = append_new_todo(todo_list); item->offset_in_buf = p - todo_list->buf.buf; - if (parse_insn_line(item, p, eol)) { + if (parse_insn_line(r, item, p, eol)) { res = error(_("invalid line %d: %.*s"), i, (int)(eol - p), p); item->command = TODO_NOOP; @@@ -2219,9 -2187,8 +2219,9 @@@ static ssize_t strbuf_read_file_or_whin return len; } -static int read_populate_todo(struct todo_list *todo_list, - struct replay_opts *opts) +static int read_populate_todo(struct repository *r, + struct todo_list *todo_list, + struct replay_opts *opts) { struct stat st; const char *todo_file = get_todo_path(opts); @@@ -2236,7 -2203,7 +2236,7 @@@ return error(_("could not stat '%s'"), todo_file); fill_stat_data(&todo_list->stat, &st); - res = parse_insn_buffer(todo_list->buf.buf, todo_list); + res = parse_insn_buffer(r, todo_list->buf.buf, todo_list); if (res) { if (is_rebase_i(opts)) return error(_("please fix this using " @@@ -2267,7 -2234,7 +2267,7 @@@ FILE *f = fopen_or_warn(rebase_path_msgtotal(), "w"); if (strbuf_read_file(&done.buf, rebase_path_done(), 0) > 0 && - !parse_insn_buffer(done.buf.buf, &done)) + !parse_insn_buffer(r, done.buf.buf, &done)) todo_list->done_nr = count_commands(&done); else todo_list->done_nr = 0; @@@ -2390,14 -2357,14 +2390,17 @@@ static int read_populate_opts(struct re if (file_exists(rebase_path_verbose())) opts->verbose = 1; + if (file_exists(rebase_path_quiet())) + opts->quiet = 1; + if (file_exists(rebase_path_signoff())) { opts->allow_ff = 0; opts->signoff = 1; } + if (file_exists(rebase_path_reschedule_failed_exec())) + opts->reschedule_failed_exec = 1; + read_strategy_opts(opts, &buf); strbuf_release(&buf); @@@ -2460,9 -2427,6 +2463,6 @@@ int write_basic_state(struct replay_opt if (quiet) write_file(rebase_path_quiet(), "%s\n", quiet); - else - write_file(rebase_path_quiet(), "\n"); - if (opts->verbose) write_file(rebase_path_verbose(), "%s", ""); if (opts->strategy) @@@ -2479,8 -2443,6 +2479,8 @@@ write_file(rebase_path_gpg_sign_opt(), "-S%s\n", opts->gpg_sign); if (opts->signoff) write_file(rebase_path_signoff(), "--signoff\n"); + if (opts->reschedule_failed_exec) + write_file(rebase_path_reschedule_failed_exec(), "%s", ""); return 0; } @@@ -2589,12 -2551,12 +2589,12 @@@ static int reset_for_rollback(const str return run_command_v_opt(argv, RUN_GIT_CMD); } -static int rollback_single_pick(void) +static int rollback_single_pick(struct repository *r) { struct object_id head_oid; - if (!file_exists(git_path_cherry_pick_head(the_repository)) && - !file_exists(git_path_revert_head(the_repository))) + if (!file_exists(git_path_cherry_pick_head(r)) && + !file_exists(git_path_revert_head(r))) return error(_("no cherry-pick or revert in progress")); if (read_ref_full("HEAD", 0, &head_oid, NULL)) return error(_("cannot resolve HEAD")); @@@ -2603,7 -2565,7 +2603,7 @@@ return reset_for_rollback(&head_oid); } -int sequencer_rollback(struct replay_opts *opts) +int sequencer_rollback(struct repository *r, struct replay_opts *opts) { FILE *f; struct object_id oid; @@@ -2617,7 -2579,7 +2617,7 @@@ * If CHERRY_PICK_HEAD or REVERT_HEAD indicates * a single-cherry-pick in progress, abort that. */ - return rollback_single_pick(); + return rollback_single_pick(r); } if (!f) return error_errno(_("cannot open '%s'"), git_path_head_file()); @@@ -2732,9 -2694,7 +2732,9 @@@ static int save_opts(struct replay_opt return res; } -static int make_patch(struct commit *commit, struct replay_opts *opts) +static int make_patch(struct repository *r, + struct commit *commit, + struct replay_opts *opts) { struct strbuf buf = STRBUF_INIT; struct rev_info log_tree_opt; @@@ -2750,7 -2710,7 +2750,7 @@@ strbuf_addf(&buf, "%s/patch", get_dir(opts)); memset(&log_tree_opt, 0, sizeof(log_tree_opt)); - repo_init_revisions(the_repository, &log_tree_opt, NULL); + repo_init_revisions(r, &log_tree_opt, NULL); log_tree_opt.abbrev = 0; log_tree_opt.diff = 1; log_tree_opt.diffopt.output_format = DIFF_FORMAT_PATCH; @@@ -2790,19 -2750,17 +2790,19 @@@ static int intend_to_amend(void return write_message(p, strlen(p), rebase_path_amend(), 1); } -static int error_with_patch(struct commit *commit, - const char *subject, int subject_len, - struct replay_opts *opts, int exit_code, int to_amend) +static int error_with_patch(struct repository *r, + struct commit *commit, + const char *subject, int subject_len, + struct replay_opts *opts, + int exit_code, int to_amend) { if (commit) { - if (make_patch(commit, opts)) + if (make_patch(r, commit, opts)) return -1; } else if (copy_file(rebase_path_message(), - git_path_merge_msg(the_repository), 0666)) + git_path_merge_msg(r), 0666)) return error(_("unable to copy '%s' to '%s'"), - git_path_merge_msg(the_repository), rebase_path_message()); + git_path_merge_msg(r), rebase_path_message()); if (to_amend) { if (intend_to_amend()) @@@ -2833,24 -2791,21 +2833,24 @@@ return exit_code; } -static int error_failed_squash(struct commit *commit, - struct replay_opts *opts, int subject_len, const char *subject) +static int error_failed_squash(struct repository *r, + struct commit *commit, + struct replay_opts *opts, + int subject_len, + const char *subject) { if (copy_file(rebase_path_message(), rebase_path_squash_msg(), 0666)) return error(_("could not copy '%s' to '%s'"), rebase_path_squash_msg(), rebase_path_message()); - unlink(git_path_merge_msg(the_repository)); - if (copy_file(git_path_merge_msg(the_repository), rebase_path_message(), 0666)) + unlink(git_path_merge_msg(r)); + if (copy_file(git_path_merge_msg(r), rebase_path_message(), 0666)) return error(_("could not copy '%s' to '%s'"), rebase_path_message(), - git_path_merge_msg(the_repository)); - return error_with_patch(commit, subject, subject_len, opts, 1, 0); + git_path_merge_msg(r)); + return error_with_patch(r, commit, subject, subject_len, opts, 1, 0); } -static int do_exec(const char *command_line) +static int do_exec(struct repository *r, const char *command_line) { struct argv_array child_env = ARGV_ARRAY_INIT; const char *child_argv[] = { NULL, NULL }; @@@ -2865,10 -2820,10 +2865,10 @@@ child_env.argv); /* force re-reading of the cache */ - if (discard_cache() < 0 || read_cache() < 0) + if (discard_index(r->index) < 0 || read_index(r->index) < 0) return error(_("could not read index")); - dirty = require_clean_work_tree("rebase", NULL, 1, 1); + dirty = require_clean_work_tree(r, "rebase", NULL, 1, 1); if (status) { warning(_("execution failed: %s\n%s" @@@ -2934,9 -2889,9 +2934,9 @@@ static int safe_append(const char *file return 0; } -static int do_label(const char *name, int len) +static int do_label(struct repository *r, const char *name, int len) { - struct ref_store *refs = get_main_ref_store(the_repository); + struct ref_store *refs = get_main_ref_store(r); struct ref_transaction *transaction; struct strbuf ref_name = STRBUF_INIT, err = STRBUF_INIT; struct strbuf msg = STRBUF_INIT; @@@ -2977,9 -2932,7 +2977,9 @@@ static const char *reflog_message(struct replay_opts *opts, const char *sub_action, const char *fmt, ...); -static int do_reset(const char *name, int len, struct replay_opts *opts) +static int do_reset(struct repository *r, + const char *name, int len, + struct replay_opts *opts) { struct strbuf ref_name = STRBUF_INIT; struct object_id oid; @@@ -3028,13 -2981,13 +3028,13 @@@ memset(&unpack_tree_opts, 0, sizeof(unpack_tree_opts)); setup_unpack_trees_porcelain(&unpack_tree_opts, "reset"); unpack_tree_opts.head_idx = 1; - unpack_tree_opts.src_index = &the_index; - unpack_tree_opts.dst_index = &the_index; + unpack_tree_opts.src_index = r->index; + unpack_tree_opts.dst_index = r->index; unpack_tree_opts.fn = oneway_merge; unpack_tree_opts.merge = 1; unpack_tree_opts.update = 1; - if (read_cache_unmerged()) { + if (read_index_unmerged(r->index)) { rollback_lock_file(&lock); strbuf_release(&ref_name); return error_resolve_conflict(_(action_name(opts))); @@@ -3056,9 -3009,9 +3056,9 @@@ } tree = parse_tree_indirect(&oid); - prime_cache_tree(&the_index, tree); + prime_cache_tree(r, r->index, tree); - if (write_locked_index(&the_index, &lock, COMMIT_LOCK) < 0) + if (write_locked_index(r->index, &lock, COMMIT_LOCK) < 0) ret = error(_("could not write index")); free((void *)desc.buffer); @@@ -3091,9 -3044,7 +3091,9 @@@ static struct commit *lookup_label(cons return commit; } -static int do_merge(struct commit *commit, const char *arg, int arg_len, +static int do_merge(struct repository *r, + struct commit *commit, + const char *arg, int arg_len, int flags, struct replay_opts *opts) { int run_commit_flags = (flags & TODO_EDIT_MERGE_MSG) ? @@@ -3160,7 -3111,7 +3160,7 @@@ ret = error(_("octopus merge cannot be executed on " "top of a [new root]")); else - ret = fast_forward_to(&to_merge->item->object.oid, + ret = fast_forward_to(r, &to_merge->item->object.oid, &head_commit->object.oid, 0, opts); goto leave_merge; @@@ -3179,11 -3130,11 +3179,11 @@@ write_author_script(message); find_commit_subject(message, &body); len = strlen(body); - ret = write_message(body, len, git_path_merge_msg(the_repository), 0); + ret = write_message(body, len, git_path_merge_msg(r), 0); unuse_commit_buffer(commit, message); if (ret) { error_errno(_("could not write '%s'"), - git_path_merge_msg(the_repository)); + git_path_merge_msg(r)); goto leave_merge; } } else { @@@ -3205,11 -3156,11 +3205,11 @@@ len = buf.len; } - ret = write_message(p, len, git_path_merge_msg(the_repository), 0); + ret = write_message(p, len, git_path_merge_msg(r), 0); strbuf_release(&buf); if (ret) { error_errno(_("could not write '%s'"), - git_path_merge_msg(the_repository)); + git_path_merge_msg(r)); goto leave_merge; } } @@@ -3245,7 -3196,7 +3245,7 @@@ if (can_fast_forward) { rollback_lock_file(&lock); - ret = fast_forward_to(&commit->object.oid, + ret = fast_forward_to(r, &commit->object.oid, &head_commit->object.oid, 0, opts); goto leave_merge; } @@@ -3270,7 -3221,7 +3270,7 @@@ argv_array_push(&cmd.args, "--no-log"); argv_array_push(&cmd.args, "--no-stat"); argv_array_push(&cmd.args, "-F"); - argv_array_push(&cmd.args, git_path_merge_msg(the_repository)); + argv_array_push(&cmd.args, git_path_merge_msg(r)); if (opts->gpg_sign) argv_array_push(&cmd.args, opts->gpg_sign); @@@ -3280,15 -3231,14 +3280,15 @@@ oid_to_hex(&j->item->object.oid)); strbuf_release(&ref_name); - unlink(git_path_cherry_pick_head(the_repository)); + unlink(git_path_cherry_pick_head(r)); rollback_lock_file(&lock); rollback_lock_file(&lock); ret = run_command(&cmd); /* force re-reading of the cache */ - if (!ret && (discard_cache() < 0 || read_cache() < 0)) + if (!ret && (discard_index(r->index) < 0 || + read_index(r->index) < 0)) ret = error(_("could not read index")); goto leave_merge; } @@@ -3303,14 -3253,14 +3303,14 @@@ } write_message(oid_to_hex(&merge_commit->object.oid), GIT_SHA1_HEXSZ, - git_path_merge_head(the_repository), 0); - write_message("no-ff", 5, git_path_merge_mode(the_repository), 0); + git_path_merge_head(r), 0); + write_message("no-ff", 5, git_path_merge_mode(r), 0); for (j = bases; j; j = j->next) commit_list_insert(j->item, &reversed); free_commit_list(bases); - read_cache(); + read_index(r->index); init_merge_options(&o); o.branch1 = "HEAD"; o.branch2 = ref_name.buf; @@@ -3335,23 -3285,23 +3335,23 @@@ */ ret = !ret; - if (active_cache_changed && - write_locked_index(&the_index, &lock, COMMIT_LOCK)) { + if (r->index->cache_changed && + write_locked_index(r->index, &lock, COMMIT_LOCK)) { ret = error(_("merge: Unable to write new index file")); goto leave_merge; } rollback_lock_file(&lock); if (ret) - repo_rerere(the_repository, opts->allow_rerere_auto); + repo_rerere(r, opts->allow_rerere_auto); else /* * In case of problems, we now want to return a positive * value (a negative one would indicate that the `merge` * command needs to be rescheduled). */ - ret = !!run_git_commit(git_path_merge_msg(the_repository), opts, - run_commit_flags); + ret = !!run_git_commit(r, git_path_merge_msg(r), opts, + run_commit_flags); leave_merge: strbuf_release(&ref_name); @@@ -3499,14 -3449,14 +3499,14 @@@ static int checkout_onto(struct replay_ return update_ref(NULL, "ORIG_HEAD", &oid, NULL, 0, UPDATE_REFS_MSG_ON_ERR); } -static int stopped_at_head(void) +static int stopped_at_head(struct repository *r) { struct object_id head; struct commit *commit; struct commit_message message; if (get_oid("HEAD", &head) || - !(commit = lookup_commit(the_repository, &head)) || + !(commit = lookup_commit(r, &head)) || parse_commit(commit) || get_message(commit, &message)) fprintf(stderr, _("Stopped at HEAD\n")); else { @@@ -3528,9 -3478,7 +3528,9 @@@ N_("Could not execute the todo command\ " git rebase --edit-todo\n" " git rebase --continue\n"); -static int pick_commits(struct todo_list *todo_list, struct replay_opts *opts) +static int pick_commits(struct repository *r, + struct todo_list *todo_list, + struct replay_opts *opts) { int res = 0, reschedule = 0; @@@ -3538,7 -3486,7 +3538,7 @@@ if (opts->allow_ff) assert(!(opts->signoff || opts->no_commit || opts->record_origin || opts->edit)); - if (read_and_refresh_cache(opts)) + if (read_and_refresh_cache(r, opts)) return -1; while (todo_list->current < todo_list->nr) { @@@ -3555,10 -3503,11 +3555,11 @@@ fprintf(f, "%d\n", todo_list->done_nr); fclose(f); } - fprintf(stderr, "Rebasing (%d/%d)%s", - todo_list->done_nr, - todo_list->total_nr, - opts->verbose ? "\n" : "\r"); + if (!opts->quiet) + fprintf(stderr, "Rebasing (%d/%d)%s", + todo_list->done_nr, + todo_list->total_nr, + opts->verbose ? "\n" : "\r"); } unlink(rebase_path_message()); unlink(rebase_path_author_script()); @@@ -3568,14 -3517,14 +3569,14 @@@ delete_ref(NULL, "REBASE_HEAD", NULL, REF_NO_DEREF); if (item->command == TODO_BREAK) - return stopped_at_head(); + return stopped_at_head(r); } if (item->command <= TODO_SQUASH) { if (is_rebase_i(opts)) setenv("GIT_REFLOG_ACTION", reflog_message(opts, command_to_string(item->command), NULL), 1); - res = do_pick_commit(item->command, item->commit, + res = do_pick_commit(r, item->command, item->commit, opts, is_final_fixup(todo_list)); if (is_rebase_i(opts) && res < 0) { /* Reschedule */ @@@ -3595,7 -3544,7 +3596,7 @@@ _("Stopped at %s... %.*s\n"), short_commit_name(commit), item->arg_len, item->arg); - return error_with_patch(commit, + return error_with_patch(r, commit, item->arg, item->arg_len, opts, res, !res); } @@@ -3605,7 -3554,7 +3606,7 @@@ if (res && is_fixup(item->command)) { if (res == 1) intend_to_amend(); - return error_failed_squash(item->commit, opts, + return error_failed_squash(r, item->commit, opts, item->arg_len, item->arg); } else if (res && is_rebase_i(opts) && item->commit) { int to_amend = 0; @@@ -3624,7 -3573,7 +3625,7 @@@ oideq(&opts->squash_onto, &oid)))) to_amend = 1; - return res | error_with_patch(item->commit, + return res | error_with_patch(r, item->commit, item->arg, item->arg_len, opts, res, to_amend); } @@@ -3634,31 -3583,30 +3635,31 @@@ struct stat st; *end_of_arg = '\0'; - res = do_exec(item->arg); + res = do_exec(r, item->arg); *end_of_arg = saved; /* Reread the todo file if it has changed. */ - if (res) - ; /* fall through */ - else if (stat(get_todo_path(opts), &st)) + if (res) { + if (opts->reschedule_failed_exec) + reschedule = 1; + } else if (stat(get_todo_path(opts), &st)) res = error_errno(_("could not stat '%s'"), get_todo_path(opts)); else if (match_stat_data(&todo_list->stat, &st)) { todo_list_release(todo_list); - if (read_populate_todo(todo_list, opts)) + if (read_populate_todo(r, todo_list, opts)) res = -1; /* message was printed */ /* `current` will be incremented below */ todo_list->current = -1; } } else if (item->command == TODO_LABEL) { - if ((res = do_label(item->arg, item->arg_len))) + if ((res = do_label(r, item->arg, item->arg_len))) reschedule = 1; } else if (item->command == TODO_RESET) { - if ((res = do_reset(item->arg, item->arg_len, opts))) + if ((res = do_reset(r, item->arg, item->arg_len, opts))) reschedule = 1; } else if (item->command == TODO_MERGE) { - if ((res = do_merge(item->commit, + if ((res = do_merge(r, item->commit, item->arg, item->arg_len, item->flags, opts)) < 0) reschedule = 1; @@@ -3667,7 -3615,7 +3668,7 @@@ peek_command(todo_list, 1)); if (res > 0) /* failed with merge conflicts */ - return error_with_patch(item->commit, + return error_with_patch(r, item->commit, item->arg, item->arg_len, opts, res, 0); @@@ -3683,8 -3631,7 +3684,8 @@@ if (save_todo(todo_list, opts)) return -1; if (item->commit) - return error_with_patch(item->commit, + return error_with_patch(r, + item->commit, item->arg, item->arg_len, opts, res, 0); @@@ -3749,7 -3696,7 +3750,7 @@@ cleanup_head_ref struct object_id orig, head; memset(&log_tree_opt, 0, sizeof(log_tree_opt)); - repo_init_revisions(the_repository, &log_tree_opt, NULL); + repo_init_revisions(r, &log_tree_opt, NULL); log_tree_opt.diff = 1; log_tree_opt.diffopt.output_format = DIFF_FORMAT_DIFFSTAT; @@@ -3792,8 -3739,10 +3793,10 @@@ } apply_autostash(opts); - fprintf(stderr, "Successfully rebased and updated %s.\n", - head_ref.buf); + if (!opts->quiet) + fprintf(stderr, + "Successfully rebased and updated %s.\n", + head_ref.buf); strbuf_release(&buf); strbuf_release(&head_ref); @@@ -3806,27 -3755,26 +3809,27 @@@ return sequencer_remove_state(opts); } -static int continue_single_pick(void) +static int continue_single_pick(struct repository *r) { const char *argv[] = { "commit", NULL }; - if (!file_exists(git_path_cherry_pick_head(the_repository)) && - !file_exists(git_path_revert_head(the_repository))) + if (!file_exists(git_path_cherry_pick_head(r)) && + !file_exists(git_path_revert_head(r))) return error(_("no cherry-pick or revert in progress")); return run_command_v_opt(argv, RUN_GIT_CMD); } -static int commit_staged_changes(struct replay_opts *opts, +static int commit_staged_changes(struct repository *r, + struct replay_opts *opts, struct todo_list *todo_list) { unsigned int flags = ALLOW_EMPTY | EDIT_MSG; unsigned int final_fixup = 0, is_clean; - if (has_unstaged_changes(1)) + if (has_unstaged_changes(r, 1)) return error(_("cannot rebase: You have unstaged changes.")); - is_clean = !has_uncommitted_changes(0); + is_clean = !has_uncommitted_changes(r, 0); if (file_exists(rebase_path_amend())) { struct strbuf rev = STRBUF_INIT; @@@ -3910,7 -3858,7 +3913,7 @@@ struct commit *commit; const char *path = rebase_path_squash_msg(); - if (parse_head(&commit) || + if (parse_head(r, &commit) || !(p = get_commit_buffer(commit, NULL)) || write_message(p, strlen(p), path, 0)) { unuse_commit_buffer(commit, p); @@@ -3926,7 -3874,7 +3929,7 @@@ } if (is_clean) { - const char *cherry_pick_head = git_path_cherry_pick_head(the_repository); + const char *cherry_pick_head = git_path_cherry_pick_head(r); if (file_exists(cherry_pick_head) && unlink(cherry_pick_head)) return error(_("could not remove CHERRY_PICK_HEAD")); @@@ -3934,7 -3882,7 +3937,7 @@@ return 0; } - if (run_git_commit(final_fixup ? NULL : rebase_path_message(), + if (run_git_commit(r, final_fixup ? NULL : rebase_path_message(), opts, flags)) return error(_("could not commit staged changes.")); unlink(rebase_path_amend()); @@@ -3955,36 -3903,36 +3958,36 @@@ return 0; } -int sequencer_continue(struct replay_opts *opts) +int sequencer_continue(struct repository *r, struct replay_opts *opts) { struct todo_list todo_list = TODO_LIST_INIT; int res; - if (read_and_refresh_cache(opts)) + if (read_and_refresh_cache(r, opts)) return -1; if (read_populate_opts(opts)) return -1; if (is_rebase_i(opts)) { - if ((res = read_populate_todo(&todo_list, opts))) + if ((res = read_populate_todo(r, &todo_list, opts))) goto release_todo_list; - if (commit_staged_changes(opts, &todo_list)) + if (commit_staged_changes(r, opts, &todo_list)) return -1; } else if (!file_exists(get_todo_path(opts))) - return continue_single_pick(); - else if ((res = read_populate_todo(&todo_list, opts))) + return continue_single_pick(r); + else if ((res = read_populate_todo(r, &todo_list, opts))) goto release_todo_list; if (!is_rebase_i(opts)) { /* Verify that the conflict has been resolved */ - if (file_exists(git_path_cherry_pick_head(the_repository)) || - file_exists(git_path_revert_head(the_repository))) { - res = continue_single_pick(); + if (file_exists(git_path_cherry_pick_head(r)) || + file_exists(git_path_revert_head(r))) { + res = continue_single_pick(r); if (res) goto release_todo_list; } - if (index_differs_from("HEAD", NULL, 0)) { - res = error_dirty_index(opts); + if (index_differs_from(r, "HEAD", NULL, 0)) { + res = error_dirty_index(r->index, opts); goto release_todo_list; } todo_list.current++; @@@ -3998,30 -3946,27 +4001,30 @@@ strbuf_release(&buf); } - res = pick_commits(&todo_list, opts); + res = pick_commits(r, &todo_list, opts); release_todo_list: todo_list_release(&todo_list); return res; } -static int single_pick(struct commit *cmit, struct replay_opts *opts) +static int single_pick(struct repository *r, + struct commit *cmit, + struct replay_opts *opts) { setenv(GIT_REFLOG_ACTION, action_name(opts), 0); - return do_pick_commit(opts->action == REPLAY_PICK ? + return do_pick_commit(r, opts->action == REPLAY_PICK ? TODO_PICK : TODO_REVERT, cmit, opts, 0); } -int sequencer_pick_revisions(struct replay_opts *opts) +int sequencer_pick_revisions(struct repository *r, + struct replay_opts *opts) { struct todo_list todo_list = TODO_LIST_INIT; struct object_id oid; int i, res; assert(opts->revs); - if (read_and_refresh_cache(opts)) + if (read_and_refresh_cache(r, opts)) return -1; for (i = 0; i < opts->revs->pending.nr; i++) { @@@ -4033,8 -3978,8 +4036,8 @@@ continue; if (!get_oid(name, &oid)) { - if (!lookup_commit_reference_gently(the_repository, &oid, 1)) { - enum object_type type = oid_object_info(the_repository, + if (!lookup_commit_reference_gently(r, &oid, 1)) { + enum object_type type = oid_object_info(r, &oid, NULL); return error(_("%s: can't cherry-pick a %s"), @@@ -4063,7 -4008,7 +4066,7 @@@ return error(_("empty commit set passed")); if (get_revision(opts->revs)) BUG("unexpected extra commit from walk"); - return single_pick(cmit, opts); + return single_pick(r, cmit, opts); } /* @@@ -4082,7 -4027,7 +4085,7 @@@ if (save_opts(opts)) return -1; update_abort_safety_file(); - res = pick_commits(&todo_list, opts); + res = pick_commits(r, &todo_list, opts); todo_list_release(&todo_list); return res; } @@@ -4486,8 -4431,7 +4489,8 @@@ static int make_script_with_merges(stru return 0; } -int sequencer_make_script(FILE *out, int argc, const char **argv, +int sequencer_make_script(struct repository *r, FILE *out, + int argc, const char **argv, unsigned flags) { char *format = NULL; @@@ -4499,7 -4443,7 +4502,7 @@@ const char *insn = flags & TODO_LIST_ABBREVIATE_CMDS ? "p" : "pick"; int rebase_merges = flags & TODO_LIST_REBASE_MERGES; - repo_init_revisions(the_repository, &revs, NULL); + repo_init_revisions(r, &revs, NULL); revs.verbose_header = 1; if (!rebase_merges) revs.max_parents = 1; @@@ -4552,8 -4496,7 +4555,8 @@@ * Add commands after pick and (series of) squash/fixup commands * in the todo list. */ -int sequencer_add_exec_commands(const char *commands) +int sequencer_add_exec_commands(struct repository *r, + const char *commands) { const char *todo_file = rebase_path_todo(); struct todo_list todo_list = TODO_LIST_INIT; @@@ -4564,7 -4507,7 +4567,7 @@@ if (strbuf_read_file(&todo_list.buf, todo_file, 0) < 0) return error(_("could not read '%s'."), todo_file); - if (parse_insn_buffer(todo_list.buf.buf, &todo_list)) { + if (parse_insn_buffer(r, todo_list.buf.buf, &todo_list)) { todo_list_release(&todo_list); return error(_("unusable todo list: '%s'"), todo_file); } @@@ -4609,7 -4552,7 +4612,7 @@@ return i; } -int transform_todos(unsigned flags) +int transform_todos(struct repository *r, unsigned flags) { const char *todo_file = rebase_path_todo(); struct todo_list todo_list = TODO_LIST_INIT; @@@ -4620,7 -4563,7 +4623,7 @@@ if (strbuf_read_file(&todo_list.buf, todo_file, 0) < 0) return error(_("could not read '%s'."), todo_file); - if (parse_insn_buffer(todo_list.buf.buf, &todo_list)) { + if (parse_insn_buffer(r, todo_list.buf.buf, &todo_list)) { todo_list_release(&todo_list); return error(_("unusable todo list: '%s'"), todo_file); } @@@ -4689,7 -4632,7 +4692,7 @@@ define_commit_slab(commit_seen, unsigne * Check if there is an unrecognized command or a * bad SHA-1 in a command. */ -int check_todo_list(void) +int check_todo_list(struct repository *r) { enum missing_commit_check_level check_level = get_missing_commit_check_level(); struct strbuf todo_file = STRBUF_INIT; @@@ -4706,7 -4649,7 +4709,7 @@@ goto leave_check; } advise_to_edit_todo = res = - parse_insn_buffer(todo_list.buf.buf, &todo_list); + parse_insn_buffer(r, todo_list.buf.buf, &todo_list); if (res || check_level == MISSING_COMMIT_CHECK_IGNORE) goto leave_check; @@@ -4725,7 -4668,7 +4728,7 @@@ goto leave_check; } strbuf_release(&todo_file); - res = !!parse_insn_buffer(todo_list.buf.buf, &todo_list); + res = !!parse_insn_buffer(r, todo_list.buf.buf, &todo_list); /* Find commits in git-rebase-todo.backup yet unseen */ for (i = todo_list.nr - 1; i >= 0; i--) { @@@ -4789,7 -4732,7 +4792,7 @@@ static int rewrite_file(const char *pat } /* skip picking commits whose parents are unchanged */ -static int skip_unnecessary_picks(struct object_id *output_oid) +static int skip_unnecessary_picks(struct repository *r, struct object_id *output_oid) { const char *todo_file = rebase_path_todo(); struct strbuf buf = STRBUF_INIT; @@@ -4807,7 -4750,7 +4810,7 @@@ if (strbuf_read_file_or_whine(&todo_list.buf, todo_file) < 0) return -1; - if (parse_insn_buffer(todo_list.buf.buf, &todo_list) < 0) { + if (parse_insn_buffer(r, todo_list.buf.buf, &todo_list) < 0) { todo_list_release(&todo_list); return -1; } @@@ -4868,7 -4811,7 +4871,7 @@@ return 0; } -int complete_action(struct replay_opts *opts, unsigned flags, +int complete_action(struct repository *r, struct replay_opts *opts, unsigned flags, const char *shortrevisions, const char *onto_name, const char *onto, const char *orig_head, const char *cmd, unsigned autosquash) @@@ -4886,16 -4829,16 +4889,16 @@@ write_message("noop\n", 5, todo_file, 0)) return -1; - if (autosquash && rearrange_squash()) + if (autosquash && rearrange_squash(r)) return -1; if (cmd && *cmd) - sequencer_add_exec_commands(cmd); + sequencer_add_exec_commands(r, cmd); if (strbuf_read_file(buf, todo_file, 0) < 0) return error_errno(_("could not read '%s'."), todo_file); - if (parse_insn_buffer(buf->buf, &todo_list)) { + if (parse_insn_buffer(r, buf->buf, &todo_list)) { todo_list_release(&todo_list); return error(_("unusable todo list: '%s'"), todo_file); } @@@ -4924,7 -4867,7 +4927,7 @@@ return error(_("could not copy '%s' to '%s'."), todo_file, rebase_path_todo_backup()); - if (transform_todos(flags | TODO_LIST_SHORTEN_IDS)) + if (transform_todos(r, flags | TODO_LIST_SHORTEN_IDS)) return error(_("could not transform the todo list")); strbuf_reset(buf); @@@ -4948,24 -4891,24 +4951,24 @@@ todo_list_release(&todo_list); - if (check_todo_list()) { + if (check_todo_list(r)) { checkout_onto(opts, onto_name, onto, orig_head); return -1; } - if (transform_todos(flags & ~(TODO_LIST_SHORTEN_IDS))) + if (transform_todos(r, flags & ~(TODO_LIST_SHORTEN_IDS))) return error(_("could not transform the todo list")); - if (opts->allow_ff && skip_unnecessary_picks(&oid)) + if (opts->allow_ff && skip_unnecessary_picks(r, &oid)) return error(_("could not skip unnecessary pick commands")); if (checkout_onto(opts, onto_name, oid_to_hex(&oid), orig_head)) return -1; - if (require_clean_work_tree("rebase", "", 1, 1)) + if (require_clean_work_tree(r, "rebase", "", 1, 1)) return -1; - return sequencer_continue(opts); + return sequencer_continue(r, opts); } struct subject2item_entry { @@@ -4992,7 -4935,7 +4995,7 @@@ define_commit_slab(commit_todo_item, st * message will have to be retrieved from the commit (as the oneline in the * script cannot be trusted) in order to normalize the autosquash arrangement. */ -int rearrange_squash(void) +int rearrange_squash(struct repository *r) { const char *todo_file = rebase_path_todo(); struct todo_list todo_list = TODO_LIST_INIT; @@@ -5003,7 -4946,7 +5006,7 @@@ if (strbuf_read_file_or_whine(&todo_list.buf, todo_file) < 0) return -1; - if (parse_insn_buffer(todo_list.buf.buf, &todo_list) < 0) { + if (parse_insn_buffer(r, todo_list.buf.buf, &todo_list) < 0) { todo_list_release(&todo_list); return -1; } diff --combined sequencer.h index 5d7bc04751,729222b583..53b8679718 --- a/sequencer.h +++ b/sequencer.h @@@ -5,7 -5,6 +5,7 @@@ #include "strbuf.h" struct commit; +struct repository; const char *git_path_commit_editmsg(void); const char *git_path_seq_dir(void); @@@ -40,7 -39,7 +40,8 @@@ struct replay_opts int allow_empty_message; int keep_redundant_commits; int verbose; + int quiet; + int reschedule_failed_exec; int mainline; @@@ -76,10 -75,9 +77,10 @@@ int write_message(const void *buf, size /* Call this to setup defaults before parsing command line options */ void sequencer_init_config(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_pick_revisions(struct repository *repo, + struct replay_opts *opts); +int sequencer_continue(struct repository *repo, struct replay_opts *opts); +int sequencer_rollback(struct repository *repo, struct replay_opts *opts); int sequencer_remove_state(struct replay_opts *opts); #define TODO_LIST_KEEP_EMPTY (1U << 0) @@@ -92,19 -90,18 +93,19 @@@ * commits should be rebased onto the new base, this flag needs to be passed. */ #define TODO_LIST_REBASE_COUSINS (1U << 4) -int sequencer_make_script(FILE *out, int argc, const char **argv, +int sequencer_make_script(struct repository *repo, FILE *out, + int argc, const char **argv, unsigned flags); -int sequencer_add_exec_commands(const char *command); -int transform_todos(unsigned flags); +int sequencer_add_exec_commands(struct repository *r, const char *command); +int transform_todos(struct repository *r, unsigned flags); enum missing_commit_check_level get_missing_commit_check_level(void); -int check_todo_list(void); -int complete_action(struct replay_opts *opts, unsigned flags, +int check_todo_list(struct repository *r); +int complete_action(struct repository *r, struct replay_opts *opts, unsigned flags, const char *shortrevisions, const char *onto_name, const char *onto, const char *orig_head, const char *cmd, unsigned autosquash); -int rearrange_squash(void); +int rearrange_squash(struct repository *r); extern const char sign_off_header[]; @@@ -116,7 -113,7 +117,7 @@@ */ void append_signoff(struct strbuf *msgbuf, size_t ignore_footer, unsigned flag); -void append_conflicts_hint(struct strbuf *msgbuf); +void append_conflicts_hint(struct index_state *istate, struct strbuf *msgbuf); int message_is_empty(const struct strbuf *sb, enum commit_msg_cleanup_mode cleanup_mode); int template_untouched(const struct strbuf *sb, const char *template_file, @@@ -132,9 -129,7 +133,9 @@@ int prepare_branch_to_be_rebased(struc #define SUMMARY_INITIAL_COMMIT (1 << 0) #define SUMMARY_SHOW_AUTHOR_DATE (1 << 1) -void print_commit_summary(const char *prefix, const struct object_id *oid, +void print_commit_summary(struct repository *repo, + const char *prefix, + const struct object_id *oid, unsigned int flags); int read_author_script(const char *path, char **name, char **email, char **date,