[GSoC][PATCH v5 10/20] t3404: todo list with commented-out commands only aborts

2018-07-31 Thread Alban Gruin
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

2018-07-31 Thread Alban Gruin
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

2018-07-31 Thread Alban Gruin
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

2018-07-31 Thread Alban Gruin
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

2018-07-31 Thread Alban Gruin
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

2018-07-31 Thread Alban Gruin
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

2018-07-31 Thread Alban Gruin
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

2018-07-31 Thread Alban Gruin
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

2018-07-31 Thread Alban Gruin
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

2018-07-31 Thread Alban Gruin
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

2018-07-31 Thread Alban Gruin
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

2018-07-31 Thread Alban Gruin
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

2018-07-31 Thread Alban Gruin
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

2018-07-31 Thread Alban Gruin
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

2018-07-30 Thread Alban Gruin
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

2018-07-30 Thread Alban Gruin
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

2018-07-24 Thread Alban Gruin
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

2018-07-24 Thread Alban Gruin
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

2018-07-24 Thread Alban Gruin
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

2018-07-24 Thread Alban Gruin
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

2018-07-24 Thread Alban Gruin
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

2018-07-24 Thread Alban Gruin
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

2018-07-24 Thread Alban Gruin
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

2018-07-24 Thread Alban Gruin
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

2018-07-24 Thread Alban Gruin
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

2018-07-24 Thread Alban Gruin
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

2018-07-24 Thread Alban Gruin
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

2018-07-24 Thread Alban Gruin
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

2018-07-24 Thread Alban Gruin
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

2018-07-24 Thread Alban Gruin
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

2018-07-24 Thread Alban Gruin
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

2018-07-24 Thread Alban Gruin
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

2018-07-24 Thread Alban Gruin
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

2018-07-24 Thread Alban Gruin
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

2018-07-24 Thread Alban Gruin
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

2018-07-24 Thread Alban Gruin
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

2018-07-24 Thread Alban Gruin
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

2018-07-24 Thread Alban Gruin
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)

2018-07-20 Thread Alban Gruin
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

2018-07-17 Thread Alban Gruin
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

2018-07-11 Thread Alban Gruin
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

2018-07-10 Thread Alban Gruin
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

2018-07-10 Thread Alban Gruin
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

2018-07-10 Thread Alban Gruin
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

2018-07-10 Thread Alban Gruin
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

2018-07-10 Thread Alban Gruin
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

2018-07-10 Thread Alban Gruin
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

2018-07-10 Thread Alban Gruin
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

2018-07-10 Thread Alban Gruin
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

2018-07-10 Thread Alban Gruin
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

2018-07-10 Thread Alban Gruin
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

2018-07-10 Thread Alban Gruin
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

2018-07-10 Thread Alban Gruin
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

2018-07-10 Thread Alban Gruin
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

2018-07-10 Thread Alban Gruin
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

2018-07-10 Thread Alban Gruin
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

2018-07-10 Thread Alban Gruin
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

2018-07-10 Thread Alban Gruin
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

2018-07-05 Thread Alban Gruin
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

2018-07-02 Thread Alban Gruin
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

2018-07-02 Thread Alban Gruin
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

2018-07-02 Thread Alban Gruin
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.

2018-07-02 Thread Alban Gruin
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

2018-07-02 Thread Alban Gruin
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

2018-07-02 Thread Alban Gruin
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

2018-07-02 Thread Alban Gruin
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

2018-07-02 Thread Alban Gruin
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

2018-07-02 Thread Alban Gruin
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

2018-07-02 Thread Alban Gruin
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

2018-06-29 Thread Alban Gruin
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

2018-06-29 Thread Alban Gruin
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.

2018-06-29 Thread Alban Gruin
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

2018-06-29 Thread Alban Gruin
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)

2018-06-29 Thread Alban Gruin
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

2018-06-28 Thread Alban Gruin
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

2018-06-28 Thread Alban Gruin
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

2018-06-28 Thread Alban Gruin
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

2018-06-27 Thread Alban Gruin
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

2018-06-27 Thread Alban Gruin
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

2018-06-26 Thread Alban Gruin
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

2018-06-26 Thread Alban Gruin
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

2018-06-26 Thread Alban Gruin
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

2018-06-26 Thread Alban Gruin
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

2018-06-26 Thread Alban Gruin
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

2018-06-26 Thread Alban Gruin
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

2018-06-26 Thread Alban Gruin
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

2018-06-26 Thread Alban Gruin
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

2018-06-25 Thread Alban Gruin
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

2018-06-25 Thread Alban Gruin
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

2018-06-25 Thread Alban Gruin
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

2018-06-25 Thread Alban Gruin
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

2018-06-25 Thread Alban Gruin
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

2018-06-25 Thread Alban Gruin
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

2018-06-22 Thread Alban Gruin
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.

2018-06-22 Thread Alban Gruin
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

2018-06-21 Thread Alban Gruin
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.

2018-06-21 Thread Alban Gruin
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

2018-06-21 Thread Alban Gruin
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

2018-06-21 Thread Alban Gruin
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.

2018-06-21 Thread Alban Gruin
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



<    1   2   3   4   5   >