[GSoC][PATCH v5 10/20] t3404: todo list with commented-out commands only aborts
If the todo list generated by `--make-script` is empty, complete_action() writes a noop, but if it has only commented-out commands, it will abort with the message "Nothing to do", and does not launch the editor. This adds a new test to ensure that complete_action() behaves this way. Signed-off-by: Alban Gruin --- No changes since v4. t/t3404-rebase-interactive.sh | 10 ++ 1 file changed, 10 insertions(+) diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh index 01616901bd..496d88d7d6 100755 --- a/t/t3404-rebase-interactive.sh +++ b/t/t3404-rebase-interactive.sh @@ -75,6 +75,16 @@ test_expect_success 'rebase --keep-empty' ' test_line_count = 6 actual ' +cat > expect <actual 2>&1 && + test_i18ncmp expect actual +' + test_expect_success 'rebase -i with the exec command' ' git checkout master && ( -- 2.18.0
[GSoC][PATCH v5 07/20] rebase -i: rewrite checkout_onto() in C
This rewrites checkout_onto() from shell to C. A new command (“checkout-onto”) is added to rebase--helper.c. The shell version is then stripped. Signed-off-by: Alban Gruin --- No changes since v4. builtin/rebase--helper.c | 7 ++- git-rebase--interactive.sh | 25 - sequencer.c| 19 +++ sequencer.h| 3 +++ 4 files changed, 32 insertions(+), 22 deletions(-) diff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c index 0e76dadba6..7d9426d23c 100644 --- a/builtin/rebase--helper.c +++ b/builtin/rebase--helper.c @@ -18,7 +18,8 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix) enum { CONTINUE = 1, ABORT, MAKE_SCRIPT, SHORTEN_OIDS, EXPAND_OIDS, CHECK_TODO_LIST, SKIP_UNNECESSARY_PICKS, REARRANGE_SQUASH, - ADD_EXEC, APPEND_TODO_HELP, EDIT_TODO, PREPARE_BRANCH + ADD_EXEC, APPEND_TODO_HELP, EDIT_TODO, PREPARE_BRANCH, + CHECKOUT_ONTO } command = 0; struct option options[] = { OPT_BOOL(0, "ff", &opts.allow_ff, N_("allow fast-forward")), @@ -54,6 +55,8 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix) EDIT_TODO), OPT_CMDMODE(0, "prepare-branch", &command, N_("prepare the branch to be rebased"), PREPARE_BRANCH), + OPT_CMDMODE(0, "checkout-onto", &command, + N_("checkout a commit"), CHECKOUT_ONTO), OPT_END() }; @@ -99,5 +102,7 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix) return !!edit_todo_list(flags); if (command == PREPARE_BRANCH && argc == 2) return !!prepare_branch_to_be_rebased(&opts, argv[1]); + if (command == CHECKOUT_ONTO && argc == 4) + return !!checkout_onto(&opts, argv[1], argv[2], argv[3]); usage_with_options(builtin_rebase_helper_usage, options); } diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh index 77e972bb6c..b68f108f28 100644 --- a/git-rebase--interactive.sh +++ b/git-rebase--interactive.sh @@ -28,17 +28,6 @@ case "$comment_char" in ;; esac -orig_reflog_action="$GIT_REFLOG_ACTION" - -comment_for_reflog () { - case "$orig_reflog_action" in - ''|rebase*) - GIT_REFLOG_ACTION="rebase -i ($1)" - export GIT_REFLOG_ACTION - ;; - esac -} - die_abort () { apply_autostash rm -rf "$state_dir" @@ -70,14 +59,6 @@ collapse_todo_ids() { git rebase--helper --shorten-ids } -# Switch to the branch in $into and notify it in the reflog -checkout_onto () { - comment_for_reflog start - GIT_REFLOG_ACTION="$GIT_REFLOG_ACTION: checkout $onto_name" - output git checkout $onto || die_abort "$(gettext "could not detach HEAD")" - git update-ref ORIG_HEAD $orig_head -} - get_missing_commit_check_level () { check_level=$(git config --get rebase.missingCommitsCheck) check_level=${check_level:-ignore} @@ -176,7 +157,8 @@ EOF git rebase--helper --check-todo-list || { ret=$? - checkout_onto + git rebase--helper --checkout-onto "$onto_name" "$onto" \ + "$orig_head" ${verbose:+--verbose} exit $ret } @@ -186,7 +168,8 @@ EOF onto="$(git rebase--helper --skip-unnecessary-picks)" || die "Could not skip unnecessary pick commands" - checkout_onto + git rebase--helper --checkout-onto "$onto_name" "$onto" "$orig_head" \ + ${verbose:+--verbose} require_clean_work_tree "rebase" exec git rebase--helper ${force_rebase:+--no-ff} $allow_empty_message \ --continue diff --git a/sequencer.c b/sequencer.c index 52949f38b3..4285247810 100644 --- a/sequencer.c +++ b/sequencer.c @@ -3171,6 +3171,25 @@ int prepare_branch_to_be_rebased(struct replay_opts *opts, const char *commit) return 0; } +int checkout_onto(struct replay_opts *opts, + const char *onto_name, const char *onto, + const char *orig_head) +{ + struct object_id oid; + const char *action = reflog_message(opts, "start", "checkout %s", onto_name); + + if (get_oid(orig_head, &oid)) + return error(_("%s: not a valid OID"), orig_head); + + if (run_git_checkout(opts, onto, action)) { + apply_autostash(opts); + sequencer_remove_state(opts); + return error(_("cou
[GSoC][PATCH v5 12/20] rebase -i: remove unused modes and functions
This removes the modes `--skip-unnecessary-picks`, `--append-todo-help`, and `--checkout-onto` from rebase--helper.c, the functions of git-rebase--interactive.sh that were rendered useless by the rewrite of complete_action(), and append_todo_help_to_file() from rebase-interactive.c. skip_unnecessary_picks() and checkout_onto() becomes static, as they are only used inside of the sequencer. Signed-off-by: Alban Gruin --- No changes since v4. builtin/rebase--helper.c | 23 ++ git-rebase--interactive.sh | 50 -- rebase-interactive.c | 22 - rebase-interactive.h | 1 - sequencer.c| 8 +++--- sequencer.h| 4 --- 6 files changed, 6 insertions(+), 102 deletions(-) diff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c index d7fa5a5062..6085527b2b 100644 --- a/builtin/rebase--helper.c +++ b/builtin/rebase--helper.c @@ -17,9 +17,8 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix) int abbreviate_commands = 0, rebase_cousins = -1; enum { CONTINUE = 1, ABORT, MAKE_SCRIPT, SHORTEN_OIDS, EXPAND_OIDS, - CHECK_TODO_LIST, SKIP_UNNECESSARY_PICKS, REARRANGE_SQUASH, - ADD_EXEC, APPEND_TODO_HELP, EDIT_TODO, PREPARE_BRANCH, - CHECKOUT_ONTO, COMPLETE_ACTION + CHECK_TODO_LIST, REARRANGE_SQUASH, ADD_EXEC, EDIT_TODO, PREPARE_BRANCH, + COMPLETE_ACTION } command = 0; struct option options[] = { OPT_BOOL(0, "ff", &opts.allow_ff, N_("allow fast-forward")), @@ -44,21 +43,15 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix) N_("expand commit ids in the todo list"), EXPAND_OIDS), 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_CMDMODE(0, "add-exec-commands", &command, N_("insert exec commands in todo list"), ADD_EXEC), - OPT_CMDMODE(0, "append-todo-help", &command, - N_("insert the help in the todo list"), APPEND_TODO_HELP), OPT_CMDMODE(0, "edit-todo", &command, N_("edit the todo list during an interactive rebase"), EDIT_TODO), OPT_CMDMODE(0, "prepare-branch", &command, N_("prepare the branch to be rebased"), PREPARE_BRANCH), - OPT_CMDMODE(0, "checkout-onto", &command, - N_("checkout a commit"), CHECKOUT_ONTO), OPT_CMDMODE(0, "complete-action", &command, N_("complete the action"), COMPLETE_ACTION), OPT_END() @@ -94,26 +87,14 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix) return !!transform_todos(flags); if (command == CHECK_TODO_LIST && argc == 1) return !!check_todo_list(); - if (command == SKIP_UNNECESSARY_PICKS && argc == 1) { - struct object_id oid; - int ret = skip_unnecessary_picks(&oid); - - if (!ret) - puts(oid_to_hex(&oid)); - return !!ret; - } if (command == REARRANGE_SQUASH && argc == 1) return !!rearrange_squash(); if (command == ADD_EXEC && argc == 2) return !!sequencer_add_exec_commands(argv[1]); - if (command == APPEND_TODO_HELP && argc == 1) - return !!append_todo_help_to_file(0, keep_empty); if (command == EDIT_TODO && argc == 1) return !!edit_todo_list(flags); if (command == PREPARE_BRANCH && argc == 2) return !!prepare_branch_to_be_rebased(&opts, argv[1]); - if (command == CHECKOUT_ONTO && argc == 4) - return !!checkout_onto(&opts, argv[1], argv[2], argv[3]); if (command == COMPLETE_ACTION && argc == 6) return !!complete_action(&opts, flags, argv[1], argv[2], argv[3], argv[4], argv[5], autosquash); diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh index 59dc4888a6..0d66c0f8b8 100644 --- a/git-rebase--interact
[GSoC][PATCH v5 11/20] rebase -i: rewrite complete_action() in C
This rewrites complete_action() from shell to C. A new mode is added to rebase--helper (`--complete-action`), as well as a new flag (`--autosquash`). Finally, complete_action() is stripped from git-rebase--interactive.sh. The original complete_action() would return the code 2 when the todo list contained no actions. This was a special case for rebase -i and -p; git-rebase.sh would then apply the autostash, delete the state directory, and die with the message "Nothing to do". This cleanup is rewritten in C instead of returning 2. As rebase -i no longer returns 2, the comment describing this behaviour in git-rebase.sh is updated to reflect this change. The first check might seem useless as we write "noop" to the todo list if it is empty. Actually, the todo list might contain commented commands (ie. empty commits). In this case, complete_action() won’t write "noop", and will abort without starting the editor. Signed-off-by: Alban Gruin --- No changes since v4. builtin/rebase--helper.c | 12 - git-rebase--interactive.sh | 53 ++-- git-rebase.sh | 2 +- sequencer.c| 99 ++ sequencer.h| 4 ++ 5 files changed, 118 insertions(+), 52 deletions(-) diff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c index bed3dd2b95..d7fa5a5062 100644 --- a/builtin/rebase--helper.c +++ b/builtin/rebase--helper.c @@ -13,13 +13,13 @@ static const char * const builtin_rebase_helper_usage[] = { int cmd_rebase__helper(int argc, const char **argv, const char *prefix) { struct replay_opts opts = REPLAY_OPTS_INIT; - unsigned flags = 0, keep_empty = 0, rebase_merges = 0; + unsigned flags = 0, keep_empty = 0, rebase_merges = 0, autosquash = 0; int abbreviate_commands = 0, rebase_cousins = -1; enum { CONTINUE = 1, ABORT, MAKE_SCRIPT, SHORTEN_OIDS, EXPAND_OIDS, CHECK_TODO_LIST, SKIP_UNNECESSARY_PICKS, REARRANGE_SQUASH, ADD_EXEC, APPEND_TODO_HELP, EDIT_TODO, PREPARE_BRANCH, - CHECKOUT_ONTO + CHECKOUT_ONTO, COMPLETE_ACTION } command = 0; struct option options[] = { OPT_BOOL(0, "ff", &opts.allow_ff, N_("allow fast-forward")), @@ -29,6 +29,8 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix) OPT_BOOL(0, "rebase-merges", &rebase_merges, N_("rebase merge commits")), OPT_BOOL(0, "rebase-cousins", &rebase_cousins, N_("keep original branch points of cousins")), + OPT_BOOL(0, "autosquash", &autosquash, +N_("move commits thas begin with squash!/fixup!")), OPT__VERBOSE(&opts.verbose, N_("be verbose")), OPT_CMDMODE(0, "continue", &command, N_("continue rebase"), CONTINUE), @@ -57,6 +59,8 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix) N_("prepare the branch to be rebased"), PREPARE_BRANCH), OPT_CMDMODE(0, "checkout-onto", &command, N_("checkout a commit"), CHECKOUT_ONTO), + OPT_CMDMODE(0, "complete-action", &command, + N_("complete the action"), COMPLETE_ACTION), OPT_END() }; @@ -110,5 +114,9 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix) return !!prepare_branch_to_be_rebased(&opts, argv[1]); if (command == CHECKOUT_ONTO && argc == 4) return !!checkout_onto(&opts, argv[1], argv[2], argv[3]); + if (command == COMPLETE_ACTION && argc == 6) + return !!complete_action(&opts, flags, argv[1], argv[2], argv[3], +argv[4], argv[5], autosquash); + usage_with_options(builtin_rebase_helper_usage, options); } diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh index b68f108f28..59dc4888a6 100644 --- a/git-rebase--interactive.sh +++ b/git-rebase--interactive.sh @@ -127,54 +127,6 @@ init_revisions_and_shortrevisions () { fi } -complete_action() { - test -s "$todo" || echo noop >> "$todo" - test -z "$autosquash" || git rebase--helper --rearrange-squash || exit - test -n "$cmd" && git rebase--helper --add-exec-commands "$cmd" - - todocount=$(git stripspace --strip-comments <"$todo" | wc -l) - todocount=${todocount##* } - -cat >>"$todo" <"$todo" || die "$(gettext "Could not generate todo list&q
[GSoC][PATCH v5 09/20] sequencer: change the way skip_unnecessary_picks() returns its result
Instead of skip_unnecessary_picks() printing its result to stdout, it returns it into a struct object_id, as the rewrite of complete_action() (to come in the next commit) will need it. rebase--helper then is modified to fit this change. Signed-off-by: Alban Gruin --- No changes since v4. builtin/rebase--helper.c | 10 -- sequencer.c | 13 ++--- sequencer.h | 2 +- 3 files changed, 15 insertions(+), 10 deletions(-) diff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c index 313092c465..bed3dd2b95 100644 --- a/builtin/rebase--helper.c +++ b/builtin/rebase--helper.c @@ -90,8 +90,14 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix) return !!transform_todos(flags); if (command == CHECK_TODO_LIST && argc == 1) return !!check_todo_list(); - if (command == SKIP_UNNECESSARY_PICKS && argc == 1) - return !!skip_unnecessary_picks(); + if (command == SKIP_UNNECESSARY_PICKS && argc == 1) { + struct object_id oid; + int ret = skip_unnecessary_picks(&oid); + + if (!ret) + puts(oid_to_hex(&oid)); + return !!ret; + } if (command == REARRANGE_SQUASH && argc == 1) return !!rearrange_squash(); if (command == ADD_EXEC && argc == 2) diff --git a/sequencer.c b/sequencer.c index 4285247810..a2e04b9eca 100644 --- a/sequencer.c +++ b/sequencer.c @@ -4420,17 +4420,17 @@ static int rewrite_file(const char *path, const char *buf, size_t len) } /* skip picking commits whose parents are unchanged */ -int skip_unnecessary_picks(void) +int skip_unnecessary_picks(struct object_id *output_oid) { const char *todo_file = rebase_path_todo(); struct strbuf buf = STRBUF_INIT; struct todo_list todo_list = TODO_LIST_INIT; - struct object_id onto_oid, *oid = &onto_oid, *parent_oid; + struct object_id *parent_oid; int fd, i; if (!read_oneliner(&buf, rebase_path_onto(), 0)) return error(_("could not read 'onto'")); - if (get_oid(buf.buf, &onto_oid)) { + if (get_oid(buf.buf, output_oid)) { strbuf_release(&buf); return error(_("need a HEAD to fixup")); } @@ -4460,9 +4460,9 @@ int skip_unnecessary_picks(void) if (item->commit->parents->next) break; /* merge commit */ parent_oid = &item->commit->parents->item->object.oid; - if (hashcmp(parent_oid->hash, oid->hash)) + if (hashcmp(parent_oid->hash, output_oid->hash)) break; - oid = &item->commit->object.oid; + oidcpy(output_oid, &item->commit->object.oid); } if (i > 0) { int offset = get_item_line_offset(&todo_list, i); @@ -4491,11 +4491,10 @@ int skip_unnecessary_picks(void) todo_list.current = i; if (is_fixup(peek_command(&todo_list, 0))) - record_in_rewritten(oid, peek_command(&todo_list, 0)); + record_in_rewritten(output_oid, peek_command(&todo_list, 0)); } todo_list_release(&todo_list); - printf("%s\n", oid_to_hex(oid)); return 0; } diff --git a/sequencer.h b/sequencer.h index 11a5334612..f11dabfd65 100644 --- a/sequencer.h +++ b/sequencer.h @@ -88,7 +88,7 @@ int sequencer_add_exec_commands(const char *command); int transform_todos(unsigned flags); enum missing_commit_check_level get_missing_commit_check_level(void); int check_todo_list(void); -int skip_unnecessary_picks(void); +int skip_unnecessary_picks(struct object_id *output_oid); int rearrange_squash(void); extern const char sign_off_header[]; -- 2.18.0
[GSoC][PATCH v5 01/20] sequencer: make two functions and an enum from sequencer.c public
This makes rebase_path_todo(), get_missing_commit_check_level() and the enum check_level accessible outside sequencer.c, renames check_level to missing_commit_check_level, and prefixes its value names by MISSING_COMMIT_ to avoid namespace pollution. This function and this enum will eventually be moved to rebase-interactive.c and become static again, so no special attention was given to the naming. This will be needed for the rewrite of append_todo_help() from shell to C, as it will be in a new library source file, rebase-interactive.c. Signed-off-by: Alban Gruin --- No changes since v4. sequencer.c | 22 +- sequencer.h | 8 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/sequencer.c b/sequencer.c index 16c1411054..8eff526584 100644 --- a/sequencer.c +++ b/sequencer.c @@ -52,7 +52,7 @@ static GIT_PATH_FUNC(rebase_path, "rebase-merge") * the lines are processed, they are removed from the front of this * file and written to the tail of 'done'. */ -static GIT_PATH_FUNC(rebase_path_todo, "rebase-merge/git-rebase-todo") +GIT_PATH_FUNC(rebase_path_todo, "rebase-merge/git-rebase-todo") /* * The rebase command lines that have already been processed. A line * is moved here when it is first handled, before any associated user @@ -4249,24 +4249,20 @@ int transform_todos(unsigned flags) return i; } -enum check_level { - CHECK_IGNORE = 0, CHECK_WARN, CHECK_ERROR -}; - -static enum check_level get_missing_commit_check_level(void) +enum missing_commit_check_level get_missing_commit_check_level(void) { const char *value; if (git_config_get_value("rebase.missingcommitscheck", &value) || !strcasecmp("ignore", value)) - return CHECK_IGNORE; + return MISSING_COMMIT_CHECK_IGNORE; if (!strcasecmp("warn", value)) - return CHECK_WARN; + return MISSING_COMMIT_CHECK_WARN; if (!strcasecmp("error", value)) - return CHECK_ERROR; + return MISSING_COMMIT_CHECK_ERROR; warning(_("unrecognized setting %s for option " "rebase.missingCommitsCheck. Ignoring."), value); - return CHECK_IGNORE; + return MISSING_COMMIT_CHECK_IGNORE; } define_commit_slab(commit_seen, unsigned char); @@ -4278,7 +4274,7 @@ define_commit_slab(commit_seen, unsigned char); */ int check_todo_list(void) { - enum check_level check_level = get_missing_commit_check_level(); + enum missing_commit_check_level check_level = get_missing_commit_check_level(); struct strbuf todo_file = STRBUF_INIT; struct todo_list todo_list = TODO_LIST_INIT; struct strbuf missing = STRBUF_INIT; @@ -4295,7 +4291,7 @@ int check_todo_list(void) advise_to_edit_todo = res = parse_insn_buffer(todo_list.buf.buf, &todo_list); - if (res || check_level == CHECK_IGNORE) + if (res || check_level == MISSING_COMMIT_CHECK_IGNORE) goto leave_check; /* Mark the commits in git-rebase-todo as seen */ @@ -4330,7 +4326,7 @@ int check_todo_list(void) if (!missing.len) goto leave_check; - if (check_level == CHECK_ERROR) + if (check_level == MISSING_COMMIT_CHECK_ERROR) advise_to_edit_todo = res = 1; fprintf(stderr, diff --git a/sequencer.h b/sequencer.h index c5787c6b56..ffab798f1e 100644 --- a/sequencer.h +++ b/sequencer.h @@ -3,6 +3,7 @@ const char *git_path_commit_editmsg(void); const char *git_path_seq_dir(void); +const char *rebase_path_todo(void); #define APPEND_SIGNOFF_DEDUP (1u << 0) @@ -57,6 +58,12 @@ struct replay_opts { }; #define REPLAY_OPTS_INIT { .action = -1, .current_fixups = STRBUF_INIT } +enum missing_commit_check_level { + MISSING_COMMIT_CHECK_IGNORE = 0, + MISSING_COMMIT_CHECK_WARN, + MISSING_COMMIT_CHECK_ERROR +}; + /* 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); @@ -79,6 +86,7 @@ int sequencer_make_script(FILE *out, int argc, const char **argv, int sequencer_add_exec_commands(const char *command); int transform_todos(unsigned flags); +enum missing_commit_check_level get_missing_commit_check_level(void); int check_todo_list(void); int skip_unnecessary_picks(void); int rearrange_squash(void); -- 2.18.0
[GSoC][PATCH v5 05/20] sequencer: add a new function to silence a command, except if it fails
This adds a new function, run_command_silent_on_success(), to redirect the stdout and stderr of a command to a strbuf, and then to run that command. This strbuf is printed only if the command fails. It is functionnaly similar to output() from git-rebase.sh. run_git_commit() is then refactored to use of run_command_silent_on_success(). Signed-off-by: Alban Gruin --- No changes since v4. sequencer.c | 51 +-- 1 file changed, 25 insertions(+), 26 deletions(-) diff --git a/sequencer.c b/sequencer.c index 8eff526584..6d87f5ae6a 100644 --- a/sequencer.c +++ b/sequencer.c @@ -769,6 +769,23 @@ N_("you have staged changes in your working tree\n" #define VERIFY_MSG (1<<4) #define CREATE_ROOT_COMMIT (1<<5) +static int run_command_silent_on_success(struct child_process *cmd) +{ + struct strbuf buf = STRBUF_INIT; + int rc; + + cmd->stdout_to_stderr = 1; + rc = pipe_command(cmd, + NULL, 0, + NULL, 0, + &buf, 0); + + if (rc) + fputs(buf.buf, stderr); + strbuf_release(&buf); + return rc; +} + /* * If we are cherry-pick, and if the merge did not result in * hand-editing, we will hit this commit and inherit the original @@ -823,18 +840,11 @@ static int run_git_commit(const char *defmsg, struct replay_opts *opts, cmd.git_cmd = 1; - if (is_rebase_i(opts)) { - if (!(flags & EDIT_MSG)) { - cmd.stdout_to_stderr = 1; - cmd.err = -1; - } - - if (read_env_script(&cmd.env_array)) { - const char *gpg_opt = gpg_sign_opt_quoted(opts); + if (is_rebase_i(opts) && read_env_script(&cmd.env_array)) { + const char *gpg_opt = gpg_sign_opt_quoted(opts); - return error(_(staged_changes_advice), -gpg_opt, gpg_opt); - } + return error(_(staged_changes_advice), +gpg_opt, gpg_opt); } argv_array_push(&cmd.args, "commit"); @@ -864,21 +874,10 @@ static int run_git_commit(const char *defmsg, struct replay_opts *opts, if (opts->allow_empty_message) argv_array_push(&cmd.args, "--allow-empty-message"); - if (cmd.err == -1) { - /* hide stderr on success */ - struct strbuf buf = STRBUF_INIT; - int rc = pipe_command(&cmd, - NULL, 0, - /* stdout is already redirected */ - NULL, 0, - &buf, 0); - if (rc) - fputs(buf.buf, stderr); - strbuf_release(&buf); - return rc; - } - - return run_command(&cmd); + if (is_rebase_i(opts) && !(flags & EDIT_MSG)) + return run_command_silent_on_success(&cmd); + else + return run_command(&cmd); } static int rest_is_empty(const struct strbuf *sb, int start) -- 2.18.0
[GSoC][PATCH v5 00/20] rebase -i: rewrite in C
This patch series rewrite the interactive rebase from shell to C. It is based on ffc6fa0e39 ("Fourth batch for 2.19 cycle", 2018-07-24). The v4 was based on b7bd9486 ("Third batch for 2.19 cycle", 2018-07-18). I wanted to make sure my series works well with 'bb/pedantic', 'jk/empty-pick-fix', and 'as/sequencer-customizable-comment-char', as they modified sequencer.c. Changes since v4: - [15/20] Add a newline char to $state_dir/quiet in write_basic_state(), even if $GIT_QUIET is not set - [20/20] Remove the declaration of cmd_rebase__helper() in builtin.h Alban Gruin (20): sequencer: make two functions and an enum from sequencer.c public rebase -i: rewrite append_todo_help() in C editor: add a function to launch the sequence editor rebase -i: rewrite the edit-todo functionality in C sequencer: add a new function to silence a command, except if it fails rebase -i: rewrite setup_reflog_action() in C rebase -i: rewrite checkout_onto() in C sequencer: refactor append_todo_help() to write its message to a buffer sequencer: change the way skip_unnecessary_picks() returns its result t3404: todo list with commented-out commands only aborts rebase -i: rewrite complete_action() in C rebase -i: remove unused modes and functions rebase -i: implement the logic to initialize $revisions in C rebase -i: rewrite the rest of init_revisions_and_shortrevisions() in C rebase -i: rewrite write_basic_state() in C rebase -i: rewrite init_basic_state() in C rebase -i: implement the main part of interactive rebase as a builtin rebase--interactive2: rewrite the submodes of interactive rebase in C rebase -i: remove git-rebase--interactive.sh rebase -i: move rebase--helper modes to rebase--interactive .gitignore | 1 - Makefile | 5 +- builtin.h | 2 +- builtin/rebase--helper.c | 88 -- builtin/rebase--interactive.c | 264 cache.h| 1 + editor.c | 27 ++- git-rebase--interactive.sh | 283 -- git-rebase--preserve-merges.sh | 10 +- git-rebase.sh | 47 - git.c | 2 +- rebase-interactive.c | 96 ++ rebase-interactive.h | 8 + sequencer.c| 311 +++-- sequencer.h| 19 +- strbuf.h | 2 + t/t3404-rebase-interactive.sh | 10 ++ 17 files changed, 729 insertions(+), 447 deletions(-) delete mode 100644 builtin/rebase--helper.c create mode 100644 builtin/rebase--interactive.c delete mode 100644 git-rebase--interactive.sh create mode 100644 rebase-interactive.c create mode 100644 rebase-interactive.h -- 2.18.0
[GSoC][PATCH v5 02/20] rebase -i: rewrite append_todo_help() in C
This rewrites append_todo_help() from shell to C. It also incorporates some parts of initiate_action() and complete_action() that also write help texts to the todo file. This also introduces the source file rebase-interactive.c. This file will contain functions necessary for interactive rebase that are too specific for the sequencer, and is part of libgit.a. Two flags are added to rebase--helper.c: one to call append_todo_help() (`--append-todo-help`), and another one to tell append_todo_help() to write the help text suited for the edit-todo mode (`--write-edit-todo`). Finally, append_todo_help() is removed from git-rebase--interactive.sh to use `rebase--helper --append-todo-help` instead. Signed-off-by: Alban Gruin --- No changes since v4. Makefile | 1 + builtin/rebase--helper.c | 11 -- git-rebase--interactive.sh | 52 ++--- rebase-interactive.c | 68 ++ rebase-interactive.h | 6 5 files changed, 86 insertions(+), 52 deletions(-) create mode 100644 rebase-interactive.c create mode 100644 rebase-interactive.h diff --git a/Makefile b/Makefile index 08e5c54549..909a687857 100644 --- a/Makefile +++ b/Makefile @@ -922,6 +922,7 @@ LIB_OBJS += protocol.o LIB_OBJS += quote.o LIB_OBJS += reachable.o LIB_OBJS += read-cache.o +LIB_OBJS += rebase-interactive.o LIB_OBJS += reflog-walk.o LIB_OBJS += refs.o LIB_OBJS += refs/files-backend.o diff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c index f7c2a5fdc8..05e73e71d4 100644 --- a/builtin/rebase--helper.c +++ b/builtin/rebase--helper.c @@ -3,6 +3,7 @@ #include "config.h" #include "parse-options.h" #include "sequencer.h" +#include "rebase-interactive.h" static const char * const builtin_rebase_helper_usage[] = { N_("git rebase--helper []"), @@ -12,12 +13,12 @@ static const char * const builtin_rebase_helper_usage[] = { int cmd_rebase__helper(int argc, const char **argv, const char *prefix) { struct replay_opts opts = REPLAY_OPTS_INIT; - unsigned flags = 0, keep_empty = 0, rebase_merges = 0; + unsigned flags = 0, keep_empty = 0, rebase_merges = 0, write_edit_todo = 0; int abbreviate_commands = 0, rebase_cousins = -1; enum { CONTINUE = 1, ABORT, MAKE_SCRIPT, SHORTEN_OIDS, EXPAND_OIDS, CHECK_TODO_LIST, SKIP_UNNECESSARY_PICKS, REARRANGE_SQUASH, - ADD_EXEC + ADD_EXEC, APPEND_TODO_HELP } command = 0; struct option options[] = { OPT_BOOL(0, "ff", &opts.allow_ff, N_("allow fast-forward")), @@ -27,6 +28,8 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix) OPT_BOOL(0, "rebase-merges", &rebase_merges, N_("rebase merge commits")), OPT_BOOL(0, "rebase-cousins", &rebase_cousins, N_("keep original branch points of cousins")), + OPT_BOOL(0, "write-edit-todo", &write_edit_todo, +N_("append the edit-todo message to the todo-list")), OPT_CMDMODE(0, "continue", &command, N_("continue rebase"), CONTINUE), OPT_CMDMODE(0, "abort", &command, N_("abort rebase"), @@ -45,6 +48,8 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix) N_("rearrange fixup/squash lines"), REARRANGE_SQUASH), OPT_CMDMODE(0, "add-exec-commands", &command, N_("insert exec commands in todo list"), ADD_EXEC), + OPT_CMDMODE(0, "append-todo-help", &command, + N_("insert the help in the todo list"), APPEND_TODO_HELP), OPT_END() }; @@ -84,5 +89,7 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix) return !!rearrange_squash(); if (command == ADD_EXEC && argc == 2) return !!sequencer_add_exec_commands(argv[1]); + if (command == APPEND_TODO_HELP && argc == 1) + return !!append_todo_help(write_edit_todo, keep_empty); usage_with_options(builtin_rebase_helper_usage, options); } diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh index 299ded2137..94c23a7af2 100644 --- a/git-rebase--interactive.sh +++ b/git-rebase--interactive.sh @@ -39,38 +39,6 @@ comment_for_reflog () { esac } -append_todo_help () { - gettext " -Commands: -p, pick = use commit -r, reword = use commit, but edit the commit message -e, edit = use commit, but stop for amending -s, squash = use commit, but meld into previous commit -f, fixup = like \"squash\&quo
[GSoC][PATCH v5 06/20] rebase -i: rewrite setup_reflog_action() in C
This rewrites (the misnamed) setup_reflog_action() from shell to C. The new version is called prepare_branch_to_be_rebased(). A new command is added to rebase--helper.c, “checkout-base”, as well as a new flag, “verbose”, to avoid silencing the output of the checkout operation called by checkout_base_commit(). The function `run_git_checkout()` will also be used in the next commit, therefore its code is not part of `checkout_base_commit()`. The shell version is then stripped in favour of a call to the helper. As $GIT_REFLOG_ACTION is no longer set at the first call of checkout_onto(), a call to comment_for_reflog() is added at the beginning of this function. Signed-off-by: Alban Gruin --- No changes since v4. builtin/rebase--helper.c | 7 ++- git-rebase--interactive.sh | 16 ++-- sequencer.c| 30 ++ sequencer.h| 2 ++ 4 files changed, 40 insertions(+), 15 deletions(-) diff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c index 731a64971d..0e76dadba6 100644 --- a/builtin/rebase--helper.c +++ b/builtin/rebase--helper.c @@ -18,7 +18,7 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix) enum { CONTINUE = 1, ABORT, MAKE_SCRIPT, SHORTEN_OIDS, EXPAND_OIDS, CHECK_TODO_LIST, SKIP_UNNECESSARY_PICKS, REARRANGE_SQUASH, - ADD_EXEC, APPEND_TODO_HELP, EDIT_TODO + ADD_EXEC, APPEND_TODO_HELP, EDIT_TODO, PREPARE_BRANCH } command = 0; struct option options[] = { OPT_BOOL(0, "ff", &opts.allow_ff, N_("allow fast-forward")), @@ -28,6 +28,7 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix) OPT_BOOL(0, "rebase-merges", &rebase_merges, N_("rebase merge commits")), OPT_BOOL(0, "rebase-cousins", &rebase_cousins, N_("keep original branch points of cousins")), + OPT__VERBOSE(&opts.verbose, N_("be verbose")), OPT_CMDMODE(0, "continue", &command, N_("continue rebase"), CONTINUE), OPT_CMDMODE(0, "abort", &command, N_("abort rebase"), @@ -51,6 +52,8 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix) OPT_CMDMODE(0, "edit-todo", &command, N_("edit the todo list during an interactive rebase"), EDIT_TODO), + OPT_CMDMODE(0, "prepare-branch", &command, + N_("prepare the branch to be rebased"), PREPARE_BRANCH), OPT_END() }; @@ -94,5 +97,7 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix) return !!append_todo_help(0, keep_empty); if (command == EDIT_TODO && argc == 1) return !!edit_todo_list(flags); + if (command == PREPARE_BRANCH && argc == 2) + return !!prepare_branch_to_be_rebased(&opts, argv[1]); usage_with_options(builtin_rebase_helper_usage, options); } diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh index 2defe607f4..77e972bb6c 100644 --- a/git-rebase--interactive.sh +++ b/git-rebase--interactive.sh @@ -72,6 +72,7 @@ collapse_todo_ids() { # Switch to the branch in $into and notify it in the reflog checkout_onto () { + comment_for_reflog start GIT_REFLOG_ACTION="$GIT_REFLOG_ACTION: checkout $onto_name" output git checkout $onto || die_abort "$(gettext "could not detach HEAD")" git update-ref ORIG_HEAD $orig_head @@ -119,19 +120,6 @@ initiate_action () { esac } -setup_reflog_action () { - comment_for_reflog start - - if test ! -z "$switch_to" - then - GIT_REFLOG_ACTION="$GIT_REFLOG_ACTION: checkout $switch_to" - output git checkout "$switch_to" -- || - die "$(eval_gettext "Could not checkout \$switch_to")" - - comment_for_reflog start - fi -} - init_basic_state () { orig_head=$(git rev-parse --verify HEAD) || die "$(gettext "No HEAD?")" mkdir -p "$state_dir" || die "$(eval_gettext "Could not create temporary \$state_dir")" @@ -211,7 +199,7 @@ git_rebase__interactive () { return 0 fi - setup_reflog_action + git rebase--helper --prepare-branch "$switch_to" ${verbose:+--verbose} init_basic_state init_revisions_and_shortrevisions diff --git a/sequencer.c b/sequencer.c index 6d87f5ae6a..52949f38b3 100644 --- a/sequencer.c +++ b/sequencer.c @@ -3141,6 +31
[GSoC][PATCH v5 04/20] rebase -i: rewrite the edit-todo functionality in C
This rewrites the edit-todo functionality from shell to C. To achieve that, a new command mode, `edit-todo`, is added, and the `write-edit-todo` flag is removed, as the shell script does not need to write the edit todo help message to the todo list anymore. The shell version is then stripped in favour of a call to the helper. Signed-off-by: Alban Gruin --- No changes since v4. builtin/rebase--helper.c | 13 - git-rebase--interactive.sh | 11 +-- rebase-interactive.c | 31 +++ rebase-interactive.h | 1 + 4 files changed, 41 insertions(+), 15 deletions(-) diff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c index 05e73e71d4..731a64971d 100644 --- a/builtin/rebase--helper.c +++ b/builtin/rebase--helper.c @@ -13,12 +13,12 @@ static const char * const builtin_rebase_helper_usage[] = { int cmd_rebase__helper(int argc, const char **argv, const char *prefix) { struct replay_opts opts = REPLAY_OPTS_INIT; - unsigned flags = 0, keep_empty = 0, rebase_merges = 0, write_edit_todo = 0; + unsigned flags = 0, keep_empty = 0, rebase_merges = 0; int abbreviate_commands = 0, rebase_cousins = -1; enum { CONTINUE = 1, ABORT, MAKE_SCRIPT, SHORTEN_OIDS, EXPAND_OIDS, CHECK_TODO_LIST, SKIP_UNNECESSARY_PICKS, REARRANGE_SQUASH, - ADD_EXEC, APPEND_TODO_HELP + ADD_EXEC, APPEND_TODO_HELP, EDIT_TODO } command = 0; struct option options[] = { OPT_BOOL(0, "ff", &opts.allow_ff, N_("allow fast-forward")), @@ -28,8 +28,6 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix) OPT_BOOL(0, "rebase-merges", &rebase_merges, N_("rebase merge commits")), OPT_BOOL(0, "rebase-cousins", &rebase_cousins, N_("keep original branch points of cousins")), - OPT_BOOL(0, "write-edit-todo", &write_edit_todo, -N_("append the edit-todo message to the todo-list")), OPT_CMDMODE(0, "continue", &command, N_("continue rebase"), CONTINUE), OPT_CMDMODE(0, "abort", &command, N_("abort rebase"), @@ -50,6 +48,9 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix) N_("insert exec commands in todo list"), ADD_EXEC), OPT_CMDMODE(0, "append-todo-help", &command, N_("insert the help in the todo list"), APPEND_TODO_HELP), + OPT_CMDMODE(0, "edit-todo", &command, + N_("edit the todo list during an interactive rebase"), + EDIT_TODO), OPT_END() }; @@ -90,6 +91,8 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix) if (command == ADD_EXEC && argc == 2) return !!sequencer_add_exec_commands(argv[1]); if (command == APPEND_TODO_HELP && argc == 1) - return !!append_todo_help(write_edit_todo, keep_empty); + return !!append_todo_help(0, keep_empty); + if (command == EDIT_TODO && argc == 1) + return !!edit_todo_list(flags); usage_with_options(builtin_rebase_helper_usage, options); } diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh index 94c23a7af2..2defe607f4 100644 --- a/git-rebase--interactive.sh +++ b/git-rebase--interactive.sh @@ -108,16 +108,7 @@ initiate_action () { --continue ;; edit-todo) - git stripspace --strip-comments <"$todo" >"$todo".new - mv -f "$todo".new "$todo" - collapse_todo_ids - git rebase--helper --append-todo-help --write-edit-todo - - git_sequence_editor "$todo" || - die "$(gettext "Could not execute editor")" - expand_todo_ids - - exit + exec git rebase--helper --edit-todo ;; show-current-patch) exec git show REBASE_HEAD -- diff --git a/rebase-interactive.c b/rebase-interactive.c index d7996bc8d9..403ecbf3c9 100644 --- a/rebase-interactive.c +++ b/rebase-interactive.c @@ -66,3 +66,34 @@ int append_todo_help(unsigned edit_todo, unsigned keep_empty) return ret; } + +int edit_todo_list(unsigned flags) +{ + struct strbuf buf = STRBUF_INIT; + const char *todo_file = rebase_path_todo(); + FILE *todo; + + if (strbuf_read_file(&buf, todo_file, 0) < 0) + return error_errno(_("could not read '
[GSoC][PATCH v5 03/20] editor: add a function to launch the sequence editor
As part of the rewrite of interactive rebase, the sequencer will need to open the sequence editor to allow the user to edit the todo list. Instead of duplicating the existing launch_editor() function, this refactors it to a new function, launch_specified_editor(), which takes the editor as a parameter, in addition to the path, the buffer and the environment variables. launch_sequence_editor() is then added to launch the sequence editor. Signed-off-by: Alban Gruin --- No changes since v4. cache.h | 1 + editor.c | 27 +-- strbuf.h | 2 ++ 3 files changed, 28 insertions(+), 2 deletions(-) diff --git a/cache.h b/cache.h index 8b447652a7..d70ae49ca2 100644 --- a/cache.h +++ b/cache.h @@ -1409,6 +1409,7 @@ extern const char *fmt_name(const char *name, const char *email); extern const char *ident_default_name(void); extern const char *ident_default_email(void); extern const char *git_editor(void); +extern const char *git_sequence_editor(void); extern const char *git_pager(int stdout_is_tty); extern int is_terminal_dumb(void); extern int git_ident_config(const char *, const char *, void *); diff --git a/editor.c b/editor.c index 9a9b4e12d1..c985eee1f9 100644 --- a/editor.c +++ b/editor.c @@ -1,4 +1,5 @@ #include "cache.h" +#include "config.h" #include "strbuf.h" #include "run-command.h" #include "sigchain.h" @@ -34,10 +35,21 @@ const char *git_editor(void) return editor; } -int launch_editor(const char *path, struct strbuf *buffer, const char *const *env) +const char *git_sequence_editor(void) { - const char *editor = git_editor(); + const char *editor = getenv("GIT_SEQUENCE_EDITOR"); + + if (!editor) + git_config_get_string_const("sequence.editor", &editor); + if (!editor) + editor = git_editor(); + return editor; +} + +static int launch_specified_editor(const char *editor, const char *path, + struct strbuf *buffer, const char *const *env) +{ if (!editor) return error("Terminal is dumb, but EDITOR unset"); @@ -95,3 +107,14 @@ int launch_editor(const char *path, struct strbuf *buffer, const char *const *en return error_errno("could not read file '%s'", path); return 0; } + +int launch_editor(const char *path, struct strbuf *buffer, const char *const *env) +{ + return launch_specified_editor(git_editor(), path, buffer, env); +} + +int launch_sequence_editor(const char *path, struct strbuf *buffer, + const char *const *env) +{ + return launch_specified_editor(git_sequence_editor(), path, buffer, env); +} diff --git a/strbuf.h b/strbuf.h index 60a35aef16..66da9822fd 100644 --- a/strbuf.h +++ b/strbuf.h @@ -575,6 +575,8 @@ extern void strbuf_add_unique_abbrev(struct strbuf *sb, * file's contents are not read into the buffer upon completion. */ extern int launch_editor(const char *path, struct strbuf *buffer, const char *const *env); +extern int launch_sequence_editor(const char *path, struct strbuf *buffer, + const char *const *env); extern void strbuf_add_lines(struct strbuf *sb, const char *prefix, const char *buf, size_t size); -- 2.18.0
Re: [GSoC][PATCH v4] fixup! rebase -i: rewrite write_basic_state() in C
Hi Junio, Le 31/07/2018 à 17:23, Junio C Hamano a écrit : > Alban Gruin writes: > >> As pointed out by SZEDER Gábor, git-rebase.sh wrote to to 'quiet' with >> an `echo`: >> >> echo "$GIT_QUIET" > "$state_dir/quiet" >> >> This mean that even if $GIT_QUIET is empty, a newline is written to >> quiet. The rewrite of write_basic_state() changed this behaviour, which >> could lead to problems. This patch changes the rewritten version to >> behave like the shell version. >> >> Signed-off-by: Alban Gruin >> --- >> Hi Junio, could you apply this patch on top of ag/rebase-i-in-c, please? > > Hmph, from reading your other message > > https://public-inbox.org/git/dce8c99b-51e9-4ed1-8ae4-28049cb6e...@gmail.com/ > > I got an impression that a rerolled version is coming anyway. Is > this fix so urgent that it needs tobe squashed in in the meantime > and cannot wait? > I wanted to reroll it first, but the only changes would have been this fix and Ramsay’s patch. I was advised to send a fixup! patch instead. I can send a reroll if you want, but it won’t have any more changes. Cheers, Alban >> >> sequencer.c | 2 +- >> 1 file changed, 1 insertion(+), 1 deletion(-) >> >> diff --git a/sequencer.c b/sequencer.c >> index d257903db0..0d41e82953 100644 >> --- a/sequencer.c >> +++ b/sequencer.c >> @@ -2332,7 +2332,7 @@ int write_basic_state(struct replay_opts *opts, const >> char *head_name, >> if (quiet) >> write_file(rebase_path_quiet(), "%s\n", quiet); >> else >> -write_file(rebase_path_quiet(), ""); >> +write_file(rebase_path_quiet(), "\n"); >> >> if (opts->verbose) >> write_file(rebase_path_verbose(), "");
[GSoC][PATCH v4] fixup! rebase -i: rewrite write_basic_state() in C
As pointed out by SZEDER Gábor, git-rebase.sh wrote to to 'quiet' with an `echo`: echo "$GIT_QUIET" > "$state_dir/quiet" This mean that even if $GIT_QUIET is empty, a newline is written to quiet. The rewrite of write_basic_state() changed this behaviour, which could lead to problems. This patch changes the rewritten version to behave like the shell version. Signed-off-by: Alban Gruin --- Hi Junio, could you apply this patch on top of ag/rebase-i-in-c, please? sequencer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sequencer.c b/sequencer.c index d257903db0..0d41e82953 100644 --- a/sequencer.c +++ b/sequencer.c @@ -2332,7 +2332,7 @@ int write_basic_state(struct replay_opts *opts, const char *head_name, if (quiet) write_file(rebase_path_quiet(), "%s\n", quiet); else - write_file(rebase_path_quiet(), ""); + write_file(rebase_path_quiet(), "\n"); if (opts->verbose) write_file(rebase_path_verbose(), ""); -- 2.18.0
Re: [GSoC][PATCH v4 15/20] rebase -i: rewrite write_basic_state() in C
Hi, Le 30/07/2018 à 20:25, SZEDER Gábor a écrit : >> diff --git a/sequencer.c b/sequencer.c >> index 1c035ceec7..d257903db0 100644 >> --- a/sequencer.c >> +++ b/sequencer.c > >> +int write_basic_state(struct replay_opts *opts, const char *head_name, >> + const char *onto, const char *orig_head) >> +{ >> +const char *quiet = getenv("GIT_QUIET"); >> + >> +if (head_name) >> +write_file(rebase_path_head_name(), "%s\n", head_name); >> +if (onto) >> +write_file(rebase_path_onto(), "%s\n", onto); >> +if (orig_head) >> +write_file(rebase_path_orig_head(), "%s\n", orig_head); >> + >> +if (quiet) >> +write_file(rebase_path_quiet(), "%s\n", quiet); >> +else >> +write_file(rebase_path_quiet(), ""); > > This is not a faithful conversion of the original. git-rebase.sh writes > this 'quiet' file with: > > echo "$GIT_QUIET" > "$state_dir"/quiet > > which means that a single newline character was written even when > $GIT_QUIET was unset/empty. > > I seem to recall a case in the past, when a shell-to-C conversion > accidentally dropped a newline from a similar state-file, which then > caused some issues later on. But I don't remember the specifics and a > quick search didn't turn up anything relevant either... > I don’t think it’s a problem here, but we’re better safe than sorry. I’ll send a fix soon. Cheers, Alban
Re: [PATCH] builtin.h: remove declaration of cmd_rebase__helper
Hi Ramsay, Le 30/07/2018 à 00:44, Ramsay Jones a écrit : > > Commit 94d4e2fb88 ("rebase -i: move rebase--helper modes to > rebase--interactive", 2018-07-24) removed the definition of the > 'cmd_rebase__helper' symbol, but forgot to remove the corresponding > declaration in the 'builtin.h' header file. > > Signed-off-by: Ramsay Jones > --- > > Hi Alban, > > If you need to re-roll your 'ag/rebase-i-in-c' branch, could you > please squash this into the relevant patch (commit 94d4e2fb88). > > Thanks! > > ATB, > Ramsay Jones > > builtin.h | 1 - > 1 file changed, 1 deletion(-) > > diff --git a/builtin.h b/builtin.h > index aac8f5f340..6538932e99 100644 > --- a/builtin.h > +++ b/builtin.h > @@ -206,7 +206,6 @@ extern int cmd_range_diff(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(int argc, const char **argv, const char *prefix); > extern int cmd_rebase__interactive(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); > Thank you for pointing this out! I will include it in my next reroll. Cheers, Alban
[GSoC] GSoC with git, week 12
Hi, I published a new blog post here: https://blog.pa1ch.fr/posts/2018/07/24/en/gsoc2018-week12.html Cheers, Alban
[GSoC][PATCH v4 18/20] rebase--interactive2: rewrite the submodes of interactive rebase in C
This rewrites the submodes of interactive rebase (`--continue`, `--skip`, `--edit-todo`, and `--show-current-patch`) in C. git-rebase.sh is then modified to call directly git-rebase--interactive2 instead of git-rebase--interactive.sh. Signed-off-by: Alban Gruin --- builtin/rebase--interactive2.c | 47 +++--- git-rebase.sh | 45 +--- 2 files changed, 84 insertions(+), 8 deletions(-) diff --git a/builtin/rebase--interactive2.c b/builtin/rebase--interactive2.c index e89ef71499..53b4f7483d 100644 --- a/builtin/rebase--interactive2.c +++ b/builtin/rebase--interactive2.c @@ -134,11 +134,14 @@ int cmd_rebase__interactive(int argc, const char **argv, const char *prefix) { struct replay_opts opts = REPLAY_OPTS_INIT; unsigned flags = 0, keep_empty = 0, rebase_merges = 0, autosquash = 0; - int abbreviate_commands = 0, rebase_cousins = -1; + int abbreviate_commands = 0, rebase_cousins = -1, ret = 0; const char *onto = NULL, *onto_name = NULL, *restrict_revision = NULL, *squash_onto = NULL, *upstream = NULL, *head_name = NULL, *switch_to = NULL, *cmd = NULL; char *raw_strategies = NULL; + enum { + NONE = 0, CONTINUE, SKIP, EDIT_TODO, SHOW_CURRENT_PATCH + } 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")), @@ -151,6 +154,13 @@ int cmd_rebase__interactive(int argc, const char **argv, const char *prefix) N_("move commits that begin with squash!/fixup!")), OPT_BOOL(0, "signoff", &opts.signoff, N_("sign commits")), OPT__VERBOSE(&opts.verbose, N_("be verbose")), + OPT_CMDMODE(0, "continue", &command, N_("continue rebase"), + CONTINUE), + OPT_CMDMODE(0, "skip", &command, N_("skip commit"), SKIP), + OPT_CMDMODE(0, "edit-todo", &command, N_("edit the todo list"), + EDIT_TODO), + OPT_CMDMODE(0, "show-current-patch", &command, N_("show the current patch"), + SHOW_CURRENT_PATCH), OPT_STRING(0, "onto", &onto, N_("onto"), N_("onto")), OPT_STRING(0, "restrict-revision", &restrict_revision, N_("restrict-revision"), N_("restrict revision")), @@ -194,7 +204,36 @@ int cmd_rebase__interactive(int argc, const char **argv, const char *prefix) warning(_("--[no-]rebase-cousins has no effect without " "--rebase-merges")); - return !!do_interactive_rebase(&opts, flags, switch_to, upstream, onto, - onto_name, squash_onto, head_name, restrict_revision, - raw_strategies, cmd, autosquash); + switch (command) { + case NONE: + ret = do_interactive_rebase(&opts, flags, switch_to, upstream, onto, + onto_name, squash_onto, head_name, restrict_revision, + raw_strategies, cmd, autosquash); + break; + case SKIP: { + struct string_list merge_rr = STRING_LIST_INIT_DUP; + + rerere_clear(&merge_rr); + /* fallthrough */ + case CONTINUE: + ret = sequencer_continue(&opts); + break; + } + case EDIT_TODO: + ret = edit_todo_list(flags); + break; + case SHOW_CURRENT_PATCH: { + struct child_process cmd = CHILD_PROCESS_INIT; + + cmd.git_cmd = 1; + argv_array_pushl(&cmd.args, "show", "REBASE_HEAD", "--", NULL); + ret = run_command(&cmd); + + break; + } + default: + BUG("invalid command '%d'", command); + } + + return !!ret; } diff --git a/git-rebase.sh b/git-rebase.sh index 86da3816be..65e909d7bd 100755 --- a/git-rebase.sh +++ b/git-rebase.sh @@ -200,19 +200,56 @@ finish_rebase () { rm -rf "$state_dir" } +run_interactive () { + GIT_CHERRY_PICK_HELP="$resolvemsg" + export GIT_CHERRY_PICK_HELP + + test -n "$keep_empty" && keep_empty="--keep-empty" + test -n "$rebase_merges" && rebase_merges="--rebase-merges" + test -n "$rebase_cousins&
[GSoC][PATCH v4 20/20] rebase -i: move rebase--helper modes to rebase--interactive
This moves the rebase--helper modes still used by git-rebase--preserve-merges.sh (`--shorten-ids`, `--expand-ids`, `--check-todo-list`, `--rearrange-squash` and `--add-exec-commands`) to rebase--interactive.c. git-rebase--preserve-merges.sh is modified accordingly, and rebase--helper.c is removed as it is useless now. Signed-off-by: Alban Gruin --- .gitignore | 1 - Makefile | 1 - builtin/rebase--helper.c | 226 - builtin/rebase--interactive.c | 27 +++- git-rebase--preserve-merges.sh | 10 +- git.c | 1 - 6 files changed, 31 insertions(+), 235 deletions(-) delete mode 100644 builtin/rebase--helper.c diff --git a/.gitignore b/.gitignore index 3284a1e9b1..406f26d050 100644 --- a/.gitignore +++ b/.gitignore @@ -116,7 +116,6 @@ /git-read-tree /git-rebase /git-rebase--am -/git-rebase--helper /git-rebase--interactive /git-rebase--merge /git-rebase--preserve-merges diff --git a/Makefile b/Makefile index 584834726d..ca3a0888dd 100644 --- a/Makefile +++ b/Makefile @@ -1059,7 +1059,6 @@ 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/rebase--interactive.o BUILTIN_OBJS += builtin/receive-pack.o BUILTIN_OBJS += builtin/reflog.o diff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c deleted file mode 100644 index ac21e8e06e..00 --- a/builtin/rebase--helper.c +++ /dev/null @@ -1,226 +0,0 @@ -#include "builtin.h" -#include "cache.h" -#include "config.h" -#include "parse-options.h" -#include "sequencer.h" -#include "rebase-interactive.h" -#include "argv-array.h" -#include "refs.h" -#include "rerere.h" -#include "alias.h" - -static GIT_PATH_FUNC(path_state_dir, "rebase-merge/") -static GIT_PATH_FUNC(path_squash_onto, "rebase-merge/squash-onto") -static GIT_PATH_FUNC(path_interactive, "rebase-merge/interactive") - -static int get_revision_ranges(const char *upstream, const char *onto, - const char **head_hash, - char **revisions, char **shortrevisions) -{ - const char *base_rev = upstream ? upstream : onto; - struct object_id orig_head; - - if (get_oid("HEAD", &orig_head)) - return error(_("no HEAD?")); - - *head_hash = find_unique_abbrev(&orig_head, GIT_MAX_HEXSZ); - - if (revisions) - *revisions = xstrfmt("%s...%s", base_rev, *head_hash); - if (shortrevisions) { - const char *shorthead; - - shorthead = find_unique_abbrev(&orig_head, DEFAULT_ABBREV); - - if (upstream) { - const char *shortrev; - struct object_id rev_oid; - - get_oid(base_rev, &rev_oid); - shortrev = find_unique_abbrev(&rev_oid, DEFAULT_ABBREV); - - *shortrevisions = xstrfmt("%s..%s", shortrev, shorthead); - } else - *shortrevisions = xstrdup(shorthead); - } - - return 0; -} - -static int init_basic_state(struct replay_opts *opts, const char *head_name, - const char *onto, const char *orig_head) -{ - FILE *interactive; - - if (!is_directory(path_state_dir()) && mkdir_in_gitdir(path_state_dir())) - return error_errno(_("could not create temporary %s"), path_state_dir()); - - delete_reflog("REBASE_HEAD"); - - interactive = fopen(path_interactive(), "w"); - if (!interactive) - return error_errno(_("could not mark as interactive")); - fclose(interactive); - - return write_basic_state(opts, head_name, onto, orig_head); -} - -static const char * const builtin_rebase_helper_usage[] = { - N_("git rebase--helper []"), - NULL -}; - -int cmd_rebase__helper(int argc, const char **argv, const char *prefix) -{ - struct replay_opts opts = REPLAY_OPTS_INIT; - unsigned flags = 0, keep_empty = 0, rebase_merges = 0, autosquash = 0; - int abbreviate_commands = 0, rebase_cousins = -1, ret; - const char *head_hash = NULL, *onto = NULL, *restrict_revision = NULL, - *squash_onto = NULL, *upstream = NULL, *head_name = NULL; - char *raw_strategies = NULL; - enum { - CONTINUE = 1, ABORT, MAKE_SCRIPT, SHORTEN_OIDS, EXPAND_OIDS, - CHECK_TODO_LIST, REARRANGE_SQUASH, ADD_EXEC, EDIT_TODO, PREPARE_BRANCH, - COMPLETE_ACTION, INIT_BASIC_STATE - } command = 0; - struct option options[] = { - OPT_BOOL(0, "ff
[GSoC][PATCH v4 07/20] rebase -i: rewrite checkout_onto() in C
This rewrites checkout_onto() from shell to C. A new command (“checkout-onto”) is added to rebase--helper.c. The shell version is then stripped. Signed-off-by: Alban Gruin --- No changes since v3. builtin/rebase--helper.c | 7 ++- git-rebase--interactive.sh | 25 - sequencer.c| 19 +++ sequencer.h| 3 +++ 4 files changed, 32 insertions(+), 22 deletions(-) diff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c index 0e76dadba6..7d9426d23c 100644 --- a/builtin/rebase--helper.c +++ b/builtin/rebase--helper.c @@ -18,7 +18,8 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix) enum { CONTINUE = 1, ABORT, MAKE_SCRIPT, SHORTEN_OIDS, EXPAND_OIDS, CHECK_TODO_LIST, SKIP_UNNECESSARY_PICKS, REARRANGE_SQUASH, - ADD_EXEC, APPEND_TODO_HELP, EDIT_TODO, PREPARE_BRANCH + ADD_EXEC, APPEND_TODO_HELP, EDIT_TODO, PREPARE_BRANCH, + CHECKOUT_ONTO } command = 0; struct option options[] = { OPT_BOOL(0, "ff", &opts.allow_ff, N_("allow fast-forward")), @@ -54,6 +55,8 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix) EDIT_TODO), OPT_CMDMODE(0, "prepare-branch", &command, N_("prepare the branch to be rebased"), PREPARE_BRANCH), + OPT_CMDMODE(0, "checkout-onto", &command, + N_("checkout a commit"), CHECKOUT_ONTO), OPT_END() }; @@ -99,5 +102,7 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix) return !!edit_todo_list(flags); if (command == PREPARE_BRANCH && argc == 2) return !!prepare_branch_to_be_rebased(&opts, argv[1]); + if (command == CHECKOUT_ONTO && argc == 4) + return !!checkout_onto(&opts, argv[1], argv[2], argv[3]); usage_with_options(builtin_rebase_helper_usage, options); } diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh index 77e972bb6c..b68f108f28 100644 --- a/git-rebase--interactive.sh +++ b/git-rebase--interactive.sh @@ -28,17 +28,6 @@ case "$comment_char" in ;; esac -orig_reflog_action="$GIT_REFLOG_ACTION" - -comment_for_reflog () { - case "$orig_reflog_action" in - ''|rebase*) - GIT_REFLOG_ACTION="rebase -i ($1)" - export GIT_REFLOG_ACTION - ;; - esac -} - die_abort () { apply_autostash rm -rf "$state_dir" @@ -70,14 +59,6 @@ collapse_todo_ids() { git rebase--helper --shorten-ids } -# Switch to the branch in $into and notify it in the reflog -checkout_onto () { - comment_for_reflog start - GIT_REFLOG_ACTION="$GIT_REFLOG_ACTION: checkout $onto_name" - output git checkout $onto || die_abort "$(gettext "could not detach HEAD")" - git update-ref ORIG_HEAD $orig_head -} - get_missing_commit_check_level () { check_level=$(git config --get rebase.missingCommitsCheck) check_level=${check_level:-ignore} @@ -176,7 +157,8 @@ EOF git rebase--helper --check-todo-list || { ret=$? - checkout_onto + git rebase--helper --checkout-onto "$onto_name" "$onto" \ + "$orig_head" ${verbose:+--verbose} exit $ret } @@ -186,7 +168,8 @@ EOF onto="$(git rebase--helper --skip-unnecessary-picks)" || die "Could not skip unnecessary pick commands" - checkout_onto + git rebase--helper --checkout-onto "$onto_name" "$onto" "$orig_head" \ + ${verbose:+--verbose} require_clean_work_tree "rebase" exec git rebase--helper ${force_rebase:+--no-ff} $allow_empty_message \ --continue diff --git a/sequencer.c b/sequencer.c index 0bc53e009e..c7d01d60b3 100644 --- a/sequencer.c +++ b/sequencer.c @@ -3169,6 +3169,25 @@ int prepare_branch_to_be_rebased(struct replay_opts *opts, const char *commit) return 0; } +int checkout_onto(struct replay_opts *opts, + const char *onto_name, const char *onto, + const char *orig_head) +{ + struct object_id oid; + const char *action = reflog_message(opts, "start", "checkout %s", onto_name); + + if (get_oid(orig_head, &oid)) + return error(_("%s: not a valid OID"), orig_head); + + if (run_git_checkout(opts, onto, action)) { + apply_autostash(opts); + sequencer_remove_state(opts); + return error(_("cou
[GSoC][PATCH v4 06/20] rebase -i: rewrite setup_reflog_action() in C
This rewrites (the misnamed) setup_reflog_action() from shell to C. The new version is called prepare_branch_to_be_rebased(). A new command is added to rebase--helper.c, “checkout-base”, as well as a new flag, “verbose”, to avoid silencing the output of the checkout operation called by checkout_base_commit(). The function `run_git_checkout()` will also be used in the next commit, therefore its code is not part of `checkout_base_commit()`. The shell version is then stripped in favour of a call to the helper. As $GIT_REFLOG_ACTION is no longer set at the first call of checkout_onto(), a call to comment_for_reflog() is added at the beginning of this function. Signed-off-by: Alban Gruin --- Dropped the `verbose` variable. builtin/rebase--helper.c | 7 ++- git-rebase--interactive.sh | 16 ++-- sequencer.c| 30 ++ sequencer.h| 2 ++ 4 files changed, 40 insertions(+), 15 deletions(-) diff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c index 731a64971d..0e76dadba6 100644 --- a/builtin/rebase--helper.c +++ b/builtin/rebase--helper.c @@ -18,7 +18,7 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix) enum { CONTINUE = 1, ABORT, MAKE_SCRIPT, SHORTEN_OIDS, EXPAND_OIDS, CHECK_TODO_LIST, SKIP_UNNECESSARY_PICKS, REARRANGE_SQUASH, - ADD_EXEC, APPEND_TODO_HELP, EDIT_TODO + ADD_EXEC, APPEND_TODO_HELP, EDIT_TODO, PREPARE_BRANCH } command = 0; struct option options[] = { OPT_BOOL(0, "ff", &opts.allow_ff, N_("allow fast-forward")), @@ -28,6 +28,7 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix) OPT_BOOL(0, "rebase-merges", &rebase_merges, N_("rebase merge commits")), OPT_BOOL(0, "rebase-cousins", &rebase_cousins, N_("keep original branch points of cousins")), + OPT__VERBOSE(&opts.verbose, N_("be verbose")), OPT_CMDMODE(0, "continue", &command, N_("continue rebase"), CONTINUE), OPT_CMDMODE(0, "abort", &command, N_("abort rebase"), @@ -51,6 +52,8 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix) OPT_CMDMODE(0, "edit-todo", &command, N_("edit the todo list during an interactive rebase"), EDIT_TODO), + OPT_CMDMODE(0, "prepare-branch", &command, + N_("prepare the branch to be rebased"), PREPARE_BRANCH), OPT_END() }; @@ -94,5 +97,7 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix) return !!append_todo_help(0, keep_empty); if (command == EDIT_TODO && argc == 1) return !!edit_todo_list(flags); + if (command == PREPARE_BRANCH && argc == 2) + return !!prepare_branch_to_be_rebased(&opts, argv[1]); usage_with_options(builtin_rebase_helper_usage, options); } diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh index 2defe607f4..77e972bb6c 100644 --- a/git-rebase--interactive.sh +++ b/git-rebase--interactive.sh @@ -72,6 +72,7 @@ collapse_todo_ids() { # Switch to the branch in $into and notify it in the reflog checkout_onto () { + comment_for_reflog start GIT_REFLOG_ACTION="$GIT_REFLOG_ACTION: checkout $onto_name" output git checkout $onto || die_abort "$(gettext "could not detach HEAD")" git update-ref ORIG_HEAD $orig_head @@ -119,19 +120,6 @@ initiate_action () { esac } -setup_reflog_action () { - comment_for_reflog start - - if test ! -z "$switch_to" - then - GIT_REFLOG_ACTION="$GIT_REFLOG_ACTION: checkout $switch_to" - output git checkout "$switch_to" -- || - die "$(eval_gettext "Could not checkout \$switch_to")" - - comment_for_reflog start - fi -} - init_basic_state () { orig_head=$(git rev-parse --verify HEAD) || die "$(gettext "No HEAD?")" mkdir -p "$state_dir" || die "$(eval_gettext "Could not create temporary \$state_dir")" @@ -211,7 +199,7 @@ git_rebase__interactive () { return 0 fi - setup_reflog_action + git rebase--helper --prepare-branch "$switch_to" ${verbose:+--verbose} init_basic_state init_revisions_and_shortrevisions diff --git a/sequencer.c b/sequencer.c index 274cddd13f..0bc53e009e 100644 --- a/sequenc
[GSoC][PATCH v4 05/20] sequencer: add a new function to silence a command, except if it fails
This adds a new function, run_command_silent_on_success(), to redirect the stdout and stderr of a command to a strbuf, and then to run that command. This strbuf is printed only if the command fails. It is functionnaly similar to output() from git-rebase.sh. run_git_commit() is then refactored to use of run_command_silent_on_success(). Signed-off-by: Alban Gruin --- No changes since v3. sequencer.c | 51 +-- 1 file changed, 25 insertions(+), 26 deletions(-) diff --git a/sequencer.c b/sequencer.c index 0fc03dfe48..274cddd13f 100644 --- a/sequencer.c +++ b/sequencer.c @@ -769,6 +769,23 @@ N_("you have staged changes in your working tree\n" #define VERIFY_MSG (1<<4) #define CREATE_ROOT_COMMIT (1<<5) +static int run_command_silent_on_success(struct child_process *cmd) +{ + struct strbuf buf = STRBUF_INIT; + int rc; + + cmd->stdout_to_stderr = 1; + rc = pipe_command(cmd, + NULL, 0, + NULL, 0, + &buf, 0); + + if (rc) + fputs(buf.buf, stderr); + strbuf_release(&buf); + return rc; +} + /* * If we are cherry-pick, and if the merge did not result in * hand-editing, we will hit this commit and inherit the original @@ -823,18 +840,11 @@ static int run_git_commit(const char *defmsg, struct replay_opts *opts, cmd.git_cmd = 1; - if (is_rebase_i(opts)) { - if (!(flags & EDIT_MSG)) { - cmd.stdout_to_stderr = 1; - cmd.err = -1; - } - - if (read_env_script(&cmd.env_array)) { - const char *gpg_opt = gpg_sign_opt_quoted(opts); + if (is_rebase_i(opts) && read_env_script(&cmd.env_array)) { + const char *gpg_opt = gpg_sign_opt_quoted(opts); - return error(_(staged_changes_advice), -gpg_opt, gpg_opt); - } + return error(_(staged_changes_advice), +gpg_opt, gpg_opt); } argv_array_push(&cmd.args, "commit"); @@ -864,21 +874,10 @@ static int run_git_commit(const char *defmsg, struct replay_opts *opts, if (opts->allow_empty_message) argv_array_push(&cmd.args, "--allow-empty-message"); - if (cmd.err == -1) { - /* hide stderr on success */ - struct strbuf buf = STRBUF_INIT; - int rc = pipe_command(&cmd, - NULL, 0, - /* stdout is already redirected */ - NULL, 0, - &buf, 0); - if (rc) - fputs(buf.buf, stderr); - strbuf_release(&buf); - return rc; - } - - return run_command(&cmd); + if (is_rebase_i(opts) && !(flags & EDIT_MSG)) + return run_command_silent_on_success(&cmd); + else + return run_command(&cmd); } static int rest_is_empty(const struct strbuf *sb, int start) -- 2.18.0
[GSoC][PATCH v4 03/20] editor: add a function to launch the sequence editor
As part of the rewrite of interactive rebase, the sequencer will need to open the sequence editor to allow the user to edit the todo list. Instead of duplicating the existing launch_editor() function, this refactors it to a new function, launch_specified_editor(), which takes the editor as a parameter, in addition to the path, the buffer and the environment variables. launch_sequence_editor() is then added to launch the sequence editor. Signed-off-by: Alban Gruin --- No changes since v3. cache.h | 1 + editor.c | 27 +-- strbuf.h | 2 ++ 3 files changed, 28 insertions(+), 2 deletions(-) diff --git a/cache.h b/cache.h index 8b447652a7..d70ae49ca2 100644 --- a/cache.h +++ b/cache.h @@ -1409,6 +1409,7 @@ extern const char *fmt_name(const char *name, const char *email); extern const char *ident_default_name(void); extern const char *ident_default_email(void); extern const char *git_editor(void); +extern const char *git_sequence_editor(void); extern const char *git_pager(int stdout_is_tty); extern int is_terminal_dumb(void); extern int git_ident_config(const char *, const char *, void *); diff --git a/editor.c b/editor.c index 9a9b4e12d1..c985eee1f9 100644 --- a/editor.c +++ b/editor.c @@ -1,4 +1,5 @@ #include "cache.h" +#include "config.h" #include "strbuf.h" #include "run-command.h" #include "sigchain.h" @@ -34,10 +35,21 @@ const char *git_editor(void) return editor; } -int launch_editor(const char *path, struct strbuf *buffer, const char *const *env) +const char *git_sequence_editor(void) { - const char *editor = git_editor(); + const char *editor = getenv("GIT_SEQUENCE_EDITOR"); + + if (!editor) + git_config_get_string_const("sequence.editor", &editor); + if (!editor) + editor = git_editor(); + return editor; +} + +static int launch_specified_editor(const char *editor, const char *path, + struct strbuf *buffer, const char *const *env) +{ if (!editor) return error("Terminal is dumb, but EDITOR unset"); @@ -95,3 +107,14 @@ int launch_editor(const char *path, struct strbuf *buffer, const char *const *en return error_errno("could not read file '%s'", path); return 0; } + +int launch_editor(const char *path, struct strbuf *buffer, const char *const *env) +{ + return launch_specified_editor(git_editor(), path, buffer, env); +} + +int launch_sequence_editor(const char *path, struct strbuf *buffer, + const char *const *env) +{ + return launch_specified_editor(git_sequence_editor(), path, buffer, env); +} diff --git a/strbuf.h b/strbuf.h index 60a35aef16..66da9822fd 100644 --- a/strbuf.h +++ b/strbuf.h @@ -575,6 +575,8 @@ extern void strbuf_add_unique_abbrev(struct strbuf *sb, * file's contents are not read into the buffer upon completion. */ extern int launch_editor(const char *path, struct strbuf *buffer, const char *const *env); +extern int launch_sequence_editor(const char *path, struct strbuf *buffer, + const char *const *env); extern void strbuf_add_lines(struct strbuf *sb, const char *prefix, const char *buf, size_t size); -- 2.18.0
[GSoC][PATCH v4 17/20] rebase -i: implement the main part of interactive rebase as a builtin
This rewrites the part of interactive rebase which initializes the basic state, make the script and complete the action, as a buitin, named git-rebase--interactive2 for now. Others modes (`--continue`, `--edit-todo`, etc.) will be rewritten in the next commit. git-rebase--interactive.sh is modified to call git-rebase--interactive2 instead of git-rebase--helper. Signed-off-by: Alban Gruin --- .gitignore | 1 + Makefile | 1 + builtin.h | 1 + builtin/rebase--interactive2.c | 200 + git-rebase--interactive.sh | 41 +++ git.c | 1 + 6 files changed, 226 insertions(+), 19 deletions(-) create mode 100644 builtin/rebase--interactive2.c diff --git a/.gitignore b/.gitignore index 3284a1e9b1..404c9a8472 100644 --- a/.gitignore +++ b/.gitignore @@ -118,6 +118,7 @@ /git-rebase--am /git-rebase--helper /git-rebase--interactive +/git-rebase--interactive2 /git-rebase--merge /git-rebase--preserve-merges /git-receive-pack diff --git a/Makefile b/Makefile index 909a687857..71f8f45fe5 100644 --- a/Makefile +++ b/Makefile @@ -1060,6 +1060,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--interactive2.o BUILTIN_OBJS += builtin/rebase--helper.o BUILTIN_OBJS += builtin/receive-pack.o BUILTIN_OBJS += builtin/reflog.o diff --git a/builtin.h b/builtin.h index 0362f1ce25..ed89b4f495 100644 --- a/builtin.h +++ b/builtin.h @@ -202,6 +202,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__interactive(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); diff --git a/builtin/rebase--interactive2.c b/builtin/rebase--interactive2.c new file mode 100644 index 00..e89ef71499 --- /dev/null +++ b/builtin/rebase--interactive2.c @@ -0,0 +1,200 @@ +#include "builtin.h" +#include "cache.h" +#include "config.h" +#include "parse-options.h" +#include "sequencer.h" +#include "rebase-interactive.h" +#include "argv-array.h" +#include "refs.h" +#include "rerere.h" +#include "run-command.h" + +static GIT_PATH_FUNC(path_state_dir, "rebase-merge/") +static GIT_PATH_FUNC(path_squash_onto, "rebase-merge/squash-onto") +static GIT_PATH_FUNC(path_interactive, "rebase-merge/interactive") + +static int get_revision_ranges(const char *upstream, const char *onto, + const char **head_hash, + char **revisions, char **shortrevisions) +{ + const char *base_rev = upstream ? upstream : onto, *shorthead; + struct object_id orig_head; + + if (get_oid("HEAD", &orig_head)) + return error(_("no HEAD?")); + + *head_hash = find_unique_abbrev(&orig_head, GIT_MAX_HEXSZ); + *revisions = xstrfmt("%s...%s", base_rev, *head_hash); + + shorthead = find_unique_abbrev(&orig_head, DEFAULT_ABBREV); + + if (upstream) { + const char *shortrev; + struct object_id rev_oid; + + get_oid(base_rev, &rev_oid); + shortrev = find_unique_abbrev(&rev_oid, DEFAULT_ABBREV); + + *shortrevisions = xstrfmt("%s..%s", shortrev, shorthead); + } else + *shortrevisions = xstrdup(shorthead); + + return 0; +} + +static int init_basic_state(struct replay_opts *opts, const char *head_name, + const char *onto, const char *orig_head) +{ + FILE *interactive; + + if (!is_directory(path_state_dir()) && mkdir_in_gitdir(path_state_dir())) + return error_errno(_("could not create temporary %s"), path_state_dir()); + + delete_reflog("REBASE_HEAD"); + + interactive = fopen(path_interactive(), "w"); + if (!interactive) + return error_errno(_("could not mark as interactive")); + fclose(interactive); + + return write_basic_state(opts, head_name, onto, orig_head); +} + +static int do_interactive_rebase(struct replay_opts *opts, unsigned flags, +const char *switch_to, const char *upstream, +const char *onto, const char *onto_name, +
[GSoC][PATCH v4 12/20] rebase -i: remove unused modes and functions
This removes the modes `--skip-unnecessary-picks`, `--append-todo-help`, and `--checkout-onto` from rebase--helper.c, the functions of git-rebase--interactive.sh that were rendered useless by the rewrite of complete_action(), and append_todo_help_to_file() from rebase-interactive.c. skip_unnecessary_picks() and checkout_onto() becomes static, as they are only used inside of the sequencer. Signed-off-by: Alban Gruin --- builtin/rebase--helper.c | 23 ++ git-rebase--interactive.sh | 50 -- rebase-interactive.c | 22 - rebase-interactive.h | 1 - sequencer.c| 8 +++--- sequencer.h| 4 --- 6 files changed, 6 insertions(+), 102 deletions(-) diff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c index d7fa5a5062..6085527b2b 100644 --- a/builtin/rebase--helper.c +++ b/builtin/rebase--helper.c @@ -17,9 +17,8 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix) int abbreviate_commands = 0, rebase_cousins = -1; enum { CONTINUE = 1, ABORT, MAKE_SCRIPT, SHORTEN_OIDS, EXPAND_OIDS, - CHECK_TODO_LIST, SKIP_UNNECESSARY_PICKS, REARRANGE_SQUASH, - ADD_EXEC, APPEND_TODO_HELP, EDIT_TODO, PREPARE_BRANCH, - CHECKOUT_ONTO, COMPLETE_ACTION + CHECK_TODO_LIST, REARRANGE_SQUASH, ADD_EXEC, EDIT_TODO, PREPARE_BRANCH, + COMPLETE_ACTION } command = 0; struct option options[] = { OPT_BOOL(0, "ff", &opts.allow_ff, N_("allow fast-forward")), @@ -44,21 +43,15 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix) N_("expand commit ids in the todo list"), EXPAND_OIDS), 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_CMDMODE(0, "add-exec-commands", &command, N_("insert exec commands in todo list"), ADD_EXEC), - OPT_CMDMODE(0, "append-todo-help", &command, - N_("insert the help in the todo list"), APPEND_TODO_HELP), OPT_CMDMODE(0, "edit-todo", &command, N_("edit the todo list during an interactive rebase"), EDIT_TODO), OPT_CMDMODE(0, "prepare-branch", &command, N_("prepare the branch to be rebased"), PREPARE_BRANCH), - OPT_CMDMODE(0, "checkout-onto", &command, - N_("checkout a commit"), CHECKOUT_ONTO), OPT_CMDMODE(0, "complete-action", &command, N_("complete the action"), COMPLETE_ACTION), OPT_END() @@ -94,26 +87,14 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix) return !!transform_todos(flags); if (command == CHECK_TODO_LIST && argc == 1) return !!check_todo_list(); - if (command == SKIP_UNNECESSARY_PICKS && argc == 1) { - struct object_id oid; - int ret = skip_unnecessary_picks(&oid); - - if (!ret) - puts(oid_to_hex(&oid)); - return !!ret; - } if (command == REARRANGE_SQUASH && argc == 1) return !!rearrange_squash(); if (command == ADD_EXEC && argc == 2) return !!sequencer_add_exec_commands(argv[1]); - if (command == APPEND_TODO_HELP && argc == 1) - return !!append_todo_help_to_file(0, keep_empty); if (command == EDIT_TODO && argc == 1) return !!edit_todo_list(flags); if (command == PREPARE_BRANCH && argc == 2) return !!prepare_branch_to_be_rebased(&opts, argv[1]); - if (command == CHECKOUT_ONTO && argc == 4) - return !!checkout_onto(&opts, argv[1], argv[2], argv[3]); if (command == COMPLETE_ACTION && argc == 6) return !!complete_action(&opts, flags, argv[1], argv[2], argv[3], argv[4], argv[5], autosquash); diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh index 59dc4888a6..0d66c0f8b8 100644 --- a/git-rebase--interactive.sh +++ b/git-rebase--i
[GSoC][PATCH v4 14/20] rebase -i: rewrite the rest of init_revisions_and_shortrevisions() in C
This rewrites the part of init_revisions_and_shortrevisions() needed by `--complete-action` (which initialize $shortrevisions) from shell to C. When `upstream` is empty, it means that the user launched a `rebase --root`, and `onto` contains the ID of an empty commit. As a range between an empty commit and `head` is not really meaningful, `onto` is not used to initialize `shortrevisions` in this case. The corresponding arguments passed to `--complete-action` are then dropped, and init_revisions_and_shortrevisions() is stripped from git-rebase--interactive.sh Signed-off-by: Alban Gruin --- builtin/rebase--helper.c | 40 -- git-rebase--interactive.sh | 27 - 2 files changed, 38 insertions(+), 29 deletions(-) diff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c index 15fa556f65..c4a4c5cfbb 100644 --- a/builtin/rebase--helper.c +++ b/builtin/rebase--helper.c @@ -10,7 +10,7 @@ static GIT_PATH_FUNC(path_squash_onto, "rebase-merge/squash-onto") static int get_revision_ranges(const char *upstream, const char *onto, const char **head_hash, - char **revisions) + char **revisions, char **shortrevisions) { const char *base_rev = upstream ? upstream : onto; struct object_id orig_head; @@ -19,7 +19,25 @@ static int get_revision_ranges(const char *upstream, const char *onto, return error(_("no HEAD?")); *head_hash = find_unique_abbrev(&orig_head, GIT_MAX_HEXSZ); - *revisions = xstrfmt("%s...%s", base_rev, *head_hash); + + if (revisions) + *revisions = xstrfmt("%s...%s", base_rev, *head_hash); + if (shortrevisions) { + const char *shorthead; + + shorthead = find_unique_abbrev(&orig_head, DEFAULT_ABBREV); + + if (upstream) { + const char *shortrev; + struct object_id rev_oid; + + get_oid(base_rev, &rev_oid); + shortrev = find_unique_abbrev(&rev_oid, DEFAULT_ABBREV); + + *shortrevisions = xstrfmt("%s..%s", shortrev, shorthead); + } else + *shortrevisions = xstrdup(shorthead); + } return 0; } @@ -116,7 +134,7 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix) if (!upstream && squash_onto) write_file(path_squash_onto(), "%s\n", squash_onto); - ret = get_revision_ranges(upstream, onto, &head_hash, &revisions); + ret = get_revision_ranges(upstream, onto, &head_hash, &revisions, NULL); if (ret) return ret; @@ -145,9 +163,19 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix) return !!edit_todo_list(flags); if (command == PREPARE_BRANCH && argc == 2) return !!prepare_branch_to_be_rebased(&opts, argv[1]); - if (command == COMPLETE_ACTION && argc == 6) - return !!complete_action(&opts, flags, argv[1], argv[2], argv[3], -argv[4], argv[5], autosquash); + if (command == COMPLETE_ACTION && argc == 3) { + char *shortrevisions = NULL; + + ret = get_revision_ranges(upstream, onto, &head_hash, NULL, &shortrevisions); + if (ret) + return ret; + + ret = complete_action(&opts, flags, shortrevisions, argv[1], onto, + head_hash, argv[2], autosquash); + + free(shortrevisions); + return !!ret; + } usage_with_options(builtin_rebase_helper_usage, options); } diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh index 4ca47aed1e..08e9a21c2f 100644 --- a/git-rebase--interactive.sh +++ b/git-rebase--interactive.sh @@ -60,23 +60,6 @@ init_basic_state () { write_basic_state } -init_revisions_and_shortrevisions () { - shorthead=$(git rev-parse --short $orig_head) - shortonto=$(git rev-parse --short $onto) - if test -z "$rebase_root" - # this is now equivalent to ! -z "$upstream" - then - shortupstream=$(git rev-parse --short $upstream) - revisions=$upstream...$orig_head - shortrevisions=$shortupstream..$shorthead - else - revisions=$onto...$orig_head - shortrevisions=$shorthead - test -z "$squash_onto" || - echo "$squash_onto" >"$state_dir"/squash-onto - fi -} - git_rebase__interactive () {
[GSoC][PATCH v4 13/20] rebase -i: implement the logic to initialize $revisions in C
This rewrites the part of init_revisions_and_shortrevisions() needed by `--make-script` from shell to C. The new version is called get_revision_ranges(), and is a static function inside of rebase--helper.c. As this does not initialize $shortrevision, the original shell version is not yet stripped. Unlike init_revisions_and_shortrevisions(), get_revision_ranges() doesn’t write $squash_onto to the state directory, it’s done by the handler of `--make-script` instead. Finally, this drops the $revision argument passed to `--make-script` in git-rebase--interactive.sh, and rebase--helper is changed accordingly. Signed-off-by: Alban Gruin --- builtin/rebase--helper.c | 56 -- git-rebase--interactive.sh | 4 ++- 2 files changed, 56 insertions(+), 4 deletions(-) diff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c index 6085527b2b..15fa556f65 100644 --- a/builtin/rebase--helper.c +++ b/builtin/rebase--helper.c @@ -4,6 +4,25 @@ #include "parse-options.h" #include "sequencer.h" #include "rebase-interactive.h" +#include "argv-array.h" + +static GIT_PATH_FUNC(path_squash_onto, "rebase-merge/squash-onto") + +static int get_revision_ranges(const char *upstream, const char *onto, + const char **head_hash, + char **revisions) +{ + const char *base_rev = upstream ? upstream : onto; + struct object_id orig_head; + + if (get_oid("HEAD", &orig_head)) + return error(_("no HEAD?")); + + *head_hash = find_unique_abbrev(&orig_head, GIT_MAX_HEXSZ); + *revisions = xstrfmt("%s...%s", base_rev, *head_hash); + + return 0; +} static const char * const builtin_rebase_helper_usage[] = { N_("git rebase--helper []"), @@ -14,7 +33,9 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix) { struct replay_opts opts = REPLAY_OPTS_INIT; unsigned flags = 0, keep_empty = 0, rebase_merges = 0, autosquash = 0; - int abbreviate_commands = 0, rebase_cousins = -1; + int abbreviate_commands = 0, rebase_cousins = -1, ret; + const char *head_hash = NULL, *onto = NULL, *restrict_revision = NULL, + *squash_onto = NULL, *upstream = NULL; enum { CONTINUE = 1, ABORT, MAKE_SCRIPT, SHORTEN_OIDS, EXPAND_OIDS, CHECK_TODO_LIST, REARRANGE_SQUASH, ADD_EXEC, EDIT_TODO, PREPARE_BRANCH, @@ -54,6 +75,13 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix) N_("prepare the branch to be rebased"), PREPARE_BRANCH), OPT_CMDMODE(0, "complete-action", &command, N_("complete the action"), COMPLETE_ACTION), + OPT_STRING(0, "onto", &onto, N_("onto"), N_("onto")), + OPT_STRING(0, "restrict-revision", &restrict_revision, + N_("restrict-revision"), N_("restrict revision")), + OPT_STRING(0, "squash-onto", &squash_onto, N_("squash-onto"), + N_("squash onto")), + OPT_STRING(0, "upstream", &upstream, N_("upstream"), + N_("the upstream commit")), OPT_END() }; @@ -81,8 +109,30 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix) return !!sequencer_continue(&opts); if (command == ABORT && argc == 1) return !!sequencer_remove_state(&opts); - if (command == MAKE_SCRIPT && argc > 1) - return !!sequencer_make_script(stdout, argc, argv, flags); + if (command == MAKE_SCRIPT && argc == 1) { + char *revisions = NULL; + struct argv_array make_script_args = ARGV_ARRAY_INIT; + + if (!upstream && squash_onto) + write_file(path_squash_onto(), "%s\n", squash_onto); + + ret = get_revision_ranges(upstream, onto, &head_hash, &revisions); + if (ret) + return ret; + + argv_array_pushl(&make_script_args, "", revisions, NULL); + if (restrict_revision) + argv_array_push(&make_script_args, restrict_revision); + + ret = sequencer_make_script(stdout, + make_script_args.argc, make_script_args.argv, + flags); + + free(revisions); + argv_array_clear(&make_script_args); + + return !!ret; + } if ((command == SHORTEN_OIDS || c
[GSoC][PATCH v4 19/20] rebase -i: remove git-rebase--interactive.sh
This removes git-rebase--interactive.sh, as its functionnality has been replaced by git-rebase--interactive2. git-rebase--interactive2.c is then renamed to git-rebase--interactive.c. Signed-off-by: Alban Gruin --- .gitignore| 1 - Makefile | 4 +- ...--interactive2.c => rebase--interactive.c} | 0 git-rebase--interactive.sh| 84 --- git-rebase.sh | 2 +- git.c | 2 +- 6 files changed, 3 insertions(+), 90 deletions(-) rename builtin/{rebase--interactive2.c => rebase--interactive.c} (100%) delete mode 100644 git-rebase--interactive.sh diff --git a/.gitignore b/.gitignore index 404c9a8472..3284a1e9b1 100644 --- a/.gitignore +++ b/.gitignore @@ -118,7 +118,6 @@ /git-rebase--am /git-rebase--helper /git-rebase--interactive -/git-rebase--interactive2 /git-rebase--merge /git-rebase--preserve-merges /git-receive-pack diff --git a/Makefile b/Makefile index 71f8f45fe5..584834726d 100644 --- a/Makefile +++ b/Makefile @@ -619,7 +619,6 @@ SCRIPT_SH += git-web--browse.sh SCRIPT_LIB += git-mergetool--lib SCRIPT_LIB += git-parse-remote SCRIPT_LIB += git-rebase--am -SCRIPT_LIB += git-rebase--interactive SCRIPT_LIB += git-rebase--preserve-merges SCRIPT_LIB += git-rebase--merge SCRIPT_LIB += git-sh-setup @@ -1060,8 +1059,8 @@ 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--interactive2.o BUILTIN_OBJS += builtin/rebase--helper.o +BUILTIN_OBJS += builtin/rebase--interactive.o BUILTIN_OBJS += builtin/receive-pack.o BUILTIN_OBJS += builtin/reflog.o BUILTIN_OBJS += builtin/remote.o @@ -2400,7 +2399,6 @@ XGETTEXT_FLAGS_PERL = $(XGETTEXT_FLAGS) --language=Perl \ LOCALIZED_C = $(C_OBJ:o=c) $(LIB_H) $(GENERATED_H) LOCALIZED_SH = $(SCRIPT_SH) LOCALIZED_SH += git-parse-remote.sh -LOCALIZED_SH += git-rebase--interactive.sh LOCALIZED_SH += git-rebase--preserve-merges.sh LOCALIZED_SH += git-sh-setup.sh LOCALIZED_PERL = $(SCRIPT_PERL) diff --git a/builtin/rebase--interactive2.c b/builtin/rebase--interactive.c similarity index 100% rename from builtin/rebase--interactive2.c rename to builtin/rebase--interactive.c diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh deleted file mode 100644 index e87d708a4d..00 --- a/git-rebase--interactive.sh +++ /dev/null @@ -1,84 +0,0 @@ -# This shell script fragment is sourced by git-rebase to implement -# its interactive mode. "git rebase --interactive" makes it easy -# to fix up commits in the middle of a series and rearrange commits. -# -# Copyright (c) 2006 Johannes E. Schindelin -# -# The original idea comes from Eric W. Biederman, in -# https://public-inbox.org/git/m1odwkyuf5.fsf...@ebiederm.dsl.xmission.com/ -# -# The file containing rebase commands, comments, and empty lines. -# This file is created by "git rebase -i" then edited by the user. As -# the lines are processed, they are removed from the front of this -# file and written to the tail of $done. -todo="$state_dir"/git-rebase-todo - -GIT_CHERRY_PICK_HELP="$resolvemsg" -export GIT_CHERRY_PICK_HELP - -# Initiate an action. If the cannot be any -# further action it may exec a command -# or exit and not return. -# -# TODO: Consider a cleaner return model so it -# never exits and always return 0 if process -# is complete. -# -# Parameter 1 is the action to initiate. -# -# Returns 0 if the action was able to complete -# and if 1 if further processing is required. -initiate_action () { - case "$1" in - continue) - exec git rebase--helper ${force_rebase:+--no-ff} $allow_empty_message \ ---continue - ;; - skip) - git rerere clear - exec git rebase--helper ${force_rebase:+--no-ff} $allow_empty_message \ ---continue - ;; - edit-todo) - exec git rebase--helper --edit-todo - ;; - show-current-patch) - exec git show REBASE_HEAD -- - ;; - *) - return 1 # continue - ;; - esac -} - -git_rebase__interactive () { - initiate_action "$action" - ret=$? - if test $ret = 0; then - return 0 - fi - - test -n "$keep_empty" && keep_empty="--keep-empty" - test -n "$rebase_merges" && rebase_merges="--rebase-merges" - test -n "$rebase_cousins" && rebase_cousins="--rebase-cousins" - test -n "$autosquash" && autosquash="--autosquash" - test -n "$verbose" && verbose="--verbose" - test -n "$force_rebase
[GSoC][PATCH v4 15/20] rebase -i: rewrite write_basic_state() in C
This rewrites write_basic_state() from git-rebase.sh in C. This is the first step in the conversion of init_basic_state(), hence the mode in rebase--helper.c is called INIT_BASIC_STATE. init_basic_state() will be converted in the next commit. The part of read_strategy_opts() that parses the stategy options is moved to a new function to allow its use in rebase--helper.c. Finally, the call to write_basic_state() is removed from git-rebase--interactive.sh, replaced by a call to `--init-basic-state`. Signed-off-by: Alban Gruin --- All patches from this one are new. builtin/rebase--helper.c | 28 +- git-rebase--interactive.sh | 7 +++- sequencer.c| 77 -- sequencer.h| 4 ++ 4 files changed, 102 insertions(+), 14 deletions(-) diff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c index c4a4c5cfbb..06fe3c018b 100644 --- a/builtin/rebase--helper.c +++ b/builtin/rebase--helper.c @@ -5,6 +5,8 @@ #include "sequencer.h" #include "rebase-interactive.h" #include "argv-array.h" +#include "rerere.h" +#include "alias.h" static GIT_PATH_FUNC(path_squash_onto, "rebase-merge/squash-onto") @@ -53,11 +55,12 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix) unsigned flags = 0, keep_empty = 0, rebase_merges = 0, autosquash = 0; int abbreviate_commands = 0, rebase_cousins = -1, ret; const char *head_hash = NULL, *onto = NULL, *restrict_revision = NULL, - *squash_onto = NULL, *upstream = NULL; + *squash_onto = NULL, *upstream = NULL, *head_name = NULL; + char *raw_strategies = NULL; enum { CONTINUE = 1, ABORT, MAKE_SCRIPT, SHORTEN_OIDS, EXPAND_OIDS, CHECK_TODO_LIST, REARRANGE_SQUASH, ADD_EXEC, EDIT_TODO, PREPARE_BRANCH, - COMPLETE_ACTION + COMPLETE_ACTION, INIT_BASIC_STATE } command = 0; struct option options[] = { OPT_BOOL(0, "ff", &opts.allow_ff, N_("allow fast-forward")), @@ -69,6 +72,7 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix) N_("keep original branch points of cousins")), OPT_BOOL(0, "autosquash", &autosquash, N_("move commits thas begin with squash!/fixup!")), + OPT_BOOL(0, "signoff", &opts.signoff, N_("sign commits")), OPT__VERBOSE(&opts.verbose, N_("be verbose")), OPT_CMDMODE(0, "continue", &command, N_("continue rebase"), CONTINUE), @@ -93,6 +97,8 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix) N_("prepare the branch to be rebased"), PREPARE_BRANCH), OPT_CMDMODE(0, "complete-action", &command, N_("complete the action"), COMPLETE_ACTION), + OPT_CMDMODE(0, "init-basic-state", &command, + N_("initialise the rebase state"), INIT_BASIC_STATE), OPT_STRING(0, "onto", &onto, N_("onto"), N_("onto")), OPT_STRING(0, "restrict-revision", &restrict_revision, N_("restrict-revision"), N_("restrict revision")), @@ -100,6 +106,14 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix) N_("squash onto")), OPT_STRING(0, "upstream", &upstream, N_("upstream"), N_("the upstream commit")), + OPT_STRING(0, "head-name", &head_name, N_("head-name"), N_("head name")), + OPT_STRING('S', "gpg-sign", &opts.gpg_sign, N_("gpg-sign"), + N_("GPG-sign commits")), + OPT_STRING(0, "strategy", &opts.strategy, N_("strategy"), + N_("rebase strategy")), + OPT_STRING(0, "strategy-opts", &raw_strategies, N_("strategy-opts"), + N_("strategy options")), + OPT_RERERE_AUTOUPDATE(&opts.allow_rerere_auto), OPT_END() }; @@ -176,6 +190,16 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix) free(shortrevisions); return !!ret; } + if (command == INIT_BASIC_STATE) { + if (raw_strategies) + parse_strategy_opts(&opts, raw_strategies); + +
[GSoC][PATCH v4 16/20] rebase -i: rewrite init_basic_state() in C
This rewrites init_basic_state() from shell to C. The call to write_basic_state() in cmd_rebase__helper() is replaced by a call to the new function. The shell version is then stripped from git-rebase--interactive.sh. Signed-off-by: Alban Gruin --- builtin/rebase--helper.c | 23 ++- git-rebase--interactive.sh | 9 - 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c index 06fe3c018b..ac21e8e06e 100644 --- a/builtin/rebase--helper.c +++ b/builtin/rebase--helper.c @@ -5,10 +5,13 @@ #include "sequencer.h" #include "rebase-interactive.h" #include "argv-array.h" +#include "refs.h" #include "rerere.h" #include "alias.h" +static GIT_PATH_FUNC(path_state_dir, "rebase-merge/") static GIT_PATH_FUNC(path_squash_onto, "rebase-merge/squash-onto") +static GIT_PATH_FUNC(path_interactive, "rebase-merge/interactive") static int get_revision_ranges(const char *upstream, const char *onto, const char **head_hash, @@ -44,6 +47,24 @@ static int get_revision_ranges(const char *upstream, const char *onto, return 0; } +static int init_basic_state(struct replay_opts *opts, const char *head_name, + const char *onto, const char *orig_head) +{ + FILE *interactive; + + if (!is_directory(path_state_dir()) && mkdir_in_gitdir(path_state_dir())) + return error_errno(_("could not create temporary %s"), path_state_dir()); + + delete_reflog("REBASE_HEAD"); + + interactive = fopen(path_interactive(), "w"); + if (!interactive) + return error_errno(_("could not mark as interactive")); + fclose(interactive); + + return write_basic_state(opts, head_name, onto, orig_head); +} + static const char * const builtin_rebase_helper_usage[] = { N_("git rebase--helper []"), NULL @@ -198,7 +219,7 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix) if (ret) return ret; - return !!write_basic_state(&opts, head_name, onto, head_hash); + return !!init_basic_state(&opts, head_name, onto, head_hash); } usage_with_options(builtin_rebase_helper_usage, options); diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh index 6367da66e2..761be95ed1 100644 --- a/git-rebase--interactive.sh +++ b/git-rebase--interactive.sh @@ -51,14 +51,6 @@ initiate_action () { esac } -init_basic_state () { - orig_head=$(git rev-parse --verify HEAD) || die "$(gettext "No HEAD?")" - mkdir -p "$state_dir" || die "$(eval_gettext "Could not create temporary \$state_dir")" - rm -f "$(git rev-parse --git-path REBASE_HEAD)" - - : > "$state_dir"/interactive || die "$(gettext "Could not mark as interactive")" -} - git_rebase__interactive () { initiate_action "$action" ret=$? @@ -67,7 +59,6 @@ git_rebase__interactive () { fi git rebase--helper --prepare-branch "$switch_to" ${verbose:+--verbose} - init_basic_state git rebase--helper --init-basic-state ${upstream:+--upstream "$upstream"} \ ${onto:+--onto "$onto"} ${head_name:+--head-name "$head_name"} \ -- 2.18.0
[GSoC][PATCH v4 10/20] t3404: todo list with commented-out commands only aborts
If the todo list generated by `--make-script` is empty, complete_action() writes a noop, but if it has only commented-out commands, it will abort with the message "Nothing to do", and does not launch the editor. This adds a new test to ensure that complete_action() behaves this way. Signed-off-by: Alban Gruin --- New patch. t/t3404-rebase-interactive.sh | 10 ++ 1 file changed, 10 insertions(+) diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh index d392160ba9..7755b68092 100755 --- a/t/t3404-rebase-interactive.sh +++ b/t/t3404-rebase-interactive.sh @@ -75,6 +75,16 @@ test_expect_success 'rebase --keep-empty' ' test_line_count = 6 actual ' +cat > expect <actual 2>&1 && + test_i18ncmp expect actual +' + test_expect_success 'rebase -i with the exec command' ' git checkout master && ( -- 2.18.0
[GSoC][PATCH v4 11/20] rebase -i: rewrite complete_action() in C
This rewrites complete_action() from shell to C. A new mode is added to rebase--helper (`--complete-action`), as well as a new flag (`--autosquash`). Finally, complete_action() is stripped from git-rebase--interactive.sh. The original complete_action() would return the code 2 when the todo list contained no actions. This was a special case for rebase -i and -p; git-rebase.sh would then apply the autostash, delete the state directory, and die with the message "Nothing to do". This cleanup is rewritten in C instead of returning 2. As rebase -i no longer returns 2, the comment describing this behaviour in git-rebase.sh is updated to reflect this change. The first check might seem useless as we write "noop" to the todo list if it is empty. Actually, the todo list might contain commented commands (ie. empty commits). In this case, complete_action() won’t write "noop", and will abort without starting the editor. Signed-off-by: Alban Gruin --- builtin/rebase--helper.c | 12 - git-rebase--interactive.sh | 53 ++-- git-rebase.sh | 2 +- sequencer.c| 99 ++ sequencer.h| 4 ++ 5 files changed, 118 insertions(+), 52 deletions(-) diff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c index bed3dd2b95..d7fa5a5062 100644 --- a/builtin/rebase--helper.c +++ b/builtin/rebase--helper.c @@ -13,13 +13,13 @@ static const char * const builtin_rebase_helper_usage[] = { int cmd_rebase__helper(int argc, const char **argv, const char *prefix) { struct replay_opts opts = REPLAY_OPTS_INIT; - unsigned flags = 0, keep_empty = 0, rebase_merges = 0; + unsigned flags = 0, keep_empty = 0, rebase_merges = 0, autosquash = 0; int abbreviate_commands = 0, rebase_cousins = -1; enum { CONTINUE = 1, ABORT, MAKE_SCRIPT, SHORTEN_OIDS, EXPAND_OIDS, CHECK_TODO_LIST, SKIP_UNNECESSARY_PICKS, REARRANGE_SQUASH, ADD_EXEC, APPEND_TODO_HELP, EDIT_TODO, PREPARE_BRANCH, - CHECKOUT_ONTO + CHECKOUT_ONTO, COMPLETE_ACTION } command = 0; struct option options[] = { OPT_BOOL(0, "ff", &opts.allow_ff, N_("allow fast-forward")), @@ -29,6 +29,8 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix) OPT_BOOL(0, "rebase-merges", &rebase_merges, N_("rebase merge commits")), OPT_BOOL(0, "rebase-cousins", &rebase_cousins, N_("keep original branch points of cousins")), + OPT_BOOL(0, "autosquash", &autosquash, +N_("move commits thas begin with squash!/fixup!")), OPT__VERBOSE(&opts.verbose, N_("be verbose")), OPT_CMDMODE(0, "continue", &command, N_("continue rebase"), CONTINUE), @@ -57,6 +59,8 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix) N_("prepare the branch to be rebased"), PREPARE_BRANCH), OPT_CMDMODE(0, "checkout-onto", &command, N_("checkout a commit"), CHECKOUT_ONTO), + OPT_CMDMODE(0, "complete-action", &command, + N_("complete the action"), COMPLETE_ACTION), OPT_END() }; @@ -110,5 +114,9 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix) return !!prepare_branch_to_be_rebased(&opts, argv[1]); if (command == CHECKOUT_ONTO && argc == 4) return !!checkout_onto(&opts, argv[1], argv[2], argv[3]); + if (command == COMPLETE_ACTION && argc == 6) + return !!complete_action(&opts, flags, argv[1], argv[2], argv[3], +argv[4], argv[5], autosquash); + usage_with_options(builtin_rebase_helper_usage, options); } diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh index b68f108f28..59dc4888a6 100644 --- a/git-rebase--interactive.sh +++ b/git-rebase--interactive.sh @@ -127,54 +127,6 @@ init_revisions_and_shortrevisions () { fi } -complete_action() { - test -s "$todo" || echo noop >> "$todo" - test -z "$autosquash" || git rebase--helper --rearrange-squash || exit - test -n "$cmd" && git rebase--helper --add-exec-commands "$cmd" - - todocount=$(git stripspace --strip-comments <"$todo" | wc -l) - todocount=${todocount##* } - -cat >>"$todo" <"$todo" || die "$(gettext "Could not generate todo list")" -
[GSoC][PATCH v4 08/20] sequencer: refactor append_todo_help() to write its message to a buffer
This refactors append_todo_help() to write its message to a buffer instead of the todo-list. This is needed for the rewrite of complete_action(), which will come after the next commit. As rebase--helper still needs the file manipulation part of append_todo_help(), it is extracted to a temporary function, append_todo_help_to_file(). This function will go away after the rewrite of complete_action(). Signed-off-by: Alban Gruin --- Dropped the `include` in rebase-interactive.h. builtin/rebase--helper.c | 2 +- rebase-interactive.c | 45 rebase-interactive.h | 4 +++- 3 files changed, 36 insertions(+), 15 deletions(-) diff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c index 7d9426d23c..313092c465 100644 --- a/builtin/rebase--helper.c +++ b/builtin/rebase--helper.c @@ -97,7 +97,7 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix) if (command == ADD_EXEC && argc == 2) return !!sequencer_add_exec_commands(argv[1]); if (command == APPEND_TODO_HELP && argc == 1) - return !!append_todo_help(0, keep_empty); + return !!append_todo_help_to_file(0, keep_empty); if (command == EDIT_TODO && argc == 1) return !!edit_todo_list(flags); if (command == PREPARE_BRANCH && argc == 2) diff --git a/rebase-interactive.c b/rebase-interactive.c index 403ecbf3c9..d8b9465597 100644 --- a/rebase-interactive.c +++ b/rebase-interactive.c @@ -4,11 +4,9 @@ #include "sequencer.h" #include "strbuf.h" -int append_todo_help(unsigned edit_todo, unsigned keep_empty) +void append_todo_help(unsigned edit_todo, unsigned keep_empty, + struct strbuf *buf) { - struct strbuf buf = STRBUF_INIT; - FILE *todo; - int ret; const char *msg = _("\nCommands:\n" "p, pick = use commit\n" "r, reword = use commit, but edit the commit message\n" @@ -26,11 +24,7 @@ int append_todo_help(unsigned edit_todo, unsigned keep_empty) "\n" "These lines can be re-ordered; they are executed from top to bottom.\n"); - todo = fopen_or_warn(rebase_path_todo(), "a"); - if (!todo) - return 1; - - strbuf_add_commented_lines(&buf, msg, strlen(msg)); + strbuf_add_commented_lines(buf, msg, strlen(msg)); if (get_missing_commit_check_level() == MISSING_COMMIT_CHECK_ERROR) msg = _("\nDo not remove any line. Use 'drop' " @@ -39,7 +33,7 @@ int append_todo_help(unsigned edit_todo, unsigned keep_empty) msg = _("\nIf you remove a line here " "THAT COMMIT WILL BE LOST.\n"); - strbuf_add_commented_lines(&buf, msg, strlen(msg)); + strbuf_add_commented_lines(buf, msg, strlen(msg)); if (edit_todo) msg = _("\nYou are editing the todo file " @@ -50,12 +44,25 @@ int append_todo_help(unsigned edit_todo, unsigned keep_empty) msg = _("\nHowever, if you remove everything, " "the rebase will be aborted.\n\n"); - strbuf_add_commented_lines(&buf, msg, strlen(msg)); + strbuf_add_commented_lines(buf, msg, strlen(msg)); if (!keep_empty) { msg = _("Note that empty commits are commented out"); - strbuf_add_commented_lines(&buf, msg, strlen(msg)); + strbuf_add_commented_lines(buf, msg, strlen(msg)); } +} + +int append_todo_help_to_file(unsigned edit_todo, unsigned keep_empty) +{ + struct strbuf buf = STRBUF_INIT; + FILE *todo; + int ret; + + todo = fopen_or_warn(rebase_path_todo(), "a"); + if (!todo) + return 1; + + append_todo_help(edit_todo, keep_empty, &buf); ret = fputs(buf.buf, todo); if (ret < 0) @@ -88,7 +95,19 @@ int edit_todo_list(unsigned flags) strbuf_release(&buf); transform_todos(flags | TODO_LIST_SHORTEN_IDS); - append_todo_help(1, 0); + + strbuf_read_file(&buf, todo_file, 0); + append_todo_help(1, 0, &buf); + + todo = fopen_or_warn(todo_file, "w"); + if (!todo) { + strbuf_release(&buf); + return 1; + } + + strbuf_write(&buf, todo); + fclose(todo); + strbuf_release(&buf); if (launch_sequence_editor(todo_file, NULL, NULL)) return 1; diff --git a/rebase-interactive.h b/rebase-interactive.h index 155219e742..d33f3176b7 100644 --- a/rebase-interactive.h +++ b/rebase-interactive.h @@ -1,7 +1,9 @@ #ifndef REBASE_INTERACTIVE_H #define REBASE_INTERACTIVE_H -int append_todo_help(unsigned edit_todo, unsigned keep_empty); +void append_todo_help(unsigned edit_todo, unsigned keep_empty, + struct strbuf *buf); +int append_todo_help_to_file(unsigned edit_todo, unsigned keep_empty); int edit_todo_list(unsigned flags); #endif -- 2.18.0
[GSoC][PATCH v4 09/20] sequencer: change the way skip_unnecessary_picks() returns its result
Instead of skip_unnecessary_picks() printing its result to stdout, it returns it into a struct object_id, as the rewrite of complete_action() (to come in the next commit) will need it. rebase--helper then is modified to fit this change. Signed-off-by: Alban Gruin --- builtin/rebase--helper.c | 10 -- sequencer.c | 13 ++--- sequencer.h | 2 +- 3 files changed, 15 insertions(+), 10 deletions(-) diff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c index 313092c465..bed3dd2b95 100644 --- a/builtin/rebase--helper.c +++ b/builtin/rebase--helper.c @@ -90,8 +90,14 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix) return !!transform_todos(flags); if (command == CHECK_TODO_LIST && argc == 1) return !!check_todo_list(); - if (command == SKIP_UNNECESSARY_PICKS && argc == 1) - return !!skip_unnecessary_picks(); + if (command == SKIP_UNNECESSARY_PICKS && argc == 1) { + struct object_id oid; + int ret = skip_unnecessary_picks(&oid); + + if (!ret) + puts(oid_to_hex(&oid)); + return !!ret; + } if (command == REARRANGE_SQUASH && argc == 1) return !!rearrange_squash(); if (command == ADD_EXEC && argc == 2) diff --git a/sequencer.c b/sequencer.c index c7d01d60b3..238c534049 100644 --- a/sequencer.c +++ b/sequencer.c @@ -4416,17 +4416,17 @@ static int rewrite_file(const char *path, const char *buf, size_t len) } /* skip picking commits whose parents are unchanged */ -int skip_unnecessary_picks(void) +int skip_unnecessary_picks(struct object_id *output_oid) { const char *todo_file = rebase_path_todo(); struct strbuf buf = STRBUF_INIT; struct todo_list todo_list = TODO_LIST_INIT; - struct object_id onto_oid, *oid = &onto_oid, *parent_oid; + struct object_id *parent_oid; int fd, i; if (!read_oneliner(&buf, rebase_path_onto(), 0)) return error(_("could not read 'onto'")); - if (get_oid(buf.buf, &onto_oid)) { + if (get_oid(buf.buf, output_oid)) { strbuf_release(&buf); return error(_("need a HEAD to fixup")); } @@ -4456,9 +4456,9 @@ int skip_unnecessary_picks(void) if (item->commit->parents->next) break; /* merge commit */ parent_oid = &item->commit->parents->item->object.oid; - if (hashcmp(parent_oid->hash, oid->hash)) + if (hashcmp(parent_oid->hash, output_oid->hash)) break; - oid = &item->commit->object.oid; + oidcpy(output_oid, &item->commit->object.oid); } if (i > 0) { int offset = get_item_line_offset(&todo_list, i); @@ -4487,11 +4487,10 @@ int skip_unnecessary_picks(void) todo_list.current = i; if (is_fixup(peek_command(&todo_list, 0))) - record_in_rewritten(oid, peek_command(&todo_list, 0)); + record_in_rewritten(output_oid, peek_command(&todo_list, 0)); } todo_list_release(&todo_list); - printf("%s\n", oid_to_hex(oid)); return 0; } diff --git a/sequencer.h b/sequencer.h index 11a5334612..f11dabfd65 100644 --- a/sequencer.h +++ b/sequencer.h @@ -88,7 +88,7 @@ int sequencer_add_exec_commands(const char *command); int transform_todos(unsigned flags); enum missing_commit_check_level get_missing_commit_check_level(void); int check_todo_list(void); -int skip_unnecessary_picks(void); +int skip_unnecessary_picks(struct object_id *output_oid); int rearrange_squash(void); extern const char sign_off_header[]; -- 2.18.0
[GSoC][PATCH v4 04/20] rebase -i: rewrite the edit-todo functionality in C
This rewrites the edit-todo functionality from shell to C. To achieve that, a new command mode, `edit-todo`, is added, and the `write-edit-todo` flag is removed, as the shell script does not need to write the edit todo help message to the todo list anymore. The shell version is then stripped in favour of a call to the helper. Signed-off-by: Alban Gruin --- No code changes since v3. builtin/rebase--helper.c | 13 - git-rebase--interactive.sh | 11 +-- rebase-interactive.c | 31 +++ rebase-interactive.h | 1 + 4 files changed, 41 insertions(+), 15 deletions(-) diff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c index 05e73e71d4..731a64971d 100644 --- a/builtin/rebase--helper.c +++ b/builtin/rebase--helper.c @@ -13,12 +13,12 @@ static const char * const builtin_rebase_helper_usage[] = { int cmd_rebase__helper(int argc, const char **argv, const char *prefix) { struct replay_opts opts = REPLAY_OPTS_INIT; - unsigned flags = 0, keep_empty = 0, rebase_merges = 0, write_edit_todo = 0; + unsigned flags = 0, keep_empty = 0, rebase_merges = 0; int abbreviate_commands = 0, rebase_cousins = -1; enum { CONTINUE = 1, ABORT, MAKE_SCRIPT, SHORTEN_OIDS, EXPAND_OIDS, CHECK_TODO_LIST, SKIP_UNNECESSARY_PICKS, REARRANGE_SQUASH, - ADD_EXEC, APPEND_TODO_HELP + ADD_EXEC, APPEND_TODO_HELP, EDIT_TODO } command = 0; struct option options[] = { OPT_BOOL(0, "ff", &opts.allow_ff, N_("allow fast-forward")), @@ -28,8 +28,6 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix) OPT_BOOL(0, "rebase-merges", &rebase_merges, N_("rebase merge commits")), OPT_BOOL(0, "rebase-cousins", &rebase_cousins, N_("keep original branch points of cousins")), - OPT_BOOL(0, "write-edit-todo", &write_edit_todo, -N_("append the edit-todo message to the todo-list")), OPT_CMDMODE(0, "continue", &command, N_("continue rebase"), CONTINUE), OPT_CMDMODE(0, "abort", &command, N_("abort rebase"), @@ -50,6 +48,9 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix) N_("insert exec commands in todo list"), ADD_EXEC), OPT_CMDMODE(0, "append-todo-help", &command, N_("insert the help in the todo list"), APPEND_TODO_HELP), + OPT_CMDMODE(0, "edit-todo", &command, + N_("edit the todo list during an interactive rebase"), + EDIT_TODO), OPT_END() }; @@ -90,6 +91,8 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix) if (command == ADD_EXEC && argc == 2) return !!sequencer_add_exec_commands(argv[1]); if (command == APPEND_TODO_HELP && argc == 1) - return !!append_todo_help(write_edit_todo, keep_empty); + return !!append_todo_help(0, keep_empty); + if (command == EDIT_TODO && argc == 1) + return !!edit_todo_list(flags); usage_with_options(builtin_rebase_helper_usage, options); } diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh index 94c23a7af2..2defe607f4 100644 --- a/git-rebase--interactive.sh +++ b/git-rebase--interactive.sh @@ -108,16 +108,7 @@ initiate_action () { --continue ;; edit-todo) - git stripspace --strip-comments <"$todo" >"$todo".new - mv -f "$todo".new "$todo" - collapse_todo_ids - git rebase--helper --append-todo-help --write-edit-todo - - git_sequence_editor "$todo" || - die "$(gettext "Could not execute editor")" - expand_todo_ids - - exit + exec git rebase--helper --edit-todo ;; show-current-patch) exec git show REBASE_HEAD -- diff --git a/rebase-interactive.c b/rebase-interactive.c index d7996bc8d9..403ecbf3c9 100644 --- a/rebase-interactive.c +++ b/rebase-interactive.c @@ -66,3 +66,34 @@ int append_todo_help(unsigned edit_todo, unsigned keep_empty) return ret; } + +int edit_todo_list(unsigned flags) +{ + struct strbuf buf = STRBUF_INIT; + const char *todo_file = rebase_path_todo(); + FILE *todo; + + if (strbuf_read_file(&buf, todo_file, 0) < 0) + return error_errno(_("could not read '
[GSoC][PATCH v4 01/20] sequencer: make two functions and an enum from sequencer.c public
This makes rebase_path_todo(), get_missing_commit_check_level() and the enum check_level accessible outside sequencer.c, renames check_level to missing_commit_check_level, and prefixes its value names by MISSING_COMMIT_ to avoid namespace pollution. This function and this enum will eventually be moved to rebase-interactive.c and become static again, so no special attention was given to the naming. This will be needed for the rewrite of append_todo_help() from shell to C, as it will be in a new library source file, rebase-interactive.c. Signed-off-by: Alban Gruin --- No code changes since v3. sequencer.c | 22 +- sequencer.h | 8 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/sequencer.c b/sequencer.c index 03c47405fb..0fc03dfe48 100644 --- a/sequencer.c +++ b/sequencer.c @@ -52,7 +52,7 @@ static GIT_PATH_FUNC(rebase_path, "rebase-merge") * the lines are processed, they are removed from the front of this * file and written to the tail of 'done'. */ -static GIT_PATH_FUNC(rebase_path_todo, "rebase-merge/git-rebase-todo") +GIT_PATH_FUNC(rebase_path_todo, "rebase-merge/git-rebase-todo") /* * The rebase command lines that have already been processed. A line * is moved here when it is first handled, before any associated user @@ -4245,24 +4245,20 @@ int transform_todos(unsigned flags) return i; } -enum check_level { - CHECK_IGNORE = 0, CHECK_WARN, CHECK_ERROR -}; - -static enum check_level get_missing_commit_check_level(void) +enum missing_commit_check_level get_missing_commit_check_level(void) { const char *value; if (git_config_get_value("rebase.missingcommitscheck", &value) || !strcasecmp("ignore", value)) - return CHECK_IGNORE; + return MISSING_COMMIT_CHECK_IGNORE; if (!strcasecmp("warn", value)) - return CHECK_WARN; + return MISSING_COMMIT_CHECK_WARN; if (!strcasecmp("error", value)) - return CHECK_ERROR; + return MISSING_COMMIT_CHECK_ERROR; warning(_("unrecognized setting %s for option " "rebase.missingCommitsCheck. Ignoring."), value); - return CHECK_IGNORE; + return MISSING_COMMIT_CHECK_IGNORE; } define_commit_slab(commit_seen, unsigned char); @@ -4274,7 +4270,7 @@ define_commit_slab(commit_seen, unsigned char); */ int check_todo_list(void) { - enum check_level check_level = get_missing_commit_check_level(); + enum missing_commit_check_level check_level = get_missing_commit_check_level(); struct strbuf todo_file = STRBUF_INIT; struct todo_list todo_list = TODO_LIST_INIT; struct strbuf missing = STRBUF_INIT; @@ -4291,7 +4287,7 @@ int check_todo_list(void) advise_to_edit_todo = res = parse_insn_buffer(todo_list.buf.buf, &todo_list); - if (res || check_level == CHECK_IGNORE) + if (res || check_level == MISSING_COMMIT_CHECK_IGNORE) goto leave_check; /* Mark the commits in git-rebase-todo as seen */ @@ -4326,7 +4322,7 @@ int check_todo_list(void) if (!missing.len) goto leave_check; - if (check_level == CHECK_ERROR) + if (check_level == MISSING_COMMIT_CHECK_ERROR) advise_to_edit_todo = res = 1; fprintf(stderr, diff --git a/sequencer.h b/sequencer.h index c5787c6b56..ffab798f1e 100644 --- a/sequencer.h +++ b/sequencer.h @@ -3,6 +3,7 @@ const char *git_path_commit_editmsg(void); const char *git_path_seq_dir(void); +const char *rebase_path_todo(void); #define APPEND_SIGNOFF_DEDUP (1u << 0) @@ -57,6 +58,12 @@ struct replay_opts { }; #define REPLAY_OPTS_INIT { .action = -1, .current_fixups = STRBUF_INIT } +enum missing_commit_check_level { + MISSING_COMMIT_CHECK_IGNORE = 0, + MISSING_COMMIT_CHECK_WARN, + MISSING_COMMIT_CHECK_ERROR +}; + /* 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); @@ -79,6 +86,7 @@ int sequencer_make_script(FILE *out, int argc, const char **argv, int sequencer_add_exec_commands(const char *command); int transform_todos(unsigned flags); +enum missing_commit_check_level get_missing_commit_check_level(void); int check_todo_list(void); int skip_unnecessary_picks(void); int rearrange_squash(void); -- 2.18.0
[GSoC][PATCH v4 02/20] rebase -i: rewrite append_todo_help() in C
This rewrites append_todo_help() from shell to C. It also incorporates some parts of initiate_action() and complete_action() that also write help texts to the todo file. This also introduces the source file rebase-interactive.c. This file will contain functions necessary for interactive rebase that are too specific for the sequencer, and is part of libgit.a. Two flags are added to rebase--helper.c: one to call append_todo_help() (`--append-todo-help`), and another one to tell append_todo_help() to write the help text suited for the edit-todo mode (`--write-edit-todo`). Finally, append_todo_help() is removed from git-rebase--interactive.sh to use `rebase--helper --append-todo-help` instead. Signed-off-by: Alban Gruin --- No code changes since v3. Makefile | 1 + builtin/rebase--helper.c | 11 -- git-rebase--interactive.sh | 52 ++--- rebase-interactive.c | 68 ++ rebase-interactive.h | 6 5 files changed, 86 insertions(+), 52 deletions(-) create mode 100644 rebase-interactive.c create mode 100644 rebase-interactive.h diff --git a/Makefile b/Makefile index 08e5c54549..909a687857 100644 --- a/Makefile +++ b/Makefile @@ -922,6 +922,7 @@ LIB_OBJS += protocol.o LIB_OBJS += quote.o LIB_OBJS += reachable.o LIB_OBJS += read-cache.o +LIB_OBJS += rebase-interactive.o LIB_OBJS += reflog-walk.o LIB_OBJS += refs.o LIB_OBJS += refs/files-backend.o diff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c index f7c2a5fdc8..05e73e71d4 100644 --- a/builtin/rebase--helper.c +++ b/builtin/rebase--helper.c @@ -3,6 +3,7 @@ #include "config.h" #include "parse-options.h" #include "sequencer.h" +#include "rebase-interactive.h" static const char * const builtin_rebase_helper_usage[] = { N_("git rebase--helper []"), @@ -12,12 +13,12 @@ static const char * const builtin_rebase_helper_usage[] = { int cmd_rebase__helper(int argc, const char **argv, const char *prefix) { struct replay_opts opts = REPLAY_OPTS_INIT; - unsigned flags = 0, keep_empty = 0, rebase_merges = 0; + unsigned flags = 0, keep_empty = 0, rebase_merges = 0, write_edit_todo = 0; int abbreviate_commands = 0, rebase_cousins = -1; enum { CONTINUE = 1, ABORT, MAKE_SCRIPT, SHORTEN_OIDS, EXPAND_OIDS, CHECK_TODO_LIST, SKIP_UNNECESSARY_PICKS, REARRANGE_SQUASH, - ADD_EXEC + ADD_EXEC, APPEND_TODO_HELP } command = 0; struct option options[] = { OPT_BOOL(0, "ff", &opts.allow_ff, N_("allow fast-forward")), @@ -27,6 +28,8 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix) OPT_BOOL(0, "rebase-merges", &rebase_merges, N_("rebase merge commits")), OPT_BOOL(0, "rebase-cousins", &rebase_cousins, N_("keep original branch points of cousins")), + OPT_BOOL(0, "write-edit-todo", &write_edit_todo, +N_("append the edit-todo message to the todo-list")), OPT_CMDMODE(0, "continue", &command, N_("continue rebase"), CONTINUE), OPT_CMDMODE(0, "abort", &command, N_("abort rebase"), @@ -45,6 +48,8 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix) N_("rearrange fixup/squash lines"), REARRANGE_SQUASH), OPT_CMDMODE(0, "add-exec-commands", &command, N_("insert exec commands in todo list"), ADD_EXEC), + OPT_CMDMODE(0, "append-todo-help", &command, + N_("insert the help in the todo list"), APPEND_TODO_HELP), OPT_END() }; @@ -84,5 +89,7 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix) return !!rearrange_squash(); if (command == ADD_EXEC && argc == 2) return !!sequencer_add_exec_commands(argv[1]); + if (command == APPEND_TODO_HELP && argc == 1) + return !!append_todo_help(write_edit_todo, keep_empty); usage_with_options(builtin_rebase_helper_usage, options); } diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh index 299ded2137..94c23a7af2 100644 --- a/git-rebase--interactive.sh +++ b/git-rebase--interactive.sh @@ -39,38 +39,6 @@ comment_for_reflog () { esac } -append_todo_help () { - gettext " -Commands: -p, pick = use commit -r, reword = use commit, but edit the commit message -e, edit = use commit, but stop for amending -s, squash = use commit, but meld into previous commit -f, fixup = like \"sq
[GSoC][PATCH v4 00/20] rebase -i: rewrite in C
This patch series rewrite the interactive rebase from shell to C. It is based on master (as of 2018-07-24). Changes since v3: - The `--verbose` option is stored directly into opts.verbose - Drop includes in rebase-interactive.h - skip_unnecessary_picks() now returns an object_id instead of a string - Add a test case to ensure interactive rebase aborts when the todo list only has commented-out commands - complete_action() aborts when the todo list only has commented-out commands - Drop the `keep_empty` parameter of complete_action() - Don’t remove the modes `--shorten-oids` and `--expand-oids` from git-rebase--helper - Replace `ret = !!x(); return ret` by `ret = x(); return !!ret` - Fail if `--make-script` is provided with two arguments instead of one - Rewrite write_basic_state() and init_basic_state() in C - Rewrite git-rebase--interactive.sh as a builtin Alban Gruin (20): sequencer: make two functions and an enum from sequencer.c public rebase -i: rewrite append_todo_help() in C editor: add a function to launch the sequence editor rebase -i: rewrite the edit-todo functionality in C sequencer: add a new function to silence a command, except if it fails rebase -i: rewrite setup_reflog_action() in C rebase -i: rewrite checkout_onto() in C sequencer: refactor append_todo_help() to write its message to a buffer sequencer: change the way skip_unnecessary_picks() returns its result t3404: todo list with commented-out commands only aborts rebase -i: rewrite complete_action() in C rebase -i: remove unused modes and functions rebase -i: implement the logic to initialize $revisions in C rebase -i: rewrite the rest of init_revisions_and_shortrevisions() in C rebase -i: rewrite write_basic_state() in C rebase -i: rewrite init_basic_state() in C rebase -i: implement the main part of interactive rebase as a builtin rebase--interactive2: rewrite the submodes of interactive rebase in C rebase -i: remove git-rebase--interactive.sh rebase -i: move rebase--helper modes to rebase--interactive .gitignore | 1 - Makefile | 5 +- builtin.h | 1 + builtin/rebase--helper.c | 88 -- builtin/rebase--interactive.c | 264 cache.h| 1 + editor.c | 27 ++- git-rebase--interactive.sh | 283 -- git-rebase--preserve-merges.sh | 10 +- git-rebase.sh | 47 - git.c | 2 +- rebase-interactive.c | 96 ++ rebase-interactive.h | 8 + sequencer.c| 311 +++-- sequencer.h| 19 +- strbuf.h | 2 + t/t3404-rebase-interactive.sh | 10 ++ 17 files changed, 729 insertions(+), 446 deletions(-) delete mode 100644 builtin/rebase--helper.c create mode 100644 builtin/rebase--interactive.c delete mode 100644 git-rebase--interactive.sh create mode 100644 rebase-interactive.c create mode 100644 rebase-interactive.h -- 2.18.0
ag/rebase-i-in-c, was Re: What's cooking in git.git (Jul 2018, #02; Wed, 18)
Hi Junio, Le 19/07/2018 à 00:03, Junio C Hamano a écrit : > * ag/rebase-i-in-c (2018-07-10) 13 commits > - rebase -i: rewrite the rest of init_revisions_and_shortrevisions in C > - rebase -i: implement the logic to initialize the variable $revision in C > - rebase--interactive: remove unused modes and functions > - rebase--interactive: rewrite complete_action() in C > - sequencer: change the way skip_unnecessary_picks() returns its result > - sequencer: refactor append_todo_help() to write its message to a buffer > - rebase -i: rewrite checkout_onto() in C > - rebase -i: rewrite setup_reflog_action() in C > - sequencer: add a new function to silence a command, except if it fails > - rebase-interactive: rewrite the edit-todo functionality in C > - editor: add a function to launch the sequence editor > - rebase--interactive: rewrite append_todo_help() in C > - sequencer: make two functions and an enum from sequencer.c public > > Piecemeal rewrite of the remaining "rebase -i" machinery in C. > > Expecting a reroll. > > The early parts of the series seem solidifying; perhaps with a > reroll or two, they become 'next' material? I am working on new changes (rewriting init_basic_state(), and making rebase--interactive a builtin), so it will probably need at least one more reroll before being trully ready for 'next'. It’s not completely finished yet, I hope to send it Monday or Tuesday. Cheers, Alban
[GSoC] GSoC with git, week 11
Hi, I published a new blog post about last week: https://blog.pa1ch.fr/posts/2018/07/17/en/gsoc2018-week11.html Cheers, Alban
Re: [GSoC][PATCH v3 10/13] rebase--interactive: rewrite complete_action() in C
Hi Junio, Le 11/07/2018 à 00:33, Junio C Hamano a écrit : > Alban Gruin writes: >> -complete_action >> +exec git rebase--helper --complete-action "$shortrevisions" >> "$onto_name" \ >> +"$shortonto" "$orig_head" "$cmd" $allow_empty_message \ >> +${autosquash:+--autosquash} ${keep_empty:+--keep-empty} \ >> +${verbose:+--verbose} ${force_rebase:+--no-ff} > > The $allow_empty_message and later options are all dashed ones. > git-rebase.sh gives us either empty or --allow-empty-message in the > variable for $allow_empty_message, and if you follow suit to prepare > all the other variables that way, the ugly ${frotz+=--frotz} dance > will all become unnecessary here. > Good idea. >> +int complete_action(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, unsigned keep_empty) >> +{ >> +const char *shortonto, *todo_file = rebase_path_todo(); >> +struct todo_list todo_list = TODO_LIST_INIT; >> +struct strbuf *buf = &(todo_list.buf); >> +struct object_id oid; >> +struct stat st; >> + >> +get_oid(onto, &oid); >> +shortonto = find_unique_abbrev(&oid, DEFAULT_ABBREV); >> + >> +if (!lstat(todo_file, &st) && st.st_size == 0 && >> +write_message("noop\n", 5, todo_file, 0)) >> +return error_errno(_("could not write '%s'"), todo_file); > > Wait a minute... thinking back to the early "age-old ommission" > topic, can the todo file be a non-empty file that does not have any > command (e.g. just a single blank line, or full of comments and > nothing else)? The original wouldn't have added "noop" and then the > first "do we have anything to do?" check would still have been > necessary, which would mean that ff74126c's not removing the first > check was actually not a bug but was a cautious and sensible thing > to do, and removal of that exact check by this commit becomes a > regression. So,... can the todo file be a non-empty file that does > not have any command in it at this point? > Hum, yes, if the commits are empty, and if rebase was invoked without the `--keep-empty` flag. In this case, it would die with the message “Nothing to do”, instead of dropping the commit altogether. I will add a test case in the next iteration. >> +if (autosquash && rearrange_squash()) >> +return 0; > > The original, when rearrange-squash failed, exited with failure, > like so: > > - test -z "$autosquash" || git rebase--helper --rearrange-squash || exit > > Now this function returns success when rearrange_squash fails. > Is that intended? > Yes, it is. I just saw in the man page that `exit` returns the last exit status. >> +if (cmd && *cmd) > > Shouldn't it be a BUG (programming error) if cmd == NULL? I thought > the caller of complete_action() in this patch insisted that it got > argc == 6 or something, so *cmd might be NUL but cmd would never be > NULL if I understand your code correctly. IOW, shouldn't the line > be more like: > > if (!cmd) > BUG("..."); > if (*cmd) > > ? > I don’t know, it’s not really problematic if cmd is NULL. And I think that when interactive rebase will be a builtin, it will be possible for cmd to be NULL. > >> +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)) { > > Nice that we have parse* function. We do not have to work with > stripspace plus "wc -l" ;-). > >> +todo_list_release(&todo_list); >> +return error(_("unusable todo list: '%s'"), todo_file); > > When the users see this error message, is it easy for them to > diagnose what went wrong (e.g. has parse_insn_buffer() already > issued some message to help pinpoint which insn in the todo list is > misspelt, for example)? > Yes, parse_insn_buffer() will say which line caused the error. But at this point, the user should not have changed the todo-list, so this error should never appear. Perhaps this is a good use case of BUG()? >> +} >> + >> +strbuf_addch(buf, '\n'); >> +strbuf_commented_addf(buf, Q_("Rebase %
[GSoC] GSoC with git, week 10
Hi, I published a new blog post: https://blog.pa1ch.fr/posts/2018/07/10/en/gsoc2018-week-10.html Cheers, Alban
Re: [GSoC][PATCH v3 03/13] editor: add a function to launch the sequence editor
Le 10/07/2018 à 14:15, Alban Gruin a écrit : > As part of the rewrite of interactive rebase, the sequencer will need to > open the sequence editor to allow the user to edit the todo list. > Instead of duplicating the existing launch_editor() function, this > refactors it to a new function, launch_specified_editor(), which takes > the editor as a parameter, in addition to the path, the buffer and the > environment variables. launch_sequence_editor() is then added to launch > the sequence editor. > > Signed-off-by: Alban Gruin > --- And this has not changed from what have been queued in pu (ag/rebase-i-in-c), and from v2.
Re: [GSoC][PATCH v3 02/13] rebase--interactive: rewrite append_todo_help() in C
Le 10/07/2018 à 14:15, Alban Gruin a écrit : > This rewrites append_todo_help() from shell to C. It also incorporates > some parts of initiate_action() and complete_action() that also write > help texts to the todo file. > > This also introduces the source file rebase-interactive.c. This file > will contain functions necessary for interactive rebase that are too > specific for the sequencer, and is part of libgit.a. > > Two flags are added to rebase--helper.c: one to call > append_todo_help() (`--append-todo-help`), and another one to tell > append_todo_help() to write the help text suited for the edit-todo > mode (`--write-edit-todo`). > > Finally, append_todo_help() is removed from git-rebase--interactive.sh > to use `rebase--helper --append-todo-help` instead. > > Signed-off-by: Alban Gruin > --- > Unchanged from what have been queued on `pu` (ag/rebase-i-in-c), and > from v2. Sorry, this has actually changed since v2.
[GSoC][PATCH v3 04/13] rebase-interactive: rewrite the edit-todo functionality in C
This rewrites the edit-todo functionality from shell to C. To achieve that, a new command mode, `edit-todo`, is added, and the `write-edit-todo` flag is removed, as the shell script does not need to write the edit todo help message to the todo list anymore. The shell version is then stripped in favour of a call to the helper. Signed-off-by: Alban Gruin --- Unchanged from v2. builtin/rebase--helper.c | 13 - git-rebase--interactive.sh | 11 +-- rebase-interactive.c | 31 +++ rebase-interactive.h | 1 + 4 files changed, 41 insertions(+), 15 deletions(-) diff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c index 05e73e71d..731a64971 100644 --- a/builtin/rebase--helper.c +++ b/builtin/rebase--helper.c @@ -13,12 +13,12 @@ static const char * const builtin_rebase_helper_usage[] = { int cmd_rebase__helper(int argc, const char **argv, const char *prefix) { struct replay_opts opts = REPLAY_OPTS_INIT; - unsigned flags = 0, keep_empty = 0, rebase_merges = 0, write_edit_todo = 0; + unsigned flags = 0, keep_empty = 0, rebase_merges = 0; int abbreviate_commands = 0, rebase_cousins = -1; enum { CONTINUE = 1, ABORT, MAKE_SCRIPT, SHORTEN_OIDS, EXPAND_OIDS, CHECK_TODO_LIST, SKIP_UNNECESSARY_PICKS, REARRANGE_SQUASH, - ADD_EXEC, APPEND_TODO_HELP + ADD_EXEC, APPEND_TODO_HELP, EDIT_TODO } command = 0; struct option options[] = { OPT_BOOL(0, "ff", &opts.allow_ff, N_("allow fast-forward")), @@ -28,8 +28,6 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix) OPT_BOOL(0, "rebase-merges", &rebase_merges, N_("rebase merge commits")), OPT_BOOL(0, "rebase-cousins", &rebase_cousins, N_("keep original branch points of cousins")), - OPT_BOOL(0, "write-edit-todo", &write_edit_todo, -N_("append the edit-todo message to the todo-list")), OPT_CMDMODE(0, "continue", &command, N_("continue rebase"), CONTINUE), OPT_CMDMODE(0, "abort", &command, N_("abort rebase"), @@ -50,6 +48,9 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix) N_("insert exec commands in todo list"), ADD_EXEC), OPT_CMDMODE(0, "append-todo-help", &command, N_("insert the help in the todo list"), APPEND_TODO_HELP), + OPT_CMDMODE(0, "edit-todo", &command, + N_("edit the todo list during an interactive rebase"), + EDIT_TODO), OPT_END() }; @@ -90,6 +91,8 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix) if (command == ADD_EXEC && argc == 2) return !!sequencer_add_exec_commands(argv[1]); if (command == APPEND_TODO_HELP && argc == 1) - return !!append_todo_help(write_edit_todo, keep_empty); + return !!append_todo_help(0, keep_empty); + if (command == EDIT_TODO && argc == 1) + return !!edit_todo_list(flags); usage_with_options(builtin_rebase_helper_usage, options); } diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh index 94c23a7af..2defe607f 100644 --- a/git-rebase--interactive.sh +++ b/git-rebase--interactive.sh @@ -108,16 +108,7 @@ initiate_action () { --continue ;; edit-todo) - git stripspace --strip-comments <"$todo" >"$todo".new - mv -f "$todo".new "$todo" - collapse_todo_ids - git rebase--helper --append-todo-help --write-edit-todo - - git_sequence_editor "$todo" || - die "$(gettext "Could not execute editor")" - expand_todo_ids - - exit + exec git rebase--helper --edit-todo ;; show-current-patch) exec git show REBASE_HEAD -- diff --git a/rebase-interactive.c b/rebase-interactive.c index d7996bc8d..403ecbf3c 100644 --- a/rebase-interactive.c +++ b/rebase-interactive.c @@ -66,3 +66,34 @@ int append_todo_help(unsigned edit_todo, unsigned keep_empty) return ret; } + +int edit_todo_list(unsigned flags) +{ + struct strbuf buf = STRBUF_INIT; + const char *todo_file = rebase_path_todo(); + FILE *todo; + + if (strbuf_read_file(&buf, todo_file, 0) < 0) + return error_errno(_("could not read '
[GSoC][PATCH v3 06/13] rebase -i: rewrite setup_reflog_action() in C
This rewrites (the misnamed) setup_reflog_action() from shell to C. The new version is called prepare_branch_to_be_rebased(). A new command is added to rebase--helper.c, “checkout-base”, as well as a new flag, “verbose”, to avoid silencing the output of the checkout operation called by checkout_base_commit(). The function `run_git_checkout()` will also be used in the next commit, therefore its code is not part of `checkout_base_commit()`. The shell version is then stripped in favour of a call to the helper. As $GIT_REFLOG_ACTION is no longer set at the first call of checkout_onto(), a call to comment_for_reflog() is added at the beginning of this function. Signed-off-by: Alban Gruin --- builtin/rebase--helper.c | 10 -- git-rebase--interactive.sh | 16 ++-- sequencer.c| 30 ++ sequencer.h| 2 ++ 4 files changed, 42 insertions(+), 16 deletions(-) diff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c index 731a64971..76bdc6fdb 100644 --- a/builtin/rebase--helper.c +++ b/builtin/rebase--helper.c @@ -13,12 +13,12 @@ static const char * const builtin_rebase_helper_usage[] = { int cmd_rebase__helper(int argc, const char **argv, const char *prefix) { struct replay_opts opts = REPLAY_OPTS_INIT; - unsigned flags = 0, keep_empty = 0, rebase_merges = 0; + unsigned flags = 0, keep_empty = 0, rebase_merges = 0, verbose = 0; int abbreviate_commands = 0, rebase_cousins = -1; enum { CONTINUE = 1, ABORT, MAKE_SCRIPT, SHORTEN_OIDS, EXPAND_OIDS, CHECK_TODO_LIST, SKIP_UNNECESSARY_PICKS, REARRANGE_SQUASH, - ADD_EXEC, APPEND_TODO_HELP, EDIT_TODO + ADD_EXEC, APPEND_TODO_HELP, EDIT_TODO, PREPARE_BRANCH } command = 0; struct option options[] = { OPT_BOOL(0, "ff", &opts.allow_ff, N_("allow fast-forward")), @@ -28,6 +28,7 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix) OPT_BOOL(0, "rebase-merges", &rebase_merges, N_("rebase merge commits")), OPT_BOOL(0, "rebase-cousins", &rebase_cousins, N_("keep original branch points of cousins")), + OPT__VERBOSE(&verbose, N_("be verbose")), OPT_CMDMODE(0, "continue", &command, N_("continue rebase"), CONTINUE), OPT_CMDMODE(0, "abort", &command, N_("abort rebase"), @@ -51,6 +52,8 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix) OPT_CMDMODE(0, "edit-todo", &command, N_("edit the todo list during an interactive rebase"), EDIT_TODO), + OPT_CMDMODE(0, "prepare-branch", &command, + N_("prepare the branch to be rebased"), PREPARE_BRANCH), OPT_END() }; @@ -60,6 +63,7 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix) opts.action = REPLAY_INTERACTIVE_REBASE; opts.allow_ff = 1; opts.allow_empty = 1; + opts.verbose = verbose; argc = parse_options(argc, argv, NULL, options, builtin_rebase_helper_usage, PARSE_OPT_KEEP_ARGV0); @@ -94,5 +98,7 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix) return !!append_todo_help(0, keep_empty); if (command == EDIT_TODO && argc == 1) return !!edit_todo_list(flags); + if (command == PREPARE_BRANCH && argc == 2) + return !!prepare_branch_to_be_rebased(&opts, argv[1]); usage_with_options(builtin_rebase_helper_usage, options); } diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh index 2defe607f..77e972bb6 100644 --- a/git-rebase--interactive.sh +++ b/git-rebase--interactive.sh @@ -72,6 +72,7 @@ collapse_todo_ids() { # Switch to the branch in $into and notify it in the reflog checkout_onto () { + comment_for_reflog start GIT_REFLOG_ACTION="$GIT_REFLOG_ACTION: checkout $onto_name" output git checkout $onto || die_abort "$(gettext "could not detach HEAD")" git update-ref ORIG_HEAD $orig_head @@ -119,19 +120,6 @@ initiate_action () { esac } -setup_reflog_action () { - comment_for_reflog start - - if test ! -z "$switch_to" - then - GIT_REFLOG_ACTION="$GIT_REFLOG_ACTION: checkout $switch_to" - output git checkout "$switch_to" -- || - die "$(eval_gettext "Could not checkout \$switch_to")" - - comment_for_reflog start -
[GSoC][PATCH v3 08/13] sequencer: refactor append_todo_help() to write its message to a buffer
This refactors append_todo_help() to write its message to a buffer instead of the todo-list. This is needed for the rewrite of complete_action(), which will come after the next commit. As rebase--helper still needs the file manipulation part of append_todo_help(), it is extracted to a temporary function, append_todo_help_to_file(). This function will go away after the rewrite of complete_action(). Signed-off-by: Alban Gruin --- builtin/rebase--helper.c | 2 +- rebase-interactive.c | 45 rebase-interactive.h | 7 ++- 3 files changed, 39 insertions(+), 15 deletions(-) diff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c index 1d9595bdb..b9af96af7 100644 --- a/builtin/rebase--helper.c +++ b/builtin/rebase--helper.c @@ -98,7 +98,7 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix) if (command == ADD_EXEC && argc == 2) return !!sequencer_add_exec_commands(argv[1]); if (command == APPEND_TODO_HELP && argc == 1) - return !!append_todo_help(0, keep_empty); + return !!append_todo_help_to_file(0, keep_empty); if (command == EDIT_TODO && argc == 1) return !!edit_todo_list(flags); if (command == PREPARE_BRANCH && argc == 2) diff --git a/rebase-interactive.c b/rebase-interactive.c index 403ecbf3c..d8b946559 100644 --- a/rebase-interactive.c +++ b/rebase-interactive.c @@ -4,11 +4,9 @@ #include "sequencer.h" #include "strbuf.h" -int append_todo_help(unsigned edit_todo, unsigned keep_empty) +void append_todo_help(unsigned edit_todo, unsigned keep_empty, + struct strbuf *buf) { - struct strbuf buf = STRBUF_INIT; - FILE *todo; - int ret; const char *msg = _("\nCommands:\n" "p, pick = use commit\n" "r, reword = use commit, but edit the commit message\n" @@ -26,11 +24,7 @@ int append_todo_help(unsigned edit_todo, unsigned keep_empty) "\n" "These lines can be re-ordered; they are executed from top to bottom.\n"); - todo = fopen_or_warn(rebase_path_todo(), "a"); - if (!todo) - return 1; - - strbuf_add_commented_lines(&buf, msg, strlen(msg)); + strbuf_add_commented_lines(buf, msg, strlen(msg)); if (get_missing_commit_check_level() == MISSING_COMMIT_CHECK_ERROR) msg = _("\nDo not remove any line. Use 'drop' " @@ -39,7 +33,7 @@ int append_todo_help(unsigned edit_todo, unsigned keep_empty) msg = _("\nIf you remove a line here " "THAT COMMIT WILL BE LOST.\n"); - strbuf_add_commented_lines(&buf, msg, strlen(msg)); + strbuf_add_commented_lines(buf, msg, strlen(msg)); if (edit_todo) msg = _("\nYou are editing the todo file " @@ -50,12 +44,25 @@ int append_todo_help(unsigned edit_todo, unsigned keep_empty) msg = _("\nHowever, if you remove everything, " "the rebase will be aborted.\n\n"); - strbuf_add_commented_lines(&buf, msg, strlen(msg)); + strbuf_add_commented_lines(buf, msg, strlen(msg)); if (!keep_empty) { msg = _("Note that empty commits are commented out"); - strbuf_add_commented_lines(&buf, msg, strlen(msg)); + strbuf_add_commented_lines(buf, msg, strlen(msg)); } +} + +int append_todo_help_to_file(unsigned edit_todo, unsigned keep_empty) +{ + struct strbuf buf = STRBUF_INIT; + FILE *todo; + int ret; + + todo = fopen_or_warn(rebase_path_todo(), "a"); + if (!todo) + return 1; + + append_todo_help(edit_todo, keep_empty, &buf); ret = fputs(buf.buf, todo); if (ret < 0) @@ -88,7 +95,19 @@ int edit_todo_list(unsigned flags) strbuf_release(&buf); transform_todos(flags | TODO_LIST_SHORTEN_IDS); - append_todo_help(1, 0); + + strbuf_read_file(&buf, todo_file, 0); + append_todo_help(1, 0, &buf); + + todo = fopen_or_warn(todo_file, "w"); + if (!todo) { + strbuf_release(&buf); + return 1; + } + + strbuf_write(&buf, todo); + fclose(todo); + strbuf_release(&buf); if (launch_sequence_editor(todo_file, NULL, NULL)) return 1; diff --git a/rebase-interactive.h b/rebase-interactive.h index 155219e74..c0ba83be3 100644 --- a/rebase-interactive.h +++ b/rebase-interactive.h @@ -1,7 +1,12 @@ #ifndef REBASE_INTERACTIVE_H #define REBASE_INTERACTIVE_H -int append_todo_help(unsigned edit_todo, unsigned keep_empty); +#include +#include + +void append_todo_help(unsigned edit_todo, unsigned keep_empty, + struct strbuf *buf); +int append_todo_help_to_file(unsigned edit_todo, unsigned keep_empty); int edit_todo_list(unsigned flags); #endif -- 2.18.0
[GSoC][PATCH v3 00/13] rebase -i: rewrite some parts in C
This patch series rewrites some parts of interactive rebase from shell to C: - append_todo_help(). The C version covers a bit more than the shell version. - The edit-todo functionnality. - The reflog operations. - complete_action(). - init_revisions_and_shortrevisions(). This patch series is based on master (as of 2018-07-10). Changes since v2: - Lowercasing error messages. - Removing a comment from run_command_silent_on_success(). - Using the `else` keyword to call run_command_silent_on_success() or run_command() in run_git_commit() and run_git_checkout(). - Dropping the `verbose` parameter in run_git_checkout(), prepare_branch_to_be_rebased(), and checkout_onto(), as the replay_opts structure already has a `verbose` field. - Rewriting complete_action() and init_revisions_and_shortrevisions(). Alban Gruin (13): sequencer: make two functions and an enum from sequencer.c public rebase--interactive: rewrite append_todo_help() in C editor: add a function to launch the sequence editor rebase-interactive: rewrite the edit-todo functionality in C sequencer: add a new function to silence a command, except if it fails rebase -i: rewrite setup_reflog_action() in C rebase -i: rewrite checkout_onto() in C sequencer: refactor append_todo_help() to write its message to a buffer sequencer: change the way skip_unnecessary_picks() returns its result rebase--interactive: rewrite complete_action() in C rebase--interactive: remove unused modes and functions rebase -i: implement the logic to initialize the variable $revision in C rebase -i: rewrite the rest of init_revisions_and_shortrevisions in C Makefile | 1 + builtin/rebase--helper.c | 123 + cache.h| 1 + editor.c | 27 - git-rebase--interactive.sh | 216 ++--- git-rebase.sh | 2 +- rebase-interactive.c | 96 + rebase-interactive.h | 11 ++ sequencer.c| 215 +--- sequencer.h| 15 ++- strbuf.h | 2 + 11 files changed, 439 insertions(+), 270 deletions(-) create mode 100644 rebase-interactive.c create mode 100644 rebase-interactive.h -- 2.18.0
[GSoC][PATCH v3 11/13] rebase--interactive: remove unused modes and functions
This removes the modes `--skip-unnecessary-picks`, `--append-todo-help`, `--checkout-onto`, `--shorten-ids` and `--expand-ids` from rebase--helper.c, the functions of git-rebase--interactive.sh that were rendered useless by the rewrite of complete_action(), and append_todo_help_to_file() from rebase-interactive.c. skip_unnecessary_picks() and checkout_onto() becomes static, as they are only used inside of the sequencer. Signed-off-by: Alban Gruin --- builtin/rebase--helper.c | 32 +++- git-rebase--interactive.sh | 50 -- rebase-interactive.c | 22 - rebase-interactive.h | 1 - sequencer.c| 8 +++--- sequencer.h| 4 --- 6 files changed, 7 insertions(+), 110 deletions(-) diff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c index bb3698dba..8ab808da4 100644 --- a/builtin/rebase--helper.c +++ b/builtin/rebase--helper.c @@ -15,13 +15,10 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix) struct replay_opts opts = REPLAY_OPTS_INIT; unsigned flags = 0, keep_empty = 0, rebase_merges = 0, verbose = 0, autosquash = 0; - int abbreviate_commands = 0, rebase_cousins = -1, ret; - const char *oid = NULL; + int abbreviate_commands = 0, rebase_cousins = -1; enum { - CONTINUE = 1, ABORT, MAKE_SCRIPT, SHORTEN_OIDS, EXPAND_OIDS, - CHECK_TODO_LIST, SKIP_UNNECESSARY_PICKS, REARRANGE_SQUASH, - ADD_EXEC, APPEND_TODO_HELP, EDIT_TODO, PREPARE_BRANCH, - CHECKOUT_ONTO, COMPLETE_ACTION + CONTINUE = 1, ABORT, MAKE_SCRIPT, CHECK_TODO_LIST, REARRANGE_SQUASH, + ADD_EXEC, EDIT_TODO, PREPARE_BRANCH, COMPLETE_ACTION } command = 0; struct option options[] = { OPT_BOOL(0, "ff", &opts.allow_ff, N_("allow fast-forward")), @@ -40,27 +37,17 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix) ABORT), OPT_CMDMODE(0, "make-script", &command, N_("make rebase script"), MAKE_SCRIPT), - OPT_CMDMODE(0, "shorten-ids", &command, - N_("shorten commit ids in the todo list"), SHORTEN_OIDS), - OPT_CMDMODE(0, "expand-ids", &command, - N_("expand commit ids in the todo list"), EXPAND_OIDS), 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_CMDMODE(0, "add-exec-commands", &command, N_("insert exec commands in todo list"), ADD_EXEC), - OPT_CMDMODE(0, "append-todo-help", &command, - N_("insert the help in the todo list"), APPEND_TODO_HELP), OPT_CMDMODE(0, "edit-todo", &command, N_("edit the todo list during an interactive rebase"), EDIT_TODO), OPT_CMDMODE(0, "prepare-branch", &command, N_("prepare the branch to be rebased"), PREPARE_BRANCH), - OPT_CMDMODE(0, "checkout-onto", &command, - N_("checkout a commit"), CHECKOUT_ONTO), OPT_CMDMODE(0, "complete-action", &command, N_("complete the action"), COMPLETE_ACTION), OPT_END() @@ -81,7 +68,6 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix) flags |= abbreviate_commands ? TODO_LIST_ABBREVIATE_CMDS : 0; flags |= rebase_merges ? TODO_LIST_REBASE_MERGES : 0; flags |= rebase_cousins > 0 ? TODO_LIST_REBASE_COUSINS : 0; - flags |= command == SHORTEN_OIDS ? TODO_LIST_SHORTEN_IDS : 0; if (rebase_cousins >= 0 && !rebase_merges) warning(_("--[no-]rebase-cousins has no effect without " @@ -93,28 +79,16 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix) return !!sequencer_remove_state(&opts); if (command == MAKE_SCRIPT && argc > 1) return !!sequencer_make_script(stdout, argc, argv, flags); - if ((command == SHORTEN_OIDS || command == EXPAND_OIDS) && argc ==
[GSoC][PATCH v3 10/13] rebase--interactive: rewrite complete_action() in C
This rewrites complete_action() from shell to C. A new mode is added to rebase--helper (`--complete-action`), as well as a new flag (`--autosquash`). Finally, complete_action() is stripped from git-rebase--interactive.sh. The original complete_action() checked twice that the todo-list had at least one operations (the first check took place after the help message was inserted, the second after the user edited the todo-list). If there are no actions, complete_action() would return with the code 2. This is a special case for rebase -i and -p; git-rebase.sh would then apply the autostash, delete the state directory, and die with the message "nothing to do". This rewrite remove the first check (because a noop is added to the todo-list if it is empty). For the second case, the cleanup is rewritten in C instead of returning 2. As rebase -i no longer returns 2, the comment describing this behaviour in git-rebase.sh is updated to reflect this change. Signed-off-by: Alban Gruin --- builtin/rebase--helper.c | 13 +- git-rebase--interactive.sh | 53 ++- git-rebase.sh | 2 +- sequencer.c| 89 ++ sequencer.h| 4 ++ 5 files changed, 109 insertions(+), 52 deletions(-) diff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c index d4cfe43e7..bb3698dba 100644 --- a/builtin/rebase--helper.c +++ b/builtin/rebase--helper.c @@ -13,14 +13,15 @@ static const char * const builtin_rebase_helper_usage[] = { int cmd_rebase__helper(int argc, const char **argv, const char *prefix) { struct replay_opts opts = REPLAY_OPTS_INIT; - unsigned flags = 0, keep_empty = 0, rebase_merges = 0, verbose = 0; + unsigned flags = 0, keep_empty = 0, rebase_merges = 0, verbose = 0, + autosquash = 0; int abbreviate_commands = 0, rebase_cousins = -1, ret; const char *oid = NULL; enum { CONTINUE = 1, ABORT, MAKE_SCRIPT, SHORTEN_OIDS, EXPAND_OIDS, CHECK_TODO_LIST, SKIP_UNNECESSARY_PICKS, REARRANGE_SQUASH, ADD_EXEC, APPEND_TODO_HELP, EDIT_TODO, PREPARE_BRANCH, - CHECKOUT_ONTO + CHECKOUT_ONTO, COMPLETE_ACTION } command = 0; struct option options[] = { OPT_BOOL(0, "ff", &opts.allow_ff, N_("allow fast-forward")), @@ -30,6 +31,8 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix) OPT_BOOL(0, "rebase-merges", &rebase_merges, N_("rebase merge commits")), OPT_BOOL(0, "rebase-cousins", &rebase_cousins, N_("keep original branch points of cousins")), + OPT_BOOL(0, "autosquash", &autosquash, +N_("move commits thas begin with squash!/fixup!")), OPT__VERBOSE(&verbose, N_("be verbose")), OPT_CMDMODE(0, "continue", &command, N_("continue rebase"), CONTINUE), @@ -58,6 +61,8 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix) N_("prepare the branch to be rebased"), PREPARE_BRANCH), OPT_CMDMODE(0, "checkout-onto", &command, N_("checkout a commit"), CHECKOUT_ONTO), + OPT_CMDMODE(0, "complete-action", &command, + N_("complete the action"), COMPLETE_ACTION), OPT_END() }; @@ -110,5 +115,9 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix) return !!prepare_branch_to_be_rebased(&opts, argv[1]); if (command == CHECKOUT_ONTO && argc == 4) return !!checkout_onto(&opts, argv[1], argv[2], argv[3]); + if (command == COMPLETE_ACTION && argc == 6) + return !!complete_action(&opts, flags, argv[1], argv[2], argv[3], +argv[4], argv[5], autosquash, keep_empty); + usage_with_options(builtin_rebase_helper_usage, options); } diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh index b68f108f2..59dc4888a 100644 --- a/git-rebase--interactive.sh +++ b/git-rebase--interactive.sh @@ -127,54 +127,6 @@ init_revisions_and_shortrevisions () { fi } -complete_action() { - test -s "$todo" || echo noop >> "$todo" - test -z "$autosquash" || git rebase--helper --rearrange-squash || exit - test -n "$cmd" && git rebase--helper --add-exec-commands "$cmd" - - todocount=$(git stripspace --strip-comments <"$todo" | wc -l) - todocount=${todocount##* } - -cat >>"$todo&quo
[GSoC][PATCH v3 01/13] sequencer: make two functions and an enum from sequencer.c public
This makes rebase_path_todo(), get_missing_commit_check_level() and the enum check_level accessible outside sequencer.c. check_level is renamed missing_commit_check_level, and its value names are prefixed by MISSING_COMMIT_ to avoid namespace pollution. This function and this enum will eventually be moved to rebase-interactive.c and become static again, so no special attention was given to the naming. This will be needed for the rewrite of append_todo_help() from shell to C, as it will be in a new library source file, rebase-interactive.c. Signed-off-by: Alban Gruin --- Unchanged from v2. sequencer.c | 22 +- sequencer.h | 8 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/sequencer.c b/sequencer.c index 5354d4d51..57fd58bc1 100644 --- a/sequencer.c +++ b/sequencer.c @@ -51,7 +51,7 @@ static GIT_PATH_FUNC(rebase_path, "rebase-merge") * the lines are processed, they are removed from the front of this * file and written to the tail of 'done'. */ -static GIT_PATH_FUNC(rebase_path_todo, "rebase-merge/git-rebase-todo") +GIT_PATH_FUNC(rebase_path_todo, "rebase-merge/git-rebase-todo") /* * The rebase command lines that have already been processed. A line * is moved here when it is first handled, before any associated user @@ -4221,24 +4221,20 @@ int transform_todos(unsigned flags) return i; } -enum check_level { - CHECK_IGNORE = 0, CHECK_WARN, CHECK_ERROR -}; - -static enum check_level get_missing_commit_check_level(void) +enum missing_commit_check_level get_missing_commit_check_level(void) { const char *value; if (git_config_get_value("rebase.missingcommitscheck", &value) || !strcasecmp("ignore", value)) - return CHECK_IGNORE; + return MISSING_COMMIT_CHECK_IGNORE; if (!strcasecmp("warn", value)) - return CHECK_WARN; + return MISSING_COMMIT_CHECK_WARN; if (!strcasecmp("error", value)) - return CHECK_ERROR; + return MISSING_COMMIT_CHECK_ERROR; warning(_("unrecognized setting %s for option " "rebase.missingCommitsCheck. Ignoring."), value); - return CHECK_IGNORE; + return MISSING_COMMIT_CHECK_IGNORE; } define_commit_slab(commit_seen, unsigned char); @@ -4250,7 +4246,7 @@ define_commit_slab(commit_seen, unsigned char); */ int check_todo_list(void) { - enum check_level check_level = get_missing_commit_check_level(); + enum missing_commit_check_level check_level = get_missing_commit_check_level(); struct strbuf todo_file = STRBUF_INIT; struct todo_list todo_list = TODO_LIST_INIT; struct strbuf missing = STRBUF_INIT; @@ -4267,7 +4263,7 @@ int check_todo_list(void) advise_to_edit_todo = res = parse_insn_buffer(todo_list.buf.buf, &todo_list); - if (res || check_level == CHECK_IGNORE) + if (res || check_level == MISSING_COMMIT_CHECK_IGNORE) goto leave_check; /* Mark the commits in git-rebase-todo as seen */ @@ -4302,7 +4298,7 @@ int check_todo_list(void) if (!missing.len) goto leave_check; - if (check_level == CHECK_ERROR) + if (check_level == MISSING_COMMIT_CHECK_ERROR) advise_to_edit_todo = res = 1; fprintf(stderr, diff --git a/sequencer.h b/sequencer.h index c5787c6b5..ffab798f1 100644 --- a/sequencer.h +++ b/sequencer.h @@ -3,6 +3,7 @@ const char *git_path_commit_editmsg(void); const char *git_path_seq_dir(void); +const char *rebase_path_todo(void); #define APPEND_SIGNOFF_DEDUP (1u << 0) @@ -57,6 +58,12 @@ struct replay_opts { }; #define REPLAY_OPTS_INIT { .action = -1, .current_fixups = STRBUF_INIT } +enum missing_commit_check_level { + MISSING_COMMIT_CHECK_IGNORE = 0, + MISSING_COMMIT_CHECK_WARN, + MISSING_COMMIT_CHECK_ERROR +}; + /* 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); @@ -79,6 +86,7 @@ int sequencer_make_script(FILE *out, int argc, const char **argv, int sequencer_add_exec_commands(const char *command); int transform_todos(unsigned flags); +enum missing_commit_check_level get_missing_commit_check_level(void); int check_todo_list(void); int skip_unnecessary_picks(void); int rearrange_squash(void); -- 2.18.0
[GSoC][PATCH v3 07/13] rebase -i: rewrite checkout_onto() in C
This rewrites checkout_onto() from shell to C. A new command (“checkout-onto”) is added to rebase--helper.c. The shell version is then stripped. Signed-off-by: Alban Gruin --- builtin/rebase--helper.c | 7 ++- git-rebase--interactive.sh | 25 - sequencer.c| 19 +++ sequencer.h| 3 +++ 4 files changed, 32 insertions(+), 22 deletions(-) diff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c index 76bdc6fdb..1d9595bdb 100644 --- a/builtin/rebase--helper.c +++ b/builtin/rebase--helper.c @@ -18,7 +18,8 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix) enum { CONTINUE = 1, ABORT, MAKE_SCRIPT, SHORTEN_OIDS, EXPAND_OIDS, CHECK_TODO_LIST, SKIP_UNNECESSARY_PICKS, REARRANGE_SQUASH, - ADD_EXEC, APPEND_TODO_HELP, EDIT_TODO, PREPARE_BRANCH + ADD_EXEC, APPEND_TODO_HELP, EDIT_TODO, PREPARE_BRANCH, + CHECKOUT_ONTO } command = 0; struct option options[] = { OPT_BOOL(0, "ff", &opts.allow_ff, N_("allow fast-forward")), @@ -54,6 +55,8 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix) EDIT_TODO), OPT_CMDMODE(0, "prepare-branch", &command, N_("prepare the branch to be rebased"), PREPARE_BRANCH), + OPT_CMDMODE(0, "checkout-onto", &command, + N_("checkout a commit"), CHECKOUT_ONTO), OPT_END() }; @@ -100,5 +103,7 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix) return !!edit_todo_list(flags); if (command == PREPARE_BRANCH && argc == 2) return !!prepare_branch_to_be_rebased(&opts, argv[1]); + if (command == CHECKOUT_ONTO && argc == 4) + return !!checkout_onto(&opts, argv[1], argv[2], argv[3]); usage_with_options(builtin_rebase_helper_usage, options); } diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh index 77e972bb6..b68f108f2 100644 --- a/git-rebase--interactive.sh +++ b/git-rebase--interactive.sh @@ -28,17 +28,6 @@ case "$comment_char" in ;; esac -orig_reflog_action="$GIT_REFLOG_ACTION" - -comment_for_reflog () { - case "$orig_reflog_action" in - ''|rebase*) - GIT_REFLOG_ACTION="rebase -i ($1)" - export GIT_REFLOG_ACTION - ;; - esac -} - die_abort () { apply_autostash rm -rf "$state_dir" @@ -70,14 +59,6 @@ collapse_todo_ids() { git rebase--helper --shorten-ids } -# Switch to the branch in $into and notify it in the reflog -checkout_onto () { - comment_for_reflog start - GIT_REFLOG_ACTION="$GIT_REFLOG_ACTION: checkout $onto_name" - output git checkout $onto || die_abort "$(gettext "could not detach HEAD")" - git update-ref ORIG_HEAD $orig_head -} - get_missing_commit_check_level () { check_level=$(git config --get rebase.missingCommitsCheck) check_level=${check_level:-ignore} @@ -176,7 +157,8 @@ EOF git rebase--helper --check-todo-list || { ret=$? - checkout_onto + git rebase--helper --checkout-onto "$onto_name" "$onto" \ + "$orig_head" ${verbose:+--verbose} exit $ret } @@ -186,7 +168,8 @@ EOF onto="$(git rebase--helper --skip-unnecessary-picks)" || die "Could not skip unnecessary pick commands" - checkout_onto + git rebase--helper --checkout-onto "$onto_name" "$onto" "$orig_head" \ + ${verbose:+--verbose} require_clean_work_tree "rebase" exec git rebase--helper ${force_rebase:+--no-ff} $allow_empty_message \ --continue diff --git a/sequencer.c b/sequencer.c index b5ea35f21..2b6ddc6cf 100644 --- a/sequencer.c +++ b/sequencer.c @@ -3162,6 +3162,25 @@ int prepare_branch_to_be_rebased(struct replay_opts *opts, const char *commit) return 0; } +int checkout_onto(struct replay_opts *opts, + const char *onto_name, const char *onto, + const char *orig_head) +{ + struct object_id oid; + const char *action = reflog_message(opts, "start", "checkout %s", onto_name); + + if (get_oid(orig_head, &oid)) + return error(_("%s: not a valid OID"), orig_head); + + if (run_git_checkout(opts, onto, action)) { + apply_autostash(opts); + sequencer_remove_state(opts); + return error(_("could not detach HEAD"));
[GSoC][PATCH v3 13/13] rebase -i: rewrite the rest of init_revisions_and_shortrevisions in C
This rewrites the part of init_revisions_and_shortrevisions() needed by `--complete-action` (which initialize $shortrevisions) from shell to C. When `upstream` is empty, it means that the user launched a `rebase --root`, and `onto` contains the ID of an empty commit. As a range between an empty commit and `head` is not really meaningful, `onto` is not used to initialize `shortrevisions` in this case. The corresponding arguments passed to `--complete-action` are then dropped, and init_revisions_and_shortrevisions is stripped from git-rebase--interactive.sh Signed-off-by: Alban Gruin --- builtin/rebase--helper.c | 40 -- git-rebase--interactive.sh | 27 - 2 files changed, 38 insertions(+), 29 deletions(-) diff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c index 5845f80de..59e788f22 100644 --- a/builtin/rebase--helper.c +++ b/builtin/rebase--helper.c @@ -10,7 +10,7 @@ static GIT_PATH_FUNC(path_squash_onto, "rebase-merge/squash-onto") static int get_revision_ranges(const char *upstream, const char *onto, const char **head_hash, - char **revisions) + char **revisions, char **shortrevisions) { const char *base_rev = upstream ? upstream : onto; struct object_id orig_head; @@ -19,7 +19,25 @@ static int get_revision_ranges(const char *upstream, const char *onto, return error(_("no HEAD?")); *head_hash = find_unique_abbrev(&orig_head, GIT_MAX_HEXSZ); - *revisions = xstrfmt("%s...%s", base_rev, *head_hash); + + if (revisions) + *revisions = xstrfmt("%s...%s", base_rev, *head_hash); + if (shortrevisions) { + const char *shorthead; + + shorthead = find_unique_abbrev(&orig_head, DEFAULT_ABBREV); + + if (upstream) { + const char *shortrev; + struct object_id rev_oid; + + get_oid(base_rev, &rev_oid); + shortrev = find_unique_abbrev(&rev_oid, DEFAULT_ABBREV); + + *shortrevisions = xstrfmt("%s..%s", shortrev, shorthead); + } else + *shortrevisions = xstrdup(shorthead); + } return 0; } @@ -112,7 +130,7 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix) if (!upstream && squash_onto) write_file(path_squash_onto(), "%s\n", squash_onto); - ret = get_revision_ranges(upstream, onto, &head_hash, &revisions); + ret = get_revision_ranges(upstream, onto, &head_hash, &revisions, NULL); if (ret) return ret; @@ -139,9 +157,19 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix) return !!edit_todo_list(flags); if (command == PREPARE_BRANCH && argc == 2) return !!prepare_branch_to_be_rebased(&opts, argv[1]); - if (command == COMPLETE_ACTION && argc == 6) - return !!complete_action(&opts, flags, argv[1], argv[2], argv[3], -argv[4], argv[5], autosquash, keep_empty); + if (command == COMPLETE_ACTION && argc == 3) { + char *shortrevisions = NULL; + + ret = get_revision_ranges(upstream, onto, &head_hash, NULL, &shortrevisions); + if (ret) + return ret; + + ret = !!complete_action(&opts, flags, shortrevisions, argv[1], onto, + head_hash, argv[2], autosquash, keep_empty); + + free(shortrevisions); + return ret; + } usage_with_options(builtin_rebase_helper_usage, options); } diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh index 4ca47aed1..08e9a21c2 100644 --- a/git-rebase--interactive.sh +++ b/git-rebase--interactive.sh @@ -60,23 +60,6 @@ init_basic_state () { write_basic_state } -init_revisions_and_shortrevisions () { - shorthead=$(git rev-parse --short $orig_head) - shortonto=$(git rev-parse --short $onto) - if test -z "$rebase_root" - # this is now equivalent to ! -z "$upstream" - then - shortupstream=$(git rev-parse --short $upstream) - revisions=$upstream...$orig_head - shortrevisions=$shortupstream..$shorthead - else - revisions=$onto...$orig_head - shortrevisions=$shorthead - test -z "$squash_onto" || - echo "$squash_onto" >"$state_dir"/squash-onto - fi -} - git_rebase__interactive () {
[GSoC][PATCH v3 09/13] sequencer: change the way skip_unnecessary_picks() returns its result
Instead of skip_unnecessary_picks() printing its result to stdout, it returns it into a const char *, as the rewrite of complete_action() (to come in the next commit) will need it. rebase--helper then is modified to fit this change. Signed-off-by: Alban Gruin --- builtin/rebase--helper.c | 11 --- sequencer.c | 4 ++-- sequencer.h | 2 +- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c index b9af96af7..d4cfe43e7 100644 --- a/builtin/rebase--helper.c +++ b/builtin/rebase--helper.c @@ -14,7 +14,8 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix) { struct replay_opts opts = REPLAY_OPTS_INIT; unsigned flags = 0, keep_empty = 0, rebase_merges = 0, verbose = 0; - int abbreviate_commands = 0, rebase_cousins = -1; + int abbreviate_commands = 0, rebase_cousins = -1, ret; + const char *oid = NULL; enum { CONTINUE = 1, ABORT, MAKE_SCRIPT, SHORTEN_OIDS, EXPAND_OIDS, CHECK_TODO_LIST, SKIP_UNNECESSARY_PICKS, REARRANGE_SQUASH, @@ -91,8 +92,12 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix) return !!transform_todos(flags); if (command == CHECK_TODO_LIST && argc == 1) return !!check_todo_list(); - if (command == SKIP_UNNECESSARY_PICKS && argc == 1) - return !!skip_unnecessary_picks(); + if (command == SKIP_UNNECESSARY_PICKS && argc == 1) { + ret = !!skip_unnecessary_picks(&oid); + if (!ret && oid) + puts(oid); + return ret; + } if (command == REARRANGE_SQUASH && argc == 1) return !!rearrange_squash(); if (command == ADD_EXEC && argc == 2) diff --git a/sequencer.c b/sequencer.c index 2b6ddc6cf..676ac1320 100644 --- a/sequencer.c +++ b/sequencer.c @@ -4392,7 +4392,7 @@ static int rewrite_file(const char *path, const char *buf, size_t len) } /* skip picking commits whose parents are unchanged */ -int skip_unnecessary_picks(void) +int skip_unnecessary_picks(const char **output_oid) { const char *todo_file = rebase_path_todo(); struct strbuf buf = STRBUF_INIT; @@ -4467,7 +4467,7 @@ int skip_unnecessary_picks(void) } todo_list_release(&todo_list); - printf("%s\n", oid_to_hex(oid)); + *output_oid = oid_to_hex(oid); return 0; } diff --git a/sequencer.h b/sequencer.h index 11a533461..25b50efe2 100644 --- a/sequencer.h +++ b/sequencer.h @@ -88,7 +88,7 @@ int sequencer_add_exec_commands(const char *command); int transform_todos(unsigned flags); enum missing_commit_check_level get_missing_commit_check_level(void); int check_todo_list(void); -int skip_unnecessary_picks(void); +int skip_unnecessary_picks(const char **output_oid); int rearrange_squash(void); extern const char sign_off_header[]; -- 2.18.0
[GSoC][PATCH v3 12/13] rebase -i: implement the logic to initialize the variable $revision in C
This rewrites the part of init_revisions_and_shortrevisions() needed by `--make-script` from shell to C. The new version is called get_revision_ranges(), and is a static function inside of rebase--helper.c. Unlike init_revisions_and_shortrevisions(), get_revision_ranges() doesn’t write $squash_onto to the state directory, it’s done by the handler of `--make-script` instead. Finally, this drops the $revision argument passed to `--make-script` in git-rebase--interactive.sh, and rebase--helper is changed accordingly. Signed-off-by: Alban Gruin --- builtin/rebase--helper.c | 56 -- git-rebase--interactive.sh | 4 ++- 2 files changed, 56 insertions(+), 4 deletions(-) diff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c index 8ab808da4..5845f80de 100644 --- a/builtin/rebase--helper.c +++ b/builtin/rebase--helper.c @@ -4,6 +4,25 @@ #include "parse-options.h" #include "sequencer.h" #include "rebase-interactive.h" +#include "argv-array.h" + +static GIT_PATH_FUNC(path_squash_onto, "rebase-merge/squash-onto") + +static int get_revision_ranges(const char *upstream, const char *onto, + const char **head_hash, + char **revisions) +{ + const char *base_rev = upstream ? upstream : onto; + struct object_id orig_head; + + if (get_oid("HEAD", &orig_head)) + return error(_("no HEAD?")); + + *head_hash = find_unique_abbrev(&orig_head, GIT_MAX_HEXSZ); + *revisions = xstrfmt("%s...%s", base_rev, *head_hash); + + return 0; +} static const char * const builtin_rebase_helper_usage[] = { N_("git rebase--helper []"), @@ -15,7 +34,9 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix) struct replay_opts opts = REPLAY_OPTS_INIT; unsigned flags = 0, keep_empty = 0, rebase_merges = 0, verbose = 0, autosquash = 0; - int abbreviate_commands = 0, rebase_cousins = -1; + int abbreviate_commands = 0, rebase_cousins = -1, ret; + const char *head_hash = NULL, *onto = NULL, *restrict_revisions = NULL, + *squash_onto = NULL, *upstream = NULL; enum { CONTINUE = 1, ABORT, MAKE_SCRIPT, CHECK_TODO_LIST, REARRANGE_SQUASH, ADD_EXEC, EDIT_TODO, PREPARE_BRANCH, COMPLETE_ACTION @@ -50,6 +71,13 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix) N_("prepare the branch to be rebased"), PREPARE_BRANCH), OPT_CMDMODE(0, "complete-action", &command, N_("complete the action"), COMPLETE_ACTION), + OPT_STRING(0, "onto", &onto, N_("onto"), N_("onto")), + OPT_STRING(0, "restrict-revision", &restrict_revisions, + N_("restrict-revision"), N_("restrict revision")), + OPT_STRING(0, "squash-onto", &squash_onto, N_("squash-onto"), + N_("squash onto")), + OPT_STRING(0, "upstream", &upstream, N_("upstream"), + N_("the upstream commit")), OPT_END() }; @@ -77,8 +105,30 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix) return !!sequencer_continue(&opts); if (command == ABORT && argc == 1) return !!sequencer_remove_state(&opts); - if (command == MAKE_SCRIPT && argc > 1) - return !!sequencer_make_script(stdout, argc, argv, flags); + if (command == MAKE_SCRIPT && (argc == 1 || argc == 2)) { + char *revisions = NULL; + struct argv_array make_script_args = ARGV_ARRAY_INIT; + + if (!upstream && squash_onto) + write_file(path_squash_onto(), "%s\n", squash_onto); + + ret = get_revision_ranges(upstream, onto, &head_hash, &revisions); + if (ret) + return ret; + + argv_array_pushl(&make_script_args, "", revisions, NULL); + if (argc == 2) + argv_array_push(&make_script_args, restrict_revisions); + + ret = !!sequencer_make_script(stdout, + make_script_args.argc, make_script_args.argv, + flags); + + free(revisions); + argv_array_clear(&make_script_args); + + return ret; + } if (command == CHECK_TODO_LIST && argc == 1) return !!check_todo_list(); if (c
[GSoC][PATCH v3 02/13] rebase--interactive: rewrite append_todo_help() in C
This rewrites append_todo_help() from shell to C. It also incorporates some parts of initiate_action() and complete_action() that also write help texts to the todo file. This also introduces the source file rebase-interactive.c. This file will contain functions necessary for interactive rebase that are too specific for the sequencer, and is part of libgit.a. Two flags are added to rebase--helper.c: one to call append_todo_help() (`--append-todo-help`), and another one to tell append_todo_help() to write the help text suited for the edit-todo mode (`--write-edit-todo`). Finally, append_todo_help() is removed from git-rebase--interactive.sh to use `rebase--helper --append-todo-help` instead. Signed-off-by: Alban Gruin --- Unchanged from what have been queued on `pu` (ag/rebase-i-in-c), and from v2. Makefile | 1 + builtin/rebase--helper.c | 11 -- git-rebase--interactive.sh | 52 ++--- rebase-interactive.c | 68 ++ rebase-interactive.h | 6 5 files changed, 86 insertions(+), 52 deletions(-) create mode 100644 rebase-interactive.c create mode 100644 rebase-interactive.h diff --git a/Makefile b/Makefile index 0cb6590f2..a281139ef 100644 --- a/Makefile +++ b/Makefile @@ -922,6 +922,7 @@ LIB_OBJS += protocol.o LIB_OBJS += quote.o LIB_OBJS += reachable.o LIB_OBJS += read-cache.o +LIB_OBJS += rebase-interactive.o LIB_OBJS += reflog-walk.o LIB_OBJS += refs.o LIB_OBJS += refs/files-backend.o diff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c index f7c2a5fdc..05e73e71d 100644 --- a/builtin/rebase--helper.c +++ b/builtin/rebase--helper.c @@ -3,6 +3,7 @@ #include "config.h" #include "parse-options.h" #include "sequencer.h" +#include "rebase-interactive.h" static const char * const builtin_rebase_helper_usage[] = { N_("git rebase--helper []"), @@ -12,12 +13,12 @@ static const char * const builtin_rebase_helper_usage[] = { int cmd_rebase__helper(int argc, const char **argv, const char *prefix) { struct replay_opts opts = REPLAY_OPTS_INIT; - unsigned flags = 0, keep_empty = 0, rebase_merges = 0; + unsigned flags = 0, keep_empty = 0, rebase_merges = 0, write_edit_todo = 0; int abbreviate_commands = 0, rebase_cousins = -1; enum { CONTINUE = 1, ABORT, MAKE_SCRIPT, SHORTEN_OIDS, EXPAND_OIDS, CHECK_TODO_LIST, SKIP_UNNECESSARY_PICKS, REARRANGE_SQUASH, - ADD_EXEC + ADD_EXEC, APPEND_TODO_HELP } command = 0; struct option options[] = { OPT_BOOL(0, "ff", &opts.allow_ff, N_("allow fast-forward")), @@ -27,6 +28,8 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix) OPT_BOOL(0, "rebase-merges", &rebase_merges, N_("rebase merge commits")), OPT_BOOL(0, "rebase-cousins", &rebase_cousins, N_("keep original branch points of cousins")), + OPT_BOOL(0, "write-edit-todo", &write_edit_todo, +N_("append the edit-todo message to the todo-list")), OPT_CMDMODE(0, "continue", &command, N_("continue rebase"), CONTINUE), OPT_CMDMODE(0, "abort", &command, N_("abort rebase"), @@ -45,6 +48,8 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix) N_("rearrange fixup/squash lines"), REARRANGE_SQUASH), OPT_CMDMODE(0, "add-exec-commands", &command, N_("insert exec commands in todo list"), ADD_EXEC), + OPT_CMDMODE(0, "append-todo-help", &command, + N_("insert the help in the todo list"), APPEND_TODO_HELP), OPT_END() }; @@ -84,5 +89,7 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix) return !!rearrange_squash(); if (command == ADD_EXEC && argc == 2) return !!sequencer_add_exec_commands(argv[1]); + if (command == APPEND_TODO_HELP && argc == 1) + return !!append_todo_help(write_edit_todo, keep_empty); usage_with_options(builtin_rebase_helper_usage, options); } diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh index 299ded213..94c23a7af 100644 --- a/git-rebase--interactive.sh +++ b/git-rebase--interactive.sh @@ -39,38 +39,6 @@ comment_for_reflog () { esac } -append_todo_help () { - gettext " -Commands: -p, pick = use commit -r, reword = use commit, but edit the commit message -e, edit = use commit, but stop for amending -s, squash = use commit, but meld
[GSoC][PATCH v3 05/13] sequencer: add a new function to silence a command, except if it fails
This adds a new function, run_command_silent_on_success(), to redirect the stdout and stderr of a command to a strbuf, and then to run that command. This strbuf is printed only if the command fails. It is functionnaly similar to output() from git-rebase.sh. run_git_commit() is then refactored to use of run_command_silent_on_success(). Signed-off-by: Alban Gruin --- sequencer.c | 51 +-- 1 file changed, 25 insertions(+), 26 deletions(-) diff --git a/sequencer.c b/sequencer.c index 57fd58bc1..1b5d50298 100644 --- a/sequencer.c +++ b/sequencer.c @@ -768,6 +768,23 @@ N_("you have staged changes in your working tree\n" #define VERIFY_MSG (1<<4) #define CREATE_ROOT_COMMIT (1<<5) +static int run_command_silent_on_success(struct child_process *cmd) +{ + struct strbuf buf = STRBUF_INIT; + int rc; + + cmd->stdout_to_stderr = 1; + rc = pipe_command(cmd, + NULL, 0, + NULL, 0, + &buf, 0); + + if (rc) + fputs(buf.buf, stderr); + strbuf_release(&buf); + return rc; +} + /* * If we are cherry-pick, and if the merge did not result in * hand-editing, we will hit this commit and inherit the original @@ -822,18 +839,11 @@ static int run_git_commit(const char *defmsg, struct replay_opts *opts, cmd.git_cmd = 1; - if (is_rebase_i(opts)) { - if (!(flags & EDIT_MSG)) { - cmd.stdout_to_stderr = 1; - cmd.err = -1; - } - - if (read_env_script(&cmd.env_array)) { - const char *gpg_opt = gpg_sign_opt_quoted(opts); + if (is_rebase_i(opts) && read_env_script(&cmd.env_array)) { + const char *gpg_opt = gpg_sign_opt_quoted(opts); - return error(_(staged_changes_advice), -gpg_opt, gpg_opt); - } + return error(_(staged_changes_advice), +gpg_opt, gpg_opt); } argv_array_push(&cmd.args, "commit"); @@ -863,21 +873,10 @@ static int run_git_commit(const char *defmsg, struct replay_opts *opts, if (opts->allow_empty_message) argv_array_push(&cmd.args, "--allow-empty-message"); - if (cmd.err == -1) { - /* hide stderr on success */ - struct strbuf buf = STRBUF_INIT; - int rc = pipe_command(&cmd, - NULL, 0, - /* stdout is already redirected */ - NULL, 0, - &buf, 0); - if (rc) - fputs(buf.buf, stderr); - strbuf_release(&buf); - return rc; - } - - return run_command(&cmd); + if (is_rebase_i(opts) && !(flags & EDIT_MSG)) + return run_command_silent_on_success(&cmd); + else + return run_command(&cmd); } static int rest_is_empty(const struct strbuf *sb, int start) -- 2.18.0
[GSoC][PATCH v3 03/13] editor: add a function to launch the sequence editor
As part of the rewrite of interactive rebase, the sequencer will need to open the sequence editor to allow the user to edit the todo list. Instead of duplicating the existing launch_editor() function, this refactors it to a new function, launch_specified_editor(), which takes the editor as a parameter, in addition to the path, the buffer and the environment variables. launch_sequence_editor() is then added to launch the sequence editor. Signed-off-by: Alban Gruin --- cache.h | 1 + editor.c | 27 +-- strbuf.h | 2 ++ 3 files changed, 28 insertions(+), 2 deletions(-) diff --git a/cache.h b/cache.h index d49092d94..33fa70f55 100644 --- a/cache.h +++ b/cache.h @@ -1472,6 +1472,7 @@ extern const char *fmt_name(const char *name, const char *email); extern const char *ident_default_name(void); extern const char *ident_default_email(void); extern const char *git_editor(void); +extern const char *git_sequence_editor(void); extern const char *git_pager(int stdout_is_tty); extern int is_terminal_dumb(void); extern int git_ident_config(const char *, const char *, void *); diff --git a/editor.c b/editor.c index 9a9b4e12d..c985eee1f 100644 --- a/editor.c +++ b/editor.c @@ -1,4 +1,5 @@ #include "cache.h" +#include "config.h" #include "strbuf.h" #include "run-command.h" #include "sigchain.h" @@ -34,10 +35,21 @@ const char *git_editor(void) return editor; } -int launch_editor(const char *path, struct strbuf *buffer, const char *const *env) +const char *git_sequence_editor(void) { - const char *editor = git_editor(); + const char *editor = getenv("GIT_SEQUENCE_EDITOR"); + + if (!editor) + git_config_get_string_const("sequence.editor", &editor); + if (!editor) + editor = git_editor(); + return editor; +} + +static int launch_specified_editor(const char *editor, const char *path, + struct strbuf *buffer, const char *const *env) +{ if (!editor) return error("Terminal is dumb, but EDITOR unset"); @@ -95,3 +107,14 @@ int launch_editor(const char *path, struct strbuf *buffer, const char *const *en return error_errno("could not read file '%s'", path); return 0; } + +int launch_editor(const char *path, struct strbuf *buffer, const char *const *env) +{ + return launch_specified_editor(git_editor(), path, buffer, env); +} + +int launch_sequence_editor(const char *path, struct strbuf *buffer, + const char *const *env) +{ + return launch_specified_editor(git_sequence_editor(), path, buffer, env); +} diff --git a/strbuf.h b/strbuf.h index 60a35aef1..66da9822f 100644 --- a/strbuf.h +++ b/strbuf.h @@ -575,6 +575,8 @@ extern void strbuf_add_unique_abbrev(struct strbuf *sb, * file's contents are not read into the buffer upon completion. */ extern int launch_editor(const char *path, struct strbuf *buffer, const char *const *env); +extern int launch_sequence_editor(const char *path, struct strbuf *buffer, + const char *const *env); extern void strbuf_add_lines(struct strbuf *sb, const char *prefix, const char *buf, size_t size); -- 2.18.0
Re: [GSoC][PATCH v2 1/7] sequencer: make two functions and an enum from sequencer.c public
Hi Junio, Le 03/07/2018 à 22:20, Junio C Hamano a écrit : > Alban Gruin writes: > >> -enum check_level { >> -CHECK_IGNORE = 0, CHECK_WARN, CHECK_ERROR >> -}; >> - >> -static enum check_level get_missing_commit_check_level(void) >> +enum missing_commit_check_level get_missing_commit_check_level(void) > > The new name definitely is better than "check_level" in the global > context, but "missing_commit" is much less important thing to say > than "this symbol is to be used when driving 'rebase' (or even > 'rebase-i')", I think. "enum rebase_i_drop_commit_check" with > "get_rebase_i_drop_commit_check()" perhaps? > I don’t really like those names, but the function and the enum should eventually move to rebase-interactive.c and become static again, so we could revert their names in due course. Cheers, Alban
[GSoC] GSoC with git, week 9
Hi, I just published a blog post about last week: https://blog.pa1ch.fr/posts/2018/07/02/en/gsoc2018-week-9.html Cheers, Alban
[GSoC][PATCH v2 4/7] rebase-interactive: rewrite the edit-todo functionality in C
This rewrites the edit-todo functionality from shell to C. To achieve that, a new command mode, `edit-todo`, is added, and the `write-edit-todo` flag is removed, as the shell script does not need to write the edit todo help message to the todo list anymore. The shell version is then stripped in favour of a call to the helper. Signed-off-by: Alban Gruin --- builtin/rebase--helper.c | 13 - git-rebase--interactive.sh | 11 +-- rebase-interactive.c | 31 +++ rebase-interactive.h | 1 + 4 files changed, 41 insertions(+), 15 deletions(-) diff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c index 05e73e71d..731a64971 100644 --- a/builtin/rebase--helper.c +++ b/builtin/rebase--helper.c @@ -13,12 +13,12 @@ static const char * const builtin_rebase_helper_usage[] = { int cmd_rebase__helper(int argc, const char **argv, const char *prefix) { struct replay_opts opts = REPLAY_OPTS_INIT; - unsigned flags = 0, keep_empty = 0, rebase_merges = 0, write_edit_todo = 0; + unsigned flags = 0, keep_empty = 0, rebase_merges = 0; int abbreviate_commands = 0, rebase_cousins = -1; enum { CONTINUE = 1, ABORT, MAKE_SCRIPT, SHORTEN_OIDS, EXPAND_OIDS, CHECK_TODO_LIST, SKIP_UNNECESSARY_PICKS, REARRANGE_SQUASH, - ADD_EXEC, APPEND_TODO_HELP + ADD_EXEC, APPEND_TODO_HELP, EDIT_TODO } command = 0; struct option options[] = { OPT_BOOL(0, "ff", &opts.allow_ff, N_("allow fast-forward")), @@ -28,8 +28,6 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix) OPT_BOOL(0, "rebase-merges", &rebase_merges, N_("rebase merge commits")), OPT_BOOL(0, "rebase-cousins", &rebase_cousins, N_("keep original branch points of cousins")), - OPT_BOOL(0, "write-edit-todo", &write_edit_todo, -N_("append the edit-todo message to the todo-list")), OPT_CMDMODE(0, "continue", &command, N_("continue rebase"), CONTINUE), OPT_CMDMODE(0, "abort", &command, N_("abort rebase"), @@ -50,6 +48,9 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix) N_("insert exec commands in todo list"), ADD_EXEC), OPT_CMDMODE(0, "append-todo-help", &command, N_("insert the help in the todo list"), APPEND_TODO_HELP), + OPT_CMDMODE(0, "edit-todo", &command, + N_("edit the todo list during an interactive rebase"), + EDIT_TODO), OPT_END() }; @@ -90,6 +91,8 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix) if (command == ADD_EXEC && argc == 2) return !!sequencer_add_exec_commands(argv[1]); if (command == APPEND_TODO_HELP && argc == 1) - return !!append_todo_help(write_edit_todo, keep_empty); + return !!append_todo_help(0, keep_empty); + if (command == EDIT_TODO && argc == 1) + return !!edit_todo_list(flags); usage_with_options(builtin_rebase_helper_usage, options); } diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh index 94c23a7af..2defe607f 100644 --- a/git-rebase--interactive.sh +++ b/git-rebase--interactive.sh @@ -108,16 +108,7 @@ initiate_action () { --continue ;; edit-todo) - git stripspace --strip-comments <"$todo" >"$todo".new - mv -f "$todo".new "$todo" - collapse_todo_ids - git rebase--helper --append-todo-help --write-edit-todo - - git_sequence_editor "$todo" || - die "$(gettext "Could not execute editor")" - expand_todo_ids - - exit + exec git rebase--helper --edit-todo ;; show-current-patch) exec git show REBASE_HEAD -- diff --git a/rebase-interactive.c b/rebase-interactive.c index 015e08cd0..fb7ad401a 100644 --- a/rebase-interactive.c +++ b/rebase-interactive.c @@ -66,3 +66,34 @@ int append_todo_help(unsigned edit_todo, unsigned keep_empty) return ret; } + +int edit_todo_list(unsigned flags) +{ + struct strbuf buf = STRBUF_INIT; + const char *todo_file = rebase_path_todo(); + FILE *todo; + + if (strbuf_read_file(&buf, todo_file, 0) < 0) + return error_errno(_("could not read '%s'."), todo_
[GSoC][PATCH v2 3/7] editor: add a function to launch the sequence editor
As part of the rewrite of interactive rebase, the sequencer will need to open the sequence editor to allow the user to edit the todo list. Instead of duplicating the existing launch_editor() function, this refactors it to a new function, launch_specified_editor(), which takes the editor as a parameter, in addition to the path, the buffer and the environment variables. launch_sequence_editor() is then added to launch the sequence editor. Signed-off-by: Alban Gruin --- cache.h | 1 + editor.c | 27 +-- strbuf.h | 2 ++ 3 files changed, 28 insertions(+), 2 deletions(-) diff --git a/cache.h b/cache.h index d49092d94..33fa70f55 100644 --- a/cache.h +++ b/cache.h @@ -1472,6 +1472,7 @@ extern const char *fmt_name(const char *name, const char *email); extern const char *ident_default_name(void); extern const char *ident_default_email(void); extern const char *git_editor(void); +extern const char *git_sequence_editor(void); extern const char *git_pager(int stdout_is_tty); extern int is_terminal_dumb(void); extern int git_ident_config(const char *, const char *, void *); diff --git a/editor.c b/editor.c index 9a9b4e12d..c985eee1f 100644 --- a/editor.c +++ b/editor.c @@ -1,4 +1,5 @@ #include "cache.h" +#include "config.h" #include "strbuf.h" #include "run-command.h" #include "sigchain.h" @@ -34,10 +35,21 @@ const char *git_editor(void) return editor; } -int launch_editor(const char *path, struct strbuf *buffer, const char *const *env) +const char *git_sequence_editor(void) { - const char *editor = git_editor(); + const char *editor = getenv("GIT_SEQUENCE_EDITOR"); + + if (!editor) + git_config_get_string_const("sequence.editor", &editor); + if (!editor) + editor = git_editor(); + return editor; +} + +static int launch_specified_editor(const char *editor, const char *path, + struct strbuf *buffer, const char *const *env) +{ if (!editor) return error("Terminal is dumb, but EDITOR unset"); @@ -95,3 +107,14 @@ int launch_editor(const char *path, struct strbuf *buffer, const char *const *en return error_errno("could not read file '%s'", path); return 0; } + +int launch_editor(const char *path, struct strbuf *buffer, const char *const *env) +{ + return launch_specified_editor(git_editor(), path, buffer, env); +} + +int launch_sequence_editor(const char *path, struct strbuf *buffer, + const char *const *env) +{ + return launch_specified_editor(git_sequence_editor(), path, buffer, env); +} diff --git a/strbuf.h b/strbuf.h index 60a35aef1..66da9822f 100644 --- a/strbuf.h +++ b/strbuf.h @@ -575,6 +575,8 @@ extern void strbuf_add_unique_abbrev(struct strbuf *sb, * file's contents are not read into the buffer upon completion. */ extern int launch_editor(const char *path, struct strbuf *buffer, const char *const *env); +extern int launch_sequence_editor(const char *path, struct strbuf *buffer, + const char *const *env); extern void strbuf_add_lines(struct strbuf *sb, const char *prefix, const char *buf, size_t size); -- 2.18.0
[GSoC][PATCH v2 5/7] sequencer: add a new function to silence a command, except if it fails.
This adds a new function, run_command_silent_on_success(), to redirect the stdout and stderr of a command to a strbuf, and then to run that command. This strbuf is printed only if the command fails. It is functionnaly similar to output() from git-rebase.sh. run_git_commit() is then refactored to use of run_command_silent_on_success(). Signed-off-by: Alban Gruin --- sequencer.c | 49 - 1 file changed, 24 insertions(+), 25 deletions(-) diff --git a/sequencer.c b/sequencer.c index 57fd58bc1..9e2b34a49 100644 --- a/sequencer.c +++ b/sequencer.c @@ -768,6 +768,24 @@ N_("you have staged changes in your working tree\n" #define VERIFY_MSG (1<<4) #define CREATE_ROOT_COMMIT (1<<5) +static int run_command_silent_on_success(struct child_process *cmd) +{ + struct strbuf buf = STRBUF_INIT; + int rc; + + cmd->stdout_to_stderr = 1; + rc = pipe_command(cmd, + NULL, 0, + /* stdout is already redirected */ + NULL, 0, + &buf, 0); + + if (rc) + fputs(buf.buf, stderr); + strbuf_release(&buf); + return rc; +} + /* * If we are cherry-pick, and if the merge did not result in * hand-editing, we will hit this commit and inherit the original @@ -822,18 +840,11 @@ static int run_git_commit(const char *defmsg, struct replay_opts *opts, cmd.git_cmd = 1; - if (is_rebase_i(opts)) { - if (!(flags & EDIT_MSG)) { - cmd.stdout_to_stderr = 1; - cmd.err = -1; - } + if (is_rebase_i(opts) && read_env_script(&cmd.env_array)) { + const char *gpg_opt = gpg_sign_opt_quoted(opts); - if (read_env_script(&cmd.env_array)) { - const char *gpg_opt = gpg_sign_opt_quoted(opts); - - return error(_(staged_changes_advice), -gpg_opt, gpg_opt); - } + return error(_(staged_changes_advice), +gpg_opt, gpg_opt); } argv_array_push(&cmd.args, "commit"); @@ -863,20 +874,8 @@ static int run_git_commit(const char *defmsg, struct replay_opts *opts, if (opts->allow_empty_message) argv_array_push(&cmd.args, "--allow-empty-message"); - if (cmd.err == -1) { - /* hide stderr on success */ - struct strbuf buf = STRBUF_INIT; - int rc = pipe_command(&cmd, - NULL, 0, - /* stdout is already redirected */ - NULL, 0, - &buf, 0); - if (rc) - fputs(buf.buf, stderr); - strbuf_release(&buf); - return rc; - } - + if (is_rebase_i(opts) && !(flags & EDIT_MSG)) + return run_command_silent_on_success(&cmd); return run_command(&cmd); } -- 2.18.0
[GSoC][PATCH v2 7/7] rebase -i: rewrite checkout_onto() in C
This rewrites checkout_onto() from shell to C. A new command (“checkout-onto”) is added to rebase--helper.c. The shell version is then stripped. Signed-off-by: Alban Gruin --- builtin/rebase--helper.c | 7 ++- git-rebase--interactive.sh | 25 - sequencer.c| 19 +++ sequencer.h| 3 +++ 4 files changed, 32 insertions(+), 22 deletions(-) diff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c index 6c789e78b..0091e094b 100644 --- a/builtin/rebase--helper.c +++ b/builtin/rebase--helper.c @@ -18,7 +18,8 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix) enum { CONTINUE = 1, ABORT, MAKE_SCRIPT, SHORTEN_OIDS, EXPAND_OIDS, CHECK_TODO_LIST, SKIP_UNNECESSARY_PICKS, REARRANGE_SQUASH, - ADD_EXEC, APPEND_TODO_HELP, EDIT_TODO, PREPARE_BRANCH + ADD_EXEC, APPEND_TODO_HELP, EDIT_TODO, PREPARE_BRANCH, + CHECKOUT_ONTO } command = 0; struct option options[] = { OPT_BOOL(0, "ff", &opts.allow_ff, N_("allow fast-forward")), @@ -54,6 +55,8 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix) EDIT_TODO), OPT_CMDMODE(0, "prepare-branch", &command, N_("prepare the branch to be rebased"), PREPARE_BRANCH), + OPT_CMDMODE(0, "checkout-onto", &command, + N_("checkout a commit"), CHECKOUT_ONTO), OPT_END() }; @@ -99,5 +102,7 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix) return !!edit_todo_list(flags); if (command == PREPARE_BRANCH && argc == 2) return !!prepare_branch_to_be_rebased(&opts, argv[1], verbose); + if (command == CHECKOUT_ONTO && argc == 4) + return !!checkout_onto(&opts, argv[1], argv[2], argv[3], verbose); usage_with_options(builtin_rebase_helper_usage, options); } diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh index 77e972bb6..b68f108f2 100644 --- a/git-rebase--interactive.sh +++ b/git-rebase--interactive.sh @@ -28,17 +28,6 @@ case "$comment_char" in ;; esac -orig_reflog_action="$GIT_REFLOG_ACTION" - -comment_for_reflog () { - case "$orig_reflog_action" in - ''|rebase*) - GIT_REFLOG_ACTION="rebase -i ($1)" - export GIT_REFLOG_ACTION - ;; - esac -} - die_abort () { apply_autostash rm -rf "$state_dir" @@ -70,14 +59,6 @@ collapse_todo_ids() { git rebase--helper --shorten-ids } -# Switch to the branch in $into and notify it in the reflog -checkout_onto () { - comment_for_reflog start - GIT_REFLOG_ACTION="$GIT_REFLOG_ACTION: checkout $onto_name" - output git checkout $onto || die_abort "$(gettext "could not detach HEAD")" - git update-ref ORIG_HEAD $orig_head -} - get_missing_commit_check_level () { check_level=$(git config --get rebase.missingCommitsCheck) check_level=${check_level:-ignore} @@ -176,7 +157,8 @@ EOF git rebase--helper --check-todo-list || { ret=$? - checkout_onto + git rebase--helper --checkout-onto "$onto_name" "$onto" \ + "$orig_head" ${verbose:+--verbose} exit $ret } @@ -186,7 +168,8 @@ EOF onto="$(git rebase--helper --skip-unnecessary-picks)" || die "Could not skip unnecessary pick commands" - checkout_onto + git rebase--helper --checkout-onto "$onto_name" "$onto" "$orig_head" \ + ${verbose:+--verbose} require_clean_work_tree "rebase" exec git rebase--helper ${force_rebase:+--no-ff} $allow_empty_message \ --continue diff --git a/sequencer.c b/sequencer.c index a61276d2c..bc0836ac9 100644 --- a/sequencer.c +++ b/sequencer.c @@ -3162,6 +3162,25 @@ int prepare_branch_to_be_rebased(struct replay_opts *opts, const char *commit, return 0; } +int checkout_onto(struct replay_opts *opts, + const char *onto_name, const char *onto, + const char *orig_head, unsigned verbose) +{ + struct object_id oid; + const char *action = reflog_message(opts, "start", "checkout %s", onto_name); + + if (get_oid(orig_head, &oid)) + return error(_("%s: not a valid OID"), orig_head); + + if (run_git_checkout(opts, onto, verbose, action)) { + apply_autostash(opts); + sequencer_remove_state(opts); + retu
[GSoC][PATCH v2 6/7] rebase -i: rewrite setup_reflog_action() in C
This rewrites (the misnamed) setup_reflog_action() from shell to C. The new version is called prepare_branch_to_be_rebased(). A new command is added to rebase--helper.c, “checkout-base”, as well as a new flag, “verbose”, to avoid silencing the output of the checkout operation called by checkout_base_commit(). The function `run_git_checkout()` will also be used in the next commit, therefore its code is not part of `checkout_base_commit()`. The shell version is then stripped in favour of a call to the helper. As $GIT_REFLOG_ACTION is no longer set at the first call of checkout_onto(), a call to comment_for_reflog() is added at the beginning of this function. Signed-off-by: Alban Gruin --- builtin/rebase--helper.c | 9 +++-- git-rebase--interactive.sh | 16 ++-- sequencer.c| 30 ++ sequencer.h| 3 +++ 4 files changed, 42 insertions(+), 16 deletions(-) diff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c index 731a64971..6c789e78b 100644 --- a/builtin/rebase--helper.c +++ b/builtin/rebase--helper.c @@ -13,12 +13,12 @@ static const char * const builtin_rebase_helper_usage[] = { int cmd_rebase__helper(int argc, const char **argv, const char *prefix) { struct replay_opts opts = REPLAY_OPTS_INIT; - unsigned flags = 0, keep_empty = 0, rebase_merges = 0; + unsigned flags = 0, keep_empty = 0, rebase_merges = 0, verbose = 0; int abbreviate_commands = 0, rebase_cousins = -1; enum { CONTINUE = 1, ABORT, MAKE_SCRIPT, SHORTEN_OIDS, EXPAND_OIDS, CHECK_TODO_LIST, SKIP_UNNECESSARY_PICKS, REARRANGE_SQUASH, - ADD_EXEC, APPEND_TODO_HELP, EDIT_TODO + ADD_EXEC, APPEND_TODO_HELP, EDIT_TODO, PREPARE_BRANCH } command = 0; struct option options[] = { OPT_BOOL(0, "ff", &opts.allow_ff, N_("allow fast-forward")), @@ -28,6 +28,7 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix) OPT_BOOL(0, "rebase-merges", &rebase_merges, N_("rebase merge commits")), OPT_BOOL(0, "rebase-cousins", &rebase_cousins, N_("keep original branch points of cousins")), + OPT__VERBOSE(&verbose, N_("be verbose")), OPT_CMDMODE(0, "continue", &command, N_("continue rebase"), CONTINUE), OPT_CMDMODE(0, "abort", &command, N_("abort rebase"), @@ -51,6 +52,8 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix) OPT_CMDMODE(0, "edit-todo", &command, N_("edit the todo list during an interactive rebase"), EDIT_TODO), + OPT_CMDMODE(0, "prepare-branch", &command, + N_("prepare the branch to be rebased"), PREPARE_BRANCH), OPT_END() }; @@ -94,5 +97,7 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix) return !!append_todo_help(0, keep_empty); if (command == EDIT_TODO && argc == 1) return !!edit_todo_list(flags); + if (command == PREPARE_BRANCH && argc == 2) + return !!prepare_branch_to_be_rebased(&opts, argv[1], verbose); usage_with_options(builtin_rebase_helper_usage, options); } diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh index 2defe607f..77e972bb6 100644 --- a/git-rebase--interactive.sh +++ b/git-rebase--interactive.sh @@ -72,6 +72,7 @@ collapse_todo_ids() { # Switch to the branch in $into and notify it in the reflog checkout_onto () { + comment_for_reflog start GIT_REFLOG_ACTION="$GIT_REFLOG_ACTION: checkout $onto_name" output git checkout $onto || die_abort "$(gettext "could not detach HEAD")" git update-ref ORIG_HEAD $orig_head @@ -119,19 +120,6 @@ initiate_action () { esac } -setup_reflog_action () { - comment_for_reflog start - - if test ! -z "$switch_to" - then - GIT_REFLOG_ACTION="$GIT_REFLOG_ACTION: checkout $switch_to" - output git checkout "$switch_to" -- || - die "$(eval_gettext "Could not checkout \$switch_to")" - - comment_for_reflog start - fi -} - init_basic_state () { orig_head=$(git rev-parse --verify HEAD) || die "$(gettext "No HEAD?")" mkdir -p "$state_dir" || die "$(eval_gettext "Could not create temporary \$state_dir")" @@ -211,7 +199,7 @@ git_rebase__interactive () { return 0 fi - setup_re
[GSoC][PATCH v2 2/7] rebase--interactive: rewrite append_todo_help() in C
This rewrites append_todo_help() from shell to C. It also incorporates some parts of initiate_action() and complete_action() that also write help texts to the todo file. This also introduces the source file rebase-interactive.c. This file will contain functions necessary for interactive rebase that are too specific for the sequencer, and is part of libgit.a. Two flags are added to rebase--helper.c: one to call append_todo_help() (`--append-todo-help`), and another one to tell append_todo_help() to write the help text suited for the edit-todo mode (`--write-edit-todo`). Finally, append_todo_help() is removed from git-rebase--interactive.sh to use `rebase--helper --append-todo-help` instead. Signed-off-by: Alban Gruin --- Makefile | 1 + builtin/rebase--helper.c | 11 -- git-rebase--interactive.sh | 52 ++--- rebase-interactive.c | 68 ++ rebase-interactive.h | 6 5 files changed, 86 insertions(+), 52 deletions(-) create mode 100644 rebase-interactive.c create mode 100644 rebase-interactive.h diff --git a/Makefile b/Makefile index 0cb6590f2..a281139ef 100644 --- a/Makefile +++ b/Makefile @@ -922,6 +922,7 @@ LIB_OBJS += protocol.o LIB_OBJS += quote.o LIB_OBJS += reachable.o LIB_OBJS += read-cache.o +LIB_OBJS += rebase-interactive.o LIB_OBJS += reflog-walk.o LIB_OBJS += refs.o LIB_OBJS += refs/files-backend.o diff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c index f7c2a5fdc..05e73e71d 100644 --- a/builtin/rebase--helper.c +++ b/builtin/rebase--helper.c @@ -3,6 +3,7 @@ #include "config.h" #include "parse-options.h" #include "sequencer.h" +#include "rebase-interactive.h" static const char * const builtin_rebase_helper_usage[] = { N_("git rebase--helper []"), @@ -12,12 +13,12 @@ static const char * const builtin_rebase_helper_usage[] = { int cmd_rebase__helper(int argc, const char **argv, const char *prefix) { struct replay_opts opts = REPLAY_OPTS_INIT; - unsigned flags = 0, keep_empty = 0, rebase_merges = 0; + unsigned flags = 0, keep_empty = 0, rebase_merges = 0, write_edit_todo = 0; int abbreviate_commands = 0, rebase_cousins = -1; enum { CONTINUE = 1, ABORT, MAKE_SCRIPT, SHORTEN_OIDS, EXPAND_OIDS, CHECK_TODO_LIST, SKIP_UNNECESSARY_PICKS, REARRANGE_SQUASH, - ADD_EXEC + ADD_EXEC, APPEND_TODO_HELP } command = 0; struct option options[] = { OPT_BOOL(0, "ff", &opts.allow_ff, N_("allow fast-forward")), @@ -27,6 +28,8 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix) OPT_BOOL(0, "rebase-merges", &rebase_merges, N_("rebase merge commits")), OPT_BOOL(0, "rebase-cousins", &rebase_cousins, N_("keep original branch points of cousins")), + OPT_BOOL(0, "write-edit-todo", &write_edit_todo, +N_("append the edit-todo message to the todo-list")), OPT_CMDMODE(0, "continue", &command, N_("continue rebase"), CONTINUE), OPT_CMDMODE(0, "abort", &command, N_("abort rebase"), @@ -45,6 +48,8 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix) N_("rearrange fixup/squash lines"), REARRANGE_SQUASH), OPT_CMDMODE(0, "add-exec-commands", &command, N_("insert exec commands in todo list"), ADD_EXEC), + OPT_CMDMODE(0, "append-todo-help", &command, + N_("insert the help in the todo list"), APPEND_TODO_HELP), OPT_END() }; @@ -84,5 +89,7 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix) return !!rearrange_squash(); if (command == ADD_EXEC && argc == 2) return !!sequencer_add_exec_commands(argv[1]); + if (command == APPEND_TODO_HELP && argc == 1) + return !!append_todo_help(write_edit_todo, keep_empty); usage_with_options(builtin_rebase_helper_usage, options); } diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh index 299ded213..94c23a7af 100644 --- a/git-rebase--interactive.sh +++ b/git-rebase--interactive.sh @@ -39,38 +39,6 @@ comment_for_reflog () { esac } -append_todo_help () { - gettext " -Commands: -p, pick = use commit -r, reword = use commit, but edit the commit message -e, edit = use commit, but stop for amending -s, squash = use commit, but meld into previous commit -f, fixup = like \"squash\", but discard
[GSoC][PATCH v2 1/7] sequencer: make two functions and an enum from sequencer.c public
This makes rebase_path_todo(), get_missing_commit_check_level() and the enum check_level accessible outside sequencer.c. check_level is renamed missing_commit_check_level, and its value names are prefixed by MISSING_COMMIT_ to avoid namespace pollution. This will be needed for the rewrite of append_todo_help() from shell to C, as it will be in a new library source file, rebase-interactive.c. Signed-off-by: Alban Gruin --- sequencer.c | 22 +- sequencer.h | 8 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/sequencer.c b/sequencer.c index 5354d4d51..57fd58bc1 100644 --- a/sequencer.c +++ b/sequencer.c @@ -51,7 +51,7 @@ static GIT_PATH_FUNC(rebase_path, "rebase-merge") * the lines are processed, they are removed from the front of this * file and written to the tail of 'done'. */ -static GIT_PATH_FUNC(rebase_path_todo, "rebase-merge/git-rebase-todo") +GIT_PATH_FUNC(rebase_path_todo, "rebase-merge/git-rebase-todo") /* * The rebase command lines that have already been processed. A line * is moved here when it is first handled, before any associated user @@ -4221,24 +4221,20 @@ int transform_todos(unsigned flags) return i; } -enum check_level { - CHECK_IGNORE = 0, CHECK_WARN, CHECK_ERROR -}; - -static enum check_level get_missing_commit_check_level(void) +enum missing_commit_check_level get_missing_commit_check_level(void) { const char *value; if (git_config_get_value("rebase.missingcommitscheck", &value) || !strcasecmp("ignore", value)) - return CHECK_IGNORE; + return MISSING_COMMIT_CHECK_IGNORE; if (!strcasecmp("warn", value)) - return CHECK_WARN; + return MISSING_COMMIT_CHECK_WARN; if (!strcasecmp("error", value)) - return CHECK_ERROR; + return MISSING_COMMIT_CHECK_ERROR; warning(_("unrecognized setting %s for option " "rebase.missingCommitsCheck. Ignoring."), value); - return CHECK_IGNORE; + return MISSING_COMMIT_CHECK_IGNORE; } define_commit_slab(commit_seen, unsigned char); @@ -4250,7 +4246,7 @@ define_commit_slab(commit_seen, unsigned char); */ int check_todo_list(void) { - enum check_level check_level = get_missing_commit_check_level(); + enum missing_commit_check_level check_level = get_missing_commit_check_level(); struct strbuf todo_file = STRBUF_INIT; struct todo_list todo_list = TODO_LIST_INIT; struct strbuf missing = STRBUF_INIT; @@ -4267,7 +4263,7 @@ int check_todo_list(void) advise_to_edit_todo = res = parse_insn_buffer(todo_list.buf.buf, &todo_list); - if (res || check_level == CHECK_IGNORE) + if (res || check_level == MISSING_COMMIT_CHECK_IGNORE) goto leave_check; /* Mark the commits in git-rebase-todo as seen */ @@ -4302,7 +4298,7 @@ int check_todo_list(void) if (!missing.len) goto leave_check; - if (check_level == CHECK_ERROR) + if (check_level == MISSING_COMMIT_CHECK_ERROR) advise_to_edit_todo = res = 1; fprintf(stderr, diff --git a/sequencer.h b/sequencer.h index c5787c6b5..ffab798f1 100644 --- a/sequencer.h +++ b/sequencer.h @@ -3,6 +3,7 @@ const char *git_path_commit_editmsg(void); const char *git_path_seq_dir(void); +const char *rebase_path_todo(void); #define APPEND_SIGNOFF_DEDUP (1u << 0) @@ -57,6 +58,12 @@ struct replay_opts { }; #define REPLAY_OPTS_INIT { .action = -1, .current_fixups = STRBUF_INIT } +enum missing_commit_check_level { + MISSING_COMMIT_CHECK_IGNORE = 0, + MISSING_COMMIT_CHECK_WARN, + MISSING_COMMIT_CHECK_ERROR +}; + /* 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); @@ -79,6 +86,7 @@ int sequencer_make_script(FILE *out, int argc, const char **argv, int sequencer_add_exec_commands(const char *command); int transform_todos(unsigned flags); +enum missing_commit_check_level get_missing_commit_check_level(void); int check_todo_list(void); int skip_unnecessary_picks(void); int rearrange_squash(void); -- 2.18.0
[GSoC][PATCH v2 0/7] rebase -i: rewrite some parts in C
This patch series rewrites some parts of interactive rebase from shell to C: - append_todo_help(). The C version covers a bit more than the shell version. - The edit-todo functionnality. - The reflog operations. The v1 of this series is an aggregate made by Junio of my patch series about append_todo_help() (v3), edit-todo (v2) and reflog (v5), and can be found in the branch `ag/rebase-i-in-c`. This branch is based on master (as of 2018-07-02). Changes since v1: - Introducing rebase-interactive.c to contain functions necessary for interactive rebase. - Show an error message when append_todo_help() fails to edit the todo list. - Renaming enumeration check_level and its values to avoid namespace pollution. - Moving append_todo_help() and edit_todo() from sequencer.c to interactive-rebase.c. Alban Gruin (7): sequencer: make two functions and an enum from sequencer.c public rebase--interactive: rewrite append_todo_help() in C editor: add a function to launch the sequence editor rebase-interactive: rewrite the edit-todo functionality in C sequencer: add a new function to silence a command, except if it fails. rebase -i: rewrite setup_reflog_action() in C rebase -i: rewrite checkout_onto() in C Makefile | 1 + builtin/rebase--helper.c | 24 +++- cache.h| 1 + editor.c | 27 - git-rebase--interactive.sh | 100 +++ rebase-interactive.c | 99 ++ rebase-interactive.h | 7 +++ sequencer.c| 120 + sequencer.h| 14 + strbuf.h | 2 + 10 files changed, 260 insertions(+), 135 deletions(-) create mode 100644 rebase-interactive.c create mode 100644 rebase-interactive.h -- 2.18.0
Re: [GSoC][PATCH v5 0/3] rebase -i: rewrite reflog operations in C
Hi Junio, Le 29/06/2018 à 20:23, Junio C Hamano a écrit : > Junio C Hamano writes: > >> Let's aggregate these topics into a single topic, and perhaps call >> it ag/rebase-i-in-c or something like that. Pretending as if they >> are separately replaceable does not make much sense, as you are not >> rerolling the earlier one and keep going forward with producing more >> parts that depends on the parts that have been submitted earlier. > > So here is what I tentatively did. > > $ git log --oneline --reverse master..ag/rebase-i-in-c > 4d303fb608 rebase--interactive: rewrite append_todo_help() in C > b4ffe143a9 editor: add a function to launch the sequence editor > 4ebe39cef9 rebase--interactive: rewrite the edit-todo functionality in C > 0ff6bf7646 sequencer: add a new function to silence a command, except if > it fails. > 36784b351f rebase -i: rewrite setup_reflog_action() in C > 415cac57ee rebase -i: rewrite checkout_onto() in C > > In several hours please fetch from me and look for "Merge branch > 'ag/rebase-i-in-c' to pu" to see how they exactly look like; some of > the patches might not be the latest ones, in which case you may need > to prod me to get them replaced (resending them as a whole with > incremented v$n header is probably the easiest if we need to do so). > > Thanks. > The patches about append_todo_help() and edit-todo are not up to date, so I’ll resend them in a few minutes. Otherwise, this looks good to me. Cheers, Alban
[GSoC][PATCH v5 2/3] rebase -i: rewrite setup_reflog_action() in C
This rewrites (the misnamed) setup_reflog_action() from shell to C. The new version is called prepare_branch_to_be_rebased(). A new command is added to rebase--helper.c, “checkout-base”, as well as a new flag, “verbose”, to avoid silencing the output of the checkout operation called by checkout_base_commit(). The function `run_git_checkout()` will also be used in the next commit, therefore its code is not part of `checkout_base_commit()`. The shell version is then stripped in favour of a call to the helper. As $GIT_REFLOG_ACTION is no longer set at the first call of checkout_onto(), a call to comment_for_reflog() is added at the beginning of this function. Signed-off-by: Alban Gruin --- builtin/rebase--helper.c | 9 +++-- git-rebase--interactive.sh | 16 ++-- sequencer.c| 31 +++ sequencer.h| 3 +++ 4 files changed, 43 insertions(+), 16 deletions(-) diff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c index 731a64971..6c789e78b 100644 --- a/builtin/rebase--helper.c +++ b/builtin/rebase--helper.c @@ -13,12 +13,12 @@ static const char * const builtin_rebase_helper_usage[] = { int cmd_rebase__helper(int argc, const char **argv, const char *prefix) { struct replay_opts opts = REPLAY_OPTS_INIT; - unsigned flags = 0, keep_empty = 0, rebase_merges = 0; + unsigned flags = 0, keep_empty = 0, rebase_merges = 0, verbose = 0; int abbreviate_commands = 0, rebase_cousins = -1; enum { CONTINUE = 1, ABORT, MAKE_SCRIPT, SHORTEN_OIDS, EXPAND_OIDS, CHECK_TODO_LIST, SKIP_UNNECESSARY_PICKS, REARRANGE_SQUASH, - ADD_EXEC, APPEND_TODO_HELP, EDIT_TODO + ADD_EXEC, APPEND_TODO_HELP, EDIT_TODO, PREPARE_BRANCH } command = 0; struct option options[] = { OPT_BOOL(0, "ff", &opts.allow_ff, N_("allow fast-forward")), @@ -28,6 +28,7 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix) OPT_BOOL(0, "rebase-merges", &rebase_merges, N_("rebase merge commits")), OPT_BOOL(0, "rebase-cousins", &rebase_cousins, N_("keep original branch points of cousins")), + OPT__VERBOSE(&verbose, N_("be verbose")), OPT_CMDMODE(0, "continue", &command, N_("continue rebase"), CONTINUE), OPT_CMDMODE(0, "abort", &command, N_("abort rebase"), @@ -51,6 +52,8 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix) OPT_CMDMODE(0, "edit-todo", &command, N_("edit the todo list during an interactive rebase"), EDIT_TODO), + OPT_CMDMODE(0, "prepare-branch", &command, + N_("prepare the branch to be rebased"), PREPARE_BRANCH), OPT_END() }; @@ -94,5 +97,7 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix) return !!append_todo_help(0, keep_empty); if (command == EDIT_TODO && argc == 1) return !!edit_todo_list(flags); + if (command == PREPARE_BRANCH && argc == 2) + return !!prepare_branch_to_be_rebased(&opts, argv[1], verbose); usage_with_options(builtin_rebase_helper_usage, options); } diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh index 2defe607f..77e972bb6 100644 --- a/git-rebase--interactive.sh +++ b/git-rebase--interactive.sh @@ -72,6 +72,7 @@ collapse_todo_ids() { # Switch to the branch in $into and notify it in the reflog checkout_onto () { + comment_for_reflog start GIT_REFLOG_ACTION="$GIT_REFLOG_ACTION: checkout $onto_name" output git checkout $onto || die_abort "$(gettext "could not detach HEAD")" git update-ref ORIG_HEAD $orig_head @@ -119,19 +120,6 @@ initiate_action () { esac } -setup_reflog_action () { - comment_for_reflog start - - if test ! -z "$switch_to" - then - GIT_REFLOG_ACTION="$GIT_REFLOG_ACTION: checkout $switch_to" - output git checkout "$switch_to" -- || - die "$(eval_gettext "Could not checkout \$switch_to")" - - comment_for_reflog start - fi -} - init_basic_state () { orig_head=$(git rev-parse --verify HEAD) || die "$(gettext "No HEAD?")" mkdir -p "$state_dir" || die "$(eval_gettext "Could not create temporary \$state_dir")" @@ -211,7 +199,7 @@ git_rebase__interactive () { return 0 fi - s
[GSoC][PATCH v5 0/3] rebase -i: rewrite reflog operations in C
This patch series rewrites the reflog operations from shell to C. This is part of the effort to rewrite interactive rebase in C. The first commit is dedicated to creating a function to silence a command, as the sequencer will do in several places with these patches. This branch is based on ag/rebase-i-rewrite-todo, and does not conflict with pu (as of 2018-06-29). Changes since v4: - Changing the order of setup_reflog_action() and checkout_onto() rewrites in the series - checkout_onto() is no longer renamed in C - setup_reflog_action() is renamed to prepare_branch_to_be_rebased(), and not to checkout_onto(). Alban Gruin (3): sequencer: add a new function to silence a command, except if it fails. rebase -i: rewrite setup_reflog_action() in C rebase -i: rewrite checkout_onto() in C builtin/rebase--helper.c | 14 - git-rebase--interactive.sh | 39 ++ sequencer.c| 101 +++-- sequencer.h| 6 +++ 4 files changed, 98 insertions(+), 62 deletions(-) -- 2.18.0
[GSoC][PATCH v5 1/3] sequencer: add a new function to silence a command, except if it fails.
This adds a new function, run_command_silent_on_success(), to redirect the stdout and stderr of a command to a strbuf, and then to run that command. This strbuf is printed only if the command fails. It is functionnaly similar to output() from git-rebase.sh. run_git_commit() is then refactored to use of run_command_silent_on_success(). Signed-off-by: Alban Gruin --- sequencer.c | 51 +-- 1 file changed, 25 insertions(+), 26 deletions(-) diff --git a/sequencer.c b/sequencer.c index cb7ec9807..d9545b366 100644 --- a/sequencer.c +++ b/sequencer.c @@ -769,6 +769,23 @@ N_("you have staged changes in your working tree\n" #define VERIFY_MSG (1<<4) #define CREATE_ROOT_COMMIT (1<<5) +static int run_command_silent_on_success(struct child_process *cmd) +{ + struct strbuf buf = STRBUF_INIT; + int rc; + + cmd->stdout_to_stderr = 1; + rc = pipe_command(cmd, + NULL, 0, + NULL, 0, + &buf, 0); + + if (rc) + fputs(buf.buf, stderr); + strbuf_release(&buf); + return rc; +} + /* * If we are cherry-pick, and if the merge did not result in * hand-editing, we will hit this commit and inherit the original @@ -823,18 +840,11 @@ static int run_git_commit(const char *defmsg, struct replay_opts *opts, cmd.git_cmd = 1; - if (is_rebase_i(opts)) { - if (!(flags & EDIT_MSG)) { - cmd.stdout_to_stderr = 1; - cmd.err = -1; - } - - if (read_env_script(&cmd.env_array)) { - const char *gpg_opt = gpg_sign_opt_quoted(opts); + if (is_rebase_i(opts) && read_env_script(&cmd.env_array)) { + const char *gpg_opt = gpg_sign_opt_quoted(opts); - return error(_(staged_changes_advice), -gpg_opt, gpg_opt); - } + return error(_(staged_changes_advice), +gpg_opt, gpg_opt); } argv_array_push(&cmd.args, "commit"); @@ -864,21 +874,10 @@ static int run_git_commit(const char *defmsg, struct replay_opts *opts, if (opts->allow_empty_message) argv_array_push(&cmd.args, "--allow-empty-message"); - if (cmd.err == -1) { - /* hide stderr on success */ - struct strbuf buf = STRBUF_INIT; - int rc = pipe_command(&cmd, - NULL, 0, - /* stdout is already redirected */ - NULL, 0, - &buf, 0); - if (rc) - fputs(buf.buf, stderr); - strbuf_release(&buf); - return rc; - } - - return run_command(&cmd); + if (is_rebase_i(opts) && !(flags & EDIT_MSG)) + return run_command_silent_on_success(&cmd); + else + return run_command(&cmd); } static int rest_is_empty(const struct strbuf *sb, int start) -- 2.18.0
[GSoC][PATCH v5 3/3] rebase -i: rewrite checkout_onto() in C
This rewrites checkout_onto() from shell to C. A new command (“checkout-onto”) is added to rebase--helper.c. The shell version is then stripped. Signed-off-by: Alban Gruin --- builtin/rebase--helper.c | 7 ++- git-rebase--interactive.sh | 25 - sequencer.c| 19 +++ sequencer.h| 3 +++ 4 files changed, 32 insertions(+), 22 deletions(-) diff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c index 6c789e78b..0091e094b 100644 --- a/builtin/rebase--helper.c +++ b/builtin/rebase--helper.c @@ -18,7 +18,8 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix) enum { CONTINUE = 1, ABORT, MAKE_SCRIPT, SHORTEN_OIDS, EXPAND_OIDS, CHECK_TODO_LIST, SKIP_UNNECESSARY_PICKS, REARRANGE_SQUASH, - ADD_EXEC, APPEND_TODO_HELP, EDIT_TODO, PREPARE_BRANCH + ADD_EXEC, APPEND_TODO_HELP, EDIT_TODO, PREPARE_BRANCH, + CHECKOUT_ONTO } command = 0; struct option options[] = { OPT_BOOL(0, "ff", &opts.allow_ff, N_("allow fast-forward")), @@ -54,6 +55,8 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix) EDIT_TODO), OPT_CMDMODE(0, "prepare-branch", &command, N_("prepare the branch to be rebased"), PREPARE_BRANCH), + OPT_CMDMODE(0, "checkout-onto", &command, + N_("checkout a commit"), CHECKOUT_ONTO), OPT_END() }; @@ -99,5 +102,7 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix) return !!edit_todo_list(flags); if (command == PREPARE_BRANCH && argc == 2) return !!prepare_branch_to_be_rebased(&opts, argv[1], verbose); + if (command == CHECKOUT_ONTO && argc == 4) + return !!checkout_onto(&opts, argv[1], argv[2], argv[3], verbose); usage_with_options(builtin_rebase_helper_usage, options); } diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh index 77e972bb6..b68f108f2 100644 --- a/git-rebase--interactive.sh +++ b/git-rebase--interactive.sh @@ -28,17 +28,6 @@ case "$comment_char" in ;; esac -orig_reflog_action="$GIT_REFLOG_ACTION" - -comment_for_reflog () { - case "$orig_reflog_action" in - ''|rebase*) - GIT_REFLOG_ACTION="rebase -i ($1)" - export GIT_REFLOG_ACTION - ;; - esac -} - die_abort () { apply_autostash rm -rf "$state_dir" @@ -70,14 +59,6 @@ collapse_todo_ids() { git rebase--helper --shorten-ids } -# Switch to the branch in $into and notify it in the reflog -checkout_onto () { - comment_for_reflog start - GIT_REFLOG_ACTION="$GIT_REFLOG_ACTION: checkout $onto_name" - output git checkout $onto || die_abort "$(gettext "could not detach HEAD")" - git update-ref ORIG_HEAD $orig_head -} - get_missing_commit_check_level () { check_level=$(git config --get rebase.missingCommitsCheck) check_level=${check_level:-ignore} @@ -176,7 +157,8 @@ EOF git rebase--helper --check-todo-list || { ret=$? - checkout_onto + git rebase--helper --checkout-onto "$onto_name" "$onto" \ + "$orig_head" ${verbose:+--verbose} exit $ret } @@ -186,7 +168,8 @@ EOF onto="$(git rebase--helper --skip-unnecessary-picks)" || die "Could not skip unnecessary pick commands" - checkout_onto + git rebase--helper --checkout-onto "$onto_name" "$onto" "$orig_head" \ + ${verbose:+--verbose} require_clean_work_tree "rebase" exec git rebase--helper ${force_rebase:+--no-ff} $allow_empty_message \ --continue diff --git a/sequencer.c b/sequencer.c index dd0cf3cb5..ec6de4eda 100644 --- a/sequencer.c +++ b/sequencer.c @@ -3165,6 +3165,25 @@ int prepare_branch_to_be_rebased(struct replay_opts *opts, const char *commit, return 0; } +int checkout_onto(struct replay_opts *opts, + const char *onto_name, const char *onto, + const char *orig_head, unsigned verbose) +{ + struct object_id oid; + const char *action = reflog_message(opts, "start", "checkout %s", onto_name); + + if (get_oid(orig_head, &oid)) + return error(_("%s: not a valid OID"), orig_head); + + if (run_git_checkout(opts, onto, verbose, action)) { + apply_autostash(opts); + sequencer_remove_state(opts); + retu
ag/rebase-i-append-todo-help, was Re: What's cooking in git.git (Jun 2018, #07; Thu, 28)
Hi Junio, Le 28/06/2018 à 23:40, Junio C Hamano a écrit : > * ag/rebase-i-append-todo-help (2018-06-14) 2 commits > - rebase--interactive: rewrite append_todo_help() in C > - Merge branch 'ag/rebase-p' into ag/rebase-i-append-todo-help > (this branch is used by ag/rebase-i-rewrite-todo.) > > Stepwise rewriting of the machinery of "rebase -i" into C continues. > > Needs a reroll. > cf. > > As I moved append_todo_help() to `rebase-interactive.c`, it should be because I did not changed `msg = _(…)` to `msg = N_(…)`. It was pointed out on IRC that it was not necessary, after all[0]. Basically, N_() is needed for static variables, not for "dynamic" variables like `msg` in append_todo_help(). [0] http://colabti.org/irclogger/irclogger_log/git-devel?date=2018-06-26#l44 Cheers, Alban
[GSoC][PATCH v5 2/2] rebase--interactive: rewrite append_todo_help() in C
This rewrites append_todo_help() from shell to C. It also incorporates some parts of initiate_action() and complete_action() that also write help texts to the todo file. This also introduces the source file rebase-interactive.c. This file will contain functions necessary for interactive rebase that are too specific for the sequencer, and is part of libgit.a. Two flags are added to rebase--helper.c: one to call append_todo_help() (`--append-todo-help`), and another one to tell append_todo_help() to write the help text suited for the edit-todo mode (`--write-edit-todo`). Finally, append_todo_help() is removed from git-rebase--interactive.sh to use `rebase--helper --append-todo-help` instead. Signed-off-by: Alban Gruin --- Makefile | 1 + builtin/rebase--helper.c | 11 -- git-rebase--interactive.sh | 52 ++--- rebase-interactive.c | 68 ++ rebase-interactive.h | 6 5 files changed, 86 insertions(+), 52 deletions(-) create mode 100644 rebase-interactive.c create mode 100644 rebase-interactive.h diff --git a/Makefile b/Makefile index 0cb6590f2..a281139ef 100644 --- a/Makefile +++ b/Makefile @@ -922,6 +922,7 @@ LIB_OBJS += protocol.o LIB_OBJS += quote.o LIB_OBJS += reachable.o LIB_OBJS += read-cache.o +LIB_OBJS += rebase-interactive.o LIB_OBJS += reflog-walk.o LIB_OBJS += refs.o LIB_OBJS += refs/files-backend.o diff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c index f7c2a5fdc..05e73e71d 100644 --- a/builtin/rebase--helper.c +++ b/builtin/rebase--helper.c @@ -3,6 +3,7 @@ #include "config.h" #include "parse-options.h" #include "sequencer.h" +#include "rebase-interactive.h" static const char * const builtin_rebase_helper_usage[] = { N_("git rebase--helper []"), @@ -12,12 +13,12 @@ static const char * const builtin_rebase_helper_usage[] = { int cmd_rebase__helper(int argc, const char **argv, const char *prefix) { struct replay_opts opts = REPLAY_OPTS_INIT; - unsigned flags = 0, keep_empty = 0, rebase_merges = 0; + unsigned flags = 0, keep_empty = 0, rebase_merges = 0, write_edit_todo = 0; int abbreviate_commands = 0, rebase_cousins = -1; enum { CONTINUE = 1, ABORT, MAKE_SCRIPT, SHORTEN_OIDS, EXPAND_OIDS, CHECK_TODO_LIST, SKIP_UNNECESSARY_PICKS, REARRANGE_SQUASH, - ADD_EXEC + ADD_EXEC, APPEND_TODO_HELP } command = 0; struct option options[] = { OPT_BOOL(0, "ff", &opts.allow_ff, N_("allow fast-forward")), @@ -27,6 +28,8 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix) OPT_BOOL(0, "rebase-merges", &rebase_merges, N_("rebase merge commits")), OPT_BOOL(0, "rebase-cousins", &rebase_cousins, N_("keep original branch points of cousins")), + OPT_BOOL(0, "write-edit-todo", &write_edit_todo, +N_("append the edit-todo message to the todo-list")), OPT_CMDMODE(0, "continue", &command, N_("continue rebase"), CONTINUE), OPT_CMDMODE(0, "abort", &command, N_("abort rebase"), @@ -45,6 +48,8 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix) N_("rearrange fixup/squash lines"), REARRANGE_SQUASH), OPT_CMDMODE(0, "add-exec-commands", &command, N_("insert exec commands in todo list"), ADD_EXEC), + OPT_CMDMODE(0, "append-todo-help", &command, + N_("insert the help in the todo list"), APPEND_TODO_HELP), OPT_END() }; @@ -84,5 +89,7 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix) return !!rearrange_squash(); if (command == ADD_EXEC && argc == 2) return !!sequencer_add_exec_commands(argv[1]); + if (command == APPEND_TODO_HELP && argc == 1) + return !!append_todo_help(write_edit_todo, keep_empty); usage_with_options(builtin_rebase_helper_usage, options); } diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh index 299ded213..94c23a7af 100644 --- a/git-rebase--interactive.sh +++ b/git-rebase--interactive.sh @@ -39,38 +39,6 @@ comment_for_reflog () { esac } -append_todo_help () { - gettext " -Commands: -p, pick = use commit -r, reword = use commit, but edit the commit message -e, edit = use commit, but stop for amending -s, squash = use commit, but meld into previous commit -f, fixup = like \"squash\", but discard
[GSoC][PATCH v5 1/2] sequencer: make two functions and an enum from sequencer.c public
This makes rebase_path_todo(), get_missing_commit_check_level() and the enum check_level accessible outside sequencer.c. check_level is renamed missing_commit_check_level, and its value names are prefixed by MISSING_COMMIT_ to avoid namespace pollution. This will be needed for the rewrite of append_todo_help() from shell to C, as it will be in a new library source file, rebase-interactive.c. Signed-off-by: Alban Gruin --- sequencer.c | 22 +- sequencer.h | 8 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/sequencer.c b/sequencer.c index 0a291c91f..cb7ec9807 100644 --- a/sequencer.c +++ b/sequencer.c @@ -52,7 +52,7 @@ static GIT_PATH_FUNC(rebase_path, "rebase-merge") * the lines are processed, they are removed from the front of this * file and written to the tail of 'done'. */ -static GIT_PATH_FUNC(rebase_path_todo, "rebase-merge/git-rebase-todo") +GIT_PATH_FUNC(rebase_path_todo, "rebase-merge/git-rebase-todo") /* * The rebase command lines that have already been processed. A line * is moved here when it is first handled, before any associated user @@ -4223,24 +4223,20 @@ int transform_todos(unsigned flags) return i; } -enum check_level { - CHECK_IGNORE = 0, CHECK_WARN, CHECK_ERROR -}; - -static enum check_level get_missing_commit_check_level(void) +enum missing_commit_check_level get_missing_commit_check_level(void) { const char *value; if (git_config_get_value("rebase.missingcommitscheck", &value) || !strcasecmp("ignore", value)) - return CHECK_IGNORE; + return MISSING_COMMIT_CHECK_IGNORE; if (!strcasecmp("warn", value)) - return CHECK_WARN; + return MISSING_COMMIT_CHECK_WARN; if (!strcasecmp("error", value)) - return CHECK_ERROR; + return MISSING_COMMIT_CHECK_ERROR; warning(_("unrecognized setting %s for option " "rebase.missingCommitsCheck. Ignoring."), value); - return CHECK_IGNORE; + return MISSING_COMMIT_CHECK_IGNORE; } define_commit_slab(commit_seen, unsigned char); @@ -4252,7 +4248,7 @@ define_commit_slab(commit_seen, unsigned char); */ int check_todo_list(void) { - enum check_level check_level = get_missing_commit_check_level(); + enum missing_commit_check_level check_level = get_missing_commit_check_level(); struct strbuf todo_file = STRBUF_INIT; struct todo_list todo_list = TODO_LIST_INIT; struct strbuf missing = STRBUF_INIT; @@ -4269,7 +4265,7 @@ int check_todo_list(void) advise_to_edit_todo = res = parse_insn_buffer(todo_list.buf.buf, &todo_list); - if (res || check_level == CHECK_IGNORE) + if (res || check_level == MISSING_COMMIT_CHECK_IGNORE) goto leave_check; /* Mark the commits in git-rebase-todo as seen */ @@ -4304,7 +4300,7 @@ int check_todo_list(void) if (!missing.len) goto leave_check; - if (check_level == CHECK_ERROR) + if (check_level == MISSING_COMMIT_CHECK_ERROR) advise_to_edit_todo = res = 1; fprintf(stderr, diff --git a/sequencer.h b/sequencer.h index c5787c6b5..ffab798f1 100644 --- a/sequencer.h +++ b/sequencer.h @@ -3,6 +3,7 @@ const char *git_path_commit_editmsg(void); const char *git_path_seq_dir(void); +const char *rebase_path_todo(void); #define APPEND_SIGNOFF_DEDUP (1u << 0) @@ -57,6 +58,12 @@ struct replay_opts { }; #define REPLAY_OPTS_INIT { .action = -1, .current_fixups = STRBUF_INIT } +enum missing_commit_check_level { + MISSING_COMMIT_CHECK_IGNORE = 0, + MISSING_COMMIT_CHECK_WARN, + MISSING_COMMIT_CHECK_ERROR +}; + /* 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); @@ -79,6 +86,7 @@ int sequencer_make_script(FILE *out, int argc, const char **argv, int sequencer_add_exec_commands(const char *command); int transform_todos(unsigned flags); +enum missing_commit_check_level get_missing_commit_check_level(void); int check_todo_list(void); int skip_unnecessary_picks(void); int rearrange_squash(void); -- 2.18.0
[GSoC][PATCH v5 0/2] rebase -i: rewrite append_todo_help() in C
This patch rewrites append_todo_help() from shell to C. The C version covers a bit more than the old shell version. To achieve that, some parameters were added to rebase--helper. This also introduce a new source file, rebase-interactive.c. This is part of the effort to rewrite interactive rebase in C. This is based on next, as of 2018-06-28. Changes since v4: - Renaming enumeration check_level and its values to avoid namespace pollution. Alban Gruin (2): sequencer: make two functions and an enum from sequencer.c public rebase--interactive: rewrite append_todo_help() in C Makefile | 1 + builtin/rebase--helper.c | 11 -- git-rebase--interactive.sh | 52 ++--- rebase-interactive.c | 68 ++ rebase-interactive.h | 6 sequencer.c| 22 +--- sequencer.h| 8 + 7 files changed, 103 insertions(+), 65 deletions(-) create mode 100644 rebase-interactive.c create mode 100644 rebase-interactive.h -- 2.18.0
Re: [GSoC][PATCH v4 0/2] rebase -i: rewrite append_todo_help() in C
Hi Johannes, Le 26/06/2018 à 23:37, Johannes Schindelin a écrit : > Hi Alban, > > On Tue, 26 Jun 2018, Alban Gruin wrote: > >> This patch rewrites append_todo_help() from shell to C. The C version >> covers a bit more than the old shell version. To achieve that, some >> parameters were added to rebase--helper. >> >> This also introduce a new source file, rebase-interactive.c. >> >> This is part of the effort to rewrite interactive rebase in C. >> >> This is based on next, as of 2018-06-26. > > Out of curiosity: which commits that are not yet in `master` are required? > None, actually. Cheers, Alban
Re: [GSoC][PATCH v4 1/2] sequencer: make two functions and an enum from sequencer.c public
Hi Johannes, Le 26/06/2018 à 23:41, Johannes Schindelin a écrit : > Hi Alban, > > On Tue, 26 Jun 2018, Alban Gruin wrote: > >> diff --git a/sequencer.h b/sequencer.h >> index c5787c6b5..08397b0d1 100644 >> --- a/sequencer.h >> +++ b/sequencer.h >> @@ -3,6 +3,7 @@ >> >> const char *git_path_commit_editmsg(void); >> const char *git_path_seq_dir(void); >> +const char *rebase_path_todo(void); >> >> #define APPEND_SIGNOFF_DEDUP (1u << 0) >> >> @@ -57,6 +58,10 @@ struct replay_opts { >> }; >> #define REPLAY_OPTS_INIT { .action = -1, .current_fixups = STRBUF_INIT } >> >> +enum check_level { >> +CHECK_IGNORE = 0, CHECK_WARN, CHECK_ERROR >> +}; >> + > > While this is contained within scopes that include `sequencer.h`, it *is* > public now, so I am slightly uneasy about keeping this enum so generic. > Maybe we want to use > > enum missing_commit_check_level { > MISSING_COMMIT_CHECK_IGNORE = 0, > MISSING_COMMIT_CHECK_WARN, > MISSING_COMMIT_CHECK_ERROR > }; > > instead? > You’re right, this would be better. Cheers, Alban
[GSoC][PATCH v3 0/2] rebase -i: rewrite the edit-todo functionality in C
This patch rewrites the edit-todo functionality from shell to C. This is part of the effort to rewrite interactive rebase in C. This patch is based on the fourth iteration of my series rewriting append_todo_help() in C. Changes since v2: - Moving edit_todo() from sequencer.c to interactive-rebase.c. Alban Gruin (2): editor: add a function to launch the sequence editor rebase-interactive: rewrite the edit-todo functionality in C builtin/rebase--helper.c | 13 - cache.h| 1 + editor.c | 27 +-- git-rebase--interactive.sh | 11 +-- rebase-interactive.c | 31 +++ rebase-interactive.h | 1 + strbuf.h | 2 ++ 7 files changed, 69 insertions(+), 17 deletions(-) -- 2.18.0
[GSoC][PATCH v3 1/2] editor: add a function to launch the sequence editor
As part of the rewrite of interactive rebase, the sequencer will need to open the sequence editor to allow the user to edit the todo list. Instead of duplicating the existing launch_editor() function, this refactors it to a new function, launch_specified_editor(), which takes the editor as a parameter, in addition to the path, the buffer and the environment variables. launch_sequence_editor() is then added to launch the sequence editor. Signed-off-by: Alban Gruin --- cache.h | 1 + editor.c | 27 +-- strbuf.h | 2 ++ 3 files changed, 28 insertions(+), 2 deletions(-) diff --git a/cache.h b/cache.h index 8b447652a..d70ae49ca 100644 --- a/cache.h +++ b/cache.h @@ -1409,6 +1409,7 @@ extern const char *fmt_name(const char *name, const char *email); extern const char *ident_default_name(void); extern const char *ident_default_email(void); extern const char *git_editor(void); +extern const char *git_sequence_editor(void); extern const char *git_pager(int stdout_is_tty); extern int is_terminal_dumb(void); extern int git_ident_config(const char *, const char *, void *); diff --git a/editor.c b/editor.c index 9a9b4e12d..c985eee1f 100644 --- a/editor.c +++ b/editor.c @@ -1,4 +1,5 @@ #include "cache.h" +#include "config.h" #include "strbuf.h" #include "run-command.h" #include "sigchain.h" @@ -34,10 +35,21 @@ const char *git_editor(void) return editor; } -int launch_editor(const char *path, struct strbuf *buffer, const char *const *env) +const char *git_sequence_editor(void) { - const char *editor = git_editor(); + const char *editor = getenv("GIT_SEQUENCE_EDITOR"); + + if (!editor) + git_config_get_string_const("sequence.editor", &editor); + if (!editor) + editor = git_editor(); + return editor; +} + +static int launch_specified_editor(const char *editor, const char *path, + struct strbuf *buffer, const char *const *env) +{ if (!editor) return error("Terminal is dumb, but EDITOR unset"); @@ -95,3 +107,14 @@ int launch_editor(const char *path, struct strbuf *buffer, const char *const *en return error_errno("could not read file '%s'", path); return 0; } + +int launch_editor(const char *path, struct strbuf *buffer, const char *const *env) +{ + return launch_specified_editor(git_editor(), path, buffer, env); +} + +int launch_sequence_editor(const char *path, struct strbuf *buffer, + const char *const *env) +{ + return launch_specified_editor(git_sequence_editor(), path, buffer, env); +} diff --git a/strbuf.h b/strbuf.h index 60a35aef1..66da9822f 100644 --- a/strbuf.h +++ b/strbuf.h @@ -575,6 +575,8 @@ extern void strbuf_add_unique_abbrev(struct strbuf *sb, * file's contents are not read into the buffer upon completion. */ extern int launch_editor(const char *path, struct strbuf *buffer, const char *const *env); +extern int launch_sequence_editor(const char *path, struct strbuf *buffer, + const char *const *env); extern void strbuf_add_lines(struct strbuf *sb, const char *prefix, const char *buf, size_t size); -- 2.18.0
[GSoC][PATCH v3 2/2] rebase-interactive: rewrite the edit-todo functionality in C
This rewrites the edit-todo functionality from shell to C. To achieve that, a new command mode, `edit-todo`, is added, and the `write-edit-todo` flag is removed, as the shell script does not need to write the edit todo help message to the todo list anymore. The shell version is then stripped in favour of a call to the helper. Signed-off-by: Alban Gruin --- builtin/rebase--helper.c | 13 - git-rebase--interactive.sh | 11 +-- rebase-interactive.c | 31 +++ rebase-interactive.h | 1 + 4 files changed, 41 insertions(+), 15 deletions(-) diff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c index 05e73e71d..731a64971 100644 --- a/builtin/rebase--helper.c +++ b/builtin/rebase--helper.c @@ -13,12 +13,12 @@ static const char * const builtin_rebase_helper_usage[] = { int cmd_rebase__helper(int argc, const char **argv, const char *prefix) { struct replay_opts opts = REPLAY_OPTS_INIT; - unsigned flags = 0, keep_empty = 0, rebase_merges = 0, write_edit_todo = 0; + unsigned flags = 0, keep_empty = 0, rebase_merges = 0; int abbreviate_commands = 0, rebase_cousins = -1; enum { CONTINUE = 1, ABORT, MAKE_SCRIPT, SHORTEN_OIDS, EXPAND_OIDS, CHECK_TODO_LIST, SKIP_UNNECESSARY_PICKS, REARRANGE_SQUASH, - ADD_EXEC, APPEND_TODO_HELP + ADD_EXEC, APPEND_TODO_HELP, EDIT_TODO } command = 0; struct option options[] = { OPT_BOOL(0, "ff", &opts.allow_ff, N_("allow fast-forward")), @@ -28,8 +28,6 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix) OPT_BOOL(0, "rebase-merges", &rebase_merges, N_("rebase merge commits")), OPT_BOOL(0, "rebase-cousins", &rebase_cousins, N_("keep original branch points of cousins")), - OPT_BOOL(0, "write-edit-todo", &write_edit_todo, -N_("append the edit-todo message to the todo-list")), OPT_CMDMODE(0, "continue", &command, N_("continue rebase"), CONTINUE), OPT_CMDMODE(0, "abort", &command, N_("abort rebase"), @@ -50,6 +48,9 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix) N_("insert exec commands in todo list"), ADD_EXEC), OPT_CMDMODE(0, "append-todo-help", &command, N_("insert the help in the todo list"), APPEND_TODO_HELP), + OPT_CMDMODE(0, "edit-todo", &command, + N_("edit the todo list during an interactive rebase"), + EDIT_TODO), OPT_END() }; @@ -90,6 +91,8 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix) if (command == ADD_EXEC && argc == 2) return !!sequencer_add_exec_commands(argv[1]); if (command == APPEND_TODO_HELP && argc == 1) - return !!append_todo_help(write_edit_todo, keep_empty); + return !!append_todo_help(0, keep_empty); + if (command == EDIT_TODO && argc == 1) + return !!edit_todo_list(flags); usage_with_options(builtin_rebase_helper_usage, options); } diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh index 94c23a7af..2defe607f 100644 --- a/git-rebase--interactive.sh +++ b/git-rebase--interactive.sh @@ -108,16 +108,7 @@ initiate_action () { --continue ;; edit-todo) - git stripspace --strip-comments <"$todo" >"$todo".new - mv -f "$todo".new "$todo" - collapse_todo_ids - git rebase--helper --append-todo-help --write-edit-todo - - git_sequence_editor "$todo" || - die "$(gettext "Could not execute editor")" - expand_todo_ids - - exit + exec git rebase--helper --edit-todo ;; show-current-patch) exec git show REBASE_HEAD -- diff --git a/rebase-interactive.c b/rebase-interactive.c index c79c819b9..ace8e095b 100644 --- a/rebase-interactive.c +++ b/rebase-interactive.c @@ -66,3 +66,34 @@ int append_todo_help(unsigned edit_todo, unsigned keep_empty) return ret; } + +int edit_todo_list(unsigned flags) +{ + struct strbuf buf = STRBUF_INIT; + const char *todo_file = rebase_path_todo(); + FILE *todo; + + if (strbuf_read_file(&buf, todo_file, 0) < 0) + return error_errno(_("could not read '%s'."), todo_
[GSoC][PATCH v4 2/2] rebase--interactive: rewrite append_todo_help() in C
This rewrites append_todo_help() from shell to C. It also incorporates some parts of initiate_action() and complete_action() that also write help texts to the todo file. This also introduces the source file rebase-interactive.c. This file will contain functions necessary for interactive rebase that are too specific for the sequencer, and is part of libgit.a. Two flags are added to rebase--helper.c: one to call append_todo_help() (`--append-todo-help`), and another one to tell append_todo_help() to write the help text suited for the edit-todo mode (`--write-edit-todo`). Finally, append_todo_help() is removed from git-rebase--interactive.sh to use `rebase--helper --append-todo-help` instead. Signed-off-by: Alban Gruin --- Makefile | 1 + builtin/rebase--helper.c | 11 -- git-rebase--interactive.sh | 52 ++--- rebase-interactive.c | 68 ++ rebase-interactive.h | 6 5 files changed, 86 insertions(+), 52 deletions(-) create mode 100644 rebase-interactive.c create mode 100644 rebase-interactive.h diff --git a/Makefile b/Makefile index 0cb6590f2..a281139ef 100644 --- a/Makefile +++ b/Makefile @@ -922,6 +922,7 @@ LIB_OBJS += protocol.o LIB_OBJS += quote.o LIB_OBJS += reachable.o LIB_OBJS += read-cache.o +LIB_OBJS += rebase-interactive.o LIB_OBJS += reflog-walk.o LIB_OBJS += refs.o LIB_OBJS += refs/files-backend.o diff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c index f7c2a5fdc..05e73e71d 100644 --- a/builtin/rebase--helper.c +++ b/builtin/rebase--helper.c @@ -3,6 +3,7 @@ #include "config.h" #include "parse-options.h" #include "sequencer.h" +#include "rebase-interactive.h" static const char * const builtin_rebase_helper_usage[] = { N_("git rebase--helper []"), @@ -12,12 +13,12 @@ static const char * const builtin_rebase_helper_usage[] = { int cmd_rebase__helper(int argc, const char **argv, const char *prefix) { struct replay_opts opts = REPLAY_OPTS_INIT; - unsigned flags = 0, keep_empty = 0, rebase_merges = 0; + unsigned flags = 0, keep_empty = 0, rebase_merges = 0, write_edit_todo = 0; int abbreviate_commands = 0, rebase_cousins = -1; enum { CONTINUE = 1, ABORT, MAKE_SCRIPT, SHORTEN_OIDS, EXPAND_OIDS, CHECK_TODO_LIST, SKIP_UNNECESSARY_PICKS, REARRANGE_SQUASH, - ADD_EXEC + ADD_EXEC, APPEND_TODO_HELP } command = 0; struct option options[] = { OPT_BOOL(0, "ff", &opts.allow_ff, N_("allow fast-forward")), @@ -27,6 +28,8 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix) OPT_BOOL(0, "rebase-merges", &rebase_merges, N_("rebase merge commits")), OPT_BOOL(0, "rebase-cousins", &rebase_cousins, N_("keep original branch points of cousins")), + OPT_BOOL(0, "write-edit-todo", &write_edit_todo, +N_("append the edit-todo message to the todo-list")), OPT_CMDMODE(0, "continue", &command, N_("continue rebase"), CONTINUE), OPT_CMDMODE(0, "abort", &command, N_("abort rebase"), @@ -45,6 +48,8 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix) N_("rearrange fixup/squash lines"), REARRANGE_SQUASH), OPT_CMDMODE(0, "add-exec-commands", &command, N_("insert exec commands in todo list"), ADD_EXEC), + OPT_CMDMODE(0, "append-todo-help", &command, + N_("insert the help in the todo list"), APPEND_TODO_HELP), OPT_END() }; @@ -84,5 +89,7 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix) return !!rearrange_squash(); if (command == ADD_EXEC && argc == 2) return !!sequencer_add_exec_commands(argv[1]); + if (command == APPEND_TODO_HELP && argc == 1) + return !!append_todo_help(write_edit_todo, keep_empty); usage_with_options(builtin_rebase_helper_usage, options); } diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh index 299ded213..94c23a7af 100644 --- a/git-rebase--interactive.sh +++ b/git-rebase--interactive.sh @@ -39,38 +39,6 @@ comment_for_reflog () { esac } -append_todo_help () { - gettext " -Commands: -p, pick = use commit -r, reword = use commit, but edit the commit message -e, edit = use commit, but stop for amending -s, squash = use commit, but meld into previous commit -f, fixup = like \"squash\", but discard
[GSoC][PATCH v4 1/2] sequencer: make two functions and an enum from sequencer.c public
This makes rebase_path_todo(), get_missign_commit_check_level() and the enum check_level accessible outside sequencer.c. This will be needed for the rewrite of append_todo_help() from shell to C, as it will be in a new library source file, rebase-interactive.c. Signed-off-by: Alban Gruin --- sequencer.c | 8 ++-- sequencer.h | 6 ++ 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/sequencer.c b/sequencer.c index 0a291c91f..881a4f7f4 100644 --- a/sequencer.c +++ b/sequencer.c @@ -52,7 +52,7 @@ static GIT_PATH_FUNC(rebase_path, "rebase-merge") * the lines are processed, they are removed from the front of this * file and written to the tail of 'done'. */ -static GIT_PATH_FUNC(rebase_path_todo, "rebase-merge/git-rebase-todo") +GIT_PATH_FUNC(rebase_path_todo, "rebase-merge/git-rebase-todo") /* * The rebase command lines that have already been processed. A line * is moved here when it is first handled, before any associated user @@ -4223,11 +4223,7 @@ int transform_todos(unsigned flags) return i; } -enum check_level { - CHECK_IGNORE = 0, CHECK_WARN, CHECK_ERROR -}; - -static enum check_level get_missing_commit_check_level(void) +enum check_level get_missing_commit_check_level(void) { const char *value; diff --git a/sequencer.h b/sequencer.h index c5787c6b5..08397b0d1 100644 --- a/sequencer.h +++ b/sequencer.h @@ -3,6 +3,7 @@ const char *git_path_commit_editmsg(void); const char *git_path_seq_dir(void); +const char *rebase_path_todo(void); #define APPEND_SIGNOFF_DEDUP (1u << 0) @@ -57,6 +58,10 @@ struct replay_opts { }; #define REPLAY_OPTS_INIT { .action = -1, .current_fixups = STRBUF_INIT } +enum check_level { + CHECK_IGNORE = 0, CHECK_WARN, CHECK_ERROR +}; + /* 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); @@ -79,6 +84,7 @@ int sequencer_make_script(FILE *out, int argc, const char **argv, int sequencer_add_exec_commands(const char *command); int transform_todos(unsigned flags); +enum check_level get_missing_commit_check_level(void); int check_todo_list(void); int skip_unnecessary_picks(void); int rearrange_squash(void); -- 2.18.0
[GSoC][PATCH v4 0/2] rebase -i: rewrite append_todo_help() in C
This patch rewrites append_todo_help() from shell to C. The C version covers a bit more than the old shell version. To achieve that, some parameters were added to rebase--helper. This also introduce a new source file, rebase-interactive.c. This is part of the effort to rewrite interactive rebase in C. This is based on next, as of 2018-06-26. Changes since v3: - Show an error message when append_todo_help() fails to edit the todo list. - Introducing rebase-interactive.c to contain functions necessary for interactive rebase. Alban Gruin (2): sequencer: make two functions and an enum from sequencer.c public rebase--interactive: rewrite append_todo_help() in C Makefile | 1 + builtin/rebase--helper.c | 11 -- git-rebase--interactive.sh | 52 ++--- rebase-interactive.c | 68 ++ rebase-interactive.h | 6 sequencer.c| 8 ++--- sequencer.h| 6 7 files changed, 94 insertions(+), 58 deletions(-) create mode 100644 rebase-interactive.c create mode 100644 rebase-interactive.h -- 2.18.0
[GSoC][PATCH 1/1] sequencer: print an error message if append_todo_help() fails
This adds an error when append_todo_help() fails to write its message to the todo file. Signed-off-by: Alban Gruin --- sequencer.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sequencer.c b/sequencer.c index 7cc76332e..7c4bdbb99 100644 --- a/sequencer.c +++ b/sequencer.c @@ -4380,6 +4380,9 @@ int append_todo_help(unsigned edit_todo, unsigned keep_empty) } ret = fputs(buf.buf, todo); + if (ret) + error_errno(_("Could not append help text to '%s'"), rebase_path_todo()); + fclose(todo); strbuf_release(&buf); -- 2.18.0
[GSoC][PATCH 0/1] sequencer: print an error message if append_todo_help() fails
Currently, append_todo_help() does not warn the user if an error occurs when trying to write to the todo file. This patch addresses this problem. This patch is based on ag/rebase-i-append-todo-help. Alban Gruin (1): sequencer: print an error message if append_todo_help() fails sequencer.c | 3 +++ 1 file changed, 3 insertions(+) -- 2.18.0
[GSoC] GSoC with git, week 8
Hi, I published my blog post about last week: https://blog.pa1ch.fr/posts/2018/06/25/en/gsoc2018-week-8.html Cheers, Alban
Re: [GSoC][PATCH v3 2/3] rebase -i: rewrite setup_reflog_action() in C
Hi Junio, Le 25/06/2018 à 17:34, Junio C Hamano a écrit : > Alban Gruin writes: > >> Hi Junio, >> >> Le 22/06/2018 à 18:27, Junio C Hamano a écrit : >>> Alban Gruin writes: >>>> This rewrites (the misnamed) setup_reflog_action() from shell to C. The >>>> new version is called checkout_base_commit(). >>> >>> ;-) on the "misnamed" part. Indeed, setting up the comment for the >>> reflog entry is secondary to what this function wants to do, which >>> is to check out the branch to be rebased. >>> >>> I do not think "base_commit" is a good name, either, though. When I >>> hear 'base' in the context of 'rebase', I would imagine that the >>> speaker is talking about the bottom of the range of the commits to >>> be rebased (i.e. "rebase --onto ONTO BASE BRANCH", which replays >>> commits BASE..BRANCH on top of ONTO and then points BRANCH at the >>> result), not the top of the range or the branch these commits are >>> taken from. >>> >> >> Perhaps should I name this function checkout_onto(), and rename >> checkout_onto() to "detach_onto()"? And I would reorder those two commits >> in >> the series, as this would be very confusing. > > I may be misunderstanding what is happening in the function, but I > think it is checking out neither the onto or the base commit. The > function instead is about checking out the branch to be rebased > before anything else happens when the optional argument is > given (and when the optional argument is not given, then we rebase > the current branch so there is no need to check it out upfront), no? > > Yes, you’re right. Now I really don’t know how to call this function. checkout_top_of_range(), perhaps? Cheers, Alban
[GSoC][PATCH v4 3/3] rebase -i: rewrite setup_reflog_action() in C
This rewrites (the misnamed) setup_reflog_action() from shell to C. The new version is called checkout_onto(). A new command is added to rebase--helper.c, “checkout-base”. The shell version is then stripped. As $GIT_REFLOG_ACTION is no longer set at the first call of checkout_onto(), a call to comment_for_reflog() is added at the beginning of this function. If the commit OID provided to checkout_onto() is empty, nothing happens and no errors are returned, otherwise it would break some tests (t3404.92 and t3404.93). Signed-off-by: Alban Gruin --- builtin/rebase--helper.c | 6 +- git-rebase--interactive.sh | 15 +-- sequencer.c| 14 ++ sequencer.h| 2 ++ 4 files changed, 22 insertions(+), 15 deletions(-) diff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c index 2dfd55c76..a00b1091d 100644 --- a/builtin/rebase--helper.c +++ b/builtin/rebase--helper.c @@ -17,7 +17,7 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix) enum { CONTINUE = 1, ABORT, MAKE_SCRIPT, SHORTEN_OIDS, EXPAND_OIDS, CHECK_TODO_LIST, SKIP_UNNECESSARY_PICKS, REARRANGE_SQUASH, - ADD_EXEC, APPEND_TODO_HELP, EDIT_TODO, DETACH_ONTO + ADD_EXEC, APPEND_TODO_HELP, EDIT_TODO, DETACH_ONTO, CHECKOUT_ONTO } command = 0; struct option options[] = { OPT_BOOL(0, "ff", &opts.allow_ff, N_("allow fast-forward")), @@ -53,6 +53,8 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix) EDIT_TODO), OPT_CMDMODE(0, "detach-onto", &command, N_("checkout a commit"), DETACH_ONTO), + OPT_CMDMODE(0, "checkout-onto", &command, + N_("checkout the base commit"), CHECKOUT_ONTO), OPT_END() }; @@ -98,5 +100,7 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix) return !!edit_todo_list(flags); if (command == DETACH_ONTO && argc == 4) return !!detach_onto(&opts, argv[1], argv[2], argv[3], verbose); + if (command == CHECKOUT_ONTO && argc == 2) + return !!checkout_onto(&opts, argv[1], verbose); usage_with_options(builtin_rebase_helper_usage, options); } diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh index 2f5761d49..375c36fb5 100644 --- a/git-rebase--interactive.sh +++ b/git-rebase--interactive.sh @@ -112,19 +112,6 @@ initiate_action () { esac } -setup_reflog_action () { - comment_for_reflog start - - if test ! -z "$switch_to" - then - GIT_REFLOG_ACTION="$GIT_REFLOG_ACTION: checkout $switch_to" - output git checkout "$switch_to" -- || - die "$(eval_gettext "Could not checkout \$switch_to")" - - comment_for_reflog start - fi -} - init_basic_state () { orig_head=$(git rev-parse --verify HEAD) || die "$(gettext "No HEAD?")" mkdir -p "$state_dir" || die "$(eval_gettext "Could not create temporary \$state_dir")" @@ -206,7 +193,7 @@ git_rebase__interactive () { return 0 fi - setup_reflog_action + git rebase--helper --checkout-onto "$switch_to" ${verbose:+--verbose} init_basic_state init_revisions_and_shortrevisions diff --git a/sequencer.c b/sequencer.c index ee6374921..620b41e96 100644 --- a/sequencer.c +++ b/sequencer.c @@ -3165,6 +3165,20 @@ int detach_onto(struct replay_opts *opts, return update_ref(NULL, "ORIG_HEAD", &oid, NULL, 0, UPDATE_REFS_MSG_ON_ERR); } +int checkout_onto(struct replay_opts *opts, const char *commit, + int verbose) +{ + const char *action; + + if (commit && *commit) { + action = reflog_message(opts, "start", "checkout %s", commit); + if (run_git_checkout(opts, commit, verbose, action)) + return error(_("Could not checkout %s"), commit); + } + + return 0; +} + static const char rescheduled_advice[] = N_("Could not execute the todo command\n" "\n" diff --git a/sequencer.h b/sequencer.h index 9f0ac5e75..afbb2edf1 100644 --- a/sequencer.h +++ b/sequencer.h @@ -103,6 +103,8 @@ void commit_post_rewrite(const struct commit *current_head, int detach_onto(struct replay_opts *opts, const char *onto_name, const char *onto, const char *orig_head, unsigned verbose); +int checkout_onto(struct replay_opts *opts, const char *commit, + int verbose); #define SUMMARY_INITIAL_COMMIT (1 << 0) #define SUMMARY_SHOW_AUTHOR_DATE (1 << 1) -- 2.18.0
[GSoC][PATCH v4 0/3] rebase -i: rewrite reflog operations in C
This patch series rewrites the reflog operations from shell to C. This is part of the effort to rewrite interactive rebase in C. The first commit is dedicated to creating a function to silence a command, as the sequencer will do in several places with these patches. This branch is based on ag/rebase-i-rewrite-todo, and does not conflict with pu (as of 2018-06-25). Changes since v3: - Removing a comment from run_command_silent_on_success() - Changing the order of setup_reflog_action() and checkout_onto() rewrites in the series - Renaming checkout_onto() to detach_onto() - Renaming checkout_base_commit() (rewrite of setup_reflog_action()) to checkout_onto() - Using the `else` keyword to call run_command_silent_on_success() or run_command() in run_git_commit() and run_git_checkout(). Alban Gruin (3): sequencer: extract a function to silence a command, except if it fails rebase -i: rewrite checkout_onto() in C rebase -i: rewrite setup_reflog_action() in C builtin/rebase--helper.c | 13 - git-rebase--interactive.sh | 28 ++ sequencer.c| 101 +++-- sequencer.h| 6 +++ 4 files changed, 97 insertions(+), 51 deletions(-) -- 2.18.0
[GSoC][PATCH v4 2/3] rebase -i: rewrite checkout_onto() in C
This rewrites checkout_onto() from shell to C. The new version is called detach_onto(), given its role. A new command (“detach-onto”) is added to rebase--helper.c, as well as a new flag, “verbose”, to avoid silencing the output of the checkout operation called by detach_onto(). The function `run_git_checkout()` will also be used in the next commit, therefore its code is not part of `detach_onto()`. The shell version is then stripped in favour of a call to the helper. Signed-off-by: Alban Gruin --- builtin/rebase--helper.c | 9 +++-- git-rebase--interactive.sh | 13 - sequencer.c| 36 sequencer.h| 4 4 files changed, 51 insertions(+), 11 deletions(-) diff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c index d2990b210..2dfd55c76 100644 --- a/builtin/rebase--helper.c +++ b/builtin/rebase--helper.c @@ -12,12 +12,12 @@ static const char * const builtin_rebase_helper_usage[] = { int cmd_rebase__helper(int argc, const char **argv, const char *prefix) { struct replay_opts opts = REPLAY_OPTS_INIT; - unsigned flags = 0, keep_empty = 0, rebase_merges = 0; + unsigned flags = 0, keep_empty = 0, rebase_merges = 0, verbose = 0; int abbreviate_commands = 0, rebase_cousins = -1; enum { CONTINUE = 1, ABORT, MAKE_SCRIPT, SHORTEN_OIDS, EXPAND_OIDS, CHECK_TODO_LIST, SKIP_UNNECESSARY_PICKS, REARRANGE_SQUASH, - ADD_EXEC, APPEND_TODO_HELP, EDIT_TODO + ADD_EXEC, APPEND_TODO_HELP, EDIT_TODO, DETACH_ONTO } command = 0; struct option options[] = { OPT_BOOL(0, "ff", &opts.allow_ff, N_("allow fast-forward")), @@ -27,6 +27,7 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix) OPT_BOOL(0, "rebase-merges", &rebase_merges, N_("rebase merge commits")), OPT_BOOL(0, "rebase-cousins", &rebase_cousins, N_("keep original branch points of cousins")), + OPT__VERBOSE(&verbose, N_("be verbose")), OPT_CMDMODE(0, "continue", &command, N_("continue rebase"), CONTINUE), OPT_CMDMODE(0, "abort", &command, N_("abort rebase"), @@ -50,6 +51,8 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix) OPT_CMDMODE(0, "edit-todo", &command, N_("edit the todo list during an interactive rebase"), EDIT_TODO), + OPT_CMDMODE(0, "detach-onto", &command, + N_("checkout a commit"), DETACH_ONTO), OPT_END() }; @@ -93,5 +96,7 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix) return !!append_todo_help(0, keep_empty); if (command == EDIT_TODO && argc == 1) return !!edit_todo_list(flags); + if (command == DETACH_ONTO && argc == 4) + return !!detach_onto(&opts, argv[1], argv[2], argv[3], verbose); usage_with_options(builtin_rebase_helper_usage, options); } diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh index 2defe607f..2f5761d49 100644 --- a/git-rebase--interactive.sh +++ b/git-rebase--interactive.sh @@ -70,13 +70,6 @@ collapse_todo_ids() { git rebase--helper --shorten-ids } -# Switch to the branch in $into and notify it in the reflog -checkout_onto () { - GIT_REFLOG_ACTION="$GIT_REFLOG_ACTION: checkout $onto_name" - output git checkout $onto || die_abort "$(gettext "could not detach HEAD")" - git update-ref ORIG_HEAD $orig_head -} - get_missing_commit_check_level () { check_level=$(git config --get rebase.missingCommitsCheck) check_level=${check_level:-ignore} @@ -188,7 +181,8 @@ EOF git rebase--helper --check-todo-list || { ret=$? - checkout_onto + git rebase--helper --detach-onto "$onto_name" "$onto" \ + "$orig_head" ${verbose:+--verbose} exit $ret } @@ -198,7 +192,8 @@ EOF onto="$(git rebase--helper --skip-unnecessary-picks)" || die "Could not skip unnecessary pick commands" - checkout_onto + git rebase--helper --detach-onto "$onto_name" "$onto" "$orig_head" \ + ${verbose:+--verbose} require_clean_work_tree "rebase" exec git rebase--helper ${force_rebase:+--no-ff} $allow_empty_message \ --continue diff --git a/sequencer.c b/sequencer.c index 9a9725e23..ee6374921 100644 --
[GSoC][PATCH v4 1/3] sequencer: extract a function to silence a command, except if it fails
This extracts the part of run_git_commit() that redirects the stdout and stderr of a command to a strbuf, and prints it if the command fails, to a helper function: run_command_silent_on_success(). It is intended to replace output() from git-rebase.sh in the rewrite of setup_reflog_action() and checkout_onto(). Signed-off-by: Alban Gruin --- sequencer.c | 51 +-- 1 file changed, 25 insertions(+), 26 deletions(-) diff --git a/sequencer.c b/sequencer.c index 7cc76332e..9a9725e23 100644 --- a/sequencer.c +++ b/sequencer.c @@ -766,6 +766,23 @@ N_("you have staged changes in your working tree\n" #define VERIFY_MSG (1<<4) #define CREATE_ROOT_COMMIT (1<<5) +static int run_command_silent_on_success(struct child_process *cmd) +{ + struct strbuf buf = STRBUF_INIT; + int rc; + + cmd->stdout_to_stderr = 1; + rc = pipe_command(cmd, + NULL, 0, + NULL, 0, + &buf, 0); + + if (rc) + fputs(buf.buf, stderr); + strbuf_release(&buf); + return rc; +} + /* * If we are cherry-pick, and if the merge did not result in * hand-editing, we will hit this commit and inherit the original @@ -820,18 +837,11 @@ static int run_git_commit(const char *defmsg, struct replay_opts *opts, cmd.git_cmd = 1; - if (is_rebase_i(opts)) { - if (!(flags & EDIT_MSG)) { - cmd.stdout_to_stderr = 1; - cmd.err = -1; - } - - if (read_env_script(&cmd.env_array)) { - const char *gpg_opt = gpg_sign_opt_quoted(opts); + if (is_rebase_i(opts) && read_env_script(&cmd.env_array)) { + const char *gpg_opt = gpg_sign_opt_quoted(opts); - return error(_(staged_changes_advice), -gpg_opt, gpg_opt); - } + return error(_(staged_changes_advice), +gpg_opt, gpg_opt); } argv_array_push(&cmd.args, "commit"); @@ -861,21 +871,10 @@ static int run_git_commit(const char *defmsg, struct replay_opts *opts, if (opts->allow_empty_message) argv_array_push(&cmd.args, "--allow-empty-message"); - if (cmd.err == -1) { - /* hide stderr on success */ - struct strbuf buf = STRBUF_INIT; - int rc = pipe_command(&cmd, - NULL, 0, - /* stdout is already redirected */ - NULL, 0, - &buf, 0); - if (rc) - fputs(buf.buf, stderr); - strbuf_release(&buf); - return rc; - } - - return run_command(&cmd); + if (is_rebase_i(opts) && !(flags & EDIT_MSG)) + return run_command_silent_on_success(&cmd); + else + return run_command(&cmd); } static int rest_is_empty(const struct strbuf *sb, int start) -- 2.18.0
Re: [GSoC][PATCH v3 2/3] rebase -i: rewrite setup_reflog_action() in C
Hi Junio, Le 22/06/2018 à 18:27, Junio C Hamano a écrit : > Alban Gruin writes: > > This rewrites (the misnamed) setup_reflog_action() from shell to C. The > > new version is called checkout_base_commit(). > > ;-) on the "misnamed" part. Indeed, setting up the comment for the > reflog entry is secondary to what this function wants to do, which > is to check out the branch to be rebased. > > I do not think "base_commit" is a good name, either, though. When I > hear 'base' in the context of 'rebase', I would imagine that the > speaker is talking about the bottom of the range of the commits to > be rebased (i.e. "rebase --onto ONTO BASE BRANCH", which replays > commits BASE..BRANCH on top of ONTO and then points BRANCH at the > result), not the top of the range or the branch these commits are > taken from. > Perhaps should I name this function checkout_onto(), and rename checkout_onto() to "detach_onto()"? And I would reorder those two commits in the series, as this would be very confusing. > > index 51c8ab7ac..27f8453fe 100644 > > --- a/sequencer.c > > +++ b/sequencer.c > > @@ -3129,6 +3129,36 @@ static const char *reflog_message(struct > > replay_opts *opts,> > > return buf.buf; > > > > } > > > > +static int run_git_checkout(struct replay_opts *opts, const char *commit, > > + int verbose, const char *action) > > +{ > > + struct child_process cmd = CHILD_PROCESS_INIT; > > + > > + cmd.git_cmd = 1; > > + > > + argv_array_push(&cmd.args, "checkout"); > > + argv_array_push(&cmd.args, commit); > > + argv_array_pushf(&cmd.env_array, GIT_REFLOG_ACTION "=%s", action); > > + > > + if (verbose) > > + return run_command(&cmd); > > + return run_command_silent_on_success(&cmd); > > For the same reason as 1/3, I think it makes more sense to have > "else" here. > Right. > > +int checkout_base_commit(struct replay_opts *opts, const char *commit, > > +int verbose) > > +{ > > + const char *action; > > + > > + if (commit && *commit) { > > Hmm, isn't it a programming error to feed !commit or !*commit here? > I offhand do not think of a reason why making such an input a silent > no-op success, instead of making it error out, would be a good idea. > I think it’s correct. > > + action = reflog_message(opts, "start", "checkout %s", commit); > > + if (run_git_checkout(opts, commit, verbose, action)) > > + return error(_("Could not checkout %s"), commit); > > + } > > + > > + return 0; > > +} > > + > > > > static const char rescheduled_advice[] = > > N_("Could not execute the todo command\n" > > "\n" > > > > diff --git a/sequencer.h b/sequencer.h > > index 35730b13e..42c3dda81 100644 > > --- a/sequencer.h > > +++ b/sequencer.h > > @@ -100,6 +100,9 @@ int update_head_with_reflog(const struct commit > > *old_head,> > > void commit_post_rewrite(const struct commit *current_head, > > > > const struct object_id *new_head); > > > > +int checkout_base_commit(struct replay_opts *opts, const char *commit, > > +int verbose); > > + > > > > #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, Cheers, Alban
Re: [GSoC][PATCH v3 1/3] sequencer: add a new function to silence a command, except if it fails.
Hi Junio, Le 22/06/2018 à 00:03, Junio C Hamano a écrit : > Alban Gruin writes: > > This adds a new function, run_command_silent_on_success(), to > > redirect the stdout and stderr of a command to a strbuf, and then to run > > that command. This strbuf is printed only if the command fails. It is > > functionnaly similar to output() from git-rebase.sh. > > > > run_git_commit() is then refactored to use of > > run_command_silent_on_success(). > > It might be just a difference in viewpoint, but I think it is more > customary in this project (hence it will be easier to understand and > accept by readers of the patch) if a change like this is explained > NOT as "introducing a new function and then rewrite an existing code > to use it", and instead as "extract a helper function from an > existing code so that future callers can reuse it." > I like your wording. It’s not a difference of point of view, I’m just bad at writing commit messages ;) > > +static int run_command_silent_on_success(struct child_process *cmd) > > +{ > > + struct strbuf buf = STRBUF_INIT; > > + int rc; > > + > > + cmd->stdout_to_stderr = 1; > > + rc = pipe_command(cmd, > > + NULL, 0, > > + /* stdout is already redirected */ > > I can see that this comment was inherited from the original place > this code was lifted from (and that is why I say this is not "adding > a new helper and rewriting an existing piece of code to use it" but > is "extracting this function out of an existing code for future > reuse"), but does it still make sense in the new context to keep the > same comment? > > The original in run_git_commit() made the .stdout_to_stderr=1 > assignment many lines before it called pipe_command(), and it made > sense to remind readers why we are passing NULL to the out buffer > and only passing the err buffer here. But in the context of this > new helper function, the redirection that may make such a reminder > necessary sits immediately before the pipe_command() call for > everybody to see. > Yeah, you’re right. > > @@ -861,20 +872,8 @@ static int run_git_commit(const char *defmsg, struct > > replay_opts *opts,> > > if (opts->allow_empty_message) > > > > argv_array_push(&cmd.args, "--allow-empty-message"); > > > > - if (cmd.err == -1) { > > - /* hide stderr on success */ > > - struct strbuf buf = STRBUF_INIT; > > - int rc = pipe_command(&cmd, > > - NULL, 0, > > - /* stdout is already redirected */ > > - NULL, 0, > > - &buf, 0); > > - if (rc) > > - fputs(buf.buf, stderr); > > - strbuf_release(&buf); > > - return rc; > > - } > > - > > + if (is_rebase_i(opts) && !(flags & EDIT_MSG)) > > + return run_command_silent_on_success(&cmd); > > > > return run_command(&cmd); > > > > } > > It probably is easier to understand the code if you added > an "else" after, to highlight the fact that this is choosing one out > of two possible ways to run "cmd", i.e. > > if (is_rebase_i(opts) && !(flags & EDIT_MSG)) > return run_command_silent_on_success(&cmd); > else > return run_command(&cmd); Okay. Cheers, Alban
[GSoC][PATCH v3 3/3] rebase -i: rewrite checkout_onto() in C
This rewrites checkout_onto() from shell to C. A new command (“checkout-onto”) is added to rebase--helper.c. The shell version is then stripped. Signed-off-by: Alban Gruin --- builtin/rebase--helper.c | 7 ++- git-rebase--interactive.sh | 25 - sequencer.c| 19 +++ sequencer.h| 3 +++ 4 files changed, 32 insertions(+), 22 deletions(-) diff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c index fb5996a2c..20dea4b3a 100644 --- a/builtin/rebase--helper.c +++ b/builtin/rebase--helper.c @@ -17,7 +17,8 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix) enum { CONTINUE = 1, ABORT, MAKE_SCRIPT, SHORTEN_OIDS, EXPAND_OIDS, CHECK_TODO_LIST, SKIP_UNNECESSARY_PICKS, REARRANGE_SQUASH, - ADD_EXEC, APPEND_TODO_HELP, EDIT_TODO, CHECKOUT_BASE + ADD_EXEC, APPEND_TODO_HELP, EDIT_TODO, CHECKOUT_BASE, + CHECKOUT_ONTO } command = 0; struct option options[] = { OPT_BOOL(0, "ff", &opts.allow_ff, N_("allow fast-forward")), @@ -53,6 +54,8 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix) EDIT_TODO), OPT_CMDMODE(0, "checkout-base", &command, N_("checkout the base commit"), CHECKOUT_BASE), + OPT_CMDMODE(0, "checkout-onto", &command, + N_("checkout a commit"), CHECKOUT_ONTO), OPT_END() }; @@ -98,5 +101,7 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix) return !!edit_todo_list(flags); if (command == CHECKOUT_BASE && argc == 2) return !!checkout_base_commit(&opts, argv[1], verbose); + if (command == CHECKOUT_ONTO && argc == 4) + return !!checkout_onto(&opts, argv[1], argv[2], argv[3], verbose); usage_with_options(builtin_rebase_helper_usage, options); } diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh index af46cf9c2..7b6142a76 100644 --- a/git-rebase--interactive.sh +++ b/git-rebase--interactive.sh @@ -28,17 +28,6 @@ case "$comment_char" in ;; esac -orig_reflog_action="$GIT_REFLOG_ACTION" - -comment_for_reflog () { - case "$orig_reflog_action" in - ''|rebase*) - GIT_REFLOG_ACTION="rebase -i ($1)" - export GIT_REFLOG_ACTION - ;; - esac -} - die_abort () { apply_autostash rm -rf "$state_dir" @@ -70,14 +59,6 @@ collapse_todo_ids() { git rebase--helper --shorten-ids } -# Switch to the branch in $into and notify it in the reflog -checkout_onto () { - comment_for_reflog start - GIT_REFLOG_ACTION="$GIT_REFLOG_ACTION: checkout $onto_name" - output git checkout $onto || die_abort "$(gettext "could not detach HEAD")" - git update-ref ORIG_HEAD $orig_head -} - get_missing_commit_check_level () { check_level=$(git config --get rebase.missingCommitsCheck) check_level=${check_level:-ignore} @@ -176,7 +157,8 @@ EOF git rebase--helper --check-todo-list || { ret=$? - checkout_onto + git rebase--helper --checkout-onto "$onto_name" "$onto" \ + "$orig_head" ${verbose:+--verbose} exit $ret } @@ -186,7 +168,8 @@ EOF onto="$(git rebase--helper --skip-unnecessary-picks)" || die "Could not skip unnecessary pick commands" - checkout_onto + git rebase--helper --checkout-onto "$onto_name" "$onto" "$orig_head" \ + ${verbose:+--verbose} require_clean_work_tree "rebase" exec git rebase--helper ${force_rebase:+--no-ff} $allow_empty_message \ --continue diff --git a/sequencer.c b/sequencer.c index 27f8453fe..b3b1a2e18 100644 --- a/sequencer.c +++ b/sequencer.c @@ -3159,6 +3159,25 @@ int checkout_base_commit(struct replay_opts *opts, const char *commit, return 0; } +int checkout_onto(struct replay_opts *opts, + const char *onto_name, const char *onto, + const char *orig_head, unsigned verbose) +{ + struct object_id oid; + const char *action = reflog_message(opts, "start", "checkout %s", onto_name); + + if (get_oid(orig_head, &oid)) + return error(_("%s: not a valid OID"), orig_head); + + if (run_git_checkout(opts, onto, verbose, action)) { + apply_autostash(opts); + sequencer_remove_state(opts); + return error(_("could not det
[GSoC][PATCH v3 1/3] sequencer: add a new function to silence a command, except if it fails.
This adds a new function, run_command_silent_on_success(), to redirect the stdout and stderr of a command to a strbuf, and then to run that command. This strbuf is printed only if the command fails. It is functionnaly similar to output() from git-rebase.sh. run_git_commit() is then refactored to use of run_command_silent_on_success(). Signed-off-by: Alban Gruin --- sequencer.c | 49 - 1 file changed, 24 insertions(+), 25 deletions(-) diff --git a/sequencer.c b/sequencer.c index 7cc76332e..51c8ab7ac 100644 --- a/sequencer.c +++ b/sequencer.c @@ -766,6 +766,24 @@ N_("you have staged changes in your working tree\n" #define VERIFY_MSG (1<<4) #define CREATE_ROOT_COMMIT (1<<5) +static int run_command_silent_on_success(struct child_process *cmd) +{ + struct strbuf buf = STRBUF_INIT; + int rc; + + cmd->stdout_to_stderr = 1; + rc = pipe_command(cmd, + NULL, 0, + /* stdout is already redirected */ + NULL, 0, + &buf, 0); + + if (rc) + fputs(buf.buf, stderr); + strbuf_release(&buf); + return rc; +} + /* * If we are cherry-pick, and if the merge did not result in * hand-editing, we will hit this commit and inherit the original @@ -820,18 +838,11 @@ static int run_git_commit(const char *defmsg, struct replay_opts *opts, cmd.git_cmd = 1; - if (is_rebase_i(opts)) { - if (!(flags & EDIT_MSG)) { - cmd.stdout_to_stderr = 1; - cmd.err = -1; - } + if (is_rebase_i(opts) && read_env_script(&cmd.env_array)) { + const char *gpg_opt = gpg_sign_opt_quoted(opts); - if (read_env_script(&cmd.env_array)) { - const char *gpg_opt = gpg_sign_opt_quoted(opts); - - return error(_(staged_changes_advice), -gpg_opt, gpg_opt); - } + return error(_(staged_changes_advice), +gpg_opt, gpg_opt); } argv_array_push(&cmd.args, "commit"); @@ -861,20 +872,8 @@ static int run_git_commit(const char *defmsg, struct replay_opts *opts, if (opts->allow_empty_message) argv_array_push(&cmd.args, "--allow-empty-message"); - if (cmd.err == -1) { - /* hide stderr on success */ - struct strbuf buf = STRBUF_INIT; - int rc = pipe_command(&cmd, - NULL, 0, - /* stdout is already redirected */ - NULL, 0, - &buf, 0); - if (rc) - fputs(buf.buf, stderr); - strbuf_release(&buf); - return rc; - } - + if (is_rebase_i(opts) && !(flags & EDIT_MSG)) + return run_command_silent_on_success(&cmd); return run_command(&cmd); } -- 2.17.1
[GSoC][PATCH v3 2/3] rebase -i: rewrite setup_reflog_action() in C
This rewrites (the misnamed) setup_reflog_action() from shell to C. The new version is called checkout_base_commit(). A new command is added to rebase--helper.c, “checkout-base”, as well as a new flag, “verbose”, to avoid silencing the output of the checkout operation called by checkout_base_commit(). The function `run_git_checkout()` will also be used in the next commit, therefore its code is not part of `checkout_base_commit()`. The shell version is then stripped in favour of a call to the helper. As $GIT_REFLOG_ACTION is no longer set at the first call of checkout_onto(), a call to comment_for_reflog() is added at the beginning of this function. Signed-off-by: Alban Gruin --- builtin/rebase--helper.c | 9 +++-- git-rebase--interactive.sh | 16 ++-- sequencer.c| 30 ++ sequencer.h| 3 +++ 4 files changed, 42 insertions(+), 16 deletions(-) diff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c index d2990b210..fb5996a2c 100644 --- a/builtin/rebase--helper.c +++ b/builtin/rebase--helper.c @@ -12,12 +12,12 @@ static const char * const builtin_rebase_helper_usage[] = { int cmd_rebase__helper(int argc, const char **argv, const char *prefix) { struct replay_opts opts = REPLAY_OPTS_INIT; - unsigned flags = 0, keep_empty = 0, rebase_merges = 0; + unsigned flags = 0, keep_empty = 0, rebase_merges = 0, verbose = 0; int abbreviate_commands = 0, rebase_cousins = -1; enum { CONTINUE = 1, ABORT, MAKE_SCRIPT, SHORTEN_OIDS, EXPAND_OIDS, CHECK_TODO_LIST, SKIP_UNNECESSARY_PICKS, REARRANGE_SQUASH, - ADD_EXEC, APPEND_TODO_HELP, EDIT_TODO + ADD_EXEC, APPEND_TODO_HELP, EDIT_TODO, CHECKOUT_BASE } command = 0; struct option options[] = { OPT_BOOL(0, "ff", &opts.allow_ff, N_("allow fast-forward")), @@ -27,6 +27,7 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix) OPT_BOOL(0, "rebase-merges", &rebase_merges, N_("rebase merge commits")), OPT_BOOL(0, "rebase-cousins", &rebase_cousins, N_("keep original branch points of cousins")), + OPT__VERBOSE(&verbose, N_("be verbose")), OPT_CMDMODE(0, "continue", &command, N_("continue rebase"), CONTINUE), OPT_CMDMODE(0, "abort", &command, N_("abort rebase"), @@ -50,6 +51,8 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix) OPT_CMDMODE(0, "edit-todo", &command, N_("edit the todo list during an interactive rebase"), EDIT_TODO), + OPT_CMDMODE(0, "checkout-base", &command, + N_("checkout the base commit"), CHECKOUT_BASE), OPT_END() }; @@ -93,5 +96,7 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix) return !!append_todo_help(0, keep_empty); if (command == EDIT_TODO && argc == 1) return !!edit_todo_list(flags); + if (command == CHECKOUT_BASE && argc == 2) + return !!checkout_base_commit(&opts, argv[1], verbose); usage_with_options(builtin_rebase_helper_usage, options); } diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh index 2defe607f..af46cf9c2 100644 --- a/git-rebase--interactive.sh +++ b/git-rebase--interactive.sh @@ -72,6 +72,7 @@ collapse_todo_ids() { # Switch to the branch in $into and notify it in the reflog checkout_onto () { + comment_for_reflog start GIT_REFLOG_ACTION="$GIT_REFLOG_ACTION: checkout $onto_name" output git checkout $onto || die_abort "$(gettext "could not detach HEAD")" git update-ref ORIG_HEAD $orig_head @@ -119,19 +120,6 @@ initiate_action () { esac } -setup_reflog_action () { - comment_for_reflog start - - if test ! -z "$switch_to" - then - GIT_REFLOG_ACTION="$GIT_REFLOG_ACTION: checkout $switch_to" - output git checkout "$switch_to" -- || - die "$(eval_gettext "Could not checkout \$switch_to")" - - comment_for_reflog start - fi -} - init_basic_state () { orig_head=$(git rev-parse --verify HEAD) || die "$(gettext "No HEAD?")" mkdir -p "$state_dir" || die "$(eval_gettext "Could not create temporary \$state_dir")" @@ -211,7 +199,7 @@ git_rebase__interactive () { return 0 fi - setup_reflog_action +
[GSoC][PATCH v3 0/3] rebase -i: rewrite reflog operations in C
Thes patch series rewrites the reflog operations from shell to C. This is part of the effort to rewrite interactive rebase in C. The first commit is dedicated to creating a function to silence a command, as the sequencer will do in several places with these patches. This branch is based on ag/rebase-i-rewrite-todo, and does not conflict with pu (as of 2018-06-21). Changes since v2: - Removing the “verbose” parameter to run_command_silent_on_success() - Rewording some parts of the second commit - Changing the help for the “--verbose” flag Alban Gruin (3): sequencer: add a new function to silence a command, except if it fails. rebase -i: rewrite setup_reflog_action() in C rebase -i: rewrite checkout_onto() in C builtin/rebase--helper.c | 14 +- git-rebase--interactive.sh | 39 ++- sequencer.c| 98 -- sequencer.h| 6 +++ 4 files changed, 96 insertions(+), 61 deletions(-) -- 2.17.1
Re: [GSoC][PATCH v2 1/3] sequencer: add a new function to silence a command, except if it fails.
Hi Johannes, Le 21/06/2018 à 11:37, Johannes Schindelin a écrit : > Hi Alban, > > On Tue, 19 Jun 2018, Alban Gruin wrote: > >> diff --git a/sequencer.c b/sequencer.c >> index 7cc76332e..9aa7ddb33 100644 >> --- a/sequencer.c >> +++ b/sequencer.c >> @@ -766,6 +766,29 @@ N_("you have staged changes in your working tree\n" >> #define VERIFY_MSG (1<<4) >> #define CREATE_ROOT_COMMIT (1<<5) >> >> +static int run_command_silent_on_success(struct child_process *cmd, >> + unsigned verbose) >> +{ >> +struct strbuf buf = STRBUF_INIT; >> +int rc; >> + >> +if (verbose) >> +return run_command(cmd); >> + >> +/* hide stderr on success */ >> +cmd->stdout_to_stderr = 1; > > This comment is a bit misleading: that line does not hide stderr on > success, it redirects stdout to stderr instead. > >> +rc = pipe_command(cmd, >> + NULL, 0, >> + /* stdout is already redirected */ >> + NULL, 0, >> + &buf, 0); >> + >> +if (rc) >> +fputs(buf.buf, stderr); >> +strbuf_release(&buf); >> +return rc; >> +} >> + >> /* >> * If we are cherry-pick, and if the merge did not result in >> * hand-editing, we will hit this commit and inherit the original >> @@ -820,18 +843,11 @@ static int run_git_commit(const char *defmsg, struct >> replay_opts *opts, >> >> cmd.git_cmd = 1; >> >> -if (is_rebase_i(opts)) { >> -if (!(flags & EDIT_MSG)) { >> -cmd.stdout_to_stderr = 1; >> -cmd.err = -1; >> -} > > This code made sure that we *only* do this redirection, and stderr > buffering, if `git commit` is called non-interactively. When it is called > interactively, redirecting stdout and stderr is absolutely not what we > want. > >> +if (is_rebase_i(opts) && read_env_script(&cmd.env_array)) { >> +const char *gpg_opt = gpg_sign_opt_quoted(opts); >> >> -if (read_env_script(&cmd.env_array)) { >> -const char *gpg_opt = gpg_sign_opt_quoted(opts); >> - >> -return error(_(staged_changes_advice), >> - gpg_opt, gpg_opt); >> -} >> +return error(_(staged_changes_advice), >> + gpg_opt, gpg_opt); >> } >> >> argv_array_push(&cmd.args, "commit"); >> @@ -861,21 +877,8 @@ static int run_git_commit(const char *defmsg, struct >> replay_opts *opts, >> if (opts->allow_empty_message) >> argv_array_push(&cmd.args, "--allow-empty-message"); >> >> -if (cmd.err == -1) { >> -/* hide stderr on success */ >> -struct strbuf buf = STRBUF_INIT; >> -int rc = pipe_command(&cmd, >> - NULL, 0, >> - /* stdout is already redirected */ >> - NULL, 0, >> - &buf, 0); >> -if (rc) >> -fputs(buf.buf, stderr); >> -strbuf_release(&buf); >> -return rc; >> -} >> - >> -return run_command(&cmd); >> +return run_command_silent_on_success(&cmd, >> + !(is_rebase_i(opts) && !(flags & >> EDIT_MSG))); > > It would probably make more sense to change the signature of > `run_command_silent_on_success()` to not even take the `int verbose` > parameter: why call it "silent on success" when we can ask it *not* to be > silent on success? > > And then you can avoid this overly-long line (as well as the quite > convoluted Boolean logic that took me a couple of seconds to verify) very > elegantly by this code: > > if (is_rebase_i(opts) && !(flags & EDIT_MSG)) > return run_command_silent_on_success(&cmd); > return run_command(&cmd); > > I vaguely recall that I wanted to make this an option in the `struct > child_process` when I originally introduced this code, but I think it was > Peff who suggested that doing it "by hand" was the more appropriate way > here because I use it only once. > > My recollection might fail me, but if it is correct, maybe that would be a > good way forward, to make this an `int silent_on_success:1;` field? > I think I found it: https://public-inbox.org/git/1e82aeabb906a35175362418b2b4957fae50c3b0.1481642927.git.johannes.schinde...@gmx.de/ Apparently, you wanted to introduce a new RUN_ flag for run_command_v_opt_cd_env(), but the change was qualified as a “bolted-on feature” by Johannes Sixt. So, I will remove the “verbose” argument in the reroll. Cheers, Alban